Merging from default branch and resolving conflicts. mvn install -DskipTests passes OK.
1.1 --- a/.hgtags Tue Apr 29 15:25:58 2014 +0200
1.2 +++ b/.hgtags Wed Apr 30 15:04:10 2014 +0200
1.3 @@ -10,3 +10,5 @@
1.4 623816269b75e53fffb4b19960df7040a3c20056 release-0.7
1.5 23572dc719bd630817d11eaabdee4565f63ef8e1 release-0.7.1
1.6 56abd247f421febd8b2c5e59d666968692e11555 release-0.7.2
1.7 +a83e16b8b825399bb21461e578c32d86982e4ed3 release-0.8
1.8 +1b30bba2b38db83c7a232039cfd2eaf7e0e25f3f release-0.8.1
2.1 --- a/benchmarks/matrix-multiplication/pom.xml Tue Apr 29 15:25:58 2014 +0200
2.2 +++ b/benchmarks/matrix-multiplication/pom.xml Wed Apr 30 15:04:10 2014 +0200
2.3 @@ -4,12 +4,12 @@
2.4
2.5 <groupId>org.apidesign.bck2brwsr</groupId>
2.6 <artifactId>matrix.multiplication</artifactId>
2.7 - <version>0.8-SNAPSHOT</version>
2.8 + <version>0.9-SNAPSHOT</version>
2.9 <packaging>jar</packaging>
2.10 <parent>
2.11 <artifactId>benchmarks</artifactId>
2.12 <groupId>org.apidesign.bck2brwsr</groupId>
2.13 - <version>0.8-SNAPSHOT</version>
2.14 + <version>0.9-SNAPSHOT</version>
2.15 </parent>
2.16
2.17 <name>Matrix multiplication</name>
2.18 @@ -74,7 +74,7 @@
2.19 <dependency>
2.20 <groupId>org.apidesign.bck2brwsr</groupId>
2.21 <artifactId>emul.mini</artifactId>
2.22 - <version>0.8-SNAPSHOT</version>
2.23 + <version>0.9-SNAPSHOT</version>
2.24 </dependency>
2.25 <dependency>
2.26 <groupId>org.testng</groupId>
2.27 @@ -91,13 +91,13 @@
2.28 <dependency>
2.29 <groupId>org.apidesign.bck2brwsr</groupId>
2.30 <artifactId>vmtest</artifactId>
2.31 - <version>0.8-SNAPSHOT</version>
2.32 + <version>0.9-SNAPSHOT</version>
2.33 <scope>test</scope>
2.34 </dependency>
2.35 <dependency>
2.36 <groupId>org.apidesign.bck2brwsr</groupId>
2.37 <artifactId>launcher.http</artifactId>
2.38 - <version>0.8-SNAPSHOT</version>
2.39 + <version>0.9-SNAPSHOT</version>
2.40 <scope>test</scope>
2.41 </dependency>
2.42 </dependencies>
3.1 --- a/benchmarks/pom.xml Tue Apr 29 15:25:58 2014 +0200
3.2 +++ b/benchmarks/pom.xml Wed Apr 30 15:04:10 2014 +0200
3.3 @@ -4,11 +4,11 @@
3.4 <parent>
3.5 <artifactId>bck2brwsr</artifactId>
3.6 <groupId>org.apidesign</groupId>
3.7 - <version>0.8-SNAPSHOT</version>
3.8 + <version>0.9-SNAPSHOT</version>
3.9 </parent>
3.10 <groupId>org.apidesign.bck2brwsr</groupId>
3.11 <artifactId>benchmarks</artifactId>
3.12 - <version>0.8-SNAPSHOT</version>
3.13 + <version>0.9-SNAPSHOT</version>
3.14 <packaging>pom</packaging>
3.15 <name>Performance benchmarks</name>
3.16 <modules>
4.1 --- a/dew/nbactions.xml Tue Apr 29 15:25:58 2014 +0200
4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
4.3 @@ -1,52 +0,0 @@
4.4 -<?xml version="1.0" encoding="UTF-8"?>
4.5 -<!--
4.6 -
4.7 - Back 2 Browser Bytecode Translator
4.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
4.9 -
4.10 - This program is free software: you can redistribute it and/or modify
4.11 - it under the terms of the GNU General Public License as published by
4.12 - the Free Software Foundation, version 2 of the License.
4.13 -
4.14 - This program is distributed in the hope that it will be useful,
4.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
4.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4.17 - GNU General Public License for more details.
4.18 -
4.19 - You should have received a copy of the GNU General Public License
4.20 - along with this program. Look for COPYING file in the top folder.
4.21 - If not, see http://opensource.org/licenses/GPL-2.0.
4.22 -
4.23 --->
4.24 -<actions>
4.25 - <action>
4.26 - <actionName>run</actionName>
4.27 - <goals>
4.28 - <goal>process-classes</goal>
4.29 - <goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
4.30 - </goals>
4.31 - </action>
4.32 - <action>
4.33 - <actionName>debug</actionName>
4.34 - <goals>
4.35 - <goal>process-classes</goal>
4.36 - <goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
4.37 - </goals>
4.38 - <properties>
4.39 - <exec.args>-Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath org.apidesign.bck2brwsr.dew.Dew</exec.args>
4.40 - <exec.executable>java</exec.executable>
4.41 - <jpda.listen>true</jpda.listen>
4.42 - </properties>
4.43 - </action>
4.44 - <action>
4.45 - <actionName>profile</actionName>
4.46 - <goals>
4.47 - <goal>process-classes</goal>
4.48 - <goal>org.codehaus.mojo:exec-maven-plugin:1.2.1:exec</goal>
4.49 - </goals>
4.50 - <properties>
4.51 - <exec.args>${profiler.args} -classpath %classpath org.apidesign.bck2brwsr.dew.Dew</exec.args>
4.52 - <exec.executable>${profiler.java}</exec.executable>
4.53 - </properties>
4.54 - </action>
4.55 - </actions>
5.1 --- a/dew/pom.xml Tue Apr 29 15:25:58 2014 +0200
5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
5.3 @@ -1,91 +0,0 @@
5.4 -<?xml version="1.0"?>
5.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5.6 - <modelVersion>4.0.0</modelVersion>
5.7 - <parent>
5.8 - <groupId>org.apidesign</groupId>
5.9 - <artifactId>bck2brwsr</artifactId>
5.10 - <version>0.8-SNAPSHOT</version>
5.11 - </parent>
5.12 - <groupId>org.apidesign.bck2brwsr</groupId>
5.13 - <artifactId>dew</artifactId>
5.14 - <version>0.8-SNAPSHOT</version>
5.15 - <name>Development Environment for Web</name>
5.16 - <url>http://maven.apache.org</url>
5.17 - <build>
5.18 - <plugins>
5.19 - <plugin>
5.20 - <groupId>org.apache.maven.plugins</groupId>
5.21 - <artifactId>maven-compiler-plugin</artifactId>
5.22 - <version>2.3.2</version>
5.23 - <configuration>
5.24 - <source>1.7</source>
5.25 - <target>1.7</target>
5.26 - </configuration>
5.27 - </plugin>
5.28 - <plugin>
5.29 - <groupId>org.codehaus.mojo</groupId>
5.30 - <artifactId>exec-maven-plugin</artifactId>
5.31 - <version>1.2.1</version>
5.32 - <executions>
5.33 - <execution>
5.34 - <goals>
5.35 - <goal>exec</goal>
5.36 - </goals>
5.37 - </execution>
5.38 - </executions>
5.39 - <configuration>
5.40 - <executable>java</executable>
5.41 - <arguments>
5.42 - <argument>-classpath</argument>
5.43 - <classpath />
5.44 - <argument>org.apidesign.bck2brwsr.dew.Dew</argument>
5.45 - </arguments>
5.46 - </configuration>
5.47 - </plugin>
5.48 - <plugin>
5.49 - <groupId>org.apache.maven.plugins</groupId>
5.50 - <artifactId>maven-deploy-plugin</artifactId>
5.51 - <version>2.7</version>
5.52 - <configuration>
5.53 - <skip>true</skip>
5.54 - </configuration>
5.55 - </plugin>
5.56 - </plugins>
5.57 - </build>
5.58 - <properties>
5.59 - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
5.60 - </properties>
5.61 - <dependencies>
5.62 - <dependency>
5.63 - <groupId>org.glassfish.grizzly</groupId>
5.64 - <artifactId>grizzly-http-server</artifactId>
5.65 - <version>2.2.19</version>
5.66 - </dependency>
5.67 - <dependency>
5.68 - <groupId>${project.groupId}</groupId>
5.69 - <artifactId>vm4brwsr</artifactId>
5.70 - <version>${project.version}</version>
5.71 - </dependency>
5.72 - <dependency>
5.73 - <groupId>org.json</groupId>
5.74 - <artifactId>json</artifactId>
5.75 - <version>20090211</version>
5.76 - </dependency>
5.77 - <dependency>
5.78 - <groupId>org.testng</groupId>
5.79 - <artifactId>testng</artifactId>
5.80 - <scope>test</scope>
5.81 - <exclusions>
5.82 - <exclusion>
5.83 - <artifactId>junit</artifactId>
5.84 - <groupId>junit</groupId>
5.85 - </exclusion>
5.86 - </exclusions>
5.87 - </dependency>
5.88 - <dependency>
5.89 - <groupId>${project.groupId}</groupId>
5.90 - <artifactId>javaquery.api</artifactId>
5.91 - <version>${project.version}</version>
5.92 - </dependency>
5.93 - </dependencies>
5.94 -</project>
6.1 --- a/dew/src/main/java/org/apidesign/bck2brwsr/dew/Compile.java Tue Apr 29 15:25:58 2014 +0200
6.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
6.3 @@ -1,203 +0,0 @@
6.4 -/**
6.5 - * Back 2 Browser Bytecode Translator
6.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
6.7 - *
6.8 - * This program is free software: you can redistribute it and/or modify
6.9 - * it under the terms of the GNU General Public License as published by
6.10 - * the Free Software Foundation, version 2 of the License.
6.11 - *
6.12 - * This program is distributed in the hope that it will be useful,
6.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
6.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6.15 - * GNU General Public License for more details.
6.16 - *
6.17 - * You should have received a copy of the GNU General Public License
6.18 - * along with this program. Look for COPYING file in the top folder.
6.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
6.20 - */
6.21 -package org.apidesign.bck2brwsr.dew;
6.22 -
6.23 -import java.io.ByteArrayInputStream;
6.24 -import java.io.ByteArrayOutputStream;
6.25 -import java.io.IOException;
6.26 -import java.io.InputStream;
6.27 -import java.io.OutputStream;
6.28 -import java.net.URI;
6.29 -import java.net.URISyntaxException;
6.30 -import java.util.ArrayList;
6.31 -import java.util.Arrays;
6.32 -import java.util.HashMap;
6.33 -import java.util.List;
6.34 -import java.util.Map;
6.35 -import java.util.regex.Matcher;
6.36 -import java.util.regex.Pattern;
6.37 -import javax.tools.Diagnostic;
6.38 -import javax.tools.DiagnosticListener;
6.39 -import javax.tools.FileObject;
6.40 -import javax.tools.ForwardingJavaFileManager;
6.41 -import javax.tools.JavaFileManager;
6.42 -import javax.tools.JavaFileObject;
6.43 -import javax.tools.JavaFileObject.Kind;
6.44 -import javax.tools.SimpleJavaFileObject;
6.45 -import javax.tools.StandardJavaFileManager;
6.46 -import javax.tools.StandardLocation;
6.47 -import javax.tools.ToolProvider;
6.48 -
6.49 -/**
6.50 - *
6.51 - * @author Jaroslav Tulach <jtulach@netbeans.org>
6.52 - */
6.53 -final class Compile implements DiagnosticListener<JavaFileObject> {
6.54 - private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<>();
6.55 - private final Map<String, byte[]> classes;
6.56 - private final String pkg;
6.57 - private final String cls;
6.58 - private final String html;
6.59 -
6.60 - private Compile(String html, String code) throws IOException {
6.61 - this.pkg = findPkg(code);
6.62 - this.cls = findCls(code);
6.63 - this.html = html;
6.64 - classes = compile(html, code);
6.65 - }
6.66 -
6.67 - /** Performs compilation of given HTML page and associated Java code
6.68 - */
6.69 - public static Compile create(String html, String code) throws IOException {
6.70 - return new Compile(html, code);
6.71 - }
6.72 -
6.73 - /** Checks for given class among compiled resources */
6.74 - public byte[] get(String res) {
6.75 - return classes.get(res);
6.76 - }
6.77 -
6.78 - /** Obtains errors created during compilation.
6.79 - */
6.80 - public List<Diagnostic<? extends JavaFileObject>> getErrors() {
6.81 - List<Diagnostic<? extends JavaFileObject>> err = new ArrayList<>();
6.82 - for (Diagnostic<? extends JavaFileObject> diagnostic : errors) {
6.83 - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
6.84 - err.add(diagnostic);
6.85 - }
6.86 - }
6.87 - return err;
6.88 - }
6.89 -
6.90 - private Map<String, byte[]> compile(final String html, final String code) throws IOException {
6.91 - StandardJavaFileManager sjfm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(this, null, null);
6.92 -
6.93 - final Map<String, ByteArrayOutputStream> class2BAOS = new HashMap<>();
6.94 -
6.95 - JavaFileObject file = new SimpleJavaFileObject(URI.create("mem://mem"), Kind.SOURCE) {
6.96 - @Override
6.97 - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
6.98 - return code;
6.99 - }
6.100 - };
6.101 - final JavaFileObject htmlFile = new SimpleJavaFileObject(URI.create("mem://mem2"), Kind.OTHER) {
6.102 - @Override
6.103 - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
6.104 - return html;
6.105 - }
6.106 -
6.107 - @Override
6.108 - public InputStream openInputStream() throws IOException {
6.109 - return new ByteArrayInputStream(html.getBytes());
6.110 - }
6.111 - };
6.112 -
6.113 - final URI scratch;
6.114 - try {
6.115 - scratch = new URI("mem://mem3");
6.116 - } catch (URISyntaxException ex) {
6.117 - throw new IOException(ex);
6.118 - }
6.119 -
6.120 - JavaFileManager jfm = new ForwardingJavaFileManager<JavaFileManager>(sjfm) {
6.121 - @Override
6.122 - public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
6.123 - if (kind == Kind.CLASS) {
6.124 - final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
6.125 -
6.126 - class2BAOS.put(className.replace('.', '/') + ".class", buffer);
6.127 - return new SimpleJavaFileObject(sibling.toUri(), kind) {
6.128 - @Override
6.129 - public OutputStream openOutputStream() throws IOException {
6.130 - return buffer;
6.131 - }
6.132 - };
6.133 - }
6.134 -
6.135 - if (kind == Kind.SOURCE) {
6.136 - return new SimpleJavaFileObject(scratch/*sibling.toUri()*/, kind) {
6.137 - private final ByteArrayOutputStream data = new ByteArrayOutputStream();
6.138 - @Override
6.139 - public OutputStream openOutputStream() throws IOException {
6.140 - return data;
6.141 - }
6.142 -
6.143 - @Override
6.144 - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
6.145 - data.close();
6.146 - return new String(data.toByteArray());
6.147 - }
6.148 - };
6.149 - }
6.150 -
6.151 - throw new IllegalStateException();
6.152 - }
6.153 -
6.154 - @Override
6.155 - public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
6.156 - if (location == StandardLocation.SOURCE_PATH) {
6.157 - if (packageName.equals(pkg)) {
6.158 - return htmlFile;
6.159 - }
6.160 - }
6.161 -
6.162 - return null;
6.163 - }
6.164 -
6.165 - };
6.166 -
6.167 - ToolProvider.getSystemJavaCompiler().getTask(null, jfm, this, /*XXX:*/Arrays.asList("-source", "1.7", "-target", "1.7"), null, Arrays.asList(file)).call();
6.168 -
6.169 - Map<String, byte[]> result = new HashMap<>();
6.170 -
6.171 - for (Map.Entry<String, ByteArrayOutputStream> e : class2BAOS.entrySet()) {
6.172 - result.put(e.getKey(), e.getValue().toByteArray());
6.173 - }
6.174 -
6.175 - return result;
6.176 - }
6.177 -
6.178 -
6.179 - @Override
6.180 - public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
6.181 - errors.add(diagnostic);
6.182 - }
6.183 - private static String findPkg(String java) throws IOException {
6.184 - Pattern p = Pattern.compile("package\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}*;", Pattern.MULTILINE);
6.185 - Matcher m = p.matcher(java);
6.186 - if (!m.find()) {
6.187 - throw new IOException("Can't find package declaration in the java file");
6.188 - }
6.189 - String pkg = m.group(1);
6.190 - return pkg;
6.191 - }
6.192 - private static String findCls(String java) throws IOException {
6.193 - Pattern p = Pattern.compile("class\\p{javaWhitespace}*([\\p{Alnum}\\.]+)\\p{javaWhitespace}", Pattern.MULTILINE);
6.194 - Matcher m = p.matcher(java);
6.195 - if (!m.find()) {
6.196 - throw new IOException("Can't find package declaration in the java file");
6.197 - }
6.198 - String cls = m.group(1);
6.199 - return cls;
6.200 - }
6.201 -
6.202 - String getHtml() {
6.203 - String fqn = "'" + pkg + '.' + cls + "'";
6.204 - return html.replace("'${fqn}'", fqn);
6.205 - }
6.206 -}
7.1 --- a/dew/src/main/java/org/apidesign/bck2brwsr/dew/Dew.java Tue Apr 29 15:25:58 2014 +0200
7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
7.3 @@ -1,138 +0,0 @@
7.4 -/**
7.5 - * Back 2 Browser Bytecode Translator
7.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
7.7 - *
7.8 - * This program is free software: you can redistribute it and/or modify
7.9 - * it under the terms of the GNU General Public License as published by
7.10 - * the Free Software Foundation, version 2 of the License.
7.11 - *
7.12 - * This program is distributed in the hope that it will be useful,
7.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.15 - * GNU General Public License for more details.
7.16 - *
7.17 - * You should have received a copy of the GNU General Public License
7.18 - * along with this program. Look for COPYING file in the top folder.
7.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
7.20 - */
7.21 -package org.apidesign.bck2brwsr.dew;
7.22 -
7.23 -import java.io.ByteArrayInputStream;
7.24 -import java.io.IOException;
7.25 -import java.io.InputStream;
7.26 -import java.io.InputStreamReader;
7.27 -import java.io.OutputStream;
7.28 -import java.util.List;
7.29 -import java.util.Locale;
7.30 -import javax.tools.Diagnostic;
7.31 -import javax.tools.JavaFileObject;
7.32 -import org.apidesign.vm4brwsr.Bck2Brwsr;
7.33 -import org.glassfish.grizzly.http.Method;
7.34 -import org.glassfish.grizzly.http.server.HttpHandler;
7.35 -import org.glassfish.grizzly.http.server.HttpServer;
7.36 -import org.glassfish.grizzly.http.server.Request;
7.37 -import org.glassfish.grizzly.http.server.Response;
7.38 -import org.glassfish.grizzly.http.util.HttpStatus;
7.39 -import org.json.JSONArray;
7.40 -import org.json.JSONObject;
7.41 -import org.json.JSONTokener;
7.42 -
7.43 -/**
7.44 - *
7.45 - * @author phrebejk
7.46 - */
7.47 -final class Dew extends HttpHandler implements Bck2Brwsr.Resources {
7.48 - private Compile data;
7.49 -
7.50 - public static void main(String... args) throws Exception {
7.51 - DewLauncher l = new DewLauncher(null);
7.52 - l.addClassLoader(DewLauncher.class.getClassLoader());
7.53 - final Dew dew = new Dew();
7.54 - HttpServer s = l.initServer(dew);
7.55 - s.getServerConfiguration().addHttpHandler(dew, "/dew/");
7.56 - l.launchServerAndBrwsr(s, "/dew/");
7.57 - System.in.read();
7.58 - }
7.59 -
7.60 - @Override
7.61 - public void service(Request request, Response response) throws Exception {
7.62 -
7.63 - if ( request.getMethod() == Method.POST ) {
7.64 - InputStream is = request.getInputStream();
7.65 - JSONTokener tok = new JSONTokener(new InputStreamReader(is));
7.66 - JSONObject obj = new JSONObject(tok);
7.67 - String tmpHtml = obj.getString("html");
7.68 - String tmpJava = obj.getString("java");
7.69 -
7.70 - Compile res = Compile.create(tmpHtml, tmpJava);
7.71 - List<Diagnostic<? extends JavaFileObject>> err = res.getErrors();
7.72 - if (err.isEmpty()) {
7.73 - data = res;
7.74 - response.getOutputStream().write("[]".getBytes());
7.75 - response.setStatus(HttpStatus.OK_200);
7.76 - } else {
7.77 -
7.78 - JSONArray errors = new JSONArray();
7.79 -
7.80 - for (Diagnostic<? extends JavaFileObject> d : err) {
7.81 - JSONObject e = new JSONObject();
7.82 - e.put("col", d.getColumnNumber());
7.83 - e.put("line", d.getLineNumber());
7.84 - e.put("kind", d.getKind().toString());
7.85 - e.put("msg", d.getMessage(Locale.ENGLISH));
7.86 - errors.put(e);
7.87 - }
7.88 -
7.89 - errors.write(response.getWriter());
7.90 - response.setStatus(HttpStatus.PRECONDITION_FAILED_412);
7.91 - }
7.92 -
7.93 - return;
7.94 - }
7.95 -
7.96 - String r = request.getHttpHandlerPath();
7.97 - if (r == null || r.equals("/")) {
7.98 - r = "index.html";
7.99 - }
7.100 - if (r.equals("/result.html")) {
7.101 - response.setContentType("text/html");
7.102 - if (data != null) {
7.103 - response.getOutputBuffer().write(data.getHtml());
7.104 - }
7.105 - response.setStatus(HttpStatus.OK_200);
7.106 - return;
7.107 - }
7.108 -
7.109 - if (r.startsWith("/")) {
7.110 - r = r.substring(1);
7.111 - }
7.112 -
7.113 - if (r.endsWith(".html") || r.endsWith(".xhtml")) {
7.114 - response.setContentType("text/html");
7.115 - }
7.116 - OutputStream os = response.getOutputStream();
7.117 - try (InputStream is = Dew.class.getResourceAsStream(r) ) {
7.118 - copyStream(is, os, request.getRequestURL().toString() );
7.119 - } catch (IOException ex) {
7.120 - response.setDetailMessage(ex.getLocalizedMessage());
7.121 - response.setError();
7.122 - response.setStatus(404);
7.123 - }
7.124 - }
7.125 -
7.126 - static void copyStream(InputStream is, OutputStream os, String baseURL) throws IOException {
7.127 - for (;;) {
7.128 - int ch = is.read();
7.129 - if (ch == -1) {
7.130 - break;
7.131 - }
7.132 - os.write(ch);
7.133 - }
7.134 - }
7.135 -
7.136 - @Override
7.137 - public InputStream get(String r) throws IOException {
7.138 - byte[] arr = data == null ? null : data.get(r);
7.139 - return arr == null ? null : new ByteArrayInputStream(arr);
7.140 - }
7.141 -}
8.1 --- a/dew/src/main/java/org/apidesign/bck2brwsr/dew/DewLauncher.java Tue Apr 29 15:25:58 2014 +0200
8.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
8.3 @@ -1,203 +0,0 @@
8.4 -/**
8.5 - * Back 2 Browser Bytecode Translator
8.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
8.7 - *
8.8 - * This program is free software: you can redistribute it and/or modify
8.9 - * it under the terms of the GNU General Public License as published by
8.10 - * the Free Software Foundation, version 2 of the License.
8.11 - *
8.12 - * This program is distributed in the hope that it will be useful,
8.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
8.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8.15 - * GNU General Public License for more details.
8.16 - *
8.17 - * You should have received a copy of the GNU General Public License
8.18 - * along with this program. Look for COPYING file in the top folder.
8.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
8.20 - */
8.21 -package org.apidesign.bck2brwsr.dew;
8.22 -
8.23 -import java.io.IOException;
8.24 -import java.io.InputStream;
8.25 -import java.io.Writer;
8.26 -import java.net.URI;
8.27 -import java.net.URISyntaxException;
8.28 -import java.net.URL;
8.29 -import java.util.Arrays;
8.30 -import java.util.Enumeration;
8.31 -import java.util.LinkedHashSet;
8.32 -import java.util.Set;
8.33 -import java.util.logging.Level;
8.34 -import java.util.logging.Logger;
8.35 -import org.apidesign.vm4brwsr.Bck2Brwsr;
8.36 -import org.glassfish.grizzly.PortRange;
8.37 -import org.glassfish.grizzly.http.server.HttpHandler;
8.38 -import org.glassfish.grizzly.http.server.HttpServer;
8.39 -import org.glassfish.grizzly.http.server.NetworkListener;
8.40 -import org.glassfish.grizzly.http.server.Request;
8.41 -import org.glassfish.grizzly.http.server.Response;
8.42 -import org.glassfish.grizzly.http.server.ServerConfiguration;
8.43 -
8.44 -/**
8.45 - * Lightweight server to launch dew - the Development Environment for Web.
8.46 - */
8.47 -final class DewLauncher {
8.48 - private static final Logger LOG = Logger.getLogger(DewLauncher.class.getName());
8.49 - private Set<ClassLoader> loaders = new LinkedHashSet<>();
8.50 - private Set<Bck2Brwsr.Resources> xRes = new LinkedHashSet<>();
8.51 - private final Res resources = new Res();
8.52 - private final String cmd;
8.53 -
8.54 - public DewLauncher(String cmd) {
8.55 - this.cmd = cmd;
8.56 - }
8.57 -
8.58 - public void addClassLoader(ClassLoader url) {
8.59 - this.loaders.add(url);
8.60 - }
8.61 -
8.62 - final HttpServer initServer(Bck2Brwsr.Resources... extraResources) throws IOException {
8.63 - xRes.addAll(Arrays.asList(extraResources));
8.64 -
8.65 - HttpServer s = HttpServer.createSimpleServer(".", new PortRange(8080, 65535));
8.66 -
8.67 - final ServerConfiguration conf = s.getServerConfiguration();
8.68 - conf.addHttpHandler(new VM(resources), "/bck2brwsr.js");
8.69 - conf.addHttpHandler(new VMInit(), "/vm.js");
8.70 - conf.addHttpHandler(new Classes(resources), "/classes/");
8.71 - return s;
8.72 - }
8.73 -
8.74 - final Object[] launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException {
8.75 - server.start();
8.76 - NetworkListener listener = server.getListeners().iterator().next();
8.77 - int port = listener.getPort();
8.78 -
8.79 - URI uri = new URI("http://localhost:" + port + page);
8.80 - LOG.log(Level.INFO, "Showing {0}", uri);
8.81 - if (cmd == null) {
8.82 - try {
8.83 - LOG.log(Level.INFO, "Trying Desktop.browse on {0} {2} by {1}", new Object[] {
8.84 - System.getProperty("java.vm.name"),
8.85 - System.getProperty("java.vm.vendor"),
8.86 - System.getProperty("java.vm.version"),
8.87 - });
8.88 - java.awt.Desktop.getDesktop().browse(uri);
8.89 - LOG.log(Level.INFO, "Desktop.browse successfully finished");
8.90 - return null;
8.91 - } catch (UnsupportedOperationException ex) {
8.92 - LOG.log(Level.INFO, "Desktop.browse not supported: {0}", ex.getMessage());
8.93 - LOG.log(Level.FINE, null, ex);
8.94 - }
8.95 - }
8.96 - {
8.97 - String cmdName = cmd == null ? "xdg-open" : cmd;
8.98 - String[] cmdArr = {
8.99 - cmdName, uri.toString()
8.100 - };
8.101 - LOG.log(Level.INFO, "Launching {0}", Arrays.toString(cmdArr));
8.102 - final Process process = Runtime.getRuntime().exec(cmdArr);
8.103 - return new Object[] { process, null };
8.104 - }
8.105 - }
8.106 -
8.107 - private class Res implements Bck2Brwsr.Resources {
8.108 - @Override
8.109 - public InputStream get(String resource) throws IOException {
8.110 - for (ClassLoader l : loaders) {
8.111 - URL u = null;
8.112 - Enumeration<URL> en = l.getResources(resource);
8.113 - while (en.hasMoreElements()) {
8.114 - u = en.nextElement();
8.115 - }
8.116 - if (u != null) {
8.117 - return u.openStream();
8.118 - }
8.119 - }
8.120 - for (Bck2Brwsr.Resources r : xRes) {
8.121 - InputStream is = r.get(resource);
8.122 - if (is != null) {
8.123 - return is;
8.124 - }
8.125 - }
8.126 - throw new IOException("Can't find " + resource);
8.127 - }
8.128 - }
8.129 -
8.130 - private static class VM extends HttpHandler {
8.131 - private final String bck2brwsr;
8.132 -
8.133 - public VM(Res loader) throws IOException {
8.134 - StringBuilder sb = new StringBuilder();
8.135 - Bck2Brwsr.generate(sb, loader);
8.136 - this.bck2brwsr = sb.toString();
8.137 - }
8.138 -
8.139 - @Override
8.140 - public void service(Request request, Response response) throws Exception {
8.141 - response.setCharacterEncoding("UTF-8");
8.142 - response.setContentType("text/javascript");
8.143 - response.getWriter().write(bck2brwsr);
8.144 - }
8.145 - }
8.146 - private static class VMInit extends HttpHandler {
8.147 - public VMInit() {
8.148 - }
8.149 -
8.150 - @Override
8.151 - public void service(Request request, Response response) throws Exception {
8.152 - response.setCharacterEncoding("UTF-8");
8.153 - response.setContentType("text/javascript");
8.154 - response.getWriter().append(
8.155 - "function ldCls(res) {\n"
8.156 - + " var request = new XMLHttpRequest();\n"
8.157 - + " request.open('GET', '/classes/' + res, false);\n"
8.158 - + " request.send();\n"
8.159 - + " var arr = eval('(' + request.responseText + ')');\n"
8.160 - + " return arr;\n"
8.161 - + "}\n"
8.162 - + "var vm = new bck2brwsr(ldCls);\n");
8.163 - }
8.164 - }
8.165 -
8.166 - private static class Classes extends HttpHandler {
8.167 - private final Res loader;
8.168 -
8.169 - public Classes(Res loader) {
8.170 - this.loader = loader;
8.171 - }
8.172 -
8.173 - @Override
8.174 - public void service(Request request, Response response) throws Exception {
8.175 - String res = request.getHttpHandlerPath();
8.176 - if (res.startsWith("/")) {
8.177 - res = res.substring(1);
8.178 - }
8.179 - try (InputStream is = loader.get(res)) {
8.180 - response.setContentType("text/javascript");
8.181 - Writer w = response.getWriter();
8.182 - w.append("[");
8.183 - for (int i = 0;; i++) {
8.184 - int b = is.read();
8.185 - if (b == -1) {
8.186 - break;
8.187 - }
8.188 - if (i > 0) {
8.189 - w.append(", ");
8.190 - }
8.191 - if (i % 20 == 0) {
8.192 - w.write("\n");
8.193 - }
8.194 - if (b > 127) {
8.195 - b = b - 256;
8.196 - }
8.197 - w.append(Integer.toString(b));
8.198 - }
8.199 - w.append("\n]");
8.200 - } catch (IOException ex) {
8.201 - response.setError();
8.202 - response.setDetailMessage(ex.getMessage());
8.203 - }
8.204 - }
8.205 - }
8.206 -}
9.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/css/app.css Tue Apr 29 15:25:58 2014 +0200
9.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
9.3 @@ -1,54 +0,0 @@
9.4 -/* app css stylesheet */
9.5 -.code-editor, .mono-font, .CodeMirror {
9.6 - font-family: "Inconsolata","Monaco","Consolas","Andale Mono","Bitstream Vera Sans Mono","Courier New",Courier,monospace;
9.7 - font-size: 13px;
9.8 - line-height: 15px;
9.9 -}
9.10 -
9.11 -.CodeMirror {
9.12 - border: 1px solid #d9edf7;
9.13 - height: 300px;
9.14 -}
9.15 -
9.16 -.CodeMirror-scroll {
9.17 - overflow-y: auto;
9.18 - overflow-x: auto;
9.19 -}
9.20 -
9.21 -.error-hover:hover {
9.22 - text-decoration: underline;
9.23 - cursor: pointer;
9.24 -}
9.25 -
9.26 -.ic-html5 {
9.27 - display: inline-block;
9.28 - height: 20px;
9.29 - width: 20px;
9.30 - vertical-align: text-bottom;
9.31 - background-repeat: no-repeat;
9.32 - background-image: url("../img/html5.png");
9.33 -}
9.34 -
9.35 -.ic-java {
9.36 - display: inline-block;
9.37 - height: 20px;
9.38 - width: 20px;
9.39 - vertical-align: text-bottom;
9.40 - background-repeat: no-repeat;
9.41 - background-image: url("../img/java.png");
9.42 -
9.43 -}
9.44 -
9.45 -.issues {
9.46 - width: 16px;
9.47 -}
9.48 -
9.49 -.issue {
9.50 - height: 16px;
9.51 - width: 16px;
9.52 - vertical-align: middle;
9.53 - background-repeat: no-repeat;
9.54 - background-image: url("../img/error.png");
9.55 - /* color: #822; */
9.56 -}
9.57 -
10.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/css/bootstrap-combined.min.css Tue Apr 29 15:25:58 2014 +0200
10.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
10.3 @@ -1,18 +0,0 @@
10.4 -/*!
10.5 - * Bootstrap v2.2.2
10.6 - *
10.7 - * Copyright 2012 Twitter, Inc
10.8 - * Licensed under the Apache License v2.0
10.9 - * http://www.apache.org/licenses/LICENSE-2.0
10.10 - *
10.11 - * Designed and built with all the love in the world @twitter by @mdo and @fat.
10.12 - */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover{color:#808080}.text-warning{color:#c09853}a.text-warning:hover{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover{color:#2d6987}.text-success{color:#468847}a.text-success:hover{color:#356635}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.warning td{background-color:#fcf8e3}.table tbody tr.info td{background-color:#d9edf7}.table-hover tbody tr.success:hover td{background-color:#d0e9c6}.table-hover tbody tr.error:hover td{background-color:#ebcccc}.table-hover tbody tr.warning:hover td{background-color:#faf2cc}.table-hover tbody tr.info:hover td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#c5c5c5;border-color:rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret{border-top-color:#555;border-bottom-color:#555}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media .pull-left{margin-right:10px}.media .pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed}
10.13 -/*!
10.14 - * Bootstrap Responsive v2.2.2
10.15 - *
10.16 - * Copyright 2012 Twitter, Inc
10.17 - * Licensed under the Apache License v2.0
10.18 - * http://www.apache.org/licenses/LICENSE-2.0
10.19 - *
10.20 - * Designed and built with all the love in the world @twitter by @mdo and @fat.
10.21 - */@-ms-viewport{width:device-width}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}
11.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/error.png has changed
12.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/glyphicons-halflings-white.png has changed
13.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/glyphicons-halflings.png has changed
14.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/html5.png has changed
15.1 Binary file dew/src/main/resources/org/apidesign/bck2brwsr/dew/img/java.png has changed
16.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/index.html Tue Apr 29 15:25:58 2014 +0200
16.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
16.3 @@ -1,98 +0,0 @@
16.4 -<!--
16.5 -To change this template, choose Tools | Templates
16.6 -and open the template in the editor.
16.7 --->
16.8 -<!DOCTYPE html>
16.9 -<html lang="en" ng-app="bck2brwsr" ng-controller="DevCtrl">
16.10 - <head>
16.11 - <title>Back2Browser - DEW</title>
16.12 - <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
16.13 - <meta name="viewport" content="width=device-width, initial-scale=1.0">
16.14 - <link rel="stylesheet" href="css/bootstrap-combined.min.css"/>
16.15 - <link rel="stylesheet" href="js/codemirror/codemirror.css">
16.16 - <link rel="stylesheet" href="js/codemirror/theme/elegant.css"/>
16.17 - <link rel="stylesheet" href="css/app.css"/>
16.18 - </head>
16.19 - <body>
16.20 -
16.21 - <div class="navbar navbar-fixed-top" style="width: 100%">
16.22 - <div class="navbar-inner" style="padding-left: 12px; padding-right: 12px;">
16.23 - <!-- a class="brand" style="font-size: 100%"><span class="text-info"><b>Java and HTML5</b></span><small>- Together at Last!</small></a-->
16.24 - <form class="navbar-form pull-right">
16.25 - <!-- select class="span2"></select -->
16.26 - <button ng-click="post()" class="btn btn-warning">Rebuild</button>
16.27 - </form>
16.28 - <!-- ul class="nav">
16.29 - <li><select class="btn-small" type="text"></select></li>
16.30 - </ul -->
16.31 - <!-- form class="form form-horizontal pull-right">
16.32 - <button class="btn btn-warning btn-small pull-right top" ng-click="post()">Rebuild</button>
16.33 - </form -->
16.34 - <!-- ul class="nav pull-right">
16.35 -
16.36 - </ul-->
16.37 - </div>
16.38 - </div>
16.39 -
16.40 - <div class="container-fluid">
16.41 -
16.42 - <div style="height: 4em;"> </div>
16.43 -
16.44 - <div class="row-fluid">
16.45 - <div class="span6" style="margin-bottom: 10px;">
16.46 - <table class="table table-condensed" style="margin-bottom: 2px">
16.47 - <tr><td><i class="ic-html5"></i> HTML5</td></tr>
16.48 - </table>
16.49 - <div>
16.50 - <textarea ui-codemirror='{ lineNumbers : true, mode : "xml", theme : "elegant", matchBrackets : true, lineWrapping : true }' ng-model="html"></textarea>
16.51 - <div class="alert alert-error" ng-show="doc.modelError">
16.52 - <small>{{doc.modelError.toString()}}</small>
16.53 - </div>
16.54 - </div>
16.55 - </div>
16.56 -
16.57 - <div class="span6">
16.58 - <table class="table table-condensed" style="margin-bottom: 2px">
16.59 - <tr><td><i class="ic-java"></i> Java</td></tr>
16.60 - </table>
16.61 - <div>
16.62 - <textarea id="editorJava" ui-codemirror='{ lineNumbers : true, mode : "text/x-java", theme : "elegant", matchBrackets : true, lineWrapping : true, gutters: ["CodeMirror-linenumbers", "issues"] }' ng-model="java"></textarea>
16.63 - <div class="alert alert-error" ng-show="doc.modelError">
16.64 - <small>{{doc.modelError.toString()}}</small>
16.65 - </div>
16.66 - </div>
16.67 - </div>
16.68 -
16.69 - </div>
16.70 -
16.71 - <table class="table table-condensed">
16.72 - <tr ng-click="gotoError(e.line, e.col)" ng-repeat="e in errors" ng-class="errorClass(e.kind)">
16.73 - <td style="text-align: right">{{e.line}}</td>
16.74 - <td>:</td>
16.75 - <td style="text-align: left">{{e.col}}</td>
16.76 - <td width="100%" class="text-error error-hover">{{e.msg}} <i class="icon-play"/></td>
16.77 - </tr>
16.78 - </table>
16.79 -
16.80 -
16.81 - <div> </div>
16.82 -
16.83 - <ul class="nav nav-tabs">
16.84 - <li ng-class="'active'"><a href="#">Result</a></li>
16.85 - </ul>
16.86 -
16.87 -
16.88 - <!-- button class="btn" ng-click="reload()">Reload</button -->
16.89 - <iframe id="result" frameborder="0" scrolling="yes" width="100%" style="height: 1000px; overflow: auto; border: 1px solid #DFDFDF;" src="result.html">
16.90 - <p>Your browser does not support iframes.</p>
16.91 - </iframe>
16.92 -
16.93 - </div>
16.94 -
16.95 - <script src="js/angular/angular.min.js"></script>
16.96 - <script src="js/codemirror/codemirror.js"></script>
16.97 - <script src="js/codemirror/mode/xml.js"></script>
16.98 - <script src="js/codemirror/mode/clike.js"></script>
16.99 - <script src="js/app.js"></script>
16.100 - </body>
16.101 -</html>
17.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/angular/angular.min.js Tue Apr 29 15:25:58 2014 +0200
17.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
17.3 @@ -1,159 +0,0 @@
17.4 -/*
17.5 - AngularJS v1.0.3
17.6 - (c) 2010-2012 Google, Inc. http://angularjs.org
17.7 - License: MIT
17.8 -*/
17.9 -(function(U,ca,p){'use strict';function m(b,a,c){var d;if(b)if(N(b))for(d in b)d!="prototype"&&d!="length"&&d!="name"&&b.hasOwnProperty(d)&&a.call(c,b[d],d);else if(b.forEach&&b.forEach!==m)b.forEach(a,c);else if(L(b)&&wa(b.length))for(d=0;d<b.length;d++)a.call(c,b[d],d);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d);return b}function lb(b){var a=[],c;for(c in b)b.hasOwnProperty(c)&&a.push(c);return a.sort()}function ec(b,a,c){for(var d=lb(b),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}
17.10 -function mb(b){return function(a,c){b(c,a)}}function xa(){for(var b=Z.length,a;b;){b--;a=Z[b].charCodeAt(0);if(a==57)return Z[b]="A",Z.join("");if(a==90)Z[b]="0";else return Z[b]=String.fromCharCode(a+1),Z.join("")}Z.unshift("0");return Z.join("")}function x(b){m(arguments,function(a){a!==b&&m(a,function(a,d){b[d]=a})});return b}function G(b){return parseInt(b,10)}function ya(b,a){return x(new (x(function(){},{prototype:b})),a)}function D(){}function ma(b){return b}function I(b){return function(){return b}}
17.11 -function t(b){return typeof b=="undefined"}function v(b){return typeof b!="undefined"}function L(b){return b!=null&&typeof b=="object"}function F(b){return typeof b=="string"}function wa(b){return typeof b=="number"}function na(b){return Sa.apply(b)=="[object Date]"}function J(b){return Sa.apply(b)=="[object Array]"}function N(b){return typeof b=="function"}function oa(b){return b&&b.document&&b.location&&b.alert&&b.setInterval}function R(b){return F(b)?b.replace(/^\s*/,"").replace(/\s*$/,""):b}function fc(b){return b&&
17.12 -(b.nodeName||b.bind&&b.find)}function Ta(b,a,c){var d=[];m(b,function(b,g,i){d.push(a.call(c,b,g,i))});return d}function gc(b,a){var c=0,d;if(J(b)||F(b))return b.length;else if(L(b))for(d in b)(!a||b.hasOwnProperty(d))&&c++;return c}function za(b,a){if(b.indexOf)return b.indexOf(a);for(var c=0;c<b.length;c++)if(a===b[c])return c;return-1}function Ua(b,a){var c=za(b,a);c>=0&&b.splice(c,1);return a}function V(b,a){if(oa(b)||b&&b.$evalAsync&&b.$watch)throw B("Can't copy Window or Scope");if(a){if(b===
17.13 -a)throw B("Can't copy equivalent objects or arrays");if(J(b)){for(;a.length;)a.pop();for(var c=0;c<b.length;c++)a.push(V(b[c]))}else for(c in m(a,function(b,c){delete a[c]}),b)a[c]=V(b[c])}else(a=b)&&(J(b)?a=V(b,[]):na(b)?a=new Date(b.getTime()):L(b)&&(a=V(b,{})));return a}function hc(b,a){var a=a||{},c;for(c in b)b.hasOwnProperty(c)&&c.substr(0,2)!=="$$"&&(a[c]=b[c]);return a}function ha(b,a){if(b===a)return!0;if(b===null||a===null)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&
17.14 -c=="object")if(J(b)){if((c=b.length)==a.length){for(d=0;d<c;d++)if(!ha(b[d],a[d]))return!1;return!0}}else if(na(b))return na(a)&&b.getTime()==a.getTime();else{if(b&&b.$evalAsync&&b.$watch||a&&a.$evalAsync&&a.$watch||oa(b)||oa(a))return!1;c={};for(d in b){if(d.charAt(0)!=="$"&&!N(b[d])&&!ha(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c[d]&&d.charAt(0)!=="$"&&!N(a[d]))return!1;return!0}return!1}function Va(b,a){var c=arguments.length>2?ia.call(arguments,2):[];return N(a)&&!(a instanceof RegExp)?c.length?
17.15 -function(){return arguments.length?a.apply(b,c.concat(ia.call(arguments,0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}:a}function ic(b,a){var c=a;/^\$+/.test(b)?c=p:oa(a)?c="$WINDOW":a&&ca===a?c="$DOCUMENT":a&&a.$evalAsync&&a.$watch&&(c="$SCOPE");return c}function da(b,a){return JSON.stringify(b,ic,a?" ":null)}function nb(b){return F(b)?JSON.parse(b):b}function Wa(b){b&&b.length!==0?(b=E(""+b),b=!(b=="f"||b=="0"||b=="false"||b=="no"||b=="n"||b=="[]")):b=!1;
17.16 -return b}function pa(b){b=u(b).clone();try{b.html("")}catch(a){}return u("<div>").append(b).html().match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+E(b)})}function Xa(b){var a={},c,d;m((b||"").split("&"),function(b){b&&(c=b.split("="),d=decodeURIComponent(c[0]),a[d]=v(c[1])?decodeURIComponent(c[1]):!0)});return a}function ob(b){var a=[];m(b,function(b,d){a.push(Ya(d,!0)+(b===!0?"":"="+Ya(b,!0)))});return a.length?a.join("&"):""}function Za(b){return Ya(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,
17.17 -"=").replace(/%2B/gi,"+")}function Ya(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(a?null:/%20/g,"+")}function jc(b,a){function c(a){a&&d.push(a)}var d=[b],e,g,i=["ng:app","ng-app","x-ng-app","data-ng-app"],f=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;m(i,function(a){i[a]=!0;c(ca.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(m(b.querySelectorAll("."+a),c),m(b.querySelectorAll("."+a+"\\:"),c),m(b.querySelectorAll("["+
17.18 -a+"]"),c))});m(d,function(a){if(!e){var b=f.exec(" "+a.className+" ");b?(e=a,g=(b[2]||"").replace(/\s+/g,",")):m(a.attributes,function(b){if(!e&&i[b.name])e=a,g=b.value})}});e&&a(e,g?[g]:[])}function pb(b,a){b=u(b);a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");var c=qb(a);c.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,i){a.$apply(function(){b.data("$injector",i);c(b)(a)})}]);return c}function $a(b,a){a=a||"_";return b.replace(kc,
17.19 -function(b,d){return(d?a:"")+b.toLowerCase()})}function qa(b,a,c){if(!b)throw new B("Argument '"+(a||"?")+"' is "+(c||"required"));return b}function ra(b,a,c){c&&J(b)&&(b=b[b.length-1]);qa(N(b),a,"not a function, got "+(b&&typeof b=="object"?b.constructor.name||"Object":typeof b));return b}function lc(b){function a(a,b,e){return a[b]||(a[b]=e())}return a(a(b,"angular",Object),"module",function(){var b={};return function(d,e,g){e&&b.hasOwnProperty(d)&&(b[d]=null);return a(b,d,function(){function a(c,
17.20 -d,e){return function(){b[e||"push"]([c,d,arguments]);return j}}if(!e)throw B("No module: "+d);var b=[],c=[],k=a("$injector","invoke"),j={_invokeQueue:b,_runBlocks:c,requires:e,name:d,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:k,run:function(a){c.push(a);
17.21 -return this}};g&&k(g);return j})}})}function rb(b){return b.replace(mc,function(a,b,d,e){return e?d.toUpperCase():d}).replace(nc,"Moz$1")}function ab(b,a){function c(){var e;for(var b=[this],c=a,i,f,h,k,j,l;b.length;){i=b.shift();f=0;for(h=i.length;f<h;f++){k=u(i[f]);c?k.triggerHandler("$destroy"):c=!c;j=0;for(e=(l=k.children()).length,k=e;j<k;j++)b.push(ja(l[j]))}}return d.apply(this,arguments)}var d=ja.fn[b],d=d.$original||d;c.$original=d;ja.fn[b]=c}function Q(b){if(b instanceof Q)return b;if(!(this instanceof
17.22 -Q)){if(F(b)&&b.charAt(0)!="<")throw B("selectors not implemented");return new Q(b)}if(F(b)){var a=ca.createElement("div");a.innerHTML="<div> </div>"+b;a.removeChild(a.firstChild);bb(this,a.childNodes);this.remove()}else bb(this,b)}function cb(b){return b.cloneNode(!0)}function sa(b){sb(b);for(var a=0,b=b.childNodes||[];a<b.length;a++)sa(b[a])}function tb(b,a,c){var d=$(b,"events");$(b,"handle")&&(t(a)?m(d,function(a,c){db(b,c,a);delete d[c]}):t(c)?(db(b,a,d[a]),delete d[a]):Ua(d[a],c))}function sb(b){var a=
17.23 -b[Aa],c=Ba[a];c&&(c.handle&&(c.events.$destroy&&c.handle({},"$destroy"),tb(b)),delete Ba[a],b[Aa]=p)}function $(b,a,c){var d=b[Aa],d=Ba[d||-1];if(v(c))d||(b[Aa]=d=++oc,d=Ba[d]={}),d[a]=c;else return d&&d[a]}function ub(b,a,c){var d=$(b,"data"),e=v(c),g=!e&&v(a),i=g&&!L(a);!d&&!i&&$(b,"data",d={});if(e)d[a]=c;else if(g)if(i)return d&&d[a];else x(d,a);else return d}function Ca(b,a){return(" "+b.className+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" ")>-1}function vb(b,a){a&&m(a.split(" "),function(a){b.className=
17.24 -R((" "+b.className+" ").replace(/[\n\t]/g," ").replace(" "+R(a)+" "," "))})}function wb(b,a){a&&m(a.split(" "),function(a){if(!Ca(b,a))b.className=R(b.className+" "+R(a))})}function bb(b,a){if(a)for(var a=!a.nodeName&&v(a.length)&&!oa(a)?a:[a],c=0;c<a.length;c++)b.push(a[c])}function xb(b,a){return Da(b,"$"+(a||"ngController")+"Controller")}function Da(b,a,c){b=u(b);for(b[0].nodeType==9&&(b=b.find("html"));b.length;){if(c=b.data(a))return c;b=b.parent()}}function yb(b,a){var c=Ea[a.toLowerCase()];
17.25 -return c&&zb[b.nodeName]&&c}function pc(b,a){var c=function(c,e){if(!c.preventDefault)c.preventDefault=function(){c.returnValue=!1};if(!c.stopPropagation)c.stopPropagation=function(){c.cancelBubble=!0};if(!c.target)c.target=c.srcElement||ca;if(t(c.defaultPrevented)){var g=c.preventDefault;c.preventDefault=function(){c.defaultPrevented=!0;g.call(c)};c.defaultPrevented=!1}c.isDefaultPrevented=function(){return c.defaultPrevented};m(a[e||c.type],function(a){a.call(b,c)});aa<=8?(c.preventDefault=null,
17.26 -c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function ga(b){var a=typeof b,c;if(a=="object"&&b!==null)if(typeof(c=b.$$hashKey)=="function")c=b.$$hashKey();else{if(c===p)c=b.$$hashKey=xa()}else c=b;return a+":"+c}function Fa(b){m(b,this.put,this)}function eb(){}function Ab(b){var a,c;if(typeof b=="function"){if(!(a=b.$inject))a=[],c=b.toString().replace(qc,""),c=c.match(rc),m(c[1].split(sc),function(b){b.replace(tc,
17.27 -function(b,c,d){a.push(d)})}),b.$inject=a}else J(b)?(c=b.length-1,ra(b[c],"fn"),a=b.slice(0,c)):ra(b,"fn",!0);return a}function qb(b){function a(a){return function(b,c){if(L(b))m(b,mb(a));else return a(b,c)}}function c(a,b){N(b)&&(b=l.instantiate(b));if(!b.$get)throw B("Provider "+a+" must define $get factory method.");return j[a+f]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[];m(a,function(a){if(!k.get(a))if(k.put(a,!0),F(a)){var c=ta(a);b=b.concat(e(c.requires)).concat(c._runBlocks);
17.28 -try{for(var d=c._invokeQueue,c=0,f=d.length;c<f;c++){var h=d[c],g=h[0]=="$injector"?l:l.get(h[0]);g[h[1]].apply(g,h[2])}}catch(n){throw n.message&&(n.message+=" from "+a),n;}}else if(N(a))try{b.push(l.invoke(a))}catch(i){throw i.message&&(i.message+=" from "+a),i;}else if(J(a))try{b.push(l.invoke(a))}catch(j){throw j.message&&(j.message+=" from "+String(a[a.length-1])),j;}else ra(a,"module")});return b}function g(a,b){function c(d){if(typeof d!=="string")throw B("Service name expected");if(a.hasOwnProperty(d)){if(a[d]===
17.29 -i)throw B("Circular dependency: "+h.join(" <- "));return a[d]}else try{return h.unshift(d),a[d]=i,a[d]=b(d)}finally{h.shift()}}function d(a,b,e){var f=[],k=Ab(a),g,n,i;n=0;for(g=k.length;n<g;n++)i=k[n],f.push(e&&e.hasOwnProperty(i)?e[i]:c(i,h));a.$inject||(a=a[g]);switch(b?-1:f.length){case 0:return a();case 1:return a(f[0]);case 2:return a(f[0],f[1]);case 3:return a(f[0],f[1],f[2]);case 4:return a(f[0],f[1],f[2],f[3]);case 5:return a(f[0],f[1],f[2],f[3],f[4]);case 6:return a(f[0],f[1],f[2],f[3],
17.30 -f[4],f[5]);case 7:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6]);case 8:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7]);case 9:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8]);case 10:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8],f[9]);default:return a.apply(b,f)}}return{invoke:d,instantiate:function(a,b){var c=function(){},e;c.prototype=(J(a)?a[a.length-1]:a).prototype;c=new c;e=d(a,c,b);return L(e)?e:c},get:c,annotate:Ab}}var i={},f="Provider",h=[],k=new Fa,j={$provide:{provider:a(c),
17.31 -factory:a(d),service:a(function(a,b){return d(a,["$injector",function(a){return a.instantiate(b)}])}),value:a(function(a,b){return d(a,I(b))}),constant:a(function(a,b){j[a]=b;o[a]=b}),decorator:function(a,b){var c=l.get(a+f),d=c.$get;c.$get=function(){var a=r.invoke(d,c);return r.invoke(b,null,{$delegate:a})}}}},l=g(j,function(){throw B("Unknown provider: "+h.join(" <- "));}),o={},r=o.$injector=g(o,function(a){a=l.get(a+f);return r.invoke(a.$get,a)});m(e(b),function(a){r.invoke(a||D)});return r}function uc(){var b=
17.32 -!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;m(a,function(a){!b&&E(a.nodeName)==="a"&&(b=a)});return b}function g(){var b=c.hash(),d;b?(d=i.getElementById(b))?d.scrollIntoView():(d=e(i.getElementsByName(b)))?d.scrollIntoView():b==="top"&&a.scrollTo(0,0):a.scrollTo(0,0)}var i=a.document;b&&d.$watch(function(){return c.hash()},function(){d.$evalAsync(g)});return g}]}function vc(b,a,c,d){function e(a){try{a.apply(null,
17.33 -ia.call(arguments,1))}finally{if(n--,n===0)for(;w.length;)try{w.pop()()}catch(b){c.error(b)}}}function g(a,b){(function ea(){m(q,function(a){a()});s=b(ea,a)})()}function i(){O!=f.url()&&(O=f.url(),m(A,function(a){a(f.url())}))}var f=this,h=a[0],k=b.location,j=b.history,l=b.setTimeout,o=b.clearTimeout,r={};f.isMock=!1;var n=0,w=[];f.$$completeOutstandingRequest=e;f.$$incOutstandingRequestCount=function(){n++};f.notifyWhenNoOutstandingRequests=function(a){m(q,function(a){a()});n===0?a():w.push(a)};
17.34 -var q=[],s;f.addPollFn=function(a){t(s)&&g(100,l);q.push(a);return a};var O=k.href,C=a.find("base");f.url=function(a,b){if(a){if(O!=a)return O=a,d.history?b?j.replaceState(null,"",a):(j.pushState(null,"",a),C.attr("href",C.attr("href"))):b?k.replace(a):k.href=a,f}else return k.href.replace(/%27/g,"'")};var A=[],K=!1;f.onUrlChange=function(a){K||(d.history&&u(b).bind("popstate",i),d.hashchange?u(b).bind("hashchange",i):f.addPollFn(i),K=!0);A.push(a);return a};f.baseHref=function(){var a=C.attr("href");
17.35 -return a?a.replace(/^https?\:\/\/[^\/]*/,""):a};var W={},y="",M=f.baseHref();f.cookies=function(a,b){var d,e,f,k;if(a)if(b===p)h.cookie=escape(a)+"=;path="+M+";expires=Thu, 01 Jan 1970 00:00:00 GMT";else{if(F(b))d=(h.cookie=escape(a)+"="+escape(b)+";path="+M).length+1,d>4096&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"),W.length>20&&c.warn("Cookie '"+a+"' possibly not set or overflowed because too many cookies were already set ("+W.length+
17.36 -" > 20 )")}else{if(h.cookie!==y){y=h.cookie;d=y.split("; ");W={};for(f=0;f<d.length;f++)e=d[f],k=e.indexOf("="),k>0&&(W[unescape(e.substring(0,k))]=unescape(e.substring(k+1)))}return W}};f.defer=function(a,b){var c;n++;c=l(function(){delete r[c];e(a)},b||0);r[c]=!0;return c};f.defer.cancel=function(a){return r[a]?(delete r[a],o(a),e(D),!0):!1}}function wc(){this.$get=["$window","$log","$sniffer","$document",function(b,a,c,d){return new vc(b,d,a,c)}]}function xc(){this.$get=function(){function b(b,
17.37 -d){function e(a){if(a!=l){if(o){if(o==a)o=a.n}else o=a;g(a.n,a.p);g(a,l);l=a;l.n=null}}function g(a,b){if(a!=b){if(a)a.p=b;if(b)b.n=a}}if(b in a)throw B("cacheId "+b+" taken");var i=0,f=x({},d,{id:b}),h={},k=d&&d.capacity||Number.MAX_VALUE,j={},l=null,o=null;return a[b]={put:function(a,b){var c=j[a]||(j[a]={key:a});e(c);t(b)||(a in h||i++,h[a]=b,i>k&&this.remove(o.key))},get:function(a){var b=j[a];if(b)return e(b),h[a]},remove:function(a){var b=j[a];if(b){if(b==l)l=b.p;if(b==o)o=b.n;g(b.n,b.p);delete j[a];
17.38 -delete h[a];i--}},removeAll:function(){h={};i=0;j={};l=o=null},destroy:function(){j=f=h=null;delete a[b]},info:function(){return x({},f,{size:i})}}}var a={};b.info=function(){var b={};m(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function yc(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function Bb(b){var a={},c="Directive",d=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,e=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,g="Template must have exactly one root element. was: ";
17.39 -this.directive=function f(d,e){F(d)?(qa(e,"directive"),a.hasOwnProperty(d)||(a[d]=[],b.factory(d+c,["$injector","$exceptionHandler",function(b,c){var e=[];m(a[d],function(a){try{var f=b.invoke(a);if(N(f))f={compile:I(f)};else if(!f.compile&&f.link)f.compile=I(f.link);f.priority=f.priority||0;f.name=f.name||d;f.require=f.require||f.controller&&f.name;f.restrict=f.restrict||"A";e.push(f)}catch(k){c(k)}});return e}])),a[d].push(e)):m(d,mb(f));return this};this.$get=["$injector","$interpolate","$exceptionHandler",
17.40 -"$http","$templateCache","$parse","$controller","$rootScope",function(b,h,k,j,l,o,r,n){function w(a,b,c){a instanceof u||(a=u(a));m(a,function(b,c){b.nodeType==3&&(a[c]=u(b).wrap("<span></span>").parent()[0])});var d=s(a,b,a,c);return function(b,c){qa(b,"scope");var e=c?ua.clone.call(a):a;e.data("$scope",b);q(e,"ng-scope");c&&c(e,b);d&&d(b,e,e);return e}}function q(a,b){try{a.addClass(b)}catch(c){}}function s(a,b,c,d){function e(a,c,d,k){for(var g,h,j,n,o,l=0,r=0,q=f.length;l<q;r++)j=c[r],g=f[l++],
17.41 -h=f[l++],g?(g.scope?(n=a.$new(L(g.scope)),u(j).data("$scope",n)):n=a,(o=g.transclude)||!k&&b?g(h,n,j,d,function(b){return function(c){var d=a.$new();return b(d,c).bind("$destroy",Va(d,d.$destroy))}}(o||b)):g(h,n,j,p,k)):h&&h(a,j.childNodes,p,k)}for(var f=[],k,g,h,j=0;j<a.length;j++)g=new ea,k=O(a[j],[],g,d),g=(k=k.length?C(k,a[j],g,b,c):null)&&k.terminal||!a[j].childNodes.length?null:s(a[j].childNodes,k?k.transclude:b),f.push(k),f.push(g),h=h||k||g;return h?e:null}function O(a,b,c,f){var k=c.$attr,
17.42 -g;switch(a.nodeType){case 1:A(b,fa(Cb(a).toLowerCase()),"E",f);var h,j,n;g=a.attributes;for(var o=0,l=g&&g.length;o<l;o++)if(h=g[o],h.specified)j=h.name,n=fa(j.toLowerCase()),k[n]=j,c[n]=h=R(aa&&j=="href"?decodeURIComponent(a.getAttribute(j,2)):h.value),yb(a,n)&&(c[n]=!0),X(a,b,h,n),A(b,n,"A",f);a=a.className;if(F(a)&&a!=="")for(;g=e.exec(a);)n=fa(g[2]),A(b,n,"C",f)&&(c[n]=R(g[3])),a=a.substr(g.index+g[0].length);break;case 3:H(b,a.nodeValue);break;case 8:try{if(g=d.exec(a.nodeValue))n=fa(g[1]),A(b,
17.43 -n,"M",f)&&(c[n]=R(g[2]))}catch(r){}}b.sort(y);return b}function C(a,b,c,d,e){function f(a,b){if(a)a.require=z.require,l.push(a);if(b)b.require=z.require,ba.push(b)}function h(a,b){var c,d="data",e=!1;if(F(a)){for(;(c=a.charAt(0))=="^"||c=="?";)a=a.substr(1),c=="^"&&(d="inheritedData"),e=e||c=="?";c=b[d]("$"+a+"Controller");if(!c&&!e)throw B("No controller: "+a);}else J(a)&&(c=[],m(a,function(a){c.push(h(a,b))}));return c}function j(a,d,e,f,g){var n,q,w,K,s;n=b===e?c:hc(c,new ea(u(e),c.$attr));q=n.$$element;
17.44 -if(C){var zc=/^\s*([@=&])\s*(\w*)\s*$/,O=d.$parent||d;m(C.scope,function(a,b){var c=a.match(zc)||[],e=c[2]||b,f,g,k;switch(c[1]){case "@":n.$observe(e,function(a){d[b]=a});n.$$observers[e].$$scope=O;break;case "=":g=o(n[e]);k=g.assign||function(){f=d[b]=g(O);throw B(Db+n[e]+" (directive: "+C.name+")");};f=d[b]=g(O);d.$watch(function(){var a=g(O);a!==d[b]&&(a!==f?f=d[b]=a:k(O,a=f=d[b]));return a});break;case "&":g=o(n[e]);d[b]=function(a){return g(O,a)};break;default:throw B("Invalid isolate scope definition for directive "+
17.45 -C.name+": "+a);}})}t&&m(t,function(a){var b={$scope:d,$element:q,$attrs:n,$transclude:g};s=a.controller;s=="@"&&(s=n[a.name]);q.data("$"+a.name+"Controller",r(s,b))});f=0;for(w=l.length;f<w;f++)try{K=l[f],K(d,q,n,K.require&&h(K.require,q))}catch(y){k(y,pa(q))}a&&a(d,e.childNodes,p,g);f=0;for(w=ba.length;f<w;f++)try{K=ba[f],K(d,q,n,K.require&&h(K.require,q))}catch(Ha){k(Ha,pa(q))}}for(var n=-Number.MAX_VALUE,l=[],ba=[],s=null,C=null,A=null,y=c.$$element=u(b),z,H,X,D,v=d,t,x,Y,E=0,G=a.length;E<G;E++){z=
17.46 -a[E];X=p;if(n>z.priority)break;if(Y=z.scope)M("isolated scope",C,z,y),L(Y)&&(q(y,"ng-isolate-scope"),C=z),q(y,"ng-scope"),s=s||z;H=z.name;if(Y=z.controller)t=t||{},M("'"+H+"' controller",t[H],z,y),t[H]=z;if(Y=z.transclude)M("transclusion",D,z,y),D=z,n=z.priority,Y=="element"?(X=u(b),y=c.$$element=u("<\!-- "+H+": "+c[H]+" --\>"),b=y[0],Ga(e,u(X[0]),b),v=w(X,d,n)):(X=u(cb(b)).contents(),y.html(""),v=w(X,d));if(Y=z.template)if(M("template",A,z,y),A=z,Y=Ha(Y),z.replace){X=u("<div>"+R(Y)+"</div>").contents();
17.47 -b=X[0];if(X.length!=1||b.nodeType!==1)throw new B(g+Y);Ga(e,y,b);H={$attr:{}};a=a.concat(O(b,a.splice(E+1,a.length-(E+1)),H));K(c,H);G=a.length}else y.html(Y);if(z.templateUrl)M("template",A,z,y),A=z,j=W(a.splice(E,a.length-E),j,y,c,e,z.replace,v),G=a.length;else if(z.compile)try{x=z.compile(y,c,v),N(x)?f(null,x):x&&f(x.pre,x.post)}catch(I){k(I,pa(y))}if(z.terminal)j.terminal=!0,n=Math.max(n,z.priority)}j.scope=s&&s.scope;j.transclude=D&&v;return j}function A(d,e,g,h){var j=!1;if(a.hasOwnProperty(e))for(var n,
17.48 -e=b.get(e+c),o=0,l=e.length;o<l;o++)try{if(n=e[o],(h===p||h>n.priority)&&n.restrict.indexOf(g)!=-1)d.push(n),j=!0}catch(r){k(r)}return j}function K(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;m(a,function(d,e){e.charAt(0)!="$"&&(b[e]&&(d+=(e==="style"?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});m(b,function(b,f){f=="class"?(q(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):f=="style"?e.attr("style",e.attr("style")+";"+b):f.charAt(0)!="$"&&!a.hasOwnProperty(f)&&(a[f]=b,d[f]=c[f])})}function W(a,b,c,d,e,
17.49 -f,k){var h=[],n,o,r=c[0],q=a.shift(),w=x({},q,{controller:null,templateUrl:null,transclude:null,scope:null});c.html("");j.get(q.templateUrl,{cache:l}).success(function(j){var l,q,j=Ha(j);if(f){q=u("<div>"+R(j)+"</div>").contents();l=q[0];if(q.length!=1||l.nodeType!==1)throw new B(g+j);j={$attr:{}};Ga(e,c,l);O(l,a,j);K(d,j)}else l=r,c.html(j);a.unshift(w);n=C(a,c,d,k);for(o=s(c.contents(),k);h.length;){var ba=h.pop(),j=h.pop();q=h.pop();var y=h.pop(),m=l;q!==r&&(m=cb(l),Ga(j,u(q),m));n(function(){b(o,
17.50 -y,m,e,ba)},y,m,e,ba)}h=null}).error(function(a,b,c,d){throw B("Failed to load template: "+d.url);});return function(a,c,d,e,f){h?(h.push(c),h.push(d),h.push(e),h.push(f)):n(function(){b(o,c,d,e,f)},c,d,e,f)}}function y(a,b){return b.priority-a.priority}function M(a,b,c,d){if(b)throw B("Multiple directives ["+b.name+", "+c.name+"] asking for "+a+" on: "+pa(d));}function H(a,b){var c=h(b,!0);c&&a.push({priority:0,compile:I(function(a,b){var d=b.parent(),e=d.data("$binding")||[];e.push(c);q(d.data("$binding",
17.51 -e),"ng-binding");a.$watch(c,function(a){b[0].nodeValue=a})})})}function X(a,b,c,d){var e=h(c,!0);e&&b.push({priority:100,compile:I(function(a,b,c){b=c.$$observers||(c.$$observers={});d==="class"&&(e=h(c[d],!0));c[d]=p;(b[d]||(b[d]=[])).$$inter=!0;(c.$$observers&&c.$$observers[d].$$scope||a).$watch(e,function(a){c.$set(d,a)})})})}function Ga(a,b,c){var d=b[0],e=d.parentNode,f,g;if(a){f=0;for(g=a.length;f<g;f++)if(a[f]==d){a[f]=c;break}}e&&e.replaceChild(c,d);c[u.expando]=d[u.expando];b[0]=c}var ea=
17.52 -function(a,b){this.$$element=a;this.$attr=b||{}};ea.prototype={$normalize:fa,$set:function(a,b,c,d){var e=yb(this.$$element[0],a),f=this.$$observers;e&&(this.$$element.prop(a,b),d=e);this[a]=b;d?this.$attr[a]=d:(d=this.$attr[a])||(this.$attr[a]=d=$a(a,"-"));c!==!1&&(b===null||b===p?this.$$element.removeAttr(d):this.$$element.attr(d,b));f&&m(f[a],function(a){try{a(b)}catch(c){k(c)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers={}),e=d[a]||(d[a]=[]);e.push(b);n.$evalAsync(function(){e.$$inter||
17.53 -b(c[a])});return b}};var D=h.startSymbol(),ba=h.endSymbol(),Ha=D=="{{"||ba=="}}"?ma:function(a){return a.replace(/\{\{/g,D).replace(/}}/g,ba)};return w}]}function fa(b){return rb(b.replace(Ac,""))}function Bc(){var b={};this.register=function(a,c){L(a)?x(b,a):b[a]=c};this.$get=["$injector","$window",function(a,c){return function(d,e){if(F(d)){var g=d,d=b.hasOwnProperty(g)?b[g]:fb(e.$scope,g,!0)||fb(c,g,!0);ra(d,g,!0)}return a.instantiate(d,e)}}]}function Cc(){this.$get=["$window",function(b){return u(b.document)}]}
17.54 -function Dc(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function Ec(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse",function(c){function d(d,f){for(var h,k,j=0,l=[],o=d.length,r=!1,n=[];j<o;)(h=d.indexOf(b,j))!=-1&&(k=d.indexOf(a,h+e))!=-1?(j!=h&&l.push(d.substring(j,h)),l.push(j=c(r=d.substring(h+e,k))),j.exp=r,j=k+g,r=!0):(j!=o&&l.push(d.substring(j)),j=o);if(!(o=
17.55 -l.length))l.push(""),o=1;if(!f||r)return n.length=o,j=function(a){for(var b=0,c=o,d;b<c;b++){if(typeof(d=l[b])=="function")d=d(a),d==null||d==p?d="":typeof d!="string"&&(d=da(d));n[b]=d}return n.join("")},j.exp=d,j.parts=l,j}var e=b.length,g=a.length;d.startSymbol=function(){return b};d.endSymbol=function(){return a};return d}]}function Eb(b){for(var b=b.split("/"),a=b.length;a--;)b[a]=Za(b[a]);return b.join("/")}function va(b,a){var c=Fb.exec(b),c={protocol:c[1],host:c[3],port:G(c[5])||Gb[c[1]]||
17.56 -null,path:c[6]||"/",search:c[8],hash:c[10]};if(a)a.$$protocol=c.protocol,a.$$host=c.host,a.$$port=c.port;return c}function ka(b,a,c){return b+"://"+a+(c==Gb[b]?"":":"+c)}function Fc(b,a,c){var d=va(b);return decodeURIComponent(d.path)!=a||t(d.hash)||d.hash.indexOf(c)!==0?b:ka(d.protocol,d.host,d.port)+a.substr(0,a.lastIndexOf("/"))+d.hash.substr(c.length)}function Gc(b,a,c){var d=va(b);if(decodeURIComponent(d.path)==a)return b;else{var e=d.search&&"?"+d.search||"",g=d.hash&&"#"+d.hash||"",i=a.substr(0,
17.57 -a.lastIndexOf("/")),f=d.path.substr(i.length);if(d.path.indexOf(i)!==0)throw B('Invalid url "'+b+'", missing path prefix "'+i+'" !');return ka(d.protocol,d.host,d.port)+a+"#"+c+f+e+g}}function gb(b,a,c){a=a||"";this.$$parse=function(b){var c=va(b,this);if(c.path.indexOf(a)!==0)throw B('Invalid url "'+b+'", missing path prefix "'+a+'" !');this.$$path=decodeURIComponent(c.path.substr(a.length));this.$$search=Xa(c.search);this.$$hash=c.hash&&decodeURIComponent(c.hash)||"";this.$$compose()};this.$$compose=
17.58 -function(){var b=ob(this.$$search),c=this.$$hash?"#"+Za(this.$$hash):"";this.$$url=Eb(this.$$path)+(b?"?"+b:"")+c;this.$$absUrl=ka(this.$$protocol,this.$$host,this.$$port)+a+this.$$url};this.$$rewriteAppUrl=function(a){if(a.indexOf(c)==0)return a};this.$$parse(b)}function Ia(b,a,c){var d;this.$$parse=function(b){var c=va(b,this);if(c.hash&&c.hash.indexOf(a)!==0)throw B('Invalid url "'+b+'", missing hash prefix "'+a+'" !');d=c.path+(c.search?"?"+c.search:"");c=Hc.exec((c.hash||"").substr(a.length));
17.59 -this.$$path=c[1]?(c[1].charAt(0)=="/"?"":"/")+decodeURIComponent(c[1]):"";this.$$search=Xa(c[3]);this.$$hash=c[5]&&decodeURIComponent(c[5])||"";this.$$compose()};this.$$compose=function(){var b=ob(this.$$search),c=this.$$hash?"#"+Za(this.$$hash):"";this.$$url=Eb(this.$$path)+(b?"?"+b:"")+c;this.$$absUrl=ka(this.$$protocol,this.$$host,this.$$port)+d+(this.$$url?"#"+a+this.$$url:"")};this.$$rewriteAppUrl=function(a){if(a.indexOf(c)==0)return a};this.$$parse(b)}function Hb(b,a,c,d){Ia.apply(this,arguments);
17.60 -this.$$rewriteAppUrl=function(b){if(b.indexOf(c)==0)return c+d+"#"+a+b.substr(c.length)}}function Ja(b){return function(){return this[b]}}function Ib(b,a){return function(c){if(t(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Ic(){var b="",a=!1;this.hashPrefix=function(a){return v(a)?(b=a,this):b};this.html5Mode=function(b){return v(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,g){function i(a){c.$broadcast("$locationChangeSuccess",
17.61 -f.absUrl(),a)}var f,h,k,j=d.url(),l=va(j);a?(h=d.baseHref()||"/",k=h.substr(0,h.lastIndexOf("/")),l=ka(l.protocol,l.host,l.port)+k+"/",f=e.history?new gb(Fc(j,h,b),k,l):new Hb(Gc(j,h,b),b,l,h.substr(k.length+1))):(l=ka(l.protocol,l.host,l.port)+(l.path||"")+(l.search?"?"+l.search:"")+"#"+b+"/",f=new Ia(j,b,l));g.bind("click",function(a){if(!a.ctrlKey&&!(a.metaKey||a.which==2)){for(var b=u(a.target);E(b[0].nodeName)!=="a";)if(b[0]===g[0]||!(b=b.parent())[0])return;var d=b.prop("href"),e=f.$$rewriteAppUrl(d);
17.62 -d&&!b.attr("target")&&e&&(f.$$parse(e),c.$apply(),a.preventDefault(),U.angular["ff-684208-preventDefault"]=!0)}});f.absUrl()!=j&&d.url(f.absUrl(),!0);d.onUrlChange(function(a){f.absUrl()!=a&&(c.$evalAsync(function(){var b=f.absUrl();f.$$parse(a);i(b)}),c.$$phase||c.$digest())});var o=0;c.$watch(function(){var a=d.url(),b=f.$$replace;if(!o||a!=f.absUrl())o++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),i(a))});f.$$replace=
17.63 -!1;return o});return f}]}function Jc(){this.$get=["$window",function(b){function a(a){a instanceof B&&(a.stack?a=a.message&&a.stack.indexOf(a.message)===-1?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function c(c){var e=b.console||{},g=e[c]||e.log||D;return g.apply?function(){var b=[];m(arguments,function(c){b.push(a(c))});return g.apply(e,b)}:function(a,b){g(a,b)}}return{log:c("log"),warn:c("warn"),info:c("info"),error:c("error")}}]}function Kc(b,
17.64 -a){function c(a){return a.indexOf(q)!=-1}function d(){return n+1<b.length?b.charAt(n+1):!1}function e(a){return"0"<=a&&a<="9"}function g(a){return a==" "||a=="\r"||a=="\t"||a=="\n"||a=="\u000b"||a=="\u00a0"}function i(a){return"a"<=a&&a<="z"||"A"<=a&&a<="Z"||"_"==a||a=="$"}function f(a){return a=="-"||a=="+"||e(a)}function h(a,c,d){d=d||n;throw B("Lexer Error: "+a+" at column"+(v(c)?"s "+c+"-"+n+" ["+b.substring(c,d)+"]":" "+d)+" in expression ["+b+"].");}function k(){for(var a="",c=n;n<b.length;){var k=
17.65 -E(b.charAt(n));if(k=="."||e(k))a+=k;else{var g=d();if(k=="e"&&f(g))a+=k;else if(f(k)&&g&&e(g)&&a.charAt(a.length-1)=="e")a+=k;else if(f(k)&&(!g||!e(g))&&a.charAt(a.length-1)=="e")h("Invalid exponent");else break}n++}a*=1;o.push({index:c,text:a,json:!0,fn:function(){return a}})}function j(){for(var c="",d=n,f,k,h;n<b.length;){var j=b.charAt(n);if(j=="."||i(j)||e(j))j=="."&&(f=n),c+=j;else break;n++}if(f)for(k=n;k<b.length;){j=b.charAt(k);if(j=="("){h=c.substr(f-d+1);c=c.substr(0,f-d);n=k;break}if(g(j))k++;
17.66 -else break}d={index:d,text:c};if(Ka.hasOwnProperty(c))d.fn=d.json=Ka[c];else{var l=Jb(c,a);d.fn=x(function(a,b){return l(a,b)},{assign:function(a,b){return Kb(a,c,b)}})}o.push(d);h&&(o.push({index:f,text:".",json:!1}),o.push({index:f+1,text:h,json:!1}))}function l(a){var c=n;n++;for(var d="",e=a,f=!1;n<b.length;){var k=b.charAt(n);e+=k;if(f)k=="u"?(k=b.substring(n+1,n+5),k.match(/[\da-f]{4}/i)||h("Invalid unicode escape [\\u"+k+"]"),n+=4,d+=String.fromCharCode(parseInt(k,16))):(f=Lc[k],d+=f?f:k),
17.67 -f=!1;else if(k=="\\")f=!0;else if(k==a){n++;o.push({index:c,text:e,string:d,json:!0,fn:function(){return d}});return}else d+=k;n++}h("Unterminated quote",c)}for(var o=[],r,n=0,w=[],q,s=":";n<b.length;){q=b.charAt(n);if(c("\"'"))l(q);else if(e(q)||c(".")&&e(d()))k();else if(i(q)){if(j(),"{,".indexOf(s)!=-1&&w[0]=="{"&&(r=o[o.length-1]))r.json=r.text.indexOf(".")==-1}else if(c("(){}[].,;:"))o.push({index:n,text:q,json:":[,".indexOf(s)!=-1&&c("{[")||c("}]:,")}),c("{[")&&w.unshift(q),c("}]")&&w.shift(),
17.68 -n++;else if(g(q)){n++;continue}else{var m=q+d(),C=Ka[q],A=Ka[m];A?(o.push({index:n,text:m,fn:A}),n+=2):C?(o.push({index:n,text:q,fn:C,json:"[,:".indexOf(s)!=-1&&c("+-")}),n+=1):h("Unexpected next character ",n,n+1)}s=q}return o}function Mc(b,a,c,d){function e(a,c){throw B("Syntax Error: Token '"+c.text+"' "+a+" at column "+(c.index+1)+" of the expression ["+b+"] starting at ["+b.substring(c.index)+"].");}function g(){if(M.length===0)throw B("Unexpected end of expression: "+b);return M[0]}function i(a,
17.69 -b,c,d){if(M.length>0){var e=M[0],f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)return e}return!1}function f(b,c,d,f){return(b=i(b,c,d,f))?(a&&!b.json&&e("is not valid json",b),M.shift(),b):!1}function h(a){f(a)||e("is unexpected, expecting ["+a+"]",i())}function k(a,b){return function(c,d){return a(c,d,b)}}function j(a,b,c){return function(d,e){return b(d,e,a,c)}}function l(){for(var a=[];;)if(M.length>0&&!i("}",")",";","]")&&a.push(v()),!f(";"))return a.length==1?a[0]:function(b,c){for(var d,
17.70 -e=0;e<a.length;e++){var f=a[e];f&&(d=f(b,c))}return d}}function o(){for(var a=f(),b=c(a.text),d=[];;)if(a=f(":"))d.push(H());else{var e=function(a,c,e){for(var e=[e],f=0;f<d.length;f++)e.push(d[f](a,c));return b.apply(a,e)};return function(){return e}}}function r(){for(var a=n(),b;;)if(b=f("||"))a=j(a,b.fn,n());else return a}function n(){var a=w(),b;if(b=f("&&"))a=j(a,b.fn,n());return a}function w(){var a=q(),b;if(b=f("==","!="))a=j(a,b.fn,w());return a}function q(){var a;a=s();for(var b;b=f("+",
17.71 -"-");)a=j(a,b.fn,s());if(b=f("<",">","<=",">="))a=j(a,b.fn,q());return a}function s(){for(var a=m(),b;b=f("*","/","%");)a=j(a,b.fn,m());return a}function m(){var a;return f("+")?C():(a=f("-"))?j(W,a.fn,m()):(a=f("!"))?k(a.fn,m()):C()}function C(){var a;if(f("("))a=v(),h(")");else if(f("["))a=A();else if(f("{"))a=K();else{var b=f();(a=b.fn)||e("not a primary expression",b)}for(var c;b=f("(","[",".");)b.text==="("?(a=u(a,c),c=null):b.text==="["?(c=a,a=ea(a)):b.text==="."?(c=a,a=t(a)):e("IMPOSSIBLE");
17.72 -return a}function A(){var a=[];if(g().text!="]"){do a.push(H());while(f(","))}h("]");return function(b,c){for(var d=[],e=0;e<a.length;e++)d.push(a[e](b,c));return d}}function K(){var a=[];if(g().text!="}"){do{var b=f(),b=b.string||b.text;h(":");var c=H();a.push({key:b,value:c})}while(f(","))}h("}");return function(b,c){for(var d={},e=0;e<a.length;e++){var f=a[e],k=f.value(b,c);d[f.key]=k}return d}}var W=I(0),y,M=Kc(b,d),H=function(){var a=r(),c,d;return(d=f("="))?(a.assign||e("implies assignment but ["+
17.73 -b.substring(0,d.index)+"] can not be assigned to",d),c=r(),function(b,d){return a.assign(b,c(b,d),d)}):a},u=function(a,b){var c=[];if(g().text!=")"){do c.push(H());while(f(","))}h(")");return function(d,e){for(var f=[],k=b?b(d,e):d,h=0;h<c.length;h++)f.push(c[h](d,e));h=a(d,e)||D;return h.apply?h.apply(k,f):h(f[0],f[1],f[2],f[3],f[4])}},t=function(a){var b=f().text,c=Jb(b,d);return x(function(b,d){return c(a(b,d),d)},{assign:function(c,d,e){return Kb(a(c,e),b,d)}})},ea=function(a){var b=H();h("]");
17.74 -return x(function(c,d){var e=a(c,d),f=b(c,d),k;if(!e)return p;if((e=e[f])&&e.then){k=e;if(!("$$v"in e))k.$$v=p,k.then(function(a){k.$$v=a});e=e.$$v}return e},{assign:function(c,d,e){return a(c,e)[b(c,e)]=d}})},v=function(){for(var a=H(),b;;)if(b=f("|"))a=j(a,b.fn,o());else return a};a?(H=r,u=t=ea=v=function(){e("is not valid json",{text:b,index:0})},y=C()):y=l();M.length!==0&&e("is an unexpected token",M[0]);return y}function Kb(b,a,c){for(var a=a.split("."),d=0;a.length>1;d++){var e=a.shift(),g=
17.75 -b[e];g||(g={},b[e]=g);b=g}return b[a.shift()]=c}function fb(b,a,c){if(!a)return b;for(var a=a.split("."),d,e=b,g=a.length,i=0;i<g;i++)d=a[i],b&&(b=(e=b)[d]);return!c&&N(b)?Va(e,b):b}function Lb(b,a,c,d,e){return function(g,i){var f=i&&i.hasOwnProperty(b)?i:g,h;if(f===null||f===p)return f;if((f=f[b])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!a||f===null||f===p)return f;if((f=f[a])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!c||f===
17.76 -null||f===p)return f;if((f=f[c])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!d||f===null||f===p)return f;if((f=f[d])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}if(!e||f===null||f===p)return f;if((f=f[e])&&f.then){if(!("$$v"in f))h=f,h.$$v=p,h.then(function(a){h.$$v=a});f=f.$$v}return f}}function Jb(b,a){if(hb.hasOwnProperty(b))return hb[b];var c=b.split("."),d=c.length,e;if(a)e=d<6?Lb(c[0],c[1],c[2],c[3],c[4]):function(a,b){var e=0,
17.77 -k;do k=Lb(c[e++],c[e++],c[e++],c[e++],c[e++])(a,b),b=p,a=k;while(e<d);return k};else{var g="var l, fn, p;\n";m(c,function(a,b){g+="if(s === null || s === undefined) return s;\nl=s;\ns="+(b?"s":'((k&&k.hasOwnProperty("'+a+'"))?k:s)')+'["'+a+'"];\nif (s && s.then) {\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v=v;});\n}\n s=s.$$v\n}\n'});g+="return s;";e=Function("s","k",g);e.toString=function(){return g}}return hb[b]=e}function Nc(){var b={};this.$get=["$filter","$sniffer",
17.78 -function(a,c){return function(d){switch(typeof d){case "string":return b.hasOwnProperty(d)?b[d]:b[d]=Mc(d,!1,a,c.csp);case "function":return d;default:return D}}}]}function Oc(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return Pc(function(a){b.$evalAsync(a)},a)}]}function Pc(b,a){function c(a){return a}function d(a){return i(a)}var e=function(){var f=[],h,k;return k={resolve:function(a){if(f){var c=f;f=p;h=g(a);c.length&&b(function(){for(var a,b=0,d=c.length;b<d;b++)a=c[b],h.then(a[0],
17.79 -a[1])})}},reject:function(a){k.resolve(i(a))},promise:{then:function(b,k){var g=e(),i=function(d){try{g.resolve((b||c)(d))}catch(e){a(e),g.reject(e)}},n=function(b){try{g.resolve((k||d)(b))}catch(c){a(c),g.reject(c)}};f?f.push([i,n]):h.then(i,n);return g.promise}}}},g=function(a){return a&&a.then?a:{then:function(c){var d=e();b(function(){d.resolve(c(a))});return d.promise}}},i=function(a){return{then:function(c,k){var g=e();b(function(){g.resolve((k||d)(a))});return g.promise}}};return{defer:e,reject:i,
17.80 -when:function(f,h,k){var j=e(),l,o=function(b){try{return(h||c)(b)}catch(d){return a(d),i(d)}},r=function(b){try{return(k||d)(b)}catch(c){return a(c),i(c)}};b(function(){g(f).then(function(a){l||(l=!0,j.resolve(g(a).then(o,r)))},function(a){l||(l=!0,j.resolve(r(a)))})});return j.promise},all:function(a){var b=e(),c=a.length,d=[];c?m(a,function(a,e){g(a).then(function(a){e in d||(d[e]=a,--c||b.resolve(d))},function(a){e in d||b.reject(a)})}):b.resolve(d);return b.promise}}}function Qc(){var b={};this.when=
17.81 -function(a,c){b[a]=x({reloadOnSearch:!0},c);if(a){var d=a[a.length-1]=="/"?a.substr(0,a.length-1):a+"/";b[d]={redirectTo:a}}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache",function(a,c,d,e,g,i,f){function h(){var b=k(),h=r.current;if(b&&h&&b.$route===h.$route&&ha(b.pathParams,h.pathParams)&&!b.reloadOnSearch&&!o)h.params=b.params,V(h.params,d),a.$broadcast("$routeUpdate",h);else if(b||
17.82 -h)o=!1,a.$broadcast("$routeChangeStart",b,h),(r.current=b)&&b.redirectTo&&(F(b.redirectTo)?c.path(j(b.redirectTo,b.params)).search(b.params).replace():c.url(b.redirectTo(b.pathParams,c.path(),c.search())).replace()),e.when(b).then(function(){if(b){var a=[],c=[],d;m(b.resolve||{},function(b,d){a.push(d);c.push(F(b)?g.get(b):g.invoke(b))});if(!v(d=b.template))if(v(d=b.templateUrl))d=i.get(d,{cache:f}).then(function(a){return a.data});v(d)&&(a.push("$template"),c.push(d));return e.all(c).then(function(b){var c=
17.83 -{};m(b,function(b,d){c[a[d]]=b});return c})}}).then(function(c){if(b==r.current){if(b)b.locals=c,V(b.params,d);a.$broadcast("$routeChangeSuccess",b,h)}},function(c){b==r.current&&a.$broadcast("$routeChangeError",b,h,c)})}function k(){var a,d;m(b,function(b,e){if(!d&&(a=l(c.path(),e)))d=ya(b,{params:x({},c.search(),a),pathParams:a}),d.$route=b});return d||b[null]&&ya(b[null],{params:{},pathParams:{}})}function j(a,b){var c=[];m((a||"").split(":"),function(a,d){if(d==0)c.push(a);else{var e=a.match(/(\w+)(.*)/),
17.84 -f=e[1];c.push(b[f]);c.push(e[2]||"");delete b[f]}});return c.join("")}var l=function(a,b){var c="^"+b.replace(/([\.\\\(\)\^\$])/g,"\\$1")+"$",d=[],e={};m(b.split(/\W/),function(a){if(a){var b=RegExp(":"+a+"([\\W])");c.match(b)&&(c=c.replace(b,"([^\\/]*)$1"),d.push(a))}});var f=a.match(RegExp(c));f&&m(d,function(a,b){e[a]=f[b+1]});return f?e:null},o=!1,r={routes:b,reload:function(){o=!0;a.$evalAsync(h)}};a.$on("$locationChangeSuccess",h);return r}]}function Rc(){this.$get=I({})}function Sc(){var b=
17.85 -10;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse",function(a,c,d){function e(){this.$id=xa();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this["this"]=this.$root=this;this.$$asyncQueue=[];this.$$listeners={}}function g(a){if(h.$$phase)throw B(h.$$phase+" already in progress");h.$$phase=a}function i(a,b){var c=d(a);ra(c,b);return c}function f(){}e.prototype={$new:function(a){if(N(a))throw B("API-CHANGE: Use $controller to instantiate controllers.");
17.86 -a?(a=new e,a.$root=this.$root):(a=function(){},a.prototype=this,a=new a,a.$id=xa());a["this"]=a;a.$$listeners={};a.$parent=this;a.$$asyncQueue=[];a.$$watchers=a.$$nextSibling=a.$$childHead=a.$$childTail=null;a.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=a:this.$$childHead=this.$$childTail=a;return a},$watch:function(a,b,c){var d=i(a,"watch"),e=this.$$watchers,g={fn:b,last:f,get:d,exp:a,eq:!!c};if(!N(b)){var h=i(b||D,"listener");g.fn=function(a,b,
17.87 -c){h(c)}}if(!e)e=this.$$watchers=[];e.unshift(g);return function(){Ua(e,g)}},$digest:function(){var a,d,e,i,r,n,m,q=b,s,p=[],C,A;g("$digest");do{m=!1;s=this;do{for(r=s.$$asyncQueue;r.length;)try{s.$eval(r.shift())}catch(K){c(K)}if(i=s.$$watchers)for(n=i.length;n--;)try{if(a=i[n],(d=a.get(s))!==(e=a.last)&&!(a.eq?ha(d,e):typeof d=="number"&&typeof e=="number"&&isNaN(d)&&isNaN(e)))m=!0,a.last=a.eq?V(d):d,a.fn(d,e===f?d:e,s),q<5&&(C=4-q,p[C]||(p[C]=[]),A=N(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):
17.88 -a.exp,A+="; newVal: "+da(d)+"; oldVal: "+da(e),p[C].push(A))}catch(W){c(W)}if(!(i=s.$$childHead||s!==this&&s.$$nextSibling))for(;s!==this&&!(i=s.$$nextSibling);)s=s.$parent}while(s=i);if(m&&!q--)throw h.$$phase=null,B(b+" $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: "+da(p));}while(m||r.length);h.$$phase=null},$destroy:function(){if(h!=this){var a=this.$parent;this.$broadcast("$destroy");if(a.$$childHead==this)a.$$childHead=this.$$nextSibling;if(a.$$childTail==
17.89 -this)a.$$childTail=this.$$prevSibling;if(this.$$prevSibling)this.$$prevSibling.$$nextSibling=this.$$nextSibling;if(this.$$nextSibling)this.$$nextSibling.$$prevSibling=this.$$prevSibling;this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null}},$eval:function(a,b){return d(a)(this,b)},$evalAsync:function(a){this.$$asyncQueue.push(a)},$apply:function(a){try{return g("$apply"),this.$eval(a)}catch(b){c(b)}finally{h.$$phase=null;try{h.$digest()}catch(d){throw c(d),d;}}},
17.90 -$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);return function(){c[za(c,b)]=null}},$emit:function(a,b){var d=[],e,f=this,g=!1,h={name:a,targetScope:f,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},i=[h].concat(ia.call(arguments,1)),m,p;do{e=f.$$listeners[a]||d;h.currentScope=f;m=0;for(p=e.length;m<p;m++)if(e[m])try{if(e[m].apply(null,i),g)return h}catch(C){c(C)}else e.splice(m,1),m--,p--;f=f.$parent}while(f);
17.91 -return h},$broadcast:function(a,b){var d=this,e=this,f={name:a,targetScope:this,preventDefault:function(){f.defaultPrevented=!0},defaultPrevented:!1},g=[f].concat(ia.call(arguments,1)),h,i;do{d=e;f.currentScope=d;e=d.$$listeners[a]||[];h=0;for(i=e.length;h<i;h++)if(e[h])try{e[h].apply(null,g)}catch(m){c(m)}else e.splice(h,1),h--,i--;if(!(e=d.$$childHead||d!==this&&d.$$nextSibling))for(;d!==this&&!(e=d.$$nextSibling);)d=d.$parent}while(d=e);return f}};var h=new e;return h}]}function Tc(){this.$get=
17.92 -["$window",function(b){var a={},c=G((/android (\d+)/.exec(E(b.navigator.userAgent))||[])[1]);return{history:!(!b.history||!b.history.pushState||c<4),hashchange:"onhashchange"in b&&(!b.document.documentMode||b.document.documentMode>7),hasEvent:function(c){if(c=="input"&&aa==9)return!1;if(t(a[c])){var e=b.document.createElement("div");a[c]="on"+c in e}return a[c]},csp:!1}}]}function Uc(){this.$get=I(U)}function Mb(b){var a={},c,d,e;if(!b)return a;m(b.split("\n"),function(b){e=b.indexOf(":");c=E(R(b.substr(0,
17.93 -e)));d=R(b.substr(e+1));c&&(a[c]?a[c]+=", "+d:a[c]=d)});return a}function Nb(b){var a=L(b)?b:p;return function(c){a||(a=Mb(b));return c?a[E(c)]||null:a}}function Ob(b,a,c){if(N(c))return c(b,a);m(c,function(c){b=c(b,a)});return b}function Vc(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d=this.defaults={transformResponse:[function(d){F(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=nb(d,!0)));return d}],transformRequest:[function(a){return L(a)&&Sa.apply(a)!=="[object File]"?da(a):a}],
17.94 -headers:{common:{Accept:"application/json, text/plain, */*","X-Requested-With":"XMLHttpRequest"},post:{"Content-Type":"application/json;charset=utf-8"},put:{"Content-Type":"application/json;charset=utf-8"}}},e=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,h,k,j){function l(a){function c(a){var b=x({},a,{data:Ob(a.data,a.headers,f)});return 200<=a.status&&a.status<300?b:k.reject(b)}a.method=la(a.method);var e=a.transformRequest||
17.95 -d.transformRequest,f=a.transformResponse||d.transformResponse,h=d.headers,h=x({"X-XSRF-TOKEN":b.cookies()["XSRF-TOKEN"]},h.common,h[E(a.method)],a.headers),e=Ob(a.data,Nb(h),e),g;t(a.data)&&delete h["Content-Type"];g=o(a,e,h);g=g.then(c,c);m(w,function(a){g=a(g)});g.success=function(b){g.then(function(c){b(c.data,c.status,c.headers,a)});return g};g.error=function(b){g.then(null,function(c){b(c.data,c.status,c.headers,a)});return g};return g}function o(b,c,d){function e(a,b,c){m&&(200<=a&&a<300?m.put(w,
17.96 -[a,b,Mb(c)]):m.remove(w));f(b,a,c);h.$apply()}function f(a,c,d){c=Math.max(c,0);(200<=c&&c<300?j.resolve:j.reject)({data:a,status:c,headers:Nb(d),config:b})}function i(){var a=za(l.pendingRequests,b);a!==-1&&l.pendingRequests.splice(a,1)}var j=k.defer(),o=j.promise,m,p,w=r(b.url,b.params);l.pendingRequests.push(b);o.then(i,i);b.cache&&b.method=="GET"&&(m=L(b.cache)?b.cache:n);if(m)if(p=m.get(w))if(p.then)return p.then(i,i),p;else J(p)?f(p[1],p[0],V(p[2])):f(p,200,{});else m.put(w,o);p||a(b.method,
17.97 -w,c,e,d,b.timeout,b.withCredentials);return o}function r(a,b){if(!b)return a;var c=[];ec(b,function(a,b){a==null||a==p||(L(a)&&(a=da(a)),c.push(encodeURIComponent(b)+"="+encodeURIComponent(a)))});return a+(a.indexOf("?")==-1?"?":"&")+c.join("&")}var n=c("$http"),w=[];m(e,function(a){w.push(F(a)?j.get(a):j.invoke(a))});l.pendingRequests=[];(function(a){m(arguments,function(a){l[a]=function(b,c){return l(x(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){m(arguments,function(a){l[a]=
17.98 -function(b,c,d){return l(x(d||{},{method:a,url:b,data:c}))}})})("post","put");l.defaults=d;return l}]}function Wc(){this.$get=["$browser","$window","$document",function(b,a,c){return Xc(b,Yc,b.defer,a.angular.callbacks,c[0],a.location.protocol.replace(":",""))}]}function Xc(b,a,c,d,e,g){function i(a,b){var c=e.createElement("script"),d=function(){e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;aa?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror=
17.99 -d;e.body.appendChild(c)}return function(e,h,k,j,l,o,r){function n(a,c,d,e){c=(h.match(Fb)||["",g])[1]=="file"?d?200:404:c;a(c==1223?204:c,d,e);b.$$completeOutstandingRequest(D)}b.$$incOutstandingRequestCount();h=h||b.url();if(E(e)=="jsonp"){var p="_"+(d.counter++).toString(36);d[p]=function(a){d[p].data=a};i(h.replace("JSON_CALLBACK","angular.callbacks."+p),function(){d[p].data?n(j,200,d[p].data):n(j,-2);delete d[p]})}else{var q=new a;q.open(e,h,!0);m(l,function(a,b){a&&q.setRequestHeader(b,a)});
17.100 -var s;q.onreadystatechange=function(){q.readyState==4&&n(j,s||q.status,q.responseText,q.getAllResponseHeaders())};if(r)q.withCredentials=!0;q.send(k||"");o>0&&c(function(){s=-1;q.abort()},o)}}}function Zc(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},
17.101 -DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",
17.102 -shortTime:"h:mm a"},pluralCat:function(b){return b===1?"one":"other"}}}}function $c(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,f,h){var k=c.defer(),j=k.promise,l=v(h)&&!h,f=a.defer(function(){try{k.resolve(e())}catch(a){k.reject(a),d(a)}l||b.$apply()},f),h=function(){delete g[j.$$timeoutId]};j.$$timeoutId=f;g[f]=k;j.then(h,h);return j}var g={};e.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),a.defer.cancel(b.$$timeoutId)):
17.103 -!1};return e}]}function Pb(b){function a(a,e){return b.factory(a+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",Qb);a("date",Rb);a("filter",ad);a("json",bd);a("limitTo",cd);a("lowercase",dd);a("number",Sb);a("orderBy",Tb);a("uppercase",ed)}function ad(){return function(b,a){if(!(b instanceof Array))return b;var c=[];c.check=function(a){for(var b=0;b<c.length;b++)if(!c[b](a))return!1;return!0};var d=function(a,b){if(b.charAt(0)===
17.104 -"!")return!d(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return(""+a).toLowerCase().indexOf(b)>-1;case "object":for(var c in a)if(c.charAt(0)!=="$"&&d(a[c],b))return!0;return!1;case "array":for(c=0;c<a.length;c++)if(d(a[c],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a={$:a};case "object":for(var e in a)e=="$"?function(){var b=(""+a[e]).toLowerCase();b&&c.push(function(a){return d(a,b)})}():function(){var b=e,f=
17.105 -(""+a[e]).toLowerCase();f&&c.push(function(a){return d(fb(a,b),f)})}();break;case "function":c.push(a);break;default:return b}for(var g=[],i=0;i<b.length;i++){var f=b[i];c.check(f)&&g.push(f)}return g}}function Qb(b){var a=b.NUMBER_FORMATS;return function(b,d){if(t(d))d=a.CURRENCY_SYM;return Ub(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,2).replace(/\u00A4/g,d)}}function Sb(b){var a=b.NUMBER_FORMATS;return function(b,d){return Ub(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function Ub(b,a,c,d,e){if(isNaN(b)||
17.106 -!isFinite(b))return"";var g=b<0,b=Math.abs(b),i=b+"",f="",h=[],k=!1;if(i.indexOf("e")!==-1){var j=i.match(/([\d\.]+)e(-?)(\d+)/);j&&j[2]=="-"&&j[3]>e+1?i="0":(f=i,k=!0)}if(!k){i=(i.split(Vb)[1]||"").length;t(e)&&(e=Math.min(Math.max(a.minFrac,i),a.maxFrac));var i=Math.pow(10,e),b=Math.round(b*i)/i,b=(""+b).split(Vb),i=b[0],b=b[1]||"",k=0,j=a.lgSize,l=a.gSize;if(i.length>=j+l)for(var k=i.length-j,o=0;o<k;o++)(k-o)%l===0&&o!==0&&(f+=c),f+=i.charAt(o);for(o=k;o<i.length;o++)(i.length-o)%j===0&&o!==0&&
17.107 -(f+=c),f+=i.charAt(o);for(;b.length<e;)b+="0";e&&(f+=d+b.substr(0,e))}h.push(g?a.negPre:a.posPre);h.push(f);h.push(g?a.negSuf:a.posSuf);return h.join("")}function ib(b,a,c){var d="";b<0&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function P(b,a,c,d){return function(e){e=e["get"+b]();if(c>0||e>-c)e+=c;e===0&&c==-12&&(e=12);return ib(e,a,d)}}function La(b,a){return function(c,d){var e=c["get"+b](),g=la(a?"SHORT"+b:b);return d[g][e]}}function Rb(b){function a(a){var b;
17.108 -if(b=a.match(c)){var a=new Date(0),g=0,i=0;b[9]&&(g=G(b[9]+b[10]),i=G(b[9]+b[11]));a.setUTCFullYear(G(b[1]),G(b[2])-1,G(b[3]));a.setUTCHours(G(b[4]||0)-g,G(b[5]||0)-i,G(b[6]||0),G(b[7]||0))}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,e){var g="",i=[],f,h,e=e||"mediumDate",e=b.DATETIME_FORMATS[e]||e;F(c)&&(c=fd.test(c)?G(c):a(c));wa(c)&&(c=new Date(c));if(!na(c))return c;for(;e;)(h=gd.exec(e))?(i=i.concat(ia.call(h,
17.109 -1)),e=i.pop()):(i.push(e),e=null);m(i,function(a){f=hd[a];g+=f?f(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function bd(){return function(b){return da(b,!0)}}function cd(){return function(b,a){if(!(b instanceof Array))return b;var a=G(a),c=[],d,e;if(!b||!(b instanceof Array))return c;a>b.length?a=b.length:a<-b.length&&(a=-b.length);a>0?(d=0,e=a):(d=b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function Tb(b){return function(a,c,d){function e(a,b){return Wa(b)?
17.110 -function(b,c){return a(c,b)}:a}if(!(a instanceof Array))return a;if(!c)return a;for(var c=J(c)?c:[c],c=Ta(c,function(a){var c=!1,d=a||ma;if(F(a)){if(a.charAt(0)=="+"||a.charAt(0)=="-")c=a.charAt(0)=="-",a=a.substring(1);d=b(a)}return e(function(a,b){var c;c=d(a);var e=d(b),f=typeof c,g=typeof e;f==g?(f=="string"&&(c=c.toLowerCase()),f=="string"&&(e=e.toLowerCase()),c=c===e?0:c<e?-1:1):c=f<g?-1:1;return c},c)}),g=[],i=0;i<a.length;i++)g.push(a[i]);return g.sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=
17.111 -c[d](a,b);if(e!==0)return e}return 0},d))}}function S(b){N(b)&&(b={link:b});b.restrict=b.restrict||"AC";return I(b)}function Wb(b,a){function c(a,c){c=c?"-"+$a(c,"-"):"";b.removeClass((a?Ma:Na)+c).addClass((a?Na:Ma)+c)}var d=this,e=b.parent().controller("form")||Oa,g=0,i=d.$error={};d.$name=a.name;d.$dirty=!1;d.$pristine=!0;d.$valid=!0;d.$invalid=!1;e.$addControl(d);b.addClass(Pa);c(!0);d.$addControl=function(a){a.$name&&!d.hasOwnProperty(a.$name)&&(d[a.$name]=a)};d.$removeControl=function(a){a.$name&&
17.112 -d[a.$name]===a&&delete d[a.$name];m(i,function(b,c){d.$setValidity(c,!0,a)})};d.$setValidity=function(a,b,k){var j=i[a];if(b){if(j&&(Ua(j,k),!j.length)){g--;if(!g)c(b),d.$valid=!0,d.$invalid=!1;i[a]=!1;c(!0,a);e.$setValidity(a,!0,d)}}else{g||c(b);if(j){if(za(j,k)!=-1)return}else i[a]=j=[],g++,c(!1,a),e.$setValidity(a,!1,d);j.push(k);d.$valid=!1;d.$invalid=!0}};d.$setDirty=function(){b.removeClass(Pa).addClass(Xb);d.$dirty=!0;d.$pristine=!1;e.$setDirty()}}function T(b){return t(b)||b===""||b===null||
17.113 -b!==b}function Qa(b,a,c,d,e,g){var i=function(){var c=R(a.val());d.$viewValue!==c&&b.$apply(function(){d.$setViewValue(c)})};if(e.hasEvent("input"))a.bind("input",i);else{var f;a.bind("keydown",function(a){a=a.keyCode;a===91||15<a&&a<19||37<=a&&a<=40||f||(f=g.defer(function(){i();f=null}))});a.bind("change",i)}d.$render=function(){a.val(T(d.$viewValue)?"":d.$viewValue)};var h=c.ngPattern,k=function(a,b){return T(b)||a.test(b)?(d.$setValidity("pattern",!0),b):(d.$setValidity("pattern",!1),p)};h&&(h.match(/^\/(.*)\/$/)?
17.114 -(h=RegExp(h.substr(1,h.length-2)),e=function(a){return k(h,a)}):e=function(a){var c=b.$eval(h);if(!c||!c.test)throw new B("Expected "+h+" to be a RegExp but was "+c);return k(c,a)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var j=G(c.ngMinlength),e=function(a){return!T(a)&&a.length<j?(d.$setValidity("minlength",!1),p):(d.$setValidity("minlength",!0),a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var l=G(c.ngMaxlength),c=function(a){return!T(a)&&a.length>l?(d.$setValidity("maxlength",
17.115 -!1),p):(d.$setValidity("maxlength",!0),a)};d.$parsers.push(c);d.$formatters.push(c)}}function jb(b,a){b="ngClass"+b;return S(function(c,d,e){function g(b,d){if(a===!0||c.$index%2===a)d&&b!==d&&i(d),f(b)}function i(a){L(a)&&!J(a)&&(a=Ta(a,function(a,b){if(a)return b}));d.removeClass(J(a)?a.join(" "):a)}function f(a){L(a)&&!J(a)&&(a=Ta(a,function(a,b){if(a)return b}));a&&d.addClass(J(a)?a.join(" "):a)}c.$watch(e[b],g,!0);e.$observe("class",function(){var a=c.$eval(e[b]);g(a,a)});b!=="ngClass"&&c.$watch("$index",
17.116 -function(d,g){var j=d%2;j!==g%2&&(j==a?f(c.$eval(e[b])):i(c.$eval(e[b])))})})}var E=function(b){return F(b)?b.toLowerCase():b},la=function(b){return F(b)?b.toUpperCase():b},B=U.Error,aa=G((/msie (\d+)/.exec(E(navigator.userAgent))||[])[1]),u,ja,ia=[].slice,Ra=[].push,Sa=Object.prototype.toString,Yb=U.angular||(U.angular={}),ta,Cb,Z=["0","0","0"];D.$inject=[];ma.$inject=[];Cb=aa<9?function(b){b=b.nodeName?b:b[0];return b.scopeName&&b.scopeName!="HTML"?la(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?
17.117 -b.nodeName:b[0].nodeName};var kc=/[A-Z]/g,id={full:"1.0.3",major:1,minor:0,dot:3,codeName:"bouncy-thunder"},Ba=Q.cache={},Aa=Q.expando="ng-"+(new Date).getTime(),oc=1,Zb=U.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},db=U.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)},mc=/([\:\-\_]+(.))/g,nc=/^moz([A-Z])/,ua=Q.prototype={ready:function(b){function a(){c||(c=!0,b())}
17.118 -var c=!1;this.bind("DOMContentLoaded",a);Q(U).bind("load",a)},toString:function(){var b=[];m(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return b>=0?u(this[b]):u(this[this.length+b])},length:0,push:Ra,sort:[].sort,splice:[].splice},Ea={};m("multiple,selected,checked,disabled,readOnly,required".split(","),function(b){Ea[E(b)]=b});var zb={};m("input,select,option,textarea,button,form".split(","),function(b){zb[la(b)]=!0});m({data:ub,inheritedData:Da,scope:function(b){return Da(b,
17.119 -"$scope")},controller:xb,injector:function(b){return Da(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Ca,css:function(b,a,c){a=rb(a);if(v(c))b.style[a]=c;else{var d;aa<=8&&(d=b.currentStyle&&b.currentStyle[a],d===""&&(d="auto"));d=d||b.style[a];aa<=8&&(d=d===""?p:d);return d}},attr:function(b,a,c){var d=E(a);if(Ea[d])if(v(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||D).specified?d:p;else if(v(c))b.setAttribute(a,
17.120 -c);else if(b.getAttribute)return b=b.getAttribute(a,2),b===null?p:b},prop:function(b,a,c){if(v(c))b[a]=c;else return b[a]},text:x(aa<9?function(b,a){if(b.nodeType==1){if(t(a))return b.innerText;b.innerText=a}else{if(t(a))return b.nodeValue;b.nodeValue=a}}:function(b,a){if(t(a))return b.textContent;b.textContent=a},{$dv:""}),val:function(b,a){if(t(a))return b.value;b.value=a},html:function(b,a){if(t(a))return b.innerHTML;for(var c=0,d=b.childNodes;c<d.length;c++)sa(d[c]);b.innerHTML=a}},function(b,
17.121 -a){Q.prototype[a]=function(a,d){var e,g;if((b.length==2&&b!==Ca&&b!==xb?a:d)===p)if(L(a)){for(e=0;e<this.length;e++)if(b===ub)b(this[e],a);else for(g in a)b(this[e],g,a[g]);return this}else{if(this.length)return b(this[0],a,d)}else{for(e=0;e<this.length;e++)b(this[e],a,d);return this}return b.$dv}});m({removeData:sb,dealoc:sa,bind:function a(c,d,e){var g=$(c,"events"),i=$(c,"handle");g||$(c,"events",g={});i||$(c,"handle",i=pc(c,g));m(d.split(" "),function(d){var h=g[d];if(!h){if(d=="mouseenter"||
17.122 -d=="mouseleave"){var k=0;g.mouseenter=[];g.mouseleave=[];a(c,"mouseover",function(a){k++;k==1&&i(a,"mouseenter")});a(c,"mouseout",function(a){k--;k==0&&i(a,"mouseleave")})}else Zb(c,d,i),g[d]=[];h=g[d]}h.push(e)})},unbind:tb,replaceWith:function(a,c){var d,e=a.parentNode;sa(a);m(new Q(c),function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];m(a.childNodes,function(a){a.nodeName!="#text"&&c.push(a)});return c},contents:function(a){return a.childNodes},
17.123 -append:function(a,c){m(new Q(c),function(c){a.nodeType===1&&a.appendChild(c)})},prepend:function(a,c){if(a.nodeType===1){var d=a.firstChild;m(new Q(c),function(c){d?a.insertBefore(c,d):(a.appendChild(c),d=c)})}},wrap:function(a,c){var c=u(c)[0],d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:function(a){sa(a);var c=a.parentNode;c&&c.removeChild(a)},after:function(a,c){var d=a,e=a.parentNode;m(new Q(c),function(a){e.insertBefore(a,d.nextSibling);d=a})},addClass:wb,removeClass:vb,toggleClass:function(a,
17.124 -c,d){t(d)&&(d=!Ca(a,c));(d?wb:vb)(a,c)},parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},next:function(a){return a.nextSibling},find:function(a,c){return a.getElementsByTagName(c)},clone:cb,triggerHandler:function(a,c){var d=($(a,"events")||{})[c];m(d,function(c){c.call(a,null)})}},function(a,c){Q.prototype[c]=function(c,e){for(var g,i=0;i<this.length;i++)g==p?(g=a(this[i],c,e),g!==p&&(g=u(g))):bb(g,a(this[i],c,e));return g==p?this:g}});Fa.prototype={put:function(a,c){this[ga(a)]=
17.125 -c},get:function(a){return this[ga(a)]},remove:function(a){var c=this[a=ga(a)];delete this[a];return c}};eb.prototype={push:function(a,c){var d=this[a=ga(a)];d?d.push(c):this[a]=[c]},shift:function(a){var c=this[a=ga(a)];if(c)return c.length==1?(delete this[a],c[0]):c.shift()},peek:function(a){if(a=this[ga(a)])return a[0]}};var rc=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,sc=/,/,tc=/^\s*(_?)(\S+?)\1\s*$/,qc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Db="Non-assignable model expression: ";Bb.$inject=["$provide"];
17.126 -var Ac=/^(x[\:\-_]|data[\:\-_])/i,Fb=/^([^:]+):\/\/(\w+:{0,1}\w*@)?([\w\.-]*)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,$b=/^([^\?#]*)?(\?([^#]*))?(#(.*))?$/,Hc=$b,Gb={http:80,https:443,ftp:21};gb.prototype={$$replace:!1,absUrl:Ja("$$absUrl"),url:function(a,c){if(t(a))return this.$$url;var d=$b.exec(a);d[1]&&this.path(decodeURIComponent(d[1]));if(d[2]||d[1])this.search(d[3]||"");this.hash(d[5]||"",c);return this},protocol:Ja("$$protocol"),host:Ja("$$host"),port:Ja("$$port"),path:Ib("$$path",function(a){return a.charAt(0)==
17.127 -"/"?a:"/"+a}),search:function(a,c){if(t(a))return this.$$search;v(c)?c===null?delete this.$$search[a]:this.$$search[a]=c:this.$$search=F(a)?Xa(a):a;this.$$compose();return this},hash:Ib("$$hash",ma),replace:function(){this.$$replace=!0;return this}};Ia.prototype=ya(gb.prototype);Hb.prototype=ya(Ia.prototype);var Ka={"null":function(){return null},"true":function(){return!0},"false":function(){return!1},undefined:D,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return v(d)?v(e)?d+e:d:v(e)?e:p},"-":function(a,
17.128 -c,d,e){d=d(a,c);e=e(a,c);return(v(d)?d:0)-(v(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^e(a,c)},"=":D,"==":function(a,c,d,e){return d(a,c)==e(a,c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,
17.129 -c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Lc={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'},hb={},Yc=U.XMLHttpRequest||function(){try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(c){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(d){}throw new B("This browser does not support XMLHttpRequest.");
17.130 -};Pb.$inject=["$provide"];Qb.$inject=["$locale"];Sb.$inject=["$locale"];var Vb=".",hd={yyyy:P("FullYear",4),yy:P("FullYear",2,0,!0),y:P("FullYear",1),MMMM:La("Month"),MMM:La("Month",!0),MM:P("Month",2,1),M:P("Month",1,1),dd:P("Date",2),d:P("Date",1),HH:P("Hours",2),H:P("Hours",1),hh:P("Hours",2,-12),h:P("Hours",1,-12),mm:P("Minutes",2),m:P("Minutes",1),ss:P("Seconds",2),s:P("Seconds",1),EEEE:La("Day"),EEE:La("Day",!0),a:function(a,c){return a.getHours()<12?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=a.getTimezoneOffset();
17.131 -return ib(a/60,2)+ib(Math.abs(a%60),2)}},gd=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,fd=/^\d+$/;Rb.$inject=["$locale"];var dd=I(E),ed=I(la);Tb.$inject=["$parse"];var jd=I({restrict:"E",compile:function(a,c){c.href||c.$set("href","");return function(a,c){c.bind("click",function(a){if(!c.attr("href"))return a.preventDefault(),!1})}}}),kb={};m(Ea,function(a,c){var d=fa("ng-"+c);kb[d]=function(){return{priority:100,compile:function(){return function(a,g,i){a.$watch(i[d],
17.132 -function(a){i.$set(c,!!a)})}}}}});m(["src","href"],function(a){var c=fa("ng-"+a);kb[c]=function(){return{priority:99,link:function(d,e,g){g.$observe(c,function(c){c&&(g.$set(a,c),aa&&e.prop(a,c))})}}}});var Oa={$addControl:D,$removeControl:D,$setValidity:D,$setDirty:D};Wb.$inject=["$element","$attrs","$scope"];var Ra=function(a){return["$timeout",function(c){var d={name:"form",restrict:"E",controller:Wb,compile:function(){return{pre:function(a,d,i,f){if(!i.action){var h=function(a){a.preventDefault?
17.133 -a.preventDefault():a.returnValue=!1};Zb(d[0],"submit",h);d.bind("$destroy",function(){c(function(){db(d[0],"submit",h)},0,!1)})}var k=d.parent().controller("form"),j=i.name||i.ngForm;j&&(a[j]=f);k&&d.bind("$destroy",function(){k.$removeControl(f);j&&(a[j]=p);x(f,Oa)})}}}};return a?x(V(d),{restrict:"EAC"}):d}]},kd=Ra(),ld=Ra(!0),md=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,nd=/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/,od=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,
17.134 -ac={text:Qa,number:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);e.$parsers.push(function(a){var c=T(a);return c||od.test(a)?(e.$setValidity("number",!0),a===""?null:c?a:parseFloat(a)):(e.$setValidity("number",!1),p)});e.$formatters.push(function(a){return T(a)?"":""+a});if(d.min){var f=parseFloat(d.min),a=function(a){return!T(a)&&a<f?(e.$setValidity("min",!1),p):(e.$setValidity("min",!0),a)};e.$parsers.push(a);e.$formatters.push(a)}if(d.max){var h=parseFloat(d.max),d=function(a){return!T(a)&&a>h?(e.$setValidity("max",
17.135 -!1),p):(e.$setValidity("max",!0),a)};e.$parsers.push(d);e.$formatters.push(d)}e.$formatters.push(function(a){return T(a)||wa(a)?(e.$setValidity("number",!0),a):(e.$setValidity("number",!1),p)})},url:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);a=function(a){return T(a)||md.test(a)?(e.$setValidity("url",!0),a):(e.$setValidity("url",!1),p)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,g,i){Qa(a,c,d,e,g,i);a=function(a){return T(a)||nd.test(a)?(e.$setValidity("email",!0),a):(e.$setValidity("email",
17.136 -!1),p)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){t(d.name)&&c.attr("name",xa());c.bind("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var g=d.ngTrueValue,i=d.ngFalseValue;F(g)||(g=!0);F(i)||(i=!1);c.bind("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$formatters.push(function(a){return a===
17.137 -g});e.$parsers.push(function(a){return a?g:i})},hidden:D,button:D,submit:D,reset:D},bc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,g,i){i&&(ac[E(g.type)]||ac.text)(d,e,g,i,c,a)}}}],Na="ng-valid",Ma="ng-invalid",Pa="ng-pristine",Xb="ng-dirty",pd=["$scope","$exceptionHandler","$attrs","$element","$parse",function(a,c,d,e,g){function i(a,c){c=c?"-"+$a(c,"-"):"";e.removeClass((a?Ma:Na)+c).addClass((a?Na:Ma)+c)}this.$modelValue=this.$viewValue=Number.NaN;
17.138 -this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var f=g(d.ngModel),h=f.assign;if(!h)throw B(Db+d.ngModel+" ("+pa(e)+")");this.$render=D;var k=e.inheritedData("$formController")||Oa,j=0,l=this.$error={};e.addClass(Pa);i(!0);this.$setValidity=function(a,c){if(l[a]!==!c){if(c){if(l[a]&&j--,!j)i(!0),this.$valid=!0,this.$invalid=!1}else i(!1),this.$invalid=!0,this.$valid=!1,j++;l[a]=!c;i(c,a);k.$setValidity(a,
17.139 -c,this)}};this.$setViewValue=function(d){this.$viewValue=d;if(this.$pristine)this.$dirty=!0,this.$pristine=!1,e.removeClass(Pa).addClass(Xb),k.$setDirty();m(this.$parsers,function(a){d=a(d)});if(this.$modelValue!==d)this.$modelValue=d,h(a,d),m(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}})};var o=this;a.$watch(function(){var c=f(a);if(o.$modelValue!==c){var d=o.$formatters,e=d.length;for(o.$modelValue=c;e--;)c=d[e](c);if(o.$viewValue!==c)o.$viewValue=c,o.$render()}})}],qd=function(){return{require:["ngModel",
17.140 -"^?form"],controller:pd,link:function(a,c,d,e){var g=e[0],i=e[1]||Oa;i.$addControl(g);c.bind("$destroy",function(){i.$removeControl(g)})}}},rd=I({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),cc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var g=function(a){if(d.required&&(T(a)||a===!1))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g);
17.141 -d.$observe("required",function(){g(e.$viewValue)})}}}},sd=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){var c=[];a&&m(a.split(g),function(a){a&&c.push(R(a))});return c});e.$formatters.push(function(a){return J(a)?a.join(", "):p})}}},td=/^(true|false|\d+)$/,ud=function(){return{priority:100,compile:function(a,c){return td.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a,
17.142 -c,g){a.$watch(g.ngValue,function(a){g.$set("value",a,!1)})}}}},vd=S(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==p?"":a)})}),wd=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],xd=[function(){return function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBindHtmlUnsafe);a.$watch(d.ngBindHtmlUnsafe,
17.143 -function(a){c.html(a||"")})}}],yd=jb("",!0),zd=jb("Odd",0),Ad=jb("Even",1),Bd=S({compile:function(a,c){c.$set("ngCloak",p);a.removeClass("ng-cloak")}}),Cd=[function(){return{scope:!0,controller:"@"}}],Dd=["$sniffer",function(a){return{priority:1E3,compile:function(){a.csp=!0}}}],dc={};m("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave".split(" "),function(a){var c=fa("ng-"+a);dc[c]=["$parse",function(d){return function(e,g,i){var f=d(i[c]);g.bind(E(a),function(a){e.$apply(function(){f(e,
17.144 -{$event:a})})})}}]});var Ed=S(function(a,c,d){c.bind("submit",function(){a.$apply(d.ngSubmit)})}),Fd=["$http","$templateCache","$anchorScroll","$compile",function(a,c,d,e){return{restrict:"ECA",terminal:!0,compile:function(g,i){var f=i.ngInclude||i.src,h=i.onload||"",k=i.autoscroll;return function(g,i){var o=0,m,n=function(){m&&(m.$destroy(),m=null);i.html("")};g.$watch(f,function(f){var p=++o;f?a.get(f,{cache:c}).success(function(a){p===o&&(m&&m.$destroy(),m=g.$new(),i.html(a),e(i.contents())(m),
17.145 -v(k)&&(!k||g.$eval(k))&&d(),m.$emit("$includeContentLoaded"),g.$eval(h))}).error(function(){p===o&&n()}):n()})}}}}],Gd=S({compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Hd=S({terminal:!0,priority:1E3}),Id=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,g,i){var f=i.count,h=g.attr(i.$attr.when),k=i.offset||0,j=e.$eval(h),l={},o=c.startSymbol(),r=c.endSymbol();m(j,function(a,e){l[e]=c(a.replace(d,o+f+"-"+k+r))});e.$watch(function(){var c=
17.146 -parseFloat(e.$eval(f));return isNaN(c)?"":(j[c]||(c=a.pluralCat(c-k)),l[c](e,g,!0))},function(a){g.text(a)})}}}],Jd=S({transclude:"element",priority:1E3,terminal:!0,compile:function(a,c,d){return function(a,c,i){var f=i.ngRepeat,i=f.match(/^\s*(.+)\s+in\s+(.*)\s*$/),h,k,j;if(!i)throw B("Expected ngRepeat in form of '_item_ in _collection_' but got '"+f+"'.");f=i[1];h=i[2];i=f.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!i)throw B("'item' in 'item in collection' should be identifier or (key, value) but got '"+
17.147 -f+"'.");k=i[3]||i[1];j=i[2];var l=new eb;a.$watch(function(a){var e,f,i=a.$eval(h),m=gc(i,!0),p,u=new eb,C,A,v,t,y=c;if(J(i))v=i||[];else{v=[];for(C in i)i.hasOwnProperty(C)&&C.charAt(0)!="$"&&v.push(C);v.sort()}e=0;for(f=v.length;e<f;e++){C=i===v?e:v[e];A=i[C];if(t=l.shift(A)){p=t.scope;u.push(A,t);if(e!==t.index)t.index=e,y.after(t.element);y=t.element}else p=a.$new();p[k]=A;j&&(p[j]=C);p.$index=e;p.$first=e===0;p.$last=e===m-1;p.$middle=!(p.$first||p.$last);t||d(p,function(a){y.after(a);t={scope:p,
17.148 -element:y=a,index:e};u.push(A,t)})}for(C in l)if(l.hasOwnProperty(C))for(v=l[C];v.length;)A=v.pop(),A.element.remove(),A.scope.$destroy();l=u})}}}),Kd=S(function(a,c,d){a.$watch(d.ngShow,function(a){c.css("display",Wa(a)?"":"none")})}),Ld=S(function(a,c,d){a.$watch(d.ngHide,function(a){c.css("display",Wa(a)?"none":"")})}),Md=S(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&m(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Nd=I({restrict:"EA",compile:function(a,c){var d=c.ngSwitch||c.on,
17.149 -e={};a.data("ng-switch",e);return function(a,i){var f,h,k;a.$watch(d,function(d){h&&(k.$destroy(),h.remove(),h=k=null);if(f=e["!"+d]||e["?"])a.$eval(c.change),k=a.$new(),f(k,function(a){h=a;i.append(a)})})}}}),Od=S({transclude:"element",priority:500,compile:function(a,c,d){a=a.inheritedData("ng-switch");qa(a);a["!"+c.ngSwitchWhen]=d}}),Pd=S({transclude:"element",priority:500,compile:function(a,c,d){a=a.inheritedData("ng-switch");qa(a);a["?"]=d}}),Qd=S({controller:["$transclude","$element",function(a,
17.150 -c){a(function(a){c.append(a)})}]}),Rd=["$http","$templateCache","$route","$anchorScroll","$compile","$controller",function(a,c,d,e,g,i){return{restrict:"ECA",terminal:!0,link:function(a,c,k){function j(){var j=d.current&&d.current.locals,k=j&&j.$template;if(k){c.html(k);l&&(l.$destroy(),l=null);var k=g(c.contents()),p=d.current;l=p.scope=a.$new();if(p.controller)j.$scope=l,j=i(p.controller,j),c.contents().data("$ngControllerController",j);k(l);l.$emit("$viewContentLoaded");l.$eval(m);e()}else c.html(""),
17.151 -l&&(l.$destroy(),l=null)}var l,m=k.onload||"";a.$on("$routeChangeSuccess",j);j()}}}],Sd=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){d.type=="text/ng-template"&&a.put(d.id,c[0].text)}}}],Td=I({terminal:!0}),Ud=["$compile","$parse",function(a,c){var d=/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/,e={$setViewValue:D};return{restrict:"E",require:["select",
17.152 -"?ngModel"],controller:["$element","$scope","$attrs",function(a,c,d){var h=this,k={},j=e,l;h.databound=d.ngModel;h.init=function(a,c,d){j=a;l=d};h.addOption=function(c){k[c]=!0;j.$viewValue==c&&(a.val(c),l.parent()&&l.remove())};h.removeOption=function(a){this.hasOption(a)&&(delete k[a],j.$viewValue==a&&this.renderUnknownOption(a))};h.renderUnknownOption=function(c){c="? "+ga(c)+" ?";l.val(c);a.prepend(l);a.val(c);l.prop("selected",!0)};h.hasOption=function(a){return k.hasOwnProperty(a)};c.$on("$destroy",
17.153 -function(){h.renderUnknownOption=D})}],link:function(e,i,f,h){function k(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(A.parent()&&A.remove(),c.val(a),a===""&&s.prop("selected",!0)):t(a)&&s?c.val(""):e.renderUnknownOption(a)};c.bind("change",function(){a.$apply(function(){A.parent()&&A.remove();d.$setViewValue(c.val())})})}function j(a,c,d){var e;d.$render=function(){var a=new Fa(d.$viewValue);m(c.children(),function(c){c.selected=v(a.get(c.value))})};a.$watch(function(){ha(e,d.$viewValue)||
17.154 -(e=V(d.$viewValue),d.$render())});c.bind("change",function(){a.$apply(function(){var a=[];m(c.children(),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function l(e,f,g){function h(){var a={"":[]},c=[""],d,i,s,t,u;s=g.$modelValue;t=r(e)||[];var y=l?lb(t):t,A,w,x;w={};u=!1;var z,B;if(n)u=new Fa(s);else if(s===null||q)a[""].push({selected:s===null,id:"",label:""}),u=!0;for(x=0;A=y.length,x<A;x++){w[k]=t[l?w[l]=y[x]:x];d=m(e,w)||"";if(!(i=a[d]))i=a[d]=[],c.push(d);n?d=u.remove(o(e,
17.155 -w))!=p:(d=s===o(e,w),u=u||d);z=j(e,w);z=z===p?"":z;i.push({id:l?y[x]:x,label:z,selected:d})}!n&&!u&&a[""].unshift({id:"?",label:"",selected:!0});w=0;for(y=c.length;w<y;w++){d=c[w];i=a[d];if(v.length<=w)s={element:C.clone().attr("label",d),label:i.label},t=[s],v.push(t),f.append(s.element);else if(t=v[w],s=t[0],s.label!=d)s.element.attr("label",s.label=d);z=null;x=0;for(A=i.length;x<A;x++)if(d=i[x],u=t[x+1]){z=u.element;if(u.label!==d.label)z.text(u.label=d.label);if(u.id!==d.id)z.val(u.id=d.id);if(u.element.selected!==
17.156 -d.selected)z.prop("selected",u.selected=d.selected)}else d.id===""&&q?B=q:(B=D.clone()).val(d.id).attr("selected",d.selected).text(d.label),t.push({element:B,label:d.label,id:d.id,selected:d.selected}),z?z.after(B):s.element.append(B),z=B;for(x++;t.length>x;)t.pop().element.remove()}for(;v.length>w;)v.pop()[0].element.remove()}var i;if(!(i=w.match(d)))throw B("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '"+w+"'.");var j=c(i[2]||i[1]),k=i[4]||
17.157 -i[6],l=i[5],m=c(i[3]||""),o=c(i[2]?i[1]:k),r=c(i[7]),v=[[{element:f,label:""}]];q&&(a(q)(e),q.removeClass("ng-scope"),q.remove());f.html("");f.bind("change",function(){e.$apply(function(){var a,c=r(e)||[],d={},h,i,j,m,q,s;if(n){i=[];m=0;for(s=v.length;m<s;m++){a=v[m];j=1;for(q=a.length;j<q;j++)if((h=a[j].element)[0].selected)h=h.val(),l&&(d[l]=h),d[k]=c[h],i.push(o(e,d))}}else h=f.val(),h=="?"?i=p:h==""?i=null:(d[k]=c[h],l&&(d[l]=h),i=o(e,d));g.$setViewValue(i)})});g.$render=h;e.$watch(h)}if(h[1]){for(var o=
17.158 -h[0],r=h[1],n=f.multiple,w=f.ngOptions,q=!1,s,D=u(ca.createElement("option")),C=u(ca.createElement("optgroup")),A=D.clone(),h=0,x=i.children(),E=x.length;h<E;h++)if(x[h].value==""){s=q=x.eq(h);break}o.init(r,q,A);if(n&&(f.required||f.ngRequired)){var y=function(a){r.$setValidity("required",!f.required||a&&a.length);return a};r.$parsers.push(y);r.$formatters.unshift(y);f.$observe("required",function(){y(r.$viewValue)})}w?l(e,i,r):n?j(e,i,r):k(e,i,r,o)}}}}],Vd=["$interpolate",function(a){var c={addOption:D,
17.159 -removeOption:D};return{restrict:"E",priority:100,compile:function(d,e){if(t(e.value)){var g=a(d.text(),!0);g||e.$set("value",d.text())}return function(a,d,e){var k=d.parent(),j=k.data("$selectController")||k.parent().data("$selectController");j&&j.databound?d.prop("selected",!1):j=c;g?a.$watch(g,function(a,c){e.$set("value",a);a!==c&&j.removeOption(c);j.addOption(a)}):j.addOption(e.value);d.bind("$destroy",function(){j.removeOption(e.value)})}}}}],Wd=I({restrict:"E",terminal:!0});(ja=U.jQuery)?(u=
17.160 -ja,x(ja.fn,{scope:ua.scope,controller:ua.controller,injector:ua.injector,inheritedData:ua.inheritedData}),ab("remove",!0),ab("empty"),ab("html")):u=Q;Yb.element=u;(function(a){x(a,{bootstrap:pb,copy:V,extend:x,equals:ha,element:u,forEach:m,injector:qb,noop:D,bind:Va,toJson:da,fromJson:nb,identity:ma,isUndefined:t,isDefined:v,isString:F,isFunction:N,isObject:L,isNumber:wa,isElement:fc,isArray:J,version:id,isDate:na,lowercase:E,uppercase:la,callbacks:{counter:0}});ta=lc(U);try{ta("ngLocale")}catch(c){ta("ngLocale",
17.161 -[]).provider("$locale",Zc)}ta("ng",["ngLocale"],["$provide",function(a){a.provider("$compile",Bb).directive({a:jd,input:bc,textarea:bc,form:kd,script:Sd,select:Ud,style:Wd,option:Vd,ngBind:vd,ngBindHtmlUnsafe:xd,ngBindTemplate:wd,ngClass:yd,ngClassEven:Ad,ngClassOdd:zd,ngCsp:Dd,ngCloak:Bd,ngController:Cd,ngForm:ld,ngHide:Ld,ngInclude:Fd,ngInit:Gd,ngNonBindable:Hd,ngPluralize:Id,ngRepeat:Jd,ngShow:Kd,ngSubmit:Ed,ngStyle:Md,ngSwitch:Nd,ngSwitchWhen:Od,ngSwitchDefault:Pd,ngOptions:Td,ngView:Rd,ngTransclude:Qd,
17.162 -ngModel:qd,ngList:sd,ngChange:rd,required:cc,ngRequired:cc,ngValue:ud}).directive(kb).directive(dc);a.provider({$anchorScroll:uc,$browser:wc,$cacheFactory:xc,$controller:Bc,$document:Cc,$exceptionHandler:Dc,$filter:Pb,$interpolate:Ec,$http:Vc,$httpBackend:Wc,$location:Ic,$log:Jc,$parse:Nc,$route:Qc,$routeParams:Rc,$rootScope:Sc,$q:Oc,$sniffer:Tc,$templateCache:yc,$timeout:$c,$window:Uc})}])})(Yb);u(ca).ready(function(){jc(ca,pb)})})(window,document);angular.element(document).find("head").append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');
18.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/app.js Tue Apr 29 15:25:58 2014 +0200
18.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
18.3 @@ -1,224 +0,0 @@
18.4 -// 'use strict';
18.5 -
18.6 -// Declare app level module which depends on filters, and services
18.7 -angular.module('bck2brwsr', []).
18.8 - directive('uiCodemirror', ['$timeout', function($timeout) {
18.9 - 'use strict';
18.10 -
18.11 - var events = ["cursorActivity", "viewportChange", "gutterClick", "focus", "blur", "scroll", "update"];
18.12 - return {
18.13 - restrict: 'A',
18.14 - require: 'ngModel',
18.15 - link: function(scope, elm, attrs, ngModel) {
18.16 - var options, opts, onChange, deferCodeMirror, codeMirror, timeoutId, val;
18.17 -
18.18 - if (elm[0].type !== 'textarea') {
18.19 - throw new Error('uiCodemirror3 can only be applied to a textarea element');
18.20 - }
18.21 -
18.22 - options = /* uiConfig.codemirror || */ {};
18.23 - opts = angular.extend({}, options, scope.$eval(attrs.uiCodemirror));
18.24 -
18.25 - onChange = function(instance, changeObj) {
18.26 - val = instance.getValue();
18.27 - $timeout.cancel(timeoutId);
18.28 - timeoutId = $timeout(function() {
18.29 - ngModel.$setViewValue(val);
18.30 - }, 500);
18.31 - };
18.32 -
18.33 - deferCodeMirror = function() {
18.34 - codeMirror = CodeMirror.fromTextArea(elm[0], opts);
18.35 - elm[0].codeMirror = codeMirror;
18.36 - // codeMirror.on("change", onChange(opts.onChange));
18.37 - codeMirror.on("change", onChange);
18.38 -
18.39 - for (var i = 0, n = events.length, aEvent; i < n; ++i) {
18.40 - aEvent = opts["on" + events[i].charAt(0).toUpperCase() + events[i].slice(1)];
18.41 - if (aEvent === void 0)
18.42 - continue;
18.43 - if (typeof aEvent !== "function")
18.44 - continue;
18.45 -
18.46 - var bound = _.bind( aEvent, scope );
18.47 -
18.48 - codeMirror.on(events[i], bound);
18.49 - }
18.50 -
18.51 - // CodeMirror expects a string, so make sure it gets one.
18.52 - // This does not change the model.
18.53 - ngModel.$formatters.push(function(value) {
18.54 - if (angular.isUndefined(value) || value === null) {
18.55 - return '';
18.56 - }
18.57 - else if (angular.isObject(value) || angular.isArray(value)) {
18.58 - throw new Error('ui-codemirror cannot use an object or an array as a model');
18.59 - }
18.60 - return value;
18.61 - });
18.62 -
18.63 - // Override the ngModelController $render method, which is what gets called when the model is updated.
18.64 - // This takes care of the synchronizing the codeMirror element with the underlying model, in the case that it is changed by something else.
18.65 - ngModel.$render = function() {
18.66 - codeMirror.setValue(ngModel.$viewValue);
18.67 - };
18.68 -
18.69 - };
18.70 -
18.71 - $timeout(deferCodeMirror);
18.72 -
18.73 - }
18.74 - };
18.75 -}]);
18.76 -
18.77 -function DevCtrl( $scope, $http ) {
18.78 - var templateHtml =
18.79 -"<html><body>\n" +
18.80 -" <input data-bind=\"value: value, valueUpdate: 'afterkeydown'\" \n" +
18.81 -" value=\"0\" type=\"number\">\n" +
18.82 -" </input>\n" +
18.83 -" * <span data-bind=\"text: value\">0</span> \n" +
18.84 -" = <span data-bind=\"text: powerValue\">0</span>\n" +
18.85 -" <br/>\n" +
18.86 -" <button id='dupl'>Duplicate!</button>\n" +
18.87 -" <button id=\"clear\">Clear!</button>" +
18.88 -" <hr/>\n" +
18.89 -"\n" +
18.90 -"\n" +
18.91 -"\n" +
18.92 -"\n" +
18.93 -"\n" +
18.94 -"\n" +
18.95 -"\n" +
18.96 -"\n" +
18.97 -"\n" +
18.98 -"\n" +
18.99 -"\n" +
18.100 -"\n" +
18.101 -"\n" +
18.102 -"\n" +
18.103 -"\n" +
18.104 -"\n" +
18.105 -"\n" +
18.106 -"\n" +
18.107 -"\n" +
18.108 -"\n" +
18.109 -" <script src=\"/bck2brwsr.js\"></script>\n" +
18.110 -" <script type=\"text/javascript\">\n" +
18.111 -" function ldCls(res) {\n" +
18.112 -" var request = new XMLHttpRequest();\n" +
18.113 -" request.open('GET', '/classes/' + res, false);\n" +
18.114 -" request.send();\n" +
18.115 -" var arr = eval('(' + request.responseText + ')');\n" +
18.116 -" return arr;\n" +
18.117 -" }\n" +
18.118 -" var vm = bck2brwsr(ldCls);\n" +
18.119 -" vm.loadClass('${fqn}');\n" +
18.120 -" </script>\n" +
18.121 -"</body></html>";
18.122 - var templateJava =
18.123 -"package bck2brwsr.demo;\n" +
18.124 -"import org.apidesign.bck2brwsr.htmlpage.api.*;\n" +
18.125 -"import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;\n" +
18.126 -"\n" +
18.127 -"@Page(xhtml=\"index.html\", className=\"Index\", properties={\n" +
18.128 -" @Property(name=\"value\", type=int.class)\n" +
18.129 -"})\n" +
18.130 -"class YourFirstHTML5PageInRealLanguage {\n" +
18.131 -" static { new Index().applyBindings(); }\n" +
18.132 -" @On(event=CLICK, id=\"dupl\") static void duplicateValue(Index m) {\n" +
18.133 -" m.setValue(m.getValue() * 2);\n" +
18.134 -" }\n" +
18.135 -" @On(event=CLICK, id=\"clear\") static void zeroTheValue(Index m) {\n" +
18.136 -" m.setValue(0);;\n" +
18.137 -" }\n" +
18.138 -" @ComputedProperty static int powerValue(int value) {\n" +
18.139 -" return value * value;\n" +
18.140 -" }\n" +
18.141 -"}";
18.142 -
18.143 -
18.144 - $scope.makeMarker = function( editor, line ) {
18.145 - var marker = document.createElement("div");
18.146 - marker.innerHTML = " ";
18.147 - marker.className = "issue";
18.148 -
18.149 - var info = editor.lineInfo(line);
18.150 - editor.setGutterMarker(line, "issues", info.markers ? null : marker);
18.151 -
18.152 - return marker;
18.153 - };
18.154 -
18.155 -
18.156 - // Returns a function, that, as long as it continues to be invoked, will not
18.157 - // be triggered. The function will be called after it stops being called for
18.158 - // N milliseconds. If `immediate` is passed, trigger the function on the
18.159 - // leading edge, instead of the trailing.
18.160 - $scope.debounce = function(func, wait, immediate) {
18.161 - var timeout, result;
18.162 - return function() {
18.163 - var context = this, args = arguments;
18.164 - var later = function() {
18.165 - timeout = null;
18.166 - if (!immediate) result = func.apply(context, args);
18.167 - };
18.168 - var callNow = immediate && !timeout;
18.169 - clearTimeout(timeout);
18.170 - timeout = setTimeout(later, wait);
18.171 - if (callNow) result = func.apply(context, args);
18.172 - return result;
18.173 - };
18.174 - };
18.175 -
18.176 - $scope.reload = function() {
18.177 - $scope.errors = null;
18.178 - var frame = document.getElementById("result");
18.179 - frame.src = "result.html";
18.180 - frame.contentDocument.location.reload(true);
18.181 - frame.contentWindow.location.reload();
18.182 - document.getElementById("editorJava").codeMirror.clearGutter("issues");
18.183 - };
18.184 -
18.185 - $scope.fail = function( data ) {
18.186 - $scope.errors = eval( data );
18.187 - var editor = document.getElementById("editorJava").codeMirror;
18.188 - editor.clearGutter( "issues" );
18.189 -
18.190 - for( var i = 0; i < $scope.errors.length; i ++ ) {
18.191 - $scope.makeMarker( editor, $scope.errors[i].line - 1 );
18.192 - }
18.193 -
18.194 - };
18.195 -
18.196 - $scope.post = function() {
18.197 - return $http({url: ".",
18.198 - method: "POST",
18.199 - //headers: this.headers,
18.200 - data: { html : $scope.html, java : $scope.java}
18.201 - }).success( $scope.reload ).error( $scope.fail );
18.202 - };
18.203 -
18.204 - $scope.errorClass = function( kind ) {
18.205 - switch( kind ) {
18.206 - case "ERROR" :
18.207 - return "error";
18.208 - default :
18.209 - return "warning";
18.210 - }
18.211 - };
18.212 -
18.213 - $scope.gotoError = function( line, col ) {
18.214 - var editor = document.getElementById("editorJava").codeMirror;
18.215 - editor.setCursor({ line: line - 1, ch : col - 1 });
18.216 - editor.focus();
18.217 - };
18.218 -
18.219 - $scope.tab = "html";
18.220 - $scope.html= templateHtml;
18.221 - $scope.java = templateJava;
18.222 -
18.223 - $scope.$watch( "html", $scope.debounce( $scope.post, 2000 ) );
18.224 - $scope.$watch( "java", $scope.debounce( $scope.post, 2000 ) );
18.225 - $scope.post();
18.226 -
18.227 -}
19.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/codemirror.css Tue Apr 29 15:25:58 2014 +0200
19.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
19.3 @@ -1,239 +0,0 @@
19.4 -/* BASICS */
19.5 -
19.6 -.CodeMirror {
19.7 - /* Set height, width, borders, and global font properties here */
19.8 - font-family: monospace;
19.9 - height: 300px;
19.10 -}
19.11 -.CodeMirror-scroll {
19.12 - /* Set scrolling behaviour here */
19.13 - overflow: auto;
19.14 -}
19.15 -
19.16 -/* PADDING */
19.17 -
19.18 -.CodeMirror-lines {
19.19 - padding: 4px 0; /* Vertical padding around content */
19.20 -}
19.21 -.CodeMirror pre {
19.22 - padding: 0 4px; /* Horizontal padding of content */
19.23 -}
19.24 -
19.25 -.CodeMirror-scrollbar-filler {
19.26 - background-color: white; /* The little square between H and V scrollbars */
19.27 -}
19.28 -
19.29 -/* GUTTER */
19.30 -
19.31 -.CodeMirror-gutters {
19.32 - border-right: 1px solid #ddd;
19.33 - background-color: #f7f7f7;
19.34 -}
19.35 -.CodeMirror-linenumbers {}
19.36 -.CodeMirror-linenumber {
19.37 - padding: 0 3px 0 5px;
19.38 - min-width: 20px;
19.39 - text-align: right;
19.40 - color: #999;
19.41 -}
19.42 -
19.43 -/* CURSOR */
19.44 -
19.45 -.CodeMirror pre.CodeMirror-cursor {
19.46 - border-left: 1px solid black;
19.47 -}
19.48 -/* Shown when moving in bi-directional text */
19.49 -.CodeMirror pre.CodeMirror-secondarycursor {
19.50 - border-left: 1px solid silver;
19.51 -}
19.52 -.cm-keymap-fat-cursor pre.CodeMirror-cursor {
19.53 - width: auto;
19.54 - border: 0;
19.55 - background: transparent;
19.56 - background: rgba(0, 200, 0, .4);
19.57 - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800);
19.58 -}
19.59 -/* Kludge to turn off filter in ie9+, which also accepts rgba */
19.60 -.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) {
19.61 - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
19.62 -}
19.63 -/* Can style cursor different in overwrite (non-insert) mode */
19.64 -.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}
19.65 -
19.66 -/* DEFAULT THEME */
19.67 -
19.68 -.cm-s-default .cm-keyword {color: #708;}
19.69 -.cm-s-default .cm-atom {color: #219;}
19.70 -.cm-s-default .cm-number {color: #164;}
19.71 -.cm-s-default .cm-def {color: #00f;}
19.72 -.cm-s-default .cm-variable {color: black;}
19.73 -.cm-s-default .cm-variable-2 {color: #05a;}
19.74 -.cm-s-default .cm-variable-3 {color: #085;}
19.75 -.cm-s-default .cm-property {color: black;}
19.76 -.cm-s-default .cm-operator {color: black;}
19.77 -.cm-s-default .cm-comment {color: #a50;}
19.78 -.cm-s-default .cm-string {color: #a11;}
19.79 -.cm-s-default .cm-string-2 {color: #f50;}
19.80 -.cm-s-default .cm-meta {color: #555;}
19.81 -.cm-s-default .cm-error {color: #f00;}
19.82 -.cm-s-default .cm-qualifier {color: #555;}
19.83 -.cm-s-default .cm-builtin {color: #30a;}
19.84 -.cm-s-default .cm-bracket {color: #997;}
19.85 -.cm-s-default .cm-tag {color: #170;}
19.86 -.cm-s-default .cm-attribute {color: #00c;}
19.87 -.cm-s-default .cm-header {color: blue;}
19.88 -.cm-s-default .cm-quote {color: #090;}
19.89 -.cm-s-default .cm-hr {color: #999;}
19.90 -.cm-s-default .cm-link {color: #00c;}
19.91 -
19.92 -.cm-negative {color: #d44;}
19.93 -.cm-positive {color: #292;}
19.94 -.cm-header, .cm-strong {font-weight: bold;}
19.95 -.cm-em {font-style: italic;}
19.96 -.cm-emstrong {font-style: italic; font-weight: bold;}
19.97 -.cm-link {text-decoration: underline;}
19.98 -
19.99 -.cm-invalidchar {color: #f00;}
19.100 -
19.101 -div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
19.102 -div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
19.103 -
19.104 -/* STOP */
19.105 -
19.106 -/* The rest of this file contains styles related to the mechanics of
19.107 - the editor. You probably shouldn't touch them. */
19.108 -
19.109 -.CodeMirror {
19.110 - line-height: 1;
19.111 - position: relative;
19.112 - overflow: hidden;
19.113 -}
19.114 -
19.115 -.CodeMirror-scroll {
19.116 - /* 30px is the magic margin used to hide the element's real scrollbars */
19.117 - /* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */
19.118 - margin-bottom: -30px; margin-right: -30px;
19.119 - padding-bottom: 30px; padding-right: 30px;
19.120 - height: 100%;
19.121 - outline: none; /* Prevent dragging from highlighting the element */
19.122 - position: relative;
19.123 -}
19.124 -.CodeMirror-sizer {
19.125 - position: relative;
19.126 -}
19.127 -
19.128 -/* The fake, visible scrollbars. Used to force redraw during scrolling
19.129 - before actuall scrolling happens, thus preventing shaking and
19.130 - flickering artifacts. */
19.131 -.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler {
19.132 - position: absolute;
19.133 - z-index: 6;
19.134 - display: none;
19.135 -}
19.136 -.CodeMirror-vscrollbar {
19.137 - right: 0; top: 0;
19.138 - overflow-x: hidden;
19.139 - overflow-y: scroll;
19.140 -}
19.141 -.CodeMirror-hscrollbar {
19.142 - bottom: 0; left: 0;
19.143 - overflow-y: hidden;
19.144 - overflow-x: scroll;
19.145 -}
19.146 -.CodeMirror-scrollbar-filler {
19.147 - right: 0; bottom: 0;
19.148 - z-index: 6;
19.149 -}
19.150 -
19.151 -.CodeMirror-gutters {
19.152 - position: absolute; left: 0; top: 0;
19.153 - height: 100%;
19.154 - z-index: 3;
19.155 -}
19.156 -.CodeMirror-gutter {
19.157 - height: 100%;
19.158 - display: inline-block;
19.159 - /* Hack to make IE7 behave */
19.160 - *zoom:1;
19.161 - *display:inline;
19.162 -}
19.163 -.CodeMirror-gutter-elt {
19.164 - position: absolute;
19.165 - cursor: default;
19.166 - z-index: 4;
19.167 -}
19.168 -
19.169 -.CodeMirror-lines {
19.170 - cursor: text;
19.171 -}
19.172 -.CodeMirror pre {
19.173 - /* Reset some styles that the rest of the page might have set */
19.174 - -moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; border-radius: 0;
19.175 - border-width: 0;
19.176 - background: transparent;
19.177 - font-family: inherit;
19.178 - font-size: inherit;
19.179 - margin: 0;
19.180 - white-space: pre;
19.181 - word-wrap: normal;
19.182 - line-height: inherit;
19.183 - color: inherit;
19.184 - z-index: 2;
19.185 - position: relative;
19.186 - overflow: visible;
19.187 -}
19.188 -.CodeMirror-wrap pre {
19.189 - word-wrap: break-word;
19.190 - white-space: pre-wrap;
19.191 - word-break: normal;
19.192 -}
19.193 -.CodeMirror-linebackground {
19.194 - position: absolute;
19.195 - left: 0; right: 0; top: 0; bottom: 0;
19.196 - z-index: 0;
19.197 -}
19.198 -
19.199 -.CodeMirror-linewidget {
19.200 - position: relative;
19.201 - z-index: 2;
19.202 -}
19.203 -
19.204 -.CodeMirror-wrap .CodeMirror-scroll {
19.205 - overflow-x: hidden;
19.206 -}
19.207 -
19.208 -.CodeMirror-measure {
19.209 - position: absolute;
19.210 - width: 100%; height: 0px;
19.211 - overflow: hidden;
19.212 - visibility: hidden;
19.213 -}
19.214 -.CodeMirror-measure pre { position: static; }
19.215 -
19.216 -.CodeMirror pre.CodeMirror-cursor {
19.217 - position: absolute;
19.218 - visibility: hidden;
19.219 - border-right: none;
19.220 - width: 0;
19.221 -}
19.222 -.CodeMirror-focused pre.CodeMirror-cursor {
19.223 - visibility: visible;
19.224 -}
19.225 -
19.226 -.CodeMirror-selected { background: #d9d9d9; }
19.227 -.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
19.228 -
19.229 -.CodeMirror-searching {
19.230 - background: #ffa;
19.231 - background: rgba(255, 255, 0, .4);
19.232 -}
19.233 -
19.234 -/* IE7 hack to prevent it from returning funny offsetTops on the spans */
19.235 -.CodeMirror span { *vertical-align: text-bottom; }
19.236 -
19.237 -@media print {
19.238 - /* Hide the cursor when printing */
19.239 - .CodeMirror pre.CodeMirror-cursor {
19.240 - visibility: hidden;
19.241 - }
19.242 -}
20.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/codemirror.js Tue Apr 29 15:25:58 2014 +0200
20.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
20.3 @@ -1,4553 +0,0 @@
20.4 -// CodeMirror version 3.0
20.5 -//
20.6 -// CodeMirror is the only global var we claim
20.7 -window.CodeMirror = (function() {
20.8 - "use strict";
20.9 -
20.10 - // BROWSER SNIFFING
20.11 -
20.12 - // Crude, but necessary to handle a number of hard-to-feature-detect
20.13 - // bugs and behavior differences.
20.14 - var gecko = /gecko\/\d/i.test(navigator.userAgent);
20.15 - var ie = /MSIE \d/.test(navigator.userAgent);
20.16 - var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
20.17 - var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
20.18 - var webkit = /WebKit\//.test(navigator.userAgent);
20.19 - var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
20.20 - var chrome = /Chrome\//.test(navigator.userAgent);
20.21 - var opera = /Opera\//.test(navigator.userAgent);
20.22 - var safari = /Apple Computer/.test(navigator.vendor);
20.23 - var khtml = /KHTML\//.test(navigator.userAgent);
20.24 - var mac_geLion = /Mac OS X 1\d\D([7-9]|\d\d)\D/.test(navigator.userAgent);
20.25 - var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
20.26 - var phantom = /PhantomJS/.test(navigator.userAgent);
20.27 -
20.28 - var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
20.29 - // This is woefully incomplete. Suggestions for alternative methods welcome.
20.30 - var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|IEMobile/i.test(navigator.userAgent);
20.31 - var mac = ios || /Mac/.test(navigator.platform);
20.32 -
20.33 - // Optimize some code when these features are not used
20.34 - var sawReadOnlySpans = false, sawCollapsedSpans = false;
20.35 -
20.36 - // CONSTRUCTOR
20.37 -
20.38 - function CodeMirror(place, options) {
20.39 - if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
20.40 -
20.41 - this.options = options = options || {};
20.42 - // Determine effective options based on given values and defaults.
20.43 - for (var opt in defaults) if (!options.hasOwnProperty(opt) && defaults.hasOwnProperty(opt))
20.44 - options[opt] = defaults[opt];
20.45 - setGuttersForLineNumbers(options);
20.46 -
20.47 - var display = this.display = makeDisplay(place);
20.48 - display.wrapper.CodeMirror = this;
20.49 - updateGutters(this);
20.50 - if (options.autofocus && !mobile) focusInput(this);
20.51 -
20.52 - this.view = makeView(new BranchChunk([new LeafChunk([makeLine("", null, textHeight(display))])]));
20.53 - this.nextOpId = 0;
20.54 - loadMode(this);
20.55 - themeChanged(this);
20.56 - if (options.lineWrapping)
20.57 - this.display.wrapper.className += " CodeMirror-wrap";
20.58 -
20.59 - // Initialize the content.
20.60 - this.setValue(options.value || "");
20.61 - // Override magic textarea content restore that IE sometimes does
20.62 - // on our hidden textarea on reload
20.63 - if (ie) setTimeout(bind(resetInput, this, true), 20);
20.64 - this.view.history = makeHistory();
20.65 -
20.66 - registerEventHandlers(this);
20.67 - // IE throws unspecified error in certain cases, when
20.68 - // trying to access activeElement before onload
20.69 - var hasFocus; try { hasFocus = (document.activeElement == display.input); } catch(e) { }
20.70 - if (hasFocus || (options.autofocus && !mobile)) setTimeout(bind(onFocus, this), 20);
20.71 - else onBlur(this);
20.72 -
20.73 - operation(this, function() {
20.74 - for (var opt in optionHandlers)
20.75 - if (optionHandlers.propertyIsEnumerable(opt))
20.76 - optionHandlers[opt](this, options[opt], Init);
20.77 - for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
20.78 - })();
20.79 - }
20.80 -
20.81 - // DISPLAY CONSTRUCTOR
20.82 -
20.83 - function makeDisplay(place) {
20.84 - var d = {};
20.85 - var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none;");
20.86 - input.setAttribute("wrap", "off"); input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off");
20.87 - // Wraps and hides input textarea
20.88 - d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
20.89 - // The actual fake scrollbars.
20.90 - d.scrollbarH = elt("div", [elt("div", null, null, "height: 1px")], "CodeMirror-hscrollbar");
20.91 - d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirror-vscrollbar");
20.92 - d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
20.93 - // DIVs containing the selection and the actual code
20.94 - d.lineDiv = elt("div");
20.95 - d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
20.96 - // Blinky cursor, and element used to ensure cursor fits at the end of a line
20.97 - d.cursor = elt("pre", "\u00a0", "CodeMirror-cursor");
20.98 - // Secondary cursor, shown when on a 'jump' in bi-directional text
20.99 - d.otherCursor = elt("pre", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor");
20.100 - // Used to measure text size
20.101 - d.measure = elt("div", null, "CodeMirror-measure");
20.102 - // Wraps everything that needs to exist inside the vertically-padded coordinate system
20.103 - d.lineSpace = elt("div", [d.measure, d.selectionDiv, d.lineDiv, d.cursor, d.otherCursor],
20.104 - null, "position: relative; outline: none");
20.105 - // Moved around its parent to cover visible view
20.106 - d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
20.107 - // Set to the height of the text, causes scrolling
20.108 - d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
20.109 - // D is needed because behavior of elts with overflow: auto and padding is inconsistent across browsers
20.110 - d.heightForcer = elt("div", "\u00a0", null, "position: absolute; height: " + scrollerCutOff + "px");
20.111 - // Will contain the gutters, if any
20.112 - d.gutters = elt("div", null, "CodeMirror-gutters");
20.113 - d.lineGutter = null;
20.114 - // Helper element to properly size the gutter backgrounds
20.115 - var scrollerInner = elt("div", [d.sizer, d.heightForcer, d.gutters], null, "position: relative; min-height: 100%");
20.116 - // Provides scrolling
20.117 - d.scroller = elt("div", [scrollerInner], "CodeMirror-scroll");
20.118 - d.scroller.setAttribute("tabIndex", "-1");
20.119 - // The element in which the editor lives.
20.120 - d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
20.121 - d.scrollbarFiller, d.scroller], "CodeMirror");
20.122 - // Work around IE7 z-index bug
20.123 - if (ie_lt8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
20.124 - if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper);
20.125 -
20.126 - // Needed to hide big blue blinking cursor on Mobile Safari
20.127 - if (ios) input.style.width = "0px";
20.128 - if (!webkit) d.scroller.draggable = true;
20.129 - // Needed to handle Tab key in KHTML
20.130 - if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
20.131 - // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
20.132 - else if (ie_lt8) d.scrollbarH.style.minWidth = d.scrollbarV.style.minWidth = "18px";
20.133 -
20.134 - // Current visible range (may be bigger than the view window).
20.135 - d.viewOffset = d.showingFrom = d.showingTo = d.lastSizeC = 0;
20.136 -
20.137 - // Used to only resize the line number gutter when necessary (when
20.138 - // the amount of lines crosses a boundary that makes its width change)
20.139 - d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
20.140 - // See readInput and resetInput
20.141 - d.prevInput = "";
20.142 - // Set to true when a non-horizontal-scrolling widget is added. As
20.143 - // an optimization, widget aligning is skipped when d is false.
20.144 - d.alignWidgets = false;
20.145 - // Flag that indicates whether we currently expect input to appear
20.146 - // (after some event like 'keypress' or 'input') and are polling
20.147 - // intensively.
20.148 - d.pollingFast = false;
20.149 - // Self-resetting timeout for the poller
20.150 - d.poll = new Delayed();
20.151 - // True when a drag from the editor is active
20.152 - d.draggingText = false;
20.153 -
20.154 - d.cachedCharWidth = d.cachedTextHeight = null;
20.155 - d.measureLineCache = [];
20.156 - d.measureLineCachePos = 0;
20.157 -
20.158 - // Tracks when resetInput has punted to just putting a short
20.159 - // string instead of the (large) selection.
20.160 - d.inaccurateSelection = false;
20.161 -
20.162 - // Used to adjust overwrite behaviour when a paste has been
20.163 - // detected
20.164 - d.pasteIncoming = false;
20.165 -
20.166 - return d;
20.167 - }
20.168 -
20.169 - // VIEW CONSTRUCTOR
20.170 -
20.171 - function makeView(doc) {
20.172 - var selPos = {line: 0, ch: 0};
20.173 - return {
20.174 - doc: doc,
20.175 - // frontier is the point up to which the content has been parsed,
20.176 - frontier: 0, highlight: new Delayed(),
20.177 - sel: {from: selPos, to: selPos, head: selPos, anchor: selPos, shift: false, extend: false},
20.178 - scrollTop: 0, scrollLeft: 0,
20.179 - overwrite: false, focused: false,
20.180 - // Tracks the maximum line length so that
20.181 - // the horizontal scrollbar can be kept
20.182 - // static when scrolling.
20.183 - maxLine: getLine(doc, 0),
20.184 - maxLineLength: 0,
20.185 - maxLineChanged: false,
20.186 - suppressEdits: false,
20.187 - goalColumn: null,
20.188 - cantEdit: false,
20.189 - keyMaps: []
20.190 - };
20.191 - }
20.192 -
20.193 - // STATE UPDATES
20.194 -
20.195 - // Used to get the editor into a consistent state again when options change.
20.196 -
20.197 - function loadMode(cm) {
20.198 - var doc = cm.view.doc;
20.199 - cm.view.mode = CodeMirror.getMode(cm.options, cm.options.mode);
20.200 - doc.iter(0, doc.size, function(line) { line.stateAfter = null; });
20.201 - cm.view.frontier = 0;
20.202 - startWorker(cm, 100);
20.203 - }
20.204 -
20.205 - function wrappingChanged(cm) {
20.206 - var doc = cm.view.doc, th = textHeight(cm.display);
20.207 - if (cm.options.lineWrapping) {
20.208 - cm.display.wrapper.className += " CodeMirror-wrap";
20.209 - var perLine = cm.display.scroller.clientWidth / charWidth(cm.display) - 3;
20.210 - doc.iter(0, doc.size, function(line) {
20.211 - if (line.height == 0) return;
20.212 - var guess = Math.ceil(line.text.length / perLine) || 1;
20.213 - if (guess != 1) updateLineHeight(line, guess * th);
20.214 - });
20.215 - cm.display.sizer.style.minWidth = "";
20.216 - } else {
20.217 - cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-wrap", "");
20.218 - computeMaxLength(cm.view);
20.219 - doc.iter(0, doc.size, function(line) {
20.220 - if (line.height != 0) updateLineHeight(line, th);
20.221 - });
20.222 - }
20.223 - regChange(cm, 0, doc.size);
20.224 - clearCaches(cm);
20.225 - setTimeout(function(){updateScrollbars(cm.display, cm.view.doc.height);}, 100);
20.226 - }
20.227 -
20.228 - function keyMapChanged(cm) {
20.229 - var style = keyMap[cm.options.keyMap].style;
20.230 - cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
20.231 - (style ? " cm-keymap-" + style : "");
20.232 - }
20.233 -
20.234 - function themeChanged(cm) {
20.235 - cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
20.236 - cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
20.237 - clearCaches(cm);
20.238 - }
20.239 -
20.240 - function guttersChanged(cm) {
20.241 - updateGutters(cm);
20.242 - updateDisplay(cm, true);
20.243 - }
20.244 -
20.245 - function updateGutters(cm) {
20.246 - var gutters = cm.display.gutters, specs = cm.options.gutters;
20.247 - removeChildren(gutters);
20.248 - for (var i = 0; i < specs.length; ++i) {
20.249 - var gutterClass = specs[i];
20.250 - var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
20.251 - if (gutterClass == "CodeMirror-linenumbers") {
20.252 - cm.display.lineGutter = gElt;
20.253 - gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
20.254 - }
20.255 - }
20.256 - gutters.style.display = i ? "" : "none";
20.257 - }
20.258 -
20.259 - function lineLength(doc, line) {
20.260 - if (line.height == 0) return 0;
20.261 - var len = line.text.length, merged, cur = line;
20.262 - while (merged = collapsedSpanAtStart(cur)) {
20.263 - var found = merged.find();
20.264 - cur = getLine(doc, found.from.line);
20.265 - len += found.from.ch - found.to.ch;
20.266 - }
20.267 - cur = line;
20.268 - while (merged = collapsedSpanAtEnd(cur)) {
20.269 - var found = merged.find();
20.270 - len -= cur.text.length - found.from.ch;
20.271 - cur = getLine(doc, found.to.line);
20.272 - len += cur.text.length - found.to.ch;
20.273 - }
20.274 - return len;
20.275 - }
20.276 -
20.277 - function computeMaxLength(view) {
20.278 - view.maxLine = getLine(view.doc, 0);
20.279 - view.maxLineLength = lineLength(view.doc, view.maxLine);
20.280 - view.maxLineChanged = true;
20.281 - view.doc.iter(1, view.doc.size, function(line) {
20.282 - var len = lineLength(view.doc, line);
20.283 - if (len > view.maxLineLength) {
20.284 - view.maxLineLength = len;
20.285 - view.maxLine = line;
20.286 - }
20.287 - });
20.288 - }
20.289 -
20.290 - // Make sure the gutters options contains the element
20.291 - // "CodeMirror-linenumbers" when the lineNumbers option is true.
20.292 - function setGuttersForLineNumbers(options) {
20.293 - var found = false;
20.294 - for (var i = 0; i < options.gutters.length; ++i) {
20.295 - if (options.gutters[i] == "CodeMirror-linenumbers") {
20.296 - if (options.lineNumbers) found = true;
20.297 - else options.gutters.splice(i--, 1);
20.298 - }
20.299 - }
20.300 - if (!found && options.lineNumbers)
20.301 - options.gutters.push("CodeMirror-linenumbers");
20.302 - }
20.303 -
20.304 - // SCROLLBARS
20.305 -
20.306 - // Re-synchronize the fake scrollbars with the actual size of the
20.307 - // content. Optionally force a scrollTop.
20.308 - function updateScrollbars(d /* display */, docHeight) {
20.309 - var totalHeight = docHeight + 2 * paddingTop(d);
20.310 - d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px";
20.311 - var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight);
20.312 - var needsH = d.scroller.scrollWidth > d.scroller.clientWidth;
20.313 - var needsV = scrollHeight > d.scroller.clientHeight;
20.314 - if (needsV) {
20.315 - d.scrollbarV.style.display = "block";
20.316 - d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0";
20.317 - d.scrollbarV.firstChild.style.height =
20.318 - (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "px";
20.319 - } else d.scrollbarV.style.display = "";
20.320 - if (needsH) {
20.321 - d.scrollbarH.style.display = "block";
20.322 - d.scrollbarH.style.right = needsV ? scrollbarWidth(d.measure) + "px" : "0";
20.323 - d.scrollbarH.firstChild.style.width =
20.324 - (d.scroller.scrollWidth - d.scroller.clientWidth + d.scrollbarH.clientWidth) + "px";
20.325 - } else d.scrollbarH.style.display = "";
20.326 - if (needsH && needsV) {
20.327 - d.scrollbarFiller.style.display = "block";
20.328 - d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + "px";
20.329 - } else d.scrollbarFiller.style.display = "";
20.330 -
20.331 - if (mac_geLion && scrollbarWidth(d.measure) === 0)
20.332 - d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px";
20.333 - }
20.334 -
20.335 - function visibleLines(display, doc, viewPort) {
20.336 - var top = display.scroller.scrollTop, height = display.wrapper.clientHeight;
20.337 - if (typeof viewPort == "number") top = viewPort;
20.338 - else if (viewPort) {top = viewPort.top; height = viewPort.bottom - viewPort.top;}
20.339 - top = Math.floor(top - paddingTop(display));
20.340 - var bottom = Math.ceil(top + height);
20.341 - return {from: lineAtHeight(doc, top), to: lineAtHeight(doc, bottom)};
20.342 - }
20.343 -
20.344 - // LINE NUMBERS
20.345 -
20.346 - function alignHorizontally(cm) {
20.347 - var display = cm.display;
20.348 - if (!display.alignWidgets && !display.gutters.firstChild) return;
20.349 - var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.view.scrollLeft;
20.350 - var gutterW = display.gutters.offsetWidth, l = comp + "px";
20.351 - for (var n = display.lineDiv.firstChild; n; n = n.nextSibling) if (n.alignable) {
20.352 - for (var i = 0, a = n.alignable; i < a.length; ++i) a[i].style.left = l;
20.353 - }
20.354 - display.gutters.style.left = (comp + gutterW) + "px";
20.355 - }
20.356 -
20.357 - function maybeUpdateLineNumberWidth(cm) {
20.358 - if (!cm.options.lineNumbers) return false;
20.359 - var doc = cm.view.doc, last = lineNumberFor(cm.options, doc.size - 1), display = cm.display;
20.360 - if (last.length != display.lineNumChars) {
20.361 - var test = display.measure.appendChild(elt("div", [elt("div", last)],
20.362 - "CodeMirror-linenumber CodeMirror-gutter-elt"));
20.363 - var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
20.364 - display.lineGutter.style.width = "";
20.365 - display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding);
20.366 - display.lineNumWidth = display.lineNumInnerWidth + padding;
20.367 - display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
20.368 - display.lineGutter.style.width = display.lineNumWidth + "px";
20.369 - return true;
20.370 - }
20.371 - return false;
20.372 - }
20.373 -
20.374 - function lineNumberFor(options, i) {
20.375 - return String(options.lineNumberFormatter(i + options.firstLineNumber));
20.376 - }
20.377 - function compensateForHScroll(display) {
20.378 - return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
20.379 - }
20.380 -
20.381 - // DISPLAY DRAWING
20.382 -
20.383 - function updateDisplay(cm, changes, viewPort) {
20.384 - var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo;
20.385 - var updated = updateDisplayInner(cm, changes, viewPort);
20.386 - if (updated) {
20.387 - signalLater(cm, cm, "update", cm);
20.388 - if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo)
20.389 - signalLater(cm, cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo);
20.390 - }
20.391 - updateSelection(cm);
20.392 - updateScrollbars(cm.display, cm.view.doc.height);
20.393 -
20.394 - return updated;
20.395 - }
20.396 -
20.397 - // Uses a set of changes plus the current scroll position to
20.398 - // determine which DOM updates have to be made, and makes the
20.399 - // updates.
20.400 - function updateDisplayInner(cm, changes, viewPort) {
20.401 - var display = cm.display, doc = cm.view.doc;
20.402 - if (!display.wrapper.clientWidth) {
20.403 - display.showingFrom = display.showingTo = display.viewOffset = 0;
20.404 - return;
20.405 - }
20.406 -
20.407 - // Compute the new visible window
20.408 - // If scrollTop is specified, use that to determine which lines
20.409 - // to render instead of the current scrollbar position.
20.410 - var visible = visibleLines(display, doc, viewPort);
20.411 - // Bail out if the visible area is already rendered and nothing changed.
20.412 - if (changes !== true && changes.length == 0 &&
20.413 - visible.from > display.showingFrom && visible.to < display.showingTo)
20.414 - return;
20.415 -
20.416 - if (changes && maybeUpdateLineNumberWidth(cm))
20.417 - changes = true;
20.418 - display.sizer.style.marginLeft = display.scrollbarH.style.left = display.gutters.offsetWidth + "px";
20.419 -
20.420 - // When merged lines are present, the line that needs to be
20.421 - // redrawn might not be the one that was changed.
20.422 - if (changes !== true && sawCollapsedSpans)
20.423 - for (var i = 0; i < changes.length; ++i) {
20.424 - var ch = changes[i], merged;
20.425 - while (merged = collapsedSpanAtStart(getLine(doc, ch.from))) {
20.426 - var from = merged.find().from.line;
20.427 - if (ch.diff) ch.diff -= ch.from - from;
20.428 - ch.from = from;
20.429 - }
20.430 - }
20.431 -
20.432 - // Used to determine which lines need their line numbers updated
20.433 - var positionsChangedFrom = changes === true ? 0 : Infinity;
20.434 - if (cm.options.lineNumbers && changes && changes !== true)
20.435 - for (var i = 0; i < changes.length; ++i)
20.436 - if (changes[i].diff) { positionsChangedFrom = changes[i].from; break; }
20.437 -
20.438 - var from = Math.max(visible.from - cm.options.viewportMargin, 0);
20.439 - var to = Math.min(doc.size, visible.to + cm.options.viewportMargin);
20.440 - if (display.showingFrom < from && from - display.showingFrom < 20) from = display.showingFrom;
20.441 - if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(doc.size, display.showingTo);
20.442 - if (sawCollapsedSpans) {
20.443 - from = lineNo(visualLine(doc, getLine(doc, from)));
20.444 - while (to < doc.size && lineIsHidden(getLine(doc, to))) ++to;
20.445 - }
20.446 -
20.447 - // Create a range of theoretically intact lines, and punch holes
20.448 - // in that using the change info.
20.449 - var intact = changes === true ? [] :
20.450 - computeIntact([{from: display.showingFrom, to: display.showingTo}], changes);
20.451 - // Clip off the parts that won't be visible
20.452 - var intactLines = 0;
20.453 - for (var i = 0; i < intact.length; ++i) {
20.454 - var range = intact[i];
20.455 - if (range.from < from) range.from = from;
20.456 - if (range.to > to) range.to = to;
20.457 - if (range.from >= range.to) intact.splice(i--, 1);
20.458 - else intactLines += range.to - range.from;
20.459 - }
20.460 - if (intactLines == to - from && from == display.showingFrom && to == display.showingTo)
20.461 - return;
20.462 - intact.sort(function(a, b) {return a.from - b.from;});
20.463 -
20.464 - if (intactLines < (to - from) * .7) display.lineDiv.style.display = "none";
20.465 - patchDisplay(cm, from, to, intact, positionsChangedFrom);
20.466 - display.lineDiv.style.display = "";
20.467 -
20.468 - var different = from != display.showingFrom || to != display.showingTo ||
20.469 - display.lastSizeC != display.wrapper.clientHeight;
20.470 - // This is just a bogus formula that detects when the editor is
20.471 - // resized or the font size changes.
20.472 - if (different) display.lastSizeC = display.wrapper.clientHeight;
20.473 - display.showingFrom = from; display.showingTo = to;
20.474 - startWorker(cm, 100);
20.475 -
20.476 - var prevBottom = display.lineDiv.offsetTop;
20.477 - for (var node = display.lineDiv.firstChild, height; node; node = node.nextSibling) if (node.lineObj) {
20.478 - if (ie_lt8) {
20.479 - var bot = node.offsetTop + node.offsetHeight;
20.480 - height = bot - prevBottom;
20.481 - prevBottom = bot;
20.482 - } else {
20.483 - var box = node.getBoundingClientRect();
20.484 - height = box.bottom - box.top;
20.485 - }
20.486 - var diff = node.lineObj.height - height;
20.487 - if (height < 2) height = textHeight(display);
20.488 - if (diff > .001 || diff < -.001)
20.489 - updateLineHeight(node.lineObj, height);
20.490 - }
20.491 - display.viewOffset = heightAtLine(cm, getLine(doc, from));
20.492 - // Position the mover div to align with the current virtual scroll position
20.493 - display.mover.style.top = display.viewOffset + "px";
20.494 - return true;
20.495 - }
20.496 -
20.497 - function computeIntact(intact, changes) {
20.498 - for (var i = 0, l = changes.length || 0; i < l; ++i) {
20.499 - var change = changes[i], intact2 = [], diff = change.diff || 0;
20.500 - for (var j = 0, l2 = intact.length; j < l2; ++j) {
20.501 - var range = intact[j];
20.502 - if (change.to <= range.from && change.diff) {
20.503 - intact2.push({from: range.from + diff, to: range.to + diff});
20.504 - } else if (change.to <= range.from || change.from >= range.to) {
20.505 - intact2.push(range);
20.506 - } else {
20.507 - if (change.from > range.from)
20.508 - intact2.push({from: range.from, to: change.from});
20.509 - if (change.to < range.to)
20.510 - intact2.push({from: change.to + diff, to: range.to + diff});
20.511 - }
20.512 - }
20.513 - intact = intact2;
20.514 - }
20.515 - return intact;
20.516 - }
20.517 -
20.518 - function getDimensions(cm) {
20.519 - var d = cm.display, left = {}, width = {};
20.520 - for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
20.521 - left[cm.options.gutters[i]] = n.offsetLeft;
20.522 - width[cm.options.gutters[i]] = n.offsetWidth;
20.523 - }
20.524 - return {fixedPos: compensateForHScroll(d),
20.525 - gutterTotalWidth: d.gutters.offsetWidth,
20.526 - gutterLeft: left,
20.527 - gutterWidth: width,
20.528 - wrapperWidth: d.wrapper.clientWidth};
20.529 - }
20.530 -
20.531 - function patchDisplay(cm, from, to, intact, updateNumbersFrom) {
20.532 - var dims = getDimensions(cm);
20.533 - var display = cm.display, lineNumbers = cm.options.lineNumbers;
20.534 - // IE does bad things to nodes when .innerHTML = "" is used on a parent
20.535 - // we still need widgets and markers intact to add back to the new content later
20.536 - if (!intact.length && !ie && (!webkit || !cm.display.currentWheelTarget))
20.537 - removeChildren(display.lineDiv);
20.538 - var container = display.lineDiv, cur = container.firstChild;
20.539 -
20.540 - function rm(node) {
20.541 - var next = node.nextSibling;
20.542 - if (webkit && mac && cm.display.currentWheelTarget == node) {
20.543 - node.style.display = "none";
20.544 - node.lineObj = null;
20.545 - } else {
20.546 - container.removeChild(node);
20.547 - }
20.548 - return next;
20.549 - }
20.550 -
20.551 - var nextIntact = intact.shift(), lineNo = from;
20.552 - cm.view.doc.iter(from, to, function(line) {
20.553 - if (nextIntact && nextIntact.to == lineNo) nextIntact = intact.shift();
20.554 - if (lineIsHidden(line)) {
20.555 - if (line.height != 0) updateLineHeight(line, 0);
20.556 - } else if (nextIntact && nextIntact.from <= lineNo && nextIntact.to > lineNo) {
20.557 - // This line is intact. Skip to the actual node. Update its
20.558 - // line number if needed.
20.559 - while (cur.lineObj != line) cur = rm(cur);
20.560 - if (lineNumbers && updateNumbersFrom <= lineNo && cur.lineNumber)
20.561 - setTextContent(cur.lineNumber, lineNumberFor(cm.options, lineNo));
20.562 - cur = cur.nextSibling;
20.563 - } else {
20.564 - // This line needs to be generated.
20.565 - var lineNode = buildLineElement(cm, line, lineNo, dims);
20.566 - container.insertBefore(lineNode, cur);
20.567 - lineNode.lineObj = line;
20.568 - }
20.569 - ++lineNo;
20.570 - });
20.571 - while (cur) cur = rm(cur);
20.572 - }
20.573 -
20.574 - function buildLineElement(cm, line, lineNo, dims) {
20.575 - var lineElement = lineContent(cm, line);
20.576 - var markers = line.gutterMarkers, display = cm.display;
20.577 -
20.578 - if (!cm.options.lineNumbers && !markers && !line.bgClass && !line.wrapClass &&
20.579 - (!line.widgets || !line.widgets.length)) return lineElement;
20.580 -
20.581 - // Lines with gutter elements or a background class need
20.582 - // to be wrapped again, and have the extra elements added
20.583 - // to the wrapper div
20.584 -
20.585 - var wrap = elt("div", null, line.wrapClass, "position: relative");
20.586 - if (cm.options.lineNumbers || markers) {
20.587 - var gutterWrap = wrap.appendChild(elt("div", null, null, "position: absolute; left: " +
20.588 - dims.fixedPos + "px"));
20.589 - wrap.alignable = [gutterWrap];
20.590 - if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
20.591 - wrap.lineNumber = gutterWrap.appendChild(
20.592 - elt("div", lineNumberFor(cm.options, lineNo),
20.593 - "CodeMirror-linenumber CodeMirror-gutter-elt",
20.594 - "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
20.595 - + display.lineNumInnerWidth + "px"));
20.596 - if (markers)
20.597 - for (var k = 0; k < cm.options.gutters.length; ++k) {
20.598 - var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
20.599 - if (found)
20.600 - gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
20.601 - dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
20.602 - }
20.603 - }
20.604 - // Kludge to make sure the styled element lies behind the selection (by z-index)
20.605 - if (line.bgClass)
20.606 - wrap.appendChild(elt("div", "\u00a0", line.bgClass + " CodeMirror-linebackground"));
20.607 - wrap.appendChild(lineElement);
20.608 - if (line.widgets)
20.609 - for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
20.610 - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
20.611 - node.widget = widget;
20.612 - if (widget.noHScroll) {
20.613 - (wrap.alignable || (wrap.alignable = [])).push(node);
20.614 - var width = dims.wrapperWidth;
20.615 - node.style.left = dims.fixedPos + "px";
20.616 - if (!widget.coverGutter) {
20.617 - width -= dims.gutterTotalWidth;
20.618 - node.style.paddingLeft = dims.gutterTotalWidth + "px";
20.619 - }
20.620 - node.style.width = width + "px";
20.621 - }
20.622 - if (widget.coverGutter) {
20.623 - node.style.zIndex = 5;
20.624 - node.style.position = "relative";
20.625 - if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
20.626 - }
20.627 - if (widget.above)
20.628 - wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement);
20.629 - else
20.630 - wrap.appendChild(node);
20.631 - }
20.632 -
20.633 - if (ie_lt8) wrap.style.zIndex = 2;
20.634 - return wrap;
20.635 - }
20.636 -
20.637 - // SELECTION / CURSOR
20.638 -
20.639 - function updateSelection(cm) {
20.640 - var display = cm.display;
20.641 - var collapsed = posEq(cm.view.sel.from, cm.view.sel.to);
20.642 - if (collapsed || cm.options.showCursorWhenSelecting)
20.643 - updateSelectionCursor(cm);
20.644 - else
20.645 - display.cursor.style.display = display.otherCursor.style.display = "none";
20.646 - if (!collapsed)
20.647 - updateSelectionRange(cm);
20.648 - else
20.649 - display.selectionDiv.style.display = "none";
20.650 -
20.651 - // Move the hidden textarea near the cursor to prevent scrolling artifacts
20.652 - var headPos = cursorCoords(cm, cm.view.sel.head, "div");
20.653 - var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
20.654 - display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
20.655 - headPos.top + lineOff.top - wrapOff.top)) + "px";
20.656 - display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
20.657 - headPos.left + lineOff.left - wrapOff.left)) + "px";
20.658 - }
20.659 -
20.660 - // No selection, plain cursor
20.661 - function updateSelectionCursor(cm) {
20.662 - var display = cm.display, pos = cursorCoords(cm, cm.view.sel.head, "div");
20.663 - display.cursor.style.left = pos.left + "px";
20.664 - display.cursor.style.top = pos.top + "px";
20.665 - display.cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
20.666 - display.cursor.style.display = "";
20.667 -
20.668 - if (pos.other) {
20.669 - display.otherCursor.style.display = "";
20.670 - display.otherCursor.style.left = pos.other.left + "px";
20.671 - display.otherCursor.style.top = pos.other.top + "px";
20.672 - display.otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
20.673 - } else { display.otherCursor.style.display = "none"; }
20.674 - }
20.675 -
20.676 - // Highlight selection
20.677 - function updateSelectionRange(cm) {
20.678 - var display = cm.display, doc = cm.view.doc, sel = cm.view.sel;
20.679 - var fragment = document.createDocumentFragment();
20.680 - var clientWidth = display.lineSpace.offsetWidth, pl = paddingLeft(cm.display);
20.681 -
20.682 - function add(left, top, width, bottom) {
20.683 - if (top < 0) top = 0;
20.684 - fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
20.685 - "px; top: " + top + "px; width: " + (width == null ? clientWidth - left : width) +
20.686 - "px; height: " + (bottom - top) + "px"));
20.687 - }
20.688 -
20.689 - function drawForLine(line, fromArg, toArg, retTop) {
20.690 - var lineObj = getLine(doc, line);
20.691 - var lineLen = lineObj.text.length, rVal = retTop ? Infinity : -Infinity;
20.692 - function coords(ch) {
20.693 - return charCoords(cm, {line: line, ch: ch}, "div", lineObj);
20.694 - }
20.695 -
20.696 - iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
20.697 - var leftPos = coords(dir == "rtl" ? to - 1 : from);
20.698 - var rightPos = coords(dir == "rtl" ? from : to - 1);
20.699 - var left = leftPos.left, right = rightPos.right;
20.700 - if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
20.701 - add(left, leftPos.top, null, leftPos.bottom);
20.702 - left = pl;
20.703 - if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
20.704 - }
20.705 - if (toArg == null && to == lineLen) right = clientWidth;
20.706 - if (fromArg == null && from == 0) left = pl;
20.707 - rVal = retTop ? Math.min(rightPos.top, rVal) : Math.max(rightPos.bottom, rVal);
20.708 - if (left < pl + 1) left = pl;
20.709 - add(left, rightPos.top, right - left, rightPos.bottom);
20.710 - });
20.711 - return rVal;
20.712 - }
20.713 -
20.714 - if (sel.from.line == sel.to.line) {
20.715 - drawForLine(sel.from.line, sel.from.ch, sel.to.ch);
20.716 - } else {
20.717 - var fromObj = getLine(doc, sel.from.line);
20.718 - var cur = fromObj, merged, path = [sel.from.line, sel.from.ch], singleLine;
20.719 - while (merged = collapsedSpanAtEnd(cur)) {
20.720 - var found = merged.find();
20.721 - path.push(found.from.ch, found.to.line, found.to.ch);
20.722 - if (found.to.line == sel.to.line) {
20.723 - path.push(sel.to.ch);
20.724 - singleLine = true;
20.725 - break;
20.726 - }
20.727 - cur = getLine(doc, found.to.line);
20.728 - }
20.729 -
20.730 - // This is a single, merged line
20.731 - if (singleLine) {
20.732 - for (var i = 0; i < path.length; i += 3)
20.733 - drawForLine(path[i], path[i+1], path[i+2]);
20.734 - } else {
20.735 - var middleTop, middleBot, toObj = getLine(doc, sel.to.line);
20.736 - if (sel.from.ch)
20.737 - // Draw the first line of selection.
20.738 - middleTop = drawForLine(sel.from.line, sel.from.ch, null, false);
20.739 - else
20.740 - // Simply include it in the middle block.
20.741 - middleTop = heightAtLine(cm, fromObj) - display.viewOffset;
20.742 -
20.743 - if (!sel.to.ch)
20.744 - middleBot = heightAtLine(cm, toObj) - display.viewOffset;
20.745 - else
20.746 - middleBot = drawForLine(sel.to.line, collapsedSpanAtStart(toObj) ? null : 0, sel.to.ch, true);
20.747 -
20.748 - if (middleTop < middleBot) add(pl, middleTop, null, middleBot);
20.749 - }
20.750 - }
20.751 -
20.752 - removeChildrenAndAdd(display.selectionDiv, fragment);
20.753 - display.selectionDiv.style.display = "";
20.754 - }
20.755 -
20.756 - // Cursor-blinking
20.757 - function restartBlink(cm) {
20.758 - var display = cm.display;
20.759 - clearInterval(display.blinker);
20.760 - var on = true;
20.761 - display.cursor.style.visibility = display.otherCursor.style.visibility = "";
20.762 - display.blinker = setInterval(function() {
20.763 - if (!display.cursor.offsetHeight) return;
20.764 - display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? "" : "hidden";
20.765 - }, cm.options.cursorBlinkRate);
20.766 - }
20.767 -
20.768 - // HIGHLIGHT WORKER
20.769 -
20.770 - function startWorker(cm, time) {
20.771 - if (cm.view.frontier < cm.display.showingTo)
20.772 - cm.view.highlight.set(time, bind(highlightWorker, cm));
20.773 - }
20.774 -
20.775 - function highlightWorker(cm) {
20.776 - var view = cm.view, doc = view.doc;
20.777 - if (view.frontier >= cm.display.showingTo) return;
20.778 - var end = +new Date + cm.options.workTime;
20.779 - var state = copyState(view.mode, getStateBefore(cm, view.frontier));
20.780 - var changed = [], prevChange;
20.781 - doc.iter(view.frontier, Math.min(doc.size, cm.display.showingTo + 500), function(line) {
20.782 - if (view.frontier >= cm.display.showingFrom) { // Visible
20.783 - if (highlightLine(cm, line, state) && view.frontier >= cm.display.showingFrom) {
20.784 - if (prevChange && prevChange.end == view.frontier) prevChange.end++;
20.785 - else changed.push(prevChange = {start: view.frontier, end: view.frontier + 1});
20.786 - }
20.787 - line.stateAfter = copyState(view.mode, state);
20.788 - } else {
20.789 - processLine(cm, line, state);
20.790 - line.stateAfter = view.frontier % 5 == 0 ? copyState(view.mode, state) : null;
20.791 - }
20.792 - ++view.frontier;
20.793 - if (+new Date > end) {
20.794 - startWorker(cm, cm.options.workDelay);
20.795 - return true;
20.796 - }
20.797 - });
20.798 - if (changed.length)
20.799 - operation(cm, function() {
20.800 - for (var i = 0; i < changed.length; ++i)
20.801 - regChange(this, changed[i].start, changed[i].end);
20.802 - })();
20.803 - }
20.804 -
20.805 - // Finds the line to start with when starting a parse. Tries to
20.806 - // find a line with a stateAfter, so that it can start with a
20.807 - // valid state. If that fails, it returns the line with the
20.808 - // smallest indentation, which tends to need the least context to
20.809 - // parse correctly.
20.810 - function findStartLine(cm, n) {
20.811 - var minindent, minline, doc = cm.view.doc;
20.812 - for (var search = n, lim = n - 100; search > lim; --search) {
20.813 - if (search == 0) return 0;
20.814 - var line = getLine(doc, search-1);
20.815 - if (line.stateAfter) return search;
20.816 - var indented = countColumn(line.text, null, cm.options.tabSize);
20.817 - if (minline == null || minindent > indented) {
20.818 - minline = search - 1;
20.819 - minindent = indented;
20.820 - }
20.821 - }
20.822 - return minline;
20.823 - }
20.824 -
20.825 - function getStateBefore(cm, n) {
20.826 - var view = cm.view;
20.827 - var pos = findStartLine(cm, n), state = pos && getLine(view.doc, pos-1).stateAfter;
20.828 - if (!state) state = startState(view.mode);
20.829 - else state = copyState(view.mode, state);
20.830 - view.doc.iter(pos, n, function(line) {
20.831 - processLine(cm, line, state);
20.832 - var save = pos == n - 1 || pos % 5 == 0 || pos >= view.showingFrom && pos < view.showingTo;
20.833 - line.stateAfter = save ? copyState(view.mode, state) : null;
20.834 - ++pos;
20.835 - });
20.836 - return state;
20.837 - }
20.838 -
20.839 - // POSITION MEASUREMENT
20.840 -
20.841 - function paddingTop(display) {return display.lineSpace.offsetTop;}
20.842 - function paddingLeft(display) {
20.843 - var e = removeChildrenAndAdd(display.measure, elt("pre")).appendChild(elt("span", "x"));
20.844 - return e.offsetLeft;
20.845 - }
20.846 -
20.847 - function measureChar(cm, line, ch, data) {
20.848 - var data = data || measureLine(cm, line), dir = -1;
20.849 - for (var pos = ch;; pos += dir) {
20.850 - var r = data[pos];
20.851 - if (r) break;
20.852 - if (dir < 0 && pos == 0) dir = 1;
20.853 - }
20.854 - return {left: pos < ch ? r.right : r.left,
20.855 - right: pos > ch ? r.left : r.right,
20.856 - top: r.top, bottom: r.bottom};
20.857 - }
20.858 -
20.859 - function measureLine(cm, line) {
20.860 - // First look in the cache
20.861 - var display = cm.display, cache = cm.display.measureLineCache;
20.862 - for (var i = 0; i < cache.length; ++i) {
20.863 - var memo = cache[i];
20.864 - if (memo.text == line.text && memo.markedSpans == line.markedSpans &&
20.865 - display.scroller.clientWidth == memo.width)
20.866 - return memo.measure;
20.867 - }
20.868 -
20.869 - var measure = measureLineInner(cm, line);
20.870 - // Store result in the cache
20.871 - var memo = {text: line.text, width: display.scroller.clientWidth,
20.872 - markedSpans: line.markedSpans, measure: measure};
20.873 - if (cache.length == 16) cache[++display.measureLineCachePos % 16] = memo;
20.874 - else cache.push(memo);
20.875 - return measure;
20.876 - }
20.877 -
20.878 - function measureLineInner(cm, line) {
20.879 - var display = cm.display, measure = emptyArray(line.text.length);
20.880 - var pre = lineContent(cm, line, measure);
20.881 -
20.882 - // IE does not cache element positions of inline elements between
20.883 - // calls to getBoundingClientRect. This makes the loop below,
20.884 - // which gathers the positions of all the characters on the line,
20.885 - // do an amount of layout work quadratic to the number of
20.886 - // characters. When line wrapping is off, we try to improve things
20.887 - // by first subdividing the line into a bunch of inline blocks, so
20.888 - // that IE can reuse most of the layout information from caches
20.889 - // for those blocks. This does interfere with line wrapping, so it
20.890 - // doesn't work when wrapping is on, but in that case the
20.891 - // situation is slightly better, since IE does cache line-wrapping
20.892 - // information and only recomputes per-line.
20.893 - if (ie && !ie_lt8 && !cm.options.lineWrapping && pre.childNodes.length > 100) {
20.894 - var fragment = document.createDocumentFragment();
20.895 - var chunk = 10, n = pre.childNodes.length;
20.896 - for (var i = 0, chunks = Math.ceil(n / chunk); i < chunks; ++i) {
20.897 - var wrap = elt("div", null, null, "display: inline-block");
20.898 - for (var j = 0; j < chunk && n; ++j) {
20.899 - wrap.appendChild(pre.firstChild);
20.900 - --n;
20.901 - }
20.902 - fragment.appendChild(wrap);
20.903 - }
20.904 - pre.appendChild(fragment);
20.905 - }
20.906 -
20.907 - removeChildrenAndAdd(display.measure, pre);
20.908 -
20.909 - var outer = display.lineDiv.getBoundingClientRect();
20.910 - var vranges = [], data = emptyArray(line.text.length), maxBot = pre.offsetHeight;
20.911 - for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) {
20.912 - var size = cur.getBoundingClientRect();
20.913 - var top = Math.max(0, size.top - outer.top), bot = Math.min(size.bottom - outer.top, maxBot);
20.914 - for (var j = 0; j < vranges.length; j += 2) {
20.915 - var rtop = vranges[j], rbot = vranges[j+1];
20.916 - if (rtop > bot || rbot < top) continue;
20.917 - if (rtop <= top && rbot >= bot ||
20.918 - top <= rtop && bot >= rbot ||
20.919 - Math.min(bot, rbot) - Math.max(top, rtop) >= (bot - top) >> 1) {
20.920 - vranges[j] = Math.min(top, rtop);
20.921 - vranges[j+1] = Math.max(bot, rbot);
20.922 - break;
20.923 - }
20.924 - }
20.925 - if (j == vranges.length) vranges.push(top, bot);
20.926 - data[i] = {left: size.left - outer.left, right: size.right - outer.left, top: j};
20.927 - }
20.928 - for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) {
20.929 - var vr = cur.top;
20.930 - cur.top = vranges[vr]; cur.bottom = vranges[vr+1];
20.931 - }
20.932 - return data;
20.933 - }
20.934 -
20.935 - function clearCaches(cm) {
20.936 - cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0;
20.937 - cm.display.cachedCharWidth = cm.display.cachedTextHeight = null;
20.938 - cm.view.maxLineChanged = true;
20.939 - }
20.940 -
20.941 - // Context is one of "line", "div" (display.lineDiv), "local"/null (editor), or "page"
20.942 - function intoCoordSystem(cm, lineObj, rect, context) {
20.943 - if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
20.944 - var size = lineObj.widgets[i].node.offsetHeight;
20.945 - rect.top += size; rect.bottom += size;
20.946 - }
20.947 - if (context == "line") return rect;
20.948 - if (!context) context = "local";
20.949 - var yOff = heightAtLine(cm, lineObj);
20.950 - if (context != "local") yOff -= cm.display.viewOffset;
20.951 - if (context == "page") {
20.952 - var lOff = cm.display.lineSpace.getBoundingClientRect();
20.953 - yOff += lOff.top + (window.pageYOffset || (document.documentElement || document.body).scrollTop);
20.954 - var xOff = lOff.left + (window.pageXOffset || (document.documentElement || document.body).scrollLeft);
20.955 - rect.left += xOff; rect.right += xOff;
20.956 - }
20.957 - rect.top += yOff; rect.bottom += yOff;
20.958 - return rect;
20.959 - }
20.960 -
20.961 - function charCoords(cm, pos, context, lineObj) {
20.962 - if (!lineObj) lineObj = getLine(cm.view.doc, pos.line);
20.963 - return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch), context);
20.964 - }
20.965 -
20.966 - function cursorCoords(cm, pos, context, lineObj, measurement) {
20.967 - lineObj = lineObj || getLine(cm.view.doc, pos.line);
20.968 - if (!measurement) measurement = measureLine(cm, lineObj);
20.969 - function get(ch, right) {
20.970 - var m = measureChar(cm, lineObj, ch, measurement);
20.971 - if (right) m.left = m.right; else m.right = m.left;
20.972 - return intoCoordSystem(cm, lineObj, m, context);
20.973 - }
20.974 - var order = getOrder(lineObj), ch = pos.ch;
20.975 - if (!order) return get(ch);
20.976 - var main, other, linedir = order[0].level;
20.977 - for (var i = 0; i < order.length; ++i) {
20.978 - var part = order[i], rtl = part.level % 2, nb, here;
20.979 - if (part.from < ch && part.to > ch) return get(ch, rtl);
20.980 - var left = rtl ? part.to : part.from, right = rtl ? part.from : part.to;
20.981 - if (left == ch) {
20.982 - // Opera and IE return bogus offsets and widths for edges
20.983 - // where the direction flips, but only for the side with the
20.984 - // lower level. So we try to use the side with the higher
20.985 - // level.
20.986 - if (i && part.level < (nb = order[i-1]).level) here = get(nb.level % 2 ? nb.from : nb.to - 1, true);
20.987 - else here = get(rtl && part.from != part.to ? ch - 1 : ch);
20.988 - if (rtl == linedir) main = here; else other = here;
20.989 - } else if (right == ch) {
20.990 - var nb = i < order.length - 1 && order[i+1];
20.991 - if (!rtl && nb && nb.from == nb.to) continue;
20.992 - if (nb && part.level < nb.level) here = get(nb.level % 2 ? nb.to - 1 : nb.from);
20.993 - else here = get(rtl ? ch : ch - 1, true);
20.994 - if (rtl == linedir) main = here; else other = here;
20.995 - }
20.996 - }
20.997 - if (linedir && !ch) other = get(order[0].to - 1);
20.998 - if (!main) return other;
20.999 - if (other) main.other = other;
20.1000 - return main;
20.1001 - }
20.1002 -
20.1003 - // Coords must be lineSpace-local
20.1004 - function coordsChar(cm, x, y) {
20.1005 - var doc = cm.view.doc;
20.1006 - y += cm.display.viewOffset;
20.1007 - if (y < 0) return {line: 0, ch: 0, outside: true};
20.1008 - var lineNo = lineAtHeight(doc, y);
20.1009 - if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc, doc.size - 1).text.length};
20.1010 - if (x < 0) x = 0;
20.1011 -
20.1012 - for (;;) {
20.1013 - var lineObj = getLine(doc, lineNo);
20.1014 - var found = coordsCharInner(cm, lineObj, lineNo, x, y);
20.1015 - var merged = collapsedSpanAtEnd(lineObj);
20.1016 - if (merged && found.ch == lineRight(lineObj))
20.1017 - lineNo = merged.find().to.line;
20.1018 - else
20.1019 - return found;
20.1020 - }
20.1021 - }
20.1022 -
20.1023 - function coordsCharInner(cm, lineObj, lineNo, x, y) {
20.1024 - var innerOff = y - heightAtLine(cm, lineObj);
20.1025 - var wrongLine = false, cWidth = cm.display.wrapper.clientWidth;
20.1026 - var measurement = measureLine(cm, lineObj);
20.1027 -
20.1028 - function getX(ch) {
20.1029 - var sp = cursorCoords(cm, {line: lineNo, ch: ch}, "line",
20.1030 - lineObj, measurement);
20.1031 - wrongLine = true;
20.1032 - if (innerOff > sp.bottom) return Math.max(0, sp.left - cWidth);
20.1033 - else if (innerOff < sp.top) return sp.left + cWidth;
20.1034 - else wrongLine = false;
20.1035 - return sp.left;
20.1036 - }
20.1037 -
20.1038 - var bidi = getOrder(lineObj), dist = lineObj.text.length;
20.1039 - var from = lineLeft(lineObj), to = lineRight(lineObj);
20.1040 - var fromX = paddingLeft(cm.display), toX = getX(to);
20.1041 -
20.1042 - if (x > toX) return {line: lineNo, ch: to, outside: wrongLine};
20.1043 - // Do a binary search between these bounds.
20.1044 - for (;;) {
20.1045 - if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
20.1046 - var after = x - fromX < toX - x, ch = after ? from : to;
20.1047 - while (isExtendingChar.test(lineObj.text.charAt(ch))) ++ch;
20.1048 - return {line: lineNo, ch: ch, after: after, outside: wrongLine};
20.1049 - }
20.1050 - var step = Math.ceil(dist / 2), middle = from + step;
20.1051 - if (bidi) {
20.1052 - middle = from;
20.1053 - for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
20.1054 - }
20.1055 - var middleX = getX(middle);
20.1056 - if (middleX > x) {to = middle; toX = middleX; if (wrongLine) toX += 1000; dist -= step;}
20.1057 - else {from = middle; fromX = middleX; dist = step;}
20.1058 - }
20.1059 - }
20.1060 -
20.1061 - var measureText;
20.1062 - function textHeight(display) {
20.1063 - if (display.cachedTextHeight != null) return display.cachedTextHeight;
20.1064 - if (measureText == null) {
20.1065 - measureText = elt("pre");
20.1066 - // Measure a bunch of lines, for browsers that compute
20.1067 - // fractional heights.
20.1068 - for (var i = 0; i < 49; ++i) {
20.1069 - measureText.appendChild(document.createTextNode("x"));
20.1070 - measureText.appendChild(elt("br"));
20.1071 - }
20.1072 - measureText.appendChild(document.createTextNode("x"));
20.1073 - }
20.1074 - removeChildrenAndAdd(display.measure, measureText);
20.1075 - var height = measureText.offsetHeight / 50;
20.1076 - if (height > 3) display.cachedTextHeight = height;
20.1077 - removeChildren(display.measure);
20.1078 - return height || 1;
20.1079 - }
20.1080 -
20.1081 - function charWidth(display) {
20.1082 - if (display.cachedCharWidth != null) return display.cachedCharWidth;
20.1083 - var anchor = elt("span", "x");
20.1084 - var pre = elt("pre", [anchor]);
20.1085 - removeChildrenAndAdd(display.measure, pre);
20.1086 - var width = anchor.offsetWidth;
20.1087 - if (width > 2) display.cachedCharWidth = width;
20.1088 - return width || 10;
20.1089 - }
20.1090 -
20.1091 - // OPERATIONS
20.1092 -
20.1093 - // Operations are used to wrap changes in such a way that each
20.1094 - // change won't have to update the cursor and display (which would
20.1095 - // be awkward, slow, and error-prone), but instead updates are
20.1096 - // batched and then all combined and executed at once.
20.1097 -
20.1098 - function startOperation(cm) {
20.1099 - if (cm.curOp) ++cm.curOp.depth;
20.1100 - else cm.curOp = {
20.1101 - // Nested operations delay update until the outermost one
20.1102 - // finishes.
20.1103 - depth: 1,
20.1104 - // An array of ranges of lines that have to be updated. See
20.1105 - // updateDisplay.
20.1106 - changes: [],
20.1107 - delayedCallbacks: [],
20.1108 - updateInput: null,
20.1109 - userSelChange: null,
20.1110 - textChanged: null,
20.1111 - selectionChanged: false,
20.1112 - updateMaxLine: false,
20.1113 - id: ++cm.nextOpId
20.1114 - };
20.1115 - }
20.1116 -
20.1117 - function endOperation(cm) {
20.1118 - var op = cm.curOp;
20.1119 - if (--op.depth) return;
20.1120 - cm.curOp = null;
20.1121 - var view = cm.view, display = cm.display;
20.1122 - if (op.updateMaxLine) computeMaxLength(view);
20.1123 - if (view.maxLineChanged && !cm.options.lineWrapping) {
20.1124 - var width = measureChar(cm, view.maxLine, view.maxLine.text.length).right;
20.1125 - display.sizer.style.minWidth = (width + 3 + scrollerCutOff) + "px";
20.1126 - view.maxLineChanged = false;
20.1127 - }
20.1128 - var newScrollPos, updated;
20.1129 - if (op.selectionChanged) {
20.1130 - var coords = cursorCoords(cm, view.sel.head);
20.1131 - newScrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom);
20.1132 - }
20.1133 - if (op.changes.length || newScrollPos && newScrollPos.scrollTop != null)
20.1134 - updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop);
20.1135 - if (!updated && op.selectionChanged) updateSelection(cm);
20.1136 - if (newScrollPos) scrollCursorIntoView(cm);
20.1137 - if (op.selectionChanged) restartBlink(cm);
20.1138 -
20.1139 - if (view.focused && op.updateInput)
20.1140 - resetInput(cm, op.userSelChange);
20.1141 -
20.1142 - if (op.textChanged)
20.1143 - signal(cm, "change", cm, op.textChanged);
20.1144 - if (op.selectionChanged) signal(cm, "cursorActivity", cm);
20.1145 - for (var i = 0; i < op.delayedCallbacks.length; ++i) op.delayedCallbacks[i](cm);
20.1146 - }
20.1147 -
20.1148 - // Wraps a function in an operation. Returns the wrapped function.
20.1149 - function operation(cm1, f) {
20.1150 - return function() {
20.1151 - var cm = cm1 || this;
20.1152 - startOperation(cm);
20.1153 - try {var result = f.apply(cm, arguments);}
20.1154 - finally {endOperation(cm);}
20.1155 - return result;
20.1156 - };
20.1157 - }
20.1158 -
20.1159 - function regChange(cm, from, to, lendiff) {
20.1160 - cm.curOp.changes.push({from: from, to: to, diff: lendiff});
20.1161 - }
20.1162 -
20.1163 - // INPUT HANDLING
20.1164 -
20.1165 - function slowPoll(cm) {
20.1166 - if (cm.view.pollingFast) return;
20.1167 - cm.display.poll.set(cm.options.pollInterval, function() {
20.1168 - readInput(cm);
20.1169 - if (cm.view.focused) slowPoll(cm);
20.1170 - });
20.1171 - }
20.1172 -
20.1173 - function fastPoll(cm) {
20.1174 - var missed = false;
20.1175 - cm.display.pollingFast = true;
20.1176 - function p() {
20.1177 - var changed = readInput(cm);
20.1178 - if (!changed && !missed) {missed = true; cm.display.poll.set(60, p);}
20.1179 - else {cm.display.pollingFast = false; slowPoll(cm);}
20.1180 - }
20.1181 - cm.display.poll.set(20, p);
20.1182 - }
20.1183 -
20.1184 - // prevInput is a hack to work with IME. If we reset the textarea
20.1185 - // on every change, that breaks IME. So we look for changes
20.1186 - // compared to the previous content instead. (Modern browsers have
20.1187 - // events that indicate IME taking place, but these are not widely
20.1188 - // supported or compatible enough yet to rely on.)
20.1189 - function readInput(cm) {
20.1190 - var input = cm.display.input, prevInput = cm.display.prevInput, view = cm.view, sel = view.sel;
20.1191 - if (!view.focused || hasSelection(input) || isReadOnly(cm)) return false;
20.1192 - var text = input.value;
20.1193 - if (text == prevInput && posEq(sel.from, sel.to)) return false;
20.1194 - startOperation(cm);
20.1195 - view.sel.shift = false;
20.1196 - var same = 0, l = Math.min(prevInput.length, text.length);
20.1197 - while (same < l && prevInput[same] == text[same]) ++same;
20.1198 - var from = sel.from, to = sel.to;
20.1199 - if (same < prevInput.length)
20.1200 - from = {line: from.line, ch: from.ch - (prevInput.length - same)};
20.1201 - else if (view.overwrite && posEq(from, to) && !cm.display.pasteIncoming)
20.1202 - to = {line: to.line, ch: Math.min(getLine(cm.view.doc, to.line).text.length, to.ch + (text.length - same))};
20.1203 - var updateInput = cm.curOp.updateInput;
20.1204 - updateDoc(cm, from, to, splitLines(text.slice(same)), "end",
20.1205 - cm.display.pasteIncoming ? "paste" : "input", {from: from, to: to});
20.1206 - cm.curOp.updateInput = updateInput;
20.1207 - if (text.length > 1000) input.value = cm.display.prevInput = "";
20.1208 - else cm.display.prevInput = text;
20.1209 - endOperation(cm);
20.1210 - cm.display.pasteIncoming = false;
20.1211 - return true;
20.1212 - }
20.1213 -
20.1214 - function resetInput(cm, user) {
20.1215 - var view = cm.view, minimal, selected;
20.1216 - if (!posEq(view.sel.from, view.sel.to)) {
20.1217 - cm.display.prevInput = "";
20.1218 - minimal = hasCopyEvent &&
20.1219 - (view.sel.to.line - view.sel.from.line > 100 || (selected = cm.getSelection()).length > 1000);
20.1220 - if (minimal) cm.display.input.value = "-";
20.1221 - else cm.display.input.value = selected || cm.getSelection();
20.1222 - if (view.focused) selectInput(cm.display.input);
20.1223 - } else if (user) cm.display.prevInput = cm.display.input.value = "";
20.1224 - cm.display.inaccurateSelection = minimal;
20.1225 - }
20.1226 -
20.1227 - function focusInput(cm) {
20.1228 - if (cm.options.readOnly != "nocursor" && (ie || document.activeElement != cm.display.input))
20.1229 - cm.display.input.focus();
20.1230 - }
20.1231 -
20.1232 - function isReadOnly(cm) {
20.1233 - return cm.options.readOnly || cm.view.cantEdit;
20.1234 - }
20.1235 -
20.1236 - // EVENT HANDLERS
20.1237 -
20.1238 - function registerEventHandlers(cm) {
20.1239 - var d = cm.display;
20.1240 - on(d.scroller, "mousedown", operation(cm, onMouseDown));
20.1241 - on(d.scroller, "dblclick", operation(cm, e_preventDefault));
20.1242 - on(d.lineSpace, "selectstart", function(e) {
20.1243 - if (!mouseEventInWidget(d, e)) e_preventDefault(e);
20.1244 - });
20.1245 - // Gecko browsers fire contextmenu *after* opening the menu, at
20.1246 - // which point we can't mess with it anymore. Context menu is
20.1247 - // handled in onMouseDown for Gecko.
20.1248 - if (!gecko) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
20.1249 -
20.1250 - on(d.scroller, "scroll", function() {
20.1251 - setScrollTop(cm, d.scroller.scrollTop);
20.1252 - setScrollLeft(cm, d.scroller.scrollLeft, true);
20.1253 - signal(cm, "scroll", cm);
20.1254 - });
20.1255 - on(d.scrollbarV, "scroll", function() {
20.1256 - setScrollTop(cm, d.scrollbarV.scrollTop);
20.1257 - });
20.1258 - on(d.scrollbarH, "scroll", function() {
20.1259 - setScrollLeft(cm, d.scrollbarH.scrollLeft);
20.1260 - });
20.1261 -
20.1262 - on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
20.1263 - on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
20.1264 -
20.1265 - function reFocus() { if (cm.view.focused) setTimeout(bind(focusInput, cm), 0); }
20.1266 - on(d.scrollbarH, "mousedown", reFocus);
20.1267 - on(d.scrollbarV, "mousedown", reFocus);
20.1268 - // Prevent wrapper from ever scrolling
20.1269 - on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
20.1270 - on(window, "resize", function resizeHandler() {
20.1271 - // Might be a text scaling operation, clear size caches.
20.1272 - d.cachedCharWidth = d.cachedTextHeight = null;
20.1273 - clearCaches(cm);
20.1274 - if (d.wrapper.parentNode) updateDisplay(cm, true);
20.1275 - else off(window, "resize", resizeHandler);
20.1276 - });
20.1277 -
20.1278 - on(d.input, "keyup", operation(cm, function(e) {
20.1279 - if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
20.1280 - if (e_prop(e, "keyCode") == 16) cm.view.sel.shift = false;
20.1281 - }));
20.1282 - on(d.input, "input", bind(fastPoll, cm));
20.1283 - on(d.input, "keydown", operation(cm, onKeyDown));
20.1284 - on(d.input, "keypress", operation(cm, onKeyPress));
20.1285 - on(d.input, "focus", bind(onFocus, cm));
20.1286 - on(d.input, "blur", bind(onBlur, cm));
20.1287 -
20.1288 - function drag_(e) {
20.1289 - if (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))) return;
20.1290 - e_stop(e);
20.1291 - }
20.1292 - if (cm.options.dragDrop) {
20.1293 - on(d.scroller, "dragstart", function(e){onDragStart(cm, e);});
20.1294 - on(d.scroller, "dragenter", drag_);
20.1295 - on(d.scroller, "dragover", drag_);
20.1296 - on(d.scroller, "drop", operation(cm, onDrop));
20.1297 - }
20.1298 - on(d.scroller, "paste", function(){focusInput(cm); fastPoll(cm);});
20.1299 - on(d.input, "paste", function() {
20.1300 - d.pasteIncoming = true;
20.1301 - fastPoll(cm);
20.1302 - });
20.1303 -
20.1304 - function prepareCopy() {
20.1305 - if (d.inaccurateSelection) {
20.1306 - d.prevInput = "";
20.1307 - d.inaccurateSelection = false;
20.1308 - d.input.value = cm.getSelection();
20.1309 - selectInput(d.input);
20.1310 - }
20.1311 - }
20.1312 - on(d.input, "cut", prepareCopy);
20.1313 - on(d.input, "copy", prepareCopy);
20.1314 -
20.1315 - // Needed to handle Tab key in KHTML
20.1316 - if (khtml) on(d.sizer, "mouseup", function() {
20.1317 - if (document.activeElement == d.input) d.input.blur();
20.1318 - focusInput(cm);
20.1319 - });
20.1320 - }
20.1321 -
20.1322 - function mouseEventInWidget(display, e) {
20.1323 - for (var n = e_target(e); n != display.wrapper; n = n.parentNode)
20.1324 - if (/\bCodeMirror-(?:line)?widget\b/.test(n.className) ||
20.1325 - n.parentNode == display.sizer && n != display.mover) return true;
20.1326 - }
20.1327 -
20.1328 - function posFromMouse(cm, e, liberal) {
20.1329 - var display = cm.display;
20.1330 - if (!liberal) {
20.1331 - var target = e_target(e);
20.1332 - if (target == display.scrollbarH || target == display.scrollbarH.firstChild ||
20.1333 - target == display.scrollbarV || target == display.scrollbarV.firstChild ||
20.1334 - target == display.scrollbarFiller) return null;
20.1335 - }
20.1336 - var x, y, space = display.lineSpace.getBoundingClientRect();
20.1337 - // Fails unpredictably on IE[67] when mouse is dragged around quickly.
20.1338 - try { x = e.clientX; y = e.clientY; } catch (e) { return null; }
20.1339 - return coordsChar(cm, x - space.left, y - space.top);
20.1340 - }
20.1341 -
20.1342 - var lastClick, lastDoubleClick;
20.1343 - function onMouseDown(e) {
20.1344 - var cm = this, display = cm.display, view = cm.view, sel = view.sel, doc = view.doc;
20.1345 - sel.shift = e_prop(e, "shiftKey");
20.1346 -
20.1347 - if (mouseEventInWidget(display, e)) {
20.1348 - if (!webkit) {
20.1349 - display.scroller.draggable = false;
20.1350 - setTimeout(function(){display.scroller.draggable = true;}, 100);
20.1351 - }
20.1352 - return;
20.1353 - }
20.1354 - if (clickInGutter(cm, e)) return;
20.1355 - var start = posFromMouse(cm, e);
20.1356 -
20.1357 - switch (e_button(e)) {
20.1358 - case 3:
20.1359 - if (gecko) onContextMenu.call(cm, cm, e);
20.1360 - return;
20.1361 - case 2:
20.1362 - if (start) extendSelection(cm, start);
20.1363 - setTimeout(bind(focusInput, cm), 20);
20.1364 - e_preventDefault(e);
20.1365 - return;
20.1366 - }
20.1367 - // For button 1, if it was clicked inside the editor
20.1368 - // (posFromMouse returning non-null), we have to adjust the
20.1369 - // selection.
20.1370 - if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); return;}
20.1371 -
20.1372 - if (!view.focused) onFocus(cm);
20.1373 -
20.1374 - var now = +new Date, type = "single";
20.1375 - if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
20.1376 - type = "triple";
20.1377 - e_preventDefault(e);
20.1378 - setTimeout(bind(focusInput, cm), 20);
20.1379 - selectLine(cm, start.line);
20.1380 - } else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
20.1381 - type = "double";
20.1382 - lastDoubleClick = {time: now, pos: start};
20.1383 - e_preventDefault(e);
20.1384 - var word = findWordAt(getLine(doc, start.line).text, start);
20.1385 - extendSelection(cm, word.from, word.to);
20.1386 - } else { lastClick = {time: now, pos: start}; }
20.1387 -
20.1388 - var last = start;
20.1389 - if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && !posEq(sel.from, sel.to) &&
20.1390 - !posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") {
20.1391 - var dragEnd = operation(cm, function(e2) {
20.1392 - if (webkit) display.scroller.draggable = false;
20.1393 - view.draggingText = false;
20.1394 - off(document, "mouseup", dragEnd);
20.1395 - off(display.scroller, "drop", dragEnd);
20.1396 - if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
20.1397 - e_preventDefault(e2);
20.1398 - extendSelection(cm, start);
20.1399 - focusInput(cm);
20.1400 - }
20.1401 - });
20.1402 - // Let the drag handler handle this.
20.1403 - if (webkit) display.scroller.draggable = true;
20.1404 - view.draggingText = dragEnd;
20.1405 - // IE's approach to draggable
20.1406 - if (display.scroller.dragDrop) display.scroller.dragDrop();
20.1407 - on(document, "mouseup", dragEnd);
20.1408 - on(display.scroller, "drop", dragEnd);
20.1409 - return;
20.1410 - }
20.1411 - e_preventDefault(e);
20.1412 - if (type == "single") extendSelection(cm, clipPos(doc, start));
20.1413 -
20.1414 - var startstart = sel.from, startend = sel.to;
20.1415 -
20.1416 - function doSelect(cur) {
20.1417 - if (type == "single") {
20.1418 - extendSelection(cm, clipPos(doc, start), cur);
20.1419 - return;
20.1420 - }
20.1421 -
20.1422 - startstart = clipPos(doc, startstart);
20.1423 - startend = clipPos(doc, startend);
20.1424 - if (type == "double") {
20.1425 - var word = findWordAt(getLine(doc, cur.line).text, cur);
20.1426 - if (posLess(cur, startstart)) extendSelection(cm, word.from, startend);
20.1427 - else extendSelection(cm, startstart, word.to);
20.1428 - } else if (type == "triple") {
20.1429 - if (posLess(cur, startstart)) extendSelection(cm, startend, clipPos(doc, {line: cur.line, ch: 0}));
20.1430 - else extendSelection(cm, startstart, clipPos(doc, {line: cur.line + 1, ch: 0}));
20.1431 - }
20.1432 - }
20.1433 -
20.1434 - var editorSize = display.wrapper.getBoundingClientRect();
20.1435 - // Used to ensure timeout re-tries don't fire when another extend
20.1436 - // happened in the meantime (clearTimeout isn't reliable -- at
20.1437 - // least on Chrome, the timeouts still happen even when cleared,
20.1438 - // if the clear happens after their scheduled firing time).
20.1439 - var counter = 0;
20.1440 -
20.1441 - function extend(e) {
20.1442 - var curCount = ++counter;
20.1443 - var cur = posFromMouse(cm, e, true);
20.1444 - if (!cur) return;
20.1445 - if (!posEq(cur, last)) {
20.1446 - if (!view.focused) onFocus(cm);
20.1447 - last = cur;
20.1448 - doSelect(cur);
20.1449 - var visible = visibleLines(display, doc);
20.1450 - if (cur.line >= visible.to || cur.line < visible.from)
20.1451 - setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
20.1452 - } else {
20.1453 - var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
20.1454 - if (outside) setTimeout(operation(cm, function() {
20.1455 - if (counter != curCount) return;
20.1456 - display.scroller.scrollTop += outside;
20.1457 - extend(e);
20.1458 - }), 50);
20.1459 - }
20.1460 - }
20.1461 -
20.1462 - function done(e) {
20.1463 - counter = Infinity;
20.1464 - var cur = posFromMouse(cm, e);
20.1465 - if (cur) doSelect(cur);
20.1466 - e_preventDefault(e);
20.1467 - focusInput(cm);
20.1468 - off(document, "mousemove", move);
20.1469 - off(document, "mouseup", up);
20.1470 - }
20.1471 -
20.1472 - var move = operation(cm, function(e) {
20.1473 - if (!ie && !e_button(e)) done(e);
20.1474 - else extend(e);
20.1475 - });
20.1476 - var up = operation(cm, done);
20.1477 - on(document, "mousemove", move);
20.1478 - on(document, "mouseup", up);
20.1479 - }
20.1480 -
20.1481 - function onDrop(e) {
20.1482 - var cm = this;
20.1483 - if (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e))) return;
20.1484 - e_preventDefault(e);
20.1485 - var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
20.1486 - if (!pos || isReadOnly(cm)) return;
20.1487 - if (files && files.length && window.FileReader && window.File) {
20.1488 - var n = files.length, text = Array(n), read = 0;
20.1489 - var loadFile = function(file, i) {
20.1490 - var reader = new FileReader;
20.1491 - reader.onload = function() {
20.1492 - text[i] = reader.result;
20.1493 - if (++read == n) {
20.1494 - pos = clipPos(cm.view.doc, pos);
20.1495 - operation(cm, function() {
20.1496 - var end = replaceRange(cm, text.join(""), pos, pos, "paste");
20.1497 - setSelection(cm, pos, end);
20.1498 - })();
20.1499 - }
20.1500 - };
20.1501 - reader.readAsText(file);
20.1502 - };
20.1503 - for (var i = 0; i < n; ++i) loadFile(files[i], i);
20.1504 - } else {
20.1505 - // Don't do a replace if the drop happened inside of the selected text.
20.1506 - if (cm.view.draggingText && !(posLess(pos, cm.view.sel.from) || posLess(cm.view.sel.to, pos))) {
20.1507 - cm.view.draggingText(e);
20.1508 - if (ie) setTimeout(bind(focusInput, cm), 50);
20.1509 - return;
20.1510 - }
20.1511 - try {
20.1512 - var text = e.dataTransfer.getData("Text");
20.1513 - if (text) {
20.1514 - var curFrom = cm.view.sel.from, curTo = cm.view.sel.to;
20.1515 - setSelection(cm, pos, pos);
20.1516 - if (cm.view.draggingText) replaceRange(cm, "", curFrom, curTo, "paste");
20.1517 - cm.replaceSelection(text, null, "paste");
20.1518 - focusInput(cm);
20.1519 - onFocus(cm);
20.1520 - }
20.1521 - }
20.1522 - catch(e){}
20.1523 - }
20.1524 - }
20.1525 -
20.1526 - function clickInGutter(cm, e) {
20.1527 - var display = cm.display;
20.1528 - try { var mX = e.clientX, mY = e.clientY; }
20.1529 - catch(e) { return false; }
20.1530 -
20.1531 - if (mX >= Math.floor(display.gutters.getBoundingClientRect().right)) return false;
20.1532 - e_preventDefault(e);
20.1533 - if (!hasHandler(cm, "gutterClick")) return true;
20.1534 -
20.1535 - var lineBox = display.lineDiv.getBoundingClientRect();
20.1536 - if (mY > lineBox.bottom) return true;
20.1537 - mY -= lineBox.top - display.viewOffset;
20.1538 -
20.1539 - for (var i = 0; i < cm.options.gutters.length; ++i) {
20.1540 - var g = display.gutters.childNodes[i];
20.1541 - if (g && g.getBoundingClientRect().right >= mX) {
20.1542 - var line = lineAtHeight(cm.view.doc, mY);
20.1543 - var gutter = cm.options.gutters[i];
20.1544 - signalLater(cm, cm, "gutterClick", cm, line, gutter, e);
20.1545 - break;
20.1546 - }
20.1547 - }
20.1548 - return true;
20.1549 - }
20.1550 -
20.1551 - function onDragStart(cm, e) {
20.1552 - var txt = cm.getSelection();
20.1553 - e.dataTransfer.setData("Text", txt);
20.1554 -
20.1555 - // Use dummy image instead of default browsers image.
20.1556 - // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
20.1557 - if (e.dataTransfer.setDragImage && !safari)
20.1558 - e.dataTransfer.setDragImage(elt('img'), 0, 0);
20.1559 - }
20.1560 -
20.1561 - function setScrollTop(cm, val) {
20.1562 - if (Math.abs(cm.view.scrollTop - val) < 2) return;
20.1563 - cm.view.scrollTop = val;
20.1564 - if (!gecko) updateDisplay(cm, [], val);
20.1565 - if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
20.1566 - if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
20.1567 - if (gecko) updateDisplay(cm, []);
20.1568 - }
20.1569 - function setScrollLeft(cm, val, isScroller) {
20.1570 - if (isScroller ? val == cm.view.scrollLeft : Math.abs(cm.view.scrollLeft - val) < 2) return;
20.1571 - cm.view.scrollLeft = val;
20.1572 - alignHorizontally(cm);
20.1573 - if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
20.1574 - if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
20.1575 - }
20.1576 -
20.1577 - // Since the delta values reported on mouse wheel events are
20.1578 - // unstandardized between browsers and even browser versions, and
20.1579 - // generally horribly unpredictable, this code starts by measuring
20.1580 - // the scroll effect that the first few mouse wheel events have,
20.1581 - // and, from that, detects the way it can convert deltas to pixel
20.1582 - // offsets afterwards.
20.1583 - //
20.1584 - // The reason we want to know the amount a wheel event will scroll
20.1585 - // is that it gives us a chance to update the display before the
20.1586 - // actual scrolling happens, reducing flickering.
20.1587 -
20.1588 - var wheelSamples = 0, wheelDX, wheelDY, wheelStartX, wheelStartY, wheelPixelsPerUnit = null;
20.1589 - // Fill in a browser-detected starting value on browsers where we
20.1590 - // know one. These don't have to be accurate -- the result of them
20.1591 - // being wrong would just be a slight flicker on the first wheel
20.1592 - // scroll (if it is large enough).
20.1593 - if (ie) wheelPixelsPerUnit = -.53;
20.1594 - else if (gecko) wheelPixelsPerUnit = 15;
20.1595 - else if (chrome) wheelPixelsPerUnit = -.7;
20.1596 - else if (safari) wheelPixelsPerUnit = -1/3;
20.1597 -
20.1598 - function onScrollWheel(cm, e) {
20.1599 - var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
20.1600 - if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
20.1601 - if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
20.1602 - else if (dy == null) dy = e.wheelDelta;
20.1603 -
20.1604 - // Webkit browsers on OS X abort momentum scrolls when the target
20.1605 - // of the scroll event is removed from the scrollable element.
20.1606 - // This hack (see related code in patchDisplay) makes sure the
20.1607 - // element is kept around.
20.1608 - if (dy && mac && webkit) {
20.1609 - for (var cur = e.target; cur != scroll; cur = cur.parentNode) {
20.1610 - if (cur.lineObj) {
20.1611 - cm.display.currentWheelTarget = cur;
20.1612 - break;
20.1613 - }
20.1614 - }
20.1615 - }
20.1616 -
20.1617 - var scroll = cm.display.scroller;
20.1618 - // On some browsers, horizontal scrolling will cause redraws to
20.1619 - // happen before the gutter has been realigned, causing it to
20.1620 - // wriggle around in a most unseemly way. When we have an
20.1621 - // estimated pixels/delta value, we just handle horizontal
20.1622 - // scrolling entirely here. It'll be slightly off from native, but
20.1623 - // better than glitching out.
20.1624 - if (dx && !gecko && !opera && wheelPixelsPerUnit != null) {
20.1625 - if (dy)
20.1626 - setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
20.1627 - setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
20.1628 - e_preventDefault(e);
20.1629 - wheelStartX = null; // Abort measurement, if in progress
20.1630 - return;
20.1631 - }
20.1632 -
20.1633 - if (dy && wheelPixelsPerUnit != null) {
20.1634 - var pixels = dy * wheelPixelsPerUnit;
20.1635 - var top = cm.view.scrollTop, bot = top + cm.display.wrapper.clientHeight;
20.1636 - if (pixels < 0) top = Math.max(0, top + pixels - 50);
20.1637 - else bot = Math.min(cm.view.doc.height, bot + pixels + 50);
20.1638 - updateDisplay(cm, [], {top: top, bottom: bot});
20.1639 - }
20.1640 -
20.1641 - if (wheelSamples < 20) {
20.1642 - if (wheelStartX == null) {
20.1643 - wheelStartX = scroll.scrollLeft; wheelStartY = scroll.scrollTop;
20.1644 - wheelDX = dx; wheelDY = dy;
20.1645 - setTimeout(function() {
20.1646 - if (wheelStartX == null) return;
20.1647 - var movedX = scroll.scrollLeft - wheelStartX;
20.1648 - var movedY = scroll.scrollTop - wheelStartY;
20.1649 - var sample = (movedY && wheelDY && movedY / wheelDY) ||
20.1650 - (movedX && wheelDX && movedX / wheelDX);
20.1651 - wheelStartX = wheelStartY = null;
20.1652 - if (!sample) return;
20.1653 - wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
20.1654 - ++wheelSamples;
20.1655 - }, 200);
20.1656 - } else {
20.1657 - wheelDX += dx; wheelDY += dy;
20.1658 - }
20.1659 - }
20.1660 - }
20.1661 -
20.1662 - function doHandleBinding(cm, bound, dropShift) {
20.1663 - if (typeof bound == "string") {
20.1664 - bound = commands[bound];
20.1665 - if (!bound) return false;
20.1666 - }
20.1667 - // Ensure previous input has been read, so that the handler sees a
20.1668 - // consistent view of the document
20.1669 - if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false;
20.1670 - var view = cm.view, prevShift = view.sel.shift;
20.1671 - try {
20.1672 - if (isReadOnly(cm)) view.suppressEdits = true;
20.1673 - if (dropShift) view.sel.shift = false;
20.1674 - bound(cm);
20.1675 - } catch(e) {
20.1676 - if (e != Pass) throw e;
20.1677 - return false;
20.1678 - } finally {
20.1679 - view.sel.shift = prevShift;
20.1680 - view.suppressEdits = false;
20.1681 - }
20.1682 - return true;
20.1683 - }
20.1684 -
20.1685 - function allKeyMaps(cm) {
20.1686 - var maps = cm.view.keyMaps.slice(0);
20.1687 - maps.push(cm.options.keyMap);
20.1688 - if (cm.options.extraKeys) maps.unshift(cm.options.extraKeys);
20.1689 - return maps;
20.1690 - }
20.1691 -
20.1692 - var maybeTransition;
20.1693 - function handleKeyBinding(cm, e) {
20.1694 - // Handle auto keymap transitions
20.1695 - var startMap = getKeyMap(cm.options.keyMap), next = startMap.auto;
20.1696 - clearTimeout(maybeTransition);
20.1697 - if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
20.1698 - if (getKeyMap(cm.options.keyMap) == startMap)
20.1699 - cm.options.keyMap = (next.call ? next.call(null, cm) : next);
20.1700 - }, 50);
20.1701 -
20.1702 - var name = keyNames[e_prop(e, "keyCode")], handled = false;
20.1703 - var flipCtrlCmd = mac && (opera || qtwebkit);
20.1704 - if (name == null || e.altGraphKey) return false;
20.1705 - if (e_prop(e, "altKey")) name = "Alt-" + name;
20.1706 - if (e_prop(e, flipCtrlCmd ? "metaKey" : "ctrlKey")) name = "Ctrl-" + name;
20.1707 - if (e_prop(e, flipCtrlCmd ? "ctrlKey" : "metaKey")) name = "Cmd-" + name;
20.1708 -
20.1709 - var stopped = false;
20.1710 - function stop() { stopped = true; }
20.1711 - var keymaps = allKeyMaps(cm);
20.1712 -
20.1713 - if (e_prop(e, "shiftKey")) {
20.1714 - handled = lookupKey("Shift-" + name, keymaps,
20.1715 - function(b) {return doHandleBinding(cm, b, true);}, stop)
20.1716 - || lookupKey(name, keymaps, function(b) {
20.1717 - if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(cm, b);
20.1718 - }, stop);
20.1719 - } else {
20.1720 - handled = lookupKey(name, keymaps,
20.1721 - function(b) { return doHandleBinding(cm, b); }, stop);
20.1722 - }
20.1723 - if (stopped) handled = false;
20.1724 - if (handled) {
20.1725 - e_preventDefault(e);
20.1726 - restartBlink(cm);
20.1727 - if (ie_lt9) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
20.1728 - }
20.1729 - return handled;
20.1730 - }
20.1731 -
20.1732 - function handleCharBinding(cm, e, ch) {
20.1733 - var handled = lookupKey("'" + ch + "'", allKeyMaps(cm),
20.1734 - function(b) { return doHandleBinding(cm, b, true); });
20.1735 - if (handled) {
20.1736 - e_preventDefault(e);
20.1737 - restartBlink(cm);
20.1738 - }
20.1739 - return handled;
20.1740 - }
20.1741 -
20.1742 - var lastStoppedKey = null;
20.1743 - function onKeyDown(e) {
20.1744 - var cm = this;
20.1745 - if (!cm.view.focused) onFocus(cm);
20.1746 - if (ie && e.keyCode == 27) { e.returnValue = false; }
20.1747 - if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
20.1748 - var code = e_prop(e, "keyCode");
20.1749 - // IE does strange things with escape.
20.1750 - cm.view.sel.shift = code == 16 || e_prop(e, "shiftKey");
20.1751 - // First give onKeyEvent option a chance to handle this.
20.1752 - var handled = handleKeyBinding(cm, e);
20.1753 - if (opera) {
20.1754 - lastStoppedKey = handled ? code : null;
20.1755 - // Opera has no cut event... we try to at least catch the key combo
20.1756 - if (!handled && code == 88 && !hasCopyEvent && e_prop(e, mac ? "metaKey" : "ctrlKey"))
20.1757 - cm.replaceSelection("");
20.1758 - }
20.1759 - }
20.1760 -
20.1761 - function onKeyPress(e) {
20.1762 - var cm = this;
20.1763 - if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return;
20.1764 - var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
20.1765 - if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
20.1766 - if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return;
20.1767 - var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
20.1768 - if (this.options.electricChars && this.view.mode.electricChars &&
20.1769 - this.options.smartIndent && !isReadOnly(this) &&
20.1770 - this.view.mode.electricChars.indexOf(ch) > -1)
20.1771 - setTimeout(operation(cm, function() {indentLine(cm, cm.view.sel.to.line, "smart");}), 75);
20.1772 - if (handleCharBinding(cm, e, ch)) return;
20.1773 - fastPoll(cm);
20.1774 - }
20.1775 -
20.1776 - function onFocus(cm) {
20.1777 - if (cm.options.readOnly == "nocursor") return;
20.1778 - if (!cm.view.focused) {
20.1779 - signal(cm, "focus", cm);
20.1780 - cm.view.focused = true;
20.1781 - if (cm.display.scroller.className.search(/\bCodeMirror-focused\b/) == -1)
20.1782 - cm.display.scroller.className += " CodeMirror-focused";
20.1783 - resetInput(cm, true);
20.1784 - }
20.1785 - slowPoll(cm);
20.1786 - restartBlink(cm);
20.1787 - }
20.1788 - function onBlur(cm) {
20.1789 - if (cm.view.focused) {
20.1790 - signal(cm, "blur", cm);
20.1791 - cm.view.focused = false;
20.1792 - cm.display.scroller.className = cm.display.scroller.className.replace(" CodeMirror-focused", "");
20.1793 - }
20.1794 - clearInterval(cm.display.blinker);
20.1795 - setTimeout(function() {if (!cm.view.focused) cm.view.sel.shift = false;}, 150);
20.1796 - }
20.1797 -
20.1798 - var detectingSelectAll;
20.1799 - function onContextMenu(cm, e) {
20.1800 - var display = cm.display, sel = cm.view.sel;
20.1801 - var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
20.1802 - if (!pos || opera) return; // Opera is difficult.
20.1803 - if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
20.1804 - operation(cm, setSelection)(cm, pos, pos);
20.1805 -
20.1806 - var oldCSS = display.input.style.cssText;
20.1807 - display.inputDiv.style.position = "absolute";
20.1808 - display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
20.1809 - "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; outline: none;" +
20.1810 - "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
20.1811 - focusInput(cm);
20.1812 - resetInput(cm, true);
20.1813 - // Adds "Select all" to context menu in FF
20.1814 - if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " ";
20.1815 -
20.1816 - function rehide() {
20.1817 - display.inputDiv.style.position = "relative";
20.1818 - display.input.style.cssText = oldCSS;
20.1819 - if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
20.1820 - slowPoll(cm);
20.1821 -
20.1822 - // Try to detect the user choosing select-all
20.1823 - if (display.input.selectionStart != null) {
20.1824 - clearTimeout(detectingSelectAll);
20.1825 - var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value), i = 0;
20.1826 - display.prevInput = " ";
20.1827 - display.input.selectionStart = 1; display.input.selectionEnd = extval.length;
20.1828 - detectingSelectAll = setTimeout(function poll(){
20.1829 - if (display.prevInput == " " && display.input.selectionStart == 0)
20.1830 - operation(cm, commands.selectAll)(cm);
20.1831 - else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500);
20.1832 - else resetInput(cm);
20.1833 - }, 200);
20.1834 - }
20.1835 - }
20.1836 -
20.1837 - if (gecko) {
20.1838 - e_stop(e);
20.1839 - on(window, "mouseup", function mouseup() {
20.1840 - off(window, "mouseup", mouseup);
20.1841 - setTimeout(rehide, 20);
20.1842 - });
20.1843 - } else {
20.1844 - setTimeout(rehide, 50);
20.1845 - }
20.1846 - }
20.1847 -
20.1848 - // UPDATING
20.1849 -
20.1850 - // Replace the range from from to to by the strings in newText.
20.1851 - // Afterwards, set the selection to selFrom, selTo.
20.1852 - function updateDoc(cm, from, to, newText, selUpdate, origin) {
20.1853 - // Possibly split or suppress the update based on the presence
20.1854 - // of read-only spans in its range.
20.1855 - var split = sawReadOnlySpans &&
20.1856 - removeReadOnlyRanges(cm.view.doc, from, to);
20.1857 - if (split) {
20.1858 - for (var i = split.length - 1; i >= 1; --i)
20.1859 - updateDocInner(cm, split[i].from, split[i].to, [""], origin);
20.1860 - if (split.length)
20.1861 - return updateDocInner(cm, split[0].from, split[0].to, newText, selUpdate, origin);
20.1862 - } else {
20.1863 - return updateDocInner(cm, from, to, newText, selUpdate, origin);
20.1864 - }
20.1865 - }
20.1866 -
20.1867 - function updateDocInner(cm, from, to, newText, selUpdate, origin) {
20.1868 - if (cm.view.suppressEdits) return;
20.1869 -
20.1870 - var view = cm.view, doc = view.doc, old = [];
20.1871 - doc.iter(from.line, to.line + 1, function(line) {
20.1872 - old.push(newHL(line.text, line.markedSpans));
20.1873 - });
20.1874 - var startSelFrom = view.sel.from, startSelTo = view.sel.to;
20.1875 - var lines = updateMarkedSpans(hlSpans(old[0]), hlSpans(lst(old)), from.ch, to.ch, newText);
20.1876 - var retval = updateDocNoUndo(cm, from, to, lines, selUpdate, origin);
20.1877 - if (view.history) addChange(cm, from.line, newText.length, old, origin,
20.1878 - startSelFrom, startSelTo, view.sel.from, view.sel.to);
20.1879 - return retval;
20.1880 - }
20.1881 -
20.1882 - function unredoHelper(cm, type) {
20.1883 - var doc = cm.view.doc, hist = cm.view.history;
20.1884 - var set = (type == "undo" ? hist.done : hist.undone).pop();
20.1885 - if (!set) return;
20.1886 - var anti = {events: [], fromBefore: set.fromAfter, toBefore: set.toAfter,
20.1887 - fromAfter: set.fromBefore, toAfter: set.toBefore};
20.1888 - for (var i = set.events.length - 1; i >= 0; i -= 1) {
20.1889 - hist.dirtyCounter += type == "undo" ? -1 : 1;
20.1890 - var change = set.events[i];
20.1891 - var replaced = [], end = change.start + change.added;
20.1892 - doc.iter(change.start, end, function(line) { replaced.push(newHL(line.text, line.markedSpans)); });
20.1893 - anti.events.push({start: change.start, added: change.old.length, old: replaced});
20.1894 - var selPos = i ? null : {from: set.fromBefore, to: set.toBefore};
20.1895 - updateDocNoUndo(cm, {line: change.start, ch: 0}, {line: end - 1, ch: getLine(doc, end-1).text.length},
20.1896 - change.old, selPos, type);
20.1897 - }
20.1898 - (type == "undo" ? hist.undone : hist.done).push(anti);
20.1899 - }
20.1900 -
20.1901 - function updateDocNoUndo(cm, from, to, lines, selUpdate, origin) {
20.1902 - var view = cm.view, doc = view.doc, display = cm.display;
20.1903 - if (view.suppressEdits) return;
20.1904 -
20.1905 - var nlines = to.line - from.line, firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
20.1906 - var recomputeMaxLength = false, checkWidthStart = from.line;
20.1907 - if (!cm.options.lineWrapping) {
20.1908 - checkWidthStart = lineNo(visualLine(doc, firstLine));
20.1909 - doc.iter(checkWidthStart, to.line + 1, function(line) {
20.1910 - if (lineLength(doc, line) == view.maxLineLength) {
20.1911 - recomputeMaxLength = true;
20.1912 - return true;
20.1913 - }
20.1914 - });
20.1915 - }
20.1916 -
20.1917 - var lastHL = lst(lines), th = textHeight(display);
20.1918 -
20.1919 - // First adjust the line structure
20.1920 - if (from.ch == 0 && to.ch == 0 && hlText(lastHL) == "") {
20.1921 - // This is a whole-line replace. Treated specially to make
20.1922 - // sure line objects move the way they are supposed to.
20.1923 - var added = [];
20.1924 - for (var i = 0, e = lines.length - 1; i < e; ++i)
20.1925 - added.push(makeLine(hlText(lines[i]), hlSpans(lines[i]), th));
20.1926 - updateLine(cm, lastLine, lastLine.text, hlSpans(lastHL));
20.1927 - if (nlines) doc.remove(from.line, nlines, cm);
20.1928 - if (added.length) doc.insert(from.line, added);
20.1929 - } else if (firstLine == lastLine) {
20.1930 - if (lines.length == 1) {
20.1931 - updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]) +
20.1932 - firstLine.text.slice(to.ch), hlSpans(lines[0]));
20.1933 - } else {
20.1934 - for (var added = [], i = 1, e = lines.length - 1; i < e; ++i)
20.1935 - added.push(makeLine(hlText(lines[i]), hlSpans(lines[i]), th));
20.1936 - added.push(makeLine(hlText(lastHL) + firstLine.text.slice(to.ch), hlSpans(lastHL), th));
20.1937 - updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0]));
20.1938 - doc.insert(from.line + 1, added);
20.1939 - }
20.1940 - } else if (lines.length == 1) {
20.1941 - updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]) +
20.1942 - lastLine.text.slice(to.ch), hlSpans(lines[0]));
20.1943 - doc.remove(from.line + 1, nlines, cm);
20.1944 - } else {
20.1945 - var added = [];
20.1946 - updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0]));
20.1947 - updateLine(cm, lastLine, hlText(lastHL) + lastLine.text.slice(to.ch), hlSpans(lastHL));
20.1948 - for (var i = 1, e = lines.length - 1; i < e; ++i)
20.1949 - added.push(makeLine(hlText(lines[i]), hlSpans(lines[i]), th));
20.1950 - if (nlines > 1) doc.remove(from.line + 1, nlines - 1, cm);
20.1951 - doc.insert(from.line + 1, added);
20.1952 - }
20.1953 -
20.1954 - if (cm.options.lineWrapping) {
20.1955 - var perLine = Math.max(5, display.scroller.clientWidth / charWidth(display) - 3);
20.1956 - doc.iter(from.line, from.line + lines.length, function(line) {
20.1957 - if (line.height == 0) return;
20.1958 - var guess = (Math.ceil(line.text.length / perLine) || 1) * th;
20.1959 - if (guess != line.height) updateLineHeight(line, guess);
20.1960 - });
20.1961 - } else {
20.1962 - doc.iter(checkWidthStart, from.line + lines.length, function(line) {
20.1963 - var len = lineLength(doc, line);
20.1964 - if (len > view.maxLineLength) {
20.1965 - view.maxLine = line;
20.1966 - view.maxLineLength = len;
20.1967 - view.maxLineChanged = true;
20.1968 - recomputeMaxLength = false;
20.1969 - }
20.1970 - });
20.1971 - if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
20.1972 - }
20.1973 -
20.1974 - // Adjust frontier, schedule worker
20.1975 - view.frontier = Math.min(view.frontier, from.line);
20.1976 - startWorker(cm, 400);
20.1977 -
20.1978 - var lendiff = lines.length - nlines - 1;
20.1979 - // Remember that these lines changed, for updating the display
20.1980 - regChange(cm, from.line, to.line + 1, lendiff);
20.1981 - if (hasHandler(cm, "change")) {
20.1982 - // Normalize lines to contain only strings, since that's what
20.1983 - // the change event handler expects
20.1984 - for (var i = 0; i < lines.length; ++i)
20.1985 - if (typeof lines[i] != "string") lines[i] = lines[i].text;
20.1986 - var changeObj = {from: from, to: to, text: lines, origin: origin};
20.1987 - if (cm.curOp.textChanged) {
20.1988 - for (var cur = cm.curOp.textChanged; cur.next; cur = cur.next) {}
20.1989 - cur.next = changeObj;
20.1990 - } else cm.curOp.textChanged = changeObj;
20.1991 - }
20.1992 -
20.1993 - // Update the selection
20.1994 - var newSelFrom, newSelTo, end = {line: from.line + lines.length - 1,
20.1995 - ch: hlText(lastHL).length + (lines.length == 1 ? from.ch : 0)};
20.1996 - if (selUpdate && typeof selUpdate != "string") {
20.1997 - if (selUpdate.from) { newSelFrom = selUpdate.from; newSelTo = selUpdate.to; }
20.1998 - else newSelFrom = newSelTo = selUpdate;
20.1999 - } else if (selUpdate == "end") {
20.2000 - newSelFrom = newSelTo = end;
20.2001 - } else if (selUpdate == "start") {
20.2002 - newSelFrom = newSelTo = from;
20.2003 - } else if (selUpdate == "around") {
20.2004 - newSelFrom = from; newSelTo = end;
20.2005 - } else {
20.2006 - var adjustPos = function(pos) {
20.2007 - if (posLess(pos, from)) return pos;
20.2008 - if (!posLess(to, pos)) return end;
20.2009 - var line = pos.line + lendiff;
20.2010 - var ch = pos.ch;
20.2011 - if (pos.line == to.line)
20.2012 - ch += hlText(lastHL).length - (to.ch - (to.line == from.line ? from.ch : 0));
20.2013 - return {line: line, ch: ch};
20.2014 - };
20.2015 - newSelFrom = adjustPos(view.sel.from);
20.2016 - newSelTo = adjustPos(view.sel.to);
20.2017 - }
20.2018 - setSelection(cm, newSelFrom, newSelTo, null, true);
20.2019 - return end;
20.2020 - }
20.2021 -
20.2022 - function replaceRange(cm, code, from, to, origin) {
20.2023 - if (!to) to = from;
20.2024 - if (posLess(to, from)) { var tmp = to; to = from; from = tmp; }
20.2025 - return updateDoc(cm, from, to, splitLines(code), null, origin);
20.2026 - }
20.2027 -
20.2028 - // SELECTION
20.2029 -
20.2030 - function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
20.2031 - function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
20.2032 - function copyPos(x) {return {line: x.line, ch: x.ch};}
20.2033 -
20.2034 - function clipLine(doc, n) {return Math.max(0, Math.min(n, doc.size-1));}
20.2035 - function clipPos(doc, pos) {
20.2036 - if (pos.line < 0) return {line: 0, ch: 0};
20.2037 - if (pos.line >= doc.size) return {line: doc.size-1, ch: getLine(doc, doc.size-1).text.length};
20.2038 - var ch = pos.ch, linelen = getLine(doc, pos.line).text.length;
20.2039 - if (ch == null || ch > linelen) return {line: pos.line, ch: linelen};
20.2040 - else if (ch < 0) return {line: pos.line, ch: 0};
20.2041 - else return pos;
20.2042 - }
20.2043 - function isLine(doc, l) {return l >= 0 && l < doc.size;}
20.2044 -
20.2045 - // If shift is held, this will move the selection anchor. Otherwise,
20.2046 - // it'll set the whole selection.
20.2047 - function extendSelection(cm, pos, other, bias) {
20.2048 - var sel = cm.view.sel;
20.2049 - if (sel.shift || sel.extend) {
20.2050 - var anchor = sel.anchor;
20.2051 - if (other) {
20.2052 - var posBefore = posLess(pos, anchor);
20.2053 - if (posBefore != posLess(other, anchor)) {
20.2054 - anchor = pos;
20.2055 - pos = other;
20.2056 - } else if (posBefore != posLess(pos, other)) {
20.2057 - pos = other;
20.2058 - }
20.2059 - }
20.2060 - setSelection(cm, anchor, pos, bias);
20.2061 - } else {
20.2062 - setSelection(cm, pos, other || pos, bias);
20.2063 - }
20.2064 - cm.curOp.userSelChange = true;
20.2065 - }
20.2066 -
20.2067 - // Update the selection. Last two args are only used by
20.2068 - // updateDoc, since they have to be expressed in the line
20.2069 - // numbers before the update.
20.2070 - function setSelection(cm, anchor, head, bias, checkAtomic) {
20.2071 - cm.view.goalColumn = null;
20.2072 - var sel = cm.view.sel;
20.2073 - // Skip over atomic spans.
20.2074 - if (checkAtomic || !posEq(anchor, sel.anchor))
20.2075 - anchor = skipAtomic(cm, anchor, bias, checkAtomic != "push");
20.2076 - if (checkAtomic || !posEq(head, sel.head))
20.2077 - head = skipAtomic(cm, head, bias, checkAtomic != "push");
20.2078 -
20.2079 - if (posEq(sel.anchor, anchor) && posEq(sel.head, head)) return;
20.2080 -
20.2081 - sel.anchor = anchor; sel.head = head;
20.2082 - var inv = posLess(head, anchor);
20.2083 - sel.from = inv ? head : anchor;
20.2084 - sel.to = inv ? anchor : head;
20.2085 -
20.2086 - cm.curOp.updateInput = true;
20.2087 - cm.curOp.selectionChanged = true;
20.2088 - }
20.2089 -
20.2090 - function reCheckSelection(cm) {
20.2091 - setSelection(cm, cm.view.sel.from, cm.view.sel.to, null, "push");
20.2092 - }
20.2093 -
20.2094 - function skipAtomic(cm, pos, bias, mayClear) {
20.2095 - var doc = cm.view.doc, flipped = false, curPos = pos;
20.2096 - var dir = bias || 1;
20.2097 - cm.view.cantEdit = false;
20.2098 - search: for (;;) {
20.2099 - var line = getLine(doc, curPos.line), toClear;
20.2100 - if (line.markedSpans) {
20.2101 - for (var i = 0; i < line.markedSpans.length; ++i) {
20.2102 - var sp = line.markedSpans[i], m = sp.marker;
20.2103 - if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
20.2104 - (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
20.2105 - if (mayClear && m.clearOnEnter) {
20.2106 - (toClear || (toClear = [])).push(m);
20.2107 - continue;
20.2108 - } else if (!m.atomic) continue;
20.2109 - var newPos = m.find()[dir < 0 ? "from" : "to"];
20.2110 - if (posEq(newPos, curPos)) {
20.2111 - newPos.ch += dir;
20.2112 - if (newPos.ch < 0) {
20.2113 - if (newPos.line) newPos = clipPos(doc, {line: newPos.line - 1});
20.2114 - else newPos = null;
20.2115 - } else if (newPos.ch > line.text.length) {
20.2116 - if (newPos.line < doc.size - 1) newPos = {line: newPos.line + 1, ch: 0};
20.2117 - else newPos = null;
20.2118 - }
20.2119 - if (!newPos) {
20.2120 - if (flipped) {
20.2121 - // Driven in a corner -- no valid cursor position found at all
20.2122 - // -- try again *with* clearing, if we didn't already
20.2123 - if (!mayClear) return skipAtomic(cm, pos, bias, true);
20.2124 - // Otherwise, turn off editing until further notice, and return the start of the doc
20.2125 - cm.view.cantEdit = true;
20.2126 - return {line: 0, ch: 0};
20.2127 - }
20.2128 - flipped = true; newPos = pos; dir = -dir;
20.2129 - }
20.2130 - }
20.2131 - curPos = newPos;
20.2132 - continue search;
20.2133 - }
20.2134 - }
20.2135 - if (toClear) for (var i = 0; i < toClear.length; ++i) toClear[i].clear();
20.2136 - }
20.2137 - return curPos;
20.2138 - }
20.2139 - }
20.2140 -
20.2141 - // SCROLLING
20.2142 -
20.2143 - function scrollCursorIntoView(cm) {
20.2144 - var view = cm.view;
20.2145 - var coords = scrollPosIntoView(cm, view.sel.head);
20.2146 - if (!view.focused) return;
20.2147 - var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
20.2148 - if (coords.top + box.top < 0) doScroll = true;
20.2149 - else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
20.2150 - if (doScroll != null && !phantom) {
20.2151 - var hidden = display.cursor.style.display == "none";
20.2152 - if (hidden) {
20.2153 - display.cursor.style.display = "";
20.2154 - display.cursor.style.left = coords.left + "px";
20.2155 - display.cursor.style.top = (coords.top - display.viewOffset) + "px";
20.2156 - }
20.2157 - display.cursor.scrollIntoView(doScroll);
20.2158 - if (hidden) display.cursor.style.display = "none";
20.2159 - }
20.2160 - }
20.2161 -
20.2162 - function scrollPosIntoView(cm, pos) {
20.2163 - for (;;) {
20.2164 - var changed = false, coords = cursorCoords(cm, pos);
20.2165 - var scrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom);
20.2166 - var startTop = cm.view.scrollTop, startLeft = cm.view.scrollLeft;
20.2167 - if (scrollPos.scrollTop != null) {
20.2168 - setScrollTop(cm, scrollPos.scrollTop);
20.2169 - if (Math.abs(cm.view.scrollTop - startTop) > 1) changed = true;
20.2170 - }
20.2171 - if (scrollPos.scrollLeft != null) {
20.2172 - setScrollLeft(cm, scrollPos.scrollLeft);
20.2173 - if (Math.abs(cm.view.scrollLeft - startLeft) > 1) changed = true;
20.2174 - }
20.2175 - if (!changed) return coords;
20.2176 - }
20.2177 - }
20.2178 -
20.2179 - function scrollIntoView(cm, x1, y1, x2, y2) {
20.2180 - var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
20.2181 - if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
20.2182 - if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
20.2183 - }
20.2184 -
20.2185 - function calculateScrollPos(cm, x1, y1, x2, y2) {
20.2186 - var display = cm.display, pt = paddingTop(display);
20.2187 - y1 += pt; y2 += pt;
20.2188 - var screen = display.scroller.clientHeight - scrollerCutOff, screentop = display.scroller.scrollTop, result = {};
20.2189 - var docBottom = cm.view.doc.height + 2 * pt;
20.2190 - var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10;
20.2191 - if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
20.2192 - else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen;
20.2193 -
20.2194 - var screenw = display.scroller.clientWidth - scrollerCutOff, screenleft = display.scroller.scrollLeft;
20.2195 - x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth;
20.2196 - var gutterw = display.gutters.offsetWidth;
20.2197 - var atLeft = x1 < gutterw + 10;
20.2198 - if (x1 < screenleft + gutterw || atLeft) {
20.2199 - if (atLeft) x1 = 0;
20.2200 - result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
20.2201 - } else if (x2 > screenw + screenleft - 3) {
20.2202 - result.scrollLeft = x2 + 10 - screenw;
20.2203 - }
20.2204 - return result;
20.2205 - }
20.2206 -
20.2207 - // API UTILITIES
20.2208 -
20.2209 - function indentLine(cm, n, how, aggressive) {
20.2210 - var doc = cm.view.doc;
20.2211 - if (!how) how = "add";
20.2212 - if (how == "smart") {
20.2213 - if (!cm.view.mode.indent) how = "prev";
20.2214 - else var state = getStateBefore(cm, n);
20.2215 - }
20.2216 -
20.2217 - var tabSize = cm.options.tabSize;
20.2218 - var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
20.2219 - var curSpaceString = line.text.match(/^\s*/)[0], indentation;
20.2220 - if (how == "smart") {
20.2221 - indentation = cm.view.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
20.2222 - if (indentation == Pass) {
20.2223 - if (!aggressive) return;
20.2224 - how = "prev";
20.2225 - }
20.2226 - }
20.2227 - if (how == "prev") {
20.2228 - if (n) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
20.2229 - else indentation = 0;
20.2230 - }
20.2231 - else if (how == "add") indentation = curSpace + cm.options.indentUnit;
20.2232 - else if (how == "subtract") indentation = curSpace - cm.options.indentUnit;
20.2233 - indentation = Math.max(0, indentation);
20.2234 -
20.2235 - var indentString = "", pos = 0;
20.2236 - if (cm.options.indentWithTabs)
20.2237 - for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
20.2238 - if (pos < indentation) indentString += spaceStr(indentation - pos);
20.2239 -
20.2240 - if (indentString != curSpaceString)
20.2241 - replaceRange(cm, indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length}, "input");
20.2242 - line.stateAfter = null;
20.2243 - }
20.2244 -
20.2245 - function changeLine(cm, handle, op) {
20.2246 - var no = handle, line = handle, doc = cm.view.doc;
20.2247 - if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
20.2248 - else no = lineNo(handle);
20.2249 - if (no == null) return null;
20.2250 - if (op(line, no)) regChange(cm, no, no + 1);
20.2251 - else return null;
20.2252 - return line;
20.2253 - }
20.2254 -
20.2255 - function findPosH(cm, dir, unit, visually) {
20.2256 - var doc = cm.view.doc, end = cm.view.sel.head, line = end.line, ch = end.ch;
20.2257 - var lineObj = getLine(doc, line);
20.2258 - function findNextLine() {
20.2259 - var l = line + dir;
20.2260 - if (l < 0 || l == doc.size) return false;
20.2261 - line = l;
20.2262 - return lineObj = getLine(doc, l);
20.2263 - }
20.2264 - function moveOnce(boundToLine) {
20.2265 - var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
20.2266 - if (next == null) {
20.2267 - if (!boundToLine && findNextLine()) {
20.2268 - if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
20.2269 - else ch = dir < 0 ? lineObj.text.length : 0;
20.2270 - } else return false;
20.2271 - } else ch = next;
20.2272 - return true;
20.2273 - }
20.2274 - if (unit == "char") moveOnce();
20.2275 - else if (unit == "column") moveOnce(true);
20.2276 - else if (unit == "word") {
20.2277 - var sawWord = false;
20.2278 - for (;;) {
20.2279 - if (dir < 0) if (!moveOnce()) break;
20.2280 - if (isWordChar(lineObj.text.charAt(ch))) sawWord = true;
20.2281 - else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;}
20.2282 - if (dir > 0) if (!moveOnce()) break;
20.2283 - }
20.2284 - }
20.2285 - return skipAtomic(cm, {line: line, ch: ch}, dir, true);
20.2286 - }
20.2287 -
20.2288 - function findWordAt(line, pos) {
20.2289 - var start = pos.ch, end = pos.ch;
20.2290 - if (line) {
20.2291 - if (pos.after === false || end == line.length) --start; else ++end;
20.2292 - var startChar = line.charAt(start);
20.2293 - var check = isWordChar(startChar) ? isWordChar :
20.2294 - /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} :
20.2295 - function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
20.2296 - while (start > 0 && check(line.charAt(start - 1))) --start;
20.2297 - while (end < line.length && check(line.charAt(end))) ++end;
20.2298 - }
20.2299 - return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}};
20.2300 - }
20.2301 -
20.2302 - function selectLine(cm, line) {
20.2303 - extendSelection(cm, {line: line, ch: 0}, clipPos(cm.view.doc, {line: line + 1, ch: 0}));
20.2304 - }
20.2305 -
20.2306 - // PROTOTYPE
20.2307 -
20.2308 - // The publicly visible API. Note that operation(null, f) means
20.2309 - // 'wrap f in an operation, performed on its `this` parameter'
20.2310 -
20.2311 - CodeMirror.prototype = {
20.2312 - getValue: function(lineSep) {
20.2313 - var text = [], doc = this.view.doc;
20.2314 - doc.iter(0, doc.size, function(line) { text.push(line.text); });
20.2315 - return text.join(lineSep || "\n");
20.2316 - },
20.2317 -
20.2318 - setValue: operation(null, function(code) {
20.2319 - var doc = this.view.doc, top = {line: 0, ch: 0}, lastLen = getLine(doc, doc.size-1).text.length;
20.2320 - updateDocInner(this, top, {line: doc.size - 1, ch: lastLen}, splitLines(code), top, top, "setValue");
20.2321 - }),
20.2322 -
20.2323 - getSelection: function(lineSep) { return this.getRange(this.view.sel.from, this.view.sel.to, lineSep); },
20.2324 -
20.2325 - replaceSelection: operation(null, function(code, collapse, origin) {
20.2326 - var sel = this.view.sel;
20.2327 - updateDoc(this, sel.from, sel.to, splitLines(code), collapse || "around", origin);
20.2328 - }),
20.2329 -
20.2330 - focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(this);},
20.2331 -
20.2332 - setOption: function(option, value) {
20.2333 - var options = this.options, old = options[option];
20.2334 - if (options[option] == value && option != "mode") return;
20.2335 - options[option] = value;
20.2336 - if (optionHandlers.hasOwnProperty(option))
20.2337 - operation(this, optionHandlers[option])(this, value, old);
20.2338 - },
20.2339 -
20.2340 - getOption: function(option) {return this.options[option];},
20.2341 -
20.2342 - getMode: function() {return this.view.mode;},
20.2343 -
20.2344 - addKeyMap: function(map) {
20.2345 - this.view.keyMaps.push(map);
20.2346 - },
20.2347 -
20.2348 - removeKeyMap: function(map) {
20.2349 - var maps = this.view.keyMaps;
20.2350 - for (var i = 0; i < maps.length; ++i)
20.2351 - if ((typeof map == "string" ? maps[i].name : maps[i]) == map) {
20.2352 - maps.splice(i, 1);
20.2353 - return true;
20.2354 - }
20.2355 - },
20.2356 -
20.2357 - undo: operation(null, function() {unredoHelper(this, "undo");}),
20.2358 - redo: operation(null, function() {unredoHelper(this, "redo");}),
20.2359 -
20.2360 - indentLine: operation(null, function(n, dir, aggressive) {
20.2361 - if (typeof dir != "string") {
20.2362 - if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
20.2363 - else dir = dir ? "add" : "subtract";
20.2364 - }
20.2365 - if (isLine(this.view.doc, n)) indentLine(this, n, dir, aggressive);
20.2366 - }),
20.2367 -
20.2368 - indentSelection: operation(null, function(how) {
20.2369 - var sel = this.view.sel;
20.2370 - if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how);
20.2371 - var e = sel.to.line - (sel.to.ch ? 0 : 1);
20.2372 - for (var i = sel.from.line; i <= e; ++i) indentLine(this, i, how);
20.2373 - }),
20.2374 -
20.2375 - historySize: function() {
20.2376 - var hist = this.view.history;
20.2377 - return {undo: hist.done.length, redo: hist.undone.length};
20.2378 - },
20.2379 -
20.2380 - clearHistory: function() {this.view.history = makeHistory();},
20.2381 -
20.2382 - markClean: function() {
20.2383 - this.view.history.dirtyCounter = 0;
20.2384 - this.view.history.lastOp = this.view.history.lastOrigin = null;
20.2385 - },
20.2386 -
20.2387 - isClean: function () {return this.view.history.dirtyCounter == 0;},
20.2388 -
20.2389 - getHistory: function() {
20.2390 - var hist = this.view.history;
20.2391 - function cp(arr) {
20.2392 - for (var i = 0, nw = [], nwelt; i < arr.length; ++i) {
20.2393 - var set = arr[i];
20.2394 - nw.push({events: nwelt = [], fromBefore: set.fromBefore, toBefore: set.toBefore,
20.2395 - fromAfter: set.fromAfter, toAfter: set.toAfter});
20.2396 - for (var j = 0, elt = set.events; j < elt.length; ++j) {
20.2397 - var old = [], cur = elt[j];
20.2398 - nwelt.push({start: cur.start, added: cur.added, old: old});
20.2399 - for (var k = 0; k < cur.old.length; ++k) old.push(hlText(cur.old[k]));
20.2400 - }
20.2401 - }
20.2402 - return nw;
20.2403 - }
20.2404 - return {done: cp(hist.done), undone: cp(hist.undone)};
20.2405 - },
20.2406 -
20.2407 - setHistory: function(histData) {
20.2408 - var hist = this.view.history = makeHistory();
20.2409 - hist.done = histData.done;
20.2410 - hist.undone = histData.undone;
20.2411 - },
20.2412 -
20.2413 - // Fetch the parser token for a given character. Useful for hacks
20.2414 - // that want to inspect the mode state (say, for completion).
20.2415 - getTokenAt: function(pos) {
20.2416 - var doc = this.view.doc;
20.2417 - pos = clipPos(doc, pos);
20.2418 - var state = getStateBefore(this, pos.line), mode = this.view.mode;
20.2419 - var line = getLine(doc, pos.line);
20.2420 - var stream = new StringStream(line.text, this.options.tabSize);
20.2421 - while (stream.pos < pos.ch && !stream.eol()) {
20.2422 - stream.start = stream.pos;
20.2423 - var style = mode.token(stream, state);
20.2424 - }
20.2425 - return {start: stream.start,
20.2426 - end: stream.pos,
20.2427 - string: stream.current(),
20.2428 - className: style || null, // Deprecated, use 'type' instead
20.2429 - type: style || null,
20.2430 - state: state};
20.2431 - },
20.2432 -
20.2433 - getStateAfter: function(line) {
20.2434 - var doc = this.view.doc;
20.2435 - line = clipLine(doc, line == null ? doc.size - 1: line);
20.2436 - return getStateBefore(this, line + 1);
20.2437 - },
20.2438 -
20.2439 - cursorCoords: function(start, mode) {
20.2440 - var pos, sel = this.view.sel;
20.2441 - if (start == null) pos = sel.head;
20.2442 - else if (typeof start == "object") pos = clipPos(this.view.doc, start);
20.2443 - else pos = start ? sel.from : sel.to;
20.2444 - return cursorCoords(this, pos, mode || "page");
20.2445 - },
20.2446 -
20.2447 - charCoords: function(pos, mode) {
20.2448 - return charCoords(this, clipPos(this.view.doc, pos), mode || "page");
20.2449 - },
20.2450 -
20.2451 - coordsChar: function(coords) {
20.2452 - var off = this.display.lineSpace.getBoundingClientRect();
20.2453 - return coordsChar(this, coords.left - off.left, coords.top - off.top);
20.2454 - },
20.2455 -
20.2456 - defaultTextHeight: function() { return textHeight(this.display); },
20.2457 -
20.2458 - markText: operation(null, function(from, to, options) {
20.2459 - return markText(this, clipPos(this.view.doc, from), clipPos(this.view.doc, to),
20.2460 - options, "range");
20.2461 - }),
20.2462 -
20.2463 - setBookmark: operation(null, function(pos, widget) {
20.2464 - pos = clipPos(this.view.doc, pos);
20.2465 - return markText(this, pos, pos, widget ? {replacedWith: widget} : {}, "bookmark");
20.2466 - }),
20.2467 -
20.2468 - findMarksAt: function(pos) {
20.2469 - var doc = this.view.doc;
20.2470 - pos = clipPos(doc, pos);
20.2471 - var markers = [], spans = getLine(doc, pos.line).markedSpans;
20.2472 - if (spans) for (var i = 0; i < spans.length; ++i) {
20.2473 - var span = spans[i];
20.2474 - if ((span.from == null || span.from <= pos.ch) &&
20.2475 - (span.to == null || span.to >= pos.ch))
20.2476 - markers.push(span.marker);
20.2477 - }
20.2478 - return markers;
20.2479 - },
20.2480 -
20.2481 - setGutterMarker: operation(null, function(line, gutterID, value) {
20.2482 - return changeLine(this, line, function(line) {
20.2483 - var markers = line.gutterMarkers || (line.gutterMarkers = {});
20.2484 - markers[gutterID] = value;
20.2485 - if (!value && isEmpty(markers)) line.gutterMarkers = null;
20.2486 - return true;
20.2487 - });
20.2488 - }),
20.2489 -
20.2490 - clearGutter: operation(null, function(gutterID) {
20.2491 - var i = 0, cm = this, doc = cm.view.doc;
20.2492 - doc.iter(0, doc.size, function(line) {
20.2493 - if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
20.2494 - line.gutterMarkers[gutterID] = null;
20.2495 - regChange(cm, i, i + 1);
20.2496 - if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
20.2497 - }
20.2498 - ++i;
20.2499 - });
20.2500 - }),
20.2501 -
20.2502 - addLineClass: operation(null, function(handle, where, cls) {
20.2503 - return changeLine(this, handle, function(line) {
20.2504 - var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
20.2505 - if (!line[prop]) line[prop] = cls;
20.2506 - else if (new RegExp("\\b" + cls + "\\b").test(line[prop])) return false;
20.2507 - else line[prop] += " " + cls;
20.2508 - return true;
20.2509 - });
20.2510 - }),
20.2511 -
20.2512 - removeLineClass: operation(null, function(handle, where, cls) {
20.2513 - return changeLine(this, handle, function(line) {
20.2514 - var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : "wrapClass";
20.2515 - var cur = line[prop];
20.2516 - if (!cur) return false;
20.2517 - else if (cls == null) line[prop] = null;
20.2518 - else {
20.2519 - var upd = cur.replace(new RegExp("^" + cls + "\\b\\s*|\\s*\\b" + cls + "\\b"), "");
20.2520 - if (upd == cur) return false;
20.2521 - line[prop] = upd || null;
20.2522 - }
20.2523 - return true;
20.2524 - });
20.2525 - }),
20.2526 -
20.2527 - addLineWidget: operation(null, function(handle, node, options) {
20.2528 - var widget = options || {};
20.2529 - widget.node = node;
20.2530 - if (widget.noHScroll) this.display.alignWidgets = true;
20.2531 - changeLine(this, handle, function(line) {
20.2532 - (line.widgets || (line.widgets = [])).push(widget);
20.2533 - widget.line = line;
20.2534 - return true;
20.2535 - });
20.2536 - return widget;
20.2537 - }),
20.2538 -
20.2539 - removeLineWidget: operation(null, function(widget) {
20.2540 - var ws = widget.line.widgets, no = lineNo(widget.line);
20.2541 - if (no == null) return;
20.2542 - for (var i = 0; i < ws.length; ++i) if (ws[i] == widget) ws.splice(i--, 1);
20.2543 - regChange(this, no, no + 1);
20.2544 - }),
20.2545 -
20.2546 - lineInfo: function(line) {
20.2547 - if (typeof line == "number") {
20.2548 - if (!isLine(this.view.doc, line)) return null;
20.2549 - var n = line;
20.2550 - line = getLine(this.view.doc, line);
20.2551 - if (!line) return null;
20.2552 - } else {
20.2553 - var n = lineNo(line);
20.2554 - if (n == null) return null;
20.2555 - }
20.2556 - return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
20.2557 - textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
20.2558 - widgets: line.widgets};
20.2559 - },
20.2560 -
20.2561 - getViewport: function() { return {from: this.display.showingFrom, to: this.display.showingTo};},
20.2562 -
20.2563 - addWidget: function(pos, node, scroll, vert, horiz) {
20.2564 - var display = this.display;
20.2565 - pos = cursorCoords(this, clipPos(this.view.doc, pos));
20.2566 - var top = pos.top, left = pos.left;
20.2567 - node.style.position = "absolute";
20.2568 - display.sizer.appendChild(node);
20.2569 - if (vert == "over") top = pos.top;
20.2570 - else if (vert == "near") {
20.2571 - var vspace = Math.max(display.wrapper.clientHeight, this.view.doc.height),
20.2572 - hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
20.2573 - if (pos.bottom + node.offsetHeight > vspace && pos.top > node.offsetHeight)
20.2574 - top = pos.top - node.offsetHeight;
20.2575 - if (left + node.offsetWidth > hspace)
20.2576 - left = hspace - node.offsetWidth;
20.2577 - }
20.2578 - node.style.top = (top + paddingTop(display)) + "px";
20.2579 - node.style.left = node.style.right = "";
20.2580 - if (horiz == "right") {
20.2581 - left = display.sizer.clientWidth - node.offsetWidth;
20.2582 - node.style.right = "0px";
20.2583 - } else {
20.2584 - if (horiz == "left") left = 0;
20.2585 - else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
20.2586 - node.style.left = left + "px";
20.2587 - }
20.2588 - if (scroll)
20.2589 - scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
20.2590 - },
20.2591 -
20.2592 - lineCount: function() {return this.view.doc.size;},
20.2593 -
20.2594 - clipPos: function(pos) {return clipPos(this.view.doc, pos);},
20.2595 -
20.2596 - getCursor: function(start) {
20.2597 - var sel = this.view.sel, pos;
20.2598 - if (start == null || start == "head") pos = sel.head;
20.2599 - else if (start == "anchor") pos = sel.anchor;
20.2600 - else if (start == "end" || start === false) pos = sel.to;
20.2601 - else pos = sel.from;
20.2602 - return copyPos(pos);
20.2603 - },
20.2604 -
20.2605 - somethingSelected: function() {return !posEq(this.view.sel.from, this.view.sel.to);},
20.2606 -
20.2607 - setCursor: operation(null, function(line, ch, extend) {
20.2608 - var pos = clipPos(this.view.doc, typeof line == "number" ? {line: line, ch: ch || 0} : line);
20.2609 - if (extend) extendSelection(this, pos);
20.2610 - else setSelection(this, pos, pos);
20.2611 - }),
20.2612 -
20.2613 - setSelection: operation(null, function(anchor, head) {
20.2614 - var doc = this.view.doc;
20.2615 - setSelection(this, clipPos(doc, anchor), clipPos(doc, head || anchor));
20.2616 - }),
20.2617 -
20.2618 - extendSelection: operation(null, function(from, to) {
20.2619 - var doc = this.view.doc;
20.2620 - extendSelection(this, clipPos(doc, from), to && clipPos(doc, to));
20.2621 - }),
20.2622 -
20.2623 - setExtending: function(val) {this.view.sel.extend = val;},
20.2624 -
20.2625 - getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
20.2626 -
20.2627 - getLineHandle: function(line) {
20.2628 - var doc = this.view.doc;
20.2629 - if (isLine(doc, line)) return getLine(doc, line);
20.2630 - },
20.2631 -
20.2632 - getLineNumber: function(line) {return lineNo(line);},
20.2633 -
20.2634 - setLine: operation(null, function(line, text) {
20.2635 - if (isLine(this.view.doc, line))
20.2636 - replaceRange(this, text, {line: line, ch: 0}, {line: line, ch: getLine(this.view.doc, line).text.length});
20.2637 - }),
20.2638 -
20.2639 - removeLine: operation(null, function(line) {
20.2640 - if (isLine(this.view.doc, line))
20.2641 - replaceRange(this, "", {line: line, ch: 0}, clipPos(this.view.doc, {line: line+1, ch: 0}));
20.2642 - }),
20.2643 -
20.2644 - replaceRange: operation(null, function(code, from, to) {
20.2645 - var doc = this.view.doc;
20.2646 - from = clipPos(doc, from);
20.2647 - to = to ? clipPos(doc, to) : from;
20.2648 - return replaceRange(this, code, from, to);
20.2649 - }),
20.2650 -
20.2651 - getRange: function(from, to, lineSep) {
20.2652 - var doc = this.view.doc;
20.2653 - from = clipPos(doc, from); to = clipPos(doc, to);
20.2654 - var l1 = from.line, l2 = to.line;
20.2655 - if (l1 == l2) return getLine(doc, l1).text.slice(from.ch, to.ch);
20.2656 - var code = [getLine(doc, l1).text.slice(from.ch)];
20.2657 - doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
20.2658 - code.push(getLine(doc, l2).text.slice(0, to.ch));
20.2659 - return code.join(lineSep || "\n");
20.2660 - },
20.2661 -
20.2662 - triggerOnKeyDown: operation(null, onKeyDown),
20.2663 -
20.2664 - execCommand: function(cmd) {return commands[cmd](this);},
20.2665 -
20.2666 - // Stuff used by commands, probably not much use to outside code.
20.2667 - moveH: operation(null, function(dir, unit) {
20.2668 - var sel = this.view.sel, pos = dir < 0 ? sel.from : sel.to;
20.2669 - if (sel.shift || sel.extend || posEq(sel.from, sel.to)) pos = findPosH(this, dir, unit, true);
20.2670 - extendSelection(this, pos, pos, dir);
20.2671 - }),
20.2672 -
20.2673 - deleteH: operation(null, function(dir, unit) {
20.2674 - var sel = this.view.sel;
20.2675 - if (!posEq(sel.from, sel.to)) replaceRange(this, "", sel.from, sel.to, "delete");
20.2676 - else replaceRange(this, "", sel.from, findPosH(this, dir, unit, false), "delete");
20.2677 - this.curOp.userSelChange = true;
20.2678 - }),
20.2679 -
20.2680 - moveV: operation(null, function(dir, unit) {
20.2681 - var view = this.view, doc = view.doc, display = this.display;
20.2682 - var cur = view.sel.head, pos = cursorCoords(this, cur, "div");
20.2683 - var x = pos.left, y;
20.2684 - if (view.goalColumn != null) x = view.goalColumn;
20.2685 - if (unit == "page") {
20.2686 - var pageSize = Math.min(display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
20.2687 - y = pos.top + dir * pageSize;
20.2688 - } else if (unit == "line") {
20.2689 - y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
20.2690 - }
20.2691 - do {
20.2692 - var target = coordsChar(this, x, y);
20.2693 - y += dir * 5;
20.2694 - } while (target.outside && (dir < 0 ? y > 0 : y < doc.height));
20.2695 -
20.2696 - if (unit == "page") display.scrollbarV.scrollTop += charCoords(this, target, "div").top - pos.top;
20.2697 - extendSelection(this, target, target, dir);
20.2698 - view.goalColumn = x;
20.2699 - }),
20.2700 -
20.2701 - toggleOverwrite: function() {
20.2702 - if (this.view.overwrite = !this.view.overwrite)
20.2703 - this.display.cursor.className += " CodeMirror-overwrite";
20.2704 - else
20.2705 - this.display.cursor.className = this.display.cursor.className.replace(" CodeMirror-overwrite", "");
20.2706 - },
20.2707 -
20.2708 - posFromIndex: function(off) {
20.2709 - var lineNo = 0, ch, doc = this.view.doc;
20.2710 - doc.iter(0, doc.size, function(line) {
20.2711 - var sz = line.text.length + 1;
20.2712 - if (sz > off) { ch = off; return true; }
20.2713 - off -= sz;
20.2714 - ++lineNo;
20.2715 - });
20.2716 - return clipPos(doc, {line: lineNo, ch: ch});
20.2717 - },
20.2718 - indexFromPos: function (coords) {
20.2719 - if (coords.line < 0 || coords.ch < 0) return 0;
20.2720 - var index = coords.ch;
20.2721 - this.view.doc.iter(0, coords.line, function (line) {
20.2722 - index += line.text.length + 1;
20.2723 - });
20.2724 - return index;
20.2725 - },
20.2726 -
20.2727 - scrollTo: function(x, y) {
20.2728 - if (x != null) this.display.scrollbarH.scrollLeft = this.display.scroller.scrollLeft = x;
20.2729 - if (y != null) this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = y;
20.2730 - updateDisplay(this, []);
20.2731 - },
20.2732 - getScrollInfo: function() {
20.2733 - var scroller = this.display.scroller, co = scrollerCutOff;
20.2734 - return {left: scroller.scrollLeft, top: scroller.scrollTop,
20.2735 - height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
20.2736 - clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
20.2737 - },
20.2738 -
20.2739 - scrollIntoView: function(pos) {
20.2740 - if (typeof pos == "number") pos = {line: pos, ch: 0};
20.2741 - pos = pos ? clipPos(this.view.doc, pos) : this.view.sel.head;
20.2742 - scrollPosIntoView(this, pos);
20.2743 - },
20.2744 -
20.2745 - setSize: function(width, height) {
20.2746 - function interpret(val) {
20.2747 - return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
20.2748 - }
20.2749 - if (width != null) this.display.wrapper.style.width = interpret(width);
20.2750 - if (height != null) this.display.wrapper.style.height = interpret(height);
20.2751 - this.refresh();
20.2752 - },
20.2753 -
20.2754 - on: function(type, f) {on(this, type, f);},
20.2755 - off: function(type, f) {off(this, type, f);},
20.2756 -
20.2757 - operation: function(f){return operation(this, f)();},
20.2758 -
20.2759 - refresh: function() {
20.2760 - clearCaches(this);
20.2761 - if (this.display.scroller.scrollHeight > this.view.scrollTop)
20.2762 - this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = this.view.scrollTop;
20.2763 - updateDisplay(this, true);
20.2764 - },
20.2765 -
20.2766 - getInputField: function(){return this.display.input;},
20.2767 - getWrapperElement: function(){return this.display.wrapper;},
20.2768 - getScrollerElement: function(){return this.display.scroller;},
20.2769 - getGutterElement: function(){return this.display.gutters;}
20.2770 - };
20.2771 -
20.2772 - // OPTION DEFAULTS
20.2773 -
20.2774 - var optionHandlers = CodeMirror.optionHandlers = {};
20.2775 -
20.2776 - // The default configuration options.
20.2777 - var defaults = CodeMirror.defaults = {};
20.2778 -
20.2779 - function option(name, deflt, handle, notOnInit) {
20.2780 - CodeMirror.defaults[name] = deflt;
20.2781 - if (handle) optionHandlers[name] =
20.2782 - notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
20.2783 - }
20.2784 -
20.2785 - var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
20.2786 -
20.2787 - // These two are, on init, called from the constructor because they
20.2788 - // have to be initialized before the editor can start at all.
20.2789 - option("value", "", function(cm, val) {cm.setValue(val);}, true);
20.2790 - option("mode", null, loadMode, true);
20.2791 -
20.2792 - option("indentUnit", 2, loadMode, true);
20.2793 - option("indentWithTabs", false);
20.2794 - option("smartIndent", true);
20.2795 - option("tabSize", 4, function(cm) {
20.2796 - loadMode(cm);
20.2797 - clearCaches(cm);
20.2798 - updateDisplay(cm, true);
20.2799 - }, true);
20.2800 - option("electricChars", true);
20.2801 -
20.2802 - option("theme", "default", function(cm) {
20.2803 - themeChanged(cm);
20.2804 - guttersChanged(cm);
20.2805 - }, true);
20.2806 - option("keyMap", "default", keyMapChanged);
20.2807 - option("extraKeys", null);
20.2808 -
20.2809 - option("onKeyEvent", null);
20.2810 - option("onDragEvent", null);
20.2811 -
20.2812 - option("lineWrapping", false, wrappingChanged, true);
20.2813 - option("gutters", [], function(cm) {
20.2814 - setGuttersForLineNumbers(cm.options);
20.2815 - guttersChanged(cm);
20.2816 - }, true);
20.2817 - option("lineNumbers", false, function(cm) {
20.2818 - setGuttersForLineNumbers(cm.options);
20.2819 - guttersChanged(cm);
20.2820 - }, true);
20.2821 - option("firstLineNumber", 1, guttersChanged, true);
20.2822 - option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
20.2823 - option("showCursorWhenSelecting", false, updateSelection, true);
20.2824 -
20.2825 - option("readOnly", false, function(cm, val) {
20.2826 - if (val == "nocursor") {onBlur(cm); cm.display.input.blur();}
20.2827 - else if (!val) resetInput(cm, true);
20.2828 - });
20.2829 - option("dragDrop", true);
20.2830 -
20.2831 - option("cursorBlinkRate", 530);
20.2832 - option("cursorHeight", 1);
20.2833 - option("workTime", 100);
20.2834 - option("workDelay", 100);
20.2835 - option("flattenSpans", true);
20.2836 - option("pollInterval", 100);
20.2837 - option("undoDepth", 40);
20.2838 - option("viewportMargin", 10, function(cm){cm.refresh();}, true);
20.2839 -
20.2840 - option("tabindex", null, function(cm, val) {
20.2841 - cm.display.input.tabIndex = val || "";
20.2842 - });
20.2843 - option("autofocus", null);
20.2844 -
20.2845 - // MODE DEFINITION AND QUERYING
20.2846 -
20.2847 - // Known modes, by name and by MIME
20.2848 - var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
20.2849 -
20.2850 - CodeMirror.defineMode = function(name, mode) {
20.2851 - if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
20.2852 - if (arguments.length > 2) {
20.2853 - mode.dependencies = [];
20.2854 - for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
20.2855 - }
20.2856 - modes[name] = mode;
20.2857 - };
20.2858 -
20.2859 - CodeMirror.defineMIME = function(mime, spec) {
20.2860 - mimeModes[mime] = spec;
20.2861 - };
20.2862 -
20.2863 - CodeMirror.resolveMode = function(spec) {
20.2864 - if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
20.2865 - spec = mimeModes[spec];
20.2866 - else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
20.2867 - return CodeMirror.resolveMode("application/xml");
20.2868 - if (typeof spec == "string") return {name: spec};
20.2869 - else return spec || {name: "null"};
20.2870 - };
20.2871 -
20.2872 - CodeMirror.getMode = function(options, spec) {
20.2873 - var spec = CodeMirror.resolveMode(spec);
20.2874 - var mfactory = modes[spec.name];
20.2875 - if (!mfactory) return CodeMirror.getMode(options, "text/plain");
20.2876 - var modeObj = mfactory(options, spec);
20.2877 - if (modeExtensions.hasOwnProperty(spec.name)) {
20.2878 - var exts = modeExtensions[spec.name];
20.2879 - for (var prop in exts) {
20.2880 - if (!exts.hasOwnProperty(prop)) continue;
20.2881 - if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
20.2882 - modeObj[prop] = exts[prop];
20.2883 - }
20.2884 - }
20.2885 - modeObj.name = spec.name;
20.2886 - return modeObj;
20.2887 - };
20.2888 -
20.2889 - CodeMirror.defineMode("null", function() {
20.2890 - return {token: function(stream) {stream.skipToEnd();}};
20.2891 - });
20.2892 - CodeMirror.defineMIME("text/plain", "null");
20.2893 -
20.2894 - var modeExtensions = CodeMirror.modeExtensions = {};
20.2895 - CodeMirror.extendMode = function(mode, properties) {
20.2896 - var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
20.2897 - for (var prop in properties) if (properties.hasOwnProperty(prop))
20.2898 - exts[prop] = properties[prop];
20.2899 - };
20.2900 -
20.2901 - // EXTENSIONS
20.2902 -
20.2903 - CodeMirror.defineExtension = function(name, func) {
20.2904 - CodeMirror.prototype[name] = func;
20.2905 - };
20.2906 -
20.2907 - CodeMirror.defineOption = option;
20.2908 -
20.2909 - var initHooks = [];
20.2910 - CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
20.2911 -
20.2912 - // MODE STATE HANDLING
20.2913 -
20.2914 - // Utility functions for working with state. Exported because modes
20.2915 - // sometimes need to do this.
20.2916 - function copyState(mode, state) {
20.2917 - if (state === true) return state;
20.2918 - if (mode.copyState) return mode.copyState(state);
20.2919 - var nstate = {};
20.2920 - for (var n in state) {
20.2921 - var val = state[n];
20.2922 - if (val instanceof Array) val = val.concat([]);
20.2923 - nstate[n] = val;
20.2924 - }
20.2925 - return nstate;
20.2926 - }
20.2927 - CodeMirror.copyState = copyState;
20.2928 -
20.2929 - function startState(mode, a1, a2) {
20.2930 - return mode.startState ? mode.startState(a1, a2) : true;
20.2931 - }
20.2932 - CodeMirror.startState = startState;
20.2933 -
20.2934 - CodeMirror.innerMode = function(mode, state) {
20.2935 - while (mode.innerMode) {
20.2936 - var info = mode.innerMode(state);
20.2937 - state = info.state;
20.2938 - mode = info.mode;
20.2939 - }
20.2940 - return info || {mode: mode, state: state};
20.2941 - };
20.2942 -
20.2943 - // STANDARD COMMANDS
20.2944 -
20.2945 - var commands = CodeMirror.commands = {
20.2946 - selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});},
20.2947 - killLine: function(cm) {
20.2948 - var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to);
20.2949 - if (!sel && cm.getLine(from.line).length == from.ch)
20.2950 - cm.replaceRange("", from, {line: from.line + 1, ch: 0}, "delete");
20.2951 - else cm.replaceRange("", from, sel ? to : {line: from.line}, "delete");
20.2952 - },
20.2953 - deleteLine: function(cm) {
20.2954 - var l = cm.getCursor().line;
20.2955 - cm.replaceRange("", {line: l, ch: 0}, {line: l}, "delete");
20.2956 - },
20.2957 - undo: function(cm) {cm.undo();},
20.2958 - redo: function(cm) {cm.redo();},
20.2959 - goDocStart: function(cm) {cm.extendSelection({line: 0, ch: 0});},
20.2960 - goDocEnd: function(cm) {cm.extendSelection({line: cm.lineCount() - 1});},
20.2961 - goLineStart: function(cm) {
20.2962 - cm.extendSelection(lineStart(cm, cm.getCursor().line));
20.2963 - },
20.2964 - goLineStartSmart: function(cm) {
20.2965 - var cur = cm.getCursor(), start = lineStart(cm, cur.line);
20.2966 - var line = cm.getLineHandle(start.line);
20.2967 - var order = getOrder(line);
20.2968 - if (!order || order[0].level == 0) {
20.2969 - var firstNonWS = Math.max(0, line.text.search(/\S/));
20.2970 - var inWS = cur.line == start.line && cur.ch <= firstNonWS && cur.ch;
20.2971 - cm.extendSelection({line: start.line, ch: inWS ? 0 : firstNonWS});
20.2972 - } else cm.extendSelection(start);
20.2973 - },
20.2974 - goLineEnd: function(cm) {
20.2975 - cm.extendSelection(lineEnd(cm, cm.getCursor().line));
20.2976 - },
20.2977 - goLineUp: function(cm) {cm.moveV(-1, "line");},
20.2978 - goLineDown: function(cm) {cm.moveV(1, "line");},
20.2979 - goPageUp: function(cm) {cm.moveV(-1, "page");},
20.2980 - goPageDown: function(cm) {cm.moveV(1, "page");},
20.2981 - goCharLeft: function(cm) {cm.moveH(-1, "char");},
20.2982 - goCharRight: function(cm) {cm.moveH(1, "char");},
20.2983 - goColumnLeft: function(cm) {cm.moveH(-1, "column");},
20.2984 - goColumnRight: function(cm) {cm.moveH(1, "column");},
20.2985 - goWordLeft: function(cm) {cm.moveH(-1, "word");},
20.2986 - goWordRight: function(cm) {cm.moveH(1, "word");},
20.2987 - delCharBefore: function(cm) {cm.deleteH(-1, "char");},
20.2988 - delCharAfter: function(cm) {cm.deleteH(1, "char");},
20.2989 - delWordBefore: function(cm) {cm.deleteH(-1, "word");},
20.2990 - delWordAfter: function(cm) {cm.deleteH(1, "word");},
20.2991 - indentAuto: function(cm) {cm.indentSelection("smart");},
20.2992 - indentMore: function(cm) {cm.indentSelection("add");},
20.2993 - indentLess: function(cm) {cm.indentSelection("subtract");},
20.2994 - insertTab: function(cm) {cm.replaceSelection("\t", "end", "input");},
20.2995 - defaultTab: function(cm) {
20.2996 - if (cm.somethingSelected()) cm.indentSelection("add");
20.2997 - else cm.replaceSelection("\t", "end", "input");
20.2998 - },
20.2999 - transposeChars: function(cm) {
20.3000 - var cur = cm.getCursor(), line = cm.getLine(cur.line);
20.3001 - if (cur.ch > 0 && cur.ch < line.length - 1)
20.3002 - cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1),
20.3003 - {line: cur.line, ch: cur.ch - 1}, {line: cur.line, ch: cur.ch + 1});
20.3004 - },
20.3005 - newlineAndIndent: function(cm) {
20.3006 - operation(cm, function() {
20.3007 - cm.replaceSelection("\n", "end", "input");
20.3008 - cm.indentLine(cm.getCursor().line, null, true);
20.3009 - })();
20.3010 - },
20.3011 - toggleOverwrite: function(cm) {cm.toggleOverwrite();}
20.3012 - };
20.3013 -
20.3014 - // STANDARD KEYMAPS
20.3015 -
20.3016 - var keyMap = CodeMirror.keyMap = {};
20.3017 - keyMap.basic = {
20.3018 - "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
20.3019 - "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
20.3020 - "Delete": "delCharAfter", "Backspace": "delCharBefore", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
20.3021 - "Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
20.3022 - };
20.3023 - // Note that the save and find-related commands aren't defined by
20.3024 - // default. Unknown commands are simply ignored.
20.3025 - keyMap.pcDefault = {
20.3026 - "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
20.3027 - "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd",
20.3028 - "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
20.3029 - "Ctrl-Backspace": "delWordBefore", "Ctrl-Delete": "delWordAfter", "Ctrl-S": "save", "Ctrl-F": "find",
20.3030 - "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
20.3031 - "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
20.3032 - fallthrough: "basic"
20.3033 - };
20.3034 - keyMap.macDefault = {
20.3035 - "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
20.3036 - "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft",
20.3037 - "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordBefore",
20.3038 - "Ctrl-Alt-Backspace": "delWordAfter", "Alt-Delete": "delWordAfter", "Cmd-S": "save", "Cmd-F": "find",
20.3039 - "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
20.3040 - "Cmd-[": "indentLess", "Cmd-]": "indentMore",
20.3041 - fallthrough: ["basic", "emacsy"]
20.3042 - };
20.3043 - keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
20.3044 - keyMap.emacsy = {
20.3045 - "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
20.3046 - "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
20.3047 - "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
20.3048 - "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
20.3049 - };
20.3050 -
20.3051 - // KEYMAP DISPATCH
20.3052 -
20.3053 - function getKeyMap(val) {
20.3054 - if (typeof val == "string") return keyMap[val];
20.3055 - else return val;
20.3056 - }
20.3057 -
20.3058 - function lookupKey(name, maps, handle, stop) {
20.3059 - function lookup(map) {
20.3060 - map = getKeyMap(map);
20.3061 - var found = map[name];
20.3062 - if (found === false) {
20.3063 - if (stop) stop();
20.3064 - return true;
20.3065 - }
20.3066 - if (found != null && handle(found)) return true;
20.3067 - if (map.nofallthrough) {
20.3068 - if (stop) stop();
20.3069 - return true;
20.3070 - }
20.3071 - var fallthrough = map.fallthrough;
20.3072 - if (fallthrough == null) return false;
20.3073 - if (Object.prototype.toString.call(fallthrough) != "[object Array]")
20.3074 - return lookup(fallthrough);
20.3075 - for (var i = 0, e = fallthrough.length; i < e; ++i) {
20.3076 - if (lookup(fallthrough[i])) return true;
20.3077 - }
20.3078 - return false;
20.3079 - }
20.3080 -
20.3081 - for (var i = 0; i < maps.length; ++i)
20.3082 - if (lookup(maps[i])) return true;
20.3083 - }
20.3084 - function isModifierKey(event) {
20.3085 - var name = keyNames[e_prop(event, "keyCode")];
20.3086 - return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
20.3087 - }
20.3088 - CodeMirror.isModifierKey = isModifierKey;
20.3089 -
20.3090 - // FROMTEXTAREA
20.3091 -
20.3092 - CodeMirror.fromTextArea = function(textarea, options) {
20.3093 - if (!options) options = {};
20.3094 - options.value = textarea.value;
20.3095 - if (!options.tabindex && textarea.tabindex)
20.3096 - options.tabindex = textarea.tabindex;
20.3097 - // Set autofocus to true if this textarea is focused, or if it has
20.3098 - // autofocus and no other element is focused.
20.3099 - if (options.autofocus == null) {
20.3100 - var hasFocus = document.body;
20.3101 - // doc.activeElement occasionally throws on IE
20.3102 - try { hasFocus = document.activeElement; } catch(e) {}
20.3103 - options.autofocus = hasFocus == textarea ||
20.3104 - textarea.getAttribute("autofocus") != null && hasFocus == document.body;
20.3105 - }
20.3106 -
20.3107 - function save() {textarea.value = cm.getValue();}
20.3108 - if (textarea.form) {
20.3109 - // Deplorable hack to make the submit method do the right thing.
20.3110 - on(textarea.form, "submit", save);
20.3111 - var form = textarea.form, realSubmit = form.submit;
20.3112 - try {
20.3113 - form.submit = function wrappedSubmit() {
20.3114 - save();
20.3115 - form.submit = realSubmit;
20.3116 - form.submit();
20.3117 - form.submit = wrappedSubmit;
20.3118 - };
20.3119 - } catch(e) {}
20.3120 - }
20.3121 -
20.3122 - textarea.style.display = "none";
20.3123 - var cm = CodeMirror(function(node) {
20.3124 - textarea.parentNode.insertBefore(node, textarea.nextSibling);
20.3125 - }, options);
20.3126 - cm.save = save;
20.3127 - cm.getTextArea = function() { return textarea; };
20.3128 - cm.toTextArea = function() {
20.3129 - save();
20.3130 - textarea.parentNode.removeChild(cm.getWrapperElement());
20.3131 - textarea.style.display = "";
20.3132 - if (textarea.form) {
20.3133 - off(textarea.form, "submit", save);
20.3134 - if (typeof textarea.form.submit == "function")
20.3135 - textarea.form.submit = realSubmit;
20.3136 - }
20.3137 - };
20.3138 - return cm;
20.3139 - };
20.3140 -
20.3141 - // STRING STREAM
20.3142 -
20.3143 - // Fed to the mode parsers, provides helper functions to make
20.3144 - // parsers more succinct.
20.3145 -
20.3146 - // The character stream used by a mode's parser.
20.3147 - function StringStream(string, tabSize) {
20.3148 - this.pos = this.start = 0;
20.3149 - this.string = string;
20.3150 - this.tabSize = tabSize || 8;
20.3151 - }
20.3152 -
20.3153 - StringStream.prototype = {
20.3154 - eol: function() {return this.pos >= this.string.length;},
20.3155 - sol: function() {return this.pos == 0;},
20.3156 - peek: function() {return this.string.charAt(this.pos) || undefined;},
20.3157 - next: function() {
20.3158 - if (this.pos < this.string.length)
20.3159 - return this.string.charAt(this.pos++);
20.3160 - },
20.3161 - eat: function(match) {
20.3162 - var ch = this.string.charAt(this.pos);
20.3163 - if (typeof match == "string") var ok = ch == match;
20.3164 - else var ok = ch && (match.test ? match.test(ch) : match(ch));
20.3165 - if (ok) {++this.pos; return ch;}
20.3166 - },
20.3167 - eatWhile: function(match) {
20.3168 - var start = this.pos;
20.3169 - while (this.eat(match)){}
20.3170 - return this.pos > start;
20.3171 - },
20.3172 - eatSpace: function() {
20.3173 - var start = this.pos;
20.3174 - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
20.3175 - return this.pos > start;
20.3176 - },
20.3177 - skipToEnd: function() {this.pos = this.string.length;},
20.3178 - skipTo: function(ch) {
20.3179 - var found = this.string.indexOf(ch, this.pos);
20.3180 - if (found > -1) {this.pos = found; return true;}
20.3181 - },
20.3182 - backUp: function(n) {this.pos -= n;},
20.3183 - column: function() {return countColumn(this.string, this.start, this.tabSize);},
20.3184 - indentation: function() {return countColumn(this.string, null, this.tabSize);},
20.3185 - match: function(pattern, consume, caseInsensitive) {
20.3186 - if (typeof pattern == "string") {
20.3187 - var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
20.3188 - if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
20.3189 - if (consume !== false) this.pos += pattern.length;
20.3190 - return true;
20.3191 - }
20.3192 - } else {
20.3193 - var match = this.string.slice(this.pos).match(pattern);
20.3194 - if (match && match.index > 0) return null;
20.3195 - if (match && consume !== false) this.pos += match[0].length;
20.3196 - return match;
20.3197 - }
20.3198 - },
20.3199 - current: function(){return this.string.slice(this.start, this.pos);}
20.3200 - };
20.3201 - CodeMirror.StringStream = StringStream;
20.3202 -
20.3203 - // TEXTMARKERS
20.3204 -
20.3205 - function TextMarker(cm, type) {
20.3206 - this.lines = [];
20.3207 - this.type = type;
20.3208 - this.cm = cm;
20.3209 - }
20.3210 -
20.3211 - TextMarker.prototype.clear = function() {
20.3212 - if (this.explicitlyCleared) return;
20.3213 - startOperation(this.cm);
20.3214 - var min = null, max = null;
20.3215 - for (var i = 0; i < this.lines.length; ++i) {
20.3216 - var line = this.lines[i];
20.3217 - var span = getMarkedSpanFor(line.markedSpans, this);
20.3218 - if (span.to != null) max = lineNo(line);
20.3219 - line.markedSpans = removeMarkedSpan(line.markedSpans, span);
20.3220 - if (span.from != null)
20.3221 - min = lineNo(line);
20.3222 - else if (this.collapsed && !lineIsHidden(line))
20.3223 - updateLineHeight(line, textHeight(this.cm.display));
20.3224 - }
20.3225 - if (min != null) regChange(this.cm, min, max + 1);
20.3226 - this.lines.length = 0;
20.3227 - this.explicitlyCleared = true;
20.3228 - if (this.collapsed && this.cm.view.cantEdit) {
20.3229 - this.cm.view.cantEdit = false;
20.3230 - reCheckSelection(this.cm);
20.3231 - }
20.3232 - endOperation(this.cm);
20.3233 - signalLater(this.cm, this, "clear");
20.3234 - };
20.3235 -
20.3236 - TextMarker.prototype.find = function() {
20.3237 - var from, to;
20.3238 - for (var i = 0; i < this.lines.length; ++i) {
20.3239 - var line = this.lines[i];
20.3240 - var span = getMarkedSpanFor(line.markedSpans, this);
20.3241 - if (span.from != null || span.to != null) {
20.3242 - var found = lineNo(line);
20.3243 - if (span.from != null) from = {line: found, ch: span.from};
20.3244 - if (span.to != null) to = {line: found, ch: span.to};
20.3245 - }
20.3246 - }
20.3247 - if (this.type == "bookmark") return from;
20.3248 - return from && {from: from, to: to};
20.3249 - };
20.3250 -
20.3251 - function markText(cm, from, to, options, type) {
20.3252 - var doc = cm.view.doc;
20.3253 - var marker = new TextMarker(cm, type);
20.3254 - if (type == "range" && !posLess(from, to)) return marker;
20.3255 - if (options) for (var opt in options) if (options.hasOwnProperty(opt))
20.3256 - marker[opt] = options[opt];
20.3257 - if (marker.replacedWith) {
20.3258 - marker.collapsed = true;
20.3259 - marker.replacedWith = elt("span", [marker.replacedWith], "CodeMirror-widget");
20.3260 - }
20.3261 - if (marker.collapsed) sawCollapsedSpans = true;
20.3262 -
20.3263 - var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd;
20.3264 - doc.iter(curLine, to.line + 1, function(line) {
20.3265 - var span = {from: null, to: null, marker: marker};
20.3266 - size += line.text.length;
20.3267 - if (curLine == from.line) {span.from = from.ch; size -= from.ch;}
20.3268 - if (curLine == to.line) {span.to = to.ch; size -= line.text.length - to.ch;}
20.3269 - if (marker.collapsed) {
20.3270 - if (curLine == to.line) collapsedAtEnd = collapsedSpanAt(line, to.ch);
20.3271 - if (curLine == from.line) collapsedAtStart = collapsedSpanAt(line, from.ch);
20.3272 - else updateLineHeight(line, 0);
20.3273 - }
20.3274 - addMarkedSpan(line, span);
20.3275 - if (marker.collapsed && curLine == from.line && lineIsHidden(line))
20.3276 - updateLineHeight(line, 0);
20.3277 - ++curLine;
20.3278 - });
20.3279 -
20.3280 - if (marker.readOnly) {
20.3281 - sawReadOnlySpans = true;
20.3282 - if (cm.view.history.done.length || cm.view.history.undone.length)
20.3283 - cm.clearHistory();
20.3284 - }
20.3285 - if (marker.collapsed) {
20.3286 - if (collapsedAtStart != collapsedAtEnd)
20.3287 - throw new Error("Inserting collapsed marker overlapping an existing one");
20.3288 - marker.size = size;
20.3289 - marker.atomic = true;
20.3290 - }
20.3291 - if (marker.className || marker.startStyle || marker.endStyle || marker.collapsed)
20.3292 - regChange(cm, from.line, to.line + 1);
20.3293 - if (marker.atomic) reCheckSelection(cm);
20.3294 - return marker;
20.3295 - }
20.3296 -
20.3297 - // TEXTMARKER SPANS
20.3298 -
20.3299 - function getMarkedSpanFor(spans, marker) {
20.3300 - if (spans) for (var i = 0; i < spans.length; ++i) {
20.3301 - var span = spans[i];
20.3302 - if (span.marker == marker) return span;
20.3303 - }
20.3304 - }
20.3305 - function removeMarkedSpan(spans, span) {
20.3306 - for (var r, i = 0; i < spans.length; ++i)
20.3307 - if (spans[i] != span) (r || (r = [])).push(spans[i]);
20.3308 - return r;
20.3309 - }
20.3310 - function addMarkedSpan(line, span) {
20.3311 - line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
20.3312 - span.marker.lines.push(line);
20.3313 - }
20.3314 -
20.3315 - function markedSpansBefore(old, startCh) {
20.3316 - if (old) for (var i = 0, nw; i < old.length; ++i) {
20.3317 - var span = old[i], marker = span.marker;
20.3318 - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
20.3319 - if (startsBefore || marker.type == "bookmark" && span.from == startCh) {
20.3320 - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
20.3321 - (nw || (nw = [])).push({from: span.from,
20.3322 - to: endsAfter ? null : span.to,
20.3323 - marker: marker});
20.3324 - }
20.3325 - }
20.3326 - return nw;
20.3327 - }
20.3328 -
20.3329 - function markedSpansAfter(old, startCh, endCh) {
20.3330 - if (old) for (var i = 0, nw; i < old.length; ++i) {
20.3331 - var span = old[i], marker = span.marker;
20.3332 - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
20.3333 - if (endsAfter || marker.type == "bookmark" && span.from == endCh && span.from != startCh) {
20.3334 - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
20.3335 - (nw || (nw = [])).push({from: startsBefore ? null : span.from - endCh,
20.3336 - to: span.to == null ? null : span.to - endCh,
20.3337 - marker: marker});
20.3338 - }
20.3339 - }
20.3340 - return nw;
20.3341 - }
20.3342 -
20.3343 - function updateMarkedSpans(oldFirst, oldLast, startCh, endCh, newText) {
20.3344 - if (!oldFirst && !oldLast) return newText;
20.3345 - // Get the spans that 'stick out' on both sides
20.3346 - var first = markedSpansBefore(oldFirst, startCh);
20.3347 - var last = markedSpansAfter(oldLast, startCh, endCh);
20.3348 -
20.3349 - // Next, merge those two ends
20.3350 - var sameLine = newText.length == 1, offset = lst(newText).length + (sameLine ? startCh : 0);
20.3351 - if (first) {
20.3352 - // Fix up .to properties of first
20.3353 - for (var i = 0; i < first.length; ++i) {
20.3354 - var span = first[i];
20.3355 - if (span.to == null) {
20.3356 - var found = getMarkedSpanFor(last, span.marker);
20.3357 - if (!found) span.to = startCh;
20.3358 - else if (sameLine) span.to = found.to == null ? null : found.to + offset;
20.3359 - }
20.3360 - }
20.3361 - }
20.3362 - if (last) {
20.3363 - // Fix up .from in last (or move them into first in case of sameLine)
20.3364 - for (var i = 0; i < last.length; ++i) {
20.3365 - var span = last[i];
20.3366 - if (span.to != null) span.to += offset;
20.3367 - if (span.from == null) {
20.3368 - var found = getMarkedSpanFor(first, span.marker);
20.3369 - if (!found) {
20.3370 - span.from = offset;
20.3371 - if (sameLine) (first || (first = [])).push(span);
20.3372 - }
20.3373 - } else {
20.3374 - span.from += offset;
20.3375 - if (sameLine) (first || (first = [])).push(span);
20.3376 - }
20.3377 - }
20.3378 - }
20.3379 -
20.3380 - var newMarkers = [newHL(newText[0], first)];
20.3381 - if (!sameLine) {
20.3382 - // Fill gap with whole-line-spans
20.3383 - var gap = newText.length - 2, gapMarkers;
20.3384 - if (gap > 0 && first)
20.3385 - for (var i = 0; i < first.length; ++i)
20.3386 - if (first[i].to == null)
20.3387 - (gapMarkers || (gapMarkers = [])).push({from: null, to: null, marker: first[i].marker});
20.3388 - for (var i = 0; i < gap; ++i)
20.3389 - newMarkers.push(newHL(newText[i+1], gapMarkers));
20.3390 - newMarkers.push(newHL(lst(newText), last));
20.3391 - }
20.3392 - return newMarkers;
20.3393 - }
20.3394 -
20.3395 - function removeReadOnlyRanges(doc, from, to) {
20.3396 - var markers = null;
20.3397 - doc.iter(from.line, to.line + 1, function(line) {
20.3398 - if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
20.3399 - var mark = line.markedSpans[i].marker;
20.3400 - if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
20.3401 - (markers || (markers = [])).push(mark);
20.3402 - }
20.3403 - });
20.3404 - if (!markers) return null;
20.3405 - var parts = [{from: from, to: to}];
20.3406 - for (var i = 0; i < markers.length; ++i) {
20.3407 - var m = markers[i].find();
20.3408 - for (var j = 0; j < parts.length; ++j) {
20.3409 - var p = parts[j];
20.3410 - if (!posLess(m.from, p.to) || posLess(m.to, p.from)) continue;
20.3411 - var newParts = [j, 1];
20.3412 - if (posLess(p.from, m.from)) newParts.push({from: p.from, to: m.from});
20.3413 - if (posLess(m.to, p.to)) newParts.push({from: m.to, to: p.to});
20.3414 - parts.splice.apply(parts, newParts);
20.3415 - j += newParts.length - 1;
20.3416 - }
20.3417 - }
20.3418 - return parts;
20.3419 - }
20.3420 -
20.3421 - function collapsedSpanAt(line, ch) {
20.3422 - var sps = sawCollapsedSpans && line.markedSpans, found;
20.3423 - if (sps) for (var sp, i = 0; i < sps.length; ++i) {
20.3424 - sp = sps[i];
20.3425 - if (!sp.marker.collapsed) continue;
20.3426 - if ((sp.from == null || sp.from < ch) &&
20.3427 - (sp.to == null || sp.to > ch) &&
20.3428 - (!found || found.width < sp.marker.width))
20.3429 - found = sp.marker;
20.3430 - }
20.3431 - return found;
20.3432 - }
20.3433 - function collapsedSpanAtStart(line) { return collapsedSpanAt(line, -1); }
20.3434 - function collapsedSpanAtEnd(line) { return collapsedSpanAt(line, line.text.length + 1); }
20.3435 -
20.3436 - function visualLine(doc, line) {
20.3437 - var merged;
20.3438 - while (merged = collapsedSpanAtStart(line))
20.3439 - line = getLine(doc, merged.find().from.line);
20.3440 - return line;
20.3441 - }
20.3442 -
20.3443 - function lineIsHidden(line) {
20.3444 - var sps = sawCollapsedSpans && line.markedSpans;
20.3445 - if (sps) for (var sp, i = 0; i < sps.length; ++i) {
20.3446 - sp = sps[i];
20.3447 - if (!sp.marker.collapsed) continue;
20.3448 - if (sp.from == null) return true;
20.3449 - if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(line, sp))
20.3450 - return true;
20.3451 - }
20.3452 - }
20.3453 - window.lineIsHidden = lineIsHidden;
20.3454 - function lineIsHiddenInner(line, span) {
20.3455 - if (span.to == null || span.marker.inclusiveRight && span.to == line.text.length)
20.3456 - return true;
20.3457 - for (var sp, i = 0; i < line.markedSpans.length; ++i) {
20.3458 - sp = line.markedSpans[i];
20.3459 - if (sp.marker.collapsed && sp.from == span.to &&
20.3460 - (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
20.3461 - lineIsHiddenInner(line, sp)) return true;
20.3462 - }
20.3463 - }
20.3464 -
20.3465 - // hl stands for history-line, a data structure that can be either a
20.3466 - // string (line without markers) or a {text, markedSpans} object.
20.3467 - function hlText(val) { return typeof val == "string" ? val : val.text; }
20.3468 - function hlSpans(val) {
20.3469 - if (typeof val == "string") return null;
20.3470 - var spans = val.markedSpans, out = null;
20.3471 - for (var i = 0; i < spans.length; ++i) {
20.3472 - if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
20.3473 - else if (out) out.push(spans[i]);
20.3474 - }
20.3475 - return !out ? spans : out.length ? out : null;
20.3476 - }
20.3477 - function newHL(text, spans) { return spans ? {text: text, markedSpans: spans} : text; }
20.3478 -
20.3479 - function detachMarkedSpans(line) {
20.3480 - var spans = line.markedSpans;
20.3481 - if (!spans) return;
20.3482 - for (var i = 0; i < spans.length; ++i) {
20.3483 - var lines = spans[i].marker.lines;
20.3484 - var ix = indexOf(lines, line);
20.3485 - lines.splice(ix, 1);
20.3486 - }
20.3487 - line.markedSpans = null;
20.3488 - }
20.3489 -
20.3490 - function attachMarkedSpans(line, spans) {
20.3491 - if (!spans) return;
20.3492 - for (var i = 0; i < spans.length; ++i)
20.3493 - spans[i].marker.lines.push(line);
20.3494 - line.markedSpans = spans;
20.3495 - }
20.3496 -
20.3497 - // LINE DATA STRUCTURE
20.3498 -
20.3499 - // Line objects. These hold state related to a line, including
20.3500 - // highlighting info (the styles array).
20.3501 - function makeLine(text, markedSpans, height) {
20.3502 - var line = {text: text, height: height};
20.3503 - attachMarkedSpans(line, markedSpans);
20.3504 - if (lineIsHidden(line)) line.height = 0;
20.3505 - return line;
20.3506 - }
20.3507 -
20.3508 - function updateLine(cm, line, text, markedSpans) {
20.3509 - line.text = text;
20.3510 - line.stateAfter = line.styles = null;
20.3511 - if (line.order != null) line.order = null;
20.3512 - detachMarkedSpans(line);
20.3513 - attachMarkedSpans(line, markedSpans);
20.3514 - if (lineIsHidden(line)) line.height = 0;
20.3515 - else if (!line.height) line.height = textHeight(cm.display);
20.3516 - signalLater(cm, line, "change");
20.3517 - }
20.3518 -
20.3519 - function cleanUpLine(line) {
20.3520 - line.parent = null;
20.3521 - detachMarkedSpans(line);
20.3522 - }
20.3523 -
20.3524 - // Run the given mode's parser over a line, update the styles
20.3525 - // array, which contains alternating fragments of text and CSS
20.3526 - // classes.
20.3527 - function highlightLine(cm, line, state) {
20.3528 - var mode = cm.view.mode, flattenSpans = cm.options.flattenSpans;
20.3529 - var changed = !line.styles, pos = 0, curText = "", curStyle = null;
20.3530 - var stream = new StringStream(line.text, cm.options.tabSize), st = line.styles || (line.styles = []);
20.3531 - if (line.text == "" && mode.blankLine) mode.blankLine(state);
20.3532 - while (!stream.eol()) {
20.3533 - var style = mode.token(stream, state), substr = stream.current();
20.3534 - stream.start = stream.pos;
20.3535 - if (!flattenSpans || curStyle != style) {
20.3536 - if (curText) {
20.3537 - changed = changed || pos >= st.length || curText != st[pos] || curStyle != st[pos+1];
20.3538 - st[pos++] = curText; st[pos++] = curStyle;
20.3539 - }
20.3540 - curText = substr; curStyle = style;
20.3541 - } else curText = curText + substr;
20.3542 - // Give up when line is ridiculously long
20.3543 - if (stream.pos > 5000) break;
20.3544 - }
20.3545 - if (curText) {
20.3546 - changed = changed || pos >= st.length || curText != st[pos] || curStyle != st[pos+1];
20.3547 - st[pos++] = curText; st[pos++] = curStyle;
20.3548 - }
20.3549 - if (stream.pos > 5000) { st[pos++] = line.text.slice(stream.pos); st[pos++] = null; }
20.3550 - if (pos != st.length) { st.length = pos; changed = true; }
20.3551 - return changed;
20.3552 - }
20.3553 -
20.3554 - // Lightweight form of highlight -- proceed over this line and
20.3555 - // update state, but don't save a style array.
20.3556 - function processLine(cm, line, state) {
20.3557 - var mode = cm.view.mode;
20.3558 - var stream = new StringStream(line.text, cm.options.tabSize);
20.3559 - if (line.text == "" && mode.blankLine) mode.blankLine(state);
20.3560 - while (!stream.eol() && stream.pos <= 5000) {
20.3561 - mode.token(stream, state);
20.3562 - stream.start = stream.pos;
20.3563 - }
20.3564 - }
20.3565 -
20.3566 - var styleToClassCache = {};
20.3567 - function styleToClass(style) {
20.3568 - if (!style) return null;
20.3569 - return styleToClassCache[style] ||
20.3570 - (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-"));
20.3571 - }
20.3572 -
20.3573 - function lineContent(cm, realLine, measure) {
20.3574 - var merged, line = realLine, lineBefore, sawBefore, simple = true;
20.3575 - while (merged = collapsedSpanAtStart(line)) {
20.3576 - simple = false;
20.3577 - line = getLine(cm.view.doc, merged.find().from.line);
20.3578 - if (!lineBefore) lineBefore = line;
20.3579 - }
20.3580 -
20.3581 - var builder = {pre: elt("pre"), col: 0, pos: 0, display: !measure,
20.3582 - measure: null, addedOne: false, cm: cm};
20.3583 - if (line.textClass) builder.pre.className = line.textClass;
20.3584 -
20.3585 - do {
20.3586 - if (!line.styles)
20.3587 - highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
20.3588 - builder.measure = line == realLine && measure;
20.3589 - builder.pos = 0;
20.3590 - builder.addToken = builder.measure ? buildTokenMeasure : buildToken;
20.3591 - if (measure && sawBefore && line != realLine && !builder.addedOne) {
20.3592 - measure[0] = builder.pre.appendChild(zeroWidthElement(cm.display.measure));
20.3593 - builder.addedOne = true;
20.3594 - }
20.3595 - var next = insertLineContent(line, builder);
20.3596 - sawBefore = line == lineBefore;
20.3597 - if (next) {
20.3598 - line = getLine(cm.view.doc, next.to.line);
20.3599 - simple = false;
20.3600 - }
20.3601 - } while (next);
20.3602 -
20.3603 - if (measure && !builder.addedOne)
20.3604 - measure[0] = builder.pre.appendChild(simple ? elt("span", "\u00a0") : zeroWidthElement(cm.display.measure));
20.3605 - if (!builder.pre.firstChild && !lineIsHidden(realLine))
20.3606 - builder.pre.appendChild(document.createTextNode("\u00a0"));
20.3607 -
20.3608 - return builder.pre;
20.3609 - }
20.3610 -
20.3611 - var tokenSpecialChars = /[\t\u0000-\u0019\u200b\u2028\u2029\uFEFF]/g;
20.3612 - function buildToken(builder, text, style, startStyle, endStyle) {
20.3613 - if (!text) return;
20.3614 - if (!tokenSpecialChars.test(text)) {
20.3615 - builder.col += text.length;
20.3616 - var content = document.createTextNode(text);
20.3617 - } else {
20.3618 - var content = document.createDocumentFragment(), pos = 0;
20.3619 - while (true) {
20.3620 - tokenSpecialChars.lastIndex = pos;
20.3621 - var m = tokenSpecialChars.exec(text);
20.3622 - var skipped = m ? m.index - pos : text.length - pos;
20.3623 - if (skipped) {
20.3624 - content.appendChild(document.createTextNode(text.slice(pos, pos + skipped)));
20.3625 - builder.col += skipped;
20.3626 - }
20.3627 - if (!m) break;
20.3628 - pos += skipped + 1;
20.3629 - if (m[0] == "\t") {
20.3630 - var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
20.3631 - content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
20.3632 - builder.col += tabWidth;
20.3633 - } else {
20.3634 - var token = elt("span", "\u2022", "cm-invalidchar");
20.3635 - token.title = "\\u" + m[0].charCodeAt(0).toString(16);
20.3636 - content.appendChild(token);
20.3637 - builder.col += 1;
20.3638 - }
20.3639 - }
20.3640 - }
20.3641 - if (style || startStyle || endStyle || builder.measure) {
20.3642 - var fullStyle = style || "";
20.3643 - if (startStyle) fullStyle += startStyle;
20.3644 - if (endStyle) fullStyle += endStyle;
20.3645 - return builder.pre.appendChild(elt("span", [content], fullStyle));
20.3646 - }
20.3647 - builder.pre.appendChild(content);
20.3648 - }
20.3649 -
20.3650 - function buildTokenMeasure(builder, text, style, startStyle, endStyle) {
20.3651 - for (var i = 0; i < text.length; ++i) {
20.3652 - if (i && i < text.length - 1 &&
20.3653 - builder.cm.options.lineWrapping &&
20.3654 - spanAffectsWrapping.test(text.slice(i - 1, i + 1)))
20.3655 - builder.pre.appendChild(elt("wbr"));
20.3656 - builder.measure[builder.pos++] =
20.3657 - buildToken(builder, text.charAt(i), style,
20.3658 - i == 0 && startStyle, i == text.length - 1 && endStyle);
20.3659 - }
20.3660 - if (text.length) builder.addedOne = true;
20.3661 - }
20.3662 -
20.3663 - function buildCollapsedSpan(builder, size, widget) {
20.3664 - if (widget) {
20.3665 - if (!builder.display) widget = widget.cloneNode(true);
20.3666 - builder.pre.appendChild(widget);
20.3667 - if (builder.measure && size) {
20.3668 - builder.measure[builder.pos] = widget;
20.3669 - builder.addedOne = true;
20.3670 - }
20.3671 - }
20.3672 - builder.pos += size;
20.3673 - }
20.3674 -
20.3675 - // Outputs a number of spans to make up a line, taking highlighting
20.3676 - // and marked text into account.
20.3677 - function insertLineContent(line, builder) {
20.3678 - var st = line.styles, spans = line.markedSpans;
20.3679 - if (!spans) {
20.3680 - for (var i = 0; i < st.length; i+=2)
20.3681 - builder.addToken(builder, st[i], styleToClass(st[i+1]));
20.3682 - return;
20.3683 - }
20.3684 -
20.3685 - var allText = line.text, len = allText.length;
20.3686 - var pos = 0, i = 0, text = "", style;
20.3687 - var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed;
20.3688 - for (;;) {
20.3689 - if (nextChange == pos) { // Update current marker set
20.3690 - spanStyle = spanEndStyle = spanStartStyle = "";
20.3691 - collapsed = null; nextChange = Infinity;
20.3692 - var foundBookmark = null;
20.3693 - for (var j = 0; j < spans.length; ++j) {
20.3694 - var sp = spans[j], m = sp.marker;
20.3695 - if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
20.3696 - if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
20.3697 - if (m.className) spanStyle += " " + m.className;
20.3698 - if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
20.3699 - if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
20.3700 - if (m.collapsed && (!collapsed || collapsed.marker.width < m.width))
20.3701 - collapsed = sp;
20.3702 - } else if (sp.from > pos && nextChange > sp.from) {
20.3703 - nextChange = sp.from;
20.3704 - }
20.3705 - if (m.type == "bookmark" && sp.from == pos && m.replacedWith)
20.3706 - foundBookmark = m.replacedWith;
20.3707 - }
20.3708 - if (collapsed && (collapsed.from || 0) == pos) {
20.3709 - buildCollapsedSpan(builder, (collapsed.to == null ? len : collapsed.to) - pos,
20.3710 - collapsed.from != null && collapsed.marker.replacedWith);
20.3711 - if (collapsed.to == null) return collapsed.marker.find();
20.3712 - }
20.3713 - if (foundBookmark && !collapsed) buildCollapsedSpan(builder, 0, foundBookmark);
20.3714 - }
20.3715 - if (pos >= len) break;
20.3716 -
20.3717 - var upto = Math.min(len, nextChange);
20.3718 - while (true) {
20.3719 - if (text) {
20.3720 - var end = pos + text.length;
20.3721 - if (!collapsed) {
20.3722 - var tokenText = end > upto ? text.slice(0, upto - pos) : text;
20.3723 - builder.addToken(builder, tokenText, style + spanStyle,
20.3724 - spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "");
20.3725 - }
20.3726 - if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
20.3727 - pos = end;
20.3728 - spanStartStyle = "";
20.3729 - }
20.3730 - text = st[i++]; style = styleToClass(st[i++]);
20.3731 - }
20.3732 - }
20.3733 - }
20.3734 -
20.3735 - // DOCUMENT DATA STRUCTURE
20.3736 -
20.3737 - function LeafChunk(lines) {
20.3738 - this.lines = lines;
20.3739 - this.parent = null;
20.3740 - for (var i = 0, e = lines.length, height = 0; i < e; ++i) {
20.3741 - lines[i].parent = this;
20.3742 - height += lines[i].height;
20.3743 - }
20.3744 - this.height = height;
20.3745 - }
20.3746 -
20.3747 - LeafChunk.prototype = {
20.3748 - chunkSize: function() { return this.lines.length; },
20.3749 - remove: function(at, n, cm) {
20.3750 - for (var i = at, e = at + n; i < e; ++i) {
20.3751 - var line = this.lines[i];
20.3752 - this.height -= line.height;
20.3753 - cleanUpLine(line);
20.3754 - signalLater(cm, line, "delete");
20.3755 - }
20.3756 - this.lines.splice(at, n);
20.3757 - },
20.3758 - collapse: function(lines) {
20.3759 - lines.splice.apply(lines, [lines.length, 0].concat(this.lines));
20.3760 - },
20.3761 - insertHeight: function(at, lines, height) {
20.3762 - this.height += height;
20.3763 - this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
20.3764 - for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
20.3765 - },
20.3766 - iterN: function(at, n, op) {
20.3767 - for (var e = at + n; at < e; ++at)
20.3768 - if (op(this.lines[at])) return true;
20.3769 - }
20.3770 - };
20.3771 -
20.3772 - function BranchChunk(children) {
20.3773 - this.children = children;
20.3774 - var size = 0, height = 0;
20.3775 - for (var i = 0, e = children.length; i < e; ++i) {
20.3776 - var ch = children[i];
20.3777 - size += ch.chunkSize(); height += ch.height;
20.3778 - ch.parent = this;
20.3779 - }
20.3780 - this.size = size;
20.3781 - this.height = height;
20.3782 - this.parent = null;
20.3783 - }
20.3784 -
20.3785 - BranchChunk.prototype = {
20.3786 - chunkSize: function() { return this.size; },
20.3787 - remove: function(at, n, callbacks) {
20.3788 - this.size -= n;
20.3789 - for (var i = 0; i < this.children.length; ++i) {
20.3790 - var child = this.children[i], sz = child.chunkSize();
20.3791 - if (at < sz) {
20.3792 - var rm = Math.min(n, sz - at), oldHeight = child.height;
20.3793 - child.remove(at, rm, callbacks);
20.3794 - this.height -= oldHeight - child.height;
20.3795 - if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
20.3796 - if ((n -= rm) == 0) break;
20.3797 - at = 0;
20.3798 - } else at -= sz;
20.3799 - }
20.3800 - if (this.size - n < 25) {
20.3801 - var lines = [];
20.3802 - this.collapse(lines);
20.3803 - this.children = [new LeafChunk(lines)];
20.3804 - this.children[0].parent = this;
20.3805 - }
20.3806 - },
20.3807 - collapse: function(lines) {
20.3808 - for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines);
20.3809 - },
20.3810 - insert: function(at, lines) {
20.3811 - var height = 0;
20.3812 - for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height;
20.3813 - this.insertHeight(at, lines, height);
20.3814 - },
20.3815 - insertHeight: function(at, lines, height) {
20.3816 - this.size += lines.length;
20.3817 - this.height += height;
20.3818 - for (var i = 0, e = this.children.length; i < e; ++i) {
20.3819 - var child = this.children[i], sz = child.chunkSize();
20.3820 - if (at <= sz) {
20.3821 - child.insertHeight(at, lines, height);
20.3822 - if (child.lines && child.lines.length > 50) {
20.3823 - while (child.lines.length > 50) {
20.3824 - var spilled = child.lines.splice(child.lines.length - 25, 25);
20.3825 - var newleaf = new LeafChunk(spilled);
20.3826 - child.height -= newleaf.height;
20.3827 - this.children.splice(i + 1, 0, newleaf);
20.3828 - newleaf.parent = this;
20.3829 - }
20.3830 - this.maybeSpill();
20.3831 - }
20.3832 - break;
20.3833 - }
20.3834 - at -= sz;
20.3835 - }
20.3836 - },
20.3837 - maybeSpill: function() {
20.3838 - if (this.children.length <= 10) return;
20.3839 - var me = this;
20.3840 - do {
20.3841 - var spilled = me.children.splice(me.children.length - 5, 5);
20.3842 - var sibling = new BranchChunk(spilled);
20.3843 - if (!me.parent) { // Become the parent node
20.3844 - var copy = new BranchChunk(me.children);
20.3845 - copy.parent = me;
20.3846 - me.children = [copy, sibling];
20.3847 - me = copy;
20.3848 - } else {
20.3849 - me.size -= sibling.size;
20.3850 - me.height -= sibling.height;
20.3851 - var myIndex = indexOf(me.parent.children, me);
20.3852 - me.parent.children.splice(myIndex + 1, 0, sibling);
20.3853 - }
20.3854 - sibling.parent = me.parent;
20.3855 - } while (me.children.length > 10);
20.3856 - me.parent.maybeSpill();
20.3857 - },
20.3858 - iter: function(from, to, op) { this.iterN(from, to - from, op); },
20.3859 - iterN: function(at, n, op) {
20.3860 - for (var i = 0, e = this.children.length; i < e; ++i) {
20.3861 - var child = this.children[i], sz = child.chunkSize();
20.3862 - if (at < sz) {
20.3863 - var used = Math.min(n, sz - at);
20.3864 - if (child.iterN(at, used, op)) return true;
20.3865 - if ((n -= used) == 0) break;
20.3866 - at = 0;
20.3867 - } else at -= sz;
20.3868 - }
20.3869 - }
20.3870 - };
20.3871 -
20.3872 - // LINE UTILITIES
20.3873 -
20.3874 - function getLine(chunk, n) {
20.3875 - while (!chunk.lines) {
20.3876 - for (var i = 0;; ++i) {
20.3877 - var child = chunk.children[i], sz = child.chunkSize();
20.3878 - if (n < sz) { chunk = child; break; }
20.3879 - n -= sz;
20.3880 - }
20.3881 - }
20.3882 - return chunk.lines[n];
20.3883 - }
20.3884 -
20.3885 - function updateLineHeight(line, height) {
20.3886 - var diff = height - line.height;
20.3887 - for (var n = line; n; n = n.parent) n.height += diff;
20.3888 - }
20.3889 -
20.3890 - function lineNo(line) {
20.3891 - if (line.parent == null) return null;
20.3892 - var cur = line.parent, no = indexOf(cur.lines, line);
20.3893 - for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
20.3894 - for (var i = 0;; ++i) {
20.3895 - if (chunk.children[i] == cur) break;
20.3896 - no += chunk.children[i].chunkSize();
20.3897 - }
20.3898 - }
20.3899 - return no;
20.3900 - }
20.3901 -
20.3902 - function lineAtHeight(chunk, h) {
20.3903 - var n = 0;
20.3904 - outer: do {
20.3905 - for (var i = 0, e = chunk.children.length; i < e; ++i) {
20.3906 - var child = chunk.children[i], ch = child.height;
20.3907 - if (h < ch) { chunk = child; continue outer; }
20.3908 - h -= ch;
20.3909 - n += child.chunkSize();
20.3910 - }
20.3911 - return n;
20.3912 - } while (!chunk.lines);
20.3913 - for (var i = 0, e = chunk.lines.length; i < e; ++i) {
20.3914 - var line = chunk.lines[i], lh = line.height;
20.3915 - if (h < lh) break;
20.3916 - h -= lh;
20.3917 - }
20.3918 - return n + i;
20.3919 - }
20.3920 -
20.3921 - function heightAtLine(cm, lineObj) {
20.3922 - lineObj = visualLine(cm.view.doc, lineObj);
20.3923 -
20.3924 - var h = 0, chunk = lineObj.parent;
20.3925 - for (var i = 0; i < chunk.lines.length; ++i) {
20.3926 - var line = chunk.lines[i];
20.3927 - if (line == lineObj) break;
20.3928 - else h += line.height;
20.3929 - }
20.3930 - for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
20.3931 - for (var i = 0; i < p.children.length; ++i) {
20.3932 - var cur = p.children[i];
20.3933 - if (cur == chunk) break;
20.3934 - else h += cur.height;
20.3935 - }
20.3936 - }
20.3937 - return h;
20.3938 - }
20.3939 -
20.3940 - function getOrder(line) {
20.3941 - var order = line.order;
20.3942 - if (order == null) order = line.order = bidiOrdering(line.text);
20.3943 - return order;
20.3944 - }
20.3945 -
20.3946 - // HISTORY
20.3947 -
20.3948 - function makeHistory() {
20.3949 - return {
20.3950 - // Arrays of history events. Doing something adds an event to
20.3951 - // done and clears undo. Undoing moves events from done to
20.3952 - // undone, redoing moves them in the other direction.
20.3953 - done: [], undone: [],
20.3954 - // Used to track when changes can be merged into a single undo
20.3955 - // event
20.3956 - lastTime: 0, lastOp: null, lastOrigin: null,
20.3957 - // Used by the isClean() method
20.3958 - dirtyCounter: 0
20.3959 - };
20.3960 - }
20.3961 -
20.3962 - function addChange(cm, start, added, old, origin, fromBefore, toBefore, fromAfter, toAfter) {
20.3963 - var history = cm.view.history;
20.3964 - history.undone.length = 0;
20.3965 - var time = +new Date, cur = lst(history.done);
20.3966 -
20.3967 - if (cur &&
20.3968 - (history.lastOp == cm.curOp.id ||
20.3969 - history.lastOrigin == origin && (origin == "input" || origin == "delete") &&
20.3970 - history.lastTime > time - 600)) {
20.3971 - // Merge this change into the last event
20.3972 - var last = lst(cur.events);
20.3973 - if (last.start > start + old.length || last.start + last.added < start) {
20.3974 - // Doesn't intersect with last sub-event, add new sub-event
20.3975 - cur.events.push({start: start, added: added, old: old});
20.3976 - } else {
20.3977 - // Patch up the last sub-event
20.3978 - var startBefore = Math.max(0, last.start - start),
20.3979 - endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
20.3980 - for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
20.3981 - for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
20.3982 - if (startBefore) last.start = start;
20.3983 - last.added += added - (old.length - startBefore - endAfter);
20.3984 - }
20.3985 - cur.fromAfter = fromAfter; cur.toAfter = toAfter;
20.3986 - } else {
20.3987 - // Can not be merged, start a new event.
20.3988 - cur = {events: [{start: start, added: added, old: old}],
20.3989 - fromBefore: fromBefore, toBefore: toBefore, fromAfter: fromAfter, toAfter: toAfter};
20.3990 - history.done.push(cur);
20.3991 - while (history.done.length > cm.options.undoDepth)
20.3992 - history.done.shift();
20.3993 - if (history.dirtyCounter < 0)
20.3994 - // The user has made a change after undoing past the last clean state.
20.3995 - // We can never get back to a clean state now until markClean() is called.
20.3996 - history.dirtyCounter = NaN;
20.3997 - else
20.3998 - history.dirtyCounter++;
20.3999 - }
20.4000 - history.lastTime = time;
20.4001 - history.lastOp = cm.curOp.id;
20.4002 - history.lastOrigin = origin;
20.4003 - }
20.4004 -
20.4005 - // EVENT OPERATORS
20.4006 -
20.4007 - function stopMethod() {e_stop(this);}
20.4008 - // Ensure an event has a stop method.
20.4009 - function addStop(event) {
20.4010 - if (!event.stop) event.stop = stopMethod;
20.4011 - return event;
20.4012 - }
20.4013 -
20.4014 - function e_preventDefault(e) {
20.4015 - if (e.preventDefault) e.preventDefault();
20.4016 - else e.returnValue = false;
20.4017 - }
20.4018 - function e_stopPropagation(e) {
20.4019 - if (e.stopPropagation) e.stopPropagation();
20.4020 - else e.cancelBubble = true;
20.4021 - }
20.4022 - function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
20.4023 - CodeMirror.e_stop = e_stop;
20.4024 - CodeMirror.e_preventDefault = e_preventDefault;
20.4025 - CodeMirror.e_stopPropagation = e_stopPropagation;
20.4026 -
20.4027 - function e_target(e) {return e.target || e.srcElement;}
20.4028 - function e_button(e) {
20.4029 - var b = e.which;
20.4030 - if (b == null) {
20.4031 - if (e.button & 1) b = 1;
20.4032 - else if (e.button & 2) b = 3;
20.4033 - else if (e.button & 4) b = 2;
20.4034 - }
20.4035 - if (mac && e.ctrlKey && b == 1) b = 3;
20.4036 - return b;
20.4037 - }
20.4038 -
20.4039 - // Allow 3rd-party code to override event properties by adding an override
20.4040 - // object to an event object.
20.4041 - function e_prop(e, prop) {
20.4042 - var overridden = e.override && e.override.hasOwnProperty(prop);
20.4043 - return overridden ? e.override[prop] : e[prop];
20.4044 - }
20.4045 -
20.4046 - // EVENT HANDLING
20.4047 -
20.4048 - function on(emitter, type, f) {
20.4049 - if (emitter.addEventListener)
20.4050 - emitter.addEventListener(type, f, false);
20.4051 - else if (emitter.attachEvent)
20.4052 - emitter.attachEvent("on" + type, f);
20.4053 - else {
20.4054 - var map = emitter._handlers || (emitter._handlers = {});
20.4055 - var arr = map[type] || (map[type] = []);
20.4056 - arr.push(f);
20.4057 - }
20.4058 - }
20.4059 -
20.4060 - function off(emitter, type, f) {
20.4061 - if (emitter.removeEventListener)
20.4062 - emitter.removeEventListener(type, f, false);
20.4063 - else if (emitter.detachEvent)
20.4064 - emitter.detachEvent("on" + type, f);
20.4065 - else {
20.4066 - var arr = emitter._handlers && emitter._handlers[type];
20.4067 - if (!arr) return;
20.4068 - for (var i = 0; i < arr.length; ++i)
20.4069 - if (arr[i] == f) { arr.splice(i, 1); break; }
20.4070 - }
20.4071 - }
20.4072 -
20.4073 - function signal(emitter, type /*, values...*/) {
20.4074 - var arr = emitter._handlers && emitter._handlers[type];
20.4075 - if (!arr) return;
20.4076 - var args = Array.prototype.slice.call(arguments, 2);
20.4077 - for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
20.4078 - }
20.4079 -
20.4080 - function signalLater(cm, emitter, type /*, values...*/) {
20.4081 - var arr = emitter._handlers && emitter._handlers[type];
20.4082 - if (!arr) return;
20.4083 - var args = Array.prototype.slice.call(arguments, 3), flist = cm.curOp && cm.curOp.delayedCallbacks;
20.4084 - function bnd(f) {return function(){f.apply(null, args);};};
20.4085 - for (var i = 0; i < arr.length; ++i)
20.4086 - if (flist) flist.push(bnd(arr[i]));
20.4087 - else arr[i].apply(null, args);
20.4088 - }
20.4089 -
20.4090 - function hasHandler(emitter, type) {
20.4091 - var arr = emitter._handlers && emitter._handlers[type];
20.4092 - return arr && arr.length > 0;
20.4093 - }
20.4094 -
20.4095 - CodeMirror.on = on; CodeMirror.off = off; CodeMirror.signal = signal;
20.4096 -
20.4097 - // MISC UTILITIES
20.4098 -
20.4099 - // Number of pixels added to scroller and sizer to hide scrollbar
20.4100 - var scrollerCutOff = 30;
20.4101 -
20.4102 - // Returned or thrown by various protocols to signal 'I'm not
20.4103 - // handling this'.
20.4104 - var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
20.4105 -
20.4106 - function Delayed() {this.id = null;}
20.4107 - Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
20.4108 -
20.4109 - // Counts the column offset in a string, taking tabs into account.
20.4110 - // Used mostly to find indentation.
20.4111 - function countColumn(string, end, tabSize) {
20.4112 - if (end == null) {
20.4113 - end = string.search(/[^\s\u00a0]/);
20.4114 - if (end == -1) end = string.length;
20.4115 - }
20.4116 - for (var i = 0, n = 0; i < end; ++i) {
20.4117 - if (string.charAt(i) == "\t") n += tabSize - (n % tabSize);
20.4118 - else ++n;
20.4119 - }
20.4120 - return n;
20.4121 - }
20.4122 - CodeMirror.countColumn = countColumn;
20.4123 -
20.4124 - var spaceStrs = [""];
20.4125 - function spaceStr(n) {
20.4126 - while (spaceStrs.length <= n)
20.4127 - spaceStrs.push(lst(spaceStrs) + " ");
20.4128 - return spaceStrs[n];
20.4129 - }
20.4130 -
20.4131 - function lst(arr) { return arr[arr.length-1]; }
20.4132 -
20.4133 - function selectInput(node) {
20.4134 - if (ios) { // Mobile Safari apparently has a bug where select() is broken.
20.4135 - node.selectionStart = 0;
20.4136 - node.selectionEnd = node.value.length;
20.4137 - } else node.select();
20.4138 - }
20.4139 -
20.4140 - function indexOf(collection, elt) {
20.4141 - if (collection.indexOf) return collection.indexOf(elt);
20.4142 - for (var i = 0, e = collection.length; i < e; ++i)
20.4143 - if (collection[i] == elt) return i;
20.4144 - return -1;
20.4145 - }
20.4146 -
20.4147 - function emptyArray(size) {
20.4148 - for (var a = [], i = 0; i < size; ++i) a.push(undefined);
20.4149 - return a;
20.4150 - }
20.4151 -
20.4152 - function bind(f) {
20.4153 - var args = Array.prototype.slice.call(arguments, 1);
20.4154 - return function(){return f.apply(null, args);};
20.4155 - }
20.4156 -
20.4157 - var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc]/;
20.4158 - function isWordChar(ch) {
20.4159 - return /\w/.test(ch) || ch > "\x80" &&
20.4160 - (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
20.4161 - }
20.4162 -
20.4163 - function isEmpty(obj) {
20.4164 - var c = 0;
20.4165 - for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) ++c;
20.4166 - return !c;
20.4167 - }
20.4168 -
20.4169 - var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F]/;
20.4170 -
20.4171 - // DOM UTILITIES
20.4172 -
20.4173 - function elt(tag, content, className, style) {
20.4174 - var e = document.createElement(tag);
20.4175 - if (className) e.className = className;
20.4176 - if (style) e.style.cssText = style;
20.4177 - if (typeof content == "string") setTextContent(e, content);
20.4178 - else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
20.4179 - return e;
20.4180 - }
20.4181 -
20.4182 - function removeChildren(e) {
20.4183 - e.innerHTML = "";
20.4184 - return e;
20.4185 - }
20.4186 -
20.4187 - function removeChildrenAndAdd(parent, e) {
20.4188 - return removeChildren(parent).appendChild(e);
20.4189 - }
20.4190 -
20.4191 - function setTextContent(e, str) {
20.4192 - if (ie_lt9) {
20.4193 - e.innerHTML = "";
20.4194 - e.appendChild(document.createTextNode(str));
20.4195 - } else e.textContent = str;
20.4196 - }
20.4197 -
20.4198 - // FEATURE DETECTION
20.4199 -
20.4200 - // Detect drag-and-drop
20.4201 - var dragAndDrop = function() {
20.4202 - // There is *some* kind of drag-and-drop support in IE6-8, but I
20.4203 - // couldn't get it to work yet.
20.4204 - if (ie_lt9) return false;
20.4205 - var div = elt('div');
20.4206 - return "draggable" in div || "dragDrop" in div;
20.4207 - }();
20.4208 -
20.4209 - // For a reason I have yet to figure out, some browsers disallow
20.4210 - // word wrapping between certain characters *only* if a new inline
20.4211 - // element is started between them. This makes it hard to reliably
20.4212 - // measure the position of things, since that requires inserting an
20.4213 - // extra span. This terribly fragile set of regexps matches the
20.4214 - // character combinations that suffer from this phenomenon on the
20.4215 - // various browsers.
20.4216 - var spanAffectsWrapping = /^$/; // Won't match any two-character string
20.4217 - if (gecko) spanAffectsWrapping = /$'/;
20.4218 - else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
20.4219 - else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
20.4220 -
20.4221 - var knownScrollbarWidth;
20.4222 - function scrollbarWidth(measure) {
20.4223 - if (knownScrollbarWidth != null) return knownScrollbarWidth;
20.4224 - var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
20.4225 - removeChildrenAndAdd(measure, test);
20.4226 - if (test.offsetWidth)
20.4227 - knownScrollbarWidth = test.offsetHeight - test.clientHeight;
20.4228 - return knownScrollbarWidth || 0;
20.4229 - }
20.4230 -
20.4231 - var zwspSupported;
20.4232 - function zeroWidthElement(measure) {
20.4233 - if (zwspSupported == null) {
20.4234 - var test = elt("span", "\u200b");
20.4235 - removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
20.4236 - if (measure.firstChild.offsetHeight != 0)
20.4237 - zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !ie_lt8;
20.4238 - }
20.4239 - if (zwspSupported) return elt("span", "\u200b");
20.4240 - else return elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
20.4241 - }
20.4242 -
20.4243 - // See if "".split is the broken IE version, if so, provide an
20.4244 - // alternative way to split lines.
20.4245 - var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
20.4246 - var pos = 0, result = [], l = string.length;
20.4247 - while (pos <= l) {
20.4248 - var nl = string.indexOf("\n", pos);
20.4249 - if (nl == -1) nl = string.length;
20.4250 - var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
20.4251 - var rt = line.indexOf("\r");
20.4252 - if (rt != -1) {
20.4253 - result.push(line.slice(0, rt));
20.4254 - pos += rt + 1;
20.4255 - } else {
20.4256 - result.push(line);
20.4257 - pos = nl + 1;
20.4258 - }
20.4259 - }
20.4260 - return result;
20.4261 - } : function(string){return string.split(/\r\n?|\n/);};
20.4262 - CodeMirror.splitLines = splitLines;
20.4263 -
20.4264 - var hasSelection = window.getSelection ? function(te) {
20.4265 - try { return te.selectionStart != te.selectionEnd; }
20.4266 - catch(e) { return false; }
20.4267 - } : function(te) {
20.4268 - try {var range = te.ownerDocument.selection.createRange();}
20.4269 - catch(e) {}
20.4270 - if (!range || range.parentElement() != te) return false;
20.4271 - return range.compareEndPoints("StartToEnd", range) != 0;
20.4272 - };
20.4273 -
20.4274 - var hasCopyEvent = (function() {
20.4275 - var e = elt("div");
20.4276 - if ("oncopy" in e) return true;
20.4277 - e.setAttribute("oncopy", "return;");
20.4278 - return typeof e.oncopy == 'function';
20.4279 - })();
20.4280 -
20.4281 - // KEY NAMING
20.4282 -
20.4283 - var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
20.4284 - 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
20.4285 - 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
20.4286 - 46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
20.4287 - 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
20.4288 - 221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
20.4289 - 63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
20.4290 - CodeMirror.keyNames = keyNames;
20.4291 - (function() {
20.4292 - // Number keys
20.4293 - for (var i = 0; i < 10; i++) keyNames[i + 48] = String(i);
20.4294 - // Alphabetic keys
20.4295 - for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
20.4296 - // Function keys
20.4297 - for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
20.4298 - })();
20.4299 -
20.4300 - // BIDI HELPERS
20.4301 -
20.4302 - function iterateBidiSections(order, from, to, f) {
20.4303 - if (!order) return f(from, to, "ltr");
20.4304 - for (var i = 0; i < order.length; ++i) {
20.4305 - var part = order[i];
20.4306 - if (part.from < to && part.to > from)
20.4307 - f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
20.4308 - }
20.4309 - }
20.4310 -
20.4311 - function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
20.4312 - function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
20.4313 -
20.4314 - function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
20.4315 - function lineRight(line) {
20.4316 - var order = getOrder(line);
20.4317 - if (!order) return line.text.length;
20.4318 - return bidiRight(lst(order));
20.4319 - }
20.4320 -
20.4321 - function lineStart(cm, lineN) {
20.4322 - var line = getLine(cm.view.doc, lineN);
20.4323 - var visual = visualLine(cm.view.doc, line);
20.4324 - if (visual != line) lineN = lineNo(visual);
20.4325 - var order = getOrder(visual);
20.4326 - var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
20.4327 - return {line: lineN, ch: ch};
20.4328 - }
20.4329 - function lineEnd(cm, lineNo) {
20.4330 - var merged, line;
20.4331 - while (merged = collapsedSpanAtEnd(line = getLine(cm.view.doc, lineNo)))
20.4332 - lineNo = merged.find().to.line;
20.4333 - var order = getOrder(line);
20.4334 - var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
20.4335 - return {line: lineNo, ch: ch};
20.4336 - }
20.4337 -
20.4338 - // This is somewhat involved. It is needed in order to move
20.4339 - // 'visually' through bi-directional text -- i.e., pressing left
20.4340 - // should make the cursor go left, even when in RTL text. The
20.4341 - // tricky part is the 'jumps', where RTL and LTR text touch each
20.4342 - // other. This often requires the cursor offset to move more than
20.4343 - // one unit, in order to visually move one unit.
20.4344 - function moveVisually(line, start, dir, byUnit) {
20.4345 - var bidi = getOrder(line);
20.4346 - if (!bidi) return moveLogically(line, start, dir, byUnit);
20.4347 - var moveOneUnit = byUnit ? function(pos, dir) {
20.4348 - do pos += dir;
20.4349 - while (pos > 0 && isExtendingChar.test(line.text.charAt(pos)));
20.4350 - return pos;
20.4351 - } : function(pos, dir) { return pos + dir; };
20.4352 - var linedir = bidi[0].level;
20.4353 - for (var i = 0; i < bidi.length; ++i) {
20.4354 - var part = bidi[i], sticky = part.level % 2 == linedir;
20.4355 - if ((part.from < start && part.to > start) ||
20.4356 - (sticky && (part.from == start || part.to == start))) break;
20.4357 - }
20.4358 - var target = moveOneUnit(start, part.level % 2 ? -dir : dir);
20.4359 -
20.4360 - while (target != null) {
20.4361 - if (part.level % 2 == linedir) {
20.4362 - if (target < part.from || target > part.to) {
20.4363 - part = bidi[i += dir];
20.4364 - target = part && (dir > 0 == part.level % 2 ? moveOneUnit(part.to, -1) : moveOneUnit(part.from, 1));
20.4365 - } else break;
20.4366 - } else {
20.4367 - if (target == bidiLeft(part)) {
20.4368 - part = bidi[--i];
20.4369 - target = part && bidiRight(part);
20.4370 - } else if (target == bidiRight(part)) {
20.4371 - part = bidi[++i];
20.4372 - target = part && bidiLeft(part);
20.4373 - } else break;
20.4374 - }
20.4375 - }
20.4376 -
20.4377 - return target < 0 || target > line.text.length ? null : target;
20.4378 - }
20.4379 -
20.4380 - function moveLogically(line, start, dir, byUnit) {
20.4381 - var target = start + dir;
20.4382 - if (byUnit) while (target > 0 && isExtendingChar.test(line.text.charAt(target))) target += dir;
20.4383 - return target < 0 || target > line.text.length ? null : target;
20.4384 - }
20.4385 -
20.4386 - // Bidirectional ordering algorithm
20.4387 - // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
20.4388 - // that this (partially) implements.
20.4389 -
20.4390 - // One-char codes used for character types:
20.4391 - // L (L): Left-to-Right
20.4392 - // R (R): Right-to-Left
20.4393 - // r (AL): Right-to-Left Arabic
20.4394 - // 1 (EN): European Number
20.4395 - // + (ES): European Number Separator
20.4396 - // % (ET): European Number Terminator
20.4397 - // n (AN): Arabic Number
20.4398 - // , (CS): Common Number Separator
20.4399 - // m (NSM): Non-Spacing Mark
20.4400 - // b (BN): Boundary Neutral
20.4401 - // s (B): Paragraph Separator
20.4402 - // t (S): Segment Separator
20.4403 - // w (WS): Whitespace
20.4404 - // N (ON): Other Neutrals
20.4405 -
20.4406 - // Returns null if characters are ordered as they appear
20.4407 - // (left-to-right), or an array of sections ({from, to, level}
20.4408 - // objects) in the order in which they occur visually.
20.4409 - var bidiOrdering = (function() {
20.4410 - // Character types for codepoints 0 to 0xff
20.4411 - var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL";
20.4412 - // Character types for codepoints 0x600 to 0x6ff
20.4413 - var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmmrrrrrrrrrrrrrrrrrr";
20.4414 - function charType(code) {
20.4415 - if (code <= 0xff) return lowTypes.charAt(code);
20.4416 - else if (0x590 <= code && code <= 0x5f4) return "R";
20.4417 - else if (0x600 <= code && code <= 0x6ff) return arabicTypes.charAt(code - 0x600);
20.4418 - else if (0x700 <= code && code <= 0x8ac) return "r";
20.4419 - else return "L";
20.4420 - }
20.4421 -
20.4422 - var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
20.4423 - var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
20.4424 -
20.4425 - return function charOrdering(str) {
20.4426 - if (!bidiRE.test(str)) return false;
20.4427 - var len = str.length, types = [], startType = null;
20.4428 - for (var i = 0, type; i < len; ++i) {
20.4429 - types.push(type = charType(str.charCodeAt(i)));
20.4430 - if (startType == null) {
20.4431 - if (type == "L") startType = "L";
20.4432 - else if (type == "R" || type == "r") startType = "R";
20.4433 - }
20.4434 - }
20.4435 - if (startType == null) startType = "L";
20.4436 -
20.4437 - // W1. Examine each non-spacing mark (NSM) in the level run, and
20.4438 - // change the type of the NSM to the type of the previous
20.4439 - // character. If the NSM is at the start of the level run, it will
20.4440 - // get the type of sor.
20.4441 - for (var i = 0, prev = startType; i < len; ++i) {
20.4442 - var type = types[i];
20.4443 - if (type == "m") types[i] = prev;
20.4444 - else prev = type;
20.4445 - }
20.4446 -
20.4447 - // W2. Search backwards from each instance of a European number
20.4448 - // until the first strong type (R, L, AL, or sor) is found. If an
20.4449 - // AL is found, change the type of the European number to Arabic
20.4450 - // number.
20.4451 - // W3. Change all ALs to R.
20.4452 - for (var i = 0, cur = startType; i < len; ++i) {
20.4453 - var type = types[i];
20.4454 - if (type == "1" && cur == "r") types[i] = "n";
20.4455 - else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
20.4456 - }
20.4457 -
20.4458 - // W4. A single European separator between two European numbers
20.4459 - // changes to a European number. A single common separator between
20.4460 - // two numbers of the same type changes to that type.
20.4461 - for (var i = 1, prev = types[0]; i < len - 1; ++i) {
20.4462 - var type = types[i];
20.4463 - if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
20.4464 - else if (type == "," && prev == types[i+1] &&
20.4465 - (prev == "1" || prev == "n")) types[i] = prev;
20.4466 - prev = type;
20.4467 - }
20.4468 -
20.4469 - // W5. A sequence of European terminators adjacent to European
20.4470 - // numbers changes to all European numbers.
20.4471 - // W6. Otherwise, separators and terminators change to Other
20.4472 - // Neutral.
20.4473 - for (var i = 0; i < len; ++i) {
20.4474 - var type = types[i];
20.4475 - if (type == ",") types[i] = "N";
20.4476 - else if (type == "%") {
20.4477 - for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
20.4478 - var replace = (i && types[i-1] == "!") || (end < len - 1 && types[end] == "1") ? "1" : "N";
20.4479 - for (var j = i; j < end; ++j) types[j] = replace;
20.4480 - i = end - 1;
20.4481 - }
20.4482 - }
20.4483 -
20.4484 - // W7. Search backwards from each instance of a European number
20.4485 - // until the first strong type (R, L, or sor) is found. If an L is
20.4486 - // found, then change the type of the European number to L.
20.4487 - for (var i = 0, cur = startType; i < len; ++i) {
20.4488 - var type = types[i];
20.4489 - if (cur == "L" && type == "1") types[i] = "L";
20.4490 - else if (isStrong.test(type)) cur = type;
20.4491 - }
20.4492 -
20.4493 - // N1. A sequence of neutrals takes the direction of the
20.4494 - // surrounding strong text if the text on both sides has the same
20.4495 - // direction. European and Arabic numbers act as if they were R in
20.4496 - // terms of their influence on neutrals. Start-of-level-run (sor)
20.4497 - // and end-of-level-run (eor) are used at level run boundaries.
20.4498 - // N2. Any remaining neutrals take the embedding direction.
20.4499 - for (var i = 0; i < len; ++i) {
20.4500 - if (isNeutral.test(types[i])) {
20.4501 - for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
20.4502 - var before = (i ? types[i-1] : startType) == "L";
20.4503 - var after = (end < len - 1 ? types[end] : startType) == "L";
20.4504 - var replace = before || after ? "L" : "R";
20.4505 - for (var j = i; j < end; ++j) types[j] = replace;
20.4506 - i = end - 1;
20.4507 - }
20.4508 - }
20.4509 -
20.4510 - // Here we depart from the documented algorithm, in order to avoid
20.4511 - // building up an actual levels array. Since there are only three
20.4512 - // levels (0, 1, 2) in an implementation that doesn't take
20.4513 - // explicit embedding into account, we can build up the order on
20.4514 - // the fly, without following the level-based algorithm.
20.4515 - var order = [], m;
20.4516 - for (var i = 0; i < len;) {
20.4517 - if (countsAsLeft.test(types[i])) {
20.4518 - var start = i;
20.4519 - for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
20.4520 - order.push({from: start, to: i, level: 0});
20.4521 - } else {
20.4522 - var pos = i, at = order.length;
20.4523 - for (++i; i < len && types[i] != "L"; ++i) {}
20.4524 - for (var j = pos; j < i;) {
20.4525 - if (countsAsNum.test(types[j])) {
20.4526 - if (pos < j) order.splice(at, 0, {from: pos, to: j, level: 1});
20.4527 - var nstart = j;
20.4528 - for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
20.4529 - order.splice(at, 0, {from: nstart, to: j, level: 2});
20.4530 - pos = j;
20.4531 - } else ++j;
20.4532 - }
20.4533 - if (pos < i) order.splice(at, 0, {from: pos, to: i, level: 1});
20.4534 - }
20.4535 - }
20.4536 - if (order[0].level == 1 && (m = str.match(/^\s+/))) {
20.4537 - order[0].from = m[0].length;
20.4538 - order.unshift({from: 0, to: m[0].length, level: 0});
20.4539 - }
20.4540 - if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
20.4541 - lst(order).to -= m[0].length;
20.4542 - order.push({from: len - m[0].length, to: len, level: 0});
20.4543 - }
20.4544 - if (order[0].level != lst(order).level)
20.4545 - order.push({from: len, to: len, level: order[0].level});
20.4546 -
20.4547 - return order;
20.4548 - };
20.4549 - })();
20.4550 -
20.4551 - // THE END
20.4552 -
20.4553 - CodeMirror.version = "3.0";
20.4554 -
20.4555 - return CodeMirror;
20.4556 -})();
21.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/mode/clike.js Tue Apr 29 15:25:58 2014 +0200
21.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
21.3 @@ -1,300 +0,0 @@
21.4 -CodeMirror.defineMode("clike", function(config, parserConfig) {
21.5 - var indentUnit = config.indentUnit,
21.6 - statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
21.7 - keywords = parserConfig.keywords || {},
21.8 - builtin = parserConfig.builtin || {},
21.9 - blockKeywords = parserConfig.blockKeywords || {},
21.10 - atoms = parserConfig.atoms || {},
21.11 - hooks = parserConfig.hooks || {},
21.12 - multiLineStrings = parserConfig.multiLineStrings;
21.13 - var isOperatorChar = /[+\-*&%=<>!?|\/]/;
21.14 -
21.15 - var curPunc;
21.16 -
21.17 - function tokenBase(stream, state) {
21.18 - var ch = stream.next();
21.19 - if (hooks[ch]) {
21.20 - var result = hooks[ch](stream, state);
21.21 - if (result !== false) return result;
21.22 - }
21.23 - if (ch == '"' || ch == "'") {
21.24 - state.tokenize = tokenString(ch);
21.25 - return state.tokenize(stream, state);
21.26 - }
21.27 - if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
21.28 - curPunc = ch;
21.29 - return null;
21.30 - }
21.31 - if (/\d/.test(ch)) {
21.32 - stream.eatWhile(/[\w\.]/);
21.33 - return "number";
21.34 - }
21.35 - if (ch == "/") {
21.36 - if (stream.eat("*")) {
21.37 - state.tokenize = tokenComment;
21.38 - return tokenComment(stream, state);
21.39 - }
21.40 - if (stream.eat("/")) {
21.41 - stream.skipToEnd();
21.42 - return "comment";
21.43 - }
21.44 - }
21.45 - if (isOperatorChar.test(ch)) {
21.46 - stream.eatWhile(isOperatorChar);
21.47 - return "operator";
21.48 - }
21.49 - stream.eatWhile(/[\w\$_]/);
21.50 - var cur = stream.current();
21.51 - if (keywords.propertyIsEnumerable(cur)) {
21.52 - if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
21.53 - return "keyword";
21.54 - }
21.55 - if (builtin.propertyIsEnumerable(cur)) {
21.56 - if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
21.57 - return "builtin";
21.58 - }
21.59 - if (atoms.propertyIsEnumerable(cur)) return "atom";
21.60 - return "variable";
21.61 - }
21.62 -
21.63 - function tokenString(quote) {
21.64 - return function(stream, state) {
21.65 - var escaped = false, next, end = false;
21.66 - while ((next = stream.next()) != null) {
21.67 - if (next == quote && !escaped) {end = true; break;}
21.68 - escaped = !escaped && next == "\\";
21.69 - }
21.70 - if (end || !(escaped || multiLineStrings))
21.71 - state.tokenize = null;
21.72 - return "string";
21.73 - };
21.74 - }
21.75 -
21.76 - function tokenComment(stream, state) {
21.77 - var maybeEnd = false, ch;
21.78 - while (ch = stream.next()) {
21.79 - if (ch == "/" && maybeEnd) {
21.80 - state.tokenize = null;
21.81 - break;
21.82 - }
21.83 - maybeEnd = (ch == "*");
21.84 - }
21.85 - return "comment";
21.86 - }
21.87 -
21.88 - function Context(indented, column, type, align, prev) {
21.89 - this.indented = indented;
21.90 - this.column = column;
21.91 - this.type = type;
21.92 - this.align = align;
21.93 - this.prev = prev;
21.94 - }
21.95 - function pushContext(state, col, type) {
21.96 - var indent = state.indented;
21.97 - if (state.context && state.context.type == "statement")
21.98 - indent = state.context.indented;
21.99 - return state.context = new Context(indent, col, type, null, state.context);
21.100 - }
21.101 - function popContext(state) {
21.102 - var t = state.context.type;
21.103 - if (t == ")" || t == "]" || t == "}")
21.104 - state.indented = state.context.indented;
21.105 - return state.context = state.context.prev;
21.106 - }
21.107 -
21.108 - // Interface
21.109 -
21.110 - return {
21.111 - startState: function(basecolumn) {
21.112 - return {
21.113 - tokenize: null,
21.114 - context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
21.115 - indented: 0,
21.116 - startOfLine: true
21.117 - };
21.118 - },
21.119 -
21.120 - token: function(stream, state) {
21.121 - var ctx = state.context;
21.122 - if (stream.sol()) {
21.123 - if (ctx.align == null) ctx.align = false;
21.124 - state.indented = stream.indentation();
21.125 - state.startOfLine = true;
21.126 - }
21.127 - if (stream.eatSpace()) return null;
21.128 - curPunc = null;
21.129 - var style = (state.tokenize || tokenBase)(stream, state);
21.130 - if (style == "comment" || style == "meta") return style;
21.131 - if (ctx.align == null) ctx.align = true;
21.132 -
21.133 - if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state);
21.134 - else if (curPunc == "{") pushContext(state, stream.column(), "}");
21.135 - else if (curPunc == "[") pushContext(state, stream.column(), "]");
21.136 - else if (curPunc == "(") pushContext(state, stream.column(), ")");
21.137 - else if (curPunc == "}") {
21.138 - while (ctx.type == "statement") ctx = popContext(state);
21.139 - if (ctx.type == "}") ctx = popContext(state);
21.140 - while (ctx.type == "statement") ctx = popContext(state);
21.141 - }
21.142 - else if (curPunc == ctx.type) popContext(state);
21.143 - else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement"))
21.144 - pushContext(state, stream.column(), "statement");
21.145 - state.startOfLine = false;
21.146 - return style;
21.147 - },
21.148 -
21.149 - indent: function(state, textAfter) {
21.150 - if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
21.151 - var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
21.152 - if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev;
21.153 - var closing = firstChar == ctx.type;
21.154 - if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
21.155 - else if (ctx.align) return ctx.column + (closing ? 0 : 1);
21.156 - else return ctx.indented + (closing ? 0 : indentUnit);
21.157 - },
21.158 -
21.159 - electricChars: "{}"
21.160 - };
21.161 -});
21.162 -
21.163 -(function() {
21.164 - function words(str) {
21.165 - var obj = {}, words = str.split(" ");
21.166 - for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
21.167 - return obj;
21.168 - }
21.169 - var cKeywords = "auto if break int case long char register continue return default short do sizeof " +
21.170 - "double static else struct entry switch extern typedef float union for unsigned " +
21.171 - "goto while enum void const signed volatile";
21.172 -
21.173 - function cppHook(stream, state) {
21.174 - if (!state.startOfLine) return false;
21.175 - for (;;) {
21.176 - if (stream.skipTo("\\")) {
21.177 - stream.next();
21.178 - if (stream.eol()) {
21.179 - state.tokenize = cppHook;
21.180 - break;
21.181 - }
21.182 - } else {
21.183 - stream.skipToEnd();
21.184 - state.tokenize = null;
21.185 - break;
21.186 - }
21.187 - }
21.188 - return "meta";
21.189 - }
21.190 -
21.191 - // C#-style strings where "" escapes a quote.
21.192 - function tokenAtString(stream, state) {
21.193 - var next;
21.194 - while ((next = stream.next()) != null) {
21.195 - if (next == '"' && !stream.eat('"')) {
21.196 - state.tokenize = null;
21.197 - break;
21.198 - }
21.199 - }
21.200 - return "string";
21.201 - }
21.202 -
21.203 - function mimes(ms, mode) {
21.204 - for (var i = 0; i < ms.length; ++i) CodeMirror.defineMIME(ms[i], mode);
21.205 - }
21.206 -
21.207 - mimes(["text/x-csrc", "text/x-c", "text/x-chdr"], {
21.208 - name: "clike",
21.209 - keywords: words(cKeywords),
21.210 - blockKeywords: words("case do else for if switch while struct"),
21.211 - atoms: words("null"),
21.212 - hooks: {"#": cppHook}
21.213 - });
21.214 - mimes(["text/x-c++src", "text/x-c++hdr"], {
21.215 - name: "clike",
21.216 - keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try bool explicit new " +
21.217 - "static_cast typeid catch operator template typename class friend private " +
21.218 - "this using const_cast inline public throw virtual delete mutable protected " +
21.219 - "wchar_t"),
21.220 - blockKeywords: words("catch class do else finally for if struct switch try while"),
21.221 - atoms: words("true false null"),
21.222 - hooks: {"#": cppHook}
21.223 - });
21.224 - CodeMirror.defineMIME("text/x-java", {
21.225 - name: "clike",
21.226 - keywords: words("abstract assert boolean break byte case catch char class const continue default " +
21.227 - "do double else enum extends final finally float for goto if implements import " +
21.228 - "instanceof int interface long native new package private protected public " +
21.229 - "return short static strictfp super switch synchronized this throw throws transient " +
21.230 - "try void volatile while"),
21.231 - blockKeywords: words("catch class do else finally for if switch try while"),
21.232 - atoms: words("true false null"),
21.233 - hooks: {
21.234 - "@": function(stream) {
21.235 - stream.eatWhile(/[\w\$_]/);
21.236 - return "meta";
21.237 - }
21.238 - }
21.239 - });
21.240 - CodeMirror.defineMIME("text/x-csharp", {
21.241 - name: "clike",
21.242 - keywords: words("abstract as base break case catch checked class const continue" +
21.243 - " default delegate do else enum event explicit extern finally fixed for" +
21.244 - " foreach goto if implicit in interface internal is lock namespace new" +
21.245 - " operator out override params private protected public readonly ref return sealed" +
21.246 - " sizeof stackalloc static struct switch this throw try typeof unchecked" +
21.247 - " unsafe using virtual void volatile while add alias ascending descending dynamic from get" +
21.248 - " global group into join let orderby partial remove select set value var yield"),
21.249 - blockKeywords: words("catch class do else finally for foreach if struct switch try while"),
21.250 - builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" +
21.251 - " Guid Int16 Int32 Int64 Object SByte Single String TimeSpan UInt16 UInt32" +
21.252 - " UInt64 bool byte char decimal double short int long object" +
21.253 - " sbyte float string ushort uint ulong"),
21.254 - atoms: words("true false null"),
21.255 - hooks: {
21.256 - "@": function(stream, state) {
21.257 - if (stream.eat('"')) {
21.258 - state.tokenize = tokenAtString;
21.259 - return tokenAtString(stream, state);
21.260 - }
21.261 - stream.eatWhile(/[\w\$_]/);
21.262 - return "meta";
21.263 - }
21.264 - }
21.265 - });
21.266 - CodeMirror.defineMIME("text/x-scala", {
21.267 - name: "clike",
21.268 - keywords: words(
21.269 -
21.270 - /* scala */
21.271 - "abstract case catch class def do else extends false final finally for forSome if " +
21.272 - "implicit import lazy match new null object override package private protected return " +
21.273 - "sealed super this throw trait try trye type val var while with yield _ : = => <- <: " +
21.274 - "<% >: # @ " +
21.275 -
21.276 - /* package scala */
21.277 - "assert assume require print println printf readLine readBoolean readByte readShort " +
21.278 - "readChar readInt readLong readFloat readDouble " +
21.279 -
21.280 - "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
21.281 - "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
21.282 - "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
21.283 - "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
21.284 - "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " +
21.285 -
21.286 - /* package java.lang */
21.287 - "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
21.288 - "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
21.289 - "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
21.290 - "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
21.291 -
21.292 -
21.293 - ),
21.294 - blockKeywords: words("catch class do else finally for forSome if match switch try while"),
21.295 - atoms: words("true false null"),
21.296 - hooks: {
21.297 - "@": function(stream) {
21.298 - stream.eatWhile(/[\w\$_]/);
21.299 - return "meta";
21.300 - }
21.301 - }
21.302 - });
21.303 -}());
22.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/mode/xml.js Tue Apr 29 15:25:58 2014 +0200
22.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
22.3 @@ -1,324 +0,0 @@
22.4 -CodeMirror.defineMode("xml", function(config, parserConfig) {
22.5 - var indentUnit = config.indentUnit;
22.6 - var Kludges = parserConfig.htmlMode ? {
22.7 - autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
22.8 - 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
22.9 - 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
22.10 - 'track': true, 'wbr': true},
22.11 - implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
22.12 - 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
22.13 - 'th': true, 'tr': true},
22.14 - contextGrabbers: {
22.15 - 'dd': {'dd': true, 'dt': true},
22.16 - 'dt': {'dd': true, 'dt': true},
22.17 - 'li': {'li': true},
22.18 - 'option': {'option': true, 'optgroup': true},
22.19 - 'optgroup': {'optgroup': true},
22.20 - 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
22.21 - 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
22.22 - 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
22.23 - 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
22.24 - 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
22.25 - 'rp': {'rp': true, 'rt': true},
22.26 - 'rt': {'rp': true, 'rt': true},
22.27 - 'tbody': {'tbody': true, 'tfoot': true},
22.28 - 'td': {'td': true, 'th': true},
22.29 - 'tfoot': {'tbody': true},
22.30 - 'th': {'td': true, 'th': true},
22.31 - 'thead': {'tbody': true, 'tfoot': true},
22.32 - 'tr': {'tr': true}
22.33 - },
22.34 - doNotIndent: {"pre": true},
22.35 - allowUnquoted: true,
22.36 - allowMissing: true
22.37 - } : {
22.38 - autoSelfClosers: {},
22.39 - implicitlyClosed: {},
22.40 - contextGrabbers: {},
22.41 - doNotIndent: {},
22.42 - allowUnquoted: false,
22.43 - allowMissing: false
22.44 - };
22.45 - var alignCDATA = parserConfig.alignCDATA;
22.46 -
22.47 - // Return variables for tokenizers
22.48 - var tagName, type;
22.49 -
22.50 - function inText(stream, state) {
22.51 - function chain(parser) {
22.52 - state.tokenize = parser;
22.53 - return parser(stream, state);
22.54 - }
22.55 -
22.56 - var ch = stream.next();
22.57 - if (ch == "<") {
22.58 - if (stream.eat("!")) {
22.59 - if (stream.eat("[")) {
22.60 - if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
22.61 - else return null;
22.62 - }
22.63 - else if (stream.match("--")) return chain(inBlock("comment", "-->"));
22.64 - else if (stream.match("DOCTYPE", true, true)) {
22.65 - stream.eatWhile(/[\w\._\-]/);
22.66 - return chain(doctype(1));
22.67 - }
22.68 - else return null;
22.69 - }
22.70 - else if (stream.eat("?")) {
22.71 - stream.eatWhile(/[\w\._\-]/);
22.72 - state.tokenize = inBlock("meta", "?>");
22.73 - return "meta";
22.74 - }
22.75 - else {
22.76 - var isClose = stream.eat("/");
22.77 - tagName = "";
22.78 - var c;
22.79 - while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
22.80 - if (!tagName) return "error";
22.81 - type = isClose ? "closeTag" : "openTag";
22.82 - state.tokenize = inTag;
22.83 - return "tag";
22.84 - }
22.85 - }
22.86 - else if (ch == "&") {
22.87 - var ok;
22.88 - if (stream.eat("#")) {
22.89 - if (stream.eat("x")) {
22.90 - ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
22.91 - } else {
22.92 - ok = stream.eatWhile(/[\d]/) && stream.eat(";");
22.93 - }
22.94 - } else {
22.95 - ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
22.96 - }
22.97 - return ok ? "atom" : "error";
22.98 - }
22.99 - else {
22.100 - stream.eatWhile(/[^&<]/);
22.101 - return null;
22.102 - }
22.103 - }
22.104 -
22.105 - function inTag(stream, state) {
22.106 - var ch = stream.next();
22.107 - if (ch == ">" || (ch == "/" && stream.eat(">"))) {
22.108 - state.tokenize = inText;
22.109 - type = ch == ">" ? "endTag" : "selfcloseTag";
22.110 - return "tag";
22.111 - }
22.112 - else if (ch == "=") {
22.113 - type = "equals";
22.114 - return null;
22.115 - }
22.116 - else if (/[\'\"]/.test(ch)) {
22.117 - state.tokenize = inAttribute(ch);
22.118 - return state.tokenize(stream, state);
22.119 - }
22.120 - else {
22.121 - stream.eatWhile(/[^\s\u00a0=<>\"\']/);
22.122 - return "word";
22.123 - }
22.124 - }
22.125 -
22.126 - function inAttribute(quote) {
22.127 - return function(stream, state) {
22.128 - while (!stream.eol()) {
22.129 - if (stream.next() == quote) {
22.130 - state.tokenize = inTag;
22.131 - break;
22.132 - }
22.133 - }
22.134 - return "string";
22.135 - };
22.136 - }
22.137 -
22.138 - function inBlock(style, terminator) {
22.139 - return function(stream, state) {
22.140 - while (!stream.eol()) {
22.141 - if (stream.match(terminator)) {
22.142 - state.tokenize = inText;
22.143 - break;
22.144 - }
22.145 - stream.next();
22.146 - }
22.147 - return style;
22.148 - };
22.149 - }
22.150 - function doctype(depth) {
22.151 - return function(stream, state) {
22.152 - var ch;
22.153 - while ((ch = stream.next()) != null) {
22.154 - if (ch == "<") {
22.155 - state.tokenize = doctype(depth + 1);
22.156 - return state.tokenize(stream, state);
22.157 - } else if (ch == ">") {
22.158 - if (depth == 1) {
22.159 - state.tokenize = inText;
22.160 - break;
22.161 - } else {
22.162 - state.tokenize = doctype(depth - 1);
22.163 - return state.tokenize(stream, state);
22.164 - }
22.165 - }
22.166 - }
22.167 - return "meta";
22.168 - };
22.169 - }
22.170 -
22.171 - var curState, setStyle;
22.172 - function pass() {
22.173 - for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
22.174 - }
22.175 - function cont() {
22.176 - pass.apply(null, arguments);
22.177 - return true;
22.178 - }
22.179 -
22.180 - function pushContext(tagName, startOfLine) {
22.181 - var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context && curState.context.noIndent);
22.182 - curState.context = {
22.183 - prev: curState.context,
22.184 - tagName: tagName,
22.185 - indent: curState.indented,
22.186 - startOfLine: startOfLine,
22.187 - noIndent: noIndent
22.188 - };
22.189 - }
22.190 - function popContext() {
22.191 - if (curState.context) curState.context = curState.context.prev;
22.192 - }
22.193 -
22.194 - function element(type) {
22.195 - if (type == "openTag") {
22.196 - curState.tagName = tagName;
22.197 - return cont(attributes, endtag(curState.startOfLine));
22.198 - } else if (type == "closeTag") {
22.199 - var err = false;
22.200 - if (curState.context) {
22.201 - if (curState.context.tagName != tagName) {
22.202 - if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
22.203 - popContext();
22.204 - }
22.205 - err = !curState.context || curState.context.tagName != tagName;
22.206 - }
22.207 - } else {
22.208 - err = true;
22.209 - }
22.210 - if (err) setStyle = "error";
22.211 - return cont(endclosetag(err));
22.212 - }
22.213 - return cont();
22.214 - }
22.215 - function endtag(startOfLine) {
22.216 - return function(type) {
22.217 - var tagName = curState.tagName;
22.218 - curState.tagName = null;
22.219 - if (type == "selfcloseTag" ||
22.220 - (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
22.221 - maybePopContext(tagName.toLowerCase());
22.222 - return cont();
22.223 - }
22.224 - if (type == "endTag") {
22.225 - maybePopContext(tagName.toLowerCase());
22.226 - pushContext(tagName, startOfLine);
22.227 - return cont();
22.228 - }
22.229 - return cont();
22.230 - };
22.231 - }
22.232 - function endclosetag(err) {
22.233 - return function(type) {
22.234 - if (err) setStyle = "error";
22.235 - if (type == "endTag") { popContext(); return cont(); }
22.236 - setStyle = "error";
22.237 - return cont(arguments.callee);
22.238 - };
22.239 - }
22.240 - function maybePopContext(nextTagName) {
22.241 - var parentTagName;
22.242 - while (true) {
22.243 - if (!curState.context) {
22.244 - return;
22.245 - }
22.246 - parentTagName = curState.context.tagName.toLowerCase();
22.247 - if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
22.248 - !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
22.249 - return;
22.250 - }
22.251 - popContext();
22.252 - }
22.253 - }
22.254 -
22.255 - function attributes(type) {
22.256 - if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
22.257 - if (type == "endTag" || type == "selfcloseTag") return pass();
22.258 - setStyle = "error";
22.259 - return cont(attributes);
22.260 - }
22.261 - function attribute(type) {
22.262 - if (type == "equals") return cont(attvalue, attributes);
22.263 - if (!Kludges.allowMissing) setStyle = "error";
22.264 - else if (type == "word") setStyle = "attribute";
22.265 - return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
22.266 - }
22.267 - function attvalue(type) {
22.268 - if (type == "string") return cont(attvaluemaybe);
22.269 - if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
22.270 - setStyle = "error";
22.271 - return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
22.272 - }
22.273 - function attvaluemaybe(type) {
22.274 - if (type == "string") return cont(attvaluemaybe);
22.275 - else return pass();
22.276 - }
22.277 -
22.278 - return {
22.279 - startState: function() {
22.280 - return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null};
22.281 - },
22.282 -
22.283 - token: function(stream, state) {
22.284 - if (stream.sol()) {
22.285 - state.startOfLine = true;
22.286 - state.indented = stream.indentation();
22.287 - }
22.288 - if (stream.eatSpace()) return null;
22.289 -
22.290 - setStyle = type = tagName = null;
22.291 - var style = state.tokenize(stream, state);
22.292 - state.type = type;
22.293 - if ((style || type) && style != "comment") {
22.294 - curState = state;
22.295 - while (true) {
22.296 - var comb = state.cc.pop() || element;
22.297 - if (comb(type || style)) break;
22.298 - }
22.299 - }
22.300 - state.startOfLine = false;
22.301 - return setStyle || style;
22.302 - },
22.303 -
22.304 - indent: function(state, textAfter, fullLine) {
22.305 - var context = state.context;
22.306 - if ((state.tokenize != inTag && state.tokenize != inText) ||
22.307 - context && context.noIndent)
22.308 - return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
22.309 - if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
22.310 - if (context && /^<\//.test(textAfter))
22.311 - context = context.prev;
22.312 - while (context && !context.startOfLine)
22.313 - context = context.prev;
22.314 - if (context) return context.indent + indentUnit;
22.315 - else return 0;
22.316 - },
22.317 -
22.318 - electricChars: "/",
22.319 -
22.320 - configuration: parserConfig.htmlMode ? "html" : "xml"
22.321 - };
22.322 -});
22.323 -
22.324 -CodeMirror.defineMIME("text/xml", "xml");
22.325 -CodeMirror.defineMIME("application/xml", "xml");
22.326 -if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
22.327 - CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
23.1 --- a/dew/src/main/resources/org/apidesign/bck2brwsr/dew/js/codemirror/theme/elegant.css Tue Apr 29 15:25:58 2014 +0200
23.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
23.3 @@ -1,10 +0,0 @@
23.4 -.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;}
23.5 -.cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;}
23.6 -.cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;}
23.7 -.cm-s-elegant span.cm-variable {color: black;}
23.8 -.cm-s-elegant span.cm-variable-2 {color: #b11;}
23.9 -.cm-s-elegant span.cm-qualifier {color: #555;}
23.10 -.cm-s-elegant span.cm-keyword {color: #730;}
23.11 -.cm-s-elegant span.cm-builtin {color: #30a;}
23.12 -.cm-s-elegant span.cm-error {background-color: #fdd;}
23.13 -.cm-s-elegant span.cm-link {color: #762;}
24.1 --- a/dew/src/test/java/org/apidesign/bck2brwsr/dew/CompileTest.java Tue Apr 29 15:25:58 2014 +0200
24.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
24.3 @@ -1,45 +0,0 @@
24.4 -/**
24.5 - * Back 2 Browser Bytecode Translator
24.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
24.7 - *
24.8 - * This program is free software: you can redistribute it and/or modify
24.9 - * it under the terms of the GNU General Public License as published by
24.10 - * the Free Software Foundation, version 2 of the License.
24.11 - *
24.12 - * This program is distributed in the hope that it will be useful,
24.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
24.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24.15 - * GNU General Public License for more details.
24.16 - *
24.17 - * You should have received a copy of the GNU General Public License
24.18 - * along with this program. Look for COPYING file in the top folder.
24.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
24.20 - */
24.21 -package org.apidesign.bck2brwsr.dew;
24.22 -
24.23 -import java.io.IOException;
24.24 -import static org.testng.Assert.*;
24.25 -import org.testng.annotations.Test;
24.26 -
24.27 -/**
24.28 - *
24.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
24.30 - */
24.31 -public class CompileTest {
24.32 - @Test public void testCompile() throws IOException {
24.33 - String html = "<html><body>"
24.34 - + " <button id='btn'>Hello!</button>"
24.35 - + "</body></html>";
24.36 - String java = "package x.y.z;"
24.37 - + "import org.apidesign.bck2brwsr.htmlpage.api.*;"
24.38 - + "import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;"
24.39 - + "@Page(xhtml=\"index.html\", className=\"Index\")"
24.40 - + "class X { "
24.41 - + " @On(event=CLICK, id=\"btn\") static void clcs() {}"
24.42 - + "}";
24.43 - Compile result = Compile.create(html, java);
24.44 -
24.45 - assertNotNull(result.get("x/y/z/X.class"), "Class X is compiled: " + result);
24.46 - assertNotNull(result.get("x/y/z/Index.class"), "Class Index is compiled: " + result);
24.47 - }
24.48 -}
25.1 --- a/ide/editor/pom.xml Tue Apr 29 15:25:58 2014 +0200
25.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
25.3 @@ -1,185 +0,0 @@
25.4 -<?xml version="1.0" encoding="UTF-8"?>
25.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
25.6 - <modelVersion>4.0.0</modelVersion>
25.7 - <parent>
25.8 - <artifactId>ide</artifactId>
25.9 - <groupId>org.apidesign.bck2brwsr</groupId>
25.10 - <version>0.8-SNAPSHOT</version>
25.11 - </parent>
25.12 -
25.13 - <groupId>org.apidesign.bck2brwsr.ide</groupId>
25.14 - <artifactId>editor</artifactId>
25.15 - <version>0.8-SNAPSHOT</version>
25.16 - <packaging>nbm</packaging>
25.17 -
25.18 - <name>Editor Support for Bck2Brwsr</name>
25.19 -
25.20 - <properties>
25.21 - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
25.22 - <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
25.23 - </properties>
25.24 -
25.25 - <repositories>
25.26 - <!--
25.27 - Repository hosting NetBeans modules, especially APIs.
25.28 - Versions are based on IDE releases, e.g.: RELEASE691
25.29 - To create your own repository, use: nbm:populate-repository
25.30 - -->
25.31 - <repository>
25.32 - <id>netbeans</id>
25.33 - <name>NetBeans</name>
25.34 - <url>http://bits.netbeans.org/maven2/</url>
25.35 - <snapshots>
25.36 - <enabled>false</enabled>
25.37 - </snapshots>
25.38 - </repository>
25.39 - </repositories>
25.40 -
25.41 - <dependencies>
25.42 - <dependency>
25.43 - <groupId>org.netbeans.api</groupId>
25.44 - <artifactId>org-netbeans-api-annotations-common</artifactId>
25.45 - </dependency>
25.46 - <dependency>
25.47 - <groupId>org.netbeans.api</groupId>
25.48 - <artifactId>org-netbeans-modules-java-source</artifactId>
25.49 - </dependency>
25.50 - <dependency>
25.51 - <groupId>org.netbeans.api</groupId>
25.52 - <artifactId>org-netbeans-libs-javacapi</artifactId>
25.53 - </dependency>
25.54 - <dependency>
25.55 - <groupId>org.netbeans.api</groupId>
25.56 - <artifactId>org-netbeans-spi-java-hints</artifactId>
25.57 - </dependency>
25.58 - <dependency>
25.59 - <groupId>org.netbeans.api</groupId>
25.60 - <artifactId>org-netbeans-modules-parsing-api</artifactId>
25.61 - </dependency>
25.62 - <dependency>
25.63 - <groupId>org.netbeans.api</groupId>
25.64 - <artifactId>org-netbeans-spi-editor-hints</artifactId>
25.65 - </dependency>
25.66 - <dependency>
25.67 - <groupId>org.netbeans.api</groupId>
25.68 - <artifactId>org-openide-util</artifactId>
25.69 - </dependency>
25.70 - <dependency>
25.71 - <groupId>org.netbeans.api</groupId>
25.72 - <artifactId>org-netbeans-modules-java-lexer</artifactId>
25.73 - </dependency>
25.74 - <dependency>
25.75 - <groupId>org.netbeans.api</groupId>
25.76 - <artifactId>org-netbeans-modules-lexer</artifactId>
25.77 - </dependency>
25.78 - <dependency>
25.79 - <groupId>org.apidesign.bck2brwsr</groupId>
25.80 - <artifactId>core</artifactId>
25.81 - <version>0.8-SNAPSHOT</version>
25.82 - <type>jar</type>
25.83 - <scope>test</scope>
25.84 - </dependency>
25.85 - <dependency>
25.86 - <groupId>org.netbeans.api</groupId>
25.87 - <artifactId>org-netbeans-modules-java-hints-test</artifactId>
25.88 - <scope>test</scope>
25.89 - </dependency>
25.90 - <dependency>
25.91 - <groupId>org.netbeans.api</groupId>
25.92 - <artifactId>org-netbeans-libs-junit4</artifactId>
25.93 - <scope>test</scope>
25.94 - </dependency>
25.95 - <dependency>
25.96 - <groupId>org.netbeans.modules</groupId>
25.97 - <artifactId>org-netbeans-lib-nbjavac</artifactId>
25.98 - <scope>test</scope>
25.99 - </dependency>
25.100 - <dependency>
25.101 - <groupId>org.testng</groupId>
25.102 - <artifactId>testng</artifactId>
25.103 - <scope>test</scope>
25.104 - </dependency>
25.105 - </dependencies>
25.106 -
25.107 - <build>
25.108 - <plugins>
25.109 - <plugin>
25.110 - <groupId>org.codehaus.mojo</groupId>
25.111 - <artifactId>nbm-maven-plugin</artifactId>
25.112 - <version>3.8</version>
25.113 - <extensions>true</extensions>
25.114 - </plugin>
25.115 -
25.116 - <plugin>
25.117 - <!-- NetBeans 6.9+ requires JDK 6 -->
25.118 - <groupId>org.apache.maven.plugins</groupId>
25.119 - <artifactId>maven-compiler-plugin</artifactId>
25.120 - <version>2.5.1</version>
25.121 - <configuration>
25.122 - <source>1.6</source>
25.123 - <target>1.6</target>
25.124 - <compilerArguments>
25.125 - <endorseddirs>${endorsed.dir}</endorseddirs>
25.126 - </compilerArguments>
25.127 - </configuration>
25.128 - </plugin>
25.129 -
25.130 - <plugin>
25.131 - <groupId>org.apache.maven.plugins</groupId>
25.132 - <artifactId>maven-jar-plugin</artifactId>
25.133 - <version>2.4</version>
25.134 - <configuration>
25.135 - <!-- to have the jar plugin pickup the nbm generated manifest -->
25.136 - <useDefaultManifestFile>true</useDefaultManifestFile>
25.137 - </configuration>
25.138 - </plugin>
25.139 -
25.140 - <plugin>
25.141 - <groupId>org.apache.maven.plugins</groupId>
25.142 - <artifactId>maven-dependency-plugin</artifactId>
25.143 - <executions>
25.144 - <execution>
25.145 - <id>endorsed</id>
25.146 - <phase>validate</phase>
25.147 - <goals>
25.148 - <goal>copy</goal>
25.149 - </goals>
25.150 - </execution>
25.151 - </executions>
25.152 - <configuration>
25.153 - <outputDirectory>${endorsed.dir}</outputDirectory>
25.154 - <silent>true</silent>
25.155 - <artifactItems>
25.156 - <artifactItem>
25.157 - <groupId>org.netbeans.api</groupId>
25.158 - <artifactId>org-netbeans-libs-javacapi</artifactId>
25.159 - <version>${netbeans.version}</version>
25.160 - </artifactItem>
25.161 - <artifactItem>
25.162 - <groupId>org.netbeans.external</groupId>
25.163 - <artifactId>nb-javac-api</artifactId>
25.164 - <version>${netbeans.version}</version>
25.165 - </artifactItem>
25.166 - <artifactItem>
25.167 - <groupId>org.netbeans.modules</groupId>
25.168 - <artifactId>org-netbeans-libs-javacimpl</artifactId>
25.169 - <version>${netbeans.version}</version>
25.170 - </artifactItem>
25.171 - <artifactItem>
25.172 - <groupId>org.netbeans.external</groupId>
25.173 - <artifactId>nb-javac-impl</artifactId>
25.174 - <version>${netbeans.version}</version>
25.175 - </artifactItem>
25.176 - </artifactItems>
25.177 - </configuration>
25.178 - </plugin>
25.179 - <plugin>
25.180 - <groupId>org.apache.maven.plugins</groupId>
25.181 - <artifactId>maven-surefire-plugin</artifactId>
25.182 - <configuration>
25.183 - <argLine>-Djava.endorsed.dirs=${endorsed.dir}</argLine>
25.184 - </configuration>
25.185 - </plugin>
25.186 - </plugins>
25.187 - </build>
25.188 -</project>
26.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JNIHelper.java Tue Apr 29 15:25:58 2014 +0200
26.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
26.3 @@ -1,80 +0,0 @@
26.4 -/**
26.5 - * Back 2 Browser Bytecode Translator
26.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
26.7 - *
26.8 - * This program is free software: you can redistribute it and/or modify
26.9 - * it under the terms of the GNU General Public License as published by
26.10 - * the Free Software Foundation, version 2 of the License.
26.11 - *
26.12 - * This program is distributed in the hope that it will be useful,
26.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
26.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26.15 - * GNU General Public License for more details.
26.16 - *
26.17 - * You should have received a copy of the GNU General Public License
26.18 - * along with this program. Look for COPYING file in the top folder.
26.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
26.20 - */
26.21 -package org.apidesign.bck2brwsr.ide.editor;
26.22 -
26.23 -import java.lang.reflect.Method;
26.24 -import java.util.HashMap;
26.25 -import java.util.Map;
26.26 -
26.27 -/**
26.28 - * JNI Helper.
26.29 - * To facilitate lookup of methods by name and signature, instead of manually parsing signatures,
26.30 - * constructs the map of all methods and uses Class.getName() to generate almost-correct signatures.
26.31 - */
26.32 -class JNIHelper {
26.33 -
26.34 - static Method method(String clazz, String method, String signature) {
26.35 - final Map<String, Method> methods = methodMap(JNIHelper.clazz(clazz));
26.36 - return methods.get(methodKey(method, signature));
26.37 - }
26.38 -
26.39 - static Class<?> clazz(String clazz) {
26.40 - try {
26.41 - return Class.forName(clazz);
26.42 - } catch (ClassNotFoundException e) {
26.43 - throw new IllegalArgumentException(e);
26.44 - }
26.45 - }
26.46 -
26.47 - static Map<String, Method> methodMap(final Class<?> clazz) {
26.48 - final Map<String, Method> map = new HashMap<String, Method>();
26.49 - final Method[] methods = clazz.getDeclaredMethods();
26.50 - for (int i = 0; i < methods.length; i++) {
26.51 - final Method method = methods[i];
26.52 - map.put(methodKey(method.getName(), signature(method)), method);
26.53 - }
26.54 - return map;
26.55 - }
26.56 -
26.57 - static String methodKey(String method, String signature) {
26.58 - return method + '@' + signature;
26.59 - }
26.60 -
26.61 - static String signature(final Method method) {
26.62 - final Class<?>[] parameterTypes = method.getParameterTypes();
26.63 - final StringBuilder b = new StringBuilder();
26.64 - for (int j = 0; j < parameterTypes.length; j++) {
26.65 - b.append(signature(parameterTypes[j]));
26.66 - }
26.67 - return b.toString();
26.68 - }
26.69 -
26.70 - static String signature(final Class<?> clazz) {
26.71 - if (clazz == boolean.class) return "Z";
26.72 - else if (clazz == byte.class) return "B";
26.73 - else if (clazz == char.class) return "C";
26.74 - else if (clazz == double.class) return "D";
26.75 - else if (clazz == float.class) return "F";
26.76 - else if (clazz == int.class) return "I";
26.77 - else if (clazz == long.class) return "J";
26.78 - else if (clazz == short.class) return "S";
26.79 - else if (clazz == void.class) return "V";
26.80 - else if (clazz.isArray()) return clazz.getName().replace('.','/');
26.81 - else return "L" + clazz.getName().replace('.','/') + ";";
26.82 - }
26.83 -}
27.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSEmbeddingProvider.java Tue Apr 29 15:25:58 2014 +0200
27.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
27.3 @@ -1,188 +0,0 @@
27.4 -/**
27.5 - * Back 2 Browser Bytecode Translator
27.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
27.7 - *
27.8 - * This program is free software: you can redistribute it and/or modify
27.9 - * it under the terms of the GNU General Public License as published by
27.10 - * the Free Software Foundation, version 2 of the License.
27.11 - *
27.12 - * This program is distributed in the hope that it will be useful,
27.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
27.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27.15 - * GNU General Public License for more details.
27.16 - *
27.17 - * You should have received a copy of the GNU General Public License
27.18 - * along with this program. Look for COPYING file in the top folder.
27.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
27.20 - */
27.21 -package org.apidesign.bck2brwsr.ide.editor;
27.22 -
27.23 -import com.sun.source.tree.AnnotationTree;
27.24 -import com.sun.source.tree.AssignmentTree;
27.25 -import com.sun.source.tree.CompilationUnitTree;
27.26 -import com.sun.source.tree.ExpressionTree;
27.27 -import com.sun.source.tree.LiteralTree;
27.28 -import com.sun.source.tree.MethodTree;
27.29 -import com.sun.source.util.SourcePositions;
27.30 -import com.sun.source.util.TreePath;
27.31 -import com.sun.source.util.TreePathScanner;
27.32 -import com.sun.source.util.Trees;
27.33 -import java.io.IOException;
27.34 -import java.util.ArrayList;
27.35 -import java.util.Collection;
27.36 -import java.util.Collections;
27.37 -import java.util.List;
27.38 -import java.util.concurrent.atomic.AtomicBoolean;
27.39 -import javax.lang.model.element.TypeElement;
27.40 -import javax.swing.text.Document;
27.41 -import org.netbeans.api.editor.mimelookup.MimeRegistration;
27.42 -import org.netbeans.api.java.source.CompilationInfo;
27.43 -import org.netbeans.api.java.source.JavaParserResultTask;
27.44 -import org.netbeans.api.java.source.JavaSource;
27.45 -import org.netbeans.api.lexer.Language;
27.46 -import org.netbeans.api.lexer.TokenHierarchy;
27.47 -import org.netbeans.api.lexer.TokenSequence;
27.48 -import org.netbeans.modules.parsing.api.Snapshot;
27.49 -import org.netbeans.modules.parsing.spi.Parser;
27.50 -import org.netbeans.modules.parsing.spi.Scheduler;
27.51 -import org.netbeans.modules.parsing.spi.SchedulerEvent;
27.52 -import org.netbeans.modules.parsing.spi.SchedulerTask;
27.53 -import org.netbeans.modules.parsing.spi.TaskFactory;
27.54 -import org.openide.util.Exceptions;
27.55 -
27.56 -/**
27.57 - *
27.58 - * @author Tomas Zezula
27.59 - */
27.60 -public final class JSEmbeddingProvider extends JavaParserResultTask<Parser.Result> {
27.61 -
27.62 - private static final int PRIORITY = 1000;
27.63 - private static final String JS_ANNOTATION = "org.apidesign.bck2brwsr.core.JavaScriptBody"; //NOI18N
27.64 - private static final String BODY = "body"; //NOI18N
27.65 - private static final String JAVA_MIME_TYPE = "text/x-java"; //NOI18N
27.66 - private static final String JAVASCRIPT_MIME_TYPE = "text/javascript"; //NOI18N
27.67 - private final AtomicBoolean canceled = new AtomicBoolean();
27.68 -
27.69 - private JSEmbeddingProvider() {
27.70 - super(JavaSource.Phase.ELEMENTS_RESOLVED);
27.71 - }
27.72 -
27.73 - @Override
27.74 - public int getPriority() {
27.75 - return PRIORITY;
27.76 - }
27.77 -
27.78 - @Override
27.79 - public void cancel() {
27.80 - canceled.set(true);
27.81 - }
27.82 -
27.83 - @Override
27.84 - public Class<? extends Scheduler> getSchedulerClass() {
27.85 - return Scheduler.EDITOR_SENSITIVE_TASK_SCHEDULER;
27.86 - }
27.87 -
27.88 - @Override
27.89 - public void run(Parser.Result t, SchedulerEvent se) {
27.90 - canceled.set(false);
27.91 - final CompilationInfo ci = CompilationInfo.get(t);
27.92 - final CompilationUnitTree cu = ci.getCompilationUnit();
27.93 - final Trees trees = ci.getTrees();
27.94 - final SourcePositions sp = trees.getSourcePositions();
27.95 - final Finder f = new Finder(trees);
27.96 - final List<LiteralTree> result = new ArrayList<LiteralTree>();
27.97 - f.scan(cu, result);
27.98 - if (!result.isEmpty()) {
27.99 - try {
27.100 - final TokenHierarchy<Document> tk = TokenHierarchy.get(ci.getDocument());
27.101 - final Language<?> java = Language.find(JAVA_MIME_TYPE);
27.102 - final Language<?> javaScript = Language.find(JAVASCRIPT_MIME_TYPE);
27.103 - if (java != null && javaScript != null) {
27.104 - final TokenSequence<?> seq = tk.tokenSequence(java);
27.105 - if (seq != null) {
27.106 - for (LiteralTree lt : result) {
27.107 - final int start = (int) sp.getStartPosition(cu, lt);
27.108 - final int end = (int) sp.getEndPosition(cu, lt);
27.109 - seq.move(start);
27.110 - while (seq.moveNext() && seq.offset() < end) {
27.111 - seq.createEmbedding(javaScript, 1, 1, true);
27.112 - }
27.113 - }
27.114 - }
27.115 - }
27.116 - } catch (IOException ioe) {
27.117 - Exceptions.printStackTrace(ioe);
27.118 - }
27.119 - }
27.120 - }
27.121 -
27.122 -
27.123 -
27.124 -
27.125 - private static final class Finder extends TreePathScanner<Void, List<? super LiteralTree>> {
27.126 -
27.127 - private final Trees trees;
27.128 - private CompilationUnitTree cu;
27.129 - private boolean inEmbedding;
27.130 -
27.131 - Finder(final Trees trees) {
27.132 - this.trees = trees;
27.133 - }
27.134 -
27.135 - @Override
27.136 - public Void visitCompilationUnit(
27.137 - final CompilationUnitTree unit,
27.138 - final List p) {
27.139 - this.cu = unit;
27.140 - return super.visitCompilationUnit(unit, p);
27.141 - }
27.142 -
27.143 -
27.144 -
27.145 - @Override
27.146 - public Void visitMethod(
27.147 - final MethodTree m,
27.148 - final List<? super LiteralTree> p) {
27.149 - for (AnnotationTree a : m.getModifiers().getAnnotations()) {
27.150 - final TypeElement ae = (TypeElement) trees.getElement(TreePath.getPath(cu, a.getAnnotationType()));
27.151 - if (ae != null && JS_ANNOTATION.contentEquals(ae.getQualifiedName())) {
27.152 - final List<? extends ExpressionTree> args = a.getArguments();
27.153 - for (ExpressionTree kvp : args) {
27.154 - if (kvp instanceof AssignmentTree) {
27.155 - final AssignmentTree assignemt = (AssignmentTree) kvp;
27.156 - if (BODY.equals(assignemt.getVariable().toString())) {
27.157 - inEmbedding = true;
27.158 - try {
27.159 - scan(assignemt.getExpression(), p);
27.160 - } finally {
27.161 - inEmbedding = false;
27.162 - }
27.163 - }
27.164 - }
27.165 - }
27.166 - }
27.167 - }
27.168 - return null;
27.169 - }
27.170 -
27.171 - @Override
27.172 - public Void visitLiteral(LiteralTree node, List<? super LiteralTree> p) {
27.173 - if (inEmbedding) {
27.174 - p.add(node);
27.175 - }
27.176 - return super.visitLiteral(node, p);
27.177 - }
27.178 -
27.179 - }
27.180 -
27.181 - @MimeRegistration(
27.182 - service = TaskFactory.class,
27.183 - mimeType = JAVA_MIME_TYPE)
27.184 - public static final class Factory extends TaskFactory {
27.185 - @Override
27.186 - public Collection<? extends SchedulerTask> create(Snapshot snpsht) {
27.187 - return Collections.singleton(new JSEmbeddingProvider());
27.188 - }
27.189 - }
27.190 -
27.191 -}
28.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JSNI2JavaScriptBody.java Tue Apr 29 15:25:58 2014 +0200
28.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
28.3 @@ -1,149 +0,0 @@
28.4 -/**
28.5 - * Back 2 Browser Bytecode Translator
28.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
28.7 - *
28.8 - * This program is free software: you can redistribute it and/or modify
28.9 - * it under the terms of the GNU General Public License as published by
28.10 - * the Free Software Foundation, version 2 of the License.
28.11 - *
28.12 - * This program is distributed in the hope that it will be useful,
28.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
28.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28.15 - * GNU General Public License for more details.
28.16 - *
28.17 - * You should have received a copy of the GNU General Public License
28.18 - * along with this program. Look for COPYING file in the top folder.
28.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
28.20 - */
28.21 -package org.apidesign.bck2brwsr.ide.editor;
28.22 -
28.23 -import com.sun.source.tree.AnnotationTree;
28.24 -import com.sun.source.tree.ExpressionTree;
28.25 -import com.sun.source.tree.LiteralTree;
28.26 -import com.sun.source.tree.MethodTree;
28.27 -import com.sun.source.tree.Tree.Kind;
28.28 -import com.sun.source.tree.VariableTree;
28.29 -import com.sun.source.util.TreePath;
28.30 -import java.util.ArrayList;
28.31 -import java.util.Arrays;
28.32 -import java.util.Collections;
28.33 -import java.util.List;
28.34 -import org.netbeans.api.java.lexer.JavaTokenId;
28.35 -import static org.netbeans.api.java.lexer.JavaTokenId.BLOCK_COMMENT;
28.36 -import static org.netbeans.api.java.lexer.JavaTokenId.JAVADOC_COMMENT;
28.37 -import static org.netbeans.api.java.lexer.JavaTokenId.LINE_COMMENT;
28.38 -import static org.netbeans.api.java.lexer.JavaTokenId.WHITESPACE;
28.39 -import org.netbeans.api.java.source.CompilationInfo;
28.40 -import org.netbeans.api.java.source.TreeMaker;
28.41 -import org.netbeans.api.lexer.Token;
28.42 -import org.netbeans.api.lexer.TokenSequence;
28.43 -import org.netbeans.spi.editor.hints.ErrorDescription;
28.44 -import org.netbeans.spi.editor.hints.Fix;
28.45 -import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
28.46 -import org.netbeans.spi.java.hints.Hint;
28.47 -import org.netbeans.spi.java.hints.HintContext;
28.48 -import org.netbeans.spi.java.hints.JavaFix;
28.49 -import org.netbeans.spi.java.hints.TriggerTreeKind;
28.50 -import org.openide.util.NbBundle.Messages;
28.51 -
28.52 -@Hint(displayName = "#DN_JSNI2JavaScriptBody", description = "#DESC_JSNI2JavaScriptBody", category = "general")
28.53 -@Messages({
28.54 - "DN_JSNI2JavaScriptBody=JSNI to @JavaScriptBody",
28.55 - "DESC_JSNI2JavaScriptBody=JSNI to @JavaScriptBody"
28.56 -})
28.57 -public class JSNI2JavaScriptBody {
28.58 -
28.59 - @TriggerTreeKind(Kind.METHOD)
28.60 - @Messages("ERR_JSNI2JavaScriptBody=Can convert JSNI to @JavaScriptBody")
28.61 - public static ErrorDescription computeWarning(final HintContext ctx) {
28.62 - Token<JavaTokenId> token = findBlockToken(ctx.getInfo(), ctx.getPath(), ctx);
28.63 -
28.64 - if (token == null) {
28.65 - return null;
28.66 - }
28.67 -
28.68 - Fix fix = new FixImpl(ctx.getInfo(), ctx.getPath()).toEditorFix();
28.69 - return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), Bundle.ERR_JSNI2JavaScriptBody(), fix);
28.70 - }
28.71 -
28.72 - private static Token<JavaTokenId> findBlockToken(CompilationInfo info, TreePath path, HintContext ctx) {
28.73 - int end = (int) info.getTrees().getSourcePositions().getEndPosition(path.getCompilationUnit(), path.getLeaf());
28.74 - TokenSequence<JavaTokenId> ts = info.getTokenHierarchy().tokenSequence(JavaTokenId.language());
28.75 -
28.76 - if (ts == null) return null;
28.77 -
28.78 - ts.move(end);
28.79 -
28.80 - if ((ctx != null && ctx.isCanceled()) || !ts.movePrevious() || ts.token().id() != JavaTokenId.SEMICOLON) return null;
28.81 -
28.82 - OUTER: while (ts.movePrevious()) {
28.83 - if (ctx != null && ctx.isCanceled()) return null;
28.84 -
28.85 - switch (ts.token().id()) {
28.86 - case WHITESPACE: break;
28.87 - case LINE_COMMENT: break;
28.88 - case JAVADOC_COMMENT: break;
28.89 - case BLOCK_COMMENT:
28.90 - final CharSequence tok = ts.token().text();
28.91 - final int l = tok.length();
28.92 - if (l > 4
28.93 - && tok.subSequence(0, 4).toString().equals("/*-{") // NOI18N
28.94 - && tok.subSequence(l - 4, l).toString().equals("}-*/") // NOI18N
28.95 - ) {
28.96 - return ts.offsetToken();
28.97 - }
28.98 - break;
28.99 - default:
28.100 - break OUTER;
28.101 - }
28.102 - }
28.103 -
28.104 - return null;
28.105 - }
28.106 -
28.107 - private static final class FixImpl extends JavaFix {
28.108 -
28.109 - public FixImpl(CompilationInfo info, TreePath tp) {
28.110 - super(info, tp);
28.111 - }
28.112 -
28.113 - @Override
28.114 - @Messages("FIX_JSNI2JavaScriptBody=Convert JSNI to @JavaScriptBody")
28.115 - protected String getText() {
28.116 - return Bundle.FIX_JSNI2JavaScriptBody();
28.117 - }
28.118 -
28.119 - @Override
28.120 - protected void performRewrite(TransformationContext ctx) {
28.121 - Token<JavaTokenId> jsniComment = findBlockToken(ctx.getWorkingCopy(), ctx.getPath(), null);
28.122 -
28.123 - if (jsniComment == null) {
28.124 - //XXX: warn?
28.125 - return ;
28.126 - }
28.127 -
28.128 - JsniCommentTokenizer tok = new JsniCommentTokenizer();
28.129 - ManglingSink ms = new ManglingSink();
28.130 - final CharSequence cmnt = jsniComment.text();
28.131 - tok.process(cmnt.subSequence(4, cmnt.length() - 4), ms);
28.132 -
28.133 - TreeMaker make = ctx.getWorkingCopy().getTreeMaker();
28.134 - MethodTree mt = (MethodTree) ctx.getPath().getLeaf();
28.135 - List<LiteralTree> params = new ArrayList<LiteralTree>();
28.136 -
28.137 - for (VariableTree p : mt.getParameters()) {
28.138 - params.add(make.Literal(p.getName().toString()));
28.139 - }
28.140 -
28.141 - AnnotationTree jsBody = make.Annotation(make.QualIdent("org.apidesign.bck2brwsr.core.JavaScriptBody"),
28.142 - Arrays.<ExpressionTree>asList(
28.143 - make.Assignment(make.Identifier("args"), make.NewArray(null, Collections.<ExpressionTree>emptyList(), params)),
28.144 - make.Assignment(make.Identifier("body"), make.Literal(ms.out.toString()))
28.145 - )
28.146 - );
28.147 -
28.148 -
28.149 - ctx.getWorkingCopy().rewrite(mt.getModifiers(), make.addModifiersAnnotation(mt.getModifiers(), jsBody));
28.150 - }
28.151 - }
28.152 -}
29.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/JsniCommentTokenizer.java Tue Apr 29 15:25:58 2014 +0200
29.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
29.3 @@ -1,70 +0,0 @@
29.4 -/**
29.5 - * Back 2 Browser Bytecode Translator
29.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
29.7 - *
29.8 - * This program is free software: you can redistribute it and/or modify
29.9 - * it under the terms of the GNU General Public License as published by
29.10 - * the Free Software Foundation, version 2 of the License.
29.11 - *
29.12 - * This program is distributed in the hope that it will be useful,
29.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
29.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29.15 - * GNU General Public License for more details.
29.16 - *
29.17 - * You should have received a copy of the GNU General Public License
29.18 - * along with this program. Look for COPYING file in the top folder.
29.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
29.20 - */
29.21 -package org.apidesign.bck2brwsr.ide.editor;
29.22 -
29.23 -import java.util.regex.Matcher;
29.24 -import java.util.regex.Pattern;
29.25 -
29.26 -final class JsniCommentTokenizer {
29.27 -
29.28 - /**
29.29 - * Tokenize the contents of JSNI comment into the provided {@linkplain Sink}.
29.30 - * @param in the contents of JSNI comment
29.31 - * @param out the sink that consumes parsed tokens
29.32 - */
29.33 - public void process(final CharSequence in, final Sink out) {
29.34 - final Matcher member = Pattern.compile("@([^:]+)::([a-zA-Z_$][a-zA-Z\\d_$]*)").matcher(in);
29.35 - final Matcher signature = Pattern.compile("\\(([^\\)]*)\\)").matcher(in);
29.36 -
29.37 - int i = 0;
29.38 - while (true) {
29.39 - if (member.find(i)) {
29.40 - final int memberStart = member.start();
29.41 - final int memberEnd = member.end();
29.42 - if (memberStart > i) out.javascript(in.subSequence(i, memberStart).toString());
29.43 -
29.44 - final String clazz = member.group(1);
29.45 - final String name = member.group(2);
29.46 -
29.47 - if (in.charAt(memberEnd) == '(') {
29.48 - if (!signature.find(memberEnd)) {
29.49 - throw new IllegalStateException("Expected method signature");
29.50 - }
29.51 - assert signature.start() == memberEnd;
29.52 - out.method(clazz, name, signature.group(1));
29.53 - i = signature.end();
29.54 - } else {
29.55 - out.field(clazz, name);
29.56 - i = memberEnd;
29.57 - }
29.58 - } else {
29.59 - out.javascript(in.subSequence(i, in.length()).toString());
29.60 - break;
29.61 - }
29.62 - }
29.63 - }
29.64 -
29.65 -
29.66 - static interface Sink {
29.67 - void javascript(String s);
29.68 -
29.69 - void method(String clazz, String method, String signature);
29.70 -
29.71 - void field(String clazz, String field);
29.72 - }
29.73 -}
30.1 --- a/ide/editor/src/main/java/org/apidesign/bck2brwsr/ide/editor/ManglingSink.java Tue Apr 29 15:25:58 2014 +0200
30.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
30.3 @@ -1,71 +0,0 @@
30.4 -/**
30.5 - * Back 2 Browser Bytecode Translator
30.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
30.7 - *
30.8 - * This program is free software: you can redistribute it and/or modify
30.9 - * it under the terms of the GNU General Public License as published by
30.10 - * the Free Software Foundation, version 2 of the License.
30.11 - *
30.12 - * This program is distributed in the hope that it will be useful,
30.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
30.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30.15 - * GNU General Public License for more details.
30.16 - *
30.17 - * You should have received a copy of the GNU General Public License
30.18 - * along with this program. Look for COPYING file in the top folder.
30.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
30.20 - */
30.21 -package org.apidesign.bck2brwsr.ide.editor;
30.22 -
30.23 -/**
30.24 - * An implementation of {@linkplain JsniCommentTokenizer.Sink} that generates B2B
30.25 - */
30.26 -class ManglingSink implements JsniCommentTokenizer.Sink {
30.27 -
30.28 - final StringBuilder out = new StringBuilder();
30.29 -
30.30 - public void javascript(String s) {
30.31 - out.append(s);
30.32 - }
30.33 -
30.34 - public void method(String clazz, String method, String signature) {
30.35 - out.append(mangle(clazz, method, signature));
30.36 - }
30.37 -
30.38 - public void field(String clazz, String field) {
30.39 -// out.append(field);
30.40 - out.append('_').append(field).append('(').append(')');
30.41 - }
30.42 -
30.43 -
30.44 - @Override
30.45 - public String toString() {
30.46 - return out.toString();
30.47 - }
30.48 -
30.49 -
30.50 - static String mangle(String clazz, String method, String signature) {
30.51 - final StringBuilder builder = new StringBuilder();
30.52 - builder.append(method);
30.53 - builder.append("__");
30.54 - builder.append(mangle(JNIHelper.signature(JNIHelper.method(clazz, method, signature).getReturnType())));
30.55 - builder.append(mangle(signature));
30.56 - return builder.toString();
30.57 - }
30.58 -
30.59 -
30.60 - static String mangle(String txt) {
30.61 - final StringBuilder sb = new StringBuilder();
30.62 - for (int i = 0; i < txt.length(); i++) {
30.63 - final char ch = txt.charAt(i);
30.64 - switch (ch) {
30.65 - case '/': sb.append('_'); break;
30.66 - case '_': sb.append("_1"); break;
30.67 - case ';': sb.append("_2"); break;
30.68 - case '[': sb.append("_3"); break;
30.69 - default: sb.append(ch); break;
30.70 - }
30.71 - }
30.72 - return sb.toString();
30.73 - }
30.74 -}
31.1 --- a/ide/editor/src/main/nbm/manifest.mf Tue Apr 29 15:25:58 2014 +0200
31.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
31.3 @@ -1,2 +0,0 @@
31.4 -Manifest-Version: 1.0
31.5 -OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/jackpot30/test/hints/Bundle.properties
32.1 --- a/ide/editor/src/main/resources/org/netbeans/modules/jackpot30/test/hints/Bundle.properties Tue Apr 29 15:25:58 2014 +0200
32.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
32.3 @@ -1,21 +0,0 @@
32.4 -#
32.5 -# Back 2 Browser Bytecode Translator
32.6 -# Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
32.7 -#
32.8 -# This program is free software: you can redistribute it and/or modify
32.9 -# it under the terms of the GNU General Public License as published by
32.10 -# the Free Software Foundation, version 2 of the License.
32.11 -#
32.12 -# This program is distributed in the hope that it will be useful,
32.13 -# but WITHOUT ANY WARRANTY; without even the implied warranty of
32.14 -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32.15 -# GNU General Public License for more details.
32.16 -#
32.17 -# You should have received a copy of the GNU General Public License
32.18 -# along with this program. Look for COPYING file in the top folder.
32.19 -# If not, see http://opensource.org/licenses/GPL-2.0.
32.20 -#
32.21 -
32.22 -OpenIDE-Module-Name=Bck2Brwsr Editor Support
32.23 -OpenIDE-Module-Short-Description=Provides hints, coloring, etc. for the bck2brwsr.apidesign.org project
32.24 -OpenIDE-Module-Display-Category=Java
33.1 --- a/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/DejsniReaderTest.java Tue Apr 29 15:25:58 2014 +0200
33.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
33.3 @@ -1,84 +0,0 @@
33.4 -/**
33.5 - * Back 2 Browser Bytecode Translator
33.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
33.7 - *
33.8 - * This program is free software: you can redistribute it and/or modify
33.9 - * it under the terms of the GNU General Public License as published by
33.10 - * the Free Software Foundation, version 2 of the License.
33.11 - *
33.12 - * This program is distributed in the hope that it will be useful,
33.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
33.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33.15 - * GNU General Public License for more details.
33.16 - *
33.17 - * You should have received a copy of the GNU General Public License
33.18 - * along with this program. Look for COPYING file in the top folder.
33.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
33.20 - */
33.21 -package org.apidesign.bck2brwsr.ide.editor;
33.22 -
33.23 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
33.24 -import org.netbeans.modules.java.hints.test.api.HintTest;
33.25 -import org.openide.filesystems.FileUtil;
33.26 -import org.testng.annotations.Test;
33.27 -
33.28 -public class DejsniReaderTest {
33.29 -
33.30 - @Test
33.31 - public void test1() throws Exception {
33.32 - String s = "class Test {\n" +
33.33 - " /** javadoc */\n" +
33.34 - " public native void test() /*-{\n" +
33.35 - " // body\n" +
33.36 - " }-*/;\n" +
33.37 - "}\n";
33.38 -
33.39 - String expected = " import org.apidesign.bck2brwsr.core.JavaScriptBody;\n"
33.40 - + "class Test {\n" +
33.41 - "\n" +
33.42 - " /** javadoc */\n" +
33.43 - " @JavaScriptBody(args = {}, body = \"\\n // body\\n \")\n" +
33.44 - " public native void test();\n" +
33.45 - "}\n";
33.46 -
33.47 - HintTest.create()
33.48 - .input(s)
33.49 - .classpath(FileUtil.getArchiveRoot(JavaScriptBody.class.getProtectionDomain().getCodeSource().getLocation()))
33.50 - .run(JSNI2JavaScriptBody.class)
33.51 - .findWarning("2:23-2:27:verifier:" + Bundle.ERR_JSNI2JavaScriptBody())
33.52 - .applyFix()
33.53 - .assertCompilable()
33.54 - .assertOutput(expected);
33.55 - }
33.56 -
33.57 -
33.58 - @Test
33.59 - public void test2() throws Exception {
33.60 - String s = "class Test {\n" +
33.61 - " /** javadoc */\n" +
33.62 - " @SuppressWarnings(\"unused\")\n" +
33.63 - " // comment\n" +
33.64 - " public native void test() /*-{\n" +
33.65 - " // body\n" +
33.66 - " }-*/;\n" +
33.67 - "}\n";
33.68 -
33.69 - String expected = " import org.apidesign.bck2brwsr.core.JavaScriptBody;\n"
33.70 - + "class Test {\n" +
33.71 - "\n" +
33.72 - " /** javadoc */\n" +
33.73 - " @SuppressWarnings(\"unused\")\n" +
33.74 - " // comment\n" +
33.75 - " @JavaScriptBody(args = {}, body = \"\\n // body\\n \")\n" +
33.76 - " public native void test();\n" +
33.77 - "}\n";
33.78 - HintTest.create()
33.79 - .input(s)
33.80 - .classpath(FileUtil.getArchiveRoot(JavaScriptBody.class.getProtectionDomain().getCodeSource().getLocation()))
33.81 - .run(JSNI2JavaScriptBody.class)
33.82 - .findWarning("4:23-4:27:verifier:" + Bundle.ERR_JSNI2JavaScriptBody())
33.83 - .applyFix()
33.84 - .assertCompilable()
33.85 - .assertOutput(expected);
33.86 - }
33.87 -}
33.88 \ No newline at end of file
34.1 --- a/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/JSNI2JavaScriptBodyTest.java Tue Apr 29 15:25:58 2014 +0200
34.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
34.3 @@ -1,46 +0,0 @@
34.4 -/**
34.5 - * Back 2 Browser Bytecode Translator
34.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
34.7 - *
34.8 - * This program is free software: you can redistribute it and/or modify
34.9 - * it under the terms of the GNU General Public License as published by
34.10 - * the Free Software Foundation, version 2 of the License.
34.11 - *
34.12 - * This program is distributed in the hope that it will be useful,
34.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
34.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34.15 - * GNU General Public License for more details.
34.16 - *
34.17 - * You should have received a copy of the GNU General Public License
34.18 - * along with this program. Look for COPYING file in the top folder.
34.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
34.20 - */
34.21 -package org.apidesign.bck2brwsr.ide.editor;
34.22 -
34.23 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
34.24 -import org.netbeans.modules.java.hints.test.api.HintTest;
34.25 -import org.openide.filesystems.FileUtil;
34.26 -import org.testng.annotations.Test;
34.27 -
34.28 -public class JSNI2JavaScriptBodyTest {
34.29 -
34.30 - @Test
34.31 - public void testFixWorking() throws Exception {
34.32 - HintTest.create()
34.33 - .input("package test;\n" +
34.34 - "public class Test {\n" +
34.35 - " public native void run(int a) /*-{ this.a = a; }-*/;\n" +
34.36 - "}\n")
34.37 - .classpath(FileUtil.getArchiveRoot(JavaScriptBody.class.getProtectionDomain().getCodeSource().getLocation()))
34.38 - .run(JSNI2JavaScriptBody.class)
34.39 - .findWarning("2:23-2:26:verifier:" + Bundle.ERR_JSNI2JavaScriptBody())
34.40 - .applyFix()
34.41 - .assertCompilable()
34.42 - .assertOutput("package test;\n" +
34.43 - "import org.apidesign.bck2brwsr.core.JavaScriptBody;\n" +
34.44 - "public class Test {\n" +
34.45 - " @JavaScriptBody(args = {\"a\"}, body = \" this.a = a; \")\n" +
34.46 - " public native void run(int a);\n" +
34.47 - "}\n");
34.48 - }
34.49 -}
35.1 --- a/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/JsniCommentTokenizerTest.java Tue Apr 29 15:25:58 2014 +0200
35.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
35.3 @@ -1,154 +0,0 @@
35.4 -/**
35.5 - * Back 2 Browser Bytecode Translator
35.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
35.7 - *
35.8 - * This program is free software: you can redistribute it and/or modify
35.9 - * it under the terms of the GNU General Public License as published by
35.10 - * the Free Software Foundation, version 2 of the License.
35.11 - *
35.12 - * This program is distributed in the hope that it will be useful,
35.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
35.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35.15 - * GNU General Public License for more details.
35.16 - *
35.17 - * You should have received a copy of the GNU General Public License
35.18 - * along with this program. Look for COPYING file in the top folder.
35.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
35.20 - */
35.21 -package org.apidesign.bck2brwsr.ide.editor;
35.22 -
35.23 -import java.io.IOException;
35.24 -import java.util.ArrayList;
35.25 -import java.util.List;
35.26 -import org.testng.Assert;
35.27 -import org.testng.annotations.Test;
35.28 -
35.29 -public class JsniCommentTokenizerTest {
35.30 -
35.31 - private static class MockSink implements JsniCommentTokenizer.Sink {
35.32 - final List<String> out = new ArrayList<String>();
35.33 -
35.34 - public void javascript(String s) {
35.35 - out.add("J " + s);
35.36 - }
35.37 -
35.38 - public void method(String clazz, String method, String signature) {
35.39 - out.add("M " + clazz + "|" + method + "|" + signature);
35.40 - }
35.41 -
35.42 - public void field(String clazz, String field) {
35.43 - out.add("F " + clazz + "|" + field);
35.44 - }
35.45 - }
35.46 -
35.47 -
35.48 - @Test
35.49 - public void testProcess_nop() throws IOException {
35.50 - final String in = "foo bar";
35.51 - final List<String> expected = new ArrayList<String>();
35.52 - expected.add("J foo bar");
35.53 -
35.54 - final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
35.55 - final MockSink out = new MockSink();
35.56 - jsniCommentTokenizer.process(in, out);
35.57 -
35.58 - Assert.assertEquals(expected, out.out);
35.59 - }
35.60 -
35.61 - @Test
35.62 - public void testProcess_read_static_field() throws IOException {
35.63 - final String in = " @com.google.gwt.examples.JSNIExample::myStaticField = val + \" and stuff\";";
35.64 - final List<String> expected = new ArrayList<String>();
35.65 - expected.add("J ");
35.66 - expected.add("F com.google.gwt.examples.JSNIExample|myStaticField");
35.67 - expected.add("J = val + \" and stuff\";");
35.68 -
35.69 - final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
35.70 - final MockSink out = new MockSink();
35.71 - jsniCommentTokenizer.process(in, out);
35.72 -
35.73 - Assert.assertEquals(expected, out.out);
35.74 - }
35.75 -
35.76 - @Test
35.77 - public void testProcess_write_instance_field() throws IOException {
35.78 - final String in = " x.@com.google.gwt.examples.JSNIExample::myInstanceField = val + \" and stuff\";";
35.79 - final List<String> expected = new ArrayList<String>();
35.80 - expected.add("J x.");
35.81 - expected.add("F com.google.gwt.examples.JSNIExample|myInstanceField");
35.82 - expected.add("J = val + \" and stuff\";");
35.83 -
35.84 - final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
35.85 - final MockSink out = new MockSink();
35.86 - jsniCommentTokenizer.process(in, out);
35.87 -
35.88 - Assert.assertEquals(expected, out.out);
35.89 - }
35.90 -
35.91 - @Test
35.92 - public void testProcess_read_instance_field() throws IOException {
35.93 - final String in = " var val = this.@com.google.gwt.examples.JSNIExample::myInstanceField;";
35.94 - final List<String> expected = new ArrayList<String>();
35.95 - expected.add("J var val = this.");
35.96 - expected.add("F com.google.gwt.examples.JSNIExample|myInstanceField");
35.97 - expected.add("J ;");
35.98 -
35.99 - final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
35.100 - final MockSink out = new MockSink();
35.101 - jsniCommentTokenizer.process(in, out);
35.102 -
35.103 - Assert.assertEquals(expected, out.out);
35.104 - }
35.105 -
35.106 -
35.107 - @Test
35.108 - public void testProcess_static_method() throws IOException {
35.109 - final String in = " @com.google.gwt.examples.JSNIExample::staticFoo(Ljava/lang/String;)(s);";
35.110 - final List<String> expected = new ArrayList<String>();
35.111 - expected.add("J ");
35.112 - expected.add("M com.google.gwt.examples.JSNIExample|staticFoo|Ljava/lang/String;");
35.113 - expected.add("J (s);");
35.114 -
35.115 - final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
35.116 - final MockSink out = new MockSink();
35.117 - jsniCommentTokenizer.process(in, out);
35.118 -
35.119 - Assert.assertEquals(expected, out.out);
35.120 - }
35.121 -
35.122 -
35.123 - @Test
35.124 - public void testProcess_instance_method() throws IOException {
35.125 - final String in = " x.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);";
35.126 - final List<String> expected = new ArrayList<String>();
35.127 - expected.add("J x.");
35.128 - expected.add("M com.google.gwt.examples.JSNIExample|instanceFoo|Ljava/lang/String;");
35.129 - expected.add("J (s);");
35.130 -
35.131 - final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
35.132 - final MockSink out = new MockSink();
35.133 - jsniCommentTokenizer.process(in, out);
35.134 -
35.135 - Assert.assertEquals(expected, out.out);
35.136 - }
35.137 -
35.138 -
35.139 - @Test
35.140 - public void testProcess_multiline() throws IOException {
35.141 - final String in =
35.142 - " x.@com.google.gwt.examples.JSNIExample::instanceFoo(Ljava/lang/String;)(s);" +
35.143 - " @com.google.gwt.examples.JSNIExample::myStaticField = val + \" and stuff\";";
35.144 - final List<String> expected = new ArrayList<String>();
35.145 - expected.add("J x.");
35.146 - expected.add("M com.google.gwt.examples.JSNIExample|instanceFoo|Ljava/lang/String;");
35.147 - expected.add("J (s); ");
35.148 - expected.add("F com.google.gwt.examples.JSNIExample|myStaticField");
35.149 - expected.add("J = val + \" and stuff\";");
35.150 -
35.151 - final JsniCommentTokenizer jsniCommentTokenizer = new JsniCommentTokenizer();
35.152 - final MockSink out = new MockSink();
35.153 - jsniCommentTokenizer.process(in, out);
35.154 -
35.155 - Assert.assertEquals(expected, out.out);
35.156 - }
35.157 -}
36.1 --- a/ide/editor/src/test/java/org/apidesign/bck2brwsr/ide/editor/ManglingSinkTest.java Tue Apr 29 15:25:58 2014 +0200
36.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
36.3 @@ -1,58 +0,0 @@
36.4 -/**
36.5 - * Back 2 Browser Bytecode Translator
36.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
36.7 - *
36.8 - * This program is free software: you can redistribute it and/or modify
36.9 - * it under the terms of the GNU General Public License as published by
36.10 - * the Free Software Foundation, version 2 of the License.
36.11 - *
36.12 - * This program is distributed in the hope that it will be useful,
36.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
36.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36.15 - * GNU General Public License for more details.
36.16 - *
36.17 - * You should have received a copy of the GNU General Public License
36.18 - * along with this program. Look for COPYING file in the top folder.
36.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
36.20 - */
36.21 -package org.apidesign.bck2brwsr.ide.editor;
36.22 -
36.23 -import org.testng.Assert;
36.24 -import org.testng.annotations.Test;
36.25 -
36.26 -
36.27 -public class ManglingSinkTest {
36.28 -
36.29 - @Test
36.30 - public void testMangle_1() {
36.31 - Assert.assertEquals(
36.32 - "binarySearch__I_3BIIB",
36.33 - ManglingSink.mangle("java.util.Arrays", "binarySearch", "[BIIB")
36.34 - );
36.35 - }
36.36 -
36.37 - @Test
36.38 - public void testMangle_2() {
36.39 - Assert.assertEquals(
36.40 - "sort__V_3I",
36.41 - ManglingSink.mangle("java.util.Arrays", "sort", "[I")
36.42 - );
36.43 - }
36.44 -
36.45 - @Test
36.46 - public void testMangle_3() {
36.47 - Assert.assertEquals(
36.48 - "binarySearch__I_3Ljava_lang_Object_2IILjava_lang_Object_2",
36.49 - ManglingSink.mangle("java.util.Arrays", "binarySearch", "[Ljava/lang/Object;IILjava/lang/Object;")
36.50 - );
36.51 - }
36.52 -
36.53 -
36.54 - @Test
36.55 - public void testField() {
36.56 - final ManglingSink manglingSink = new ManglingSink();
36.57 - manglingSink.field(null, "value");
36.58 -
36.59 - Assert.assertEquals("_value()", manglingSink.toString());
36.60 - }
36.61 -}
37.1 --- a/ide/pom.xml Tue Apr 29 15:25:58 2014 +0200
37.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
37.3 @@ -1,29 +0,0 @@
37.4 -<?xml version="1.0" encoding="UTF-8"?>
37.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
37.6 - <modelVersion>4.0.0</modelVersion>
37.7 - <parent>
37.8 - <artifactId>bck2brwsr</artifactId>
37.9 - <groupId>org.apidesign</groupId>
37.10 - <version>0.8-SNAPSHOT</version>
37.11 - </parent>
37.12 - <groupId>org.apidesign.bck2brwsr</groupId>
37.13 - <artifactId>ide</artifactId>
37.14 - <version>0.8-SNAPSHOT</version>
37.15 - <packaging>pom</packaging>
37.16 - <name>IDE Support</name>
37.17 - <modules>
37.18 - <module>editor</module>
37.19 - </modules>
37.20 - <build>
37.21 - <plugins>
37.22 - <plugin>
37.23 - <groupId>org.apache.maven.plugins</groupId>
37.24 - <artifactId>maven-deploy-plugin</artifactId>
37.25 - <version>2.7</version>
37.26 - <configuration>
37.27 - <skip>true</skip>
37.28 - </configuration>
37.29 - </plugin>
37.30 - </plugins>
37.31 - </build>
37.32 -</project>
38.1 --- a/javaquery/api/pom.xml Tue Apr 29 15:25:58 2014 +0200
38.2 +++ b/javaquery/api/pom.xml Wed Apr 30 15:04:10 2014 +0200
38.3 @@ -4,11 +4,11 @@
38.4 <parent>
38.5 <groupId>org.apidesign.bck2brwsr</groupId>
38.6 <artifactId>javaquery</artifactId>
38.7 - <version>0.8-SNAPSHOT</version>
38.8 + <version>0.9-SNAPSHOT</version>
38.9 </parent>
38.10 <groupId>org.apidesign.bck2brwsr</groupId>
38.11 <artifactId>javaquery.api</artifactId>
38.12 - <version>0.8-SNAPSHOT</version>
38.13 + <version>0.9-SNAPSHOT</version>
38.14 <name>JavaQuery API</name>
38.15 <url>http://maven.apache.org</url>
38.16 <build>
39.1 --- a/javaquery/demo-calculator-dynamic/pom.xml Tue Apr 29 15:25:58 2014 +0200
39.2 +++ b/javaquery/demo-calculator-dynamic/pom.xml Wed Apr 30 15:04:10 2014 +0200
39.3 @@ -4,7 +4,7 @@
39.4
39.5 <groupId>org.apidesign.bck2brwsr</groupId>
39.6 <artifactId>demo.calculator</artifactId>
39.7 - <version>0.8-SNAPSHOT</version>
39.8 + <version>0.9-SNAPSHOT</version>
39.9 <packaging>jar</packaging>
39.10
39.11 <name>JavaQuery Demo - Calculator</name>
40.1 --- a/javaquery/demo-calculator/pom.xml Tue Apr 29 15:25:58 2014 +0200
40.2 +++ b/javaquery/demo-calculator/pom.xml Wed Apr 30 15:04:10 2014 +0200
40.3 @@ -4,7 +4,7 @@
40.4
40.5 <groupId>org.apidesign.bck2brwsr</groupId>
40.6 <artifactId>demo.static.calculator</artifactId>
40.7 - <version>0.8-SNAPSHOT</version>
40.8 + <version>0.9-SNAPSHOT</version>
40.9 <packaging>jar</packaging>
40.10
40.11 <name>JavaQuery Demo - Calculator - Static Compilation</name>
41.1 --- a/javaquery/demo-twitter/bck2brwsr-assembly.xml Tue Apr 29 15:25:58 2014 +0200
41.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
41.3 @@ -1,62 +0,0 @@
41.4 -<?xml version="1.0"?>
41.5 -<!--
41.6 -
41.7 - Back 2 Browser Bytecode Translator
41.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
41.9 -
41.10 - This program is free software: you can redistribute it and/or modify
41.11 - it under the terms of the GNU General Public License as published by
41.12 - the Free Software Foundation, version 2 of the License.
41.13 -
41.14 - This program is distributed in the hope that it will be useful,
41.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
41.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41.17 - GNU General Public License for more details.
41.18 -
41.19 - You should have received a copy of the GNU General Public License
41.20 - along with this program. Look for COPYING file in the top folder.
41.21 - If not, see http://opensource.org/licenses/GPL-2.0.
41.22 -
41.23 --->
41.24 -<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
41.25 - xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
41.26 -
41.27 - <id>bck2brwsr</id>
41.28 - <formats>
41.29 - <format>zip</format>
41.30 - </formats>
41.31 - <baseDirectory>public_html</baseDirectory>
41.32 - <dependencySets>
41.33 - <dependencySet>
41.34 - <useProjectArtifact>false</useProjectArtifact>
41.35 - <scope>runtime</scope>
41.36 - <outputDirectory>lib</outputDirectory>
41.37 - <includes>
41.38 - <include>*:jar</include>
41.39 - <include>*:rt</include>
41.40 - </includes>
41.41 - </dependencySet>
41.42 - </dependencySets>
41.43 - <fileSets>
41.44 - <fileSet>
41.45 - <directory>${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/twitter/</directory>
41.46 - <includes>
41.47 - <include>**/*</include>
41.48 - </includes>
41.49 - <excludes>
41.50 - <exclude>**/*.class</exclude>
41.51 - </excludes>
41.52 - <outputDirectory>/</outputDirectory>
41.53 - </fileSet>
41.54 - </fileSets>
41.55 - <files>
41.56 - <file>
41.57 - <source>${project.build.directory}/${project.build.finalName}.jar</source>
41.58 - <outputDirectory>/</outputDirectory>
41.59 - </file>
41.60 - <file>
41.61 - <source>${project.build.directory}/bck2brwsr.js</source>
41.62 - <outputDirectory>/</outputDirectory>
41.63 - </file>
41.64 - </files>
41.65 -</assembly>
41.66 \ No newline at end of file
42.1 --- a/javaquery/demo-twitter/nb-configuration.xml Tue Apr 29 15:25:58 2014 +0200
42.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
42.3 @@ -1,37 +0,0 @@
42.4 -<?xml version="1.0" encoding="UTF-8"?>
42.5 -<!--
42.6 -
42.7 - Back 2 Browser Bytecode Translator
42.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
42.9 -
42.10 - This program is free software: you can redistribute it and/or modify
42.11 - it under the terms of the GNU General Public License as published by
42.12 - the Free Software Foundation, version 2 of the License.
42.13 -
42.14 - This program is distributed in the hope that it will be useful,
42.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
42.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42.17 - GNU General Public License for more details.
42.18 -
42.19 - You should have received a copy of the GNU General Public License
42.20 - along with this program. Look for COPYING file in the top folder.
42.21 - If not, see http://opensource.org/licenses/GPL-2.0.
42.22 -
42.23 --->
42.24 -<project-shared-configuration>
42.25 - <!--
42.26 -This file contains additional configuration written by modules in the NetBeans IDE.
42.27 -The configuration is intended to be shared among all the users of project and
42.28 -therefore it is assumed to be part of version control checkout.
42.29 -Without this configuration present, some functionality in the IDE may be limited or fail altogether.
42.30 --->
42.31 - <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
42.32 - <!--
42.33 -Properties that influence various parts of the IDE, especially code formatting and the like.
42.34 -You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
42.35 -That way multiple projects can share the same settings (useful for formatting rules for example).
42.36 -Any value defined here will override the pom.xml file value but is only applicable to the current project.
42.37 --->
42.38 - <netbeans.compile.on.save>none</netbeans.compile.on.save>
42.39 - </properties>
42.40 -</project-shared-configuration>
43.1 --- a/javaquery/demo-twitter/nbactions.xml Tue Apr 29 15:25:58 2014 +0200
43.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
43.3 @@ -1,29 +0,0 @@
43.4 -<?xml version="1.0" encoding="UTF-8"?>
43.5 -<!--
43.6 -
43.7 - Back 2 Browser Bytecode Translator
43.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
43.9 -
43.10 - This program is free software: you can redistribute it and/or modify
43.11 - it under the terms of the GNU General Public License as published by
43.12 - the Free Software Foundation, version 2 of the License.
43.13 -
43.14 - This program is distributed in the hope that it will be useful,
43.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
43.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43.17 - GNU General Public License for more details.
43.18 -
43.19 - You should have received a copy of the GNU General Public License
43.20 - along with this program. Look for COPYING file in the top folder.
43.21 - If not, see http://opensource.org/licenses/GPL-2.0.
43.22 -
43.23 --->
43.24 -<actions>
43.25 - <action>
43.26 - <actionName>run</actionName>
43.27 - <goals>
43.28 - <goal>process-classes</goal>
43.29 - <goal>bck2brwsr:brwsr</goal>
43.30 - </goals>
43.31 - </action>
43.32 -</actions>
44.1 --- a/javaquery/demo-twitter/pom.xml Tue Apr 29 15:25:58 2014 +0200
44.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
44.3 @@ -1,151 +0,0 @@
44.4 -<?xml version="1.0" encoding="UTF-8"?>
44.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
44.6 - <modelVersion>4.0.0</modelVersion>
44.7 - <parent>
44.8 - <artifactId>javaquery</artifactId>
44.9 - <groupId>org.apidesign.bck2brwsr</groupId>
44.10 - <version>0.8-SNAPSHOT</version>
44.11 - </parent>
44.12 -
44.13 - <groupId>org.apidesign.bck2brwsr</groupId>
44.14 - <artifactId>demo-twitter</artifactId>
44.15 - <version>0.8-SNAPSHOT</version>
44.16 - <packaging>jar</packaging>
44.17 -
44.18 - <name>Bck2Brwsr's Twttr</name>
44.19 - <description>
44.20 - Rewrite of knockoutjs example to use model written in Java and
44.21 - execute using Bck2Brwsr virtual machine.
44.22 - </description>
44.23 -
44.24 - <repositories>
44.25 - <repository>
44.26 - <id>java.net</id>
44.27 - <name>Java.net</name>
44.28 - <url>https://maven.java.net/content/repositories/releases/</url>
44.29 - <snapshots>
44.30 - </snapshots>
44.31 - </repository>
44.32 - <repository>
44.33 - <id>netbeans</id>
44.34 - <name>NetBeans</name>
44.35 - <url>http://bits.netbeans.org/maven2/</url>
44.36 - </repository>
44.37 - </repositories>
44.38 - <pluginRepositories>
44.39 - <pluginRepository>
44.40 - <id>java.net</id>
44.41 - <name>Java.net</name>
44.42 - <url>https://maven.java.net/content/repositories/releases/</url>
44.43 - <snapshots>
44.44 - </snapshots>
44.45 - </pluginRepository>
44.46 - </pluginRepositories>
44.47 -
44.48 - <properties>
44.49 - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
44.50 - <bck2brwsr.obfuscationlevel>MINIMAL</bck2brwsr.obfuscationlevel>
44.51 - </properties>
44.52 - <build>
44.53 - <plugins>
44.54 - <plugin>
44.55 - <groupId>org.apidesign.bck2brwsr</groupId>
44.56 - <artifactId>bck2brwsr-maven-plugin</artifactId>
44.57 - <version>${project.version}</version>
44.58 - <executions>
44.59 - <execution>
44.60 - <goals>
44.61 - <goal>brwsr</goal>
44.62 - <goal>j2js</goal>
44.63 - </goals>
44.64 - </execution>
44.65 - </executions>
44.66 - <configuration>
44.67 - <startpage>org/apidesign/bck2brwsr/demo/twitter/index.html</startpage>
44.68 - <javascript>${project.build.directory}/bck2brwsr.js</javascript>
44.69 - <obfuscation>${bck2brwsr.obfuscationlevel}</obfuscation>
44.70 - </configuration>
44.71 - </plugin>
44.72 - <plugin>
44.73 - <groupId>org.apache.maven.plugins</groupId>
44.74 - <artifactId>maven-compiler-plugin</artifactId>
44.75 - <version>2.3.2</version>
44.76 - <configuration>
44.77 - <source>1.7</source>
44.78 - <target>1.7</target>
44.79 - </configuration>
44.80 - </plugin>
44.81 - <plugin>
44.82 - <groupId>org.apache.maven.plugins</groupId>
44.83 - <artifactId>maven-jar-plugin</artifactId>
44.84 - <version>2.4</version>
44.85 - <configuration>
44.86 - <archive>
44.87 - <manifest>
44.88 - <addClasspath>true</addClasspath>
44.89 - <classpathPrefix>lib/</classpathPrefix>
44.90 - </manifest>
44.91 - </archive>
44.92 - </configuration>
44.93 - </plugin>
44.94 - <plugin>
44.95 - <groupId>org.apache.maven.plugins</groupId>
44.96 - <artifactId>maven-deploy-plugin</artifactId>
44.97 - <version>2.7</version>
44.98 - <configuration>
44.99 - <skip>true</skip>
44.100 - </configuration>
44.101 - </plugin>
44.102 - <plugin>
44.103 - <artifactId>maven-assembly-plugin</artifactId>
44.104 - <version>2.4</version>
44.105 - <executions>
44.106 - <execution>
44.107 - <id>distro-assembly</id>
44.108 - <phase>package</phase>
44.109 - <goals>
44.110 - <goal>single</goal>
44.111 - </goals>
44.112 - <configuration>
44.113 - <descriptors>
44.114 - <descriptor>bck2brwsr-assembly.xml</descriptor>
44.115 - </descriptors>
44.116 - </configuration>
44.117 - </execution>
44.118 - </executions>
44.119 - </plugin>
44.120 - </plugins>
44.121 - </build>
44.122 -
44.123 - <dependencies>
44.124 - <dependency>
44.125 - <groupId>org.apidesign.bck2brwsr</groupId>
44.126 - <artifactId>emul</artifactId>
44.127 - <version>${project.version}</version>
44.128 - <classifier>rt</classifier>
44.129 - </dependency>
44.130 - <dependency>
44.131 - <groupId>org.apidesign.bck2brwsr</groupId>
44.132 - <artifactId>javaquery.api</artifactId>
44.133 - <version>${project.version}</version>
44.134 - </dependency>
44.135 - <dependency>
44.136 - <groupId>org.testng</groupId>
44.137 - <artifactId>testng</artifactId>
44.138 - <version>6.5.2</version>
44.139 - <scope>test</scope>
44.140 - </dependency>
44.141 - <dependency>
44.142 - <groupId>org.apidesign.bck2brwsr</groupId>
44.143 - <artifactId>vmtest</artifactId>
44.144 - <version>${project.version}</version>
44.145 - <scope>test</scope>
44.146 - </dependency>
44.147 - <dependency>
44.148 - <groupId>org.apidesign.bck2brwsr</groupId>
44.149 - <artifactId>launcher.http</artifactId>
44.150 - <version>${project.version}</version>
44.151 - <scope>runtime</scope>
44.152 - </dependency>
44.153 - </dependencies>
44.154 -</project>
45.1 --- a/javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java Tue Apr 29 15:25:58 2014 +0200
45.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
45.3 @@ -1,194 +0,0 @@
45.4 -/**
45.5 - * Back 2 Browser Bytecode Translator
45.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
45.7 - *
45.8 - * This program is free software: you can redistribute it and/or modify
45.9 - * it under the terms of the GNU General Public License as published by
45.10 - * the Free Software Foundation, version 2 of the License.
45.11 - *
45.12 - * This program is distributed in the hope that it will be useful,
45.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
45.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45.15 - * GNU General Public License for more details.
45.16 - *
45.17 - * You should have received a copy of the GNU General Public License
45.18 - * along with this program. Look for COPYING file in the top folder.
45.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
45.20 - */
45.21 -package org.apidesign.bck2brwsr.demo.twitter;
45.22 -
45.23 -import java.util.Arrays;
45.24 -import java.util.List;
45.25 -import org.apidesign.bck2brwsr.htmlpage.api.*;
45.26 -import org.apidesign.bck2brwsr.htmlpage.api.Page;
45.27 -import org.apidesign.bck2brwsr.htmlpage.api.Property;
45.28 -import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
45.29 -
45.30 -/** Controller class for access to Twitter.
45.31 - *
45.32 - * @author Jaroslav Tulach
45.33 - */
45.34 -@Page(xhtml="index.html", className="TwitterModel", properties={
45.35 - @Property(name="savedLists", type=Tweeters.class, array = true),
45.36 - @Property(name="activeTweetersName", type=String.class),
45.37 - @Property(name="activeTweeters", type=String.class, array = true),
45.38 - @Property(name="userNameToAdd", type=String.class),
45.39 - @Property(name="currentTweets", type=Tweet.class, array = true)
45.40 -})
45.41 -public class TwitterClient {
45.42 - @Model(className = "Tweeters", properties = {
45.43 - @Property(name="name", type = String.class),
45.44 - @Property(name="userNames", type = String.class, array = true)
45.45 - })
45.46 - static class Twttrs {
45.47 - }
45.48 - @Model(className = "Tweet", properties = {
45.49 - @Property(name = "from_user", type = String.class),
45.50 - @Property(name = "from_user_id", type = int.class),
45.51 - @Property(name = "profile_image_url", type = String.class),
45.52 - @Property(name = "text", type = String.class),
45.53 - @Property(name = "created_at", type = String.class),
45.54 - })
45.55 - static final class Twt {
45.56 - @ComputedProperty static String html(String text) {
45.57 - StringBuilder sb = new StringBuilder(320);
45.58 - for (int pos = 0;;) {
45.59 - int http = text.indexOf("http", pos);
45.60 - if (http == -1) {
45.61 - sb.append(text.substring(pos));
45.62 - return sb.toString();
45.63 - }
45.64 - int spc = text.indexOf(' ', http);
45.65 - if (spc == -1) {
45.66 - spc = text.length();
45.67 - }
45.68 - sb.append(text.substring(pos, http));
45.69 - String url = text.substring(http, spc);
45.70 - sb.append("<a href='").append(url).append("'>").append(url).append("</a>");
45.71 - pos = spc;
45.72 - }
45.73 - }
45.74 -
45.75 - @ComputedProperty static String userUrl(String from_user) {
45.76 - return "http://twitter.com/" + from_user;
45.77 - }
45.78 - }
45.79 - @Model(className = "TwitterQuery", properties = {
45.80 - @Property(array = true, name = "results", type = Twt.class)
45.81 - })
45.82 - public static final class TwttrQr {
45.83 - }
45.84 -
45.85 - @OnReceive(url="{root}/search.json?{query}&callback={me}", jsonp="me")
45.86 - static void queryTweets(TwitterModel page, TwitterQuery q) {
45.87 - page.getCurrentTweets().clear();
45.88 - page.getCurrentTweets().addAll(q.getResults());
45.89 - }
45.90 -
45.91 - @OnPropertyChange("activeTweetersName")
45.92 - static void changeTweetersList(TwitterModel model) {
45.93 - Tweeters people = findByName(model.getSavedLists(), model.getActiveTweetersName());
45.94 - model.getActiveTweeters().clear();
45.95 - model.getActiveTweeters().addAll(people.getUserNames());
45.96 - }
45.97 -
45.98 - @OnPropertyChange({ "activeTweeters", "activeTweetersCount" })
45.99 - static void refreshTweets(TwitterModel model) {
45.100 - StringBuilder sb = new StringBuilder();
45.101 - sb.append("rpp=25&q=");
45.102 - String sep = "";
45.103 - for (String p : model.getActiveTweeters()) {
45.104 - sb.append(sep);
45.105 - sb.append("from:");
45.106 - sb.append(p);
45.107 - sep = " OR ";
45.108 - }
45.109 - model.queryTweets("http://search.twitter.com", sb.toString());
45.110 - }
45.111 -
45.112 - static {
45.113 - final TwitterModel model = new TwitterModel();
45.114 - final List<Tweeters> svdLst = model.getSavedLists();
45.115 - svdLst.add(newTweeters("API Design", "JaroslavTulach"));
45.116 - svdLst.add(newTweeters("Celebrities", "JohnCleese", "MCHammer", "StephenFry", "algore", "StevenSanderson"));
45.117 - svdLst.add(newTweeters("Microsoft people", "BillGates", "shanselman", "ScottGu"));
45.118 - svdLst.add(newTweeters("NetBeans", "GeertjanW","monacotoni", "NetBeans", "petrjiricka"));
45.119 - svdLst.add(newTweeters("Tech pundits", "Scobleizer", "LeoLaporte", "techcrunch", "BoingBoing", "timoreilly", "codinghorror"));
45.120 -
45.121 - model.setActiveTweetersName("NetBeans");
45.122 -
45.123 - model.applyBindings();
45.124 - }
45.125 -
45.126 - @ComputedProperty
45.127 - static boolean hasUnsavedChanges(List<String> activeTweeters, List<Tweeters> savedLists, String activeTweetersName) {
45.128 - Tweeters tw = findByName(savedLists, activeTweetersName);
45.129 - if (activeTweeters == null) {
45.130 - return false;
45.131 - }
45.132 - return !tw.getUserNames().equals(activeTweeters);
45.133 - }
45.134 -
45.135 - @ComputedProperty
45.136 - static int activeTweetersCount(List<String> activeTweeters) {
45.137 - return activeTweeters.size();
45.138 - }
45.139 -
45.140 - @ComputedProperty
45.141 - static boolean userNameToAddIsValid(
45.142 - String userNameToAdd, String activeTweetersName, List<Tweeters> savedLists, List<String> activeTweeters
45.143 - ) {
45.144 - return userNameToAdd != null &&
45.145 - userNameToAdd.matches("[a-zA-Z0-9_]{1,15}") &&
45.146 - !activeTweeters.contains(userNameToAdd);
45.147 - }
45.148 -
45.149 - @OnFunction
45.150 - static void deleteList(TwitterModel model) {
45.151 - final List<Tweeters> sl = model.getSavedLists();
45.152 - sl.remove(findByName(sl, model.getActiveTweetersName()));
45.153 - if (sl.isEmpty()) {
45.154 - final Tweeters t = new Tweeters();
45.155 - t.setName("New");
45.156 - sl.add(t);
45.157 - }
45.158 - model.setActiveTweetersName(sl.get(0).getName());
45.159 - }
45.160 -
45.161 - @OnFunction
45.162 - static void saveChanges(TwitterModel model) {
45.163 - Tweeters t = findByName(model.getSavedLists(), model.getActiveTweetersName());
45.164 - int indx = model.getSavedLists().indexOf(t);
45.165 - if (indx != -1) {
45.166 - t.setName(model.getActiveTweetersName());
45.167 - t.getUserNames().clear();
45.168 - t.getUserNames().addAll(model.getActiveTweeters());
45.169 - }
45.170 - }
45.171 -
45.172 - @OnFunction
45.173 - static void addUser(TwitterModel model) {
45.174 - String n = model.getUserNameToAdd();
45.175 - model.getActiveTweeters().add(n);
45.176 - }
45.177 - @OnFunction
45.178 - static void removeUser(String data, TwitterModel model) {
45.179 - model.getActiveTweeters().remove(data);
45.180 - }
45.181 -
45.182 - private static Tweeters findByName(List<Tweeters> list, String name) {
45.183 - for (Tweeters l : list) {
45.184 - if (l.getName() != null && l.getName().equals(name)) {
45.185 - return l;
45.186 - }
45.187 - }
45.188 - return list.isEmpty() ? new Tweeters() : list.get(0);
45.189 - }
45.190 -
45.191 - private static Tweeters newTweeters(String listName, String... userNames) {
45.192 - Tweeters t = new Tweeters();
45.193 - t.setName(listName);
45.194 - t.getUserNames().addAll(Arrays.asList(userNames));
45.195 - return t;
45.196 - }
45.197 -}
46.1 --- a/javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/index.html Tue Apr 29 15:25:58 2014 +0200
46.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
46.3 @@ -1,99 +0,0 @@
46.4 -<?xml version="1.0" encoding="UTF-8"?>
46.5 -<!--
46.6 -
46.7 - Back 2 Browser Bytecode Translator
46.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
46.9 -
46.10 - This program is free software: you can redistribute it and/or modify
46.11 - it under the terms of the GNU General Public License as published by
46.12 - the Free Software Foundation, version 2 of the License.
46.13 -
46.14 - This program is distributed in the hope that it will be useful,
46.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
46.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46.17 - GNU General Public License for more details.
46.18 -
46.19 - You should have received a copy of the GNU General Public License
46.20 - along with this program. Look for COPYING file in the top folder.
46.21 - If not, see http://opensource.org/licenses/GPL-2.0.
46.22 -
46.23 --->
46.24 -
46.25 -<!--
46.26 - Copied from knockout.js Twitter example:
46.27 - http://knockoutjs.com/examples/twitter.html
46.28 --->
46.29 -
46.30 -<!DOCTYPE html>
46.31 -<html xmlns="http://www.w3.org/1999/xhtml">
46.32 - <head>
46.33 - <title>Bck2Brwsr's Twitter</title>
46.34 - </head>
46.35 - <body>
46.36 - <link href='twitterExample.css' rel='Stylesheet' ></link>
46.37 -
46.38 - <style type='text/css'>
46.39 - .liveExample select { height: 1.7em; }
46.40 - .liveExample button { height: 2em; }
46.41 - </style>
46.42 -
46.43 -
46.44 - <h2>Bck2Brwsr's Twitter</h2>
46.45 -
46.46 - <p>
46.47 - This code based on original <a href="http://knockoutjs.com/examples/twitter.html">knockout.js Twitter example</a> and
46.48 - uses almost unmodified HTML code. It just changes the model. It
46.49 - is written in Java language and it is executed using <a href="http://bck2brwsr.apidesign.org">Bck2Brwsr</a>
46.50 - virtual machine. The Java source code has about 190 lines and is available
46.51 - <a href="http://source.apidesign.org/hg/bck2brwsr/file/7fc6b7e9c982/javaquery/demo-twitter/src/main/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClient.java">here</a>
46.52 - - in fact it may even be more dense than the original JavaScript model.
46.53 - </p>
46.54 -
46.55 - <div class='liveExample'>
46.56 - <div class='configuration'>
46.57 - <div class='listChooser'>
46.58 - <button data-bind='click: deleteList, enable: activeTweetersName'>Delete</button>
46.59 - <button data-bind='click: saveChanges, enable: hasUnsavedChanges'>Save</button>
46.60 - <select data-bind='options: savedLists, optionsValue: "name", value: activeTweetersName'> </select>
46.61 - </div>
46.62 -
46.63 - <p>Currently viewing <span data-bind='text: activeTweetersCount'> </span> user(s):</p>
46.64 - <div class='currentUsers' >
46.65 - <ul data-bind='foreach: activeTweeters'>
46.66 - <li>
46.67 - <button data-bind='click: $root.removeUser'>Remove</button>
46.68 - <div data-bind='text: $data'> </div>
46.69 - </li>
46.70 - </ul>
46.71 - </div>
46.72 -
46.73 - <form data-bind='submit: addUser'>
46.74 - <label>Add user:</label>
46.75 - <input data-bind='value: userNameToAdd, valueUpdate: "keyup", css: { invalid: !userNameToAddIsValid() }' />
46.76 - <button data-bind='enable: userNameToAddIsValid' type='submit'>Add</button>
46.77 - </form>
46.78 - </div>
46.79 - <div class='tweets'>
46.80 - <div class='loadingIndicator'>Loading...</div>
46.81 - <table data-bind='foreach: currentTweets' width='100%'>
46.82 - <tr>
46.83 - <td><img data-bind='attr: { src: profile_image_url }' /></td>
46.84 - <td>
46.85 - <a class='twitterUser' data-bind='attr: { href: userUrl }, text: from_user'> </a>
46.86 - <span data-bind='html: html'> </span>
46.87 - <div class='tweetInfo' data-bind='text: created_at'> </div>
46.88 - </td>
46.89 - </tr>
46.90 - </table>
46.91 - </div>
46.92 - </div>
46.93 -
46.94 - <script src="bck2brwsr.js"></script>
46.95 - <script type="text/javascript">
46.96 - var vm = bck2brwsr('demo-twitter-0.8-SNAPSHOT.jar');
46.97 - vm.loadClass('org.apidesign.bck2brwsr.demo.twitter.TwitterClient');
46.98 - </script>
46.99 -
46.100 -
46.101 - </body>
46.102 -</html>
47.1 --- a/javaquery/demo-twitter/src/main/resources/org/apidesign/bck2brwsr/demo/twitter/twitterExample.css Tue Apr 29 15:25:58 2014 +0200
47.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
47.3 @@ -1,50 +0,0 @@
47.4 -/**
47.5 - * Back 2 Browser Bytecode Translator
47.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
47.7 - *
47.8 - * This program is free software: you can redistribute it and/or modify
47.9 - * it under the terms of the GNU General Public License as published by
47.10 - * the Free Software Foundation, version 2 of the License.
47.11 - *
47.12 - * This program is distributed in the hope that it will be useful,
47.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
47.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47.15 - * GNU General Public License for more details.
47.16 - *
47.17 - * You should have received a copy of the GNU General Public License
47.18 - * along with this program. Look for COPYING file in the top folder.
47.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
47.20 - */
47.21 -
47.22 -/*
47.23 - Copied from knockout.js Twitter example:
47.24 - http://knockoutjs.com/examples/twitter.html
47.25 -*/
47.26 -
47.27 -.configuration, .tweets, .tweets td { font-family: Verdana; font-size: 13px; }
47.28 -.configuration { background-color: #DEDEDE; border: 2px solid gray; float:left; height: 40em; width: 40%; padding: 0.5em; border-right-width:0; }
47.29 -.tweets { width: 55%; border: 2px solid gray; height: 40em; overflow: scroll; overflow-x: hidden; background-color: Black; color: White; padding: 0.5em; position: relative; }
47.30 -.tweets table { border-width: 0;}
47.31 -.tweets tr { vertical-align: top; }
47.32 -.tweets td { padding: 0.4em 0.3em 1em 0.4em; border-width: 0; }
47.33 -.tweets img { width: 4em; }
47.34 -.tweetInfo { color: Gray; font-size: 0.9em; }
47.35 -.twitterUser { color: #77AAFF; text-decoration: none; font-size: 1.1em; font-weight: bold; }
47.36 -input.invalid { border: 1px solid red !important; background-color: #FFAAAA !important; }
47.37 -
47.38 -.listChooser select, .listChooser button { vertical-align:top; }
47.39 -.listChooser select { width: 60%; font-size:1.2em; height:1.4em; }
47.40 -.listChooser button { width: 19%; height:1.68em; float:right; }
47.41 -
47.42 -.currentUsers { height: 28em; overflow-y: auto; overflow-x: hidden; }
47.43 -.currentUsers button { float: right; height: 2.5em; margin: 0.1em; padding-left: 1em; padding-right: 1em; }
47.44 -.currentUsers ul, .configuration li { list-style: none; margin: 0; padding: 0 }
47.45 -.currentUsers li { height: 2.4em; font-size: 1.2em; background-color: #A7D0E3; border: 1px solid gray; margin-bottom: 0.3em; -webkit-border-radius: 5px; -moz-border-radius: 5px; -webkit-box-shadow: 0 0.2em 0.5em gray; -moz-box-shadow: 0 0.2em 0.5em gray; }
47.46 -.currentUsers li div { padding: 0.6em; }
47.47 -.currentUsers li:hover { background-color: #EEC; }
47.48 -
47.49 -.configuration form label { width: 25%; display: inline-block; text-align:right; overflow: hidden; }
47.50 -.configuration form input { width:40%; font-size: 1.3em; border:1px solid silver; background-color: White; padding: 0.1em; }
47.51 -.configuration form button { width: 20%; margin-left: 0.3em; height: 2em; }
47.52 -
47.53 -.loadingIndicator { position: absolute; top: 0.1em; left: 0.1em; font: 0.8em Arial; background-color: #229; color: White; padding: 0.2em 0.5em 0.2em 0.5em; display: none; }
48.1 --- a/javaquery/demo-twitter/src/test/java/org/apidesign/bck2brwsr/demo/twitter/TwitterClientTest.java Tue Apr 29 15:25:58 2014 +0200
48.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
48.3 @@ -1,67 +0,0 @@
48.4 -/**
48.5 - * Back 2 Browser Bytecode Translator
48.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
48.7 - *
48.8 - * This program is free software: you can redistribute it and/or modify
48.9 - * it under the terms of the GNU General Public License as published by
48.10 - * the Free Software Foundation, version 2 of the License.
48.11 - *
48.12 - * This program is distributed in the hope that it will be useful,
48.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
48.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48.15 - * GNU General Public License for more details.
48.16 - *
48.17 - * You should have received a copy of the GNU General Public License
48.18 - * along with this program. Look for COPYING file in the top folder.
48.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
48.20 - */
48.21 -package org.apidesign.bck2brwsr.demo.twitter;
48.22 -
48.23 -import java.util.List;
48.24 -import static org.testng.Assert.*;
48.25 -import org.testng.annotations.BeforeMethod;
48.26 -import org.testng.annotations.Test;
48.27 -
48.28 -/** We can unit test the TwitterModel smoothly.
48.29 - *
48.30 - * @author Jaroslav Tulach <jtulach@netbeans.org>
48.31 - */
48.32 -public class TwitterClientTest {
48.33 - private TwitterModel model;
48.34 -
48.35 -
48.36 - @BeforeMethod
48.37 - public void initModel() {
48.38 - model = new TwitterModel().applyBindings();
48.39 - }
48.40 -
48.41 - @Test public void testIsValidToAdd() {
48.42 - model.setUserNameToAdd("Joe");
48.43 - Tweeters t = new Tweeters();
48.44 - t.setName("test");
48.45 - model.getSavedLists().add(t);
48.46 - model.setActiveTweetersName("test");
48.47 -
48.48 - assertTrue(model.isUserNameToAddIsValid(), "Joe is OK");
48.49 - TwitterClient.addUser(model);
48.50 - assertFalse(model.isUserNameToAddIsValid(), "Can't add Joe for the 2nd time");
48.51 - assertEquals(t.getUserNames().size(), 0, "Original tweeters list remains empty");
48.52 -
48.53 - List<String> mod = model.getActiveTweeters();
48.54 - assertTrue(model.isHasUnsavedChanges(), "We have modifications");
48.55 - assertEquals(mod.size(), 1, "One element in the list");
48.56 - assertEquals(mod.get(0), "Joe", "Its name is Joe");
48.57 -
48.58 - assertSame(model.getActiveTweeters(), mod, "Editing list is the modified one");
48.59 -
48.60 - TwitterClient.saveChanges(model);
48.61 - assertFalse(model.isHasUnsavedChanges(), "Does not have anything to save");
48.62 -
48.63 - assertSame(model.getActiveTweeters(), mod, "Still editing the old modified one");
48.64 - }
48.65 -
48.66 - @Test public void httpAtTheEnd() {
48.67 - String res = TwitterClient.Twt.html("Ahoj http://kuk");
48.68 - assertEquals(res, "Ahoj <a href='http://kuk'>http://kuk</a>");
48.69 - }
48.70 -}
49.1 --- a/javaquery/pom.xml Tue Apr 29 15:25:58 2014 +0200
49.2 +++ b/javaquery/pom.xml Wed Apr 30 15:04:10 2014 +0200
49.3 @@ -4,17 +4,16 @@
49.4 <parent>
49.5 <artifactId>bck2brwsr</artifactId>
49.6 <groupId>org.apidesign</groupId>
49.7 - <version>0.8-SNAPSHOT</version>
49.8 + <version>0.9-SNAPSHOT</version>
49.9 </parent>
49.10 <groupId>org.apidesign.bck2brwsr</groupId>
49.11 <artifactId>javaquery</artifactId>
49.12 - <version>0.8-SNAPSHOT</version>
49.13 + <version>0.9-SNAPSHOT</version>
49.14 <packaging>pom</packaging>
49.15 <name>JavaQuery API and Demo</name>
49.16 <modules>
49.17 <module>api</module>
49.18 <module>demo-calculator</module>
49.19 <module>demo-calculator-dynamic</module>
49.20 - <module>demo-twitter</module>
49.21 </modules>
49.22 -</project>
49.23 \ No newline at end of file
49.24 +</project>
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
50.2 +++ b/ko/archetype-test/pom.xml Wed Apr 30 15:04:10 2014 +0200
50.3 @@ -0,0 +1,48 @@
50.4 +<?xml version="1.0"?>
50.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
50.6 + <modelVersion>4.0.0</modelVersion>
50.7 + <parent>
50.8 + <groupId>org.apidesign.bck2brwsr</groupId>
50.9 + <artifactId>ko</artifactId>
50.10 + <version>0.9-SNAPSHOT</version>
50.11 + </parent>
50.12 + <groupId>org.apidesign.bck2brwsr</groupId>
50.13 + <artifactId>ko-archetype-test</artifactId>
50.14 + <version>0.9-SNAPSHOT</version>
50.15 + <name>Knockout Bck2Brwsr Archetype Test</name>
50.16 + <url>http://maven.apache.org</url>
50.17 + <description>Verifies the Knockout & net.java.html.json archetype behaves properly.</description>
50.18 + <properties>
50.19 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
50.20 + </properties>
50.21 + <dependencies>
50.22 + <dependency>
50.23 + <groupId>${project.groupId}</groupId>
50.24 + <artifactId>knockout4j-archetype</artifactId>
50.25 + <version>${project.version}</version>
50.26 + </dependency>
50.27 + <dependency>
50.28 + <groupId>org.testng</groupId>
50.29 + <artifactId>testng</artifactId>
50.30 + <scope>test</scope>
50.31 + </dependency>
50.32 + <dependency>
50.33 + <groupId>org.apache.maven.shared</groupId>
50.34 + <artifactId>maven-verifier</artifactId>
50.35 + <version>1.4</version>
50.36 + <scope>test</scope>
50.37 + </dependency>
50.38 + <dependency>
50.39 + <groupId>${project.groupId}</groupId>
50.40 + <artifactId>ko-fx</artifactId>
50.41 + <version>${project.version}</version>
50.42 + <scope>provided</scope>
50.43 + </dependency>
50.44 + <dependency>
50.45 + <groupId>${project.groupId}</groupId>
50.46 + <artifactId>ko-bck2brwsr</artifactId>
50.47 + <version>${project.version}</version>
50.48 + <scope>provided</scope>
50.49 + </dependency>
50.50 + </dependencies>
50.51 +</project>
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
51.2 +++ b/ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/ArchetypeVersionTest.java Wed Apr 30 15:04:10 2014 +0200
51.3 @@ -0,0 +1,140 @@
51.4 +/**
51.5 + * Back 2 Browser Bytecode Translator
51.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
51.7 + *
51.8 + * This program is free software: you can redistribute it and/or modify
51.9 + * it under the terms of the GNU General Public License as published by
51.10 + * the Free Software Foundation, version 2 of the License.
51.11 + *
51.12 + * This program is distributed in the hope that it will be useful,
51.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
51.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51.15 + * GNU General Public License for more details.
51.16 + *
51.17 + * You should have received a copy of the GNU General Public License
51.18 + * along with this program. Look for COPYING file in the top folder.
51.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
51.20 + */
51.21 +package org.apidesign.bck2brwsr.ko.archetype.test;
51.22 +
51.23 +import java.io.IOException;
51.24 +import java.net.URL;
51.25 +import javax.xml.XMLConstants;
51.26 +import javax.xml.parsers.DocumentBuilderFactory;
51.27 +import javax.xml.parsers.ParserConfigurationException;
51.28 +import javax.xml.xpath.XPathConstants;
51.29 +import javax.xml.xpath.XPathExpression;
51.30 +import javax.xml.xpath.XPathExpressionException;
51.31 +import javax.xml.xpath.XPathFactory;
51.32 +import javax.xml.xpath.XPathFactoryConfigurationException;
51.33 +import org.testng.annotations.Test;
51.34 +import static org.testng.Assert.*;
51.35 +import org.testng.annotations.BeforeClass;
51.36 +import org.w3c.dom.Document;
51.37 +import org.w3c.dom.NodeList;
51.38 +import org.xml.sax.SAXException;
51.39 +
51.40 +/**
51.41 + *
51.42 + * @author Jaroslav Tulach <jtulach@netbeans.org>
51.43 + */
51.44 +public class ArchetypeVersionTest {
51.45 + private String version;
51.46 +
51.47 + public ArchetypeVersionTest() {
51.48 + }
51.49 +
51.50 + @BeforeClass public void readCurrentVersion() throws Exception {
51.51 + version = findCurrentVersion();
51.52 + assertFalse(version.isEmpty(), "There should be some version string");
51.53 + }
51.54 +
51.55 +
51.56 + @Test public void testComparePomDepsVersions() throws Exception {
51.57 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
51.58 + URL r = l.getResource("archetype-resources/pom.xml");
51.59 + assertNotNull(r, "Archetype pom found");
51.60 +
51.61 + final XPathFactory fact = XPathFactory.newInstance();
51.62 + XPathExpression xp2 = fact.newXPath().compile(
51.63 + "//properties/net.java.html.version/text()"
51.64 + );
51.65 +
51.66 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
51.67 + String arch = (String) xp2.evaluate(dom, XPathConstants.STRING);
51.68 +
51.69 + int snapshot = arch.indexOf("-SNAPSHOT");
51.70 + if (snapshot >= 0) {
51.71 + arch = arch.substring(0, snapshot);
51.72 + }
51.73 +
51.74 + assertTrue(arch.matches("[0-9\\.]+"), "net.java.html.json version seems valid: " + arch);
51.75 + }
51.76 +
51.77 + @Test public void testCheckLauncher() throws Exception {
51.78 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
51.79 + URL r = l.getResource("archetype-resources/pom.xml");
51.80 + assertNotNull(r, "Archetype pom found");
51.81 +
51.82 + final XPathFactory fact = XPathFactory.newInstance();
51.83 + XPathExpression xp2 = fact.newXPath().compile(
51.84 + "//properties/bck2brwsr.launcher.version/text()"
51.85 + );
51.86 +
51.87 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
51.88 + String arch = (String) xp2.evaluate(dom, XPathConstants.STRING);
51.89 +
51.90 + assertEquals(arch, version, "launcher dependency is on more recent version");
51.91 + }
51.92 +
51.93 + @Test public void testCheckBck2Brwsr() throws Exception {
51.94 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
51.95 + URL r = l.getResource("archetype-resources/pom.xml");
51.96 + assertNotNull(r, "Archetype pom found");
51.97 +
51.98 + final XPathFactory fact = XPathFactory.newInstance();
51.99 + XPathExpression xp2 = fact.newXPath().compile(
51.100 + "//properties/bck2brwsr.version/text()"
51.101 + );
51.102 +
51.103 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
51.104 + String arch = (String) xp2.evaluate(dom, XPathConstants.STRING);
51.105 +
51.106 + assertEquals(arch, version, "bck2brwsr dependency is on more recent version");
51.107 + }
51.108 +
51.109 + @Test public void testNbActions() throws Exception {
51.110 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
51.111 + URL r = l.getResource("archetype-resources/nbactions.xml");
51.112 + assertNotNull(r, "Archetype nb file found");
51.113 +
51.114 + final XPathFactory fact = XPathFactory.newInstance();
51.115 + XPathExpression xp2 = fact.newXPath().compile(
51.116 + "//goal/text()"
51.117 + );
51.118 +
51.119 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
51.120 + NodeList goals = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET);
51.121 +
51.122 + for (int i = 0; i < goals.getLength(); i++) {
51.123 + String s = goals.item(i).getTextContent();
51.124 + if (s.contains("apidesign")) {
51.125 + assertFalse(s.matches(".*apidesign.*[0-9].*"), "No numbers: " + s);
51.126 + }
51.127 + }
51.128 + }
51.129 +
51.130 + static String findCurrentVersion() throws XPathExpressionException, IOException, ParserConfigurationException, SAXException, XPathFactoryConfigurationException {
51.131 + final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
51.132 + URL u = l.getResource("META-INF/maven/org.apidesign.bck2brwsr/knockout4j-archetype/pom.xml");
51.133 + assertNotNull(u, "Own pom found: " + System.getProperty("java.class.path"));
51.134 +
51.135 + final XPathFactory fact = XPathFactory.newInstance();
51.136 + fact.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
51.137 +
51.138 + XPathExpression xp = fact.newXPath().compile("project/version/text()");
51.139 +
51.140 + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(u.openStream());
51.141 + return xp.evaluate(dom);
51.142 + }
51.143 +}
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
52.2 +++ b/ko/archetype-test/src/test/java/org/apidesign/bck2brwsr/ko/archetype/test/VerifyArchetypeTest.java Wed Apr 30 15:04:10 2014 +0200
52.3 @@ -0,0 +1,133 @@
52.4 +/**
52.5 + * Back 2 Browser Bytecode Translator
52.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
52.7 + *
52.8 + * This program is free software: you can redistribute it and/or modify
52.9 + * it under the terms of the GNU General Public License as published by
52.10 + * the Free Software Foundation, version 2 of the License.
52.11 + *
52.12 + * This program is distributed in the hope that it will be useful,
52.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
52.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52.15 + * GNU General Public License for more details.
52.16 + *
52.17 + * You should have received a copy of the GNU General Public License
52.18 + * along with this program. Look for COPYING file in the top folder.
52.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
52.20 + */
52.21 +package org.apidesign.bck2brwsr.ko.archetype.test;
52.22 +
52.23 +import java.io.File;
52.24 +import java.io.IOException;
52.25 +import java.io.InputStream;
52.26 +import java.util.Properties;
52.27 +import java.util.zip.ZipEntry;
52.28 +import java.util.zip.ZipFile;
52.29 +import org.apache.maven.it.Verifier;
52.30 +import org.testng.annotations.Test;
52.31 +import static org.testng.Assert.*;
52.32 +import org.testng.reporters.Files;
52.33 +
52.34 +/**
52.35 + *
52.36 + * @author Jaroslav Tulach <jtulach@netbeans.org>
52.37 + */
52.38 +public class VerifyArchetypeTest {
52.39 + @Test public void fxBrwsrCompiles() throws Exception {
52.40 + final File dir = new File("target/tests/fxcompile/").getAbsoluteFile();
52.41 + generateFromArchetype(dir);
52.42 +
52.43 + File created = new File(dir, "o-a-test");
52.44 + assertTrue(created.isDirectory(), "Project created");
52.45 + assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there");
52.46 +
52.47 + Verifier v = new Verifier(created.getAbsolutePath());
52.48 + v.executeGoal("verify");
52.49 +
52.50 + v.verifyErrorFreeLog();
52.51 +
52.52 + for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) {
52.53 + if (l.contains("j2js")) {
52.54 + fail("No pre-compilaton:\n" + l);
52.55 + }
52.56 + }
52.57 +
52.58 + v.verifyTextInLog("org.apidesign.bck2brwsr.launcher.FXBrwsrLauncher");
52.59 + v.verifyTextInLog("fxcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-fxbrwsr.zip");
52.60 + }
52.61 +
52.62 + @Test public void bck2BrwsrCompiles() throws Exception {
52.63 + final File dir = new File("target/tests/b2bcompile/").getAbsoluteFile();
52.64 + generateFromArchetype(dir);
52.65 +
52.66 + File created = new File(dir, "o-a-test");
52.67 + assertTrue(created.isDirectory(), "Project created");
52.68 + assertTrue(new File(created, "pom.xml").isFile(), "Pom file is in there");
52.69 +
52.70 + Verifier v = new Verifier(created.getAbsolutePath());
52.71 + Properties sysProp = v.getSystemProperties();
52.72 + if (Boolean.getBoolean("java.awt.headless")) {
52.73 + sysProp.put("java.awt.headless", "true");
52.74 + }
52.75 + v.addCliOption("-Pbck2brwsr");
52.76 + v.executeGoal("verify");
52.77 +
52.78 + v.verifyErrorFreeLog();
52.79 +
52.80 + // no longer does pre-compilation to JavaScript
52.81 + // v.verifyTextInLog("j2js");
52.82 + // uses Bck2BrwsrLauncher
52.83 + v.verifyTextInLog("BaseHTTPLauncher showBrwsr");
52.84 + // building zip:
52.85 + v.verifyTextInLog("b2bcompile/o-a-test/target/o-a-test-1.0-SNAPSHOT-bck2brwsr.zip");
52.86 +
52.87 + for (String l : v.loadFile(v.getBasedir(), v.getLogFileName(), false)) {
52.88 + if (l.contains("fxbrwsr")) {
52.89 + fail("No fxbrwsr:\n" + l);
52.90 + }
52.91 + }
52.92 +
52.93 + File zip = new File(new File(created, "target"), "o-a-test-1.0-SNAPSHOT-bck2brwsr.zip");
52.94 + assertTrue(zip.isFile(), "Zip file with website was created");
52.95 +
52.96 + ZipFile zf = new ZipFile(zip);
52.97 + final ZipEntry index = zf.getEntry("public_html/index.html");
52.98 + assertNotNull(index, "index.html found");
52.99 +
52.100 + String txt = readText(zf.getInputStream(index));
52.101 + final int beg = txt.indexOf("${");
52.102 + if (beg >= 0) {
52.103 + int end = txt.indexOf("}", beg);
52.104 + if (end < beg) {
52.105 + end = txt.length();
52.106 + }
52.107 + fail("No substitutions in index.html. Found: " + txt.substring(beg, end));
52.108 + }
52.109 + }
52.110 +
52.111 + private Verifier generateFromArchetype(final File dir, String... params) throws Exception {
52.112 + Verifier v = new Verifier(dir.getAbsolutePath());
52.113 + v.setAutoclean(false);
52.114 + v.setLogFileName("generate.log");
52.115 + v.deleteDirectory("");
52.116 + dir.mkdirs();
52.117 + Properties sysProp = v.getSystemProperties();
52.118 + sysProp.put("groupId", "org.apidesign.test");
52.119 + sysProp.put("artifactId", "o-a-test");
52.120 + sysProp.put("package", "org.apidesign.test.oat");
52.121 + sysProp.put("archetypeGroupId", "org.apidesign.bck2brwsr");
52.122 + sysProp.put("archetypeArtifactId", "knockout4j-archetype");
52.123 + sysProp.put("archetypeVersion", ArchetypeVersionTest.findCurrentVersion());
52.124 +
52.125 + for (String p : params) {
52.126 + v.addCliOption(p);
52.127 + }
52.128 + v.executeGoal("archetype:generate");
52.129 + v.verifyErrorFreeLog();
52.130 + return v;
52.131 + }
52.132 +
52.133 + private static String readText(InputStream is) throws IOException {
52.134 + return Files.readFile(is);
52.135 + }
52.136 +}
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
53.2 +++ b/ko/archetype/pom.xml Wed Apr 30 15:04:10 2014 +0200
53.3 @@ -0,0 +1,58 @@
53.4 +<?xml version="1.0" encoding="UTF-8"?>
53.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
53.6 + <modelVersion>4.0.0</modelVersion>
53.7 + <parent>
53.8 + <artifactId>ko</artifactId>
53.9 + <groupId>org.apidesign.bck2brwsr</groupId>
53.10 + <version>0.9-SNAPSHOT</version>
53.11 + </parent>
53.12 + <groupId>org.apidesign.bck2brwsr</groupId>
53.13 + <artifactId>knockout4j-archetype</artifactId>
53.14 + <version>0.9-SNAPSHOT</version>
53.15 + <packaging>jar</packaging>
53.16 + <name>Knockout Bck2Brwsr Maven Archetype</name>
53.17 + <description>
53.18 + HTML page with Knockout.js bindings driven by application model
53.19 + written in Java. Use your favorite language to code. Use
53.20 + HTML as a lightweight rendering toolkit. Deploy using JavaFX or
53.21 + bck2brwsr virtual machine.
53.22 + </description>
53.23 + <build>
53.24 + <resources>
53.25 + <resource>
53.26 + <directory>src/main/resources</directory>
53.27 + <filtering>true</filtering>
53.28 + <includes>
53.29 + <include>**/pom.xml</include>
53.30 + </includes>
53.31 + </resource>
53.32 + <resource>
53.33 + <directory>src/main/resources</directory>
53.34 + <filtering>false</filtering>
53.35 + <excludes>
53.36 + <exclude>**/pom.xml</exclude>
53.37 + </excludes>
53.38 + </resource>
53.39 + </resources>
53.40 + <plugins>
53.41 + <plugin>
53.42 + <groupId>org.apache.maven.plugins</groupId>
53.43 + <artifactId>maven-compiler-plugin</artifactId>
53.44 + <version>2.3.2</version>
53.45 + <configuration>
53.46 + <source>1.6</source>
53.47 + <target>1.6</target>
53.48 + </configuration>
53.49 + </plugin>
53.50 + <plugin>
53.51 + <groupId>org.apache.maven.plugins</groupId>
53.52 + <artifactId>maven-resources-plugin</artifactId>
53.53 + <version>2.6</version>
53.54 + <configuration>
53.55 + <escapeString>\</escapeString>
53.56 + <target>1.6</target>
53.57 + </configuration>
53.58 + </plugin>
53.59 + </plugins>
53.60 + </build>
53.61 +</project>
54.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
54.2 +++ b/ko/archetype/src/main/java/org/apidesign/bck2brwsr/ko/archetype/package-info.java Wed Apr 30 15:04:10 2014 +0200
54.3 @@ -0,0 +1,18 @@
54.4 +/**
54.5 + * Back 2 Browser Bytecode Translator
54.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
54.7 + *
54.8 + * This program is free software: you can redistribute it and/or modify
54.9 + * it under the terms of the GNU General Public License as published by
54.10 + * the Free Software Foundation, version 2 of the License.
54.11 + *
54.12 + * This program is distributed in the hope that it will be useful,
54.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
54.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54.15 + * GNU General Public License for more details.
54.16 + *
54.17 + * You should have received a copy of the GNU General Public License
54.18 + * along with this program. Look for COPYING file in the top folder.
54.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
54.20 + */
54.21 +package org.apidesign.bck2brwsr.ko.archetype;
55.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
55.2 +++ b/ko/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml Wed Apr 30 15:04:10 2014 +0200
55.3 @@ -0,0 +1,63 @@
55.4 +<?xml version="1.0" encoding="UTF-8"?>
55.5 +<!--
55.6 +
55.7 + Back 2 Browser Bytecode Translator
55.8 + Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
55.9 +
55.10 + This program is free software: you can redistribute it and/or modify
55.11 + it under the terms of the GNU General Public License as published by
55.12 + the Free Software Foundation, version 2 of the License.
55.13 +
55.14 + This program is distributed in the hope that it will be useful,
55.15 + but WITHOUT ANY WARRANTY; without even the implied warranty of
55.16 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55.17 + GNU General Public License for more details.
55.18 +
55.19 + You should have received a copy of the GNU General Public License
55.20 + along with this program. Look for COPYING file in the top folder.
55.21 + If not, see http://opensource.org/licenses/GPL-2.0.
55.22 +
55.23 +-->
55.24 +<archetype-descriptor name="FX/Bck2Brwsr Example">
55.25 + <fileSets>
55.26 + <fileSet filtered="true" packaged="true">
55.27 + <directory>src/main/java</directory>
55.28 + <includes>
55.29 + <include>**/*.java</include>
55.30 + </includes>
55.31 + </fileSet>
55.32 + <fileSet filtered="true" packaged="false">
55.33 + <directory>src/main/webapp/pages</directory>
55.34 + <includes>
55.35 + <include>**/*.xhtml</include>
55.36 + <include>**/*.html</include>
55.37 + <include>**/*.css</include>
55.38 + </includes>
55.39 + </fileSet>
55.40 + <fileSet filtered="true" packaged="true">
55.41 + <directory>src/test/java</directory>
55.42 + <includes>
55.43 + <include>**/*Test.java</include>
55.44 + </includes>
55.45 + </fileSet>
55.46 + <fileSet filtered="true" packaged="false">
55.47 + <directory>src/main/assembly</directory>
55.48 + <includes>
55.49 + <include>**/*.xml</include>
55.50 + </includes>
55.51 + </fileSet>
55.52 + <fileSet filtered="false" packaged="false">
55.53 + <directory></directory>
55.54 + <includes>
55.55 + <include>nbactions*.xml</include>
55.56 + </includes>
55.57 + </fileSet>
55.58 + <fileSet filtered="true" packaged="false">
55.59 + <directory>assembly</directory>
55.60 + <includes>
55.61 + <include>fxbrwsr-assembly.xml</include>
55.62 + <include>bck2brwsr-assembly.xml</include>
55.63 + </includes>
55.64 + </fileSet>
55.65 + </fileSets>
55.66 +</archetype-descriptor>
55.67 \ No newline at end of file
56.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
56.2 +++ b/ko/archetype/src/main/resources/archetype-resources/nbactions-bck2brwsr.xml Wed Apr 30 15:04:10 2014 +0200
56.3 @@ -0,0 +1,14 @@
56.4 +<?xml version="1.0" encoding="UTF-8"?>
56.5 +<actions>
56.6 + <action>
56.7 + <actionName>run</actionName>
56.8 + <goals>
56.9 + <goal>package</goal>
56.10 + <goal>bck2brwsr:brwsr</goal>
56.11 + </goals>
56.12 + <properties>
56.13 + <skipTests>true</skipTests>
56.14 + <bck2brwsr.obfuscationlevel>NONE</bck2brwsr.obfuscationlevel>
56.15 + </properties>
56.16 + </action>
56.17 +</actions>
57.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
57.2 +++ b/ko/archetype/src/main/resources/archetype-resources/nbactions-fxbrwsr.xml Wed Apr 30 15:04:10 2014 +0200
57.3 @@ -0,0 +1,20 @@
57.4 +<?xml version="1.0" encoding="UTF-8"?>
57.5 +<actions>
57.6 + <action>
57.7 + <actionName>run</actionName>
57.8 + <goals>
57.9 + <goal>process-classes</goal>
57.10 + <goal>bck2brwsr:brwsr</goal>
57.11 + </goals>
57.12 + </action>
57.13 + <action>
57.14 + <actionName>debug</actionName>
57.15 + <goals>
57.16 + <goal>process-classes</goal>
57.17 + <goal>bck2brwsr:brwsr</goal>
57.18 + </goals>
57.19 + <properties>
57.20 + <jpda.listen>maven</jpda.listen>
57.21 + </properties>
57.22 + </action>
57.23 +</actions>
58.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
58.2 +++ b/ko/archetype/src/main/resources/archetype-resources/nbactions.xml Wed Apr 30 15:04:10 2014 +0200
58.3 @@ -0,0 +1,20 @@
58.4 +<?xml version="1.0" encoding="UTF-8"?>
58.5 +<actions>
58.6 + <action>
58.7 + <actionName>run</actionName>
58.8 + <goals>
58.9 + <goal>process-classes</goal>
58.10 + <goal>bck2brwsr:brwsr</goal>
58.11 + </goals>
58.12 + </action>
58.13 + <action>
58.14 + <actionName>debug</actionName>
58.15 + <goals>
58.16 + <goal>process-classes</goal>
58.17 + <goal>bck2brwsr:brwsr</goal>
58.18 + </goals>
58.19 + <properties>
58.20 + <jpda.listen>maven</jpda.listen>
58.21 + </properties>
58.22 + </action>
58.23 +</actions>
59.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
59.2 +++ b/ko/archetype/src/main/resources/archetype-resources/pom.xml Wed Apr 30 15:04:10 2014 +0200
59.3 @@ -0,0 +1,283 @@
59.4 +<?xml version="1.0"?>
59.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
59.6 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
59.7 + <modelVersion>4.0.0</modelVersion>
59.8 +
59.9 + <groupId>\${groupId}</groupId>
59.10 + <artifactId>\${artifactId}</artifactId>
59.11 + <version>\${version}</version>
59.12 + <packaging>jar</packaging>
59.13 +
59.14 + <name>\${artifactId}</name>
59.15 +
59.16 + <repositories>
59.17 + <repository>
59.18 + <id>java.net</id>
59.19 + <name>Java.net</name>
59.20 + <url>https://maven.java.net/content/repositories/releases/</url>
59.21 + <snapshots>
59.22 + <enabled>true</enabled>
59.23 + </snapshots>
59.24 + </repository>
59.25 + <repository>
59.26 + <id>netbeans</id>
59.27 + <name>NetBeans</name>
59.28 + <url>http://bits.netbeans.org/maven2/</url>
59.29 + </repository>
59.30 + </repositories>
59.31 + <pluginRepositories>
59.32 + <pluginRepository>
59.33 + <id>java.net</id>
59.34 + <name>Java.net</name>
59.35 + <url>https://maven.java.net/content/repositories/releases/</url>
59.36 + <snapshots>
59.37 + <enabled>true</enabled>
59.38 + </snapshots>
59.39 + </pluginRepository>
59.40 + </pluginRepositories>
59.41 +
59.42 + <properties>
59.43 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
59.44 + <net.java.html.version>${net.java.html.version}</net.java.html.version>
59.45 + <bck2brwsr.version>${project.version}</bck2brwsr.version>
59.46 + <bck2brwsr.launcher.version>${project.version}</bck2brwsr.launcher.version>
59.47 + <bck2brwsr.obfuscationlevel>MINIMAL</bck2brwsr.obfuscationlevel>
59.48 + <brwsr.startpage>pages/index.html</brwsr.startpage>
59.49 + <netbeans.compile.on.save>none</netbeans.compile.on.save>
59.50 + </properties>
59.51 + <build>
59.52 + <plugins>
59.53 + <plugin>
59.54 + <groupId>org.apidesign.bck2brwsr</groupId>
59.55 + <artifactId>bck2brwsr-maven-plugin</artifactId>
59.56 + <version>\${bck2brwsr.launcher.version}</version>
59.57 + <executions>
59.58 + <execution>
59.59 + <goals>
59.60 + <goal>brwsr</goal>
59.61 + </goals>
59.62 + </execution>
59.63 + </executions>
59.64 + <configuration>
59.65 + <directory>\${basedir}/src/main/webapp/</directory>
59.66 + <startpage>${brwsr.startpage}</startpage>
59.67 + <launcher>${brwsr}</launcher>
59.68 + </configuration>
59.69 + </plugin>
59.70 + <plugin>
59.71 + <groupId>org.netbeans.html</groupId>
59.72 + <artifactId>html4j-maven-plugin</artifactId>
59.73 + <version>${net.java.html.version}</version>
59.74 + <executions>
59.75 + <execution>
59.76 + <id>js-classes</id>
59.77 + <goals>
59.78 + <goal>process-js-annotations</goal>
59.79 + </goals>
59.80 + </execution>
59.81 + </executions>
59.82 + </plugin>
59.83 + <plugin>
59.84 + <groupId>org.apache.maven.plugins</groupId>
59.85 + <artifactId>maven-compiler-plugin</artifactId>
59.86 + <version>2.3.2</version>
59.87 + <configuration>
59.88 + <source>1.7</source>
59.89 + <target>1.7</target>
59.90 + </configuration>
59.91 + </plugin>
59.92 + <plugin>
59.93 + <groupId>org.apache.maven.plugins</groupId>
59.94 + <artifactId>maven-surefire-plugin</artifactId>
59.95 + <version>2.14.1</version>
59.96 + <configuration>
59.97 + <systemPropertyVariables>
59.98 + <vmtest.brwsrs>\${brwsr}</vmtest.brwsrs>
59.99 + </systemPropertyVariables>
59.100 + </configuration>
59.101 + </plugin>
59.102 + <plugin>
59.103 + <groupId>org.apache.maven.plugins</groupId>
59.104 + <artifactId>maven-jar-plugin</artifactId>
59.105 + <version>2.4</version>
59.106 + <configuration>
59.107 + <archive>
59.108 + <manifest>
59.109 + <addClasspath>true</addClasspath>
59.110 + <classpathPrefix>lib/</classpathPrefix>
59.111 + </manifest>
59.112 + </archive>
59.113 + </configuration>
59.114 + </plugin>
59.115 + <plugin>
59.116 + <groupId>org.apache.maven.plugins</groupId>
59.117 + <artifactId>maven-deploy-plugin</artifactId>
59.118 + <version>2.7</version>
59.119 + <configuration>
59.120 + <skip>true</skip>
59.121 + </configuration>
59.122 + </plugin>
59.123 + </plugins>
59.124 + </build>
59.125 +
59.126 + <dependencies>
59.127 + <dependency>
59.128 + <groupId>org.testng</groupId>
59.129 + <artifactId>testng</artifactId>
59.130 + <version>6.7</version>
59.131 + <scope>test</scope>
59.132 + </dependency>
59.133 + <dependency>
59.134 + <groupId>org.apidesign.bck2brwsr</groupId>
59.135 + <artifactId>launcher.http</artifactId>
59.136 + <version>\${bck2brwsr.launcher.version}</version>
59.137 + <scope>test</scope>
59.138 + </dependency>
59.139 + <dependency>
59.140 + <groupId>org.apidesign.bck2brwsr</groupId>
59.141 + <artifactId>vmtest</artifactId>
59.142 + <version>\${bck2brwsr.version}</version>
59.143 + <scope>test</scope>
59.144 + </dependency>
59.145 + <dependency>
59.146 + <groupId>org.netbeans.html</groupId>
59.147 + <artifactId>net.java.html.json</artifactId>
59.148 + <version>\${net.java.html.version}</version>
59.149 + <type>jar</type>
59.150 + </dependency>
59.151 + <dependency>
59.152 + <groupId>org.netbeans.html</groupId>
59.153 + <artifactId>net.java.html.boot</artifactId>
59.154 + <version>\${net.java.html.version}</version>
59.155 + <type>jar</type>
59.156 + </dependency>
59.157 + </dependencies>
59.158 + <profiles>
59.159 + <profile>
59.160 + <id>fxbrwsr</id>
59.161 + <activation>
59.162 + <activeByDefault>true</activeByDefault>
59.163 + </activation>
59.164 + <properties>
59.165 + <brwsr>fxbrwsr</brwsr>
59.166 + </properties>
59.167 + <build>
59.168 + <plugins>
59.169 + <plugin>
59.170 + <groupId>org.apache.maven.plugins</groupId>
59.171 + <artifactId>maven-jar-plugin</artifactId>
59.172 + <version>2.4</version>
59.173 + <configuration>
59.174 + <archive>
59.175 + <manifest>
59.176 + <mainClass>org.apidesign.bck2brwsr.launcher.FXBrwsrLauncher</mainClass>
59.177 + <addClasspath>true</addClasspath>
59.178 + <classpathPrefix>lib/</classpathPrefix>
59.179 + </manifest>
59.180 + <manifestEntries>
59.181 + <StartPage>\${brwsr.startpage}</StartPage>
59.182 + </manifestEntries>
59.183 + </archive>
59.184 + </configuration>
59.185 + </plugin>
59.186 + <plugin>
59.187 + <artifactId>maven-assembly-plugin</artifactId>
59.188 + <version>2.4</version>
59.189 + <executions>
59.190 + <execution>
59.191 + <id>distro-assembly</id>
59.192 + <phase>package</phase>
59.193 + <goals>
59.194 + <goal>single</goal>
59.195 + </goals>
59.196 + <configuration>
59.197 + <descriptors>
59.198 + <descriptor>src/main/assembly/fxbrwsr.xml</descriptor>
59.199 + </descriptors>
59.200 + </configuration>
59.201 + </execution>
59.202 + </executions>
59.203 + </plugin>
59.204 + </plugins>
59.205 + </build>
59.206 + <dependencies>
59.207 + <dependency>
59.208 + <groupId>org.netbeans.html</groupId>
59.209 + <artifactId>ko4j</artifactId>
59.210 + <version>\${net.java.html.version}</version>
59.211 + </dependency>
59.212 + <dependency>
59.213 + <groupId>org.apidesign.bck2brwsr</groupId>
59.214 + <artifactId>launcher.fx</artifactId>
59.215 + <version>\${bck2brwsr.launcher.version}</version>
59.216 + <scope>runtime</scope>
59.217 + </dependency>
59.218 + </dependencies>
59.219 + </profile>
59.220 + <profile>
59.221 + <id>bck2brwsr</id>
59.222 + <activation>
59.223 + <property>
59.224 + <name>brwsr</name>
59.225 + <value>bck2brwsr</value>
59.226 + </property>
59.227 + </activation>
59.228 + <build>
59.229 + <plugins>
59.230 + <plugin>
59.231 + <groupId>org.apache.maven.plugins</groupId>
59.232 + <artifactId>maven-compiler-plugin</artifactId>
59.233 + <configuration>
59.234 + <compilerArguments>
59.235 + <bootclasspath>netbeans.ignore.jdk.bootclasspath</bootclasspath>
59.236 + </compilerArguments>
59.237 + <testExcludes>
59.238 + <exclude>**/JsInteractionTest*</exclude>
59.239 + </testExcludes>
59.240 + </configuration>
59.241 + </plugin>
59.242 + <plugin>
59.243 + <artifactId>maven-assembly-plugin</artifactId>
59.244 + <version>2.4</version>
59.245 + <executions>
59.246 + <execution>
59.247 + <id>distro-assembly</id>
59.248 + <phase>package</phase>
59.249 + <goals>
59.250 + <goal>single</goal>
59.251 + </goals>
59.252 + <configuration>
59.253 + <descriptors>
59.254 + <descriptor>src/main/assembly/bck2brwsr.xml</descriptor>
59.255 + </descriptors>
59.256 + </configuration>
59.257 + </execution>
59.258 + </executions>
59.259 + </plugin>
59.260 + </plugins>
59.261 + </build>
59.262 + <dependencies>
59.263 + <dependency>
59.264 + <groupId>org.apidesign.bck2brwsr</groupId>
59.265 + <artifactId>emul</artifactId>
59.266 + <version>\${bck2brwsr.version}</version>
59.267 + <classifier>rt</classifier>
59.268 + </dependency>
59.269 + <dependency>
59.270 + <groupId>org.apidesign.bck2brwsr</groupId>
59.271 + <artifactId>ko-bck2brwsr</artifactId>
59.272 + <version>\${bck2brwsr.version}</version>
59.273 + <scope>runtime</scope>
59.274 + </dependency>
59.275 + <dependency>
59.276 + <groupId>org.apidesign.bck2brwsr</groupId>
59.277 + <artifactId>vm4brwsr</artifactId>
59.278 + <classifier>js</classifier>
59.279 + <type>zip</type>
59.280 + <version>\${bck2brwsr.version}</version>
59.281 + <scope>provided</scope>
59.282 + </dependency>
59.283 + </dependencies>
59.284 + </profile>
59.285 + </profiles>
59.286 +</project>
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
60.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/assembly/bck2brwsr.xml Wed Apr 30 15:04:10 2014 +0200
60.3 @@ -0,0 +1,43 @@
60.4 +<?xml version="1.0"?>
60.5 +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
60.6 + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
60.7 +
60.8 + <id>bck2brwsr</id>
60.9 + <formats>
60.10 + <format>zip</format>
60.11 + </formats>
60.12 + <baseDirectory>public_html</baseDirectory>
60.13 + <dependencySets>
60.14 + <dependencySet>
60.15 + <useProjectArtifact>false</useProjectArtifact>
60.16 + <scope>runtime</scope>
60.17 + <outputDirectory>lib</outputDirectory>
60.18 + <includes>
60.19 + <include>*:jar</include>
60.20 + <include>*:rt</include>
60.21 + </includes>
60.22 + </dependencySet>
60.23 + <dependencySet>
60.24 + <useProjectArtifact>false</useProjectArtifact>
60.25 + <scope>provided</scope>
60.26 + <includes>
60.27 + <include>*:js</include>
60.28 + </includes>
60.29 + <unpack>true</unpack>
60.30 + <outputDirectory>/</outputDirectory>
60.31 + </dependencySet>
60.32 + </dependencySets>
60.33 + <fileSets>
60.34 + <fileSet>
60.35 + <directory>src/main/webapp/pages</directory>
60.36 + <outputDirectory>/</outputDirectory>
60.37 + <filtered>true</filtered>
60.38 + </fileSet>
60.39 + </fileSets>
60.40 + <files>
60.41 + <file>
60.42 + <source>${project.build.directory}/${project.build.finalName}.jar</source>
60.43 + <outputDirectory>/</outputDirectory>
60.44 + </file>
60.45 + </files>
60.46 +</assembly>
60.47 \ No newline at end of file
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
61.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/assembly/fxbrwsr.xml Wed Apr 30 15:04:10 2014 +0200
61.3 @@ -0,0 +1,33 @@
61.4 +<?xml version="1.0"?>
61.5 +<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
61.6 + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
61.7 +
61.8 + <id>fxbrwsr</id>
61.9 + <formats>
61.10 + <format>zip</format>
61.11 + </formats>
61.12 + <baseDirectory>${project.build.finalName}-fxbrwsr</baseDirectory>
61.13 + <dependencySets>
61.14 + <dependencySet>
61.15 + <useProjectArtifact>false</useProjectArtifact>
61.16 + <scope>runtime</scope>
61.17 + <outputDirectory>lib</outputDirectory>
61.18 + </dependencySet>
61.19 + </dependencySets>
61.20 + <files>
61.21 + <file>
61.22 + <source>${project.build.directory}/${project.build.finalName}.jar</source>
61.23 + <outputDirectory>/</outputDirectory>
61.24 + </file>
61.25 + </files>
61.26 + <fileSets>
61.27 + <fileSet>
61.28 + <directory>src/main/webapp/</directory>
61.29 + <outputDirectory>/</outputDirectory>
61.30 + <includes>
61.31 + <include>pages/**</include>
61.32 + </includes>
61.33 + <filtered>true</filtered>
61.34 + </fileSet>
61.35 + </fileSets>
61.36 +</assembly>
61.37 \ No newline at end of file
62.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
62.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/java/DataModel.java Wed Apr 30 15:04:10 2014 +0200
62.3 @@ -0,0 +1,45 @@
62.4 +package ${package};
62.5 +
62.6 +import net.java.html.json.ComputedProperty;
62.7 +import net.java.html.json.Function;
62.8 +import net.java.html.json.Model;
62.9 +import net.java.html.json.Property;
62.10 +
62.11 +/** Model annotation generates class Data with
62.12 + * one message property, boolean property and read only words property
62.13 + */
62.14 +@Model(className = "Data", properties = {
62.15 + @Property(name = "message", type = String.class),
62.16 + @Property(name = "on", type = boolean.class)
62.17 +})
62.18 +final class DataModel {
62.19 + @ComputedProperty static java.util.List<String> words(String message) {
62.20 + String[] arr = new String[6];
62.21 + String[] words = message == null ? new String[0] : message.split(" ", 6);
62.22 + for (int i = 0; i < 6; i++) {
62.23 + arr[i] = words.length > i ? words[i] : "!";
62.24 + }
62.25 + return java.util.Arrays.asList(arr);
62.26 + }
62.27 +
62.28 + @Function static void turnOn(Data model) {
62.29 + model.setOn(true);
62.30 + }
62.31 +
62.32 + @Function static void turnOff(final Data model) {
62.33 + confirmByUser("Really turn off?", new Runnable() {
62.34 + @Override
62.35 + public void run() {
62.36 + model.setOn(false);
62.37 + }
62.38 + });
62.39 + }
62.40 +
62.41 + /** Shows direct interaction with JavaScript */
62.42 + @net.java.html.js.JavaScriptBody(
62.43 + args = { "msg", "callback" },
62.44 + javacall = true,
62.45 + body = "alert(msg); callback.@java.lang.Runnable::run()();"
62.46 + )
62.47 + static native void confirmByUser(String msg, Runnable callback);
62.48 +}
63.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
63.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/java/Main.java Wed Apr 30 15:04:10 2014 +0200
63.3 @@ -0,0 +1,15 @@
63.4 +package ${package};
63.5 +
63.6 +public final class Main {
63.7 + private Main() {
63.8 + }
63.9 +
63.10 + /**
63.11 + * Called when the page is ready.
63.12 + */
63.13 + static {
63.14 + Data d = new Data();
63.15 + d.setMessage("Hello World from HTML and Java!");
63.16 + d.applyBindings();
63.17 + }
63.18 +}
64.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
64.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/main/webapp/pages/index.html Wed Apr 30 15:04:10 2014 +0200
64.3 @@ -0,0 +1,72 @@
64.4 +<!DOCTYPE html>
64.5 +<html>
64.6 + <head>
64.7 + <title></title>
64.8 + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
64.9 +
64.10 + <style type="text/css">
64.11 + @-webkit-keyframes spin {
64.12 + 0% { -webkit-transform: rotate(0deg); }
64.13 + 100% { -webkit-transform: rotate(360deg); }
64.14 + }
64.15 + @keyframes spin {
64.16 + 0% { transform: rotate(0deg); }
64.17 + 100% { transform: rotate(360deg); }
64.18 + }
64.19 +
64.20 + .rotate {
64.21 + -webkit-animation-name: spin;
64.22 + -webkit-animation-duration: 3s;
64.23 + -webkit-animation-iteration-count: infinite;
64.24 + -webkit-animation-direction: alternate;
64.25 +
64.26 + animation-name: spin;
64.27 + animation-duration: 3s;
64.28 + animation-iteration-count: infinite;
64.29 + animation-direction: alternate;
64.30 + }
64.31 +
64.32 + #scene {
64.33 + position: relative;
64.34 + top: 60px;
64.35 + text-align: center;
64.36 + }
64.37 +
64.38 + #words span {
64.39 + border: 1px solid #ccc;
64.40 + background: rgba(255,255,155,0.8);
64.41 + text-align: center;
64.42 + font-size: 30px;
64.43 + -webkit-box-shadow: inset 0 0 40px rgba(0,0,0,0.4);
64.44 + position: absolute;
64.45 + }
64.46 +
64.47 + #words span:nth-child(1) { left: 45%; top: 0px; }
64.48 + #words span:nth-child(2) { left: 25%; top: 100px; }
64.49 + #words span:nth-child(3) { left: 65%; top: 100px; }
64.50 + #words span:nth-child(4) { left: 10%; top: 200px; }
64.51 + #words span:nth-child(5) { left: 45%; top: 200px; }
64.52 + #words span:nth-child(6) { left: 80%; top: 200px; }
64.53 +
64.54 + </style>
64.55 +
64.56 + </head>
64.57 + <body>
64.58 + <h1>Words Demo</h1>
64.59 + <input data-bind="value: message, valueUpdate: 'afterkeydown'" size="80">
64.60 + <br>
64.61 + <button data-bind="enable: !on(), click: $root.turnOn">Start</button>
64.62 + <button data-bind="enable: on, click: $root.turnOff">Stop</button>
64.63 +
64.64 + <div id="scene">
64.65 + <span id="words" data-bind="foreach: words">
64.66 + <span data-bind="text: $data, css: { 'rotate' : $root.on } "></span>
64.67 + </span>
64.68 + </div>
64.69 + <script type="text/javascript" src="bck2brwsr.js"></script>
64.70 + <script>
64.71 + var vm = bck2brwsr('${project.build.finalName}.jar');
64.72 + vm.loadClass('${package}.Main');
64.73 + </script>
64.74 + </body>
64.75 +</html>
65.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
65.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/test/java/DataModelTest.java Wed Apr 30 15:04:10 2014 +0200
65.3 @@ -0,0 +1,16 @@
65.4 +package ${package};
65.5 +
65.6 +import static org.testng.Assert.*;
65.7 +import org.testng.annotations.Test;
65.8 +
65.9 +public class DataModelTest {
65.10 + @Test public void areHelloWorldTwoWords() {
65.11 + Data model = new Data();
65.12 + model.setMessage("Hello World!");
65.13 +
65.14 + java.util.List<String> arr = model.getWords();
65.15 + assertEquals(arr.size(), 6, "Six words always");
65.16 + assertEquals("Hello", arr.get(0), "Hello is the first word");
65.17 + assertEquals("World!", arr.get(1), "World is the second word");
65.18 + }
65.19 +}
66.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
66.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java Wed Apr 30 15:04:10 2014 +0200
66.3 @@ -0,0 +1,38 @@
66.4 +package ${package};
66.5 +
66.6 +import org.apidesign.bck2brwsr.vmtest.Compare;
66.7 +import org.apidesign.bck2brwsr.vmtest.VMTest;
66.8 +import org.testng.annotations.Factory;
66.9 +
66.10 +/** Bck2brwsr cares about compatibility with real Java. Whatever API is
66.11 + * supported by bck2brwsr, it needs to behave the same way as when running
66.12 + * in HotSpot VM.
66.13 + * <p>
66.14 + * There can be bugs, however. To help us fix them, we kindly ask you to
66.15 + * write an "inconsistency" test. A test that compares behavior of the API
66.16 + * between real VM and bck2brwsr VM. This class is skeleton of such test.
66.17 + */
66.18 +public class InconsistencyTest {
66.19 + /** A method to demonstrate inconsistency between bck2brwsr and HotSpot.
66.20 + * Make calls to an API that behaves strangely, return some result at
66.21 + * the end. No need to use any <code>assert</code>.
66.22 + *
66.23 + * @return value to compare between HotSpot and bck2brwsr
66.24 + */
66.25 + @Compare
66.26 + public int checkStringHashCode() throws Exception {
66.27 + return "Is string hashCode the same?".hashCode();
66.28 + }
66.29 +
66.30 + /** Factory method that creates a three tests for each method annotated with
66.31 + * {@link org.apidesign.bck2brwsr.vmtest.Compare}. One executes the code in
66.32 + * HotSpot, one in Rhino and the last one compares the results.
66.33 + *
66.34 + * @see org.apidesign.bck2brwsr.vmtest.VMTest
66.35 + */
66.36 + @Factory
66.37 + public static Object[] create() {
66.38 + return VMTest.create(InconsistencyTest.class);
66.39 + }
66.40 +
66.41 +}
67.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
67.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java Wed Apr 30 15:04:10 2014 +0200
67.3 @@ -0,0 +1,31 @@
67.4 +package ${package};
67.5 +
67.6 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
67.7 +import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
67.8 +import org.apidesign.bck2brwsr.vmtest.VMTest;
67.9 +import org.testng.annotations.Factory;
67.10 +
67.11 +/** Sometimes it is useful to run tests inside of the real browser.
67.12 + * To do that just annotate your method with {@link org.apidesign.bck2brwsr.vmtest.BrwsrTest}
67.13 + * and that is it. If your code references elements on the HTML page,
67.14 + * you can pass in an {@link org.apidesign.bck2brwsr.vmtest.HtmlFragment} which
67.15 + * will be made available on the page before your test starts.
67.16 + */
67.17 +public class IntegrationTest {
67.18 +
67.19 + /** Write to testing code here. Use <code>assert</code> (but not TestNG's
67.20 + * Assert, as TestNG is not compiled with target 1.6 yet).
67.21 + */
67.22 + @HtmlFragment(
67.23 + "<h1>Put this snippet on the HTML page</h1>\n"
67.24 + )
67.25 + @BrwsrTest
67.26 + public void runThisTestInABrowser() {
67.27 + }
67.28 +
67.29 + @Factory
67.30 + public static Object[] create() {
67.31 + return VMTest.create(IntegrationTest.class);
67.32 + }
67.33 +
67.34 +}
68.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
68.2 +++ b/ko/archetype/src/main/resources/archetype-resources/src/test/java/JsInteractionTest.java Wed Apr 30 15:04:10 2014 +0200
68.3 @@ -0,0 +1,103 @@
68.4 +package ${package};
68.5 +
68.6 +import java.io.Closeable;
68.7 +import java.io.Reader;
68.8 +import java.net.URL;
68.9 +import java.util.ArrayList;
68.10 +import java.util.List;
68.11 +import javax.script.Invocable;
68.12 +import javax.script.ScriptEngine;
68.13 +import javax.script.ScriptEngineManager;
68.14 +import javax.script.ScriptException;
68.15 +import org.apidesign.html.boot.spi.Fn;
68.16 +import static org.testng.Assert.assertEquals;
68.17 +import org.testng.annotations.AfterMethod;
68.18 +import org.testng.annotations.BeforeMethod;
68.19 +import org.testng.annotations.Test;
68.20 +
68.21 +/** Tests for behavior of @JavaScriptBody methods. Set your JavaScript
68.22 + * environment up (for example define <code>alert</code> or use some
68.23 + * emulation library like <em>env.js</em>), register script presenter
68.24 + * and then you can call methods that deal with JavaScript in your tests.
68.25 + */
68.26 +public class JsInteractionTest {
68.27 + private Closeable jsEngine;
68.28 + @BeforeMethod public void initializeJSEngine() throws Exception {
68.29 + jsEngine = Fn.activate(new ScriptPresenter());
68.30 + }
68.31 +
68.32 + @AfterMethod public void shutdownJSEngine() throws Exception {
68.33 + jsEngine.close();
68.34 + }
68.35 +
68.36 + @Test public void testCallbackFromJavaScript() throws Exception {
68.37 + class R implements Runnable {
68.38 + int called;
68.39 +
68.40 + @Override
68.41 + public void run() {
68.42 + called++;
68.43 + }
68.44 + }
68.45 + R callback = new R();
68.46 +
68.47 + DataModel.confirmByUser("Hello", callback);
68.48 +
68.49 + assertEquals(callback.called, 1, "One immediate callback");
68.50 + }
68.51 +
68.52 + private static class ScriptPresenter implements Fn.Presenter {
68.53 + private final ScriptEngine eng;
68.54 +
68.55 + public ScriptPresenter() throws ScriptException {
68.56 + eng = new ScriptEngineManager().getEngineByName("javascript");
68.57 + eng.eval("function alert(msg) { Packages.java.lang.System.out.println(msg); };");
68.58 + }
68.59 +
68.60 + @Override
68.61 + public Fn defineFn(String code, String... names) {
68.62 + StringBuilder sb = new StringBuilder();
68.63 + sb.append("(function() {");
68.64 + sb.append(" return function(");
68.65 + String sep = "";
68.66 + for (String n : names) {
68.67 + sb.append(sep).append(n);
68.68 + sep = ",";
68.69 + }
68.70 + sb.append(") {\n");
68.71 + sb.append(code);
68.72 + sb.append("};");
68.73 + sb.append("})()");
68.74 +
68.75 + final Object fn;
68.76 + try {
68.77 + fn = eng.eval(sb.toString());
68.78 + } catch (ScriptException ex) {
68.79 + throw new IllegalStateException(ex);
68.80 + }
68.81 + return new Fn(this) {
68.82 + @Override
68.83 + public Object invoke(Object thiz, Object... args) throws Exception {
68.84 + List<Object> all = new ArrayList<Object>(args.length + 1);
68.85 + all.add(thiz == null ? fn : thiz);
68.86 + for (int i = 0; i < args.length; i++) {
68.87 + all.add(args[i]);
68.88 + }
68.89 + Object ret = ((Invocable)eng).invokeMethod(fn, "call", all.toArray()); // NOI18N
68.90 + return fn.equals(ret) ? null : thiz;
68.91 + }
68.92 + };
68.93 + }
68.94 +
68.95 + @Override
68.96 + public void displayPage(URL page, Runnable onPageLoad) {
68.97 + // not really displaying anything
68.98 + onPageLoad.run();
68.99 + }
68.100 +
68.101 + @Override
68.102 + public void loadScript(Reader code) throws Exception {
68.103 + eng.eval(code);
68.104 + }
68.105 + }
68.106 +}
69.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
69.2 +++ b/ko/bck2brwsr/pom.xml Wed Apr 30 15:04:10 2014 +0200
69.3 @@ -0,0 +1,135 @@
69.4 +<?xml version="1.0"?>
69.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
69.6 + <modelVersion>4.0.0</modelVersion>
69.7 + <parent>
69.8 + <groupId>org.apidesign.bck2brwsr</groupId>
69.9 + <artifactId>ko</artifactId>
69.10 + <version>0.9-SNAPSHOT</version>
69.11 + </parent>
69.12 + <groupId>org.apidesign.bck2brwsr</groupId>
69.13 + <artifactId>ko-bck2brwsr</artifactId>
69.14 + <version>0.9-SNAPSHOT</version>
69.15 + <name>Knockout.b2b</name>
69.16 + <url>http://maven.apache.org</url>
69.17 + <build>
69.18 + <plugins>
69.19 + <plugin>
69.20 + <groupId>org.apache.maven.plugins</groupId>
69.21 + <artifactId>maven-compiler-plugin</artifactId>
69.22 + <version>2.3.2</version>
69.23 + <configuration>
69.24 + <source>1.7</source>
69.25 + <target>1.7</target>
69.26 + </configuration>
69.27 + </plugin>
69.28 + <plugin>
69.29 + <groupId>org.apache.maven.plugins</groupId>
69.30 + <artifactId>maven-javadoc-plugin</artifactId>
69.31 + <configuration>
69.32 + <skip>false</skip>
69.33 + </configuration>
69.34 + </plugin>
69.35 + </plugins>
69.36 + </build>
69.37 + <dependencies>
69.38 + <dependency>
69.39 + <groupId>org.testng</groupId>
69.40 + <artifactId>testng</artifactId>
69.41 + <scope>test</scope>
69.42 + <exclusions>
69.43 + <exclusion>
69.44 + <artifactId>junit</artifactId>
69.45 + <groupId>junit</groupId>
69.46 + </exclusion>
69.47 + </exclusions>
69.48 + </dependency>
69.49 + <dependency>
69.50 + <groupId>org.netbeans.api</groupId>
69.51 + <artifactId>org-openide-util-lookup</artifactId>
69.52 + <scope>provided</scope>
69.53 + </dependency>
69.54 + <dependency>
69.55 + <groupId>org.apidesign.bck2brwsr</groupId>
69.56 + <artifactId>emul</artifactId>
69.57 + <version>${project.version}</version>
69.58 + <classifier>rt</classifier>
69.59 + <type>jar</type>
69.60 + <scope>compile</scope>
69.61 + </dependency>
69.62 + <dependency>
69.63 + <groupId>org.apidesign.bck2brwsr</groupId>
69.64 + <artifactId>vm4brwsr</artifactId>
69.65 + <version>${project.version}</version>
69.66 + <type>jar</type>
69.67 + <scope>test</scope>
69.68 + <exclusions>
69.69 + <exclusion>
69.70 + <artifactId>json</artifactId>
69.71 + <groupId>org.json</groupId>
69.72 + </exclusion>
69.73 + </exclusions>
69.74 + </dependency>
69.75 + <dependency>
69.76 + <groupId>org.apidesign.bck2brwsr</groupId>
69.77 + <artifactId>vmtest</artifactId>
69.78 + <version>${project.version}</version>
69.79 + <scope>test</scope>
69.80 + </dependency>
69.81 + <dependency>
69.82 + <groupId>org.apidesign.bck2brwsr</groupId>
69.83 + <artifactId>launcher.http</artifactId>
69.84 + <version>${project.version}</version>
69.85 + <scope>test</scope>
69.86 + <exclusions>
69.87 + <exclusion>
69.88 + <artifactId>asm</artifactId>
69.89 + <groupId>org.ow2.asm</groupId>
69.90 + </exclusion>
69.91 + </exclusions>
69.92 + </dependency>
69.93 + <dependency>
69.94 + <groupId>org.netbeans.html</groupId>
69.95 + <artifactId>net.java.html.json</artifactId>
69.96 + <version>${net.java.html.version}</version>
69.97 + </dependency>
69.98 + <dependency>
69.99 + <groupId>org.netbeans.html</groupId>
69.100 + <artifactId>net.java.html.json.tck</artifactId>
69.101 + <version>${net.java.html.version}</version>
69.102 + <scope>test</scope>
69.103 + </dependency>
69.104 + <dependency>
69.105 + <groupId>org.apidesign.bck2brwsr</groupId>
69.106 + <artifactId>core</artifactId>
69.107 + <version>${project.version}</version>
69.108 + <type>jar</type>
69.109 + </dependency>
69.110 + <dependency>
69.111 + <groupId>org.netbeans.html</groupId>
69.112 + <artifactId>net.java.html.boot</artifactId>
69.113 + <version>${net.java.html.version}</version>
69.114 + <type>jar</type>
69.115 + <exclusions>
69.116 + <exclusion>
69.117 + <artifactId>asm</artifactId>
69.118 + <groupId>org.ow2.asm</groupId>
69.119 + </exclusion>
69.120 + </exclusions>
69.121 + </dependency>
69.122 + <dependency>
69.123 + <groupId>org.netbeans.html</groupId>
69.124 + <artifactId>ko4j</artifactId>
69.125 + <version>${net.java.html.version}</version>
69.126 + <exclusions>
69.127 + <exclusion>
69.128 + <artifactId>json</artifactId>
69.129 + <groupId>org.json</groupId>
69.130 + </exclusion>
69.131 + <exclusion>
69.132 + <artifactId>org.json-osgi</artifactId>
69.133 + <groupId>de.twentyeleven.skysail</groupId>
69.134 + </exclusion>
69.135 + </exclusions>
69.136 + </dependency>
69.137 + </dependencies>
69.138 +</project>
70.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
70.2 +++ b/ko/bck2brwsr/src/test/java/org/apidesign/bck2brwsr/ko2brwsr/Bck2BrwsrJavaScriptBodyTest.java Wed Apr 30 15:04:10 2014 +0200
70.3 @@ -0,0 +1,34 @@
70.4 +/**
70.5 + * Back 2 Browser Bytecode Translator
70.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
70.7 + *
70.8 + * This program is free software: you can redistribute it and/or modify
70.9 + * it under the terms of the GNU General Public License as published by
70.10 + * the Free Software Foundation, version 2 of the License.
70.11 + *
70.12 + * This program is distributed in the hope that it will be useful,
70.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
70.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
70.15 + * GNU General Public License for more details.
70.16 + *
70.17 + * You should have received a copy of the GNU General Public License
70.18 + * along with this program. Look for COPYING file in the top folder.
70.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
70.20 + */
70.21 +package org.apidesign.bck2brwsr.ko2brwsr;
70.22 +
70.23 +import org.apidesign.bck2brwsr.vmtest.VMTest;
70.24 +import org.apidesign.html.json.tck.JavaScriptTCK;
70.25 +import org.apidesign.html.json.tck.KOTest;
70.26 +import org.testng.annotations.Factory;
70.27 +
70.28 +/**
70.29 + *
70.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
70.31 + */
70.32 +public class Bck2BrwsrJavaScriptBodyTest extends JavaScriptTCK {
70.33 + @Factory public static Object[] tests() {
70.34 + return VMTest.newTests().withClasses(testClasses())
70.35 + .withTestAnnotation(KOTest.class).build();
70.36 + }
70.37 +}
71.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
71.2 +++ b/ko/bck2brwsr/src/test/java/org/apidesign/bck2brwsr/ko2brwsr/Bck2BrwsrKnockoutTest.java Wed Apr 30 15:04:10 2014 +0200
71.3 @@ -0,0 +1,122 @@
71.4 +/**
71.5 + * Back 2 Browser Bytecode Translator
71.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
71.7 + *
71.8 + * This program is free software: you can redistribute it and/or modify
71.9 + * it under the terms of the GNU General Public License as published by
71.10 + * the Free Software Foundation, version 2 of the License.
71.11 + *
71.12 + * This program is distributed in the hope that it will be useful,
71.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
71.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
71.15 + * GNU General Public License for more details.
71.16 + *
71.17 + * You should have received a copy of the GNU General Public License
71.18 + * along with this program. Look for COPYING file in the top folder.
71.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
71.20 + */
71.21 +package org.apidesign.bck2brwsr.ko2brwsr;
71.22 +
71.23 +import java.io.IOException;
71.24 +import java.net.URI;
71.25 +import java.net.URISyntaxException;
71.26 +import java.net.URL;
71.27 +import java.util.Map;
71.28 +import net.java.html.BrwsrCtx;
71.29 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
71.30 +import org.apidesign.bck2brwsr.vmtest.VMTest;
71.31 +import org.apidesign.html.context.spi.Contexts;
71.32 +import org.apidesign.html.json.spi.Technology;
71.33 +import org.apidesign.html.json.spi.Transfer;
71.34 +import org.apidesign.html.json.spi.WSTransfer;
71.35 +import org.apidesign.html.json.tck.KOTest;
71.36 +import org.apidesign.html.json.tck.KnockoutTCK;
71.37 +import org.netbeans.html.ko4j.KO4J;
71.38 +import org.openide.util.lookup.ServiceProvider;
71.39 +import org.testng.annotations.Factory;
71.40 +
71.41 +/**
71.42 + *
71.43 + * @author Jaroslav Tulach <jtulach@netbeans.org>
71.44 + */
71.45 +@ServiceProvider(service = KnockoutTCK.class)
71.46 +public final class Bck2BrwsrKnockoutTest extends KnockoutTCK {
71.47 + @Factory public static Object[] create() {
71.48 + return VMTest.newTests().
71.49 + withClasses(testClasses()).
71.50 + withLaunchers("bck2brwsr").
71.51 + withTestAnnotation(KOTest.class).
71.52 + build();
71.53 + }
71.54 +
71.55 + @Override
71.56 + public BrwsrCtx createContext() {
71.57 + KO4J ko = new KO4J(null);
71.58 + return Contexts.newBuilder().
71.59 + register(Transfer.class, ko.transfer(), 9).
71.60 + register(WSTransfer.class, ko.websockets(), 9).
71.61 + register(Technology.class, ko.knockout(), 9).build();
71.62 + }
71.63 +
71.64 +
71.65 +
71.66 + @Override
71.67 + public Object createJSON(Map<String, Object> values) {
71.68 + Object json = createJSON();
71.69 +
71.70 + for (Map.Entry<String, Object> entry : values.entrySet()) {
71.71 + putValue(json, entry.getKey(), entry.getValue());
71.72 + }
71.73 + return json;
71.74 + }
71.75 +
71.76 + @JavaScriptBody(args = {}, body = "return new Object();")
71.77 + private static native Object createJSON();
71.78 +
71.79 + @JavaScriptBody(args = { "json", "key", "value" }, body = "json[key] = value;")
71.80 + private static native void putValue(Object json, String key, Object value);
71.81 +
71.82 + @Override
71.83 + public Object executeScript(String script, Object[] arguments) {
71.84 + return execScript(script, arguments);
71.85 + }
71.86 +
71.87 + @JavaScriptBody(args = { "s", "args" }, body =
71.88 + "var f = new Function(s); return f.apply(null, args);"
71.89 + )
71.90 + private static native Object execScript(String s, Object[] arguments);
71.91 +
71.92 + @JavaScriptBody(args = { }, body =
71.93 + "var h;"
71.94 + + "if (!!window && !!window.location && !!window.location.href)\n"
71.95 + + " h = window.location.href;\n"
71.96 + + "else "
71.97 + + " h = null;"
71.98 + + "return h;\n"
71.99 + )
71.100 + private static native String findBaseURL();
71.101 +
71.102 + @Override
71.103 + public URI prepareURL(String content, String mimeType, String[] parameters) {
71.104 + try {
71.105 + final URL baseURL = new URL(findBaseURL());
71.106 + StringBuilder sb = new StringBuilder();
71.107 + sb.append("/dynamic?mimeType=").append(mimeType);
71.108 + for (int i = 0; i < parameters.length; i++) {
71.109 + sb.append("¶m" + i).append("=").append(parameters[i]);
71.110 + }
71.111 + String mangle = content.replace("\n", "%0a")
71.112 + .replace("\"", "\\\"").replace(" ", "%20");
71.113 + sb.append("&content=").append(mangle);
71.114 +
71.115 + URL query = new URL(baseURL, sb.toString());
71.116 + String uri = (String) query.getContent(new Class[] { String.class });
71.117 + URI connectTo = new URI(uri.trim());
71.118 + return connectTo;
71.119 + } catch (IOException ex) {
71.120 + throw new IllegalStateException(ex);
71.121 + } catch (URISyntaxException ex) {
71.122 + throw new IllegalStateException(ex);
71.123 + }
71.124 + }
71.125 +}
72.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
72.2 +++ b/ko/fx/pom.xml Wed Apr 30 15:04:10 2014 +0200
72.3 @@ -0,0 +1,119 @@
72.4 +<?xml version="1.0"?>
72.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
72.6 + <modelVersion>4.0.0</modelVersion>
72.7 + <parent>
72.8 + <groupId>org.apidesign.bck2brwsr</groupId>
72.9 + <artifactId>ko</artifactId>
72.10 + <version>0.9-SNAPSHOT</version>
72.11 + </parent>
72.12 + <groupId>org.apidesign.bck2brwsr</groupId>
72.13 + <artifactId>ko-fx</artifactId>
72.14 + <version>0.9-SNAPSHOT</version>
72.15 + <name>Knockout.fx in Brwsr</name>
72.16 + <url>http://maven.apache.org</url>
72.17 + <properties>
72.18 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
72.19 + </properties>
72.20 + <build>
72.21 + <plugins>
72.22 + <plugin>
72.23 + <groupId>org.apache.maven.plugins</groupId>
72.24 + <artifactId>maven-javadoc-plugin</artifactId>
72.25 + <configuration>
72.26 + <skip>false</skip>
72.27 + </configuration>
72.28 + </plugin>
72.29 + </plugins>
72.30 + </build>
72.31 + <dependencies>
72.32 + <dependency>
72.33 + <groupId>com.oracle</groupId>
72.34 + <artifactId>javafx</artifactId>
72.35 + <version>2.2</version>
72.36 + <scope>system</scope>
72.37 + <systemPath>${jfxrt.jar}</systemPath>
72.38 + </dependency>
72.39 + <dependency>
72.40 + <groupId>org.json</groupId>
72.41 + <artifactId>json</artifactId>
72.42 + <version>20090211</version>
72.43 + <type>jar</type>
72.44 + </dependency>
72.45 + <dependency>
72.46 + <groupId>org.netbeans.html</groupId>
72.47 + <artifactId>net.java.html.json</artifactId>
72.48 + <version>${net.java.html.version}</version>
72.49 + </dependency>
72.50 + <dependency>
72.51 + <groupId>org.testng</groupId>
72.52 + <artifactId>testng</artifactId>
72.53 + <scope>test</scope>
72.54 + </dependency>
72.55 + <dependency>
72.56 + <groupId>org.netbeans.html</groupId>
72.57 + <artifactId>net.java.html.json.tck</artifactId>
72.58 + <version>${net.java.html.version}</version>
72.59 + <scope>test</scope>
72.60 + </dependency>
72.61 + <dependency>
72.62 + <groupId>org.netbeans.api</groupId>
72.63 + <artifactId>org-openide-util</artifactId>
72.64 + <scope>provided</scope>
72.65 + </dependency>
72.66 + <dependency>
72.67 + <groupId>org.apidesign.bck2brwsr</groupId>
72.68 + <artifactId>launcher.fx</artifactId>
72.69 + <version>${project.version}</version>
72.70 + <scope>test</scope>
72.71 + </dependency>
72.72 + <dependency>
72.73 + <groupId>org.netbeans.html</groupId>
72.74 + <artifactId>net.java.html.boot</artifactId>
72.75 + <version>${net.java.html.version}</version>
72.76 + <type>jar</type>
72.77 + </dependency>
72.78 + <dependency>
72.79 + <groupId>org.netbeans.html</groupId>
72.80 + <artifactId>ko4j</artifactId>
72.81 + <version>${net.java.html.version}</version>
72.82 + <type>jar</type>
72.83 + </dependency>
72.84 + <dependency>
72.85 + <groupId>org.apidesign.bck2brwsr</groupId>
72.86 + <artifactId>vmtest</artifactId>
72.87 + <version>${project.version}</version>
72.88 + <scope>test</scope>
72.89 + <type>jar</type>
72.90 + </dependency>
72.91 + <dependency>
72.92 + <groupId>org.netbeans.html</groupId>
72.93 + <artifactId>ko-ws-tyrus</artifactId>
72.94 + <version>${net.java.html.version}</version>
72.95 + <scope>test</scope>
72.96 + </dependency>
72.97 + </dependencies>
72.98 + <profiles>
72.99 + <profile>
72.100 + <id>jdk8</id>
72.101 + <activation>
72.102 + <file>
72.103 + <exists>${java.home}/lib/ext/jfxrt.jar</exists>
72.104 + </file>
72.105 + </activation>
72.106 + <properties>
72.107 + <jfxrt.jar>${java.home}/lib/ext/jfxrt.jar</jfxrt.jar>
72.108 + </properties>
72.109 + </profile>
72.110 + <profile>
72.111 + <id>jdk7</id>
72.112 + <activation>
72.113 + <file>
72.114 + <exists>${java.home}/lib/jfxrt.jar</exists>
72.115 + </file>
72.116 + </activation>
72.117 + <properties>
72.118 + <jfxrt.jar>${java.home}/lib/jfxrt.jar</jfxrt.jar>
72.119 + </properties>
72.120 + </profile>
72.121 + </profiles>
72.122 +</project>
73.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
73.2 +++ b/ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/JavaScriptBodyFXBrwsrTest.java Wed Apr 30 15:04:10 2014 +0200
73.3 @@ -0,0 +1,36 @@
73.4 +/**
73.5 + * Back 2 Browser Bytecode Translator
73.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
73.7 + *
73.8 + * This program is free software: you can redistribute it and/or modify
73.9 + * it under the terms of the GNU General Public License as published by
73.10 + * the Free Software Foundation, version 2 of the License.
73.11 + *
73.12 + * This program is distributed in the hope that it will be useful,
73.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
73.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
73.15 + * GNU General Public License for more details.
73.16 + *
73.17 + * You should have received a copy of the GNU General Public License
73.18 + * along with this program. Look for COPYING file in the top folder.
73.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
73.20 + */
73.21 +package org.apidesign.bck2brwsr.kofx;
73.22 +
73.23 +import org.apidesign.bck2brwsr.vmtest.VMTest;
73.24 +import org.apidesign.html.json.tck.JavaScriptTCK;
73.25 +import org.apidesign.html.json.tck.KOTest;
73.26 +import org.testng.annotations.Factory;
73.27 +
73.28 +/**
73.29 + *
73.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
73.31 + */
73.32 +public class JavaScriptBodyFXBrwsrTest extends JavaScriptTCK {
73.33 + @Factory public static Object[] create() {
73.34 + return VMTest.newTests().
73.35 + withLaunchers("fxbrwsr").
73.36 + withClasses(testClasses()).
73.37 + withTestAnnotation(KOTest.class).build();
73.38 + }
73.39 +}
74.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
74.2 +++ b/ko/fx/src/test/java/org/apidesign/bck2brwsr/kofx/KnockoutFXTest.java Wed Apr 30 15:04:10 2014 +0200
74.3 @@ -0,0 +1,140 @@
74.4 +/**
74.5 + * Back 2 Browser Bytecode Translator
74.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
74.7 + *
74.8 + * This program is free software: you can redistribute it and/or modify
74.9 + * it under the terms of the GNU General Public License as published by
74.10 + * the Free Software Foundation, version 2 of the License.
74.11 + *
74.12 + * This program is distributed in the hope that it will be useful,
74.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
74.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74.15 + * GNU General Public License for more details.
74.16 + *
74.17 + * You should have received a copy of the GNU General Public License
74.18 + * along with this program. Look for COPYING file in the top folder.
74.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
74.20 + */
74.21 +package org.apidesign.bck2brwsr.kofx;
74.22 +
74.23 +import java.io.BufferedReader;
74.24 +import java.io.IOException;
74.25 +import java.io.InputStreamReader;
74.26 +import java.net.URI;
74.27 +import java.net.URISyntaxException;
74.28 +import java.net.URL;
74.29 +import java.net.URLConnection;
74.30 +import java.util.Map;
74.31 +import java.util.concurrent.Executor;
74.32 +import net.java.html.BrwsrCtx;
74.33 +import net.java.html.js.JavaScriptBody;
74.34 +import org.apidesign.bck2brwsr.vmtest.VMTest;
74.35 +import org.apidesign.html.boot.spi.Fn;
74.36 +import org.apidesign.html.context.spi.Contexts;
74.37 +import org.apidesign.html.json.spi.Technology;
74.38 +import org.apidesign.html.json.spi.Transfer;
74.39 +import org.apidesign.html.json.spi.WSTransfer;
74.40 +import org.apidesign.html.json.tck.KOTest;
74.41 +import org.apidesign.html.json.tck.KnockoutTCK;
74.42 +import org.json.JSONException;
74.43 +import org.json.JSONObject;
74.44 +import org.netbeans.html.ko4j.KO4J;
74.45 +import org.netbeans.html.wstyrus.TyrusContext;
74.46 +import org.openide.util.lookup.ServiceProvider;
74.47 +import org.testng.annotations.Factory;
74.48 +
74.49 +/**
74.50 + *
74.51 + * @author Jaroslav Tulach <jtulach@netbeans.org>
74.52 + */
74.53 +@ServiceProvider(service = KnockoutTCK.class)
74.54 +public final class KnockoutFXTest extends KnockoutTCK {
74.55 + public KnockoutFXTest() {
74.56 + }
74.57 +
74.58 + @Factory public static Object[] compatibilityTests() {
74.59 + return VMTest.newTests().
74.60 + withClasses(testClasses()).
74.61 + withTestAnnotation(KOTest.class).
74.62 + withLaunchers("fxbrwsr").build();
74.63 + }
74.64 +
74.65 + @Override
74.66 + public BrwsrCtx createContext() {
74.67 + final Fn.Presenter p = Fn.activePresenter();
74.68 + KO4J ko = new KO4J(p);
74.69 + TyrusContext tc = new TyrusContext();
74.70 + Contexts.Builder b = Contexts.newBuilder().
74.71 + register(Technology.class, ko.knockout(), 10).
74.72 + register(Transfer.class, ko.transfer(), 10);
74.73 + if (p instanceof Executor) {
74.74 + b.register(Executor.class, (Executor)p, 10);
74.75 + }
74.76 + try {
74.77 + Class.forName("java.util.function.Function");
74.78 + // prefer WebView's WebSockets on JDK8
74.79 + b.register(WSTransfer.class, ko.websockets(), 10);
74.80 + } catch (ClassNotFoundException ex) {
74.81 + // ok, JDK7 needs tyrus
74.82 + b.register(WSTransfer.class, tc, 20);
74.83 + b.register(Transfer.class, tc, 5);
74.84 + }
74.85 + return b.build();
74.86 + }
74.87 +
74.88 + @Override
74.89 + public Object createJSON(Map<String, Object> values) {
74.90 + Object json = createJSON();
74.91 + for (Map.Entry<String, Object> entry : values.entrySet()) {
74.92 + setProperty(json, entry.getKey(), entry.getValue());
74.93 + }
74.94 + return json;
74.95 + }
74.96 +
74.97 + @JavaScriptBody(args = {}, body = "return new Object();")
74.98 + private static native Object createJSON();
74.99 + @JavaScriptBody(args = { "json", "key", "value" }, body = "json[key] = value;")
74.100 + private static native void setProperty(Object json, String key, Object value);
74.101 +
74.102 + @Override
74.103 + @JavaScriptBody(args = { "s", "args" }, body = ""
74.104 + + "var f = new Function(s); "
74.105 + + "return f.apply(null, args);"
74.106 + )
74.107 + public native Object executeScript(String script, Object[] arguments);
74.108 +
74.109 + @JavaScriptBody(args = { }, body =
74.110 + "var h;"
74.111 + + "if (!!window && !!window.location && !!window.location.href)\n"
74.112 + + " h = window.location.href;\n"
74.113 + + "else "
74.114 + + " h = null;"
74.115 + + "return h;\n"
74.116 + )
74.117 + private static native String findBaseURL();
74.118 +
74.119 + @Override
74.120 + public URI prepareURL(String content, String mimeType, String[] parameters) {
74.121 + try {
74.122 + final URL baseURL = new URL(findBaseURL());
74.123 + StringBuilder sb = new StringBuilder();
74.124 + sb.append("/dynamic?mimeType=").append(mimeType);
74.125 + for (int i = 0; i < parameters.length; i++) {
74.126 + sb.append("¶m" + i).append("=").append(parameters[i]);
74.127 + }
74.128 + String mangle = content.replace("\n", "%0a")
74.129 + .replace("\"", "\\\"").replace(" ", "%20");
74.130 + sb.append("&content=").append(mangle);
74.131 +
74.132 + URL query = new URL(baseURL, sb.toString());
74.133 + URLConnection c = query.openConnection();
74.134 + BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
74.135 + URI connectTo = new URI(br.readLine());
74.136 + return connectTo;
74.137 + } catch (IOException ex) {
74.138 + throw new IllegalStateException(ex);
74.139 + } catch (URISyntaxException ex) {
74.140 + throw new IllegalStateException(ex);
74.141 + }
74.142 + }
74.143 +}
75.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
75.2 +++ b/ko/pom.xml Wed Apr 30 15:04:10 2014 +0200
75.3 @@ -0,0 +1,20 @@
75.4 +<?xml version="1.0" encoding="UTF-8"?>
75.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
75.6 + <modelVersion>4.0.0</modelVersion>
75.7 + <groupId>org.apidesign.bck2brwsr</groupId>
75.8 + <artifactId>ko</artifactId>
75.9 + <version>0.9-SNAPSHOT</version>
75.10 + <packaging>pom</packaging>
75.11 + <name>Bck2Brwsr Knockout Support</name>
75.12 + <parent>
75.13 + <groupId>org.apidesign</groupId>
75.14 + <artifactId>bck2brwsr</artifactId>
75.15 + <version>0.9-SNAPSHOT</version>
75.16 + </parent>
75.17 + <modules>
75.18 + <module>archetype</module>
75.19 + <module>archetype-test</module>
75.20 + <module>bck2brwsr</module>
75.21 + <module>fx</module>
75.22 + </modules>
75.23 +</project>
76.1 --- a/launcher/api/pom.xml Tue Apr 29 15:25:58 2014 +0200
76.2 +++ b/launcher/api/pom.xml Wed Apr 30 15:04:10 2014 +0200
76.3 @@ -4,11 +4,11 @@
76.4 <parent>
76.5 <groupId>org.apidesign.bck2brwsr</groupId>
76.6 <artifactId>launcher-pom</artifactId>
76.7 - <version>0.8-SNAPSHOT</version>
76.8 + <version>0.9-SNAPSHOT</version>
76.9 </parent>
76.10 <groupId>org.apidesign.bck2brwsr</groupId>
76.11 <artifactId>launcher</artifactId>
76.12 - <version>0.8-SNAPSHOT</version>
76.13 + <version>0.9-SNAPSHOT</version>
76.14 <name>Launcher API</name>
76.15 <url>http://maven.apache.org</url>
76.16 <properties>
77.1 --- a/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java Tue Apr 29 15:25:58 2014 +0200
77.2 +++ b/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/InvocationContext.java Wed Apr 30 15:04:10 2014 +0200
77.3 @@ -19,6 +19,7 @@
77.4
77.5 import java.io.IOException;
77.6 import java.io.InputStream;
77.7 +import java.net.URI;
77.8 import java.util.ArrayList;
77.9 import java.util.List;
77.10 import java.util.concurrent.CountDownLatch;
77.11 @@ -95,7 +96,6 @@
77.12 wait.countDown();
77.13 }
77.14
77.15 -
77.16 static final class Resource {
77.17 final InputStream httpContent;
77.18 final String httpType;
78.1 --- a/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Tue Apr 29 15:25:58 2014 +0200
78.2 +++ b/launcher/api/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Wed Apr 30 15:04:10 2014 +0200
78.3 @@ -135,14 +135,34 @@
78.4 * The <code>startpage</code> should be relative location inside the root
78.5 * directory. Opens a browser with URL showing the start page.
78.6 *
78.7 + * @param brwsr type of the browser to use
78.8 + * @param directory the root directory on disk
78.9 + * @param classes additional classloader with access to classes or <code>null</code>
78.10 + * @param startpage relative path from the root to the page
78.11 + * @return instance of server that can be closed
78.12 + * @exception IOException if something goes wrong.
78.13 + * @since 0.8
78.14 + */
78.15 + public static Closeable showDir(String brwsr, File directory, ClassLoader classes, String startpage) throws IOException {
78.16 + Launcher l = createBrowser(brwsr);
78.17 + if (classes != null) {
78.18 + l.addClassLoader(classes);
78.19 + }
78.20 + l.showDirectory(directory, startpage, classes != null);
78.21 + return (Closeable) l;
78.22 + }
78.23 +
78.24 + /** Starts an HTTP server which provides access to certain directory.
78.25 + * The <code>startpage</code> should be relative location inside the root
78.26 + * directory. Opens a browser with URL showing the start page.
78.27 + *
78.28 * @param directory the root directory on disk
78.29 * @param startpage relative path from the root to the page
78.30 + * @return instance of server that can be closed
78.31 * @exception IOException if something goes wrong.
78.32 */
78.33 public static Closeable showDir(File directory, String startpage) throws IOException {
78.34 - Launcher l = createBrowser(null);
78.35 - l.showDirectory(directory, startpage);
78.36 - return (Closeable) l;
78.37 + return showDir(null, directory, null, startpage);
78.38 }
78.39
78.40 abstract InvocationContext runMethod(InvocationContext c) throws IOException;
78.41 @@ -152,7 +172,7 @@
78.42 return Launcher.class.getClassLoader().loadClass(cn);
78.43 }
78.44
78.45 - void showDirectory(File directory, String startpage) throws IOException {
78.46 + void showDirectory(File directory, String startpage, boolean addClasses) throws IOException {
78.47 throw new UnsupportedOperationException();
78.48 }
78.49
79.1 --- a/launcher/fx/pom.xml Tue Apr 29 15:25:58 2014 +0200
79.2 +++ b/launcher/fx/pom.xml Wed Apr 30 15:04:10 2014 +0200
79.3 @@ -4,11 +4,11 @@
79.4 <parent>
79.5 <groupId>org.apidesign.bck2brwsr</groupId>
79.6 <artifactId>launcher-pom</artifactId>
79.7 - <version>0.8-SNAPSHOT</version>
79.8 + <version>0.9-SNAPSHOT</version>
79.9 </parent>
79.10 <groupId>org.apidesign.bck2brwsr</groupId>
79.11 <artifactId>launcher.fx</artifactId>
79.12 - <version>0.8-SNAPSHOT</version>
79.13 + <version>0.9-SNAPSHOT</version>
79.14 <name>FXBrwsr Launcher</name>
79.15 <url>http://maven.apache.org</url>
79.16 <build>
79.17 @@ -18,8 +18,8 @@
79.18 <artifactId>maven-compiler-plugin</artifactId>
79.19 <version>2.3.2</version>
79.20 <configuration>
79.21 - <source>1.7</source>
79.22 - <target>1.7</target>
79.23 + <source>1.6</source>
79.24 + <target>1.6</target>
79.25 </configuration>
79.26 </plugin>
79.27 <plugin>
79.28 @@ -58,5 +58,44 @@
79.29 <artifactId>testng</artifactId>
79.30 <scope>test</scope>
79.31 </dependency>
79.32 + <!--
79.33 + <dependency>
79.34 + <groupId>org.netbeans.modules</groupId>
79.35 + <artifactId>org-netbeans-bootstrap</artifactId>
79.36 + <version>RELEASE73</version>
79.37 + </dependency>
79.38 + -->
79.39 + <dependency>
79.40 + <groupId>${project.groupId}</groupId>
79.41 + <artifactId>core</artifactId>
79.42 + <version>${project.version}</version>
79.43 + <scope>compile</scope>
79.44 + </dependency>
79.45 + <dependency>
79.46 + <groupId>org.ow2.asm</groupId>
79.47 + <artifactId>asm</artifactId>
79.48 + <version>4.1</version>
79.49 + </dependency>
79.50 + <dependency>
79.51 + <groupId>org.netbeans.html</groupId>
79.52 + <artifactId>net.java.html.boot</artifactId>
79.53 + <version>${net.java.html.version}</version>
79.54 + </dependency>
79.55 + <dependency>
79.56 + <groupId>org.glassfish.grizzly</groupId>
79.57 + <artifactId>grizzly-websockets-server</artifactId>
79.58 + <version>${grizzly.version}</version>
79.59 + <type>jar</type>
79.60 + </dependency>
79.61 + <dependency>
79.62 + <groupId>org.glassfish.grizzly</groupId>
79.63 + <artifactId>grizzly-http-servlet</artifactId>
79.64 + <version>${grizzly.version}</version>
79.65 + </dependency>
79.66 + <dependency>
79.67 + <groupId>javax.servlet</groupId>
79.68 + <artifactId>javax.servlet-api</artifactId>
79.69 + <version>3.1.0</version>
79.70 + </dependency>
79.71 </dependencies>
79.72 </project>
80.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java Tue Apr 29 15:25:58 2014 +0200
80.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/BaseHTTPLauncher.java Wed Apr 30 15:04:10 2014 +0200
80.3 @@ -17,6 +17,8 @@
80.4 */
80.5 package org.apidesign.bck2brwsr.launcher;
80.6
80.7 +import java.io.ByteArrayInputStream;
80.8 +import java.io.ByteArrayOutputStream;
80.9 import java.io.Closeable;
80.10 import java.io.File;
80.11 import java.io.IOException;
80.12 @@ -52,7 +54,13 @@
80.13 import org.glassfish.grizzly.http.server.Request;
80.14 import org.glassfish.grizzly.http.server.Response;
80.15 import org.glassfish.grizzly.http.server.ServerConfiguration;
80.16 +import org.glassfish.grizzly.http.server.StaticHttpHandler;
80.17 import org.glassfish.grizzly.http.util.HttpStatus;
80.18 +import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
80.19 +import org.glassfish.grizzly.websockets.WebSocket;
80.20 +import org.glassfish.grizzly.websockets.WebSocketAddOn;
80.21 +import org.glassfish.grizzly.websockets.WebSocketApplication;
80.22 +import org.glassfish.grizzly.websockets.WebSocketEngine;
80.23
80.24 /**
80.25 * Lightweight server to launch Bck2Brwsr applications and tests.
80.26 @@ -62,8 +70,8 @@
80.27 abstract class BaseHTTPLauncher extends Launcher implements Closeable, Callable<HttpServer> {
80.28 static final Logger LOG = Logger.getLogger(BaseHTTPLauncher.class.getName());
80.29 private static final InvocationContext END = new InvocationContext(null, null, null);
80.30 - private final Set<ClassLoader> loaders = new LinkedHashSet<>();
80.31 - private final BlockingQueue<InvocationContext> methods = new LinkedBlockingQueue<>();
80.32 + private final Set<ClassLoader> loaders = new LinkedHashSet<ClassLoader>();
80.33 + private final BlockingQueue<InvocationContext> methods = new LinkedBlockingQueue<InvocationContext>();
80.34 private long timeOut;
80.35 private final Res resources = new Res();
80.36 private final String cmd;
80.37 @@ -105,7 +113,7 @@
80.38 if (!startpage.startsWith("/")) {
80.39 startpage = "/" + startpage;
80.40 }
80.41 - HttpServer s = initServer(".", true);
80.42 + HttpServer s = initServer(".", true, "");
80.43 int last = startpage.lastIndexOf('/');
80.44 String prefix = startpage.substring(0, last);
80.45 String simpleName = startpage.substring(last);
80.46 @@ -113,19 +121,24 @@
80.47 server = s;
80.48 try {
80.49 launchServerAndBrwsr(s, simpleName);
80.50 - } catch (URISyntaxException | InterruptedException ex) {
80.51 + } catch (Exception ex) {
80.52 throw new IOException(ex);
80.53 }
80.54 }
80.55
80.56 - void showDirectory(File dir, String startpage) throws IOException {
80.57 + void showDirectory(File dir, String startpage, boolean addClasses) throws IOException {
80.58 if (!startpage.startsWith("/")) {
80.59 startpage = "/" + startpage;
80.60 }
80.61 - HttpServer s = initServer(dir.getPath(), false);
80.62 + String prefix = "";
80.63 + int last = startpage.lastIndexOf('/');
80.64 + if (last >= 0) {
80.65 + prefix = startpage.substring(0, last);
80.66 + }
80.67 + HttpServer s = initServer(dir.getPath(), addClasses, prefix);
80.68 try {
80.69 launchServerAndBrwsr(s, startpage);
80.70 - } catch (URISyntaxException | InterruptedException ex) {
80.71 + } catch (Exception ex) {
80.72 throw new IOException(ex);
80.73 }
80.74 }
80.75 @@ -149,16 +162,16 @@
80.76 }
80.77 }
80.78
80.79 - private HttpServer initServer(String path, boolean addClasses) throws IOException {
80.80 - HttpServer s = HttpServer.createSimpleServer(path, new PortRange(8080, 65535));
80.81 -/*
80.82 + private HttpServer initServer(String path, boolean addClasses, String vmPrefix) throws IOException {
80.83 + HttpServer s = HttpServer.createSimpleServer(null, new PortRange(8080, 65535));
80.84 + /*
80.85 ThreadPoolConfig fewThreads = ThreadPoolConfig.defaultConfig().copy().
80.86 setPoolName("Fx/Bck2 Brwsr").
80.87 - setCorePoolSize(1).
80.88 + setCorePoolSize(3).
80.89 setMaxPoolSize(5);
80.90 ThreadPoolConfig oneKernel = ThreadPoolConfig.defaultConfig().copy().
80.91 setPoolName("Kernel Fx/Bck2").
80.92 - setCorePoolSize(1).
80.93 + setCorePoolSize(3).
80.94 setMaxPoolSize(3);
80.95 for (NetworkListener nl : s.getListeners()) {
80.96 nl.getTransport().setWorkerThreadPoolConfig(fewThreads);
80.97 @@ -166,36 +179,81 @@
80.98 }
80.99 */
80.100 final ServerConfiguration conf = s.getServerConfiguration();
80.101 + VMAndPages vm = new VMAndPages();
80.102 + conf.addHttpHandler(vm, "/");
80.103 + if (vmPrefix != null) {
80.104 + vm.registerVM(vmPrefix + "/bck2brwsr.js");
80.105 + }
80.106 + if (path != null) {
80.107 + vm.addDocRoot(path);
80.108 + }
80.109 if (addClasses) {
80.110 - conf.addHttpHandler(new VM(), "/bck2brwsr.js");
80.111 conf.addHttpHandler(new Classes(resources), "/classes/");
80.112 }
80.113 + final WebSocketAddOn addon = new WebSocketAddOn();
80.114 + for (NetworkListener listener : s.getListeners()) {
80.115 + listener.registerAddOn(addon);
80.116 + }
80.117 return s;
80.118 }
80.119
80.120 private void executeInBrowser() throws InterruptedException, URISyntaxException, IOException {
80.121 wait = new CountDownLatch(1);
80.122 - server = initServer(".", true);
80.123 + server = initServer(".", true, "");
80.124 final ServerConfiguration conf = server.getServerConfiguration();
80.125
80.126 class DynamicResourceHandler extends HttpHandler {
80.127 private final InvocationContext ic;
80.128 + private int resourcesCount;
80.129 + DynamicResourceHandler delegate;
80.130 public DynamicResourceHandler(InvocationContext ic) {
80.131 - if (ic == null || ic.resources.isEmpty()) {
80.132 - throw new NullPointerException();
80.133 - }
80.134 this.ic = ic;
80.135 for (Resource r : ic.resources) {
80.136 conf.addHttpHandler(this, r.httpPath);
80.137 }
80.138 }
80.139
80.140 - public void close() {
80.141 + public void close(DynamicResourceHandler del) {
80.142 conf.removeHttpHandler(this);
80.143 + delegate = del;
80.144 }
80.145
80.146 @Override
80.147 public void service(Request request, Response response) throws Exception {
80.148 + if (delegate != null) {
80.149 + delegate.service(request, response);
80.150 + return;
80.151 + }
80.152 +
80.153 + if ("/dynamic".equals(request.getRequestURI())) {
80.154 + boolean webSocket = false;
80.155 + String mimeType = request.getParameter("mimeType");
80.156 + List<String> params = new ArrayList<String>();
80.157 + for (int i = 0; ; i++) {
80.158 + String p = request.getParameter("param" + i);
80.159 + if (p == null) {
80.160 + break;
80.161 + }
80.162 + params.add(p);
80.163 + if ("protocol:ws".equals(p)) {
80.164 + webSocket = true;
80.165 + continue;
80.166 + } }
80.167 + final String cnt = request.getParameter("content");
80.168 + String mangle = cnt.replace("%20", " ").replace("%0A", "\n");
80.169 + ByteArrayInputStream is = new ByteArrayInputStream(mangle.getBytes("UTF-8"));
80.170 + URI url;
80.171 + final Resource res = new Resource(is, mimeType, "/dynamic/res" + ++resourcesCount, params.toArray(new String[params.size()]));
80.172 + if (webSocket) {
80.173 + url = registerWebSocket(res);
80.174 + } else {
80.175 + url = registerResource(res);
80.176 + }
80.177 + response.getWriter().write(url.toString());
80.178 + response.getWriter().write("\n");
80.179 + return;
80.180 + }
80.181 +
80.182 for (Resource r : ic.resources) {
80.183 if (r.httpPath.equals(request.getRequestURI())) {
80.184 LOG.log(Level.INFO, "Serving HttpResource for {0}", request.getRequestURI());
80.185 @@ -232,13 +290,26 @@
80.186 }
80.187 }
80.188 }
80.189 +
80.190 + private URI registerWebSocket(Resource r) {
80.191 + WebSocketEngine.getEngine().register("", r.httpPath, new WS(r));
80.192 + return pageURL("ws", server, r.httpPath);
80.193 + }
80.194 +
80.195 + private URI registerResource(Resource r) {
80.196 + if (!ic.resources.contains(r)) {
80.197 + ic.resources.add(r);
80.198 + conf.addHttpHandler(this, r.httpPath);
80.199 + }
80.200 + return pageURL("http", server, r.httpPath);
80.201 + }
80.202 }
80.203
80.204 conf.addHttpHandler(new Page(resources, harnessResource()), "/execute");
80.205
80.206 conf.addHttpHandler(new HttpHandler() {
80.207 int cnt;
80.208 - List<InvocationContext> cases = new ArrayList<>();
80.209 + List<InvocationContext> cases = new ArrayList<InvocationContext>();
80.210 DynamicResourceHandler prev;
80.211 @Override
80.212 public void service(Request request, Response response) throws Exception {
80.213 @@ -270,11 +341,6 @@
80.214 }
80.215 }
80.216
80.217 - if (prev != null) {
80.218 - prev.close();
80.219 - prev = null;
80.220 - }
80.221 -
80.222 if (mi == null) {
80.223 mi = methods.take();
80.224 caseNmbr = cnt++;
80.225 @@ -286,10 +352,12 @@
80.226 LOG.log(Level.INFO, "End of data reached. Exiting.");
80.227 return;
80.228 }
80.229 -
80.230 - if (!mi.resources.isEmpty()) {
80.231 - prev = new DynamicResourceHandler(mi);
80.232 + final DynamicResourceHandler newRH = new DynamicResourceHandler(mi);
80.233 + if (prev != null) {
80.234 + prev.close(newRH);
80.235 }
80.236 + prev = newRH;
80.237 + conf.addHttpHandler(prev, "/dynamic");
80.238
80.239 cases.add(mi);
80.240 final String cn = mi.clazz.getName();
80.241 @@ -382,10 +450,7 @@
80.242
80.243 private Object[] launchServerAndBrwsr(HttpServer server, final String page) throws IOException, URISyntaxException, InterruptedException {
80.244 server.start();
80.245 - NetworkListener listener = server.getListeners().iterator().next();
80.246 - int port = listener.getPort();
80.247 -
80.248 - URI uri = new URI("http://localhost:" + port + page);
80.249 + URI uri = pageURL("http", server, page);
80.250 return showBrwsr(uri);
80.251 }
80.252 private static String toUTF8(String value) throws UnsupportedEncodingException {
80.253 @@ -503,6 +568,16 @@
80.254 return null;
80.255 }
80.256
80.257 + private static URI pageURL(String protocol, HttpServer server, final String page) {
80.258 + NetworkListener listener = server.getListeners().iterator().next();
80.259 + int port = listener.getPort();
80.260 + try {
80.261 + return new URI(protocol + "://localhost:" + port + page);
80.262 + } catch (URISyntaxException ex) {
80.263 + throw new IllegalStateException(ex);
80.264 + }
80.265 + }
80.266 +
80.267 final class Res {
80.268 String compileJar(JarFile jar) throws IOException {
80.269 return BaseHTTPLauncher.this.compileJar(jar);
80.270 @@ -510,7 +585,10 @@
80.271 String compileFromClassPath(URL f) throws IOException {
80.272 return BaseHTTPLauncher.this.compileFromClassPath(f, this);
80.273 }
80.274 - public URL get(String resource) throws IOException {
80.275 + public URL get(String resource, int skip) throws IOException {
80.276 + if (!resource.endsWith(".class")) {
80.277 + return getResource(resource, skip);
80.278 + }
80.279 URL u = null;
80.280 for (ClassLoader l : loaders) {
80.281 Enumeration<URL> en = l.getResources(resource);
80.282 @@ -523,12 +601,30 @@
80.283 }
80.284 if (u != null) {
80.285 if (u.toExternalForm().contains("rt.jar")) {
80.286 - LOG.log(Level.WARNING, "Fallback to bootclasspath for {0}", u);
80.287 + LOG.log(Level.WARNING, "No fallback to bootclasspath for {0}", u);
80.288 + return null;
80.289 }
80.290 return u;
80.291 }
80.292 throw new IOException("Can't find " + resource);
80.293 }
80.294 + private URL getResource(String resource, int skip) throws IOException {
80.295 + for (ClassLoader l : loaders) {
80.296 + Enumeration<URL> en = l.getResources(resource);
80.297 + while (en.hasMoreElements()) {
80.298 + final URL now = en.nextElement();
80.299 + if (now.toExternalForm().contains("sisu-inject-bean")) {
80.300 + // certainly we don't want this resource, as that
80.301 + // module is not compiled with target 1.6, currently
80.302 + continue;
80.303 + }
80.304 + if (--skip < 0) {
80.305 + return now;
80.306 + }
80.307 + }
80.308 + }
80.309 + throw new IOException("Not found (anymore of) " + resource);
80.310 + }
80.311 }
80.312
80.313 private static class Page extends HttpHandler {
80.314 @@ -560,7 +656,8 @@
80.315 replace = args;
80.316 }
80.317 OutputStream os = response.getOutputStream();
80.318 - try (InputStream is = res.get(r).openStream()) {
80.319 + try {
80.320 + InputStream is = res.get(r, 0).openStream();
80.321 copyStream(is, os, request.getRequestURL().toString(), replace);
80.322 } catch (IOException ex) {
80.323 response.setDetailMessage(ex.getLocalizedMessage());
80.324 @@ -592,14 +689,28 @@
80.325
80.326 }
80.327
80.328 - private class VM extends HttpHandler {
80.329 + private class VMAndPages extends StaticHttpHandler {
80.330 + private String vmResource;
80.331 +
80.332 + public VMAndPages() {
80.333 + super((String[]) null);
80.334 + }
80.335 +
80.336 @Override
80.337 public void service(Request request, Response response) throws Exception {
80.338 - response.setCharacterEncoding("UTF-8");
80.339 - response.setContentType("text/javascript");
80.340 - StringBuilder sb = new StringBuilder();
80.341 - generateBck2BrwsrJS(sb, BaseHTTPLauncher.this.resources);
80.342 - response.getWriter().write(sb.toString());
80.343 + if (request.getRequestURI().equals(vmResource)) {
80.344 + response.setCharacterEncoding("UTF-8");
80.345 + response.setContentType("text/javascript");
80.346 + StringBuilder sb = new StringBuilder();
80.347 + generateBck2BrwsrJS(sb, BaseHTTPLauncher.this.resources);
80.348 + response.getWriter().write(sb.toString());
80.349 + } else {
80.350 + super.service(request, response);
80.351 + }
80.352 + }
80.353 +
80.354 + private void registerVM(String vmResource) {
80.355 + this.vmResource = vmResource;
80.356 }
80.357 }
80.358
80.359 @@ -616,7 +727,9 @@
80.360 if (res.startsWith("/")) {
80.361 res = res.substring(1);
80.362 }
80.363 - URL url = loader.get(res);
80.364 + String skip = request.getParameter("skip");
80.365 + int skipCnt = skip == null ? 0 : Integer.parseInt(skip);
80.366 + URL url = loader.get(res, skipCnt);
80.367 if (url.getProtocol().equals("jar")) {
80.368 JarURLConnection juc = (JarURLConnection) url.openConnection();
80.369 String s = loader.compileJar(juc.getJarFile());
80.370 @@ -639,6 +752,13 @@
80.371 Exception ex = new Exception("Won't server bytes of " + url);
80.372 /*
80.373 try (InputStream is = url.openStream()) {
80.374 +=======
80.375 + InputStream is = null;
80.376 + try {
80.377 + String skip = request.getParameter("skip");
80.378 + int skipCnt = skip == null ? 0 : Integer.parseInt(skip);
80.379 + is = loader.get(res, skipCnt);
80.380 +>>>>>>> other
80.381 response.setContentType("text/javascript");
80.382 Writer w = response.getWriter();
80.383 w.append("([");
80.384 @@ -664,8 +784,33 @@
80.385 response.setStatus(HttpStatus.NOT_FOUND_404);
80.386 response.setError();
80.387 response.setDetailMessage(ex.getMessage());
80.388 + } /*finally {
80.389 + if (is != null) {
80.390 + is.close();
80.391 + }
80.392 + }*/
80.393 + }
80.394 +
80.395 + }
80.396 + private static class WS extends WebSocketApplication {
80.397 +
80.398 + private final Resource r;
80.399 +
80.400 + private WS(Resource r) {
80.401 + this.r = r;
80.402 + }
80.403 +
80.404 + @Override
80.405 + public void onMessage(WebSocket socket, String text) {
80.406 + try {
80.407 + r.httpContent.reset();
80.408 + ByteArrayOutputStream out = new ByteArrayOutputStream();
80.409 + copyStream(r.httpContent, out, null, text);
80.410 + String s = new String(out.toByteArray(), "UTF-8");
80.411 + socket.send(s);
80.412 + } catch (IOException ex) {
80.413 + LOG.log(Level.WARNING, null, ex);
80.414 }
80.415 }
80.416
80.417 - }
80.418 -}
80.419 + }}
81.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/FXBrwsrLauncher.java Tue Apr 29 15:25:58 2014 +0200
81.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/FXBrwsrLauncher.java Wed Apr 30 15:04:10 2014 +0200
81.3 @@ -17,13 +17,17 @@
81.4 */
81.5 package org.apidesign.bck2brwsr.launcher;
81.6
81.7 +import java.io.File;
81.8 import org.apidesign.bck2brwsr.launcher.fximpl.FXBrwsr;
81.9 import java.io.IOException;
81.10 import java.io.InputStream;
81.11 import java.lang.reflect.Method;
81.12 +import java.net.JarURLConnection;
81.13 import java.net.URI;
81.14 +import java.net.URISyntaxException;
81.15 import java.net.URL;
81.16 import java.net.URLClassLoader;
81.17 +import java.util.ArrayList;
81.18 import java.util.Enumeration;
81.19 import java.util.List;
81.20
81.21 @@ -67,7 +71,17 @@
81.22 public void run() {
81.23 LOG.log(Level.INFO, "In FX thread. Launching!");
81.24 try {
81.25 - FXBrwsr.launch(FXBrwsr.class, url.toString());
81.26 + List<String> params = new ArrayList<String>();
81.27 + params.add(url.toString());
81.28 + if (isDebugged()) {
81.29 + params.add("--toolbar=true");
81.30 + params.add("--firebug=true");
81.31 + String ud = System.getProperty("netbeans.user");
81.32 + if (ud != null) {
81.33 + params.add("--userdir=" + ud);
81.34 + }
81.35 + }
81.36 + FXBrwsr.launch(FXBrwsr.class, params.toArray(new String[params.size()]));
81.37 LOG.log(Level.INFO, "Launcher is back. Closing");
81.38 close();
81.39 System.exit(0);
81.40 @@ -87,17 +101,6 @@
81.41 sb.append("(function() {\n"
81.42 + " var impl = this.bck2brwsr;\n"
81.43 + " this.bck2brwsr = function() { return impl; };\n");
81.44 - if (isDebugged()) {
81.45 - sb.append("var scr = window.document.createElement('script');\n");
81.46 - sb.append("scr.type = 'text/javascript';\n");
81.47 - sb.append("scr.src = 'https://getfirebug.com/firebug-lite.js';\n");
81.48 - sb.append("scr.text = '{ startOpened: true }';\n");
81.49 - sb.append("var head = window.document.getElementsByTagName('head')[0];");
81.50 - sb.append("head.appendChild(scr);\n");
81.51 - sb.append("var html = window.document.getElementsByTagName('html')[0];");
81.52 - sb.append("html.debug = true;\n");
81.53 - }
81.54 -
81.55 sb.append("})(window);\n");
81.56 JVMBridge.onBck2BrwsrLoad();
81.57 }
81.58 @@ -116,25 +119,46 @@
81.59 String startPage = null;
81.60
81.61 final ClassLoader cl = FXBrwsrLauncher.class.getClassLoader();
81.62 - startPage = findStartPage(cl, startPage);
81.63 + URL[] manifestURL = { null };
81.64 + startPage = findStartPage(cl, startPage, manifestURL);
81.65 if (startPage == null) {
81.66 throw new NullPointerException("Can't find StartPage tag in manifests!");
81.67 }
81.68
81.69 - Launcher.showURL("fxbrwsr", cl, startPage);
81.70 + File dir = new File(".");
81.71 + if (manifestURL[0].getProtocol().equals("jar")) {
81.72 + try {
81.73 + dir = new File(
81.74 + ((JarURLConnection)manifestURL[0].openConnection()).getJarFileURL().toURI()
81.75 + ).getParentFile();
81.76 + } catch (URISyntaxException ex) {
81.77 + LOG.log(Level.WARNING, "Can't find root directory", ex);
81.78 + }
81.79 + }
81.80 +
81.81 + Launcher.showDir("fxbrwsr", dir, cl, startPage);
81.82 }
81.83
81.84 - private static String findStartPage(final ClassLoader cl, String startPage) throws IOException {
81.85 + private static String findStartPage(
81.86 + final ClassLoader cl, String startPage, URL[] startURL
81.87 + ) throws IOException {
81.88 Enumeration<URL> en = cl.getResources("META-INF/MANIFEST.MF");
81.89 while (en.hasMoreElements()) {
81.90 URL url = en.nextElement();
81.91 Manifest mf;
81.92 - try (InputStream is = url.openStream()) {
81.93 + InputStream is = null;
81.94 + try {
81.95 + is = url.openStream();
81.96 mf = new Manifest(is);
81.97 + } finally {
81.98 + if (is != null) is.close();
81.99 }
81.100 String sp = mf.getMainAttributes().getValue("StartPage");
81.101 if (sp != null) {
81.102 startPage = sp;
81.103 + if (startURL != null) {
81.104 + startURL[0] = url;
81.105 + }
81.106 break;
81.107 }
81.108 }
82.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/BrowserToolbar.java Wed Apr 30 15:04:10 2014 +0200
82.3 @@ -0,0 +1,381 @@
82.4 +/**
82.5 + * Back 2 Browser Bytecode Translator
82.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
82.7 + *
82.8 + * This program is free software: you can redistribute it and/or modify
82.9 + * it under the terms of the GNU General Public License as published by
82.10 + * the Free Software Foundation, version 2 of the License.
82.11 + *
82.12 + * This program is distributed in the hope that it will be useful,
82.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
82.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
82.15 + * GNU General Public License for more details.
82.16 + *
82.17 + * You should have received a copy of the GNU General Public License
82.18 + * along with this program. Look for COPYING file in the top folder.
82.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
82.20 + */
82.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
82.22 +
82.23 +import java.util.ArrayList;
82.24 +import java.util.List;
82.25 +import javafx.beans.InvalidationListener;
82.26 +import javafx.beans.Observable;
82.27 +import javafx.beans.value.ChangeListener;
82.28 +import javafx.beans.value.ObservableValue;
82.29 +import javafx.collections.FXCollections;
82.30 +import javafx.scene.control.ComboBox;
82.31 +import javafx.scene.control.ScrollPane;
82.32 +import javafx.scene.control.Separator;
82.33 +import javafx.scene.control.Toggle;
82.34 +import javafx.scene.control.ToggleButton;
82.35 +import javafx.scene.control.ToggleGroup;
82.36 +import javafx.scene.control.ToolBar;
82.37 +import javafx.scene.control.Tooltip;
82.38 +import javafx.scene.image.Image;
82.39 +import javafx.scene.image.ImageView;
82.40 +import javafx.scene.layout.Pane;
82.41 +import javafx.scene.web.WebEngine;
82.42 +import javafx.scene.web.WebView;
82.43 +
82.44 +final class BrowserToolbar extends ToolBar {
82.45 + private final ArrayList<ResizeBtn> resizeButtons;
82.46 + private final WebView webView;
82.47 + private final Pane container;
82.48 + private final ToggleGroup resizeGroup = new ToggleGroup();
82.49 + private final ComboBox<String> comboZoom = new ComboBox<String>();
82.50 +
82.51 + BrowserToolbar(WebView webView, Pane container, boolean useFirebug) {
82.52 + this.webView = webView;
82.53 + this.container = container;
82.54 +
82.55 + List<ResizeOption> options = ResizeOption.loadAll();
82.56 + options.add( 0, ResizeOption.SIZE_TO_FIT );
82.57 + resizeButtons = new ArrayList<ResizeBtn>( options.size() );
82.58 +
82.59 + for( ResizeOption ro : options ) {
82.60 + ResizeBtn button = new ResizeBtn(ro);
82.61 + resizeButtons.add( button );
82.62 + resizeGroup.getToggles().add( button );
82.63 + getItems().add( button );
82.64 + }
82.65 + resizeButtons.get( 0 ).setSelected( true );
82.66 + resizeGroup.selectedToggleProperty().addListener( new InvalidationListener() {
82.67 +
82.68 + @Override
82.69 + public void invalidated( Observable o ) {
82.70 + resize();
82.71 + }
82.72 + });
82.73 +
82.74 + getItems().add( new Separator() );
82.75 +
82.76 + getItems().add( comboZoom );
82.77 + ArrayList<String> zoomModel = new ArrayList<String>( 6 );
82.78 + zoomModel.add( "200%" ); //NOI18N
82.79 + zoomModel.add( "150%" ); //NOI18N
82.80 + zoomModel.add( "100%" ); //NOI18N
82.81 + zoomModel.add( "75%" ); //NOI18N
82.82 + zoomModel.add( "50%" ); //NOI18N
82.83 + comboZoom.setItems( FXCollections.observableList( zoomModel ) );
82.84 + comboZoom.setEditable( true );
82.85 + comboZoom.setValue( "100%" ); //NOI18N
82.86 + comboZoom.valueProperty().addListener( new ChangeListener<String>() {
82.87 +
82.88 + @Override
82.89 + public void changed( ObservableValue<? extends String> ov, String t, String t1 ) {
82.90 + String newZoom = zoom( t1 );
82.91 + comboZoom.setValue( newZoom );
82.92 + }
82.93 + });
82.94 +
82.95 + if (useFirebug) {
82.96 + getItems().add(new Separator());
82.97 +
82.98 + final ToggleButton firebug = new ToggleButton(null, new ImageView(
82.99 + new Image(BrowserToolbar.class.getResourceAsStream("firebug.png"))
82.100 + ));
82.101 + firebug.setTooltip(new Tooltip("Show/Hide firebug"));
82.102 + firebug.selectedProperty().addListener(new InvalidationListener() {
82.103 + @Override
82.104 + public void invalidated(Observable o) {
82.105 + toggleFireBug(firebug.isSelected());
82.106 + }
82.107 + });
82.108 + getItems().add(firebug);
82.109 + }
82.110 + }
82.111 +
82.112 + private String zoom( String zoomFactor ) {
82.113 + if( zoomFactor.trim().isEmpty() )
82.114 + return null;
82.115 +
82.116 + try {
82.117 + zoomFactor = zoomFactor.replaceAll( "\\%", ""); //NOI18N
82.118 + zoomFactor = zoomFactor.trim();
82.119 + double zoom = Double.parseDouble( zoomFactor );
82.120 + zoom = Math.abs( zoom )/100;
82.121 + if( zoom <= 0.0 )
82.122 + return null;
82.123 + webView.setScaleX(zoom);
82.124 + webView.setScaleY(zoom);
82.125 + webView.setScaleZ(zoom);
82.126 + return (int)(100*zoom) + "%"; //NOI18N
82.127 + } catch( NumberFormatException nfe ) {
82.128 + //ignore
82.129 + }
82.130 + return null;
82.131 + }
82.132 +
82.133 + private void resize() {
82.134 + Toggle selection = resizeGroup.getSelectedToggle();
82.135 + if( selection instanceof ResizeBtn ) {
82.136 + ResizeOption ro = ((ResizeBtn)selection).getResizeOption();
82.137 + if( ro == ResizeOption.SIZE_TO_FIT ) {
82.138 + _autofit();
82.139 + } else {
82.140 + _resize( ro.getWidth(), ro.getHeight() );
82.141 + }
82.142 + }
82.143 +
82.144 + }
82.145 +
82.146 + private void _resize( final double width, final double height ) {
82.147 + ScrollPane scroll;
82.148 + if( !(container.getChildren().get( 0) instanceof ScrollPane) ) {
82.149 + scroll = new ScrollPane();
82.150 + scroll.setContent( webView );
82.151 + container.getChildren().clear();
82.152 + container.getChildren().add( scroll );
82.153 + } else {
82.154 + scroll = ( ScrollPane ) container.getChildren().get( 0 );
82.155 + }
82.156 + scroll.setPrefViewportWidth( width );
82.157 + scroll.setPrefViewportHeight(height );
82.158 + webView.setMaxWidth( width );
82.159 + webView.setMaxHeight( height );
82.160 + webView.setMinWidth( width );
82.161 + webView.setMinHeight( height );
82.162 + }
82.163 +
82.164 + private void _autofit() {
82.165 + if( container.getChildren().get( 0) instanceof ScrollPane ) {
82.166 + container.getChildren().clear();
82.167 + container.getChildren().add( webView );
82.168 + }
82.169 + webView.setMaxWidth( Integer.MAX_VALUE );
82.170 + webView.setMaxHeight( Integer.MAX_VALUE );
82.171 + webView.setMinWidth( -1 );
82.172 + webView.setMinHeight( -1 );
82.173 + webView.autosize();
82.174 + }
82.175 +
82.176 + final void toggleFireBug(boolean enable) {
82.177 + WebEngine eng = webView.getEngine();
82.178 + Object installed = eng.executeScript("window.Firebug");
82.179 + if ("undefined".equals(installed)) {
82.180 + StringBuilder sb = new StringBuilder();
82.181 + sb.append("var scr = window.document.createElement('script');\n");
82.182 + sb.append("scr.type = 'text/javascript';\n");
82.183 + sb.append("scr.src = 'https://getfirebug.com/firebug-lite.js';\n");
82.184 + sb.append("scr.text = '{ startOpened: true }';\n");
82.185 + sb.append("var head = window.document.getElementsByTagName('head')[0];");
82.186 + sb.append("head.appendChild(scr);\n");
82.187 + sb.append("var html = window.document.getElementsByTagName('html')[0];");
82.188 + sb.append("html.debug = true;\n");
82.189 + eng.executeScript(sb.toString());
82.190 + } else {
82.191 + if (enable) {
82.192 + eng.executeScript("Firebug.chrome.open()");
82.193 + } else {
82.194 + eng.executeScript("Firebug.chrome.close()");
82.195 + }
82.196 + }
82.197 + }
82.198 +
82.199 + /**
82.200 + * Button to resize the browser window.
82.201 + * Taken from NetBeans. Kept GPLwithCPEx license.
82.202 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
82.203 + *
82.204 + * @author S. Aubrecht
82.205 + */
82.206 + static final class ResizeBtn extends ToggleButton {
82.207 +
82.208 + private final ResizeOption resizeOption;
82.209 +
82.210 + ResizeBtn(ResizeOption resizeOption) {
82.211 + super(null, new ImageView(toImage(resizeOption)));
82.212 + this.resizeOption = resizeOption;
82.213 + setTooltip(new Tooltip(resizeOption.getToolTip()));
82.214 + }
82.215 +
82.216 + ResizeOption getResizeOption() {
82.217 + return resizeOption;
82.218 + }
82.219 +
82.220 + static Image toImage(ResizeOption ro) {
82.221 + if (ro == ResizeOption.SIZE_TO_FIT) {
82.222 + return ResizeOption.Type.CUSTOM.getImage();
82.223 + }
82.224 + return ro.getType().getImage();
82.225 + }
82.226 + }
82.227 +
82.228 + /**
82.229 + * Immutable value class describing a single button to resize web browser window.
82.230 + * Taken from NetBeans. Kept GPLwithCPEx license.
82.231 + * Portions Copyrighted 2012 Sun Microsystems, Inc.
82.232 + *
82.233 + * @author S. Aubrecht
82.234 + */
82.235 + static final class ResizeOption {
82.236 +
82.237 + private final Type type;
82.238 + private final String displayName;
82.239 + private final int width;
82.240 + private final int height;
82.241 + private final boolean isDefault;
82.242 +
82.243 + enum Type {
82.244 + DESKTOP("desktop.png"),
82.245 + TABLET_PORTRAIT("tabletPortrait.png"),
82.246 + TABLET_LANDSCAPE("tabletLandscape.png"),
82.247 + SMARTPHONE_PORTRAIT("handheldPortrait.png"),
82.248 + SMARTPHONE_LANDSCAPE("handheldLandscape.png"),
82.249 + WIDESCREEN("widescreen.png"),
82.250 + NETBOOK("netbook.png"),
82.251 + CUSTOM("sizeToFit.png");
82.252 +
82.253 +
82.254 + private final String resource;
82.255 +
82.256 + private Type(String r) {
82.257 + resource = r;
82.258 + }
82.259 +
82.260 + public Image getImage() {
82.261 + return new Image(Type.class.getResourceAsStream(resource));
82.262 + }
82.263 + }
82.264 +
82.265 + private ResizeOption(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
82.266 + super();
82.267 + this.type = type;
82.268 + this.displayName = displayName;
82.269 + this.width = width;
82.270 + this.height = height;
82.271 + this.isDefault = isDefault;
82.272 + }
82.273 +
82.274 + static List<ResizeOption> loadAll() {
82.275 + List<ResizeOption> res = new ArrayList<ResizeOption>(10);
82.276 + res.add(ResizeOption.create(ResizeOption.Type.DESKTOP, "Desktop", 1280, 1024, true, true));
82.277 + res.add(ResizeOption.create(ResizeOption.Type.TABLET_LANDSCAPE, "Tablet Landscape", 1024, 768, true, true));
82.278 + res.add(ResizeOption.create(ResizeOption.Type.TABLET_PORTRAIT, "Tablet Portrait", 768, 1024, true, true));
82.279 + res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_LANDSCAPE, "Smartphone Landscape", 480, 320, true, true));
82.280 + res.add(ResizeOption.create(ResizeOption.Type.SMARTPHONE_PORTRAIT, "Smartphone Portrait", 320, 480, true, true));
82.281 + res.add(ResizeOption.create(ResizeOption.Type.WIDESCREEN, "Widescreen", 1680, 1050, false, true));
82.282 + res.add(ResizeOption.create(ResizeOption.Type.NETBOOK, "Netbook", 1024, 600, false, true));
82.283 + return res;
82.284 + }
82.285 +
82.286 + /**
82.287 + * Creates a new instance.
82.288 + * @param type
82.289 + * @param displayName Display name to show in tooltip, cannot be empty.
82.290 + * @param width Screen width
82.291 + * @param height Screen height
82.292 + * @param showInToolbar True to show in web developer toolbar.
82.293 + * @param isDefault True if this is a predefined option that cannot be removed.
82.294 + * @return New instance.
82.295 + */
82.296 + public static ResizeOption create(Type type, String displayName, int width, int height, boolean showInToolbar, boolean isDefault) {
82.297 + if (width <= 0 || height <= 0) {
82.298 + throw new IllegalArgumentException("Invalid screen dimensions: " + width + " x " + height); //NOI18N
82.299 + }
82.300 + return new ResizeOption(type, displayName, width, height, showInToolbar, isDefault);
82.301 + }
82.302 + /**
82.303 + * An extra option to size the browser content to fit its window.
82.304 + */
82.305 + public static final ResizeOption SIZE_TO_FIT = new ResizeOption(Type.CUSTOM, "Size To Fit", -1, -1, true, true);
82.306 +
82.307 + public String getDisplayName() {
82.308 + return displayName;
82.309 + }
82.310 +
82.311 + public Type getType() {
82.312 + return type;
82.313 + }
82.314 +
82.315 + public int getWidth() {
82.316 + return width;
82.317 + }
82.318 +
82.319 + public int getHeight() {
82.320 + return height;
82.321 + }
82.322 +
82.323 + public boolean isDefault() {
82.324 + return isDefault;
82.325 + }
82.326 +
82.327 + @Override
82.328 + public String toString() {
82.329 + return displayName;
82.330 + }
82.331 +
82.332 + public String getToolTip() {
82.333 + if (width < 0 || height < 0) {
82.334 + return displayName;
82.335 + }
82.336 + StringBuilder sb = new StringBuilder();
82.337 + sb.append(width);
82.338 + sb.append(" x "); //NOI18N
82.339 + sb.append(height);
82.340 + sb.append(" ("); //NOI18N
82.341 + sb.append(displayName);
82.342 + sb.append(')'); //NOI18N
82.343 + return sb.toString();
82.344 + }
82.345 +
82.346 + @Override
82.347 + public boolean equals(Object obj) {
82.348 + if (obj == null) {
82.349 + return false;
82.350 + }
82.351 + if (getClass() != obj.getClass()) {
82.352 + return false;
82.353 + }
82.354 + final ResizeOption other = (ResizeOption) obj;
82.355 + if (this.type != other.type) {
82.356 + return false;
82.357 + }
82.358 + if ((this.displayName == null) ? (other.displayName != null) : !this.displayName.equals(other.displayName)) {
82.359 + return false;
82.360 + }
82.361 + if (this.width != other.width) {
82.362 + return false;
82.363 + }
82.364 + if (this.height != other.height) {
82.365 + return false;
82.366 + }
82.367 + if (this.isDefault != other.isDefault) {
82.368 + return false;
82.369 + }
82.370 + return true;
82.371 + }
82.372 +
82.373 + @Override
82.374 + public int hashCode() {
82.375 + int hash = 7;
82.376 + hash = 11 * hash + (this.type != null ? this.type.hashCode() : 0);
82.377 + hash = 11 * hash + (this.displayName != null ? this.displayName.hashCode() : 0);
82.378 + hash = 11 * hash + this.width;
82.379 + hash = 11 * hash + this.height;
82.380 + hash = 11 * hash + (this.isDefault ? 1 : 0);
82.381 + return hash;
82.382 + }
82.383 + }
82.384 +}
83.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Console.java Tue Apr 29 15:25:58 2014 +0200
83.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Console.java Wed Apr 30 15:04:10 2014 +0200
83.3 @@ -25,7 +25,7 @@
83.4 import java.lang.reflect.Modifier;
83.5 import java.net.URL;
83.6 import java.util.Enumeration;
83.7 -import javafx.scene.web.WebEngine;
83.8 +import net.java.html.js.JavaScriptBody;
83.9 import netscape.javascript.JSObject;
83.10
83.11 /**
83.12 @@ -35,17 +35,15 @@
83.13 public final class Console {
83.14 public Console() {
83.15 }
83.16 -
83.17 - private static Object getAttr(Object elem, String attr) {
83.18 - return InvokeJS.CObject.call("getAttr", elem, attr);
83.19 - }
83.20
83.21 - private static void setAttr(String id, String attr, Object value) {
83.22 - InvokeJS.CObject.call("setAttrId", id, attr, value);
83.23 - }
83.24 - private static void setAttr(Object id, String attr, Object value) {
83.25 - InvokeJS.CObject.call("setAttr", id, attr, value);
83.26 - }
83.27 + @JavaScriptBody(args = { "elem", "attr" }, body = "return elem[attr].toString();")
83.28 + private static native Object getAttr(Object elem, String attr);
83.29 +
83.30 + @JavaScriptBody(args = { "id", "attr", "value" }, body = "window.document.getElementById(id)[attr] = value;")
83.31 + private static native void setAttr(String id, String attr, Object value);
83.32 +
83.33 + @JavaScriptBody(args = { "elem", "attr", "value" }, body = "elem[attr] = value;")
83.34 + private static native void setAttr(Object id, String attr, Object value);
83.35
83.36 private static void closeWindow() {}
83.37
83.38 @@ -62,8 +60,7 @@
83.39 }
83.40
83.41 private static void beginTest(Case c) {
83.42 - Object[] arr = new Object[2];
83.43 - beginTest(c.getClassName() + "." + c.getMethodName(), c, arr);
83.44 + Object[] arr = beginTest(c.getClassName() + "." + c.getMethodName(), c, new Object[2]);
83.45 textArea = arr[0];
83.46 statusArea = arr[1];
83.47 }
83.48 @@ -78,7 +75,7 @@
83.49 textArea = null;
83.50 }
83.51
83.52 - private static final String BEGIN_TEST =
83.53 + @JavaScriptBody(args = { "test", "c", "arr" }, body =
83.54 "var ul = window.document.getElementById('bck2brwsr.result');\n"
83.55 + "var li = window.document.createElement('li');\n"
83.56 + "var span = window.document.createElement('span');"
83.57 @@ -103,27 +100,24 @@
83.58 + "p.appendChild(pre);\n"
83.59 + "ul.appendChild(li);\n"
83.60 + "arr[0] = pre;\n"
83.61 - + "arr[1] = status;\n";
83.62 -
83.63 - private static void beginTest(String test, Case c, Object[] arr) {
83.64 - InvokeJS.CObject.call("beginTest", test, c, arr);
83.65 - }
83.66 + + "arr[1] = status;\n"
83.67 + + "return arr;"
83.68 + )
83.69 + private static native Object[] beginTest(String test, Case c, Object[] arr);
83.70
83.71 - private static final String LOAD_TEXT =
83.72 + @JavaScriptBody(args = { "url", "callback" }, javacall = true, body =
83.73 "var request = new XMLHttpRequest();\n"
83.74 + "request.open('GET', url, true);\n"
83.75 + "request.setRequestHeader('Content-Type', 'text/plain; charset=utf-8');\n"
83.76 + "request.onreadystatechange = function() {\n"
83.77 + " if (this.readyState!==4) return;\n"
83.78 - + " try {"
83.79 - + " arr[0] = this.responseText;\n"
83.80 - + " callback.run__V();\n"
83.81 - + " } catch (e) { alert(e); }"
83.82 - + "};"
83.83 - + "request.send();";
83.84 - private static void loadText(String url, Runnable callback, String[] arr) throws IOException {
83.85 - InvokeJS.CObject.call("loadText", url, new Run(callback), arr);
83.86 - }
83.87 + + " try {\n"
83.88 + + " callback.@org.apidesign.bck2brwsr.launcher.fximpl.OnMessage::onMessage(Ljava/lang/String;)(this.responseText);\n"
83.89 + + " } catch (e) { alert(e); }\n"
83.90 + + "};\n"
83.91 + + "request.send();\n"
83.92 + )
83.93 + private static native void loadText(String url, OnMessage callback) throws IOException;
83.94
83.95 public static void runHarness(String url) throws IOException {
83.96 new Console().harness(url);
83.97 @@ -134,7 +128,7 @@
83.98 Request r = new Request(url);
83.99 }
83.100
83.101 - private static class Request implements Runnable {
83.102 + private static class Request implements Runnable, OnMessage {
83.103 private final String[] arr = { null };
83.104 private final String url;
83.105 private Case c;
83.106 @@ -142,15 +136,22 @@
83.107
83.108 private Request(String url) throws IOException {
83.109 this.url = url;
83.110 - loadText(url, this, arr);
83.111 + loadText(url, this);
83.112 }
83.113 private Request(String url, String u) throws IOException {
83.114 this.url = url;
83.115 - loadText(u, this, arr);
83.116 + loadText(u, this);
83.117 + }
83.118 +
83.119 + @Override
83.120 + public void onMessage(String msg) {
83.121 + arr[0] = msg;
83.122 + run();
83.123 }
83.124
83.125 @Override
83.126 public void run() {
83.127 + Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
83.128 try {
83.129 if (c == null) {
83.130 String data = arr[0];
83.131 @@ -232,7 +233,9 @@
83.132 if (u == null) {
83.133 throw new IOException("Can't find " + name);
83.134 }
83.135 - try (InputStream is = u.openStream()) {
83.136 + InputStream is = null;
83.137 + try {
83.138 + is = u.openStream();
83.139 byte[] arr;
83.140 arr = new byte[is.available()];
83.141 int offset = 0;
83.142 @@ -244,15 +247,20 @@
83.143 offset += len;
83.144 }
83.145 return arr;
83.146 + } finally {
83.147 + if (is != null) is.close();
83.148 }
83.149 }
83.150
83.151 private static void turnAssetionStatusOn() {
83.152 }
83.153
83.154 - private static Object schedule(Runnable r, int time) {
83.155 - return InvokeJS.CObject.call("schedule", new Run(r), time);
83.156 - }
83.157 + @JavaScriptBody(args = { "r", "time" }, javacall = true, body =
83.158 + "return window.setTimeout(function() { "
83.159 + + "r.@java.lang.Runnable::run()(); "
83.160 + + "}, time);"
83.161 + )
83.162 + private static native Object schedule(Runnable r, int time);
83.163
83.164 private static final class Case {
83.165 private final Object data;
83.166 @@ -348,48 +356,16 @@
83.167 }
83.168 return res;
83.169 }
83.170 -
83.171 - private static Object toJSON(String s) {
83.172 - return InvokeJS.CObject.call("toJSON", s);
83.173 - }
83.174 +
83.175 + @JavaScriptBody(args = { "s" }, body = "return eval('(' + s + ')');")
83.176 + private static native Object toJSON(String s);
83.177
83.178 private static Object value(String p, Object d) {
83.179 return ((JSObject)d).getMember(p);
83.180 }
83.181 }
83.182
83.183 - private static String safe(String txt) {
83.184 - return "try {" + txt + "} catch (err) { alert(err); }";
83.185 - }
83.186 -
83.187 static {
83.188 turnAssetionStatusOn();
83.189 }
83.190 -
83.191 - private static final class InvokeJS {
83.192 - static final JSObject CObject = initJS();
83.193 -
83.194 - private static JSObject initJS() {
83.195 - WebEngine web = (WebEngine) System.getProperties().get("webEngine");
83.196 - return (JSObject) web.executeScript("(function() {"
83.197 - + "var CObject = {};"
83.198 -
83.199 - + "CObject.getAttr = function(elem, attr) { return elem[attr].toString(); };"
83.200 -
83.201 - + "CObject.setAttrId = function(id, attr, value) { window.document.getElementById(id)[attr] = value; };"
83.202 - + "CObject.setAttr = function(elem, attr, value) { elem[attr] = value; };"
83.203 -
83.204 - + "CObject.beginTest = function(test, c, arr) {" + safe(BEGIN_TEST) + "};"
83.205 -
83.206 - + "CObject.loadText = function(url, callback, arr) {" + safe(LOAD_TEXT.replace("run__V", "run")) + "};"
83.207 -
83.208 - + "CObject.schedule = function(r, time) { return window.setTimeout(function() { r.run(); }, time); };"
83.209 -
83.210 - + "CObject.toJSON = function(s) { return eval('(' + s + ')'); };"
83.211 -
83.212 - + "return CObject;"
83.213 - + "})(this)");
83.214 - }
83.215 - }
83.216 -
83.217 }
84.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXBrwsr.java Tue Apr 29 15:25:58 2014 +0200
84.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXBrwsr.java Wed Apr 30 15:04:10 2014 +0200
84.3 @@ -27,16 +27,13 @@
84.4 import javafx.beans.value.ObservableValue;
84.5 import javafx.event.ActionEvent;
84.6 import javafx.event.EventHandler;
84.7 -import javafx.geometry.HPos;
84.8 import javafx.geometry.Insets;
84.9 import javafx.geometry.Pos;
84.10 -import javafx.geometry.VPos;
84.11 -import javafx.scene.Node;
84.12 import javafx.scene.Scene;
84.13 import javafx.scene.control.Button;
84.14 -import javafx.scene.layout.ColumnConstraints;
84.15 -import javafx.scene.layout.GridPane;
84.16 -import javafx.scene.layout.Pane;
84.17 +import javafx.scene.control.ToolBar;
84.18 +import javafx.scene.layout.BorderPane;
84.19 +import javafx.scene.layout.HBox;
84.20 import javafx.scene.layout.Priority;
84.21 import javafx.scene.layout.VBox;
84.22 import javafx.scene.text.Text;
84.23 @@ -55,30 +52,52 @@
84.24 */
84.25 public class FXBrwsr extends Application {
84.26 private static final Logger LOG = Logger.getLogger(FXBrwsr.class.getName());
84.27 -
84.28 +
84.29 @Override
84.30 public void start(Stage primaryStage) throws Exception {
84.31 - Pane root = new WebViewPane(getParameters().getUnnamed());
84.32 - primaryStage.setScene(new Scene(root, 1024, 768));
84.33 - LOG.info("Showing the stage");
84.34 + WebView view = new WebView();
84.35 + WebController wc = new WebController(view, getParameters().getUnnamed());
84.36 +
84.37 + FXInspect.initialize(view.getEngine());
84.38 +
84.39 + final VBox vbox = new VBox();
84.40 + vbox.setAlignment( Pos.CENTER );
84.41 + vbox.setStyle( "-fx-background-color: #808080;");
84.42 +
84.43 +
84.44 + HBox hbox = new HBox();
84.45 + hbox.setStyle( "-fx-background-color: #808080;");
84.46 + hbox.setAlignment(Pos.CENTER);
84.47 + hbox.getChildren().add(vbox);
84.48 + HBox.setHgrow(vbox, Priority.ALWAYS);
84.49 + vbox.getChildren().add(view);
84.50 + VBox.setVgrow(view, Priority.ALWAYS);
84.51 +
84.52 + BorderPane root = new BorderPane();
84.53 + final boolean showToolbar = "true".equals(this.getParameters().getNamed().get("toolbar")); // NOI18N
84.54 + final boolean useFirebug = "true".equals(this.getParameters().getNamed().get("firebug")); // NOI18N
84.55 + if (showToolbar) {
84.56 + final ToolBar toolbar = new BrowserToolbar(view, vbox, useFirebug);
84.57 + root.setTop( toolbar );
84.58 + }
84.59 + root.setCenter(hbox);
84.60 +
84.61 + Scene scene = new Scene(root, 800, 600);
84.62 +
84.63 + primaryStage.setTitle( "Device Emulator" );
84.64 + primaryStage.setScene( scene );
84.65 primaryStage.show();
84.66 - LOG.log(Level.INFO, "State shown: {0}", primaryStage.isShowing());
84.67 }
84.68
84.69 /**
84.70 * Create a resizable WebView pane
84.71 */
84.72 - private class WebViewPane extends Pane {
84.73 - private final JVMBridge bridge = new JVMBridge();
84.74 + private static class WebController {
84.75 + private final JVMBridge bridge;
84.76
84.77 - public WebViewPane(List<String> params) {
84.78 + public WebController(WebView view, List<String> params) {
84.79 + this.bridge = new JVMBridge(view.getEngine());
84.80 LOG.log(Level.INFO, "Initializing WebView with {0}", params);
84.81 - VBox.setVgrow(this, Priority.ALWAYS);
84.82 - setMaxWidth(Double.MAX_VALUE);
84.83 - setMaxHeight(Double.MAX_VALUE);
84.84 - WebView view = new WebView();
84.85 - view.setMinSize(500, 400);
84.86 - view.setPrefSize(500, 400);
84.87 final WebEngine eng = view.getEngine();
84.88 try {
84.89 JVMBridge.addBck2BrwsrLoad(new InitBck2Brwsr(eng));
84.90 @@ -120,13 +139,6 @@
84.91 dialogStage.showAndWait();
84.92 }
84.93 });
84.94 - GridPane grid = new GridPane();
84.95 - grid.setVgap(5);
84.96 - grid.setHgap(5);
84.97 - GridPane.setConstraints(view, 0, 1, 2, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.ALWAYS);
84.98 - grid.getColumnConstraints().addAll(new ColumnConstraints(100, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true), new ColumnConstraints(40, 40, 40, Priority.NEVER, HPos.CENTER, true));
84.99 - grid.getChildren().addAll(view);
84.100 - getChildren().add(grid);
84.101 }
84.102
84.103 boolean initBck2Brwsr(WebEngine webEngine) {
84.104 @@ -134,28 +146,12 @@
84.105 LOG.log(Level.FINE, "window: {0}", jsobj);
84.106 Object prev = jsobj.getMember("bck2brwsr");
84.107 if ("undefined".equals(prev)) {
84.108 - System.getProperties().put("webEngine", webEngine);
84.109 jsobj.setMember("bck2brwsr", bridge);
84.110 return true;
84.111 }
84.112 return false;
84.113 }
84.114
84.115 - @Override
84.116 - protected void layoutChildren() {
84.117 - List<Node> managed = getManagedChildren();
84.118 - double width = getWidth();
84.119 - double height = getHeight();
84.120 - double top = getInsets().getTop();
84.121 - double right = getInsets().getRight();
84.122 - double left = getInsets().getLeft();
84.123 - double bottom = getInsets().getBottom();
84.124 - for (int i = 0; i < managed.size(); i++) {
84.125 - Node child = managed.get(i);
84.126 - layoutInArea(child, left, top, width - left - right, height - top - bottom, 0, Insets.EMPTY, true, true, HPos.CENTER, VPos.CENTER);
84.127 - }
84.128 - }
84.129 -
84.130 private class InitBck2Brwsr implements ChangeListener<Void>, Runnable {
84.131 private final WebEngine eng;
84.132
85.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
85.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/FXInspect.java Wed Apr 30 15:04:10 2014 +0200
85.3 @@ -0,0 +1,111 @@
85.4 +/**
85.5 + * Back 2 Browser Bytecode Translator
85.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
85.7 + *
85.8 + * This program is free software: you can redistribute it and/or modify
85.9 + * it under the terms of the GNU General Public License as published by
85.10 + * the Free Software Foundation, version 2 of the License.
85.11 + *
85.12 + * This program is distributed in the hope that it will be useful,
85.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
85.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85.15 + * GNU General Public License for more details.
85.16 + *
85.17 + * You should have received a copy of the GNU General Public License
85.18 + * along with this program. Look for COPYING file in the top folder.
85.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
85.20 + */
85.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
85.22 +
85.23 +import com.sun.javafx.scene.web.Debugger;
85.24 +import java.io.IOException;
85.25 +import java.io.ObjectInputStream;
85.26 +import java.io.ObjectOutputStream;
85.27 +import java.net.InetAddress;
85.28 +import java.net.Socket;
85.29 +import java.nio.charset.StandardCharsets;
85.30 +import java.util.logging.Level;
85.31 +import java.util.logging.Logger;
85.32 +import javafx.application.Platform;
85.33 +import javafx.scene.web.WebEngine;
85.34 +import javafx.util.Callback;
85.35 +
85.36 +/**
85.37 + *
85.38 + * @author Jaroslav Tulach <jtulach@netbeans.org>
85.39 + */
85.40 +final class FXInspect implements Runnable {
85.41 + private static final Logger LOG = Logger.getLogger(FXInspect.class.getName());
85.42 +
85.43 +
85.44 + private final WebEngine engine;
85.45 + private final ObjectInputStream input;
85.46 +
85.47 + private FXInspect(WebEngine engine, int port) throws IOException {
85.48 + this.engine = engine;
85.49 +
85.50 + Socket socket = new Socket(InetAddress.getByName(null), port);
85.51 + ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
85.52 + this.input = new ObjectInputStream(socket.getInputStream());
85.53 + initializeDebugger(output);
85.54 + }
85.55 +
85.56 + static boolean initialize(WebEngine engine) {
85.57 + final int inspectPort = Integer.getInteger("netbeans.inspect.port", -1); // NOI18N
85.58 + if (inspectPort != -1) {
85.59 + try {
85.60 + FXInspect inspector = new FXInspect(engine, inspectPort);
85.61 + Thread t = new Thread(inspector, "FX<->NetBeans Inspector");
85.62 + t.start();
85.63 + return true;
85.64 + } catch (IOException ex) {
85.65 + LOG.log(Level.INFO, "Cannot connect to NetBeans IDE to port " + inspectPort, ex); // NOI18N
85.66 + }
85.67 + }
85.68 + return false;
85.69 + }
85.70 +
85.71 + private void initializeDebugger(final ObjectOutputStream output) {
85.72 + Platform.runLater(new Runnable() {
85.73 + @Override
85.74 + public void run() {
85.75 + Debugger debugger = engine.impl_getDebugger();
85.76 + debugger.setEnabled(true);
85.77 + debugger.setMessageCallback(new Callback<String,Void>() {
85.78 + @Override
85.79 + public Void call(String message) {
85.80 + try {
85.81 + byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
85.82 + output.writeInt(bytes.length);
85.83 + output.write(bytes);
85.84 + output.flush();
85.85 + } catch (IOException ioex) {
85.86 + ioex.printStackTrace();
85.87 + }
85.88 + return null;
85.89 + }
85.90 + });
85.91 + }
85.92 + });
85.93 + }
85.94 +
85.95 + @Override
85.96 + public void run() {
85.97 + try {
85.98 + while (true) {
85.99 + int length = input.readInt();
85.100 + byte[] bytes = new byte[length];
85.101 + input.readFully(bytes);
85.102 + final String message = new String(bytes, StandardCharsets.UTF_8);
85.103 + Platform.runLater(new Runnable() {
85.104 + @Override
85.105 + public void run() {
85.106 + engine.impl_getDebugger().sendMessage(message);
85.107 + }
85.108 + });
85.109 + }
85.110 + } catch (IOException ioex) {
85.111 + ioex.printStackTrace();
85.112 + }
85.113 + }
85.114 +}
86.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Tue Apr 29 15:25:58 2014 +0200
86.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Wed Apr 30 15:04:10 2014 +0200
86.3 @@ -17,16 +17,45 @@
86.4 */
86.5 package org.apidesign.bck2brwsr.launcher.fximpl;
86.6
86.7 +import java.io.BufferedReader;
86.8 +import java.io.Reader;
86.9 +import java.net.URL;
86.10 +import java.util.ArrayList;
86.11 +import java.util.Arrays;
86.12 +import java.util.Collection;
86.13 +import java.util.List;
86.14 import java.util.TooManyListenersException;
86.15 +import java.util.concurrent.Executor;
86.16 +import java.util.logging.Level;
86.17 +import java.util.logging.Logger;
86.18 +import javafx.application.Platform;
86.19 import javafx.beans.value.ChangeListener;
86.20 +import javafx.scene.web.WebEngine;
86.21 +import netscape.javascript.JSObject;
86.22 +import org.apidesign.html.boot.spi.Fn;
86.23 +import org.netbeans.html.boot.impl.FindResources;
86.24 +import org.netbeans.html.boot.impl.FnUtils;
86.25
86.26 /**
86.27 *
86.28 * @author Jaroslav Tulach <jtulach@netbeans.org>
86.29 */
86.30 public final class JVMBridge {
86.31 + static final Logger LOG = Logger.getLogger(JVMBridge.class.getName());
86.32 +
86.33 + private final WebEngine engine;
86.34 + private final ClassLoader cl;
86.35 + private final WebPresenter presenter;
86.36 +
86.37 private static ClassLoader[] ldrs;
86.38 private static ChangeListener<Void> onBck2BrwsrLoad;
86.39 +
86.40 + JVMBridge(WebEngine eng) {
86.41 + this.engine = eng;
86.42 + final ClassLoader p = JVMBridge.class.getClassLoader().getParent();
86.43 + this.presenter = new WebPresenter();
86.44 + this.cl = FnUtils.newLoader(presenter, presenter, p);
86.45 + }
86.46
86.47 public static void registerClassLoaders(ClassLoader[] loaders) {
86.48 ldrs = loaders.clone();
86.49 @@ -47,18 +76,189 @@
86.50 }
86.51
86.52 public Class<?> loadClass(String name) throws ClassNotFoundException {
86.53 - System.err.println("trying to load " + name);
86.54 - ClassNotFoundException ex = null;
86.55 - if (ldrs != null) for (ClassLoader l : ldrs) {
86.56 - try {
86.57 - return Class.forName(name, true, l);
86.58 - } catch (ClassNotFoundException ex2) {
86.59 - ex = ex2;
86.60 + Fn.activate(presenter);
86.61 + return Class.forName(name, true, cl);
86.62 + }
86.63 +
86.64 + private final class WebPresenter
86.65 + implements FindResources, Fn.Presenter, Fn.ToJavaScript, Fn.FromJavaScript, Executor {
86.66 + @Override
86.67 + public void findResources(String name, Collection<? super URL> results, boolean oneIsEnough) {
86.68 + if (ldrs != null) for (ClassLoader l : ldrs) {
86.69 + URL u = l.getResource(name);
86.70 + if (u != null) {
86.71 + results.add(u);
86.72 + }
86.73 }
86.74 }
86.75 - if (ex == null) {
86.76 - ex = new ClassNotFoundException("No loaders");
86.77 +
86.78 + @Override
86.79 + public Fn defineFn(String code, String... names) {
86.80 + return defineJSFn(code, names);
86.81 }
86.82 - throw ex;
86.83 + private JSFn defineJSFn(String code, String... names) {
86.84 + StringBuilder sb = new StringBuilder();
86.85 + sb.append("(function() {");
86.86 + sb.append(" return function(");
86.87 + String sep = "";
86.88 + for (String n : names) {
86.89 + sb.append(sep).append(n);
86.90 + sep = ",";
86.91 + }
86.92 + sb.append(") {\n");
86.93 + sb.append(code);
86.94 + sb.append("};");
86.95 + sb.append("})()");
86.96 +
86.97 + JSObject x = (JSObject) engine.executeScript(sb.toString());
86.98 + return new JSFn(this, x);
86.99 + }
86.100 +
86.101 + @Override
86.102 + public void displayPage(URL page, Runnable onPageLoad) {
86.103 + throw new UnsupportedOperationException("Not supported yet.");
86.104 + }
86.105 +
86.106 + @Override
86.107 + public void loadScript(Reader code) throws Exception {
86.108 + BufferedReader r = new BufferedReader(code);
86.109 + StringBuilder sb = new StringBuilder();
86.110 + for (;;) {
86.111 + String l = r.readLine();
86.112 + if (l == null) {
86.113 + break;
86.114 + }
86.115 + sb.append(l).append('\n');
86.116 + }
86.117 + engine.executeScript(sb.toString());
86.118 + }
86.119 +
86.120 + @Override
86.121 + public Object toJava(Object js) {
86.122 + return checkArray(js);
86.123 + }
86.124 +
86.125 + @Override
86.126 + public Object toJavaScript(Object toReturn) {
86.127 + if (toReturn instanceof Object[]) {
86.128 + return convertArrays((Object[]) toReturn);
86.129 + }
86.130 + return toReturn;
86.131 + }
86.132 +
86.133 + @Override
86.134 + public void execute(Runnable command) {
86.135 + if (Platform.isFxApplicationThread()) {
86.136 + command.run();
86.137 + } else {
86.138 + Platform.runLater(command);
86.139 + }
86.140 + }
86.141 +
86.142 + final JSObject convertArrays(Object[] arr) {
86.143 + for (int i = 0; i < arr.length; i++) {
86.144 + if (arr[i] instanceof Object[]) {
86.145 + arr[i] = convertArrays((Object[]) arr[i]);
86.146 + }
86.147 + }
86.148 + final JSObject wrapArr = (JSObject) wrapArrFn().call("array", arr); // NOI18N
86.149 + return wrapArr;
86.150 + }
86.151 +
86.152 + private JSObject wrapArrImpl;
86.153 +
86.154 + private final JSObject wrapArrFn() {
86.155 + if (wrapArrImpl == null) {
86.156 + try {
86.157 + wrapArrImpl = (JSObject) defineJSFn(" var k = {};"
86.158 + + " k.array= function() {"
86.159 + + " return Array.prototype.slice.call(arguments);"
86.160 + + " };"
86.161 + + " return k;"
86.162 + ).invokeImpl(null, false);
86.163 + } catch (Exception ex) {
86.164 + throw new IllegalStateException(ex);
86.165 + }
86.166 + }
86.167 + return wrapArrImpl;
86.168 + }
86.169 +
86.170 + final Object checkArray(Object val) {
86.171 + int length = ((Number) arraySizeFn().call("array", val, null)).intValue();
86.172 + if (length == -1) {
86.173 + return val;
86.174 + }
86.175 + Object[] arr = new Object[length];
86.176 + arraySizeFn().call("array", val, arr);
86.177 + return arr;
86.178 + }
86.179 + private JSObject arraySize;
86.180 +
86.181 + private final JSObject arraySizeFn() {
86.182 + if (arraySize == null) {
86.183 + try {
86.184 + arraySize = (JSObject) defineJSFn(" var k = {};"
86.185 + + " k.array = function(arr, to) {"
86.186 + + " if (to === null) {"
86.187 + + " if (Object.prototype.toString.call(arr) === '[object Array]') return arr.length;"
86.188 + + " else return -1;"
86.189 + + " } else {"
86.190 + + " var l = arr.length;"
86.191 + + " for (var i = 0; i < l; i++) to[i] = arr[i];"
86.192 + + " return l;"
86.193 + + " }"
86.194 + + " };"
86.195 + + " return k;"
86.196 + ).invokeImpl(null, false);
86.197 + } catch (Exception ex) {
86.198 + throw new IllegalStateException(ex);
86.199 + }
86.200 + }
86.201 + return arraySize;
86.202 + }
86.203 +
86.204 + }
86.205 +
86.206 + private static final class JSFn extends Fn {
86.207 + private final JSObject fn;
86.208 +
86.209 + private JSFn(WebPresenter cl, JSObject fn) {
86.210 + super(cl);
86.211 + this.fn = fn;
86.212 + }
86.213 +
86.214 + @Override
86.215 + public Object invoke(Object thiz, Object... args) throws Exception {
86.216 + return invokeImpl(thiz, true, args);
86.217 + }
86.218 +
86.219 + final Object invokeImpl(Object thiz, boolean arrayChecks, Object... args) throws Exception {
86.220 + try {
86.221 + List<Object> all = new ArrayList<Object>(args.length + 1);
86.222 + all.add(thiz == null ? fn : thiz);
86.223 + for (int i = 0; i < args.length; i++) {
86.224 + if (arrayChecks && args[i] instanceof Object[]) {
86.225 + Object[] arr = (Object[]) args[i];
86.226 + Object conv = ((WebPresenter) presenter()).convertArrays(arr);
86.227 + args[i] = conv;
86.228 + }
86.229 + all.add(args[i]);
86.230 + }
86.231 + Object ret = fn.call("call", all.toArray()); // NOI18N
86.232 + if (ret == fn) {
86.233 + return null;
86.234 + }
86.235 + if (!arrayChecks) {
86.236 + return ret;
86.237 + }
86.238 + return ((WebPresenter) presenter()).checkArray(ret);
86.239 + } catch (Error t) {
86.240 + t.printStackTrace();
86.241 + throw t;
86.242 + } catch (Exception t) {
86.243 + t.printStackTrace();
86.244 + throw t;
86.245 + }
86.246 + }
86.247 }
86.248 }
87.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
87.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/OnMessage.java Wed Apr 30 15:04:10 2014 +0200
87.3 @@ -0,0 +1,26 @@
87.4 +/**
87.5 + * Back 2 Browser Bytecode Translator
87.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
87.7 + *
87.8 + * This program is free software: you can redistribute it and/or modify
87.9 + * it under the terms of the GNU General Public License as published by
87.10 + * the Free Software Foundation, version 2 of the License.
87.11 + *
87.12 + * This program is distributed in the hope that it will be useful,
87.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
87.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
87.15 + * GNU General Public License for more details.
87.16 + *
87.17 + * You should have received a copy of the GNU General Public License
87.18 + * along with this program. Look for COPYING file in the top folder.
87.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
87.20 + */
87.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
87.22 +
87.23 +/**
87.24 + *
87.25 + * @author Jaroslav Tulach <jtulach@netbeans.org>
87.26 + */
87.27 +interface OnMessage {
87.28 + public void onMessage(String msg);
87.29 +}
88.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Run.java Tue Apr 29 15:25:58 2014 +0200
88.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
88.3 @@ -1,35 +0,0 @@
88.4 -/**
88.5 - * Back 2 Browser Bytecode Translator
88.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
88.7 - *
88.8 - * This program is free software: you can redistribute it and/or modify
88.9 - * it under the terms of the GNU General Public License as published by
88.10 - * the Free Software Foundation, version 2 of the License.
88.11 - *
88.12 - * This program is distributed in the hope that it will be useful,
88.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
88.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
88.15 - * GNU General Public License for more details.
88.16 - *
88.17 - * You should have received a copy of the GNU General Public License
88.18 - * along with this program. Look for COPYING file in the top folder.
88.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
88.20 - */
88.21 -
88.22 -package org.apidesign.bck2brwsr.launcher.fximpl;
88.23 -
88.24 -/**
88.25 - *
88.26 - * @author Jaroslav Tulach <jtulach@netbeans.org>
88.27 - */
88.28 -public final class Run implements Runnable {
88.29 - private final Runnable r;
88.30 - Run(Runnable r) {
88.31 - this.r = r;
88.32 - }
88.33 -
88.34 - @Override
88.35 - public void run() {
88.36 - r.run();
88.37 - }
88.38 -}
89.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/desktop.png has changed
90.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/firebug.png has changed
91.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/handheldLandscape.png has changed
92.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/handheldPortrait.png has changed
93.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/netbook.png has changed
94.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/selectionMode.png has changed
95.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/sizeToFit.png has changed
96.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/tabletLandscape.png has changed
97.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/tabletPortrait.png has changed
98.1 Binary file launcher/fx/src/main/resources/org/apidesign/bck2brwsr/launcher/fximpl/widescreen.png has changed
99.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
99.2 +++ b/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoaderTest.java Wed Apr 30 15:04:10 2014 +0200
99.3 @@ -0,0 +1,182 @@
99.4 +/**
99.5 + * Back 2 Browser Bytecode Translator
99.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
99.7 + *
99.8 + * This program is free software: you can redistribute it and/or modify
99.9 + * it under the terms of the GNU General Public License as published by
99.10 + * the Free Software Foundation, version 2 of the License.
99.11 + *
99.12 + * This program is distributed in the hope that it will be useful,
99.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
99.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
99.15 + * GNU General Public License for more details.
99.16 + *
99.17 + * You should have received a copy of the GNU General Public License
99.18 + * along with this program. Look for COPYING file in the top folder.
99.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
99.20 + */
99.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
99.22 +
99.23 +import java.io.Reader;
99.24 +import java.lang.reflect.InvocationTargetException;
99.25 +import java.lang.reflect.Method;
99.26 +import java.net.URL;
99.27 +import java.net.URLClassLoader;
99.28 +import java.util.ArrayList;
99.29 +import java.util.Arrays;
99.30 +import java.util.Collection;
99.31 +import java.util.List;
99.32 +import javax.script.Invocable;
99.33 +import javax.script.ScriptEngine;
99.34 +import javax.script.ScriptEngineManager;
99.35 +import javax.script.ScriptException;
99.36 +import org.apidesign.html.boot.spi.Fn;
99.37 +import org.netbeans.html.boot.impl.FindResources;
99.38 +import org.netbeans.html.boot.impl.FnUtils;
99.39 +import static org.testng.Assert.*;
99.40 +import org.testng.annotations.BeforeClass;
99.41 +import org.testng.annotations.BeforeMethod;
99.42 +import org.testng.annotations.Test;
99.43 +
99.44 +/**
99.45 + *
99.46 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
99.47 + */
99.48 +public class JsClassLoaderTest {
99.49 + private static ClassLoader loader;
99.50 + private static Class<?> methodClass;
99.51 + private static Fn.Presenter presenter;
99.52 +
99.53 + public JsClassLoaderTest() {
99.54 + }
99.55 +
99.56 + @BeforeClass
99.57 + public static void setUpClass() throws Exception {
99.58 + ScriptEngineManager sem = new ScriptEngineManager();
99.59 + final ScriptEngine eng = sem.getEngineByMimeType("text/javascript");
99.60 +
99.61 + final URL my = JsClassLoaderTest.class.getProtectionDomain().getCodeSource().getLocation();
99.62 + ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent();
99.63 + final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent);
99.64 + class Fr implements FindResources, Fn.Presenter {
99.65 + @Override
99.66 + public void findResources(String path, Collection<? super URL> results, boolean oneIsEnough) {
99.67 + URL u = ul.getResource(path);
99.68 + if (u != null) {
99.69 + results.add(u);
99.70 + }
99.71 + }
99.72 +
99.73 + @Override
99.74 + public Fn defineFn(String code, String... names) {
99.75 + StringBuilder sb = new StringBuilder();
99.76 + sb.append("(function() {");
99.77 + sb.append("return function(");
99.78 + String sep = "";
99.79 + for (String n : names) {
99.80 + sb.append(sep);
99.81 + sb.append(n);
99.82 + sep = ", ";
99.83 + }
99.84 + sb.append(") {");
99.85 + sb.append(code);
99.86 + sb.append("};");
99.87 + sb.append("})()");
99.88 + try {
99.89 + final Object val = eng.eval(sb.toString());
99.90 + return new Fn(this) {
99.91 + @Override
99.92 + public Object invoke(Object thiz, Object... args) throws Exception {
99.93 + List<Object> all = new ArrayList<Object>(args.length + 1);
99.94 + all.add(thiz == null ? val : thiz);
99.95 + all.addAll(Arrays.asList(args));
99.96 + Invocable inv = (Invocable)eng;
99.97 + Object ret = inv.invokeMethod(val, "call", all.toArray());
99.98 + return val.equals(ret) ? null : ret;
99.99 + }
99.100 + };
99.101 + } catch (ScriptException ex) {
99.102 + throw new LinkageError("Can't parse: " + sb, ex);
99.103 + }
99.104 + }
99.105 +
99.106 + @Override
99.107 + public void displayPage(URL page, Runnable onPageLoad) {
99.108 + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
99.109 + }
99.110 +
99.111 + @Override
99.112 + public void loadScript(Reader code) throws Exception {
99.113 + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
99.114 + }
99.115 + }
99.116 +
99.117 + Fr fr = new Fr();
99.118 + presenter = fr;
99.119 + loader = FnUtils.newLoader(fr, fr, parent);
99.120 + methodClass = loader.loadClass(JsMethods.class.getName());
99.121 + }
99.122 +
99.123 + @BeforeMethod public void registerPresenter() {
99.124 + Fn.activate(presenter);
99.125 + }
99.126 +
99.127 + @Test public void noParamMethod() throws Throwable {
99.128 + Method plus = methodClass.getMethod("fortyTwo");
99.129 + try {
99.130 + final Object val = plus.invoke(null);
99.131 + assertTrue(val instanceof Number, "A number returned " + val);
99.132 + assertEquals(((Number)val).intValue(), 42);
99.133 + } catch (InvocationTargetException ex) {
99.134 + throw ex.getTargetException();
99.135 + }
99.136 + }
99.137 +
99.138 + @Test public void testExecuteScript() throws Throwable {
99.139 + Method plus = methodClass.getMethod("plus", int.class, int.class);
99.140 + try {
99.141 + assertEquals(plus.invoke(null, 10, 20), 30);
99.142 + } catch (InvocationTargetException ex) {
99.143 + throw ex.getTargetException();
99.144 + }
99.145 + }
99.146 +
99.147 + @Test public void overloadedMethod() throws Throwable {
99.148 + Method plus = methodClass.getMethod("plus", int.class);
99.149 + try {
99.150 + assertEquals(plus.invoke(null, 10), 10);
99.151 + } catch (InvocationTargetException ex) {
99.152 + throw ex.getTargetException();
99.153 + }
99.154 + }
99.155 +
99.156 + @Test public void instanceMethod() throws Throwable {
99.157 + Method plus = methodClass.getMethod("plusInst", int.class);
99.158 + Object inst = methodClass.newInstance();
99.159 + try {
99.160 + assertEquals(plus.invoke(inst, 10), 10);
99.161 + } catch (InvocationTargetException ex) {
99.162 + throw ex.getTargetException();
99.163 + }
99.164 + }
99.165 +
99.166 + @Test public void staticThis() throws Throwable {
99.167 + Method st = methodClass.getMethod("staticThis");
99.168 + try {
99.169 + assertNull(st.invoke(null));
99.170 + } catch (InvocationTargetException ex) {
99.171 + throw ex.getTargetException();
99.172 + }
99.173 + }
99.174 +
99.175 + @Test public void getThis() throws Throwable {
99.176 + Object th = methodClass.newInstance();
99.177 + Method st = methodClass.getMethod("getThis");
99.178 + try {
99.179 + assertEquals(st.invoke(th), th);
99.180 + } catch (InvocationTargetException ex) {
99.181 + throw ex.getTargetException();
99.182 + }
99.183 + }
99.184 +
99.185 +}
99.186 \ No newline at end of file
100.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
100.2 +++ b/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsMethods.java Wed Apr 30 15:04:10 2014 +0200
100.3 @@ -0,0 +1,45 @@
100.4 +/**
100.5 + * Back 2 Browser Bytecode Translator
100.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
100.7 + *
100.8 + * This program is free software: you can redistribute it and/or modify
100.9 + * it under the terms of the GNU General Public License as published by
100.10 + * the Free Software Foundation, version 2 of the License.
100.11 + *
100.12 + * This program is distributed in the hope that it will be useful,
100.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
100.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
100.15 + * GNU General Public License for more details.
100.16 + *
100.17 + * You should have received a copy of the GNU General Public License
100.18 + * along with this program. Look for COPYING file in the top folder.
100.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
100.20 + */
100.21 +package org.apidesign.bck2brwsr.launcher.fximpl;
100.22 +
100.23 +import net.java.html.js.JavaScriptBody;
100.24 +
100.25 +/**
100.26 + *
100.27 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
100.28 + */
100.29 +public class JsMethods {
100.30 + @JavaScriptBody(args = {}, body = "return 42;")
100.31 + public static Object fortyTwo() {
100.32 + return -42;
100.33 + }
100.34 +
100.35 + @JavaScriptBody(args = {"x", "y" }, body = "return x + y;")
100.36 + public static native int plus(int x, int y);
100.37 +
100.38 + @JavaScriptBody(args = {"x"}, body = "return x;")
100.39 + public static native int plus(int x);
100.40 +
100.41 + @JavaScriptBody(args = {}, body = "return this;")
100.42 + public static native Object staticThis();
100.43 +
100.44 + @JavaScriptBody(args = {}, body = "return this;")
100.45 + public native Object getThis();
100.46 + @JavaScriptBody(args = {"x"}, body = "return x;")
100.47 + public native int plusInst(int x);
100.48 +}
101.1 --- a/launcher/http/pom.xml Tue Apr 29 15:25:58 2014 +0200
101.2 +++ b/launcher/http/pom.xml Wed Apr 30 15:04:10 2014 +0200
101.3 @@ -4,11 +4,11 @@
101.4 <parent>
101.5 <groupId>org.apidesign.bck2brwsr</groupId>
101.6 <artifactId>launcher-pom</artifactId>
101.7 - <version>0.8-SNAPSHOT</version>
101.8 + <version>0.9-SNAPSHOT</version>
101.9 </parent>
101.10 <groupId>org.apidesign.bck2brwsr</groupId>
101.11 <artifactId>launcher.http</artifactId>
101.12 - <version>0.8-SNAPSHOT</version>
101.13 + <version>0.9-SNAPSHOT</version>
101.14 <name>Bck2Brwsr Launcher</name>
101.15 <url>http://maven.apache.org</url>
101.16 <build>
102.1 --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Tue Apr 29 15:25:58 2014 +0200
102.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/Bck2BrwsrLauncher.java Wed Apr 30 15:04:10 2014 +0200
102.3 @@ -17,9 +17,17 @@
102.4 */
102.5 package org.apidesign.bck2brwsr.launcher;
102.6
102.7 +import java.io.File;
102.8 +import java.io.FileReader;
102.9 import java.io.IOException;
102.10 +import java.io.InputStream;
102.11 +import java.io.InputStreamReader;
102.12 +import java.io.Reader;
102.13 +import java.net.MalformedURLException;
102.14 import java.net.URL;
102.15 import java.util.jar.JarFile;
102.16 +import java.util.logging.Level;
102.17 +import org.apidesign.vm4brwsr.Bck2Brwsr;
102.18
102.19 /**
102.20 * Lightweight server to launch Bck2Brwsr applications and tests.
102.21 @@ -48,15 +56,54 @@
102.22
102.23 @Override
102.24 void generateBck2BrwsrJS(StringBuilder sb, final Res loader) throws IOException {
102.25 - CompileCP.compileVM(sb, loader);
102.26 + String b2b = System.getProperty("bck2brwsr.js");
102.27 + if (b2b != null) {
102.28 + LOG.log(Level.INFO, "Serving bck2brwsr.js from {0}", b2b);
102.29 + URL bu;
102.30 + try {
102.31 + bu = new URL(b2b);
102.32 + } catch (MalformedURLException ex) {
102.33 + File f = new File(b2b);
102.34 + if (f.exists()) {
102.35 + bu = f.toURI().toURL();
102.36 + } else {
102.37 + throw ex;
102.38 + }
102.39 + }
102.40 + try (Reader r = new InputStreamReader(bu.openStream())) {
102.41 + char[] arr = new char[4096];
102.42 + for (;;) {
102.43 + int len = r.read(arr);
102.44 + if (len == -1) {
102.45 + break;
102.46 + }
102.47 + sb.append(arr, 0, len);
102.48 + }
102.49 + }
102.50 + } else {
102.51 + LOG.log(Level.INFO, "Generating bck2brwsr.js from scratch", b2b);
102.52 + CompileCP.compileVM(sb, loader);
102.53 + }
102.54 sb.append(
102.55 - "(function WrapperVM(global) {"
102.56 - + " function ldCls(res) {\n"
102.57 + "(function WrapperVM(global) {\n"
102.58 + + " var cache = {};\n"
102.59 + + " function ldCls(res, skip) {\n"
102.60 + + " var c = cache[res];\n"
102.61 + + " if (c) {\n"
102.62 + + " if (c[skip]) return c[skip];\n"
102.63 + + " if (c[skip] === null) return null;\n"
102.64 + + " } else {\n"
102.65 + + " cache[res] = c = new Array();\n"
102.66 + + " }\n"
102.67 + " var request = new XMLHttpRequest();\n"
102.68 - + " request.open('GET', '/classes/' + res, false);\n"
102.69 + + " request.open('GET', '/classes/' + res + '?skip=' + skip, false);\n"
102.70 + " request.send();\n"
102.71 - + " if (request.status !== 200) return null;\n"
102.72 + + " if (request.status !== 200) {\n"
102.73 + + " c[skip] = null;\n"
102.74 + + " return null;\n"
102.75 + + " }\n"
102.76 + " var arr = eval(request.responseText);\n"
102.77 + + " c[skip] = arr;\n"
102.78 + " return arr;\n"
102.79 + " }\n"
102.80 + " var prevvm = global.bck2brwsr;\n"
102.81 @@ -68,6 +115,7 @@
102.82 + " global.bck2brwsr.registerExtension = prevvm.registerExtension;\n"
102.83 + "})(this);\n"
102.84 );
102.85 + LOG.log(Level.INFO, "Serving bck2brwsr.js", b2b);
102.86 }
102.87
102.88 }
103.1 --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java Tue Apr 29 15:25:58 2014 +0200
103.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/CompileCP.java Wed Apr 30 15:04:10 2014 +0200
103.3 @@ -93,7 +93,7 @@
103.4 .resources(new EmulationResources() {
103.5 @Override
103.6 public InputStream get(String resource) throws IOException {
103.7 - return r != null ? r.get(resource).openStream() : super.get(resource);
103.8 + return r != null ? r.get(resource, 0).openStream() : super.get(resource);
103.9 }
103.10 })
103.11 .generate(w);
103.12 @@ -156,7 +156,7 @@
103.13 }
103.14
103.15 static void compileVM(StringBuilder sb, final Res r) throws IOException {
103.16 - URL u = r.get(InterruptedException.class.getName().replace('.', '/') + ".class");
103.17 + URL u = r.get(InterruptedException.class.getName().replace('.', '/') + ".class", 0);
103.18 JarURLConnection juc = (JarURLConnection)u.openConnection();
103.19
103.20 List<String> arr = new ArrayList<>();
103.21 @@ -167,7 +167,7 @@
103.22 .resources(new Bck2Brwsr.Resources() {
103.23 @Override
103.24 public InputStream get(String resource) throws IOException {
103.25 - return r.get(resource).openStream();
103.26 + return r.get(resource, 0).openStream();
103.27 }
103.28 }).generate(sb);
103.29 }
104.1 --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Tue Apr 29 15:25:58 2014 +0200
104.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/JSLauncher.java Wed Apr 30 15:04:10 2014 +0200
104.3 @@ -126,6 +126,10 @@
104.4 u = en.nextElement();
104.5 }
104.6 if (u != null) {
104.7 + if (u.toExternalForm().contains("rt.jar")) {
104.8 + LOG.log(Level.WARNING, "No fallback to bootclasspath for {0}", u);
104.9 + return null;
104.10 + }
104.11 return u.openStream();
104.12 }
104.13 }
105.1 --- a/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java Tue Apr 29 15:25:58 2014 +0200
105.2 +++ b/launcher/http/src/main/java/org/apidesign/bck2brwsr/launcher/impl/Console.java Wed Apr 30 15:04:10 2014 +0200
105.3 @@ -221,14 +221,22 @@
105.4 * @return the array of bytes in the given resource
105.5 * @throws IOException I/O in case something goes wrong
105.6 */
105.7 - public static byte[] read(String name) throws IOException {
105.8 + public static byte[] read(String name, int skip) throws IOException {
105.9 URL u = null;
105.10 - Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
105.11 - while (en.hasMoreElements()) {
105.12 - u = en.nextElement();
105.13 + if (!name.endsWith(".class")) {
105.14 + u = getResource(name, skip);
105.15 + } else {
105.16 + Enumeration<URL> en = Console.class.getClassLoader().getResources(name);
105.17 + while (en.hasMoreElements()) {
105.18 + u = en.nextElement();
105.19 + }
105.20 }
105.21 if (u == null) {
105.22 - throw new IOException("Can't find " + name);
105.23 + if (name.endsWith(".class")) {
105.24 + throw new IOException("Can't find " + name);
105.25 + } else {
105.26 + return null;
105.27 + }
105.28 }
105.29 try (InputStream is = u.openStream()) {
105.30 byte[] arr;
105.31 @@ -245,6 +253,19 @@
105.32 }
105.33 }
105.34
105.35 + private static URL getResource(String resource, int skip) throws IOException {
105.36 + URL u = null;
105.37 + Enumeration<URL> en = Console.class.getClassLoader().getResources(resource);
105.38 + while (en.hasMoreElements()) {
105.39 + final URL now = en.nextElement();
105.40 + if (--skip < 0) {
105.41 + u = now;
105.42 + break;
105.43 + }
105.44 + }
105.45 + return u;
105.46 + }
105.47 +
105.48 @JavaScriptBody(args = {}, body = "vm.desiredAssertionStatus = true;")
105.49 private static void turnAssetionStatusOn() {
105.50 }
106.1 --- a/launcher/pom.xml Tue Apr 29 15:25:58 2014 +0200
106.2 +++ b/launcher/pom.xml Wed Apr 30 15:04:10 2014 +0200
106.3 @@ -4,15 +4,15 @@
106.4 <parent>
106.5 <artifactId>bck2brwsr</artifactId>
106.6 <groupId>org.apidesign</groupId>
106.7 - <version>0.8-SNAPSHOT</version>
106.8 + <version>0.9-SNAPSHOT</version>
106.9 </parent>
106.10 <groupId>org.apidesign.bck2brwsr</groupId>
106.11 <artifactId>launcher-pom</artifactId>
106.12 - <version>0.8-SNAPSHOT</version>
106.13 + <version>0.9-SNAPSHOT</version>
106.14 <packaging>pom</packaging>
106.15 <name>Launchers</name>
106.16 <properties>
106.17 - <grizzly.version>2.3.2</grizzly.version>
106.18 + <grizzly.version>2.3.3</grizzly.version>
106.19 </properties>
106.20 <modules>
106.21 <module>api</module>
107.1 --- a/pom.xml Tue Apr 29 15:25:58 2014 +0200
107.2 +++ b/pom.xml Wed Apr 30 15:04:10 2014 +0200
107.3 @@ -3,7 +3,7 @@
107.4 <modelVersion>4.0.0</modelVersion>
107.5 <groupId>org.apidesign</groupId>
107.6 <artifactId>bck2brwsr</artifactId>
107.7 - <version>0.8-SNAPSHOT</version>
107.8 + <version>0.9-SNAPSHOT</version>
107.9 <packaging>pom</packaging>
107.10 <name>Back 2 Browser</name>
107.11 <parent>
107.12 @@ -15,13 +15,13 @@
107.13 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
107.14 <netbeans.version>RELEASE80</netbeans.version>
107.15 <license>COPYING</license>
107.16 + <net.java.html.version>0.7.6</net.java.html.version>
107.17 <netbeans.compile.on.save>none</netbeans.compile.on.save>
107.18 </properties>
107.19 <modules>
107.20 - <module>dew</module>
107.21 <module>javaquery</module>
107.22 <module>benchmarks</module>
107.23 - <module>ide</module>
107.24 + <module>ko</module>
107.25 <module>launcher</module>
107.26 <module>rt</module>
107.27 </modules>
107.28 @@ -85,12 +85,13 @@
107.29 <excludes>
107.30 <exclude>*</exclude>
107.31 <exclude>.*/**</exclude>
107.32 - <exclude>rt/emul/*/src/main/**</exclude>
107.33 + <exclude>rt/emul/mini/src/main/**</exclude>
107.34 + <exclude>rt/emul/compact/src/main/**</exclude>
107.35 <exclude>rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java</exclude>
107.36 <exclude>rt/archetype/src/main/resources/archetype-resources/**</exclude>
107.37 <exclude>rt/emul/*/src/test/resources/**</exclude>
107.38 - <exclude>dew/src/main/resources/org/apidesign/bck2brwsr/dew/**</exclude>
107.39 <exclude>javaquery/api/src/main/resources/org/apidesign/bck2brwsr/htmlpage/knockout*.js</exclude>
107.40 + <exclude>ko/archetype/src/main/resources/archetype-resources/**</exclude>
107.41 </excludes>
107.42 </configuration>
107.43 </plugin>
108.1 --- a/rt/archetype/pom.xml Tue Apr 29 15:25:58 2014 +0200
108.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
108.3 @@ -1,87 +0,0 @@
108.4 -<?xml version="1.0" encoding="UTF-8"?>
108.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
108.6 - <modelVersion>4.0.0</modelVersion>
108.7 - <parent>
108.8 - <artifactId>rt</artifactId>
108.9 - <groupId>org.apidesign.bck2brwsr</groupId>
108.10 - <version>0.8-SNAPSHOT</version>
108.11 - </parent>
108.12 - <groupId>org.apidesign.bck2brwsr</groupId>
108.13 - <artifactId>bck2brwsr-archetype-html-sample</artifactId>
108.14 - <version>0.8-SNAPSHOT</version>
108.15 - <packaging>jar</packaging>
108.16 - <name>Bck2Brwsr Maven Archetype</name>
108.17 - <description>
108.18 - Creates a skeletal HTML page and associated Java controller class.
108.19 - Runs in any browser (even without Java plugin) with the help of Bck2Brwsr
108.20 - virtual machine.
108.21 - </description>
108.22 - <build>
108.23 - <resources>
108.24 - <resource>
108.25 - <directory>src/main/resources</directory>
108.26 - <filtering>true</filtering>
108.27 - <includes>
108.28 - <include>**/pom.xml</include>
108.29 - </includes>
108.30 - </resource>
108.31 - <resource>
108.32 - <directory>src/main/resources</directory>
108.33 - <filtering>false</filtering>
108.34 - <excludes>
108.35 - <exclude>**/pom.xml</exclude>
108.36 - </excludes>
108.37 - </resource>
108.38 - </resources>
108.39 - <plugins>
108.40 - <plugin>
108.41 - <groupId>org.apache.maven.plugins</groupId>
108.42 - <artifactId>maven-compiler-plugin</artifactId>
108.43 - <version>2.3.2</version>
108.44 - <configuration>
108.45 - <source>1.6</source>
108.46 - <target>1.6</target>
108.47 - </configuration>
108.48 - </plugin>
108.49 - <plugin>
108.50 - <groupId>org.apache.maven.plugins</groupId>
108.51 - <artifactId>maven-resources-plugin</artifactId>
108.52 - <version>2.6</version>
108.53 - <configuration>
108.54 - <escapeString>\</escapeString>
108.55 - <target>1.6</target>
108.56 - </configuration>
108.57 - </plugin>
108.58 - <plugin>
108.59 - <groupId>org.apache.maven.plugins</groupId>
108.60 - <artifactId>maven-surefire-plugin</artifactId>
108.61 - <configuration>
108.62 - <skipTests>true</skipTests>
108.63 - </configuration>
108.64 - <executions>
108.65 - <execution>
108.66 - <id>test</id>
108.67 - <goals>
108.68 - <goal>test</goal>
108.69 - </goals>
108.70 - <phase>integration-test</phase>
108.71 - <configuration>
108.72 - <additionalClasspathElements>
108.73 - <additionalClasspathElement>${project.build.directory}/bck2brwsr-archetype-html-sample-${project.version}.jar</additionalClasspathElement>
108.74 - </additionalClasspathElements>
108.75 - <skipTests>false</skipTests>
108.76 - </configuration>
108.77 - </execution>
108.78 -
108.79 - </executions>
108.80 - </plugin>
108.81 - </plugins>
108.82 - </build>
108.83 - <dependencies>
108.84 - <dependency>
108.85 - <groupId>org.testng</groupId>
108.86 - <artifactId>testng</artifactId>
108.87 - <scope>test</scope>
108.88 - </dependency>
108.89 - </dependencies>
108.90 -</project>
109.1 --- a/rt/archetype/src/main/java/org/apidesign/bck2brwsr/archetype/package-info.java Tue Apr 29 15:25:58 2014 +0200
109.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
109.3 @@ -1,18 +0,0 @@
109.4 -/**
109.5 - * Back 2 Browser Bytecode Translator
109.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
109.7 - *
109.8 - * This program is free software: you can redistribute it and/or modify
109.9 - * it under the terms of the GNU General Public License as published by
109.10 - * the Free Software Foundation, version 2 of the License.
109.11 - *
109.12 - * This program is distributed in the hope that it will be useful,
109.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
109.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
109.15 - * GNU General Public License for more details.
109.16 - *
109.17 - * You should have received a copy of the GNU General Public License
109.18 - * along with this program. Look for COPYING file in the top folder.
109.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
109.20 - */
109.21 -package org.apidesign.bck2brwsr.archetype;
110.1 --- a/rt/archetype/src/main/resources/META-INF/maven/archetype-metadata.xml Tue Apr 29 15:25:58 2014 +0200
110.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
110.3 @@ -1,55 +0,0 @@
110.4 -<?xml version="1.0" encoding="UTF-8"?>
110.5 -<!--
110.6 -
110.7 - Back 2 Browser Bytecode Translator
110.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
110.9 -
110.10 - This program is free software: you can redistribute it and/or modify
110.11 - it under the terms of the GNU General Public License as published by
110.12 - the Free Software Foundation, version 2 of the License.
110.13 -
110.14 - This program is distributed in the hope that it will be useful,
110.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
110.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
110.17 - GNU General Public License for more details.
110.18 -
110.19 - You should have received a copy of the GNU General Public License
110.20 - along with this program. Look for COPYING file in the top folder.
110.21 - If not, see http://opensource.org/licenses/GPL-2.0.
110.22 -
110.23 --->
110.24 -<archetype-descriptor name="Get Java Bck2Brwsr!">
110.25 - <fileSets>
110.26 - <fileSet filtered="true" packaged="true">
110.27 - <directory>src/main/java</directory>
110.28 - <includes>
110.29 - <include>**/App.java</include>
110.30 - </includes>
110.31 - </fileSet>
110.32 - <fileSet filtered="true" packaged="true">
110.33 - <directory>src/main/resources</directory>
110.34 - <includes>
110.35 - <include>**/*.xhtml</include>
110.36 - <include>**/*.html</include>
110.37 - </includes>
110.38 - </fileSet>
110.39 - <fileSet filtered="true" packaged="true">
110.40 - <directory>src/test/java</directory>
110.41 - <includes>
110.42 - <include>**/*Test.java</include>
110.43 - </includes>
110.44 - </fileSet>
110.45 - <fileSet filtered="false" packaged="false">
110.46 - <directory></directory>
110.47 - <includes>
110.48 - <include>nbactions.xml</include>
110.49 - </includes>
110.50 - </fileSet>
110.51 - <fileSet filtered="true" packaged="false">
110.52 - <directory></directory>
110.53 - <includes>
110.54 - <include>bck2brwsr-assembly.xml</include>
110.55 - </includes>
110.56 - </fileSet>
110.57 - </fileSets>
110.58 -</archetype-descriptor>
110.59 \ No newline at end of file
111.1 --- a/rt/archetype/src/main/resources/archetype-resources/bck2brwsr-assembly.xml Tue Apr 29 15:25:58 2014 +0200
111.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
111.3 @@ -1,61 +0,0 @@
111.4 -<?xml version="1.0"?>
111.5 -<!--
111.6 -
111.7 - Back 2 Browser Bytecode Translator
111.8 - Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
111.9 -
111.10 - This program is free software: you can redistribute it and/or modify
111.11 - it under the terms of the GNU General Public License as published by
111.12 - the Free Software Foundation, version 2 of the License.
111.13 -
111.14 - This program is distributed in the hope that it will be useful,
111.15 - but WITHOUT ANY WARRANTY; without even the implied warranty of
111.16 - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
111.17 - GNU General Public License for more details.
111.18 -
111.19 - You should have received a copy of the GNU General Public License
111.20 - along with this program. Look for COPYING file in the top folder.
111.21 - If not, see http://opensource.org/licenses/GPL-2.0.
111.22 -
111.23 --->
111.24 -<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
111.25 - xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
111.26 -
111.27 - <id>bck2brwsr</id>
111.28 - <formats>
111.29 - <format>zip</format>
111.30 - </formats>
111.31 - <baseDirectory>public_html</baseDirectory>
111.32 - <dependencySets>
111.33 - <dependencySet>
111.34 - <useProjectArtifact>false</useProjectArtifact>
111.35 - <scope>runtime</scope>
111.36 - <outputDirectory>lib</outputDirectory>
111.37 - <includes>
111.38 - <include>*:jar</include>
111.39 - <include>*:rt</include>
111.40 - </includes>
111.41 - </dependencySet>
111.42 - <dependencySet>
111.43 - <useProjectArtifact>false</useProjectArtifact>
111.44 - <scope>provided</scope>
111.45 - <includes>
111.46 - <include>*:js</include>
111.47 - </includes>
111.48 - <unpack>true</unpack>
111.49 - <outputDirectory>/</outputDirectory>
111.50 - </dependencySet>
111.51 - </dependencySets>
111.52 - <files>
111.53 - <file>
111.54 - <source>${project.build.directory}/${project.build.finalName}.jar</source>
111.55 - <outputDirectory>/</outputDirectory>
111.56 - </file>
111.57 - <file>
111.58 - <source>${project.build.directory}/classes/${package.replace('.','/')}/index.html</source>
111.59 - <outputDirectory>/</outputDirectory>
111.60 - <destName>index.html</destName>
111.61 - </file>
111.62 - </files>
111.63 -
111.64 -</assembly>
111.65 \ No newline at end of file
112.1 --- a/rt/archetype/src/main/resources/archetype-resources/nbactions.xml Tue Apr 29 15:25:58 2014 +0200
112.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
112.3 @@ -1,10 +0,0 @@
112.4 -<?xml version="1.0" encoding="UTF-8"?>
112.5 -<actions>
112.6 - <action>
112.7 - <actionName>run</actionName>
112.8 - <goals>
112.9 - <goal>process-classes</goal>
112.10 - <goal>bck2brwsr:brwsr</goal>
112.11 - </goals>
112.12 - </action>
112.13 -</actions>
113.1 --- a/rt/archetype/src/main/resources/archetype-resources/pom.xml Tue Apr 29 15:25:58 2014 +0200
113.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
113.3 @@ -1,135 +0,0 @@
113.4 -<?xml version="1.0"?>
113.5 -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
113.6 - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
113.7 - <modelVersion>4.0.0</modelVersion>
113.8 -
113.9 - <groupId>\${groupId}</groupId>
113.10 - <artifactId>\${artifactId}</artifactId>
113.11 - <version>\${version}</version>
113.12 - <packaging>jar</packaging>
113.13 -
113.14 - <name>\${artifactId}</name>
113.15 -
113.16 - <repositories>
113.17 - <repository>
113.18 - <id>java.net</id>
113.19 - <name>Java.net</name>
113.20 - <url>https://maven.java.net/content/repositories/releases/</url>
113.21 - <snapshots>
113.22 - <enabled>true</enabled>
113.23 - </snapshots>
113.24 - </repository>
113.25 - <repository>
113.26 - <id>netbeans</id>
113.27 - <name>NetBeans</name>
113.28 - <url>http://bits.netbeans.org/maven2/</url>
113.29 - </repository>
113.30 - </repositories>
113.31 - <pluginRepositories>
113.32 - <pluginRepository>
113.33 - <id>java.net</id>
113.34 - <name>Java.net</name>
113.35 - <url>https://maven.java.net/content/repositories/releases/</url>
113.36 - <snapshots>
113.37 - <enabled>true</enabled>
113.38 - </snapshots>
113.39 - </pluginRepository>
113.40 - </pluginRepositories>
113.41 -
113.42 - <properties>
113.43 - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
113.44 - </properties>
113.45 - <build>
113.46 - <plugins>
113.47 - <plugin>
113.48 - <groupId>org.apidesign.bck2brwsr</groupId>
113.49 - <artifactId>bck2brwsr-maven-plugin</artifactId>
113.50 - <version>${project.version}</version>
113.51 - <executions>
113.52 - <execution>
113.53 - <goals>
113.54 - <goal>brwsr</goal>
113.55 - </goals>
113.56 - </execution>
113.57 - </executions>
113.58 - <configuration>
113.59 - <startpage>\${package.replace('.','/')}/index.html</startpage>
113.60 - </configuration>
113.61 - </plugin>
113.62 - <plugin>
113.63 - <groupId>org.apache.maven.plugins</groupId>
113.64 - <artifactId>maven-compiler-plugin</artifactId>
113.65 - <version>2.3.2</version>
113.66 - <configuration>
113.67 - <source>1.7</source>
113.68 - <target>1.7</target>
113.69 - </configuration>
113.70 - </plugin>
113.71 - <plugin>
113.72 - <groupId>org.apache.maven.plugins</groupId>
113.73 - <artifactId>maven-jar-plugin</artifactId>
113.74 - <version>2.4</version>
113.75 - <configuration>
113.76 - <archive>
113.77 - <manifest>
113.78 - <addClasspath>true</addClasspath>
113.79 - <classpathPrefix>lib/</classpathPrefix>
113.80 - </manifest>
113.81 - </archive>
113.82 - </configuration>
113.83 - </plugin>
113.84 - <plugin>
113.85 - <artifactId>maven-assembly-plugin</artifactId>
113.86 - <version>2.4</version>
113.87 - <executions>
113.88 - <execution>
113.89 - <id>distro-assembly</id>
113.90 - <phase>package</phase>
113.91 - <goals>
113.92 - <goal>single</goal>
113.93 - </goals>
113.94 - <configuration>
113.95 - <descriptors>
113.96 - <descriptor>bck2brwsr-assembly.xml</descriptor>
113.97 - </descriptors>
113.98 - </configuration>
113.99 - </execution>
113.100 - </executions>
113.101 - </plugin>
113.102 - </plugins>
113.103 - </build>
113.104 -
113.105 - <dependencies>
113.106 - <dependency>
113.107 - <groupId>org.apidesign.bck2brwsr</groupId>
113.108 - <artifactId>emul</artifactId>
113.109 - <version>${project.version}</version>
113.110 - <classifier>rt</classifier>
113.111 - </dependency>
113.112 - <dependency>
113.113 - <groupId>org.apidesign.bck2brwsr</groupId>
113.114 - <artifactId>javaquery.api</artifactId>
113.115 - <version>${project.version}</version>
113.116 - </dependency>
113.117 - <dependency>
113.118 - <groupId>org.testng</groupId>
113.119 - <artifactId>testng</artifactId>
113.120 - <version>6.5.2</version>
113.121 - <scope>test</scope>
113.122 - </dependency>
113.123 - <dependency>
113.124 - <groupId>org.apidesign.bck2brwsr</groupId>
113.125 - <artifactId>vm4brwsr</artifactId>
113.126 - <classifier>js</classifier>
113.127 - <type>zip</type>
113.128 - <version>${project.version}</version>
113.129 - <scope>provided</scope>
113.130 - </dependency>
113.131 - <dependency>
113.132 - <groupId>org.apidesign.bck2brwsr</groupId>
113.133 - <artifactId>vmtest</artifactId>
113.134 - <version>${project.version}</version>
113.135 - <scope>test</scope>
113.136 - </dependency>
113.137 - </dependencies>
113.138 -</project>
114.1 --- a/rt/archetype/src/main/resources/archetype-resources/src/main/java/App.java Tue Apr 29 15:25:58 2014 +0200
114.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
114.3 @@ -1,88 +0,0 @@
114.4 -package ${package};
114.5 -
114.6 -import java.util.List;
114.7 -import org.apidesign.bck2brwsr.htmlpage.api.*;
114.8 -import static org.apidesign.bck2brwsr.htmlpage.api.OnEvent.*;
114.9 -import org.apidesign.bck2brwsr.htmlpage.api.Page;
114.10 -import org.apidesign.bck2brwsr.htmlpage.api.Property;
114.11 -import org.apidesign.bck2brwsr.htmlpage.api.ComputedProperty;
114.12 -
114.13 -/** This is the controller class for associated index.html page. The <code>Index</code>
114.14 - * is autogenerated by parsing the index.html page. It fields represent individual
114.15 - * elements annotated by "id" in the page.
114.16 - */
114.17 -@Page(xhtml="index.html", className="Index", properties={
114.18 - @Property(name="name", type=String.class),
114.19 - @Property(name="messages", type=String.class, array=true),
114.20 -})
114.21 -public class App {
114.22 - static {
114.23 - Index model = new Index();
114.24 - model.setName("World");
114.25 - model.applyBindings();
114.26 - }
114.27 -
114.28 - /**
114.29 - * @param m the model of the index page creates in static initializer
114.30 - */
114.31 - @On(event = CLICK, id="hello")
114.32 - static void hello(Index m) {
114.33 - display(m.getHelloMessage(), m);
114.34 - m.getMessages().add(m.getHelloMessage());
114.35 - }
114.36 -
114.37 - /** Reacts when mouse moves over the canvas.
114.38 - *
114.39 - * @param m the model of the page
114.40 - * @param x property "x" extracted from the event generated by the browser
114.41 - * @param y property "y" from the mouse event
114.42 - */
114.43 - @On(event = MOUSE_MOVE, id="canvas")
114.44 - static void clearPoint(Index m, int x, int y) {
114.45 - GraphicsContext g = m.canvas.getContext();
114.46 - boolean even = (x + y) % 2 == 0;
114.47 - if (even) {
114.48 - g.setFillStyle("blue");
114.49 - } else {
114.50 - g.setFillStyle("red");
114.51 - }
114.52 - g.clearRect(0, 0, 1000, 1000);
114.53 - g.setFont("italic 40px Calibri");
114.54 - g.fillText(m.getHelloMessage(), 10, 40);
114.55 - }
114.56 -
114.57 - /** Callback function called by the KnockOut/Java binding on elements
114.58 - * representing href's with individual messages being their data.
114.59 - *
114.60 - * @param data the data associated with the element
114.61 - * @param m the model of the page
114.62 - */
114.63 - @OnFunction
114.64 - static void display(String data, Index m) {
114.65 - GraphicsContext g = m.canvas.getContext();
114.66 - g.clearRect(0, 0, 1000, 1000);
114.67 - g.setFillStyle("black");
114.68 - g.setFont("italic 40px Calibri");
114.69 - g.fillText(data, 10, 40);
114.70 - }
114.71 -
114.72 - /** Callback function.
114.73 - *
114.74 - * @param data data associated with the actual element on the page
114.75 - * @param m the model of the page
114.76 - */
114.77 - @OnFunction
114.78 - static void remove(String data, Index m) {
114.79 - m.getMessages().remove(data);
114.80 - }
114.81 -
114.82 - @ComputedProperty
114.83 - static String helloMessage(String name) {
114.84 - return "Hello " + name + "!";
114.85 - }
114.86 -
114.87 - @ComputedProperty
114.88 - static boolean noMessages(List<String> messages) {
114.89 - return messages.isEmpty();
114.90 - }
114.91 -}
115.1 --- a/rt/archetype/src/main/resources/archetype-resources/src/main/resources/index.html Tue Apr 29 15:25:58 2014 +0200
115.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
115.3 @@ -1,31 +0,0 @@
115.4 -<?xml version="1.0" encoding="UTF-8"?>
115.5 -<!DOCTYPE html>
115.6 -<html xmlns="http://www.w3.org/1999/xhtml">
115.7 - <head>
115.8 - <title>Bck2Brwsr's Hello World</title>
115.9 - </head>
115.10 - <body>
115.11 - <h1 data-bind="text: helloMessage">Loading Bck2Brwsr's Hello World...</h1>
115.12 - Your name: <input id='input' data-bind="value: name, valueUpdate: 'afterkeydown'"></input>
115.13 - <button id="hello">Say Hello!</button>
115.14 - <p>
115.15 - <canvas id="canvas" width="300" height="50">
115.16 - </canvas>
115.17 - </p>
115.18 -
115.19 -
115.20 - <div data-bind="if: noMessages">No message displayed yet.</div>
115.21 - <ul data-bind="foreach: messages">
115.22 - <li>
115.23 - <a href="#" data-bind="text: $data, click: $root.display"></a>
115.24 - (<a href="#" data-bind="click: $root.remove">delete</a>)
115.25 - </li>
115.26 - </ul>
115.27 -
115.28 - <script src="bck2brwsr.js"></script>
115.29 - <script type="text/javascript">
115.30 - var vm = bck2brwsr('${artifactId}-${version}.jar');
115.31 - vm.loadClass('${package}.App');
115.32 - </script>
115.33 - </body>
115.34 -</html>
116.1 --- a/rt/archetype/src/main/resources/archetype-resources/src/test/java/AppTest.java Tue Apr 29 15:25:58 2014 +0200
116.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
116.3 @@ -1,26 +0,0 @@
116.4 -package ${package};
116.5 -
116.6 -import static org.testng.Assert.*;
116.7 -import org.testng.annotations.BeforeMethod;
116.8 -import org.testng.annotations.Test;
116.9 -
116.10 -/** Demonstrating POJO testing of HTML page model. Runs in good old HotSpot
116.11 - * as it does not reference any HTML elements or browser functionality. Just
116.12 - * operates on the page model.
116.13 - *
116.14 - * @author Jaroslav Tulach <jtulach@netbeans.org>
116.15 - */
116.16 -public class AppTest {
116.17 - private Index model;
116.18 -
116.19 -
116.20 - @BeforeMethod
116.21 - public void initModel() {
116.22 - model = new Index().applyBindings();
116.23 - }
116.24 -
116.25 - @Test public void testHelloMessage() {
116.26 - model.setName("Joe");
116.27 - assertEquals(model.getHelloMessage(), "Hello Joe!", "Cleared after pressing +");
116.28 - }
116.29 -}
117.1 --- a/rt/archetype/src/main/resources/archetype-resources/src/test/java/InconsistencyTest.java Tue Apr 29 15:25:58 2014 +0200
117.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
117.3 @@ -1,40 +0,0 @@
117.4 -package ${package};
117.5 -
117.6 -import org.apidesign.bck2brwsr.vmtest.Compare;
117.7 -import org.apidesign.bck2brwsr.vmtest.VMTest;
117.8 -import org.testng.annotations.Factory;
117.9 -
117.10 -/** Bck2brwsr cares about compatibility with real Java. Whatever API is
117.11 - * supported by bck2brwsr, it needs to behave the same way as when running
117.12 - * in HotSpot VM.
117.13 - * <p>
117.14 - * There can be bugs, however. To help us fix them, we kindly ask you to
117.15 - * write an "inconsistency" test. A test that compares behavior of the API
117.16 - * between real VM and bck2brwsr VM. This class is skeleton of such test.
117.17 - *
117.18 - * @author Jaroslav Tulach <jtulach@netbeans.org>
117.19 - */
117.20 -public class InconsistencyTest {
117.21 - /** A method to demonstrate inconsistency between bck2brwsr and HotSpot.
117.22 - * Make calls to an API that behaves strangely, return some result at
117.23 - * the end. No need to use any <code>assert</code>.
117.24 - *
117.25 - * @return value to compare between HotSpot and bck2brwsr
117.26 - */
117.27 - @Compare
117.28 - public int checkStringHashCode() throws Exception {
117.29 - return "Is string hashCode the same?".hashCode();
117.30 - }
117.31 -
117.32 - /** Factory method that creates a three tests for each method annotated with
117.33 - * {@link org.apidesign.bck2brwsr.vmtest.Compare}. One executes the code in
117.34 - * HotSpot, one in Rhino and the last one compares the results.
117.35 - *
117.36 - * @see org.apidesign.bck2brwsr.vmtest.VMTest
117.37 - */
117.38 - @Factory
117.39 - public static Object[] create() {
117.40 - return VMTest.create(InconsistencyTest.class);
117.41 - }
117.42 -
117.43 -}
118.1 --- a/rt/archetype/src/main/resources/archetype-resources/src/test/java/IntegrationTest.java Tue Apr 29 15:25:58 2014 +0200
118.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
118.3 @@ -1,46 +0,0 @@
118.4 -package ${package};
118.5 -
118.6 -import org.apidesign.bck2brwsr.htmlpage.api.OnEvent;
118.7 -import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
118.8 -import org.apidesign.bck2brwsr.vmtest.HtmlFragment;
118.9 -import org.apidesign.bck2brwsr.vmtest.VMTest;
118.10 -import org.testng.annotations.Factory;
118.11 -
118.12 -/** Sometimes it is useful to run tests inside of the real browser.
118.13 - * To do that just annotate your method with {@link org.apidesign.bck2brwsr.vmtest.BrwsrTest}
118.14 - * and that is it. If your code references elements on the HTML page,
118.15 - * you can pass in an {@link org.apidesign.bck2brwsr.vmtest.HtmlFragment} which
118.16 - * will be made available on the page before your test starts.
118.17 - *
118.18 - * @author Jaroslav Tulach <jtulach@netbeans.org>
118.19 - */
118.20 -public class IntegrationTest {
118.21 -
118.22 - /** Write to testing code here. Use <code>assert</code> (but not TestNG's
118.23 - * Assert, as TestNG is not compiled with target 1.6 yet).
118.24 - */
118.25 - @HtmlFragment(
118.26 - "<h1 data-bind=\"text: helloMessage\">Loading Bck2Brwsr's Hello World...</h1>\n" +
118.27 - "Your name: <input id='input' data-bind=\"value: name, valueUpdate: 'afterkeydown'\"></input>\n" +
118.28 - "<button id=\"hello\">Say Hello!</button>\n" +
118.29 - "<p>\n" +
118.30 - " <canvas id=\"canvas\" width=\"300\" height=\"50\"></canvas>\n" +
118.31 - "</p>\n"
118.32 - )
118.33 - @BrwsrTest
118.34 - public void modifyValueAssertChangeInModel() {
118.35 - Index m = new Index();
118.36 - m.setName("Joe Hacker");
118.37 - m.applyBindings();
118.38 - assert "Joe Hacker".equals(m.input.getValue()) : "Value is really Joe Hacker: " + m.input.getValue();
118.39 - m.input.setValue("Happy Joe");
118.40 - m.triggerEvent(m.input, OnEvent.CHANGE);
118.41 - assert "Happy Joe".equals(m.getName()) : "Name property updated to Happy Joe: " + m.getName();
118.42 - }
118.43 -
118.44 - @Factory
118.45 - public static Object[] create() {
118.46 - return VMTest.create(IntegrationTest.class);
118.47 - }
118.48 -
118.49 -}
119.1 --- a/rt/archetype/src/test/java/org/apidesign/bck2brwsr/archetype/ArchetypeVersionTest.java Tue Apr 29 15:25:58 2014 +0200
119.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
119.3 @@ -1,101 +0,0 @@
119.4 -/**
119.5 - * Back 2 Browser Bytecode Translator
119.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
119.7 - *
119.8 - * This program is free software: you can redistribute it and/or modify
119.9 - * it under the terms of the GNU General Public License as published by
119.10 - * the Free Software Foundation, version 2 of the License.
119.11 - *
119.12 - * This program is distributed in the hope that it will be useful,
119.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
119.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
119.15 - * GNU General Public License for more details.
119.16 - *
119.17 - * You should have received a copy of the GNU General Public License
119.18 - * along with this program. Look for COPYING file in the top folder.
119.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
119.20 - */
119.21 -package org.apidesign.bck2brwsr.archetype;
119.22 -
119.23 -import java.net.URL;
119.24 -import javax.xml.XMLConstants;
119.25 -import javax.xml.parsers.DocumentBuilderFactory;
119.26 -import javax.xml.xpath.XPathConstants;
119.27 -import javax.xml.xpath.XPathExpression;
119.28 -import javax.xml.xpath.XPathFactory;
119.29 -import org.testng.annotations.Test;
119.30 -import static org.testng.Assert.*;
119.31 -import org.testng.annotations.BeforeClass;
119.32 -import org.w3c.dom.Document;
119.33 -import org.w3c.dom.NodeList;
119.34 -
119.35 -/**
119.36 - *
119.37 - * @author Jaroslav Tulach <jtulach@netbeans.org>
119.38 - */
119.39 -public class ArchetypeVersionTest {
119.40 - private String version;
119.41 -
119.42 - public ArchetypeVersionTest() {
119.43 - }
119.44 -
119.45 - @BeforeClass public void readCurrentVersion() throws Exception {
119.46 - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
119.47 - URL u = l.getResource("META-INF/maven/org.apidesign.bck2brwsr/bck2brwsr-archetype-html-sample/pom.xml");
119.48 - assertNotNull(u, "Own pom found: " + System.getProperty("java.class.path"));
119.49 -
119.50 - final XPathFactory fact = XPathFactory.newInstance();
119.51 - fact.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
119.52 -
119.53 - XPathExpression xp = fact.newXPath().compile("project/version/text()");
119.54 -
119.55 - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(u.openStream());
119.56 - version = xp.evaluate(dom);
119.57 -
119.58 - assertFalse(version.isEmpty(), "There should be some version string");
119.59 - }
119.60 -
119.61 -
119.62 - @Test public void testComparePomDepsVersions() throws Exception {
119.63 - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
119.64 - URL r = l.getResource("archetype-resources/pom.xml");
119.65 - assertNotNull(r, "Archetype pom found");
119.66 -
119.67 - final XPathFactory fact = XPathFactory.newInstance();
119.68 - XPathExpression xp2 = fact.newXPath().compile(
119.69 - "//version[../groupId/text() = 'org.apidesign.bck2brwsr']/text()"
119.70 - );
119.71 -
119.72 - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
119.73 - NodeList arch = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET);
119.74 -
119.75 - if (arch.getLength() < 3) {
119.76 - fail("There should be at least three dependencies to bck2brwsr APIs: " + arch.getLength());
119.77 - }
119.78 -
119.79 - for (int i = 0; i < arch.getLength(); i++) {
119.80 - assertEquals(arch.item(i).getTextContent(), version, i + "th dependency needs to be on latest version of bck2brwsr");
119.81 - }
119.82 - }
119.83 -
119.84 - @Test public void testNbActions() throws Exception {
119.85 - final ClassLoader l = ArchetypeVersionTest.class.getClassLoader();
119.86 - URL r = l.getResource("archetype-resources/nbactions.xml");
119.87 - assertNotNull(r, "Archetype nb file found");
119.88 -
119.89 - final XPathFactory fact = XPathFactory.newInstance();
119.90 - XPathExpression xp2 = fact.newXPath().compile(
119.91 - "//goal/text()"
119.92 - );
119.93 -
119.94 - Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(r.openStream());
119.95 - NodeList goals = (NodeList) xp2.evaluate(dom, XPathConstants.NODESET);
119.96 -
119.97 - for (int i = 0; i < goals.getLength(); i++) {
119.98 - String s = goals.item(i).getTextContent();
119.99 - if (s.contains("bck2brwsr")) {
119.100 - assertFalse(s.matches(".*bck2brwsr.*[0-9].*"), "No numbers: " + s);
119.101 - }
119.102 - }
119.103 - }
119.104 -}
120.1 --- a/rt/core/pom.xml Tue Apr 29 15:25:58 2014 +0200
120.2 +++ b/rt/core/pom.xml Wed Apr 30 15:04:10 2014 +0200
120.3 @@ -4,11 +4,11 @@
120.4 <parent>
120.5 <groupId>org.apidesign.bck2brwsr</groupId>
120.6 <artifactId>rt</artifactId>
120.7 - <version>0.8-SNAPSHOT</version>
120.8 + <version>0.9-SNAPSHOT</version>
120.9 </parent>
120.10 <groupId>org.apidesign.bck2brwsr</groupId>
120.11 <artifactId>core</artifactId>
120.12 - <version>0.8-SNAPSHOT</version>
120.13 + <version>0.9-SNAPSHOT</version>
120.14 <name>Bck2Brwsr Native Annotations</name>
120.15 <url>http://maven.apache.org</url>
120.16 <build>
121.1 --- a/rt/emul/brwsrtest/pom.xml Tue Apr 29 15:25:58 2014 +0200
121.2 +++ b/rt/emul/brwsrtest/pom.xml Wed Apr 30 15:04:10 2014 +0200
121.3 @@ -4,11 +4,11 @@
121.4 <parent>
121.5 <groupId>org.apidesign.bck2brwsr</groupId>
121.6 <artifactId>emul.pom</artifactId>
121.7 - <version>0.8-SNAPSHOT</version>
121.8 + <version>0.9-SNAPSHOT</version>
121.9 </parent>
121.10 <groupId>org.apidesign.bck2brwsr</groupId>
121.11 <artifactId>brwsrtest</artifactId>
121.12 - <version>0.8-SNAPSHOT</version>
121.13 + <version>0.9-SNAPSHOT</version>
121.14 <name>Tests Inside Real Browser</name>
121.15 <url>http://maven.apache.org</url>
121.16 <properties>
122.1 --- a/rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/ResourcesInBrwsrTest.java Tue Apr 29 15:25:58 2014 +0200
122.2 +++ b/rt/emul/brwsrtest/src/test/java/org/apidesign/bck2brwsr/brwsrtest/ResourcesInBrwsrTest.java Wed Apr 30 15:04:10 2014 +0200
122.3 @@ -17,7 +17,10 @@
122.4 */
122.5 package org.apidesign.bck2brwsr.brwsrtest;
122.6
122.7 +import java.io.IOException;
122.8 import java.io.InputStream;
122.9 +import java.net.URL;
122.10 +import java.util.Enumeration;
122.11 import org.apidesign.bck2brwsr.vmtest.Compare;
122.12 import org.apidesign.bck2brwsr.vmtest.VMTest;
122.13 import org.testng.annotations.Factory;
122.14 @@ -30,14 +33,36 @@
122.15
122.16 @Compare public String readResourceAsStream() throws Exception {
122.17 InputStream is = getClass().getResourceAsStream("Resources.txt");
122.18 - assert is != null : "The stream for Resources.txt should be found";
122.19 - byte[] b = new byte[30];
122.20 - int len = is.read(b);
122.21 + return readString(is);
122.22 + }
122.23 +
122.24 + @Compare public String readResourceViaConnection() throws Exception {
122.25 + InputStream is = getClass().getResource("Resources.txt").openConnection().getInputStream();
122.26 + return readString(is);
122.27 + }
122.28 +
122.29 + private String readString(InputStream is) throws IOException {
122.30 StringBuilder sb = new StringBuilder();
122.31 - for (int i = 0; i < len; i++) {
122.32 - sb.append((char)b[i]);
122.33 + byte[] b = new byte[512];
122.34 + for (;;) {
122.35 + int len = is.read(b);
122.36 + if (len == -1) {
122.37 + return sb.toString();
122.38 + }
122.39 + for (int i = 0; i < len; i++) {
122.40 + sb.append((char)b[i]);
122.41 + }
122.42 }
122.43 - return sb.toString();
122.44 + }
122.45 +
122.46 + @Compare public String readResourceAsStreamFromClassLoader() throws Exception {
122.47 + InputStream is = getClass().getClassLoader().getResourceAsStream("org/apidesign/bck2brwsr/brwsrtest/Resources.txt");
122.48 + return readString(is);
122.49 + }
122.50 +
122.51 + @Compare public String toURIFromURL() throws Exception {
122.52 + URL u = new URL("http://apidesign.org");
122.53 + return u.toURI().toString();
122.54 }
122.55
122.56 @Factory public static Object[] create() {
123.1 --- a/rt/emul/compact/pom.xml Tue Apr 29 15:25:58 2014 +0200
123.2 +++ b/rt/emul/compact/pom.xml Wed Apr 30 15:04:10 2014 +0200
123.3 @@ -4,11 +4,11 @@
123.4 <parent>
123.5 <groupId>org.apidesign.bck2brwsr</groupId>
123.6 <artifactId>emul.pom</artifactId>
123.7 - <version>0.8-SNAPSHOT</version>
123.8 + <version>0.9-SNAPSHOT</version>
123.9 </parent>
123.10 <groupId>org.apidesign.bck2brwsr</groupId>
123.11 <artifactId>emul</artifactId>
123.12 - <version>0.8-SNAPSHOT</version>
123.13 + <version>0.9-SNAPSHOT</version>
123.14 <name>Bck2Brwsr API Profile</name>
123.15 <url>http://maven.apache.org</url>
123.16 <properties>
124.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
124.2 +++ b/rt/emul/compact/src/main/java/java/io/BufferedInputStream.java Wed Apr 30 15:04:10 2014 +0200
124.3 @@ -0,0 +1,458 @@
124.4 +/*
124.5 + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
124.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
124.7 + *
124.8 + * This code is free software; you can redistribute it and/or modify it
124.9 + * under the terms of the GNU General Public License version 2 only, as
124.10 + * published by the Free Software Foundation. Oracle designates this
124.11 + * particular file as subject to the "Classpath" exception as provided
124.12 + * by Oracle in the LICENSE file that accompanied this code.
124.13 + *
124.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
124.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
124.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
124.17 + * version 2 for more details (a copy is included in the LICENSE file that
124.18 + * accompanied this code).
124.19 + *
124.20 + * You should have received a copy of the GNU General Public License version
124.21 + * 2 along with this work; if not, write to the Free Software Foundation,
124.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
124.23 + *
124.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
124.25 + * or visit www.oracle.com if you need additional information or have any
124.26 + * questions.
124.27 + */
124.28 +
124.29 +package java.io;
124.30 +
124.31 +/**
124.32 + * A <code>BufferedInputStream</code> adds
124.33 + * functionality to another input stream-namely,
124.34 + * the ability to buffer the input and to
124.35 + * support the <code>mark</code> and <code>reset</code>
124.36 + * methods. When the <code>BufferedInputStream</code>
124.37 + * is created, an internal buffer array is
124.38 + * created. As bytes from the stream are read
124.39 + * or skipped, the internal buffer is refilled
124.40 + * as necessary from the contained input stream,
124.41 + * many bytes at a time. The <code>mark</code>
124.42 + * operation remembers a point in the input
124.43 + * stream and the <code>reset</code> operation
124.44 + * causes all the bytes read since the most
124.45 + * recent <code>mark</code> operation to be
124.46 + * reread before new bytes are taken from
124.47 + * the contained input stream.
124.48 + *
124.49 + * @author Arthur van Hoff
124.50 + * @since JDK1.0
124.51 + */
124.52 +public
124.53 +class BufferedInputStream extends FilterInputStream {
124.54 +
124.55 + private static int defaultBufferSize = 8192;
124.56 +
124.57 + /**
124.58 + * The internal buffer array where the data is stored. When necessary,
124.59 + * it may be replaced by another array of
124.60 + * a different size.
124.61 + */
124.62 + protected volatile byte buf[];
124.63 +
124.64 +
124.65 + /**
124.66 + * The index one greater than the index of the last valid byte in
124.67 + * the buffer.
124.68 + * This value is always
124.69 + * in the range <code>0</code> through <code>buf.length</code>;
124.70 + * elements <code>buf[0]</code> through <code>buf[count-1]
124.71 + * </code>contain buffered input data obtained
124.72 + * from the underlying input stream.
124.73 + */
124.74 + protected int count;
124.75 +
124.76 + /**
124.77 + * The current position in the buffer. This is the index of the next
124.78 + * character to be read from the <code>buf</code> array.
124.79 + * <p>
124.80 + * This value is always in the range <code>0</code>
124.81 + * through <code>count</code>. If it is less
124.82 + * than <code>count</code>, then <code>buf[pos]</code>
124.83 + * is the next byte to be supplied as input;
124.84 + * if it is equal to <code>count</code>, then
124.85 + * the next <code>read</code> or <code>skip</code>
124.86 + * operation will require more bytes to be
124.87 + * read from the contained input stream.
124.88 + *
124.89 + * @see java.io.BufferedInputStream#buf
124.90 + */
124.91 + protected int pos;
124.92 +
124.93 + /**
124.94 + * The value of the <code>pos</code> field at the time the last
124.95 + * <code>mark</code> method was called.
124.96 + * <p>
124.97 + * This value is always
124.98 + * in the range <code>-1</code> through <code>pos</code>.
124.99 + * If there is no marked position in the input
124.100 + * stream, this field is <code>-1</code>. If
124.101 + * there is a marked position in the input
124.102 + * stream, then <code>buf[markpos]</code>
124.103 + * is the first byte to be supplied as input
124.104 + * after a <code>reset</code> operation. If
124.105 + * <code>markpos</code> is not <code>-1</code>,
124.106 + * then all bytes from positions <code>buf[markpos]</code>
124.107 + * through <code>buf[pos-1]</code> must remain
124.108 + * in the buffer array (though they may be
124.109 + * moved to another place in the buffer array,
124.110 + * with suitable adjustments to the values
124.111 + * of <code>count</code>, <code>pos</code>,
124.112 + * and <code>markpos</code>); they may not
124.113 + * be discarded unless and until the difference
124.114 + * between <code>pos</code> and <code>markpos</code>
124.115 + * exceeds <code>marklimit</code>.
124.116 + *
124.117 + * @see java.io.BufferedInputStream#mark(int)
124.118 + * @see java.io.BufferedInputStream#pos
124.119 + */
124.120 + protected int markpos = -1;
124.121 +
124.122 + /**
124.123 + * The maximum read ahead allowed after a call to the
124.124 + * <code>mark</code> method before subsequent calls to the
124.125 + * <code>reset</code> method fail.
124.126 + * Whenever the difference between <code>pos</code>
124.127 + * and <code>markpos</code> exceeds <code>marklimit</code>,
124.128 + * then the mark may be dropped by setting
124.129 + * <code>markpos</code> to <code>-1</code>.
124.130 + *
124.131 + * @see java.io.BufferedInputStream#mark(int)
124.132 + * @see java.io.BufferedInputStream#reset()
124.133 + */
124.134 + protected int marklimit;
124.135 +
124.136 + /**
124.137 + * Check to make sure that underlying input stream has not been
124.138 + * nulled out due to close; if not return it;
124.139 + */
124.140 + private InputStream getInIfOpen() throws IOException {
124.141 + InputStream input = in;
124.142 + if (input == null)
124.143 + throw new IOException("Stream closed");
124.144 + return input;
124.145 + }
124.146 +
124.147 + /**
124.148 + * Check to make sure that buffer has not been nulled out due to
124.149 + * close; if not return it;
124.150 + */
124.151 + private byte[] getBufIfOpen() throws IOException {
124.152 + byte[] buffer = buf;
124.153 + if (buffer == null)
124.154 + throw new IOException("Stream closed");
124.155 + return buffer;
124.156 + }
124.157 +
124.158 + /**
124.159 + * Creates a <code>BufferedInputStream</code>
124.160 + * and saves its argument, the input stream
124.161 + * <code>in</code>, for later use. An internal
124.162 + * buffer array is created and stored in <code>buf</code>.
124.163 + *
124.164 + * @param in the underlying input stream.
124.165 + */
124.166 + public BufferedInputStream(InputStream in) {
124.167 + this(in, defaultBufferSize);
124.168 + }
124.169 +
124.170 + /**
124.171 + * Creates a <code>BufferedInputStream</code>
124.172 + * with the specified buffer size,
124.173 + * and saves its argument, the input stream
124.174 + * <code>in</code>, for later use. An internal
124.175 + * buffer array of length <code>size</code>
124.176 + * is created and stored in <code>buf</code>.
124.177 + *
124.178 + * @param in the underlying input stream.
124.179 + * @param size the buffer size.
124.180 + * @exception IllegalArgumentException if size <= 0.
124.181 + */
124.182 + public BufferedInputStream(InputStream in, int size) {
124.183 + super(in);
124.184 + if (size <= 0) {
124.185 + throw new IllegalArgumentException("Buffer size <= 0");
124.186 + }
124.187 + buf = new byte[size];
124.188 + }
124.189 +
124.190 + /**
124.191 + * Fills the buffer with more data, taking into account
124.192 + * shuffling and other tricks for dealing with marks.
124.193 + * Assumes that it is being called by a synchronized method.
124.194 + * This method also assumes that all data has already been read in,
124.195 + * hence pos > count.
124.196 + */
124.197 + private void fill() throws IOException {
124.198 + byte[] buffer = getBufIfOpen();
124.199 + if (markpos < 0)
124.200 + pos = 0; /* no mark: throw away the buffer */
124.201 + else if (pos >= buffer.length) /* no room left in buffer */
124.202 + if (markpos > 0) { /* can throw away early part of the buffer */
124.203 + int sz = pos - markpos;
124.204 + System.arraycopy(buffer, markpos, buffer, 0, sz);
124.205 + pos = sz;
124.206 + markpos = 0;
124.207 + } else if (buffer.length >= marklimit) {
124.208 + markpos = -1; /* buffer got too big, invalidate mark */
124.209 + pos = 0; /* drop buffer contents */
124.210 + } else { /* grow buffer */
124.211 + int nsz = pos * 2;
124.212 + if (nsz > marklimit)
124.213 + nsz = marklimit;
124.214 + byte nbuf[] = new byte[nsz];
124.215 + System.arraycopy(buffer, 0, nbuf, 0, pos);
124.216 + buffer = nbuf;
124.217 + }
124.218 + count = pos;
124.219 + int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
124.220 + if (n > 0)
124.221 + count = n + pos;
124.222 + }
124.223 +
124.224 + /**
124.225 + * See
124.226 + * the general contract of the <code>read</code>
124.227 + * method of <code>InputStream</code>.
124.228 + *
124.229 + * @return the next byte of data, or <code>-1</code> if the end of the
124.230 + * stream is reached.
124.231 + * @exception IOException if this input stream has been closed by
124.232 + * invoking its {@link #close()} method,
124.233 + * or an I/O error occurs.
124.234 + * @see java.io.FilterInputStream#in
124.235 + */
124.236 + public synchronized int read() throws IOException {
124.237 + if (pos >= count) {
124.238 + fill();
124.239 + if (pos >= count)
124.240 + return -1;
124.241 + }
124.242 + return getBufIfOpen()[pos++] & 0xff;
124.243 + }
124.244 +
124.245 + /**
124.246 + * Read characters into a portion of an array, reading from the underlying
124.247 + * stream at most once if necessary.
124.248 + */
124.249 + private int read1(byte[] b, int off, int len) throws IOException {
124.250 + int avail = count - pos;
124.251 + if (avail <= 0) {
124.252 + /* If the requested length is at least as large as the buffer, and
124.253 + if there is no mark/reset activity, do not bother to copy the
124.254 + bytes into the local buffer. In this way buffered streams will
124.255 + cascade harmlessly. */
124.256 + if (len >= getBufIfOpen().length && markpos < 0) {
124.257 + return getInIfOpen().read(b, off, len);
124.258 + }
124.259 + fill();
124.260 + avail = count - pos;
124.261 + if (avail <= 0) return -1;
124.262 + }
124.263 + int cnt = (avail < len) ? avail : len;
124.264 + System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
124.265 + pos += cnt;
124.266 + return cnt;
124.267 + }
124.268 +
124.269 + /**
124.270 + * Reads bytes from this byte-input stream into the specified byte array,
124.271 + * starting at the given offset.
124.272 + *
124.273 + * <p> This method implements the general contract of the corresponding
124.274 + * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
124.275 + * the <code>{@link InputStream}</code> class. As an additional
124.276 + * convenience, it attempts to read as many bytes as possible by repeatedly
124.277 + * invoking the <code>read</code> method of the underlying stream. This
124.278 + * iterated <code>read</code> continues until one of the following
124.279 + * conditions becomes true: <ul>
124.280 + *
124.281 + * <li> The specified number of bytes have been read,
124.282 + *
124.283 + * <li> The <code>read</code> method of the underlying stream returns
124.284 + * <code>-1</code>, indicating end-of-file, or
124.285 + *
124.286 + * <li> The <code>available</code> method of the underlying stream
124.287 + * returns zero, indicating that further input requests would block.
124.288 + *
124.289 + * </ul> If the first <code>read</code> on the underlying stream returns
124.290 + * <code>-1</code> to indicate end-of-file then this method returns
124.291 + * <code>-1</code>. Otherwise this method returns the number of bytes
124.292 + * actually read.
124.293 + *
124.294 + * <p> Subclasses of this class are encouraged, but not required, to
124.295 + * attempt to read as many bytes as possible in the same fashion.
124.296 + *
124.297 + * @param b destination buffer.
124.298 + * @param off offset at which to start storing bytes.
124.299 + * @param len maximum number of bytes to read.
124.300 + * @return the number of bytes read, or <code>-1</code> if the end of
124.301 + * the stream has been reached.
124.302 + * @exception IOException if this input stream has been closed by
124.303 + * invoking its {@link #close()} method,
124.304 + * or an I/O error occurs.
124.305 + */
124.306 + public synchronized int read(byte b[], int off, int len)
124.307 + throws IOException
124.308 + {
124.309 + getBufIfOpen(); // Check for closed stream
124.310 + if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
124.311 + throw new IndexOutOfBoundsException();
124.312 + } else if (len == 0) {
124.313 + return 0;
124.314 + }
124.315 +
124.316 + int n = 0;
124.317 + for (;;) {
124.318 + int nread = read1(b, off + n, len - n);
124.319 + if (nread <= 0)
124.320 + return (n == 0) ? nread : n;
124.321 + n += nread;
124.322 + if (n >= len)
124.323 + return n;
124.324 + // if not closed but no bytes available, return
124.325 + InputStream input = in;
124.326 + if (input != null && input.available() <= 0)
124.327 + return n;
124.328 + }
124.329 + }
124.330 +
124.331 + /**
124.332 + * See the general contract of the <code>skip</code>
124.333 + * method of <code>InputStream</code>.
124.334 + *
124.335 + * @exception IOException if the stream does not support seek,
124.336 + * or if this input stream has been closed by
124.337 + * invoking its {@link #close()} method, or an
124.338 + * I/O error occurs.
124.339 + */
124.340 + public synchronized long skip(long n) throws IOException {
124.341 + getBufIfOpen(); // Check for closed stream
124.342 + if (n <= 0) {
124.343 + return 0;
124.344 + }
124.345 + long avail = count - pos;
124.346 +
124.347 + if (avail <= 0) {
124.348 + // If no mark position set then don't keep in buffer
124.349 + if (markpos <0)
124.350 + return getInIfOpen().skip(n);
124.351 +
124.352 + // Fill in buffer to save bytes for reset
124.353 + fill();
124.354 + avail = count - pos;
124.355 + if (avail <= 0)
124.356 + return 0;
124.357 + }
124.358 +
124.359 + long skipped = (avail < n) ? avail : n;
124.360 + pos += skipped;
124.361 + return skipped;
124.362 + }
124.363 +
124.364 + /**
124.365 + * Returns an estimate of the number of bytes that can be read (or
124.366 + * skipped over) from this input stream without blocking by the next
124.367 + * invocation of a method for this input stream. The next invocation might be
124.368 + * the same thread or another thread. A single read or skip of this
124.369 + * many bytes will not block, but may read or skip fewer bytes.
124.370 + * <p>
124.371 + * This method returns the sum of the number of bytes remaining to be read in
124.372 + * the buffer (<code>count - pos</code>) and the result of calling the
124.373 + * {@link java.io.FilterInputStream#in in}.available().
124.374 + *
124.375 + * @return an estimate of the number of bytes that can be read (or skipped
124.376 + * over) from this input stream without blocking.
124.377 + * @exception IOException if this input stream has been closed by
124.378 + * invoking its {@link #close()} method,
124.379 + * or an I/O error occurs.
124.380 + */
124.381 + public synchronized int available() throws IOException {
124.382 + int n = count - pos;
124.383 + int avail = getInIfOpen().available();
124.384 + return n > (Integer.MAX_VALUE - avail)
124.385 + ? Integer.MAX_VALUE
124.386 + : n + avail;
124.387 + }
124.388 +
124.389 + /**
124.390 + * See the general contract of the <code>mark</code>
124.391 + * method of <code>InputStream</code>.
124.392 + *
124.393 + * @param readlimit the maximum limit of bytes that can be read before
124.394 + * the mark position becomes invalid.
124.395 + * @see java.io.BufferedInputStream#reset()
124.396 + */
124.397 + public synchronized void mark(int readlimit) {
124.398 + marklimit = readlimit;
124.399 + markpos = pos;
124.400 + }
124.401 +
124.402 + /**
124.403 + * See the general contract of the <code>reset</code>
124.404 + * method of <code>InputStream</code>.
124.405 + * <p>
124.406 + * If <code>markpos</code> is <code>-1</code>
124.407 + * (no mark has been set or the mark has been
124.408 + * invalidated), an <code>IOException</code>
124.409 + * is thrown. Otherwise, <code>pos</code> is
124.410 + * set equal to <code>markpos</code>.
124.411 + *
124.412 + * @exception IOException if this stream has not been marked or,
124.413 + * if the mark has been invalidated, or the stream
124.414 + * has been closed by invoking its {@link #close()}
124.415 + * method, or an I/O error occurs.
124.416 + * @see java.io.BufferedInputStream#mark(int)
124.417 + */
124.418 + public synchronized void reset() throws IOException {
124.419 + getBufIfOpen(); // Cause exception if closed
124.420 + if (markpos < 0)
124.421 + throw new IOException("Resetting to invalid mark");
124.422 + pos = markpos;
124.423 + }
124.424 +
124.425 + /**
124.426 + * Tests if this input stream supports the <code>mark</code>
124.427 + * and <code>reset</code> methods. The <code>markSupported</code>
124.428 + * method of <code>BufferedInputStream</code> returns
124.429 + * <code>true</code>.
124.430 + *
124.431 + * @return a <code>boolean</code> indicating if this stream type supports
124.432 + * the <code>mark</code> and <code>reset</code> methods.
124.433 + * @see java.io.InputStream#mark(int)
124.434 + * @see java.io.InputStream#reset()
124.435 + */
124.436 + public boolean markSupported() {
124.437 + return true;
124.438 + }
124.439 +
124.440 + /**
124.441 + * Closes this input stream and releases any system resources
124.442 + * associated with the stream.
124.443 + * Once the stream has been closed, further read(), available(), reset(),
124.444 + * or skip() invocations will throw an IOException.
124.445 + * Closing a previously closed stream has no effect.
124.446 + *
124.447 + * @exception IOException if an I/O error occurs.
124.448 + */
124.449 + public void close() throws IOException {
124.450 + byte[] buffer;
124.451 + while ( (buffer = buf) != null) {
124.452 + InputStream input = in;
124.453 + buf = null;
124.454 + in = null;
124.455 + if (input != null)
124.456 + input.close();
124.457 + return;
124.458 + // Else retry in case a new buf was CASed in fill()
124.459 + }
124.460 + }
124.461 +}
125.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
125.2 +++ b/rt/emul/compact/src/main/java/java/io/BufferedWriter.java Wed Apr 30 15:04:10 2014 +0200
125.3 @@ -0,0 +1,271 @@
125.4 +/*
125.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
125.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
125.7 + *
125.8 + * This code is free software; you can redistribute it and/or modify it
125.9 + * under the terms of the GNU General Public License version 2 only, as
125.10 + * published by the Free Software Foundation. Oracle designates this
125.11 + * particular file as subject to the "Classpath" exception as provided
125.12 + * by Oracle in the LICENSE file that accompanied this code.
125.13 + *
125.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
125.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
125.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
125.17 + * version 2 for more details (a copy is included in the LICENSE file that
125.18 + * accompanied this code).
125.19 + *
125.20 + * You should have received a copy of the GNU General Public License version
125.21 + * 2 along with this work; if not, write to the Free Software Foundation,
125.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
125.23 + *
125.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
125.25 + * or visit www.oracle.com if you need additional information or have any
125.26 + * questions.
125.27 + */
125.28 +
125.29 +package java.io;
125.30 +
125.31 +
125.32 +/**
125.33 + * Writes text to a character-output stream, buffering characters so as to
125.34 + * provide for the efficient writing of single characters, arrays, and strings.
125.35 + *
125.36 + * <p> The buffer size may be specified, or the default size may be accepted.
125.37 + * The default is large enough for most purposes.
125.38 + *
125.39 + * <p> A newLine() method is provided, which uses the platform's own notion of
125.40 + * line separator as defined by the system property <tt>line.separator</tt>.
125.41 + * Not all platforms use the newline character ('\n') to terminate lines.
125.42 + * Calling this method to terminate each output line is therefore preferred to
125.43 + * writing a newline character directly.
125.44 + *
125.45 + * <p> In general, a Writer sends its output immediately to the underlying
125.46 + * character or byte stream. Unless prompt output is required, it is advisable
125.47 + * to wrap a BufferedWriter around any Writer whose write() operations may be
125.48 + * costly, such as FileWriters and OutputStreamWriters. For example,
125.49 + *
125.50 + * <pre>
125.51 + * PrintWriter out
125.52 + * = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
125.53 + * </pre>
125.54 + *
125.55 + * will buffer the PrintWriter's output to the file. Without buffering, each
125.56 + * invocation of a print() method would cause characters to be converted into
125.57 + * bytes that would then be written immediately to the file, which can be very
125.58 + * inefficient.
125.59 + *
125.60 + * @see PrintWriter
125.61 + * @see FileWriter
125.62 + * @see OutputStreamWriter
125.63 + * @see java.nio.file.Files#newBufferedWriter
125.64 + *
125.65 + * @author Mark Reinhold
125.66 + * @since JDK1.1
125.67 + */
125.68 +
125.69 +public class BufferedWriter extends Writer {
125.70 +
125.71 + private Writer out;
125.72 +
125.73 + private char cb[];
125.74 + private int nChars, nextChar;
125.75 +
125.76 + private static int defaultCharBufferSize = 8192;
125.77 +
125.78 + /**
125.79 + * Line separator string. This is the value of the line.separator
125.80 + * property at the moment that the stream was created.
125.81 + */
125.82 + private String lineSeparator;
125.83 +
125.84 + /**
125.85 + * Creates a buffered character-output stream that uses a default-sized
125.86 + * output buffer.
125.87 + *
125.88 + * @param out A Writer
125.89 + */
125.90 + public BufferedWriter(Writer out) {
125.91 + this(out, defaultCharBufferSize);
125.92 + }
125.93 +
125.94 + /**
125.95 + * Creates a new buffered character-output stream that uses an output
125.96 + * buffer of the given size.
125.97 + *
125.98 + * @param out A Writer
125.99 + * @param sz Output-buffer size, a positive integer
125.100 + *
125.101 + * @exception IllegalArgumentException If sz is <= 0
125.102 + */
125.103 + public BufferedWriter(Writer out, int sz) {
125.104 + super(out);
125.105 + if (sz <= 0)
125.106 + throw new IllegalArgumentException("Buffer size <= 0");
125.107 + this.out = out;
125.108 + cb = new char[sz];
125.109 + nChars = sz;
125.110 + nextChar = 0;
125.111 +
125.112 + lineSeparator = "\n";
125.113 + }
125.114 +
125.115 + /** Checks to make sure that the stream has not been closed */
125.116 + private void ensureOpen() throws IOException {
125.117 + if (out == null)
125.118 + throw new IOException("Stream closed");
125.119 + }
125.120 +
125.121 + /**
125.122 + * Flushes the output buffer to the underlying character stream, without
125.123 + * flushing the stream itself. This method is non-private only so that it
125.124 + * may be invoked by PrintStream.
125.125 + */
125.126 + void flushBuffer() throws IOException {
125.127 + synchronized (lock) {
125.128 + ensureOpen();
125.129 + if (nextChar == 0)
125.130 + return;
125.131 + out.write(cb, 0, nextChar);
125.132 + nextChar = 0;
125.133 + }
125.134 + }
125.135 +
125.136 + /**
125.137 + * Writes a single character.
125.138 + *
125.139 + * @exception IOException If an I/O error occurs
125.140 + */
125.141 + public void write(int c) throws IOException {
125.142 + synchronized (lock) {
125.143 + ensureOpen();
125.144 + if (nextChar >= nChars)
125.145 + flushBuffer();
125.146 + cb[nextChar++] = (char) c;
125.147 + }
125.148 + }
125.149 +
125.150 + /**
125.151 + * Our own little min method, to avoid loading java.lang.Math if we've run
125.152 + * out of file descriptors and we're trying to print a stack trace.
125.153 + */
125.154 + private int min(int a, int b) {
125.155 + if (a < b) return a;
125.156 + return b;
125.157 + }
125.158 +
125.159 + /**
125.160 + * Writes a portion of an array of characters.
125.161 + *
125.162 + * <p> Ordinarily this method stores characters from the given array into
125.163 + * this stream's buffer, flushing the buffer to the underlying stream as
125.164 + * needed. If the requested length is at least as large as the buffer,
125.165 + * however, then this method will flush the buffer and write the characters
125.166 + * directly to the underlying stream. Thus redundant
125.167 + * <code>BufferedWriter</code>s will not copy data unnecessarily.
125.168 + *
125.169 + * @param cbuf A character array
125.170 + * @param off Offset from which to start reading characters
125.171 + * @param len Number of characters to write
125.172 + *
125.173 + * @exception IOException If an I/O error occurs
125.174 + */
125.175 + public void write(char cbuf[], int off, int len) throws IOException {
125.176 + synchronized (lock) {
125.177 + ensureOpen();
125.178 + if ((off < 0) || (off > cbuf.length) || (len < 0) ||
125.179 + ((off + len) > cbuf.length) || ((off + len) < 0)) {
125.180 + throw new IndexOutOfBoundsException();
125.181 + } else if (len == 0) {
125.182 + return;
125.183 + }
125.184 +
125.185 + if (len >= nChars) {
125.186 + /* If the request length exceeds the size of the output buffer,
125.187 + flush the buffer and then write the data directly. In this
125.188 + way buffered streams will cascade harmlessly. */
125.189 + flushBuffer();
125.190 + out.write(cbuf, off, len);
125.191 + return;
125.192 + }
125.193 +
125.194 + int b = off, t = off + len;
125.195 + while (b < t) {
125.196 + int d = min(nChars - nextChar, t - b);
125.197 + System.arraycopy(cbuf, b, cb, nextChar, d);
125.198 + b += d;
125.199 + nextChar += d;
125.200 + if (nextChar >= nChars)
125.201 + flushBuffer();
125.202 + }
125.203 + }
125.204 + }
125.205 +
125.206 + /**
125.207 + * Writes a portion of a String.
125.208 + *
125.209 + * <p> If the value of the <tt>len</tt> parameter is negative then no
125.210 + * characters are written. This is contrary to the specification of this
125.211 + * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int)
125.212 + * superclass}, which requires that an {@link IndexOutOfBoundsException} be
125.213 + * thrown.
125.214 + *
125.215 + * @param s String to be written
125.216 + * @param off Offset from which to start reading characters
125.217 + * @param len Number of characters to be written
125.218 + *
125.219 + * @exception IOException If an I/O error occurs
125.220 + */
125.221 + public void write(String s, int off, int len) throws IOException {
125.222 + synchronized (lock) {
125.223 + ensureOpen();
125.224 +
125.225 + int b = off, t = off + len;
125.226 + while (b < t) {
125.227 + int d = min(nChars - nextChar, t - b);
125.228 + s.getChars(b, b + d, cb, nextChar);
125.229 + b += d;
125.230 + nextChar += d;
125.231 + if (nextChar >= nChars)
125.232 + flushBuffer();
125.233 + }
125.234 + }
125.235 + }
125.236 +
125.237 + /**
125.238 + * Writes a line separator. The line separator string is defined by the
125.239 + * system property <tt>line.separator</tt>, and is not necessarily a single
125.240 + * newline ('\n') character.
125.241 + *
125.242 + * @exception IOException If an I/O error occurs
125.243 + */
125.244 + public void newLine() throws IOException {
125.245 + write(lineSeparator);
125.246 + }
125.247 +
125.248 + /**
125.249 + * Flushes the stream.
125.250 + *
125.251 + * @exception IOException If an I/O error occurs
125.252 + */
125.253 + public void flush() throws IOException {
125.254 + synchronized (lock) {
125.255 + flushBuffer();
125.256 + out.flush();
125.257 + }
125.258 + }
125.259 +
125.260 + public void close() throws IOException {
125.261 + synchronized (lock) {
125.262 + if (out == null) {
125.263 + return;
125.264 + }
125.265 + try {
125.266 + flushBuffer();
125.267 + } finally {
125.268 + out.close();
125.269 + out = null;
125.270 + cb = null;
125.271 + }
125.272 + }
125.273 + }
125.274 +}
126.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
126.2 +++ b/rt/emul/compact/src/main/java/java/io/File.java Wed Apr 30 15:04:10 2014 +0200
126.3 @@ -0,0 +1,1927 @@
126.4 +/*
126.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
126.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
126.7 + *
126.8 + * This code is free software; you can redistribute it and/or modify it
126.9 + * under the terms of the GNU General Public License version 2 only, as
126.10 + * published by the Free Software Foundation. Oracle designates this
126.11 + * particular file as subject to the "Classpath" exception as provided
126.12 + * by Oracle in the LICENSE file that accompanied this code.
126.13 + *
126.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
126.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
126.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
126.17 + * version 2 for more details (a copy is included in the LICENSE file that
126.18 + * accompanied this code).
126.19 + *
126.20 + * You should have received a copy of the GNU General Public License version
126.21 + * 2 along with this work; if not, write to the Free Software Foundation,
126.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
126.23 + *
126.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
126.25 + * or visit www.oracle.com if you need additional information or have any
126.26 + * questions.
126.27 + */
126.28 +
126.29 +package java.io;
126.30 +
126.31 +import java.net.URI;
126.32 +import java.net.URL;
126.33 +import java.net.MalformedURLException;
126.34 +import java.net.URISyntaxException;
126.35 +
126.36 +/**
126.37 + * An abstract representation of file and directory pathnames.
126.38 + *
126.39 + * <p> User interfaces and operating systems use system-dependent <em>pathname
126.40 + * strings</em> to name files and directories. This class presents an
126.41 + * abstract, system-independent view of hierarchical pathnames. An
126.42 + * <em>abstract pathname</em> has two components:
126.43 + *
126.44 + * <ol>
126.45 + * <li> An optional system-dependent <em>prefix</em> string,
126.46 + * such as a disk-drive specifier, <code>"/"</code> for the UNIX root
126.47 + * directory, or <code>"\\\\"</code> for a Microsoft Windows UNC pathname, and
126.48 + * <li> A sequence of zero or more string <em>names</em>.
126.49 + * </ol>
126.50 + *
126.51 + * The first name in an abstract pathname may be a directory name or, in the
126.52 + * case of Microsoft Windows UNC pathnames, a hostname. Each subsequent name
126.53 + * in an abstract pathname denotes a directory; the last name may denote
126.54 + * either a directory or a file. The <em>empty</em> abstract pathname has no
126.55 + * prefix and an empty name sequence.
126.56 + *
126.57 + * <p> The conversion of a pathname string to or from an abstract pathname is
126.58 + * inherently system-dependent. When an abstract pathname is converted into a
126.59 + * pathname string, each name is separated from the next by a single copy of
126.60 + * the default <em>separator character</em>. The default name-separator
126.61 + * character is defined by the system property <code>file.separator</code>, and
126.62 + * is made available in the public static fields <code>{@link
126.63 + * #separator}</code> and <code>{@link #separatorChar}</code> of this class.
126.64 + * When a pathname string is converted into an abstract pathname, the names
126.65 + * within it may be separated by the default name-separator character or by any
126.66 + * other name-separator character that is supported by the underlying system.
126.67 + *
126.68 + * <p> A pathname, whether abstract or in string form, may be either
126.69 + * <em>absolute</em> or <em>relative</em>. An absolute pathname is complete in
126.70 + * that no other information is required in order to locate the file that it
126.71 + * denotes. A relative pathname, in contrast, must be interpreted in terms of
126.72 + * information taken from some other pathname. By default the classes in the
126.73 + * <code>java.io</code> package always resolve relative pathnames against the
126.74 + * current user directory. This directory is named by the system property
126.75 + * <code>user.dir</code>, and is typically the directory in which the Java
126.76 + * virtual machine was invoked.
126.77 + *
126.78 + * <p> The <em>parent</em> of an abstract pathname may be obtained by invoking
126.79 + * the {@link #getParent} method of this class and consists of the pathname's
126.80 + * prefix and each name in the pathname's name sequence except for the last.
126.81 + * Each directory's absolute pathname is an ancestor of any <tt>File</tt>
126.82 + * object with an absolute abstract pathname which begins with the directory's
126.83 + * absolute pathname. For example, the directory denoted by the abstract
126.84 + * pathname <tt>"/usr"</tt> is an ancestor of the directory denoted by the
126.85 + * pathname <tt>"/usr/local/bin"</tt>.
126.86 + *
126.87 + * <p> The prefix concept is used to handle root directories on UNIX platforms,
126.88 + * and drive specifiers, root directories and UNC pathnames on Microsoft Windows platforms,
126.89 + * as follows:
126.90 + *
126.91 + * <ul>
126.92 + *
126.93 + * <li> For UNIX platforms, the prefix of an absolute pathname is always
126.94 + * <code>"/"</code>. Relative pathnames have no prefix. The abstract pathname
126.95 + * denoting the root directory has the prefix <code>"/"</code> and an empty
126.96 + * name sequence.
126.97 + *
126.98 + * <li> For Microsoft Windows platforms, the prefix of a pathname that contains a drive
126.99 + * specifier consists of the drive letter followed by <code>":"</code> and
126.100 + * possibly followed by <code>"\\"</code> if the pathname is absolute. The
126.101 + * prefix of a UNC pathname is <code>"\\\\"</code>; the hostname and the share
126.102 + * name are the first two names in the name sequence. A relative pathname that
126.103 + * does not specify a drive has no prefix.
126.104 + *
126.105 + * </ul>
126.106 + *
126.107 + * <p> Instances of this class may or may not denote an actual file-system
126.108 + * object such as a file or a directory. If it does denote such an object
126.109 + * then that object resides in a <i>partition</i>. A partition is an
126.110 + * operating system-specific portion of storage for a file system. A single
126.111 + * storage device (e.g. a physical disk-drive, flash memory, CD-ROM) may
126.112 + * contain multiple partitions. The object, if any, will reside on the
126.113 + * partition <a name="partName">named</a> by some ancestor of the absolute
126.114 + * form of this pathname.
126.115 + *
126.116 + * <p> A file system may implement restrictions to certain operations on the
126.117 + * actual file-system object, such as reading, writing, and executing. These
126.118 + * restrictions are collectively known as <i>access permissions</i>. The file
126.119 + * system may have multiple sets of access permissions on a single object.
126.120 + * For example, one set may apply to the object's <i>owner</i>, and another
126.121 + * may apply to all other users. The access permissions on an object may
126.122 + * cause some methods in this class to fail.
126.123 + *
126.124 + * <p> Instances of the <code>File</code> class are immutable; that is, once
126.125 + * created, the abstract pathname represented by a <code>File</code> object
126.126 + * will never change.
126.127 + *
126.128 + * <h4>Interoperability with {@code java.nio.file} package</h4>
126.129 + *
126.130 + * <p> The <a href="../../java/nio/file/package-summary.html">{@code java.nio.file}</a>
126.131 + * package defines interfaces and classes for the Java virtual machine to access
126.132 + * files, file attributes, and file systems. This API may be used to overcome
126.133 + * many of the limitations of the {@code java.io.File} class.
126.134 + * The {@link #toPath toPath} method may be used to obtain a {@link
126.135 + * Path} that uses the abstract path represented by a {@code File} object to
126.136 + * locate a file. The resulting {@code Path} may be used with the {@link
126.137 + * java.nio.file.Files} class to provide more efficient and extensive access to
126.138 + * additional file operations, file attributes, and I/O exceptions to help
126.139 + * diagnose errors when an operation on a file fails.
126.140 + *
126.141 + * @author unascribed
126.142 + * @since JDK1.0
126.143 + */
126.144 +
126.145 +public class File
126.146 + implements Serializable, Comparable<File>
126.147 +{
126.148 +
126.149 + /**
126.150 + * The FileSystem object representing the platform's local file system.
126.151 + */
126.152 + static private FileSystem fs = new FileSystem();
126.153 + private static class FileSystem {
126.154 +
126.155 + private char getSeparator() {
126.156 + return '/';
126.157 + }
126.158 +
126.159 + private String resolve(String path, String child) {
126.160 + return path + '/' + child;
126.161 + }
126.162 +
126.163 + private String normalize(String pathname) {
126.164 + return pathname;
126.165 + }
126.166 +
126.167 + private int prefixLength(String path) {
126.168 + return 0;
126.169 + }
126.170 +
126.171 + private String getDefaultParent() {
126.172 + return "/";
126.173 + }
126.174 +
126.175 + private String fromURIPath(String p) {
126.176 + return p;
126.177 + }
126.178 +
126.179 + private boolean isAbsolute(File aThis) {
126.180 + return aThis.getPath().startsWith("/");
126.181 + }
126.182 +
126.183 + private int compare(File one, File two) {
126.184 + return one.getPath().compareTo(two.getPath());
126.185 + }
126.186 +
126.187 + private int hashCode(File aThis) {
126.188 + return aThis.getPath().hashCode();
126.189 + }
126.190 +
126.191 + private char getPathSeparator() {
126.192 + return ':';
126.193 + }
126.194 +
126.195 + }
126.196 +
126.197 + /**
126.198 + * This abstract pathname's normalized pathname string. A normalized
126.199 + * pathname string uses the default name-separator character and does not
126.200 + * contain any duplicate or redundant separators.
126.201 + *
126.202 + * @serial
126.203 + */
126.204 + private String path;
126.205 +
126.206 + /**
126.207 + * The length of this abstract pathname's prefix, or zero if it has no
126.208 + * prefix.
126.209 + */
126.210 + private transient int prefixLength;
126.211 +
126.212 + /**
126.213 + * Returns the length of this abstract pathname's prefix.
126.214 + * For use by FileSystem classes.
126.215 + */
126.216 + int getPrefixLength() {
126.217 + return prefixLength;
126.218 + }
126.219 +
126.220 + /**
126.221 + * The system-dependent default name-separator character. This field is
126.222 + * initialized to contain the first character of the value of the system
126.223 + * property <code>file.separator</code>. On UNIX systems the value of this
126.224 + * field is <code>'/'</code>; on Microsoft Windows systems it is <code>'\\'</code>.
126.225 + *
126.226 + * @see java.lang.System#getProperty(java.lang.String)
126.227 + */
126.228 + public static final char separatorChar = fs.getSeparator();
126.229 +
126.230 + /**
126.231 + * The system-dependent default name-separator character, represented as a
126.232 + * string for convenience. This string contains a single character, namely
126.233 + * <code>{@link #separatorChar}</code>.
126.234 + */
126.235 + public static final String separator = "" + separatorChar;
126.236 +
126.237 + /**
126.238 + * The system-dependent path-separator character. This field is
126.239 + * initialized to contain the first character of the value of the system
126.240 + * property <code>path.separator</code>. This character is used to
126.241 + * separate filenames in a sequence of files given as a <em>path list</em>.
126.242 + * On UNIX systems, this character is <code>':'</code>; on Microsoft Windows systems it
126.243 + * is <code>';'</code>.
126.244 + *
126.245 + * @see java.lang.System#getProperty(java.lang.String)
126.246 + */
126.247 + public static final char pathSeparatorChar = fs.getPathSeparator();
126.248 +
126.249 + /**
126.250 + * The system-dependent path-separator character, represented as a string
126.251 + * for convenience. This string contains a single character, namely
126.252 + * <code>{@link #pathSeparatorChar}</code>.
126.253 + */
126.254 + public static final String pathSeparator = "" + pathSeparatorChar;
126.255 +
126.256 +
126.257 + /* -- Constructors -- */
126.258 +
126.259 + /**
126.260 + * Internal constructor for already-normalized pathname strings.
126.261 + */
126.262 + private File(String pathname, int prefixLength) {
126.263 + this.path = pathname;
126.264 + this.prefixLength = prefixLength;
126.265 + }
126.266 +
126.267 + /**
126.268 + * Internal constructor for already-normalized pathname strings.
126.269 + * The parameter order is used to disambiguate this method from the
126.270 + * public(File, String) constructor.
126.271 + */
126.272 + private File(String child, File parent) {
126.273 + assert parent.path != null;
126.274 + assert (!parent.path.equals(""));
126.275 + this.path = fs.resolve(parent.path, child);
126.276 + this.prefixLength = parent.prefixLength;
126.277 + }
126.278 +
126.279 + /**
126.280 + * Creates a new <code>File</code> instance by converting the given
126.281 + * pathname string into an abstract pathname. If the given string is
126.282 + * the empty string, then the result is the empty abstract pathname.
126.283 + *
126.284 + * @param pathname A pathname string
126.285 + * @throws NullPointerException
126.286 + * If the <code>pathname</code> argument is <code>null</code>
126.287 + */
126.288 + public File(String pathname) {
126.289 + if (pathname == null) {
126.290 + throw new NullPointerException();
126.291 + }
126.292 + this.path = fs.normalize(pathname);
126.293 + this.prefixLength = fs.prefixLength(this.path);
126.294 + }
126.295 +
126.296 + /* Note: The two-argument File constructors do not interpret an empty
126.297 + parent abstract pathname as the current user directory. An empty parent
126.298 + instead causes the child to be resolved against the system-dependent
126.299 + directory defined by the FileSystem.getDefaultParent method. On Unix
126.300 + this default is "/", while on Microsoft Windows it is "\\". This is required for
126.301 + compatibility with the original behavior of this class. */
126.302 +
126.303 + /**
126.304 + * Creates a new <code>File</code> instance from a parent pathname string
126.305 + * and a child pathname string.
126.306 + *
126.307 + * <p> If <code>parent</code> is <code>null</code> then the new
126.308 + * <code>File</code> instance is created as if by invoking the
126.309 + * single-argument <code>File</code> constructor on the given
126.310 + * <code>child</code> pathname string.
126.311 + *
126.312 + * <p> Otherwise the <code>parent</code> pathname string is taken to denote
126.313 + * a directory, and the <code>child</code> pathname string is taken to
126.314 + * denote either a directory or a file. If the <code>child</code> pathname
126.315 + * string is absolute then it is converted into a relative pathname in a
126.316 + * system-dependent way. If <code>parent</code> is the empty string then
126.317 + * the new <code>File</code> instance is created by converting
126.318 + * <code>child</code> into an abstract pathname and resolving the result
126.319 + * against a system-dependent default directory. Otherwise each pathname
126.320 + * string is converted into an abstract pathname and the child abstract
126.321 + * pathname is resolved against the parent.
126.322 + *
126.323 + * @param parent The parent pathname string
126.324 + * @param child The child pathname string
126.325 + * @throws NullPointerException
126.326 + * If <code>child</code> is <code>null</code>
126.327 + */
126.328 + public File(String parent, String child) {
126.329 + if (child == null) {
126.330 + throw new NullPointerException();
126.331 + }
126.332 + if (parent != null) {
126.333 + if (parent.equals("")) {
126.334 + this.path = fs.resolve(fs.getDefaultParent(),
126.335 + fs.normalize(child));
126.336 + } else {
126.337 + this.path = fs.resolve(fs.normalize(parent),
126.338 + fs.normalize(child));
126.339 + }
126.340 + } else {
126.341 + this.path = fs.normalize(child);
126.342 + }
126.343 + this.prefixLength = fs.prefixLength(this.path);
126.344 + }
126.345 +
126.346 + /**
126.347 + * Creates a new <code>File</code> instance from a parent abstract
126.348 + * pathname and a child pathname string.
126.349 + *
126.350 + * <p> If <code>parent</code> is <code>null</code> then the new
126.351 + * <code>File</code> instance is created as if by invoking the
126.352 + * single-argument <code>File</code> constructor on the given
126.353 + * <code>child</code> pathname string.
126.354 + *
126.355 + * <p> Otherwise the <code>parent</code> abstract pathname is taken to
126.356 + * denote a directory, and the <code>child</code> pathname string is taken
126.357 + * to denote either a directory or a file. If the <code>child</code>
126.358 + * pathname string is absolute then it is converted into a relative
126.359 + * pathname in a system-dependent way. If <code>parent</code> is the empty
126.360 + * abstract pathname then the new <code>File</code> instance is created by
126.361 + * converting <code>child</code> into an abstract pathname and resolving
126.362 + * the result against a system-dependent default directory. Otherwise each
126.363 + * pathname string is converted into an abstract pathname and the child
126.364 + * abstract pathname is resolved against the parent.
126.365 + *
126.366 + * @param parent The parent abstract pathname
126.367 + * @param child The child pathname string
126.368 + * @throws NullPointerException
126.369 + * If <code>child</code> is <code>null</code>
126.370 + */
126.371 + public File(File parent, String child) {
126.372 + if (child == null) {
126.373 + throw new NullPointerException();
126.374 + }
126.375 + if (parent != null) {
126.376 + if (parent.path.equals("")) {
126.377 + this.path = fs.resolve(fs.getDefaultParent(),
126.378 + fs.normalize(child));
126.379 + } else {
126.380 + this.path = fs.resolve(parent.path,
126.381 + fs.normalize(child));
126.382 + }
126.383 + } else {
126.384 + this.path = fs.normalize(child);
126.385 + }
126.386 + this.prefixLength = fs.prefixLength(this.path);
126.387 + }
126.388 +
126.389 + /**
126.390 + * Creates a new <tt>File</tt> instance by converting the given
126.391 + * <tt>file:</tt> URI into an abstract pathname.
126.392 + *
126.393 + * <p> The exact form of a <tt>file:</tt> URI is system-dependent, hence
126.394 + * the transformation performed by this constructor is also
126.395 + * system-dependent.
126.396 + *
126.397 + * <p> For a given abstract pathname <i>f</i> it is guaranteed that
126.398 + *
126.399 + * <blockquote><tt>
126.400 + * new File(</tt><i> f</i><tt>.{@link #toURI() toURI}()).equals(</tt><i> f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
126.401 + * </tt></blockquote>
126.402 + *
126.403 + * so long as the original abstract pathname, the URI, and the new abstract
126.404 + * pathname are all created in (possibly different invocations of) the same
126.405 + * Java virtual machine. This relationship typically does not hold,
126.406 + * however, when a <tt>file:</tt> URI that is created in a virtual machine
126.407 + * on one operating system is converted into an abstract pathname in a
126.408 + * virtual machine on a different operating system.
126.409 + *
126.410 + * @param uri
126.411 + * An absolute, hierarchical URI with a scheme equal to
126.412 + * <tt>"file"</tt>, a non-empty path component, and undefined
126.413 + * authority, query, and fragment components
126.414 + *
126.415 + * @throws NullPointerException
126.416 + * If <tt>uri</tt> is <tt>null</tt>
126.417 + *
126.418 + * @throws IllegalArgumentException
126.419 + * If the preconditions on the parameter do not hold
126.420 + *
126.421 + * @see #toURI()
126.422 + * @see java.net.URI
126.423 + * @since 1.4
126.424 + */
126.425 + public File(URI uri) {
126.426 +
126.427 + // Check our many preconditions
126.428 + if (!uri.isAbsolute())
126.429 + throw new IllegalArgumentException("URI is not absolute");
126.430 + if (uri.isOpaque())
126.431 + throw new IllegalArgumentException("URI is not hierarchical");
126.432 + String scheme = uri.getScheme();
126.433 + if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
126.434 + throw new IllegalArgumentException("URI scheme is not \"file\"");
126.435 + if (uri.getAuthority() != null)
126.436 + throw new IllegalArgumentException("URI has an authority component");
126.437 + if (uri.getFragment() != null)
126.438 + throw new IllegalArgumentException("URI has a fragment component");
126.439 + if (uri.getQuery() != null)
126.440 + throw new IllegalArgumentException("URI has a query component");
126.441 + String p = uri.getPath();
126.442 + if (p.equals(""))
126.443 + throw new IllegalArgumentException("URI path component is empty");
126.444 +
126.445 + // Okay, now initialize
126.446 + p = fs.fromURIPath(p);
126.447 + if (File.separatorChar != '/')
126.448 + p = p.replace('/', File.separatorChar);
126.449 + this.path = fs.normalize(p);
126.450 + this.prefixLength = fs.prefixLength(this.path);
126.451 + }
126.452 +
126.453 +
126.454 + /* -- Path-component accessors -- */
126.455 +
126.456 + /**
126.457 + * Returns the name of the file or directory denoted by this abstract
126.458 + * pathname. This is just the last name in the pathname's name
126.459 + * sequence. If the pathname's name sequence is empty, then the empty
126.460 + * string is returned.
126.461 + *
126.462 + * @return The name of the file or directory denoted by this abstract
126.463 + * pathname, or the empty string if this pathname's name sequence
126.464 + * is empty
126.465 + */
126.466 + public String getName() {
126.467 + int index = path.lastIndexOf(separatorChar);
126.468 + if (index < prefixLength) return path.substring(prefixLength);
126.469 + return path.substring(index + 1);
126.470 + }
126.471 +
126.472 + /**
126.473 + * Returns the pathname string of this abstract pathname's parent, or
126.474 + * <code>null</code> if this pathname does not name a parent directory.
126.475 + *
126.476 + * <p> The <em>parent</em> of an abstract pathname consists of the
126.477 + * pathname's prefix, if any, and each name in the pathname's name
126.478 + * sequence except for the last. If the name sequence is empty then
126.479 + * the pathname does not name a parent directory.
126.480 + *
126.481 + * @return The pathname string of the parent directory named by this
126.482 + * abstract pathname, or <code>null</code> if this pathname
126.483 + * does not name a parent
126.484 + */
126.485 + public String getParent() {
126.486 + int index = path.lastIndexOf(separatorChar);
126.487 + if (index < prefixLength) {
126.488 + if ((prefixLength > 0) && (path.length() > prefixLength))
126.489 + return path.substring(0, prefixLength);
126.490 + return null;
126.491 + }
126.492 + return path.substring(0, index);
126.493 + }
126.494 +
126.495 + /**
126.496 + * Returns the abstract pathname of this abstract pathname's parent,
126.497 + * or <code>null</code> if this pathname does not name a parent
126.498 + * directory.
126.499 + *
126.500 + * <p> The <em>parent</em> of an abstract pathname consists of the
126.501 + * pathname's prefix, if any, and each name in the pathname's name
126.502 + * sequence except for the last. If the name sequence is empty then
126.503 + * the pathname does not name a parent directory.
126.504 + *
126.505 + * @return The abstract pathname of the parent directory named by this
126.506 + * abstract pathname, or <code>null</code> if this pathname
126.507 + * does not name a parent
126.508 + *
126.509 + * @since 1.2
126.510 + */
126.511 + public File getParentFile() {
126.512 + String p = this.getParent();
126.513 + if (p == null) return null;
126.514 + return new File(p, this.prefixLength);
126.515 + }
126.516 +
126.517 + /**
126.518 + * Converts this abstract pathname into a pathname string. The resulting
126.519 + * string uses the {@link #separator default name-separator character} to
126.520 + * separate the names in the name sequence.
126.521 + *
126.522 + * @return The string form of this abstract pathname
126.523 + */
126.524 + public String getPath() {
126.525 + return path;
126.526 + }
126.527 +
126.528 +
126.529 + /* -- Path operations -- */
126.530 +
126.531 + /**
126.532 + * Tests whether this abstract pathname is absolute. The definition of
126.533 + * absolute pathname is system dependent. On UNIX systems, a pathname is
126.534 + * absolute if its prefix is <code>"/"</code>. On Microsoft Windows systems, a
126.535 + * pathname is absolute if its prefix is a drive specifier followed by
126.536 + * <code>"\\"</code>, or if its prefix is <code>"\\\\"</code>.
126.537 + *
126.538 + * @return <code>true</code> if this abstract pathname is absolute,
126.539 + * <code>false</code> otherwise
126.540 + */
126.541 + public boolean isAbsolute() {
126.542 + return fs.isAbsolute(this);
126.543 + }
126.544 +
126.545 + /**
126.546 + * Returns the absolute pathname string of this abstract pathname.
126.547 + *
126.548 + * <p> If this abstract pathname is already absolute, then the pathname
126.549 + * string is simply returned as if by the <code>{@link #getPath}</code>
126.550 + * method. If this abstract pathname is the empty abstract pathname then
126.551 + * the pathname string of the current user directory, which is named by the
126.552 + * system property <code>user.dir</code>, is returned. Otherwise this
126.553 + * pathname is resolved in a system-dependent way. On UNIX systems, a
126.554 + * relative pathname is made absolute by resolving it against the current
126.555 + * user directory. On Microsoft Windows systems, a relative pathname is made absolute
126.556 + * by resolving it against the current directory of the drive named by the
126.557 + * pathname, if any; if not, it is resolved against the current user
126.558 + * directory.
126.559 + *
126.560 + * @return The absolute pathname string denoting the same file or
126.561 + * directory as this abstract pathname
126.562 + *
126.563 + * @throws SecurityException
126.564 + * If a required system property value cannot be accessed.
126.565 + *
126.566 + * @see java.io.File#isAbsolute()
126.567 + */
126.568 + public String getAbsolutePath() {
126.569 + throw new SecurityException();
126.570 + }
126.571 +
126.572 + /**
126.573 + * Returns the absolute form of this abstract pathname. Equivalent to
126.574 + * <code>new File(this.{@link #getAbsolutePath})</code>.
126.575 + *
126.576 + * @return The absolute abstract pathname denoting the same file or
126.577 + * directory as this abstract pathname
126.578 + *
126.579 + * @throws SecurityException
126.580 + * If a required system property value cannot be accessed.
126.581 + *
126.582 + * @since 1.2
126.583 + */
126.584 + public File getAbsoluteFile() {
126.585 + String absPath = getAbsolutePath();
126.586 + return new File(absPath, fs.prefixLength(absPath));
126.587 + }
126.588 +
126.589 + /**
126.590 + * Returns the canonical pathname string of this abstract pathname.
126.591 + *
126.592 + * <p> A canonical pathname is both absolute and unique. The precise
126.593 + * definition of canonical form is system-dependent. This method first
126.594 + * converts this pathname to absolute form if necessary, as if by invoking the
126.595 + * {@link #getAbsolutePath} method, and then maps it to its unique form in a
126.596 + * system-dependent way. This typically involves removing redundant names
126.597 + * such as <tt>"."</tt> and <tt>".."</tt> from the pathname, resolving
126.598 + * symbolic links (on UNIX platforms), and converting drive letters to a
126.599 + * standard case (on Microsoft Windows platforms).
126.600 + *
126.601 + * <p> Every pathname that denotes an existing file or directory has a
126.602 + * unique canonical form. Every pathname that denotes a nonexistent file
126.603 + * or directory also has a unique canonical form. The canonical form of
126.604 + * the pathname of a nonexistent file or directory may be different from
126.605 + * the canonical form of the same pathname after the file or directory is
126.606 + * created. Similarly, the canonical form of the pathname of an existing
126.607 + * file or directory may be different from the canonical form of the same
126.608 + * pathname after the file or directory is deleted.
126.609 + *
126.610 + * @return The canonical pathname string denoting the same file or
126.611 + * directory as this abstract pathname
126.612 + *
126.613 + * @throws IOException
126.614 + * If an I/O error occurs, which is possible because the
126.615 + * construction of the canonical pathname may require
126.616 + * filesystem queries
126.617 + *
126.618 + * @throws SecurityException
126.619 + * If a required system property value cannot be accessed, or
126.620 + * if a security manager exists and its <code>{@link
126.621 + * java.lang.SecurityManager#checkRead}</code> method denies
126.622 + * read access to the file
126.623 + *
126.624 + * @since JDK1.1
126.625 + * @see Path#toRealPath
126.626 + */
126.627 + public String getCanonicalPath() throws IOException {
126.628 + throw new SecurityException();
126.629 + }
126.630 +
126.631 + /**
126.632 + * Returns the canonical form of this abstract pathname. Equivalent to
126.633 + * <code>new File(this.{@link #getCanonicalPath})</code>.
126.634 + *
126.635 + * @return The canonical pathname string denoting the same file or
126.636 + * directory as this abstract pathname
126.637 + *
126.638 + * @throws IOException
126.639 + * If an I/O error occurs, which is possible because the
126.640 + * construction of the canonical pathname may require
126.641 + * filesystem queries
126.642 + *
126.643 + * @throws SecurityException
126.644 + * If a required system property value cannot be accessed, or
126.645 + * if a security manager exists and its <code>{@link
126.646 + * java.lang.SecurityManager#checkRead}</code> method denies
126.647 + * read access to the file
126.648 + *
126.649 + * @since 1.2
126.650 + * @see Path#toRealPath
126.651 + */
126.652 + public File getCanonicalFile() throws IOException {
126.653 + String canonPath = getCanonicalPath();
126.654 + return new File(canonPath, fs.prefixLength(canonPath));
126.655 + }
126.656 +
126.657 + private static String slashify(String path, boolean isDirectory) {
126.658 + String p = path;
126.659 + if (File.separatorChar != '/')
126.660 + p = p.replace(File.separatorChar, '/');
126.661 + if (!p.startsWith("/"))
126.662 + p = "/" + p;
126.663 + if (!p.endsWith("/") && isDirectory)
126.664 + p = p + "/";
126.665 + return p;
126.666 + }
126.667 +
126.668 + /**
126.669 + * Converts this abstract pathname into a <code>file:</code> URL. The
126.670 + * exact form of the URL is system-dependent. If it can be determined that
126.671 + * the file denoted by this abstract pathname is a directory, then the
126.672 + * resulting URL will end with a slash.
126.673 + *
126.674 + * @return A URL object representing the equivalent file URL
126.675 + *
126.676 + * @throws MalformedURLException
126.677 + * If the path cannot be parsed as a URL
126.678 + *
126.679 + * @see #toURI()
126.680 + * @see java.net.URI
126.681 + * @see java.net.URI#toURL()
126.682 + * @see java.net.URL
126.683 + * @since 1.2
126.684 + *
126.685 + * @deprecated This method does not automatically escape characters that
126.686 + * are illegal in URLs. It is recommended that new code convert an
126.687 + * abstract pathname into a URL by first converting it into a URI, via the
126.688 + * {@link #toURI() toURI} method, and then converting the URI into a URL
126.689 + * via the {@link java.net.URI#toURL() URI.toURL} method.
126.690 + */
126.691 + @Deprecated
126.692 + public URL toURL() throws MalformedURLException {
126.693 + return new URL("file", "", slashify(getAbsolutePath(), isDirectory()));
126.694 + }
126.695 +
126.696 + /**
126.697 + * Constructs a <tt>file:</tt> URI that represents this abstract pathname.
126.698 + *
126.699 + * <p> The exact form of the URI is system-dependent. If it can be
126.700 + * determined that the file denoted by this abstract pathname is a
126.701 + * directory, then the resulting URI will end with a slash.
126.702 + *
126.703 + * <p> For a given abstract pathname <i>f</i>, it is guaranteed that
126.704 + *
126.705 + * <blockquote><tt>
126.706 + * new {@link #File(java.net.URI) File}(</tt><i> f</i><tt>.toURI()).equals(</tt><i> f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
126.707 + * </tt></blockquote>
126.708 + *
126.709 + * so long as the original abstract pathname, the URI, and the new abstract
126.710 + * pathname are all created in (possibly different invocations of) the same
126.711 + * Java virtual machine. Due to the system-dependent nature of abstract
126.712 + * pathnames, however, this relationship typically does not hold when a
126.713 + * <tt>file:</tt> URI that is created in a virtual machine on one operating
126.714 + * system is converted into an abstract pathname in a virtual machine on a
126.715 + * different operating system.
126.716 + *
126.717 + * <p> Note that when this abstract pathname represents a UNC pathname then
126.718 + * all components of the UNC (including the server name component) are encoded
126.719 + * in the {@code URI} path. The authority component is undefined, meaning
126.720 + * that it is represented as {@code null}. The {@link Path} class defines the
126.721 + * {@link Path#toUri toUri} method to encode the server name in the authority
126.722 + * component of the resulting {@code URI}. The {@link #toPath toPath} method
126.723 + * may be used to obtain a {@code Path} representing this abstract pathname.
126.724 + *
126.725 + * @return An absolute, hierarchical URI with a scheme equal to
126.726 + * <tt>"file"</tt>, a path representing this abstract pathname,
126.727 + * and undefined authority, query, and fragment components
126.728 + * @throws SecurityException If a required system property value cannot
126.729 + * be accessed.
126.730 + *
126.731 + * @see #File(java.net.URI)
126.732 + * @see java.net.URI
126.733 + * @see java.net.URI#toURL()
126.734 + * @since 1.4
126.735 + */
126.736 + public URI toURI() {
126.737 + try {
126.738 + File f = getAbsoluteFile();
126.739 + String sp = slashify(f.getPath(), f.isDirectory());
126.740 + if (sp.startsWith("//"))
126.741 + sp = "//" + sp;
126.742 + return new URI("file", null, sp, null);
126.743 + } catch (URISyntaxException x) {
126.744 + throw new Error(x); // Can't happen
126.745 + }
126.746 + }
126.747 +
126.748 +
126.749 + /* -- Attribute accessors -- */
126.750 +
126.751 + /**
126.752 + * Tests whether the application can read the file denoted by this
126.753 + * abstract pathname.
126.754 + *
126.755 + * @return <code>true</code> if and only if the file specified by this
126.756 + * abstract pathname exists <em>and</em> can be read by the
126.757 + * application; <code>false</code> otherwise
126.758 + *
126.759 + * @throws SecurityException
126.760 + * If a security manager exists and its <code>{@link
126.761 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
126.762 + * method denies read access to the file
126.763 + */
126.764 + public boolean canRead() {
126.765 + throw new SecurityException();
126.766 + }
126.767 +
126.768 + /**
126.769 + * Tests whether the application can modify the file denoted by this
126.770 + * abstract pathname.
126.771 + *
126.772 + * @return <code>true</code> if and only if the file system actually
126.773 + * contains a file denoted by this abstract pathname <em>and</em>
126.774 + * the application is allowed to write to the file;
126.775 + * <code>false</code> otherwise.
126.776 + *
126.777 + * @throws SecurityException
126.778 + * If a security manager exists and its <code>{@link
126.779 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.780 + * method denies write access to the file
126.781 + */
126.782 + public boolean canWrite() {
126.783 + throw new SecurityException();
126.784 + }
126.785 +
126.786 + /**
126.787 + * Tests whether the file or directory denoted by this abstract pathname
126.788 + * exists.
126.789 + *
126.790 + * @return <code>true</code> if and only if the file or directory denoted
126.791 + * by this abstract pathname exists; <code>false</code> otherwise
126.792 + *
126.793 + * @throws SecurityException
126.794 + * If a security manager exists and its <code>{@link
126.795 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
126.796 + * method denies read access to the file or directory
126.797 + */
126.798 + public boolean exists() {
126.799 + throw new SecurityException();
126.800 + }
126.801 +
126.802 + /**
126.803 + * Tests whether the file denoted by this abstract pathname is a
126.804 + * directory.
126.805 + *
126.806 + * <p> Where it is required to distinguish an I/O exception from the case
126.807 + * that the file is not a directory, or where several attributes of the
126.808 + * same file are required at the same time, then the {@link
126.809 + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
126.810 + * Files.readAttributes} method may be used.
126.811 + *
126.812 + * @return <code>true</code> if and only if the file denoted by this
126.813 + * abstract pathname exists <em>and</em> is a directory;
126.814 + * <code>false</code> otherwise
126.815 + *
126.816 + * @throws SecurityException
126.817 + * If a security manager exists and its <code>{@link
126.818 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
126.819 + * method denies read access to the file
126.820 + */
126.821 + public boolean isDirectory() {
126.822 + throw new SecurityException();
126.823 + }
126.824 +
126.825 + /**
126.826 + * Tests whether the file denoted by this abstract pathname is a normal
126.827 + * file. A file is <em>normal</em> if it is not a directory and, in
126.828 + * addition, satisfies other system-dependent criteria. Any non-directory
126.829 + * file created by a Java application is guaranteed to be a normal file.
126.830 + *
126.831 + * <p> Where it is required to distinguish an I/O exception from the case
126.832 + * that the file is not a normal file, or where several attributes of the
126.833 + * same file are required at the same time, then the {@link
126.834 + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
126.835 + * Files.readAttributes} method may be used.
126.836 + *
126.837 + * @return <code>true</code> if and only if the file denoted by this
126.838 + * abstract pathname exists <em>and</em> is a normal file;
126.839 + * <code>false</code> otherwise
126.840 + *
126.841 + * @throws SecurityException
126.842 + * If a security manager exists and its <code>{@link
126.843 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
126.844 + * method denies read access to the file
126.845 + */
126.846 + public boolean isFile() {
126.847 + throw new SecurityException();
126.848 + }
126.849 +
126.850 + /**
126.851 + * Tests whether the file named by this abstract pathname is a hidden
126.852 + * file. The exact definition of <em>hidden</em> is system-dependent. On
126.853 + * UNIX systems, a file is considered to be hidden if its name begins with
126.854 + * a period character (<code>'.'</code>). On Microsoft Windows systems, a file is
126.855 + * considered to be hidden if it has been marked as such in the filesystem.
126.856 + *
126.857 + * @return <code>true</code> if and only if the file denoted by this
126.858 + * abstract pathname is hidden according to the conventions of the
126.859 + * underlying platform
126.860 + *
126.861 + * @throws SecurityException
126.862 + * If a security manager exists and its <code>{@link
126.863 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
126.864 + * method denies read access to the file
126.865 + *
126.866 + * @since 1.2
126.867 + */
126.868 + public boolean isHidden() {
126.869 + throw new SecurityException();
126.870 + }
126.871 +
126.872 + /**
126.873 + * Returns the time that the file denoted by this abstract pathname was
126.874 + * last modified.
126.875 + *
126.876 + * <p> Where it is required to distinguish an I/O exception from the case
126.877 + * where {@code 0L} is returned, or where several attributes of the
126.878 + * same file are required at the same time, or where the time of last
126.879 + * access or the creation time are required, then the {@link
126.880 + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
126.881 + * Files.readAttributes} method may be used.
126.882 + *
126.883 + * @return A <code>long</code> value representing the time the file was
126.884 + * last modified, measured in milliseconds since the epoch
126.885 + * (00:00:00 GMT, January 1, 1970), or <code>0L</code> if the
126.886 + * file does not exist or if an I/O error occurs
126.887 + *
126.888 + * @throws SecurityException
126.889 + * If a security manager exists and its <code>{@link
126.890 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
126.891 + * method denies read access to the file
126.892 + */
126.893 + public long lastModified() {
126.894 + throw new SecurityException();
126.895 + }
126.896 +
126.897 + /**
126.898 + * Returns the length of the file denoted by this abstract pathname.
126.899 + * The return value is unspecified if this pathname denotes a directory.
126.900 + *
126.901 + * <p> Where it is required to distinguish an I/O exception from the case
126.902 + * that {@code 0L} is returned, or where several attributes of the same file
126.903 + * are required at the same time, then the {@link
126.904 + * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
126.905 + * Files.readAttributes} method may be used.
126.906 + *
126.907 + * @return The length, in bytes, of the file denoted by this abstract
126.908 + * pathname, or <code>0L</code> if the file does not exist. Some
126.909 + * operating systems may return <code>0L</code> for pathnames
126.910 + * denoting system-dependent entities such as devices or pipes.
126.911 + *
126.912 + * @throws SecurityException
126.913 + * If a security manager exists and its <code>{@link
126.914 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
126.915 + * method denies read access to the file
126.916 + */
126.917 + public long length() {
126.918 + throw new SecurityException();
126.919 + }
126.920 +
126.921 +
126.922 + /* -- File operations -- */
126.923 +
126.924 + /**
126.925 + * Atomically creates a new, empty file named by this abstract pathname if
126.926 + * and only if a file with this name does not yet exist. The check for the
126.927 + * existence of the file and the creation of the file if it does not exist
126.928 + * are a single operation that is atomic with respect to all other
126.929 + * filesystem activities that might affect the file.
126.930 + * <P>
126.931 + * Note: this method should <i>not</i> be used for file-locking, as
126.932 + * the resulting protocol cannot be made to work reliably. The
126.933 + * {@link java.nio.channels.FileLock FileLock}
126.934 + * facility should be used instead.
126.935 + *
126.936 + * @return <code>true</code> if the named file does not exist and was
126.937 + * successfully created; <code>false</code> if the named file
126.938 + * already exists
126.939 + *
126.940 + * @throws IOException
126.941 + * If an I/O error occurred
126.942 + *
126.943 + * @throws SecurityException
126.944 + * If a security manager exists and its <code>{@link
126.945 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.946 + * method denies write access to the file
126.947 + *
126.948 + * @since 1.2
126.949 + */
126.950 + public boolean createNewFile() throws IOException {
126.951 + throw new SecurityException();
126.952 + }
126.953 +
126.954 + /**
126.955 + * Deletes the file or directory denoted by this abstract pathname. If
126.956 + * this pathname denotes a directory, then the directory must be empty in
126.957 + * order to be deleted.
126.958 + *
126.959 + * <p> Note that the {@link java.nio.file.Files} class defines the {@link
126.960 + * java.nio.file.Files#delete(Path) delete} method to throw an {@link IOException}
126.961 + * when a file cannot be deleted. This is useful for error reporting and to
126.962 + * diagnose why a file cannot be deleted.
126.963 + *
126.964 + * @return <code>true</code> if and only if the file or directory is
126.965 + * successfully deleted; <code>false</code> otherwise
126.966 + *
126.967 + * @throws SecurityException
126.968 + * If a security manager exists and its <code>{@link
126.969 + * java.lang.SecurityManager#checkDelete}</code> method denies
126.970 + * delete access to the file
126.971 + */
126.972 + public boolean delete() {
126.973 + throw new SecurityException();
126.974 + }
126.975 +
126.976 + /**
126.977 + * Requests that the file or directory denoted by this abstract
126.978 + * pathname be deleted when the virtual machine terminates.
126.979 + * Files (or directories) are deleted in the reverse order that
126.980 + * they are registered. Invoking this method to delete a file or
126.981 + * directory that is already registered for deletion has no effect.
126.982 + * Deletion will be attempted only for normal termination of the
126.983 + * virtual machine, as defined by the Java Language Specification.
126.984 + *
126.985 + * <p> Once deletion has been requested, it is not possible to cancel the
126.986 + * request. This method should therefore be used with care.
126.987 + *
126.988 + * <P>
126.989 + * Note: this method should <i>not</i> be used for file-locking, as
126.990 + * the resulting protocol cannot be made to work reliably. The
126.991 + * {@link java.nio.channels.FileLock FileLock}
126.992 + * facility should be used instead.
126.993 + *
126.994 + * @throws SecurityException
126.995 + * If a security manager exists and its <code>{@link
126.996 + * java.lang.SecurityManager#checkDelete}</code> method denies
126.997 + * delete access to the file
126.998 + *
126.999 + * @see #delete
126.1000 + *
126.1001 + * @since 1.2
126.1002 + */
126.1003 + public void deleteOnExit() {
126.1004 + throw new SecurityException();
126.1005 + }
126.1006 +
126.1007 + /**
126.1008 + * Returns an array of strings naming the files and directories in the
126.1009 + * directory denoted by this abstract pathname.
126.1010 + *
126.1011 + * <p> If this abstract pathname does not denote a directory, then this
126.1012 + * method returns {@code null}. Otherwise an array of strings is
126.1013 + * returned, one for each file or directory in the directory. Names
126.1014 + * denoting the directory itself and the directory's parent directory are
126.1015 + * not included in the result. Each string is a file name rather than a
126.1016 + * complete path.
126.1017 + *
126.1018 + * <p> There is no guarantee that the name strings in the resulting array
126.1019 + * will appear in any specific order; they are not, in particular,
126.1020 + * guaranteed to appear in alphabetical order.
126.1021 + *
126.1022 + * <p> Note that the {@link java.nio.file.Files} class defines the {@link
126.1023 + * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method to
126.1024 + * open a directory and iterate over the names of the files in the directory.
126.1025 + * This may use less resources when working with very large directories, and
126.1026 + * may be more responsive when working with remote directories.
126.1027 + *
126.1028 + * @return An array of strings naming the files and directories in the
126.1029 + * directory denoted by this abstract pathname. The array will be
126.1030 + * empty if the directory is empty. Returns {@code null} if
126.1031 + * this abstract pathname does not denote a directory, or if an
126.1032 + * I/O error occurs.
126.1033 + *
126.1034 + * @throws SecurityException
126.1035 + * If a security manager exists and its {@link
126.1036 + * SecurityManager#checkRead(String)} method denies read access to
126.1037 + * the directory
126.1038 + */
126.1039 + public String[] list() {
126.1040 + throw new SecurityException();
126.1041 + }
126.1042 +
126.1043 + /**
126.1044 + * Returns an array of strings naming the files and directories in the
126.1045 + * directory denoted by this abstract pathname that satisfy the specified
126.1046 + * filter. The behavior of this method is the same as that of the
126.1047 + * {@link #list()} method, except that the strings in the returned array
126.1048 + * must satisfy the filter. If the given {@code filter} is {@code null}
126.1049 + * then all names are accepted. Otherwise, a name satisfies the filter if
126.1050 + * and only if the value {@code true} results when the {@link
126.1051 + * FilenameFilter#accept FilenameFilter.accept(File, String)} method
126.1052 + * of the filter is invoked on this abstract pathname and the name of a
126.1053 + * file or directory in the directory that it denotes.
126.1054 + *
126.1055 + * @param filter
126.1056 + * A filename filter
126.1057 + *
126.1058 + * @return An array of strings naming the files and directories in the
126.1059 + * directory denoted by this abstract pathname that were accepted
126.1060 + * by the given {@code filter}. The array will be empty if the
126.1061 + * directory is empty or if no names were accepted by the filter.
126.1062 + * Returns {@code null} if this abstract pathname does not denote
126.1063 + * a directory, or if an I/O error occurs.
126.1064 + *
126.1065 + * @throws SecurityException
126.1066 + * If a security manager exists and its {@link
126.1067 + * SecurityManager#checkRead(String)} method denies read access to
126.1068 + * the directory
126.1069 + *
126.1070 + * @see java.nio.file.Files#newDirectoryStream(Path,String)
126.1071 + */
126.1072 + public String[] list(FilenameFilter filter) {
126.1073 + throw new SecurityException();
126.1074 + }
126.1075 +
126.1076 + /**
126.1077 + * Returns an array of abstract pathnames denoting the files in the
126.1078 + * directory denoted by this abstract pathname.
126.1079 + *
126.1080 + * <p> If this abstract pathname does not denote a directory, then this
126.1081 + * method returns {@code null}. Otherwise an array of {@code File} objects
126.1082 + * is returned, one for each file or directory in the directory. Pathnames
126.1083 + * denoting the directory itself and the directory's parent directory are
126.1084 + * not included in the result. Each resulting abstract pathname is
126.1085 + * constructed from this abstract pathname using the {@link #File(File,
126.1086 + * String) File(File, String)} constructor. Therefore if this
126.1087 + * pathname is absolute then each resulting pathname is absolute; if this
126.1088 + * pathname is relative then each resulting pathname will be relative to
126.1089 + * the same directory.
126.1090 + *
126.1091 + * <p> There is no guarantee that the name strings in the resulting array
126.1092 + * will appear in any specific order; they are not, in particular,
126.1093 + * guaranteed to appear in alphabetical order.
126.1094 + *
126.1095 + * <p> Note that the {@link java.nio.file.Files} class defines the {@link
126.1096 + * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method
126.1097 + * to open a directory and iterate over the names of the files in the
126.1098 + * directory. This may use less resources when working with very large
126.1099 + * directories.
126.1100 + *
126.1101 + * @return An array of abstract pathnames denoting the files and
126.1102 + * directories in the directory denoted by this abstract pathname.
126.1103 + * The array will be empty if the directory is empty. Returns
126.1104 + * {@code null} if this abstract pathname does not denote a
126.1105 + * directory, or if an I/O error occurs.
126.1106 + *
126.1107 + * @throws SecurityException
126.1108 + * If a security manager exists and its {@link
126.1109 + * SecurityManager#checkRead(String)} method denies read access to
126.1110 + * the directory
126.1111 + *
126.1112 + * @since 1.2
126.1113 + */
126.1114 + public File[] listFiles() {
126.1115 + throw new SecurityException();
126.1116 + }
126.1117 +
126.1118 + /**
126.1119 + * Returns an array of abstract pathnames denoting the files and
126.1120 + * directories in the directory denoted by this abstract pathname that
126.1121 + * satisfy the specified filter. The behavior of this method is the same
126.1122 + * as that of the {@link #listFiles()} method, except that the pathnames in
126.1123 + * the returned array must satisfy the filter. If the given {@code filter}
126.1124 + * is {@code null} then all pathnames are accepted. Otherwise, a pathname
126.1125 + * satisfies the filter if and only if the value {@code true} results when
126.1126 + * the {@link FilenameFilter#accept
126.1127 + * FilenameFilter.accept(File, String)} method of the filter is
126.1128 + * invoked on this abstract pathname and the name of a file or directory in
126.1129 + * the directory that it denotes.
126.1130 + *
126.1131 + * @param filter
126.1132 + * A filename filter
126.1133 + *
126.1134 + * @return An array of abstract pathnames denoting the files and
126.1135 + * directories in the directory denoted by this abstract pathname.
126.1136 + * The array will be empty if the directory is empty. Returns
126.1137 + * {@code null} if this abstract pathname does not denote a
126.1138 + * directory, or if an I/O error occurs.
126.1139 + *
126.1140 + * @throws SecurityException
126.1141 + * If a security manager exists and its {@link
126.1142 + * SecurityManager#checkRead(String)} method denies read access to
126.1143 + * the directory
126.1144 + *
126.1145 + * @since 1.2
126.1146 + * @see java.nio.file.Files#newDirectoryStream(Path,String)
126.1147 + */
126.1148 + public File[] listFiles(FilenameFilter filter) {
126.1149 + throw new SecurityException();
126.1150 + }
126.1151 +
126.1152 + /**
126.1153 + * Returns an array of abstract pathnames denoting the files and
126.1154 + * directories in the directory denoted by this abstract pathname that
126.1155 + * satisfy the specified filter. The behavior of this method is the same
126.1156 + * as that of the {@link #listFiles()} method, except that the pathnames in
126.1157 + * the returned array must satisfy the filter. If the given {@code filter}
126.1158 + * is {@code null} then all pathnames are accepted. Otherwise, a pathname
126.1159 + * satisfies the filter if and only if the value {@code true} results when
126.1160 + * the {@link FileFilter#accept FileFilter.accept(File)} method of the
126.1161 + * filter is invoked on the pathname.
126.1162 + *
126.1163 + * @param filter
126.1164 + * A file filter
126.1165 + *
126.1166 + * @return An array of abstract pathnames denoting the files and
126.1167 + * directories in the directory denoted by this abstract pathname.
126.1168 + * The array will be empty if the directory is empty. Returns
126.1169 + * {@code null} if this abstract pathname does not denote a
126.1170 + * directory, or if an I/O error occurs.
126.1171 + *
126.1172 + * @throws SecurityException
126.1173 + * If a security manager exists and its {@link
126.1174 + * SecurityManager#checkRead(String)} method denies read access to
126.1175 + * the directory
126.1176 + *
126.1177 + * @since 1.2
126.1178 + * @see java.nio.file.Files#newDirectoryStream(Path,java.nio.file.DirectoryStream.Filter)
126.1179 + */
126.1180 + public File[] listFiles(FileFilter filter) {
126.1181 + throw new SecurityException();
126.1182 + }
126.1183 +
126.1184 + /**
126.1185 + * Creates the directory named by this abstract pathname.
126.1186 + *
126.1187 + * @return <code>true</code> if and only if the directory was
126.1188 + * created; <code>false</code> otherwise
126.1189 + *
126.1190 + * @throws SecurityException
126.1191 + * If a security manager exists and its <code>{@link
126.1192 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1193 + * method does not permit the named directory to be created
126.1194 + */
126.1195 + public boolean mkdir() {
126.1196 + throw new SecurityException();
126.1197 + }
126.1198 +
126.1199 + /**
126.1200 + * Creates the directory named by this abstract pathname, including any
126.1201 + * necessary but nonexistent parent directories. Note that if this
126.1202 + * operation fails it may have succeeded in creating some of the necessary
126.1203 + * parent directories.
126.1204 + *
126.1205 + * @return <code>true</code> if and only if the directory was created,
126.1206 + * along with all necessary parent directories; <code>false</code>
126.1207 + * otherwise
126.1208 + *
126.1209 + * @throws SecurityException
126.1210 + * If a security manager exists and its <code>{@link
126.1211 + * java.lang.SecurityManager#checkRead(java.lang.String)}</code>
126.1212 + * method does not permit verification of the existence of the
126.1213 + * named directory and all necessary parent directories; or if
126.1214 + * the <code>{@link
126.1215 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1216 + * method does not permit the named directory and all necessary
126.1217 + * parent directories to be created
126.1218 + */
126.1219 + public boolean mkdirs() {
126.1220 + throw new SecurityException();
126.1221 + }
126.1222 +
126.1223 + /**
126.1224 + * Renames the file denoted by this abstract pathname.
126.1225 + *
126.1226 + * <p> Many aspects of the behavior of this method are inherently
126.1227 + * platform-dependent: The rename operation might not be able to move a
126.1228 + * file from one filesystem to another, it might not be atomic, and it
126.1229 + * might not succeed if a file with the destination abstract pathname
126.1230 + * already exists. The return value should always be checked to make sure
126.1231 + * that the rename operation was successful.
126.1232 + *
126.1233 + * <p> Note that the {@link java.nio.file.Files} class defines the {@link
126.1234 + * java.nio.file.Files#move move} method to move or rename a file in a
126.1235 + * platform independent manner.
126.1236 + *
126.1237 + * @param dest The new abstract pathname for the named file
126.1238 + *
126.1239 + * @return <code>true</code> if and only if the renaming succeeded;
126.1240 + * <code>false</code> otherwise
126.1241 + *
126.1242 + * @throws SecurityException
126.1243 + * If a security manager exists and its <code>{@link
126.1244 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1245 + * method denies write access to either the old or new pathnames
126.1246 + *
126.1247 + * @throws NullPointerException
126.1248 + * If parameter <code>dest</code> is <code>null</code>
126.1249 + */
126.1250 + public boolean renameTo(File dest) {
126.1251 + throw new SecurityException();
126.1252 + }
126.1253 +
126.1254 + /**
126.1255 + * Sets the last-modified time of the file or directory named by this
126.1256 + * abstract pathname.
126.1257 + *
126.1258 + * <p> All platforms support file-modification times to the nearest second,
126.1259 + * but some provide more precision. The argument will be truncated to fit
126.1260 + * the supported precision. If the operation succeeds and no intervening
126.1261 + * operations on the file take place, then the next invocation of the
126.1262 + * <code>{@link #lastModified}</code> method will return the (possibly
126.1263 + * truncated) <code>time</code> argument that was passed to this method.
126.1264 + *
126.1265 + * @param time The new last-modified time, measured in milliseconds since
126.1266 + * the epoch (00:00:00 GMT, January 1, 1970)
126.1267 + *
126.1268 + * @return <code>true</code> if and only if the operation succeeded;
126.1269 + * <code>false</code> otherwise
126.1270 + *
126.1271 + * @throws IllegalArgumentException If the argument is negative
126.1272 + *
126.1273 + * @throws SecurityException
126.1274 + * If a security manager exists and its <code>{@link
126.1275 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1276 + * method denies write access to the named file
126.1277 + *
126.1278 + * @since 1.2
126.1279 + */
126.1280 + public boolean setLastModified(long time) {
126.1281 + throw new SecurityException();
126.1282 + }
126.1283 +
126.1284 + /**
126.1285 + * Marks the file or directory named by this abstract pathname so that
126.1286 + * only read operations are allowed. After invoking this method the file
126.1287 + * or directory is guaranteed not to change until it is either deleted or
126.1288 + * marked to allow write access. Whether or not a read-only file or
126.1289 + * directory may be deleted depends upon the underlying system.
126.1290 + *
126.1291 + * @return <code>true</code> if and only if the operation succeeded;
126.1292 + * <code>false</code> otherwise
126.1293 + *
126.1294 + * @throws SecurityException
126.1295 + * If a security manager exists and its <code>{@link
126.1296 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1297 + * method denies write access to the named file
126.1298 + *
126.1299 + * @since 1.2
126.1300 + */
126.1301 + public boolean setReadOnly() {
126.1302 + throw new SecurityException();
126.1303 + }
126.1304 +
126.1305 + /**
126.1306 + * Sets the owner's or everybody's write permission for this abstract
126.1307 + * pathname.
126.1308 + *
126.1309 + * <p> The {@link java.nio.file.Files} class defines methods that operate on
126.1310 + * file attributes including file permissions. This may be used when finer
126.1311 + * manipulation of file permissions is required.
126.1312 + *
126.1313 + * @param writable
126.1314 + * If <code>true</code>, sets the access permission to allow write
126.1315 + * operations; if <code>false</code> to disallow write operations
126.1316 + *
126.1317 + * @param ownerOnly
126.1318 + * If <code>true</code>, the write permission applies only to the
126.1319 + * owner's write permission; otherwise, it applies to everybody. If
126.1320 + * the underlying file system can not distinguish the owner's write
126.1321 + * permission from that of others, then the permission will apply to
126.1322 + * everybody, regardless of this value.
126.1323 + *
126.1324 + * @return <code>true</code> if and only if the operation succeeded. The
126.1325 + * operation will fail if the user does not have permission to change
126.1326 + * the access permissions of this abstract pathname.
126.1327 + *
126.1328 + * @throws SecurityException
126.1329 + * If a security manager exists and its <code>{@link
126.1330 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1331 + * method denies write access to the named file
126.1332 + *
126.1333 + * @since 1.6
126.1334 + */
126.1335 + public boolean setWritable(boolean writable, boolean ownerOnly) {
126.1336 + throw new SecurityException();
126.1337 + }
126.1338 +
126.1339 + /**
126.1340 + * A convenience method to set the owner's write permission for this abstract
126.1341 + * pathname.
126.1342 + *
126.1343 + * <p> An invocation of this method of the form <tt>file.setWritable(arg)</tt>
126.1344 + * behaves in exactly the same way as the invocation
126.1345 + *
126.1346 + * <pre>
126.1347 + * file.setWritable(arg, true) </pre>
126.1348 + *
126.1349 + * @param writable
126.1350 + * If <code>true</code>, sets the access permission to allow write
126.1351 + * operations; if <code>false</code> to disallow write operations
126.1352 + *
126.1353 + * @return <code>true</code> if and only if the operation succeeded. The
126.1354 + * operation will fail if the user does not have permission to
126.1355 + * change the access permissions of this abstract pathname.
126.1356 + *
126.1357 + * @throws SecurityException
126.1358 + * If a security manager exists and its <code>{@link
126.1359 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1360 + * method denies write access to the file
126.1361 + *
126.1362 + * @since 1.6
126.1363 + */
126.1364 + public boolean setWritable(boolean writable) {
126.1365 + return setWritable(writable, true);
126.1366 + }
126.1367 +
126.1368 + /**
126.1369 + * Sets the owner's or everybody's read permission for this abstract
126.1370 + * pathname.
126.1371 + *
126.1372 + * <p> The {@link java.nio.file.Files} class defines methods that operate on
126.1373 + * file attributes including file permissions. This may be used when finer
126.1374 + * manipulation of file permissions is required.
126.1375 + *
126.1376 + * @param readable
126.1377 + * If <code>true</code>, sets the access permission to allow read
126.1378 + * operations; if <code>false</code> to disallow read operations
126.1379 + *
126.1380 + * @param ownerOnly
126.1381 + * If <code>true</code>, the read permission applies only to the
126.1382 + * owner's read permission; otherwise, it applies to everybody. If
126.1383 + * the underlying file system can not distinguish the owner's read
126.1384 + * permission from that of others, then the permission will apply to
126.1385 + * everybody, regardless of this value.
126.1386 + *
126.1387 + * @return <code>true</code> if and only if the operation succeeded. The
126.1388 + * operation will fail if the user does not have permission to
126.1389 + * change the access permissions of this abstract pathname. If
126.1390 + * <code>readable</code> is <code>false</code> and the underlying
126.1391 + * file system does not implement a read permission, then the
126.1392 + * operation will fail.
126.1393 + *
126.1394 + * @throws SecurityException
126.1395 + * If a security manager exists and its <code>{@link
126.1396 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1397 + * method denies write access to the file
126.1398 + *
126.1399 + * @since 1.6
126.1400 + */
126.1401 + public boolean setReadable(boolean readable, boolean ownerOnly) {
126.1402 + throw new SecurityException();
126.1403 + }
126.1404 +
126.1405 + /**
126.1406 + * A convenience method to set the owner's read permission for this abstract
126.1407 + * pathname.
126.1408 + *
126.1409 + * <p>An invocation of this method of the form <tt>file.setReadable(arg)</tt>
126.1410 + * behaves in exactly the same way as the invocation
126.1411 + *
126.1412 + * <pre>
126.1413 + * file.setReadable(arg, true) </pre>
126.1414 + *
126.1415 + * @param readable
126.1416 + * If <code>true</code>, sets the access permission to allow read
126.1417 + * operations; if <code>false</code> to disallow read operations
126.1418 + *
126.1419 + * @return <code>true</code> if and only if the operation succeeded. The
126.1420 + * operation will fail if the user does not have permission to
126.1421 + * change the access permissions of this abstract pathname. If
126.1422 + * <code>readable</code> is <code>false</code> and the underlying
126.1423 + * file system does not implement a read permission, then the
126.1424 + * operation will fail.
126.1425 + *
126.1426 + * @throws SecurityException
126.1427 + * If a security manager exists and its <code>{@link
126.1428 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1429 + * method denies write access to the file
126.1430 + *
126.1431 + * @since 1.6
126.1432 + */
126.1433 + public boolean setReadable(boolean readable) {
126.1434 + return setReadable(readable, true);
126.1435 + }
126.1436 +
126.1437 + /**
126.1438 + * Sets the owner's or everybody's execute permission for this abstract
126.1439 + * pathname.
126.1440 + *
126.1441 + * <p> The {@link java.nio.file.Files} class defines methods that operate on
126.1442 + * file attributes including file permissions. This may be used when finer
126.1443 + * manipulation of file permissions is required.
126.1444 + *
126.1445 + * @param executable
126.1446 + * If <code>true</code>, sets the access permission to allow execute
126.1447 + * operations; if <code>false</code> to disallow execute operations
126.1448 + *
126.1449 + * @param ownerOnly
126.1450 + * If <code>true</code>, the execute permission applies only to the
126.1451 + * owner's execute permission; otherwise, it applies to everybody.
126.1452 + * If the underlying file system can not distinguish the owner's
126.1453 + * execute permission from that of others, then the permission will
126.1454 + * apply to everybody, regardless of this value.
126.1455 + *
126.1456 + * @return <code>true</code> if and only if the operation succeeded. The
126.1457 + * operation will fail if the user does not have permission to
126.1458 + * change the access permissions of this abstract pathname. If
126.1459 + * <code>executable</code> is <code>false</code> and the underlying
126.1460 + * file system does not implement an execute permission, then the
126.1461 + * operation will fail.
126.1462 + *
126.1463 + * @throws SecurityException
126.1464 + * If a security manager exists and its <code>{@link
126.1465 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1466 + * method denies write access to the file
126.1467 + *
126.1468 + * @since 1.6
126.1469 + */
126.1470 + public boolean setExecutable(boolean executable, boolean ownerOnly) {
126.1471 + throw new SecurityException();
126.1472 + }
126.1473 +
126.1474 + /**
126.1475 + * A convenience method to set the owner's execute permission for this abstract
126.1476 + * pathname.
126.1477 + *
126.1478 + * <p>An invocation of this method of the form <tt>file.setExcutable(arg)</tt>
126.1479 + * behaves in exactly the same way as the invocation
126.1480 + *
126.1481 + * <pre>
126.1482 + * file.setExecutable(arg, true) </pre>
126.1483 + *
126.1484 + * @param executable
126.1485 + * If <code>true</code>, sets the access permission to allow execute
126.1486 + * operations; if <code>false</code> to disallow execute operations
126.1487 + *
126.1488 + * @return <code>true</code> if and only if the operation succeeded. The
126.1489 + * operation will fail if the user does not have permission to
126.1490 + * change the access permissions of this abstract pathname. If
126.1491 + * <code>executable</code> is <code>false</code> and the underlying
126.1492 + * file system does not implement an excute permission, then the
126.1493 + * operation will fail.
126.1494 + *
126.1495 + * @throws SecurityException
126.1496 + * If a security manager exists and its <code>{@link
126.1497 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1498 + * method denies write access to the file
126.1499 + *
126.1500 + * @since 1.6
126.1501 + */
126.1502 + public boolean setExecutable(boolean executable) {
126.1503 + return setExecutable(executable, true);
126.1504 + }
126.1505 +
126.1506 + /**
126.1507 + * Tests whether the application can execute the file denoted by this
126.1508 + * abstract pathname.
126.1509 + *
126.1510 + * @return <code>true</code> if and only if the abstract pathname exists
126.1511 + * <em>and</em> the application is allowed to execute the file
126.1512 + *
126.1513 + * @throws SecurityException
126.1514 + * If a security manager exists and its <code>{@link
126.1515 + * java.lang.SecurityManager#checkExec(java.lang.String)}</code>
126.1516 + * method denies execute access to the file
126.1517 + *
126.1518 + * @since 1.6
126.1519 + */
126.1520 + public boolean canExecute() {
126.1521 + throw new SecurityException();
126.1522 + }
126.1523 +
126.1524 +
126.1525 + /* -- Filesystem interface -- */
126.1526 +
126.1527 + /**
126.1528 + * List the available filesystem roots.
126.1529 + *
126.1530 + * <p> A particular Java platform may support zero or more
126.1531 + * hierarchically-organized file systems. Each file system has a
126.1532 + * {@code root} directory from which all other files in that file system
126.1533 + * can be reached. Windows platforms, for example, have a root directory
126.1534 + * for each active drive; UNIX platforms have a single root directory,
126.1535 + * namely {@code "/"}. The set of available filesystem roots is affected
126.1536 + * by various system-level operations such as the insertion or ejection of
126.1537 + * removable media and the disconnecting or unmounting of physical or
126.1538 + * virtual disk drives.
126.1539 + *
126.1540 + * <p> This method returns an array of {@code File} objects that denote the
126.1541 + * root directories of the available filesystem roots. It is guaranteed
126.1542 + * that the canonical pathname of any file physically present on the local
126.1543 + * machine will begin with one of the roots returned by this method.
126.1544 + *
126.1545 + * <p> The canonical pathname of a file that resides on some other machine
126.1546 + * and is accessed via a remote-filesystem protocol such as SMB or NFS may
126.1547 + * or may not begin with one of the roots returned by this method. If the
126.1548 + * pathname of a remote file is syntactically indistinguishable from the
126.1549 + * pathname of a local file then it will begin with one of the roots
126.1550 + * returned by this method. Thus, for example, {@code File} objects
126.1551 + * denoting the root directories of the mapped network drives of a Windows
126.1552 + * platform will be returned by this method, while {@code File} objects
126.1553 + * containing UNC pathnames will not be returned by this method.
126.1554 + *
126.1555 + * <p> Unlike most methods in this class, this method does not throw
126.1556 + * security exceptions. If a security manager exists and its {@link
126.1557 + * SecurityManager#checkRead(String)} method denies read access to a
126.1558 + * particular root directory, then that directory will not appear in the
126.1559 + * result.
126.1560 + *
126.1561 + * @return An array of {@code File} objects denoting the available
126.1562 + * filesystem roots, or {@code null} if the set of roots could not
126.1563 + * be determined. The array will be empty if there are no
126.1564 + * filesystem roots.
126.1565 + *
126.1566 + * @since 1.2
126.1567 + * @see java.nio.file.FileStore
126.1568 + */
126.1569 + public static File[] listRoots() {
126.1570 + throw new SecurityException();
126.1571 + }
126.1572 +
126.1573 +
126.1574 + /* -- Disk usage -- */
126.1575 +
126.1576 + /**
126.1577 + * Returns the size of the partition <a href="#partName">named</a> by this
126.1578 + * abstract pathname.
126.1579 + *
126.1580 + * @return The size, in bytes, of the partition or <tt>0L</tt> if this
126.1581 + * abstract pathname does not name a partition
126.1582 + *
126.1583 + * @throws SecurityException
126.1584 + * If a security manager has been installed and it denies
126.1585 + * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
126.1586 + * or its {@link SecurityManager#checkRead(String)} method denies
126.1587 + * read access to the file named by this abstract pathname
126.1588 + *
126.1589 + * @since 1.6
126.1590 + */
126.1591 + public long getTotalSpace() {
126.1592 + throw new SecurityException();
126.1593 + }
126.1594 +
126.1595 + /**
126.1596 + * Returns the number of unallocated bytes in the partition <a
126.1597 + * href="#partName">named</a> by this abstract path name.
126.1598 + *
126.1599 + * <p> The returned number of unallocated bytes is a hint, but not
126.1600 + * a guarantee, that it is possible to use most or any of these
126.1601 + * bytes. The number of unallocated bytes is most likely to be
126.1602 + * accurate immediately after this call. It is likely to be made
126.1603 + * inaccurate by any external I/O operations including those made
126.1604 + * on the system outside of this virtual machine. This method
126.1605 + * makes no guarantee that write operations to this file system
126.1606 + * will succeed.
126.1607 + *
126.1608 + * @return The number of unallocated bytes on the partition <tt>0L</tt>
126.1609 + * if the abstract pathname does not name a partition. This
126.1610 + * value will be less than or equal to the total file system size
126.1611 + * returned by {@link #getTotalSpace}.
126.1612 + *
126.1613 + * @throws SecurityException
126.1614 + * If a security manager has been installed and it denies
126.1615 + * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
126.1616 + * or its {@link SecurityManager#checkRead(String)} method denies
126.1617 + * read access to the file named by this abstract pathname
126.1618 + *
126.1619 + * @since 1.6
126.1620 + */
126.1621 + public long getFreeSpace() {
126.1622 + throw new SecurityException();
126.1623 + }
126.1624 +
126.1625 + /**
126.1626 + * Returns the number of bytes available to this virtual machine on the
126.1627 + * partition <a href="#partName">named</a> by this abstract pathname. When
126.1628 + * possible, this method checks for write permissions and other operating
126.1629 + * system restrictions and will therefore usually provide a more accurate
126.1630 + * estimate of how much new data can actually be written than {@link
126.1631 + * #getFreeSpace}.
126.1632 + *
126.1633 + * <p> The returned number of available bytes is a hint, but not a
126.1634 + * guarantee, that it is possible to use most or any of these bytes. The
126.1635 + * number of unallocated bytes is most likely to be accurate immediately
126.1636 + * after this call. It is likely to be made inaccurate by any external
126.1637 + * I/O operations including those made on the system outside of this
126.1638 + * virtual machine. This method makes no guarantee that write operations
126.1639 + * to this file system will succeed.
126.1640 + *
126.1641 + * @return The number of available bytes on the partition or <tt>0L</tt>
126.1642 + * if the abstract pathname does not name a partition. On
126.1643 + * systems where this information is not available, this method
126.1644 + * will be equivalent to a call to {@link #getFreeSpace}.
126.1645 + *
126.1646 + * @throws SecurityException
126.1647 + * If a security manager has been installed and it denies
126.1648 + * {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
126.1649 + * or its {@link SecurityManager#checkRead(String)} method denies
126.1650 + * read access to the file named by this abstract pathname
126.1651 + *
126.1652 + * @since 1.6
126.1653 + */
126.1654 + public long getUsableSpace() {
126.1655 + throw new SecurityException();
126.1656 + }
126.1657 +
126.1658 + /* -- Temporary files -- */
126.1659 +
126.1660 +
126.1661 + /**
126.1662 + * <p> Creates a new empty file in the specified directory, using the
126.1663 + * given prefix and suffix strings to generate its name. If this method
126.1664 + * returns successfully then it is guaranteed that:
126.1665 + *
126.1666 + * <ol>
126.1667 + * <li> The file denoted by the returned abstract pathname did not exist
126.1668 + * before this method was invoked, and
126.1669 + * <li> Neither this method nor any of its variants will return the same
126.1670 + * abstract pathname again in the current invocation of the virtual
126.1671 + * machine.
126.1672 + * </ol>
126.1673 + *
126.1674 + * This method provides only part of a temporary-file facility. To arrange
126.1675 + * for a file created by this method to be deleted automatically, use the
126.1676 + * <code>{@link #deleteOnExit}</code> method.
126.1677 + *
126.1678 + * <p> The <code>prefix</code> argument must be at least three characters
126.1679 + * long. It is recommended that the prefix be a short, meaningful string
126.1680 + * such as <code>"hjb"</code> or <code>"mail"</code>. The
126.1681 + * <code>suffix</code> argument may be <code>null</code>, in which case the
126.1682 + * suffix <code>".tmp"</code> will be used.
126.1683 + *
126.1684 + * <p> To create the new file, the prefix and the suffix may first be
126.1685 + * adjusted to fit the limitations of the underlying platform. If the
126.1686 + * prefix is too long then it will be truncated, but its first three
126.1687 + * characters will always be preserved. If the suffix is too long then it
126.1688 + * too will be truncated, but if it begins with a period character
126.1689 + * (<code>'.'</code>) then the period and the first three characters
126.1690 + * following it will always be preserved. Once these adjustments have been
126.1691 + * made the name of the new file will be generated by concatenating the
126.1692 + * prefix, five or more internally-generated characters, and the suffix.
126.1693 + *
126.1694 + * <p> If the <code>directory</code> argument is <code>null</code> then the
126.1695 + * system-dependent default temporary-file directory will be used. The
126.1696 + * default temporary-file directory is specified by the system property
126.1697 + * <code>java.io.tmpdir</code>. On UNIX systems the default value of this
126.1698 + * property is typically <code>"/tmp"</code> or <code>"/var/tmp"</code>; on
126.1699 + * Microsoft Windows systems it is typically <code>"C:\\WINNT\\TEMP"</code>. A different
126.1700 + * value may be given to this system property when the Java virtual machine
126.1701 + * is invoked, but programmatic changes to this property are not guaranteed
126.1702 + * to have any effect upon the temporary directory used by this method.
126.1703 + *
126.1704 + * @param prefix The prefix string to be used in generating the file's
126.1705 + * name; must be at least three characters long
126.1706 + *
126.1707 + * @param suffix The suffix string to be used in generating the file's
126.1708 + * name; may be <code>null</code>, in which case the
126.1709 + * suffix <code>".tmp"</code> will be used
126.1710 + *
126.1711 + * @param directory The directory in which the file is to be created, or
126.1712 + * <code>null</code> if the default temporary-file
126.1713 + * directory is to be used
126.1714 + *
126.1715 + * @return An abstract pathname denoting a newly-created empty file
126.1716 + *
126.1717 + * @throws IllegalArgumentException
126.1718 + * If the <code>prefix</code> argument contains fewer than three
126.1719 + * characters
126.1720 + *
126.1721 + * @throws IOException If a file could not be created
126.1722 + *
126.1723 + * @throws SecurityException
126.1724 + * If a security manager exists and its <code>{@link
126.1725 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1726 + * method does not allow a file to be created
126.1727 + *
126.1728 + * @since 1.2
126.1729 + */
126.1730 + public static File createTempFile(String prefix, String suffix,
126.1731 + File directory)
126.1732 + throws IOException
126.1733 + {
126.1734 + throw new SecurityException();
126.1735 + }
126.1736 +
126.1737 + /**
126.1738 + * Creates an empty file in the default temporary-file directory, using
126.1739 + * the given prefix and suffix to generate its name. Invoking this method
126.1740 + * is equivalent to invoking <code>{@link #createTempFile(java.lang.String,
126.1741 + * java.lang.String, java.io.File)
126.1742 + * createTempFile(prefix, suffix, null)}</code>.
126.1743 + *
126.1744 + * <p> The {@link
126.1745 + * java.nio.file.Files#createTempFile(String,String,java.nio.file.attribute.FileAttribute[])
126.1746 + * Files.createTempFile} method provides an alternative method to create an
126.1747 + * empty file in the temporary-file directory. Files created by that method
126.1748 + * may have more restrictive access permissions to files created by this
126.1749 + * method and so may be more suited to security-sensitive applications.
126.1750 + *
126.1751 + * @param prefix The prefix string to be used in generating the file's
126.1752 + * name; must be at least three characters long
126.1753 + *
126.1754 + * @param suffix The suffix string to be used in generating the file's
126.1755 + * name; may be <code>null</code>, in which case the
126.1756 + * suffix <code>".tmp"</code> will be used
126.1757 + *
126.1758 + * @return An abstract pathname denoting a newly-created empty file
126.1759 + *
126.1760 + * @throws IllegalArgumentException
126.1761 + * If the <code>prefix</code> argument contains fewer than three
126.1762 + * characters
126.1763 + *
126.1764 + * @throws IOException If a file could not be created
126.1765 + *
126.1766 + * @throws SecurityException
126.1767 + * If a security manager exists and its <code>{@link
126.1768 + * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
126.1769 + * method does not allow a file to be created
126.1770 + *
126.1771 + * @since 1.2
126.1772 + * @see java.nio.file.Files#createTempDirectory(String,FileAttribute[])
126.1773 + */
126.1774 + public static File createTempFile(String prefix, String suffix)
126.1775 + throws IOException
126.1776 + {
126.1777 + return createTempFile(prefix, suffix, null);
126.1778 + }
126.1779 +
126.1780 + /* -- Basic infrastructure -- */
126.1781 +
126.1782 + /**
126.1783 + * Compares two abstract pathnames lexicographically. The ordering
126.1784 + * defined by this method depends upon the underlying system. On UNIX
126.1785 + * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
126.1786 + * systems it is not.
126.1787 + *
126.1788 + * @param pathname The abstract pathname to be compared to this abstract
126.1789 + * pathname
126.1790 + *
126.1791 + * @return Zero if the argument is equal to this abstract pathname, a
126.1792 + * value less than zero if this abstract pathname is
126.1793 + * lexicographically less than the argument, or a value greater
126.1794 + * than zero if this abstract pathname is lexicographically
126.1795 + * greater than the argument
126.1796 + *
126.1797 + * @since 1.2
126.1798 + */
126.1799 + public int compareTo(File pathname) {
126.1800 + return fs.compare(this, pathname);
126.1801 + }
126.1802 +
126.1803 + /**
126.1804 + * Tests this abstract pathname for equality with the given object.
126.1805 + * Returns <code>true</code> if and only if the argument is not
126.1806 + * <code>null</code> and is an abstract pathname that denotes the same file
126.1807 + * or directory as this abstract pathname. Whether or not two abstract
126.1808 + * pathnames are equal depends upon the underlying system. On UNIX
126.1809 + * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
126.1810 + * systems it is not.
126.1811 + *
126.1812 + * @param obj The object to be compared with this abstract pathname
126.1813 + *
126.1814 + * @return <code>true</code> if and only if the objects are the same;
126.1815 + * <code>false</code> otherwise
126.1816 + */
126.1817 + public boolean equals(Object obj) {
126.1818 + if ((obj != null) && (obj instanceof File)) {
126.1819 + return compareTo((File)obj) == 0;
126.1820 + }
126.1821 + return false;
126.1822 + }
126.1823 +
126.1824 + /**
126.1825 + * Computes a hash code for this abstract pathname. Because equality of
126.1826 + * abstract pathnames is inherently system-dependent, so is the computation
126.1827 + * of their hash codes. On UNIX systems, the hash code of an abstract
126.1828 + * pathname is equal to the exclusive <em>or</em> of the hash code
126.1829 + * of its pathname string and the decimal value
126.1830 + * <code>1234321</code>. On Microsoft Windows systems, the hash
126.1831 + * code is equal to the exclusive <em>or</em> of the hash code of
126.1832 + * its pathname string converted to lower case and the decimal
126.1833 + * value <code>1234321</code>. Locale is not taken into account on
126.1834 + * lowercasing the pathname string.
126.1835 + *
126.1836 + * @return A hash code for this abstract pathname
126.1837 + */
126.1838 + public int hashCode() {
126.1839 + return fs.hashCode(this);
126.1840 + }
126.1841 +
126.1842 + /**
126.1843 + * Returns the pathname string of this abstract pathname. This is just the
126.1844 + * string returned by the <code>{@link #getPath}</code> method.
126.1845 + *
126.1846 + * @return The string form of this abstract pathname
126.1847 + */
126.1848 + public String toString() {
126.1849 + return getPath();
126.1850 + }
126.1851 +
126.1852 + /**
126.1853 + * WriteObject is called to save this filename.
126.1854 + * The separator character is saved also so it can be replaced
126.1855 + * in case the path is reconstituted on a different host type.
126.1856 + * <p>
126.1857 + * @serialData Default fields followed by separator character.
126.1858 + */
126.1859 + private synchronized void writeObject(java.io.ObjectOutputStream s)
126.1860 + throws IOException
126.1861 + {
126.1862 + s.defaultWriteObject();
126.1863 + s.writeChar(this.separatorChar); // Add the separator character
126.1864 + }
126.1865 +
126.1866 + /**
126.1867 + * readObject is called to restore this filename.
126.1868 + * The original separator character is read. If it is different
126.1869 + * than the separator character on this system, then the old separator
126.1870 + * is replaced by the local separator.
126.1871 + */
126.1872 + private synchronized void readObject(java.io.ObjectInputStream s)
126.1873 + throws IOException, ClassNotFoundException
126.1874 + {
126.1875 + ObjectInputStream.GetField fields = s.readFields();
126.1876 + String pathField = (String)fields.get("path", null);
126.1877 + char sep = s.readChar(); // read the previous separator char
126.1878 + if (sep != separatorChar)
126.1879 + pathField = pathField.replace(sep, separatorChar);
126.1880 + this.path = fs.normalize(pathField);
126.1881 + this.prefixLength = fs.prefixLength(this.path);
126.1882 + }
126.1883 +
126.1884 + /** use serialVersionUID from JDK 1.0.2 for interoperability */
126.1885 + private static final long serialVersionUID = 301077366599181567L;
126.1886 +
126.1887 + // -- Integration with java.nio.file --
126.1888 +/*
126.1889 + private volatile transient Path filePath;
126.1890 +
126.1891 + /**
126.1892 + * Returns a {@link Path java.nio.file.Path} object constructed from the
126.1893 + * this abstract path. The resulting {@code Path} is associated with the
126.1894 + * {@link java.nio.file.FileSystems#getDefault default-filesystem}.
126.1895 + *
126.1896 + * <p> The first invocation of this method works as if invoking it were
126.1897 + * equivalent to evaluating the expression:
126.1898 + * <blockquote><pre>
126.1899 + * {@link java.nio.file.FileSystems#getDefault FileSystems.getDefault}().{@link
126.1900 + * java.nio.file.FileSystem#getPath getPath}(this.{@link #getPath getPath}());
126.1901 + * </pre></blockquote>
126.1902 + * Subsequent invocations of this method return the same {@code Path}.
126.1903 + *
126.1904 + * <p> If this abstract pathname is the empty abstract pathname then this
126.1905 + * method returns a {@code Path} that may be used to access the current
126.1906 + * user directory.
126.1907 + *
126.1908 + * @return a {@code Path} constructed from this abstract path
126.1909 + *
126.1910 + * @throws java.nio.file.InvalidPathException
126.1911 + * if a {@code Path} object cannot be constructed from the abstract
126.1912 + * path (see {@link java.nio.file.FileSystem#getPath FileSystem.getPath})
126.1913 + *
126.1914 + * @since 1.7
126.1915 + * @see Path#toFile
126.1916 + */
126.1917 +// public Path toPath() {
126.1918 +// Path result = filePath;
126.1919 +// if (result == null) {
126.1920 +// synchronized (this) {
126.1921 +// result = filePath;
126.1922 +// if (result == null) {
126.1923 +// result = FileSystems.getDefault().getPath(path);
126.1924 +// filePath = result;
126.1925 +// }
126.1926 +// }
126.1927 +// }
126.1928 +// return result;
126.1929 +// }
126.1930 +}
127.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
127.2 +++ b/rt/emul/compact/src/main/java/java/io/FileDescriptor.java Wed Apr 30 15:04:10 2014 +0200
127.3 @@ -0,0 +1,146 @@
127.4 +/*
127.5 + * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
127.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
127.7 + *
127.8 + *
127.9 + *
127.10 + *
127.11 + *
127.12 + *
127.13 + *
127.14 + *
127.15 + *
127.16 + *
127.17 + *
127.18 + *
127.19 + *
127.20 + *
127.21 + *
127.22 + *
127.23 + *
127.24 + *
127.25 + *
127.26 + *
127.27 + */
127.28 +
127.29 +package java.io;
127.30 +
127.31 +import java.util.concurrent.atomic.AtomicInteger;
127.32 +
127.33 +/**
127.34 + * Instances of the file descriptor class serve as an opaque handle
127.35 + * to the underlying machine-specific structure representing an open
127.36 + * file, an open socket, or another source or sink of bytes. The
127.37 + * main practical use for a file descriptor is to create a
127.38 + * <code>FileInputStream</code> or <code>FileOutputStream</code> to
127.39 + * contain it.
127.40 + * <p>
127.41 + * Applications should not create their own file descriptors.
127.42 + *
127.43 + * @author Pavani Diwanji
127.44 + * @see java.io.FileInputStream
127.45 + * @see java.io.FileOutputStream
127.46 + * @since JDK1.0
127.47 + */
127.48 +public final class FileDescriptor {
127.49 +
127.50 + private int fd;
127.51 +
127.52 + /**
127.53 + * A counter for tracking the FIS/FOS/RAF instances that
127.54 + * use this FileDescriptor. The FIS/FOS.finalize() will not release
127.55 + * the FileDescriptor if it is still under user by a stream.
127.56 + */
127.57 + private AtomicInteger useCount;
127.58 +
127.59 + /**
127.60 + * Constructs an (invalid) FileDescriptor
127.61 + * object.
127.62 + */
127.63 + public /**/ FileDescriptor() {
127.64 + fd = -1;
127.65 + useCount = new AtomicInteger();
127.66 + }
127.67 +
127.68 + private /* */ FileDescriptor(int fd) {
127.69 + this.fd = fd;
127.70 + useCount = new AtomicInteger();
127.71 + }
127.72 +
127.73 + /**
127.74 + * A handle to the standard input stream. Usually, this file
127.75 + * descriptor is not used directly, but rather via the input stream
127.76 + * known as <code>System.in</code>.
127.77 + *
127.78 + * @see java.lang.System#in
127.79 + */
127.80 + public static final FileDescriptor in = new FileDescriptor(0);
127.81 +
127.82 + /**
127.83 + * A handle to the standard output stream. Usually, this file
127.84 + * descriptor is not used directly, but rather via the output stream
127.85 + * known as <code>System.out</code>.
127.86 + * @see java.lang.System#out
127.87 + */
127.88 + public static final FileDescriptor out = new FileDescriptor(1);
127.89 +
127.90 + /**
127.91 + * A handle to the standard error stream. Usually, this file
127.92 + * descriptor is not used directly, but rather via the output stream
127.93 + * known as <code>System.err</code>.
127.94 + *
127.95 + * @see java.lang.System#err
127.96 + */
127.97 + public static final FileDescriptor err = new FileDescriptor(2);
127.98 +
127.99 + /**
127.100 + * Tests if this file descriptor object is valid.
127.101 + *
127.102 + * @return <code>true</code> if the file descriptor object represents a
127.103 + * valid, open file, socket, or other active I/O connection;
127.104 + * <code>false</code> otherwise.
127.105 + */
127.106 + public boolean valid() {
127.107 + return fd != -1;
127.108 + }
127.109 +
127.110 + /**
127.111 + * Force all system buffers to synchronize with the underlying
127.112 + * device. This method returns after all modified data and
127.113 + * attributes of this FileDescriptor have been written to the
127.114 + * relevant device(s). In particular, if this FileDescriptor
127.115 + * refers to a physical storage medium, such as a file in a file
127.116 + * system, sync will not return until all in-memory modified copies
127.117 + * of buffers associated with this FileDescriptor have been
127.118 + * written to the physical medium.
127.119 + *
127.120 + * sync is meant to be used by code that requires physical
127.121 + * storage (such as a file) to be in a known state For
127.122 + * example, a class that provided a simple transaction facility
127.123 + * might use sync to ensure that all changes to a file caused
127.124 + * by a given transaction were recorded on a storage medium.
127.125 + *
127.126 + * sync only affects buffers downstream of this FileDescriptor. If
127.127 + * any in-memory buffering is being done by the application (for
127.128 + * example, by a BufferedOutputStream object), those buffers must
127.129 + * be flushed into the FileDescriptor (for example, by invoking
127.130 + * OutputStream.flush) before that data will be affected by sync.
127.131 + *
127.132 + * @exception SyncFailedException
127.133 + * Thrown when the buffers cannot be flushed,
127.134 + * or because the system cannot guarantee that all the
127.135 + * buffers have been synchronized with physical media.
127.136 + * @since JDK1.1
127.137 + */
127.138 + public native void sync() throws SyncFailedException;
127.139 +
127.140 + // package private methods used by FIS, FOS and RAF
127.141 +
127.142 + int incrementAndGetUseCount() {
127.143 + return useCount.incrementAndGet();
127.144 + }
127.145 +
127.146 + int decrementAndGetUseCount() {
127.147 + return useCount.decrementAndGet();
127.148 + }
127.149 +}
128.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
128.2 +++ b/rt/emul/compact/src/main/java/java/io/FileFilter.java Wed Apr 30 15:04:10 2014 +0200
128.3 @@ -0,0 +1,50 @@
128.4 +/*
128.5 + * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved.
128.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
128.7 + *
128.8 + * This code is free software; you can redistribute it and/or modify it
128.9 + * under the terms of the GNU General Public License version 2 only, as
128.10 + * published by the Free Software Foundation. Oracle designates this
128.11 + * particular file as subject to the "Classpath" exception as provided
128.12 + * by Oracle in the LICENSE file that accompanied this code.
128.13 + *
128.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
128.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
128.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
128.17 + * version 2 for more details (a copy is included in the LICENSE file that
128.18 + * accompanied this code).
128.19 + *
128.20 + * You should have received a copy of the GNU General Public License version
128.21 + * 2 along with this work; if not, write to the Free Software Foundation,
128.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
128.23 + *
128.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
128.25 + * or visit www.oracle.com if you need additional information or have any
128.26 + * questions.
128.27 + */
128.28 +
128.29 +package java.io;
128.30 +
128.31 +
128.32 +/**
128.33 + * A filter for abstract pathnames.
128.34 + *
128.35 + * <p> Instances of this interface may be passed to the <code>{@link
128.36 + * File#listFiles(java.io.FileFilter) listFiles(FileFilter)}</code> method
128.37 + * of the <code>{@link java.io.File}</code> class.
128.38 + *
128.39 + * @since 1.2
128.40 + */
128.41 +public interface FileFilter {
128.42 +
128.43 + /**
128.44 + * Tests whether or not the specified abstract pathname should be
128.45 + * included in a pathname list.
128.46 + *
128.47 + * @param pathname The abstract pathname to be tested
128.48 + * @return <code>true</code> if and only if <code>pathname</code>
128.49 + * should be included
128.50 + */
128.51 + boolean accept(File pathname);
128.52 +
128.53 +}
129.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
129.2 +++ b/rt/emul/compact/src/main/java/java/io/FileInputStream.java Wed Apr 30 15:04:10 2014 +0200
129.3 @@ -0,0 +1,382 @@
129.4 +/*
129.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
129.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
129.7 + *
129.8 + * This code is free software; you can redistribute it and/or modify it
129.9 + * under the terms of the GNU General Public License version 2 only, as
129.10 + * published by the Free Software Foundation. Oracle designates this
129.11 + * particular file as subject to the "Classpath" exception as provided
129.12 + * by Oracle in the LICENSE file that accompanied this code.
129.13 + *
129.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
129.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
129.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
129.17 + * version 2 for more details (a copy is included in the LICENSE file that
129.18 + * accompanied this code).
129.19 + *
129.20 + * You should have received a copy of the GNU General Public License version
129.21 + * 2 along with this work; if not, write to the Free Software Foundation,
129.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
129.23 + *
129.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
129.25 + * or visit www.oracle.com if you need additional information or have any
129.26 + * questions.
129.27 + */
129.28 +
129.29 +package java.io;
129.30 +
129.31 +
129.32 +
129.33 +/**
129.34 + * A <code>FileInputStream</code> obtains input bytes
129.35 + * from a file in a file system. What files
129.36 + * are available depends on the host environment.
129.37 + *
129.38 + * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
129.39 + * such as image data. For reading streams of characters, consider using
129.40 + * <code>FileReader</code>.
129.41 + *
129.42 + * @author Arthur van Hoff
129.43 + * @see java.io.File
129.44 + * @see java.io.FileDescriptor
129.45 + * @see java.io.FileOutputStream
129.46 + * @see java.nio.file.Files#newInputStream
129.47 + * @since JDK1.0
129.48 + */
129.49 +public
129.50 +class FileInputStream extends InputStream
129.51 +{
129.52 + /* File Descriptor - handle to the open file */
129.53 + private final FileDescriptor fd;
129.54 +
129.55 +// private FileChannel channel = null;
129.56 +
129.57 + private final Object closeLock = new Object();
129.58 + private volatile boolean closed = false;
129.59 +
129.60 + private static final ThreadLocal<Boolean> runningFinalize =
129.61 + new ThreadLocal<>();
129.62 +
129.63 + private static boolean isRunningFinalize() {
129.64 + Boolean val;
129.65 + if ((val = runningFinalize.get()) != null)
129.66 + return val.booleanValue();
129.67 + return false;
129.68 + }
129.69 +
129.70 + /**
129.71 + * Creates a <code>FileInputStream</code> by
129.72 + * opening a connection to an actual file,
129.73 + * the file named by the path name <code>name</code>
129.74 + * in the file system. A new <code>FileDescriptor</code>
129.75 + * object is created to represent this file
129.76 + * connection.
129.77 + * <p>
129.78 + * First, if there is a security
129.79 + * manager, its <code>checkRead</code> method
129.80 + * is called with the <code>name</code> argument
129.81 + * as its argument.
129.82 + * <p>
129.83 + * If the named file does not exist, is a directory rather than a regular
129.84 + * file, or for some other reason cannot be opened for reading then a
129.85 + * <code>FileNotFoundException</code> is thrown.
129.86 + *
129.87 + * @param name the system-dependent file name.
129.88 + * @exception FileNotFoundException if the file does not exist,
129.89 + * is a directory rather than a regular file,
129.90 + * or for some other reason cannot be opened for
129.91 + * reading.
129.92 + * @exception SecurityException if a security manager exists and its
129.93 + * <code>checkRead</code> method denies read access
129.94 + * to the file.
129.95 + * @see java.lang.SecurityManager#checkRead(java.lang.String)
129.96 + */
129.97 + public FileInputStream(String name) throws FileNotFoundException {
129.98 + this(name != null ? new File(name) : null);
129.99 + }
129.100 +
129.101 + /**
129.102 + * Creates a <code>FileInputStream</code> by
129.103 + * opening a connection to an actual file,
129.104 + * the file named by the <code>File</code>
129.105 + * object <code>file</code> in the file system.
129.106 + * A new <code>FileDescriptor</code> object
129.107 + * is created to represent this file connection.
129.108 + * <p>
129.109 + * First, if there is a security manager,
129.110 + * its <code>checkRead</code> method is called
129.111 + * with the path represented by the <code>file</code>
129.112 + * argument as its argument.
129.113 + * <p>
129.114 + * If the named file does not exist, is a directory rather than a regular
129.115 + * file, or for some other reason cannot be opened for reading then a
129.116 + * <code>FileNotFoundException</code> is thrown.
129.117 + *
129.118 + * @param file the file to be opened for reading.
129.119 + * @exception FileNotFoundException if the file does not exist,
129.120 + * is a directory rather than a regular file,
129.121 + * or for some other reason cannot be opened for
129.122 + * reading.
129.123 + * @exception SecurityException if a security manager exists and its
129.124 + * <code>checkRead</code> method denies read access to the file.
129.125 + * @see java.io.File#getPath()
129.126 + * @see java.lang.SecurityManager#checkRead(java.lang.String)
129.127 + */
129.128 + public FileInputStream(File file) throws FileNotFoundException {
129.129 + throw new SecurityException();
129.130 + }
129.131 +
129.132 + /**
129.133 + * Creates a <code>FileInputStream</code> by using the file descriptor
129.134 + * <code>fdObj</code>, which represents an existing connection to an
129.135 + * actual file in the file system.
129.136 + * <p>
129.137 + * If there is a security manager, its <code>checkRead</code> method is
129.138 + * called with the file descriptor <code>fdObj</code> as its argument to
129.139 + * see if it's ok to read the file descriptor. If read access is denied
129.140 + * to the file descriptor a <code>SecurityException</code> is thrown.
129.141 + * <p>
129.142 + * If <code>fdObj</code> is null then a <code>NullPointerException</code>
129.143 + * is thrown.
129.144 + * <p>
129.145 + * This constructor does not throw an exception if <code>fdObj</code>
129.146 + * is {@link java.io.FileDescriptor#valid() invalid}.
129.147 + * However, if the methods are invoked on the resulting stream to attempt
129.148 + * I/O on the stream, an <code>IOException</code> is thrown.
129.149 + *
129.150 + * @param fdObj the file descriptor to be opened for reading.
129.151 + * @throws SecurityException if a security manager exists and its
129.152 + * <code>checkRead</code> method denies read access to the
129.153 + * file descriptor.
129.154 + * @see SecurityManager#checkRead(java.io.FileDescriptor)
129.155 + */
129.156 + public FileInputStream(FileDescriptor fdObj) {
129.157 + throw new SecurityException();
129.158 + }
129.159 +
129.160 + /**
129.161 + * Opens the specified file for reading.
129.162 + * @param name the name of the file
129.163 + */
129.164 + private native void open(String name) throws FileNotFoundException;
129.165 +
129.166 + /**
129.167 + * Reads a byte of data from this input stream. This method blocks
129.168 + * if no input is yet available.
129.169 + *
129.170 + * @return the next byte of data, or <code>-1</code> if the end of the
129.171 + * file is reached.
129.172 + * @exception IOException if an I/O error occurs.
129.173 + */
129.174 + public native int read() throws IOException;
129.175 +
129.176 + /**
129.177 + * Reads a subarray as a sequence of bytes.
129.178 + * @param b the data to be written
129.179 + * @param off the start offset in the data
129.180 + * @param len the number of bytes that are written
129.181 + * @exception IOException If an I/O error has occurred.
129.182 + */
129.183 + private native int readBytes(byte b[], int off, int len) throws IOException;
129.184 +
129.185 + /**
129.186 + * Reads up to <code>b.length</code> bytes of data from this input
129.187 + * stream into an array of bytes. This method blocks until some input
129.188 + * is available.
129.189 + *
129.190 + * @param b the buffer into which the data is read.
129.191 + * @return the total number of bytes read into the buffer, or
129.192 + * <code>-1</code> if there is no more data because the end of
129.193 + * the file has been reached.
129.194 + * @exception IOException if an I/O error occurs.
129.195 + */
129.196 + public int read(byte b[]) throws IOException {
129.197 + return readBytes(b, 0, b.length);
129.198 + }
129.199 +
129.200 + /**
129.201 + * Reads up to <code>len</code> bytes of data from this input stream
129.202 + * into an array of bytes. If <code>len</code> is not zero, the method
129.203 + * blocks until some input is available; otherwise, no
129.204 + * bytes are read and <code>0</code> is returned.
129.205 + *
129.206 + * @param b the buffer into which the data is read.
129.207 + * @param off the start offset in the destination array <code>b</code>
129.208 + * @param len the maximum number of bytes read.
129.209 + * @return the total number of bytes read into the buffer, or
129.210 + * <code>-1</code> if there is no more data because the end of
129.211 + * the file has been reached.
129.212 + * @exception NullPointerException If <code>b</code> is <code>null</code>.
129.213 + * @exception IndexOutOfBoundsException If <code>off</code> is negative,
129.214 + * <code>len</code> is negative, or <code>len</code> is greater than
129.215 + * <code>b.length - off</code>
129.216 + * @exception IOException if an I/O error occurs.
129.217 + */
129.218 + public int read(byte b[], int off, int len) throws IOException {
129.219 + return readBytes(b, off, len);
129.220 + }
129.221 +
129.222 + /**
129.223 + * Skips over and discards <code>n</code> bytes of data from the
129.224 + * input stream.
129.225 + *
129.226 + * <p>The <code>skip</code> method may, for a variety of
129.227 + * reasons, end up skipping over some smaller number of bytes,
129.228 + * possibly <code>0</code>. If <code>n</code> is negative, an
129.229 + * <code>IOException</code> is thrown, even though the <code>skip</code>
129.230 + * method of the {@link InputStream} superclass does nothing in this case.
129.231 + * The actual number of bytes skipped is returned.
129.232 + *
129.233 + * <p>This method may skip more bytes than are remaining in the backing
129.234 + * file. This produces no exception and the number of bytes skipped
129.235 + * may include some number of bytes that were beyond the EOF of the
129.236 + * backing file. Attempting to read from the stream after skipping past
129.237 + * the end will result in -1 indicating the end of the file.
129.238 + *
129.239 + * @param n the number of bytes to be skipped.
129.240 + * @return the actual number of bytes skipped.
129.241 + * @exception IOException if n is negative, if the stream does not
129.242 + * support seek, or if an I/O error occurs.
129.243 + */
129.244 + public native long skip(long n) throws IOException;
129.245 +
129.246 + /**
129.247 + * Returns an estimate of the number of remaining bytes that can be read (or
129.248 + * skipped over) from this input stream without blocking by the next
129.249 + * invocation of a method for this input stream. The next invocation might be
129.250 + * the same thread or another thread. A single read or skip of this
129.251 + * many bytes will not block, but may read or skip fewer bytes.
129.252 + *
129.253 + * <p> In some cases, a non-blocking read (or skip) may appear to be
129.254 + * blocked when it is merely slow, for example when reading large
129.255 + * files over slow networks.
129.256 + *
129.257 + * @return an estimate of the number of remaining bytes that can be read
129.258 + * (or skipped over) from this input stream without blocking.
129.259 + * @exception IOException if this file input stream has been closed by calling
129.260 + * {@code close} or an I/O error occurs.
129.261 + */
129.262 + public native int available() throws IOException;
129.263 +
129.264 + /**
129.265 + * Closes this file input stream and releases any system resources
129.266 + * associated with the stream.
129.267 + *
129.268 + * <p> If this stream has an associated channel then the channel is closed
129.269 + * as well.
129.270 + *
129.271 + * @exception IOException if an I/O error occurs.
129.272 + *
129.273 + * @revised 1.4
129.274 + * @spec JSR-51
129.275 + */
129.276 + public void close() throws IOException {
129.277 + synchronized (closeLock) {
129.278 + if (closed) {
129.279 + return;
129.280 + }
129.281 + closed = true;
129.282 + }
129.283 +// if (channel != null) {
129.284 +// /*
129.285 +// * Decrement the FD use count associated with the channel
129.286 +// * The use count is incremented whenever a new channel
129.287 +// * is obtained from this stream.
129.288 +// */
129.289 +// fd.decrementAndGetUseCount();
129.290 +// channel.close();
129.291 +// }
129.292 +
129.293 + /*
129.294 + * Decrement the FD use count associated with this stream
129.295 + */
129.296 + int useCount = fd.decrementAndGetUseCount();
129.297 +
129.298 + /*
129.299 + * If FileDescriptor is still in use by another stream, the finalizer
129.300 + * will not close it.
129.301 + */
129.302 + if ((useCount <= 0) || !isRunningFinalize()) {
129.303 + close0();
129.304 + }
129.305 + }
129.306 +
129.307 + /**
129.308 + * Returns the <code>FileDescriptor</code>
129.309 + * object that represents the connection to
129.310 + * the actual file in the file system being
129.311 + * used by this <code>FileInputStream</code>.
129.312 + *
129.313 + * @return the file descriptor object associated with this stream.
129.314 + * @exception IOException if an I/O error occurs.
129.315 + * @see java.io.FileDescriptor
129.316 + */
129.317 + public final FileDescriptor getFD() throws IOException {
129.318 + if (fd != null) return fd;
129.319 + throw new IOException();
129.320 + }
129.321 +
129.322 + /**
129.323 + * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
129.324 + * object associated with this file input stream.
129.325 + *
129.326 + * <p> The initial {@link java.nio.channels.FileChannel#position()
129.327 + * </code>position<code>} of the returned channel will be equal to the
129.328 + * number of bytes read from the file so far. Reading bytes from this
129.329 + * stream will increment the channel's position. Changing the channel's
129.330 + * position, either explicitly or by reading, will change this stream's
129.331 + * file position.
129.332 + *
129.333 + * @return the file channel associated with this file input stream
129.334 + *
129.335 + * @since 1.4
129.336 + * @spec JSR-51
129.337 + */
129.338 +// public FileChannel getChannel() {
129.339 +// synchronized (this) {
129.340 +// if (channel == null) {
129.341 +// channel = FileChannelImpl.open(fd, true, false, this);
129.342 +//
129.343 +// /*
129.344 +// * Increment fd's use count. Invoking the channel's close()
129.345 +// * method will result in decrementing the use count set for
129.346 +// * the channel.
129.347 +// */
129.348 +// fd.incrementAndGetUseCount();
129.349 +// }
129.350 +// return channel;
129.351 +// }
129.352 +// }
129.353 +
129.354 + private static native void initIDs();
129.355 +
129.356 + private native void close0() throws IOException;
129.357 +
129.358 + static {
129.359 + initIDs();
129.360 + }
129.361 +
129.362 + /**
129.363 + * Ensures that the <code>close</code> method of this file input stream is
129.364 + * called when there are no more references to it.
129.365 + *
129.366 + * @exception IOException if an I/O error occurs.
129.367 + * @see java.io.FileInputStream#close()
129.368 + */
129.369 + protected void finalize() throws IOException {
129.370 + if ((fd != null) && (fd != FileDescriptor.in)) {
129.371 +
129.372 + /*
129.373 + * Finalizer should not release the FileDescriptor if another
129.374 + * stream is still using it. If the user directly invokes
129.375 + * close() then the FileDescriptor is also released.
129.376 + */
129.377 + runningFinalize.set(Boolean.TRUE);
129.378 + try {
129.379 + close();
129.380 + } finally {
129.381 + runningFinalize.set(Boolean.FALSE);
129.382 + }
129.383 + }
129.384 + }
129.385 +}
130.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
130.2 +++ b/rt/emul/compact/src/main/java/java/io/FileNotFoundException.java Wed Apr 30 15:04:10 2014 +0200
130.3 @@ -0,0 +1,82 @@
130.4 +/*
130.5 + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
130.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
130.7 + *
130.8 + * This code is free software; you can redistribute it and/or modify it
130.9 + * under the terms of the GNU General Public License version 2 only, as
130.10 + * published by the Free Software Foundation. Oracle designates this
130.11 + * particular file as subject to the "Classpath" exception as provided
130.12 + * by Oracle in the LICENSE file that accompanied this code.
130.13 + *
130.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
130.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
130.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
130.17 + * version 2 for more details (a copy is included in the LICENSE file that
130.18 + * accompanied this code).
130.19 + *
130.20 + * You should have received a copy of the GNU General Public License version
130.21 + * 2 along with this work; if not, write to the Free Software Foundation,
130.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
130.23 + *
130.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
130.25 + * or visit www.oracle.com if you need additional information or have any
130.26 + * questions.
130.27 + */
130.28 +
130.29 +package java.io;
130.30 +
130.31 +
130.32 +/**
130.33 + * Signals that an attempt to open the file denoted by a specified pathname
130.34 + * has failed.
130.35 + *
130.36 + * <p> This exception will be thrown by the {@link FileInputStream}, {@link
130.37 + * FileOutputStream}, and {@link RandomAccessFile} constructors when a file
130.38 + * with the specified pathname does not exist. It will also be thrown by these
130.39 + * constructors if the file does exist but for some reason is inaccessible, for
130.40 + * example when an attempt is made to open a read-only file for writing.
130.41 + *
130.42 + * @author unascribed
130.43 + * @since JDK1.0
130.44 + */
130.45 +
130.46 +public class FileNotFoundException extends IOException {
130.47 + private static final long serialVersionUID = -897856973823710492L;
130.48 +
130.49 + /**
130.50 + * Constructs a <code>FileNotFoundException</code> with
130.51 + * <code>null</code> as its error detail message.
130.52 + */
130.53 + public FileNotFoundException() {
130.54 + super();
130.55 + }
130.56 +
130.57 + /**
130.58 + * Constructs a <code>FileNotFoundException</code> with the
130.59 + * specified detail message. The string <code>s</code> can be
130.60 + * retrieved later by the
130.61 + * <code>{@link java.lang.Throwable#getMessage}</code>
130.62 + * method of class <code>java.lang.Throwable</code>.
130.63 + *
130.64 + * @param s the detail message.
130.65 + */
130.66 + public FileNotFoundException(String s) {
130.67 + super(s);
130.68 + }
130.69 +
130.70 + /**
130.71 + * Constructs a <code>FileNotFoundException</code> with a detail message
130.72 + * consisting of the given pathname string followed by the given reason
130.73 + * string. If the <code>reason</code> argument is <code>null</code> then
130.74 + * it will be omitted. This private constructor is invoked only by native
130.75 + * I/O methods.
130.76 + *
130.77 + * @since 1.2
130.78 + */
130.79 + private FileNotFoundException(String path, String reason) {
130.80 + super(path + ((reason == null)
130.81 + ? ""
130.82 + : " (" + reason + ")"));
130.83 + }
130.84 +
130.85 +}
131.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
131.2 +++ b/rt/emul/compact/src/main/java/java/io/FileOutputStream.java Wed Apr 30 15:04:10 2014 +0200
131.3 @@ -0,0 +1,422 @@
131.4 +/*
131.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
131.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
131.7 + *
131.8 + * This code is free software; you can redistribute it and/or modify it
131.9 + * under the terms of the GNU General Public License version 2 only, as
131.10 + * published by the Free Software Foundation. Oracle designates this
131.11 + * particular file as subject to the "Classpath" exception as provided
131.12 + * by Oracle in the LICENSE file that accompanied this code.
131.13 + *
131.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
131.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
131.17 + * version 2 for more details (a copy is included in the LICENSE file that
131.18 + * accompanied this code).
131.19 + *
131.20 + * You should have received a copy of the GNU General Public License version
131.21 + * 2 along with this work; if not, write to the Free Software Foundation,
131.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
131.23 + *
131.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
131.25 + * or visit www.oracle.com if you need additional information or have any
131.26 + * questions.
131.27 + */
131.28 +
131.29 +package java.io;
131.30 +
131.31 +
131.32 +
131.33 +/**
131.34 + * A file output stream is an output stream for writing data to a
131.35 + * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not
131.36 + * a file is available or may be created depends upon the underlying
131.37 + * platform. Some platforms, in particular, allow a file to be opened
131.38 + * for writing by only one <tt>FileOutputStream</tt> (or other
131.39 + * file-writing object) at a time. In such situations the constructors in
131.40 + * this class will fail if the file involved is already open.
131.41 + *
131.42 + * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes
131.43 + * such as image data. For writing streams of characters, consider using
131.44 + * <code>FileWriter</code>.
131.45 + *
131.46 + * @author Arthur van Hoff
131.47 + * @see java.io.File
131.48 + * @see java.io.FileDescriptor
131.49 + * @see java.io.FileInputStream
131.50 + * @see java.nio.file.Files#newOutputStream
131.51 + * @since JDK1.0
131.52 + */
131.53 +public
131.54 +class FileOutputStream extends OutputStream
131.55 +{
131.56 + /**
131.57 + * The system dependent file descriptor.
131.58 + */
131.59 + private final FileDescriptor fd;
131.60 +
131.61 + /**
131.62 + * True if the file is opened for append.
131.63 + */
131.64 + private final boolean append;
131.65 +
131.66 + /**
131.67 + * The associated channel, initalized lazily.
131.68 + */
131.69 +// private FileChannel channel;
131.70 +
131.71 + private final Object closeLock = new Object();
131.72 + private volatile boolean closed = false;
131.73 + private static final ThreadLocal<Boolean> runningFinalize =
131.74 + new ThreadLocal<>();
131.75 +
131.76 + private static boolean isRunningFinalize() {
131.77 + Boolean val;
131.78 + if ((val = runningFinalize.get()) != null)
131.79 + return val.booleanValue();
131.80 + return false;
131.81 + }
131.82 +
131.83 + /**
131.84 + * Creates a file output stream to write to the file with the
131.85 + * specified name. A new <code>FileDescriptor</code> object is
131.86 + * created to represent this file connection.
131.87 + * <p>
131.88 + * First, if there is a security manager, its <code>checkWrite</code>
131.89 + * method is called with <code>name</code> as its argument.
131.90 + * <p>
131.91 + * If the file exists but is a directory rather than a regular file, does
131.92 + * not exist but cannot be created, or cannot be opened for any other
131.93 + * reason then a <code>FileNotFoundException</code> is thrown.
131.94 + *
131.95 + * @param name the system-dependent filename
131.96 + * @exception FileNotFoundException if the file exists but is a directory
131.97 + * rather than a regular file, does not exist but cannot
131.98 + * be created, or cannot be opened for any other reason
131.99 + * @exception SecurityException if a security manager exists and its
131.100 + * <code>checkWrite</code> method denies write access
131.101 + * to the file.
131.102 + * @see java.lang.SecurityManager#checkWrite(java.lang.String)
131.103 + */
131.104 + public FileOutputStream(String name) throws FileNotFoundException {
131.105 + this(name != null ? new File(name) : null, false);
131.106 + }
131.107 +
131.108 + /**
131.109 + * Creates a file output stream to write to the file with the specified
131.110 + * name. If the second argument is <code>true</code>, then
131.111 + * bytes will be written to the end of the file rather than the beginning.
131.112 + * A new <code>FileDescriptor</code> object is created to represent this
131.113 + * file connection.
131.114 + * <p>
131.115 + * First, if there is a security manager, its <code>checkWrite</code>
131.116 + * method is called with <code>name</code> as its argument.
131.117 + * <p>
131.118 + * If the file exists but is a directory rather than a regular file, does
131.119 + * not exist but cannot be created, or cannot be opened for any other
131.120 + * reason then a <code>FileNotFoundException</code> is thrown.
131.121 + *
131.122 + * @param name the system-dependent file name
131.123 + * @param append if <code>true</code>, then bytes will be written
131.124 + * to the end of the file rather than the beginning
131.125 + * @exception FileNotFoundException if the file exists but is a directory
131.126 + * rather than a regular file, does not exist but cannot
131.127 + * be created, or cannot be opened for any other reason.
131.128 + * @exception SecurityException if a security manager exists and its
131.129 + * <code>checkWrite</code> method denies write access
131.130 + * to the file.
131.131 + * @see java.lang.SecurityManager#checkWrite(java.lang.String)
131.132 + * @since JDK1.1
131.133 + */
131.134 + public FileOutputStream(String name, boolean append)
131.135 + throws FileNotFoundException
131.136 + {
131.137 + this(name != null ? new File(name) : null, append);
131.138 + }
131.139 +
131.140 + /**
131.141 + * Creates a file output stream to write to the file represented by
131.142 + * the specified <code>File</code> object. A new
131.143 + * <code>FileDescriptor</code> object is created to represent this
131.144 + * file connection.
131.145 + * <p>
131.146 + * First, if there is a security manager, its <code>checkWrite</code>
131.147 + * method is called with the path represented by the <code>file</code>
131.148 + * argument as its argument.
131.149 + * <p>
131.150 + * If the file exists but is a directory rather than a regular file, does
131.151 + * not exist but cannot be created, or cannot be opened for any other
131.152 + * reason then a <code>FileNotFoundException</code> is thrown.
131.153 + *
131.154 + * @param file the file to be opened for writing.
131.155 + * @exception FileNotFoundException if the file exists but is a directory
131.156 + * rather than a regular file, does not exist but cannot
131.157 + * be created, or cannot be opened for any other reason
131.158 + * @exception SecurityException if a security manager exists and its
131.159 + * <code>checkWrite</code> method denies write access
131.160 + * to the file.
131.161 + * @see java.io.File#getPath()
131.162 + * @see java.lang.SecurityException
131.163 + * @see java.lang.SecurityManager#checkWrite(java.lang.String)
131.164 + */
131.165 + public FileOutputStream(File file) throws FileNotFoundException {
131.166 + this(file, false);
131.167 + }
131.168 +
131.169 + /**
131.170 + * Creates a file output stream to write to the file represented by
131.171 + * the specified <code>File</code> object. If the second argument is
131.172 + * <code>true</code>, then bytes will be written to the end of the file
131.173 + * rather than the beginning. A new <code>FileDescriptor</code> object is
131.174 + * created to represent this file connection.
131.175 + * <p>
131.176 + * First, if there is a security manager, its <code>checkWrite</code>
131.177 + * method is called with the path represented by the <code>file</code>
131.178 + * argument as its argument.
131.179 + * <p>
131.180 + * If the file exists but is a directory rather than a regular file, does
131.181 + * not exist but cannot be created, or cannot be opened for any other
131.182 + * reason then a <code>FileNotFoundException</code> is thrown.
131.183 + *
131.184 + * @param file the file to be opened for writing.
131.185 + * @param append if <code>true</code>, then bytes will be written
131.186 + * to the end of the file rather than the beginning
131.187 + * @exception FileNotFoundException if the file exists but is a directory
131.188 + * rather than a regular file, does not exist but cannot
131.189 + * be created, or cannot be opened for any other reason
131.190 + * @exception SecurityException if a security manager exists and its
131.191 + * <code>checkWrite</code> method denies write access
131.192 + * to the file.
131.193 + * @see java.io.File#getPath()
131.194 + * @see java.lang.SecurityException
131.195 + * @see java.lang.SecurityManager#checkWrite(java.lang.String)
131.196 + * @since 1.4
131.197 + */
131.198 + public FileOutputStream(File file, boolean append)
131.199 + throws FileNotFoundException
131.200 + {
131.201 + throw new SecurityException();
131.202 + }
131.203 +
131.204 + /**
131.205 + * Creates a file output stream to write to the specified file
131.206 + * descriptor, which represents an existing connection to an actual
131.207 + * file in the file system.
131.208 + * <p>
131.209 + * First, if there is a security manager, its <code>checkWrite</code>
131.210 + * method is called with the file descriptor <code>fdObj</code>
131.211 + * argument as its argument.
131.212 + * <p>
131.213 + * If <code>fdObj</code> is null then a <code>NullPointerException</code>
131.214 + * is thrown.
131.215 + * <p>
131.216 + * This constructor does not throw an exception if <code>fdObj</code>
131.217 + * is {@link java.io.FileDescriptor#valid() invalid}.
131.218 + * However, if the methods are invoked on the resulting stream to attempt
131.219 + * I/O on the stream, an <code>IOException</code> is thrown.
131.220 + *
131.221 + * @param fdObj the file descriptor to be opened for writing
131.222 + * @exception SecurityException if a security manager exists and its
131.223 + * <code>checkWrite</code> method denies
131.224 + * write access to the file descriptor
131.225 + * @see java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
131.226 + */
131.227 + public FileOutputStream(FileDescriptor fdObj) {
131.228 + throw new SecurityException();
131.229 + }
131.230 +
131.231 + /**
131.232 + * Opens a file, with the specified name, for overwriting or appending.
131.233 + * @param name name of file to be opened
131.234 + * @param append whether the file is to be opened in append mode
131.235 + */
131.236 + private native void open(String name, boolean append)
131.237 + throws FileNotFoundException;
131.238 +
131.239 + /**
131.240 + * Writes the specified byte to this file output stream.
131.241 + *
131.242 + * @param b the byte to be written.
131.243 + * @param append {@code true} if the write operation first
131.244 + * advances the position to the end of file
131.245 + */
131.246 + private native void write(int b, boolean append) throws IOException;
131.247 +
131.248 + /**
131.249 + * Writes the specified byte to this file output stream. Implements
131.250 + * the <code>write</code> method of <code>OutputStream</code>.
131.251 + *
131.252 + * @param b the byte to be written.
131.253 + * @exception IOException if an I/O error occurs.
131.254 + */
131.255 + public void write(int b) throws IOException {
131.256 + write(b, append);
131.257 + }
131.258 +
131.259 + /**
131.260 + * Writes a sub array as a sequence of bytes.
131.261 + * @param b the data to be written
131.262 + * @param off the start offset in the data
131.263 + * @param len the number of bytes that are written
131.264 + * @param append {@code true} to first advance the position to the
131.265 + * end of file
131.266 + * @exception IOException If an I/O error has occurred.
131.267 + */
131.268 + private native void writeBytes(byte b[], int off, int len, boolean append)
131.269 + throws IOException;
131.270 +
131.271 + /**
131.272 + * Writes <code>b.length</code> bytes from the specified byte array
131.273 + * to this file output stream.
131.274 + *
131.275 + * @param b the data.
131.276 + * @exception IOException if an I/O error occurs.
131.277 + */
131.278 + public void write(byte b[]) throws IOException {
131.279 + writeBytes(b, 0, b.length, append);
131.280 + }
131.281 +
131.282 + /**
131.283 + * Writes <code>len</code> bytes from the specified byte array
131.284 + * starting at offset <code>off</code> to this file output stream.
131.285 + *
131.286 + * @param b the data.
131.287 + * @param off the start offset in the data.
131.288 + * @param len the number of bytes to write.
131.289 + * @exception IOException if an I/O error occurs.
131.290 + */
131.291 + public void write(byte b[], int off, int len) throws IOException {
131.292 + writeBytes(b, off, len, append);
131.293 + }
131.294 +
131.295 + /**
131.296 + * Closes this file output stream and releases any system resources
131.297 + * associated with this stream. This file output stream may no longer
131.298 + * be used for writing bytes.
131.299 + *
131.300 + * <p> If this stream has an associated channel then the channel is closed
131.301 + * as well.
131.302 + *
131.303 + * @exception IOException if an I/O error occurs.
131.304 + *
131.305 + * @revised 1.4
131.306 + * @spec JSR-51
131.307 + */
131.308 + public void close() throws IOException {
131.309 + synchronized (closeLock) {
131.310 + if (closed) {
131.311 + return;
131.312 + }
131.313 + closed = true;
131.314 + }
131.315 +//
131.316 +// if (channel != null) {
131.317 +// /*
131.318 +// * Decrement FD use count associated with the channel
131.319 +// * The use count is incremented whenever a new channel
131.320 +// * is obtained from this stream.
131.321 +// */
131.322 +// fd.decrementAndGetUseCount();
131.323 +// channel.close();
131.324 +// }
131.325 +
131.326 + /*
131.327 + * Decrement FD use count associated with this stream
131.328 + */
131.329 + int useCount = fd.decrementAndGetUseCount();
131.330 +
131.331 + /*
131.332 + * If FileDescriptor is still in use by another stream, the finalizer
131.333 + * will not close it.
131.334 + */
131.335 + if ((useCount <= 0) || !isRunningFinalize()) {
131.336 + close0();
131.337 + }
131.338 + }
131.339 +
131.340 + /**
131.341 + * Returns the file descriptor associated with this stream.
131.342 + *
131.343 + * @return the <code>FileDescriptor</code> object that represents
131.344 + * the connection to the file in the file system being used
131.345 + * by this <code>FileOutputStream</code> object.
131.346 + *
131.347 + * @exception IOException if an I/O error occurs.
131.348 + * @see java.io.FileDescriptor
131.349 + */
131.350 + public final FileDescriptor getFD() throws IOException {
131.351 + if (fd != null) return fd;
131.352 + throw new IOException();
131.353 + }
131.354 +
131.355 + /**
131.356 + * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
131.357 + * object associated with this file output stream. </p>
131.358 + *
131.359 + * <p> The initial {@link java.nio.channels.FileChannel#position()
131.360 + * </code>position<code>} of the returned channel will be equal to the
131.361 + * number of bytes written to the file so far unless this stream is in
131.362 + * append mode, in which case it will be equal to the size of the file.
131.363 + * Writing bytes to this stream will increment the channel's position
131.364 + * accordingly. Changing the channel's position, either explicitly or by
131.365 + * writing, will change this stream's file position.
131.366 + *
131.367 + * @return the file channel associated with this file output stream
131.368 + *
131.369 + * @since 1.4
131.370 + * @spec JSR-51
131.371 + */
131.372 +// public FileChannel getChannel() {
131.373 +// synchronized (this) {
131.374 +// if (channel == null) {
131.375 +// channel = FileChannelImpl.open(fd, false, true, append, this);
131.376 +//
131.377 +// /*
131.378 +// * Increment fd's use count. Invoking the channel's close()
131.379 +// * method will result in decrementing the use count set for
131.380 +// * the channel.
131.381 +// */
131.382 +// fd.incrementAndGetUseCount();
131.383 +// }
131.384 +// return channel;
131.385 +// }
131.386 +// }
131.387 +
131.388 + /**
131.389 + * Cleans up the connection to the file, and ensures that the
131.390 + * <code>close</code> method of this file output stream is
131.391 + * called when there are no more references to this stream.
131.392 + *
131.393 + * @exception IOException if an I/O error occurs.
131.394 + * @see java.io.FileInputStream#close()
131.395 + */
131.396 + protected void finalize() throws IOException {
131.397 + if (fd != null) {
131.398 + if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
131.399 + flush();
131.400 + } else {
131.401 +
131.402 + /*
131.403 + * Finalizer should not release the FileDescriptor if another
131.404 + * stream is still using it. If the user directly invokes
131.405 + * close() then the FileDescriptor is also released.
131.406 + */
131.407 + runningFinalize.set(Boolean.TRUE);
131.408 + try {
131.409 + close();
131.410 + } finally {
131.411 + runningFinalize.set(Boolean.FALSE);
131.412 + }
131.413 + }
131.414 + }
131.415 + }
131.416 +
131.417 + private native void close0() throws IOException;
131.418 +
131.419 + private static native void initIDs();
131.420 +
131.421 + static {
131.422 + initIDs();
131.423 + }
131.424 +
131.425 +}
132.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
132.2 +++ b/rt/emul/compact/src/main/java/java/io/FileReader.java Wed Apr 30 15:04:10 2014 +0200
132.3 @@ -0,0 +1,85 @@
132.4 +/*
132.5 + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
132.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
132.7 + *
132.8 + * This code is free software; you can redistribute it and/or modify it
132.9 + * under the terms of the GNU General Public License version 2 only, as
132.10 + * published by the Free Software Foundation. Oracle designates this
132.11 + * particular file as subject to the "Classpath" exception as provided
132.12 + * by Oracle in the LICENSE file that accompanied this code.
132.13 + *
132.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
132.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
132.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
132.17 + * version 2 for more details (a copy is included in the LICENSE file that
132.18 + * accompanied this code).
132.19 + *
132.20 + * You should have received a copy of the GNU General Public License version
132.21 + * 2 along with this work; if not, write to the Free Software Foundation,
132.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
132.23 + *
132.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
132.25 + * or visit www.oracle.com if you need additional information or have any
132.26 + * questions.
132.27 + */
132.28 +
132.29 +package java.io;
132.30 +
132.31 +
132.32 +/**
132.33 + * Convenience class for reading character files. The constructors of this
132.34 + * class assume that the default character encoding and the default byte-buffer
132.35 + * size are appropriate. To specify these values yourself, construct an
132.36 + * InputStreamReader on a FileInputStream.
132.37 + *
132.38 + * <p><code>FileReader</code> is meant for reading streams of characters.
132.39 + * For reading streams of raw bytes, consider using a
132.40 + * <code>FileInputStream</code>.
132.41 + *
132.42 + * @see InputStreamReader
132.43 + * @see FileInputStream
132.44 + *
132.45 + * @author Mark Reinhold
132.46 + * @since JDK1.1
132.47 + */
132.48 +public class FileReader extends InputStreamReader {
132.49 +
132.50 + /**
132.51 + * Creates a new <tt>FileReader</tt>, given the name of the
132.52 + * file to read from.
132.53 + *
132.54 + * @param fileName the name of the file to read from
132.55 + * @exception FileNotFoundException if the named file does not exist,
132.56 + * is a directory rather than a regular file,
132.57 + * or for some other reason cannot be opened for
132.58 + * reading.
132.59 + */
132.60 + public FileReader(String fileName) throws FileNotFoundException {
132.61 + super(new FileInputStream(fileName));
132.62 + }
132.63 +
132.64 + /**
132.65 + * Creates a new <tt>FileReader</tt>, given the <tt>File</tt>
132.66 + * to read from.
132.67 + *
132.68 + * @param file the <tt>File</tt> to read from
132.69 + * @exception FileNotFoundException if the file does not exist,
132.70 + * is a directory rather than a regular file,
132.71 + * or for some other reason cannot be opened for
132.72 + * reading.
132.73 + */
132.74 + public FileReader(File file) throws FileNotFoundException {
132.75 + super(new FileInputStream(file));
132.76 + }
132.77 +
132.78 + /**
132.79 + * Creates a new <tt>FileReader</tt>, given the
132.80 + * <tt>FileDescriptor</tt> to read from.
132.81 + *
132.82 + * @param fd the FileDescriptor to read from
132.83 + */
132.84 + public FileReader(FileDescriptor fd) {
132.85 + super(new FileInputStream(fd));
132.86 + }
132.87 +
132.88 +}
133.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
133.2 +++ b/rt/emul/compact/src/main/java/java/io/FileWriter.java Wed Apr 30 15:04:10 2014 +0200
133.3 @@ -0,0 +1,119 @@
133.4 +/*
133.5 + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
133.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
133.7 + *
133.8 + * This code is free software; you can redistribute it and/or modify it
133.9 + * under the terms of the GNU General Public License version 2 only, as
133.10 + * published by the Free Software Foundation. Oracle designates this
133.11 + * particular file as subject to the "Classpath" exception as provided
133.12 + * by Oracle in the LICENSE file that accompanied this code.
133.13 + *
133.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
133.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
133.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
133.17 + * version 2 for more details (a copy is included in the LICENSE file that
133.18 + * accompanied this code).
133.19 + *
133.20 + * You should have received a copy of the GNU General Public License version
133.21 + * 2 along with this work; if not, write to the Free Software Foundation,
133.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
133.23 + *
133.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
133.25 + * or visit www.oracle.com if you need additional information or have any
133.26 + * questions.
133.27 + */
133.28 +
133.29 +package java.io;
133.30 +
133.31 +
133.32 +/**
133.33 + * Convenience class for writing character files. The constructors of this
133.34 + * class assume that the default character encoding and the default byte-buffer
133.35 + * size are acceptable. To specify these values yourself, construct an
133.36 + * OutputStreamWriter on a FileOutputStream.
133.37 + *
133.38 + * <p>Whether or not a file is available or may be created depends upon the
133.39 + * underlying platform. Some platforms, in particular, allow a file to be
133.40 + * opened for writing by only one <tt>FileWriter</tt> (or other file-writing
133.41 + * object) at a time. In such situations the constructors in this class
133.42 + * will fail if the file involved is already open.
133.43 + *
133.44 + * <p><code>FileWriter</code> is meant for writing streams of characters.
133.45 + * For writing streams of raw bytes, consider using a
133.46 + * <code>FileOutputStream</code>.
133.47 + *
133.48 + * @see OutputStreamWriter
133.49 + * @see FileOutputStream
133.50 + *
133.51 + * @author Mark Reinhold
133.52 + * @since JDK1.1
133.53 + */
133.54 +
133.55 +public class FileWriter extends OutputStreamWriter {
133.56 +
133.57 + /**
133.58 + * Constructs a FileWriter object given a file name.
133.59 + *
133.60 + * @param fileName String The system-dependent filename.
133.61 + * @throws IOException if the named file exists but is a directory rather
133.62 + * than a regular file, does not exist but cannot be
133.63 + * created, or cannot be opened for any other reason
133.64 + */
133.65 + public FileWriter(String fileName) throws IOException {
133.66 + super(new FileOutputStream(fileName));
133.67 + }
133.68 +
133.69 + /**
133.70 + * Constructs a FileWriter object given a file name with a boolean
133.71 + * indicating whether or not to append the data written.
133.72 + *
133.73 + * @param fileName String The system-dependent filename.
133.74 + * @param append boolean if <code>true</code>, then data will be written
133.75 + * to the end of the file rather than the beginning.
133.76 + * @throws IOException if the named file exists but is a directory rather
133.77 + * than a regular file, does not exist but cannot be
133.78 + * created, or cannot be opened for any other reason
133.79 + */
133.80 + public FileWriter(String fileName, boolean append) throws IOException {
133.81 + super(new FileOutputStream(fileName, append));
133.82 + }
133.83 +
133.84 + /**
133.85 + * Constructs a FileWriter object given a File object.
133.86 + *
133.87 + * @param file a File object to write to.
133.88 + * @throws IOException if the file exists but is a directory rather than
133.89 + * a regular file, does not exist but cannot be created,
133.90 + * or cannot be opened for any other reason
133.91 + */
133.92 + public FileWriter(File file) throws IOException {
133.93 + super(new FileOutputStream(file));
133.94 + }
133.95 +
133.96 + /**
133.97 + * Constructs a FileWriter object given a File object. If the second
133.98 + * argument is <code>true</code>, then bytes will be written to the end
133.99 + * of the file rather than the beginning.
133.100 + *
133.101 + * @param file a File object to write to
133.102 + * @param append if <code>true</code>, then bytes will be written
133.103 + * to the end of the file rather than the beginning
133.104 + * @throws IOException if the file exists but is a directory rather than
133.105 + * a regular file, does not exist but cannot be created,
133.106 + * or cannot be opened for any other reason
133.107 + * @since 1.4
133.108 + */
133.109 + public FileWriter(File file, boolean append) throws IOException {
133.110 + super(new FileOutputStream(file, append));
133.111 + }
133.112 +
133.113 + /**
133.114 + * Constructs a FileWriter object associated with a file descriptor.
133.115 + *
133.116 + * @param fd FileDescriptor object to write to.
133.117 + */
133.118 + public FileWriter(FileDescriptor fd) {
133.119 + super(new FileOutputStream(fd));
133.120 + }
133.121 +
133.122 +}
134.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
134.2 +++ b/rt/emul/compact/src/main/java/java/io/FilenameFilter.java Wed Apr 30 15:04:10 2014 +0200
134.3 @@ -0,0 +1,53 @@
134.4 +/*
134.5 + * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
134.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
134.7 + *
134.8 + * This code is free software; you can redistribute it and/or modify it
134.9 + * under the terms of the GNU General Public License version 2 only, as
134.10 + * published by the Free Software Foundation. Oracle designates this
134.11 + * particular file as subject to the "Classpath" exception as provided
134.12 + * by Oracle in the LICENSE file that accompanied this code.
134.13 + *
134.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
134.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
134.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
134.17 + * version 2 for more details (a copy is included in the LICENSE file that
134.18 + * accompanied this code).
134.19 + *
134.20 + * You should have received a copy of the GNU General Public License version
134.21 + * 2 along with this work; if not, write to the Free Software Foundation,
134.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
134.23 + *
134.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
134.25 + * or visit www.oracle.com if you need additional information or have any
134.26 + * questions.
134.27 + */
134.28 +
134.29 +package java.io;
134.30 +
134.31 +/**
134.32 + * Instances of classes that implement this interface are used to
134.33 + * filter filenames. These instances are used to filter directory
134.34 + * listings in the <code>list</code> method of class
134.35 + * <code>File</code>, and by the Abstract Window Toolkit's file
134.36 + * dialog component.
134.37 + *
134.38 + * @author Arthur van Hoff
134.39 + * @author Jonathan Payne
134.40 + * @see java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter)
134.41 + * @see java.io.File
134.42 + * @see java.io.File#list(java.io.FilenameFilter)
134.43 + * @since JDK1.0
134.44 + */
134.45 +public
134.46 +interface FilenameFilter {
134.47 + /**
134.48 + * Tests if a specified file should be included in a file list.
134.49 + *
134.50 + * @param dir the directory in which the file was found.
134.51 + * @param name the name of the file.
134.52 + * @return <code>true</code> if and only if the name should be
134.53 + * included in the file list; <code>false</code> otherwise.
134.54 + */
134.55 + boolean accept(File dir, String name);
134.56 +}
135.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
135.2 +++ b/rt/emul/compact/src/main/java/java/io/FilterReader.java Wed Apr 30 15:04:10 2014 +0200
135.3 @@ -0,0 +1,124 @@
135.4 +/*
135.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
135.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
135.7 + *
135.8 + * This code is free software; you can redistribute it and/or modify it
135.9 + * under the terms of the GNU General Public License version 2 only, as
135.10 + * published by the Free Software Foundation. Oracle designates this
135.11 + * particular file as subject to the "Classpath" exception as provided
135.12 + * by Oracle in the LICENSE file that accompanied this code.
135.13 + *
135.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
135.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
135.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
135.17 + * version 2 for more details (a copy is included in the LICENSE file that
135.18 + * accompanied this code).
135.19 + *
135.20 + * You should have received a copy of the GNU General Public License version
135.21 + * 2 along with this work; if not, write to the Free Software Foundation,
135.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
135.23 + *
135.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
135.25 + * or visit www.oracle.com if you need additional information or have any
135.26 + * questions.
135.27 + */
135.28 +
135.29 +package java.io;
135.30 +
135.31 +
135.32 +/**
135.33 + * Abstract class for reading filtered character streams.
135.34 + * The abstract class <code>FilterReader</code> itself
135.35 + * provides default methods that pass all requests to
135.36 + * the contained stream. Subclasses of <code>FilterReader</code>
135.37 + * should override some of these methods and may also provide
135.38 + * additional methods and fields.
135.39 + *
135.40 + * @author Mark Reinhold
135.41 + * @since JDK1.1
135.42 + */
135.43 +
135.44 +public abstract class FilterReader extends Reader {
135.45 +
135.46 + /**
135.47 + * The underlying character-input stream.
135.48 + */
135.49 + protected Reader in;
135.50 +
135.51 + /**
135.52 + * Creates a new filtered reader.
135.53 + *
135.54 + * @param in a Reader object providing the underlying stream.
135.55 + * @throws NullPointerException if <code>in</code> is <code>null</code>
135.56 + */
135.57 + protected FilterReader(Reader in) {
135.58 + super(in);
135.59 + this.in = in;
135.60 + }
135.61 +
135.62 + /**
135.63 + * Reads a single character.
135.64 + *
135.65 + * @exception IOException If an I/O error occurs
135.66 + */
135.67 + public int read() throws IOException {
135.68 + return in.read();
135.69 + }
135.70 +
135.71 + /**
135.72 + * Reads characters into a portion of an array.
135.73 + *
135.74 + * @exception IOException If an I/O error occurs
135.75 + */
135.76 + public int read(char cbuf[], int off, int len) throws IOException {
135.77 + return in.read(cbuf, off, len);
135.78 + }
135.79 +
135.80 + /**
135.81 + * Skips characters.
135.82 + *
135.83 + * @exception IOException If an I/O error occurs
135.84 + */
135.85 + public long skip(long n) throws IOException {
135.86 + return in.skip(n);
135.87 + }
135.88 +
135.89 + /**
135.90 + * Tells whether this stream is ready to be read.
135.91 + *
135.92 + * @exception IOException If an I/O error occurs
135.93 + */
135.94 + public boolean ready() throws IOException {
135.95 + return in.ready();
135.96 + }
135.97 +
135.98 + /**
135.99 + * Tells whether this stream supports the mark() operation.
135.100 + */
135.101 + public boolean markSupported() {
135.102 + return in.markSupported();
135.103 + }
135.104 +
135.105 + /**
135.106 + * Marks the present position in the stream.
135.107 + *
135.108 + * @exception IOException If an I/O error occurs
135.109 + */
135.110 + public void mark(int readAheadLimit) throws IOException {
135.111 + in.mark(readAheadLimit);
135.112 + }
135.113 +
135.114 + /**
135.115 + * Resets the stream.
135.116 + *
135.117 + * @exception IOException If an I/O error occurs
135.118 + */
135.119 + public void reset() throws IOException {
135.120 + in.reset();
135.121 + }
135.122 +
135.123 + public void close() throws IOException {
135.124 + in.close();
135.125 + }
135.126 +
135.127 +}
136.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
136.2 +++ b/rt/emul/compact/src/main/java/java/io/FilterWriter.java Wed Apr 30 15:04:10 2014 +0200
136.3 @@ -0,0 +1,107 @@
136.4 +/*
136.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
136.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
136.7 + *
136.8 + * This code is free software; you can redistribute it and/or modify it
136.9 + * under the terms of the GNU General Public License version 2 only, as
136.10 + * published by the Free Software Foundation. Oracle designates this
136.11 + * particular file as subject to the "Classpath" exception as provided
136.12 + * by Oracle in the LICENSE file that accompanied this code.
136.13 + *
136.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
136.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
136.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
136.17 + * version 2 for more details (a copy is included in the LICENSE file that
136.18 + * accompanied this code).
136.19 + *
136.20 + * You should have received a copy of the GNU General Public License version
136.21 + * 2 along with this work; if not, write to the Free Software Foundation,
136.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
136.23 + *
136.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
136.25 + * or visit www.oracle.com if you need additional information or have any
136.26 + * questions.
136.27 + */
136.28 +
136.29 +package java.io;
136.30 +
136.31 +
136.32 +/**
136.33 + * Abstract class for writing filtered character streams.
136.34 + * The abstract class <code>FilterWriter</code> itself
136.35 + * provides default methods that pass all requests to the
136.36 + * contained stream. Subclasses of <code>FilterWriter</code>
136.37 + * should override some of these methods and may also
136.38 + * provide additional methods and fields.
136.39 + *
136.40 + * @author Mark Reinhold
136.41 + * @since JDK1.1
136.42 + */
136.43 +
136.44 +public abstract class FilterWriter extends Writer {
136.45 +
136.46 + /**
136.47 + * The underlying character-output stream.
136.48 + */
136.49 + protected Writer out;
136.50 +
136.51 + /**
136.52 + * Create a new filtered writer.
136.53 + *
136.54 + * @param out a Writer object to provide the underlying stream.
136.55 + * @throws NullPointerException if <code>out</code> is <code>null</code>
136.56 + */
136.57 + protected FilterWriter(Writer out) {
136.58 + super(out);
136.59 + this.out = out;
136.60 + }
136.61 +
136.62 + /**
136.63 + * Writes a single character.
136.64 + *
136.65 + * @exception IOException If an I/O error occurs
136.66 + */
136.67 + public void write(int c) throws IOException {
136.68 + out.write(c);
136.69 + }
136.70 +
136.71 + /**
136.72 + * Writes a portion of an array of characters.
136.73 + *
136.74 + * @param cbuf Buffer of characters to be written
136.75 + * @param off Offset from which to start reading characters
136.76 + * @param len Number of characters to be written
136.77 + *
136.78 + * @exception IOException If an I/O error occurs
136.79 + */
136.80 + public void write(char cbuf[], int off, int len) throws IOException {
136.81 + out.write(cbuf, off, len);
136.82 + }
136.83 +
136.84 + /**
136.85 + * Writes a portion of a string.
136.86 + *
136.87 + * @param str String to be written
136.88 + * @param off Offset from which to start reading characters
136.89 + * @param len Number of characters to be written
136.90 + *
136.91 + * @exception IOException If an I/O error occurs
136.92 + */
136.93 + public void write(String str, int off, int len) throws IOException {
136.94 + out.write(str, off, len);
136.95 + }
136.96 +
136.97 + /**
136.98 + * Flushes the stream.
136.99 + *
136.100 + * @exception IOException If an I/O error occurs
136.101 + */
136.102 + public void flush() throws IOException {
136.103 + out.flush();
136.104 + }
136.105 +
136.106 + public void close() throws IOException {
136.107 + out.close();
136.108 + }
136.109 +
136.110 +}
137.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
137.2 +++ b/rt/emul/compact/src/main/java/java/io/InterruptedIOException.java Wed Apr 30 15:04:10 2014 +0200
137.3 @@ -0,0 +1,74 @@
137.4 +/*
137.5 + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
137.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
137.7 + *
137.8 + * This code is free software; you can redistribute it and/or modify it
137.9 + * under the terms of the GNU General Public License version 2 only, as
137.10 + * published by the Free Software Foundation. Oracle designates this
137.11 + * particular file as subject to the "Classpath" exception as provided
137.12 + * by Oracle in the LICENSE file that accompanied this code.
137.13 + *
137.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
137.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
137.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
137.17 + * version 2 for more details (a copy is included in the LICENSE file that
137.18 + * accompanied this code).
137.19 + *
137.20 + * You should have received a copy of the GNU General Public License version
137.21 + * 2 along with this work; if not, write to the Free Software Foundation,
137.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
137.23 + *
137.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
137.25 + * or visit www.oracle.com if you need additional information or have any
137.26 + * questions.
137.27 + */
137.28 +
137.29 +package java.io;
137.30 +
137.31 +/**
137.32 + * Signals that an I/O operation has been interrupted. An
137.33 + * <code>InterruptedIOException</code> is thrown to indicate that an
137.34 + * input or output transfer has been terminated because the thread
137.35 + * performing it was interrupted. The field {@link #bytesTransferred}
137.36 + * indicates how many bytes were successfully transferred before
137.37 + * the interruption occurred.
137.38 + *
137.39 + * @author unascribed
137.40 + * @see java.io.InputStream
137.41 + * @see java.io.OutputStream
137.42 + * @see java.lang.Thread#interrupt()
137.43 + * @since JDK1.0
137.44 + */
137.45 +public
137.46 +class InterruptedIOException extends IOException {
137.47 + private static final long serialVersionUID = 4020568460727500567L;
137.48 +
137.49 + /**
137.50 + * Constructs an <code>InterruptedIOException</code> with
137.51 + * <code>null</code> as its error detail message.
137.52 + */
137.53 + public InterruptedIOException() {
137.54 + super();
137.55 + }
137.56 +
137.57 + /**
137.58 + * Constructs an <code>InterruptedIOException</code> with the
137.59 + * specified detail message. The string <code>s</code> can be
137.60 + * retrieved later by the
137.61 + * <code>{@link java.lang.Throwable#getMessage}</code>
137.62 + * method of class <code>java.lang.Throwable</code>.
137.63 + *
137.64 + * @param s the detail message.
137.65 + */
137.66 + public InterruptedIOException(String s) {
137.67 + super(s);
137.68 + }
137.69 +
137.70 + /**
137.71 + * Reports how many bytes had been transferred as part of the I/O
137.72 + * operation before it was interrupted.
137.73 + *
137.74 + * @serial
137.75 + */
137.76 + public int bytesTransferred = 0;
137.77 +}
138.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
138.2 +++ b/rt/emul/compact/src/main/java/java/io/LineNumberInputStream.java Wed Apr 30 15:04:10 2014 +0200
138.3 @@ -0,0 +1,292 @@
138.4 +/*
138.5 + * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
138.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
138.7 + *
138.8 + * This code is free software; you can redistribute it and/or modify it
138.9 + * under the terms of the GNU General Public License version 2 only, as
138.10 + * published by the Free Software Foundation. Oracle designates this
138.11 + * particular file as subject to the "Classpath" exception as provided
138.12 + * by Oracle in the LICENSE file that accompanied this code.
138.13 + *
138.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
138.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
138.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
138.17 + * version 2 for more details (a copy is included in the LICENSE file that
138.18 + * accompanied this code).
138.19 + *
138.20 + * You should have received a copy of the GNU General Public License version
138.21 + * 2 along with this work; if not, write to the Free Software Foundation,
138.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
138.23 + *
138.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
138.25 + * or visit www.oracle.com if you need additional information or have any
138.26 + * questions.
138.27 + */
138.28 +
138.29 +package java.io;
138.30 +
138.31 +/**
138.32 + * This class is an input stream filter that provides the added
138.33 + * functionality of keeping track of the current line number.
138.34 + * <p>
138.35 + * A line is a sequence of bytes ending with a carriage return
138.36 + * character (<code>'\r'</code>), a newline character
138.37 + * (<code>'\n'</code>), or a carriage return character followed
138.38 + * immediately by a linefeed character. In all three cases, the line
138.39 + * terminating character(s) are returned as a single newline character.
138.40 + * <p>
138.41 + * The line number begins at <code>0</code>, and is incremented by
138.42 + * <code>1</code> when a <code>read</code> returns a newline character.
138.43 + *
138.44 + * @author Arthur van Hoff
138.45 + * @see java.io.LineNumberReader
138.46 + * @since JDK1.0
138.47 + * @deprecated This class incorrectly assumes that bytes adequately represent
138.48 + * characters. As of JDK 1.1, the preferred way to operate on
138.49 + * character streams is via the new character-stream classes, which
138.50 + * include a class for counting line numbers.
138.51 + */
138.52 +@Deprecated
138.53 +public
138.54 +class LineNumberInputStream extends FilterInputStream {
138.55 + int pushBack = -1;
138.56 + int lineNumber;
138.57 + int markLineNumber;
138.58 + int markPushBack = -1;
138.59 +
138.60 + /**
138.61 + * Constructs a newline number input stream that reads its input
138.62 + * from the specified input stream.
138.63 + *
138.64 + * @param in the underlying input stream.
138.65 + */
138.66 + public LineNumberInputStream(InputStream in) {
138.67 + super(in);
138.68 + }
138.69 +
138.70 + /**
138.71 + * Reads the next byte of data from this input stream. The value
138.72 + * byte is returned as an <code>int</code> in the range
138.73 + * <code>0</code> to <code>255</code>. If no byte is available
138.74 + * because the end of the stream has been reached, the value
138.75 + * <code>-1</code> is returned. This method blocks until input data
138.76 + * is available, the end of the stream is detected, or an exception
138.77 + * is thrown.
138.78 + * <p>
138.79 + * The <code>read</code> method of
138.80 + * <code>LineNumberInputStream</code> calls the <code>read</code>
138.81 + * method of the underlying input stream. It checks for carriage
138.82 + * returns and newline characters in the input, and modifies the
138.83 + * current line number as appropriate. A carriage-return character or
138.84 + * a carriage return followed by a newline character are both
138.85 + * converted into a single newline character.
138.86 + *
138.87 + * @return the next byte of data, or <code>-1</code> if the end of this
138.88 + * stream is reached.
138.89 + * @exception IOException if an I/O error occurs.
138.90 + * @see java.io.FilterInputStream#in
138.91 + * @see java.io.LineNumberInputStream#getLineNumber()
138.92 + */
138.93 + public int read() throws IOException {
138.94 + int c = pushBack;
138.95 +
138.96 + if (c != -1) {
138.97 + pushBack = -1;
138.98 + } else {
138.99 + c = in.read();
138.100 + }
138.101 +
138.102 + switch (c) {
138.103 + case '\r':
138.104 + pushBack = in.read();
138.105 + if (pushBack == '\n') {
138.106 + pushBack = -1;
138.107 + }
138.108 + case '\n':
138.109 + lineNumber++;
138.110 + return '\n';
138.111 + }
138.112 + return c;
138.113 + }
138.114 +
138.115 + /**
138.116 + * Reads up to <code>len</code> bytes of data from this input stream
138.117 + * into an array of bytes. This method blocks until some input is available.
138.118 + * <p>
138.119 + * The <code>read</code> method of
138.120 + * <code>LineNumberInputStream</code> repeatedly calls the
138.121 + * <code>read</code> method of zero arguments to fill in the byte array.
138.122 + *
138.123 + * @param b the buffer into which the data is read.
138.124 + * @param off the start offset of the data.
138.125 + * @param len the maximum number of bytes read.
138.126 + * @return the total number of bytes read into the buffer, or
138.127 + * <code>-1</code> if there is no more data because the end of
138.128 + * this stream has been reached.
138.129 + * @exception IOException if an I/O error occurs.
138.130 + * @see java.io.LineNumberInputStream#read()
138.131 + */
138.132 + public int read(byte b[], int off, int len) throws IOException {
138.133 + if (b == null) {
138.134 + throw new NullPointerException();
138.135 + } else if ((off < 0) || (off > b.length) || (len < 0) ||
138.136 + ((off + len) > b.length) || ((off + len) < 0)) {
138.137 + throw new IndexOutOfBoundsException();
138.138 + } else if (len == 0) {
138.139 + return 0;
138.140 + }
138.141 +
138.142 + int c = read();
138.143 + if (c == -1) {
138.144 + return -1;
138.145 + }
138.146 + b[off] = (byte)c;
138.147 +
138.148 + int i = 1;
138.149 + try {
138.150 + for (; i < len ; i++) {
138.151 + c = read();
138.152 + if (c == -1) {
138.153 + break;
138.154 + }
138.155 + if (b != null) {
138.156 + b[off + i] = (byte)c;
138.157 + }
138.158 + }
138.159 + } catch (IOException ee) {
138.160 + }
138.161 + return i;
138.162 + }
138.163 +
138.164 + /**
138.165 + * Skips over and discards <code>n</code> bytes of data from this
138.166 + * input stream. The <code>skip</code> method may, for a variety of
138.167 + * reasons, end up skipping over some smaller number of bytes,
138.168 + * possibly <code>0</code>. The actual number of bytes skipped is
138.169 + * returned. If <code>n</code> is negative, no bytes are skipped.
138.170 + * <p>
138.171 + * The <code>skip</code> method of <code>LineNumberInputStream</code> creates
138.172 + * a byte array and then repeatedly reads into it until
138.173 + * <code>n</code> bytes have been read or the end of the stream has
138.174 + * been reached.
138.175 + *
138.176 + * @param n the number of bytes to be skipped.
138.177 + * @return the actual number of bytes skipped.
138.178 + * @exception IOException if an I/O error occurs.
138.179 + * @see java.io.FilterInputStream#in
138.180 + */
138.181 + public long skip(long n) throws IOException {
138.182 + int chunk = 2048;
138.183 + long remaining = n;
138.184 + byte data[];
138.185 + int nr;
138.186 +
138.187 + if (n <= 0) {
138.188 + return 0;
138.189 + }
138.190 +
138.191 + data = new byte[chunk];
138.192 + while (remaining > 0) {
138.193 + nr = read(data, 0, (int) Math.min(chunk, remaining));
138.194 + if (nr < 0) {
138.195 + break;
138.196 + }
138.197 + remaining -= nr;
138.198 + }
138.199 +
138.200 + return n - remaining;
138.201 + }
138.202 +
138.203 + /**
138.204 + * Sets the line number to the specified argument.
138.205 + *
138.206 + * @param lineNumber the new line number.
138.207 + * @see #getLineNumber
138.208 + */
138.209 + public void setLineNumber(int lineNumber) {
138.210 + this.lineNumber = lineNumber;
138.211 + }
138.212 +
138.213 + /**
138.214 + * Returns the current line number.
138.215 + *
138.216 + * @return the current line number.
138.217 + * @see #setLineNumber
138.218 + */
138.219 + public int getLineNumber() {
138.220 + return lineNumber;
138.221 + }
138.222 +
138.223 +
138.224 + /**
138.225 + * Returns the number of bytes that can be read from this input
138.226 + * stream without blocking.
138.227 + * <p>
138.228 + * Note that if the underlying input stream is able to supply
138.229 + * <i>k</i> input characters without blocking, the
138.230 + * <code>LineNumberInputStream</code> can guarantee only to provide
138.231 + * <i>k</i>/2 characters without blocking, because the
138.232 + * <i>k</i> characters from the underlying input stream might
138.233 + * consist of <i>k</i>/2 pairs of <code>'\r'</code> and
138.234 + * <code>'\n'</code>, which are converted to just
138.235 + * <i>k</i>/2 <code>'\n'</code> characters.
138.236 + *
138.237 + * @return the number of bytes that can be read from this input stream
138.238 + * without blocking.
138.239 + * @exception IOException if an I/O error occurs.
138.240 + * @see java.io.FilterInputStream#in
138.241 + */
138.242 + public int available() throws IOException {
138.243 + return (pushBack == -1) ? super.available()/2 : super.available()/2 + 1;
138.244 + }
138.245 +
138.246 + /**
138.247 + * Marks the current position in this input stream. A subsequent
138.248 + * call to the <code>reset</code> method repositions this stream at
138.249 + * the last marked position so that subsequent reads re-read the same bytes.
138.250 + * <p>
138.251 + * The <code>mark</code> method of
138.252 + * <code>LineNumberInputStream</code> remembers the current line
138.253 + * number in a private variable, and then calls the <code>mark</code>
138.254 + * method of the underlying input stream.
138.255 + *
138.256 + * @param readlimit the maximum limit of bytes that can be read before
138.257 + * the mark position becomes invalid.
138.258 + * @see java.io.FilterInputStream#in
138.259 + * @see java.io.LineNumberInputStream#reset()
138.260 + */
138.261 + public void mark(int readlimit) {
138.262 + markLineNumber = lineNumber;
138.263 + markPushBack = pushBack;
138.264 + in.mark(readlimit);
138.265 + }
138.266 +
138.267 + /**
138.268 + * Repositions this stream to the position at the time the
138.269 + * <code>mark</code> method was last called on this input stream.
138.270 + * <p>
138.271 + * The <code>reset</code> method of
138.272 + * <code>LineNumberInputStream</code> resets the line number to be
138.273 + * the line number at the time the <code>mark</code> method was
138.274 + * called, and then calls the <code>reset</code> method of the
138.275 + * underlying input stream.
138.276 + * <p>
138.277 + * Stream marks are intended to be used in
138.278 + * situations where you need to read ahead a little to see what's in
138.279 + * the stream. Often this is most easily done by invoking some
138.280 + * general parser. If the stream is of the type handled by the
138.281 + * parser, it just chugs along happily. If the stream is not of
138.282 + * that type, the parser should toss an exception when it fails,
138.283 + * which, if it happens within readlimit bytes, allows the outer
138.284 + * code to reset the stream and try another parser.
138.285 + *
138.286 + * @exception IOException if an I/O error occurs.
138.287 + * @see java.io.FilterInputStream#in
138.288 + * @see java.io.LineNumberInputStream#mark(int)
138.289 + */
138.290 + public void reset() throws IOException {
138.291 + lineNumber = markLineNumber;
138.292 + pushBack = markPushBack;
138.293 + in.reset();
138.294 + }
138.295 +}
139.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
139.2 +++ b/rt/emul/compact/src/main/java/java/io/LineNumberReader.java Wed Apr 30 15:04:10 2014 +0200
139.3 @@ -0,0 +1,281 @@
139.4 +/*
139.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
139.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
139.7 + *
139.8 + * This code is free software; you can redistribute it and/or modify it
139.9 + * under the terms of the GNU General Public License version 2 only, as
139.10 + * published by the Free Software Foundation. Oracle designates this
139.11 + * particular file as subject to the "Classpath" exception as provided
139.12 + * by Oracle in the LICENSE file that accompanied this code.
139.13 + *
139.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
139.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
139.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
139.17 + * version 2 for more details (a copy is included in the LICENSE file that
139.18 + * accompanied this code).
139.19 + *
139.20 + * You should have received a copy of the GNU General Public License version
139.21 + * 2 along with this work; if not, write to the Free Software Foundation,
139.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
139.23 + *
139.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
139.25 + * or visit www.oracle.com if you need additional information or have any
139.26 + * questions.
139.27 + */
139.28 +
139.29 +package java.io;
139.30 +
139.31 +
139.32 +/**
139.33 + * A buffered character-input stream that keeps track of line numbers. This
139.34 + * class defines methods {@link #setLineNumber(int)} and {@link
139.35 + * #getLineNumber()} for setting and getting the current line number
139.36 + * respectively.
139.37 + *
139.38 + * <p> By default, line numbering begins at 0. This number increments at every
139.39 + * <a href="#lt">line terminator</a> as the data is read, and can be changed
139.40 + * with a call to <tt>setLineNumber(int)</tt>. Note however, that
139.41 + * <tt>setLineNumber(int)</tt> does not actually change the current position in
139.42 + * the stream; it only changes the value that will be returned by
139.43 + * <tt>getLineNumber()</tt>.
139.44 + *
139.45 + * <p> A line is considered to be <a name="lt">terminated</a> by any one of a
139.46 + * line feed ('\n'), a carriage return ('\r'), or a carriage return followed
139.47 + * immediately by a linefeed.
139.48 + *
139.49 + * @author Mark Reinhold
139.50 + * @since JDK1.1
139.51 + */
139.52 +
139.53 +public class LineNumberReader extends BufferedReader {
139.54 +
139.55 + /** The current line number */
139.56 + private int lineNumber = 0;
139.57 +
139.58 + /** The line number of the mark, if any */
139.59 + private int markedLineNumber; // Defaults to 0
139.60 +
139.61 + /** If the next character is a line feed, skip it */
139.62 + private boolean skipLF;
139.63 +
139.64 + /** The skipLF flag when the mark was set */
139.65 + private boolean markedSkipLF;
139.66 +
139.67 + /**
139.68 + * Create a new line-numbering reader, using the default input-buffer
139.69 + * size.
139.70 + *
139.71 + * @param in
139.72 + * A Reader object to provide the underlying stream
139.73 + */
139.74 + public LineNumberReader(Reader in) {
139.75 + super(in);
139.76 + }
139.77 +
139.78 + /**
139.79 + * Create a new line-numbering reader, reading characters into a buffer of
139.80 + * the given size.
139.81 + *
139.82 + * @param in
139.83 + * A Reader object to provide the underlying stream
139.84 + *
139.85 + * @param sz
139.86 + * An int specifying the size of the buffer
139.87 + */
139.88 + public LineNumberReader(Reader in, int sz) {
139.89 + super(in, sz);
139.90 + }
139.91 +
139.92 + /**
139.93 + * Set the current line number.
139.94 + *
139.95 + * @param lineNumber
139.96 + * An int specifying the line number
139.97 + *
139.98 + * @see #getLineNumber
139.99 + */
139.100 + public void setLineNumber(int lineNumber) {
139.101 + this.lineNumber = lineNumber;
139.102 + }
139.103 +
139.104 + /**
139.105 + * Get the current line number.
139.106 + *
139.107 + * @return The current line number
139.108 + *
139.109 + * @see #setLineNumber
139.110 + */
139.111 + public int getLineNumber() {
139.112 + return lineNumber;
139.113 + }
139.114 +
139.115 + /**
139.116 + * Read a single character. <a href="#lt">Line terminators</a> are
139.117 + * compressed into single newline ('\n') characters. Whenever a line
139.118 + * terminator is read the current line number is incremented.
139.119 + *
139.120 + * @return The character read, or -1 if the end of the stream has been
139.121 + * reached
139.122 + *
139.123 + * @throws IOException
139.124 + * If an I/O error occurs
139.125 + */
139.126 + public int read() throws IOException {
139.127 + synchronized (lock) {
139.128 + int c = super.read();
139.129 + if (skipLF) {
139.130 + if (c == '\n')
139.131 + c = super.read();
139.132 + skipLF = false;
139.133 + }
139.134 + switch (c) {
139.135 + case '\r':
139.136 + skipLF = true;
139.137 + case '\n': /* Fall through */
139.138 + lineNumber++;
139.139 + return '\n';
139.140 + }
139.141 + return c;
139.142 + }
139.143 + }
139.144 +
139.145 + /**
139.146 + * Read characters into a portion of an array. Whenever a <a
139.147 + * href="#lt">line terminator</a> is read the current line number is
139.148 + * incremented.
139.149 + *
139.150 + * @param cbuf
139.151 + * Destination buffer
139.152 + *
139.153 + * @param off
139.154 + * Offset at which to start storing characters
139.155 + *
139.156 + * @param len
139.157 + * Maximum number of characters to read
139.158 + *
139.159 + * @return The number of bytes read, or -1 if the end of the stream has
139.160 + * already been reached
139.161 + *
139.162 + * @throws IOException
139.163 + * If an I/O error occurs
139.164 + */
139.165 + public int read(char cbuf[], int off, int len) throws IOException {
139.166 + synchronized (lock) {
139.167 + int n = super.read(cbuf, off, len);
139.168 +
139.169 + for (int i = off; i < off + n; i++) {
139.170 + int c = cbuf[i];
139.171 + if (skipLF) {
139.172 + skipLF = false;
139.173 + if (c == '\n')
139.174 + continue;
139.175 + }
139.176 + switch (c) {
139.177 + case '\r':
139.178 + skipLF = true;
139.179 + case '\n': /* Fall through */
139.180 + lineNumber++;
139.181 + break;
139.182 + }
139.183 + }
139.184 +
139.185 + return n;
139.186 + }
139.187 + }
139.188 +
139.189 + /**
139.190 + * Read a line of text. Whenever a <a href="#lt">line terminator</a> is
139.191 + * read the current line number is incremented.
139.192 + *
139.193 + * @return A String containing the contents of the line, not including
139.194 + * any <a href="#lt">line termination characters</a>, or
139.195 + * <tt>null</tt> if the end of the stream has been reached
139.196 + *
139.197 + * @throws IOException
139.198 + * If an I/O error occurs
139.199 + */
139.200 + public String readLine() throws IOException {
139.201 + synchronized (lock) {
139.202 + String l = super.readLine(skipLF);
139.203 + skipLF = false;
139.204 + if (l != null)
139.205 + lineNumber++;
139.206 + return l;
139.207 + }
139.208 + }
139.209 +
139.210 + /** Maximum skip-buffer size */
139.211 + private static final int maxSkipBufferSize = 8192;
139.212 +
139.213 + /** Skip buffer, null until allocated */
139.214 + private char skipBuffer[] = null;
139.215 +
139.216 + /**
139.217 + * Skip characters.
139.218 + *
139.219 + * @param n
139.220 + * The number of characters to skip
139.221 + *
139.222 + * @return The number of characters actually skipped
139.223 + *
139.224 + * @throws IOException
139.225 + * If an I/O error occurs
139.226 + *
139.227 + * @throws IllegalArgumentException
139.228 + * If <tt>n</tt> is negative
139.229 + */
139.230 + public long skip(long n) throws IOException {
139.231 + if (n < 0)
139.232 + throw new IllegalArgumentException("skip() value is negative");
139.233 + int nn = (int) Math.min(n, maxSkipBufferSize);
139.234 + synchronized (lock) {
139.235 + if ((skipBuffer == null) || (skipBuffer.length < nn))
139.236 + skipBuffer = new char[nn];
139.237 + long r = n;
139.238 + while (r > 0) {
139.239 + int nc = read(skipBuffer, 0, (int) Math.min(r, nn));
139.240 + if (nc == -1)
139.241 + break;
139.242 + r -= nc;
139.243 + }
139.244 + return n - r;
139.245 + }
139.246 + }
139.247 +
139.248 + /**
139.249 + * Mark the present position in the stream. Subsequent calls to reset()
139.250 + * will attempt to reposition the stream to this point, and will also reset
139.251 + * the line number appropriately.
139.252 + *
139.253 + * @param readAheadLimit
139.254 + * Limit on the number of characters that may be read while still
139.255 + * preserving the mark. After reading this many characters,
139.256 + * attempting to reset the stream may fail.
139.257 + *
139.258 + * @throws IOException
139.259 + * If an I/O error occurs
139.260 + */
139.261 + public void mark(int readAheadLimit) throws IOException {
139.262 + synchronized (lock) {
139.263 + super.mark(readAheadLimit);
139.264 + markedLineNumber = lineNumber;
139.265 + markedSkipLF = skipLF;
139.266 + }
139.267 + }
139.268 +
139.269 + /**
139.270 + * Reset the stream to the most recent mark.
139.271 + *
139.272 + * @throws IOException
139.273 + * If the stream has not been marked, or if the mark has been
139.274 + * invalidated
139.275 + */
139.276 + public void reset() throws IOException {
139.277 + synchronized (lock) {
139.278 + super.reset();
139.279 + lineNumber = markedLineNumber;
139.280 + skipLF = markedSkipLF;
139.281 + }
139.282 + }
139.283 +
139.284 +}
140.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
140.2 +++ b/rt/emul/compact/src/main/java/java/io/OutputStreamWriter.java Wed Apr 30 15:04:10 2014 +0200
140.3 @@ -0,0 +1,241 @@
140.4 +/*
140.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
140.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
140.7 + *
140.8 + * This code is free software; you can redistribute it and/or modify it
140.9 + * under the terms of the GNU General Public License version 2 only, as
140.10 + * published by the Free Software Foundation. Oracle designates this
140.11 + * particular file as subject to the "Classpath" exception as provided
140.12 + * by Oracle in the LICENSE file that accompanied this code.
140.13 + *
140.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
140.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
140.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
140.17 + * version 2 for more details (a copy is included in the LICENSE file that
140.18 + * accompanied this code).
140.19 + *
140.20 + * You should have received a copy of the GNU General Public License version
140.21 + * 2 along with this work; if not, write to the Free Software Foundation,
140.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
140.23 + *
140.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
140.25 + * or visit www.oracle.com if you need additional information or have any
140.26 + * questions.
140.27 + */
140.28 +
140.29 +package java.io;
140.30 +
140.31 +import java.nio.charset.Charset;
140.32 +
140.33 +/**
140.34 + * An OutputStreamWriter is a bridge from character streams to byte streams:
140.35 + * Characters written to it are encoded into bytes using a specified {@link
140.36 + * java.nio.charset.Charset <code>charset</code>}. The charset that it uses
140.37 + * may be specified by name or may be given explicitly, or the platform's
140.38 + * default charset may be accepted.
140.39 + *
140.40 + * <p> Each invocation of a write() method causes the encoding converter to be
140.41 + * invoked on the given character(s). The resulting bytes are accumulated in a
140.42 + * buffer before being written to the underlying output stream. The size of
140.43 + * this buffer may be specified, but by default it is large enough for most
140.44 + * purposes. Note that the characters passed to the write() methods are not
140.45 + * buffered.
140.46 + *
140.47 + * <p> For top efficiency, consider wrapping an OutputStreamWriter within a
140.48 + * BufferedWriter so as to avoid frequent converter invocations. For example:
140.49 + *
140.50 + * <pre>
140.51 + * Writer out
140.52 + * = new BufferedWriter(new OutputStreamWriter(System.out));
140.53 + * </pre>
140.54 + *
140.55 + * <p> A <i>surrogate pair</i> is a character represented by a sequence of two
140.56 + * <tt>char</tt> values: A <i>high</i> surrogate in the range '\uD800' to
140.57 + * '\uDBFF' followed by a <i>low</i> surrogate in the range '\uDC00' to
140.58 + * '\uDFFF'.
140.59 + *
140.60 + * <p> A <i>malformed surrogate element</i> is a high surrogate that is not
140.61 + * followed by a low surrogate or a low surrogate that is not preceded by a
140.62 + * high surrogate.
140.63 + *
140.64 + * <p> This class always replaces malformed surrogate elements and unmappable
140.65 + * character sequences with the charset's default <i>substitution sequence</i>.
140.66 + * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
140.67 + * control over the encoding process is required.
140.68 + *
140.69 + * @see BufferedWriter
140.70 + * @see OutputStream
140.71 + * @see java.nio.charset.Charset
140.72 + *
140.73 + * @author Mark Reinhold
140.74 + * @since JDK1.1
140.75 + */
140.76 +
140.77 +public class OutputStreamWriter extends Writer {
140.78 +
140.79 + /**
140.80 + * Creates an OutputStreamWriter that uses the named charset.
140.81 + *
140.82 + * @param out
140.83 + * An OutputStream
140.84 + *
140.85 + * @param charsetName
140.86 + * The name of a supported
140.87 + * {@link java.nio.charset.Charset </code>charset<code>}
140.88 + *
140.89 + * @exception UnsupportedEncodingException
140.90 + * If the named encoding is not supported
140.91 + */
140.92 + public OutputStreamWriter(OutputStream out, String charsetName)
140.93 + throws UnsupportedEncodingException
140.94 + {
140.95 + super(out);
140.96 + if (charsetName == null)
140.97 + throw new NullPointerException("charsetName");
140.98 + if (!charsetName.toUpperCase().equals("UTF-8")) {
140.99 + throw new UnsupportedEncodingException(charsetName);
140.100 + }
140.101 + }
140.102 +
140.103 + /**
140.104 + * Creates an OutputStreamWriter that uses the default character encoding.
140.105 + *
140.106 + * @param out An OutputStream
140.107 + */
140.108 + public OutputStreamWriter(OutputStream out) {
140.109 + super(out);
140.110 + }
140.111 +
140.112 + /**
140.113 + * Creates an OutputStreamWriter that uses the given charset. </p>
140.114 + *
140.115 + * @param out
140.116 + * An OutputStream
140.117 + *
140.118 + * @param cs
140.119 + * A charset
140.120 + *
140.121 + * @since 1.4
140.122 + * @spec JSR-51
140.123 + */
140.124 + public OutputStreamWriter(OutputStream out, Charset cs) {
140.125 + this(out);
140.126 + }
140.127 +
140.128 + /**
140.129 + * Creates an OutputStreamWriter that uses the given charset encoder. </p>
140.130 + *
140.131 + * @param out
140.132 + * An OutputStream
140.133 + *
140.134 + * @param enc
140.135 + * A charset encoder
140.136 + *
140.137 + * @since 1.4
140.138 + * @spec JSR-51
140.139 + */
140.140 +// public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
140.141 +// super(out);
140.142 +// if (enc == null)
140.143 +// throw new NullPointerException("charset encoder");
140.144 +// se = StreamEncoder.forOutputStreamWriter(out, this, enc);
140.145 +// }
140.146 +
140.147 + /**
140.148 + * Returns the name of the character encoding being used by this stream.
140.149 + *
140.150 + * <p> If the encoding has an historical name then that name is returned;
140.151 + * otherwise the encoding's canonical name is returned.
140.152 + *
140.153 + * <p> If this instance was created with the {@link
140.154 + * #OutputStreamWriter(OutputStream, String)} constructor then the returned
140.155 + * name, being unique for the encoding, may differ from the name passed to
140.156 + * the constructor. This method may return <tt>null</tt> if the stream has
140.157 + * been closed. </p>
140.158 + *
140.159 + * @return The historical name of this encoding, or possibly
140.160 + * <code>null</code> if the stream has been closed
140.161 + *
140.162 + * @see java.nio.charset.Charset
140.163 + *
140.164 + * @revised 1.4
140.165 + * @spec JSR-51
140.166 + */
140.167 + public String getEncoding() {
140.168 + return "UTF-8";
140.169 + }
140.170 +
140.171 + /**
140.172 + * Flushes the output buffer to the underlying byte stream, without flushing
140.173 + * the byte stream itself. This method is non-private only so that it may
140.174 + * be invoked by PrintStream.
140.175 + */
140.176 + void flushBuffer() throws IOException {
140.177 + out().flush();
140.178 + }
140.179 +
140.180 + /**
140.181 + * Writes a single character.
140.182 + *
140.183 + * @exception IOException If an I/O error occurs
140.184 + */
140.185 + public void write(int c) throws IOException {
140.186 + if (c <= 0x7F) {
140.187 + out().write(c);
140.188 + } else if (c <= 0x7FF) {
140.189 + out().write(0xC0 | (c >> 6));
140.190 + out().write(0x80 | (c & 0x3F));
140.191 + } else {
140.192 + out().write(0xE0 | (c >> 12));
140.193 + out().write(0x80 | ((c >> 6) & 0x3F));
140.194 + out().write(0x80 | (c & 0x3F));
140.195 + }
140.196 + }
140.197 +
140.198 + /**
140.199 + * Writes a portion of an array of characters.
140.200 + *
140.201 + * @param cbuf Buffer of characters
140.202 + * @param off Offset from which to start writing characters
140.203 + * @param len Number of characters to write
140.204 + *
140.205 + * @exception IOException If an I/O error occurs
140.206 + */
140.207 + public void write(char cbuf[], int off, int len) throws IOException {
140.208 + while (len-- > 0) {
140.209 + write(cbuf[off++]);
140.210 + }
140.211 + }
140.212 +
140.213 + /**
140.214 + * Writes a portion of a string.
140.215 + *
140.216 + * @param str A String
140.217 + * @param off Offset from which to start writing characters
140.218 + * @param len Number of characters to write
140.219 + *
140.220 + * @exception IOException If an I/O error occurs
140.221 + */
140.222 + public void write(String str, int off, int len) throws IOException {
140.223 + while (len-- > 0) {
140.224 + write(str.charAt(off++));
140.225 + }
140.226 + }
140.227 +
140.228 + /**
140.229 + * Flushes the stream.
140.230 + *
140.231 + * @exception IOException If an I/O error occurs
140.232 + */
140.233 + public void flush() throws IOException {
140.234 + out().flush();
140.235 + }
140.236 +
140.237 + public void close() throws IOException {
140.238 + out().close();
140.239 + }
140.240 +
140.241 + private OutputStream out() {
140.242 + return (OutputStream) lock;
140.243 + }
140.244 +}
141.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
141.2 +++ b/rt/emul/compact/src/main/java/java/io/PrintStream.java Wed Apr 30 15:04:10 2014 +0200
141.3 @@ -0,0 +1,1123 @@
141.4 +/*
141.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
141.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
141.7 + *
141.8 + * This code is free software; you can redistribute it and/or modify it
141.9 + * under the terms of the GNU General Public License version 2 only, as
141.10 + * published by the Free Software Foundation. Oracle designates this
141.11 + * particular file as subject to the "Classpath" exception as provided
141.12 + * by Oracle in the LICENSE file that accompanied this code.
141.13 + *
141.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
141.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
141.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
141.17 + * version 2 for more details (a copy is included in the LICENSE file that
141.18 + * accompanied this code).
141.19 + *
141.20 + * You should have received a copy of the GNU General Public License version
141.21 + * 2 along with this work; if not, write to the Free Software Foundation,
141.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
141.23 + *
141.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
141.25 + * or visit www.oracle.com if you need additional information or have any
141.26 + * questions.
141.27 + */
141.28 +
141.29 +package java.io;
141.30 +
141.31 +import java.nio.charset.Charset;
141.32 +import java.util.Arrays;
141.33 +
141.34 +
141.35 +/**
141.36 + * A <code>PrintStream</code> adds functionality to another output stream,
141.37 + * namely the ability to print representations of various data values
141.38 + * conveniently. Two other features are provided as well. Unlike other output
141.39 + * streams, a <code>PrintStream</code> never throws an
141.40 + * <code>IOException</code>; instead, exceptional situations merely set an
141.41 + * internal flag that can be tested via the <code>checkError</code> method.
141.42 + * Optionally, a <code>PrintStream</code> can be created so as to flush
141.43 + * automatically; this means that the <code>flush</code> method is
141.44 + * automatically invoked after a byte array is written, one of the
141.45 + * <code>println</code> methods is invoked, or a newline character or byte
141.46 + * (<code>'\n'</code>) is written.
141.47 + *
141.48 + * <p> All characters printed by a <code>PrintStream</code> are converted into
141.49 + * bytes using the platform's default character encoding. The <code>{@link
141.50 + * PrintWriter}</code> class should be used in situations that require writing
141.51 + * characters rather than bytes.
141.52 + *
141.53 + * @author Frank Yellin
141.54 + * @author Mark Reinhold
141.55 + * @since JDK1.0
141.56 + */
141.57 +
141.58 +public class PrintStream extends FilterOutputStream
141.59 + implements Appendable, Closeable
141.60 +{
141.61 +
141.62 + private final boolean autoFlush;
141.63 + private boolean trouble = false;
141.64 + private Formatter formatter;
141.65 +
141.66 + /**
141.67 + * Track both the text- and character-output streams, so that their buffers
141.68 + * can be flushed without flushing the entire stream.
141.69 + */
141.70 + private BufferedWriter textOut;
141.71 + private OutputStreamWriter charOut;
141.72 +
141.73 + /**
141.74 + * requireNonNull is explicitly declared here so as not to create an extra
141.75 + * dependency on java.util.Objects.requireNonNull. PrintStream is loaded
141.76 + * early during system initialization.
141.77 + */
141.78 + private static <T> T requireNonNull(T obj, String message) {
141.79 + if (obj == null)
141.80 + throw new NullPointerException(message);
141.81 + return obj;
141.82 + }
141.83 +
141.84 + /* Private constructors */
141.85 + private PrintStream(boolean autoFlush, OutputStream out) {
141.86 + super(out);
141.87 + this.autoFlush = autoFlush;
141.88 + this.charOut = new OutputStreamWriter(this);
141.89 + this.textOut = new BufferedWriter(charOut);
141.90 + }
141.91 +
141.92 + static final class Formatter {
141.93 + }
141.94 +
141.95 + static Charset toCharset(String ch) throws UnsupportedEncodingException {
141.96 + if (!"UTF-8".equals(ch)) {
141.97 + throw new UnsupportedEncodingException();
141.98 + }
141.99 + return null;
141.100 + }
141.101 +
141.102 + private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
141.103 + super(out);
141.104 + this.autoFlush = autoFlush;
141.105 + this.charOut = new OutputStreamWriter(this);
141.106 + this.textOut = new BufferedWriter(charOut);
141.107 + }
141.108 +
141.109 + /* Variant of the private constructor so that the given charset name
141.110 + * can be verified before evaluating the OutputStream argument. Used
141.111 + * by constructors creating a FileOutputStream that also take a
141.112 + * charset name.
141.113 + */
141.114 + private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
141.115 + throws UnsupportedEncodingException
141.116 + {
141.117 + this(autoFlush, out, charset);
141.118 + }
141.119 +
141.120 + /**
141.121 + * Creates a new print stream. This stream will not flush automatically.
141.122 + *
141.123 + * @param out The output stream to which values and objects will be
141.124 + * printed
141.125 + *
141.126 + * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream)
141.127 + */
141.128 + public PrintStream(OutputStream out) {
141.129 + this(out, false);
141.130 + }
141.131 +
141.132 + /**
141.133 + * Creates a new print stream.
141.134 + *
141.135 + * @param out The output stream to which values and objects will be
141.136 + * printed
141.137 + * @param autoFlush A boolean; if true, the output buffer will be flushed
141.138 + * whenever a byte array is written, one of the
141.139 + * <code>println</code> methods is invoked, or a newline
141.140 + * character or byte (<code>'\n'</code>) is written
141.141 + *
141.142 + * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
141.143 + */
141.144 + public PrintStream(OutputStream out, boolean autoFlush) {
141.145 + this(autoFlush, requireNonNull(out, "Null output stream"));
141.146 + }
141.147 +
141.148 + /**
141.149 + * Creates a new print stream.
141.150 + *
141.151 + * @param out The output stream to which values and objects will be
141.152 + * printed
141.153 + * @param autoFlush A boolean; if true, the output buffer will be flushed
141.154 + * whenever a byte array is written, one of the
141.155 + * <code>println</code> methods is invoked, or a newline
141.156 + * character or byte (<code>'\n'</code>) is written
141.157 + * @param encoding The name of a supported
141.158 + * <a href="../lang/package-summary.html#charenc">
141.159 + * character encoding</a>
141.160 + *
141.161 + * @throws UnsupportedEncodingException
141.162 + * If the named encoding is not supported
141.163 + *
141.164 + * @since 1.4
141.165 + */
141.166 + public PrintStream(OutputStream out, boolean autoFlush, String encoding)
141.167 + throws UnsupportedEncodingException
141.168 + {
141.169 + this(autoFlush,
141.170 + requireNonNull(out, "Null output stream"),
141.171 + toCharset(encoding));
141.172 + }
141.173 +
141.174 + /**
141.175 + * Creates a new print stream, without automatic line flushing, with the
141.176 + * specified file name. This convenience constructor creates
141.177 + * the necessary intermediate {@link java.io.OutputStreamWriter
141.178 + * OutputStreamWriter}, which will encode characters using the
141.179 + * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
141.180 + * for this instance of the Java virtual machine.
141.181 + *
141.182 + * @param fileName
141.183 + * The name of the file to use as the destination of this print
141.184 + * stream. If the file exists, then it will be truncated to
141.185 + * zero size; otherwise, a new file will be created. The output
141.186 + * will be written to the file and is buffered.
141.187 + *
141.188 + * @throws FileNotFoundException
141.189 + * If the given file object does not denote an existing, writable
141.190 + * regular file and a new regular file of that name cannot be
141.191 + * created, or if some other error occurs while opening or
141.192 + * creating the file
141.193 + *
141.194 + * @throws SecurityException
141.195 + * If a security manager is present and {@link
141.196 + * SecurityManager#checkWrite checkWrite(fileName)} denies write
141.197 + * access to the file
141.198 + *
141.199 + * @since 1.5
141.200 + */
141.201 + public PrintStream(String fileName) throws FileNotFoundException {
141.202 + super(null);
141.203 + throw new FileNotFoundException();
141.204 + }
141.205 +
141.206 + /**
141.207 + * Creates a new print stream, without automatic line flushing, with the
141.208 + * specified file name and charset. This convenience constructor creates
141.209 + * the necessary intermediate {@link java.io.OutputStreamWriter
141.210 + * OutputStreamWriter}, which will encode characters using the provided
141.211 + * charset.
141.212 + *
141.213 + * @param fileName
141.214 + * The name of the file to use as the destination of this print
141.215 + * stream. If the file exists, then it will be truncated to
141.216 + * zero size; otherwise, a new file will be created. The output
141.217 + * will be written to the file and is buffered.
141.218 + *
141.219 + * @param csn
141.220 + * The name of a supported {@linkplain java.nio.charset.Charset
141.221 + * charset}
141.222 + *
141.223 + * @throws FileNotFoundException
141.224 + * If the given file object does not denote an existing, writable
141.225 + * regular file and a new regular file of that name cannot be
141.226 + * created, or if some other error occurs while opening or
141.227 + * creating the file
141.228 + *
141.229 + * @throws SecurityException
141.230 + * If a security manager is present and {@link
141.231 + * SecurityManager#checkWrite checkWrite(fileName)} denies write
141.232 + * access to the file
141.233 + *
141.234 + * @throws UnsupportedEncodingException
141.235 + * If the named charset is not supported
141.236 + *
141.237 + * @since 1.5
141.238 + */
141.239 + public PrintStream(String fileName, String csn)
141.240 + throws FileNotFoundException, UnsupportedEncodingException
141.241 + {
141.242 + super(null);
141.243 + throw new FileNotFoundException();
141.244 + }
141.245 +
141.246 + /**
141.247 + * Creates a new print stream, without automatic line flushing, with the
141.248 + * specified file. This convenience constructor creates the necessary
141.249 + * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
141.250 + * which will encode characters using the {@linkplain
141.251 + * java.nio.charset.Charset#defaultCharset() default charset} for this
141.252 + * instance of the Java virtual machine.
141.253 + *
141.254 + * @param file
141.255 + * The file to use as the destination of this print stream. If the
141.256 + * file exists, then it will be truncated to zero size; otherwise,
141.257 + * a new file will be created. The output will be written to the
141.258 + * file and is buffered.
141.259 + *
141.260 + * @throws FileNotFoundException
141.261 + * If the given file object does not denote an existing, writable
141.262 + * regular file and a new regular file of that name cannot be
141.263 + * created, or if some other error occurs while opening or
141.264 + * creating the file
141.265 + *
141.266 + * @throws SecurityException
141.267 + * If a security manager is present and {@link
141.268 + * SecurityManager#checkWrite checkWrite(file.getPath())}
141.269 + * denies write access to the file
141.270 + *
141.271 + * @since 1.5
141.272 + */
141.273 + public PrintStream(File file) throws FileNotFoundException {
141.274 + super(null);
141.275 + throw new FileNotFoundException();
141.276 + }
141.277 +
141.278 + /**
141.279 + * Creates a new print stream, without automatic line flushing, with the
141.280 + * specified file and charset. This convenience constructor creates
141.281 + * the necessary intermediate {@link java.io.OutputStreamWriter
141.282 + * OutputStreamWriter}, which will encode characters using the provided
141.283 + * charset.
141.284 + *
141.285 + * @param file
141.286 + * The file to use as the destination of this print stream. If the
141.287 + * file exists, then it will be truncated to zero size; otherwise,
141.288 + * a new file will be created. The output will be written to the
141.289 + * file and is buffered.
141.290 + *
141.291 + * @param csn
141.292 + * The name of a supported {@linkplain java.nio.charset.Charset
141.293 + * charset}
141.294 + *
141.295 + * @throws FileNotFoundException
141.296 + * If the given file object does not denote an existing, writable
141.297 + * regular file and a new regular file of that name cannot be
141.298 + * created, or if some other error occurs while opening or
141.299 + * creating the file
141.300 + *
141.301 + * @throws SecurityException
141.302 + * If a security manager is presentand {@link
141.303 + * SecurityManager#checkWrite checkWrite(file.getPath())}
141.304 + * denies write access to the file
141.305 + *
141.306 + * @throws UnsupportedEncodingException
141.307 + * If the named charset is not supported
141.308 + *
141.309 + * @since 1.5
141.310 + */
141.311 + public PrintStream(File file, String csn)
141.312 + throws FileNotFoundException, UnsupportedEncodingException
141.313 + {
141.314 + super(null);
141.315 + throw new FileNotFoundException();
141.316 + }
141.317 +
141.318 + /** Check to make sure that the stream has not been closed */
141.319 + private void ensureOpen() throws IOException {
141.320 + if (out == null)
141.321 + throw new IOException("Stream closed");
141.322 + }
141.323 +
141.324 + /**
141.325 + * Flushes the stream. This is done by writing any buffered output bytes to
141.326 + * the underlying output stream and then flushing that stream.
141.327 + *
141.328 + * @see java.io.OutputStream#flush()
141.329 + */
141.330 + public void flush() {
141.331 + synchronized (this) {
141.332 + try {
141.333 + ensureOpen();
141.334 + out.flush();
141.335 + }
141.336 + catch (IOException x) {
141.337 + trouble = true;
141.338 + }
141.339 + }
141.340 + }
141.341 +
141.342 + private boolean closing = false; /* To avoid recursive closing */
141.343 +
141.344 + /**
141.345 + * Closes the stream. This is done by flushing the stream and then closing
141.346 + * the underlying output stream.
141.347 + *
141.348 + * @see java.io.OutputStream#close()
141.349 + */
141.350 + public void close() {
141.351 + synchronized (this) {
141.352 + if (! closing) {
141.353 + closing = true;
141.354 + try {
141.355 + textOut.close();
141.356 + out.close();
141.357 + }
141.358 + catch (IOException x) {
141.359 + trouble = true;
141.360 + }
141.361 + textOut = null;
141.362 + charOut = null;
141.363 + out = null;
141.364 + }
141.365 + }
141.366 + }
141.367 +
141.368 + /**
141.369 + * Flushes the stream and checks its error state. The internal error state
141.370 + * is set to <code>true</code> when the underlying output stream throws an
141.371 + * <code>IOException</code> other than <code>InterruptedIOException</code>,
141.372 + * and when the <code>setError</code> method is invoked. If an operation
141.373 + * on the underlying output stream throws an
141.374 + * <code>InterruptedIOException</code>, then the <code>PrintStream</code>
141.375 + * converts the exception back into an interrupt by doing:
141.376 + * <pre>
141.377 + * Thread.currentThread().interrupt();
141.378 + * </pre>
141.379 + * or the equivalent.
141.380 + *
141.381 + * @return <code>true</code> if and only if this stream has encountered an
141.382 + * <code>IOException</code> other than
141.383 + * <code>InterruptedIOException</code>, or the
141.384 + * <code>setError</code> method has been invoked
141.385 + */
141.386 + public boolean checkError() {
141.387 + if (out != null)
141.388 + flush();
141.389 + if (out instanceof java.io.PrintStream) {
141.390 + PrintStream ps = (PrintStream) out;
141.391 + return ps.checkError();
141.392 + }
141.393 + return trouble;
141.394 + }
141.395 +
141.396 + /**
141.397 + * Sets the error state of the stream to <code>true</code>.
141.398 + *
141.399 + * <p> This method will cause subsequent invocations of {@link
141.400 + * #checkError()} to return <tt>true</tt> until {@link
141.401 + * #clearError()} is invoked.
141.402 + *
141.403 + * @since JDK1.1
141.404 + */
141.405 + protected void setError() {
141.406 + trouble = true;
141.407 + }
141.408 +
141.409 + /**
141.410 + * Clears the internal error state of this stream.
141.411 + *
141.412 + * <p> This method will cause subsequent invocations of {@link
141.413 + * #checkError()} to return <tt>false</tt> until another write
141.414 + * operation fails and invokes {@link #setError()}.
141.415 + *
141.416 + * @since 1.6
141.417 + */
141.418 + protected void clearError() {
141.419 + trouble = false;
141.420 + }
141.421 +
141.422 + /*
141.423 + * Exception-catching, synchronized output operations,
141.424 + * which also implement the write() methods of OutputStream
141.425 + */
141.426 +
141.427 + /**
141.428 + * Writes the specified byte to this stream. If the byte is a newline and
141.429 + * automatic flushing is enabled then the <code>flush</code> method will be
141.430 + * invoked.
141.431 + *
141.432 + * <p> Note that the byte is written as given; to write a character that
141.433 + * will be translated according to the platform's default character
141.434 + * encoding, use the <code>print(char)</code> or <code>println(char)</code>
141.435 + * methods.
141.436 + *
141.437 + * @param b The byte to be written
141.438 + * @see #print(char)
141.439 + * @see #println(char)
141.440 + */
141.441 + public void write(int b) {
141.442 + try {
141.443 + synchronized (this) {
141.444 + ensureOpen();
141.445 + out.write(b);
141.446 + if ((b == '\n') && autoFlush)
141.447 + out.flush();
141.448 + }
141.449 + }
141.450 + catch (InterruptedIOException x) {
141.451 + Thread.currentThread().interrupt();
141.452 + }
141.453 + catch (IOException x) {
141.454 + trouble = true;
141.455 + }
141.456 + }
141.457 +
141.458 + /**
141.459 + * Writes <code>len</code> bytes from the specified byte array starting at
141.460 + * offset <code>off</code> to this stream. If automatic flushing is
141.461 + * enabled then the <code>flush</code> method will be invoked.
141.462 + *
141.463 + * <p> Note that the bytes will be written as given; to write characters
141.464 + * that will be translated according to the platform's default character
141.465 + * encoding, use the <code>print(char)</code> or <code>println(char)</code>
141.466 + * methods.
141.467 + *
141.468 + * @param buf A byte array
141.469 + * @param off Offset from which to start taking bytes
141.470 + * @param len Number of bytes to write
141.471 + */
141.472 + public void write(byte buf[], int off, int len) {
141.473 + try {
141.474 + synchronized (this) {
141.475 + ensureOpen();
141.476 + out.write(buf, off, len);
141.477 + if (autoFlush)
141.478 + out.flush();
141.479 + }
141.480 + }
141.481 + catch (InterruptedIOException x) {
141.482 + Thread.currentThread().interrupt();
141.483 + }
141.484 + catch (IOException x) {
141.485 + trouble = true;
141.486 + }
141.487 + }
141.488 +
141.489 + /*
141.490 + * The following private methods on the text- and character-output streams
141.491 + * always flush the stream buffers, so that writes to the underlying byte
141.492 + * stream occur as promptly as with the original PrintStream.
141.493 + */
141.494 +
141.495 + private void write(char buf[]) {
141.496 + try {
141.497 + synchronized (this) {
141.498 + ensureOpen();
141.499 + textOut.write(buf);
141.500 + textOut.flushBuffer();
141.501 + charOut.flushBuffer();
141.502 + if (autoFlush) {
141.503 + for (int i = 0; i < buf.length; i++)
141.504 + if (buf[i] == '\n')
141.505 + out.flush();
141.506 + }
141.507 + }
141.508 + }
141.509 + catch (InterruptedIOException x) {
141.510 + Thread.currentThread().interrupt();
141.511 + }
141.512 + catch (IOException x) {
141.513 + trouble = true;
141.514 + }
141.515 + }
141.516 +
141.517 + private void write(String s) {
141.518 + try {
141.519 + synchronized (this) {
141.520 + ensureOpen();
141.521 + textOut.write(s);
141.522 + textOut.flushBuffer();
141.523 + charOut.flushBuffer();
141.524 + if (autoFlush && (s.indexOf('\n') >= 0))
141.525 + out.flush();
141.526 + }
141.527 + }
141.528 + catch (InterruptedIOException x) {
141.529 + Thread.currentThread().interrupt();
141.530 + }
141.531 + catch (IOException x) {
141.532 + trouble = true;
141.533 + }
141.534 + }
141.535 +
141.536 + private void newLine() {
141.537 + try {
141.538 + synchronized (this) {
141.539 + ensureOpen();
141.540 + textOut.newLine();
141.541 + textOut.flushBuffer();
141.542 + charOut.flushBuffer();
141.543 + if (autoFlush)
141.544 + out.flush();
141.545 + }
141.546 + }
141.547 + catch (InterruptedIOException x) {
141.548 + Thread.currentThread().interrupt();
141.549 + }
141.550 + catch (IOException x) {
141.551 + trouble = true;
141.552 + }
141.553 + }
141.554 +
141.555 + /* Methods that do not terminate lines */
141.556 +
141.557 + /**
141.558 + * Prints a boolean value. The string produced by <code>{@link
141.559 + * java.lang.String#valueOf(boolean)}</code> is translated into bytes
141.560 + * according to the platform's default character encoding, and these bytes
141.561 + * are written in exactly the manner of the
141.562 + * <code>{@link #write(int)}</code> method.
141.563 + *
141.564 + * @param b The <code>boolean</code> to be printed
141.565 + */
141.566 + public void print(boolean b) {
141.567 + write(b ? "true" : "false");
141.568 + }
141.569 +
141.570 + /**
141.571 + * Prints a character. The character is translated into one or more bytes
141.572 + * according to the platform's default character encoding, and these bytes
141.573 + * are written in exactly the manner of the
141.574 + * <code>{@link #write(int)}</code> method.
141.575 + *
141.576 + * @param c The <code>char</code> to be printed
141.577 + */
141.578 + public void print(char c) {
141.579 + write(String.valueOf(c));
141.580 + }
141.581 +
141.582 + /**
141.583 + * Prints an integer. The string produced by <code>{@link
141.584 + * java.lang.String#valueOf(int)}</code> is translated into bytes
141.585 + * according to the platform's default character encoding, and these bytes
141.586 + * are written in exactly the manner of the
141.587 + * <code>{@link #write(int)}</code> method.
141.588 + *
141.589 + * @param i The <code>int</code> to be printed
141.590 + * @see java.lang.Integer#toString(int)
141.591 + */
141.592 + public void print(int i) {
141.593 + write(String.valueOf(i));
141.594 + }
141.595 +
141.596 + /**
141.597 + * Prints a long integer. The string produced by <code>{@link
141.598 + * java.lang.String#valueOf(long)}</code> is translated into bytes
141.599 + * according to the platform's default character encoding, and these bytes
141.600 + * are written in exactly the manner of the
141.601 + * <code>{@link #write(int)}</code> method.
141.602 + *
141.603 + * @param l The <code>long</code> to be printed
141.604 + * @see java.lang.Long#toString(long)
141.605 + */
141.606 + public void print(long l) {
141.607 + write(String.valueOf(l));
141.608 + }
141.609 +
141.610 + /**
141.611 + * Prints a floating-point number. The string produced by <code>{@link
141.612 + * java.lang.String#valueOf(float)}</code> is translated into bytes
141.613 + * according to the platform's default character encoding, and these bytes
141.614 + * are written in exactly the manner of the
141.615 + * <code>{@link #write(int)}</code> method.
141.616 + *
141.617 + * @param f The <code>float</code> to be printed
141.618 + * @see java.lang.Float#toString(float)
141.619 + */
141.620 + public void print(float f) {
141.621 + write(String.valueOf(f));
141.622 + }
141.623 +
141.624 + /**
141.625 + * Prints a double-precision floating-point number. The string produced by
141.626 + * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
141.627 + * bytes according to the platform's default character encoding, and these
141.628 + * bytes are written in exactly the manner of the <code>{@link
141.629 + * #write(int)}</code> method.
141.630 + *
141.631 + * @param d The <code>double</code> to be printed
141.632 + * @see java.lang.Double#toString(double)
141.633 + */
141.634 + public void print(double d) {
141.635 + write(String.valueOf(d));
141.636 + }
141.637 +
141.638 + /**
141.639 + * Prints an array of characters. The characters are converted into bytes
141.640 + * according to the platform's default character encoding, and these bytes
141.641 + * are written in exactly the manner of the
141.642 + * <code>{@link #write(int)}</code> method.
141.643 + *
141.644 + * @param s The array of chars to be printed
141.645 + *
141.646 + * @throws NullPointerException If <code>s</code> is <code>null</code>
141.647 + */
141.648 + public void print(char s[]) {
141.649 + write(s);
141.650 + }
141.651 +
141.652 + /**
141.653 + * Prints a string. If the argument is <code>null</code> then the string
141.654 + * <code>"null"</code> is printed. Otherwise, the string's characters are
141.655 + * converted into bytes according to the platform's default character
141.656 + * encoding, and these bytes are written in exactly the manner of the
141.657 + * <code>{@link #write(int)}</code> method.
141.658 + *
141.659 + * @param s The <code>String</code> to be printed
141.660 + */
141.661 + public void print(String s) {
141.662 + if (s == null) {
141.663 + s = "null";
141.664 + }
141.665 + write(s);
141.666 + }
141.667 +
141.668 + /**
141.669 + * Prints an object. The string produced by the <code>{@link
141.670 + * java.lang.String#valueOf(Object)}</code> method is translated into bytes
141.671 + * according to the platform's default character encoding, and these bytes
141.672 + * are written in exactly the manner of the
141.673 + * <code>{@link #write(int)}</code> method.
141.674 + *
141.675 + * @param obj The <code>Object</code> to be printed
141.676 + * @see java.lang.Object#toString()
141.677 + */
141.678 + public void print(Object obj) {
141.679 + write(String.valueOf(obj));
141.680 + }
141.681 +
141.682 +
141.683 + /* Methods that do terminate lines */
141.684 +
141.685 + /**
141.686 + * Terminates the current line by writing the line separator string. The
141.687 + * line separator string is defined by the system property
141.688 + * <code>line.separator</code>, and is not necessarily a single newline
141.689 + * character (<code>'\n'</code>).
141.690 + */
141.691 + public void println() {
141.692 + newLine();
141.693 + }
141.694 +
141.695 + /**
141.696 + * Prints a boolean and then terminate the line. This method behaves as
141.697 + * though it invokes <code>{@link #print(boolean)}</code> and then
141.698 + * <code>{@link #println()}</code>.
141.699 + *
141.700 + * @param x The <code>boolean</code> to be printed
141.701 + */
141.702 + public void println(boolean x) {
141.703 + synchronized (this) {
141.704 + print(x);
141.705 + newLine();
141.706 + }
141.707 + }
141.708 +
141.709 + /**
141.710 + * Prints a character and then terminate the line. This method behaves as
141.711 + * though it invokes <code>{@link #print(char)}</code> and then
141.712 + * <code>{@link #println()}</code>.
141.713 + *
141.714 + * @param x The <code>char</code> to be printed.
141.715 + */
141.716 + public void println(char x) {
141.717 + synchronized (this) {
141.718 + print(x);
141.719 + newLine();
141.720 + }
141.721 + }
141.722 +
141.723 + /**
141.724 + * Prints an integer and then terminate the line. This method behaves as
141.725 + * though it invokes <code>{@link #print(int)}</code> and then
141.726 + * <code>{@link #println()}</code>.
141.727 + *
141.728 + * @param x The <code>int</code> to be printed.
141.729 + */
141.730 + public void println(int x) {
141.731 + synchronized (this) {
141.732 + print(x);
141.733 + newLine();
141.734 + }
141.735 + }
141.736 +
141.737 + /**
141.738 + * Prints a long and then terminate the line. This method behaves as
141.739 + * though it invokes <code>{@link #print(long)}</code> and then
141.740 + * <code>{@link #println()}</code>.
141.741 + *
141.742 + * @param x a The <code>long</code> to be printed.
141.743 + */
141.744 + public void println(long x) {
141.745 + synchronized (this) {
141.746 + print(x);
141.747 + newLine();
141.748 + }
141.749 + }
141.750 +
141.751 + /**
141.752 + * Prints a float and then terminate the line. This method behaves as
141.753 + * though it invokes <code>{@link #print(float)}</code> and then
141.754 + * <code>{@link #println()}</code>.
141.755 + *
141.756 + * @param x The <code>float</code> to be printed.
141.757 + */
141.758 + public void println(float x) {
141.759 + synchronized (this) {
141.760 + print(x);
141.761 + newLine();
141.762 + }
141.763 + }
141.764 +
141.765 + /**
141.766 + * Prints a double and then terminate the line. This method behaves as
141.767 + * though it invokes <code>{@link #print(double)}</code> and then
141.768 + * <code>{@link #println()}</code>.
141.769 + *
141.770 + * @param x The <code>double</code> to be printed.
141.771 + */
141.772 + public void println(double x) {
141.773 + synchronized (this) {
141.774 + print(x);
141.775 + newLine();
141.776 + }
141.777 + }
141.778 +
141.779 + /**
141.780 + * Prints an array of characters and then terminate the line. This method
141.781 + * behaves as though it invokes <code>{@link #print(char[])}</code> and
141.782 + * then <code>{@link #println()}</code>.
141.783 + *
141.784 + * @param x an array of chars to print.
141.785 + */
141.786 + public void println(char x[]) {
141.787 + synchronized (this) {
141.788 + print(x);
141.789 + newLine();
141.790 + }
141.791 + }
141.792 +
141.793 + /**
141.794 + * Prints a String and then terminate the line. This method behaves as
141.795 + * though it invokes <code>{@link #print(String)}</code> and then
141.796 + * <code>{@link #println()}</code>.
141.797 + *
141.798 + * @param x The <code>String</code> to be printed.
141.799 + */
141.800 + public void println(String x) {
141.801 + synchronized (this) {
141.802 + print(x);
141.803 + newLine();
141.804 + }
141.805 + }
141.806 +
141.807 + /**
141.808 + * Prints an Object and then terminate the line. This method calls
141.809 + * at first String.valueOf(x) to get the printed object's string value,
141.810 + * then behaves as
141.811 + * though it invokes <code>{@link #print(String)}</code> and then
141.812 + * <code>{@link #println()}</code>.
141.813 + *
141.814 + * @param x The <code>Object</code> to be printed.
141.815 + */
141.816 + public void println(Object x) {
141.817 + String s = String.valueOf(x);
141.818 + synchronized (this) {
141.819 + print(s);
141.820 + newLine();
141.821 + }
141.822 + }
141.823 +
141.824 +
141.825 + /**
141.826 + * A convenience method to write a formatted string to this output stream
141.827 + * using the specified format string and arguments.
141.828 + *
141.829 + * <p> An invocation of this method of the form <tt>out.printf(format,
141.830 + * args)</tt> behaves in exactly the same way as the invocation
141.831 + *
141.832 + * <pre>
141.833 + * out.format(format, args) </pre>
141.834 + *
141.835 + * @param format
141.836 + * A format string as described in <a
141.837 + * href="../util/Formatter.html#syntax">Format string syntax</a>
141.838 + *
141.839 + * @param args
141.840 + * Arguments referenced by the format specifiers in the format
141.841 + * string. If there are more arguments than format specifiers, the
141.842 + * extra arguments are ignored. The number of arguments is
141.843 + * variable and may be zero. The maximum number of arguments is
141.844 + * limited by the maximum dimension of a Java array as defined by
141.845 + * <cite>The Java™ Virtual Machine Specification</cite>.
141.846 + * The behaviour on a
141.847 + * <tt>null</tt> argument depends on the <a
141.848 + * href="../util/Formatter.html#syntax">conversion</a>.
141.849 + *
141.850 + * @throws IllegalFormatException
141.851 + * If a format string contains an illegal syntax, a format
141.852 + * specifier that is incompatible with the given arguments,
141.853 + * insufficient arguments given the format string, or other
141.854 + * illegal conditions. For specification of all possible
141.855 + * formatting errors, see the <a
141.856 + * href="../util/Formatter.html#detail">Details</a> section of the
141.857 + * formatter class specification.
141.858 + *
141.859 + * @throws NullPointerException
141.860 + * If the <tt>format</tt> is <tt>null</tt>
141.861 + *
141.862 + * @return This output stream
141.863 + *
141.864 + * @since 1.5
141.865 + */
141.866 + public PrintStream printf(String format, Object ... args) {
141.867 + append(format).append(Arrays.toString(args));
141.868 + return this;
141.869 + }
141.870 +
141.871 + /**
141.872 + * A convenience method to write a formatted string to this output stream
141.873 + * using the specified format string and arguments.
141.874 + *
141.875 + * <p> An invocation of this method of the form <tt>out.printf(l, format,
141.876 + * args)</tt> behaves in exactly the same way as the invocation
141.877 + *
141.878 + * <pre>
141.879 + * out.format(l, format, args) </pre>
141.880 + *
141.881 + * @param l
141.882 + * The {@linkplain java.util.Locale locale} to apply during
141.883 + * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
141.884 + * is applied.
141.885 + *
141.886 + * @param format
141.887 + * A format string as described in <a
141.888 + * href="../util/Formatter.html#syntax">Format string syntax</a>
141.889 + *
141.890 + * @param args
141.891 + * Arguments referenced by the format specifiers in the format
141.892 + * string. If there are more arguments than format specifiers, the
141.893 + * extra arguments are ignored. The number of arguments is
141.894 + * variable and may be zero. The maximum number of arguments is
141.895 + * limited by the maximum dimension of a Java array as defined by
141.896 + * <cite>The Java™ Virtual Machine Specification</cite>.
141.897 + * The behaviour on a
141.898 + * <tt>null</tt> argument depends on the <a
141.899 + * href="../util/Formatter.html#syntax">conversion</a>.
141.900 + *
141.901 + * @throws IllegalFormatException
141.902 + * If a format string contains an illegal syntax, a format
141.903 + * specifier that is incompatible with the given arguments,
141.904 + * insufficient arguments given the format string, or other
141.905 + * illegal conditions. For specification of all possible
141.906 + * formatting errors, see the <a
141.907 + * href="../util/Formatter.html#detail">Details</a> section of the
141.908 + * formatter class specification.
141.909 + *
141.910 + * @throws NullPointerException
141.911 + * If the <tt>format</tt> is <tt>null</tt>
141.912 + *
141.913 + * @return This output stream
141.914 + *
141.915 + * @since 1.5
141.916 + */
141.917 +// public PrintStream printf(Locale l, String format, Object ... args) {
141.918 +// return format(l, format, args);
141.919 +// }
141.920 +
141.921 + /**
141.922 + * Writes a formatted string to this output stream using the specified
141.923 + * format string and arguments.
141.924 + *
141.925 + * <p> The locale always used is the one returned by {@link
141.926 + * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
141.927 + * previous invocations of other formatting methods on this object.
141.928 + *
141.929 + * @param format
141.930 + * A format string as described in <a
141.931 + * href="../util/Formatter.html#syntax">Format string syntax</a>
141.932 + *
141.933 + * @param args
141.934 + * Arguments referenced by the format specifiers in the format
141.935 + * string. If there are more arguments than format specifiers, the
141.936 + * extra arguments are ignored. The number of arguments is
141.937 + * variable and may be zero. The maximum number of arguments is
141.938 + * limited by the maximum dimension of a Java array as defined by
141.939 + * <cite>The Java™ Virtual Machine Specification</cite>.
141.940 + * The behaviour on a
141.941 + * <tt>null</tt> argument depends on the <a
141.942 + * href="../util/Formatter.html#syntax">conversion</a>.
141.943 + *
141.944 + * @throws IllegalFormatException
141.945 + * If a format string contains an illegal syntax, a format
141.946 + * specifier that is incompatible with the given arguments,
141.947 + * insufficient arguments given the format string, or other
141.948 + * illegal conditions. For specification of all possible
141.949 + * formatting errors, see the <a
141.950 + * href="../util/Formatter.html#detail">Details</a> section of the
141.951 + * formatter class specification.
141.952 + *
141.953 + * @throws NullPointerException
141.954 + * If the <tt>format</tt> is <tt>null</tt>
141.955 + *
141.956 + * @return This output stream
141.957 + *
141.958 + * @since 1.5
141.959 + */
141.960 +// public PrintStream format(String format, Object ... args) {
141.961 +// try {
141.962 +// synchronized (this) {
141.963 +// ensureOpen();
141.964 +// if ((formatter == null)
141.965 +// || (formatter.locale() != Locale.getDefault()))
141.966 +// formatter = new Formatter((Appendable) this);
141.967 +// formatter.format(Locale.getDefault(), format, args);
141.968 +// }
141.969 +// } catch (InterruptedIOException x) {
141.970 +// Thread.currentThread().interrupt();
141.971 +// } catch (IOException x) {
141.972 +// trouble = true;
141.973 +// }
141.974 +// return this;
141.975 +// }
141.976 +
141.977 + /**
141.978 + * Writes a formatted string to this output stream using the specified
141.979 + * format string and arguments.
141.980 + *
141.981 + * @param l
141.982 + * The {@linkplain java.util.Locale locale} to apply during
141.983 + * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
141.984 + * is applied.
141.985 + *
141.986 + * @param format
141.987 + * A format string as described in <a
141.988 + * href="../util/Formatter.html#syntax">Format string syntax</a>
141.989 + *
141.990 + * @param args
141.991 + * Arguments referenced by the format specifiers in the format
141.992 + * string. If there are more arguments than format specifiers, the
141.993 + * extra arguments are ignored. The number of arguments is
141.994 + * variable and may be zero. The maximum number of arguments is
141.995 + * limited by the maximum dimension of a Java array as defined by
141.996 + * <cite>The Java™ Virtual Machine Specification</cite>.
141.997 + * The behaviour on a
141.998 + * <tt>null</tt> argument depends on the <a
141.999 + * href="../util/Formatter.html#syntax">conversion</a>.
141.1000 + *
141.1001 + * @throws IllegalFormatException
141.1002 + * If a format string contains an illegal syntax, a format
141.1003 + * specifier that is incompatible with the given arguments,
141.1004 + * insufficient arguments given the format string, or other
141.1005 + * illegal conditions. For specification of all possible
141.1006 + * formatting errors, see the <a
141.1007 + * href="../util/Formatter.html#detail">Details</a> section of the
141.1008 + * formatter class specification.
141.1009 + *
141.1010 + * @throws NullPointerException
141.1011 + * If the <tt>format</tt> is <tt>null</tt>
141.1012 + *
141.1013 + * @return This output stream
141.1014 + *
141.1015 + * @since 1.5
141.1016 + */
141.1017 +//// public PrintStream format(Locale l, String format, Object ... args) {
141.1018 +//// try {
141.1019 +//// synchronized (this) {
141.1020 +//// ensureOpen();
141.1021 +//// if ((formatter == null)
141.1022 +//// || (formatter.locale() != l))
141.1023 +//// formatter = new Formatter(this, l);
141.1024 +//// formatter.format(l, format, args);
141.1025 +//// }
141.1026 +//// } catch (InterruptedIOException x) {
141.1027 +//// Thread.currentThread().interrupt();
141.1028 +//// } catch (IOException x) {
141.1029 +//// trouble = true;
141.1030 +//// }
141.1031 +//// return this;
141.1032 +//// }
141.1033 +
141.1034 + /**
141.1035 + * Appends the specified character sequence to this output stream.
141.1036 + *
141.1037 + * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
141.1038 + * behaves in exactly the same way as the invocation
141.1039 + *
141.1040 + * <pre>
141.1041 + * out.print(csq.toString()) </pre>
141.1042 + *
141.1043 + * <p> Depending on the specification of <tt>toString</tt> for the
141.1044 + * character sequence <tt>csq</tt>, the entire sequence may not be
141.1045 + * appended. For instance, invoking then <tt>toString</tt> method of a
141.1046 + * character buffer will return a subsequence whose content depends upon
141.1047 + * the buffer's position and limit.
141.1048 + *
141.1049 + * @param csq
141.1050 + * The character sequence to append. If <tt>csq</tt> is
141.1051 + * <tt>null</tt>, then the four characters <tt>"null"</tt> are
141.1052 + * appended to this output stream.
141.1053 + *
141.1054 + * @return This output stream
141.1055 + *
141.1056 + * @since 1.5
141.1057 + */
141.1058 + public PrintStream append(CharSequence csq) {
141.1059 + if (csq == null)
141.1060 + print("null");
141.1061 + else
141.1062 + print(csq.toString());
141.1063 + return this;
141.1064 + }
141.1065 +
141.1066 + /**
141.1067 + * Appends a subsequence of the specified character sequence to this output
141.1068 + * stream.
141.1069 + *
141.1070 + * <p> An invocation of this method of the form <tt>out.append(csq, start,
141.1071 + * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
141.1072 + * exactly the same way as the invocation
141.1073 + *
141.1074 + * <pre>
141.1075 + * out.print(csq.subSequence(start, end).toString()) </pre>
141.1076 + *
141.1077 + * @param csq
141.1078 + * The character sequence from which a subsequence will be
141.1079 + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
141.1080 + * will be appended as if <tt>csq</tt> contained the four
141.1081 + * characters <tt>"null"</tt>.
141.1082 + *
141.1083 + * @param start
141.1084 + * The index of the first character in the subsequence
141.1085 + *
141.1086 + * @param end
141.1087 + * The index of the character following the last character in the
141.1088 + * subsequence
141.1089 + *
141.1090 + * @return This output stream
141.1091 + *
141.1092 + * @throws IndexOutOfBoundsException
141.1093 + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
141.1094 + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
141.1095 + * <tt>csq.length()</tt>
141.1096 + *
141.1097 + * @since 1.5
141.1098 + */
141.1099 + public PrintStream append(CharSequence csq, int start, int end) {
141.1100 + CharSequence cs = (csq == null ? "null" : csq);
141.1101 + write(cs.subSequence(start, end).toString());
141.1102 + return this;
141.1103 + }
141.1104 +
141.1105 + /**
141.1106 + * Appends the specified character to this output stream.
141.1107 + *
141.1108 + * <p> An invocation of this method of the form <tt>out.append(c)</tt>
141.1109 + * behaves in exactly the same way as the invocation
141.1110 + *
141.1111 + * <pre>
141.1112 + * out.print(c) </pre>
141.1113 + *
141.1114 + * @param c
141.1115 + * The 16-bit character to append
141.1116 + *
141.1117 + * @return This output stream
141.1118 + *
141.1119 + * @since 1.5
141.1120 + */
141.1121 + public PrintStream append(char c) {
141.1122 + print(c);
141.1123 + return this;
141.1124 + }
141.1125 +
141.1126 +}
142.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
142.2 +++ b/rt/emul/compact/src/main/java/java/io/PrintWriter.java Wed Apr 30 15:04:10 2014 +0200
142.3 @@ -0,0 +1,1029 @@
142.4 +/*
142.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
142.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
142.7 + *
142.8 + * This code is free software; you can redistribute it and/or modify it
142.9 + * under the terms of the GNU General Public License version 2 only, as
142.10 + * published by the Free Software Foundation. Oracle designates this
142.11 + * particular file as subject to the "Classpath" exception as provided
142.12 + * by Oracle in the LICENSE file that accompanied this code.
142.13 + *
142.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
142.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
142.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
142.17 + * version 2 for more details (a copy is included in the LICENSE file that
142.18 + * accompanied this code).
142.19 + *
142.20 + * You should have received a copy of the GNU General Public License version
142.21 + * 2 along with this work; if not, write to the Free Software Foundation,
142.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
142.23 + *
142.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
142.25 + * or visit www.oracle.com if you need additional information or have any
142.26 + * questions.
142.27 + */
142.28 +
142.29 +package java.io;
142.30 +
142.31 +import java.io.PrintStream.Formatter;
142.32 +import java.nio.charset.Charset;
142.33 +import java.util.Arrays;
142.34 +
142.35 +/**
142.36 + * Prints formatted representations of objects to a text-output stream. This
142.37 + * class implements all of the <tt>print</tt> methods found in {@link
142.38 + * PrintStream}. It does not contain methods for writing raw bytes, for which
142.39 + * a program should use unencoded byte streams.
142.40 + *
142.41 + * <p> Unlike the {@link PrintStream} class, if automatic flushing is enabled
142.42 + * it will be done only when one of the <tt>println</tt>, <tt>printf</tt>, or
142.43 + * <tt>format</tt> methods is invoked, rather than whenever a newline character
142.44 + * happens to be output. These methods use the platform's own notion of line
142.45 + * separator rather than the newline character.
142.46 + *
142.47 + * <p> Methods in this class never throw I/O exceptions, although some of its
142.48 + * constructors may. The client may inquire as to whether any errors have
142.49 + * occurred by invoking {@link #checkError checkError()}.
142.50 + *
142.51 + * @author Frank Yellin
142.52 + * @author Mark Reinhold
142.53 + * @since JDK1.1
142.54 + */
142.55 +
142.56 +public class PrintWriter extends Writer {
142.57 +
142.58 + /**
142.59 + * The underlying character-output stream of this
142.60 + * <code>PrintWriter</code>.
142.61 + *
142.62 + * @since 1.2
142.63 + */
142.64 + protected Writer out;
142.65 +
142.66 + private final boolean autoFlush;
142.67 + private boolean trouble = false;
142.68 + private Formatter formatter;
142.69 +// private PrintStream psOut = null;
142.70 +
142.71 + /**
142.72 + * Line separator string. This is the value of the line.separator
142.73 + * property at the moment that the stream was created.
142.74 + */
142.75 + private final String lineSeparator;
142.76 +
142.77 + /**
142.78 + * Returns a charset object for the given charset name.
142.79 + * @throws NullPointerException is csn is null
142.80 + * @throws UnsupportedEncodingException if the charset is not supported
142.81 + */
142.82 + private static Charset toCharset(String csn)
142.83 + throws UnsupportedEncodingException
142.84 + {
142.85 + return PrintStream.toCharset(csn);
142.86 + }
142.87 +
142.88 + /**
142.89 + * Creates a new PrintWriter, without automatic line flushing.
142.90 + *
142.91 + * @param out A character-output stream
142.92 + */
142.93 + public PrintWriter (Writer out) {
142.94 + this(out, false);
142.95 + }
142.96 +
142.97 + /**
142.98 + * Creates a new PrintWriter.
142.99 + *
142.100 + * @param out A character-output stream
142.101 + * @param autoFlush A boolean; if true, the <tt>println</tt>,
142.102 + * <tt>printf</tt>, or <tt>format</tt> methods will
142.103 + * flush the output buffer
142.104 + */
142.105 + public PrintWriter(Writer out,
142.106 + boolean autoFlush) {
142.107 + super(out);
142.108 + this.out = out;
142.109 + this.autoFlush = autoFlush;
142.110 + lineSeparator = "\n";
142.111 + }
142.112 +
142.113 + /**
142.114 + * Creates a new PrintWriter, without automatic line flushing, from an
142.115 + * existing OutputStream. This convenience constructor creates the
142.116 + * necessary intermediate OutputStreamWriter, which will convert characters
142.117 + * into bytes using the default character encoding.
142.118 + *
142.119 + * @param out An output stream
142.120 + *
142.121 + * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
142.122 + */
142.123 + public PrintWriter(OutputStream out) {
142.124 + this(out, false);
142.125 + }
142.126 +
142.127 + /**
142.128 + * Creates a new PrintWriter from an existing OutputStream. This
142.129 + * convenience constructor creates the necessary intermediate
142.130 + * OutputStreamWriter, which will convert characters into bytes using the
142.131 + * default character encoding.
142.132 + *
142.133 + * @param out An output stream
142.134 + * @param autoFlush A boolean; if true, the <tt>println</tt>,
142.135 + * <tt>printf</tt>, or <tt>format</tt> methods will
142.136 + * flush the output buffer
142.137 + *
142.138 + * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
142.139 + */
142.140 + public PrintWriter(OutputStream out, boolean autoFlush) {
142.141 + this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
142.142 +
142.143 + // save print stream for error propagation
142.144 +// if (out instanceof java.io.PrintStream) {
142.145 +// psOut = (PrintStream) out;
142.146 +// }
142.147 + }
142.148 +
142.149 + /**
142.150 + * Creates a new PrintWriter, without automatic line flushing, with the
142.151 + * specified file name. This convenience constructor creates the necessary
142.152 + * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
142.153 + * which will encode characters using the {@linkplain
142.154 + * java.nio.charset.Charset#defaultCharset() default charset} for this
142.155 + * instance of the Java virtual machine.
142.156 + *
142.157 + * @param fileName
142.158 + * The name of the file to use as the destination of this writer.
142.159 + * If the file exists then it will be truncated to zero size;
142.160 + * otherwise, a new file will be created. The output will be
142.161 + * written to the file and is buffered.
142.162 + *
142.163 + * @throws FileNotFoundException
142.164 + * If the given string does not denote an existing, writable
142.165 + * regular file and a new regular file of that name cannot be
142.166 + * created, or if some other error occurs while opening or
142.167 + * creating the file
142.168 + *
142.169 + * @throws SecurityException
142.170 + * If a security manager is present and {@link
142.171 + * SecurityManager#checkWrite checkWrite(fileName)} denies write
142.172 + * access to the file
142.173 + *
142.174 + * @since 1.5
142.175 + */
142.176 + public PrintWriter(String fileName) throws FileNotFoundException {
142.177 + super();
142.178 + throw new FileNotFoundException();
142.179 + }
142.180 +
142.181 + /* Private constructor */
142.182 + private PrintWriter(Charset charset, File file)
142.183 + throws FileNotFoundException
142.184 + {
142.185 + super();
142.186 + throw new FileNotFoundException();
142.187 + }
142.188 +
142.189 + /**
142.190 + * Creates a new PrintWriter, without automatic line flushing, with the
142.191 + * specified file name and charset. This convenience constructor creates
142.192 + * the necessary intermediate {@link java.io.OutputStreamWriter
142.193 + * OutputStreamWriter}, which will encode characters using the provided
142.194 + * charset.
142.195 + *
142.196 + * @param fileName
142.197 + * The name of the file to use as the destination of this writer.
142.198 + * If the file exists then it will be truncated to zero size;
142.199 + * otherwise, a new file will be created. The output will be
142.200 + * written to the file and is buffered.
142.201 + *
142.202 + * @param csn
142.203 + * The name of a supported {@linkplain java.nio.charset.Charset
142.204 + * charset}
142.205 + *
142.206 + * @throws FileNotFoundException
142.207 + * If the given string does not denote an existing, writable
142.208 + * regular file and a new regular file of that name cannot be
142.209 + * created, or if some other error occurs while opening or
142.210 + * creating the file
142.211 + *
142.212 + * @throws SecurityException
142.213 + * If a security manager is present and {@link
142.214 + * SecurityManager#checkWrite checkWrite(fileName)} denies write
142.215 + * access to the file
142.216 + *
142.217 + * @throws UnsupportedEncodingException
142.218 + * If the named charset is not supported
142.219 + *
142.220 + * @since 1.5
142.221 + */
142.222 + public PrintWriter(String fileName, String csn)
142.223 + throws FileNotFoundException, UnsupportedEncodingException
142.224 + {
142.225 + this(toCharset(csn), new File(fileName));
142.226 + }
142.227 +
142.228 + /**
142.229 + * Creates a new PrintWriter, without automatic line flushing, with the
142.230 + * specified file. This convenience constructor creates the necessary
142.231 + * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
142.232 + * which will encode characters using the {@linkplain
142.233 + * java.nio.charset.Charset#defaultCharset() default charset} for this
142.234 + * instance of the Java virtual machine.
142.235 + *
142.236 + * @param file
142.237 + * The file to use as the destination of this writer. If the file
142.238 + * exists then it will be truncated to zero size; otherwise, a new
142.239 + * file will be created. The output will be written to the file
142.240 + * and is buffered.
142.241 + *
142.242 + * @throws FileNotFoundException
142.243 + * If the given file object does not denote an existing, writable
142.244 + * regular file and a new regular file of that name cannot be
142.245 + * created, or if some other error occurs while opening or
142.246 + * creating the file
142.247 + *
142.248 + * @throws SecurityException
142.249 + * If a security manager is present and {@link
142.250 + * SecurityManager#checkWrite checkWrite(file.getPath())}
142.251 + * denies write access to the file
142.252 + *
142.253 + * @since 1.5
142.254 + */
142.255 + public PrintWriter(File file) throws FileNotFoundException {
142.256 + super();
142.257 + throw new FileNotFoundException();
142.258 + }
142.259 +
142.260 + /**
142.261 + * Creates a new PrintWriter, without automatic line flushing, with the
142.262 + * specified file and charset. This convenience constructor creates the
142.263 + * necessary intermediate {@link java.io.OutputStreamWriter
142.264 + * OutputStreamWriter}, which will encode characters using the provided
142.265 + * charset.
142.266 + *
142.267 + * @param file
142.268 + * The file to use as the destination of this writer. If the file
142.269 + * exists then it will be truncated to zero size; otherwise, a new
142.270 + * file will be created. The output will be written to the file
142.271 + * and is buffered.
142.272 + *
142.273 + * @param csn
142.274 + * The name of a supported {@linkplain java.nio.charset.Charset
142.275 + * charset}
142.276 + *
142.277 + * @throws FileNotFoundException
142.278 + * If the given file object does not denote an existing, writable
142.279 + * regular file and a new regular file of that name cannot be
142.280 + * created, or if some other error occurs while opening or
142.281 + * creating the file
142.282 + *
142.283 + * @throws SecurityException
142.284 + * If a security manager is present and {@link
142.285 + * SecurityManager#checkWrite checkWrite(file.getPath())}
142.286 + * denies write access to the file
142.287 + *
142.288 + * @throws UnsupportedEncodingException
142.289 + * If the named charset is not supported
142.290 + *
142.291 + * @since 1.5
142.292 + */
142.293 + public PrintWriter(File file, String csn)
142.294 + throws FileNotFoundException, UnsupportedEncodingException
142.295 + {
142.296 + this(toCharset(csn), file);
142.297 + }
142.298 +
142.299 + /** Checks to make sure that the stream has not been closed */
142.300 + private void ensureOpen() throws IOException {
142.301 + if (out == null)
142.302 + throw new IOException("Stream closed");
142.303 + }
142.304 +
142.305 + /**
142.306 + * Flushes the stream.
142.307 + * @see #checkError()
142.308 + */
142.309 + public void flush() {
142.310 + try {
142.311 + synchronized (lock) {
142.312 + ensureOpen();
142.313 + out.flush();
142.314 + }
142.315 + }
142.316 + catch (IOException x) {
142.317 + trouble = true;
142.318 + }
142.319 + }
142.320 +
142.321 + /**
142.322 + * Closes the stream and releases any system resources associated
142.323 + * with it. Closing a previously closed stream has no effect.
142.324 + *
142.325 + * @see #checkError()
142.326 + */
142.327 + public void close() {
142.328 + try {
142.329 + synchronized (lock) {
142.330 + if (out == null)
142.331 + return;
142.332 + out.close();
142.333 + out = null;
142.334 + }
142.335 + }
142.336 + catch (IOException x) {
142.337 + trouble = true;
142.338 + }
142.339 + }
142.340 +
142.341 + /**
142.342 + * Flushes the stream if it's not closed and checks its error state.
142.343 + *
142.344 + * @return <code>true</code> if the print stream has encountered an error,
142.345 + * either on the underlying output stream or during a format
142.346 + * conversion.
142.347 + */
142.348 + public boolean checkError() {
142.349 + if (out != null) {
142.350 + flush();
142.351 + }
142.352 + if (out instanceof java.io.PrintWriter) {
142.353 + PrintWriter pw = (PrintWriter) out;
142.354 + return pw.checkError();
142.355 + } else
142.356 +// if (psOut != null) {
142.357 +// return psOut.checkError();
142.358 +// }
142.359 + return trouble;
142.360 + }
142.361 +
142.362 + /**
142.363 + * Indicates that an error has occurred.
142.364 + *
142.365 + * <p> This method will cause subsequent invocations of {@link
142.366 + * #checkError()} to return <tt>true</tt> until {@link
142.367 + * #clearError()} is invoked.
142.368 + */
142.369 + protected void setError() {
142.370 + trouble = true;
142.371 + }
142.372 +
142.373 + /**
142.374 + * Clears the error state of this stream.
142.375 + *
142.376 + * <p> This method will cause subsequent invocations of {@link
142.377 + * #checkError()} to return <tt>false</tt> until another write
142.378 + * operation fails and invokes {@link #setError()}.
142.379 + *
142.380 + * @since 1.6
142.381 + */
142.382 + protected void clearError() {
142.383 + trouble = false;
142.384 + }
142.385 +
142.386 + /*
142.387 + * Exception-catching, synchronized output operations,
142.388 + * which also implement the write() methods of Writer
142.389 + */
142.390 +
142.391 + /**
142.392 + * Writes a single character.
142.393 + * @param c int specifying a character to be written.
142.394 + */
142.395 + public void write(int c) {
142.396 + try {
142.397 + synchronized (lock) {
142.398 + ensureOpen();
142.399 + out.write(c);
142.400 + }
142.401 + }
142.402 + catch (InterruptedIOException x) {
142.403 + Thread.currentThread().interrupt();
142.404 + }
142.405 + catch (IOException x) {
142.406 + trouble = true;
142.407 + }
142.408 + }
142.409 +
142.410 + /**
142.411 + * Writes A Portion of an array of characters.
142.412 + * @param buf Array of characters
142.413 + * @param off Offset from which to start writing characters
142.414 + * @param len Number of characters to write
142.415 + */
142.416 + public void write(char buf[], int off, int len) {
142.417 + try {
142.418 + synchronized (lock) {
142.419 + ensureOpen();
142.420 + out.write(buf, off, len);
142.421 + }
142.422 + }
142.423 + catch (InterruptedIOException x) {
142.424 + Thread.currentThread().interrupt();
142.425 + }
142.426 + catch (IOException x) {
142.427 + trouble = true;
142.428 + }
142.429 + }
142.430 +
142.431 + /**
142.432 + * Writes an array of characters. This method cannot be inherited from the
142.433 + * Writer class because it must suppress I/O exceptions.
142.434 + * @param buf Array of characters to be written
142.435 + */
142.436 + public void write(char buf[]) {
142.437 + write(buf, 0, buf.length);
142.438 + }
142.439 +
142.440 + /**
142.441 + * Writes a portion of a string.
142.442 + * @param s A String
142.443 + * @param off Offset from which to start writing characters
142.444 + * @param len Number of characters to write
142.445 + */
142.446 + public void write(String s, int off, int len) {
142.447 + try {
142.448 + synchronized (lock) {
142.449 + ensureOpen();
142.450 + out.write(s, off, len);
142.451 + }
142.452 + }
142.453 + catch (InterruptedIOException x) {
142.454 + Thread.currentThread().interrupt();
142.455 + }
142.456 + catch (IOException x) {
142.457 + trouble = true;
142.458 + }
142.459 + }
142.460 +
142.461 + /**
142.462 + * Writes a string. This method cannot be inherited from the Writer class
142.463 + * because it must suppress I/O exceptions.
142.464 + * @param s String to be written
142.465 + */
142.466 + public void write(String s) {
142.467 + write(s, 0, s.length());
142.468 + }
142.469 +
142.470 + private void newLine() {
142.471 + try {
142.472 + synchronized (lock) {
142.473 + ensureOpen();
142.474 + out.write(lineSeparator);
142.475 + if (autoFlush)
142.476 + out.flush();
142.477 + }
142.478 + }
142.479 + catch (InterruptedIOException x) {
142.480 + Thread.currentThread().interrupt();
142.481 + }
142.482 + catch (IOException x) {
142.483 + trouble = true;
142.484 + }
142.485 + }
142.486 +
142.487 + /* Methods that do not terminate lines */
142.488 +
142.489 + /**
142.490 + * Prints a boolean value. The string produced by <code>{@link
142.491 + * java.lang.String#valueOf(boolean)}</code> is translated into bytes
142.492 + * according to the platform's default character encoding, and these bytes
142.493 + * are written in exactly the manner of the <code>{@link
142.494 + * #write(int)}</code> method.
142.495 + *
142.496 + * @param b The <code>boolean</code> to be printed
142.497 + */
142.498 + public void print(boolean b) {
142.499 + write(b ? "true" : "false");
142.500 + }
142.501 +
142.502 + /**
142.503 + * Prints a character. The character is translated into one or more bytes
142.504 + * according to the platform's default character encoding, and these bytes
142.505 + * are written in exactly the manner of the <code>{@link
142.506 + * #write(int)}</code> method.
142.507 + *
142.508 + * @param c The <code>char</code> to be printed
142.509 + */
142.510 + public void print(char c) {
142.511 + write(c);
142.512 + }
142.513 +
142.514 + /**
142.515 + * Prints an integer. The string produced by <code>{@link
142.516 + * java.lang.String#valueOf(int)}</code> is translated into bytes according
142.517 + * to the platform's default character encoding, and these bytes are
142.518 + * written in exactly the manner of the <code>{@link #write(int)}</code>
142.519 + * method.
142.520 + *
142.521 + * @param i The <code>int</code> to be printed
142.522 + * @see java.lang.Integer#toString(int)
142.523 + */
142.524 + public void print(int i) {
142.525 + write(String.valueOf(i));
142.526 + }
142.527 +
142.528 + /**
142.529 + * Prints a long integer. The string produced by <code>{@link
142.530 + * java.lang.String#valueOf(long)}</code> is translated into bytes
142.531 + * according to the platform's default character encoding, and these bytes
142.532 + * are written in exactly the manner of the <code>{@link #write(int)}</code>
142.533 + * method.
142.534 + *
142.535 + * @param l The <code>long</code> to be printed
142.536 + * @see java.lang.Long#toString(long)
142.537 + */
142.538 + public void print(long l) {
142.539 + write(String.valueOf(l));
142.540 + }
142.541 +
142.542 + /**
142.543 + * Prints a floating-point number. The string produced by <code>{@link
142.544 + * java.lang.String#valueOf(float)}</code> is translated into bytes
142.545 + * according to the platform's default character encoding, and these bytes
142.546 + * are written in exactly the manner of the <code>{@link #write(int)}</code>
142.547 + * method.
142.548 + *
142.549 + * @param f The <code>float</code> to be printed
142.550 + * @see java.lang.Float#toString(float)
142.551 + */
142.552 + public void print(float f) {
142.553 + write(String.valueOf(f));
142.554 + }
142.555 +
142.556 + /**
142.557 + * Prints a double-precision floating-point number. The string produced by
142.558 + * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
142.559 + * bytes according to the platform's default character encoding, and these
142.560 + * bytes are written in exactly the manner of the <code>{@link
142.561 + * #write(int)}</code> method.
142.562 + *
142.563 + * @param d The <code>double</code> to be printed
142.564 + * @see java.lang.Double#toString(double)
142.565 + */
142.566 + public void print(double d) {
142.567 + write(String.valueOf(d));
142.568 + }
142.569 +
142.570 + /**
142.571 + * Prints an array of characters. The characters are converted into bytes
142.572 + * according to the platform's default character encoding, and these bytes
142.573 + * are written in exactly the manner of the <code>{@link #write(int)}</code>
142.574 + * method.
142.575 + *
142.576 + * @param s The array of chars to be printed
142.577 + *
142.578 + * @throws NullPointerException If <code>s</code> is <code>null</code>
142.579 + */
142.580 + public void print(char s[]) {
142.581 + write(s);
142.582 + }
142.583 +
142.584 + /**
142.585 + * Prints a string. If the argument is <code>null</code> then the string
142.586 + * <code>"null"</code> is printed. Otherwise, the string's characters are
142.587 + * converted into bytes according to the platform's default character
142.588 + * encoding, and these bytes are written in exactly the manner of the
142.589 + * <code>{@link #write(int)}</code> method.
142.590 + *
142.591 + * @param s The <code>String</code> to be printed
142.592 + */
142.593 + public void print(String s) {
142.594 + if (s == null) {
142.595 + s = "null";
142.596 + }
142.597 + write(s);
142.598 + }
142.599 +
142.600 + /**
142.601 + * Prints an object. The string produced by the <code>{@link
142.602 + * java.lang.String#valueOf(Object)}</code> method is translated into bytes
142.603 + * according to the platform's default character encoding, and these bytes
142.604 + * are written in exactly the manner of the <code>{@link #write(int)}</code>
142.605 + * method.
142.606 + *
142.607 + * @param obj The <code>Object</code> to be printed
142.608 + * @see java.lang.Object#toString()
142.609 + */
142.610 + public void print(Object obj) {
142.611 + write(String.valueOf(obj));
142.612 + }
142.613 +
142.614 + /* Methods that do terminate lines */
142.615 +
142.616 + /**
142.617 + * Terminates the current line by writing the line separator string. The
142.618 + * line separator string is defined by the system property
142.619 + * <code>line.separator</code>, and is not necessarily a single newline
142.620 + * character (<code>'\n'</code>).
142.621 + */
142.622 + public void println() {
142.623 + newLine();
142.624 + }
142.625 +
142.626 + /**
142.627 + * Prints a boolean value and then terminates the line. This method behaves
142.628 + * as though it invokes <code>{@link #print(boolean)}</code> and then
142.629 + * <code>{@link #println()}</code>.
142.630 + *
142.631 + * @param x the <code>boolean</code> value to be printed
142.632 + */
142.633 + public void println(boolean x) {
142.634 + synchronized (lock) {
142.635 + print(x);
142.636 + println();
142.637 + }
142.638 + }
142.639 +
142.640 + /**
142.641 + * Prints a character and then terminates the line. This method behaves as
142.642 + * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
142.643 + * #println()}</code>.
142.644 + *
142.645 + * @param x the <code>char</code> value to be printed
142.646 + */
142.647 + public void println(char x) {
142.648 + synchronized (lock) {
142.649 + print(x);
142.650 + println();
142.651 + }
142.652 + }
142.653 +
142.654 + /**
142.655 + * Prints an integer and then terminates the line. This method behaves as
142.656 + * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
142.657 + * #println()}</code>.
142.658 + *
142.659 + * @param x the <code>int</code> value to be printed
142.660 + */
142.661 + public void println(int x) {
142.662 + synchronized (lock) {
142.663 + print(x);
142.664 + println();
142.665 + }
142.666 + }
142.667 +
142.668 + /**
142.669 + * Prints a long integer and then terminates the line. This method behaves
142.670 + * as though it invokes <code>{@link #print(long)}</code> and then
142.671 + * <code>{@link #println()}</code>.
142.672 + *
142.673 + * @param x the <code>long</code> value to be printed
142.674 + */
142.675 + public void println(long x) {
142.676 + synchronized (lock) {
142.677 + print(x);
142.678 + println();
142.679 + }
142.680 + }
142.681 +
142.682 + /**
142.683 + * Prints a floating-point number and then terminates the line. This method
142.684 + * behaves as though it invokes <code>{@link #print(float)}</code> and then
142.685 + * <code>{@link #println()}</code>.
142.686 + *
142.687 + * @param x the <code>float</code> value to be printed
142.688 + */
142.689 + public void println(float x) {
142.690 + synchronized (lock) {
142.691 + print(x);
142.692 + println();
142.693 + }
142.694 + }
142.695 +
142.696 + /**
142.697 + * Prints a double-precision floating-point number and then terminates the
142.698 + * line. This method behaves as though it invokes <code>{@link
142.699 + * #print(double)}</code> and then <code>{@link #println()}</code>.
142.700 + *
142.701 + * @param x the <code>double</code> value to be printed
142.702 + */
142.703 + public void println(double x) {
142.704 + synchronized (lock) {
142.705 + print(x);
142.706 + println();
142.707 + }
142.708 + }
142.709 +
142.710 + /**
142.711 + * Prints an array of characters and then terminates the line. This method
142.712 + * behaves as though it invokes <code>{@link #print(char[])}</code> and then
142.713 + * <code>{@link #println()}</code>.
142.714 + *
142.715 + * @param x the array of <code>char</code> values to be printed
142.716 + */
142.717 + public void println(char x[]) {
142.718 + synchronized (lock) {
142.719 + print(x);
142.720 + println();
142.721 + }
142.722 + }
142.723 +
142.724 + /**
142.725 + * Prints a String and then terminates the line. This method behaves as
142.726 + * though it invokes <code>{@link #print(String)}</code> and then
142.727 + * <code>{@link #println()}</code>.
142.728 + *
142.729 + * @param x the <code>String</code> value to be printed
142.730 + */
142.731 + public void println(String x) {
142.732 + synchronized (lock) {
142.733 + print(x);
142.734 + println();
142.735 + }
142.736 + }
142.737 +
142.738 + /**
142.739 + * Prints an Object and then terminates the line. This method calls
142.740 + * at first String.valueOf(x) to get the printed object's string value,
142.741 + * then behaves as
142.742 + * though it invokes <code>{@link #print(String)}</code> and then
142.743 + * <code>{@link #println()}</code>.
142.744 + *
142.745 + * @param x The <code>Object</code> to be printed.
142.746 + */
142.747 + public void println(Object x) {
142.748 + String s = String.valueOf(x);
142.749 + synchronized (lock) {
142.750 + print(s);
142.751 + println();
142.752 + }
142.753 + }
142.754 +
142.755 + /**
142.756 + * A convenience method to write a formatted string to this writer using
142.757 + * the specified format string and arguments. If automatic flushing is
142.758 + * enabled, calls to this method will flush the output buffer.
142.759 + *
142.760 + * <p> An invocation of this method of the form <tt>out.printf(format,
142.761 + * args)</tt> behaves in exactly the same way as the invocation
142.762 + *
142.763 + * <pre>
142.764 + * out.format(format, args) </pre>
142.765 + *
142.766 + * @param format
142.767 + * A format string as described in <a
142.768 + * href="../util/Formatter.html#syntax">Format string syntax</a>.
142.769 + *
142.770 + * @param args
142.771 + * Arguments referenced by the format specifiers in the format
142.772 + * string. If there are more arguments than format specifiers, the
142.773 + * extra arguments are ignored. The number of arguments is
142.774 + * variable and may be zero. The maximum number of arguments is
142.775 + * limited by the maximum dimension of a Java array as defined by
142.776 + * <cite>The Java™ Virtual Machine Specification</cite>.
142.777 + * The behaviour on a
142.778 + * <tt>null</tt> argument depends on the <a
142.779 + * href="../util/Formatter.html#syntax">conversion</a>.
142.780 + *
142.781 + * @throws IllegalFormatException
142.782 + * If a format string contains an illegal syntax, a format
142.783 + * specifier that is incompatible with the given arguments,
142.784 + * insufficient arguments given the format string, or other
142.785 + * illegal conditions. For specification of all possible
142.786 + * formatting errors, see the <a
142.787 + * href="../util/Formatter.html#detail">Details</a> section of the
142.788 + * formatter class specification.
142.789 + *
142.790 + * @throws NullPointerException
142.791 + * If the <tt>format</tt> is <tt>null</tt>
142.792 + *
142.793 + * @return This writer
142.794 + *
142.795 + * @since 1.5
142.796 + */
142.797 + public PrintWriter printf(String format, Object ... args) {
142.798 + return format(format, args);
142.799 + }
142.800 +
142.801 + /**
142.802 + * A convenience method to write a formatted string to this writer using
142.803 + * the specified format string and arguments. If automatic flushing is
142.804 + * enabled, calls to this method will flush the output buffer.
142.805 + *
142.806 + * <p> An invocation of this method of the form <tt>out.printf(l, format,
142.807 + * args)</tt> behaves in exactly the same way as the invocation
142.808 + *
142.809 + * <pre>
142.810 + * out.format(l, format, args) </pre>
142.811 + *
142.812 + * @param l
142.813 + * The {@linkplain java.util.Locale locale} to apply during
142.814 + * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
142.815 + * is applied.
142.816 + *
142.817 + * @param format
142.818 + * A format string as described in <a
142.819 + * href="../util/Formatter.html#syntax">Format string syntax</a>.
142.820 + *
142.821 + * @param args
142.822 + * Arguments referenced by the format specifiers in the format
142.823 + * string. If there are more arguments than format specifiers, the
142.824 + * extra arguments are ignored. The number of arguments is
142.825 + * variable and may be zero. The maximum number of arguments is
142.826 + * limited by the maximum dimension of a Java array as defined by
142.827 + * <cite>The Java™ Virtual Machine Specification</cite>.
142.828 + * The behaviour on a
142.829 + * <tt>null</tt> argument depends on the <a
142.830 + * href="../util/Formatter.html#syntax">conversion</a>.
142.831 + *
142.832 + * @throws IllegalFormatException
142.833 + * If a format string contains an illegal syntax, a format
142.834 + * specifier that is incompatible with the given arguments,
142.835 + * insufficient arguments given the format string, or other
142.836 + * illegal conditions. For specification of all possible
142.837 + * formatting errors, see the <a
142.838 + * href="../util/Formatter.html#detail">Details</a> section of the
142.839 + * formatter class specification.
142.840 + *
142.841 + * @throws NullPointerException
142.842 + * If the <tt>format</tt> is <tt>null</tt>
142.843 + *
142.844 + * @return This writer
142.845 + *
142.846 + * @since 1.5
142.847 + */
142.848 +// public PrintWriter printf(Locale l, String format, Object ... args) {
142.849 +// return format(l, format, args);
142.850 +// }
142.851 +
142.852 + /**
142.853 + * Writes a formatted string to this writer using the specified format
142.854 + * string and arguments. If automatic flushing is enabled, calls to this
142.855 + * method will flush the output buffer.
142.856 + *
142.857 + * <p> The locale always used is the one returned by {@link
142.858 + * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
142.859 + * previous invocations of other formatting methods on this object.
142.860 + *
142.861 + * @param format
142.862 + * A format string as described in <a
142.863 + * href="../util/Formatter.html#syntax">Format string syntax</a>.
142.864 + *
142.865 + * @param args
142.866 + * Arguments referenced by the format specifiers in the format
142.867 + * string. If there are more arguments than format specifiers, the
142.868 + * extra arguments are ignored. The number of arguments is
142.869 + * variable and may be zero. The maximum number of arguments is
142.870 + * limited by the maximum dimension of a Java array as defined by
142.871 + * <cite>The Java™ Virtual Machine Specification</cite>.
142.872 + * The behaviour on a
142.873 + * <tt>null</tt> argument depends on the <a
142.874 + * href="../util/Formatter.html#syntax">conversion</a>.
142.875 + *
142.876 + * @throws IllegalFormatException
142.877 + * If a format string contains an illegal syntax, a format
142.878 + * specifier that is incompatible with the given arguments,
142.879 + * insufficient arguments given the format string, or other
142.880 + * illegal conditions. For specification of all possible
142.881 + * formatting errors, see the <a
142.882 + * href="../util/Formatter.html#detail">Details</a> section of the
142.883 + * Formatter class specification.
142.884 + *
142.885 + * @throws NullPointerException
142.886 + * If the <tt>format</tt> is <tt>null</tt>
142.887 + *
142.888 + * @return This writer
142.889 + *
142.890 + * @since 1.5
142.891 + */
142.892 + public PrintWriter format(String format, Object ... args) {
142.893 + append(format).append(Arrays.toString(args));
142.894 + return this;
142.895 + }
142.896 +
142.897 + /**
142.898 + * Writes a formatted string to this writer using the specified format
142.899 + * string and arguments. If automatic flushing is enabled, calls to this
142.900 + * method will flush the output buffer.
142.901 + *
142.902 + * @param l
142.903 + * The {@linkplain java.util.Locale locale} to apply during
142.904 + * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
142.905 + * is applied.
142.906 + *
142.907 + * @param format
142.908 + * A format string as described in <a
142.909 + * href="../util/Formatter.html#syntax">Format string syntax</a>.
142.910 + *
142.911 + * @param args
142.912 + * Arguments referenced by the format specifiers in the format
142.913 + * string. If there are more arguments than format specifiers, the
142.914 + * extra arguments are ignored. The number of arguments is
142.915 + * variable and may be zero. The maximum number of arguments is
142.916 + * limited by the maximum dimension of a Java array as defined by
142.917 + * <cite>The Java™ Virtual Machine Specification</cite>.
142.918 + * The behaviour on a
142.919 + * <tt>null</tt> argument depends on the <a
142.920 + * href="../util/Formatter.html#syntax">conversion</a>.
142.921 + *
142.922 + * @throws IllegalFormatException
142.923 + * If a format string contains an illegal syntax, a format
142.924 + * specifier that is incompatible with the given arguments,
142.925 + * insufficient arguments given the format string, or other
142.926 + * illegal conditions. For specification of all possible
142.927 + * formatting errors, see the <a
142.928 + * href="../util/Formatter.html#detail">Details</a> section of the
142.929 + * formatter class specification.
142.930 + *
142.931 + * @throws NullPointerException
142.932 + * If the <tt>format</tt> is <tt>null</tt>
142.933 + *
142.934 + * @return This writer
142.935 + *
142.936 + * @since 1.5
142.937 + */
142.938 +// public PrintWriter format(Locale l, String format, Object ... args) {
142.939 +// return format(format, args);
142.940 +// }
142.941 +
142.942 + /**
142.943 + * Appends the specified character sequence to this writer.
142.944 + *
142.945 + * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
142.946 + * behaves in exactly the same way as the invocation
142.947 + *
142.948 + * <pre>
142.949 + * out.write(csq.toString()) </pre>
142.950 + *
142.951 + * <p> Depending on the specification of <tt>toString</tt> for the
142.952 + * character sequence <tt>csq</tt>, the entire sequence may not be
142.953 + * appended. For instance, invoking the <tt>toString</tt> method of a
142.954 + * character buffer will return a subsequence whose content depends upon
142.955 + * the buffer's position and limit.
142.956 + *
142.957 + * @param csq
142.958 + * The character sequence to append. If <tt>csq</tt> is
142.959 + * <tt>null</tt>, then the four characters <tt>"null"</tt> are
142.960 + * appended to this writer.
142.961 + *
142.962 + * @return This writer
142.963 + *
142.964 + * @since 1.5
142.965 + */
142.966 + public PrintWriter append(CharSequence csq) {
142.967 + if (csq == null)
142.968 + write("null");
142.969 + else
142.970 + write(csq.toString());
142.971 + return this;
142.972 + }
142.973 +
142.974 + /**
142.975 + * Appends a subsequence of the specified character sequence to this writer.
142.976 + *
142.977 + * <p> An invocation of this method of the form <tt>out.append(csq, start,
142.978 + * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
142.979 + * exactly the same way as the invocation
142.980 + *
142.981 + * <pre>
142.982 + * out.write(csq.subSequence(start, end).toString()) </pre>
142.983 + *
142.984 + * @param csq
142.985 + * The character sequence from which a subsequence will be
142.986 + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
142.987 + * will be appended as if <tt>csq</tt> contained the four
142.988 + * characters <tt>"null"</tt>.
142.989 + *
142.990 + * @param start
142.991 + * The index of the first character in the subsequence
142.992 + *
142.993 + * @param end
142.994 + * The index of the character following the last character in the
142.995 + * subsequence
142.996 + *
142.997 + * @return This writer
142.998 + *
142.999 + * @throws IndexOutOfBoundsException
142.1000 + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
142.1001 + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
142.1002 + * <tt>csq.length()</tt>
142.1003 + *
142.1004 + * @since 1.5
142.1005 + */
142.1006 + public PrintWriter append(CharSequence csq, int start, int end) {
142.1007 + CharSequence cs = (csq == null ? "null" : csq);
142.1008 + write(cs.subSequence(start, end).toString());
142.1009 + return this;
142.1010 + }
142.1011 +
142.1012 + /**
142.1013 + * Appends the specified character to this writer.
142.1014 + *
142.1015 + * <p> An invocation of this method of the form <tt>out.append(c)</tt>
142.1016 + * behaves in exactly the same way as the invocation
142.1017 + *
142.1018 + * <pre>
142.1019 + * out.write(c) </pre>
142.1020 + *
142.1021 + * @param c
142.1022 + * The 16-bit character to append
142.1023 + *
142.1024 + * @return This writer
142.1025 + *
142.1026 + * @since 1.5
142.1027 + */
142.1028 + public PrintWriter append(char c) {
142.1029 + write(c);
142.1030 + return this;
142.1031 + }
142.1032 +}
143.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
143.2 +++ b/rt/emul/compact/src/main/java/java/io/StringReader.java Wed Apr 30 15:04:10 2014 +0200
143.3 @@ -0,0 +1,201 @@
143.4 +/*
143.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
143.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
143.7 + *
143.8 + * This code is free software; you can redistribute it and/or modify it
143.9 + * under the terms of the GNU General Public License version 2 only, as
143.10 + * published by the Free Software Foundation. Oracle designates this
143.11 + * particular file as subject to the "Classpath" exception as provided
143.12 + * by Oracle in the LICENSE file that accompanied this code.
143.13 + *
143.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
143.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
143.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
143.17 + * version 2 for more details (a copy is included in the LICENSE file that
143.18 + * accompanied this code).
143.19 + *
143.20 + * You should have received a copy of the GNU General Public License version
143.21 + * 2 along with this work; if not, write to the Free Software Foundation,
143.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
143.23 + *
143.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
143.25 + * or visit www.oracle.com if you need additional information or have any
143.26 + * questions.
143.27 + */
143.28 +
143.29 +package java.io;
143.30 +
143.31 +
143.32 +/**
143.33 + * A character stream whose source is a string.
143.34 + *
143.35 + * @author Mark Reinhold
143.36 + * @since JDK1.1
143.37 + */
143.38 +
143.39 +public class StringReader extends Reader {
143.40 +
143.41 + private String str;
143.42 + private int length;
143.43 + private int next = 0;
143.44 + private int mark = 0;
143.45 +
143.46 + /**
143.47 + * Creates a new string reader.
143.48 + *
143.49 + * @param s String providing the character stream.
143.50 + */
143.51 + public StringReader(String s) {
143.52 + this.str = s;
143.53 + this.length = s.length();
143.54 + }
143.55 +
143.56 + /** Check to make sure that the stream has not been closed */
143.57 + private void ensureOpen() throws IOException {
143.58 + if (str == null)
143.59 + throw new IOException("Stream closed");
143.60 + }
143.61 +
143.62 + /**
143.63 + * Reads a single character.
143.64 + *
143.65 + * @return The character read, or -1 if the end of the stream has been
143.66 + * reached
143.67 + *
143.68 + * @exception IOException If an I/O error occurs
143.69 + */
143.70 + public int read() throws IOException {
143.71 + synchronized (lock) {
143.72 + ensureOpen();
143.73 + if (next >= length)
143.74 + return -1;
143.75 + return str.charAt(next++);
143.76 + }
143.77 + }
143.78 +
143.79 + /**
143.80 + * Reads characters into a portion of an array.
143.81 + *
143.82 + * @param cbuf Destination buffer
143.83 + * @param off Offset at which to start writing characters
143.84 + * @param len Maximum number of characters to read
143.85 + *
143.86 + * @return The number of characters read, or -1 if the end of the
143.87 + * stream has been reached
143.88 + *
143.89 + * @exception IOException If an I/O error occurs
143.90 + */
143.91 + public int read(char cbuf[], int off, int len) throws IOException {
143.92 + synchronized (lock) {
143.93 + ensureOpen();
143.94 + if ((off < 0) || (off > cbuf.length) || (len < 0) ||
143.95 + ((off + len) > cbuf.length) || ((off + len) < 0)) {
143.96 + throw new IndexOutOfBoundsException();
143.97 + } else if (len == 0) {
143.98 + return 0;
143.99 + }
143.100 + if (next >= length)
143.101 + return -1;
143.102 + int n = Math.min(length - next, len);
143.103 + str.getChars(next, next + n, cbuf, off);
143.104 + next += n;
143.105 + return n;
143.106 + }
143.107 + }
143.108 +
143.109 + /**
143.110 + * Skips the specified number of characters in the stream. Returns
143.111 + * the number of characters that were skipped.
143.112 + *
143.113 + * <p>The <code>ns</code> parameter may be negative, even though the
143.114 + * <code>skip</code> method of the {@link Reader} superclass throws
143.115 + * an exception in this case. Negative values of <code>ns</code> cause the
143.116 + * stream to skip backwards. Negative return values indicate a skip
143.117 + * backwards. It is not possible to skip backwards past the beginning of
143.118 + * the string.
143.119 + *
143.120 + * <p>If the entire string has been read or skipped, then this method has
143.121 + * no effect and always returns 0.
143.122 + *
143.123 + * @exception IOException If an I/O error occurs
143.124 + */
143.125 + public long skip(long ns) throws IOException {
143.126 + synchronized (lock) {
143.127 + ensureOpen();
143.128 + if (next >= length)
143.129 + return 0;
143.130 + // Bound skip by beginning and end of the source
143.131 + long n = Math.min(length - next, ns);
143.132 + n = Math.max(-next, n);
143.133 + next += n;
143.134 + return n;
143.135 + }
143.136 + }
143.137 +
143.138 + /**
143.139 + * Tells whether this stream is ready to be read.
143.140 + *
143.141 + * @return True if the next read() is guaranteed not to block for input
143.142 + *
143.143 + * @exception IOException If the stream is closed
143.144 + */
143.145 + public boolean ready() throws IOException {
143.146 + synchronized (lock) {
143.147 + ensureOpen();
143.148 + return true;
143.149 + }
143.150 + }
143.151 +
143.152 + /**
143.153 + * Tells whether this stream supports the mark() operation, which it does.
143.154 + */
143.155 + public boolean markSupported() {
143.156 + return true;
143.157 + }
143.158 +
143.159 + /**
143.160 + * Marks the present position in the stream. Subsequent calls to reset()
143.161 + * will reposition the stream to this point.
143.162 + *
143.163 + * @param readAheadLimit Limit on the number of characters that may be
143.164 + * read while still preserving the mark. Because
143.165 + * the stream's input comes from a string, there
143.166 + * is no actual limit, so this argument must not
143.167 + * be negative, but is otherwise ignored.
143.168 + *
143.169 + * @exception IllegalArgumentException If readAheadLimit is < 0
143.170 + * @exception IOException If an I/O error occurs
143.171 + */
143.172 + public void mark(int readAheadLimit) throws IOException {
143.173 + if (readAheadLimit < 0){
143.174 + throw new IllegalArgumentException("Read-ahead limit < 0");
143.175 + }
143.176 + synchronized (lock) {
143.177 + ensureOpen();
143.178 + mark = next;
143.179 + }
143.180 + }
143.181 +
143.182 + /**
143.183 + * Resets the stream to the most recent mark, or to the beginning of the
143.184 + * string if it has never been marked.
143.185 + *
143.186 + * @exception IOException If an I/O error occurs
143.187 + */
143.188 + public void reset() throws IOException {
143.189 + synchronized (lock) {
143.190 + ensureOpen();
143.191 + next = mark;
143.192 + }
143.193 + }
143.194 +
143.195 + /**
143.196 + * Closes the stream and releases any system resources associated with
143.197 + * it. Once the stream has been closed, further read(),
143.198 + * ready(), mark(), or reset() invocations will throw an IOException.
143.199 + * Closing a previously closed stream has no effect.
143.200 + */
143.201 + public void close() {
143.202 + str = null;
143.203 + }
143.204 +}
144.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
144.2 +++ b/rt/emul/compact/src/main/java/java/io/StringWriter.java Wed Apr 30 15:04:10 2014 +0200
144.3 @@ -0,0 +1,236 @@
144.4 +/*
144.5 + * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
144.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
144.7 + *
144.8 + * This code is free software; you can redistribute it and/or modify it
144.9 + * under the terms of the GNU General Public License version 2 only, as
144.10 + * published by the Free Software Foundation. Oracle designates this
144.11 + * particular file as subject to the "Classpath" exception as provided
144.12 + * by Oracle in the LICENSE file that accompanied this code.
144.13 + *
144.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
144.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
144.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
144.17 + * version 2 for more details (a copy is included in the LICENSE file that
144.18 + * accompanied this code).
144.19 + *
144.20 + * You should have received a copy of the GNU General Public License version
144.21 + * 2 along with this work; if not, write to the Free Software Foundation,
144.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
144.23 + *
144.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
144.25 + * or visit www.oracle.com if you need additional information or have any
144.26 + * questions.
144.27 + */
144.28 +
144.29 +package java.io;
144.30 +
144.31 +
144.32 +/**
144.33 + * A character stream that collects its output in a string buffer, which can
144.34 + * then be used to construct a string.
144.35 + * <p>
144.36 + * Closing a <tt>StringWriter</tt> has no effect. The methods in this class
144.37 + * can be called after the stream has been closed without generating an
144.38 + * <tt>IOException</tt>.
144.39 + *
144.40 + * @author Mark Reinhold
144.41 + * @since JDK1.1
144.42 + */
144.43 +
144.44 +public class StringWriter extends Writer {
144.45 +
144.46 + private StringBuffer buf;
144.47 +
144.48 + /**
144.49 + * Create a new string writer using the default initial string-buffer
144.50 + * size.
144.51 + */
144.52 + public StringWriter() {
144.53 + buf = new StringBuffer();
144.54 + lock = buf;
144.55 + }
144.56 +
144.57 + /**
144.58 + * Create a new string writer using the specified initial string-buffer
144.59 + * size.
144.60 + *
144.61 + * @param initialSize
144.62 + * The number of <tt>char</tt> values that will fit into this buffer
144.63 + * before it is automatically expanded
144.64 + *
144.65 + * @throws IllegalArgumentException
144.66 + * If <tt>initialSize</tt> is negative
144.67 + */
144.68 + public StringWriter(int initialSize) {
144.69 + if (initialSize < 0) {
144.70 + throw new IllegalArgumentException("Negative buffer size");
144.71 + }
144.72 + buf = new StringBuffer(initialSize);
144.73 + lock = buf;
144.74 + }
144.75 +
144.76 + /**
144.77 + * Write a single character.
144.78 + */
144.79 + public void write(int c) {
144.80 + buf.append((char) c);
144.81 + }
144.82 +
144.83 + /**
144.84 + * Write a portion of an array of characters.
144.85 + *
144.86 + * @param cbuf Array of characters
144.87 + * @param off Offset from which to start writing characters
144.88 + * @param len Number of characters to write
144.89 + */
144.90 + public void write(char cbuf[], int off, int len) {
144.91 + if ((off < 0) || (off > cbuf.length) || (len < 0) ||
144.92 + ((off + len) > cbuf.length) || ((off + len) < 0)) {
144.93 + throw new IndexOutOfBoundsException();
144.94 + } else if (len == 0) {
144.95 + return;
144.96 + }
144.97 + buf.append(cbuf, off, len);
144.98 + }
144.99 +
144.100 + /**
144.101 + * Write a string.
144.102 + */
144.103 + public void write(String str) {
144.104 + buf.append(str);
144.105 + }
144.106 +
144.107 + /**
144.108 + * Write a portion of a string.
144.109 + *
144.110 + * @param str String to be written
144.111 + * @param off Offset from which to start writing characters
144.112 + * @param len Number of characters to write
144.113 + */
144.114 + public void write(String str, int off, int len) {
144.115 + buf.append(str.substring(off, off + len));
144.116 + }
144.117 +
144.118 + /**
144.119 + * Appends the specified character sequence to this writer.
144.120 + *
144.121 + * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
144.122 + * behaves in exactly the same way as the invocation
144.123 + *
144.124 + * <pre>
144.125 + * out.write(csq.toString()) </pre>
144.126 + *
144.127 + * <p> Depending on the specification of <tt>toString</tt> for the
144.128 + * character sequence <tt>csq</tt>, the entire sequence may not be
144.129 + * appended. For instance, invoking the <tt>toString</tt> method of a
144.130 + * character buffer will return a subsequence whose content depends upon
144.131 + * the buffer's position and limit.
144.132 + *
144.133 + * @param csq
144.134 + * The character sequence to append. If <tt>csq</tt> is
144.135 + * <tt>null</tt>, then the four characters <tt>"null"</tt> are
144.136 + * appended to this writer.
144.137 + *
144.138 + * @return This writer
144.139 + *
144.140 + * @since 1.5
144.141 + */
144.142 + public StringWriter append(CharSequence csq) {
144.143 + if (csq == null)
144.144 + write("null");
144.145 + else
144.146 + write(csq.toString());
144.147 + return this;
144.148 + }
144.149 +
144.150 + /**
144.151 + * Appends a subsequence of the specified character sequence to this writer.
144.152 + *
144.153 + * <p> An invocation of this method of the form <tt>out.append(csq, start,
144.154 + * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
144.155 + * exactly the same way as the invocation
144.156 + *
144.157 + * <pre>
144.158 + * out.write(csq.subSequence(start, end).toString()) </pre>
144.159 + *
144.160 + * @param csq
144.161 + * The character sequence from which a subsequence will be
144.162 + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
144.163 + * will be appended as if <tt>csq</tt> contained the four
144.164 + * characters <tt>"null"</tt>.
144.165 + *
144.166 + * @param start
144.167 + * The index of the first character in the subsequence
144.168 + *
144.169 + * @param end
144.170 + * The index of the character following the last character in the
144.171 + * subsequence
144.172 + *
144.173 + * @return This writer
144.174 + *
144.175 + * @throws IndexOutOfBoundsException
144.176 + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
144.177 + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
144.178 + * <tt>csq.length()</tt>
144.179 + *
144.180 + * @since 1.5
144.181 + */
144.182 + public StringWriter append(CharSequence csq, int start, int end) {
144.183 + CharSequence cs = (csq == null ? "null" : csq);
144.184 + write(cs.subSequence(start, end).toString());
144.185 + return this;
144.186 + }
144.187 +
144.188 + /**
144.189 + * Appends the specified character to this writer.
144.190 + *
144.191 + * <p> An invocation of this method of the form <tt>out.append(c)</tt>
144.192 + * behaves in exactly the same way as the invocation
144.193 + *
144.194 + * <pre>
144.195 + * out.write(c) </pre>
144.196 + *
144.197 + * @param c
144.198 + * The 16-bit character to append
144.199 + *
144.200 + * @return This writer
144.201 + *
144.202 + * @since 1.5
144.203 + */
144.204 + public StringWriter append(char c) {
144.205 + write(c);
144.206 + return this;
144.207 + }
144.208 +
144.209 + /**
144.210 + * Return the buffer's current value as a string.
144.211 + */
144.212 + public String toString() {
144.213 + return buf.toString();
144.214 + }
144.215 +
144.216 + /**
144.217 + * Return the string buffer itself.
144.218 + *
144.219 + * @return StringBuffer holding the current buffer value.
144.220 + */
144.221 + public StringBuffer getBuffer() {
144.222 + return buf;
144.223 + }
144.224 +
144.225 + /**
144.226 + * Flush the stream.
144.227 + */
144.228 + public void flush() {
144.229 + }
144.230 +
144.231 + /**
144.232 + * Closing a <tt>StringWriter</tt> has no effect. The methods in this
144.233 + * class can be called after the stream has been closed without generating
144.234 + * an <tt>IOException</tt>.
144.235 + */
144.236 + public void close() throws IOException {
144.237 + }
144.238 +
144.239 +}
145.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
145.2 +++ b/rt/emul/compact/src/main/java/java/io/SyncFailedException.java Wed Apr 30 15:04:10 2014 +0200
145.3 @@ -0,0 +1,48 @@
145.4 +/*
145.5 + * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
145.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
145.7 + *
145.8 + * This code is free software; you can redistribute it and/or modify it
145.9 + * under the terms of the GNU General Public License version 2 only, as
145.10 + * published by the Free Software Foundation. Oracle designates this
145.11 + * particular file as subject to the "Classpath" exception as provided
145.12 + * by Oracle in the LICENSE file that accompanied this code.
145.13 + *
145.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
145.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
145.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
145.17 + * version 2 for more details (a copy is included in the LICENSE file that
145.18 + * accompanied this code).
145.19 + *
145.20 + * You should have received a copy of the GNU General Public License version
145.21 + * 2 along with this work; if not, write to the Free Software Foundation,
145.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
145.23 + *
145.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
145.25 + * or visit www.oracle.com if you need additional information or have any
145.26 + * questions.
145.27 + */
145.28 +
145.29 +package java.io;
145.30 +
145.31 +/**
145.32 + * Signals that a sync operation has failed.
145.33 + *
145.34 + * @author Ken Arnold
145.35 + * @see java.io.FileDescriptor#sync
145.36 + * @see java.io.IOException
145.37 + * @since JDK1.1
145.38 + */
145.39 +public class SyncFailedException extends IOException {
145.40 + private static final long serialVersionUID = -2353342684412443330L;
145.41 +
145.42 + /**
145.43 + * Constructs an SyncFailedException with a detail message.
145.44 + * A detail message is a String that describes this particular exception.
145.45 + *
145.46 + * @param desc a String describing the exception.
145.47 + */
145.48 + public SyncFailedException(String desc) {
145.49 + super(desc);
145.50 + }
145.51 +}
146.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
146.2 +++ b/rt/emul/compact/src/main/java/java/io/Writer.java Wed Apr 30 15:04:10 2014 +0200
146.3 @@ -0,0 +1,325 @@
146.4 +/*
146.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
146.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
146.7 + *
146.8 + * This code is free software; you can redistribute it and/or modify it
146.9 + * under the terms of the GNU General Public License version 2 only, as
146.10 + * published by the Free Software Foundation. Oracle designates this
146.11 + * particular file as subject to the "Classpath" exception as provided
146.12 + * by Oracle in the LICENSE file that accompanied this code.
146.13 + *
146.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
146.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
146.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
146.17 + * version 2 for more details (a copy is included in the LICENSE file that
146.18 + * accompanied this code).
146.19 + *
146.20 + * You should have received a copy of the GNU General Public License version
146.21 + * 2 along with this work; if not, write to the Free Software Foundation,
146.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
146.23 + *
146.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
146.25 + * or visit www.oracle.com if you need additional information or have any
146.26 + * questions.
146.27 + */
146.28 +
146.29 +package java.io;
146.30 +
146.31 +
146.32 +/**
146.33 + * Abstract class for writing to character streams. The only methods that a
146.34 + * subclass must implement are write(char[], int, int), flush(), and close().
146.35 + * Most subclasses, however, will override some of the methods defined here in
146.36 + * order to provide higher efficiency, additional functionality, or both.
146.37 + *
146.38 + * @see Writer
146.39 + * @see BufferedWriter
146.40 + * @see CharArrayWriter
146.41 + * @see FilterWriter
146.42 + * @see OutputStreamWriter
146.43 + * @see FileWriter
146.44 + * @see PipedWriter
146.45 + * @see PrintWriter
146.46 + * @see StringWriter
146.47 + * @see Reader
146.48 + *
146.49 + * @author Mark Reinhold
146.50 + * @since JDK1.1
146.51 + */
146.52 +
146.53 +public abstract class Writer implements Appendable, Closeable, Flushable {
146.54 +
146.55 + /**
146.56 + * Temporary buffer used to hold writes of strings and single characters
146.57 + */
146.58 + private char[] writeBuffer;
146.59 +
146.60 + /**
146.61 + * Size of writeBuffer, must be >= 1
146.62 + */
146.63 + private final int writeBufferSize = 1024;
146.64 +
146.65 + /**
146.66 + * The object used to synchronize operations on this stream. For
146.67 + * efficiency, a character-stream object may use an object other than
146.68 + * itself to protect critical sections. A subclass should therefore use
146.69 + * the object in this field rather than <tt>this</tt> or a synchronized
146.70 + * method.
146.71 + */
146.72 + protected Object lock;
146.73 +
146.74 + /**
146.75 + * Creates a new character-stream writer whose critical sections will
146.76 + * synchronize on the writer itself.
146.77 + */
146.78 + protected Writer() {
146.79 + this.lock = this;
146.80 + }
146.81 +
146.82 + /**
146.83 + * Creates a new character-stream writer whose critical sections will
146.84 + * synchronize on the given object.
146.85 + *
146.86 + * @param lock
146.87 + * Object to synchronize on
146.88 + */
146.89 + protected Writer(Object lock) {
146.90 + if (lock == null) {
146.91 + throw new NullPointerException();
146.92 + }
146.93 + this.lock = lock;
146.94 + }
146.95 +
146.96 + /**
146.97 + * Writes a single character. The character to be written is contained in
146.98 + * the 16 low-order bits of the given integer value; the 16 high-order bits
146.99 + * are ignored.
146.100 + *
146.101 + * <p> Subclasses that intend to support efficient single-character output
146.102 + * should override this method.
146.103 + *
146.104 + * @param c
146.105 + * int specifying a character to be written
146.106 + *
146.107 + * @throws IOException
146.108 + * If an I/O error occurs
146.109 + */
146.110 + public void write(int c) throws IOException {
146.111 + synchronized (lock) {
146.112 + if (writeBuffer == null){
146.113 + writeBuffer = new char[writeBufferSize];
146.114 + }
146.115 + writeBuffer[0] = (char) c;
146.116 + write(writeBuffer, 0, 1);
146.117 + }
146.118 + }
146.119 +
146.120 + /**
146.121 + * Writes an array of characters.
146.122 + *
146.123 + * @param cbuf
146.124 + * Array of characters to be written
146.125 + *
146.126 + * @throws IOException
146.127 + * If an I/O error occurs
146.128 + */
146.129 + public void write(char cbuf[]) throws IOException {
146.130 + write(cbuf, 0, cbuf.length);
146.131 + }
146.132 +
146.133 + /**
146.134 + * Writes a portion of an array of characters.
146.135 + *
146.136 + * @param cbuf
146.137 + * Array of characters
146.138 + *
146.139 + * @param off
146.140 + * Offset from which to start writing characters
146.141 + *
146.142 + * @param len
146.143 + * Number of characters to write
146.144 + *
146.145 + * @throws IOException
146.146 + * If an I/O error occurs
146.147 + */
146.148 + abstract public void write(char cbuf[], int off, int len) throws IOException;
146.149 +
146.150 + /**
146.151 + * Writes a string.
146.152 + *
146.153 + * @param str
146.154 + * String to be written
146.155 + *
146.156 + * @throws IOException
146.157 + * If an I/O error occurs
146.158 + */
146.159 + public void write(String str) throws IOException {
146.160 + write(str, 0, str.length());
146.161 + }
146.162 +
146.163 + /**
146.164 + * Writes a portion of a string.
146.165 + *
146.166 + * @param str
146.167 + * A String
146.168 + *
146.169 + * @param off
146.170 + * Offset from which to start writing characters
146.171 + *
146.172 + * @param len
146.173 + * Number of characters to write
146.174 + *
146.175 + * @throws IndexOutOfBoundsException
146.176 + * If <tt>off</tt> is negative, or <tt>len</tt> is negative,
146.177 + * or <tt>off+len</tt> is negative or greater than the length
146.178 + * of the given string
146.179 + *
146.180 + * @throws IOException
146.181 + * If an I/O error occurs
146.182 + */
146.183 + public void write(String str, int off, int len) throws IOException {
146.184 + synchronized (lock) {
146.185 + char cbuf[];
146.186 + if (len <= writeBufferSize) {
146.187 + if (writeBuffer == null) {
146.188 + writeBuffer = new char[writeBufferSize];
146.189 + }
146.190 + cbuf = writeBuffer;
146.191 + } else { // Don't permanently allocate very large buffers.
146.192 + cbuf = new char[len];
146.193 + }
146.194 + str.getChars(off, (off + len), cbuf, 0);
146.195 + write(cbuf, 0, len);
146.196 + }
146.197 + }
146.198 +
146.199 + /**
146.200 + * Appends the specified character sequence to this writer.
146.201 + *
146.202 + * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
146.203 + * behaves in exactly the same way as the invocation
146.204 + *
146.205 + * <pre>
146.206 + * out.write(csq.toString()) </pre>
146.207 + *
146.208 + * <p> Depending on the specification of <tt>toString</tt> for the
146.209 + * character sequence <tt>csq</tt>, the entire sequence may not be
146.210 + * appended. For instance, invoking the <tt>toString</tt> method of a
146.211 + * character buffer will return a subsequence whose content depends upon
146.212 + * the buffer's position and limit.
146.213 + *
146.214 + * @param csq
146.215 + * The character sequence to append. If <tt>csq</tt> is
146.216 + * <tt>null</tt>, then the four characters <tt>"null"</tt> are
146.217 + * appended to this writer.
146.218 + *
146.219 + * @return This writer
146.220 + *
146.221 + * @throws IOException
146.222 + * If an I/O error occurs
146.223 + *
146.224 + * @since 1.5
146.225 + */
146.226 + public Writer append(CharSequence csq) throws IOException {
146.227 + if (csq == null)
146.228 + write("null");
146.229 + else
146.230 + write(csq.toString());
146.231 + return this;
146.232 + }
146.233 +
146.234 + /**
146.235 + * Appends a subsequence of the specified character sequence to this writer.
146.236 + * <tt>Appendable</tt>.
146.237 + *
146.238 + * <p> An invocation of this method of the form <tt>out.append(csq, start,
146.239 + * end)</tt> when <tt>csq</tt> is not <tt>null</tt> behaves in exactly the
146.240 + * same way as the invocation
146.241 + *
146.242 + * <pre>
146.243 + * out.write(csq.subSequence(start, end).toString()) </pre>
146.244 + *
146.245 + * @param csq
146.246 + * The character sequence from which a subsequence will be
146.247 + * appended. If <tt>csq</tt> is <tt>null</tt>, then characters
146.248 + * will be appended as if <tt>csq</tt> contained the four
146.249 + * characters <tt>"null"</tt>.
146.250 + *
146.251 + * @param start
146.252 + * The index of the first character in the subsequence
146.253 + *
146.254 + * @param end
146.255 + * The index of the character following the last character in the
146.256 + * subsequence
146.257 + *
146.258 + * @return This writer
146.259 + *
146.260 + * @throws IndexOutOfBoundsException
146.261 + * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
146.262 + * is greater than <tt>end</tt>, or <tt>end</tt> is greater than
146.263 + * <tt>csq.length()</tt>
146.264 + *
146.265 + * @throws IOException
146.266 + * If an I/O error occurs
146.267 + *
146.268 + * @since 1.5
146.269 + */
146.270 + public Writer append(CharSequence csq, int start, int end) throws IOException {
146.271 + CharSequence cs = (csq == null ? "null" : csq);
146.272 + write(cs.subSequence(start, end).toString());
146.273 + return this;
146.274 + }
146.275 +
146.276 + /**
146.277 + * Appends the specified character to this writer.
146.278 + *
146.279 + * <p> An invocation of this method of the form <tt>out.append(c)</tt>
146.280 + * behaves in exactly the same way as the invocation
146.281 + *
146.282 + * <pre>
146.283 + * out.write(c) </pre>
146.284 + *
146.285 + * @param c
146.286 + * The 16-bit character to append
146.287 + *
146.288 + * @return This writer
146.289 + *
146.290 + * @throws IOException
146.291 + * If an I/O error occurs
146.292 + *
146.293 + * @since 1.5
146.294 + */
146.295 + public Writer append(char c) throws IOException {
146.296 + write(c);
146.297 + return this;
146.298 + }
146.299 +
146.300 + /**
146.301 + * Flushes the stream. If the stream has saved any characters from the
146.302 + * various write() methods in a buffer, write them immediately to their
146.303 + * intended destination. Then, if that destination is another character or
146.304 + * byte stream, flush it. Thus one flush() invocation will flush all the
146.305 + * buffers in a chain of Writers and OutputStreams.
146.306 + *
146.307 + * <p> If the intended destination of this stream is an abstraction provided
146.308 + * by the underlying operating system, for example a file, then flushing the
146.309 + * stream guarantees only that bytes previously written to the stream are
146.310 + * passed to the operating system for writing; it does not guarantee that
146.311 + * they are actually written to a physical device such as a disk drive.
146.312 + *
146.313 + * @throws IOException
146.314 + * If an I/O error occurs
146.315 + */
146.316 + abstract public void flush() throws IOException;
146.317 +
146.318 + /**
146.319 + * Closes the stream, flushing it first. Once the stream has been closed,
146.320 + * further write() or flush() invocations will cause an IOException to be
146.321 + * thrown. Closing a previously closed stream has no effect.
146.322 + *
146.323 + * @throws IOException
146.324 + * If an I/O error occurs
146.325 + */
146.326 + abstract public void close() throws IOException;
146.327 +
146.328 +}
147.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
147.2 +++ b/rt/emul/compact/src/main/java/java/lang/StackOverflowError.java Wed Apr 30 15:04:10 2014 +0200
147.3 @@ -0,0 +1,55 @@
147.4 +/*
147.5 + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
147.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
147.7 + *
147.8 + * This code is free software; you can redistribute it and/or modify it
147.9 + * under the terms of the GNU General Public License version 2 only, as
147.10 + * published by the Free Software Foundation. Oracle designates this
147.11 + * particular file as subject to the "Classpath" exception as provided
147.12 + * by Oracle in the LICENSE file that accompanied this code.
147.13 + *
147.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
147.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
147.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
147.17 + * version 2 for more details (a copy is included in the LICENSE file that
147.18 + * accompanied this code).
147.19 + *
147.20 + * You should have received a copy of the GNU General Public License version
147.21 + * 2 along with this work; if not, write to the Free Software Foundation,
147.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
147.23 + *
147.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
147.25 + * or visit www.oracle.com if you need additional information or have any
147.26 + * questions.
147.27 + */
147.28 +
147.29 +package java.lang;
147.30 +
147.31 +/**
147.32 + * Thrown when a stack overflow occurs because an application
147.33 + * recurses too deeply.
147.34 + *
147.35 + * @author unascribed
147.36 + * @since JDK1.0
147.37 + */
147.38 +public
147.39 +class StackOverflowError extends VirtualMachineError {
147.40 + private static final long serialVersionUID = 8609175038441759607L;
147.41 +
147.42 + /**
147.43 + * Constructs a <code>StackOverflowError</code> with no detail message.
147.44 + */
147.45 + public StackOverflowError() {
147.46 + super();
147.47 + }
147.48 +
147.49 + /**
147.50 + * Constructs a <code>StackOverflowError</code> with the specified
147.51 + * detail message.
147.52 + *
147.53 + * @param s the detail message.
147.54 + */
147.55 + public StackOverflowError(String s) {
147.56 + super(s);
147.57 + }
147.58 +}
148.1 --- a/rt/emul/compact/src/main/java/java/lang/System.java Tue Apr 29 15:25:58 2014 +0200
148.2 +++ b/rt/emul/compact/src/main/java/java/lang/System.java Wed Apr 30 15:04:10 2014 +0200
148.3 @@ -17,6 +17,15 @@
148.4 */
148.5 package java.lang;
148.6
148.7 +import java.io.BufferedOutputStream;
148.8 +import java.io.ByteArrayInputStream;
148.9 +import java.io.IOException;
148.10 +import java.io.InputStream;
148.11 +import java.io.OutputStream;
148.12 +import java.io.PrintStream;
148.13 +import java.util.Properties;
148.14 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
148.15 +
148.16 /** Poor man's re-implementation of most important System methods.
148.17 *
148.18 * @author Jaroslav Tulach <jtulach@netbeans.org>
148.19 @@ -33,4 +42,90 @@
148.20 return org.apidesign.bck2brwsr.emul.lang.System.currentTimeMillis();
148.21 }
148.22
148.23 + public static int identityHashCode(Object obj) {
148.24 + return Class.defaultHashCode(obj);
148.25 + }
148.26 +
148.27 + public static String getProperty(String name) {
148.28 + if ("os.name".equals(name)) {
148.29 + return userAgent();
148.30 + }
148.31 + return null;
148.32 + }
148.33 +
148.34 + @JavaScriptBody(args = {}, body = "return (typeof navigator !== 'undefined') ? navigator.userAgent : 'unknown';")
148.35 + private static native String userAgent();
148.36 +
148.37 + public static String getProperty(String key, String def) {
148.38 + return def;
148.39 + }
148.40 +
148.41 + public static Properties getProperties() {
148.42 + throw new SecurityException();
148.43 + }
148.44 +
148.45 + public static void setProperties(Properties p) {
148.46 + throw new SecurityException();
148.47 + }
148.48 +
148.49 + /**
148.50 + * Returns the system-dependent line separator string. It always
148.51 + * returns the same value - the initial value of the {@linkplain
148.52 + * #getProperty(String) system property} {@code line.separator}.
148.53 + *
148.54 + * <p>On UNIX systems, it returns {@code "\n"}; on Microsoft
148.55 + * Windows systems it returns {@code "\r\n"}.
148.56 + */
148.57 + public static String lineSeparator() {
148.58 + return "\n";
148.59 + }
148.60 +
148.61 + @JavaScriptBody(args = { "exitCode" }, body = "window.close();")
148.62 + public static void exit(int exitCode) {
148.63 + }
148.64 +
148.65 + public final static InputStream in;
148.66 +
148.67 + public final static PrintStream out;
148.68 +
148.69 + public final static PrintStream err;
148.70 +
148.71 + public static void setOut(PrintStream out) {
148.72 + throw new SecurityException();
148.73 + }
148.74 +
148.75 + public static void setIn(InputStream in) {
148.76 + throw new SecurityException();
148.77 + }
148.78 +
148.79 + public static void setErr(PrintStream err) {
148.80 + throw new SecurityException();
148.81 + }
148.82 +
148.83 + static {
148.84 + in = new ByteArrayInputStream(new byte[0]);
148.85 + out = new PrintStream(new BufferedOutputStream(new SystemStream("log")));
148.86 + err = new PrintStream(new BufferedOutputStream(new SystemStream("warn")));
148.87 + }
148.88 +
148.89 + private static final class SystemStream extends OutputStream {
148.90 + private final String method;
148.91 +
148.92 + public SystemStream(String method) {
148.93 + this.method = method;
148.94 + }
148.95 +
148.96 + @Override
148.97 + public void write(byte b[], int off, int len) throws IOException {
148.98 + write(method, new String(b, off, len, "UTF-8"));
148.99 + }
148.100 +
148.101 + @JavaScriptBody(args = { "method", "b" }, body = "if (typeof console !== 'undefined') console[method](b.toString());")
148.102 + private static native void write(String method, String b);
148.103 +
148.104 + @Override
148.105 + public void write(int b) throws IOException {
148.106 + write(new byte[] { (byte)b });
148.107 + }
148.108 + } // end of SystemStream
148.109 }
149.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
149.2 +++ b/rt/emul/compact/src/main/java/java/lang/Thread.java Wed Apr 30 15:04:10 2014 +0200
149.3 @@ -0,0 +1,1547 @@
149.4 +/*
149.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
149.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
149.7 + *
149.8 + * This code is free software; you can redistribute it and/or modify it
149.9 + * under the terms of the GNU General Public License version 2 only, as
149.10 + * published by the Free Software Foundation. Oracle designates this
149.11 + * particular file as subject to the "Classpath" exception as provided
149.12 + * by Oracle in the LICENSE file that accompanied this code.
149.13 + *
149.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
149.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
149.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
149.17 + * version 2 for more details (a copy is included in the LICENSE file that
149.18 + * accompanied this code).
149.19 + *
149.20 + * You should have received a copy of the GNU General Public License version
149.21 + * 2 along with this work; if not, write to the Free Software Foundation,
149.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
149.23 + *
149.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
149.25 + * or visit www.oracle.com if you need additional information or have any
149.26 + * questions.
149.27 + */
149.28 +
149.29 +package java.lang;
149.30 +
149.31 +import java.util.Map;
149.32 +
149.33 +
149.34 +/**
149.35 + * A <i>thread</i> is a thread of execution in a program. The Java
149.36 + * Virtual Machine allows an application to have multiple threads of
149.37 + * execution running concurrently.
149.38 + * <p>
149.39 + * Every thread has a priority. Threads with higher priority are
149.40 + * executed in preference to threads with lower priority. Each thread
149.41 + * may or may not also be marked as a daemon. When code running in
149.42 + * some thread creates a new <code>Thread</code> object, the new
149.43 + * thread has its priority initially set equal to the priority of the
149.44 + * creating thread, and is a daemon thread if and only if the
149.45 + * creating thread is a daemon.
149.46 + * <p>
149.47 + * When a Java Virtual Machine starts up, there is usually a single
149.48 + * non-daemon thread (which typically calls the method named
149.49 + * <code>main</code> of some designated class). The Java Virtual
149.50 + * Machine continues to execute threads until either of the following
149.51 + * occurs:
149.52 + * <ul>
149.53 + * <li>The <code>exit</code> method of class <code>Runtime</code> has been
149.54 + * called and the security manager has permitted the exit operation
149.55 + * to take place.
149.56 + * <li>All threads that are not daemon threads have died, either by
149.57 + * returning from the call to the <code>run</code> method or by
149.58 + * throwing an exception that propagates beyond the <code>run</code>
149.59 + * method.
149.60 + * </ul>
149.61 + * <p>
149.62 + * There are two ways to create a new thread of execution. One is to
149.63 + * declare a class to be a subclass of <code>Thread</code>. This
149.64 + * subclass should override the <code>run</code> method of class
149.65 + * <code>Thread</code>. An instance of the subclass can then be
149.66 + * allocated and started. For example, a thread that computes primes
149.67 + * larger than a stated value could be written as follows:
149.68 + * <p><hr><blockquote><pre>
149.69 + * class PrimeThread extends Thread {
149.70 + * long minPrime;
149.71 + * PrimeThread(long minPrime) {
149.72 + * this.minPrime = minPrime;
149.73 + * }
149.74 + *
149.75 + * public void run() {
149.76 + * // compute primes larger than minPrime
149.77 + * . . .
149.78 + * }
149.79 + * }
149.80 + * </pre></blockquote><hr>
149.81 + * <p>
149.82 + * The following code would then create a thread and start it running:
149.83 + * <p><blockquote><pre>
149.84 + * PrimeThread p = new PrimeThread(143);
149.85 + * p.start();
149.86 + * </pre></blockquote>
149.87 + * <p>
149.88 + * The other way to create a thread is to declare a class that
149.89 + * implements the <code>Runnable</code> interface. That class then
149.90 + * implements the <code>run</code> method. An instance of the class can
149.91 + * then be allocated, passed as an argument when creating
149.92 + * <code>Thread</code>, and started. The same example in this other
149.93 + * style looks like the following:
149.94 + * <p><hr><blockquote><pre>
149.95 + * class PrimeRun implements Runnable {
149.96 + * long minPrime;
149.97 + * PrimeRun(long minPrime) {
149.98 + * this.minPrime = minPrime;
149.99 + * }
149.100 + *
149.101 + * public void run() {
149.102 + * // compute primes larger than minPrime
149.103 + * . . .
149.104 + * }
149.105 + * }
149.106 + * </pre></blockquote><hr>
149.107 + * <p>
149.108 + * The following code would then create a thread and start it running:
149.109 + * <p><blockquote><pre>
149.110 + * PrimeRun p = new PrimeRun(143);
149.111 + * new Thread(p).start();
149.112 + * </pre></blockquote>
149.113 + * <p>
149.114 + * Every thread has a name for identification purposes. More than
149.115 + * one thread may have the same name. If a name is not specified when
149.116 + * a thread is created, a new name is generated for it.
149.117 + * <p>
149.118 + * Unless otherwise noted, passing a {@code null} argument to a constructor
149.119 + * or method in this class will cause a {@link NullPointerException} to be
149.120 + * thrown.
149.121 + *
149.122 + * @author unascribed
149.123 + * @see Runnable
149.124 + * @see Runtime#exit(int)
149.125 + * @see #run()
149.126 + * @see #stop()
149.127 + * @since JDK1.0
149.128 + */
149.129 +public
149.130 +class Thread implements Runnable {
149.131 +
149.132 + /**
149.133 + * The minimum priority that a thread can have.
149.134 + */
149.135 + public final static int MIN_PRIORITY = 1;
149.136 +
149.137 + /**
149.138 + * The default priority that is assigned to a thread.
149.139 + */
149.140 + public final static int NORM_PRIORITY = 5;
149.141 +
149.142 + /**
149.143 + * The maximum priority that a thread can have.
149.144 + */
149.145 + public final static int MAX_PRIORITY = 10;
149.146 +
149.147 + private static final Thread ONE = new Thread("main");
149.148 + /**
149.149 + * Returns a reference to the currently executing thread object.
149.150 + *
149.151 + * @return the currently executing thread.
149.152 + */
149.153 + public static Thread currentThread() {
149.154 + return ONE;
149.155 + }
149.156 +
149.157 + /**
149.158 + * A hint to the scheduler that the current thread is willing to yield
149.159 + * its current use of a processor. The scheduler is free to ignore this
149.160 + * hint.
149.161 + *
149.162 + * <p> Yield is a heuristic attempt to improve relative progression
149.163 + * between threads that would otherwise over-utilise a CPU. Its use
149.164 + * should be combined with detailed profiling and benchmarking to
149.165 + * ensure that it actually has the desired effect.
149.166 + *
149.167 + * <p> It is rarely appropriate to use this method. It may be useful
149.168 + * for debugging or testing purposes, where it may help to reproduce
149.169 + * bugs due to race conditions. It may also be useful when designing
149.170 + * concurrency control constructs such as the ones in the
149.171 + * {@link java.util.concurrent.locks} package.
149.172 + */
149.173 + public static void yield() {
149.174 + }
149.175 +
149.176 + /**
149.177 + * Causes the currently executing thread to sleep (temporarily cease
149.178 + * execution) for the specified number of milliseconds, subject to
149.179 + * the precision and accuracy of system timers and schedulers. The thread
149.180 + * does not lose ownership of any monitors.
149.181 + *
149.182 + * @param millis
149.183 + * the length of time to sleep in milliseconds
149.184 + *
149.185 + * @throws IllegalArgumentException
149.186 + * if the value of {@code millis} is negative
149.187 + *
149.188 + * @throws InterruptedException
149.189 + * if any thread has interrupted the current thread. The
149.190 + * <i>interrupted status</i> of the current thread is
149.191 + * cleared when this exception is thrown.
149.192 + */
149.193 + public static native void sleep(long millis) throws InterruptedException;
149.194 +
149.195 + /**
149.196 + * Causes the currently executing thread to sleep (temporarily cease
149.197 + * execution) for the specified number of milliseconds plus the specified
149.198 + * number of nanoseconds, subject to the precision and accuracy of system
149.199 + * timers and schedulers. The thread does not lose ownership of any
149.200 + * monitors.
149.201 + *
149.202 + * @param millis
149.203 + * the length of time to sleep in milliseconds
149.204 + *
149.205 + * @param nanos
149.206 + * {@code 0-999999} additional nanoseconds to sleep
149.207 + *
149.208 + * @throws IllegalArgumentException
149.209 + * if the value of {@code millis} is negative, or the value of
149.210 + * {@code nanos} is not in the range {@code 0-999999}
149.211 + *
149.212 + * @throws InterruptedException
149.213 + * if any thread has interrupted the current thread. The
149.214 + * <i>interrupted status</i> of the current thread is
149.215 + * cleared when this exception is thrown.
149.216 + */
149.217 + public static void sleep(long millis, int nanos)
149.218 + throws InterruptedException {
149.219 + if (millis < 0) {
149.220 + throw new IllegalArgumentException("timeout value is negative");
149.221 + }
149.222 +
149.223 + if (nanos < 0 || nanos > 999999) {
149.224 + throw new IllegalArgumentException(
149.225 + "nanosecond timeout value out of range");
149.226 + }
149.227 +
149.228 + if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
149.229 + millis++;
149.230 + }
149.231 +
149.232 + sleep(millis);
149.233 + }
149.234 + private Runnable target;
149.235 + private String name;
149.236 +
149.237 + /**
149.238 + * Throws CloneNotSupportedException as a Thread can not be meaningfully
149.239 + * cloned. Construct a new Thread instead.
149.240 + *
149.241 + * @throws CloneNotSupportedException
149.242 + * always
149.243 + */
149.244 + @Override
149.245 + protected Object clone() throws CloneNotSupportedException {
149.246 + throw new CloneNotSupportedException();
149.247 + }
149.248 +
149.249 + /**
149.250 + * Allocates a new {@code Thread} object. This constructor has the same
149.251 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
149.252 + * {@code (null, null, gname)}, where {@code gname} is a newly generated
149.253 + * name. Automatically generated names are of the form
149.254 + * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
149.255 + */
149.256 + public Thread() {
149.257 + init(null, null, "Thread-" + nextThreadNum(), 0);
149.258 + }
149.259 +
149.260 + private static int nextThreadNum() {
149.261 + return -1;
149.262 + }
149.263 +
149.264 + /**
149.265 + * Allocates a new {@code Thread} object. This constructor has the same
149.266 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
149.267 + * {@code (null, target, gname)}, where {@code gname} is a newly generated
149.268 + * name. Automatically generated names are of the form
149.269 + * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
149.270 + *
149.271 + * @param target
149.272 + * the object whose {@code run} method is invoked when this thread
149.273 + * is started. If {@code null}, this classes {@code run} method does
149.274 + * nothing.
149.275 + */
149.276 + public Thread(Runnable target) {
149.277 + init(null, target, "Thread-" + nextThreadNum(), 0);
149.278 + }
149.279 +
149.280 + /**
149.281 + * Allocates a new {@code Thread} object. This constructor has the same
149.282 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
149.283 + * {@code (group, target, gname)} ,where {@code gname} is a newly generated
149.284 + * name. Automatically generated names are of the form
149.285 + * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
149.286 + *
149.287 + * @param group
149.288 + * the thread group. If {@code null} and there is a security
149.289 + * manager, the group is determined by {@linkplain
149.290 + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
149.291 + * If there is not a security manager or {@code
149.292 + * SecurityManager.getThreadGroup()} returns {@code null}, the group
149.293 + * is set to the current thread's thread group.
149.294 + *
149.295 + * @param target
149.296 + * the object whose {@code run} method is invoked when this thread
149.297 + * is started. If {@code null}, this thread's run method is invoked.
149.298 + *
149.299 + * @throws SecurityException
149.300 + * if the current thread cannot create a thread in the specified
149.301 + * thread group
149.302 + */
149.303 +// public Thread(ThreadGroup group, Runnable target) {
149.304 +// init(group, target, "Thread-" + nextThreadNum(), 0);
149.305 +// }
149.306 +
149.307 + /**
149.308 + * Allocates a new {@code Thread} object. This constructor has the same
149.309 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
149.310 + * {@code (null, null, name)}.
149.311 + *
149.312 + * @param name
149.313 + * the name of the new thread
149.314 + */
149.315 + public Thread(String name) {
149.316 + init(null, null, name, 0);
149.317 + }
149.318 +
149.319 + private void init(Object o1, Runnable trgt, String nm, int i4) {
149.320 + this.target = trgt;
149.321 + this.name = nm;
149.322 + }
149.323 +
149.324 + /**
149.325 + * Allocates a new {@code Thread} object. This constructor has the same
149.326 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
149.327 + * {@code (group, null, name)}.
149.328 + *
149.329 + * @param group
149.330 + * the thread group. If {@code null} and there is a security
149.331 + * manager, the group is determined by {@linkplain
149.332 + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
149.333 + * If there is not a security manager or {@code
149.334 + * SecurityManager.getThreadGroup()} returns {@code null}, the group
149.335 + * is set to the current thread's thread group.
149.336 + *
149.337 + * @param name
149.338 + * the name of the new thread
149.339 + *
149.340 + * @throws SecurityException
149.341 + * if the current thread cannot create a thread in the specified
149.342 + * thread group
149.343 + */
149.344 +// public Thread(ThreadGroup group, String name) {
149.345 +// init(group, null, name, 0);
149.346 +// }
149.347 +
149.348 + /**
149.349 + * Allocates a new {@code Thread} object. This constructor has the same
149.350 + * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
149.351 + * {@code (null, target, name)}.
149.352 + *
149.353 + * @param target
149.354 + * the object whose {@code run} method is invoked when this thread
149.355 + * is started. If {@code null}, this thread's run method is invoked.
149.356 + *
149.357 + * @param name
149.358 + * the name of the new thread
149.359 + */
149.360 + public Thread(Runnable target, String name) {
149.361 + init(null, target, name, 0);
149.362 + }
149.363 +
149.364 + /**
149.365 + * Allocates a new {@code Thread} object so that it has {@code target}
149.366 + * as its run object, has the specified {@code name} as its name,
149.367 + * and belongs to the thread group referred to by {@code group}.
149.368 + *
149.369 + * <p>If there is a security manager, its
149.370 + * {@link SecurityManager#checkAccess(ThreadGroup) checkAccess}
149.371 + * method is invoked with the ThreadGroup as its argument.
149.372 + *
149.373 + * <p>In addition, its {@code checkPermission} method is invoked with
149.374 + * the {@code RuntimePermission("enableContextClassLoaderOverride")}
149.375 + * permission when invoked directly or indirectly by the constructor
149.376 + * of a subclass which overrides the {@code getContextClassLoader}
149.377 + * or {@code setContextClassLoader} methods.
149.378 + *
149.379 + * <p>The priority of the newly created thread is set equal to the
149.380 + * priority of the thread creating it, that is, the currently running
149.381 + * thread. The method {@linkplain #setPriority setPriority} may be
149.382 + * used to change the priority to a new value.
149.383 + *
149.384 + * <p>The newly created thread is initially marked as being a daemon
149.385 + * thread if and only if the thread creating it is currently marked
149.386 + * as a daemon thread. The method {@linkplain #setDaemon setDaemon}
149.387 + * may be used to change whether or not a thread is a daemon.
149.388 + *
149.389 + * @param group
149.390 + * the thread group. If {@code null} and there is a security
149.391 + * manager, the group is determined by {@linkplain
149.392 + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
149.393 + * If there is not a security manager or {@code
149.394 + * SecurityManager.getThreadGroup()} returns {@code null}, the group
149.395 + * is set to the current thread's thread group.
149.396 + *
149.397 + * @param target
149.398 + * the object whose {@code run} method is invoked when this thread
149.399 + * is started. If {@code null}, this thread's run method is invoked.
149.400 + *
149.401 + * @param name
149.402 + * the name of the new thread
149.403 + *
149.404 + * @throws SecurityException
149.405 + * if the current thread cannot create a thread in the specified
149.406 + * thread group or cannot override the context class loader methods.
149.407 + */
149.408 +// public Thread(ThreadGroup group, Runnable target, String name) {
149.409 +// init(group, target, name, 0);
149.410 +// }
149.411 +
149.412 + /**
149.413 + * Allocates a new {@code Thread} object so that it has {@code target}
149.414 + * as its run object, has the specified {@code name} as its name,
149.415 + * and belongs to the thread group referred to by {@code group}, and has
149.416 + * the specified <i>stack size</i>.
149.417 + *
149.418 + * <p>This constructor is identical to {@link
149.419 + * #Thread(ThreadGroup,Runnable,String)} with the exception of the fact
149.420 + * that it allows the thread stack size to be specified. The stack size
149.421 + * is the approximate number of bytes of address space that the virtual
149.422 + * machine is to allocate for this thread's stack. <b>The effect of the
149.423 + * {@code stackSize} parameter, if any, is highly platform dependent.</b>
149.424 + *
149.425 + * <p>On some platforms, specifying a higher value for the
149.426 + * {@code stackSize} parameter may allow a thread to achieve greater
149.427 + * recursion depth before throwing a {@link StackOverflowError}.
149.428 + * Similarly, specifying a lower value may allow a greater number of
149.429 + * threads to exist concurrently without throwing an {@link
149.430 + * OutOfMemoryError} (or other internal error). The details of
149.431 + * the relationship between the value of the <tt>stackSize</tt> parameter
149.432 + * and the maximum recursion depth and concurrency level are
149.433 + * platform-dependent. <b>On some platforms, the value of the
149.434 + * {@code stackSize} parameter may have no effect whatsoever.</b>
149.435 + *
149.436 + * <p>The virtual machine is free to treat the {@code stackSize}
149.437 + * parameter as a suggestion. If the specified value is unreasonably low
149.438 + * for the platform, the virtual machine may instead use some
149.439 + * platform-specific minimum value; if the specified value is unreasonably
149.440 + * high, the virtual machine may instead use some platform-specific
149.441 + * maximum. Likewise, the virtual machine is free to round the specified
149.442 + * value up or down as it sees fit (or to ignore it completely).
149.443 + *
149.444 + * <p>Specifying a value of zero for the {@code stackSize} parameter will
149.445 + * cause this constructor to behave exactly like the
149.446 + * {@code Thread(ThreadGroup, Runnable, String)} constructor.
149.447 + *
149.448 + * <p><i>Due to the platform-dependent nature of the behavior of this
149.449 + * constructor, extreme care should be exercised in its use.
149.450 + * The thread stack size necessary to perform a given computation will
149.451 + * likely vary from one JRE implementation to another. In light of this
149.452 + * variation, careful tuning of the stack size parameter may be required,
149.453 + * and the tuning may need to be repeated for each JRE implementation on
149.454 + * which an application is to run.</i>
149.455 + *
149.456 + * <p>Implementation note: Java platform implementers are encouraged to
149.457 + * document their implementation's behavior with respect to the
149.458 + * {@code stackSize} parameter.
149.459 + *
149.460 + *
149.461 + * @param group
149.462 + * the thread group. If {@code null} and there is a security
149.463 + * manager, the group is determined by {@linkplain
149.464 + * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
149.465 + * If there is not a security manager or {@code
149.466 + * SecurityManager.getThreadGroup()} returns {@code null}, the group
149.467 + * is set to the current thread's thread group.
149.468 + *
149.469 + * @param target
149.470 + * the object whose {@code run} method is invoked when this thread
149.471 + * is started. If {@code null}, this thread's run method is invoked.
149.472 + *
149.473 + * @param name
149.474 + * the name of the new thread
149.475 + *
149.476 + * @param stackSize
149.477 + * the desired stack size for the new thread, or zero to indicate
149.478 + * that this parameter is to be ignored.
149.479 + *
149.480 + * @throws SecurityException
149.481 + * if the current thread cannot create a thread in the specified
149.482 + * thread group
149.483 + *
149.484 + * @since 1.4
149.485 + */
149.486 +// public Thread(ThreadGroup group, Runnable target, String name,
149.487 +// long stackSize) {
149.488 +// init(group, target, name, stackSize);
149.489 +// }
149.490 +
149.491 + /**
149.492 + * Causes this thread to begin execution; the Java Virtual Machine
149.493 + * calls the <code>run</code> method of this thread.
149.494 + * <p>
149.495 + * The result is that two threads are running concurrently: the
149.496 + * current thread (which returns from the call to the
149.497 + * <code>start</code> method) and the other thread (which executes its
149.498 + * <code>run</code> method).
149.499 + * <p>
149.500 + * It is never legal to start a thread more than once.
149.501 + * In particular, a thread may not be restarted once it has completed
149.502 + * execution.
149.503 + *
149.504 + * @exception IllegalThreadStateException if the thread was already
149.505 + * started.
149.506 + * @see #run()
149.507 + * @see #stop()
149.508 + */
149.509 + public void start() {
149.510 + throw new SecurityException();
149.511 + }
149.512 +
149.513 + /**
149.514 + * If this thread was constructed using a separate
149.515 + * <code>Runnable</code> run object, then that
149.516 + * <code>Runnable</code> object's <code>run</code> method is called;
149.517 + * otherwise, this method does nothing and returns.
149.518 + * <p>
149.519 + * Subclasses of <code>Thread</code> should override this method.
149.520 + *
149.521 + * @see #start()
149.522 + * @see #stop()
149.523 + * @see #Thread(ThreadGroup, Runnable, String)
149.524 + */
149.525 + @Override
149.526 + public void run() {
149.527 + if (target != null) {
149.528 + target.run();
149.529 + }
149.530 + }
149.531 +
149.532 + /**
149.533 + * Forces the thread to stop executing.
149.534 + * <p>
149.535 + * If there is a security manager installed, its <code>checkAccess</code>
149.536 + * method is called with <code>this</code>
149.537 + * as its argument. This may result in a
149.538 + * <code>SecurityException</code> being raised (in the current thread).
149.539 + * <p>
149.540 + * If this thread is different from the current thread (that is, the current
149.541 + * thread is trying to stop a thread other than itself), the
149.542 + * security manager's <code>checkPermission</code> method (with a
149.543 + * <code>RuntimePermission("stopThread")</code> argument) is called in
149.544 + * addition.
149.545 + * Again, this may result in throwing a
149.546 + * <code>SecurityException</code> (in the current thread).
149.547 + * <p>
149.548 + * The thread represented by this thread is forced to stop whatever
149.549 + * it is doing abnormally and to throw a newly created
149.550 + * <code>ThreadDeath</code> object as an exception.
149.551 + * <p>
149.552 + * It is permitted to stop a thread that has not yet been started.
149.553 + * If the thread is eventually started, it immediately terminates.
149.554 + * <p>
149.555 + * An application should not normally try to catch
149.556 + * <code>ThreadDeath</code> unless it must do some extraordinary
149.557 + * cleanup operation (note that the throwing of
149.558 + * <code>ThreadDeath</code> causes <code>finally</code> clauses of
149.559 + * <code>try</code> statements to be executed before the thread
149.560 + * officially dies). If a <code>catch</code> clause catches a
149.561 + * <code>ThreadDeath</code> object, it is important to rethrow the
149.562 + * object so that the thread actually dies.
149.563 + * <p>
149.564 + * The top-level error handler that reacts to otherwise uncaught
149.565 + * exceptions does not print out a message or otherwise notify the
149.566 + * application if the uncaught exception is an instance of
149.567 + * <code>ThreadDeath</code>.
149.568 + *
149.569 + * @exception SecurityException if the current thread cannot
149.570 + * modify this thread.
149.571 + * @see #interrupt()
149.572 + * @see #checkAccess()
149.573 + * @see #run()
149.574 + * @see #start()
149.575 + * @see ThreadDeath
149.576 + * @see ThreadGroup#uncaughtException(Thread,Throwable)
149.577 + * @see SecurityManager#checkAccess(Thread)
149.578 + * @see SecurityManager#checkPermission
149.579 + * @deprecated This method is inherently unsafe. Stopping a thread with
149.580 + * Thread.stop causes it to unlock all of the monitors that it
149.581 + * has locked (as a natural consequence of the unchecked
149.582 + * <code>ThreadDeath</code> exception propagating up the stack). If
149.583 + * any of the objects previously protected by these monitors were in
149.584 + * an inconsistent state, the damaged objects become visible to
149.585 + * other threads, potentially resulting in arbitrary behavior. Many
149.586 + * uses of <code>stop</code> should be replaced by code that simply
149.587 + * modifies some variable to indicate that the target thread should
149.588 + * stop running. The target thread should check this variable
149.589 + * regularly, and return from its run method in an orderly fashion
149.590 + * if the variable indicates that it is to stop running. If the
149.591 + * target thread waits for long periods (on a condition variable,
149.592 + * for example), the <code>interrupt</code> method should be used to
149.593 + * interrupt the wait.
149.594 + * For more information, see
149.595 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
149.596 + * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
149.597 + */
149.598 + @Deprecated
149.599 + public final void stop() {
149.600 + stop(null);
149.601 + }
149.602 +
149.603 + /**
149.604 + * Forces the thread to stop executing.
149.605 + * <p>
149.606 + * If there is a security manager installed, the <code>checkAccess</code>
149.607 + * method of this thread is called, which may result in a
149.608 + * <code>SecurityException</code> being raised (in the current thread).
149.609 + * <p>
149.610 + * If this thread is different from the current thread (that is, the current
149.611 + * thread is trying to stop a thread other than itself) or
149.612 + * <code>obj</code> is not an instance of <code>ThreadDeath</code>, the
149.613 + * security manager's <code>checkPermission</code> method (with the
149.614 + * <code>RuntimePermission("stopThread")</code> argument) is called in
149.615 + * addition.
149.616 + * Again, this may result in throwing a
149.617 + * <code>SecurityException</code> (in the current thread).
149.618 + * <p>
149.619 + * If the argument <code>obj</code> is null, a
149.620 + * <code>NullPointerException</code> is thrown (in the current thread).
149.621 + * <p>
149.622 + * The thread represented by this thread is forced to stop
149.623 + * whatever it is doing abnormally and to throw the
149.624 + * <code>Throwable</code> object <code>obj</code> as an exception. This
149.625 + * is an unusual action to take; normally, the <code>stop</code> method
149.626 + * that takes no arguments should be used.
149.627 + * <p>
149.628 + * It is permitted to stop a thread that has not yet been started.
149.629 + * If the thread is eventually started, it immediately terminates.
149.630 + *
149.631 + * @param obj the Throwable object to be thrown.
149.632 + * @exception SecurityException if the current thread cannot modify
149.633 + * this thread.
149.634 + * @throws NullPointerException if obj is <tt>null</tt>.
149.635 + * @see #interrupt()
149.636 + * @see #checkAccess()
149.637 + * @see #run()
149.638 + * @see #start()
149.639 + * @see #stop()
149.640 + * @see SecurityManager#checkAccess(Thread)
149.641 + * @see SecurityManager#checkPermission
149.642 + * @deprecated This method is inherently unsafe. See {@link #stop()}
149.643 + * for details. An additional danger of this
149.644 + * method is that it may be used to generate exceptions that the
149.645 + * target thread is unprepared to handle (including checked
149.646 + * exceptions that the thread could not possibly throw, were it
149.647 + * not for this method).
149.648 + * For more information, see
149.649 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
149.650 + * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
149.651 + */
149.652 + @Deprecated
149.653 + public final synchronized void stop(Throwable obj) {
149.654 + throw new SecurityException();
149.655 + }
149.656 +
149.657 + /**
149.658 + * Interrupts this thread.
149.659 + *
149.660 + * <p> Unless the current thread is interrupting itself, which is
149.661 + * always permitted, the {@link #checkAccess() checkAccess} method
149.662 + * of this thread is invoked, which may cause a {@link
149.663 + * SecurityException} to be thrown.
149.664 + *
149.665 + * <p> If this thread is blocked in an invocation of the {@link
149.666 + * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
149.667 + * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
149.668 + * class, or of the {@link #join()}, {@link #join(long)}, {@link
149.669 + * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
149.670 + * methods of this class, then its interrupt status will be cleared and it
149.671 + * will receive an {@link InterruptedException}.
149.672 + *
149.673 + * <p> If this thread is blocked in an I/O operation upon an {@link
149.674 + * java.nio.channels.InterruptibleChannel </code>interruptible
149.675 + * channel<code>} then the channel will be closed, the thread's interrupt
149.676 + * status will be set, and the thread will receive a {@link
149.677 + * java.nio.channels.ClosedByInterruptException}.
149.678 + *
149.679 + * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
149.680 + * then the thread's interrupt status will be set and it will return
149.681 + * immediately from the selection operation, possibly with a non-zero
149.682 + * value, just as if the selector's {@link
149.683 + * java.nio.channels.Selector#wakeup wakeup} method were invoked.
149.684 + *
149.685 + * <p> If none of the previous conditions hold then this thread's interrupt
149.686 + * status will be set. </p>
149.687 + *
149.688 + * <p> Interrupting a thread that is not alive need not have any effect.
149.689 + *
149.690 + * @throws SecurityException
149.691 + * if the current thread cannot modify this thread
149.692 + *
149.693 + * @revised 6.0
149.694 + * @spec JSR-51
149.695 + */
149.696 + public void interrupt() {
149.697 + throw new SecurityException();
149.698 + }
149.699 +
149.700 + /**
149.701 + * Tests whether the current thread has been interrupted. The
149.702 + * <i>interrupted status</i> of the thread is cleared by this method. In
149.703 + * other words, if this method were to be called twice in succession, the
149.704 + * second call would return false (unless the current thread were
149.705 + * interrupted again, after the first call had cleared its interrupted
149.706 + * status and before the second call had examined it).
149.707 + *
149.708 + * <p>A thread interruption ignored because a thread was not alive
149.709 + * at the time of the interrupt will be reflected by this method
149.710 + * returning false.
149.711 + *
149.712 + * @return <code>true</code> if the current thread has been interrupted;
149.713 + * <code>false</code> otherwise.
149.714 + * @see #isInterrupted()
149.715 + * @revised 6.0
149.716 + */
149.717 + public static boolean interrupted() {
149.718 + return currentThread().isInterrupted();
149.719 + }
149.720 +
149.721 + /**
149.722 + * Tests whether this thread has been interrupted. The <i>interrupted
149.723 + * status</i> of the thread is unaffected by this method.
149.724 + *
149.725 + * <p>A thread interruption ignored because a thread was not alive
149.726 + * at the time of the interrupt will be reflected by this method
149.727 + * returning false.
149.728 + *
149.729 + * @return <code>true</code> if this thread has been interrupted;
149.730 + * <code>false</code> otherwise.
149.731 + * @see #interrupted()
149.732 + * @revised 6.0
149.733 + */
149.734 + public boolean isInterrupted() {
149.735 + return false;
149.736 + }
149.737 +
149.738 + /**
149.739 + * Throws {@link NoSuchMethodError}.
149.740 + *
149.741 + * @deprecated This method was originally designed to destroy this
149.742 + * thread without any cleanup. Any monitors it held would have
149.743 + * remained locked. However, the method was never implemented.
149.744 + * If if were to be implemented, it would be deadlock-prone in
149.745 + * much the manner of {@link #suspend}. If the target thread held
149.746 + * a lock protecting a critical system resource when it was
149.747 + * destroyed, no thread could ever access this resource again.
149.748 + * If another thread ever attempted to lock this resource, deadlock
149.749 + * would result. Such deadlocks typically manifest themselves as
149.750 + * "frozen" processes. For more information, see
149.751 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">
149.752 + * Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
149.753 + * @throws NoSuchMethodError always
149.754 + */
149.755 + @Deprecated
149.756 + public void destroy() {
149.757 + throw new SecurityException();
149.758 + }
149.759 +
149.760 + /**
149.761 + * Tests if this thread is alive. A thread is alive if it has
149.762 + * been started and has not yet died.
149.763 + *
149.764 + * @return <code>true</code> if this thread is alive;
149.765 + * <code>false</code> otherwise.
149.766 + */
149.767 + public final boolean isAlive() {
149.768 + return true;
149.769 + }
149.770 +
149.771 + /**
149.772 + * Suspends this thread.
149.773 + * <p>
149.774 + * First, the <code>checkAccess</code> method of this thread is called
149.775 + * with no arguments. This may result in throwing a
149.776 + * <code>SecurityException </code>(in the current thread).
149.777 + * <p>
149.778 + * If the thread is alive, it is suspended and makes no further
149.779 + * progress unless and until it is resumed.
149.780 + *
149.781 + * @exception SecurityException if the current thread cannot modify
149.782 + * this thread.
149.783 + * @see #checkAccess
149.784 + * @deprecated This method has been deprecated, as it is
149.785 + * inherently deadlock-prone. If the target thread holds a lock on the
149.786 + * monitor protecting a critical system resource when it is suspended, no
149.787 + * thread can access this resource until the target thread is resumed. If
149.788 + * the thread that would resume the target thread attempts to lock this
149.789 + * monitor prior to calling <code>resume</code>, deadlock results. Such
149.790 + * deadlocks typically manifest themselves as "frozen" processes.
149.791 + * For more information, see
149.792 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
149.793 + * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
149.794 + */
149.795 + @Deprecated
149.796 + public final void suspend() {
149.797 + checkAccess();
149.798 + }
149.799 +
149.800 + /**
149.801 + * Resumes a suspended thread.
149.802 + * <p>
149.803 + * First, the <code>checkAccess</code> method of this thread is called
149.804 + * with no arguments. This may result in throwing a
149.805 + * <code>SecurityException</code> (in the current thread).
149.806 + * <p>
149.807 + * If the thread is alive but suspended, it is resumed and is
149.808 + * permitted to make progress in its execution.
149.809 + *
149.810 + * @exception SecurityException if the current thread cannot modify this
149.811 + * thread.
149.812 + * @see #checkAccess
149.813 + * @see #suspend()
149.814 + * @deprecated This method exists solely for use with {@link #suspend},
149.815 + * which has been deprecated because it is deadlock-prone.
149.816 + * For more information, see
149.817 + * <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
149.818 + * are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
149.819 + */
149.820 + @Deprecated
149.821 + public final void resume() {
149.822 + checkAccess();
149.823 + }
149.824 +
149.825 + /**
149.826 + * Changes the priority of this thread.
149.827 + * <p>
149.828 + * First the <code>checkAccess</code> method of this thread is called
149.829 + * with no arguments. This may result in throwing a
149.830 + * <code>SecurityException</code>.
149.831 + * <p>
149.832 + * Otherwise, the priority of this thread is set to the smaller of
149.833 + * the specified <code>newPriority</code> and the maximum permitted
149.834 + * priority of the thread's thread group.
149.835 + *
149.836 + * @param newPriority priority to set this thread to
149.837 + * @exception IllegalArgumentException If the priority is not in the
149.838 + * range <code>MIN_PRIORITY</code> to
149.839 + * <code>MAX_PRIORITY</code>.
149.840 + * @exception SecurityException if the current thread cannot modify
149.841 + * this thread.
149.842 + * @see #getPriority
149.843 + * @see #checkAccess()
149.844 + * @see #getThreadGroup()
149.845 + * @see #MAX_PRIORITY
149.846 + * @see #MIN_PRIORITY
149.847 + * @see ThreadGroup#getMaxPriority()
149.848 + */
149.849 + public final void setPriority(int newPriority) {
149.850 + throw new SecurityException();
149.851 + }
149.852 +
149.853 + /**
149.854 + * Returns this thread's priority.
149.855 + *
149.856 + * @return this thread's priority.
149.857 + * @see #setPriority
149.858 + */
149.859 + public final int getPriority() {
149.860 + return Thread.NORM_PRIORITY;
149.861 + }
149.862 +
149.863 + /**
149.864 + * Changes the name of this thread to be equal to the argument
149.865 + * <code>name</code>.
149.866 + * <p>
149.867 + * First the <code>checkAccess</code> method of this thread is called
149.868 + * with no arguments. This may result in throwing a
149.869 + * <code>SecurityException</code>.
149.870 + *
149.871 + * @param name the new name for this thread.
149.872 + * @exception SecurityException if the current thread cannot modify this
149.873 + * thread.
149.874 + * @see #getName
149.875 + * @see #checkAccess()
149.876 + */
149.877 + public final void setName(String name) {
149.878 + throw new SecurityException();
149.879 + }
149.880 +
149.881 + /**
149.882 + * Returns this thread's name.
149.883 + *
149.884 + * @return this thread's name.
149.885 + * @see #setName(String)
149.886 + */
149.887 + public final String getName() {
149.888 + return String.valueOf(name);
149.889 + }
149.890 +
149.891 + /**
149.892 + * Returns the thread group to which this thread belongs.
149.893 + * This method returns null if this thread has died
149.894 + * (been stopped).
149.895 + *
149.896 + * @return this thread's thread group.
149.897 + */
149.898 +// public final ThreadGroup getThreadGroup() {
149.899 +// return group;
149.900 +// }
149.901 +
149.902 + /**
149.903 + * Returns an estimate of the number of active threads in the current
149.904 + * thread's {@linkplain java.lang.ThreadGroup thread group} and its
149.905 + * subgroups. Recursively iterates over all subgroups in the current
149.906 + * thread's thread group.
149.907 + *
149.908 + * <p> The value returned is only an estimate because the number of
149.909 + * threads may change dynamically while this method traverses internal
149.910 + * data structures, and might be affected by the presence of certain
149.911 + * system threads. This method is intended primarily for debugging
149.912 + * and monitoring purposes.
149.913 + *
149.914 + * @return an estimate of the number of active threads in the current
149.915 + * thread's thread group and in any other thread group that
149.916 + * has the current thread's thread group as an ancestor
149.917 + */
149.918 + public static int activeCount() {
149.919 + return 1;
149.920 + }
149.921 +
149.922 + /**
149.923 + * Copies into the specified array every active thread in the current
149.924 + * thread's thread group and its subgroups. This method simply
149.925 + * invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])}
149.926 + * method of the current thread's thread group.
149.927 + *
149.928 + * <p> An application might use the {@linkplain #activeCount activeCount}
149.929 + * method to get an estimate of how big the array should be, however
149.930 + * <i>if the array is too short to hold all the threads, the extra threads
149.931 + * are silently ignored.</i> If it is critical to obtain every active
149.932 + * thread in the current thread's thread group and its subgroups, the
149.933 + * invoker should verify that the returned int value is strictly less
149.934 + * than the length of {@code tarray}.
149.935 + *
149.936 + * <p> Due to the inherent race condition in this method, it is recommended
149.937 + * that the method only be used for debugging and monitoring purposes.
149.938 + *
149.939 + * @param tarray
149.940 + * an array into which to put the list of threads
149.941 + *
149.942 + * @return the number of threads put into the array
149.943 + *
149.944 + * @throws SecurityException
149.945 + * if {@link java.lang.ThreadGroup#checkAccess} determines that
149.946 + * the current thread cannot access its thread group
149.947 + */
149.948 + public static int enumerate(Thread tarray[]) {
149.949 + throw new SecurityException();
149.950 + }
149.951 +
149.952 + /**
149.953 + * Counts the number of stack frames in this thread. The thread must
149.954 + * be suspended.
149.955 + *
149.956 + * @return the number of stack frames in this thread.
149.957 + * @exception IllegalThreadStateException if this thread is not
149.958 + * suspended.
149.959 + * @deprecated The definition of this call depends on {@link #suspend},
149.960 + * which is deprecated. Further, the results of this call
149.961 + * were never well-defined.
149.962 + */
149.963 + @Deprecated
149.964 + public native int countStackFrames();
149.965 +
149.966 + /**
149.967 + * Waits at most {@code millis} milliseconds for this thread to
149.968 + * die. A timeout of {@code 0} means to wait forever.
149.969 + *
149.970 + * <p> This implementation uses a loop of {@code this.wait} calls
149.971 + * conditioned on {@code this.isAlive}. As a thread terminates the
149.972 + * {@code this.notifyAll} method is invoked. It is recommended that
149.973 + * applications not use {@code wait}, {@code notify}, or
149.974 + * {@code notifyAll} on {@code Thread} instances.
149.975 + *
149.976 + * @param millis
149.977 + * the time to wait in milliseconds
149.978 + *
149.979 + * @throws IllegalArgumentException
149.980 + * if the value of {@code millis} is negative
149.981 + *
149.982 + * @throws InterruptedException
149.983 + * if any thread has interrupted the current thread. The
149.984 + * <i>interrupted status</i> of the current thread is
149.985 + * cleared when this exception is thrown.
149.986 + */
149.987 + public final synchronized void join(long millis)
149.988 + throws InterruptedException {
149.989 + long base = System.currentTimeMillis();
149.990 + long now = 0;
149.991 +
149.992 + if (millis < 0) {
149.993 + throw new IllegalArgumentException("timeout value is negative");
149.994 + }
149.995 +
149.996 + if (millis == 0) {
149.997 + while (isAlive()) {
149.998 + wait(0);
149.999 + }
149.1000 + } else {
149.1001 + while (isAlive()) {
149.1002 + long delay = millis - now;
149.1003 + if (delay <= 0) {
149.1004 + break;
149.1005 + }
149.1006 + wait(delay);
149.1007 + now = System.currentTimeMillis() - base;
149.1008 + }
149.1009 + }
149.1010 + }
149.1011 +
149.1012 + /**
149.1013 + * Waits at most {@code millis} milliseconds plus
149.1014 + * {@code nanos} nanoseconds for this thread to die.
149.1015 + *
149.1016 + * <p> This implementation uses a loop of {@code this.wait} calls
149.1017 + * conditioned on {@code this.isAlive}. As a thread terminates the
149.1018 + * {@code this.notifyAll} method is invoked. It is recommended that
149.1019 + * applications not use {@code wait}, {@code notify}, or
149.1020 + * {@code notifyAll} on {@code Thread} instances.
149.1021 + *
149.1022 + * @param millis
149.1023 + * the time to wait in milliseconds
149.1024 + *
149.1025 + * @param nanos
149.1026 + * {@code 0-999999} additional nanoseconds to wait
149.1027 + *
149.1028 + * @throws IllegalArgumentException
149.1029 + * if the value of {@code millis} is negative, or the value
149.1030 + * of {@code nanos} is not in the range {@code 0-999999}
149.1031 + *
149.1032 + * @throws InterruptedException
149.1033 + * if any thread has interrupted the current thread. The
149.1034 + * <i>interrupted status</i> of the current thread is
149.1035 + * cleared when this exception is thrown.
149.1036 + */
149.1037 + public final synchronized void join(long millis, int nanos)
149.1038 + throws InterruptedException {
149.1039 +
149.1040 + if (millis < 0) {
149.1041 + throw new IllegalArgumentException("timeout value is negative");
149.1042 + }
149.1043 +
149.1044 + if (nanos < 0 || nanos > 999999) {
149.1045 + throw new IllegalArgumentException(
149.1046 + "nanosecond timeout value out of range");
149.1047 + }
149.1048 +
149.1049 + if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
149.1050 + millis++;
149.1051 + }
149.1052 +
149.1053 + join(millis);
149.1054 + }
149.1055 +
149.1056 + /**
149.1057 + * Waits for this thread to die.
149.1058 + *
149.1059 + * <p> An invocation of this method behaves in exactly the same
149.1060 + * way as the invocation
149.1061 + *
149.1062 + * <blockquote>
149.1063 + * {@linkplain #join(long) join}{@code (0)}
149.1064 + * </blockquote>
149.1065 + *
149.1066 + * @throws InterruptedException
149.1067 + * if any thread has interrupted the current thread. The
149.1068 + * <i>interrupted status</i> of the current thread is
149.1069 + * cleared when this exception is thrown.
149.1070 + */
149.1071 + public final void join() throws InterruptedException {
149.1072 + join(0);
149.1073 + }
149.1074 +
149.1075 + /**
149.1076 + * Prints a stack trace of the current thread to the standard error stream.
149.1077 + * This method is used only for debugging.
149.1078 + *
149.1079 + * @see Throwable#printStackTrace()
149.1080 + */
149.1081 + public static void dumpStack() {
149.1082 + new Exception("Stack trace").printStackTrace();
149.1083 + }
149.1084 +
149.1085 + /**
149.1086 + * Marks this thread as either a {@linkplain #isDaemon daemon} thread
149.1087 + * or a user thread. The Java Virtual Machine exits when the only
149.1088 + * threads running are all daemon threads.
149.1089 + *
149.1090 + * <p> This method must be invoked before the thread is started.
149.1091 + *
149.1092 + * @param on
149.1093 + * if {@code true}, marks this thread as a daemon thread
149.1094 + *
149.1095 + * @throws IllegalThreadStateException
149.1096 + * if this thread is {@linkplain #isAlive alive}
149.1097 + *
149.1098 + * @throws SecurityException
149.1099 + * if {@link #checkAccess} determines that the current
149.1100 + * thread cannot modify this thread
149.1101 + */
149.1102 + public final void setDaemon(boolean on) {
149.1103 + throw new SecurityException();
149.1104 + }
149.1105 +
149.1106 + /**
149.1107 + * Tests if this thread is a daemon thread.
149.1108 + *
149.1109 + * @return <code>true</code> if this thread is a daemon thread;
149.1110 + * <code>false</code> otherwise.
149.1111 + * @see #setDaemon(boolean)
149.1112 + */
149.1113 + public final boolean isDaemon() {
149.1114 + return false;
149.1115 + }
149.1116 +
149.1117 + /**
149.1118 + * Determines if the currently running thread has permission to
149.1119 + * modify this thread.
149.1120 + * <p>
149.1121 + * If there is a security manager, its <code>checkAccess</code> method
149.1122 + * is called with this thread as its argument. This may result in
149.1123 + * throwing a <code>SecurityException</code>.
149.1124 + *
149.1125 + * @exception SecurityException if the current thread is not allowed to
149.1126 + * access this thread.
149.1127 + * @see SecurityManager#checkAccess(Thread)
149.1128 + */
149.1129 + public final void checkAccess() {
149.1130 + throw new SecurityException();
149.1131 + }
149.1132 +
149.1133 + /**
149.1134 + * Returns a string representation of this thread, including the
149.1135 + * thread's name, priority, and thread group.
149.1136 + *
149.1137 + * @return a string representation of this thread.
149.1138 + */
149.1139 + public String toString() {
149.1140 + return "Thread[" + getName() + "," + getPriority() + "," +
149.1141 + "" + "]";
149.1142 + }
149.1143 +
149.1144 + /**
149.1145 + * Returns the context ClassLoader for this Thread. The context
149.1146 + * ClassLoader is provided by the creator of the thread for use
149.1147 + * by code running in this thread when loading classes and resources.
149.1148 + * If not {@linkplain #setContextClassLoader set}, the default is the
149.1149 + * ClassLoader context of the parent Thread. The context ClassLoader of the
149.1150 + * primordial thread is typically set to the class loader used to load the
149.1151 + * application.
149.1152 + *
149.1153 + * <p>If a security manager is present, and the invoker's class loader is not
149.1154 + * {@code null} and is not the same as or an ancestor of the context class
149.1155 + * loader, then this method invokes the security manager's {@link
149.1156 + * SecurityManager#checkPermission(java.security.Permission) checkPermission}
149.1157 + * method with a {@link RuntimePermission RuntimePermission}{@code
149.1158 + * ("getClassLoader")} permission to verify that retrieval of the context
149.1159 + * class loader is permitted.
149.1160 + *
149.1161 + * @return the context ClassLoader for this Thread, or {@code null}
149.1162 + * indicating the system class loader (or, failing that, the
149.1163 + * bootstrap class loader)
149.1164 + *
149.1165 + * @throws SecurityException
149.1166 + * if the current thread cannot get the context ClassLoader
149.1167 + *
149.1168 + * @since 1.2
149.1169 + */
149.1170 + public ClassLoader getContextClassLoader() {
149.1171 + return ClassLoader.getSystemClassLoader();
149.1172 + }
149.1173 +
149.1174 + /**
149.1175 + * Sets the context ClassLoader for this Thread. The context
149.1176 + * ClassLoader can be set when a thread is created, and allows
149.1177 + * the creator of the thread to provide the appropriate class loader,
149.1178 + * through {@code getContextClassLoader}, to code running in the thread
149.1179 + * when loading classes and resources.
149.1180 + *
149.1181 + * <p>If a security manager is present, its {@link
149.1182 + * SecurityManager#checkPermission(java.security.Permission) checkPermission}
149.1183 + * method is invoked with a {@link RuntimePermission RuntimePermission}{@code
149.1184 + * ("setContextClassLoader")} permission to see if setting the context
149.1185 + * ClassLoader is permitted.
149.1186 + *
149.1187 + * @param cl
149.1188 + * the context ClassLoader for this Thread, or null indicating the
149.1189 + * system class loader (or, failing that, the bootstrap class loader)
149.1190 + *
149.1191 + * @throws SecurityException
149.1192 + * if the current thread cannot set the context ClassLoader
149.1193 + *
149.1194 + * @since 1.2
149.1195 + */
149.1196 + public void setContextClassLoader(ClassLoader cl) {
149.1197 + if (cl == ClassLoader.getSystemClassLoader()) {
149.1198 + return;
149.1199 + }
149.1200 + throw new SecurityException();
149.1201 + }
149.1202 +
149.1203 + /**
149.1204 + * Returns <tt>true</tt> if and only if the current thread holds the
149.1205 + * monitor lock on the specified object.
149.1206 + *
149.1207 + * <p>This method is designed to allow a program to assert that
149.1208 + * the current thread already holds a specified lock:
149.1209 + * <pre>
149.1210 + * assert Thread.holdsLock(obj);
149.1211 + * </pre>
149.1212 + *
149.1213 + * @param obj the object on which to test lock ownership
149.1214 + * @throws NullPointerException if obj is <tt>null</tt>
149.1215 + * @return <tt>true</tt> if the current thread holds the monitor lock on
149.1216 + * the specified object.
149.1217 + * @since 1.4
149.1218 + */
149.1219 + public static boolean holdsLock(Object obj) {
149.1220 + return true;
149.1221 + }
149.1222 +
149.1223 + /**
149.1224 + * Returns an array of stack trace elements representing the stack dump
149.1225 + * of this thread. This method will return a zero-length array if
149.1226 + * this thread has not started, has started but has not yet been
149.1227 + * scheduled to run by the system, or has terminated.
149.1228 + * If the returned array is of non-zero length then the first element of
149.1229 + * the array represents the top of the stack, which is the most recent
149.1230 + * method invocation in the sequence. The last element of the array
149.1231 + * represents the bottom of the stack, which is the least recent method
149.1232 + * invocation in the sequence.
149.1233 + *
149.1234 + * <p>If there is a security manager, and this thread is not
149.1235 + * the current thread, then the security manager's
149.1236 + * <tt>checkPermission</tt> method is called with a
149.1237 + * <tt>RuntimePermission("getStackTrace")</tt> permission
149.1238 + * to see if it's ok to get the stack trace.
149.1239 + *
149.1240 + * <p>Some virtual machines may, under some circumstances, omit one
149.1241 + * or more stack frames from the stack trace. In the extreme case,
149.1242 + * a virtual machine that has no stack trace information concerning
149.1243 + * this thread is permitted to return a zero-length array from this
149.1244 + * method.
149.1245 + *
149.1246 + * @return an array of <tt>StackTraceElement</tt>,
149.1247 + * each represents one stack frame.
149.1248 + *
149.1249 + * @throws SecurityException
149.1250 + * if a security manager exists and its
149.1251 + * <tt>checkPermission</tt> method doesn't allow
149.1252 + * getting the stack trace of thread.
149.1253 + * @see SecurityManager#checkPermission
149.1254 + * @see RuntimePermission
149.1255 + * @see Throwable#getStackTrace
149.1256 + *
149.1257 + * @since 1.5
149.1258 + */
149.1259 + public StackTraceElement[] getStackTrace() {
149.1260 + throw new SecurityException();
149.1261 + }
149.1262 +
149.1263 + /**
149.1264 + * Returns a map of stack traces for all live threads.
149.1265 + * The map keys are threads and each map value is an array of
149.1266 + * <tt>StackTraceElement</tt> that represents the stack dump
149.1267 + * of the corresponding <tt>Thread</tt>.
149.1268 + * The returned stack traces are in the format specified for
149.1269 + * the {@link #getStackTrace getStackTrace} method.
149.1270 + *
149.1271 + * <p>The threads may be executing while this method is called.
149.1272 + * The stack trace of each thread only represents a snapshot and
149.1273 + * each stack trace may be obtained at different time. A zero-length
149.1274 + * array will be returned in the map value if the virtual machine has
149.1275 + * no stack trace information about a thread.
149.1276 + *
149.1277 + * <p>If there is a security manager, then the security manager's
149.1278 + * <tt>checkPermission</tt> method is called with a
149.1279 + * <tt>RuntimePermission("getStackTrace")</tt> permission as well as
149.1280 + * <tt>RuntimePermission("modifyThreadGroup")</tt> permission
149.1281 + * to see if it is ok to get the stack trace of all threads.
149.1282 + *
149.1283 + * @return a <tt>Map</tt> from <tt>Thread</tt> to an array of
149.1284 + * <tt>StackTraceElement</tt> that represents the stack trace of
149.1285 + * the corresponding thread.
149.1286 + *
149.1287 + * @throws SecurityException
149.1288 + * if a security manager exists and its
149.1289 + * <tt>checkPermission</tt> method doesn't allow
149.1290 + * getting the stack trace of thread.
149.1291 + * @see #getStackTrace
149.1292 + * @see SecurityManager#checkPermission
149.1293 + * @see RuntimePermission
149.1294 + * @see Throwable#getStackTrace
149.1295 + *
149.1296 + * @since 1.5
149.1297 + */
149.1298 + public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
149.1299 + throw new SecurityException();
149.1300 + }
149.1301 +
149.1302 + /**
149.1303 + * Returns the identifier of this Thread. The thread ID is a positive
149.1304 + * <tt>long</tt> number generated when this thread was created.
149.1305 + * The thread ID is unique and remains unchanged during its lifetime.
149.1306 + * When a thread is terminated, this thread ID may be reused.
149.1307 + *
149.1308 + * @return this thread's ID.
149.1309 + * @since 1.5
149.1310 + */
149.1311 + public long getId() {
149.1312 + return 0;
149.1313 + }
149.1314 +
149.1315 + /**
149.1316 + * A thread state. A thread can be in one of the following states:
149.1317 + * <ul>
149.1318 + * <li>{@link #NEW}<br>
149.1319 + * A thread that has not yet started is in this state.
149.1320 + * </li>
149.1321 + * <li>{@link #RUNNABLE}<br>
149.1322 + * A thread executing in the Java virtual machine is in this state.
149.1323 + * </li>
149.1324 + * <li>{@link #BLOCKED}<br>
149.1325 + * A thread that is blocked waiting for a monitor lock
149.1326 + * is in this state.
149.1327 + * </li>
149.1328 + * <li>{@link #WAITING}<br>
149.1329 + * A thread that is waiting indefinitely for another thread to
149.1330 + * perform a particular action is in this state.
149.1331 + * </li>
149.1332 + * <li>{@link #TIMED_WAITING}<br>
149.1333 + * A thread that is waiting for another thread to perform an action
149.1334 + * for up to a specified waiting time is in this state.
149.1335 + * </li>
149.1336 + * <li>{@link #TERMINATED}<br>
149.1337 + * A thread that has exited is in this state.
149.1338 + * </li>
149.1339 + * </ul>
149.1340 + *
149.1341 + * <p>
149.1342 + * A thread can be in only one state at a given point in time.
149.1343 + * These states are virtual machine states which do not reflect
149.1344 + * any operating system thread states.
149.1345 + *
149.1346 + * @since 1.5
149.1347 + * @see #getState
149.1348 + */
149.1349 + public enum State {
149.1350 + /**
149.1351 + * Thread state for a thread which has not yet started.
149.1352 + */
149.1353 + NEW,
149.1354 +
149.1355 + /**
149.1356 + * Thread state for a runnable thread. A thread in the runnable
149.1357 + * state is executing in the Java virtual machine but it may
149.1358 + * be waiting for other resources from the operating system
149.1359 + * such as processor.
149.1360 + */
149.1361 + RUNNABLE,
149.1362 +
149.1363 + /**
149.1364 + * Thread state for a thread blocked waiting for a monitor lock.
149.1365 + * A thread in the blocked state is waiting for a monitor lock
149.1366 + * to enter a synchronized block/method or
149.1367 + * reenter a synchronized block/method after calling
149.1368 + * {@link Object#wait() Object.wait}.
149.1369 + */
149.1370 + BLOCKED,
149.1371 +
149.1372 + /**
149.1373 + * Thread state for a waiting thread.
149.1374 + * A thread is in the waiting state due to calling one of the
149.1375 + * following methods:
149.1376 + * <ul>
149.1377 + * <li>{@link Object#wait() Object.wait} with no timeout</li>
149.1378 + * <li>{@link #join() Thread.join} with no timeout</li>
149.1379 + * <li>{@link LockSupport#park() LockSupport.park}</li>
149.1380 + * </ul>
149.1381 + *
149.1382 + * <p>A thread in the waiting state is waiting for another thread to
149.1383 + * perform a particular action.
149.1384 + *
149.1385 + * For example, a thread that has called <tt>Object.wait()</tt>
149.1386 + * on an object is waiting for another thread to call
149.1387 + * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
149.1388 + * that object. A thread that has called <tt>Thread.join()</tt>
149.1389 + * is waiting for a specified thread to terminate.
149.1390 + */
149.1391 + WAITING,
149.1392 +
149.1393 + /**
149.1394 + * Thread state for a waiting thread with a specified waiting time.
149.1395 + * A thread is in the timed waiting state due to calling one of
149.1396 + * the following methods with a specified positive waiting time:
149.1397 + * <ul>
149.1398 + * <li>{@link #sleep Thread.sleep}</li>
149.1399 + * <li>{@link Object#wait(long) Object.wait} with timeout</li>
149.1400 + * <li>{@link #join(long) Thread.join} with timeout</li>
149.1401 + * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
149.1402 + * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
149.1403 + * </ul>
149.1404 + */
149.1405 + TIMED_WAITING,
149.1406 +
149.1407 + /**
149.1408 + * Thread state for a terminated thread.
149.1409 + * The thread has completed execution.
149.1410 + */
149.1411 + TERMINATED;
149.1412 + }
149.1413 +
149.1414 + /**
149.1415 + * Returns the state of this thread.
149.1416 + * This method is designed for use in monitoring of the system state,
149.1417 + * not for synchronization control.
149.1418 + *
149.1419 + * @return this thread's state.
149.1420 + * @since 1.5
149.1421 + */
149.1422 + public State getState() {
149.1423 + // get current thread state
149.1424 + return State.RUNNABLE;
149.1425 + }
149.1426 +
149.1427 + // Added in JSR-166
149.1428 +
149.1429 + /**
149.1430 + * Interface for handlers invoked when a <tt>Thread</tt> abruptly
149.1431 + * terminates due to an uncaught exception.
149.1432 + * <p>When a thread is about to terminate due to an uncaught exception
149.1433 + * the Java Virtual Machine will query the thread for its
149.1434 + * <tt>UncaughtExceptionHandler</tt> using
149.1435 + * {@link #getUncaughtExceptionHandler} and will invoke the handler's
149.1436 + * <tt>uncaughtException</tt> method, passing the thread and the
149.1437 + * exception as arguments.
149.1438 + * If a thread has not had its <tt>UncaughtExceptionHandler</tt>
149.1439 + * explicitly set, then its <tt>ThreadGroup</tt> object acts as its
149.1440 + * <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object
149.1441 + * has no
149.1442 + * special requirements for dealing with the exception, it can forward
149.1443 + * the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
149.1444 + * default uncaught exception handler}.
149.1445 + *
149.1446 + * @see #setDefaultUncaughtExceptionHandler
149.1447 + * @see #setUncaughtExceptionHandler
149.1448 + * @see ThreadGroup#uncaughtException
149.1449 + * @since 1.5
149.1450 + */
149.1451 + public interface UncaughtExceptionHandler {
149.1452 + /**
149.1453 + * Method invoked when the given thread terminates due to the
149.1454 + * given uncaught exception.
149.1455 + * <p>Any exception thrown by this method will be ignored by the
149.1456 + * Java Virtual Machine.
149.1457 + * @param t the thread
149.1458 + * @param e the exception
149.1459 + */
149.1460 + void uncaughtException(Thread t, Throwable e);
149.1461 + }
149.1462 +
149.1463 + // null unless explicitly set
149.1464 + private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
149.1465 +
149.1466 + // null unless explicitly set
149.1467 + private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
149.1468 +
149.1469 + /**
149.1470 + * Set the default handler invoked when a thread abruptly terminates
149.1471 + * due to an uncaught exception, and no other handler has been defined
149.1472 + * for that thread.
149.1473 + *
149.1474 + * <p>Uncaught exception handling is controlled first by the thread, then
149.1475 + * by the thread's {@link ThreadGroup} object and finally by the default
149.1476 + * uncaught exception handler. If the thread does not have an explicit
149.1477 + * uncaught exception handler set, and the thread's thread group
149.1478 + * (including parent thread groups) does not specialize its
149.1479 + * <tt>uncaughtException</tt> method, then the default handler's
149.1480 + * <tt>uncaughtException</tt> method will be invoked.
149.1481 + * <p>By setting the default uncaught exception handler, an application
149.1482 + * can change the way in which uncaught exceptions are handled (such as
149.1483 + * logging to a specific device, or file) for those threads that would
149.1484 + * already accept whatever "default" behavior the system
149.1485 + * provided.
149.1486 + *
149.1487 + * <p>Note that the default uncaught exception handler should not usually
149.1488 + * defer to the thread's <tt>ThreadGroup</tt> object, as that could cause
149.1489 + * infinite recursion.
149.1490 + *
149.1491 + * @param eh the object to use as the default uncaught exception handler.
149.1492 + * If <tt>null</tt> then there is no default handler.
149.1493 + *
149.1494 + * @throws SecurityException if a security manager is present and it
149.1495 + * denies <tt>{@link RuntimePermission}
149.1496 + * ("setDefaultUncaughtExceptionHandler")</tt>
149.1497 + *
149.1498 + * @see #setUncaughtExceptionHandler
149.1499 + * @see #getUncaughtExceptionHandler
149.1500 + * @see ThreadGroup#uncaughtException
149.1501 + * @since 1.5
149.1502 + */
149.1503 + public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
149.1504 + throw new SecurityException();
149.1505 + }
149.1506 +
149.1507 + /**
149.1508 + * Returns the default handler invoked when a thread abruptly terminates
149.1509 + * due to an uncaught exception. If the returned value is <tt>null</tt>,
149.1510 + * there is no default.
149.1511 + * @since 1.5
149.1512 + * @see #setDefaultUncaughtExceptionHandler
149.1513 + */
149.1514 + public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
149.1515 + return defaultUncaughtExceptionHandler;
149.1516 + }
149.1517 +
149.1518 + /**
149.1519 + * Returns the handler invoked when this thread abruptly terminates
149.1520 + * due to an uncaught exception. If this thread has not had an
149.1521 + * uncaught exception handler explicitly set then this thread's
149.1522 + * <tt>ThreadGroup</tt> object is returned, unless this thread
149.1523 + * has terminated, in which case <tt>null</tt> is returned.
149.1524 + * @since 1.5
149.1525 + */
149.1526 + public UncaughtExceptionHandler getUncaughtExceptionHandler() {
149.1527 + return uncaughtExceptionHandler != null ?
149.1528 + uncaughtExceptionHandler : null;
149.1529 + }
149.1530 +
149.1531 + /**
149.1532 + * Set the handler invoked when this thread abruptly terminates
149.1533 + * due to an uncaught exception.
149.1534 + * <p>A thread can take full control of how it responds to uncaught
149.1535 + * exceptions by having its uncaught exception handler explicitly set.
149.1536 + * If no such handler is set then the thread's <tt>ThreadGroup</tt>
149.1537 + * object acts as its handler.
149.1538 + * @param eh the object to use as this thread's uncaught exception
149.1539 + * handler. If <tt>null</tt> then this thread has no explicit handler.
149.1540 + * @throws SecurityException if the current thread is not allowed to
149.1541 + * modify this thread.
149.1542 + * @see #setDefaultUncaughtExceptionHandler
149.1543 + * @see ThreadGroup#uncaughtException
149.1544 + * @since 1.5
149.1545 + */
149.1546 + public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
149.1547 + checkAccess();
149.1548 + uncaughtExceptionHandler = eh;
149.1549 + }
149.1550 +}
150.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
150.2 +++ b/rt/emul/compact/src/main/java/java/lang/ThreadLocal.java Wed Apr 30 15:04:10 2014 +0200
150.3 @@ -0,0 +1,157 @@
150.4 +/*
150.5 + * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
150.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
150.7 + *
150.8 + * This code is free software; you can redistribute it and/or modify it
150.9 + * under the terms of the GNU General Public License version 2 only, as
150.10 + * published by the Free Software Foundation. Oracle designates this
150.11 + * particular file as subject to the "Classpath" exception as provided
150.12 + * by Oracle in the LICENSE file that accompanied this code.
150.13 + *
150.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
150.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
150.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
150.17 + * version 2 for more details (a copy is included in the LICENSE file that
150.18 + * accompanied this code).
150.19 + *
150.20 + * You should have received a copy of the GNU General Public License version
150.21 + * 2 along with this work; if not, write to the Free Software Foundation,
150.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
150.23 + *
150.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
150.25 + * or visit www.oracle.com if you need additional information or have any
150.26 + * questions.
150.27 + */
150.28 +
150.29 +package java.lang;
150.30 +
150.31 +/**
150.32 + * This class provides thread-local variables. These variables differ from
150.33 + * their normal counterparts in that each thread that accesses one (via its
150.34 + * <tt>get</tt> or <tt>set</tt> method) has its own, independently initialized
150.35 + * copy of the variable. <tt>ThreadLocal</tt> instances are typically private
150.36 + * static fields in classes that wish to associate state with a thread (e.g.,
150.37 + * a user ID or Transaction ID).
150.38 + *
150.39 + * <p>For example, the class below generates unique identifiers local to each
150.40 + * thread.
150.41 + * A thread's id is assigned the first time it invokes <tt>ThreadId.get()</tt>
150.42 + * and remains unchanged on subsequent calls.
150.43 + * <pre>
150.44 + * import java.util.concurrent.atomic.AtomicInteger;
150.45 + *
150.46 + * public class ThreadId {
150.47 + * // Atomic integer containing the next thread ID to be assigned
150.48 + * private static final AtomicInteger nextId = new AtomicInteger(0);
150.49 + *
150.50 + * // Thread local variable containing each thread's ID
150.51 + * private static final ThreadLocal<Integer> threadId =
150.52 + * new ThreadLocal<Integer>() {
150.53 + * @Override protected Integer initialValue() {
150.54 + * return nextId.getAndIncrement();
150.55 + * }
150.56 + * };
150.57 + *
150.58 + * // Returns the current thread's unique ID, assigning it if necessary
150.59 + * public static int get() {
150.60 + * return threadId.get();
150.61 + * }
150.62 + * }
150.63 + * </pre>
150.64 + * <p>Each thread holds an implicit reference to its copy of a thread-local
150.65 + * variable as long as the thread is alive and the <tt>ThreadLocal</tt>
150.66 + * instance is accessible; after a thread goes away, all of its copies of
150.67 + * thread-local instances are subject to garbage collection (unless other
150.68 + * references to these copies exist).
150.69 + *
150.70 + * @author Josh Bloch and Doug Lea
150.71 + * @since 1.2
150.72 + */
150.73 +public class ThreadLocal<T> {
150.74 + private static final Object NONE = new Object();
150.75 + private Object value = NONE;
150.76 +
150.77 + /**
150.78 + * Returns the current thread's "initial value" for this
150.79 + * thread-local variable. This method will be invoked the first
150.80 + * time a thread accesses the variable with the {@link #get}
150.81 + * method, unless the thread previously invoked the {@link #set}
150.82 + * method, in which case the <tt>initialValue</tt> method will not
150.83 + * be invoked for the thread. Normally, this method is invoked at
150.84 + * most once per thread, but it may be invoked again in case of
150.85 + * subsequent invocations of {@link #remove} followed by {@link #get}.
150.86 + *
150.87 + * <p>This implementation simply returns <tt>null</tt>; if the
150.88 + * programmer desires thread-local variables to have an initial
150.89 + * value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be
150.90 + * subclassed, and this method overridden. Typically, an
150.91 + * anonymous inner class will be used.
150.92 + *
150.93 + * @return the initial value for this thread-local
150.94 + */
150.95 + protected T initialValue() {
150.96 + return null;
150.97 + }
150.98 +
150.99 + /**
150.100 + * Creates a thread local variable.
150.101 + */
150.102 + public ThreadLocal() {
150.103 + }
150.104 +
150.105 + /**
150.106 + * Returns the value in the current thread's copy of this
150.107 + * thread-local variable. If the variable has no value for the
150.108 + * current thread, it is first initialized to the value returned
150.109 + * by an invocation of the {@link #initialValue} method.
150.110 + *
150.111 + * @return the current thread's value of this thread-local
150.112 + */
150.113 + public T get() {
150.114 + if (value == NONE) {
150.115 + return setInitialValue();
150.116 + } else {
150.117 + return (T)value;
150.118 + }
150.119 + }
150.120 +
150.121 + /**
150.122 + * Variant of set() to establish initialValue. Used instead
150.123 + * of set() in case user has overridden the set() method.
150.124 + *
150.125 + * @return the initial value
150.126 + */
150.127 + private T setInitialValue() {
150.128 + T v = initialValue();
150.129 + this.value = v;
150.130 + return v;
150.131 + }
150.132 +
150.133 + /**
150.134 + * Sets the current thread's copy of this thread-local variable
150.135 + * to the specified value. Most subclasses will have no need to
150.136 + * override this method, relying solely on the {@link #initialValue}
150.137 + * method to set the values of thread-locals.
150.138 + *
150.139 + * @param value the value to be stored in the current thread's copy of
150.140 + * this thread-local.
150.141 + */
150.142 + public void set(T value) {
150.143 + this.value = value;
150.144 + }
150.145 +
150.146 + /**
150.147 + * Removes the current thread's value for this thread-local
150.148 + * variable. If this thread-local variable is subsequently
150.149 + * {@linkplain #get read} by the current thread, its value will be
150.150 + * reinitialized by invoking its {@link #initialValue} method,
150.151 + * unless its value is {@linkplain #set set} by the current thread
150.152 + * in the interim. This may result in multiple invocations of the
150.153 + * <tt>initialValue</tt> method in the current thread.
150.154 + *
150.155 + * @since 1.5
150.156 + */
150.157 + public void remove() {
150.158 + this.value = NONE;
150.159 + }
150.160 +}
151.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
151.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Annotation.java Wed Apr 30 15:04:10 2014 +0200
151.3 @@ -0,0 +1,131 @@
151.4 +/*
151.5 + * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
151.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
151.7 + *
151.8 + * This code is free software; you can redistribute it and/or modify it
151.9 + * under the terms of the GNU General Public License version 2 only, as
151.10 + * published by the Free Software Foundation. Oracle designates this
151.11 + * particular file as subject to the "Classpath" exception as provided
151.12 + * by Oracle in the LICENSE file that accompanied this code.
151.13 + *
151.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
151.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
151.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
151.17 + * version 2 for more details (a copy is included in the LICENSE file that
151.18 + * accompanied this code).
151.19 + *
151.20 + * You should have received a copy of the GNU General Public License version
151.21 + * 2 along with this work; if not, write to the Free Software Foundation,
151.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
151.23 + *
151.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
151.25 + * or visit www.oracle.com if you need additional information or have any
151.26 + * questions.
151.27 + */
151.28 +
151.29 +package java.lang.annotation;
151.30 +
151.31 +/**
151.32 + * The common interface extended by all annotation types. Note that an
151.33 + * interface that manually extends this one does <i>not</i> define
151.34 + * an annotation type. Also note that this interface does not itself
151.35 + * define an annotation type.
151.36 + *
151.37 + * More information about annotation types can be found in section 9.6 of
151.38 + * <cite>The Java™ Language Specification</cite>.
151.39 + *
151.40 + * @author Josh Bloch
151.41 + * @since 1.5
151.42 + */
151.43 +public interface Annotation {
151.44 + /**
151.45 + * Returns true if the specified object represents an annotation
151.46 + * that is logically equivalent to this one. In other words,
151.47 + * returns true if the specified object is an instance of the same
151.48 + * annotation type as this instance, all of whose members are equal
151.49 + * to the corresponding member of this annotation, as defined below:
151.50 + * <ul>
151.51 + * <li>Two corresponding primitive typed members whose values are
151.52 + * <tt>x</tt> and <tt>y</tt> are considered equal if <tt>x == y</tt>,
151.53 + * unless their type is <tt>float</tt> or <tt>double</tt>.
151.54 + *
151.55 + * <li>Two corresponding <tt>float</tt> members whose values
151.56 + * are <tt>x</tt> and <tt>y</tt> are considered equal if
151.57 + * <tt>Float.valueOf(x).equals(Float.valueOf(y))</tt>.
151.58 + * (Unlike the <tt>==</tt> operator, NaN is considered equal
151.59 + * to itself, and <tt>0.0f</tt> unequal to <tt>-0.0f</tt>.)
151.60 + *
151.61 + * <li>Two corresponding <tt>double</tt> members whose values
151.62 + * are <tt>x</tt> and <tt>y</tt> are considered equal if
151.63 + * <tt>Double.valueOf(x).equals(Double.valueOf(y))</tt>.
151.64 + * (Unlike the <tt>==</tt> operator, NaN is considered equal
151.65 + * to itself, and <tt>0.0</tt> unequal to <tt>-0.0</tt>.)
151.66 + *
151.67 + * <li>Two corresponding <tt>String</tt>, <tt>Class</tt>, enum, or
151.68 + * annotation typed members whose values are <tt>x</tt> and <tt>y</tt>
151.69 + * are considered equal if <tt>x.equals(y)</tt>. (Note that this
151.70 + * definition is recursive for annotation typed members.)
151.71 + *
151.72 + * <li>Two corresponding array typed members <tt>x</tt> and <tt>y</tt>
151.73 + * are considered equal if <tt>Arrays.equals(x, y)</tt>, for the
151.74 + * appropriate overloading of {@link java.util.Arrays#equals}.
151.75 + * </ul>
151.76 + *
151.77 + * @return true if the specified object represents an annotation
151.78 + * that is logically equivalent to this one, otherwise false
151.79 + */
151.80 + boolean equals(Object obj);
151.81 +
151.82 + /**
151.83 + * Returns the hash code of this annotation, as defined below:
151.84 + *
151.85 + * <p>The hash code of an annotation is the sum of the hash codes
151.86 + * of its members (including those with default values), as defined
151.87 + * below:
151.88 + *
151.89 + * The hash code of an annotation member is (127 times the hash code
151.90 + * of the member-name as computed by {@link String#hashCode()}) XOR
151.91 + * the hash code of the member-value, as defined below:
151.92 + *
151.93 + * <p>The hash code of a member-value depends on its type:
151.94 + * <ul>
151.95 + * <li>The hash code of a primitive value <tt><i>v</i></tt> is equal to
151.96 + * <tt><i>WrapperType</i>.valueOf(<i>v</i>).hashCode()</tt>, where
151.97 + * <tt><i>WrapperType</i></tt> is the wrapper type corresponding
151.98 + * to the primitive type of <tt><i>v</i></tt> ({@link Byte},
151.99 + * {@link Character}, {@link Double}, {@link Float}, {@link Integer},
151.100 + * {@link Long}, {@link Short}, or {@link Boolean}).
151.101 + *
151.102 + * <li>The hash code of a string, enum, class, or annotation member-value
151.103 + I <tt><i>v</i></tt> is computed as by calling
151.104 + * <tt><i>v</i>.hashCode()</tt>. (In the case of annotation
151.105 + * member values, this is a recursive definition.)
151.106 + *
151.107 + * <li>The hash code of an array member-value is computed by calling
151.108 + * the appropriate overloading of
151.109 + * {@link java.util.Arrays#hashCode(long[]) Arrays.hashCode}
151.110 + * on the value. (There is one overloading for each primitive
151.111 + * type, and one for object reference types.)
151.112 + * </ul>
151.113 + *
151.114 + * @return the hash code of this annotation
151.115 + */
151.116 + int hashCode();
151.117 +
151.118 + /**
151.119 + * Returns a string representation of this annotation. The details
151.120 + * of the representation are implementation-dependent, but the following
151.121 + * may be regarded as typical:
151.122 + * <pre>
151.123 + * @com.acme.util.Name(first=Alfred, middle=E., last=Neuman)
151.124 + * </pre>
151.125 + *
151.126 + * @return a string representation of this annotation
151.127 + */
151.128 + String toString();
151.129 +
151.130 + /**
151.131 + * Returns the annotation type of this annotation.
151.132 + */
151.133 + Class<? extends Annotation> annotationType();
151.134 +}
152.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
152.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/AnnotationFormatError.java Wed Apr 30 15:04:10 2014 +0200
152.3 @@ -0,0 +1,79 @@
152.4 +/*
152.5 + * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
152.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
152.7 + *
152.8 + * This code is free software; you can redistribute it and/or modify it
152.9 + * under the terms of the GNU General Public License version 2 only, as
152.10 + * published by the Free Software Foundation. Oracle designates this
152.11 + * particular file as subject to the "Classpath" exception as provided
152.12 + * by Oracle in the LICENSE file that accompanied this code.
152.13 + *
152.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
152.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
152.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
152.17 + * version 2 for more details (a copy is included in the LICENSE file that
152.18 + * accompanied this code).
152.19 + *
152.20 + * You should have received a copy of the GNU General Public License version
152.21 + * 2 along with this work; if not, write to the Free Software Foundation,
152.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
152.23 + *
152.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
152.25 + * or visit www.oracle.com if you need additional information or have any
152.26 + * questions.
152.27 + */
152.28 +
152.29 +package java.lang.annotation;
152.30 +
152.31 +/**
152.32 + * Thrown when the annotation parser attempts to read an annotation
152.33 + * from a class file and determines that the annotation is malformed.
152.34 + * This error can be thrown by the {@linkplain
152.35 + * java.lang.reflect.AnnotatedElement API used to read annotations
152.36 + * reflectively}.
152.37 + *
152.38 + * @author Josh Bloch
152.39 + * @see java.lang.reflect.AnnotatedElement
152.40 + * @since 1.5
152.41 + */
152.42 +public class AnnotationFormatError extends Error {
152.43 + private static final long serialVersionUID = -4256701562333669892L;
152.44 +
152.45 + /**
152.46 + * Constructs a new <tt>AnnotationFormatError</tt> with the specified
152.47 + * detail message.
152.48 + *
152.49 + * @param message the detail message.
152.50 + */
152.51 + public AnnotationFormatError(String message) {
152.52 + super(message);
152.53 + }
152.54 +
152.55 + /**
152.56 + * Constructs a new <tt>AnnotationFormatError</tt> with the specified
152.57 + * detail message and cause. Note that the detail message associated
152.58 + * with <code>cause</code> is <i>not</i> automatically incorporated in
152.59 + * this error's detail message.
152.60 + *
152.61 + * @param message the detail message
152.62 + * @param cause the cause (A <tt>null</tt> value is permitted, and
152.63 + * indicates that the cause is nonexistent or unknown.)
152.64 + */
152.65 + public AnnotationFormatError(String message, Throwable cause) {
152.66 + super(message, cause);
152.67 + }
152.68 +
152.69 +
152.70 + /**
152.71 + * Constructs a new <tt>AnnotationFormatError</tt> with the specified
152.72 + * cause and a detail message of
152.73 + * <tt>(cause == null ? null : cause.toString())</tt> (which
152.74 + * typically contains the class and detail message of <tt>cause</tt>).
152.75 + *
152.76 + * @param cause the cause (A <tt>null</tt> value is permitted, and
152.77 + * indicates that the cause is nonexistent or unknown.)
152.78 + */
152.79 + public AnnotationFormatError(Throwable cause) {
152.80 + super(cause);
152.81 + }
152.82 +}
153.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
153.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java Wed Apr 30 15:04:10 2014 +0200
153.3 @@ -0,0 +1,91 @@
153.4 +/*
153.5 + * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
153.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
153.7 + *
153.8 + * This code is free software; you can redistribute it and/or modify it
153.9 + * under the terms of the GNU General Public License version 2 only, as
153.10 + * published by the Free Software Foundation. Oracle designates this
153.11 + * particular file as subject to the "Classpath" exception as provided
153.12 + * by Oracle in the LICENSE file that accompanied this code.
153.13 + *
153.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
153.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
153.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
153.17 + * version 2 for more details (a copy is included in the LICENSE file that
153.18 + * accompanied this code).
153.19 + *
153.20 + * You should have received a copy of the GNU General Public License version
153.21 + * 2 along with this work; if not, write to the Free Software Foundation,
153.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
153.23 + *
153.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
153.25 + * or visit www.oracle.com if you need additional information or have any
153.26 + * questions.
153.27 + */
153.28 +
153.29 +package java.lang.annotation;
153.30 +import java.lang.reflect.Method;
153.31 +
153.32 +/**
153.33 + * Thrown to indicate that a program has attempted to access an element of
153.34 + * an annotation whose type has changed after the annotation was compiled
153.35 + * (or serialized).
153.36 + * This exception can be thrown by the {@linkplain
153.37 + * java.lang.reflect.AnnotatedElement API used to read annotations
153.38 + * reflectively}.
153.39 + *
153.40 + * @author Josh Bloch
153.41 + * @see java.lang.reflect.AnnotatedElement
153.42 + * @since 1.5
153.43 + */
153.44 +public class AnnotationTypeMismatchException extends RuntimeException {
153.45 + private static final long serialVersionUID = 8125925355765570191L;
153.46 +
153.47 + /**
153.48 + * The <tt>Method</tt> object for the annotation element.
153.49 + */
153.50 + private final Method element;
153.51 +
153.52 + /**
153.53 + * The (erroneous) type of data found in the annotation. This string
153.54 + * may, but is not required to, contain the value as well. The exact
153.55 + * format of the string is unspecified.
153.56 + */
153.57 + private final String foundType;
153.58 +
153.59 + /**
153.60 + * Constructs an AnnotationTypeMismatchException for the specified
153.61 + * annotation type element and found data type.
153.62 + *
153.63 + * @param element the <tt>Method</tt> object for the annotation element
153.64 + * @param foundType the (erroneous) type of data found in the annotation.
153.65 + * This string may, but is not required to, contain the value
153.66 + * as well. The exact format of the string is unspecified.
153.67 + */
153.68 + public AnnotationTypeMismatchException(Method element, String foundType) {
153.69 + super("Incorrectly typed data found for annotation element " + element
153.70 + + " (Found data of type " + foundType + ")");
153.71 + this.element = element;
153.72 + this.foundType = foundType;
153.73 + }
153.74 +
153.75 + /**
153.76 + * Returns the <tt>Method</tt> object for the incorrectly typed element.
153.77 + *
153.78 + * @return the <tt>Method</tt> object for the incorrectly typed element
153.79 + */
153.80 + public Method element() {
153.81 + return this.element;
153.82 + }
153.83 +
153.84 + /**
153.85 + * Returns the type of data found in the incorrectly typed element.
153.86 + * The returned string may, but is not required to, contain the value
153.87 + * as well. The exact format of the string is unspecified.
153.88 + *
153.89 + * @return the type of data found in the incorrectly typed element
153.90 + */
153.91 + public String foundType() {
153.92 + return this.foundType;
153.93 + }
153.94 +}
154.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
154.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Documented.java Wed Apr 30 15:04:10 2014 +0200
154.3 @@ -0,0 +1,43 @@
154.4 +/*
154.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
154.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
154.7 + *
154.8 + * This code is free software; you can redistribute it and/or modify it
154.9 + * under the terms of the GNU General Public License version 2 only, as
154.10 + * published by the Free Software Foundation. Oracle designates this
154.11 + * particular file as subject to the "Classpath" exception as provided
154.12 + * by Oracle in the LICENSE file that accompanied this code.
154.13 + *
154.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
154.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
154.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
154.17 + * version 2 for more details (a copy is included in the LICENSE file that
154.18 + * accompanied this code).
154.19 + *
154.20 + * You should have received a copy of the GNU General Public License version
154.21 + * 2 along with this work; if not, write to the Free Software Foundation,
154.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
154.23 + *
154.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
154.25 + * or visit www.oracle.com if you need additional information or have any
154.26 + * questions.
154.27 + */
154.28 +
154.29 +package java.lang.annotation;
154.30 +
154.31 +/**
154.32 + * Indicates that annotations with a type are to be documented by javadoc
154.33 + * and similar tools by default. This type should be used to annotate the
154.34 + * declarations of types whose annotations affect the use of annotated
154.35 + * elements by their clients. If a type declaration is annotated with
154.36 + * Documented, its annotations become part of the public API
154.37 + * of the annotated elements.
154.38 + *
154.39 + * @author Joshua Bloch
154.40 + * @since 1.5
154.41 + */
154.42 +@Documented
154.43 +@Retention(RetentionPolicy.RUNTIME)
154.44 +@Target(ElementType.ANNOTATION_TYPE)
154.45 +public @interface Documented {
154.46 +}
155.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
155.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/ElementType.java Wed Apr 30 15:04:10 2014 +0200
155.3 @@ -0,0 +1,63 @@
155.4 +/*
155.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
155.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
155.7 + *
155.8 + * This code is free software; you can redistribute it and/or modify it
155.9 + * under the terms of the GNU General Public License version 2 only, as
155.10 + * published by the Free Software Foundation. Oracle designates this
155.11 + * particular file as subject to the "Classpath" exception as provided
155.12 + * by Oracle in the LICENSE file that accompanied this code.
155.13 + *
155.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
155.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
155.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
155.17 + * version 2 for more details (a copy is included in the LICENSE file that
155.18 + * accompanied this code).
155.19 + *
155.20 + * You should have received a copy of the GNU General Public License version
155.21 + * 2 along with this work; if not, write to the Free Software Foundation,
155.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
155.23 + *
155.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
155.25 + * or visit www.oracle.com if you need additional information or have any
155.26 + * questions.
155.27 + */
155.28 +
155.29 +package java.lang.annotation;
155.30 +
155.31 +/**
155.32 + * A program element type. The constants of this enumerated type
155.33 + * provide a simple classification of the declared elements in a
155.34 + * Java program.
155.35 + *
155.36 + * <p>These constants are used with the {@link Target} meta-annotation type
155.37 + * to specify where it is legal to use an annotation type.
155.38 + *
155.39 + * @author Joshua Bloch
155.40 + * @since 1.5
155.41 + */
155.42 +public enum ElementType {
155.43 + /** Class, interface (including annotation type), or enum declaration */
155.44 + TYPE,
155.45 +
155.46 + /** Field declaration (includes enum constants) */
155.47 + FIELD,
155.48 +
155.49 + /** Method declaration */
155.50 + METHOD,
155.51 +
155.52 + /** Parameter declaration */
155.53 + PARAMETER,
155.54 +
155.55 + /** Constructor declaration */
155.56 + CONSTRUCTOR,
155.57 +
155.58 + /** Local variable declaration */
155.59 + LOCAL_VARIABLE,
155.60 +
155.61 + /** Annotation type declaration */
155.62 + ANNOTATION_TYPE,
155.63 +
155.64 + /** Package declaration */
155.65 + PACKAGE
155.66 +}
156.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
156.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/IncompleteAnnotationException.java Wed Apr 30 15:04:10 2014 +0200
156.3 @@ -0,0 +1,83 @@
156.4 +/*
156.5 + * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
156.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
156.7 + *
156.8 + * This code is free software; you can redistribute it and/or modify it
156.9 + * under the terms of the GNU General Public License version 2 only, as
156.10 + * published by the Free Software Foundation. Oracle designates this
156.11 + * particular file as subject to the "Classpath" exception as provided
156.12 + * by Oracle in the LICENSE file that accompanied this code.
156.13 + *
156.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
156.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
156.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
156.17 + * version 2 for more details (a copy is included in the LICENSE file that
156.18 + * accompanied this code).
156.19 + *
156.20 + * You should have received a copy of the GNU General Public License version
156.21 + * 2 along with this work; if not, write to the Free Software Foundation,
156.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
156.23 + *
156.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
156.25 + * or visit www.oracle.com if you need additional information or have any
156.26 + * questions.
156.27 + */
156.28 +
156.29 +package java.lang.annotation;
156.30 +
156.31 +/**
156.32 + * Thrown to indicate that a program has attempted to access an element of
156.33 + * an annotation type that was added to the annotation type definition after
156.34 + * the annotation was compiled (or serialized). This exception will not be
156.35 + * thrown if the new element has a default value.
156.36 + * This exception can be thrown by the {@linkplain
156.37 + * java.lang.reflect.AnnotatedElement API used to read annotations
156.38 + * reflectively}.
156.39 + *
156.40 + * @author Josh Bloch
156.41 + * @see java.lang.reflect.AnnotatedElement
156.42 + * @since 1.5
156.43 + */
156.44 +public class IncompleteAnnotationException extends RuntimeException {
156.45 + private static final long serialVersionUID = 8445097402741811912L;
156.46 +
156.47 + private Class annotationType;
156.48 + private String elementName;
156.49 +
156.50 +
156.51 + /**
156.52 + * Constructs an IncompleteAnnotationException to indicate that
156.53 + * the named element was missing from the specified annotation type.
156.54 + *
156.55 + * @param annotationType the Class object for the annotation type
156.56 + * @param elementName the name of the missing element
156.57 + */
156.58 + public IncompleteAnnotationException(
156.59 + Class<? extends Annotation> annotationType,
156.60 + String elementName) {
156.61 + super(annotationType.getName() + " missing element " + elementName);
156.62 +
156.63 + this.annotationType = annotationType;
156.64 + this.elementName = elementName;
156.65 + }
156.66 +
156.67 + /**
156.68 + * Returns the Class object for the annotation type with the
156.69 + * missing element.
156.70 + *
156.71 + * @return the Class object for the annotation type with the
156.72 + * missing element
156.73 + */
156.74 + public Class<? extends Annotation> annotationType() {
156.75 + return annotationType;
156.76 + }
156.77 +
156.78 + /**
156.79 + * Returns the name of the missing element.
156.80 + *
156.81 + * @return the name of the missing element
156.82 + */
156.83 + public String elementName() {
156.84 + return elementName;
156.85 + }
156.86 +}
157.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
157.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Inherited.java Wed Apr 30 15:04:10 2014 +0200
157.3 @@ -0,0 +1,52 @@
157.4 +/*
157.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
157.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
157.7 + *
157.8 + * This code is free software; you can redistribute it and/or modify it
157.9 + * under the terms of the GNU General Public License version 2 only, as
157.10 + * published by the Free Software Foundation. Oracle designates this
157.11 + * particular file as subject to the "Classpath" exception as provided
157.12 + * by Oracle in the LICENSE file that accompanied this code.
157.13 + *
157.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
157.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
157.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
157.17 + * version 2 for more details (a copy is included in the LICENSE file that
157.18 + * accompanied this code).
157.19 + *
157.20 + * You should have received a copy of the GNU General Public License version
157.21 + * 2 along with this work; if not, write to the Free Software Foundation,
157.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
157.23 + *
157.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
157.25 + * or visit www.oracle.com if you need additional information or have any
157.26 + * questions.
157.27 + */
157.28 +
157.29 +package java.lang.annotation;
157.30 +
157.31 +/**
157.32 + * Indicates that an annotation type is automatically inherited. If
157.33 + * an Inherited meta-annotation is present on an annotation type
157.34 + * declaration, and the user queries the annotation type on a class
157.35 + * declaration, and the class declaration has no annotation for this type,
157.36 + * then the class's superclass will automatically be queried for the
157.37 + * annotation type. This process will be repeated until an annotation for this
157.38 + * type is found, or the top of the class hierarchy (Object)
157.39 + * is reached. If no superclass has an annotation for this type, then
157.40 + * the query will indicate that the class in question has no such annotation.
157.41 + *
157.42 + * <p>Note that this meta-annotation type has no effect if the annotated
157.43 + * type is used to annotate anything other than a class. Note also
157.44 + * that this meta-annotation only causes annotations to be inherited
157.45 + * from superclasses; annotations on implemented interfaces have no
157.46 + * effect.
157.47 + *
157.48 + * @author Joshua Bloch
157.49 + * @since 1.5
157.50 + */
157.51 +@Documented
157.52 +@Retention(RetentionPolicy.RUNTIME)
157.53 +@Target(ElementType.ANNOTATION_TYPE)
157.54 +public @interface Inherited {
157.55 +}
158.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
158.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Retention.java Wed Apr 30 15:04:10 2014 +0200
158.3 @@ -0,0 +1,47 @@
158.4 +/*
158.5 + * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
158.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
158.7 + *
158.8 + * This code is free software; you can redistribute it and/or modify it
158.9 + * under the terms of the GNU General Public License version 2 only, as
158.10 + * published by the Free Software Foundation. Oracle designates this
158.11 + * particular file as subject to the "Classpath" exception as provided
158.12 + * by Oracle in the LICENSE file that accompanied this code.
158.13 + *
158.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
158.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
158.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
158.17 + * version 2 for more details (a copy is included in the LICENSE file that
158.18 + * accompanied this code).
158.19 + *
158.20 + * You should have received a copy of the GNU General Public License version
158.21 + * 2 along with this work; if not, write to the Free Software Foundation,
158.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
158.23 + *
158.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
158.25 + * or visit www.oracle.com if you need additional information or have any
158.26 + * questions.
158.27 + */
158.28 +
158.29 +package java.lang.annotation;
158.30 +
158.31 +/**
158.32 + * Indicates how long annotations with the annotated type are to
158.33 + * be retained. If no Retention annotation is present on
158.34 + * an annotation type declaration, the retention policy defaults to
158.35 + * {@code RetentionPolicy.CLASS}.
158.36 + *
158.37 + * <p>A Retention meta-annotation has effect only if the
158.38 + * meta-annotated type is used directly for annotation. It has no
158.39 + * effect if the meta-annotated type is used as a member type in
158.40 + * another annotation type.
158.41 + *
158.42 + * @author Joshua Bloch
158.43 + * @since 1.5
158.44 + */
158.45 +@Documented
158.46 +@Retention(RetentionPolicy.RUNTIME)
158.47 +@Target(ElementType.ANNOTATION_TYPE)
158.48 +public @interface Retention {
158.49 + RetentionPolicy value();
158.50 +}
159.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
159.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/RetentionPolicy.java Wed Apr 30 15:04:10 2014 +0200
159.3 @@ -0,0 +1,57 @@
159.4 +/*
159.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
159.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
159.7 + *
159.8 + * This code is free software; you can redistribute it and/or modify it
159.9 + * under the terms of the GNU General Public License version 2 only, as
159.10 + * published by the Free Software Foundation. Oracle designates this
159.11 + * particular file as subject to the "Classpath" exception as provided
159.12 + * by Oracle in the LICENSE file that accompanied this code.
159.13 + *
159.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
159.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
159.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
159.17 + * version 2 for more details (a copy is included in the LICENSE file that
159.18 + * accompanied this code).
159.19 + *
159.20 + * You should have received a copy of the GNU General Public License version
159.21 + * 2 along with this work; if not, write to the Free Software Foundation,
159.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
159.23 + *
159.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
159.25 + * or visit www.oracle.com if you need additional information or have any
159.26 + * questions.
159.27 + */
159.28 +
159.29 +package java.lang.annotation;
159.30 +
159.31 +/**
159.32 + * Annotation retention policy. The constants of this enumerated type
159.33 + * describe the various policies for retaining annotations. They are used
159.34 + * in conjunction with the {@link Retention} meta-annotation type to specify
159.35 + * how long annotations are to be retained.
159.36 + *
159.37 + * @author Joshua Bloch
159.38 + * @since 1.5
159.39 + */
159.40 +public enum RetentionPolicy {
159.41 + /**
159.42 + * Annotations are to be discarded by the compiler.
159.43 + */
159.44 + SOURCE,
159.45 +
159.46 + /**
159.47 + * Annotations are to be recorded in the class file by the compiler
159.48 + * but need not be retained by the VM at run time. This is the default
159.49 + * behavior.
159.50 + */
159.51 + CLASS,
159.52 +
159.53 + /**
159.54 + * Annotations are to be recorded in the class file by the compiler and
159.55 + * retained by the VM at run time, so they may be read reflectively.
159.56 + *
159.57 + * @see java.lang.reflect.AnnotatedElement
159.58 + */
159.59 + RUNTIME
159.60 +}
160.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
160.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/Target.java Wed Apr 30 15:04:10 2014 +0200
160.3 @@ -0,0 +1,68 @@
160.4 +/*
160.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
160.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
160.7 + *
160.8 + * This code is free software; you can redistribute it and/or modify it
160.9 + * under the terms of the GNU General Public License version 2 only, as
160.10 + * published by the Free Software Foundation. Oracle designates this
160.11 + * particular file as subject to the "Classpath" exception as provided
160.12 + * by Oracle in the LICENSE file that accompanied this code.
160.13 + *
160.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
160.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
160.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
160.17 + * version 2 for more details (a copy is included in the LICENSE file that
160.18 + * accompanied this code).
160.19 + *
160.20 + * You should have received a copy of the GNU General Public License version
160.21 + * 2 along with this work; if not, write to the Free Software Foundation,
160.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
160.23 + *
160.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
160.25 + * or visit www.oracle.com if you need additional information or have any
160.26 + * questions.
160.27 + */
160.28 +
160.29 +package java.lang.annotation;
160.30 +
160.31 +/**
160.32 + * Indicates the kinds of program element to which an annotation type
160.33 + * is applicable. If a Target meta-annotation is not present on an
160.34 + * annotation type declaration, the declared type may be used on any
160.35 + * program element. If such a meta-annotation is present, the compiler
160.36 + * will enforce the specified usage restriction.
160.37 + *
160.38 + * For example, this meta-annotation indicates that the declared type is
160.39 + * itself a meta-annotation type. It can only be used on annotation type
160.40 + * declarations:
160.41 + * <pre>
160.42 + * @Target(ElementType.ANNOTATION_TYPE)
160.43 + * public @interface MetaAnnotationType {
160.44 + * ...
160.45 + * }
160.46 + * </pre>
160.47 + * This meta-annotation indicates that the declared type is intended solely
160.48 + * for use as a member type in complex annotation type declarations. It
160.49 + * cannot be used to annotate anything directly:
160.50 + * <pre>
160.51 + * @Target({})
160.52 + * public @interface MemberType {
160.53 + * ...
160.54 + * }
160.55 + * </pre>
160.56 + * It is a compile-time error for a single ElementType constant to
160.57 + * appear more than once in a Target annotation. For example, the
160.58 + * following meta-annotation is illegal:
160.59 + * <pre>
160.60 + * @Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
160.61 + * public @interface Bogus {
160.62 + * ...
160.63 + * }
160.64 + * </pre>
160.65 + */
160.66 +@Documented
160.67 +@Retention(RetentionPolicy.RUNTIME)
160.68 +@Target(ElementType.ANNOTATION_TYPE)
160.69 +public @interface Target {
160.70 + ElementType[] value();
160.71 +}
161.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
161.2 +++ b/rt/emul/compact/src/main/java/java/lang/annotation/package-info.java Wed Apr 30 15:04:10 2014 +0200
161.3 @@ -0,0 +1,33 @@
161.4 +/*
161.5 + * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
161.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
161.7 + *
161.8 + * This code is free software; you can redistribute it and/or modify it
161.9 + * under the terms of the GNU General Public License version 2 only, as
161.10 + * published by the Free Software Foundation. Oracle designates this
161.11 + * particular file as subject to the "Classpath" exception as provided
161.12 + * by Oracle in the LICENSE file that accompanied this code.
161.13 + *
161.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
161.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
161.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
161.17 + * version 2 for more details (a copy is included in the LICENSE file that
161.18 + * accompanied this code).
161.19 + *
161.20 + * You should have received a copy of the GNU General Public License version
161.21 + * 2 along with this work; if not, write to the Free Software Foundation,
161.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
161.23 + *
161.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
161.25 + * or visit www.oracle.com if you need additional information or have any
161.26 + * questions.
161.27 + */
161.28 +
161.29 +/**
161.30 + * Provides library support for the Java programming language
161.31 + * annotation facility.
161.32 + *
161.33 + * @author Josh Bloch
161.34 + * @since 1.5
161.35 + */
161.36 +package java.lang.annotation;
162.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
162.2 +++ b/rt/emul/compact/src/main/java/java/math/BigDecimal.java Wed Apr 30 15:04:10 2014 +0200
162.3 @@ -0,0 +1,3842 @@
162.4 +/*
162.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
162.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
162.7 + *
162.8 + * This code is free software; you can redistribute it and/or modify it
162.9 + * under the terms of the GNU General Public License version 2 only, as
162.10 + * published by the Free Software Foundation. Oracle designates this
162.11 + * particular file as subject to the "Classpath" exception as provided
162.12 + * by Oracle in the LICENSE file that accompanied this code.
162.13 + *
162.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
162.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
162.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
162.17 + * version 2 for more details (a copy is included in the LICENSE file that
162.18 + * accompanied this code).
162.19 + *
162.20 + * You should have received a copy of the GNU General Public License version
162.21 + * 2 along with this work; if not, write to the Free Software Foundation,
162.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
162.23 + *
162.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
162.25 + * or visit www.oracle.com if you need additional information or have any
162.26 + * questions.
162.27 + */
162.28 +
162.29 +/*
162.30 + * Portions Copyright IBM Corporation, 2001. All Rights Reserved.
162.31 + */
162.32 +
162.33 +package java.math;
162.34 +
162.35 +import java.util.Arrays;
162.36 +import static java.math.BigInteger.LONG_MASK;
162.37 +
162.38 +/**
162.39 + * Immutable, arbitrary-precision signed decimal numbers. A
162.40 + * {@code BigDecimal} consists of an arbitrary precision integer
162.41 + * <i>unscaled value</i> and a 32-bit integer <i>scale</i>. If zero
162.42 + * or positive, the scale is the number of digits to the right of the
162.43 + * decimal point. If negative, the unscaled value of the number is
162.44 + * multiplied by ten to the power of the negation of the scale. The
162.45 + * value of the number represented by the {@code BigDecimal} is
162.46 + * therefore <tt>(unscaledValue × 10<sup>-scale</sup>)</tt>.
162.47 + *
162.48 + * <p>The {@code BigDecimal} class provides operations for
162.49 + * arithmetic, scale manipulation, rounding, comparison, hashing, and
162.50 + * format conversion. The {@link #toString} method provides a
162.51 + * canonical representation of a {@code BigDecimal}.
162.52 + *
162.53 + * <p>The {@code BigDecimal} class gives its user complete control
162.54 + * over rounding behavior. If no rounding mode is specified and the
162.55 + * exact result cannot be represented, an exception is thrown;
162.56 + * otherwise, calculations can be carried out to a chosen precision
162.57 + * and rounding mode by supplying an appropriate {@link MathContext}
162.58 + * object to the operation. In either case, eight <em>rounding
162.59 + * modes</em> are provided for the control of rounding. Using the
162.60 + * integer fields in this class (such as {@link #ROUND_HALF_UP}) to
162.61 + * represent rounding mode is largely obsolete; the enumeration values
162.62 + * of the {@code RoundingMode} {@code enum}, (such as {@link
162.63 + * RoundingMode#HALF_UP}) should be used instead.
162.64 + *
162.65 + * <p>When a {@code MathContext} object is supplied with a precision
162.66 + * setting of 0 (for example, {@link MathContext#UNLIMITED}),
162.67 + * arithmetic operations are exact, as are the arithmetic methods
162.68 + * which take no {@code MathContext} object. (This is the only
162.69 + * behavior that was supported in releases prior to 5.) As a
162.70 + * corollary of computing the exact result, the rounding mode setting
162.71 + * of a {@code MathContext} object with a precision setting of 0 is
162.72 + * not used and thus irrelevant. In the case of divide, the exact
162.73 + * quotient could have an infinitely long decimal expansion; for
162.74 + * example, 1 divided by 3. If the quotient has a nonterminating
162.75 + * decimal expansion and the operation is specified to return an exact
162.76 + * result, an {@code ArithmeticException} is thrown. Otherwise, the
162.77 + * exact result of the division is returned, as done for other
162.78 + * operations.
162.79 + *
162.80 + * <p>When the precision setting is not 0, the rules of
162.81 + * {@code BigDecimal} arithmetic are broadly compatible with selected
162.82 + * modes of operation of the arithmetic defined in ANSI X3.274-1996
162.83 + * and ANSI X3.274-1996/AM 1-2000 (section 7.4). Unlike those
162.84 + * standards, {@code BigDecimal} includes many rounding modes, which
162.85 + * were mandatory for division in {@code BigDecimal} releases prior
162.86 + * to 5. Any conflicts between these ANSI standards and the
162.87 + * {@code BigDecimal} specification are resolved in favor of
162.88 + * {@code BigDecimal}.
162.89 + *
162.90 + * <p>Since the same numerical value can have different
162.91 + * representations (with different scales), the rules of arithmetic
162.92 + * and rounding must specify both the numerical result and the scale
162.93 + * used in the result's representation.
162.94 + *
162.95 + *
162.96 + * <p>In general the rounding modes and precision setting determine
162.97 + * how operations return results with a limited number of digits when
162.98 + * the exact result has more digits (perhaps infinitely many in the
162.99 + * case of division) than the number of digits returned.
162.100 + *
162.101 + * First, the
162.102 + * total number of digits to return is specified by the
162.103 + * {@code MathContext}'s {@code precision} setting; this determines
162.104 + * the result's <i>precision</i>. The digit count starts from the
162.105 + * leftmost nonzero digit of the exact result. The rounding mode
162.106 + * determines how any discarded trailing digits affect the returned
162.107 + * result.
162.108 + *
162.109 + * <p>For all arithmetic operators , the operation is carried out as
162.110 + * though an exact intermediate result were first calculated and then
162.111 + * rounded to the number of digits specified by the precision setting
162.112 + * (if necessary), using the selected rounding mode. If the exact
162.113 + * result is not returned, some digit positions of the exact result
162.114 + * are discarded. When rounding increases the magnitude of the
162.115 + * returned result, it is possible for a new digit position to be
162.116 + * created by a carry propagating to a leading {@literal "9"} digit.
162.117 + * For example, rounding the value 999.9 to three digits rounding up
162.118 + * would be numerically equal to one thousand, represented as
162.119 + * 100×10<sup>1</sup>. In such cases, the new {@literal "1"} is
162.120 + * the leading digit position of the returned result.
162.121 + *
162.122 + * <p>Besides a logical exact result, each arithmetic operation has a
162.123 + * preferred scale for representing a result. The preferred
162.124 + * scale for each operation is listed in the table below.
162.125 + *
162.126 + * <table border>
162.127 + * <caption><b>Preferred Scales for Results of Arithmetic Operations
162.128 + * </b></caption>
162.129 + * <tr><th>Operation</th><th>Preferred Scale of Result</th></tr>
162.130 + * <tr><td>Add</td><td>max(addend.scale(), augend.scale())</td>
162.131 + * <tr><td>Subtract</td><td>max(minuend.scale(), subtrahend.scale())</td>
162.132 + * <tr><td>Multiply</td><td>multiplier.scale() + multiplicand.scale()</td>
162.133 + * <tr><td>Divide</td><td>dividend.scale() - divisor.scale()</td>
162.134 + * </table>
162.135 + *
162.136 + * These scales are the ones used by the methods which return exact
162.137 + * arithmetic results; except that an exact divide may have to use a
162.138 + * larger scale since the exact result may have more digits. For
162.139 + * example, {@code 1/32} is {@code 0.03125}.
162.140 + *
162.141 + * <p>Before rounding, the scale of the logical exact intermediate
162.142 + * result is the preferred scale for that operation. If the exact
162.143 + * numerical result cannot be represented in {@code precision}
162.144 + * digits, rounding selects the set of digits to return and the scale
162.145 + * of the result is reduced from the scale of the intermediate result
162.146 + * to the least scale which can represent the {@code precision}
162.147 + * digits actually returned. If the exact result can be represented
162.148 + * with at most {@code precision} digits, the representation
162.149 + * of the result with the scale closest to the preferred scale is
162.150 + * returned. In particular, an exactly representable quotient may be
162.151 + * represented in fewer than {@code precision} digits by removing
162.152 + * trailing zeros and decreasing the scale. For example, rounding to
162.153 + * three digits using the {@linkplain RoundingMode#FLOOR floor}
162.154 + * rounding mode, <br>
162.155 + *
162.156 + * {@code 19/100 = 0.19 // integer=19, scale=2} <br>
162.157 + *
162.158 + * but<br>
162.159 + *
162.160 + * {@code 21/110 = 0.190 // integer=190, scale=3} <br>
162.161 + *
162.162 + * <p>Note that for add, subtract, and multiply, the reduction in
162.163 + * scale will equal the number of digit positions of the exact result
162.164 + * which are discarded. If the rounding causes a carry propagation to
162.165 + * create a new high-order digit position, an additional digit of the
162.166 + * result is discarded than when no new digit position is created.
162.167 + *
162.168 + * <p>Other methods may have slightly different rounding semantics.
162.169 + * For example, the result of the {@code pow} method using the
162.170 + * {@linkplain #pow(int, MathContext) specified algorithm} can
162.171 + * occasionally differ from the rounded mathematical result by more
162.172 + * than one unit in the last place, one <i>{@linkplain #ulp() ulp}</i>.
162.173 + *
162.174 + * <p>Two types of operations are provided for manipulating the scale
162.175 + * of a {@code BigDecimal}: scaling/rounding operations and decimal
162.176 + * point motion operations. Scaling/rounding operations ({@link
162.177 + * #setScale setScale} and {@link #round round}) return a
162.178 + * {@code BigDecimal} whose value is approximately (or exactly) equal
162.179 + * to that of the operand, but whose scale or precision is the
162.180 + * specified value; that is, they increase or decrease the precision
162.181 + * of the stored number with minimal effect on its value. Decimal
162.182 + * point motion operations ({@link #movePointLeft movePointLeft} and
162.183 + * {@link #movePointRight movePointRight}) return a
162.184 + * {@code BigDecimal} created from the operand by moving the decimal
162.185 + * point a specified distance in the specified direction.
162.186 + *
162.187 + * <p>For the sake of brevity and clarity, pseudo-code is used
162.188 + * throughout the descriptions of {@code BigDecimal} methods. The
162.189 + * pseudo-code expression {@code (i + j)} is shorthand for "a
162.190 + * {@code BigDecimal} whose value is that of the {@code BigDecimal}
162.191 + * {@code i} added to that of the {@code BigDecimal}
162.192 + * {@code j}." The pseudo-code expression {@code (i == j)} is
162.193 + * shorthand for "{@code true} if and only if the
162.194 + * {@code BigDecimal} {@code i} represents the same value as the
162.195 + * {@code BigDecimal} {@code j}." Other pseudo-code expressions
162.196 + * are interpreted similarly. Square brackets are used to represent
162.197 + * the particular {@code BigInteger} and scale pair defining a
162.198 + * {@code BigDecimal} value; for example [19, 2] is the
162.199 + * {@code BigDecimal} numerically equal to 0.19 having a scale of 2.
162.200 + *
162.201 + * <p>Note: care should be exercised if {@code BigDecimal} objects
162.202 + * are used as keys in a {@link java.util.SortedMap SortedMap} or
162.203 + * elements in a {@link java.util.SortedSet SortedSet} since
162.204 + * {@code BigDecimal}'s <i>natural ordering</i> is <i>inconsistent
162.205 + * with equals</i>. See {@link Comparable}, {@link
162.206 + * java.util.SortedMap} or {@link java.util.SortedSet} for more
162.207 + * information.
162.208 + *
162.209 + * <p>All methods and constructors for this class throw
162.210 + * {@code NullPointerException} when passed a {@code null} object
162.211 + * reference for any input parameter.
162.212 + *
162.213 + * @see BigInteger
162.214 + * @see MathContext
162.215 + * @see RoundingMode
162.216 + * @see java.util.SortedMap
162.217 + * @see java.util.SortedSet
162.218 + * @author Josh Bloch
162.219 + * @author Mike Cowlishaw
162.220 + * @author Joseph D. Darcy
162.221 + */
162.222 +public class BigDecimal extends Number implements Comparable<BigDecimal> {
162.223 + /**
162.224 + * The unscaled value of this BigDecimal, as returned by {@link
162.225 + * #unscaledValue}.
162.226 + *
162.227 + * @serial
162.228 + * @see #unscaledValue
162.229 + */
162.230 + private volatile BigInteger intVal;
162.231 +
162.232 + /**
162.233 + * The scale of this BigDecimal, as returned by {@link #scale}.
162.234 + *
162.235 + * @serial
162.236 + * @see #scale
162.237 + */
162.238 + private int scale; // Note: this may have any value, so
162.239 + // calculations must be done in longs
162.240 + /**
162.241 + * The number of decimal digits in this BigDecimal, or 0 if the
162.242 + * number of digits are not known (lookaside information). If
162.243 + * nonzero, the value is guaranteed correct. Use the precision()
162.244 + * method to obtain and set the value if it might be 0. This
162.245 + * field is mutable until set nonzero.
162.246 + *
162.247 + * @since 1.5
162.248 + */
162.249 + private transient int precision;
162.250 +
162.251 + /**
162.252 + * Used to store the canonical string representation, if computed.
162.253 + */
162.254 + private transient String stringCache;
162.255 +
162.256 + /**
162.257 + * Sentinel value for {@link #intCompact} indicating the
162.258 + * significand information is only available from {@code intVal}.
162.259 + */
162.260 + static final long INFLATED = Long.MIN_VALUE;
162.261 +
162.262 + /**
162.263 + * If the absolute value of the significand of this BigDecimal is
162.264 + * less than or equal to {@code Long.MAX_VALUE}, the value can be
162.265 + * compactly stored in this field and used in computations.
162.266 + */
162.267 + private transient long intCompact;
162.268 +
162.269 + // All 18-digit base ten strings fit into a long; not all 19-digit
162.270 + // strings will
162.271 + private static final int MAX_COMPACT_DIGITS = 18;
162.272 +
162.273 + private static final int MAX_BIGINT_BITS = 62;
162.274 +
162.275 + /* Appease the serialization gods */
162.276 + private static final long serialVersionUID = 6108874887143696463L;
162.277 +
162.278 + // Cache of common small BigDecimal values.
162.279 + private static final BigDecimal zeroThroughTen[] = {
162.280 + new BigDecimal(BigInteger.ZERO, 0, 0, 1),
162.281 + new BigDecimal(BigInteger.ONE, 1, 0, 1),
162.282 + new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),
162.283 + new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),
162.284 + new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),
162.285 + new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),
162.286 + new BigDecimal(BigInteger.valueOf(6), 6, 0, 1),
162.287 + new BigDecimal(BigInteger.valueOf(7), 7, 0, 1),
162.288 + new BigDecimal(BigInteger.valueOf(8), 8, 0, 1),
162.289 + new BigDecimal(BigInteger.valueOf(9), 9, 0, 1),
162.290 + new BigDecimal(BigInteger.TEN, 10, 0, 2),
162.291 + };
162.292 +
162.293 + // Cache of zero scaled by 0 - 15
162.294 + private static final BigDecimal[] ZERO_SCALED_BY = {
162.295 + zeroThroughTen[0],
162.296 + new BigDecimal(BigInteger.ZERO, 0, 1, 1),
162.297 + new BigDecimal(BigInteger.ZERO, 0, 2, 1),
162.298 + new BigDecimal(BigInteger.ZERO, 0, 3, 1),
162.299 + new BigDecimal(BigInteger.ZERO, 0, 4, 1),
162.300 + new BigDecimal(BigInteger.ZERO, 0, 5, 1),
162.301 + new BigDecimal(BigInteger.ZERO, 0, 6, 1),
162.302 + new BigDecimal(BigInteger.ZERO, 0, 7, 1),
162.303 + new BigDecimal(BigInteger.ZERO, 0, 8, 1),
162.304 + new BigDecimal(BigInteger.ZERO, 0, 9, 1),
162.305 + new BigDecimal(BigInteger.ZERO, 0, 10, 1),
162.306 + new BigDecimal(BigInteger.ZERO, 0, 11, 1),
162.307 + new BigDecimal(BigInteger.ZERO, 0, 12, 1),
162.308 + new BigDecimal(BigInteger.ZERO, 0, 13, 1),
162.309 + new BigDecimal(BigInteger.ZERO, 0, 14, 1),
162.310 + new BigDecimal(BigInteger.ZERO, 0, 15, 1),
162.311 + };
162.312 +
162.313 + // Half of Long.MIN_VALUE & Long.MAX_VALUE.
162.314 + private static final long HALF_LONG_MAX_VALUE = Long.MAX_VALUE / 2;
162.315 + private static final long HALF_LONG_MIN_VALUE = Long.MIN_VALUE / 2;
162.316 +
162.317 + // Constants
162.318 + /**
162.319 + * The value 0, with a scale of 0.
162.320 + *
162.321 + * @since 1.5
162.322 + */
162.323 + public static final BigDecimal ZERO =
162.324 + zeroThroughTen[0];
162.325 +
162.326 + /**
162.327 + * The value 1, with a scale of 0.
162.328 + *
162.329 + * @since 1.5
162.330 + */
162.331 + public static final BigDecimal ONE =
162.332 + zeroThroughTen[1];
162.333 +
162.334 + /**
162.335 + * The value 10, with a scale of 0.
162.336 + *
162.337 + * @since 1.5
162.338 + */
162.339 + public static final BigDecimal TEN =
162.340 + zeroThroughTen[10];
162.341 +
162.342 + // Constructors
162.343 +
162.344 + /**
162.345 + * Trusted package private constructor.
162.346 + * Trusted simply means if val is INFLATED, intVal could not be null and
162.347 + * if intVal is null, val could not be INFLATED.
162.348 + */
162.349 + BigDecimal(BigInteger intVal, long val, int scale, int prec) {
162.350 + this.scale = scale;
162.351 + this.precision = prec;
162.352 + this.intCompact = val;
162.353 + this.intVal = intVal;
162.354 + }
162.355 +
162.356 + /**
162.357 + * Translates a character array representation of a
162.358 + * {@code BigDecimal} into a {@code BigDecimal}, accepting the
162.359 + * same sequence of characters as the {@link #BigDecimal(String)}
162.360 + * constructor, while allowing a sub-array to be specified.
162.361 + *
162.362 + * <p>Note that if the sequence of characters is already available
162.363 + * within a character array, using this constructor is faster than
162.364 + * converting the {@code char} array to string and using the
162.365 + * {@code BigDecimal(String)} constructor .
162.366 + *
162.367 + * @param in {@code char} array that is the source of characters.
162.368 + * @param offset first character in the array to inspect.
162.369 + * @param len number of characters to consider.
162.370 + * @throws NumberFormatException if {@code in} is not a valid
162.371 + * representation of a {@code BigDecimal} or the defined subarray
162.372 + * is not wholly within {@code in}.
162.373 + * @since 1.5
162.374 + */
162.375 + public BigDecimal(char[] in, int offset, int len) {
162.376 + // protect against huge length.
162.377 + if (offset+len > in.length || offset < 0)
162.378 + throw new NumberFormatException();
162.379 + // This is the primary string to BigDecimal constructor; all
162.380 + // incoming strings end up here; it uses explicit (inline)
162.381 + // parsing for speed and generates at most one intermediate
162.382 + // (temporary) object (a char[] array) for non-compact case.
162.383 +
162.384 + // Use locals for all fields values until completion
162.385 + int prec = 0; // record precision value
162.386 + int scl = 0; // record scale value
162.387 + long rs = 0; // the compact value in long
162.388 + BigInteger rb = null; // the inflated value in BigInteger
162.389 +
162.390 + // use array bounds checking to handle too-long, len == 0,
162.391 + // bad offset, etc.
162.392 + try {
162.393 + // handle the sign
162.394 + boolean isneg = false; // assume positive
162.395 + if (in[offset] == '-') {
162.396 + isneg = true; // leading minus means negative
162.397 + offset++;
162.398 + len--;
162.399 + } else if (in[offset] == '+') { // leading + allowed
162.400 + offset++;
162.401 + len--;
162.402 + }
162.403 +
162.404 + // should now be at numeric part of the significand
162.405 + boolean dot = false; // true when there is a '.'
162.406 + int cfirst = offset; // record start of integer
162.407 + long exp = 0; // exponent
162.408 + char c; // current character
162.409 +
162.410 + boolean isCompact = (len <= MAX_COMPACT_DIGITS);
162.411 + // integer significand array & idx is the index to it. The array
162.412 + // is ONLY used when we can't use a compact representation.
162.413 + char coeff[] = isCompact ? null : new char[len];
162.414 + int idx = 0;
162.415 +
162.416 + for (; len > 0; offset++, len--) {
162.417 + c = in[offset];
162.418 + // have digit
162.419 + if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
162.420 + // First compact case, we need not to preserve the character
162.421 + // and we can just compute the value in place.
162.422 + if (isCompact) {
162.423 + int digit = Character.digit(c, 10);
162.424 + if (digit == 0) {
162.425 + if (prec == 0)
162.426 + prec = 1;
162.427 + else if (rs != 0) {
162.428 + rs *= 10;
162.429 + ++prec;
162.430 + } // else digit is a redundant leading zero
162.431 + } else {
162.432 + if (prec != 1 || rs != 0)
162.433 + ++prec; // prec unchanged if preceded by 0s
162.434 + rs = rs * 10 + digit;
162.435 + }
162.436 + } else { // the unscaled value is likely a BigInteger object.
162.437 + if (c == '0' || Character.digit(c, 10) == 0) {
162.438 + if (prec == 0) {
162.439 + coeff[idx] = c;
162.440 + prec = 1;
162.441 + } else if (idx != 0) {
162.442 + coeff[idx++] = c;
162.443 + ++prec;
162.444 + } // else c must be a redundant leading zero
162.445 + } else {
162.446 + if (prec != 1 || idx != 0)
162.447 + ++prec; // prec unchanged if preceded by 0s
162.448 + coeff[idx++] = c;
162.449 + }
162.450 + }
162.451 + if (dot)
162.452 + ++scl;
162.453 + continue;
162.454 + }
162.455 + // have dot
162.456 + if (c == '.') {
162.457 + // have dot
162.458 + if (dot) // two dots
162.459 + throw new NumberFormatException();
162.460 + dot = true;
162.461 + continue;
162.462 + }
162.463 + // exponent expected
162.464 + if ((c != 'e') && (c != 'E'))
162.465 + throw new NumberFormatException();
162.466 + offset++;
162.467 + c = in[offset];
162.468 + len--;
162.469 + boolean negexp = (c == '-');
162.470 + // optional sign
162.471 + if (negexp || c == '+') {
162.472 + offset++;
162.473 + c = in[offset];
162.474 + len--;
162.475 + }
162.476 + if (len <= 0) // no exponent digits
162.477 + throw new NumberFormatException();
162.478 + // skip leading zeros in the exponent
162.479 + while (len > 10 && Character.digit(c, 10) == 0) {
162.480 + offset++;
162.481 + c = in[offset];
162.482 + len--;
162.483 + }
162.484 + if (len > 10) // too many nonzero exponent digits
162.485 + throw new NumberFormatException();
162.486 + // c now holds first digit of exponent
162.487 + for (;; len--) {
162.488 + int v;
162.489 + if (c >= '0' && c <= '9') {
162.490 + v = c - '0';
162.491 + } else {
162.492 + v = Character.digit(c, 10);
162.493 + if (v < 0) // not a digit
162.494 + throw new NumberFormatException();
162.495 + }
162.496 + exp = exp * 10 + v;
162.497 + if (len == 1)
162.498 + break; // that was final character
162.499 + offset++;
162.500 + c = in[offset];
162.501 + }
162.502 + if (negexp) // apply sign
162.503 + exp = -exp;
162.504 + // Next test is required for backwards compatibility
162.505 + if ((int)exp != exp) // overflow
162.506 + throw new NumberFormatException();
162.507 + break; // [saves a test]
162.508 + }
162.509 + // here when no characters left
162.510 + if (prec == 0) // no digits found
162.511 + throw new NumberFormatException();
162.512 +
162.513 + // Adjust scale if exp is not zero.
162.514 + if (exp != 0) { // had significant exponent
162.515 + // Can't call checkScale which relies on proper fields value
162.516 + long adjustedScale = scl - exp;
162.517 + if (adjustedScale > Integer.MAX_VALUE ||
162.518 + adjustedScale < Integer.MIN_VALUE)
162.519 + throw new NumberFormatException("Scale out of range.");
162.520 + scl = (int)adjustedScale;
162.521 + }
162.522 +
162.523 + // Remove leading zeros from precision (digits count)
162.524 + if (isCompact) {
162.525 + rs = isneg ? -rs : rs;
162.526 + } else {
162.527 + char quick[];
162.528 + if (!isneg) {
162.529 + quick = (coeff.length != prec) ?
162.530 + Arrays.copyOf(coeff, prec) : coeff;
162.531 + } else {
162.532 + quick = new char[prec + 1];
162.533 + quick[0] = '-';
162.534 + System.arraycopy(coeff, 0, quick, 1, prec);
162.535 + }
162.536 + rb = new BigInteger(quick);
162.537 + rs = compactValFor(rb);
162.538 + }
162.539 + } catch (ArrayIndexOutOfBoundsException e) {
162.540 + throw new NumberFormatException();
162.541 + } catch (NegativeArraySizeException e) {
162.542 + throw new NumberFormatException();
162.543 + }
162.544 + this.scale = scl;
162.545 + this.precision = prec;
162.546 + this.intCompact = rs;
162.547 + this.intVal = (rs != INFLATED) ? null : rb;
162.548 + }
162.549 +
162.550 + /**
162.551 + * Translates a character array representation of a
162.552 + * {@code BigDecimal} into a {@code BigDecimal}, accepting the
162.553 + * same sequence of characters as the {@link #BigDecimal(String)}
162.554 + * constructor, while allowing a sub-array to be specified and
162.555 + * with rounding according to the context settings.
162.556 + *
162.557 + * <p>Note that if the sequence of characters is already available
162.558 + * within a character array, using this constructor is faster than
162.559 + * converting the {@code char} array to string and using the
162.560 + * {@code BigDecimal(String)} constructor .
162.561 + *
162.562 + * @param in {@code char} array that is the source of characters.
162.563 + * @param offset first character in the array to inspect.
162.564 + * @param len number of characters to consider..
162.565 + * @param mc the context to use.
162.566 + * @throws ArithmeticException if the result is inexact but the
162.567 + * rounding mode is {@code UNNECESSARY}.
162.568 + * @throws NumberFormatException if {@code in} is not a valid
162.569 + * representation of a {@code BigDecimal} or the defined subarray
162.570 + * is not wholly within {@code in}.
162.571 + * @since 1.5
162.572 + */
162.573 + public BigDecimal(char[] in, int offset, int len, MathContext mc) {
162.574 + this(in, offset, len);
162.575 + if (mc.precision > 0)
162.576 + roundThis(mc);
162.577 + }
162.578 +
162.579 + /**
162.580 + * Translates a character array representation of a
162.581 + * {@code BigDecimal} into a {@code BigDecimal}, accepting the
162.582 + * same sequence of characters as the {@link #BigDecimal(String)}
162.583 + * constructor.
162.584 + *
162.585 + * <p>Note that if the sequence of characters is already available
162.586 + * as a character array, using this constructor is faster than
162.587 + * converting the {@code char} array to string and using the
162.588 + * {@code BigDecimal(String)} constructor .
162.589 + *
162.590 + * @param in {@code char} array that is the source of characters.
162.591 + * @throws NumberFormatException if {@code in} is not a valid
162.592 + * representation of a {@code BigDecimal}.
162.593 + * @since 1.5
162.594 + */
162.595 + public BigDecimal(char[] in) {
162.596 + this(in, 0, in.length);
162.597 + }
162.598 +
162.599 + /**
162.600 + * Translates a character array representation of a
162.601 + * {@code BigDecimal} into a {@code BigDecimal}, accepting the
162.602 + * same sequence of characters as the {@link #BigDecimal(String)}
162.603 + * constructor and with rounding according to the context
162.604 + * settings.
162.605 + *
162.606 + * <p>Note that if the sequence of characters is already available
162.607 + * as a character array, using this constructor is faster than
162.608 + * converting the {@code char} array to string and using the
162.609 + * {@code BigDecimal(String)} constructor .
162.610 + *
162.611 + * @param in {@code char} array that is the source of characters.
162.612 + * @param mc the context to use.
162.613 + * @throws ArithmeticException if the result is inexact but the
162.614 + * rounding mode is {@code UNNECESSARY}.
162.615 + * @throws NumberFormatException if {@code in} is not a valid
162.616 + * representation of a {@code BigDecimal}.
162.617 + * @since 1.5
162.618 + */
162.619 + public BigDecimal(char[] in, MathContext mc) {
162.620 + this(in, 0, in.length, mc);
162.621 + }
162.622 +
162.623 + /**
162.624 + * Translates the string representation of a {@code BigDecimal}
162.625 + * into a {@code BigDecimal}. The string representation consists
162.626 + * of an optional sign, {@code '+'} (<tt> '\u002B'</tt>) or
162.627 + * {@code '-'} (<tt>'\u002D'</tt>), followed by a sequence of
162.628 + * zero or more decimal digits ("the integer"), optionally
162.629 + * followed by a fraction, optionally followed by an exponent.
162.630 + *
162.631 + * <p>The fraction consists of a decimal point followed by zero
162.632 + * or more decimal digits. The string must contain at least one
162.633 + * digit in either the integer or the fraction. The number formed
162.634 + * by the sign, the integer and the fraction is referred to as the
162.635 + * <i>significand</i>.
162.636 + *
162.637 + * <p>The exponent consists of the character {@code 'e'}
162.638 + * (<tt>'\u0065'</tt>) or {@code 'E'} (<tt>'\u0045'</tt>)
162.639 + * followed by one or more decimal digits. The value of the
162.640 + * exponent must lie between -{@link Integer#MAX_VALUE} ({@link
162.641 + * Integer#MIN_VALUE}+1) and {@link Integer#MAX_VALUE}, inclusive.
162.642 + *
162.643 + * <p>More formally, the strings this constructor accepts are
162.644 + * described by the following grammar:
162.645 + * <blockquote>
162.646 + * <dl>
162.647 + * <dt><i>BigDecimalString:</i>
162.648 + * <dd><i>Sign<sub>opt</sub> Significand Exponent<sub>opt</sub></i>
162.649 + * <p>
162.650 + * <dt><i>Sign:</i>
162.651 + * <dd>{@code +}
162.652 + * <dd>{@code -}
162.653 + * <p>
162.654 + * <dt><i>Significand:</i>
162.655 + * <dd><i>IntegerPart</i> {@code .} <i>FractionPart<sub>opt</sub></i>
162.656 + * <dd>{@code .} <i>FractionPart</i>
162.657 + * <dd><i>IntegerPart</i>
162.658 + * <p>
162.659 + * <dt><i>IntegerPart:</i>
162.660 + * <dd><i>Digits</i>
162.661 + * <p>
162.662 + * <dt><i>FractionPart:</i>
162.663 + * <dd><i>Digits</i>
162.664 + * <p>
162.665 + * <dt><i>Exponent:</i>
162.666 + * <dd><i>ExponentIndicator SignedInteger</i>
162.667 + * <p>
162.668 + * <dt><i>ExponentIndicator:</i>
162.669 + * <dd>{@code e}
162.670 + * <dd>{@code E}
162.671 + * <p>
162.672 + * <dt><i>SignedInteger:</i>
162.673 + * <dd><i>Sign<sub>opt</sub> Digits</i>
162.674 + * <p>
162.675 + * <dt><i>Digits:</i>
162.676 + * <dd><i>Digit</i>
162.677 + * <dd><i>Digits Digit</i>
162.678 + * <p>
162.679 + * <dt><i>Digit:</i>
162.680 + * <dd>any character for which {@link Character#isDigit}
162.681 + * returns {@code true}, including 0, 1, 2 ...
162.682 + * </dl>
162.683 + * </blockquote>
162.684 + *
162.685 + * <p>The scale of the returned {@code BigDecimal} will be the
162.686 + * number of digits in the fraction, or zero if the string
162.687 + * contains no decimal point, subject to adjustment for any
162.688 + * exponent; if the string contains an exponent, the exponent is
162.689 + * subtracted from the scale. The value of the resulting scale
162.690 + * must lie between {@code Integer.MIN_VALUE} and
162.691 + * {@code Integer.MAX_VALUE}, inclusive.
162.692 + *
162.693 + * <p>The character-to-digit mapping is provided by {@link
162.694 + * java.lang.Character#digit} set to convert to radix 10. The
162.695 + * String may not contain any extraneous characters (whitespace,
162.696 + * for example).
162.697 + *
162.698 + * <p><b>Examples:</b><br>
162.699 + * The value of the returned {@code BigDecimal} is equal to
162.700 + * <i>significand</i> × 10<sup> <i>exponent</i></sup>.
162.701 + * For each string on the left, the resulting representation
162.702 + * [{@code BigInteger}, {@code scale}] is shown on the right.
162.703 + * <pre>
162.704 + * "0" [0,0]
162.705 + * "0.00" [0,2]
162.706 + * "123" [123,0]
162.707 + * "-123" [-123,0]
162.708 + * "1.23E3" [123,-1]
162.709 + * "1.23E+3" [123,-1]
162.710 + * "12.3E+7" [123,-6]
162.711 + * "12.0" [120,1]
162.712 + * "12.3" [123,1]
162.713 + * "0.00123" [123,5]
162.714 + * "-1.23E-12" [-123,14]
162.715 + * "1234.5E-4" [12345,5]
162.716 + * "0E+7" [0,-7]
162.717 + * "-0" [0,0]
162.718 + * </pre>
162.719 + *
162.720 + * <p>Note: For values other than {@code float} and
162.721 + * {@code double} NaN and ±Infinity, this constructor is
162.722 + * compatible with the values returned by {@link Float#toString}
162.723 + * and {@link Double#toString}. This is generally the preferred
162.724 + * way to convert a {@code float} or {@code double} into a
162.725 + * BigDecimal, as it doesn't suffer from the unpredictability of
162.726 + * the {@link #BigDecimal(double)} constructor.
162.727 + *
162.728 + * @param val String representation of {@code BigDecimal}.
162.729 + *
162.730 + * @throws NumberFormatException if {@code val} is not a valid
162.731 + * representation of a {@code BigDecimal}.
162.732 + */
162.733 + public BigDecimal(String val) {
162.734 + this(val.toCharArray(), 0, val.length());
162.735 + }
162.736 +
162.737 + /**
162.738 + * Translates the string representation of a {@code BigDecimal}
162.739 + * into a {@code BigDecimal}, accepting the same strings as the
162.740 + * {@link #BigDecimal(String)} constructor, with rounding
162.741 + * according to the context settings.
162.742 + *
162.743 + * @param val string representation of a {@code BigDecimal}.
162.744 + * @param mc the context to use.
162.745 + * @throws ArithmeticException if the result is inexact but the
162.746 + * rounding mode is {@code UNNECESSARY}.
162.747 + * @throws NumberFormatException if {@code val} is not a valid
162.748 + * representation of a BigDecimal.
162.749 + * @since 1.5
162.750 + */
162.751 + public BigDecimal(String val, MathContext mc) {
162.752 + this(val.toCharArray(), 0, val.length());
162.753 + if (mc.precision > 0)
162.754 + roundThis(mc);
162.755 + }
162.756 +
162.757 + /**
162.758 + * Translates a {@code double} into a {@code BigDecimal} which
162.759 + * is the exact decimal representation of the {@code double}'s
162.760 + * binary floating-point value. The scale of the returned
162.761 + * {@code BigDecimal} is the smallest value such that
162.762 + * <tt>(10<sup>scale</sup> × val)</tt> is an integer.
162.763 + * <p>
162.764 + * <b>Notes:</b>
162.765 + * <ol>
162.766 + * <li>
162.767 + * The results of this constructor can be somewhat unpredictable.
162.768 + * One might assume that writing {@code new BigDecimal(0.1)} in
162.769 + * Java creates a {@code BigDecimal} which is exactly equal to
162.770 + * 0.1 (an unscaled value of 1, with a scale of 1), but it is
162.771 + * actually equal to
162.772 + * 0.1000000000000000055511151231257827021181583404541015625.
162.773 + * This is because 0.1 cannot be represented exactly as a
162.774 + * {@code double} (or, for that matter, as a binary fraction of
162.775 + * any finite length). Thus, the value that is being passed
162.776 + * <i>in</i> to the constructor is not exactly equal to 0.1,
162.777 + * appearances notwithstanding.
162.778 + *
162.779 + * <li>
162.780 + * The {@code String} constructor, on the other hand, is
162.781 + * perfectly predictable: writing {@code new BigDecimal("0.1")}
162.782 + * creates a {@code BigDecimal} which is <i>exactly</i> equal to
162.783 + * 0.1, as one would expect. Therefore, it is generally
162.784 + * recommended that the {@linkplain #BigDecimal(String)
162.785 + * <tt>String</tt> constructor} be used in preference to this one.
162.786 + *
162.787 + * <li>
162.788 + * When a {@code double} must be used as a source for a
162.789 + * {@code BigDecimal}, note that this constructor provides an
162.790 + * exact conversion; it does not give the same result as
162.791 + * converting the {@code double} to a {@code String} using the
162.792 + * {@link Double#toString(double)} method and then using the
162.793 + * {@link #BigDecimal(String)} constructor. To get that result,
162.794 + * use the {@code static} {@link #valueOf(double)} method.
162.795 + * </ol>
162.796 + *
162.797 + * @param val {@code double} value to be converted to
162.798 + * {@code BigDecimal}.
162.799 + * @throws NumberFormatException if {@code val} is infinite or NaN.
162.800 + */
162.801 + public BigDecimal(double val) {
162.802 + if (Double.isInfinite(val) || Double.isNaN(val))
162.803 + throw new NumberFormatException("Infinite or NaN");
162.804 +
162.805 + // Translate the double into sign, exponent and significand, according
162.806 + // to the formulae in JLS, Section 20.10.22.
162.807 + long valBits = Double.doubleToLongBits(val);
162.808 + int sign = ((valBits >> 63)==0 ? 1 : -1);
162.809 + int exponent = (int) ((valBits >> 52) & 0x7ffL);
162.810 + long significand = (exponent==0 ? (valBits & ((1L<<52) - 1)) << 1
162.811 + : (valBits & ((1L<<52) - 1)) | (1L<<52));
162.812 + exponent -= 1075;
162.813 + // At this point, val == sign * significand * 2**exponent.
162.814 +
162.815 + /*
162.816 + * Special case zero to supress nonterminating normalization
162.817 + * and bogus scale calculation.
162.818 + */
162.819 + if (significand == 0) {
162.820 + intVal = BigInteger.ZERO;
162.821 + intCompact = 0;
162.822 + precision = 1;
162.823 + return;
162.824 + }
162.825 +
162.826 + // Normalize
162.827 + while((significand & 1) == 0) { // i.e., significand is even
162.828 + significand >>= 1;
162.829 + exponent++;
162.830 + }
162.831 +
162.832 + // Calculate intVal and scale
162.833 + long s = sign * significand;
162.834 + BigInteger b;
162.835 + if (exponent < 0) {
162.836 + b = BigInteger.valueOf(5).pow(-exponent).multiply(s);
162.837 + scale = -exponent;
162.838 + } else if (exponent > 0) {
162.839 + b = BigInteger.valueOf(2).pow(exponent).multiply(s);
162.840 + } else {
162.841 + b = BigInteger.valueOf(s);
162.842 + }
162.843 + intCompact = compactValFor(b);
162.844 + intVal = (intCompact != INFLATED) ? null : b;
162.845 + }
162.846 +
162.847 + /**
162.848 + * Translates a {@code double} into a {@code BigDecimal}, with
162.849 + * rounding according to the context settings. The scale of the
162.850 + * {@code BigDecimal} is the smallest value such that
162.851 + * <tt>(10<sup>scale</sup> × val)</tt> is an integer.
162.852 + *
162.853 + * <p>The results of this constructor can be somewhat unpredictable
162.854 + * and its use is generally not recommended; see the notes under
162.855 + * the {@link #BigDecimal(double)} constructor.
162.856 + *
162.857 + * @param val {@code double} value to be converted to
162.858 + * {@code BigDecimal}.
162.859 + * @param mc the context to use.
162.860 + * @throws ArithmeticException if the result is inexact but the
162.861 + * RoundingMode is UNNECESSARY.
162.862 + * @throws NumberFormatException if {@code val} is infinite or NaN.
162.863 + * @since 1.5
162.864 + */
162.865 + public BigDecimal(double val, MathContext mc) {
162.866 + this(val);
162.867 + if (mc.precision > 0)
162.868 + roundThis(mc);
162.869 + }
162.870 +
162.871 + /**
162.872 + * Translates a {@code BigInteger} into a {@code BigDecimal}.
162.873 + * The scale of the {@code BigDecimal} is zero.
162.874 + *
162.875 + * @param val {@code BigInteger} value to be converted to
162.876 + * {@code BigDecimal}.
162.877 + */
162.878 + public BigDecimal(BigInteger val) {
162.879 + intCompact = compactValFor(val);
162.880 + intVal = (intCompact != INFLATED) ? null : val;
162.881 + }
162.882 +
162.883 + /**
162.884 + * Translates a {@code BigInteger} into a {@code BigDecimal}
162.885 + * rounding according to the context settings. The scale of the
162.886 + * {@code BigDecimal} is zero.
162.887 + *
162.888 + * @param val {@code BigInteger} value to be converted to
162.889 + * {@code BigDecimal}.
162.890 + * @param mc the context to use.
162.891 + * @throws ArithmeticException if the result is inexact but the
162.892 + * rounding mode is {@code UNNECESSARY}.
162.893 + * @since 1.5
162.894 + */
162.895 + public BigDecimal(BigInteger val, MathContext mc) {
162.896 + this(val);
162.897 + if (mc.precision > 0)
162.898 + roundThis(mc);
162.899 + }
162.900 +
162.901 + /**
162.902 + * Translates a {@code BigInteger} unscaled value and an
162.903 + * {@code int} scale into a {@code BigDecimal}. The value of
162.904 + * the {@code BigDecimal} is
162.905 + * <tt>(unscaledVal × 10<sup>-scale</sup>)</tt>.
162.906 + *
162.907 + * @param unscaledVal unscaled value of the {@code BigDecimal}.
162.908 + * @param scale scale of the {@code BigDecimal}.
162.909 + */
162.910 + public BigDecimal(BigInteger unscaledVal, int scale) {
162.911 + // Negative scales are now allowed
162.912 + this(unscaledVal);
162.913 + this.scale = scale;
162.914 + }
162.915 +
162.916 + /**
162.917 + * Translates a {@code BigInteger} unscaled value and an
162.918 + * {@code int} scale into a {@code BigDecimal}, with rounding
162.919 + * according to the context settings. The value of the
162.920 + * {@code BigDecimal} is <tt>(unscaledVal ×
162.921 + * 10<sup>-scale</sup>)</tt>, rounded according to the
162.922 + * {@code precision} and rounding mode settings.
162.923 + *
162.924 + * @param unscaledVal unscaled value of the {@code BigDecimal}.
162.925 + * @param scale scale of the {@code BigDecimal}.
162.926 + * @param mc the context to use.
162.927 + * @throws ArithmeticException if the result is inexact but the
162.928 + * rounding mode is {@code UNNECESSARY}.
162.929 + * @since 1.5
162.930 + */
162.931 + public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
162.932 + this(unscaledVal);
162.933 + this.scale = scale;
162.934 + if (mc.precision > 0)
162.935 + roundThis(mc);
162.936 + }
162.937 +
162.938 + /**
162.939 + * Translates an {@code int} into a {@code BigDecimal}. The
162.940 + * scale of the {@code BigDecimal} is zero.
162.941 + *
162.942 + * @param val {@code int} value to be converted to
162.943 + * {@code BigDecimal}.
162.944 + * @since 1.5
162.945 + */
162.946 + public BigDecimal(int val) {
162.947 + intCompact = val;
162.948 + }
162.949 +
162.950 + /**
162.951 + * Translates an {@code int} into a {@code BigDecimal}, with
162.952 + * rounding according to the context settings. The scale of the
162.953 + * {@code BigDecimal}, before any rounding, is zero.
162.954 + *
162.955 + * @param val {@code int} value to be converted to {@code BigDecimal}.
162.956 + * @param mc the context to use.
162.957 + * @throws ArithmeticException if the result is inexact but the
162.958 + * rounding mode is {@code UNNECESSARY}.
162.959 + * @since 1.5
162.960 + */
162.961 + public BigDecimal(int val, MathContext mc) {
162.962 + intCompact = val;
162.963 + if (mc.precision > 0)
162.964 + roundThis(mc);
162.965 + }
162.966 +
162.967 + /**
162.968 + * Translates a {@code long} into a {@code BigDecimal}. The
162.969 + * scale of the {@code BigDecimal} is zero.
162.970 + *
162.971 + * @param val {@code long} value to be converted to {@code BigDecimal}.
162.972 + * @since 1.5
162.973 + */
162.974 + public BigDecimal(long val) {
162.975 + this.intCompact = val;
162.976 + this.intVal = (val == INFLATED) ? BigInteger.valueOf(val) : null;
162.977 + }
162.978 +
162.979 + /**
162.980 + * Translates a {@code long} into a {@code BigDecimal}, with
162.981 + * rounding according to the context settings. The scale of the
162.982 + * {@code BigDecimal}, before any rounding, is zero.
162.983 + *
162.984 + * @param val {@code long} value to be converted to {@code BigDecimal}.
162.985 + * @param mc the context to use.
162.986 + * @throws ArithmeticException if the result is inexact but the
162.987 + * rounding mode is {@code UNNECESSARY}.
162.988 + * @since 1.5
162.989 + */
162.990 + public BigDecimal(long val, MathContext mc) {
162.991 + this(val);
162.992 + if (mc.precision > 0)
162.993 + roundThis(mc);
162.994 + }
162.995 +
162.996 + // Static Factory Methods
162.997 +
162.998 + /**
162.999 + * Translates a {@code long} unscaled value and an
162.1000 + * {@code int} scale into a {@code BigDecimal}. This
162.1001 + * {@literal "static factory method"} is provided in preference to
162.1002 + * a ({@code long}, {@code int}) constructor because it
162.1003 + * allows for reuse of frequently used {@code BigDecimal} values..
162.1004 + *
162.1005 + * @param unscaledVal unscaled value of the {@code BigDecimal}.
162.1006 + * @param scale scale of the {@code BigDecimal}.
162.1007 + * @return a {@code BigDecimal} whose value is
162.1008 + * <tt>(unscaledVal × 10<sup>-scale</sup>)</tt>.
162.1009 + */
162.1010 + public static BigDecimal valueOf(long unscaledVal, int scale) {
162.1011 + if (scale == 0)
162.1012 + return valueOf(unscaledVal);
162.1013 + else if (unscaledVal == 0) {
162.1014 + if (scale > 0 && scale < ZERO_SCALED_BY.length)
162.1015 + return ZERO_SCALED_BY[scale];
162.1016 + else
162.1017 + return new BigDecimal(BigInteger.ZERO, 0, scale, 1);
162.1018 + }
162.1019 + return new BigDecimal(unscaledVal == INFLATED ?
162.1020 + BigInteger.valueOf(unscaledVal) : null,
162.1021 + unscaledVal, scale, 0);
162.1022 + }
162.1023 +
162.1024 + /**
162.1025 + * Translates a {@code long} value into a {@code BigDecimal}
162.1026 + * with a scale of zero. This {@literal "static factory method"}
162.1027 + * is provided in preference to a ({@code long}) constructor
162.1028 + * because it allows for reuse of frequently used
162.1029 + * {@code BigDecimal} values.
162.1030 + *
162.1031 + * @param val value of the {@code BigDecimal}.
162.1032 + * @return a {@code BigDecimal} whose value is {@code val}.
162.1033 + */
162.1034 + public static BigDecimal valueOf(long val) {
162.1035 + if (val >= 0 && val < zeroThroughTen.length)
162.1036 + return zeroThroughTen[(int)val];
162.1037 + else if (val != INFLATED)
162.1038 + return new BigDecimal(null, val, 0, 0);
162.1039 + return new BigDecimal(BigInteger.valueOf(val), val, 0, 0);
162.1040 + }
162.1041 +
162.1042 + /**
162.1043 + * Translates a {@code double} into a {@code BigDecimal}, using
162.1044 + * the {@code double}'s canonical string representation provided
162.1045 + * by the {@link Double#toString(double)} method.
162.1046 + *
162.1047 + * <p><b>Note:</b> This is generally the preferred way to convert
162.1048 + * a {@code double} (or {@code float}) into a
162.1049 + * {@code BigDecimal}, as the value returned is equal to that
162.1050 + * resulting from constructing a {@code BigDecimal} from the
162.1051 + * result of using {@link Double#toString(double)}.
162.1052 + *
162.1053 + * @param val {@code double} to convert to a {@code BigDecimal}.
162.1054 + * @return a {@code BigDecimal} whose value is equal to or approximately
162.1055 + * equal to the value of {@code val}.
162.1056 + * @throws NumberFormatException if {@code val} is infinite or NaN.
162.1057 + * @since 1.5
162.1058 + */
162.1059 + public static BigDecimal valueOf(double val) {
162.1060 + // Reminder: a zero double returns '0.0', so we cannot fastpath
162.1061 + // to use the constant ZERO. This might be important enough to
162.1062 + // justify a factory approach, a cache, or a few private
162.1063 + // constants, later.
162.1064 + return new BigDecimal(Double.toString(val));
162.1065 + }
162.1066 +
162.1067 + // Arithmetic Operations
162.1068 + /**
162.1069 + * Returns a {@code BigDecimal} whose value is {@code (this +
162.1070 + * augend)}, and whose scale is {@code max(this.scale(),
162.1071 + * augend.scale())}.
162.1072 + *
162.1073 + * @param augend value to be added to this {@code BigDecimal}.
162.1074 + * @return {@code this + augend}
162.1075 + */
162.1076 + public BigDecimal add(BigDecimal augend) {
162.1077 + long xs = this.intCompact;
162.1078 + long ys = augend.intCompact;
162.1079 + BigInteger fst = (xs != INFLATED) ? null : this.intVal;
162.1080 + BigInteger snd = (ys != INFLATED) ? null : augend.intVal;
162.1081 + int rscale = this.scale;
162.1082 +
162.1083 + long sdiff = (long)rscale - augend.scale;
162.1084 + if (sdiff != 0) {
162.1085 + if (sdiff < 0) {
162.1086 + int raise = checkScale(-sdiff);
162.1087 + rscale = augend.scale;
162.1088 + if (xs == INFLATED ||
162.1089 + (xs = longMultiplyPowerTen(xs, raise)) == INFLATED)
162.1090 + fst = bigMultiplyPowerTen(raise);
162.1091 + } else {
162.1092 + int raise = augend.checkScale(sdiff);
162.1093 + if (ys == INFLATED ||
162.1094 + (ys = longMultiplyPowerTen(ys, raise)) == INFLATED)
162.1095 + snd = augend.bigMultiplyPowerTen(raise);
162.1096 + }
162.1097 + }
162.1098 + if (xs != INFLATED && ys != INFLATED) {
162.1099 + long sum = xs + ys;
162.1100 + // See "Hacker's Delight" section 2-12 for explanation of
162.1101 + // the overflow test.
162.1102 + if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) // not overflowed
162.1103 + return BigDecimal.valueOf(sum, rscale);
162.1104 + }
162.1105 + if (fst == null)
162.1106 + fst = BigInteger.valueOf(xs);
162.1107 + if (snd == null)
162.1108 + snd = BigInteger.valueOf(ys);
162.1109 + BigInteger sum = fst.add(snd);
162.1110 + return (fst.signum == snd.signum) ?
162.1111 + new BigDecimal(sum, INFLATED, rscale, 0) :
162.1112 + new BigDecimal(sum, rscale);
162.1113 + }
162.1114 +
162.1115 + /**
162.1116 + * Returns a {@code BigDecimal} whose value is {@code (this + augend)},
162.1117 + * with rounding according to the context settings.
162.1118 + *
162.1119 + * If either number is zero and the precision setting is nonzero then
162.1120 + * the other number, rounded if necessary, is used as the result.
162.1121 + *
162.1122 + * @param augend value to be added to this {@code BigDecimal}.
162.1123 + * @param mc the context to use.
162.1124 + * @return {@code this + augend}, rounded as necessary.
162.1125 + * @throws ArithmeticException if the result is inexact but the
162.1126 + * rounding mode is {@code UNNECESSARY}.
162.1127 + * @since 1.5
162.1128 + */
162.1129 + public BigDecimal add(BigDecimal augend, MathContext mc) {
162.1130 + if (mc.precision == 0)
162.1131 + return add(augend);
162.1132 + BigDecimal lhs = this;
162.1133 +
162.1134 + // Could optimize if values are compact
162.1135 + this.inflate();
162.1136 + augend.inflate();
162.1137 +
162.1138 + // If either number is zero then the other number, rounded and
162.1139 + // scaled if necessary, is used as the result.
162.1140 + {
162.1141 + boolean lhsIsZero = lhs.signum() == 0;
162.1142 + boolean augendIsZero = augend.signum() == 0;
162.1143 +
162.1144 + if (lhsIsZero || augendIsZero) {
162.1145 + int preferredScale = Math.max(lhs.scale(), augend.scale());
162.1146 + BigDecimal result;
162.1147 +
162.1148 + // Could use a factory for zero instead of a new object
162.1149 + if (lhsIsZero && augendIsZero)
162.1150 + return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0);
162.1151 +
162.1152 + result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc);
162.1153 +
162.1154 + if (result.scale() == preferredScale)
162.1155 + return result;
162.1156 + else if (result.scale() > preferredScale) {
162.1157 + BigDecimal scaledResult =
162.1158 + new BigDecimal(result.intVal, result.intCompact,
162.1159 + result.scale, 0);
162.1160 + scaledResult.stripZerosToMatchScale(preferredScale);
162.1161 + return scaledResult;
162.1162 + } else { // result.scale < preferredScale
162.1163 + int precisionDiff = mc.precision - result.precision();
162.1164 + int scaleDiff = preferredScale - result.scale();
162.1165 +
162.1166 + if (precisionDiff >= scaleDiff)
162.1167 + return result.setScale(preferredScale); // can achieve target scale
162.1168 + else
162.1169 + return result.setScale(result.scale() + precisionDiff);
162.1170 + }
162.1171 + }
162.1172 + }
162.1173 +
162.1174 + long padding = (long)lhs.scale - augend.scale;
162.1175 + if (padding != 0) { // scales differ; alignment needed
162.1176 + BigDecimal arg[] = preAlign(lhs, augend, padding, mc);
162.1177 + matchScale(arg);
162.1178 + lhs = arg[0];
162.1179 + augend = arg[1];
162.1180 + }
162.1181 +
162.1182 + BigDecimal d = new BigDecimal(lhs.inflate().add(augend.inflate()),
162.1183 + lhs.scale);
162.1184 + return doRound(d, mc);
162.1185 + }
162.1186 +
162.1187 + /**
162.1188 + * Returns an array of length two, the sum of whose entries is
162.1189 + * equal to the rounded sum of the {@code BigDecimal} arguments.
162.1190 + *
162.1191 + * <p>If the digit positions of the arguments have a sufficient
162.1192 + * gap between them, the value smaller in magnitude can be
162.1193 + * condensed into a {@literal "sticky bit"} and the end result will
162.1194 + * round the same way <em>if</em> the precision of the final
162.1195 + * result does not include the high order digit of the small
162.1196 + * magnitude operand.
162.1197 + *
162.1198 + * <p>Note that while strictly speaking this is an optimization,
162.1199 + * it makes a much wider range of additions practical.
162.1200 + *
162.1201 + * <p>This corresponds to a pre-shift operation in a fixed
162.1202 + * precision floating-point adder; this method is complicated by
162.1203 + * variable precision of the result as determined by the
162.1204 + * MathContext. A more nuanced operation could implement a
162.1205 + * {@literal "right shift"} on the smaller magnitude operand so
162.1206 + * that the number of digits of the smaller operand could be
162.1207 + * reduced even though the significands partially overlapped.
162.1208 + */
162.1209 + private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend,
162.1210 + long padding, MathContext mc) {
162.1211 + assert padding != 0;
162.1212 + BigDecimal big;
162.1213 + BigDecimal small;
162.1214 +
162.1215 + if (padding < 0) { // lhs is big; augend is small
162.1216 + big = lhs;
162.1217 + small = augend;
162.1218 + } else { // lhs is small; augend is big
162.1219 + big = augend;
162.1220 + small = lhs;
162.1221 + }
162.1222 +
162.1223 + /*
162.1224 + * This is the estimated scale of an ulp of the result; it
162.1225 + * assumes that the result doesn't have a carry-out on a true
162.1226 + * add (e.g. 999 + 1 => 1000) or any subtractive cancellation
162.1227 + * on borrowing (e.g. 100 - 1.2 => 98.8)
162.1228 + */
162.1229 + long estResultUlpScale = (long)big.scale - big.precision() + mc.precision;
162.1230 +
162.1231 + /*
162.1232 + * The low-order digit position of big is big.scale(). This
162.1233 + * is true regardless of whether big has a positive or
162.1234 + * negative scale. The high-order digit position of small is
162.1235 + * small.scale - (small.precision() - 1). To do the full
162.1236 + * condensation, the digit positions of big and small must be
162.1237 + * disjoint *and* the digit positions of small should not be
162.1238 + * directly visible in the result.
162.1239 + */
162.1240 + long smallHighDigitPos = (long)small.scale - small.precision() + 1;
162.1241 + if (smallHighDigitPos > big.scale + 2 && // big and small disjoint
162.1242 + smallHighDigitPos > estResultUlpScale + 2) { // small digits not visible
162.1243 + small = BigDecimal.valueOf(small.signum(),
162.1244 + this.checkScale(Math.max(big.scale, estResultUlpScale) + 3));
162.1245 + }
162.1246 +
162.1247 + // Since addition is symmetric, preserving input order in
162.1248 + // returned operands doesn't matter
162.1249 + BigDecimal[] result = {big, small};
162.1250 + return result;
162.1251 + }
162.1252 +
162.1253 + /**
162.1254 + * Returns a {@code BigDecimal} whose value is {@code (this -
162.1255 + * subtrahend)}, and whose scale is {@code max(this.scale(),
162.1256 + * subtrahend.scale())}.
162.1257 + *
162.1258 + * @param subtrahend value to be subtracted from this {@code BigDecimal}.
162.1259 + * @return {@code this - subtrahend}
162.1260 + */
162.1261 + public BigDecimal subtract(BigDecimal subtrahend) {
162.1262 + return add(subtrahend.negate());
162.1263 + }
162.1264 +
162.1265 + /**
162.1266 + * Returns a {@code BigDecimal} whose value is {@code (this - subtrahend)},
162.1267 + * with rounding according to the context settings.
162.1268 + *
162.1269 + * If {@code subtrahend} is zero then this, rounded if necessary, is used as the
162.1270 + * result. If this is zero then the result is {@code subtrahend.negate(mc)}.
162.1271 + *
162.1272 + * @param subtrahend value to be subtracted from this {@code BigDecimal}.
162.1273 + * @param mc the context to use.
162.1274 + * @return {@code this - subtrahend}, rounded as necessary.
162.1275 + * @throws ArithmeticException if the result is inexact but the
162.1276 + * rounding mode is {@code UNNECESSARY}.
162.1277 + * @since 1.5
162.1278 + */
162.1279 + public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
162.1280 + BigDecimal nsubtrahend = subtrahend.negate();
162.1281 + if (mc.precision == 0)
162.1282 + return add(nsubtrahend);
162.1283 + // share the special rounding code in add()
162.1284 + return add(nsubtrahend, mc);
162.1285 + }
162.1286 +
162.1287 + /**
162.1288 + * Returns a {@code BigDecimal} whose value is <tt>(this ×
162.1289 + * multiplicand)</tt>, and whose scale is {@code (this.scale() +
162.1290 + * multiplicand.scale())}.
162.1291 + *
162.1292 + * @param multiplicand value to be multiplied by this {@code BigDecimal}.
162.1293 + * @return {@code this * multiplicand}
162.1294 + */
162.1295 + public BigDecimal multiply(BigDecimal multiplicand) {
162.1296 + long x = this.intCompact;
162.1297 + long y = multiplicand.intCompact;
162.1298 + int productScale = checkScale((long)scale + multiplicand.scale);
162.1299 +
162.1300 + // Might be able to do a more clever check incorporating the
162.1301 + // inflated check into the overflow computation.
162.1302 + if (x != INFLATED && y != INFLATED) {
162.1303 + /*
162.1304 + * If the product is not an overflowed value, continue
162.1305 + * to use the compact representation. if either of x or y
162.1306 + * is INFLATED, the product should also be regarded as
162.1307 + * an overflow. Before using the overflow test suggested in
162.1308 + * "Hacker's Delight" section 2-12, we perform quick checks
162.1309 + * using the precision information to see whether the overflow
162.1310 + * would occur since division is expensive on most CPUs.
162.1311 + */
162.1312 + long product = x * y;
162.1313 + long prec = this.precision() + multiplicand.precision();
162.1314 + if (prec < 19 || (prec < 21 && (y == 0 || product / y == x)))
162.1315 + return BigDecimal.valueOf(product, productScale);
162.1316 + return new BigDecimal(BigInteger.valueOf(x).multiply(y), INFLATED,
162.1317 + productScale, 0);
162.1318 + }
162.1319 + BigInteger rb;
162.1320 + if (x == INFLATED && y == INFLATED)
162.1321 + rb = this.intVal.multiply(multiplicand.intVal);
162.1322 + else if (x != INFLATED)
162.1323 + rb = multiplicand.intVal.multiply(x);
162.1324 + else
162.1325 + rb = this.intVal.multiply(y);
162.1326 + return new BigDecimal(rb, INFLATED, productScale, 0);
162.1327 + }
162.1328 +
162.1329 + /**
162.1330 + * Returns a {@code BigDecimal} whose value is <tt>(this ×
162.1331 + * multiplicand)</tt>, with rounding according to the context settings.
162.1332 + *
162.1333 + * @param multiplicand value to be multiplied by this {@code BigDecimal}.
162.1334 + * @param mc the context to use.
162.1335 + * @return {@code this * multiplicand}, rounded as necessary.
162.1336 + * @throws ArithmeticException if the result is inexact but the
162.1337 + * rounding mode is {@code UNNECESSARY}.
162.1338 + * @since 1.5
162.1339 + */
162.1340 + public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
162.1341 + if (mc.precision == 0)
162.1342 + return multiply(multiplicand);
162.1343 + return doRound(this.multiply(multiplicand), mc);
162.1344 + }
162.1345 +
162.1346 + /**
162.1347 + * Returns a {@code BigDecimal} whose value is {@code (this /
162.1348 + * divisor)}, and whose scale is as specified. If rounding must
162.1349 + * be performed to generate a result with the specified scale, the
162.1350 + * specified rounding mode is applied.
162.1351 + *
162.1352 + * <p>The new {@link #divide(BigDecimal, int, RoundingMode)} method
162.1353 + * should be used in preference to this legacy method.
162.1354 + *
162.1355 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1356 + * @param scale scale of the {@code BigDecimal} quotient to be returned.
162.1357 + * @param roundingMode rounding mode to apply.
162.1358 + * @return {@code this / divisor}
162.1359 + * @throws ArithmeticException if {@code divisor} is zero,
162.1360 + * {@code roundingMode==ROUND_UNNECESSARY} and
162.1361 + * the specified scale is insufficient to represent the result
162.1362 + * of the division exactly.
162.1363 + * @throws IllegalArgumentException if {@code roundingMode} does not
162.1364 + * represent a valid rounding mode.
162.1365 + * @see #ROUND_UP
162.1366 + * @see #ROUND_DOWN
162.1367 + * @see #ROUND_CEILING
162.1368 + * @see #ROUND_FLOOR
162.1369 + * @see #ROUND_HALF_UP
162.1370 + * @see #ROUND_HALF_DOWN
162.1371 + * @see #ROUND_HALF_EVEN
162.1372 + * @see #ROUND_UNNECESSARY
162.1373 + */
162.1374 + public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
162.1375 + /*
162.1376 + * IMPLEMENTATION NOTE: This method *must* return a new object
162.1377 + * since divideAndRound uses divide to generate a value whose
162.1378 + * scale is then modified.
162.1379 + */
162.1380 + if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
162.1381 + throw new IllegalArgumentException("Invalid rounding mode");
162.1382 + /*
162.1383 + * Rescale dividend or divisor (whichever can be "upscaled" to
162.1384 + * produce correctly scaled quotient).
162.1385 + * Take care to detect out-of-range scales
162.1386 + */
162.1387 + BigDecimal dividend = this;
162.1388 + if (checkScale((long)scale + divisor.scale) > this.scale)
162.1389 + dividend = this.setScale(scale + divisor.scale, ROUND_UNNECESSARY);
162.1390 + else
162.1391 + divisor = divisor.setScale(checkScale((long)this.scale - scale),
162.1392 + ROUND_UNNECESSARY);
162.1393 + return divideAndRound(dividend.intCompact, dividend.intVal,
162.1394 + divisor.intCompact, divisor.intVal,
162.1395 + scale, roundingMode, scale);
162.1396 + }
162.1397 +
162.1398 + /**
162.1399 + * Internally used for division operation. The dividend and divisor are
162.1400 + * passed both in {@code long} format and {@code BigInteger} format. The
162.1401 + * returned {@code BigDecimal} object is the quotient whose scale is set to
162.1402 + * the passed in scale. If the remainder is not zero, it will be rounded
162.1403 + * based on the passed in roundingMode. Also, if the remainder is zero and
162.1404 + * the last parameter, i.e. preferredScale is NOT equal to scale, the
162.1405 + * trailing zeros of the result is stripped to match the preferredScale.
162.1406 + */
162.1407 + private static BigDecimal divideAndRound(long ldividend, BigInteger bdividend,
162.1408 + long ldivisor, BigInteger bdivisor,
162.1409 + int scale, int roundingMode,
162.1410 + int preferredScale) {
162.1411 + boolean isRemainderZero; // record remainder is zero or not
162.1412 + int qsign; // quotient sign
162.1413 + long q = 0, r = 0; // store quotient & remainder in long
162.1414 + MutableBigInteger mq = null; // store quotient
162.1415 + MutableBigInteger mr = null; // store remainder
162.1416 + MutableBigInteger mdivisor = null;
162.1417 + boolean isLongDivision = (ldividend != INFLATED && ldivisor != INFLATED);
162.1418 + if (isLongDivision) {
162.1419 + q = ldividend / ldivisor;
162.1420 + if (roundingMode == ROUND_DOWN && scale == preferredScale)
162.1421 + return new BigDecimal(null, q, scale, 0);
162.1422 + r = ldividend % ldivisor;
162.1423 + isRemainderZero = (r == 0);
162.1424 + qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
162.1425 + } else {
162.1426 + if (bdividend == null)
162.1427 + bdividend = BigInteger.valueOf(ldividend);
162.1428 + // Descend into mutables for faster remainder checks
162.1429 + MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
162.1430 + mq = new MutableBigInteger();
162.1431 + if (ldivisor != INFLATED) {
162.1432 + r = mdividend.divide(ldivisor, mq);
162.1433 + isRemainderZero = (r == 0);
162.1434 + qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
162.1435 + } else {
162.1436 + mdivisor = new MutableBigInteger(bdivisor.mag);
162.1437 + mr = mdividend.divide(mdivisor, mq);
162.1438 + isRemainderZero = mr.isZero();
162.1439 + qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
162.1440 + }
162.1441 + }
162.1442 + boolean increment = false;
162.1443 + if (!isRemainderZero) {
162.1444 + int cmpFracHalf;
162.1445 + /* Round as appropriate */
162.1446 + if (roundingMode == ROUND_UNNECESSARY) { // Rounding prohibited
162.1447 + throw new ArithmeticException("Rounding necessary");
162.1448 + } else if (roundingMode == ROUND_UP) { // Away from zero
162.1449 + increment = true;
162.1450 + } else if (roundingMode == ROUND_DOWN) { // Towards zero
162.1451 + increment = false;
162.1452 + } else if (roundingMode == ROUND_CEILING) { // Towards +infinity
162.1453 + increment = (qsign > 0);
162.1454 + } else if (roundingMode == ROUND_FLOOR) { // Towards -infinity
162.1455 + increment = (qsign < 0);
162.1456 + } else {
162.1457 + if (isLongDivision || ldivisor != INFLATED) {
162.1458 + if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
162.1459 + cmpFracHalf = 1; // 2 * r can't fit into long
162.1460 + } else {
162.1461 + cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
162.1462 + }
162.1463 + } else {
162.1464 + cmpFracHalf = mr.compareHalf(mdivisor);
162.1465 + }
162.1466 + if (cmpFracHalf < 0)
162.1467 + increment = false; // We're closer to higher digit
162.1468 + else if (cmpFracHalf > 0) // We're closer to lower digit
162.1469 + increment = true;
162.1470 + else if (roundingMode == ROUND_HALF_UP)
162.1471 + increment = true;
162.1472 + else if (roundingMode == ROUND_HALF_DOWN)
162.1473 + increment = false;
162.1474 + else // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd
162.1475 + increment = isLongDivision ? (q & 1L) != 0L : mq.isOdd();
162.1476 + }
162.1477 + }
162.1478 + BigDecimal res;
162.1479 + if (isLongDivision)
162.1480 + res = new BigDecimal(null, (increment ? q + qsign : q), scale, 0);
162.1481 + else {
162.1482 + if (increment)
162.1483 + mq.add(MutableBigInteger.ONE);
162.1484 + res = mq.toBigDecimal(qsign, scale);
162.1485 + }
162.1486 + if (isRemainderZero && preferredScale != scale)
162.1487 + res.stripZerosToMatchScale(preferredScale);
162.1488 + return res;
162.1489 + }
162.1490 +
162.1491 + /**
162.1492 + * Returns a {@code BigDecimal} whose value is {@code (this /
162.1493 + * divisor)}, and whose scale is as specified. If rounding must
162.1494 + * be performed to generate a result with the specified scale, the
162.1495 + * specified rounding mode is applied.
162.1496 + *
162.1497 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1498 + * @param scale scale of the {@code BigDecimal} quotient to be returned.
162.1499 + * @param roundingMode rounding mode to apply.
162.1500 + * @return {@code this / divisor}
162.1501 + * @throws ArithmeticException if {@code divisor} is zero,
162.1502 + * {@code roundingMode==RoundingMode.UNNECESSARY} and
162.1503 + * the specified scale is insufficient to represent the result
162.1504 + * of the division exactly.
162.1505 + * @since 1.5
162.1506 + */
162.1507 + public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) {
162.1508 + return divide(divisor, scale, roundingMode.oldMode);
162.1509 + }
162.1510 +
162.1511 + /**
162.1512 + * Returns a {@code BigDecimal} whose value is {@code (this /
162.1513 + * divisor)}, and whose scale is {@code this.scale()}. If
162.1514 + * rounding must be performed to generate a result with the given
162.1515 + * scale, the specified rounding mode is applied.
162.1516 + *
162.1517 + * <p>The new {@link #divide(BigDecimal, RoundingMode)} method
162.1518 + * should be used in preference to this legacy method.
162.1519 + *
162.1520 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1521 + * @param roundingMode rounding mode to apply.
162.1522 + * @return {@code this / divisor}
162.1523 + * @throws ArithmeticException if {@code divisor==0}, or
162.1524 + * {@code roundingMode==ROUND_UNNECESSARY} and
162.1525 + * {@code this.scale()} is insufficient to represent the result
162.1526 + * of the division exactly.
162.1527 + * @throws IllegalArgumentException if {@code roundingMode} does not
162.1528 + * represent a valid rounding mode.
162.1529 + * @see #ROUND_UP
162.1530 + * @see #ROUND_DOWN
162.1531 + * @see #ROUND_CEILING
162.1532 + * @see #ROUND_FLOOR
162.1533 + * @see #ROUND_HALF_UP
162.1534 + * @see #ROUND_HALF_DOWN
162.1535 + * @see #ROUND_HALF_EVEN
162.1536 + * @see #ROUND_UNNECESSARY
162.1537 + */
162.1538 + public BigDecimal divide(BigDecimal divisor, int roundingMode) {
162.1539 + return this.divide(divisor, scale, roundingMode);
162.1540 + }
162.1541 +
162.1542 + /**
162.1543 + * Returns a {@code BigDecimal} whose value is {@code (this /
162.1544 + * divisor)}, and whose scale is {@code this.scale()}. If
162.1545 + * rounding must be performed to generate a result with the given
162.1546 + * scale, the specified rounding mode is applied.
162.1547 + *
162.1548 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1549 + * @param roundingMode rounding mode to apply.
162.1550 + * @return {@code this / divisor}
162.1551 + * @throws ArithmeticException if {@code divisor==0}, or
162.1552 + * {@code roundingMode==RoundingMode.UNNECESSARY} and
162.1553 + * {@code this.scale()} is insufficient to represent the result
162.1554 + * of the division exactly.
162.1555 + * @since 1.5
162.1556 + */
162.1557 + public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) {
162.1558 + return this.divide(divisor, scale, roundingMode.oldMode);
162.1559 + }
162.1560 +
162.1561 + /**
162.1562 + * Returns a {@code BigDecimal} whose value is {@code (this /
162.1563 + * divisor)}, and whose preferred scale is {@code (this.scale() -
162.1564 + * divisor.scale())}; if the exact quotient cannot be
162.1565 + * represented (because it has a non-terminating decimal
162.1566 + * expansion) an {@code ArithmeticException} is thrown.
162.1567 + *
162.1568 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1569 + * @throws ArithmeticException if the exact quotient does not have a
162.1570 + * terminating decimal expansion
162.1571 + * @return {@code this / divisor}
162.1572 + * @since 1.5
162.1573 + * @author Joseph D. Darcy
162.1574 + */
162.1575 + public BigDecimal divide(BigDecimal divisor) {
162.1576 + /*
162.1577 + * Handle zero cases first.
162.1578 + */
162.1579 + if (divisor.signum() == 0) { // x/0
162.1580 + if (this.signum() == 0) // 0/0
162.1581 + throw new ArithmeticException("Division undefined"); // NaN
162.1582 + throw new ArithmeticException("Division by zero");
162.1583 + }
162.1584 +
162.1585 + // Calculate preferred scale
162.1586 + int preferredScale = saturateLong((long)this.scale - divisor.scale);
162.1587 + if (this.signum() == 0) // 0/y
162.1588 + return (preferredScale >= 0 &&
162.1589 + preferredScale < ZERO_SCALED_BY.length) ?
162.1590 + ZERO_SCALED_BY[preferredScale] :
162.1591 + BigDecimal.valueOf(0, preferredScale);
162.1592 + else {
162.1593 + this.inflate();
162.1594 + divisor.inflate();
162.1595 + /*
162.1596 + * If the quotient this/divisor has a terminating decimal
162.1597 + * expansion, the expansion can have no more than
162.1598 + * (a.precision() + ceil(10*b.precision)/3) digits.
162.1599 + * Therefore, create a MathContext object with this
162.1600 + * precision and do a divide with the UNNECESSARY rounding
162.1601 + * mode.
162.1602 + */
162.1603 + MathContext mc = new MathContext( (int)Math.min(this.precision() +
162.1604 + (long)Math.ceil(10.0*divisor.precision()/3.0),
162.1605 + Integer.MAX_VALUE),
162.1606 + RoundingMode.UNNECESSARY);
162.1607 + BigDecimal quotient;
162.1608 + try {
162.1609 + quotient = this.divide(divisor, mc);
162.1610 + } catch (ArithmeticException e) {
162.1611 + throw new ArithmeticException("Non-terminating decimal expansion; " +
162.1612 + "no exact representable decimal result.");
162.1613 + }
162.1614 +
162.1615 + int quotientScale = quotient.scale();
162.1616 +
162.1617 + // divide(BigDecimal, mc) tries to adjust the quotient to
162.1618 + // the desired one by removing trailing zeros; since the
162.1619 + // exact divide method does not have an explicit digit
162.1620 + // limit, we can add zeros too.
162.1621 +
162.1622 + if (preferredScale > quotientScale)
162.1623 + return quotient.setScale(preferredScale, ROUND_UNNECESSARY);
162.1624 +
162.1625 + return quotient;
162.1626 + }
162.1627 + }
162.1628 +
162.1629 + /**
162.1630 + * Returns a {@code BigDecimal} whose value is {@code (this /
162.1631 + * divisor)}, with rounding according to the context settings.
162.1632 + *
162.1633 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1634 + * @param mc the context to use.
162.1635 + * @return {@code this / divisor}, rounded as necessary.
162.1636 + * @throws ArithmeticException if the result is inexact but the
162.1637 + * rounding mode is {@code UNNECESSARY} or
162.1638 + * {@code mc.precision == 0} and the quotient has a
162.1639 + * non-terminating decimal expansion.
162.1640 + * @since 1.5
162.1641 + */
162.1642 + public BigDecimal divide(BigDecimal divisor, MathContext mc) {
162.1643 + int mcp = mc.precision;
162.1644 + if (mcp == 0)
162.1645 + return divide(divisor);
162.1646 +
162.1647 + BigDecimal dividend = this;
162.1648 + long preferredScale = (long)dividend.scale - divisor.scale;
162.1649 + // Now calculate the answer. We use the existing
162.1650 + // divide-and-round method, but as this rounds to scale we have
162.1651 + // to normalize the values here to achieve the desired result.
162.1652 + // For x/y we first handle y=0 and x=0, and then normalize x and
162.1653 + // y to give x' and y' with the following constraints:
162.1654 + // (a) 0.1 <= x' < 1
162.1655 + // (b) x' <= y' < 10*x'
162.1656 + // Dividing x'/y' with the required scale set to mc.precision then
162.1657 + // will give a result in the range 0.1 to 1 rounded to exactly
162.1658 + // the right number of digits (except in the case of a result of
162.1659 + // 1.000... which can arise when x=y, or when rounding overflows
162.1660 + // The 1.000... case will reduce properly to 1.
162.1661 + if (divisor.signum() == 0) { // x/0
162.1662 + if (dividend.signum() == 0) // 0/0
162.1663 + throw new ArithmeticException("Division undefined"); // NaN
162.1664 + throw new ArithmeticException("Division by zero");
162.1665 + }
162.1666 + if (dividend.signum() == 0) // 0/y
162.1667 + return new BigDecimal(BigInteger.ZERO, 0,
162.1668 + saturateLong(preferredScale), 1);
162.1669 +
162.1670 + // Normalize dividend & divisor so that both fall into [0.1, 0.999...]
162.1671 + int xscale = dividend.precision();
162.1672 + int yscale = divisor.precision();
162.1673 + dividend = new BigDecimal(dividend.intVal, dividend.intCompact,
162.1674 + xscale, xscale);
162.1675 + divisor = new BigDecimal(divisor.intVal, divisor.intCompact,
162.1676 + yscale, yscale);
162.1677 + if (dividend.compareMagnitude(divisor) > 0) // satisfy constraint (b)
162.1678 + yscale = divisor.scale -= 1; // [that is, divisor *= 10]
162.1679 +
162.1680 + // In order to find out whether the divide generates the exact result,
162.1681 + // we avoid calling the above divide method. 'quotient' holds the
162.1682 + // return BigDecimal object whose scale will be set to 'scl'.
162.1683 + BigDecimal quotient;
162.1684 + int scl = checkScale(preferredScale + yscale - xscale + mcp);
162.1685 + if (checkScale((long)mcp + yscale) > xscale)
162.1686 + dividend = dividend.setScale(mcp + yscale, ROUND_UNNECESSARY);
162.1687 + else
162.1688 + divisor = divisor.setScale(checkScale((long)xscale - mcp),
162.1689 + ROUND_UNNECESSARY);
162.1690 + quotient = divideAndRound(dividend.intCompact, dividend.intVal,
162.1691 + divisor.intCompact, divisor.intVal,
162.1692 + scl, mc.roundingMode.oldMode,
162.1693 + checkScale(preferredScale));
162.1694 + // doRound, here, only affects 1000000000 case.
162.1695 + quotient = doRound(quotient, mc);
162.1696 +
162.1697 + return quotient;
162.1698 + }
162.1699 +
162.1700 + /**
162.1701 + * Returns a {@code BigDecimal} whose value is the integer part
162.1702 + * of the quotient {@code (this / divisor)} rounded down. The
162.1703 + * preferred scale of the result is {@code (this.scale() -
162.1704 + * divisor.scale())}.
162.1705 + *
162.1706 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1707 + * @return The integer part of {@code this / divisor}.
162.1708 + * @throws ArithmeticException if {@code divisor==0}
162.1709 + * @since 1.5
162.1710 + */
162.1711 + public BigDecimal divideToIntegralValue(BigDecimal divisor) {
162.1712 + // Calculate preferred scale
162.1713 + int preferredScale = saturateLong((long)this.scale - divisor.scale);
162.1714 + if (this.compareMagnitude(divisor) < 0) {
162.1715 + // much faster when this << divisor
162.1716 + return BigDecimal.valueOf(0, preferredScale);
162.1717 + }
162.1718 +
162.1719 + if(this.signum() == 0 && divisor.signum() != 0)
162.1720 + return this.setScale(preferredScale, ROUND_UNNECESSARY);
162.1721 +
162.1722 + // Perform a divide with enough digits to round to a correct
162.1723 + // integer value; then remove any fractional digits
162.1724 +
162.1725 + int maxDigits = (int)Math.min(this.precision() +
162.1726 + (long)Math.ceil(10.0*divisor.precision()/3.0) +
162.1727 + Math.abs((long)this.scale() - divisor.scale()) + 2,
162.1728 + Integer.MAX_VALUE);
162.1729 + BigDecimal quotient = this.divide(divisor, new MathContext(maxDigits,
162.1730 + RoundingMode.DOWN));
162.1731 + if (quotient.scale > 0) {
162.1732 + quotient = quotient.setScale(0, RoundingMode.DOWN);
162.1733 + quotient.stripZerosToMatchScale(preferredScale);
162.1734 + }
162.1735 +
162.1736 + if (quotient.scale < preferredScale) {
162.1737 + // pad with zeros if necessary
162.1738 + quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY);
162.1739 + }
162.1740 + return quotient;
162.1741 + }
162.1742 +
162.1743 + /**
162.1744 + * Returns a {@code BigDecimal} whose value is the integer part
162.1745 + * of {@code (this / divisor)}. Since the integer part of the
162.1746 + * exact quotient does not depend on the rounding mode, the
162.1747 + * rounding mode does not affect the values returned by this
162.1748 + * method. The preferred scale of the result is
162.1749 + * {@code (this.scale() - divisor.scale())}. An
162.1750 + * {@code ArithmeticException} is thrown if the integer part of
162.1751 + * the exact quotient needs more than {@code mc.precision}
162.1752 + * digits.
162.1753 + *
162.1754 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1755 + * @param mc the context to use.
162.1756 + * @return The integer part of {@code this / divisor}.
162.1757 + * @throws ArithmeticException if {@code divisor==0}
162.1758 + * @throws ArithmeticException if {@code mc.precision} {@literal >} 0 and the result
162.1759 + * requires a precision of more than {@code mc.precision} digits.
162.1760 + * @since 1.5
162.1761 + * @author Joseph D. Darcy
162.1762 + */
162.1763 + public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
162.1764 + if (mc.precision == 0 || // exact result
162.1765 + (this.compareMagnitude(divisor) < 0) ) // zero result
162.1766 + return divideToIntegralValue(divisor);
162.1767 +
162.1768 + // Calculate preferred scale
162.1769 + int preferredScale = saturateLong((long)this.scale - divisor.scale);
162.1770 +
162.1771 + /*
162.1772 + * Perform a normal divide to mc.precision digits. If the
162.1773 + * remainder has absolute value less than the divisor, the
162.1774 + * integer portion of the quotient fits into mc.precision
162.1775 + * digits. Next, remove any fractional digits from the
162.1776 + * quotient and adjust the scale to the preferred value.
162.1777 + */
162.1778 + BigDecimal result = this.
162.1779 + divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
162.1780 +
162.1781 + if (result.scale() < 0) {
162.1782 + /*
162.1783 + * Result is an integer. See if quotient represents the
162.1784 + * full integer portion of the exact quotient; if it does,
162.1785 + * the computed remainder will be less than the divisor.
162.1786 + */
162.1787 + BigDecimal product = result.multiply(divisor);
162.1788 + // If the quotient is the full integer value,
162.1789 + // |dividend-product| < |divisor|.
162.1790 + if (this.subtract(product).compareMagnitude(divisor) >= 0) {
162.1791 + throw new ArithmeticException("Division impossible");
162.1792 + }
162.1793 + } else if (result.scale() > 0) {
162.1794 + /*
162.1795 + * Integer portion of quotient will fit into precision
162.1796 + * digits; recompute quotient to scale 0 to avoid double
162.1797 + * rounding and then try to adjust, if necessary.
162.1798 + */
162.1799 + result = result.setScale(0, RoundingMode.DOWN);
162.1800 + }
162.1801 + // else result.scale() == 0;
162.1802 +
162.1803 + int precisionDiff;
162.1804 + if ((preferredScale > result.scale()) &&
162.1805 + (precisionDiff = mc.precision - result.precision()) > 0) {
162.1806 + return result.setScale(result.scale() +
162.1807 + Math.min(precisionDiff, preferredScale - result.scale) );
162.1808 + } else {
162.1809 + result.stripZerosToMatchScale(preferredScale);
162.1810 + return result;
162.1811 + }
162.1812 + }
162.1813 +
162.1814 + /**
162.1815 + * Returns a {@code BigDecimal} whose value is {@code (this % divisor)}.
162.1816 + *
162.1817 + * <p>The remainder is given by
162.1818 + * {@code this.subtract(this.divideToIntegralValue(divisor).multiply(divisor))}.
162.1819 + * Note that this is not the modulo operation (the result can be
162.1820 + * negative).
162.1821 + *
162.1822 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1823 + * @return {@code this % divisor}.
162.1824 + * @throws ArithmeticException if {@code divisor==0}
162.1825 + * @since 1.5
162.1826 + */
162.1827 + public BigDecimal remainder(BigDecimal divisor) {
162.1828 + BigDecimal divrem[] = this.divideAndRemainder(divisor);
162.1829 + return divrem[1];
162.1830 + }
162.1831 +
162.1832 +
162.1833 + /**
162.1834 + * Returns a {@code BigDecimal} whose value is {@code (this %
162.1835 + * divisor)}, with rounding according to the context settings.
162.1836 + * The {@code MathContext} settings affect the implicit divide
162.1837 + * used to compute the remainder. The remainder computation
162.1838 + * itself is by definition exact. Therefore, the remainder may
162.1839 + * contain more than {@code mc.getPrecision()} digits.
162.1840 + *
162.1841 + * <p>The remainder is given by
162.1842 + * {@code this.subtract(this.divideToIntegralValue(divisor,
162.1843 + * mc).multiply(divisor))}. Note that this is not the modulo
162.1844 + * operation (the result can be negative).
162.1845 + *
162.1846 + * @param divisor value by which this {@code BigDecimal} is to be divided.
162.1847 + * @param mc the context to use.
162.1848 + * @return {@code this % divisor}, rounded as necessary.
162.1849 + * @throws ArithmeticException if {@code divisor==0}
162.1850 + * @throws ArithmeticException if the result is inexact but the
162.1851 + * rounding mode is {@code UNNECESSARY}, or {@code mc.precision}
162.1852 + * {@literal >} 0 and the result of {@code this.divideToIntgralValue(divisor)} would
162.1853 + * require a precision of more than {@code mc.precision} digits.
162.1854 + * @see #divideToIntegralValue(java.math.BigDecimal, java.math.MathContext)
162.1855 + * @since 1.5
162.1856 + */
162.1857 + public BigDecimal remainder(BigDecimal divisor, MathContext mc) {
162.1858 + BigDecimal divrem[] = this.divideAndRemainder(divisor, mc);
162.1859 + return divrem[1];
162.1860 + }
162.1861 +
162.1862 + /**
162.1863 + * Returns a two-element {@code BigDecimal} array containing the
162.1864 + * result of {@code divideToIntegralValue} followed by the result of
162.1865 + * {@code remainder} on the two operands.
162.1866 + *
162.1867 + * <p>Note that if both the integer quotient and remainder are
162.1868 + * needed, this method is faster than using the
162.1869 + * {@code divideToIntegralValue} and {@code remainder} methods
162.1870 + * separately because the division need only be carried out once.
162.1871 + *
162.1872 + * @param divisor value by which this {@code BigDecimal} is to be divided,
162.1873 + * and the remainder computed.
162.1874 + * @return a two element {@code BigDecimal} array: the quotient
162.1875 + * (the result of {@code divideToIntegralValue}) is the initial element
162.1876 + * and the remainder is the final element.
162.1877 + * @throws ArithmeticException if {@code divisor==0}
162.1878 + * @see #divideToIntegralValue(java.math.BigDecimal, java.math.MathContext)
162.1879 + * @see #remainder(java.math.BigDecimal, java.math.MathContext)
162.1880 + * @since 1.5
162.1881 + */
162.1882 + public BigDecimal[] divideAndRemainder(BigDecimal divisor) {
162.1883 + // we use the identity x = i * y + r to determine r
162.1884 + BigDecimal[] result = new BigDecimal[2];
162.1885 +
162.1886 + result[0] = this.divideToIntegralValue(divisor);
162.1887 + result[1] = this.subtract(result[0].multiply(divisor));
162.1888 + return result;
162.1889 + }
162.1890 +
162.1891 + /**
162.1892 + * Returns a two-element {@code BigDecimal} array containing the
162.1893 + * result of {@code divideToIntegralValue} followed by the result of
162.1894 + * {@code remainder} on the two operands calculated with rounding
162.1895 + * according to the context settings.
162.1896 + *
162.1897 + * <p>Note that if both the integer quotient and remainder are
162.1898 + * needed, this method is faster than using the
162.1899 + * {@code divideToIntegralValue} and {@code remainder} methods
162.1900 + * separately because the division need only be carried out once.
162.1901 + *
162.1902 + * @param divisor value by which this {@code BigDecimal} is to be divided,
162.1903 + * and the remainder computed.
162.1904 + * @param mc the context to use.
162.1905 + * @return a two element {@code BigDecimal} array: the quotient
162.1906 + * (the result of {@code divideToIntegralValue}) is the
162.1907 + * initial element and the remainder is the final element.
162.1908 + * @throws ArithmeticException if {@code divisor==0}
162.1909 + * @throws ArithmeticException if the result is inexact but the
162.1910 + * rounding mode is {@code UNNECESSARY}, or {@code mc.precision}
162.1911 + * {@literal >} 0 and the result of {@code this.divideToIntgralValue(divisor)} would
162.1912 + * require a precision of more than {@code mc.precision} digits.
162.1913 + * @see #divideToIntegralValue(java.math.BigDecimal, java.math.MathContext)
162.1914 + * @see #remainder(java.math.BigDecimal, java.math.MathContext)
162.1915 + * @since 1.5
162.1916 + */
162.1917 + public BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc) {
162.1918 + if (mc.precision == 0)
162.1919 + return divideAndRemainder(divisor);
162.1920 +
162.1921 + BigDecimal[] result = new BigDecimal[2];
162.1922 + BigDecimal lhs = this;
162.1923 +
162.1924 + result[0] = lhs.divideToIntegralValue(divisor, mc);
162.1925 + result[1] = lhs.subtract(result[0].multiply(divisor));
162.1926 + return result;
162.1927 + }
162.1928 +
162.1929 + /**
162.1930 + * Returns a {@code BigDecimal} whose value is
162.1931 + * <tt>(this<sup>n</sup>)</tt>, The power is computed exactly, to
162.1932 + * unlimited precision.
162.1933 + *
162.1934 + * <p>The parameter {@code n} must be in the range 0 through
162.1935 + * 999999999, inclusive. {@code ZERO.pow(0)} returns {@link
162.1936 + * #ONE}.
162.1937 + *
162.1938 + * Note that future releases may expand the allowable exponent
162.1939 + * range of this method.
162.1940 + *
162.1941 + * @param n power to raise this {@code BigDecimal} to.
162.1942 + * @return <tt>this<sup>n</sup></tt>
162.1943 + * @throws ArithmeticException if {@code n} is out of range.
162.1944 + * @since 1.5
162.1945 + */
162.1946 + public BigDecimal pow(int n) {
162.1947 + if (n < 0 || n > 999999999)
162.1948 + throw new ArithmeticException("Invalid operation");
162.1949 + // No need to calculate pow(n) if result will over/underflow.
162.1950 + // Don't attempt to support "supernormal" numbers.
162.1951 + int newScale = checkScale((long)scale * n);
162.1952 + this.inflate();
162.1953 + return new BigDecimal(intVal.pow(n), newScale);
162.1954 + }
162.1955 +
162.1956 +
162.1957 + /**
162.1958 + * Returns a {@code BigDecimal} whose value is
162.1959 + * <tt>(this<sup>n</sup>)</tt>. The current implementation uses
162.1960 + * the core algorithm defined in ANSI standard X3.274-1996 with
162.1961 + * rounding according to the context settings. In general, the
162.1962 + * returned numerical value is within two ulps of the exact
162.1963 + * numerical value for the chosen precision. Note that future
162.1964 + * releases may use a different algorithm with a decreased
162.1965 + * allowable error bound and increased allowable exponent range.
162.1966 + *
162.1967 + * <p>The X3.274-1996 algorithm is:
162.1968 + *
162.1969 + * <ul>
162.1970 + * <li> An {@code ArithmeticException} exception is thrown if
162.1971 + * <ul>
162.1972 + * <li>{@code abs(n) > 999999999}
162.1973 + * <li>{@code mc.precision == 0} and {@code n < 0}
162.1974 + * <li>{@code mc.precision > 0} and {@code n} has more than
162.1975 + * {@code mc.precision} decimal digits
162.1976 + * </ul>
162.1977 + *
162.1978 + * <li> if {@code n} is zero, {@link #ONE} is returned even if
162.1979 + * {@code this} is zero, otherwise
162.1980 + * <ul>
162.1981 + * <li> if {@code n} is positive, the result is calculated via
162.1982 + * the repeated squaring technique into a single accumulator.
162.1983 + * The individual multiplications with the accumulator use the
162.1984 + * same math context settings as in {@code mc} except for a
162.1985 + * precision increased to {@code mc.precision + elength + 1}
162.1986 + * where {@code elength} is the number of decimal digits in
162.1987 + * {@code n}.
162.1988 + *
162.1989 + * <li> if {@code n} is negative, the result is calculated as if
162.1990 + * {@code n} were positive; this value is then divided into one
162.1991 + * using the working precision specified above.
162.1992 + *
162.1993 + * <li> The final value from either the positive or negative case
162.1994 + * is then rounded to the destination precision.
162.1995 + * </ul>
162.1996 + * </ul>
162.1997 + *
162.1998 + * @param n power to raise this {@code BigDecimal} to.
162.1999 + * @param mc the context to use.
162.2000 + * @return <tt>this<sup>n</sup></tt> using the ANSI standard X3.274-1996
162.2001 + * algorithm
162.2002 + * @throws ArithmeticException if the result is inexact but the
162.2003 + * rounding mode is {@code UNNECESSARY}, or {@code n} is out
162.2004 + * of range.
162.2005 + * @since 1.5
162.2006 + */
162.2007 + public BigDecimal pow(int n, MathContext mc) {
162.2008 + if (mc.precision == 0)
162.2009 + return pow(n);
162.2010 + if (n < -999999999 || n > 999999999)
162.2011 + throw new ArithmeticException("Invalid operation");
162.2012 + if (n == 0)
162.2013 + return ONE; // x**0 == 1 in X3.274
162.2014 + this.inflate();
162.2015 + BigDecimal lhs = this;
162.2016 + MathContext workmc = mc; // working settings
162.2017 + int mag = Math.abs(n); // magnitude of n
162.2018 + if (mc.precision > 0) {
162.2019 +
162.2020 + int elength = longDigitLength(mag); // length of n in digits
162.2021 + if (elength > mc.precision) // X3.274 rule
162.2022 + throw new ArithmeticException("Invalid operation");
162.2023 + workmc = new MathContext(mc.precision + elength + 1,
162.2024 + mc.roundingMode);
162.2025 + }
162.2026 + // ready to carry out power calculation...
162.2027 + BigDecimal acc = ONE; // accumulator
162.2028 + boolean seenbit = false; // set once we've seen a 1-bit
162.2029 + for (int i=1;;i++) { // for each bit [top bit ignored]
162.2030 + mag += mag; // shift left 1 bit
162.2031 + if (mag < 0) { // top bit is set
162.2032 + seenbit = true; // OK, we're off
162.2033 + acc = acc.multiply(lhs, workmc); // acc=acc*x
162.2034 + }
162.2035 + if (i == 31)
162.2036 + break; // that was the last bit
162.2037 + if (seenbit)
162.2038 + acc=acc.multiply(acc, workmc); // acc=acc*acc [square]
162.2039 + // else (!seenbit) no point in squaring ONE
162.2040 + }
162.2041 + // if negative n, calculate the reciprocal using working precision
162.2042 + if (n<0) // [hence mc.precision>0]
162.2043 + acc=ONE.divide(acc, workmc);
162.2044 + // round to final precision and strip zeros
162.2045 + return doRound(acc, mc);
162.2046 + }
162.2047 +
162.2048 + /**
162.2049 + * Returns a {@code BigDecimal} whose value is the absolute value
162.2050 + * of this {@code BigDecimal}, and whose scale is
162.2051 + * {@code this.scale()}.
162.2052 + *
162.2053 + * @return {@code abs(this)}
162.2054 + */
162.2055 + public BigDecimal abs() {
162.2056 + return (signum() < 0 ? negate() : this);
162.2057 + }
162.2058 +
162.2059 + /**
162.2060 + * Returns a {@code BigDecimal} whose value is the absolute value
162.2061 + * of this {@code BigDecimal}, with rounding according to the
162.2062 + * context settings.
162.2063 + *
162.2064 + * @param mc the context to use.
162.2065 + * @return {@code abs(this)}, rounded as necessary.
162.2066 + * @throws ArithmeticException if the result is inexact but the
162.2067 + * rounding mode is {@code UNNECESSARY}.
162.2068 + * @since 1.5
162.2069 + */
162.2070 + public BigDecimal abs(MathContext mc) {
162.2071 + return (signum() < 0 ? negate(mc) : plus(mc));
162.2072 + }
162.2073 +
162.2074 + /**
162.2075 + * Returns a {@code BigDecimal} whose value is {@code (-this)},
162.2076 + * and whose scale is {@code this.scale()}.
162.2077 + *
162.2078 + * @return {@code -this}.
162.2079 + */
162.2080 + public BigDecimal negate() {
162.2081 + BigDecimal result;
162.2082 + if (intCompact != INFLATED)
162.2083 + result = BigDecimal.valueOf(-intCompact, scale);
162.2084 + else {
162.2085 + result = new BigDecimal(intVal.negate(), scale);
162.2086 + result.precision = precision;
162.2087 + }
162.2088 + return result;
162.2089 + }
162.2090 +
162.2091 + /**
162.2092 + * Returns a {@code BigDecimal} whose value is {@code (-this)},
162.2093 + * with rounding according to the context settings.
162.2094 + *
162.2095 + * @param mc the context to use.
162.2096 + * @return {@code -this}, rounded as necessary.
162.2097 + * @throws ArithmeticException if the result is inexact but the
162.2098 + * rounding mode is {@code UNNECESSARY}.
162.2099 + * @since 1.5
162.2100 + */
162.2101 + public BigDecimal negate(MathContext mc) {
162.2102 + return negate().plus(mc);
162.2103 + }
162.2104 +
162.2105 + /**
162.2106 + * Returns a {@code BigDecimal} whose value is {@code (+this)}, and whose
162.2107 + * scale is {@code this.scale()}.
162.2108 + *
162.2109 + * <p>This method, which simply returns this {@code BigDecimal}
162.2110 + * is included for symmetry with the unary minus method {@link
162.2111 + * #negate()}.
162.2112 + *
162.2113 + * @return {@code this}.
162.2114 + * @see #negate()
162.2115 + * @since 1.5
162.2116 + */
162.2117 + public BigDecimal plus() {
162.2118 + return this;
162.2119 + }
162.2120 +
162.2121 + /**
162.2122 + * Returns a {@code BigDecimal} whose value is {@code (+this)},
162.2123 + * with rounding according to the context settings.
162.2124 + *
162.2125 + * <p>The effect of this method is identical to that of the {@link
162.2126 + * #round(MathContext)} method.
162.2127 + *
162.2128 + * @param mc the context to use.
162.2129 + * @return {@code this}, rounded as necessary. A zero result will
162.2130 + * have a scale of 0.
162.2131 + * @throws ArithmeticException if the result is inexact but the
162.2132 + * rounding mode is {@code UNNECESSARY}.
162.2133 + * @see #round(MathContext)
162.2134 + * @since 1.5
162.2135 + */
162.2136 + public BigDecimal plus(MathContext mc) {
162.2137 + if (mc.precision == 0) // no rounding please
162.2138 + return this;
162.2139 + return doRound(this, mc);
162.2140 + }
162.2141 +
162.2142 + /**
162.2143 + * Returns the signum function of this {@code BigDecimal}.
162.2144 + *
162.2145 + * @return -1, 0, or 1 as the value of this {@code BigDecimal}
162.2146 + * is negative, zero, or positive.
162.2147 + */
162.2148 + public int signum() {
162.2149 + return (intCompact != INFLATED)?
162.2150 + Long.signum(intCompact):
162.2151 + intVal.signum();
162.2152 + }
162.2153 +
162.2154 + /**
162.2155 + * Returns the <i>scale</i> of this {@code BigDecimal}. If zero
162.2156 + * or positive, the scale is the number of digits to the right of
162.2157 + * the decimal point. If negative, the unscaled value of the
162.2158 + * number is multiplied by ten to the power of the negation of the
162.2159 + * scale. For example, a scale of {@code -3} means the unscaled
162.2160 + * value is multiplied by 1000.
162.2161 + *
162.2162 + * @return the scale of this {@code BigDecimal}.
162.2163 + */
162.2164 + public int scale() {
162.2165 + return scale;
162.2166 + }
162.2167 +
162.2168 + /**
162.2169 + * Returns the <i>precision</i> of this {@code BigDecimal}. (The
162.2170 + * precision is the number of digits in the unscaled value.)
162.2171 + *
162.2172 + * <p>The precision of a zero value is 1.
162.2173 + *
162.2174 + * @return the precision of this {@code BigDecimal}.
162.2175 + * @since 1.5
162.2176 + */
162.2177 + public int precision() {
162.2178 + int result = precision;
162.2179 + if (result == 0) {
162.2180 + long s = intCompact;
162.2181 + if (s != INFLATED)
162.2182 + result = longDigitLength(s);
162.2183 + else
162.2184 + result = bigDigitLength(inflate());
162.2185 + precision = result;
162.2186 + }
162.2187 + return result;
162.2188 + }
162.2189 +
162.2190 +
162.2191 + /**
162.2192 + * Returns a {@code BigInteger} whose value is the <i>unscaled
162.2193 + * value</i> of this {@code BigDecimal}. (Computes <tt>(this *
162.2194 + * 10<sup>this.scale()</sup>)</tt>.)
162.2195 + *
162.2196 + * @return the unscaled value of this {@code BigDecimal}.
162.2197 + * @since 1.2
162.2198 + */
162.2199 + public BigInteger unscaledValue() {
162.2200 + return this.inflate();
162.2201 + }
162.2202 +
162.2203 + // Rounding Modes
162.2204 +
162.2205 + /**
162.2206 + * Rounding mode to round away from zero. Always increments the
162.2207 + * digit prior to a nonzero discarded fraction. Note that this rounding
162.2208 + * mode never decreases the magnitude of the calculated value.
162.2209 + */
162.2210 + public final static int ROUND_UP = 0;
162.2211 +
162.2212 + /**
162.2213 + * Rounding mode to round towards zero. Never increments the digit
162.2214 + * prior to a discarded fraction (i.e., truncates). Note that this
162.2215 + * rounding mode never increases the magnitude of the calculated value.
162.2216 + */
162.2217 + public final static int ROUND_DOWN = 1;
162.2218 +
162.2219 + /**
162.2220 + * Rounding mode to round towards positive infinity. If the
162.2221 + * {@code BigDecimal} is positive, behaves as for
162.2222 + * {@code ROUND_UP}; if negative, behaves as for
162.2223 + * {@code ROUND_DOWN}. Note that this rounding mode never
162.2224 + * decreases the calculated value.
162.2225 + */
162.2226 + public final static int ROUND_CEILING = 2;
162.2227 +
162.2228 + /**
162.2229 + * Rounding mode to round towards negative infinity. If the
162.2230 + * {@code BigDecimal} is positive, behave as for
162.2231 + * {@code ROUND_DOWN}; if negative, behave as for
162.2232 + * {@code ROUND_UP}. Note that this rounding mode never
162.2233 + * increases the calculated value.
162.2234 + */
162.2235 + public final static int ROUND_FLOOR = 3;
162.2236 +
162.2237 + /**
162.2238 + * Rounding mode to round towards {@literal "nearest neighbor"}
162.2239 + * unless both neighbors are equidistant, in which case round up.
162.2240 + * Behaves as for {@code ROUND_UP} if the discarded fraction is
162.2241 + * ≥ 0.5; otherwise, behaves as for {@code ROUND_DOWN}. Note
162.2242 + * that this is the rounding mode that most of us were taught in
162.2243 + * grade school.
162.2244 + */
162.2245 + public final static int ROUND_HALF_UP = 4;
162.2246 +
162.2247 + /**
162.2248 + * Rounding mode to round towards {@literal "nearest neighbor"}
162.2249 + * unless both neighbors are equidistant, in which case round
162.2250 + * down. Behaves as for {@code ROUND_UP} if the discarded
162.2251 + * fraction is {@literal >} 0.5; otherwise, behaves as for
162.2252 + * {@code ROUND_DOWN}.
162.2253 + */
162.2254 + public final static int ROUND_HALF_DOWN = 5;
162.2255 +
162.2256 + /**
162.2257 + * Rounding mode to round towards the {@literal "nearest neighbor"}
162.2258 + * unless both neighbors are equidistant, in which case, round
162.2259 + * towards the even neighbor. Behaves as for
162.2260 + * {@code ROUND_HALF_UP} if the digit to the left of the
162.2261 + * discarded fraction is odd; behaves as for
162.2262 + * {@code ROUND_HALF_DOWN} if it's even. Note that this is the
162.2263 + * rounding mode that minimizes cumulative error when applied
162.2264 + * repeatedly over a sequence of calculations.
162.2265 + */
162.2266 + public final static int ROUND_HALF_EVEN = 6;
162.2267 +
162.2268 + /**
162.2269 + * Rounding mode to assert that the requested operation has an exact
162.2270 + * result, hence no rounding is necessary. If this rounding mode is
162.2271 + * specified on an operation that yields an inexact result, an
162.2272 + * {@code ArithmeticException} is thrown.
162.2273 + */
162.2274 + public final static int ROUND_UNNECESSARY = 7;
162.2275 +
162.2276 +
162.2277 + // Scaling/Rounding Operations
162.2278 +
162.2279 + /**
162.2280 + * Returns a {@code BigDecimal} rounded according to the
162.2281 + * {@code MathContext} settings. If the precision setting is 0 then
162.2282 + * no rounding takes place.
162.2283 + *
162.2284 + * <p>The effect of this method is identical to that of the
162.2285 + * {@link #plus(MathContext)} method.
162.2286 + *
162.2287 + * @param mc the context to use.
162.2288 + * @return a {@code BigDecimal} rounded according to the
162.2289 + * {@code MathContext} settings.
162.2290 + * @throws ArithmeticException if the rounding mode is
162.2291 + * {@code UNNECESSARY} and the
162.2292 + * {@code BigDecimal} operation would require rounding.
162.2293 + * @see #plus(MathContext)
162.2294 + * @since 1.5
162.2295 + */
162.2296 + public BigDecimal round(MathContext mc) {
162.2297 + return plus(mc);
162.2298 + }
162.2299 +
162.2300 + /**
162.2301 + * Returns a {@code BigDecimal} whose scale is the specified
162.2302 + * value, and whose unscaled value is determined by multiplying or
162.2303 + * dividing this {@code BigDecimal}'s unscaled value by the
162.2304 + * appropriate power of ten to maintain its overall value. If the
162.2305 + * scale is reduced by the operation, the unscaled value must be
162.2306 + * divided (rather than multiplied), and the value may be changed;
162.2307 + * in this case, the specified rounding mode is applied to the
162.2308 + * division.
162.2309 + *
162.2310 + * <p>Note that since BigDecimal objects are immutable, calls of
162.2311 + * this method do <i>not</i> result in the original object being
162.2312 + * modified, contrary to the usual convention of having methods
162.2313 + * named <tt>set<i>X</i></tt> mutate field <i>{@code X}</i>.
162.2314 + * Instead, {@code setScale} returns an object with the proper
162.2315 + * scale; the returned object may or may not be newly allocated.
162.2316 + *
162.2317 + * @param newScale scale of the {@code BigDecimal} value to be returned.
162.2318 + * @param roundingMode The rounding mode to apply.
162.2319 + * @return a {@code BigDecimal} whose scale is the specified value,
162.2320 + * and whose unscaled value is determined by multiplying or
162.2321 + * dividing this {@code BigDecimal}'s unscaled value by the
162.2322 + * appropriate power of ten to maintain its overall value.
162.2323 + * @throws ArithmeticException if {@code roundingMode==UNNECESSARY}
162.2324 + * and the specified scaling operation would require
162.2325 + * rounding.
162.2326 + * @see RoundingMode
162.2327 + * @since 1.5
162.2328 + */
162.2329 + public BigDecimal setScale(int newScale, RoundingMode roundingMode) {
162.2330 + return setScale(newScale, roundingMode.oldMode);
162.2331 + }
162.2332 +
162.2333 + /**
162.2334 + * Returns a {@code BigDecimal} whose scale is the specified
162.2335 + * value, and whose unscaled value is determined by multiplying or
162.2336 + * dividing this {@code BigDecimal}'s unscaled value by the
162.2337 + * appropriate power of ten to maintain its overall value. If the
162.2338 + * scale is reduced by the operation, the unscaled value must be
162.2339 + * divided (rather than multiplied), and the value may be changed;
162.2340 + * in this case, the specified rounding mode is applied to the
162.2341 + * division.
162.2342 + *
162.2343 + * <p>Note that since BigDecimal objects are immutable, calls of
162.2344 + * this method do <i>not</i> result in the original object being
162.2345 + * modified, contrary to the usual convention of having methods
162.2346 + * named <tt>set<i>X</i></tt> mutate field <i>{@code X}</i>.
162.2347 + * Instead, {@code setScale} returns an object with the proper
162.2348 + * scale; the returned object may or may not be newly allocated.
162.2349 + *
162.2350 + * <p>The new {@link #setScale(int, RoundingMode)} method should
162.2351 + * be used in preference to this legacy method.
162.2352 + *
162.2353 + * @param newScale scale of the {@code BigDecimal} value to be returned.
162.2354 + * @param roundingMode The rounding mode to apply.
162.2355 + * @return a {@code BigDecimal} whose scale is the specified value,
162.2356 + * and whose unscaled value is determined by multiplying or
162.2357 + * dividing this {@code BigDecimal}'s unscaled value by the
162.2358 + * appropriate power of ten to maintain its overall value.
162.2359 + * @throws ArithmeticException if {@code roundingMode==ROUND_UNNECESSARY}
162.2360 + * and the specified scaling operation would require
162.2361 + * rounding.
162.2362 + * @throws IllegalArgumentException if {@code roundingMode} does not
162.2363 + * represent a valid rounding mode.
162.2364 + * @see #ROUND_UP
162.2365 + * @see #ROUND_DOWN
162.2366 + * @see #ROUND_CEILING
162.2367 + * @see #ROUND_FLOOR
162.2368 + * @see #ROUND_HALF_UP
162.2369 + * @see #ROUND_HALF_DOWN
162.2370 + * @see #ROUND_HALF_EVEN
162.2371 + * @see #ROUND_UNNECESSARY
162.2372 + */
162.2373 + public BigDecimal setScale(int newScale, int roundingMode) {
162.2374 + if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
162.2375 + throw new IllegalArgumentException("Invalid rounding mode");
162.2376 +
162.2377 + int oldScale = this.scale;
162.2378 + if (newScale == oldScale) // easy case
162.2379 + return this;
162.2380 + if (this.signum() == 0) // zero can have any scale
162.2381 + return BigDecimal.valueOf(0, newScale);
162.2382 +
162.2383 + long rs = this.intCompact;
162.2384 + if (newScale > oldScale) {
162.2385 + int raise = checkScale((long)newScale - oldScale);
162.2386 + BigInteger rb = null;
162.2387 + if (rs == INFLATED ||
162.2388 + (rs = longMultiplyPowerTen(rs, raise)) == INFLATED)
162.2389 + rb = bigMultiplyPowerTen(raise);
162.2390 + return new BigDecimal(rb, rs, newScale,
162.2391 + (precision > 0) ? precision + raise : 0);
162.2392 + } else {
162.2393 + // newScale < oldScale -- drop some digits
162.2394 + // Can't predict the precision due to the effect of rounding.
162.2395 + int drop = checkScale((long)oldScale - newScale);
162.2396 + if (drop < LONG_TEN_POWERS_TABLE.length)
162.2397 + return divideAndRound(rs, this.intVal,
162.2398 + LONG_TEN_POWERS_TABLE[drop], null,
162.2399 + newScale, roundingMode, newScale);
162.2400 + else
162.2401 + return divideAndRound(rs, this.intVal,
162.2402 + INFLATED, bigTenToThe(drop),
162.2403 + newScale, roundingMode, newScale);
162.2404 + }
162.2405 + }
162.2406 +
162.2407 + /**
162.2408 + * Returns a {@code BigDecimal} whose scale is the specified
162.2409 + * value, and whose value is numerically equal to this
162.2410 + * {@code BigDecimal}'s. Throws an {@code ArithmeticException}
162.2411 + * if this is not possible.
162.2412 + *
162.2413 + * <p>This call is typically used to increase the scale, in which
162.2414 + * case it is guaranteed that there exists a {@code BigDecimal}
162.2415 + * of the specified scale and the correct value. The call can
162.2416 + * also be used to reduce the scale if the caller knows that the
162.2417 + * {@code BigDecimal} has sufficiently many zeros at the end of
162.2418 + * its fractional part (i.e., factors of ten in its integer value)
162.2419 + * to allow for the rescaling without changing its value.
162.2420 + *
162.2421 + * <p>This method returns the same result as the two-argument
162.2422 + * versions of {@code setScale}, but saves the caller the trouble
162.2423 + * of specifying a rounding mode in cases where it is irrelevant.
162.2424 + *
162.2425 + * <p>Note that since {@code BigDecimal} objects are immutable,
162.2426 + * calls of this method do <i>not</i> result in the original
162.2427 + * object being modified, contrary to the usual convention of
162.2428 + * having methods named <tt>set<i>X</i></tt> mutate field
162.2429 + * <i>{@code X}</i>. Instead, {@code setScale} returns an
162.2430 + * object with the proper scale; the returned object may or may
162.2431 + * not be newly allocated.
162.2432 + *
162.2433 + * @param newScale scale of the {@code BigDecimal} value to be returned.
162.2434 + * @return a {@code BigDecimal} whose scale is the specified value, and
162.2435 + * whose unscaled value is determined by multiplying or dividing
162.2436 + * this {@code BigDecimal}'s unscaled value by the appropriate
162.2437 + * power of ten to maintain its overall value.
162.2438 + * @throws ArithmeticException if the specified scaling operation would
162.2439 + * require rounding.
162.2440 + * @see #setScale(int, int)
162.2441 + * @see #setScale(int, RoundingMode)
162.2442 + */
162.2443 + public BigDecimal setScale(int newScale) {
162.2444 + return setScale(newScale, ROUND_UNNECESSARY);
162.2445 + }
162.2446 +
162.2447 + // Decimal Point Motion Operations
162.2448 +
162.2449 + /**
162.2450 + * Returns a {@code BigDecimal} which is equivalent to this one
162.2451 + * with the decimal point moved {@code n} places to the left. If
162.2452 + * {@code n} is non-negative, the call merely adds {@code n} to
162.2453 + * the scale. If {@code n} is negative, the call is equivalent
162.2454 + * to {@code movePointRight(-n)}. The {@code BigDecimal}
162.2455 + * returned by this call has value <tt>(this ×
162.2456 + * 10<sup>-n</sup>)</tt> and scale {@code max(this.scale()+n,
162.2457 + * 0)}.
162.2458 + *
162.2459 + * @param n number of places to move the decimal point to the left.
162.2460 + * @return a {@code BigDecimal} which is equivalent to this one with the
162.2461 + * decimal point moved {@code n} places to the left.
162.2462 + * @throws ArithmeticException if scale overflows.
162.2463 + */
162.2464 + public BigDecimal movePointLeft(int n) {
162.2465 + // Cannot use movePointRight(-n) in case of n==Integer.MIN_VALUE
162.2466 + int newScale = checkScale((long)scale + n);
162.2467 + BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
162.2468 + return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
162.2469 + }
162.2470 +
162.2471 + /**
162.2472 + * Returns a {@code BigDecimal} which is equivalent to this one
162.2473 + * with the decimal point moved {@code n} places to the right.
162.2474 + * If {@code n} is non-negative, the call merely subtracts
162.2475 + * {@code n} from the scale. If {@code n} is negative, the call
162.2476 + * is equivalent to {@code movePointLeft(-n)}. The
162.2477 + * {@code BigDecimal} returned by this call has value <tt>(this
162.2478 + * × 10<sup>n</sup>)</tt> and scale {@code max(this.scale()-n,
162.2479 + * 0)}.
162.2480 + *
162.2481 + * @param n number of places to move the decimal point to the right.
162.2482 + * @return a {@code BigDecimal} which is equivalent to this one
162.2483 + * with the decimal point moved {@code n} places to the right.
162.2484 + * @throws ArithmeticException if scale overflows.
162.2485 + */
162.2486 + public BigDecimal movePointRight(int n) {
162.2487 + // Cannot use movePointLeft(-n) in case of n==Integer.MIN_VALUE
162.2488 + int newScale = checkScale((long)scale - n);
162.2489 + BigDecimal num = new BigDecimal(intVal, intCompact, newScale, 0);
162.2490 + return num.scale < 0 ? num.setScale(0, ROUND_UNNECESSARY) : num;
162.2491 + }
162.2492 +
162.2493 + /**
162.2494 + * Returns a BigDecimal whose numerical value is equal to
162.2495 + * ({@code this} * 10<sup>n</sup>). The scale of
162.2496 + * the result is {@code (this.scale() - n)}.
162.2497 + *
162.2498 + * @throws ArithmeticException if the scale would be
162.2499 + * outside the range of a 32-bit integer.
162.2500 + *
162.2501 + * @since 1.5
162.2502 + */
162.2503 + public BigDecimal scaleByPowerOfTen(int n) {
162.2504 + return new BigDecimal(intVal, intCompact,
162.2505 + checkScale((long)scale - n), precision);
162.2506 + }
162.2507 +
162.2508 + /**
162.2509 + * Returns a {@code BigDecimal} which is numerically equal to
162.2510 + * this one but with any trailing zeros removed from the
162.2511 + * representation. For example, stripping the trailing zeros from
162.2512 + * the {@code BigDecimal} value {@code 600.0}, which has
162.2513 + * [{@code BigInteger}, {@code scale}] components equals to
162.2514 + * [6000, 1], yields {@code 6E2} with [{@code BigInteger},
162.2515 + * {@code scale}] components equals to [6, -2]
162.2516 + *
162.2517 + * @return a numerically equal {@code BigDecimal} with any
162.2518 + * trailing zeros removed.
162.2519 + * @since 1.5
162.2520 + */
162.2521 + public BigDecimal stripTrailingZeros() {
162.2522 + this.inflate();
162.2523 + BigDecimal result = new BigDecimal(intVal, scale);
162.2524 + result.stripZerosToMatchScale(Long.MIN_VALUE);
162.2525 + return result;
162.2526 + }
162.2527 +
162.2528 + // Comparison Operations
162.2529 +
162.2530 + /**
162.2531 + * Compares this {@code BigDecimal} with the specified
162.2532 + * {@code BigDecimal}. Two {@code BigDecimal} objects that are
162.2533 + * equal in value but have a different scale (like 2.0 and 2.00)
162.2534 + * are considered equal by this method. This method is provided
162.2535 + * in preference to individual methods for each of the six boolean
162.2536 + * comparison operators ({@literal <}, ==,
162.2537 + * {@literal >}, {@literal >=}, !=, {@literal <=}). The
162.2538 + * suggested idiom for performing these comparisons is:
162.2539 + * {@code (x.compareTo(y)} <<i>op</i>> {@code 0)}, where
162.2540 + * <<i>op</i>> is one of the six comparison operators.
162.2541 + *
162.2542 + * @param val {@code BigDecimal} to which this {@code BigDecimal} is
162.2543 + * to be compared.
162.2544 + * @return -1, 0, or 1 as this {@code BigDecimal} is numerically
162.2545 + * less than, equal to, or greater than {@code val}.
162.2546 + */
162.2547 + public int compareTo(BigDecimal val) {
162.2548 + // Quick path for equal scale and non-inflated case.
162.2549 + if (scale == val.scale) {
162.2550 + long xs = intCompact;
162.2551 + long ys = val.intCompact;
162.2552 + if (xs != INFLATED && ys != INFLATED)
162.2553 + return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
162.2554 + }
162.2555 + int xsign = this.signum();
162.2556 + int ysign = val.signum();
162.2557 + if (xsign != ysign)
162.2558 + return (xsign > ysign) ? 1 : -1;
162.2559 + if (xsign == 0)
162.2560 + return 0;
162.2561 + int cmp = compareMagnitude(val);
162.2562 + return (xsign > 0) ? cmp : -cmp;
162.2563 + }
162.2564 +
162.2565 + /**
162.2566 + * Version of compareTo that ignores sign.
162.2567 + */
162.2568 + private int compareMagnitude(BigDecimal val) {
162.2569 + // Match scales, avoid unnecessary inflation
162.2570 + long ys = val.intCompact;
162.2571 + long xs = this.intCompact;
162.2572 + if (xs == 0)
162.2573 + return (ys == 0) ? 0 : -1;
162.2574 + if (ys == 0)
162.2575 + return 1;
162.2576 +
162.2577 + int sdiff = this.scale - val.scale;
162.2578 + if (sdiff != 0) {
162.2579 + // Avoid matching scales if the (adjusted) exponents differ
162.2580 + int xae = this.precision() - this.scale; // [-1]
162.2581 + int yae = val.precision() - val.scale; // [-1]
162.2582 + if (xae < yae)
162.2583 + return -1;
162.2584 + if (xae > yae)
162.2585 + return 1;
162.2586 + BigInteger rb = null;
162.2587 + if (sdiff < 0) {
162.2588 + if ( (xs == INFLATED ||
162.2589 + (xs = longMultiplyPowerTen(xs, -sdiff)) == INFLATED) &&
162.2590 + ys == INFLATED) {
162.2591 + rb = bigMultiplyPowerTen(-sdiff);
162.2592 + return rb.compareMagnitude(val.intVal);
162.2593 + }
162.2594 + } else { // sdiff > 0
162.2595 + if ( (ys == INFLATED ||
162.2596 + (ys = longMultiplyPowerTen(ys, sdiff)) == INFLATED) &&
162.2597 + xs == INFLATED) {
162.2598 + rb = val.bigMultiplyPowerTen(sdiff);
162.2599 + return this.intVal.compareMagnitude(rb);
162.2600 + }
162.2601 + }
162.2602 + }
162.2603 + if (xs != INFLATED)
162.2604 + return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1;
162.2605 + else if (ys != INFLATED)
162.2606 + return 1;
162.2607 + else
162.2608 + return this.intVal.compareMagnitude(val.intVal);
162.2609 + }
162.2610 +
162.2611 + /**
162.2612 + * Compares this {@code BigDecimal} with the specified
162.2613 + * {@code Object} for equality. Unlike {@link
162.2614 + * #compareTo(BigDecimal) compareTo}, this method considers two
162.2615 + * {@code BigDecimal} objects equal only if they are equal in
162.2616 + * value and scale (thus 2.0 is not equal to 2.00 when compared by
162.2617 + * this method).
162.2618 + *
162.2619 + * @param x {@code Object} to which this {@code BigDecimal} is
162.2620 + * to be compared.
162.2621 + * @return {@code true} if and only if the specified {@code Object} is a
162.2622 + * {@code BigDecimal} whose value and scale are equal to this
162.2623 + * {@code BigDecimal}'s.
162.2624 + * @see #compareTo(java.math.BigDecimal)
162.2625 + * @see #hashCode
162.2626 + */
162.2627 + @Override
162.2628 + public boolean equals(Object x) {
162.2629 + if (!(x instanceof BigDecimal))
162.2630 + return false;
162.2631 + BigDecimal xDec = (BigDecimal) x;
162.2632 + if (x == this)
162.2633 + return true;
162.2634 + if (scale != xDec.scale)
162.2635 + return false;
162.2636 + long s = this.intCompact;
162.2637 + long xs = xDec.intCompact;
162.2638 + if (s != INFLATED) {
162.2639 + if (xs == INFLATED)
162.2640 + xs = compactValFor(xDec.intVal);
162.2641 + return xs == s;
162.2642 + } else if (xs != INFLATED)
162.2643 + return xs == compactValFor(this.intVal);
162.2644 +
162.2645 + return this.inflate().equals(xDec.inflate());
162.2646 + }
162.2647 +
162.2648 + /**
162.2649 + * Returns the minimum of this {@code BigDecimal} and
162.2650 + * {@code val}.
162.2651 + *
162.2652 + * @param val value with which the minimum is to be computed.
162.2653 + * @return the {@code BigDecimal} whose value is the lesser of this
162.2654 + * {@code BigDecimal} and {@code val}. If they are equal,
162.2655 + * as defined by the {@link #compareTo(BigDecimal) compareTo}
162.2656 + * method, {@code this} is returned.
162.2657 + * @see #compareTo(java.math.BigDecimal)
162.2658 + */
162.2659 + public BigDecimal min(BigDecimal val) {
162.2660 + return (compareTo(val) <= 0 ? this : val);
162.2661 + }
162.2662 +
162.2663 + /**
162.2664 + * Returns the maximum of this {@code BigDecimal} and {@code val}.
162.2665 + *
162.2666 + * @param val value with which the maximum is to be computed.
162.2667 + * @return the {@code BigDecimal} whose value is the greater of this
162.2668 + * {@code BigDecimal} and {@code val}. If they are equal,
162.2669 + * as defined by the {@link #compareTo(BigDecimal) compareTo}
162.2670 + * method, {@code this} is returned.
162.2671 + * @see #compareTo(java.math.BigDecimal)
162.2672 + */
162.2673 + public BigDecimal max(BigDecimal val) {
162.2674 + return (compareTo(val) >= 0 ? this : val);
162.2675 + }
162.2676 +
162.2677 + // Hash Function
162.2678 +
162.2679 + /**
162.2680 + * Returns the hash code for this {@code BigDecimal}. Note that
162.2681 + * two {@code BigDecimal} objects that are numerically equal but
162.2682 + * differ in scale (like 2.0 and 2.00) will generally <i>not</i>
162.2683 + * have the same hash code.
162.2684 + *
162.2685 + * @return hash code for this {@code BigDecimal}.
162.2686 + * @see #equals(Object)
162.2687 + */
162.2688 + @Override
162.2689 + public int hashCode() {
162.2690 + if (intCompact != INFLATED) {
162.2691 + long val2 = (intCompact < 0)? -intCompact : intCompact;
162.2692 + int temp = (int)( ((int)(val2 >>> 32)) * 31 +
162.2693 + (val2 & LONG_MASK));
162.2694 + return 31*((intCompact < 0) ?-temp:temp) + scale;
162.2695 + } else
162.2696 + return 31*intVal.hashCode() + scale;
162.2697 + }
162.2698 +
162.2699 + // Format Converters
162.2700 +
162.2701 + /**
162.2702 + * Returns the string representation of this {@code BigDecimal},
162.2703 + * using scientific notation if an exponent is needed.
162.2704 + *
162.2705 + * <p>A standard canonical string form of the {@code BigDecimal}
162.2706 + * is created as though by the following steps: first, the
162.2707 + * absolute value of the unscaled value of the {@code BigDecimal}
162.2708 + * is converted to a string in base ten using the characters
162.2709 + * {@code '0'} through {@code '9'} with no leading zeros (except
162.2710 + * if its value is zero, in which case a single {@code '0'}
162.2711 + * character is used).
162.2712 + *
162.2713 + * <p>Next, an <i>adjusted exponent</i> is calculated; this is the
162.2714 + * negated scale, plus the number of characters in the converted
162.2715 + * unscaled value, less one. That is,
162.2716 + * {@code -scale+(ulength-1)}, where {@code ulength} is the
162.2717 + * length of the absolute value of the unscaled value in decimal
162.2718 + * digits (its <i>precision</i>).
162.2719 + *
162.2720 + * <p>If the scale is greater than or equal to zero and the
162.2721 + * adjusted exponent is greater than or equal to {@code -6}, the
162.2722 + * number will be converted to a character form without using
162.2723 + * exponential notation. In this case, if the scale is zero then
162.2724 + * no decimal point is added and if the scale is positive a
162.2725 + * decimal point will be inserted with the scale specifying the
162.2726 + * number of characters to the right of the decimal point.
162.2727 + * {@code '0'} characters are added to the left of the converted
162.2728 + * unscaled value as necessary. If no character precedes the
162.2729 + * decimal point after this insertion then a conventional
162.2730 + * {@code '0'} character is prefixed.
162.2731 + *
162.2732 + * <p>Otherwise (that is, if the scale is negative, or the
162.2733 + * adjusted exponent is less than {@code -6}), the number will be
162.2734 + * converted to a character form using exponential notation. In
162.2735 + * this case, if the converted {@code BigInteger} has more than
162.2736 + * one digit a decimal point is inserted after the first digit.
162.2737 + * An exponent in character form is then suffixed to the converted
162.2738 + * unscaled value (perhaps with inserted decimal point); this
162.2739 + * comprises the letter {@code 'E'} followed immediately by the
162.2740 + * adjusted exponent converted to a character form. The latter is
162.2741 + * in base ten, using the characters {@code '0'} through
162.2742 + * {@code '9'} with no leading zeros, and is always prefixed by a
162.2743 + * sign character {@code '-'} (<tt>'\u002D'</tt>) if the
162.2744 + * adjusted exponent is negative, {@code '+'}
162.2745 + * (<tt>'\u002B'</tt>) otherwise).
162.2746 + *
162.2747 + * <p>Finally, the entire string is prefixed by a minus sign
162.2748 + * character {@code '-'} (<tt>'\u002D'</tt>) if the unscaled
162.2749 + * value is less than zero. No sign character is prefixed if the
162.2750 + * unscaled value is zero or positive.
162.2751 + *
162.2752 + * <p><b>Examples:</b>
162.2753 + * <p>For each representation [<i>unscaled value</i>, <i>scale</i>]
162.2754 + * on the left, the resulting string is shown on the right.
162.2755 + * <pre>
162.2756 + * [123,0] "123"
162.2757 + * [-123,0] "-123"
162.2758 + * [123,-1] "1.23E+3"
162.2759 + * [123,-3] "1.23E+5"
162.2760 + * [123,1] "12.3"
162.2761 + * [123,5] "0.00123"
162.2762 + * [123,10] "1.23E-8"
162.2763 + * [-123,12] "-1.23E-10"
162.2764 + * </pre>
162.2765 + *
162.2766 + * <b>Notes:</b>
162.2767 + * <ol>
162.2768 + *
162.2769 + * <li>There is a one-to-one mapping between the distinguishable
162.2770 + * {@code BigDecimal} values and the result of this conversion.
162.2771 + * That is, every distinguishable {@code BigDecimal} value
162.2772 + * (unscaled value and scale) has a unique string representation
162.2773 + * as a result of using {@code toString}. If that string
162.2774 + * representation is converted back to a {@code BigDecimal} using
162.2775 + * the {@link #BigDecimal(String)} constructor, then the original
162.2776 + * value will be recovered.
162.2777 + *
162.2778 + * <li>The string produced for a given number is always the same;
162.2779 + * it is not affected by locale. This means that it can be used
162.2780 + * as a canonical string representation for exchanging decimal
162.2781 + * data, or as a key for a Hashtable, etc. Locale-sensitive
162.2782 + * number formatting and parsing is handled by the {@link
162.2783 + * java.text.NumberFormat} class and its subclasses.
162.2784 + *
162.2785 + * <li>The {@link #toEngineeringString} method may be used for
162.2786 + * presenting numbers with exponents in engineering notation, and the
162.2787 + * {@link #setScale(int,RoundingMode) setScale} method may be used for
162.2788 + * rounding a {@code BigDecimal} so it has a known number of digits after
162.2789 + * the decimal point.
162.2790 + *
162.2791 + * <li>The digit-to-character mapping provided by
162.2792 + * {@code Character.forDigit} is used.
162.2793 + *
162.2794 + * </ol>
162.2795 + *
162.2796 + * @return string representation of this {@code BigDecimal}.
162.2797 + * @see Character#forDigit
162.2798 + * @see #BigDecimal(java.lang.String)
162.2799 + */
162.2800 + @Override
162.2801 + public String toString() {
162.2802 + String sc = stringCache;
162.2803 + if (sc == null)
162.2804 + stringCache = sc = layoutChars(true);
162.2805 + return sc;
162.2806 + }
162.2807 +
162.2808 + /**
162.2809 + * Returns a string representation of this {@code BigDecimal},
162.2810 + * using engineering notation if an exponent is needed.
162.2811 + *
162.2812 + * <p>Returns a string that represents the {@code BigDecimal} as
162.2813 + * described in the {@link #toString()} method, except that if
162.2814 + * exponential notation is used, the power of ten is adjusted to
162.2815 + * be a multiple of three (engineering notation) such that the
162.2816 + * integer part of nonzero values will be in the range 1 through
162.2817 + * 999. If exponential notation is used for zero values, a
162.2818 + * decimal point and one or two fractional zero digits are used so
162.2819 + * that the scale of the zero value is preserved. Note that
162.2820 + * unlike the output of {@link #toString()}, the output of this
162.2821 + * method is <em>not</em> guaranteed to recover the same [integer,
162.2822 + * scale] pair of this {@code BigDecimal} if the output string is
162.2823 + * converting back to a {@code BigDecimal} using the {@linkplain
162.2824 + * #BigDecimal(String) string constructor}. The result of this method meets
162.2825 + * the weaker constraint of always producing a numerically equal
162.2826 + * result from applying the string constructor to the method's output.
162.2827 + *
162.2828 + * @return string representation of this {@code BigDecimal}, using
162.2829 + * engineering notation if an exponent is needed.
162.2830 + * @since 1.5
162.2831 + */
162.2832 + public String toEngineeringString() {
162.2833 + return layoutChars(false);
162.2834 + }
162.2835 +
162.2836 + /**
162.2837 + * Returns a string representation of this {@code BigDecimal}
162.2838 + * without an exponent field. For values with a positive scale,
162.2839 + * the number of digits to the right of the decimal point is used
162.2840 + * to indicate scale. For values with a zero or negative scale,
162.2841 + * the resulting string is generated as if the value were
162.2842 + * converted to a numerically equal value with zero scale and as
162.2843 + * if all the trailing zeros of the zero scale value were present
162.2844 + * in the result.
162.2845 + *
162.2846 + * The entire string is prefixed by a minus sign character '-'
162.2847 + * (<tt>'\u002D'</tt>) if the unscaled value is less than
162.2848 + * zero. No sign character is prefixed if the unscaled value is
162.2849 + * zero or positive.
162.2850 + *
162.2851 + * Note that if the result of this method is passed to the
162.2852 + * {@linkplain #BigDecimal(String) string constructor}, only the
162.2853 + * numerical value of this {@code BigDecimal} will necessarily be
162.2854 + * recovered; the representation of the new {@code BigDecimal}
162.2855 + * may have a different scale. In particular, if this
162.2856 + * {@code BigDecimal} has a negative scale, the string resulting
162.2857 + * from this method will have a scale of zero when processed by
162.2858 + * the string constructor.
162.2859 + *
162.2860 + * (This method behaves analogously to the {@code toString}
162.2861 + * method in 1.4 and earlier releases.)
162.2862 + *
162.2863 + * @return a string representation of this {@code BigDecimal}
162.2864 + * without an exponent field.
162.2865 + * @since 1.5
162.2866 + * @see #toString()
162.2867 + * @see #toEngineeringString()
162.2868 + */
162.2869 + public String toPlainString() {
162.2870 + BigDecimal bd = this;
162.2871 + if (bd.scale < 0)
162.2872 + bd = bd.setScale(0);
162.2873 + bd.inflate();
162.2874 + if (bd.scale == 0) // No decimal point
162.2875 + return bd.intVal.toString();
162.2876 + return bd.getValueString(bd.signum(), bd.intVal.abs().toString(), bd.scale);
162.2877 + }
162.2878 +
162.2879 + /* Returns a digit.digit string */
162.2880 + private String getValueString(int signum, String intString, int scale) {
162.2881 + /* Insert decimal point */
162.2882 + StringBuilder buf;
162.2883 + int insertionPoint = intString.length() - scale;
162.2884 + if (insertionPoint == 0) { /* Point goes right before intVal */
162.2885 + return (signum<0 ? "-0." : "0.") + intString;
162.2886 + } else if (insertionPoint > 0) { /* Point goes inside intVal */
162.2887 + buf = new StringBuilder(intString);
162.2888 + buf.insert(insertionPoint, '.');
162.2889 + if (signum < 0)
162.2890 + buf.insert(0, '-');
162.2891 + } else { /* We must insert zeros between point and intVal */
162.2892 + buf = new StringBuilder(3-insertionPoint + intString.length());
162.2893 + buf.append(signum<0 ? "-0." : "0.");
162.2894 + for (int i=0; i<-insertionPoint; i++)
162.2895 + buf.append('0');
162.2896 + buf.append(intString);
162.2897 + }
162.2898 + return buf.toString();
162.2899 + }
162.2900 +
162.2901 + /**
162.2902 + * Converts this {@code BigDecimal} to a {@code BigInteger}.
162.2903 + * This conversion is analogous to the
162.2904 + * <i>narrowing primitive conversion</i> from {@code double} to
162.2905 + * {@code long} as defined in section 5.1.3 of
162.2906 + * <cite>The Java™ Language Specification</cite>:
162.2907 + * any fractional part of this
162.2908 + * {@code BigDecimal} will be discarded. Note that this
162.2909 + * conversion can lose information about the precision of the
162.2910 + * {@code BigDecimal} value.
162.2911 + * <p>
162.2912 + * To have an exception thrown if the conversion is inexact (in
162.2913 + * other words if a nonzero fractional part is discarded), use the
162.2914 + * {@link #toBigIntegerExact()} method.
162.2915 + *
162.2916 + * @return this {@code BigDecimal} converted to a {@code BigInteger}.
162.2917 + */
162.2918 + public BigInteger toBigInteger() {
162.2919 + // force to an integer, quietly
162.2920 + return this.setScale(0, ROUND_DOWN).inflate();
162.2921 + }
162.2922 +
162.2923 + /**
162.2924 + * Converts this {@code BigDecimal} to a {@code BigInteger},
162.2925 + * checking for lost information. An exception is thrown if this
162.2926 + * {@code BigDecimal} has a nonzero fractional part.
162.2927 + *
162.2928 + * @return this {@code BigDecimal} converted to a {@code BigInteger}.
162.2929 + * @throws ArithmeticException if {@code this} has a nonzero
162.2930 + * fractional part.
162.2931 + * @since 1.5
162.2932 + */
162.2933 + public BigInteger toBigIntegerExact() {
162.2934 + // round to an integer, with Exception if decimal part non-0
162.2935 + return this.setScale(0, ROUND_UNNECESSARY).inflate();
162.2936 + }
162.2937 +
162.2938 + /**
162.2939 + * Converts this {@code BigDecimal} to a {@code long}.
162.2940 + * This conversion is analogous to the
162.2941 + * <i>narrowing primitive conversion</i> from {@code double} to
162.2942 + * {@code short} as defined in section 5.1.3 of
162.2943 + * <cite>The Java™ Language Specification</cite>:
162.2944 + * any fractional part of this
162.2945 + * {@code BigDecimal} will be discarded, and if the resulting
162.2946 + * "{@code BigInteger}" is too big to fit in a
162.2947 + * {@code long}, only the low-order 64 bits are returned.
162.2948 + * Note that this conversion can lose information about the
162.2949 + * overall magnitude and precision of this {@code BigDecimal} value as well
162.2950 + * as return a result with the opposite sign.
162.2951 + *
162.2952 + * @return this {@code BigDecimal} converted to a {@code long}.
162.2953 + */
162.2954 + public long longValue(){
162.2955 + return (intCompact != INFLATED && scale == 0) ?
162.2956 + intCompact:
162.2957 + toBigInteger().longValue();
162.2958 + }
162.2959 +
162.2960 + /**
162.2961 + * Converts this {@code BigDecimal} to a {@code long}, checking
162.2962 + * for lost information. If this {@code BigDecimal} has a
162.2963 + * nonzero fractional part or is out of the possible range for a
162.2964 + * {@code long} result then an {@code ArithmeticException} is
162.2965 + * thrown.
162.2966 + *
162.2967 + * @return this {@code BigDecimal} converted to a {@code long}.
162.2968 + * @throws ArithmeticException if {@code this} has a nonzero
162.2969 + * fractional part, or will not fit in a {@code long}.
162.2970 + * @since 1.5
162.2971 + */
162.2972 + public long longValueExact() {
162.2973 + if (intCompact != INFLATED && scale == 0)
162.2974 + return intCompact;
162.2975 + // If more than 19 digits in integer part it cannot possibly fit
162.2976 + if ((precision() - scale) > 19) // [OK for negative scale too]
162.2977 + throw new java.lang.ArithmeticException("Overflow");
162.2978 + // Fastpath zero and < 1.0 numbers (the latter can be very slow
162.2979 + // to round if very small)
162.2980 + if (this.signum() == 0)
162.2981 + return 0;
162.2982 + if ((this.precision() - this.scale) <= 0)
162.2983 + throw new ArithmeticException("Rounding necessary");
162.2984 + // round to an integer, with Exception if decimal part non-0
162.2985 + BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
162.2986 + if (num.precision() >= 19) // need to check carefully
162.2987 + LongOverflow.check(num);
162.2988 + return num.inflate().longValue();
162.2989 + }
162.2990 +
162.2991 + private static class LongOverflow {
162.2992 + /** BigInteger equal to Long.MIN_VALUE. */
162.2993 + private static final BigInteger LONGMIN = BigInteger.valueOf(Long.MIN_VALUE);
162.2994 +
162.2995 + /** BigInteger equal to Long.MAX_VALUE. */
162.2996 + private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE);
162.2997 +
162.2998 + public static void check(BigDecimal num) {
162.2999 + num.inflate();
162.3000 + if ((num.intVal.compareTo(LONGMIN) < 0) ||
162.3001 + (num.intVal.compareTo(LONGMAX) > 0))
162.3002 + throw new java.lang.ArithmeticException("Overflow");
162.3003 + }
162.3004 + }
162.3005 +
162.3006 + /**
162.3007 + * Converts this {@code BigDecimal} to an {@code int}.
162.3008 + * This conversion is analogous to the
162.3009 + * <i>narrowing primitive conversion</i> from {@code double} to
162.3010 + * {@code short} as defined in section 5.1.3 of
162.3011 + * <cite>The Java™ Language Specification</cite>:
162.3012 + * any fractional part of this
162.3013 + * {@code BigDecimal} will be discarded, and if the resulting
162.3014 + * "{@code BigInteger}" is too big to fit in an
162.3015 + * {@code int}, only the low-order 32 bits are returned.
162.3016 + * Note that this conversion can lose information about the
162.3017 + * overall magnitude and precision of this {@code BigDecimal}
162.3018 + * value as well as return a result with the opposite sign.
162.3019 + *
162.3020 + * @return this {@code BigDecimal} converted to an {@code int}.
162.3021 + */
162.3022 + public int intValue() {
162.3023 + return (intCompact != INFLATED && scale == 0) ?
162.3024 + (int)intCompact :
162.3025 + toBigInteger().intValue();
162.3026 + }
162.3027 +
162.3028 + /**
162.3029 + * Converts this {@code BigDecimal} to an {@code int}, checking
162.3030 + * for lost information. If this {@code BigDecimal} has a
162.3031 + * nonzero fractional part or is out of the possible range for an
162.3032 + * {@code int} result then an {@code ArithmeticException} is
162.3033 + * thrown.
162.3034 + *
162.3035 + * @return this {@code BigDecimal} converted to an {@code int}.
162.3036 + * @throws ArithmeticException if {@code this} has a nonzero
162.3037 + * fractional part, or will not fit in an {@code int}.
162.3038 + * @since 1.5
162.3039 + */
162.3040 + public int intValueExact() {
162.3041 + long num;
162.3042 + num = this.longValueExact(); // will check decimal part
162.3043 + if ((int)num != num)
162.3044 + throw new java.lang.ArithmeticException("Overflow");
162.3045 + return (int)num;
162.3046 + }
162.3047 +
162.3048 + /**
162.3049 + * Converts this {@code BigDecimal} to a {@code short}, checking
162.3050 + * for lost information. If this {@code BigDecimal} has a
162.3051 + * nonzero fractional part or is out of the possible range for a
162.3052 + * {@code short} result then an {@code ArithmeticException} is
162.3053 + * thrown.
162.3054 + *
162.3055 + * @return this {@code BigDecimal} converted to a {@code short}.
162.3056 + * @throws ArithmeticException if {@code this} has a nonzero
162.3057 + * fractional part, or will not fit in a {@code short}.
162.3058 + * @since 1.5
162.3059 + */
162.3060 + public short shortValueExact() {
162.3061 + long num;
162.3062 + num = this.longValueExact(); // will check decimal part
162.3063 + if ((short)num != num)
162.3064 + throw new java.lang.ArithmeticException("Overflow");
162.3065 + return (short)num;
162.3066 + }
162.3067 +
162.3068 + /**
162.3069 + * Converts this {@code BigDecimal} to a {@code byte}, checking
162.3070 + * for lost information. If this {@code BigDecimal} has a
162.3071 + * nonzero fractional part or is out of the possible range for a
162.3072 + * {@code byte} result then an {@code ArithmeticException} is
162.3073 + * thrown.
162.3074 + *
162.3075 + * @return this {@code BigDecimal} converted to a {@code byte}.
162.3076 + * @throws ArithmeticException if {@code this} has a nonzero
162.3077 + * fractional part, or will not fit in a {@code byte}.
162.3078 + * @since 1.5
162.3079 + */
162.3080 + public byte byteValueExact() {
162.3081 + long num;
162.3082 + num = this.longValueExact(); // will check decimal part
162.3083 + if ((byte)num != num)
162.3084 + throw new java.lang.ArithmeticException("Overflow");
162.3085 + return (byte)num;
162.3086 + }
162.3087 +
162.3088 + /**
162.3089 + * Converts this {@code BigDecimal} to a {@code float}.
162.3090 + * This conversion is similar to the
162.3091 + * <i>narrowing primitive conversion</i> from {@code double} to
162.3092 + * {@code float} as defined in section 5.1.3 of
162.3093 + * <cite>The Java™ Language Specification</cite>:
162.3094 + * if this {@code BigDecimal} has too great a
162.3095 + * magnitude to represent as a {@code float}, it will be
162.3096 + * converted to {@link Float#NEGATIVE_INFINITY} or {@link
162.3097 + * Float#POSITIVE_INFINITY} as appropriate. Note that even when
162.3098 + * the return value is finite, this conversion can lose
162.3099 + * information about the precision of the {@code BigDecimal}
162.3100 + * value.
162.3101 + *
162.3102 + * @return this {@code BigDecimal} converted to a {@code float}.
162.3103 + */
162.3104 + public float floatValue(){
162.3105 + if (scale == 0 && intCompact != INFLATED)
162.3106 + return (float)intCompact;
162.3107 + // Somewhat inefficient, but guaranteed to work.
162.3108 + return Float.parseFloat(this.toString());
162.3109 + }
162.3110 +
162.3111 + /**
162.3112 + * Converts this {@code BigDecimal} to a {@code double}.
162.3113 + * This conversion is similar to the
162.3114 + * <i>narrowing primitive conversion</i> from {@code double} to
162.3115 + * {@code float} as defined in section 5.1.3 of
162.3116 + * <cite>The Java™ Language Specification</cite>:
162.3117 + * if this {@code BigDecimal} has too great a
162.3118 + * magnitude represent as a {@code double}, it will be
162.3119 + * converted to {@link Double#NEGATIVE_INFINITY} or {@link
162.3120 + * Double#POSITIVE_INFINITY} as appropriate. Note that even when
162.3121 + * the return value is finite, this conversion can lose
162.3122 + * information about the precision of the {@code BigDecimal}
162.3123 + * value.
162.3124 + *
162.3125 + * @return this {@code BigDecimal} converted to a {@code double}.
162.3126 + */
162.3127 + public double doubleValue(){
162.3128 + if (scale == 0 && intCompact != INFLATED)
162.3129 + return (double)intCompact;
162.3130 + // Somewhat inefficient, but guaranteed to work.
162.3131 + return Double.parseDouble(this.toString());
162.3132 + }
162.3133 +
162.3134 + /**
162.3135 + * Returns the size of an ulp, a unit in the last place, of this
162.3136 + * {@code BigDecimal}. An ulp of a nonzero {@code BigDecimal}
162.3137 + * value is the positive distance between this value and the
162.3138 + * {@code BigDecimal} value next larger in magnitude with the
162.3139 + * same number of digits. An ulp of a zero value is numerically
162.3140 + * equal to 1 with the scale of {@code this}. The result is
162.3141 + * stored with the same scale as {@code this} so the result
162.3142 + * for zero and nonzero values is equal to {@code [1,
162.3143 + * this.scale()]}.
162.3144 + *
162.3145 + * @return the size of an ulp of {@code this}
162.3146 + * @since 1.5
162.3147 + */
162.3148 + public BigDecimal ulp() {
162.3149 + return BigDecimal.valueOf(1, this.scale());
162.3150 + }
162.3151 +
162.3152 +
162.3153 + // Private class to build a string representation for BigDecimal object.
162.3154 + // "StringBuilderHelper" is constructed as a thread local variable so it is
162.3155 + // thread safe. The StringBuilder field acts as a buffer to hold the temporary
162.3156 + // representation of BigDecimal. The cmpCharArray holds all the characters for
162.3157 + // the compact representation of BigDecimal (except for '-' sign' if it is
162.3158 + // negative) if its intCompact field is not INFLATED. It is shared by all
162.3159 + // calls to toString() and its variants in that particular thread.
162.3160 + static class StringBuilderHelper {
162.3161 + private static StringBuilderHelper INSTANCE = new StringBuilderHelper();
162.3162 + final StringBuilder sb; // Placeholder for BigDecimal string
162.3163 + final char[] cmpCharArray; // character array to place the intCompact
162.3164 +
162.3165 + StringBuilderHelper() {
162.3166 + sb = new StringBuilder();
162.3167 + // All non negative longs can be made to fit into 19 character array.
162.3168 + cmpCharArray = new char[19];
162.3169 + }
162.3170 +
162.3171 + // Accessors.
162.3172 + StringBuilder getStringBuilder() {
162.3173 + sb.setLength(0);
162.3174 + return sb;
162.3175 + }
162.3176 +
162.3177 + char[] getCompactCharArray() {
162.3178 + return cmpCharArray;
162.3179 + }
162.3180 +
162.3181 + /**
162.3182 + * Places characters representing the intCompact in {@code long} into
162.3183 + * cmpCharArray and returns the offset to the array where the
162.3184 + * representation starts.
162.3185 + *
162.3186 + * @param intCompact the number to put into the cmpCharArray.
162.3187 + * @return offset to the array where the representation starts.
162.3188 + * Note: intCompact must be greater or equal to zero.
162.3189 + */
162.3190 + int putIntCompact(long intCompact) {
162.3191 + assert intCompact >= 0;
162.3192 +
162.3193 + long q;
162.3194 + int r;
162.3195 + // since we start from the least significant digit, charPos points to
162.3196 + // the last character in cmpCharArray.
162.3197 + int charPos = cmpCharArray.length;
162.3198 +
162.3199 + // Get 2 digits/iteration using longs until quotient fits into an int
162.3200 + while (intCompact > Integer.MAX_VALUE) {
162.3201 + q = intCompact / 100;
162.3202 + r = (int)(intCompact - q * 100);
162.3203 + intCompact = q;
162.3204 + cmpCharArray[--charPos] = DIGIT_ONES[r];
162.3205 + cmpCharArray[--charPos] = DIGIT_TENS[r];
162.3206 + }
162.3207 +
162.3208 + // Get 2 digits/iteration using ints when i2 >= 100
162.3209 + int q2;
162.3210 + int i2 = (int)intCompact;
162.3211 + while (i2 >= 100) {
162.3212 + q2 = i2 / 100;
162.3213 + r = i2 - q2 * 100;
162.3214 + i2 = q2;
162.3215 + cmpCharArray[--charPos] = DIGIT_ONES[r];
162.3216 + cmpCharArray[--charPos] = DIGIT_TENS[r];
162.3217 + }
162.3218 +
162.3219 + cmpCharArray[--charPos] = DIGIT_ONES[i2];
162.3220 + if (i2 >= 10)
162.3221 + cmpCharArray[--charPos] = DIGIT_TENS[i2];
162.3222 +
162.3223 + return charPos;
162.3224 + }
162.3225 +
162.3226 + final static char[] DIGIT_TENS = {
162.3227 + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
162.3228 + '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
162.3229 + '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
162.3230 + '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
162.3231 + '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
162.3232 + '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
162.3233 + '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
162.3234 + '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
162.3235 + '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
162.3236 + '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
162.3237 + };
162.3238 +
162.3239 + final static char[] DIGIT_ONES = {
162.3240 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3241 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3242 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3243 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3244 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3245 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3246 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3247 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3248 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3249 + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
162.3250 + };
162.3251 + }
162.3252 +
162.3253 + /**
162.3254 + * Lay out this {@code BigDecimal} into a {@code char[]} array.
162.3255 + * The Java 1.2 equivalent to this was called {@code getValueString}.
162.3256 + *
162.3257 + * @param sci {@code true} for Scientific exponential notation;
162.3258 + * {@code false} for Engineering
162.3259 + * @return string with canonical string representation of this
162.3260 + * {@code BigDecimal}
162.3261 + */
162.3262 + private String layoutChars(boolean sci) {
162.3263 + if (scale == 0) // zero scale is trivial
162.3264 + return (intCompact != INFLATED) ?
162.3265 + Long.toString(intCompact):
162.3266 + intVal.toString();
162.3267 +
162.3268 + StringBuilderHelper sbHelper = StringBuilderHelper.INSTANCE;
162.3269 + char[] coeff;
162.3270 + int offset; // offset is the starting index for coeff array
162.3271 + // Get the significand as an absolute value
162.3272 + if (intCompact != INFLATED) {
162.3273 + offset = sbHelper.putIntCompact(Math.abs(intCompact));
162.3274 + coeff = sbHelper.getCompactCharArray();
162.3275 + } else {
162.3276 + offset = 0;
162.3277 + coeff = intVal.abs().toString().toCharArray();
162.3278 + }
162.3279 +
162.3280 + // Construct a buffer, with sufficient capacity for all cases.
162.3281 + // If E-notation is needed, length will be: +1 if negative, +1
162.3282 + // if '.' needed, +2 for "E+", + up to 10 for adjusted exponent.
162.3283 + // Otherwise it could have +1 if negative, plus leading "0.00000"
162.3284 + StringBuilder buf = sbHelper.getStringBuilder();
162.3285 + if (signum() < 0) // prefix '-' if negative
162.3286 + buf.append('-');
162.3287 + int coeffLen = coeff.length - offset;
162.3288 + long adjusted = -(long)scale + (coeffLen -1);
162.3289 + if ((scale >= 0) && (adjusted >= -6)) { // plain number
162.3290 + int pad = scale - coeffLen; // count of padding zeros
162.3291 + if (pad >= 0) { // 0.xxx form
162.3292 + buf.append('0');
162.3293 + buf.append('.');
162.3294 + for (; pad>0; pad--) {
162.3295 + buf.append('0');
162.3296 + }
162.3297 + buf.append(coeff, offset, coeffLen);
162.3298 + } else { // xx.xx form
162.3299 + buf.append(coeff, offset, -pad);
162.3300 + buf.append('.');
162.3301 + buf.append(coeff, -pad + offset, scale);
162.3302 + }
162.3303 + } else { // E-notation is needed
162.3304 + if (sci) { // Scientific notation
162.3305 + buf.append(coeff[offset]); // first character
162.3306 + if (coeffLen > 1) { // more to come
162.3307 + buf.append('.');
162.3308 + buf.append(coeff, offset + 1, coeffLen - 1);
162.3309 + }
162.3310 + } else { // Engineering notation
162.3311 + int sig = (int)(adjusted % 3);
162.3312 + if (sig < 0)
162.3313 + sig += 3; // [adjusted was negative]
162.3314 + adjusted -= sig; // now a multiple of 3
162.3315 + sig++;
162.3316 + if (signum() == 0) {
162.3317 + switch (sig) {
162.3318 + case 1:
162.3319 + buf.append('0'); // exponent is a multiple of three
162.3320 + break;
162.3321 + case 2:
162.3322 + buf.append("0.00");
162.3323 + adjusted += 3;
162.3324 + break;
162.3325 + case 3:
162.3326 + buf.append("0.0");
162.3327 + adjusted += 3;
162.3328 + break;
162.3329 + default:
162.3330 + throw new AssertionError("Unexpected sig value " + sig);
162.3331 + }
162.3332 + } else if (sig >= coeffLen) { // significand all in integer
162.3333 + buf.append(coeff, offset, coeffLen);
162.3334 + // may need some zeros, too
162.3335 + for (int i = sig - coeffLen; i > 0; i--)
162.3336 + buf.append('0');
162.3337 + } else { // xx.xxE form
162.3338 + buf.append(coeff, offset, sig);
162.3339 + buf.append('.');
162.3340 + buf.append(coeff, offset + sig, coeffLen - sig);
162.3341 + }
162.3342 + }
162.3343 + if (adjusted != 0) { // [!sci could have made 0]
162.3344 + buf.append('E');
162.3345 + if (adjusted > 0) // force sign for positive
162.3346 + buf.append('+');
162.3347 + buf.append(adjusted);
162.3348 + }
162.3349 + }
162.3350 + return buf.toString();
162.3351 + }
162.3352 +
162.3353 + /**
162.3354 + * Return 10 to the power n, as a {@code BigInteger}.
162.3355 + *
162.3356 + * @param n the power of ten to be returned (>=0)
162.3357 + * @return a {@code BigInteger} with the value (10<sup>n</sup>)
162.3358 + */
162.3359 + private static BigInteger bigTenToThe(int n) {
162.3360 + if (n < 0)
162.3361 + return BigInteger.ZERO;
162.3362 +
162.3363 + if (n < BIG_TEN_POWERS_TABLE_MAX) {
162.3364 + BigInteger[] pows = BIG_TEN_POWERS_TABLE;
162.3365 + if (n < pows.length)
162.3366 + return pows[n];
162.3367 + else
162.3368 + return expandBigIntegerTenPowers(n);
162.3369 + }
162.3370 + // BigInteger.pow is slow, so make 10**n by constructing a
162.3371 + // BigInteger from a character string (still not very fast)
162.3372 + char tenpow[] = new char[n + 1];
162.3373 + tenpow[0] = '1';
162.3374 + for (int i = 1; i <= n; i++)
162.3375 + tenpow[i] = '0';
162.3376 + return new BigInteger(tenpow);
162.3377 + }
162.3378 +
162.3379 + /**
162.3380 + * Expand the BIG_TEN_POWERS_TABLE array to contain at least 10**n.
162.3381 + *
162.3382 + * @param n the power of ten to be returned (>=0)
162.3383 + * @return a {@code BigDecimal} with the value (10<sup>n</sup>) and
162.3384 + * in the meantime, the BIG_TEN_POWERS_TABLE array gets
162.3385 + * expanded to the size greater than n.
162.3386 + */
162.3387 + private static BigInteger expandBigIntegerTenPowers(int n) {
162.3388 + synchronized(BigDecimal.class) {
162.3389 + BigInteger[] pows = BIG_TEN_POWERS_TABLE;
162.3390 + int curLen = pows.length;
162.3391 + // The following comparison and the above synchronized statement is
162.3392 + // to prevent multiple threads from expanding the same array.
162.3393 + if (curLen <= n) {
162.3394 + int newLen = curLen << 1;
162.3395 + while (newLen <= n)
162.3396 + newLen <<= 1;
162.3397 + pows = Arrays.copyOf(pows, newLen);
162.3398 + for (int i = curLen; i < newLen; i++)
162.3399 + pows[i] = pows[i - 1].multiply(BigInteger.TEN);
162.3400 + // Based on the following facts:
162.3401 + // 1. pows is a private local varible;
162.3402 + // 2. the following store is a volatile store.
162.3403 + // the newly created array elements can be safely published.
162.3404 + BIG_TEN_POWERS_TABLE = pows;
162.3405 + }
162.3406 + return pows[n];
162.3407 + }
162.3408 + }
162.3409 +
162.3410 + private static final long[] LONG_TEN_POWERS_TABLE = {
162.3411 + 1, // 0 / 10^0
162.3412 + 10, // 1 / 10^1
162.3413 + 100, // 2 / 10^2
162.3414 + 1000, // 3 / 10^3
162.3415 + 10000, // 4 / 10^4
162.3416 + 100000, // 5 / 10^5
162.3417 + 1000000, // 6 / 10^6
162.3418 + 10000000, // 7 / 10^7
162.3419 + 100000000, // 8 / 10^8
162.3420 + 1000000000, // 9 / 10^9
162.3421 + 10000000000L, // 10 / 10^10
162.3422 + 100000000000L, // 11 / 10^11
162.3423 + 1000000000000L, // 12 / 10^12
162.3424 + 10000000000000L, // 13 / 10^13
162.3425 + 100000000000000L, // 14 / 10^14
162.3426 + 1000000000000000L, // 15 / 10^15
162.3427 + 10000000000000000L, // 16 / 10^16
162.3428 + 100000000000000000L, // 17 / 10^17
162.3429 + 1000000000000000000L // 18 / 10^18
162.3430 + };
162.3431 +
162.3432 + private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {BigInteger.ONE,
162.3433 + BigInteger.valueOf(10), BigInteger.valueOf(100),
162.3434 + BigInteger.valueOf(1000), BigInteger.valueOf(10000),
162.3435 + BigInteger.valueOf(100000), BigInteger.valueOf(1000000),
162.3436 + BigInteger.valueOf(10000000), BigInteger.valueOf(100000000),
162.3437 + BigInteger.valueOf(1000000000),
162.3438 + BigInteger.valueOf(10000000000L),
162.3439 + BigInteger.valueOf(100000000000L),
162.3440 + BigInteger.valueOf(1000000000000L),
162.3441 + BigInteger.valueOf(10000000000000L),
162.3442 + BigInteger.valueOf(100000000000000L),
162.3443 + BigInteger.valueOf(1000000000000000L),
162.3444 + BigInteger.valueOf(10000000000000000L),
162.3445 + BigInteger.valueOf(100000000000000000L),
162.3446 + BigInteger.valueOf(1000000000000000000L)
162.3447 + };
162.3448 +
162.3449 + private static final int BIG_TEN_POWERS_TABLE_INITLEN =
162.3450 + BIG_TEN_POWERS_TABLE.length;
162.3451 + private static final int BIG_TEN_POWERS_TABLE_MAX =
162.3452 + 16 * BIG_TEN_POWERS_TABLE_INITLEN;
162.3453 +
162.3454 + private static final long THRESHOLDS_TABLE[] = {
162.3455 + Long.MAX_VALUE, // 0
162.3456 + Long.MAX_VALUE/10L, // 1
162.3457 + Long.MAX_VALUE/100L, // 2
162.3458 + Long.MAX_VALUE/1000L, // 3
162.3459 + Long.MAX_VALUE/10000L, // 4
162.3460 + Long.MAX_VALUE/100000L, // 5
162.3461 + Long.MAX_VALUE/1000000L, // 6
162.3462 + Long.MAX_VALUE/10000000L, // 7
162.3463 + Long.MAX_VALUE/100000000L, // 8
162.3464 + Long.MAX_VALUE/1000000000L, // 9
162.3465 + Long.MAX_VALUE/10000000000L, // 10
162.3466 + Long.MAX_VALUE/100000000000L, // 11
162.3467 + Long.MAX_VALUE/1000000000000L, // 12
162.3468 + Long.MAX_VALUE/10000000000000L, // 13
162.3469 + Long.MAX_VALUE/100000000000000L, // 14
162.3470 + Long.MAX_VALUE/1000000000000000L, // 15
162.3471 + Long.MAX_VALUE/10000000000000000L, // 16
162.3472 + Long.MAX_VALUE/100000000000000000L, // 17
162.3473 + Long.MAX_VALUE/1000000000000000000L // 18
162.3474 + };
162.3475 +
162.3476 + /**
162.3477 + * Compute val * 10 ^ n; return this product if it is
162.3478 + * representable as a long, INFLATED otherwise.
162.3479 + */
162.3480 + private static long longMultiplyPowerTen(long val, int n) {
162.3481 + if (val == 0 || n <= 0)
162.3482 + return val;
162.3483 + long[] tab = LONG_TEN_POWERS_TABLE;
162.3484 + long[] bounds = THRESHOLDS_TABLE;
162.3485 + if (n < tab.length && n < bounds.length) {
162.3486 + long tenpower = tab[n];
162.3487 + if (val == 1)
162.3488 + return tenpower;
162.3489 + if (Math.abs(val) <= bounds[n])
162.3490 + return val * tenpower;
162.3491 + }
162.3492 + return INFLATED;
162.3493 + }
162.3494 +
162.3495 + /**
162.3496 + * Compute this * 10 ^ n.
162.3497 + * Needed mainly to allow special casing to trap zero value
162.3498 + */
162.3499 + private BigInteger bigMultiplyPowerTen(int n) {
162.3500 + if (n <= 0)
162.3501 + return this.inflate();
162.3502 +
162.3503 + if (intCompact != INFLATED)
162.3504 + return bigTenToThe(n).multiply(intCompact);
162.3505 + else
162.3506 + return intVal.multiply(bigTenToThe(n));
162.3507 + }
162.3508 +
162.3509 + /**
162.3510 + * Assign appropriate BigInteger to intVal field if intVal is
162.3511 + * null, i.e. the compact representation is in use.
162.3512 + */
162.3513 + private BigInteger inflate() {
162.3514 + if (intVal == null)
162.3515 + intVal = BigInteger.valueOf(intCompact);
162.3516 + return intVal;
162.3517 + }
162.3518 +
162.3519 + /**
162.3520 + * Match the scales of two {@code BigDecimal}s to align their
162.3521 + * least significant digits.
162.3522 + *
162.3523 + * <p>If the scales of val[0] and val[1] differ, rescale
162.3524 + * (non-destructively) the lower-scaled {@code BigDecimal} so
162.3525 + * they match. That is, the lower-scaled reference will be
162.3526 + * replaced by a reference to a new object with the same scale as
162.3527 + * the other {@code BigDecimal}.
162.3528 + *
162.3529 + * @param val array of two elements referring to the two
162.3530 + * {@code BigDecimal}s to be aligned.
162.3531 + */
162.3532 + private static void matchScale(BigDecimal[] val) {
162.3533 + if (val[0].scale == val[1].scale) {
162.3534 + return;
162.3535 + } else if (val[0].scale < val[1].scale) {
162.3536 + val[0] = val[0].setScale(val[1].scale, ROUND_UNNECESSARY);
162.3537 + } else if (val[1].scale < val[0].scale) {
162.3538 + val[1] = val[1].setScale(val[0].scale, ROUND_UNNECESSARY);
162.3539 + }
162.3540 + }
162.3541 +
162.3542 + /**
162.3543 + * Reconstitute the {@code BigDecimal} instance from a stream (that is,
162.3544 + * deserialize it).
162.3545 + *
162.3546 + * @param s the stream being read.
162.3547 + */
162.3548 + private void readObject(java.io.ObjectInputStream s)
162.3549 + throws java.io.IOException, ClassNotFoundException {
162.3550 + // Read in all fields
162.3551 + s.defaultReadObject();
162.3552 + // validate possibly bad fields
162.3553 + if (intVal == null) {
162.3554 + String message = "BigDecimal: null intVal in stream";
162.3555 + throw new java.io.StreamCorruptedException(message);
162.3556 + // [all values of scale are now allowed]
162.3557 + }
162.3558 + intCompact = compactValFor(intVal);
162.3559 + }
162.3560 +
162.3561 + /**
162.3562 + * Serialize this {@code BigDecimal} to the stream in question
162.3563 + *
162.3564 + * @param s the stream to serialize to.
162.3565 + */
162.3566 + private void writeObject(java.io.ObjectOutputStream s)
162.3567 + throws java.io.IOException {
162.3568 + // Must inflate to maintain compatible serial form.
162.3569 + this.inflate();
162.3570 +
162.3571 + // Write proper fields
162.3572 + s.defaultWriteObject();
162.3573 + }
162.3574 +
162.3575 +
162.3576 + /**
162.3577 + * Returns the length of the absolute value of a {@code long}, in decimal
162.3578 + * digits.
162.3579 + *
162.3580 + * @param x the {@code long}
162.3581 + * @return the length of the unscaled value, in deciaml digits.
162.3582 + */
162.3583 + private static int longDigitLength(long x) {
162.3584 + /*
162.3585 + * As described in "Bit Twiddling Hacks" by Sean Anderson,
162.3586 + * (http://graphics.stanford.edu/~seander/bithacks.html)
162.3587 + * integer log 10 of x is within 1 of
162.3588 + * (1233/4096)* (1 + integer log 2 of x).
162.3589 + * The fraction 1233/4096 approximates log10(2). So we first
162.3590 + * do a version of log2 (a variant of Long class with
162.3591 + * pre-checks and opposite directionality) and then scale and
162.3592 + * check against powers table. This is a little simpler in
162.3593 + * present context than the version in Hacker's Delight sec
162.3594 + * 11-4. Adding one to bit length allows comparing downward
162.3595 + * from the LONG_TEN_POWERS_TABLE that we need anyway.
162.3596 + */
162.3597 + assert x != INFLATED;
162.3598 + if (x < 0)
162.3599 + x = -x;
162.3600 + if (x < 10) // must screen for 0, might as well 10
162.3601 + return 1;
162.3602 + int n = 64; // not 63, to avoid needing to add 1 later
162.3603 + int y = (int)(x >>> 32);
162.3604 + if (y == 0) { n -= 32; y = (int)x; }
162.3605 + if (y >>> 16 == 0) { n -= 16; y <<= 16; }
162.3606 + if (y >>> 24 == 0) { n -= 8; y <<= 8; }
162.3607 + if (y >>> 28 == 0) { n -= 4; y <<= 4; }
162.3608 + if (y >>> 30 == 0) { n -= 2; y <<= 2; }
162.3609 + int r = (((y >>> 31) + n) * 1233) >>> 12;
162.3610 + long[] tab = LONG_TEN_POWERS_TABLE;
162.3611 + // if r >= length, must have max possible digits for long
162.3612 + return (r >= tab.length || x < tab[r])? r : r+1;
162.3613 + }
162.3614 +
162.3615 + /**
162.3616 + * Returns the length of the absolute value of a BigInteger, in
162.3617 + * decimal digits.
162.3618 + *
162.3619 + * @param b the BigInteger
162.3620 + * @return the length of the unscaled value, in decimal digits
162.3621 + */
162.3622 + private static int bigDigitLength(BigInteger b) {
162.3623 + /*
162.3624 + * Same idea as the long version, but we need a better
162.3625 + * approximation of log10(2). Using 646456993/2^31
162.3626 + * is accurate up to max possible reported bitLength.
162.3627 + */
162.3628 + if (b.signum == 0)
162.3629 + return 1;
162.3630 + int r = (int)((((long)b.bitLength() + 1) * 646456993) >>> 31);
162.3631 + return b.compareMagnitude(bigTenToThe(r)) < 0? r : r+1;
162.3632 + }
162.3633 +
162.3634 +
162.3635 + /**
162.3636 + * Remove insignificant trailing zeros from this
162.3637 + * {@code BigDecimal} until the preferred scale is reached or no
162.3638 + * more zeros can be removed. If the preferred scale is less than
162.3639 + * Integer.MIN_VALUE, all the trailing zeros will be removed.
162.3640 + *
162.3641 + * {@code BigInteger} assistance could help, here?
162.3642 + *
162.3643 + * <p>WARNING: This method should only be called on new objects as
162.3644 + * it mutates the value fields.
162.3645 + *
162.3646 + * @return this {@code BigDecimal} with a scale possibly reduced
162.3647 + * to be closed to the preferred scale.
162.3648 + */
162.3649 + private BigDecimal stripZerosToMatchScale(long preferredScale) {
162.3650 + this.inflate();
162.3651 + BigInteger qr[]; // quotient-remainder pair
162.3652 + while ( intVal.compareMagnitude(BigInteger.TEN) >= 0 &&
162.3653 + scale > preferredScale) {
162.3654 + if (intVal.testBit(0))
162.3655 + break; // odd number cannot end in 0
162.3656 + qr = intVal.divideAndRemainder(BigInteger.TEN);
162.3657 + if (qr[1].signum() != 0)
162.3658 + break; // non-0 remainder
162.3659 + intVal=qr[0];
162.3660 + scale = checkScale((long)scale-1); // could Overflow
162.3661 + if (precision > 0) // adjust precision if known
162.3662 + precision--;
162.3663 + }
162.3664 + if (intVal != null)
162.3665 + intCompact = compactValFor(intVal);
162.3666 + return this;
162.3667 + }
162.3668 +
162.3669 + /**
162.3670 + * Check a scale for Underflow or Overflow. If this BigDecimal is
162.3671 + * nonzero, throw an exception if the scale is outof range. If this
162.3672 + * is zero, saturate the scale to the extreme value of the right
162.3673 + * sign if the scale is out of range.
162.3674 + *
162.3675 + * @param val The new scale.
162.3676 + * @throws ArithmeticException (overflow or underflow) if the new
162.3677 + * scale is out of range.
162.3678 + * @return validated scale as an int.
162.3679 + */
162.3680 + private int checkScale(long val) {
162.3681 + int asInt = (int)val;
162.3682 + if (asInt != val) {
162.3683 + asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
162.3684 + BigInteger b;
162.3685 + if (intCompact != 0 &&
162.3686 + ((b = intVal) == null || b.signum() != 0))
162.3687 + throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
162.3688 + }
162.3689 + return asInt;
162.3690 + }
162.3691 +
162.3692 + /**
162.3693 + * Round an operand; used only if digits > 0. Does not change
162.3694 + * {@code this}; if rounding is needed a new {@code BigDecimal}
162.3695 + * is created and returned.
162.3696 + *
162.3697 + * @param mc the context to use.
162.3698 + * @throws ArithmeticException if the result is inexact but the
162.3699 + * rounding mode is {@code UNNECESSARY}.
162.3700 + */
162.3701 + private BigDecimal roundOp(MathContext mc) {
162.3702 + BigDecimal rounded = doRound(this, mc);
162.3703 + return rounded;
162.3704 + }
162.3705 +
162.3706 + /** Round this BigDecimal according to the MathContext settings;
162.3707 + * used only if precision {@literal >} 0.
162.3708 + *
162.3709 + * <p>WARNING: This method should only be called on new objects as
162.3710 + * it mutates the value fields.
162.3711 + *
162.3712 + * @param mc the context to use.
162.3713 + * @throws ArithmeticException if the rounding mode is
162.3714 + * {@code RoundingMode.UNNECESSARY} and the
162.3715 + * {@code BigDecimal} operation would require rounding.
162.3716 + */
162.3717 + private void roundThis(MathContext mc) {
162.3718 + BigDecimal rounded = doRound(this, mc);
162.3719 + if (rounded == this) // wasn't rounded
162.3720 + return;
162.3721 + this.intVal = rounded.intVal;
162.3722 + this.intCompact = rounded.intCompact;
162.3723 + this.scale = rounded.scale;
162.3724 + this.precision = rounded.precision;
162.3725 + }
162.3726 +
162.3727 + /**
162.3728 + * Returns a {@code BigDecimal} rounded according to the
162.3729 + * MathContext settings; used only if {@code mc.precision > 0}.
162.3730 + * Does not change {@code this}; if rounding is needed a new
162.3731 + * {@code BigDecimal} is created and returned.
162.3732 + *
162.3733 + * @param mc the context to use.
162.3734 + * @return a {@code BigDecimal} rounded according to the MathContext
162.3735 + * settings. May return this, if no rounding needed.
162.3736 + * @throws ArithmeticException if the rounding mode is
162.3737 + * {@code RoundingMode.UNNECESSARY} and the
162.3738 + * result is inexact.
162.3739 + */
162.3740 + private static BigDecimal doRound(BigDecimal d, MathContext mc) {
162.3741 + int mcp = mc.precision;
162.3742 + int drop;
162.3743 + // This might (rarely) iterate to cover the 999=>1000 case
162.3744 + while ((drop = d.precision() - mcp) > 0) {
162.3745 + int newScale = d.checkScale((long)d.scale - drop);
162.3746 + int mode = mc.roundingMode.oldMode;
162.3747 + if (drop < LONG_TEN_POWERS_TABLE.length)
162.3748 + d = divideAndRound(d.intCompact, d.intVal,
162.3749 + LONG_TEN_POWERS_TABLE[drop], null,
162.3750 + newScale, mode, newScale);
162.3751 + else
162.3752 + d = divideAndRound(d.intCompact, d.intVal,
162.3753 + INFLATED, bigTenToThe(drop),
162.3754 + newScale, mode, newScale);
162.3755 + }
162.3756 + return d;
162.3757 + }
162.3758 +
162.3759 + /**
162.3760 + * Returns the compact value for given {@code BigInteger}, or
162.3761 + * INFLATED if too big. Relies on internal representation of
162.3762 + * {@code BigInteger}.
162.3763 + */
162.3764 + private static long compactValFor(BigInteger b) {
162.3765 + int[] m = b.mag;
162.3766 + int len = m.length;
162.3767 + if (len == 0)
162.3768 + return 0;
162.3769 + int d = m[0];
162.3770 + if (len > 2 || (len == 2 && d < 0))
162.3771 + return INFLATED;
162.3772 +
162.3773 + long u = (len == 2)?
162.3774 + (((long) m[1] & LONG_MASK) + (((long)d) << 32)) :
162.3775 + (((long)d) & LONG_MASK);
162.3776 + return (b.signum < 0)? -u : u;
162.3777 + }
162.3778 +
162.3779 + private static int longCompareMagnitude(long x, long y) {
162.3780 + if (x < 0)
162.3781 + x = -x;
162.3782 + if (y < 0)
162.3783 + y = -y;
162.3784 + return (x < y) ? -1 : ((x == y) ? 0 : 1);
162.3785 + }
162.3786 +
162.3787 + private static int saturateLong(long s) {
162.3788 + int i = (int)s;
162.3789 + return (s == i) ? i : (s < 0 ? Integer.MIN_VALUE : Integer.MAX_VALUE);
162.3790 + }
162.3791 +
162.3792 + /*
162.3793 + * Internal printing routine
162.3794 + */
162.3795 + private static void print(String name, BigDecimal bd) {
162.3796 + }
162.3797 +
162.3798 + /**
162.3799 + * Check internal invariants of this BigDecimal. These invariants
162.3800 + * include:
162.3801 + *
162.3802 + * <ul>
162.3803 + *
162.3804 + * <li>The object must be initialized; either intCompact must not be
162.3805 + * INFLATED or intVal is non-null. Both of these conditions may
162.3806 + * be true.
162.3807 + *
162.3808 + * <li>If both intCompact and intVal and set, their values must be
162.3809 + * consistent.
162.3810 + *
162.3811 + * <li>If precision is nonzero, it must have the right value.
162.3812 + * </ul>
162.3813 + *
162.3814 + * Note: Since this is an audit method, we are not supposed to change the
162.3815 + * state of this BigDecimal object.
162.3816 + */
162.3817 + private BigDecimal audit() {
162.3818 + if (intCompact == INFLATED) {
162.3819 + if (intVal == null) {
162.3820 + print("audit", this);
162.3821 + throw new AssertionError("null intVal");
162.3822 + }
162.3823 + // Check precision
162.3824 + if (precision > 0 && precision != bigDigitLength(intVal)) {
162.3825 + print("audit", this);
162.3826 + throw new AssertionError("precision mismatch");
162.3827 + }
162.3828 + } else {
162.3829 + if (intVal != null) {
162.3830 + long val = intVal.longValue();
162.3831 + if (val != intCompact) {
162.3832 + print("audit", this);
162.3833 + throw new AssertionError("Inconsistent state, intCompact=" +
162.3834 + intCompact + "\t intVal=" + val);
162.3835 + }
162.3836 + }
162.3837 + // Check precision
162.3838 + if (precision > 0 && precision != longDigitLength(intCompact)) {
162.3839 + print("audit", this);
162.3840 + throw new AssertionError("precision mismatch");
162.3841 + }
162.3842 + }
162.3843 + return this;
162.3844 + }
162.3845 +}
163.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
163.2 +++ b/rt/emul/compact/src/main/java/java/math/BigInteger.java Wed Apr 30 15:04:10 2014 +0200
163.3 @@ -0,0 +1,3122 @@
163.4 +/*
163.5 + * Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
163.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
163.7 + *
163.8 + * This code is free software; you can redistribute it and/or modify it
163.9 + * under the terms of the GNU General Public License version 2 only, as
163.10 + * published by the Free Software Foundation. Oracle designates this
163.11 + * particular file as subject to the "Classpath" exception as provided
163.12 + * by Oracle in the LICENSE file that accompanied this code.
163.13 + *
163.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
163.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
163.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
163.17 + * version 2 for more details (a copy is included in the LICENSE file that
163.18 + * accompanied this code).
163.19 + *
163.20 + * You should have received a copy of the GNU General Public License version
163.21 + * 2 along with this work; if not, write to the Free Software Foundation,
163.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
163.23 + *
163.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
163.25 + * or visit www.oracle.com if you need additional information or have any
163.26 + * questions.
163.27 + */
163.28 +
163.29 +/*
163.30 + * Portions Copyright (c) 1995 Colin Plumb. All rights reserved.
163.31 + */
163.32 +
163.33 +package java.math;
163.34 +
163.35 +import java.util.Random;
163.36 +import java.io.*;
163.37 +
163.38 +/**
163.39 + * Immutable arbitrary-precision integers. All operations behave as if
163.40 + * BigIntegers were represented in two's-complement notation (like Java's
163.41 + * primitive integer types). BigInteger provides analogues to all of Java's
163.42 + * primitive integer operators, and all relevant methods from java.lang.Math.
163.43 + * Additionally, BigInteger provides operations for modular arithmetic, GCD
163.44 + * calculation, primality testing, prime generation, bit manipulation,
163.45 + * and a few other miscellaneous operations.
163.46 + *
163.47 + * <p>Semantics of arithmetic operations exactly mimic those of Java's integer
163.48 + * arithmetic operators, as defined in <i>The Java Language Specification</i>.
163.49 + * For example, division by zero throws an {@code ArithmeticException}, and
163.50 + * division of a negative by a positive yields a negative (or zero) remainder.
163.51 + * All of the details in the Spec concerning overflow are ignored, as
163.52 + * BigIntegers are made as large as necessary to accommodate the results of an
163.53 + * operation.
163.54 + *
163.55 + * <p>Semantics of shift operations extend those of Java's shift operators
163.56 + * to allow for negative shift distances. A right-shift with a negative
163.57 + * shift distance results in a left shift, and vice-versa. The unsigned
163.58 + * right shift operator ({@code >>>}) is omitted, as this operation makes
163.59 + * little sense in combination with the "infinite word size" abstraction
163.60 + * provided by this class.
163.61 + *
163.62 + * <p>Semantics of bitwise logical operations exactly mimic those of Java's
163.63 + * bitwise integer operators. The binary operators ({@code and},
163.64 + * {@code or}, {@code xor}) implicitly perform sign extension on the shorter
163.65 + * of the two operands prior to performing the operation.
163.66 + *
163.67 + * <p>Comparison operations perform signed integer comparisons, analogous to
163.68 + * those performed by Java's relational and equality operators.
163.69 + *
163.70 + * <p>Modular arithmetic operations are provided to compute residues, perform
163.71 + * exponentiation, and compute multiplicative inverses. These methods always
163.72 + * return a non-negative result, between {@code 0} and {@code (modulus - 1)},
163.73 + * inclusive.
163.74 + *
163.75 + * <p>Bit operations operate on a single bit of the two's-complement
163.76 + * representation of their operand. If necessary, the operand is sign-
163.77 + * extended so that it contains the designated bit. None of the single-bit
163.78 + * operations can produce a BigInteger with a different sign from the
163.79 + * BigInteger being operated on, as they affect only a single bit, and the
163.80 + * "infinite word size" abstraction provided by this class ensures that there
163.81 + * are infinitely many "virtual sign bits" preceding each BigInteger.
163.82 + *
163.83 + * <p>For the sake of brevity and clarity, pseudo-code is used throughout the
163.84 + * descriptions of BigInteger methods. The pseudo-code expression
163.85 + * {@code (i + j)} is shorthand for "a BigInteger whose value is
163.86 + * that of the BigInteger {@code i} plus that of the BigInteger {@code j}."
163.87 + * The pseudo-code expression {@code (i == j)} is shorthand for
163.88 + * "{@code true} if and only if the BigInteger {@code i} represents the same
163.89 + * value as the BigInteger {@code j}." Other pseudo-code expressions are
163.90 + * interpreted similarly.
163.91 + *
163.92 + * <p>All methods and constructors in this class throw
163.93 + * {@code NullPointerException} when passed
163.94 + * a null object reference for any input parameter.
163.95 + *
163.96 + * @see BigDecimal
163.97 + * @author Josh Bloch
163.98 + * @author Michael McCloskey
163.99 + * @since JDK1.1
163.100 + */
163.101 +
163.102 +public class BigInteger extends Number implements Comparable<BigInteger> {
163.103 + /**
163.104 + * The signum of this BigInteger: -1 for negative, 0 for zero, or
163.105 + * 1 for positive. Note that the BigInteger zero <i>must</i> have
163.106 + * a signum of 0. This is necessary to ensures that there is exactly one
163.107 + * representation for each BigInteger value.
163.108 + *
163.109 + * @serial
163.110 + */
163.111 + final int signum;
163.112 +
163.113 + /**
163.114 + * The magnitude of this BigInteger, in <i>big-endian</i> order: the
163.115 + * zeroth element of this array is the most-significant int of the
163.116 + * magnitude. The magnitude must be "minimal" in that the most-significant
163.117 + * int ({@code mag[0]}) must be non-zero. This is necessary to
163.118 + * ensure that there is exactly one representation for each BigInteger
163.119 + * value. Note that this implies that the BigInteger zero has a
163.120 + * zero-length mag array.
163.121 + */
163.122 + final int[] mag;
163.123 +
163.124 + // These "redundant fields" are initialized with recognizable nonsense
163.125 + // values, and cached the first time they are needed (or never, if they
163.126 + // aren't needed).
163.127 +
163.128 + /**
163.129 + * One plus the bitCount of this BigInteger. Zeros means unitialized.
163.130 + *
163.131 + * @serial
163.132 + * @see #bitCount
163.133 + * @deprecated Deprecated since logical value is offset from stored
163.134 + * value and correction factor is applied in accessor method.
163.135 + */
163.136 + @Deprecated
163.137 + private int bitCount;
163.138 +
163.139 + /**
163.140 + * One plus the bitLength of this BigInteger. Zeros means unitialized.
163.141 + * (either value is acceptable).
163.142 + *
163.143 + * @serial
163.144 + * @see #bitLength()
163.145 + * @deprecated Deprecated since logical value is offset from stored
163.146 + * value and correction factor is applied in accessor method.
163.147 + */
163.148 + @Deprecated
163.149 + private int bitLength;
163.150 +
163.151 + /**
163.152 + * Two plus the lowest set bit of this BigInteger, as returned by
163.153 + * getLowestSetBit().
163.154 + *
163.155 + * @serial
163.156 + * @see #getLowestSetBit
163.157 + * @deprecated Deprecated since logical value is offset from stored
163.158 + * value and correction factor is applied in accessor method.
163.159 + */
163.160 + @Deprecated
163.161 + private int lowestSetBit;
163.162 +
163.163 + /**
163.164 + * Two plus the index of the lowest-order int in the magnitude of this
163.165 + * BigInteger that contains a nonzero int, or -2 (either value is acceptable).
163.166 + * The least significant int has int-number 0, the next int in order of
163.167 + * increasing significance has int-number 1, and so forth.
163.168 + * @deprecated Deprecated since logical value is offset from stored
163.169 + * value and correction factor is applied in accessor method.
163.170 + */
163.171 + @Deprecated
163.172 + private int firstNonzeroIntNum;
163.173 +
163.174 + /**
163.175 + * This mask is used to obtain the value of an int as if it were unsigned.
163.176 + */
163.177 + final static long LONG_MASK = 0xffffffffL;
163.178 +
163.179 + //Constructors
163.180 +
163.181 + /**
163.182 + * Translates a byte array containing the two's-complement binary
163.183 + * representation of a BigInteger into a BigInteger. The input array is
163.184 + * assumed to be in <i>big-endian</i> byte-order: the most significant
163.185 + * byte is in the zeroth element.
163.186 + *
163.187 + * @param val big-endian two's-complement binary representation of
163.188 + * BigInteger.
163.189 + * @throws NumberFormatException {@code val} is zero bytes long.
163.190 + */
163.191 + public BigInteger(byte[] val) {
163.192 + if (val.length == 0)
163.193 + throw new NumberFormatException("Zero length BigInteger");
163.194 +
163.195 + if (val[0] < 0) {
163.196 + mag = makePositive(val);
163.197 + signum = -1;
163.198 + } else {
163.199 + mag = stripLeadingZeroBytes(val);
163.200 + signum = (mag.length == 0 ? 0 : 1);
163.201 + }
163.202 + }
163.203 +
163.204 + /**
163.205 + * This private constructor translates an int array containing the
163.206 + * two's-complement binary representation of a BigInteger into a
163.207 + * BigInteger. The input array is assumed to be in <i>big-endian</i>
163.208 + * int-order: the most significant int is in the zeroth element.
163.209 + */
163.210 + private BigInteger(int[] val) {
163.211 + if (val.length == 0)
163.212 + throw new NumberFormatException("Zero length BigInteger");
163.213 +
163.214 + if (val[0] < 0) {
163.215 + mag = makePositive(val);
163.216 + signum = -1;
163.217 + } else {
163.218 + mag = trustedStripLeadingZeroInts(val);
163.219 + signum = (mag.length == 0 ? 0 : 1);
163.220 + }
163.221 + }
163.222 +
163.223 + /**
163.224 + * Translates the sign-magnitude representation of a BigInteger into a
163.225 + * BigInteger. The sign is represented as an integer signum value: -1 for
163.226 + * negative, 0 for zero, or 1 for positive. The magnitude is a byte array
163.227 + * in <i>big-endian</i> byte-order: the most significant byte is in the
163.228 + * zeroth element. A zero-length magnitude array is permissible, and will
163.229 + * result in a BigInteger value of 0, whether signum is -1, 0 or 1.
163.230 + *
163.231 + * @param signum signum of the number (-1 for negative, 0 for zero, 1
163.232 + * for positive).
163.233 + * @param magnitude big-endian binary representation of the magnitude of
163.234 + * the number.
163.235 + * @throws NumberFormatException {@code signum} is not one of the three
163.236 + * legal values (-1, 0, and 1), or {@code signum} is 0 and
163.237 + * {@code magnitude} contains one or more non-zero bytes.
163.238 + */
163.239 + public BigInteger(int signum, byte[] magnitude) {
163.240 + this.mag = stripLeadingZeroBytes(magnitude);
163.241 +
163.242 + if (signum < -1 || signum > 1)
163.243 + throw(new NumberFormatException("Invalid signum value"));
163.244 +
163.245 + if (this.mag.length==0) {
163.246 + this.signum = 0;
163.247 + } else {
163.248 + if (signum == 0)
163.249 + throw(new NumberFormatException("signum-magnitude mismatch"));
163.250 + this.signum = signum;
163.251 + }
163.252 + }
163.253 +
163.254 + /**
163.255 + * A constructor for internal use that translates the sign-magnitude
163.256 + * representation of a BigInteger into a BigInteger. It checks the
163.257 + * arguments and copies the magnitude so this constructor would be
163.258 + * safe for external use.
163.259 + */
163.260 + private BigInteger(int signum, int[] magnitude) {
163.261 + this.mag = stripLeadingZeroInts(magnitude);
163.262 +
163.263 + if (signum < -1 || signum > 1)
163.264 + throw(new NumberFormatException("Invalid signum value"));
163.265 +
163.266 + if (this.mag.length==0) {
163.267 + this.signum = 0;
163.268 + } else {
163.269 + if (signum == 0)
163.270 + throw(new NumberFormatException("signum-magnitude mismatch"));
163.271 + this.signum = signum;
163.272 + }
163.273 + }
163.274 +
163.275 + /**
163.276 + * Translates the String representation of a BigInteger in the
163.277 + * specified radix into a BigInteger. The String representation
163.278 + * consists of an optional minus or plus sign followed by a
163.279 + * sequence of one or more digits in the specified radix. The
163.280 + * character-to-digit mapping is provided by {@code
163.281 + * Character.digit}. The String may not contain any extraneous
163.282 + * characters (whitespace, for example).
163.283 + *
163.284 + * @param val String representation of BigInteger.
163.285 + * @param radix radix to be used in interpreting {@code val}.
163.286 + * @throws NumberFormatException {@code val} is not a valid representation
163.287 + * of a BigInteger in the specified radix, or {@code radix} is
163.288 + * outside the range from {@link Character#MIN_RADIX} to
163.289 + * {@link Character#MAX_RADIX}, inclusive.
163.290 + * @see Character#digit
163.291 + */
163.292 + public BigInteger(String val, int radix) {
163.293 + int cursor = 0, numDigits;
163.294 + final int len = val.length();
163.295 +
163.296 + if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
163.297 + throw new NumberFormatException("Radix out of range");
163.298 + if (len == 0)
163.299 + throw new NumberFormatException("Zero length BigInteger");
163.300 +
163.301 + // Check for at most one leading sign
163.302 + int sign = 1;
163.303 + int index1 = val.lastIndexOf('-');
163.304 + int index2 = val.lastIndexOf('+');
163.305 + if ((index1 + index2) <= -1) {
163.306 + // No leading sign character or at most one leading sign character
163.307 + if (index1 == 0 || index2 == 0) {
163.308 + cursor = 1;
163.309 + if (len == 1)
163.310 + throw new NumberFormatException("Zero length BigInteger");
163.311 + }
163.312 + if (index1 == 0)
163.313 + sign = -1;
163.314 + } else
163.315 + throw new NumberFormatException("Illegal embedded sign character");
163.316 +
163.317 + // Skip leading zeros and compute number of digits in magnitude
163.318 + while (cursor < len &&
163.319 + Character.digit(val.charAt(cursor), radix) == 0)
163.320 + cursor++;
163.321 + if (cursor == len) {
163.322 + signum = 0;
163.323 + mag = ZERO.mag;
163.324 + return;
163.325 + }
163.326 +
163.327 + numDigits = len - cursor;
163.328 + signum = sign;
163.329 +
163.330 + // Pre-allocate array of expected size. May be too large but can
163.331 + // never be too small. Typically exact.
163.332 + int numBits = (int)(((numDigits * bitsPerDigit[radix]) >>> 10) + 1);
163.333 + int numWords = (numBits + 31) >>> 5;
163.334 + int[] magnitude = new int[numWords];
163.335 +
163.336 + // Process first (potentially short) digit group
163.337 + int firstGroupLen = numDigits % digitsPerInt[radix];
163.338 + if (firstGroupLen == 0)
163.339 + firstGroupLen = digitsPerInt[radix];
163.340 + String group = val.substring(cursor, cursor += firstGroupLen);
163.341 + magnitude[numWords - 1] = Integer.parseInt(group, radix);
163.342 + if (magnitude[numWords - 1] < 0)
163.343 + throw new NumberFormatException("Illegal digit");
163.344 +
163.345 + // Process remaining digit groups
163.346 + int superRadix = intRadix[radix];
163.347 + int groupVal = 0;
163.348 + while (cursor < len) {
163.349 + group = val.substring(cursor, cursor += digitsPerInt[radix]);
163.350 + groupVal = Integer.parseInt(group, radix);
163.351 + if (groupVal < 0)
163.352 + throw new NumberFormatException("Illegal digit");
163.353 + destructiveMulAdd(magnitude, superRadix, groupVal);
163.354 + }
163.355 + // Required for cases where the array was overallocated.
163.356 + mag = trustedStripLeadingZeroInts(magnitude);
163.357 + }
163.358 +
163.359 + // Constructs a new BigInteger using a char array with radix=10
163.360 + BigInteger(char[] val) {
163.361 + int cursor = 0, numDigits;
163.362 + int len = val.length;
163.363 +
163.364 + // Check for leading minus sign
163.365 + int sign = 1;
163.366 + if (val[0] == '-') {
163.367 + if (len == 1)
163.368 + throw new NumberFormatException("Zero length BigInteger");
163.369 + sign = -1;
163.370 + cursor = 1;
163.371 + } else if (val[0] == '+') {
163.372 + if (len == 1)
163.373 + throw new NumberFormatException("Zero length BigInteger");
163.374 + cursor = 1;
163.375 + }
163.376 +
163.377 + // Skip leading zeros and compute number of digits in magnitude
163.378 + while (cursor < len && Character.digit(val[cursor], 10) == 0)
163.379 + cursor++;
163.380 + if (cursor == len) {
163.381 + signum = 0;
163.382 + mag = ZERO.mag;
163.383 + return;
163.384 + }
163.385 +
163.386 + numDigits = len - cursor;
163.387 + signum = sign;
163.388 +
163.389 + // Pre-allocate array of expected size
163.390 + int numWords;
163.391 + if (len < 10) {
163.392 + numWords = 1;
163.393 + } else {
163.394 + int numBits = (int)(((numDigits * bitsPerDigit[10]) >>> 10) + 1);
163.395 + numWords = (numBits + 31) >>> 5;
163.396 + }
163.397 + int[] magnitude = new int[numWords];
163.398 +
163.399 + // Process first (potentially short) digit group
163.400 + int firstGroupLen = numDigits % digitsPerInt[10];
163.401 + if (firstGroupLen == 0)
163.402 + firstGroupLen = digitsPerInt[10];
163.403 + magnitude[numWords - 1] = parseInt(val, cursor, cursor += firstGroupLen);
163.404 +
163.405 + // Process remaining digit groups
163.406 + while (cursor < len) {
163.407 + int groupVal = parseInt(val, cursor, cursor += digitsPerInt[10]);
163.408 + destructiveMulAdd(magnitude, intRadix[10], groupVal);
163.409 + }
163.410 + mag = trustedStripLeadingZeroInts(magnitude);
163.411 + }
163.412 +
163.413 + // Create an integer with the digits between the two indexes
163.414 + // Assumes start < end. The result may be negative, but it
163.415 + // is to be treated as an unsigned value.
163.416 + private int parseInt(char[] source, int start, int end) {
163.417 + int result = Character.digit(source[start++], 10);
163.418 + if (result == -1)
163.419 + throw new NumberFormatException(new String(source));
163.420 +
163.421 + for (int index = start; index<end; index++) {
163.422 + int nextVal = Character.digit(source[index], 10);
163.423 + if (nextVal == -1)
163.424 + throw new NumberFormatException(new String(source));
163.425 + result = 10*result + nextVal;
163.426 + }
163.427 +
163.428 + return result;
163.429 + }
163.430 +
163.431 + // bitsPerDigit in the given radix times 1024
163.432 + // Rounded up to avoid underallocation.
163.433 + private static long bitsPerDigit[] = { 0, 0,
163.434 + 1024, 1624, 2048, 2378, 2648, 2875, 3072, 3247, 3402, 3543, 3672,
163.435 + 3790, 3899, 4001, 4096, 4186, 4271, 4350, 4426, 4498, 4567, 4633,
163.436 + 4696, 4756, 4814, 4870, 4923, 4975, 5025, 5074, 5120, 5166, 5210,
163.437 + 5253, 5295};
163.438 +
163.439 + // Multiply x array times word y in place, and add word z
163.440 + private static void destructiveMulAdd(int[] x, int y, int z) {
163.441 + // Perform the multiplication word by word
163.442 + long ylong = y & LONG_MASK;
163.443 + long zlong = z & LONG_MASK;
163.444 + int len = x.length;
163.445 +
163.446 + long product = 0;
163.447 + long carry = 0;
163.448 + for (int i = len-1; i >= 0; i--) {
163.449 + product = ylong * (x[i] & LONG_MASK) + carry;
163.450 + x[i] = (int)product;
163.451 + carry = product >>> 32;
163.452 + }
163.453 +
163.454 + // Perform the addition
163.455 + long sum = (x[len-1] & LONG_MASK) + zlong;
163.456 + x[len-1] = (int)sum;
163.457 + carry = sum >>> 32;
163.458 + for (int i = len-2; i >= 0; i--) {
163.459 + sum = (x[i] & LONG_MASK) + carry;
163.460 + x[i] = (int)sum;
163.461 + carry = sum >>> 32;
163.462 + }
163.463 + }
163.464 +
163.465 + /**
163.466 + * Translates the decimal String representation of a BigInteger into a
163.467 + * BigInteger. The String representation consists of an optional minus
163.468 + * sign followed by a sequence of one or more decimal digits. The
163.469 + * character-to-digit mapping is provided by {@code Character.digit}.
163.470 + * The String may not contain any extraneous characters (whitespace, for
163.471 + * example).
163.472 + *
163.473 + * @param val decimal String representation of BigInteger.
163.474 + * @throws NumberFormatException {@code val} is not a valid representation
163.475 + * of a BigInteger.
163.476 + * @see Character#digit
163.477 + */
163.478 + public BigInteger(String val) {
163.479 + this(val, 10);
163.480 + }
163.481 +
163.482 + /**
163.483 + * Constructs a randomly generated BigInteger, uniformly distributed over
163.484 + * the range 0 to (2<sup>{@code numBits}</sup> - 1), inclusive.
163.485 + * The uniformity of the distribution assumes that a fair source of random
163.486 + * bits is provided in {@code rnd}. Note that this constructor always
163.487 + * constructs a non-negative BigInteger.
163.488 + *
163.489 + * @param numBits maximum bitLength of the new BigInteger.
163.490 + * @param rnd source of randomness to be used in computing the new
163.491 + * BigInteger.
163.492 + * @throws IllegalArgumentException {@code numBits} is negative.
163.493 + * @see #bitLength()
163.494 + */
163.495 + public BigInteger(int numBits, Random rnd) {
163.496 + this(1, randomBits(numBits, rnd));
163.497 + }
163.498 +
163.499 + private static byte[] randomBits(int numBits, Random rnd) {
163.500 + if (numBits < 0)
163.501 + throw new IllegalArgumentException("numBits must be non-negative");
163.502 + int numBytes = (int)(((long)numBits+7)/8); // avoid overflow
163.503 + byte[] randomBits = new byte[numBytes];
163.504 +
163.505 + // Generate random bytes and mask out any excess bits
163.506 + if (numBytes > 0) {
163.507 + rnd.nextBytes(randomBits);
163.508 + int excessBits = 8*numBytes - numBits;
163.509 + randomBits[0] &= (1 << (8-excessBits)) - 1;
163.510 + }
163.511 + return randomBits;
163.512 + }
163.513 +
163.514 + /**
163.515 + * Constructs a randomly generated positive BigInteger that is probably
163.516 + * prime, with the specified bitLength.
163.517 + *
163.518 + * <p>It is recommended that the {@link #probablePrime probablePrime}
163.519 + * method be used in preference to this constructor unless there
163.520 + * is a compelling need to specify a certainty.
163.521 + *
163.522 + * @param bitLength bitLength of the returned BigInteger.
163.523 + * @param certainty a measure of the uncertainty that the caller is
163.524 + * willing to tolerate. The probability that the new BigInteger
163.525 + * represents a prime number will exceed
163.526 + * (1 - 1/2<sup>{@code certainty}</sup>). The execution time of
163.527 + * this constructor is proportional to the value of this parameter.
163.528 + * @param rnd source of random bits used to select candidates to be
163.529 + * tested for primality.
163.530 + * @throws ArithmeticException {@code bitLength < 2}.
163.531 + * @see #bitLength()
163.532 + */
163.533 + public BigInteger(int bitLength, int certainty, Random rnd) {
163.534 + BigInteger prime;
163.535 +
163.536 + if (bitLength < 2)
163.537 + throw new ArithmeticException("bitLength < 2");
163.538 + // The cutoff of 95 was chosen empirically for best performance
163.539 + prime = (bitLength < 95 ? smallPrime(bitLength, certainty, rnd)
163.540 + : largePrime(bitLength, certainty, rnd));
163.541 + signum = 1;
163.542 + mag = prime.mag;
163.543 + }
163.544 +
163.545 + // Minimum size in bits that the requested prime number has
163.546 + // before we use the large prime number generating algorithms
163.547 + private static final int SMALL_PRIME_THRESHOLD = 95;
163.548 +
163.549 + // Certainty required to meet the spec of probablePrime
163.550 + private static final int DEFAULT_PRIME_CERTAINTY = 100;
163.551 +
163.552 + /**
163.553 + * Returns a positive BigInteger that is probably prime, with the
163.554 + * specified bitLength. The probability that a BigInteger returned
163.555 + * by this method is composite does not exceed 2<sup>-100</sup>.
163.556 + *
163.557 + * @param bitLength bitLength of the returned BigInteger.
163.558 + * @param rnd source of random bits used to select candidates to be
163.559 + * tested for primality.
163.560 + * @return a BigInteger of {@code bitLength} bits that is probably prime
163.561 + * @throws ArithmeticException {@code bitLength < 2}.
163.562 + * @see #bitLength()
163.563 + * @since 1.4
163.564 + */
163.565 + public static BigInteger probablePrime(int bitLength, Random rnd) {
163.566 + if (bitLength < 2)
163.567 + throw new ArithmeticException("bitLength < 2");
163.568 +
163.569 + // The cutoff of 95 was chosen empirically for best performance
163.570 + return (bitLength < SMALL_PRIME_THRESHOLD ?
163.571 + smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) :
163.572 + largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd));
163.573 + }
163.574 +
163.575 + /**
163.576 + * Find a random number of the specified bitLength that is probably prime.
163.577 + * This method is used for smaller primes, its performance degrades on
163.578 + * larger bitlengths.
163.579 + *
163.580 + * This method assumes bitLength > 1.
163.581 + */
163.582 + private static BigInteger smallPrime(int bitLength, int certainty, Random rnd) {
163.583 + int magLen = (bitLength + 31) >>> 5;
163.584 + int temp[] = new int[magLen];
163.585 + int highBit = 1 << ((bitLength+31) & 0x1f); // High bit of high int
163.586 + int highMask = (highBit << 1) - 1; // Bits to keep in high int
163.587 +
163.588 + while(true) {
163.589 + // Construct a candidate
163.590 + for (int i=0; i<magLen; i++)
163.591 + temp[i] = rnd.nextInt();
163.592 + temp[0] = (temp[0] & highMask) | highBit; // Ensure exact length
163.593 + if (bitLength > 2)
163.594 + temp[magLen-1] |= 1; // Make odd if bitlen > 2
163.595 +
163.596 + BigInteger p = new BigInteger(temp, 1);
163.597 +
163.598 + // Do cheap "pre-test" if applicable
163.599 + if (bitLength > 6) {
163.600 + long r = p.remainder(SMALL_PRIME_PRODUCT).longValue();
163.601 + if ((r%3==0) || (r%5==0) || (r%7==0) || (r%11==0) ||
163.602 + (r%13==0) || (r%17==0) || (r%19==0) || (r%23==0) ||
163.603 + (r%29==0) || (r%31==0) || (r%37==0) || (r%41==0))
163.604 + continue; // Candidate is composite; try another
163.605 + }
163.606 +
163.607 + // All candidates of bitLength 2 and 3 are prime by this point
163.608 + if (bitLength < 4)
163.609 + return p;
163.610 +
163.611 + // Do expensive test if we survive pre-test (or it's inapplicable)
163.612 + if (p.primeToCertainty(certainty, rnd))
163.613 + return p;
163.614 + }
163.615 + }
163.616 +
163.617 + private static final BigInteger SMALL_PRIME_PRODUCT
163.618 + = valueOf(3L*5*7*11*13*17*19*23*29*31*37*41);
163.619 +
163.620 + /**
163.621 + * Find a random number of the specified bitLength that is probably prime.
163.622 + * This method is more appropriate for larger bitlengths since it uses
163.623 + * a sieve to eliminate most composites before using a more expensive
163.624 + * test.
163.625 + */
163.626 + private static BigInteger largePrime(int bitLength, int certainty, Random rnd) {
163.627 + BigInteger p;
163.628 + p = new BigInteger(bitLength, rnd).setBit(bitLength-1);
163.629 + p.mag[p.mag.length-1] &= 0xfffffffe;
163.630 +
163.631 + // Use a sieve length likely to contain the next prime number
163.632 + int searchLen = (bitLength / 20) * 64;
163.633 + BitSieve searchSieve = new BitSieve(p, searchLen);
163.634 + BigInteger candidate = searchSieve.retrieve(p, certainty, rnd);
163.635 +
163.636 + while ((candidate == null) || (candidate.bitLength() != bitLength)) {
163.637 + p = p.add(BigInteger.valueOf(2*searchLen));
163.638 + if (p.bitLength() != bitLength)
163.639 + p = new BigInteger(bitLength, rnd).setBit(bitLength-1);
163.640 + p.mag[p.mag.length-1] &= 0xfffffffe;
163.641 + searchSieve = new BitSieve(p, searchLen);
163.642 + candidate = searchSieve.retrieve(p, certainty, rnd);
163.643 + }
163.644 + return candidate;
163.645 + }
163.646 +
163.647 + /**
163.648 + * Returns the first integer greater than this {@code BigInteger} that
163.649 + * is probably prime. The probability that the number returned by this
163.650 + * method is composite does not exceed 2<sup>-100</sup>. This method will
163.651 + * never skip over a prime when searching: if it returns {@code p}, there
163.652 + * is no prime {@code q} such that {@code this < q < p}.
163.653 + *
163.654 + * @return the first integer greater than this {@code BigInteger} that
163.655 + * is probably prime.
163.656 + * @throws ArithmeticException {@code this < 0}.
163.657 + * @since 1.5
163.658 + */
163.659 + public BigInteger nextProbablePrime() {
163.660 + if (this.signum < 0)
163.661 + throw new ArithmeticException("start < 0: " + this);
163.662 +
163.663 + // Handle trivial cases
163.664 + if ((this.signum == 0) || this.equals(ONE))
163.665 + return TWO;
163.666 +
163.667 + BigInteger result = this.add(ONE);
163.668 +
163.669 + // Fastpath for small numbers
163.670 + if (result.bitLength() < SMALL_PRIME_THRESHOLD) {
163.671 +
163.672 + // Ensure an odd number
163.673 + if (!result.testBit(0))
163.674 + result = result.add(ONE);
163.675 +
163.676 + while(true) {
163.677 + // Do cheap "pre-test" if applicable
163.678 + if (result.bitLength() > 6) {
163.679 + long r = result.remainder(SMALL_PRIME_PRODUCT).longValue();
163.680 + if ((r%3==0) || (r%5==0) || (r%7==0) || (r%11==0) ||
163.681 + (r%13==0) || (r%17==0) || (r%19==0) || (r%23==0) ||
163.682 + (r%29==0) || (r%31==0) || (r%37==0) || (r%41==0)) {
163.683 + result = result.add(TWO);
163.684 + continue; // Candidate is composite; try another
163.685 + }
163.686 + }
163.687 +
163.688 + // All candidates of bitLength 2 and 3 are prime by this point
163.689 + if (result.bitLength() < 4)
163.690 + return result;
163.691 +
163.692 + // The expensive test
163.693 + if (result.primeToCertainty(DEFAULT_PRIME_CERTAINTY, null))
163.694 + return result;
163.695 +
163.696 + result = result.add(TWO);
163.697 + }
163.698 + }
163.699 +
163.700 + // Start at previous even number
163.701 + if (result.testBit(0))
163.702 + result = result.subtract(ONE);
163.703 +
163.704 + // Looking for the next large prime
163.705 + int searchLen = (result.bitLength() / 20) * 64;
163.706 +
163.707 + while(true) {
163.708 + BitSieve searchSieve = new BitSieve(result, searchLen);
163.709 + BigInteger candidate = searchSieve.retrieve(result,
163.710 + DEFAULT_PRIME_CERTAINTY, null);
163.711 + if (candidate != null)
163.712 + return candidate;
163.713 + result = result.add(BigInteger.valueOf(2 * searchLen));
163.714 + }
163.715 + }
163.716 +
163.717 + /**
163.718 + * Returns {@code true} if this BigInteger is probably prime,
163.719 + * {@code false} if it's definitely composite.
163.720 + *
163.721 + * This method assumes bitLength > 2.
163.722 + *
163.723 + * @param certainty a measure of the uncertainty that the caller is
163.724 + * willing to tolerate: if the call returns {@code true}
163.725 + * the probability that this BigInteger is prime exceeds
163.726 + * {@code (1 - 1/2<sup>certainty</sup>)}. The execution time of
163.727 + * this method is proportional to the value of this parameter.
163.728 + * @return {@code true} if this BigInteger is probably prime,
163.729 + * {@code false} if it's definitely composite.
163.730 + */
163.731 + boolean primeToCertainty(int certainty, Random random) {
163.732 + int rounds = 0;
163.733 + int n = (Math.min(certainty, Integer.MAX_VALUE-1)+1)/2;
163.734 +
163.735 + // The relationship between the certainty and the number of rounds
163.736 + // we perform is given in the draft standard ANSI X9.80, "PRIME
163.737 + // NUMBER GENERATION, PRIMALITY TESTING, AND PRIMALITY CERTIFICATES".
163.738 + int sizeInBits = this.bitLength();
163.739 + if (sizeInBits < 100) {
163.740 + rounds = 50;
163.741 + rounds = n < rounds ? n : rounds;
163.742 + return passesMillerRabin(rounds, random);
163.743 + }
163.744 +
163.745 + if (sizeInBits < 256) {
163.746 + rounds = 27;
163.747 + } else if (sizeInBits < 512) {
163.748 + rounds = 15;
163.749 + } else if (sizeInBits < 768) {
163.750 + rounds = 8;
163.751 + } else if (sizeInBits < 1024) {
163.752 + rounds = 4;
163.753 + } else {
163.754 + rounds = 2;
163.755 + }
163.756 + rounds = n < rounds ? n : rounds;
163.757 +
163.758 + return passesMillerRabin(rounds, random) && passesLucasLehmer();
163.759 + }
163.760 +
163.761 + /**
163.762 + * Returns true iff this BigInteger is a Lucas-Lehmer probable prime.
163.763 + *
163.764 + * The following assumptions are made:
163.765 + * This BigInteger is a positive, odd number.
163.766 + */
163.767 + private boolean passesLucasLehmer() {
163.768 + BigInteger thisPlusOne = this.add(ONE);
163.769 +
163.770 + // Step 1
163.771 + int d = 5;
163.772 + while (jacobiSymbol(d, this) != -1) {
163.773 + // 5, -7, 9, -11, ...
163.774 + d = (d<0) ? Math.abs(d)+2 : -(d+2);
163.775 + }
163.776 +
163.777 + // Step 2
163.778 + BigInteger u = lucasLehmerSequence(d, thisPlusOne, this);
163.779 +
163.780 + // Step 3
163.781 + return u.mod(this).equals(ZERO);
163.782 + }
163.783 +
163.784 + /**
163.785 + * Computes Jacobi(p,n).
163.786 + * Assumes n positive, odd, n>=3.
163.787 + */
163.788 + private static int jacobiSymbol(int p, BigInteger n) {
163.789 + if (p == 0)
163.790 + return 0;
163.791 +
163.792 + // Algorithm and comments adapted from Colin Plumb's C library.
163.793 + int j = 1;
163.794 + int u = n.mag[n.mag.length-1];
163.795 +
163.796 + // Make p positive
163.797 + if (p < 0) {
163.798 + p = -p;
163.799 + int n8 = u & 7;
163.800 + if ((n8 == 3) || (n8 == 7))
163.801 + j = -j; // 3 (011) or 7 (111) mod 8
163.802 + }
163.803 +
163.804 + // Get rid of factors of 2 in p
163.805 + while ((p & 3) == 0)
163.806 + p >>= 2;
163.807 + if ((p & 1) == 0) {
163.808 + p >>= 1;
163.809 + if (((u ^ (u>>1)) & 2) != 0)
163.810 + j = -j; // 3 (011) or 5 (101) mod 8
163.811 + }
163.812 + if (p == 1)
163.813 + return j;
163.814 + // Then, apply quadratic reciprocity
163.815 + if ((p & u & 2) != 0) // p = u = 3 (mod 4)?
163.816 + j = -j;
163.817 + // And reduce u mod p
163.818 + u = n.mod(BigInteger.valueOf(p)).intValue();
163.819 +
163.820 + // Now compute Jacobi(u,p), u < p
163.821 + while (u != 0) {
163.822 + while ((u & 3) == 0)
163.823 + u >>= 2;
163.824 + if ((u & 1) == 0) {
163.825 + u >>= 1;
163.826 + if (((p ^ (p>>1)) & 2) != 0)
163.827 + j = -j; // 3 (011) or 5 (101) mod 8
163.828 + }
163.829 + if (u == 1)
163.830 + return j;
163.831 + // Now both u and p are odd, so use quadratic reciprocity
163.832 + assert (u < p);
163.833 + int t = u; u = p; p = t;
163.834 + if ((u & p & 2) != 0) // u = p = 3 (mod 4)?
163.835 + j = -j;
163.836 + // Now u >= p, so it can be reduced
163.837 + u %= p;
163.838 + }
163.839 + return 0;
163.840 + }
163.841 +
163.842 + private static BigInteger lucasLehmerSequence(int z, BigInteger k, BigInteger n) {
163.843 + BigInteger d = BigInteger.valueOf(z);
163.844 + BigInteger u = ONE; BigInteger u2;
163.845 + BigInteger v = ONE; BigInteger v2;
163.846 +
163.847 + for (int i=k.bitLength()-2; i>=0; i--) {
163.848 + u2 = u.multiply(v).mod(n);
163.849 +
163.850 + v2 = v.square().add(d.multiply(u.square())).mod(n);
163.851 + if (v2.testBit(0))
163.852 + v2 = v2.subtract(n);
163.853 +
163.854 + v2 = v2.shiftRight(1);
163.855 +
163.856 + u = u2; v = v2;
163.857 + if (k.testBit(i)) {
163.858 + u2 = u.add(v).mod(n);
163.859 + if (u2.testBit(0))
163.860 + u2 = u2.subtract(n);
163.861 +
163.862 + u2 = u2.shiftRight(1);
163.863 + v2 = v.add(d.multiply(u)).mod(n);
163.864 + if (v2.testBit(0))
163.865 + v2 = v2.subtract(n);
163.866 + v2 = v2.shiftRight(1);
163.867 +
163.868 + u = u2; v = v2;
163.869 + }
163.870 + }
163.871 + return u;
163.872 + }
163.873 +
163.874 + private static volatile Random staticRandom;
163.875 +
163.876 + private static Random getSecureRandom() {
163.877 + if (staticRandom == null) {
163.878 + staticRandom = new Random();
163.879 + }
163.880 + return staticRandom;
163.881 + }
163.882 +
163.883 + /**
163.884 + * Returns true iff this BigInteger passes the specified number of
163.885 + * Miller-Rabin tests. This test is taken from the DSA spec (NIST FIPS
163.886 + * 186-2).
163.887 + *
163.888 + * The following assumptions are made:
163.889 + * This BigInteger is a positive, odd number greater than 2.
163.890 + * iterations<=50.
163.891 + */
163.892 + private boolean passesMillerRabin(int iterations, Random rnd) {
163.893 + // Find a and m such that m is odd and this == 1 + 2**a * m
163.894 + BigInteger thisMinusOne = this.subtract(ONE);
163.895 + BigInteger m = thisMinusOne;
163.896 + int a = m.getLowestSetBit();
163.897 + m = m.shiftRight(a);
163.898 +
163.899 + // Do the tests
163.900 + if (rnd == null) {
163.901 + rnd = getSecureRandom();
163.902 + }
163.903 + for (int i=0; i<iterations; i++) {
163.904 + // Generate a uniform random on (1, this)
163.905 + BigInteger b;
163.906 + do {
163.907 + b = new BigInteger(this.bitLength(), rnd);
163.908 + } while (b.compareTo(ONE) <= 0 || b.compareTo(this) >= 0);
163.909 +
163.910 + int j = 0;
163.911 + BigInteger z = b.modPow(m, this);
163.912 + while(!((j==0 && z.equals(ONE)) || z.equals(thisMinusOne))) {
163.913 + if (j>0 && z.equals(ONE) || ++j==a)
163.914 + return false;
163.915 + z = z.modPow(TWO, this);
163.916 + }
163.917 + }
163.918 + return true;
163.919 + }
163.920 +
163.921 + /**
163.922 + * This internal constructor differs from its public cousin
163.923 + * with the arguments reversed in two ways: it assumes that its
163.924 + * arguments are correct, and it doesn't copy the magnitude array.
163.925 + */
163.926 + BigInteger(int[] magnitude, int signum) {
163.927 + this.signum = (magnitude.length==0 ? 0 : signum);
163.928 + this.mag = magnitude;
163.929 + }
163.930 +
163.931 + /**
163.932 + * This private constructor is for internal use and assumes that its
163.933 + * arguments are correct.
163.934 + */
163.935 + private BigInteger(byte[] magnitude, int signum) {
163.936 + this.signum = (magnitude.length==0 ? 0 : signum);
163.937 + this.mag = stripLeadingZeroBytes(magnitude);
163.938 + }
163.939 +
163.940 + //Static Factory Methods
163.941 +
163.942 + /**
163.943 + * Returns a BigInteger whose value is equal to that of the
163.944 + * specified {@code long}. This "static factory method" is
163.945 + * provided in preference to a ({@code long}) constructor
163.946 + * because it allows for reuse of frequently used BigIntegers.
163.947 + *
163.948 + * @param val value of the BigInteger to return.
163.949 + * @return a BigInteger with the specified value.
163.950 + */
163.951 + public static BigInteger valueOf(long val) {
163.952 + // If -MAX_CONSTANT < val < MAX_CONSTANT, return stashed constant
163.953 + if (val == 0)
163.954 + return ZERO;
163.955 + if (val > 0 && val <= MAX_CONSTANT)
163.956 + return posConst[(int) val];
163.957 + else if (val < 0 && val >= -MAX_CONSTANT)
163.958 + return negConst[(int) -val];
163.959 +
163.960 + return new BigInteger(val);
163.961 + }
163.962 +
163.963 + /**
163.964 + * Constructs a BigInteger with the specified value, which may not be zero.
163.965 + */
163.966 + private BigInteger(long val) {
163.967 + if (val < 0) {
163.968 + val = -val;
163.969 + signum = -1;
163.970 + } else {
163.971 + signum = 1;
163.972 + }
163.973 +
163.974 + int highWord = (int)(val >>> 32);
163.975 + if (highWord==0) {
163.976 + mag = new int[1];
163.977 + mag[0] = (int)val;
163.978 + } else {
163.979 + mag = new int[2];
163.980 + mag[0] = highWord;
163.981 + mag[1] = (int)val;
163.982 + }
163.983 + }
163.984 +
163.985 + /**
163.986 + * Returns a BigInteger with the given two's complement representation.
163.987 + * Assumes that the input array will not be modified (the returned
163.988 + * BigInteger will reference the input array if feasible).
163.989 + */
163.990 + private static BigInteger valueOf(int val[]) {
163.991 + return (val[0]>0 ? new BigInteger(val, 1) : new BigInteger(val));
163.992 + }
163.993 +
163.994 + // Constants
163.995 +
163.996 + /**
163.997 + * Initialize static constant array when class is loaded.
163.998 + */
163.999 + private final static int MAX_CONSTANT = 16;
163.1000 + private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];
163.1001 + private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];
163.1002 + static {
163.1003 + for (int i = 1; i <= MAX_CONSTANT; i++) {
163.1004 + int[] magnitude = new int[1];
163.1005 + magnitude[0] = i;
163.1006 + posConst[i] = new BigInteger(magnitude, 1);
163.1007 + negConst[i] = new BigInteger(magnitude, -1);
163.1008 + }
163.1009 + }
163.1010 +
163.1011 + /**
163.1012 + * The BigInteger constant zero.
163.1013 + *
163.1014 + * @since 1.2
163.1015 + */
163.1016 + public static final BigInteger ZERO = new BigInteger(new int[0], 0);
163.1017 +
163.1018 + /**
163.1019 + * The BigInteger constant one.
163.1020 + *
163.1021 + * @since 1.2
163.1022 + */
163.1023 + public static final BigInteger ONE = valueOf(1);
163.1024 +
163.1025 + /**
163.1026 + * The BigInteger constant two. (Not exported.)
163.1027 + */
163.1028 + private static final BigInteger TWO = valueOf(2);
163.1029 +
163.1030 + /**
163.1031 + * The BigInteger constant ten.
163.1032 + *
163.1033 + * @since 1.5
163.1034 + */
163.1035 + public static final BigInteger TEN = valueOf(10);
163.1036 +
163.1037 + // Arithmetic Operations
163.1038 +
163.1039 + /**
163.1040 + * Returns a BigInteger whose value is {@code (this + val)}.
163.1041 + *
163.1042 + * @param val value to be added to this BigInteger.
163.1043 + * @return {@code this + val}
163.1044 + */
163.1045 + public BigInteger add(BigInteger val) {
163.1046 + if (val.signum == 0)
163.1047 + return this;
163.1048 + if (signum == 0)
163.1049 + return val;
163.1050 + if (val.signum == signum)
163.1051 + return new BigInteger(add(mag, val.mag), signum);
163.1052 +
163.1053 + int cmp = compareMagnitude(val);
163.1054 + if (cmp == 0)
163.1055 + return ZERO;
163.1056 + int[] resultMag = (cmp > 0 ? subtract(mag, val.mag)
163.1057 + : subtract(val.mag, mag));
163.1058 + resultMag = trustedStripLeadingZeroInts(resultMag);
163.1059 +
163.1060 + return new BigInteger(resultMag, cmp == signum ? 1 : -1);
163.1061 + }
163.1062 +
163.1063 + /**
163.1064 + * Adds the contents of the int arrays x and y. This method allocates
163.1065 + * a new int array to hold the answer and returns a reference to that
163.1066 + * array.
163.1067 + */
163.1068 + private static int[] add(int[] x, int[] y) {
163.1069 + // If x is shorter, swap the two arrays
163.1070 + if (x.length < y.length) {
163.1071 + int[] tmp = x;
163.1072 + x = y;
163.1073 + y = tmp;
163.1074 + }
163.1075 +
163.1076 + int xIndex = x.length;
163.1077 + int yIndex = y.length;
163.1078 + int result[] = new int[xIndex];
163.1079 + long sum = 0;
163.1080 +
163.1081 + // Add common parts of both numbers
163.1082 + while(yIndex > 0) {
163.1083 + sum = (x[--xIndex] & LONG_MASK) +
163.1084 + (y[--yIndex] & LONG_MASK) + (sum >>> 32);
163.1085 + result[xIndex] = (int)sum;
163.1086 + }
163.1087 +
163.1088 + // Copy remainder of longer number while carry propagation is required
163.1089 + boolean carry = (sum >>> 32 != 0);
163.1090 + while (xIndex > 0 && carry)
163.1091 + carry = ((result[--xIndex] = x[xIndex] + 1) == 0);
163.1092 +
163.1093 + // Copy remainder of longer number
163.1094 + while (xIndex > 0)
163.1095 + result[--xIndex] = x[xIndex];
163.1096 +
163.1097 + // Grow result if necessary
163.1098 + if (carry) {
163.1099 + int bigger[] = new int[result.length + 1];
163.1100 + System.arraycopy(result, 0, bigger, 1, result.length);
163.1101 + bigger[0] = 0x01;
163.1102 + return bigger;
163.1103 + }
163.1104 + return result;
163.1105 + }
163.1106 +
163.1107 + /**
163.1108 + * Returns a BigInteger whose value is {@code (this - val)}.
163.1109 + *
163.1110 + * @param val value to be subtracted from this BigInteger.
163.1111 + * @return {@code this - val}
163.1112 + */
163.1113 + public BigInteger subtract(BigInteger val) {
163.1114 + if (val.signum == 0)
163.1115 + return this;
163.1116 + if (signum == 0)
163.1117 + return val.negate();
163.1118 + if (val.signum != signum)
163.1119 + return new BigInteger(add(mag, val.mag), signum);
163.1120 +
163.1121 + int cmp = compareMagnitude(val);
163.1122 + if (cmp == 0)
163.1123 + return ZERO;
163.1124 + int[] resultMag = (cmp > 0 ? subtract(mag, val.mag)
163.1125 + : subtract(val.mag, mag));
163.1126 + resultMag = trustedStripLeadingZeroInts(resultMag);
163.1127 + return new BigInteger(resultMag, cmp == signum ? 1 : -1);
163.1128 + }
163.1129 +
163.1130 + /**
163.1131 + * Subtracts the contents of the second int arrays (little) from the
163.1132 + * first (big). The first int array (big) must represent a larger number
163.1133 + * than the second. This method allocates the space necessary to hold the
163.1134 + * answer.
163.1135 + */
163.1136 + private static int[] subtract(int[] big, int[] little) {
163.1137 + int bigIndex = big.length;
163.1138 + int result[] = new int[bigIndex];
163.1139 + int littleIndex = little.length;
163.1140 + long difference = 0;
163.1141 +
163.1142 + // Subtract common parts of both numbers
163.1143 + while(littleIndex > 0) {
163.1144 + difference = (big[--bigIndex] & LONG_MASK) -
163.1145 + (little[--littleIndex] & LONG_MASK) +
163.1146 + (difference >> 32);
163.1147 + result[bigIndex] = (int)difference;
163.1148 + }
163.1149 +
163.1150 + // Subtract remainder of longer number while borrow propagates
163.1151 + boolean borrow = (difference >> 32 != 0);
163.1152 + while (bigIndex > 0 && borrow)
163.1153 + borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1);
163.1154 +
163.1155 + // Copy remainder of longer number
163.1156 + while (bigIndex > 0)
163.1157 + result[--bigIndex] = big[bigIndex];
163.1158 +
163.1159 + return result;
163.1160 + }
163.1161 +
163.1162 + /**
163.1163 + * Returns a BigInteger whose value is {@code (this * val)}.
163.1164 + *
163.1165 + * @param val value to be multiplied by this BigInteger.
163.1166 + * @return {@code this * val}
163.1167 + */
163.1168 + public BigInteger multiply(BigInteger val) {
163.1169 + if (val.signum == 0 || signum == 0)
163.1170 + return ZERO;
163.1171 +
163.1172 + int[] result = multiplyToLen(mag, mag.length,
163.1173 + val.mag, val.mag.length, null);
163.1174 + result = trustedStripLeadingZeroInts(result);
163.1175 + return new BigInteger(result, signum == val.signum ? 1 : -1);
163.1176 + }
163.1177 +
163.1178 + /**
163.1179 + * Package private methods used by BigDecimal code to multiply a BigInteger
163.1180 + * with a long. Assumes v is not equal to INFLATED.
163.1181 + */
163.1182 + BigInteger multiply(long v) {
163.1183 + if (v == 0 || signum == 0)
163.1184 + return ZERO;
163.1185 + if (v == BigDecimal.INFLATED)
163.1186 + return multiply(BigInteger.valueOf(v));
163.1187 + int rsign = (v > 0 ? signum : -signum);
163.1188 + if (v < 0)
163.1189 + v = -v;
163.1190 + long dh = v >>> 32; // higher order bits
163.1191 + long dl = v & LONG_MASK; // lower order bits
163.1192 +
163.1193 + int xlen = mag.length;
163.1194 + int[] value = mag;
163.1195 + int[] rmag = (dh == 0L) ? (new int[xlen + 1]) : (new int[xlen + 2]);
163.1196 + long carry = 0;
163.1197 + int rstart = rmag.length - 1;
163.1198 + for (int i = xlen - 1; i >= 0; i--) {
163.1199 + long product = (value[i] & LONG_MASK) * dl + carry;
163.1200 + rmag[rstart--] = (int)product;
163.1201 + carry = product >>> 32;
163.1202 + }
163.1203 + rmag[rstart] = (int)carry;
163.1204 + if (dh != 0L) {
163.1205 + carry = 0;
163.1206 + rstart = rmag.length - 2;
163.1207 + for (int i = xlen - 1; i >= 0; i--) {
163.1208 + long product = (value[i] & LONG_MASK) * dh +
163.1209 + (rmag[rstart] & LONG_MASK) + carry;
163.1210 + rmag[rstart--] = (int)product;
163.1211 + carry = product >>> 32;
163.1212 + }
163.1213 + rmag[0] = (int)carry;
163.1214 + }
163.1215 + if (carry == 0L)
163.1216 + rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length);
163.1217 + return new BigInteger(rmag, rsign);
163.1218 + }
163.1219 +
163.1220 + /**
163.1221 + * Multiplies int arrays x and y to the specified lengths and places
163.1222 + * the result into z. There will be no leading zeros in the resultant array.
163.1223 + */
163.1224 + private int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) {
163.1225 + int xstart = xlen - 1;
163.1226 + int ystart = ylen - 1;
163.1227 +
163.1228 + if (z == null || z.length < (xlen+ ylen))
163.1229 + z = new int[xlen+ylen];
163.1230 +
163.1231 + long carry = 0;
163.1232 + for (int j=ystart, k=ystart+1+xstart; j>=0; j--, k--) {
163.1233 + long product = (y[j] & LONG_MASK) *
163.1234 + (x[xstart] & LONG_MASK) + carry;
163.1235 + z[k] = (int)product;
163.1236 + carry = product >>> 32;
163.1237 + }
163.1238 + z[xstart] = (int)carry;
163.1239 +
163.1240 + for (int i = xstart-1; i >= 0; i--) {
163.1241 + carry = 0;
163.1242 + for (int j=ystart, k=ystart+1+i; j>=0; j--, k--) {
163.1243 + long product = (y[j] & LONG_MASK) *
163.1244 + (x[i] & LONG_MASK) +
163.1245 + (z[k] & LONG_MASK) + carry;
163.1246 + z[k] = (int)product;
163.1247 + carry = product >>> 32;
163.1248 + }
163.1249 + z[i] = (int)carry;
163.1250 + }
163.1251 + return z;
163.1252 + }
163.1253 +
163.1254 + /**
163.1255 + * Returns a BigInteger whose value is {@code (this<sup>2</sup>)}.
163.1256 + *
163.1257 + * @return {@code this<sup>2</sup>}
163.1258 + */
163.1259 + private BigInteger square() {
163.1260 + if (signum == 0)
163.1261 + return ZERO;
163.1262 + int[] z = squareToLen(mag, mag.length, null);
163.1263 + return new BigInteger(trustedStripLeadingZeroInts(z), 1);
163.1264 + }
163.1265 +
163.1266 + /**
163.1267 + * Squares the contents of the int array x. The result is placed into the
163.1268 + * int array z. The contents of x are not changed.
163.1269 + */
163.1270 + private static final int[] squareToLen(int[] x, int len, int[] z) {
163.1271 + /*
163.1272 + * The algorithm used here is adapted from Colin Plumb's C library.
163.1273 + * Technique: Consider the partial products in the multiplication
163.1274 + * of "abcde" by itself:
163.1275 + *
163.1276 + * a b c d e
163.1277 + * * a b c d e
163.1278 + * ==================
163.1279 + * ae be ce de ee
163.1280 + * ad bd cd dd de
163.1281 + * ac bc cc cd ce
163.1282 + * ab bb bc bd be
163.1283 + * aa ab ac ad ae
163.1284 + *
163.1285 + * Note that everything above the main diagonal:
163.1286 + * ae be ce de = (abcd) * e
163.1287 + * ad bd cd = (abc) * d
163.1288 + * ac bc = (ab) * c
163.1289 + * ab = (a) * b
163.1290 + *
163.1291 + * is a copy of everything below the main diagonal:
163.1292 + * de
163.1293 + * cd ce
163.1294 + * bc bd be
163.1295 + * ab ac ad ae
163.1296 + *
163.1297 + * Thus, the sum is 2 * (off the diagonal) + diagonal.
163.1298 + *
163.1299 + * This is accumulated beginning with the diagonal (which
163.1300 + * consist of the squares of the digits of the input), which is then
163.1301 + * divided by two, the off-diagonal added, and multiplied by two
163.1302 + * again. The low bit is simply a copy of the low bit of the
163.1303 + * input, so it doesn't need special care.
163.1304 + */
163.1305 + int zlen = len << 1;
163.1306 + if (z == null || z.length < zlen)
163.1307 + z = new int[zlen];
163.1308 +
163.1309 + // Store the squares, right shifted one bit (i.e., divided by 2)
163.1310 + int lastProductLowWord = 0;
163.1311 + for (int j=0, i=0; j<len; j++) {
163.1312 + long piece = (x[j] & LONG_MASK);
163.1313 + long product = piece * piece;
163.1314 + z[i++] = (lastProductLowWord << 31) | (int)(product >>> 33);
163.1315 + z[i++] = (int)(product >>> 1);
163.1316 + lastProductLowWord = (int)product;
163.1317 + }
163.1318 +
163.1319 + // Add in off-diagonal sums
163.1320 + for (int i=len, offset=1; i>0; i--, offset+=2) {
163.1321 + int t = x[i-1];
163.1322 + t = mulAdd(z, x, offset, i-1, t);
163.1323 + addOne(z, offset-1, i, t);
163.1324 + }
163.1325 +
163.1326 + // Shift back up and set low bit
163.1327 + primitiveLeftShift(z, zlen, 1);
163.1328 + z[zlen-1] |= x[len-1] & 1;
163.1329 +
163.1330 + return z;
163.1331 + }
163.1332 +
163.1333 + /**
163.1334 + * Returns a BigInteger whose value is {@code (this / val)}.
163.1335 + *
163.1336 + * @param val value by which this BigInteger is to be divided.
163.1337 + * @return {@code this / val}
163.1338 + * @throws ArithmeticException if {@code val} is zero.
163.1339 + */
163.1340 + public BigInteger divide(BigInteger val) {
163.1341 + MutableBigInteger q = new MutableBigInteger(),
163.1342 + a = new MutableBigInteger(this.mag),
163.1343 + b = new MutableBigInteger(val.mag);
163.1344 +
163.1345 + a.divide(b, q);
163.1346 + return q.toBigInteger(this.signum == val.signum ? 1 : -1);
163.1347 + }
163.1348 +
163.1349 + /**
163.1350 + * Returns an array of two BigIntegers containing {@code (this / val)}
163.1351 + * followed by {@code (this % val)}.
163.1352 + *
163.1353 + * @param val value by which this BigInteger is to be divided, and the
163.1354 + * remainder computed.
163.1355 + * @return an array of two BigIntegers: the quotient {@code (this / val)}
163.1356 + * is the initial element, and the remainder {@code (this % val)}
163.1357 + * is the final element.
163.1358 + * @throws ArithmeticException if {@code val} is zero.
163.1359 + */
163.1360 + public BigInteger[] divideAndRemainder(BigInteger val) {
163.1361 + BigInteger[] result = new BigInteger[2];
163.1362 + MutableBigInteger q = new MutableBigInteger(),
163.1363 + a = new MutableBigInteger(this.mag),
163.1364 + b = new MutableBigInteger(val.mag);
163.1365 + MutableBigInteger r = a.divide(b, q);
163.1366 + result[0] = q.toBigInteger(this.signum == val.signum ? 1 : -1);
163.1367 + result[1] = r.toBigInteger(this.signum);
163.1368 + return result;
163.1369 + }
163.1370 +
163.1371 + /**
163.1372 + * Returns a BigInteger whose value is {@code (this % val)}.
163.1373 + *
163.1374 + * @param val value by which this BigInteger is to be divided, and the
163.1375 + * remainder computed.
163.1376 + * @return {@code this % val}
163.1377 + * @throws ArithmeticException if {@code val} is zero.
163.1378 + */
163.1379 + public BigInteger remainder(BigInteger val) {
163.1380 + MutableBigInteger q = new MutableBigInteger(),
163.1381 + a = new MutableBigInteger(this.mag),
163.1382 + b = new MutableBigInteger(val.mag);
163.1383 +
163.1384 + return a.divide(b, q).toBigInteger(this.signum);
163.1385 + }
163.1386 +
163.1387 + /**
163.1388 + * Returns a BigInteger whose value is <tt>(this<sup>exponent</sup>)</tt>.
163.1389 + * Note that {@code exponent} is an integer rather than a BigInteger.
163.1390 + *
163.1391 + * @param exponent exponent to which this BigInteger is to be raised.
163.1392 + * @return <tt>this<sup>exponent</sup></tt>
163.1393 + * @throws ArithmeticException {@code exponent} is negative. (This would
163.1394 + * cause the operation to yield a non-integer value.)
163.1395 + */
163.1396 + public BigInteger pow(int exponent) {
163.1397 + if (exponent < 0)
163.1398 + throw new ArithmeticException("Negative exponent");
163.1399 + if (signum==0)
163.1400 + return (exponent==0 ? ONE : this);
163.1401 +
163.1402 + // Perform exponentiation using repeated squaring trick
163.1403 + int newSign = (signum<0 && (exponent&1)==1 ? -1 : 1);
163.1404 + int[] baseToPow2 = this.mag;
163.1405 + int[] result = {1};
163.1406 +
163.1407 + while (exponent != 0) {
163.1408 + if ((exponent & 1)==1) {
163.1409 + result = multiplyToLen(result, result.length,
163.1410 + baseToPow2, baseToPow2.length, null);
163.1411 + result = trustedStripLeadingZeroInts(result);
163.1412 + }
163.1413 + if ((exponent >>>= 1) != 0) {
163.1414 + baseToPow2 = squareToLen(baseToPow2, baseToPow2.length, null);
163.1415 + baseToPow2 = trustedStripLeadingZeroInts(baseToPow2);
163.1416 + }
163.1417 + }
163.1418 + return new BigInteger(result, newSign);
163.1419 + }
163.1420 +
163.1421 + /**
163.1422 + * Returns a BigInteger whose value is the greatest common divisor of
163.1423 + * {@code abs(this)} and {@code abs(val)}. Returns 0 if
163.1424 + * {@code this==0 && val==0}.
163.1425 + *
163.1426 + * @param val value with which the GCD is to be computed.
163.1427 + * @return {@code GCD(abs(this), abs(val))}
163.1428 + */
163.1429 + public BigInteger gcd(BigInteger val) {
163.1430 + if (val.signum == 0)
163.1431 + return this.abs();
163.1432 + else if (this.signum == 0)
163.1433 + return val.abs();
163.1434 +
163.1435 + MutableBigInteger a = new MutableBigInteger(this);
163.1436 + MutableBigInteger b = new MutableBigInteger(val);
163.1437 +
163.1438 + MutableBigInteger result = a.hybridGCD(b);
163.1439 +
163.1440 + return result.toBigInteger(1);
163.1441 + }
163.1442 +
163.1443 + /**
163.1444 + * Package private method to return bit length for an integer.
163.1445 + */
163.1446 + static int bitLengthForInt(int n) {
163.1447 + return 32 - Integer.numberOfLeadingZeros(n);
163.1448 + }
163.1449 +
163.1450 + /**
163.1451 + * Left shift int array a up to len by n bits. Returns the array that
163.1452 + * results from the shift since space may have to be reallocated.
163.1453 + */
163.1454 + private static int[] leftShift(int[] a, int len, int n) {
163.1455 + int nInts = n >>> 5;
163.1456 + int nBits = n&0x1F;
163.1457 + int bitsInHighWord = bitLengthForInt(a[0]);
163.1458 +
163.1459 + // If shift can be done without recopy, do so
163.1460 + if (n <= (32-bitsInHighWord)) {
163.1461 + primitiveLeftShift(a, len, nBits);
163.1462 + return a;
163.1463 + } else { // Array must be resized
163.1464 + if (nBits <= (32-bitsInHighWord)) {
163.1465 + int result[] = new int[nInts+len];
163.1466 + for (int i=0; i<len; i++)
163.1467 + result[i] = a[i];
163.1468 + primitiveLeftShift(result, result.length, nBits);
163.1469 + return result;
163.1470 + } else {
163.1471 + int result[] = new int[nInts+len+1];
163.1472 + for (int i=0; i<len; i++)
163.1473 + result[i] = a[i];
163.1474 + primitiveRightShift(result, result.length, 32 - nBits);
163.1475 + return result;
163.1476 + }
163.1477 + }
163.1478 + }
163.1479 +
163.1480 + // shifts a up to len right n bits assumes no leading zeros, 0<n<32
163.1481 + static void primitiveRightShift(int[] a, int len, int n) {
163.1482 + int n2 = 32 - n;
163.1483 + for (int i=len-1, c=a[i]; i>0; i--) {
163.1484 + int b = c;
163.1485 + c = a[i-1];
163.1486 + a[i] = (c << n2) | (b >>> n);
163.1487 + }
163.1488 + a[0] >>>= n;
163.1489 + }
163.1490 +
163.1491 + // shifts a up to len left n bits assumes no leading zeros, 0<=n<32
163.1492 + static void primitiveLeftShift(int[] a, int len, int n) {
163.1493 + if (len == 0 || n == 0)
163.1494 + return;
163.1495 +
163.1496 + int n2 = 32 - n;
163.1497 + for (int i=0, c=a[i], m=i+len-1; i<m; i++) {
163.1498 + int b = c;
163.1499 + c = a[i+1];
163.1500 + a[i] = (b << n) | (c >>> n2);
163.1501 + }
163.1502 + a[len-1] <<= n;
163.1503 + }
163.1504 +
163.1505 + /**
163.1506 + * Calculate bitlength of contents of the first len elements an int array,
163.1507 + * assuming there are no leading zero ints.
163.1508 + */
163.1509 + private static int bitLength(int[] val, int len) {
163.1510 + if (len == 0)
163.1511 + return 0;
163.1512 + return ((len - 1) << 5) + bitLengthForInt(val[0]);
163.1513 + }
163.1514 +
163.1515 + /**
163.1516 + * Returns a BigInteger whose value is the absolute value of this
163.1517 + * BigInteger.
163.1518 + *
163.1519 + * @return {@code abs(this)}
163.1520 + */
163.1521 + public BigInteger abs() {
163.1522 + return (signum >= 0 ? this : this.negate());
163.1523 + }
163.1524 +
163.1525 + /**
163.1526 + * Returns a BigInteger whose value is {@code (-this)}.
163.1527 + *
163.1528 + * @return {@code -this}
163.1529 + */
163.1530 + public BigInteger negate() {
163.1531 + return new BigInteger(this.mag, -this.signum);
163.1532 + }
163.1533 +
163.1534 + /**
163.1535 + * Returns the signum function of this BigInteger.
163.1536 + *
163.1537 + * @return -1, 0 or 1 as the value of this BigInteger is negative, zero or
163.1538 + * positive.
163.1539 + */
163.1540 + public int signum() {
163.1541 + return this.signum;
163.1542 + }
163.1543 +
163.1544 + // Modular Arithmetic Operations
163.1545 +
163.1546 + /**
163.1547 + * Returns a BigInteger whose value is {@code (this mod m}). This method
163.1548 + * differs from {@code remainder} in that it always returns a
163.1549 + * <i>non-negative</i> BigInteger.
163.1550 + *
163.1551 + * @param m the modulus.
163.1552 + * @return {@code this mod m}
163.1553 + * @throws ArithmeticException {@code m} ≤ 0
163.1554 + * @see #remainder
163.1555 + */
163.1556 + public BigInteger mod(BigInteger m) {
163.1557 + if (m.signum <= 0)
163.1558 + throw new ArithmeticException("BigInteger: modulus not positive");
163.1559 +
163.1560 + BigInteger result = this.remainder(m);
163.1561 + return (result.signum >= 0 ? result : result.add(m));
163.1562 + }
163.1563 +
163.1564 + /**
163.1565 + * Returns a BigInteger whose value is
163.1566 + * <tt>(this<sup>exponent</sup> mod m)</tt>. (Unlike {@code pow}, this
163.1567 + * method permits negative exponents.)
163.1568 + *
163.1569 + * @param exponent the exponent.
163.1570 + * @param m the modulus.
163.1571 + * @return <tt>this<sup>exponent</sup> mod m</tt>
163.1572 + * @throws ArithmeticException {@code m} ≤ 0 or the exponent is
163.1573 + * negative and this BigInteger is not <i>relatively
163.1574 + * prime</i> to {@code m}.
163.1575 + * @see #modInverse
163.1576 + */
163.1577 + public BigInteger modPow(BigInteger exponent, BigInteger m) {
163.1578 + if (m.signum <= 0)
163.1579 + throw new ArithmeticException("BigInteger: modulus not positive");
163.1580 +
163.1581 + // Trivial cases
163.1582 + if (exponent.signum == 0)
163.1583 + return (m.equals(ONE) ? ZERO : ONE);
163.1584 +
163.1585 + if (this.equals(ONE))
163.1586 + return (m.equals(ONE) ? ZERO : ONE);
163.1587 +
163.1588 + if (this.equals(ZERO) && exponent.signum >= 0)
163.1589 + return ZERO;
163.1590 +
163.1591 + if (this.equals(negConst[1]) && (!exponent.testBit(0)))
163.1592 + return (m.equals(ONE) ? ZERO : ONE);
163.1593 +
163.1594 + boolean invertResult;
163.1595 + if ((invertResult = (exponent.signum < 0)))
163.1596 + exponent = exponent.negate();
163.1597 +
163.1598 + BigInteger base = (this.signum < 0 || this.compareTo(m) >= 0
163.1599 + ? this.mod(m) : this);
163.1600 + BigInteger result;
163.1601 + if (m.testBit(0)) { // odd modulus
163.1602 + result = base.oddModPow(exponent, m);
163.1603 + } else {
163.1604 + /*
163.1605 + * Even modulus. Tear it into an "odd part" (m1) and power of two
163.1606 + * (m2), exponentiate mod m1, manually exponentiate mod m2, and
163.1607 + * use Chinese Remainder Theorem to combine results.
163.1608 + */
163.1609 +
163.1610 + // Tear m apart into odd part (m1) and power of 2 (m2)
163.1611 + int p = m.getLowestSetBit(); // Max pow of 2 that divides m
163.1612 +
163.1613 + BigInteger m1 = m.shiftRight(p); // m/2**p
163.1614 + BigInteger m2 = ONE.shiftLeft(p); // 2**p
163.1615 +
163.1616 + // Calculate new base from m1
163.1617 + BigInteger base2 = (this.signum < 0 || this.compareTo(m1) >= 0
163.1618 + ? this.mod(m1) : this);
163.1619 +
163.1620 + // Caculate (base ** exponent) mod m1.
163.1621 + BigInteger a1 = (m1.equals(ONE) ? ZERO :
163.1622 + base2.oddModPow(exponent, m1));
163.1623 +
163.1624 + // Calculate (this ** exponent) mod m2
163.1625 + BigInteger a2 = base.modPow2(exponent, p);
163.1626 +
163.1627 + // Combine results using Chinese Remainder Theorem
163.1628 + BigInteger y1 = m2.modInverse(m1);
163.1629 + BigInteger y2 = m1.modInverse(m2);
163.1630 +
163.1631 + result = a1.multiply(m2).multiply(y1).add
163.1632 + (a2.multiply(m1).multiply(y2)).mod(m);
163.1633 + }
163.1634 +
163.1635 + return (invertResult ? result.modInverse(m) : result);
163.1636 + }
163.1637 +
163.1638 + static int[] bnExpModThreshTable = {7, 25, 81, 241, 673, 1793,
163.1639 + Integer.MAX_VALUE}; // Sentinel
163.1640 +
163.1641 + /**
163.1642 + * Returns a BigInteger whose value is x to the power of y mod z.
163.1643 + * Assumes: z is odd && x < z.
163.1644 + */
163.1645 + private BigInteger oddModPow(BigInteger y, BigInteger z) {
163.1646 + /*
163.1647 + * The algorithm is adapted from Colin Plumb's C library.
163.1648 + *
163.1649 + * The window algorithm:
163.1650 + * The idea is to keep a running product of b1 = n^(high-order bits of exp)
163.1651 + * and then keep appending exponent bits to it. The following patterns
163.1652 + * apply to a 3-bit window (k = 3):
163.1653 + * To append 0: square
163.1654 + * To append 1: square, multiply by n^1
163.1655 + * To append 10: square, multiply by n^1, square
163.1656 + * To append 11: square, square, multiply by n^3
163.1657 + * To append 100: square, multiply by n^1, square, square
163.1658 + * To append 101: square, square, square, multiply by n^5
163.1659 + * To append 110: square, square, multiply by n^3, square
163.1660 + * To append 111: square, square, square, multiply by n^7
163.1661 + *
163.1662 + * Since each pattern involves only one multiply, the longer the pattern
163.1663 + * the better, except that a 0 (no multiplies) can be appended directly.
163.1664 + * We precompute a table of odd powers of n, up to 2^k, and can then
163.1665 + * multiply k bits of exponent at a time. Actually, assuming random
163.1666 + * exponents, there is on average one zero bit between needs to
163.1667 + * multiply (1/2 of the time there's none, 1/4 of the time there's 1,
163.1668 + * 1/8 of the time, there's 2, 1/32 of the time, there's 3, etc.), so
163.1669 + * you have to do one multiply per k+1 bits of exponent.
163.1670 + *
163.1671 + * The loop walks down the exponent, squaring the result buffer as
163.1672 + * it goes. There is a wbits+1 bit lookahead buffer, buf, that is
163.1673 + * filled with the upcoming exponent bits. (What is read after the
163.1674 + * end of the exponent is unimportant, but it is filled with zero here.)
163.1675 + * When the most-significant bit of this buffer becomes set, i.e.
163.1676 + * (buf & tblmask) != 0, we have to decide what pattern to multiply
163.1677 + * by, and when to do it. We decide, remember to do it in future
163.1678 + * after a suitable number of squarings have passed (e.g. a pattern
163.1679 + * of "100" in the buffer requires that we multiply by n^1 immediately;
163.1680 + * a pattern of "110" calls for multiplying by n^3 after one more
163.1681 + * squaring), clear the buffer, and continue.
163.1682 + *
163.1683 + * When we start, there is one more optimization: the result buffer
163.1684 + * is implcitly one, so squaring it or multiplying by it can be
163.1685 + * optimized away. Further, if we start with a pattern like "100"
163.1686 + * in the lookahead window, rather than placing n into the buffer
163.1687 + * and then starting to square it, we have already computed n^2
163.1688 + * to compute the odd-powers table, so we can place that into
163.1689 + * the buffer and save a squaring.
163.1690 + *
163.1691 + * This means that if you have a k-bit window, to compute n^z,
163.1692 + * where z is the high k bits of the exponent, 1/2 of the time
163.1693 + * it requires no squarings. 1/4 of the time, it requires 1
163.1694 + * squaring, ... 1/2^(k-1) of the time, it reqires k-2 squarings.
163.1695 + * And the remaining 1/2^(k-1) of the time, the top k bits are a
163.1696 + * 1 followed by k-1 0 bits, so it again only requires k-2
163.1697 + * squarings, not k-1. The average of these is 1. Add that
163.1698 + * to the one squaring we have to do to compute the table,
163.1699 + * and you'll see that a k-bit window saves k-2 squarings
163.1700 + * as well as reducing the multiplies. (It actually doesn't
163.1701 + * hurt in the case k = 1, either.)
163.1702 + */
163.1703 + // Special case for exponent of one
163.1704 + if (y.equals(ONE))
163.1705 + return this;
163.1706 +
163.1707 + // Special case for base of zero
163.1708 + if (signum==0)
163.1709 + return ZERO;
163.1710 +
163.1711 + int[] base = mag.clone();
163.1712 + int[] exp = y.mag;
163.1713 + int[] mod = z.mag;
163.1714 + int modLen = mod.length;
163.1715 +
163.1716 + // Select an appropriate window size
163.1717 + int wbits = 0;
163.1718 + int ebits = bitLength(exp, exp.length);
163.1719 + // if exponent is 65537 (0x10001), use minimum window size
163.1720 + if ((ebits != 17) || (exp[0] != 65537)) {
163.1721 + while (ebits > bnExpModThreshTable[wbits]) {
163.1722 + wbits++;
163.1723 + }
163.1724 + }
163.1725 +
163.1726 + // Calculate appropriate table size
163.1727 + int tblmask = 1 << wbits;
163.1728 +
163.1729 + // Allocate table for precomputed odd powers of base in Montgomery form
163.1730 + int[][] table = new int[tblmask][];
163.1731 + for (int i=0; i<tblmask; i++)
163.1732 + table[i] = new int[modLen];
163.1733 +
163.1734 + // Compute the modular inverse
163.1735 + int inv = -MutableBigInteger.inverseMod32(mod[modLen-1]);
163.1736 +
163.1737 + // Convert base to Montgomery form
163.1738 + int[] a = leftShift(base, base.length, modLen << 5);
163.1739 +
163.1740 + MutableBigInteger q = new MutableBigInteger(),
163.1741 + a2 = new MutableBigInteger(a),
163.1742 + b2 = new MutableBigInteger(mod);
163.1743 +
163.1744 + MutableBigInteger r= a2.divide(b2, q);
163.1745 + table[0] = r.toIntArray();
163.1746 +
163.1747 + // Pad table[0] with leading zeros so its length is at least modLen
163.1748 + if (table[0].length < modLen) {
163.1749 + int offset = modLen - table[0].length;
163.1750 + int[] t2 = new int[modLen];
163.1751 + for (int i=0; i<table[0].length; i++)
163.1752 + t2[i+offset] = table[0][i];
163.1753 + table[0] = t2;
163.1754 + }
163.1755 +
163.1756 + // Set b to the square of the base
163.1757 + int[] b = squareToLen(table[0], modLen, null);
163.1758 + b = montReduce(b, mod, modLen, inv);
163.1759 +
163.1760 + // Set t to high half of b
163.1761 + int[] t = new int[modLen];
163.1762 + for(int i=0; i<modLen; i++)
163.1763 + t[i] = b[i];
163.1764 +
163.1765 + // Fill in the table with odd powers of the base
163.1766 + for (int i=1; i<tblmask; i++) {
163.1767 + int[] prod = multiplyToLen(t, modLen, table[i-1], modLen, null);
163.1768 + table[i] = montReduce(prod, mod, modLen, inv);
163.1769 + }
163.1770 +
163.1771 + // Pre load the window that slides over the exponent
163.1772 + int bitpos = 1 << ((ebits-1) & (32-1));
163.1773 +
163.1774 + int buf = 0;
163.1775 + int elen = exp.length;
163.1776 + int eIndex = 0;
163.1777 + for (int i = 0; i <= wbits; i++) {
163.1778 + buf = (buf << 1) | (((exp[eIndex] & bitpos) != 0)?1:0);
163.1779 + bitpos >>>= 1;
163.1780 + if (bitpos == 0) {
163.1781 + eIndex++;
163.1782 + bitpos = 1 << (32-1);
163.1783 + elen--;
163.1784 + }
163.1785 + }
163.1786 +
163.1787 + int multpos = ebits;
163.1788 +
163.1789 + // The first iteration, which is hoisted out of the main loop
163.1790 + ebits--;
163.1791 + boolean isone = true;
163.1792 +
163.1793 + multpos = ebits - wbits;
163.1794 + while ((buf & 1) == 0) {
163.1795 + buf >>>= 1;
163.1796 + multpos++;
163.1797 + }
163.1798 +
163.1799 + int[] mult = table[buf >>> 1];
163.1800 +
163.1801 + buf = 0;
163.1802 + if (multpos == ebits)
163.1803 + isone = false;
163.1804 +
163.1805 + // The main loop
163.1806 + while(true) {
163.1807 + ebits--;
163.1808 + // Advance the window
163.1809 + buf <<= 1;
163.1810 +
163.1811 + if (elen != 0) {
163.1812 + buf |= ((exp[eIndex] & bitpos) != 0) ? 1 : 0;
163.1813 + bitpos >>>= 1;
163.1814 + if (bitpos == 0) {
163.1815 + eIndex++;
163.1816 + bitpos = 1 << (32-1);
163.1817 + elen--;
163.1818 + }
163.1819 + }
163.1820 +
163.1821 + // Examine the window for pending multiplies
163.1822 + if ((buf & tblmask) != 0) {
163.1823 + multpos = ebits - wbits;
163.1824 + while ((buf & 1) == 0) {
163.1825 + buf >>>= 1;
163.1826 + multpos++;
163.1827 + }
163.1828 + mult = table[buf >>> 1];
163.1829 + buf = 0;
163.1830 + }
163.1831 +
163.1832 + // Perform multiply
163.1833 + if (ebits == multpos) {
163.1834 + if (isone) {
163.1835 + b = mult.clone();
163.1836 + isone = false;
163.1837 + } else {
163.1838 + t = b;
163.1839 + a = multiplyToLen(t, modLen, mult, modLen, a);
163.1840 + a = montReduce(a, mod, modLen, inv);
163.1841 + t = a; a = b; b = t;
163.1842 + }
163.1843 + }
163.1844 +
163.1845 + // Check if done
163.1846 + if (ebits == 0)
163.1847 + break;
163.1848 +
163.1849 + // Square the input
163.1850 + if (!isone) {
163.1851 + t = b;
163.1852 + a = squareToLen(t, modLen, a);
163.1853 + a = montReduce(a, mod, modLen, inv);
163.1854 + t = a; a = b; b = t;
163.1855 + }
163.1856 + }
163.1857 +
163.1858 + // Convert result out of Montgomery form and return
163.1859 + int[] t2 = new int[2*modLen];
163.1860 + for(int i=0; i<modLen; i++)
163.1861 + t2[i+modLen] = b[i];
163.1862 +
163.1863 + b = montReduce(t2, mod, modLen, inv);
163.1864 +
163.1865 + t2 = new int[modLen];
163.1866 + for(int i=0; i<modLen; i++)
163.1867 + t2[i] = b[i];
163.1868 +
163.1869 + return new BigInteger(1, t2);
163.1870 + }
163.1871 +
163.1872 + /**
163.1873 + * Montgomery reduce n, modulo mod. This reduces modulo mod and divides
163.1874 + * by 2^(32*mlen). Adapted from Colin Plumb's C library.
163.1875 + */
163.1876 + private static int[] montReduce(int[] n, int[] mod, int mlen, int inv) {
163.1877 + int c=0;
163.1878 + int len = mlen;
163.1879 + int offset=0;
163.1880 +
163.1881 + do {
163.1882 + int nEnd = n[n.length-1-offset];
163.1883 + int carry = mulAdd(n, mod, offset, mlen, inv * nEnd);
163.1884 + c += addOne(n, offset, mlen, carry);
163.1885 + offset++;
163.1886 + } while(--len > 0);
163.1887 +
163.1888 + while(c>0)
163.1889 + c += subN(n, mod, mlen);
163.1890 +
163.1891 + while (intArrayCmpToLen(n, mod, mlen) >= 0)
163.1892 + subN(n, mod, mlen);
163.1893 +
163.1894 + return n;
163.1895 + }
163.1896 +
163.1897 +
163.1898 + /*
163.1899 + * Returns -1, 0 or +1 as big-endian unsigned int array arg1 is less than,
163.1900 + * equal to, or greater than arg2 up to length len.
163.1901 + */
163.1902 + private static int intArrayCmpToLen(int[] arg1, int[] arg2, int len) {
163.1903 + for (int i=0; i<len; i++) {
163.1904 + long b1 = arg1[i] & LONG_MASK;
163.1905 + long b2 = arg2[i] & LONG_MASK;
163.1906 + if (b1 < b2)
163.1907 + return -1;
163.1908 + if (b1 > b2)
163.1909 + return 1;
163.1910 + }
163.1911 + return 0;
163.1912 + }
163.1913 +
163.1914 + /**
163.1915 + * Subtracts two numbers of same length, returning borrow.
163.1916 + */
163.1917 + private static int subN(int[] a, int[] b, int len) {
163.1918 + long sum = 0;
163.1919 +
163.1920 + while(--len >= 0) {
163.1921 + sum = (a[len] & LONG_MASK) -
163.1922 + (b[len] & LONG_MASK) + (sum >> 32);
163.1923 + a[len] = (int)sum;
163.1924 + }
163.1925 +
163.1926 + return (int)(sum >> 32);
163.1927 + }
163.1928 +
163.1929 + /**
163.1930 + * Multiply an array by one word k and add to result, return the carry
163.1931 + */
163.1932 + static int mulAdd(int[] out, int[] in, int offset, int len, int k) {
163.1933 + long kLong = k & LONG_MASK;
163.1934 + long carry = 0;
163.1935 +
163.1936 + offset = out.length-offset - 1;
163.1937 + for (int j=len-1; j >= 0; j--) {
163.1938 + long product = (in[j] & LONG_MASK) * kLong +
163.1939 + (out[offset] & LONG_MASK) + carry;
163.1940 + out[offset--] = (int)product;
163.1941 + carry = product >>> 32;
163.1942 + }
163.1943 + return (int)carry;
163.1944 + }
163.1945 +
163.1946 + /**
163.1947 + * Add one word to the number a mlen words into a. Return the resulting
163.1948 + * carry.
163.1949 + */
163.1950 + static int addOne(int[] a, int offset, int mlen, int carry) {
163.1951 + offset = a.length-1-mlen-offset;
163.1952 + long t = (a[offset] & LONG_MASK) + (carry & LONG_MASK);
163.1953 +
163.1954 + a[offset] = (int)t;
163.1955 + if ((t >>> 32) == 0)
163.1956 + return 0;
163.1957 + while (--mlen >= 0) {
163.1958 + if (--offset < 0) { // Carry out of number
163.1959 + return 1;
163.1960 + } else {
163.1961 + a[offset]++;
163.1962 + if (a[offset] != 0)
163.1963 + return 0;
163.1964 + }
163.1965 + }
163.1966 + return 1;
163.1967 + }
163.1968 +
163.1969 + /**
163.1970 + * Returns a BigInteger whose value is (this ** exponent) mod (2**p)
163.1971 + */
163.1972 + private BigInteger modPow2(BigInteger exponent, int p) {
163.1973 + /*
163.1974 + * Perform exponentiation using repeated squaring trick, chopping off
163.1975 + * high order bits as indicated by modulus.
163.1976 + */
163.1977 + BigInteger result = valueOf(1);
163.1978 + BigInteger baseToPow2 = this.mod2(p);
163.1979 + int expOffset = 0;
163.1980 +
163.1981 + int limit = exponent.bitLength();
163.1982 +
163.1983 + if (this.testBit(0))
163.1984 + limit = (p-1) < limit ? (p-1) : limit;
163.1985 +
163.1986 + while (expOffset < limit) {
163.1987 + if (exponent.testBit(expOffset))
163.1988 + result = result.multiply(baseToPow2).mod2(p);
163.1989 + expOffset++;
163.1990 + if (expOffset < limit)
163.1991 + baseToPow2 = baseToPow2.square().mod2(p);
163.1992 + }
163.1993 +
163.1994 + return result;
163.1995 + }
163.1996 +
163.1997 + /**
163.1998 + * Returns a BigInteger whose value is this mod(2**p).
163.1999 + * Assumes that this {@code BigInteger >= 0} and {@code p > 0}.
163.2000 + */
163.2001 + private BigInteger mod2(int p) {
163.2002 + if (bitLength() <= p)
163.2003 + return this;
163.2004 +
163.2005 + // Copy remaining ints of mag
163.2006 + int numInts = (p + 31) >>> 5;
163.2007 + int[] mag = new int[numInts];
163.2008 + for (int i=0; i<numInts; i++)
163.2009 + mag[i] = this.mag[i + (this.mag.length - numInts)];
163.2010 +
163.2011 + // Mask out any excess bits
163.2012 + int excessBits = (numInts << 5) - p;
163.2013 + mag[0] &= (1L << (32-excessBits)) - 1;
163.2014 +
163.2015 + return (mag[0]==0 ? new BigInteger(1, mag) : new BigInteger(mag, 1));
163.2016 + }
163.2017 +
163.2018 + /**
163.2019 + * Returns a BigInteger whose value is {@code (this}<sup>-1</sup> {@code mod m)}.
163.2020 + *
163.2021 + * @param m the modulus.
163.2022 + * @return {@code this}<sup>-1</sup> {@code mod m}.
163.2023 + * @throws ArithmeticException {@code m} ≤ 0, or this BigInteger
163.2024 + * has no multiplicative inverse mod m (that is, this BigInteger
163.2025 + * is not <i>relatively prime</i> to m).
163.2026 + */
163.2027 + public BigInteger modInverse(BigInteger m) {
163.2028 + if (m.signum != 1)
163.2029 + throw new ArithmeticException("BigInteger: modulus not positive");
163.2030 +
163.2031 + if (m.equals(ONE))
163.2032 + return ZERO;
163.2033 +
163.2034 + // Calculate (this mod m)
163.2035 + BigInteger modVal = this;
163.2036 + if (signum < 0 || (this.compareMagnitude(m) >= 0))
163.2037 + modVal = this.mod(m);
163.2038 +
163.2039 + if (modVal.equals(ONE))
163.2040 + return ONE;
163.2041 +
163.2042 + MutableBigInteger a = new MutableBigInteger(modVal);
163.2043 + MutableBigInteger b = new MutableBigInteger(m);
163.2044 +
163.2045 + MutableBigInteger result = a.mutableModInverse(b);
163.2046 + return result.toBigInteger(1);
163.2047 + }
163.2048 +
163.2049 + // Shift Operations
163.2050 +
163.2051 + /**
163.2052 + * Returns a BigInteger whose value is {@code (this << n)}.
163.2053 + * The shift distance, {@code n}, may be negative, in which case
163.2054 + * this method performs a right shift.
163.2055 + * (Computes <tt>floor(this * 2<sup>n</sup>)</tt>.)
163.2056 + *
163.2057 + * @param n shift distance, in bits.
163.2058 + * @return {@code this << n}
163.2059 + * @throws ArithmeticException if the shift distance is {@code
163.2060 + * Integer.MIN_VALUE}.
163.2061 + * @see #shiftRight
163.2062 + */
163.2063 + public BigInteger shiftLeft(int n) {
163.2064 + if (signum == 0)
163.2065 + return ZERO;
163.2066 + if (n==0)
163.2067 + return this;
163.2068 + if (n<0) {
163.2069 + if (n == Integer.MIN_VALUE) {
163.2070 + throw new ArithmeticException("Shift distance of Integer.MIN_VALUE not supported.");
163.2071 + } else {
163.2072 + return shiftRight(-n);
163.2073 + }
163.2074 + }
163.2075 +
163.2076 + int nInts = n >>> 5;
163.2077 + int nBits = n & 0x1f;
163.2078 + int magLen = mag.length;
163.2079 + int newMag[] = null;
163.2080 +
163.2081 + if (nBits == 0) {
163.2082 + newMag = new int[magLen + nInts];
163.2083 + for (int i=0; i<magLen; i++)
163.2084 + newMag[i] = mag[i];
163.2085 + } else {
163.2086 + int i = 0;
163.2087 + int nBits2 = 32 - nBits;
163.2088 + int highBits = mag[0] >>> nBits2;
163.2089 + if (highBits != 0) {
163.2090 + newMag = new int[magLen + nInts + 1];
163.2091 + newMag[i++] = highBits;
163.2092 + } else {
163.2093 + newMag = new int[magLen + nInts];
163.2094 + }
163.2095 + int j=0;
163.2096 + while (j < magLen-1)
163.2097 + newMag[i++] = mag[j++] << nBits | mag[j] >>> nBits2;
163.2098 + newMag[i] = mag[j] << nBits;
163.2099 + }
163.2100 +
163.2101 + return new BigInteger(newMag, signum);
163.2102 + }
163.2103 +
163.2104 + /**
163.2105 + * Returns a BigInteger whose value is {@code (this >> n)}. Sign
163.2106 + * extension is performed. The shift distance, {@code n}, may be
163.2107 + * negative, in which case this method performs a left shift.
163.2108 + * (Computes <tt>floor(this / 2<sup>n</sup>)</tt>.)
163.2109 + *
163.2110 + * @param n shift distance, in bits.
163.2111 + * @return {@code this >> n}
163.2112 + * @throws ArithmeticException if the shift distance is {@code
163.2113 + * Integer.MIN_VALUE}.
163.2114 + * @see #shiftLeft
163.2115 + */
163.2116 + public BigInteger shiftRight(int n) {
163.2117 + if (n==0)
163.2118 + return this;
163.2119 + if (n<0) {
163.2120 + if (n == Integer.MIN_VALUE) {
163.2121 + throw new ArithmeticException("Shift distance of Integer.MIN_VALUE not supported.");
163.2122 + } else {
163.2123 + return shiftLeft(-n);
163.2124 + }
163.2125 + }
163.2126 +
163.2127 + int nInts = n >>> 5;
163.2128 + int nBits = n & 0x1f;
163.2129 + int magLen = mag.length;
163.2130 + int newMag[] = null;
163.2131 +
163.2132 + // Special case: entire contents shifted off the end
163.2133 + if (nInts >= magLen)
163.2134 + return (signum >= 0 ? ZERO : negConst[1]);
163.2135 +
163.2136 + if (nBits == 0) {
163.2137 + int newMagLen = magLen - nInts;
163.2138 + newMag = new int[newMagLen];
163.2139 + for (int i=0; i<newMagLen; i++)
163.2140 + newMag[i] = mag[i];
163.2141 + } else {
163.2142 + int i = 0;
163.2143 + int highBits = mag[0] >>> nBits;
163.2144 + if (highBits != 0) {
163.2145 + newMag = new int[magLen - nInts];
163.2146 + newMag[i++] = highBits;
163.2147 + } else {
163.2148 + newMag = new int[magLen - nInts -1];
163.2149 + }
163.2150 +
163.2151 + int nBits2 = 32 - nBits;
163.2152 + int j=0;
163.2153 + while (j < magLen - nInts - 1)
163.2154 + newMag[i++] = (mag[j++] << nBits2) | (mag[j] >>> nBits);
163.2155 + }
163.2156 +
163.2157 + if (signum < 0) {
163.2158 + // Find out whether any one-bits were shifted off the end.
163.2159 + boolean onesLost = false;
163.2160 + for (int i=magLen-1, j=magLen-nInts; i>=j && !onesLost; i--)
163.2161 + onesLost = (mag[i] != 0);
163.2162 + if (!onesLost && nBits != 0)
163.2163 + onesLost = (mag[magLen - nInts - 1] << (32 - nBits) != 0);
163.2164 +
163.2165 + if (onesLost)
163.2166 + newMag = javaIncrement(newMag);
163.2167 + }
163.2168 +
163.2169 + return new BigInteger(newMag, signum);
163.2170 + }
163.2171 +
163.2172 + int[] javaIncrement(int[] val) {
163.2173 + int lastSum = 0;
163.2174 + for (int i=val.length-1; i >= 0 && lastSum == 0; i--)
163.2175 + lastSum = (val[i] += 1);
163.2176 + if (lastSum == 0) {
163.2177 + val = new int[val.length+1];
163.2178 + val[0] = 1;
163.2179 + }
163.2180 + return val;
163.2181 + }
163.2182 +
163.2183 + // Bitwise Operations
163.2184 +
163.2185 + /**
163.2186 + * Returns a BigInteger whose value is {@code (this & val)}. (This
163.2187 + * method returns a negative BigInteger if and only if this and val are
163.2188 + * both negative.)
163.2189 + *
163.2190 + * @param val value to be AND'ed with this BigInteger.
163.2191 + * @return {@code this & val}
163.2192 + */
163.2193 + public BigInteger and(BigInteger val) {
163.2194 + int[] result = new int[Math.max(intLength(), val.intLength())];
163.2195 + for (int i=0; i<result.length; i++)
163.2196 + result[i] = (getInt(result.length-i-1)
163.2197 + & val.getInt(result.length-i-1));
163.2198 +
163.2199 + return valueOf(result);
163.2200 + }
163.2201 +
163.2202 + /**
163.2203 + * Returns a BigInteger whose value is {@code (this | val)}. (This method
163.2204 + * returns a negative BigInteger if and only if either this or val is
163.2205 + * negative.)
163.2206 + *
163.2207 + * @param val value to be OR'ed with this BigInteger.
163.2208 + * @return {@code this | val}
163.2209 + */
163.2210 + public BigInteger or(BigInteger val) {
163.2211 + int[] result = new int[Math.max(intLength(), val.intLength())];
163.2212 + for (int i=0; i<result.length; i++)
163.2213 + result[i] = (getInt(result.length-i-1)
163.2214 + | val.getInt(result.length-i-1));
163.2215 +
163.2216 + return valueOf(result);
163.2217 + }
163.2218 +
163.2219 + /**
163.2220 + * Returns a BigInteger whose value is {@code (this ^ val)}. (This method
163.2221 + * returns a negative BigInteger if and only if exactly one of this and
163.2222 + * val are negative.)
163.2223 + *
163.2224 + * @param val value to be XOR'ed with this BigInteger.
163.2225 + * @return {@code this ^ val}
163.2226 + */
163.2227 + public BigInteger xor(BigInteger val) {
163.2228 + int[] result = new int[Math.max(intLength(), val.intLength())];
163.2229 + for (int i=0; i<result.length; i++)
163.2230 + result[i] = (getInt(result.length-i-1)
163.2231 + ^ val.getInt(result.length-i-1));
163.2232 +
163.2233 + return valueOf(result);
163.2234 + }
163.2235 +
163.2236 + /**
163.2237 + * Returns a BigInteger whose value is {@code (~this)}. (This method
163.2238 + * returns a negative value if and only if this BigInteger is
163.2239 + * non-negative.)
163.2240 + *
163.2241 + * @return {@code ~this}
163.2242 + */
163.2243 + public BigInteger not() {
163.2244 + int[] result = new int[intLength()];
163.2245 + for (int i=0; i<result.length; i++)
163.2246 + result[i] = ~getInt(result.length-i-1);
163.2247 +
163.2248 + return valueOf(result);
163.2249 + }
163.2250 +
163.2251 + /**
163.2252 + * Returns a BigInteger whose value is {@code (this & ~val)}. This
163.2253 + * method, which is equivalent to {@code and(val.not())}, is provided as
163.2254 + * a convenience for masking operations. (This method returns a negative
163.2255 + * BigInteger if and only if {@code this} is negative and {@code val} is
163.2256 + * positive.)
163.2257 + *
163.2258 + * @param val value to be complemented and AND'ed with this BigInteger.
163.2259 + * @return {@code this & ~val}
163.2260 + */
163.2261 + public BigInteger andNot(BigInteger val) {
163.2262 + int[] result = new int[Math.max(intLength(), val.intLength())];
163.2263 + for (int i=0; i<result.length; i++)
163.2264 + result[i] = (getInt(result.length-i-1)
163.2265 + & ~val.getInt(result.length-i-1));
163.2266 +
163.2267 + return valueOf(result);
163.2268 + }
163.2269 +
163.2270 +
163.2271 + // Single Bit Operations
163.2272 +
163.2273 + /**
163.2274 + * Returns {@code true} if and only if the designated bit is set.
163.2275 + * (Computes {@code ((this & (1<<n)) != 0)}.)
163.2276 + *
163.2277 + * @param n index of bit to test.
163.2278 + * @return {@code true} if and only if the designated bit is set.
163.2279 + * @throws ArithmeticException {@code n} is negative.
163.2280 + */
163.2281 + public boolean testBit(int n) {
163.2282 + if (n<0)
163.2283 + throw new ArithmeticException("Negative bit address");
163.2284 +
163.2285 + return (getInt(n >>> 5) & (1 << (n & 31))) != 0;
163.2286 + }
163.2287 +
163.2288 + /**
163.2289 + * Returns a BigInteger whose value is equivalent to this BigInteger
163.2290 + * with the designated bit set. (Computes {@code (this | (1<<n))}.)
163.2291 + *
163.2292 + * @param n index of bit to set.
163.2293 + * @return {@code this | (1<<n)}
163.2294 + * @throws ArithmeticException {@code n} is negative.
163.2295 + */
163.2296 + public BigInteger setBit(int n) {
163.2297 + if (n<0)
163.2298 + throw new ArithmeticException("Negative bit address");
163.2299 +
163.2300 + int intNum = n >>> 5;
163.2301 + int[] result = new int[Math.max(intLength(), intNum+2)];
163.2302 +
163.2303 + for (int i=0; i<result.length; i++)
163.2304 + result[result.length-i-1] = getInt(i);
163.2305 +
163.2306 + result[result.length-intNum-1] |= (1 << (n & 31));
163.2307 +
163.2308 + return valueOf(result);
163.2309 + }
163.2310 +
163.2311 + /**
163.2312 + * Returns a BigInteger whose value is equivalent to this BigInteger
163.2313 + * with the designated bit cleared.
163.2314 + * (Computes {@code (this & ~(1<<n))}.)
163.2315 + *
163.2316 + * @param n index of bit to clear.
163.2317 + * @return {@code this & ~(1<<n)}
163.2318 + * @throws ArithmeticException {@code n} is negative.
163.2319 + */
163.2320 + public BigInteger clearBit(int n) {
163.2321 + if (n<0)
163.2322 + throw new ArithmeticException("Negative bit address");
163.2323 +
163.2324 + int intNum = n >>> 5;
163.2325 + int[] result = new int[Math.max(intLength(), ((n + 1) >>> 5) + 1)];
163.2326 +
163.2327 + for (int i=0; i<result.length; i++)
163.2328 + result[result.length-i-1] = getInt(i);
163.2329 +
163.2330 + result[result.length-intNum-1] &= ~(1 << (n & 31));
163.2331 +
163.2332 + return valueOf(result);
163.2333 + }
163.2334 +
163.2335 + /**
163.2336 + * Returns a BigInteger whose value is equivalent to this BigInteger
163.2337 + * with the designated bit flipped.
163.2338 + * (Computes {@code (this ^ (1<<n))}.)
163.2339 + *
163.2340 + * @param n index of bit to flip.
163.2341 + * @return {@code this ^ (1<<n)}
163.2342 + * @throws ArithmeticException {@code n} is negative.
163.2343 + */
163.2344 + public BigInteger flipBit(int n) {
163.2345 + if (n<0)
163.2346 + throw new ArithmeticException("Negative bit address");
163.2347 +
163.2348 + int intNum = n >>> 5;
163.2349 + int[] result = new int[Math.max(intLength(), intNum+2)];
163.2350 +
163.2351 + for (int i=0; i<result.length; i++)
163.2352 + result[result.length-i-1] = getInt(i);
163.2353 +
163.2354 + result[result.length-intNum-1] ^= (1 << (n & 31));
163.2355 +
163.2356 + return valueOf(result);
163.2357 + }
163.2358 +
163.2359 + /**
163.2360 + * Returns the index of the rightmost (lowest-order) one bit in this
163.2361 + * BigInteger (the number of zero bits to the right of the rightmost
163.2362 + * one bit). Returns -1 if this BigInteger contains no one bits.
163.2363 + * (Computes {@code (this==0? -1 : log2(this & -this))}.)
163.2364 + *
163.2365 + * @return index of the rightmost one bit in this BigInteger.
163.2366 + */
163.2367 + public int getLowestSetBit() {
163.2368 + @SuppressWarnings("deprecation") int lsb = lowestSetBit - 2;
163.2369 + if (lsb == -2) { // lowestSetBit not initialized yet
163.2370 + lsb = 0;
163.2371 + if (signum == 0) {
163.2372 + lsb -= 1;
163.2373 + } else {
163.2374 + // Search for lowest order nonzero int
163.2375 + int i,b;
163.2376 + for (i=0; (b = getInt(i))==0; i++)
163.2377 + ;
163.2378 + lsb += (i << 5) + Integer.numberOfTrailingZeros(b);
163.2379 + }
163.2380 + lowestSetBit = lsb + 2;
163.2381 + }
163.2382 + return lsb;
163.2383 + }
163.2384 +
163.2385 +
163.2386 + // Miscellaneous Bit Operations
163.2387 +
163.2388 + /**
163.2389 + * Returns the number of bits in the minimal two's-complement
163.2390 + * representation of this BigInteger, <i>excluding</i> a sign bit.
163.2391 + * For positive BigIntegers, this is equivalent to the number of bits in
163.2392 + * the ordinary binary representation. (Computes
163.2393 + * {@code (ceil(log2(this < 0 ? -this : this+1)))}.)
163.2394 + *
163.2395 + * @return number of bits in the minimal two's-complement
163.2396 + * representation of this BigInteger, <i>excluding</i> a sign bit.
163.2397 + */
163.2398 + public int bitLength() {
163.2399 + @SuppressWarnings("deprecation") int n = bitLength - 1;
163.2400 + if (n == -1) { // bitLength not initialized yet
163.2401 + int[] m = mag;
163.2402 + int len = m.length;
163.2403 + if (len == 0) {
163.2404 + n = 0; // offset by one to initialize
163.2405 + } else {
163.2406 + // Calculate the bit length of the magnitude
163.2407 + int magBitLength = ((len - 1) << 5) + bitLengthForInt(mag[0]);
163.2408 + if (signum < 0) {
163.2409 + // Check if magnitude is a power of two
163.2410 + boolean pow2 = (Integer.bitCount(mag[0]) == 1);
163.2411 + for(int i=1; i< len && pow2; i++)
163.2412 + pow2 = (mag[i] == 0);
163.2413 +
163.2414 + n = (pow2 ? magBitLength -1 : magBitLength);
163.2415 + } else {
163.2416 + n = magBitLength;
163.2417 + }
163.2418 + }
163.2419 + bitLength = n + 1;
163.2420 + }
163.2421 + return n;
163.2422 + }
163.2423 +
163.2424 + /**
163.2425 + * Returns the number of bits in the two's complement representation
163.2426 + * of this BigInteger that differ from its sign bit. This method is
163.2427 + * useful when implementing bit-vector style sets atop BigIntegers.
163.2428 + *
163.2429 + * @return number of bits in the two's complement representation
163.2430 + * of this BigInteger that differ from its sign bit.
163.2431 + */
163.2432 + public int bitCount() {
163.2433 + @SuppressWarnings("deprecation") int bc = bitCount - 1;
163.2434 + if (bc == -1) { // bitCount not initialized yet
163.2435 + bc = 0; // offset by one to initialize
163.2436 + // Count the bits in the magnitude
163.2437 + for (int i=0; i<mag.length; i++)
163.2438 + bc += Integer.bitCount(mag[i]);
163.2439 + if (signum < 0) {
163.2440 + // Count the trailing zeros in the magnitude
163.2441 + int magTrailingZeroCount = 0, j;
163.2442 + for (j=mag.length-1; mag[j]==0; j--)
163.2443 + magTrailingZeroCount += 32;
163.2444 + magTrailingZeroCount += Integer.numberOfTrailingZeros(mag[j]);
163.2445 + bc += magTrailingZeroCount - 1;
163.2446 + }
163.2447 + bitCount = bc + 1;
163.2448 + }
163.2449 + return bc;
163.2450 + }
163.2451 +
163.2452 + // Primality Testing
163.2453 +
163.2454 + /**
163.2455 + * Returns {@code true} if this BigInteger is probably prime,
163.2456 + * {@code false} if it's definitely composite. If
163.2457 + * {@code certainty} is ≤ 0, {@code true} is
163.2458 + * returned.
163.2459 + *
163.2460 + * @param certainty a measure of the uncertainty that the caller is
163.2461 + * willing to tolerate: if the call returns {@code true}
163.2462 + * the probability that this BigInteger is prime exceeds
163.2463 + * (1 - 1/2<sup>{@code certainty}</sup>). The execution time of
163.2464 + * this method is proportional to the value of this parameter.
163.2465 + * @return {@code true} if this BigInteger is probably prime,
163.2466 + * {@code false} if it's definitely composite.
163.2467 + */
163.2468 + public boolean isProbablePrime(int certainty) {
163.2469 + if (certainty <= 0)
163.2470 + return true;
163.2471 + BigInteger w = this.abs();
163.2472 + if (w.equals(TWO))
163.2473 + return true;
163.2474 + if (!w.testBit(0) || w.equals(ONE))
163.2475 + return false;
163.2476 +
163.2477 + return w.primeToCertainty(certainty, null);
163.2478 + }
163.2479 +
163.2480 + // Comparison Operations
163.2481 +
163.2482 + /**
163.2483 + * Compares this BigInteger with the specified BigInteger. This
163.2484 + * method is provided in preference to individual methods for each
163.2485 + * of the six boolean comparison operators ({@literal <}, ==,
163.2486 + * {@literal >}, {@literal >=}, !=, {@literal <=}). The suggested
163.2487 + * idiom for performing these comparisons is: {@code
163.2488 + * (x.compareTo(y)} <<i>op</i>> {@code 0)}, where
163.2489 + * <<i>op</i>> is one of the six comparison operators.
163.2490 + *
163.2491 + * @param val BigInteger to which this BigInteger is to be compared.
163.2492 + * @return -1, 0 or 1 as this BigInteger is numerically less than, equal
163.2493 + * to, or greater than {@code val}.
163.2494 + */
163.2495 + public int compareTo(BigInteger val) {
163.2496 + if (signum == val.signum) {
163.2497 + switch (signum) {
163.2498 + case 1:
163.2499 + return compareMagnitude(val);
163.2500 + case -1:
163.2501 + return val.compareMagnitude(this);
163.2502 + default:
163.2503 + return 0;
163.2504 + }
163.2505 + }
163.2506 + return signum > val.signum ? 1 : -1;
163.2507 + }
163.2508 +
163.2509 + /**
163.2510 + * Compares the magnitude array of this BigInteger with the specified
163.2511 + * BigInteger's. This is the version of compareTo ignoring sign.
163.2512 + *
163.2513 + * @param val BigInteger whose magnitude array to be compared.
163.2514 + * @return -1, 0 or 1 as this magnitude array is less than, equal to or
163.2515 + * greater than the magnitude aray for the specified BigInteger's.
163.2516 + */
163.2517 + final int compareMagnitude(BigInteger val) {
163.2518 + int[] m1 = mag;
163.2519 + int len1 = m1.length;
163.2520 + int[] m2 = val.mag;
163.2521 + int len2 = m2.length;
163.2522 + if (len1 < len2)
163.2523 + return -1;
163.2524 + if (len1 > len2)
163.2525 + return 1;
163.2526 + for (int i = 0; i < len1; i++) {
163.2527 + int a = m1[i];
163.2528 + int b = m2[i];
163.2529 + if (a != b)
163.2530 + return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
163.2531 + }
163.2532 + return 0;
163.2533 + }
163.2534 +
163.2535 + /**
163.2536 + * Compares this BigInteger with the specified Object for equality.
163.2537 + *
163.2538 + * @param x Object to which this BigInteger is to be compared.
163.2539 + * @return {@code true} if and only if the specified Object is a
163.2540 + * BigInteger whose value is numerically equal to this BigInteger.
163.2541 + */
163.2542 + public boolean equals(Object x) {
163.2543 + // This test is just an optimization, which may or may not help
163.2544 + if (x == this)
163.2545 + return true;
163.2546 +
163.2547 + if (!(x instanceof BigInteger))
163.2548 + return false;
163.2549 +
163.2550 + BigInteger xInt = (BigInteger) x;
163.2551 + if (xInt.signum != signum)
163.2552 + return false;
163.2553 +
163.2554 + int[] m = mag;
163.2555 + int len = m.length;
163.2556 + int[] xm = xInt.mag;
163.2557 + if (len != xm.length)
163.2558 + return false;
163.2559 +
163.2560 + for (int i = 0; i < len; i++)
163.2561 + if (xm[i] != m[i])
163.2562 + return false;
163.2563 +
163.2564 + return true;
163.2565 + }
163.2566 +
163.2567 + /**
163.2568 + * Returns the minimum of this BigInteger and {@code val}.
163.2569 + *
163.2570 + * @param val value with which the minimum is to be computed.
163.2571 + * @return the BigInteger whose value is the lesser of this BigInteger and
163.2572 + * {@code val}. If they are equal, either may be returned.
163.2573 + */
163.2574 + public BigInteger min(BigInteger val) {
163.2575 + return (compareTo(val)<0 ? this : val);
163.2576 + }
163.2577 +
163.2578 + /**
163.2579 + * Returns the maximum of this BigInteger and {@code val}.
163.2580 + *
163.2581 + * @param val value with which the maximum is to be computed.
163.2582 + * @return the BigInteger whose value is the greater of this and
163.2583 + * {@code val}. If they are equal, either may be returned.
163.2584 + */
163.2585 + public BigInteger max(BigInteger val) {
163.2586 + return (compareTo(val)>0 ? this : val);
163.2587 + }
163.2588 +
163.2589 +
163.2590 + // Hash Function
163.2591 +
163.2592 + /**
163.2593 + * Returns the hash code for this BigInteger.
163.2594 + *
163.2595 + * @return hash code for this BigInteger.
163.2596 + */
163.2597 + public int hashCode() {
163.2598 + int hashCode = 0;
163.2599 +
163.2600 + for (int i=0; i<mag.length; i++)
163.2601 + hashCode = (int)(31*hashCode + (mag[i] & LONG_MASK));
163.2602 +
163.2603 + return hashCode * signum;
163.2604 + }
163.2605 +
163.2606 + /**
163.2607 + * Returns the String representation of this BigInteger in the
163.2608 + * given radix. If the radix is outside the range from {@link
163.2609 + * Character#MIN_RADIX} to {@link Character#MAX_RADIX} inclusive,
163.2610 + * it will default to 10 (as is the case for
163.2611 + * {@code Integer.toString}). The digit-to-character mapping
163.2612 + * provided by {@code Character.forDigit} is used, and a minus
163.2613 + * sign is prepended if appropriate. (This representation is
163.2614 + * compatible with the {@link #BigInteger(String, int) (String,
163.2615 + * int)} constructor.)
163.2616 + *
163.2617 + * @param radix radix of the String representation.
163.2618 + * @return String representation of this BigInteger in the given radix.
163.2619 + * @see Integer#toString
163.2620 + * @see Character#forDigit
163.2621 + * @see #BigInteger(java.lang.String, int)
163.2622 + */
163.2623 + public String toString(int radix) {
163.2624 + if (signum == 0)
163.2625 + return "0";
163.2626 + if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
163.2627 + radix = 10;
163.2628 +
163.2629 + // Compute upper bound on number of digit groups and allocate space
163.2630 + int maxNumDigitGroups = (4*mag.length + 6)/7;
163.2631 + String digitGroup[] = new String[maxNumDigitGroups];
163.2632 +
163.2633 + // Translate number to string, a digit group at a time
163.2634 + BigInteger tmp = this.abs();
163.2635 + int numGroups = 0;
163.2636 + while (tmp.signum != 0) {
163.2637 + BigInteger d = longRadix[radix];
163.2638 +
163.2639 + MutableBigInteger q = new MutableBigInteger(),
163.2640 + a = new MutableBigInteger(tmp.mag),
163.2641 + b = new MutableBigInteger(d.mag);
163.2642 + MutableBigInteger r = a.divide(b, q);
163.2643 + BigInteger q2 = q.toBigInteger(tmp.signum * d.signum);
163.2644 + BigInteger r2 = r.toBigInteger(tmp.signum * d.signum);
163.2645 +
163.2646 + digitGroup[numGroups++] = Long.toString(r2.longValue(), radix);
163.2647 + tmp = q2;
163.2648 + }
163.2649 +
163.2650 + // Put sign (if any) and first digit group into result buffer
163.2651 + StringBuilder buf = new StringBuilder(numGroups*digitsPerLong[radix]+1);
163.2652 + if (signum<0)
163.2653 + buf.append('-');
163.2654 + buf.append(digitGroup[numGroups-1]);
163.2655 +
163.2656 + // Append remaining digit groups padded with leading zeros
163.2657 + for (int i=numGroups-2; i>=0; i--) {
163.2658 + // Prepend (any) leading zeros for this digit group
163.2659 + int numLeadingZeros = digitsPerLong[radix]-digitGroup[i].length();
163.2660 + if (numLeadingZeros != 0)
163.2661 + buf.append(zeros[numLeadingZeros]);
163.2662 + buf.append(digitGroup[i]);
163.2663 + }
163.2664 + return buf.toString();
163.2665 + }
163.2666 +
163.2667 + /* zero[i] is a string of i consecutive zeros. */
163.2668 + private static String zeros[] = new String[64];
163.2669 + static {
163.2670 + zeros[63] =
163.2671 + "000000000000000000000000000000000000000000000000000000000000000";
163.2672 + for (int i=0; i<63; i++)
163.2673 + zeros[i] = zeros[63].substring(0, i);
163.2674 + }
163.2675 +
163.2676 + /**
163.2677 + * Returns the decimal String representation of this BigInteger.
163.2678 + * The digit-to-character mapping provided by
163.2679 + * {@code Character.forDigit} is used, and a minus sign is
163.2680 + * prepended if appropriate. (This representation is compatible
163.2681 + * with the {@link #BigInteger(String) (String)} constructor, and
163.2682 + * allows for String concatenation with Java's + operator.)
163.2683 + *
163.2684 + * @return decimal String representation of this BigInteger.
163.2685 + * @see Character#forDigit
163.2686 + * @see #BigInteger(java.lang.String)
163.2687 + */
163.2688 + public String toString() {
163.2689 + return toString(10);
163.2690 + }
163.2691 +
163.2692 + /**
163.2693 + * Returns a byte array containing the two's-complement
163.2694 + * representation of this BigInteger. The byte array will be in
163.2695 + * <i>big-endian</i> byte-order: the most significant byte is in
163.2696 + * the zeroth element. The array will contain the minimum number
163.2697 + * of bytes required to represent this BigInteger, including at
163.2698 + * least one sign bit, which is {@code (ceil((this.bitLength() +
163.2699 + * 1)/8))}. (This representation is compatible with the
163.2700 + * {@link #BigInteger(byte[]) (byte[])} constructor.)
163.2701 + *
163.2702 + * @return a byte array containing the two's-complement representation of
163.2703 + * this BigInteger.
163.2704 + * @see #BigInteger(byte[])
163.2705 + */
163.2706 + public byte[] toByteArray() {
163.2707 + int byteLen = bitLength()/8 + 1;
163.2708 + byte[] byteArray = new byte[byteLen];
163.2709 +
163.2710 + for (int i=byteLen-1, bytesCopied=4, nextInt=0, intIndex=0; i>=0; i--) {
163.2711 + if (bytesCopied == 4) {
163.2712 + nextInt = getInt(intIndex++);
163.2713 + bytesCopied = 1;
163.2714 + } else {
163.2715 + nextInt >>>= 8;
163.2716 + bytesCopied++;
163.2717 + }
163.2718 + byteArray[i] = (byte)nextInt;
163.2719 + }
163.2720 + return byteArray;
163.2721 + }
163.2722 +
163.2723 + /**
163.2724 + * Converts this BigInteger to an {@code int}. This
163.2725 + * conversion is analogous to a
163.2726 + * <i>narrowing primitive conversion</i> from {@code long} to
163.2727 + * {@code int} as defined in section 5.1.3 of
163.2728 + * <cite>The Java™ Language Specification</cite>:
163.2729 + * if this BigInteger is too big to fit in an
163.2730 + * {@code int}, only the low-order 32 bits are returned.
163.2731 + * Note that this conversion can lose information about the
163.2732 + * overall magnitude of the BigInteger value as well as return a
163.2733 + * result with the opposite sign.
163.2734 + *
163.2735 + * @return this BigInteger converted to an {@code int}.
163.2736 + */
163.2737 + public int intValue() {
163.2738 + int result = 0;
163.2739 + result = getInt(0);
163.2740 + return result;
163.2741 + }
163.2742 +
163.2743 + /**
163.2744 + * Converts this BigInteger to a {@code long}. This
163.2745 + * conversion is analogous to a
163.2746 + * <i>narrowing primitive conversion</i> from {@code long} to
163.2747 + * {@code int} as defined in section 5.1.3 of
163.2748 + * <cite>The Java™ Language Specification</cite>:
163.2749 + * if this BigInteger is too big to fit in a
163.2750 + * {@code long}, only the low-order 64 bits are returned.
163.2751 + * Note that this conversion can lose information about the
163.2752 + * overall magnitude of the BigInteger value as well as return a
163.2753 + * result with the opposite sign.
163.2754 + *
163.2755 + * @return this BigInteger converted to a {@code long}.
163.2756 + */
163.2757 + public long longValue() {
163.2758 + long result = 0;
163.2759 +
163.2760 + for (int i=1; i>=0; i--)
163.2761 + result = (result << 32) + (getInt(i) & LONG_MASK);
163.2762 + return result;
163.2763 + }
163.2764 +
163.2765 + /**
163.2766 + * Converts this BigInteger to a {@code float}. This
163.2767 + * conversion is similar to the
163.2768 + * <i>narrowing primitive conversion</i> from {@code double} to
163.2769 + * {@code float} as defined in section 5.1.3 of
163.2770 + * <cite>The Java™ Language Specification</cite>:
163.2771 + * if this BigInteger has too great a magnitude
163.2772 + * to represent as a {@code float}, it will be converted to
163.2773 + * {@link Float#NEGATIVE_INFINITY} or {@link
163.2774 + * Float#POSITIVE_INFINITY} as appropriate. Note that even when
163.2775 + * the return value is finite, this conversion can lose
163.2776 + * information about the precision of the BigInteger value.
163.2777 + *
163.2778 + * @return this BigInteger converted to a {@code float}.
163.2779 + */
163.2780 + public float floatValue() {
163.2781 + // Somewhat inefficient, but guaranteed to work.
163.2782 + return Float.parseFloat(this.toString());
163.2783 + }
163.2784 +
163.2785 + /**
163.2786 + * Converts this BigInteger to a {@code double}. This
163.2787 + * conversion is similar to the
163.2788 + * <i>narrowing primitive conversion</i> from {@code double} to
163.2789 + * {@code float} as defined in section 5.1.3 of
163.2790 + * <cite>The Java™ Language Specification</cite>:
163.2791 + * if this BigInteger has too great a magnitude
163.2792 + * to represent as a {@code double}, it will be converted to
163.2793 + * {@link Double#NEGATIVE_INFINITY} or {@link
163.2794 + * Double#POSITIVE_INFINITY} as appropriate. Note that even when
163.2795 + * the return value is finite, this conversion can lose
163.2796 + * information about the precision of the BigInteger value.
163.2797 + *
163.2798 + * @return this BigInteger converted to a {@code double}.
163.2799 + */
163.2800 + public double doubleValue() {
163.2801 + // Somewhat inefficient, but guaranteed to work.
163.2802 + return Double.parseDouble(this.toString());
163.2803 + }
163.2804 +
163.2805 + /**
163.2806 + * Returns a copy of the input array stripped of any leading zero bytes.
163.2807 + */
163.2808 + private static int[] stripLeadingZeroInts(int val[]) {
163.2809 + int vlen = val.length;
163.2810 + int keep;
163.2811 +
163.2812 + // Find first nonzero byte
163.2813 + for (keep = 0; keep < vlen && val[keep] == 0; keep++)
163.2814 + ;
163.2815 + return java.util.Arrays.copyOfRange(val, keep, vlen);
163.2816 + }
163.2817 +
163.2818 + /**
163.2819 + * Returns the input array stripped of any leading zero bytes.
163.2820 + * Since the source is trusted the copying may be skipped.
163.2821 + */
163.2822 + private static int[] trustedStripLeadingZeroInts(int val[]) {
163.2823 + int vlen = val.length;
163.2824 + int keep;
163.2825 +
163.2826 + // Find first nonzero byte
163.2827 + for (keep = 0; keep < vlen && val[keep] == 0; keep++)
163.2828 + ;
163.2829 + return keep == 0 ? val : java.util.Arrays.copyOfRange(val, keep, vlen);
163.2830 + }
163.2831 +
163.2832 + /**
163.2833 + * Returns a copy of the input array stripped of any leading zero bytes.
163.2834 + */
163.2835 + private static int[] stripLeadingZeroBytes(byte a[]) {
163.2836 + int byteLength = a.length;
163.2837 + int keep;
163.2838 +
163.2839 + // Find first nonzero byte
163.2840 + for (keep = 0; keep < byteLength && a[keep]==0; keep++)
163.2841 + ;
163.2842 +
163.2843 + // Allocate new array and copy relevant part of input array
163.2844 + int intLength = ((byteLength - keep) + 3) >>> 2;
163.2845 + int[] result = new int[intLength];
163.2846 + int b = byteLength - 1;
163.2847 + for (int i = intLength-1; i >= 0; i--) {
163.2848 + result[i] = a[b--] & 0xff;
163.2849 + int bytesRemaining = b - keep + 1;
163.2850 + int bytesToTransfer = Math.min(3, bytesRemaining);
163.2851 + for (int j=8; j <= (bytesToTransfer << 3); j += 8)
163.2852 + result[i] |= ((a[b--] & 0xff) << j);
163.2853 + }
163.2854 + return result;
163.2855 + }
163.2856 +
163.2857 + /**
163.2858 + * Takes an array a representing a negative 2's-complement number and
163.2859 + * returns the minimal (no leading zero bytes) unsigned whose value is -a.
163.2860 + */
163.2861 + private static int[] makePositive(byte a[]) {
163.2862 + int keep, k;
163.2863 + int byteLength = a.length;
163.2864 +
163.2865 + // Find first non-sign (0xff) byte of input
163.2866 + for (keep=0; keep<byteLength && a[keep]==-1; keep++)
163.2867 + ;
163.2868 +
163.2869 +
163.2870 + /* Allocate output array. If all non-sign bytes are 0x00, we must
163.2871 + * allocate space for one extra output byte. */
163.2872 + for (k=keep; k<byteLength && a[k]==0; k++)
163.2873 + ;
163.2874 +
163.2875 + int extraByte = (k==byteLength) ? 1 : 0;
163.2876 + int intLength = ((byteLength - keep + extraByte) + 3)/4;
163.2877 + int result[] = new int[intLength];
163.2878 +
163.2879 + /* Copy one's complement of input into output, leaving extra
163.2880 + * byte (if it exists) == 0x00 */
163.2881 + int b = byteLength - 1;
163.2882 + for (int i = intLength-1; i >= 0; i--) {
163.2883 + result[i] = a[b--] & 0xff;
163.2884 + int numBytesToTransfer = Math.min(3, b-keep+1);
163.2885 + if (numBytesToTransfer < 0)
163.2886 + numBytesToTransfer = 0;
163.2887 + for (int j=8; j <= 8*numBytesToTransfer; j += 8)
163.2888 + result[i] |= ((a[b--] & 0xff) << j);
163.2889 +
163.2890 + // Mask indicates which bits must be complemented
163.2891 + int mask = -1 >>> (8*(3-numBytesToTransfer));
163.2892 + result[i] = ~result[i] & mask;
163.2893 + }
163.2894 +
163.2895 + // Add one to one's complement to generate two's complement
163.2896 + for (int i=result.length-1; i>=0; i--) {
163.2897 + result[i] = (int)((result[i] & LONG_MASK) + 1);
163.2898 + if (result[i] != 0)
163.2899 + break;
163.2900 + }
163.2901 +
163.2902 + return result;
163.2903 + }
163.2904 +
163.2905 + /**
163.2906 + * Takes an array a representing a negative 2's-complement number and
163.2907 + * returns the minimal (no leading zero ints) unsigned whose value is -a.
163.2908 + */
163.2909 + private static int[] makePositive(int a[]) {
163.2910 + int keep, j;
163.2911 +
163.2912 + // Find first non-sign (0xffffffff) int of input
163.2913 + for (keep=0; keep<a.length && a[keep]==-1; keep++)
163.2914 + ;
163.2915 +
163.2916 + /* Allocate output array. If all non-sign ints are 0x00, we must
163.2917 + * allocate space for one extra output int. */
163.2918 + for (j=keep; j<a.length && a[j]==0; j++)
163.2919 + ;
163.2920 + int extraInt = (j==a.length ? 1 : 0);
163.2921 + int result[] = new int[a.length - keep + extraInt];
163.2922 +
163.2923 + /* Copy one's complement of input into output, leaving extra
163.2924 + * int (if it exists) == 0x00 */
163.2925 + for (int i = keep; i<a.length; i++)
163.2926 + result[i - keep + extraInt] = ~a[i];
163.2927 +
163.2928 + // Add one to one's complement to generate two's complement
163.2929 + for (int i=result.length-1; ++result[i]==0; i--)
163.2930 + ;
163.2931 +
163.2932 + return result;
163.2933 + }
163.2934 +
163.2935 + /*
163.2936 + * The following two arrays are used for fast String conversions. Both
163.2937 + * are indexed by radix. The first is the number of digits of the given
163.2938 + * radix that can fit in a Java long without "going negative", i.e., the
163.2939 + * highest integer n such that radix**n < 2**63. The second is the
163.2940 + * "long radix" that tears each number into "long digits", each of which
163.2941 + * consists of the number of digits in the corresponding element in
163.2942 + * digitsPerLong (longRadix[i] = i**digitPerLong[i]). Both arrays have
163.2943 + * nonsense values in their 0 and 1 elements, as radixes 0 and 1 are not
163.2944 + * used.
163.2945 + */
163.2946 + private static int digitsPerLong[] = {0, 0,
163.2947 + 62, 39, 31, 27, 24, 22, 20, 19, 18, 18, 17, 17, 16, 16, 15, 15, 15, 14,
163.2948 + 14, 14, 14, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12};
163.2949 +
163.2950 + private static BigInteger longRadix[] = {null, null,
163.2951 + valueOf(0x4000000000000000L), valueOf(0x383d9170b85ff80bL),
163.2952 + valueOf(0x4000000000000000L), valueOf(0x6765c793fa10079dL),
163.2953 + valueOf(0x41c21cb8e1000000L), valueOf(0x3642798750226111L),
163.2954 + valueOf(0x1000000000000000L), valueOf(0x12bf307ae81ffd59L),
163.2955 + valueOf( 0xde0b6b3a7640000L), valueOf(0x4d28cb56c33fa539L),
163.2956 + valueOf(0x1eca170c00000000L), valueOf(0x780c7372621bd74dL),
163.2957 + valueOf(0x1e39a5057d810000L), valueOf(0x5b27ac993df97701L),
163.2958 + valueOf(0x1000000000000000L), valueOf(0x27b95e997e21d9f1L),
163.2959 + valueOf(0x5da0e1e53c5c8000L), valueOf( 0xb16a458ef403f19L),
163.2960 + valueOf(0x16bcc41e90000000L), valueOf(0x2d04b7fdd9c0ef49L),
163.2961 + valueOf(0x5658597bcaa24000L), valueOf( 0x6feb266931a75b7L),
163.2962 + valueOf( 0xc29e98000000000L), valueOf(0x14adf4b7320334b9L),
163.2963 + valueOf(0x226ed36478bfa000L), valueOf(0x383d9170b85ff80bL),
163.2964 + valueOf(0x5a3c23e39c000000L), valueOf( 0x4e900abb53e6b71L),
163.2965 + valueOf( 0x7600ec618141000L), valueOf( 0xaee5720ee830681L),
163.2966 + valueOf(0x1000000000000000L), valueOf(0x172588ad4f5f0981L),
163.2967 + valueOf(0x211e44f7d02c1000L), valueOf(0x2ee56725f06e5c71L),
163.2968 + valueOf(0x41c21cb8e1000000L)};
163.2969 +
163.2970 + /*
163.2971 + * These two arrays are the integer analogue of above.
163.2972 + */
163.2973 + private static int digitsPerInt[] = {0, 0, 30, 19, 15, 13, 11,
163.2974 + 11, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6,
163.2975 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5};
163.2976 +
163.2977 + private static int intRadix[] = {0, 0,
163.2978 + 0x40000000, 0x4546b3db, 0x40000000, 0x48c27395, 0x159fd800,
163.2979 + 0x75db9c97, 0x40000000, 0x17179149, 0x3b9aca00, 0xcc6db61,
163.2980 + 0x19a10000, 0x309f1021, 0x57f6c100, 0xa2f1b6f, 0x10000000,
163.2981 + 0x18754571, 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,
163.2982 + 0x6c20a40, 0x8d2d931, 0xb640000, 0xe8d4a51, 0x1269ae40,
163.2983 + 0x17179149, 0x1cb91000, 0x23744899, 0x2b73a840, 0x34e63b41,
163.2984 + 0x40000000, 0x4cfa3cc1, 0x5c13d840, 0x6d91b519, 0x39aa400
163.2985 + };
163.2986 +
163.2987 + /**
163.2988 + * These routines provide access to the two's complement representation
163.2989 + * of BigIntegers.
163.2990 + */
163.2991 +
163.2992 + /**
163.2993 + * Returns the length of the two's complement representation in ints,
163.2994 + * including space for at least one sign bit.
163.2995 + */
163.2996 + private int intLength() {
163.2997 + return (bitLength() >>> 5) + 1;
163.2998 + }
163.2999 +
163.3000 + /* Returns sign bit */
163.3001 + private int signBit() {
163.3002 + return signum < 0 ? 1 : 0;
163.3003 + }
163.3004 +
163.3005 + /* Returns an int of sign bits */
163.3006 + private int signInt() {
163.3007 + return signum < 0 ? -1 : 0;
163.3008 + }
163.3009 +
163.3010 + /**
163.3011 + * Returns the specified int of the little-endian two's complement
163.3012 + * representation (int 0 is the least significant). The int number can
163.3013 + * be arbitrarily high (values are logically preceded by infinitely many
163.3014 + * sign ints).
163.3015 + */
163.3016 + private int getInt(int n) {
163.3017 + if (n < 0)
163.3018 + return 0;
163.3019 + if (n >= mag.length)
163.3020 + return signInt();
163.3021 +
163.3022 + int magInt = mag[mag.length-n-1];
163.3023 +
163.3024 + return (signum >= 0 ? magInt :
163.3025 + (n <= firstNonzeroIntNum() ? -magInt : ~magInt));
163.3026 + }
163.3027 +
163.3028 + /**
163.3029 + * Returns the index of the int that contains the first nonzero int in the
163.3030 + * little-endian binary representation of the magnitude (int 0 is the
163.3031 + * least significant). If the magnitude is zero, return value is undefined.
163.3032 + */
163.3033 + private int firstNonzeroIntNum() {
163.3034 + int fn = firstNonzeroIntNum - 2;
163.3035 + if (fn == -2) { // firstNonzeroIntNum not initialized yet
163.3036 + fn = 0;
163.3037 +
163.3038 + // Search for the first nonzero int
163.3039 + int i;
163.3040 + int mlen = mag.length;
163.3041 + for (i = mlen - 1; i >= 0 && mag[i] == 0; i--)
163.3042 + ;
163.3043 + fn = mlen - i - 1;
163.3044 + firstNonzeroIntNum = fn + 2; // offset by two to initialize
163.3045 + }
163.3046 + return fn;
163.3047 + }
163.3048 +
163.3049 + /** use serialVersionUID from JDK 1.1. for interoperability */
163.3050 + private static final long serialVersionUID = -8287574255936472291L;
163.3051 +
163.3052 + /**
163.3053 + * Serializable fields for BigInteger.
163.3054 + *
163.3055 + * @serialField signum int
163.3056 + * signum of this BigInteger.
163.3057 + * @serialField magnitude int[]
163.3058 + * magnitude array of this BigInteger.
163.3059 + * @serialField bitCount int
163.3060 + * number of bits in this BigInteger
163.3061 + * @serialField bitLength int
163.3062 + * the number of bits in the minimal two's-complement
163.3063 + * representation of this BigInteger
163.3064 + * @serialField lowestSetBit int
163.3065 + * lowest set bit in the twos complement representation
163.3066 + */
163.3067 + private static final ObjectStreamField[] serialPersistentFields = {
163.3068 + new ObjectStreamField("signum", Integer.TYPE),
163.3069 + new ObjectStreamField("magnitude", byte[].class),
163.3070 + new ObjectStreamField("bitCount", Integer.TYPE),
163.3071 + new ObjectStreamField("bitLength", Integer.TYPE),
163.3072 + new ObjectStreamField("firstNonzeroByteNum", Integer.TYPE),
163.3073 + new ObjectStreamField("lowestSetBit", Integer.TYPE)
163.3074 + };
163.3075 +
163.3076 +
163.3077 +
163.3078 + /**
163.3079 + * Save the {@code BigInteger} instance to a stream.
163.3080 + * The magnitude of a BigInteger is serialized as a byte array for
163.3081 + * historical reasons.
163.3082 + *
163.3083 + * @serialData two necessary fields are written as well as obsolete
163.3084 + * fields for compatibility with older versions.
163.3085 + */
163.3086 + private void writeObject(ObjectOutputStream s) throws IOException {
163.3087 + // set the values of the Serializable fields
163.3088 + ObjectOutputStream.PutField fields = s.putFields();
163.3089 + fields.put("signum", signum);
163.3090 + fields.put("magnitude", magSerializedForm());
163.3091 + // The values written for cached fields are compatible with older
163.3092 + // versions, but are ignored in readObject so don't otherwise matter.
163.3093 + fields.put("bitCount", -1);
163.3094 + fields.put("bitLength", -1);
163.3095 + fields.put("lowestSetBit", -2);
163.3096 + fields.put("firstNonzeroByteNum", -2);
163.3097 +
163.3098 + // save them
163.3099 + s.writeFields();
163.3100 +}
163.3101 +
163.3102 + /**
163.3103 + * Returns the mag array as an array of bytes.
163.3104 + */
163.3105 + private byte[] magSerializedForm() {
163.3106 + int len = mag.length;
163.3107 +
163.3108 + int bitLen = (len == 0 ? 0 : ((len - 1) << 5) + bitLengthForInt(mag[0]));
163.3109 + int byteLen = (bitLen + 7) >>> 3;
163.3110 + byte[] result = new byte[byteLen];
163.3111 +
163.3112 + for (int i = byteLen - 1, bytesCopied = 4, intIndex = len - 1, nextInt = 0;
163.3113 + i>=0; i--) {
163.3114 + if (bytesCopied == 4) {
163.3115 + nextInt = mag[intIndex--];
163.3116 + bytesCopied = 1;
163.3117 + } else {
163.3118 + nextInt >>>= 8;
163.3119 + bytesCopied++;
163.3120 + }
163.3121 + result[i] = (byte)nextInt;
163.3122 + }
163.3123 + return result;
163.3124 + }
163.3125 +}
164.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
164.2 +++ b/rt/emul/compact/src/main/java/java/math/BitSieve.java Wed Apr 30 15:04:10 2014 +0200
164.3 @@ -0,0 +1,212 @@
164.4 +/*
164.5 + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
164.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
164.7 + *
164.8 + * This code is free software; you can redistribute it and/or modify it
164.9 + * under the terms of the GNU General Public License version 2 only, as
164.10 + * published by the Free Software Foundation. Oracle designates this
164.11 + * particular file as subject to the "Classpath" exception as provided
164.12 + * by Oracle in the LICENSE file that accompanied this code.
164.13 + *
164.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
164.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
164.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
164.17 + * version 2 for more details (a copy is included in the LICENSE file that
164.18 + * accompanied this code).
164.19 + *
164.20 + * You should have received a copy of the GNU General Public License version
164.21 + * 2 along with this work; if not, write to the Free Software Foundation,
164.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
164.23 + *
164.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
164.25 + * or visit www.oracle.com if you need additional information or have any
164.26 + * questions.
164.27 + */
164.28 +
164.29 +package java.math;
164.30 +
164.31 +/**
164.32 + * A simple bit sieve used for finding prime number candidates. Allows setting
164.33 + * and clearing of bits in a storage array. The size of the sieve is assumed to
164.34 + * be constant to reduce overhead. All the bits of a new bitSieve are zero, and
164.35 + * bits are removed from it by setting them.
164.36 + *
164.37 + * To reduce storage space and increase efficiency, no even numbers are
164.38 + * represented in the sieve (each bit in the sieve represents an odd number).
164.39 + * The relationship between the index of a bit and the number it represents is
164.40 + * given by
164.41 + * N = offset + (2*index + 1);
164.42 + * Where N is the integer represented by a bit in the sieve, offset is some
164.43 + * even integer offset indicating where the sieve begins, and index is the
164.44 + * index of a bit in the sieve array.
164.45 + *
164.46 + * @see BigInteger
164.47 + * @author Michael McCloskey
164.48 + * @since 1.3
164.49 + */
164.50 +class BitSieve {
164.51 + /**
164.52 + * Stores the bits in this bitSieve.
164.53 + */
164.54 + private long bits[];
164.55 +
164.56 + /**
164.57 + * Length is how many bits this sieve holds.
164.58 + */
164.59 + private int length;
164.60 +
164.61 + /**
164.62 + * A small sieve used to filter out multiples of small primes in a search
164.63 + * sieve.
164.64 + */
164.65 + private static BitSieve smallSieve = new BitSieve();
164.66 +
164.67 + /**
164.68 + * Construct a "small sieve" with a base of 0. This constructor is
164.69 + * used internally to generate the set of "small primes" whose multiples
164.70 + * are excluded from sieves generated by the main (package private)
164.71 + * constructor, BitSieve(BigInteger base, int searchLen). The length
164.72 + * of the sieve generated by this constructor was chosen for performance;
164.73 + * it controls a tradeoff between how much time is spent constructing
164.74 + * other sieves, and how much time is wasted testing composite candidates
164.75 + * for primality. The length was chosen experimentally to yield good
164.76 + * performance.
164.77 + */
164.78 + private BitSieve() {
164.79 + length = 150 * 64;
164.80 + bits = new long[(unitIndex(length - 1) + 1)];
164.81 +
164.82 + // Mark 1 as composite
164.83 + set(0);
164.84 + int nextIndex = 1;
164.85 + int nextPrime = 3;
164.86 +
164.87 + // Find primes and remove their multiples from sieve
164.88 + do {
164.89 + sieveSingle(length, nextIndex + nextPrime, nextPrime);
164.90 + nextIndex = sieveSearch(length, nextIndex + 1);
164.91 + nextPrime = 2*nextIndex + 1;
164.92 + } while((nextIndex > 0) && (nextPrime < length));
164.93 + }
164.94 +
164.95 + /**
164.96 + * Construct a bit sieve of searchLen bits used for finding prime number
164.97 + * candidates. The new sieve begins at the specified base, which must
164.98 + * be even.
164.99 + */
164.100 + BitSieve(BigInteger base, int searchLen) {
164.101 + /*
164.102 + * Candidates are indicated by clear bits in the sieve. As a candidates
164.103 + * nonprimality is calculated, a bit is set in the sieve to eliminate
164.104 + * it. To reduce storage space and increase efficiency, no even numbers
164.105 + * are represented in the sieve (each bit in the sieve represents an
164.106 + * odd number).
164.107 + */
164.108 + bits = new long[(unitIndex(searchLen-1) + 1)];
164.109 + length = searchLen;
164.110 + int start = 0;
164.111 +
164.112 + int step = smallSieve.sieveSearch(smallSieve.length, start);
164.113 + int convertedStep = (step *2) + 1;
164.114 +
164.115 + // Construct the large sieve at an even offset specified by base
164.116 + MutableBigInteger b = new MutableBigInteger(base);
164.117 + MutableBigInteger q = new MutableBigInteger();
164.118 + do {
164.119 + // Calculate base mod convertedStep
164.120 + start = b.divideOneWord(convertedStep, q);
164.121 +
164.122 + // Take each multiple of step out of sieve
164.123 + start = convertedStep - start;
164.124 + if (start%2 == 0)
164.125 + start += convertedStep;
164.126 + sieveSingle(searchLen, (start-1)/2, convertedStep);
164.127 +
164.128 + // Find next prime from small sieve
164.129 + step = smallSieve.sieveSearch(smallSieve.length, step+1);
164.130 + convertedStep = (step *2) + 1;
164.131 + } while (step > 0);
164.132 + }
164.133 +
164.134 + /**
164.135 + * Given a bit index return unit index containing it.
164.136 + */
164.137 + private static int unitIndex(int bitIndex) {
164.138 + return bitIndex >>> 6;
164.139 + }
164.140 +
164.141 + /**
164.142 + * Return a unit that masks the specified bit in its unit.
164.143 + */
164.144 + private static long bit(int bitIndex) {
164.145 + return 1L << (bitIndex & ((1<<6) - 1));
164.146 + }
164.147 +
164.148 + /**
164.149 + * Get the value of the bit at the specified index.
164.150 + */
164.151 + private boolean get(int bitIndex) {
164.152 + int unitIndex = unitIndex(bitIndex);
164.153 + return ((bits[unitIndex] & bit(bitIndex)) != 0);
164.154 + }
164.155 +
164.156 + /**
164.157 + * Set the bit at the specified index.
164.158 + */
164.159 + private void set(int bitIndex) {
164.160 + int unitIndex = unitIndex(bitIndex);
164.161 + bits[unitIndex] |= bit(bitIndex);
164.162 + }
164.163 +
164.164 + /**
164.165 + * This method returns the index of the first clear bit in the search
164.166 + * array that occurs at or after start. It will not search past the
164.167 + * specified limit. It returns -1 if there is no such clear bit.
164.168 + */
164.169 + private int sieveSearch(int limit, int start) {
164.170 + if (start >= limit)
164.171 + return -1;
164.172 +
164.173 + int index = start;
164.174 + do {
164.175 + if (!get(index))
164.176 + return index;
164.177 + index++;
164.178 + } while(index < limit-1);
164.179 + return -1;
164.180 + }
164.181 +
164.182 + /**
164.183 + * Sieve a single set of multiples out of the sieve. Begin to remove
164.184 + * multiples of the specified step starting at the specified start index,
164.185 + * up to the specified limit.
164.186 + */
164.187 + private void sieveSingle(int limit, int start, int step) {
164.188 + while(start < limit) {
164.189 + set(start);
164.190 + start += step;
164.191 + }
164.192 + }
164.193 +
164.194 + /**
164.195 + * Test probable primes in the sieve and return successful candidates.
164.196 + */
164.197 + BigInteger retrieve(BigInteger initValue, int certainty, java.util.Random random) {
164.198 + // Examine the sieve one long at a time to find possible primes
164.199 + int offset = 1;
164.200 + for (int i=0; i<bits.length; i++) {
164.201 + long nextLong = ~bits[i];
164.202 + for (int j=0; j<64; j++) {
164.203 + if ((nextLong & 1) == 1) {
164.204 + BigInteger candidate = initValue.add(
164.205 + BigInteger.valueOf(offset));
164.206 + if (candidate.primeToCertainty(certainty, random))
164.207 + return candidate;
164.208 + }
164.209 + nextLong >>>= 1;
164.210 + offset+=2;
164.211 + }
164.212 + }
164.213 + return null;
164.214 + }
164.215 +}
165.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
165.2 +++ b/rt/emul/compact/src/main/java/java/math/MathContext.java Wed Apr 30 15:04:10 2014 +0200
165.3 @@ -0,0 +1,326 @@
165.4 +/*
165.5 + * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
165.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
165.7 + *
165.8 + * This code is free software; you can redistribute it and/or modify it
165.9 + * under the terms of the GNU General Public License version 2 only, as
165.10 + * published by the Free Software Foundation. Oracle designates this
165.11 + * particular file as subject to the "Classpath" exception as provided
165.12 + * by Oracle in the LICENSE file that accompanied this code.
165.13 + *
165.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
165.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
165.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
165.17 + * version 2 for more details (a copy is included in the LICENSE file that
165.18 + * accompanied this code).
165.19 + *
165.20 + * You should have received a copy of the GNU General Public License version
165.21 + * 2 along with this work; if not, write to the Free Software Foundation,
165.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
165.23 + *
165.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
165.25 + * or visit www.oracle.com if you need additional information or have any
165.26 + * questions.
165.27 + */
165.28 +
165.29 +/*
165.30 + * Portions Copyright IBM Corporation, 1997, 2001. All Rights Reserved.
165.31 + */
165.32 +
165.33 +package java.math;
165.34 +import java.io.*;
165.35 +
165.36 +/**
165.37 + * Immutable objects which encapsulate the context settings which
165.38 + * describe certain rules for numerical operators, such as those
165.39 + * implemented by the {@link BigDecimal} class.
165.40 + *
165.41 + * <p>The base-independent settings are:
165.42 + * <ol>
165.43 + * <li>{@code precision}:
165.44 + * the number of digits to be used for an operation; results are
165.45 + * rounded to this precision
165.46 + *
165.47 + * <li>{@code roundingMode}:
165.48 + * a {@link RoundingMode} object which specifies the algorithm to be
165.49 + * used for rounding.
165.50 + * </ol>
165.51 + *
165.52 + * @see BigDecimal
165.53 + * @see RoundingMode
165.54 + * @author Mike Cowlishaw
165.55 + * @author Joseph D. Darcy
165.56 + * @since 1.5
165.57 + */
165.58 +
165.59 +public final class MathContext implements Serializable {
165.60 +
165.61 + /* ----- Constants ----- */
165.62 +
165.63 + // defaults for constructors
165.64 + private static final int DEFAULT_DIGITS = 9;
165.65 + private static final RoundingMode DEFAULT_ROUNDINGMODE = RoundingMode.HALF_UP;
165.66 + // Smallest values for digits (Maximum is Integer.MAX_VALUE)
165.67 + private static final int MIN_DIGITS = 0;
165.68 +
165.69 + // Serialization version
165.70 + private static final long serialVersionUID = 5579720004786848255L;
165.71 +
165.72 + /* ----- Public Properties ----- */
165.73 + /**
165.74 + * A {@code MathContext} object whose settings have the values
165.75 + * required for unlimited precision arithmetic.
165.76 + * The values of the settings are:
165.77 + * <code>
165.78 + * precision=0 roundingMode=HALF_UP
165.79 + * </code>
165.80 + */
165.81 + public static final MathContext UNLIMITED =
165.82 + new MathContext(0, RoundingMode.HALF_UP);
165.83 +
165.84 + /**
165.85 + * A {@code MathContext} object with a precision setting
165.86 + * matching the IEEE 754R Decimal32 format, 7 digits, and a
165.87 + * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
165.88 + * IEEE 754R default.
165.89 + */
165.90 + public static final MathContext DECIMAL32 =
165.91 + new MathContext(7, RoundingMode.HALF_EVEN);
165.92 +
165.93 + /**
165.94 + * A {@code MathContext} object with a precision setting
165.95 + * matching the IEEE 754R Decimal64 format, 16 digits, and a
165.96 + * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
165.97 + * IEEE 754R default.
165.98 + */
165.99 + public static final MathContext DECIMAL64 =
165.100 + new MathContext(16, RoundingMode.HALF_EVEN);
165.101 +
165.102 + /**
165.103 + * A {@code MathContext} object with a precision setting
165.104 + * matching the IEEE 754R Decimal128 format, 34 digits, and a
165.105 + * rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
165.106 + * IEEE 754R default.
165.107 + */
165.108 + public static final MathContext DECIMAL128 =
165.109 + new MathContext(34, RoundingMode.HALF_EVEN);
165.110 +
165.111 + /* ----- Shared Properties ----- */
165.112 + /**
165.113 + * The number of digits to be used for an operation. A value of 0
165.114 + * indicates that unlimited precision (as many digits as are
165.115 + * required) will be used. Note that leading zeros (in the
165.116 + * coefficient of a number) are never significant.
165.117 + *
165.118 + * <p>{@code precision} will always be non-negative.
165.119 + *
165.120 + * @serial
165.121 + */
165.122 + final int precision;
165.123 +
165.124 + /**
165.125 + * The rounding algorithm to be used for an operation.
165.126 + *
165.127 + * @see RoundingMode
165.128 + * @serial
165.129 + */
165.130 + final RoundingMode roundingMode;
165.131 +
165.132 + /* ----- Constructors ----- */
165.133 +
165.134 + /**
165.135 + * Constructs a new {@code MathContext} with the specified
165.136 + * precision and the {@link RoundingMode#HALF_UP HALF_UP} rounding
165.137 + * mode.
165.138 + *
165.139 + * @param setPrecision The non-negative {@code int} precision setting.
165.140 + * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
165.141 + * than zero.
165.142 + */
165.143 + public MathContext(int setPrecision) {
165.144 + this(setPrecision, DEFAULT_ROUNDINGMODE);
165.145 + return;
165.146 + }
165.147 +
165.148 + /**
165.149 + * Constructs a new {@code MathContext} with a specified
165.150 + * precision and rounding mode.
165.151 + *
165.152 + * @param setPrecision The non-negative {@code int} precision setting.
165.153 + * @param setRoundingMode The rounding mode to use.
165.154 + * @throws IllegalArgumentException if the {@code setPrecision} parameter is less
165.155 + * than zero.
165.156 + * @throws NullPointerException if the rounding mode argument is {@code null}
165.157 + */
165.158 + public MathContext(int setPrecision,
165.159 + RoundingMode setRoundingMode) {
165.160 + if (setPrecision < MIN_DIGITS)
165.161 + throw new IllegalArgumentException("Digits < 0");
165.162 + if (setRoundingMode == null)
165.163 + throw new NullPointerException("null RoundingMode");
165.164 +
165.165 + precision = setPrecision;
165.166 + roundingMode = setRoundingMode;
165.167 + return;
165.168 + }
165.169 +
165.170 + /**
165.171 + * Constructs a new {@code MathContext} from a string.
165.172 + *
165.173 + * The string must be in the same format as that produced by the
165.174 + * {@link #toString} method.
165.175 + *
165.176 + * <p>An {@code IllegalArgumentException} is thrown if the precision
165.177 + * section of the string is out of range ({@code < 0}) or the string is
165.178 + * not in the format created by the {@link #toString} method.
165.179 + *
165.180 + * @param val The string to be parsed
165.181 + * @throws IllegalArgumentException if the precision section is out of range
165.182 + * or of incorrect format
165.183 + * @throws NullPointerException if the argument is {@code null}
165.184 + */
165.185 + public MathContext(String val) {
165.186 + boolean bad = false;
165.187 + int setPrecision;
165.188 + if (val == null)
165.189 + throw new NullPointerException("null String");
165.190 + try { // any error here is a string format problem
165.191 + if (!val.startsWith("precision=")) throw new RuntimeException();
165.192 + int fence = val.indexOf(' '); // could be -1
165.193 + int off = 10; // where value starts
165.194 + setPrecision = Integer.parseInt(val.substring(10, fence));
165.195 +
165.196 + if (!val.startsWith("roundingMode=", fence+1))
165.197 + throw new RuntimeException();
165.198 + off = fence + 1 + 13;
165.199 + String str = val.substring(off, val.length());
165.200 + roundingMode = RoundingMode.valueOf(str);
165.201 + } catch (RuntimeException re) {
165.202 + throw new IllegalArgumentException("bad string format");
165.203 + }
165.204 +
165.205 + if (setPrecision < MIN_DIGITS)
165.206 + throw new IllegalArgumentException("Digits < 0");
165.207 + // the other parameters cannot be invalid if we got here
165.208 + precision = setPrecision;
165.209 + }
165.210 +
165.211 + /**
165.212 + * Returns the {@code precision} setting.
165.213 + * This value is always non-negative.
165.214 + *
165.215 + * @return an {@code int} which is the value of the {@code precision}
165.216 + * setting
165.217 + */
165.218 + public int getPrecision() {
165.219 + return precision;
165.220 + }
165.221 +
165.222 + /**
165.223 + * Returns the roundingMode setting.
165.224 + * This will be one of
165.225 + * {@link RoundingMode#CEILING},
165.226 + * {@link RoundingMode#DOWN},
165.227 + * {@link RoundingMode#FLOOR},
165.228 + * {@link RoundingMode#HALF_DOWN},
165.229 + * {@link RoundingMode#HALF_EVEN},
165.230 + * {@link RoundingMode#HALF_UP},
165.231 + * {@link RoundingMode#UNNECESSARY}, or
165.232 + * {@link RoundingMode#UP}.
165.233 + *
165.234 + * @return a {@code RoundingMode} object which is the value of the
165.235 + * {@code roundingMode} setting
165.236 + */
165.237 +
165.238 + public RoundingMode getRoundingMode() {
165.239 + return roundingMode;
165.240 + }
165.241 +
165.242 + /**
165.243 + * Compares this {@code MathContext} with the specified
165.244 + * {@code Object} for equality.
165.245 + *
165.246 + * @param x {@code Object} to which this {@code MathContext} is to
165.247 + * be compared.
165.248 + * @return {@code true} if and only if the specified {@code Object} is
165.249 + * a {@code MathContext} object which has exactly the same
165.250 + * settings as this object
165.251 + */
165.252 + public boolean equals(Object x){
165.253 + MathContext mc;
165.254 + if (!(x instanceof MathContext))
165.255 + return false;
165.256 + mc = (MathContext) x;
165.257 + return mc.precision == this.precision
165.258 + && mc.roundingMode == this.roundingMode; // no need for .equals()
165.259 + }
165.260 +
165.261 + /**
165.262 + * Returns the hash code for this {@code MathContext}.
165.263 + *
165.264 + * @return hash code for this {@code MathContext}
165.265 + */
165.266 + public int hashCode() {
165.267 + return this.precision + roundingMode.hashCode() * 59;
165.268 + }
165.269 +
165.270 + /**
165.271 + * Returns the string representation of this {@code MathContext}.
165.272 + * The {@code String} returned represents the settings of the
165.273 + * {@code MathContext} object as two space-delimited words
165.274 + * (separated by a single space character, <tt>'\u0020'</tt>,
165.275 + * and with no leading or trailing white space), as follows:
165.276 + * <ol>
165.277 + * <li>
165.278 + * The string {@code "precision="}, immediately followed
165.279 + * by the value of the precision setting as a numeric string as if
165.280 + * generated by the {@link Integer#toString(int) Integer.toString}
165.281 + * method.
165.282 + *
165.283 + * <li>
165.284 + * The string {@code "roundingMode="}, immediately
165.285 + * followed by the value of the {@code roundingMode} setting as a
165.286 + * word. This word will be the same as the name of the
165.287 + * corresponding public constant in the {@link RoundingMode}
165.288 + * enum.
165.289 + * </ol>
165.290 + * <p>
165.291 + * For example:
165.292 + * <pre>
165.293 + * precision=9 roundingMode=HALF_UP
165.294 + * </pre>
165.295 + *
165.296 + * Additional words may be appended to the result of
165.297 + * {@code toString} in the future if more properties are added to
165.298 + * this class.
165.299 + *
165.300 + * @return a {@code String} representing the context settings
165.301 + */
165.302 + public java.lang.String toString() {
165.303 + return "precision=" + precision + " " +
165.304 + "roundingMode=" + roundingMode.toString();
165.305 + }
165.306 +
165.307 + // Private methods
165.308 +
165.309 + /**
165.310 + * Reconstitute the {@code MathContext} instance from a stream (that is,
165.311 + * deserialize it).
165.312 + *
165.313 + * @param s the stream being read.
165.314 + */
165.315 + private void readObject(java.io.ObjectInputStream s)
165.316 + throws java.io.IOException, ClassNotFoundException {
165.317 + s.defaultReadObject(); // read in all fields
165.318 + // validate possibly bad fields
165.319 + if (precision < MIN_DIGITS) {
165.320 + String message = "MathContext: invalid digits in stream";
165.321 + throw new java.io.StreamCorruptedException(message);
165.322 + }
165.323 + if (roundingMode == null) {
165.324 + String message = "MathContext: null roundingMode in stream";
165.325 + throw new java.io.StreamCorruptedException(message);
165.326 + }
165.327 + }
165.328 +
165.329 +}
166.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
166.2 +++ b/rt/emul/compact/src/main/java/java/math/MutableBigInteger.java Wed Apr 30 15:04:10 2014 +0200
166.3 @@ -0,0 +1,1477 @@
166.4 +/*
166.5 + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
166.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
166.7 + *
166.8 + * This code is free software; you can redistribute it and/or modify it
166.9 + * under the terms of the GNU General Public License version 2 only, as
166.10 + * published by the Free Software Foundation. Oracle designates this
166.11 + * particular file as subject to the "Classpath" exception as provided
166.12 + * by Oracle in the LICENSE file that accompanied this code.
166.13 + *
166.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
166.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
166.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
166.17 + * version 2 for more details (a copy is included in the LICENSE file that
166.18 + * accompanied this code).
166.19 + *
166.20 + * You should have received a copy of the GNU General Public License version
166.21 + * 2 along with this work; if not, write to the Free Software Foundation,
166.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
166.23 + *
166.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
166.25 + * or visit www.oracle.com if you need additional information or have any
166.26 + * questions.
166.27 + */
166.28 +
166.29 +package java.math;
166.30 +
166.31 +/**
166.32 + * A class used to represent multiprecision integers that makes efficient
166.33 + * use of allocated space by allowing a number to occupy only part of
166.34 + * an array so that the arrays do not have to be reallocated as often.
166.35 + * When performing an operation with many iterations the array used to
166.36 + * hold a number is only reallocated when necessary and does not have to
166.37 + * be the same size as the number it represents. A mutable number allows
166.38 + * calculations to occur on the same number without having to create
166.39 + * a new number for every step of the calculation as occurs with
166.40 + * BigIntegers.
166.41 + *
166.42 + * @see BigInteger
166.43 + * @author Michael McCloskey
166.44 + * @since 1.3
166.45 + */
166.46 +
166.47 +import java.util.Arrays;
166.48 +
166.49 +import static java.math.BigInteger.LONG_MASK;
166.50 +import static java.math.BigDecimal.INFLATED;
166.51 +
166.52 +class MutableBigInteger {
166.53 + /**
166.54 + * Holds the magnitude of this MutableBigInteger in big endian order.
166.55 + * The magnitude may start at an offset into the value array, and it may
166.56 + * end before the length of the value array.
166.57 + */
166.58 + int[] value;
166.59 +
166.60 + /**
166.61 + * The number of ints of the value array that are currently used
166.62 + * to hold the magnitude of this MutableBigInteger. The magnitude starts
166.63 + * at an offset and offset + intLen may be less than value.length.
166.64 + */
166.65 + int intLen;
166.66 +
166.67 + /**
166.68 + * The offset into the value array where the magnitude of this
166.69 + * MutableBigInteger begins.
166.70 + */
166.71 + int offset = 0;
166.72 +
166.73 + // Constants
166.74 + /**
166.75 + * MutableBigInteger with one element value array with the value 1. Used by
166.76 + * BigDecimal divideAndRound to increment the quotient. Use this constant
166.77 + * only when the method is not going to modify this object.
166.78 + */
166.79 + static final MutableBigInteger ONE = new MutableBigInteger(1);
166.80 +
166.81 + // Constructors
166.82 +
166.83 + /**
166.84 + * The default constructor. An empty MutableBigInteger is created with
166.85 + * a one word capacity.
166.86 + */
166.87 + MutableBigInteger() {
166.88 + value = new int[1];
166.89 + intLen = 0;
166.90 + }
166.91 +
166.92 + /**
166.93 + * Construct a new MutableBigInteger with a magnitude specified by
166.94 + * the int val.
166.95 + */
166.96 + MutableBigInteger(int val) {
166.97 + value = new int[1];
166.98 + intLen = 1;
166.99 + value[0] = val;
166.100 + }
166.101 +
166.102 + /**
166.103 + * Construct a new MutableBigInteger with the specified value array
166.104 + * up to the length of the array supplied.
166.105 + */
166.106 + MutableBigInteger(int[] val) {
166.107 + value = val;
166.108 + intLen = val.length;
166.109 + }
166.110 +
166.111 + /**
166.112 + * Construct a new MutableBigInteger with a magnitude equal to the
166.113 + * specified BigInteger.
166.114 + */
166.115 + MutableBigInteger(BigInteger b) {
166.116 + intLen = b.mag.length;
166.117 + value = Arrays.copyOf(b.mag, intLen);
166.118 + }
166.119 +
166.120 + /**
166.121 + * Construct a new MutableBigInteger with a magnitude equal to the
166.122 + * specified MutableBigInteger.
166.123 + */
166.124 + MutableBigInteger(MutableBigInteger val) {
166.125 + intLen = val.intLen;
166.126 + value = Arrays.copyOfRange(val.value, val.offset, val.offset + intLen);
166.127 + }
166.128 +
166.129 + /**
166.130 + * Internal helper method to return the magnitude array. The caller is not
166.131 + * supposed to modify the returned array.
166.132 + */
166.133 + private int[] getMagnitudeArray() {
166.134 + if (offset > 0 || value.length != intLen)
166.135 + return Arrays.copyOfRange(value, offset, offset + intLen);
166.136 + return value;
166.137 + }
166.138 +
166.139 + /**
166.140 + * Convert this MutableBigInteger to a long value. The caller has to make
166.141 + * sure this MutableBigInteger can be fit into long.
166.142 + */
166.143 + private long toLong() {
166.144 + assert (intLen <= 2) : "this MutableBigInteger exceeds the range of long";
166.145 + if (intLen == 0)
166.146 + return 0;
166.147 + long d = value[offset] & LONG_MASK;
166.148 + return (intLen == 2) ? d << 32 | (value[offset + 1] & LONG_MASK) : d;
166.149 + }
166.150 +
166.151 + /**
166.152 + * Convert this MutableBigInteger to a BigInteger object.
166.153 + */
166.154 + BigInteger toBigInteger(int sign) {
166.155 + if (intLen == 0 || sign == 0)
166.156 + return BigInteger.ZERO;
166.157 + return new BigInteger(getMagnitudeArray(), sign);
166.158 + }
166.159 +
166.160 + /**
166.161 + * Convert this MutableBigInteger to BigDecimal object with the specified sign
166.162 + * and scale.
166.163 + */
166.164 + BigDecimal toBigDecimal(int sign, int scale) {
166.165 + if (intLen == 0 || sign == 0)
166.166 + return BigDecimal.valueOf(0, scale);
166.167 + int[] mag = getMagnitudeArray();
166.168 + int len = mag.length;
166.169 + int d = mag[0];
166.170 + // If this MutableBigInteger can't be fit into long, we need to
166.171 + // make a BigInteger object for the resultant BigDecimal object.
166.172 + if (len > 2 || (d < 0 && len == 2))
166.173 + return new BigDecimal(new BigInteger(mag, sign), INFLATED, scale, 0);
166.174 + long v = (len == 2) ?
166.175 + ((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
166.176 + d & LONG_MASK;
166.177 + return new BigDecimal(null, sign == -1 ? -v : v, scale, 0);
166.178 + }
166.179 +
166.180 + /**
166.181 + * Clear out a MutableBigInteger for reuse.
166.182 + */
166.183 + void clear() {
166.184 + offset = intLen = 0;
166.185 + for (int index=0, n=value.length; index < n; index++)
166.186 + value[index] = 0;
166.187 + }
166.188 +
166.189 + /**
166.190 + * Set a MutableBigInteger to zero, removing its offset.
166.191 + */
166.192 + void reset() {
166.193 + offset = intLen = 0;
166.194 + }
166.195 +
166.196 + /**
166.197 + * Compare the magnitude of two MutableBigIntegers. Returns -1, 0 or 1
166.198 + * as this MutableBigInteger is numerically less than, equal to, or
166.199 + * greater than <tt>b</tt>.
166.200 + */
166.201 + final int compare(MutableBigInteger b) {
166.202 + int blen = b.intLen;
166.203 + if (intLen < blen)
166.204 + return -1;
166.205 + if (intLen > blen)
166.206 + return 1;
166.207 +
166.208 + // Add Integer.MIN_VALUE to make the comparison act as unsigned integer
166.209 + // comparison.
166.210 + int[] bval = b.value;
166.211 + for (int i = offset, j = b.offset; i < intLen + offset; i++, j++) {
166.212 + int b1 = value[i] + 0x80000000;
166.213 + int b2 = bval[j] + 0x80000000;
166.214 + if (b1 < b2)
166.215 + return -1;
166.216 + if (b1 > b2)
166.217 + return 1;
166.218 + }
166.219 + return 0;
166.220 + }
166.221 +
166.222 + /**
166.223 + * Compare this against half of a MutableBigInteger object (Needed for
166.224 + * remainder tests).
166.225 + * Assumes no leading unnecessary zeros, which holds for results
166.226 + * from divide().
166.227 + */
166.228 + final int compareHalf(MutableBigInteger b) {
166.229 + int blen = b.intLen;
166.230 + int len = intLen;
166.231 + if (len <= 0)
166.232 + return blen <=0 ? 0 : -1;
166.233 + if (len > blen)
166.234 + return 1;
166.235 + if (len < blen - 1)
166.236 + return -1;
166.237 + int[] bval = b.value;
166.238 + int bstart = 0;
166.239 + int carry = 0;
166.240 + // Only 2 cases left:len == blen or len == blen - 1
166.241 + if (len != blen) { // len == blen - 1
166.242 + if (bval[bstart] == 1) {
166.243 + ++bstart;
166.244 + carry = 0x80000000;
166.245 + } else
166.246 + return -1;
166.247 + }
166.248 + // compare values with right-shifted values of b,
166.249 + // carrying shifted-out bits across words
166.250 + int[] val = value;
166.251 + for (int i = offset, j = bstart; i < len + offset;) {
166.252 + int bv = bval[j++];
166.253 + long hb = ((bv >>> 1) + carry) & LONG_MASK;
166.254 + long v = val[i++] & LONG_MASK;
166.255 + if (v != hb)
166.256 + return v < hb ? -1 : 1;
166.257 + carry = (bv & 1) << 31; // carray will be either 0x80000000 or 0
166.258 + }
166.259 + return carry == 0? 0 : -1;
166.260 + }
166.261 +
166.262 + /**
166.263 + * Return the index of the lowest set bit in this MutableBigInteger. If the
166.264 + * magnitude of this MutableBigInteger is zero, -1 is returned.
166.265 + */
166.266 + private final int getLowestSetBit() {
166.267 + if (intLen == 0)
166.268 + return -1;
166.269 + int j, b;
166.270 + for (j=intLen-1; (j>0) && (value[j+offset]==0); j--)
166.271 + ;
166.272 + b = value[j+offset];
166.273 + if (b==0)
166.274 + return -1;
166.275 + return ((intLen-1-j)<<5) + Integer.numberOfTrailingZeros(b);
166.276 + }
166.277 +
166.278 + /**
166.279 + * Return the int in use in this MutableBigInteger at the specified
166.280 + * index. This method is not used because it is not inlined on all
166.281 + * platforms.
166.282 + */
166.283 + private final int getInt(int index) {
166.284 + return value[offset+index];
166.285 + }
166.286 +
166.287 + /**
166.288 + * Return a long which is equal to the unsigned value of the int in
166.289 + * use in this MutableBigInteger at the specified index. This method is
166.290 + * not used because it is not inlined on all platforms.
166.291 + */
166.292 + private final long getLong(int index) {
166.293 + return value[offset+index] & LONG_MASK;
166.294 + }
166.295 +
166.296 + /**
166.297 + * Ensure that the MutableBigInteger is in normal form, specifically
166.298 + * making sure that there are no leading zeros, and that if the
166.299 + * magnitude is zero, then intLen is zero.
166.300 + */
166.301 + final void normalize() {
166.302 + if (intLen == 0) {
166.303 + offset = 0;
166.304 + return;
166.305 + }
166.306 +
166.307 + int index = offset;
166.308 + if (value[index] != 0)
166.309 + return;
166.310 +
166.311 + int indexBound = index+intLen;
166.312 + do {
166.313 + index++;
166.314 + } while(index < indexBound && value[index]==0);
166.315 +
166.316 + int numZeros = index - offset;
166.317 + intLen -= numZeros;
166.318 + offset = (intLen==0 ? 0 : offset+numZeros);
166.319 + }
166.320 +
166.321 + /**
166.322 + * If this MutableBigInteger cannot hold len words, increase the size
166.323 + * of the value array to len words.
166.324 + */
166.325 + private final void ensureCapacity(int len) {
166.326 + if (value.length < len) {
166.327 + value = new int[len];
166.328 + offset = 0;
166.329 + intLen = len;
166.330 + }
166.331 + }
166.332 +
166.333 + /**
166.334 + * Convert this MutableBigInteger into an int array with no leading
166.335 + * zeros, of a length that is equal to this MutableBigInteger's intLen.
166.336 + */
166.337 + int[] toIntArray() {
166.338 + int[] result = new int[intLen];
166.339 + for(int i=0; i<intLen; i++)
166.340 + result[i] = value[offset+i];
166.341 + return result;
166.342 + }
166.343 +
166.344 + /**
166.345 + * Sets the int at index+offset in this MutableBigInteger to val.
166.346 + * This does not get inlined on all platforms so it is not used
166.347 + * as often as originally intended.
166.348 + */
166.349 + void setInt(int index, int val) {
166.350 + value[offset + index] = val;
166.351 + }
166.352 +
166.353 + /**
166.354 + * Sets this MutableBigInteger's value array to the specified array.
166.355 + * The intLen is set to the specified length.
166.356 + */
166.357 + void setValue(int[] val, int length) {
166.358 + value = val;
166.359 + intLen = length;
166.360 + offset = 0;
166.361 + }
166.362 +
166.363 + /**
166.364 + * Sets this MutableBigInteger's value array to a copy of the specified
166.365 + * array. The intLen is set to the length of the new array.
166.366 + */
166.367 + void copyValue(MutableBigInteger src) {
166.368 + int len = src.intLen;
166.369 + if (value.length < len)
166.370 + value = new int[len];
166.371 + System.arraycopy(src.value, src.offset, value, 0, len);
166.372 + intLen = len;
166.373 + offset = 0;
166.374 + }
166.375 +
166.376 + /**
166.377 + * Sets this MutableBigInteger's value array to a copy of the specified
166.378 + * array. The intLen is set to the length of the specified array.
166.379 + */
166.380 + void copyValue(int[] val) {
166.381 + int len = val.length;
166.382 + if (value.length < len)
166.383 + value = new int[len];
166.384 + System.arraycopy(val, 0, value, 0, len);
166.385 + intLen = len;
166.386 + offset = 0;
166.387 + }
166.388 +
166.389 + /**
166.390 + * Returns true iff this MutableBigInteger has a value of one.
166.391 + */
166.392 + boolean isOne() {
166.393 + return (intLen == 1) && (value[offset] == 1);
166.394 + }
166.395 +
166.396 + /**
166.397 + * Returns true iff this MutableBigInteger has a value of zero.
166.398 + */
166.399 + boolean isZero() {
166.400 + return (intLen == 0);
166.401 + }
166.402 +
166.403 + /**
166.404 + * Returns true iff this MutableBigInteger is even.
166.405 + */
166.406 + boolean isEven() {
166.407 + return (intLen == 0) || ((value[offset + intLen - 1] & 1) == 0);
166.408 + }
166.409 +
166.410 + /**
166.411 + * Returns true iff this MutableBigInteger is odd.
166.412 + */
166.413 + boolean isOdd() {
166.414 + return isZero() ? false : ((value[offset + intLen - 1] & 1) == 1);
166.415 + }
166.416 +
166.417 + /**
166.418 + * Returns true iff this MutableBigInteger is in normal form. A
166.419 + * MutableBigInteger is in normal form if it has no leading zeros
166.420 + * after the offset, and intLen + offset <= value.length.
166.421 + */
166.422 + boolean isNormal() {
166.423 + if (intLen + offset > value.length)
166.424 + return false;
166.425 + if (intLen ==0)
166.426 + return true;
166.427 + return (value[offset] != 0);
166.428 + }
166.429 +
166.430 + /**
166.431 + * Returns a String representation of this MutableBigInteger in radix 10.
166.432 + */
166.433 + public String toString() {
166.434 + BigInteger b = toBigInteger(1);
166.435 + return b.toString();
166.436 + }
166.437 +
166.438 + /**
166.439 + * Right shift this MutableBigInteger n bits. The MutableBigInteger is left
166.440 + * in normal form.
166.441 + */
166.442 + void rightShift(int n) {
166.443 + if (intLen == 0)
166.444 + return;
166.445 + int nInts = n >>> 5;
166.446 + int nBits = n & 0x1F;
166.447 + this.intLen -= nInts;
166.448 + if (nBits == 0)
166.449 + return;
166.450 + int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]);
166.451 + if (nBits >= bitsInHighWord) {
166.452 + this.primitiveLeftShift(32 - nBits);
166.453 + this.intLen--;
166.454 + } else {
166.455 + primitiveRightShift(nBits);
166.456 + }
166.457 + }
166.458 +
166.459 + /**
166.460 + * Left shift this MutableBigInteger n bits.
166.461 + */
166.462 + void leftShift(int n) {
166.463 + /*
166.464 + * If there is enough storage space in this MutableBigInteger already
166.465 + * the available space will be used. Space to the right of the used
166.466 + * ints in the value array is faster to utilize, so the extra space
166.467 + * will be taken from the right if possible.
166.468 + */
166.469 + if (intLen == 0)
166.470 + return;
166.471 + int nInts = n >>> 5;
166.472 + int nBits = n&0x1F;
166.473 + int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]);
166.474 +
166.475 + // If shift can be done without moving words, do so
166.476 + if (n <= (32-bitsInHighWord)) {
166.477 + primitiveLeftShift(nBits);
166.478 + return;
166.479 + }
166.480 +
166.481 + int newLen = intLen + nInts +1;
166.482 + if (nBits <= (32-bitsInHighWord))
166.483 + newLen--;
166.484 + if (value.length < newLen) {
166.485 + // The array must grow
166.486 + int[] result = new int[newLen];
166.487 + for (int i=0; i<intLen; i++)
166.488 + result[i] = value[offset+i];
166.489 + setValue(result, newLen);
166.490 + } else if (value.length - offset >= newLen) {
166.491 + // Use space on right
166.492 + for(int i=0; i<newLen - intLen; i++)
166.493 + value[offset+intLen+i] = 0;
166.494 + } else {
166.495 + // Must use space on left
166.496 + for (int i=0; i<intLen; i++)
166.497 + value[i] = value[offset+i];
166.498 + for (int i=intLen; i<newLen; i++)
166.499 + value[i] = 0;
166.500 + offset = 0;
166.501 + }
166.502 + intLen = newLen;
166.503 + if (nBits == 0)
166.504 + return;
166.505 + if (nBits <= (32-bitsInHighWord))
166.506 + primitiveLeftShift(nBits);
166.507 + else
166.508 + primitiveRightShift(32 -nBits);
166.509 + }
166.510 +
166.511 + /**
166.512 + * A primitive used for division. This method adds in one multiple of the
166.513 + * divisor a back to the dividend result at a specified offset. It is used
166.514 + * when qhat was estimated too large, and must be adjusted.
166.515 + */
166.516 + private int divadd(int[] a, int[] result, int offset) {
166.517 + long carry = 0;
166.518 +
166.519 + for (int j=a.length-1; j >= 0; j--) {
166.520 + long sum = (a[j] & LONG_MASK) +
166.521 + (result[j+offset] & LONG_MASK) + carry;
166.522 + result[j+offset] = (int)sum;
166.523 + carry = sum >>> 32;
166.524 + }
166.525 + return (int)carry;
166.526 + }
166.527 +
166.528 + /**
166.529 + * This method is used for division. It multiplies an n word input a by one
166.530 + * word input x, and subtracts the n word product from q. This is needed
166.531 + * when subtracting qhat*divisor from dividend.
166.532 + */
166.533 + private int mulsub(int[] q, int[] a, int x, int len, int offset) {
166.534 + long xLong = x & LONG_MASK;
166.535 + long carry = 0;
166.536 + offset += len;
166.537 +
166.538 + for (int j=len-1; j >= 0; j--) {
166.539 + long product = (a[j] & LONG_MASK) * xLong + carry;
166.540 + long difference = q[offset] - product;
166.541 + q[offset--] = (int)difference;
166.542 + carry = (product >>> 32)
166.543 + + (((difference & LONG_MASK) >
166.544 + (((~(int)product) & LONG_MASK))) ? 1:0);
166.545 + }
166.546 + return (int)carry;
166.547 + }
166.548 +
166.549 + /**
166.550 + * Right shift this MutableBigInteger n bits, where n is
166.551 + * less than 32.
166.552 + * Assumes that intLen > 0, n > 0 for speed
166.553 + */
166.554 + private final void primitiveRightShift(int n) {
166.555 + int[] val = value;
166.556 + int n2 = 32 - n;
166.557 + for (int i=offset+intLen-1, c=val[i]; i>offset; i--) {
166.558 + int b = c;
166.559 + c = val[i-1];
166.560 + val[i] = (c << n2) | (b >>> n);
166.561 + }
166.562 + val[offset] >>>= n;
166.563 + }
166.564 +
166.565 + /**
166.566 + * Left shift this MutableBigInteger n bits, where n is
166.567 + * less than 32.
166.568 + * Assumes that intLen > 0, n > 0 for speed
166.569 + */
166.570 + private final void primitiveLeftShift(int n) {
166.571 + int[] val = value;
166.572 + int n2 = 32 - n;
166.573 + for (int i=offset, c=val[i], m=i+intLen-1; i<m; i++) {
166.574 + int b = c;
166.575 + c = val[i+1];
166.576 + val[i] = (b << n) | (c >>> n2);
166.577 + }
166.578 + val[offset+intLen-1] <<= n;
166.579 + }
166.580 +
166.581 + /**
166.582 + * Adds the contents of two MutableBigInteger objects.The result
166.583 + * is placed within this MutableBigInteger.
166.584 + * The contents of the addend are not changed.
166.585 + */
166.586 + void add(MutableBigInteger addend) {
166.587 + int x = intLen;
166.588 + int y = addend.intLen;
166.589 + int resultLen = (intLen > addend.intLen ? intLen : addend.intLen);
166.590 + int[] result = (value.length < resultLen ? new int[resultLen] : value);
166.591 +
166.592 + int rstart = result.length-1;
166.593 + long sum;
166.594 + long carry = 0;
166.595 +
166.596 + // Add common parts of both numbers
166.597 + while(x>0 && y>0) {
166.598 + x--; y--;
166.599 + sum = (value[x+offset] & LONG_MASK) +
166.600 + (addend.value[y+addend.offset] & LONG_MASK) + carry;
166.601 + result[rstart--] = (int)sum;
166.602 + carry = sum >>> 32;
166.603 + }
166.604 +
166.605 + // Add remainder of the longer number
166.606 + while(x>0) {
166.607 + x--;
166.608 + if (carry == 0 && result == value && rstart == (x + offset))
166.609 + return;
166.610 + sum = (value[x+offset] & LONG_MASK) + carry;
166.611 + result[rstart--] = (int)sum;
166.612 + carry = sum >>> 32;
166.613 + }
166.614 + while(y>0) {
166.615 + y--;
166.616 + sum = (addend.value[y+addend.offset] & LONG_MASK) + carry;
166.617 + result[rstart--] = (int)sum;
166.618 + carry = sum >>> 32;
166.619 + }
166.620 +
166.621 + if (carry > 0) { // Result must grow in length
166.622 + resultLen++;
166.623 + if (result.length < resultLen) {
166.624 + int temp[] = new int[resultLen];
166.625 + // Result one word longer from carry-out; copy low-order
166.626 + // bits into new result.
166.627 + System.arraycopy(result, 0, temp, 1, result.length);
166.628 + temp[0] = 1;
166.629 + result = temp;
166.630 + } else {
166.631 + result[rstart--] = 1;
166.632 + }
166.633 + }
166.634 +
166.635 + value = result;
166.636 + intLen = resultLen;
166.637 + offset = result.length - resultLen;
166.638 + }
166.639 +
166.640 +
166.641 + /**
166.642 + * Subtracts the smaller of this and b from the larger and places the
166.643 + * result into this MutableBigInteger.
166.644 + */
166.645 + int subtract(MutableBigInteger b) {
166.646 + MutableBigInteger a = this;
166.647 +
166.648 + int[] result = value;
166.649 + int sign = a.compare(b);
166.650 +
166.651 + if (sign == 0) {
166.652 + reset();
166.653 + return 0;
166.654 + }
166.655 + if (sign < 0) {
166.656 + MutableBigInteger tmp = a;
166.657 + a = b;
166.658 + b = tmp;
166.659 + }
166.660 +
166.661 + int resultLen = a.intLen;
166.662 + if (result.length < resultLen)
166.663 + result = new int[resultLen];
166.664 +
166.665 + long diff = 0;
166.666 + int x = a.intLen;
166.667 + int y = b.intLen;
166.668 + int rstart = result.length - 1;
166.669 +
166.670 + // Subtract common parts of both numbers
166.671 + while (y>0) {
166.672 + x--; y--;
166.673 +
166.674 + diff = (a.value[x+a.offset] & LONG_MASK) -
166.675 + (b.value[y+b.offset] & LONG_MASK) - ((int)-(diff>>32));
166.676 + result[rstart--] = (int)diff;
166.677 + }
166.678 + // Subtract remainder of longer number
166.679 + while (x>0) {
166.680 + x--;
166.681 + diff = (a.value[x+a.offset] & LONG_MASK) - ((int)-(diff>>32));
166.682 + result[rstart--] = (int)diff;
166.683 + }
166.684 +
166.685 + value = result;
166.686 + intLen = resultLen;
166.687 + offset = value.length - resultLen;
166.688 + normalize();
166.689 + return sign;
166.690 + }
166.691 +
166.692 + /**
166.693 + * Subtracts the smaller of a and b from the larger and places the result
166.694 + * into the larger. Returns 1 if the answer is in a, -1 if in b, 0 if no
166.695 + * operation was performed.
166.696 + */
166.697 + private int difference(MutableBigInteger b) {
166.698 + MutableBigInteger a = this;
166.699 + int sign = a.compare(b);
166.700 + if (sign ==0)
166.701 + return 0;
166.702 + if (sign < 0) {
166.703 + MutableBigInteger tmp = a;
166.704 + a = b;
166.705 + b = tmp;
166.706 + }
166.707 +
166.708 + long diff = 0;
166.709 + int x = a.intLen;
166.710 + int y = b.intLen;
166.711 +
166.712 + // Subtract common parts of both numbers
166.713 + while (y>0) {
166.714 + x--; y--;
166.715 + diff = (a.value[a.offset+ x] & LONG_MASK) -
166.716 + (b.value[b.offset+ y] & LONG_MASK) - ((int)-(diff>>32));
166.717 + a.value[a.offset+x] = (int)diff;
166.718 + }
166.719 + // Subtract remainder of longer number
166.720 + while (x>0) {
166.721 + x--;
166.722 + diff = (a.value[a.offset+ x] & LONG_MASK) - ((int)-(diff>>32));
166.723 + a.value[a.offset+x] = (int)diff;
166.724 + }
166.725 +
166.726 + a.normalize();
166.727 + return sign;
166.728 + }
166.729 +
166.730 + /**
166.731 + * Multiply the contents of two MutableBigInteger objects. The result is
166.732 + * placed into MutableBigInteger z. The contents of y are not changed.
166.733 + */
166.734 + void multiply(MutableBigInteger y, MutableBigInteger z) {
166.735 + int xLen = intLen;
166.736 + int yLen = y.intLen;
166.737 + int newLen = xLen + yLen;
166.738 +
166.739 + // Put z into an appropriate state to receive product
166.740 + if (z.value.length < newLen)
166.741 + z.value = new int[newLen];
166.742 + z.offset = 0;
166.743 + z.intLen = newLen;
166.744 +
166.745 + // The first iteration is hoisted out of the loop to avoid extra add
166.746 + long carry = 0;
166.747 + for (int j=yLen-1, k=yLen+xLen-1; j >= 0; j--, k--) {
166.748 + long product = (y.value[j+y.offset] & LONG_MASK) *
166.749 + (value[xLen-1+offset] & LONG_MASK) + carry;
166.750 + z.value[k] = (int)product;
166.751 + carry = product >>> 32;
166.752 + }
166.753 + z.value[xLen-1] = (int)carry;
166.754 +
166.755 + // Perform the multiplication word by word
166.756 + for (int i = xLen-2; i >= 0; i--) {
166.757 + carry = 0;
166.758 + for (int j=yLen-1, k=yLen+i; j >= 0; j--, k--) {
166.759 + long product = (y.value[j+y.offset] & LONG_MASK) *
166.760 + (value[i+offset] & LONG_MASK) +
166.761 + (z.value[k] & LONG_MASK) + carry;
166.762 + z.value[k] = (int)product;
166.763 + carry = product >>> 32;
166.764 + }
166.765 + z.value[i] = (int)carry;
166.766 + }
166.767 +
166.768 + // Remove leading zeros from product
166.769 + z.normalize();
166.770 + }
166.771 +
166.772 + /**
166.773 + * Multiply the contents of this MutableBigInteger by the word y. The
166.774 + * result is placed into z.
166.775 + */
166.776 + void mul(int y, MutableBigInteger z) {
166.777 + if (y == 1) {
166.778 + z.copyValue(this);
166.779 + return;
166.780 + }
166.781 +
166.782 + if (y == 0) {
166.783 + z.clear();
166.784 + return;
166.785 + }
166.786 +
166.787 + // Perform the multiplication word by word
166.788 + long ylong = y & LONG_MASK;
166.789 + int[] zval = (z.value.length<intLen+1 ? new int[intLen + 1]
166.790 + : z.value);
166.791 + long carry = 0;
166.792 + for (int i = intLen-1; i >= 0; i--) {
166.793 + long product = ylong * (value[i+offset] & LONG_MASK) + carry;
166.794 + zval[i+1] = (int)product;
166.795 + carry = product >>> 32;
166.796 + }
166.797 +
166.798 + if (carry == 0) {
166.799 + z.offset = 1;
166.800 + z.intLen = intLen;
166.801 + } else {
166.802 + z.offset = 0;
166.803 + z.intLen = intLen + 1;
166.804 + zval[0] = (int)carry;
166.805 + }
166.806 + z.value = zval;
166.807 + }
166.808 +
166.809 + /**
166.810 + * This method is used for division of an n word dividend by a one word
166.811 + * divisor. The quotient is placed into quotient. The one word divisor is
166.812 + * specified by divisor.
166.813 + *
166.814 + * @return the remainder of the division is returned.
166.815 + *
166.816 + */
166.817 + int divideOneWord(int divisor, MutableBigInteger quotient) {
166.818 + long divisorLong = divisor & LONG_MASK;
166.819 +
166.820 + // Special case of one word dividend
166.821 + if (intLen == 1) {
166.822 + long dividendValue = value[offset] & LONG_MASK;
166.823 + int q = (int) (dividendValue / divisorLong);
166.824 + int r = (int) (dividendValue - q * divisorLong);
166.825 + quotient.value[0] = q;
166.826 + quotient.intLen = (q == 0) ? 0 : 1;
166.827 + quotient.offset = 0;
166.828 + return r;
166.829 + }
166.830 +
166.831 + if (quotient.value.length < intLen)
166.832 + quotient.value = new int[intLen];
166.833 + quotient.offset = 0;
166.834 + quotient.intLen = intLen;
166.835 +
166.836 + // Normalize the divisor
166.837 + int shift = Integer.numberOfLeadingZeros(divisor);
166.838 +
166.839 + int rem = value[offset];
166.840 + long remLong = rem & LONG_MASK;
166.841 + if (remLong < divisorLong) {
166.842 + quotient.value[0] = 0;
166.843 + } else {
166.844 + quotient.value[0] = (int)(remLong / divisorLong);
166.845 + rem = (int) (remLong - (quotient.value[0] * divisorLong));
166.846 + remLong = rem & LONG_MASK;
166.847 + }
166.848 +
166.849 + int xlen = intLen;
166.850 + int[] qWord = new int[2];
166.851 + while (--xlen > 0) {
166.852 + long dividendEstimate = (remLong<<32) |
166.853 + (value[offset + intLen - xlen] & LONG_MASK);
166.854 + if (dividendEstimate >= 0) {
166.855 + qWord[0] = (int) (dividendEstimate / divisorLong);
166.856 + qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong);
166.857 + } else {
166.858 + divWord(qWord, dividendEstimate, divisor);
166.859 + }
166.860 + quotient.value[intLen - xlen] = qWord[0];
166.861 + rem = qWord[1];
166.862 + remLong = rem & LONG_MASK;
166.863 + }
166.864 +
166.865 + quotient.normalize();
166.866 + // Unnormalize
166.867 + if (shift > 0)
166.868 + return rem % divisor;
166.869 + else
166.870 + return rem;
166.871 + }
166.872 +
166.873 + /**
166.874 + * Calculates the quotient of this div b and places the quotient in the
166.875 + * provided MutableBigInteger objects and the remainder object is returned.
166.876 + *
166.877 + * Uses Algorithm D in Knuth section 4.3.1.
166.878 + * Many optimizations to that algorithm have been adapted from the Colin
166.879 + * Plumb C library.
166.880 + * It special cases one word divisors for speed. The content of b is not
166.881 + * changed.
166.882 + *
166.883 + */
166.884 + MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) {
166.885 + if (b.intLen == 0)
166.886 + throw new ArithmeticException("BigInteger divide by zero");
166.887 +
166.888 + // Dividend is zero
166.889 + if (intLen == 0) {
166.890 + quotient.intLen = quotient.offset;
166.891 + return new MutableBigInteger();
166.892 + }
166.893 +
166.894 + int cmp = compare(b);
166.895 + // Dividend less than divisor
166.896 + if (cmp < 0) {
166.897 + quotient.intLen = quotient.offset = 0;
166.898 + return new MutableBigInteger(this);
166.899 + }
166.900 + // Dividend equal to divisor
166.901 + if (cmp == 0) {
166.902 + quotient.value[0] = quotient.intLen = 1;
166.903 + quotient.offset = 0;
166.904 + return new MutableBigInteger();
166.905 + }
166.906 +
166.907 + quotient.clear();
166.908 + // Special case one word divisor
166.909 + if (b.intLen == 1) {
166.910 + int r = divideOneWord(b.value[b.offset], quotient);
166.911 + if (r == 0)
166.912 + return new MutableBigInteger();
166.913 + return new MutableBigInteger(r);
166.914 + }
166.915 +
166.916 + // Copy divisor value to protect divisor
166.917 + int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen);
166.918 + return divideMagnitude(div, quotient);
166.919 + }
166.920 +
166.921 + /**
166.922 + * Internally used to calculate the quotient of this div v and places the
166.923 + * quotient in the provided MutableBigInteger object and the remainder is
166.924 + * returned.
166.925 + *
166.926 + * @return the remainder of the division will be returned.
166.927 + */
166.928 + long divide(long v, MutableBigInteger quotient) {
166.929 + if (v == 0)
166.930 + throw new ArithmeticException("BigInteger divide by zero");
166.931 +
166.932 + // Dividend is zero
166.933 + if (intLen == 0) {
166.934 + quotient.intLen = quotient.offset = 0;
166.935 + return 0;
166.936 + }
166.937 + if (v < 0)
166.938 + v = -v;
166.939 +
166.940 + int d = (int)(v >>> 32);
166.941 + quotient.clear();
166.942 + // Special case on word divisor
166.943 + if (d == 0)
166.944 + return divideOneWord((int)v, quotient) & LONG_MASK;
166.945 + else {
166.946 + int[] div = new int[]{ d, (int)(v & LONG_MASK) };
166.947 + return divideMagnitude(div, quotient).toLong();
166.948 + }
166.949 + }
166.950 +
166.951 + /**
166.952 + * Divide this MutableBigInteger by the divisor represented by its magnitude
166.953 + * array. The quotient will be placed into the provided quotient object &
166.954 + * the remainder object is returned.
166.955 + */
166.956 + private MutableBigInteger divideMagnitude(int[] divisor,
166.957 + MutableBigInteger quotient) {
166.958 +
166.959 + // Remainder starts as dividend with space for a leading zero
166.960 + MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]);
166.961 + System.arraycopy(value, offset, rem.value, 1, intLen);
166.962 + rem.intLen = intLen;
166.963 + rem.offset = 1;
166.964 +
166.965 + int nlen = rem.intLen;
166.966 +
166.967 + // Set the quotient size
166.968 + int dlen = divisor.length;
166.969 + int limit = nlen - dlen + 1;
166.970 + if (quotient.value.length < limit) {
166.971 + quotient.value = new int[limit];
166.972 + quotient.offset = 0;
166.973 + }
166.974 + quotient.intLen = limit;
166.975 + int[] q = quotient.value;
166.976 +
166.977 + // D1 normalize the divisor
166.978 + int shift = Integer.numberOfLeadingZeros(divisor[0]);
166.979 + if (shift > 0) {
166.980 + // First shift will not grow array
166.981 + BigInteger.primitiveLeftShift(divisor, dlen, shift);
166.982 + // But this one might
166.983 + rem.leftShift(shift);
166.984 + }
166.985 +
166.986 + // Must insert leading 0 in rem if its length did not change
166.987 + if (rem.intLen == nlen) {
166.988 + rem.offset = 0;
166.989 + rem.value[0] = 0;
166.990 + rem.intLen++;
166.991 + }
166.992 +
166.993 + int dh = divisor[0];
166.994 + long dhLong = dh & LONG_MASK;
166.995 + int dl = divisor[1];
166.996 + int[] qWord = new int[2];
166.997 +
166.998 + // D2 Initialize j
166.999 + for(int j=0; j<limit; j++) {
166.1000 + // D3 Calculate qhat
166.1001 + // estimate qhat
166.1002 + int qhat = 0;
166.1003 + int qrem = 0;
166.1004 + boolean skipCorrection = false;
166.1005 + int nh = rem.value[j+rem.offset];
166.1006 + int nh2 = nh + 0x80000000;
166.1007 + int nm = rem.value[j+1+rem.offset];
166.1008 +
166.1009 + if (nh == dh) {
166.1010 + qhat = ~0;
166.1011 + qrem = nh + nm;
166.1012 + skipCorrection = qrem + 0x80000000 < nh2;
166.1013 + } else {
166.1014 + long nChunk = (((long)nh) << 32) | (nm & LONG_MASK);
166.1015 + if (nChunk >= 0) {
166.1016 + qhat = (int) (nChunk / dhLong);
166.1017 + qrem = (int) (nChunk - (qhat * dhLong));
166.1018 + } else {
166.1019 + divWord(qWord, nChunk, dh);
166.1020 + qhat = qWord[0];
166.1021 + qrem = qWord[1];
166.1022 + }
166.1023 + }
166.1024 +
166.1025 + if (qhat == 0)
166.1026 + continue;
166.1027 +
166.1028 + if (!skipCorrection) { // Correct qhat
166.1029 + long nl = rem.value[j+2+rem.offset] & LONG_MASK;
166.1030 + long rs = ((qrem & LONG_MASK) << 32) | nl;
166.1031 + long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
166.1032 +
166.1033 + if (unsignedLongCompare(estProduct, rs)) {
166.1034 + qhat--;
166.1035 + qrem = (int)((qrem & LONG_MASK) + dhLong);
166.1036 + if ((qrem & LONG_MASK) >= dhLong) {
166.1037 + estProduct -= (dl & LONG_MASK);
166.1038 + rs = ((qrem & LONG_MASK) << 32) | nl;
166.1039 + if (unsignedLongCompare(estProduct, rs))
166.1040 + qhat--;
166.1041 + }
166.1042 + }
166.1043 + }
166.1044 +
166.1045 + // D4 Multiply and subtract
166.1046 + rem.value[j+rem.offset] = 0;
166.1047 + int borrow = mulsub(rem.value, divisor, qhat, dlen, j+rem.offset);
166.1048 +
166.1049 + // D5 Test remainder
166.1050 + if (borrow + 0x80000000 > nh2) {
166.1051 + // D6 Add back
166.1052 + divadd(divisor, rem.value, j+1+rem.offset);
166.1053 + qhat--;
166.1054 + }
166.1055 +
166.1056 + // Store the quotient digit
166.1057 + q[j] = qhat;
166.1058 + } // D7 loop on j
166.1059 +
166.1060 + // D8 Unnormalize
166.1061 + if (shift > 0)
166.1062 + rem.rightShift(shift);
166.1063 +
166.1064 + quotient.normalize();
166.1065 + rem.normalize();
166.1066 + return rem;
166.1067 + }
166.1068 +
166.1069 + /**
166.1070 + * Compare two longs as if they were unsigned.
166.1071 + * Returns true iff one is bigger than two.
166.1072 + */
166.1073 + private boolean unsignedLongCompare(long one, long two) {
166.1074 + return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE);
166.1075 + }
166.1076 +
166.1077 + /**
166.1078 + * This method divides a long quantity by an int to estimate
166.1079 + * qhat for two multi precision numbers. It is used when
166.1080 + * the signed value of n is less than zero.
166.1081 + */
166.1082 + private void divWord(int[] result, long n, int d) {
166.1083 + long dLong = d & LONG_MASK;
166.1084 +
166.1085 + if (dLong == 1) {
166.1086 + result[0] = (int)n;
166.1087 + result[1] = 0;
166.1088 + return;
166.1089 + }
166.1090 +
166.1091 + // Approximate the quotient and remainder
166.1092 + long q = (n >>> 1) / (dLong >>> 1);
166.1093 + long r = n - q*dLong;
166.1094 +
166.1095 + // Correct the approximation
166.1096 + while (r < 0) {
166.1097 + r += dLong;
166.1098 + q--;
166.1099 + }
166.1100 + while (r >= dLong) {
166.1101 + r -= dLong;
166.1102 + q++;
166.1103 + }
166.1104 +
166.1105 + // n - q*dlong == r && 0 <= r <dLong, hence we're done.
166.1106 + result[0] = (int)q;
166.1107 + result[1] = (int)r;
166.1108 + }
166.1109 +
166.1110 + /**
166.1111 + * Calculate GCD of this and b. This and b are changed by the computation.
166.1112 + */
166.1113 + MutableBigInteger hybridGCD(MutableBigInteger b) {
166.1114 + // Use Euclid's algorithm until the numbers are approximately the
166.1115 + // same length, then use the binary GCD algorithm to find the GCD.
166.1116 + MutableBigInteger a = this;
166.1117 + MutableBigInteger q = new MutableBigInteger();
166.1118 +
166.1119 + while (b.intLen != 0) {
166.1120 + if (Math.abs(a.intLen - b.intLen) < 2)
166.1121 + return a.binaryGCD(b);
166.1122 +
166.1123 + MutableBigInteger r = a.divide(b, q);
166.1124 + a = b;
166.1125 + b = r;
166.1126 + }
166.1127 + return a;
166.1128 + }
166.1129 +
166.1130 + /**
166.1131 + * Calculate GCD of this and v.
166.1132 + * Assumes that this and v are not zero.
166.1133 + */
166.1134 + private MutableBigInteger binaryGCD(MutableBigInteger v) {
166.1135 + // Algorithm B from Knuth section 4.5.2
166.1136 + MutableBigInteger u = this;
166.1137 + MutableBigInteger r = new MutableBigInteger();
166.1138 +
166.1139 + // step B1
166.1140 + int s1 = u.getLowestSetBit();
166.1141 + int s2 = v.getLowestSetBit();
166.1142 + int k = (s1 < s2) ? s1 : s2;
166.1143 + if (k != 0) {
166.1144 + u.rightShift(k);
166.1145 + v.rightShift(k);
166.1146 + }
166.1147 +
166.1148 + // step B2
166.1149 + boolean uOdd = (k==s1);
166.1150 + MutableBigInteger t = uOdd ? v: u;
166.1151 + int tsign = uOdd ? -1 : 1;
166.1152 +
166.1153 + int lb;
166.1154 + while ((lb = t.getLowestSetBit()) >= 0) {
166.1155 + // steps B3 and B4
166.1156 + t.rightShift(lb);
166.1157 + // step B5
166.1158 + if (tsign > 0)
166.1159 + u = t;
166.1160 + else
166.1161 + v = t;
166.1162 +
166.1163 + // Special case one word numbers
166.1164 + if (u.intLen < 2 && v.intLen < 2) {
166.1165 + int x = u.value[u.offset];
166.1166 + int y = v.value[v.offset];
166.1167 + x = binaryGcd(x, y);
166.1168 + r.value[0] = x;
166.1169 + r.intLen = 1;
166.1170 + r.offset = 0;
166.1171 + if (k > 0)
166.1172 + r.leftShift(k);
166.1173 + return r;
166.1174 + }
166.1175 +
166.1176 + // step B6
166.1177 + if ((tsign = u.difference(v)) == 0)
166.1178 + break;
166.1179 + t = (tsign >= 0) ? u : v;
166.1180 + }
166.1181 +
166.1182 + if (k > 0)
166.1183 + u.leftShift(k);
166.1184 + return u;
166.1185 + }
166.1186 +
166.1187 + /**
166.1188 + * Calculate GCD of a and b interpreted as unsigned integers.
166.1189 + */
166.1190 + static int binaryGcd(int a, int b) {
166.1191 + if (b==0)
166.1192 + return a;
166.1193 + if (a==0)
166.1194 + return b;
166.1195 +
166.1196 + // Right shift a & b till their last bits equal to 1.
166.1197 + int aZeros = Integer.numberOfTrailingZeros(a);
166.1198 + int bZeros = Integer.numberOfTrailingZeros(b);
166.1199 + a >>>= aZeros;
166.1200 + b >>>= bZeros;
166.1201 +
166.1202 + int t = (aZeros < bZeros ? aZeros : bZeros);
166.1203 +
166.1204 + while (a != b) {
166.1205 + if ((a+0x80000000) > (b+0x80000000)) { // a > b as unsigned
166.1206 + a -= b;
166.1207 + a >>>= Integer.numberOfTrailingZeros(a);
166.1208 + } else {
166.1209 + b -= a;
166.1210 + b >>>= Integer.numberOfTrailingZeros(b);
166.1211 + }
166.1212 + }
166.1213 + return a<<t;
166.1214 + }
166.1215 +
166.1216 + /**
166.1217 + * Returns the modInverse of this mod p. This and p are not affected by
166.1218 + * the operation.
166.1219 + */
166.1220 + MutableBigInteger mutableModInverse(MutableBigInteger p) {
166.1221 + // Modulus is odd, use Schroeppel's algorithm
166.1222 + if (p.isOdd())
166.1223 + return modInverse(p);
166.1224 +
166.1225 + // Base and modulus are even, throw exception
166.1226 + if (isEven())
166.1227 + throw new ArithmeticException("BigInteger not invertible.");
166.1228 +
166.1229 + // Get even part of modulus expressed as a power of 2
166.1230 + int powersOf2 = p.getLowestSetBit();
166.1231 +
166.1232 + // Construct odd part of modulus
166.1233 + MutableBigInteger oddMod = new MutableBigInteger(p);
166.1234 + oddMod.rightShift(powersOf2);
166.1235 +
166.1236 + if (oddMod.isOne())
166.1237 + return modInverseMP2(powersOf2);
166.1238 +
166.1239 + // Calculate 1/a mod oddMod
166.1240 + MutableBigInteger oddPart = modInverse(oddMod);
166.1241 +
166.1242 + // Calculate 1/a mod evenMod
166.1243 + MutableBigInteger evenPart = modInverseMP2(powersOf2);
166.1244 +
166.1245 + // Combine the results using Chinese Remainder Theorem
166.1246 + MutableBigInteger y1 = modInverseBP2(oddMod, powersOf2);
166.1247 + MutableBigInteger y2 = oddMod.modInverseMP2(powersOf2);
166.1248 +
166.1249 + MutableBigInteger temp1 = new MutableBigInteger();
166.1250 + MutableBigInteger temp2 = new MutableBigInteger();
166.1251 + MutableBigInteger result = new MutableBigInteger();
166.1252 +
166.1253 + oddPart.leftShift(powersOf2);
166.1254 + oddPart.multiply(y1, result);
166.1255 +
166.1256 + evenPart.multiply(oddMod, temp1);
166.1257 + temp1.multiply(y2, temp2);
166.1258 +
166.1259 + result.add(temp2);
166.1260 + return result.divide(p, temp1);
166.1261 + }
166.1262 +
166.1263 + /*
166.1264 + * Calculate the multiplicative inverse of this mod 2^k.
166.1265 + */
166.1266 + MutableBigInteger modInverseMP2(int k) {
166.1267 + if (isEven())
166.1268 + throw new ArithmeticException("Non-invertible. (GCD != 1)");
166.1269 +
166.1270 + if (k > 64)
166.1271 + return euclidModInverse(k);
166.1272 +
166.1273 + int t = inverseMod32(value[offset+intLen-1]);
166.1274 +
166.1275 + if (k < 33) {
166.1276 + t = (k == 32 ? t : t & ((1 << k) - 1));
166.1277 + return new MutableBigInteger(t);
166.1278 + }
166.1279 +
166.1280 + long pLong = (value[offset+intLen-1] & LONG_MASK);
166.1281 + if (intLen > 1)
166.1282 + pLong |= ((long)value[offset+intLen-2] << 32);
166.1283 + long tLong = t & LONG_MASK;
166.1284 + tLong = tLong * (2 - pLong * tLong); // 1 more Newton iter step
166.1285 + tLong = (k == 64 ? tLong : tLong & ((1L << k) - 1));
166.1286 +
166.1287 + MutableBigInteger result = new MutableBigInteger(new int[2]);
166.1288 + result.value[0] = (int)(tLong >>> 32);
166.1289 + result.value[1] = (int)tLong;
166.1290 + result.intLen = 2;
166.1291 + result.normalize();
166.1292 + return result;
166.1293 + }
166.1294 +
166.1295 + /*
166.1296 + * Returns the multiplicative inverse of val mod 2^32. Assumes val is odd.
166.1297 + */
166.1298 + static int inverseMod32(int val) {
166.1299 + // Newton's iteration!
166.1300 + int t = val;
166.1301 + t *= 2 - val*t;
166.1302 + t *= 2 - val*t;
166.1303 + t *= 2 - val*t;
166.1304 + t *= 2 - val*t;
166.1305 + return t;
166.1306 + }
166.1307 +
166.1308 + /*
166.1309 + * Calculate the multiplicative inverse of 2^k mod mod, where mod is odd.
166.1310 + */
166.1311 + static MutableBigInteger modInverseBP2(MutableBigInteger mod, int k) {
166.1312 + // Copy the mod to protect original
166.1313 + return fixup(new MutableBigInteger(1), new MutableBigInteger(mod), k);
166.1314 + }
166.1315 +
166.1316 + /**
166.1317 + * Calculate the multiplicative inverse of this mod mod, where mod is odd.
166.1318 + * This and mod are not changed by the calculation.
166.1319 + *
166.1320 + * This method implements an algorithm due to Richard Schroeppel, that uses
166.1321 + * the same intermediate representation as Montgomery Reduction
166.1322 + * ("Montgomery Form"). The algorithm is described in an unpublished
166.1323 + * manuscript entitled "Fast Modular Reciprocals."
166.1324 + */
166.1325 + private MutableBigInteger modInverse(MutableBigInteger mod) {
166.1326 + MutableBigInteger p = new MutableBigInteger(mod);
166.1327 + MutableBigInteger f = new MutableBigInteger(this);
166.1328 + MutableBigInteger g = new MutableBigInteger(p);
166.1329 + SignedMutableBigInteger c = new SignedMutableBigInteger(1);
166.1330 + SignedMutableBigInteger d = new SignedMutableBigInteger();
166.1331 + MutableBigInteger temp = null;
166.1332 + SignedMutableBigInteger sTemp = null;
166.1333 +
166.1334 + int k = 0;
166.1335 + // Right shift f k times until odd, left shift d k times
166.1336 + if (f.isEven()) {
166.1337 + int trailingZeros = f.getLowestSetBit();
166.1338 + f.rightShift(trailingZeros);
166.1339 + d.leftShift(trailingZeros);
166.1340 + k = trailingZeros;
166.1341 + }
166.1342 +
166.1343 + // The Almost Inverse Algorithm
166.1344 + while(!f.isOne()) {
166.1345 + // If gcd(f, g) != 1, number is not invertible modulo mod
166.1346 + if (f.isZero())
166.1347 + throw new ArithmeticException("BigInteger not invertible.");
166.1348 +
166.1349 + // If f < g exchange f, g and c, d
166.1350 + if (f.compare(g) < 0) {
166.1351 + temp = f; f = g; g = temp;
166.1352 + sTemp = d; d = c; c = sTemp;
166.1353 + }
166.1354 +
166.1355 + // If f == g (mod 4)
166.1356 + if (((f.value[f.offset + f.intLen - 1] ^
166.1357 + g.value[g.offset + g.intLen - 1]) & 3) == 0) {
166.1358 + f.subtract(g);
166.1359 + c.signedSubtract(d);
166.1360 + } else { // If f != g (mod 4)
166.1361 + f.add(g);
166.1362 + c.signedAdd(d);
166.1363 + }
166.1364 +
166.1365 + // Right shift f k times until odd, left shift d k times
166.1366 + int trailingZeros = f.getLowestSetBit();
166.1367 + f.rightShift(trailingZeros);
166.1368 + d.leftShift(trailingZeros);
166.1369 + k += trailingZeros;
166.1370 + }
166.1371 +
166.1372 + while (c.sign < 0)
166.1373 + c.signedAdd(p);
166.1374 +
166.1375 + return fixup(c, p, k);
166.1376 + }
166.1377 +
166.1378 + /*
166.1379 + * The Fixup Algorithm
166.1380 + * Calculates X such that X = C * 2^(-k) (mod P)
166.1381 + * Assumes C<P and P is odd.
166.1382 + */
166.1383 + static MutableBigInteger fixup(MutableBigInteger c, MutableBigInteger p,
166.1384 + int k) {
166.1385 + MutableBigInteger temp = new MutableBigInteger();
166.1386 + // Set r to the multiplicative inverse of p mod 2^32
166.1387 + int r = -inverseMod32(p.value[p.offset+p.intLen-1]);
166.1388 +
166.1389 + for(int i=0, numWords = k >> 5; i<numWords; i++) {
166.1390 + // V = R * c (mod 2^j)
166.1391 + int v = r * c.value[c.offset + c.intLen-1];
166.1392 + // c = c + (v * p)
166.1393 + p.mul(v, temp);
166.1394 + c.add(temp);
166.1395 + // c = c / 2^j
166.1396 + c.intLen--;
166.1397 + }
166.1398 + int numBits = k & 0x1f;
166.1399 + if (numBits != 0) {
166.1400 + // V = R * c (mod 2^j)
166.1401 + int v = r * c.value[c.offset + c.intLen-1];
166.1402 + v &= ((1<<numBits) - 1);
166.1403 + // c = c + (v * p)
166.1404 + p.mul(v, temp);
166.1405 + c.add(temp);
166.1406 + // c = c / 2^j
166.1407 + c.rightShift(numBits);
166.1408 + }
166.1409 +
166.1410 + // In theory, c may be greater than p at this point (Very rare!)
166.1411 + while (c.compare(p) >= 0)
166.1412 + c.subtract(p);
166.1413 +
166.1414 + return c;
166.1415 + }
166.1416 +
166.1417 + /**
166.1418 + * Uses the extended Euclidean algorithm to compute the modInverse of base
166.1419 + * mod a modulus that is a power of 2. The modulus is 2^k.
166.1420 + */
166.1421 + MutableBigInteger euclidModInverse(int k) {
166.1422 + MutableBigInteger b = new MutableBigInteger(1);
166.1423 + b.leftShift(k);
166.1424 + MutableBigInteger mod = new MutableBigInteger(b);
166.1425 +
166.1426 + MutableBigInteger a = new MutableBigInteger(this);
166.1427 + MutableBigInteger q = new MutableBigInteger();
166.1428 + MutableBigInteger r = b.divide(a, q);
166.1429 +
166.1430 + MutableBigInteger swapper = b;
166.1431 + // swap b & r
166.1432 + b = r;
166.1433 + r = swapper;
166.1434 +
166.1435 + MutableBigInteger t1 = new MutableBigInteger(q);
166.1436 + MutableBigInteger t0 = new MutableBigInteger(1);
166.1437 + MutableBigInteger temp = new MutableBigInteger();
166.1438 +
166.1439 + while (!b.isOne()) {
166.1440 + r = a.divide(b, q);
166.1441 +
166.1442 + if (r.intLen == 0)
166.1443 + throw new ArithmeticException("BigInteger not invertible.");
166.1444 +
166.1445 + swapper = r;
166.1446 + a = swapper;
166.1447 +
166.1448 + if (q.intLen == 1)
166.1449 + t1.mul(q.value[q.offset], temp);
166.1450 + else
166.1451 + q.multiply(t1, temp);
166.1452 + swapper = q;
166.1453 + q = temp;
166.1454 + temp = swapper;
166.1455 + t0.add(q);
166.1456 +
166.1457 + if (a.isOne())
166.1458 + return t0;
166.1459 +
166.1460 + r = b.divide(a, q);
166.1461 +
166.1462 + if (r.intLen == 0)
166.1463 + throw new ArithmeticException("BigInteger not invertible.");
166.1464 +
166.1465 + swapper = b;
166.1466 + b = r;
166.1467 +
166.1468 + if (q.intLen == 1)
166.1469 + t0.mul(q.value[q.offset], temp);
166.1470 + else
166.1471 + q.multiply(t0, temp);
166.1472 + swapper = q; q = temp; temp = swapper;
166.1473 +
166.1474 + t1.add(q);
166.1475 + }
166.1476 + mod.subtract(t1);
166.1477 + return mod;
166.1478 + }
166.1479 +
166.1480 +}
167.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
167.2 +++ b/rt/emul/compact/src/main/java/java/math/RoundingMode.java Wed Apr 30 15:04:10 2014 +0200
167.3 @@ -0,0 +1,349 @@
167.4 +/*
167.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
167.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
167.7 + *
167.8 + * This code is free software; you can redistribute it and/or modify it
167.9 + * under the terms of the GNU General Public License version 2 only, as
167.10 + * published by the Free Software Foundation. Oracle designates this
167.11 + * particular file as subject to the "Classpath" exception as provided
167.12 + * by Oracle in the LICENSE file that accompanied this code.
167.13 + *
167.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
167.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
167.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
167.17 + * version 2 for more details (a copy is included in the LICENSE file that
167.18 + * accompanied this code).
167.19 + *
167.20 + * You should have received a copy of the GNU General Public License version
167.21 + * 2 along with this work; if not, write to the Free Software Foundation,
167.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
167.23 + *
167.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
167.25 + * or visit www.oracle.com if you need additional information or have any
167.26 + * questions.
167.27 + */
167.28 +
167.29 +/*
167.30 + * Portions Copyright IBM Corporation, 2001. All Rights Reserved.
167.31 + */
167.32 +package java.math;
167.33 +
167.34 +/**
167.35 + * Specifies a <i>rounding behavior</i> for numerical operations
167.36 + * capable of discarding precision. Each rounding mode indicates how
167.37 + * the least significant returned digit of a rounded result is to be
167.38 + * calculated. If fewer digits are returned than the digits needed to
167.39 + * represent the exact numerical result, the discarded digits will be
167.40 + * referred to as the <i>discarded fraction</i> regardless the digits'
167.41 + * contribution to the value of the number. In other words,
167.42 + * considered as a numerical value, the discarded fraction could have
167.43 + * an absolute value greater than one.
167.44 + *
167.45 + * <p>Each rounding mode description includes a table listing how
167.46 + * different two-digit decimal values would round to a one digit
167.47 + * decimal value under the rounding mode in question. The result
167.48 + * column in the tables could be gotten by creating a
167.49 + * {@code BigDecimal} number with the specified value, forming a
167.50 + * {@link MathContext} object with the proper settings
167.51 + * ({@code precision} set to {@code 1}, and the
167.52 + * {@code roundingMode} set to the rounding mode in question), and
167.53 + * calling {@link BigDecimal#round round} on this number with the
167.54 + * proper {@code MathContext}. A summary table showing the results
167.55 + * of these rounding operations for all rounding modes appears below.
167.56 + *
167.57 + *<p>
167.58 + *<table border>
167.59 + * <caption><b>Summary of Rounding Operations Under Different Rounding Modes</b></caption>
167.60 + * <tr><th></th><th colspan=8>Result of rounding input to one digit with the given
167.61 + * rounding mode</th>
167.62 + * <tr valign=top>
167.63 + * <th>Input Number</th> <th>{@code UP}</th>
167.64 + * <th>{@code DOWN}</th>
167.65 + * <th>{@code CEILING}</th>
167.66 + * <th>{@code FLOOR}</th>
167.67 + * <th>{@code HALF_UP}</th>
167.68 + * <th>{@code HALF_DOWN}</th>
167.69 + * <th>{@code HALF_EVEN}</th>
167.70 + * <th>{@code UNNECESSARY}</th>
167.71 + *
167.72 + * <tr align=right><td>5.5</td> <td>6</td> <td>5</td> <td>6</td> <td>5</td> <td>6</td> <td>5</td> <td>6</td> <td>throw {@code ArithmeticException}</td>
167.73 + * <tr align=right><td>2.5</td> <td>3</td> <td>2</td> <td>3</td> <td>2</td> <td>3</td> <td>2</td> <td>2</td> <td>throw {@code ArithmeticException}</td>
167.74 + * <tr align=right><td>1.6</td> <td>2</td> <td>1</td> <td>2</td> <td>1</td> <td>2</td> <td>2</td> <td>2</td> <td>throw {@code ArithmeticException}</td>
167.75 + * <tr align=right><td>1.1</td> <td>2</td> <td>1</td> <td>2</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>throw {@code ArithmeticException}</td>
167.76 + * <tr align=right><td>1.0</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td> <td>1</td>
167.77 + * <tr align=right><td>-1.0</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>-1</td>
167.78 + * <tr align=right><td>-1.1</td> <td>-2</td> <td>-1</td> <td>-1</td> <td>-2</td> <td>-1</td> <td>-1</td> <td>-1</td> <td>throw {@code ArithmeticException}</td>
167.79 + * <tr align=right><td>-1.6</td> <td>-2</td> <td>-1</td> <td>-1</td> <td>-2</td> <td>-2</td> <td>-2</td> <td>-2</td> <td>throw {@code ArithmeticException}</td>
167.80 + * <tr align=right><td>-2.5</td> <td>-3</td> <td>-2</td> <td>-2</td> <td>-3</td> <td>-3</td> <td>-2</td> <td>-2</td> <td>throw {@code ArithmeticException}</td>
167.81 + * <tr align=right><td>-5.5</td> <td>-6</td> <td>-5</td> <td>-5</td> <td>-6</td> <td>-6</td> <td>-5</td> <td>-6</td> <td>throw {@code ArithmeticException}</td>
167.82 + *</table>
167.83 + *
167.84 + *
167.85 + * <p>This {@code enum} is intended to replace the integer-based
167.86 + * enumeration of rounding mode constants in {@link BigDecimal}
167.87 + * ({@link BigDecimal#ROUND_UP}, {@link BigDecimal#ROUND_DOWN},
167.88 + * etc. ).
167.89 + *
167.90 + * @see BigDecimal
167.91 + * @see MathContext
167.92 + * @author Josh Bloch
167.93 + * @author Mike Cowlishaw
167.94 + * @author Joseph D. Darcy
167.95 + * @since 1.5
167.96 + */
167.97 +public enum RoundingMode {
167.98 +
167.99 + /**
167.100 + * Rounding mode to round away from zero. Always increments the
167.101 + * digit prior to a non-zero discarded fraction. Note that this
167.102 + * rounding mode never decreases the magnitude of the calculated
167.103 + * value.
167.104 + *
167.105 + *<p>Example:
167.106 + *<table border>
167.107 + *<tr valign=top><th>Input Number</th>
167.108 + * <th>Input rounded to one digit<br> with {@code UP} rounding
167.109 + *<tr align=right><td>5.5</td> <td>6</td>
167.110 + *<tr align=right><td>2.5</td> <td>3</td>
167.111 + *<tr align=right><td>1.6</td> <td>2</td>
167.112 + *<tr align=right><td>1.1</td> <td>2</td>
167.113 + *<tr align=right><td>1.0</td> <td>1</td>
167.114 + *<tr align=right><td>-1.0</td> <td>-1</td>
167.115 + *<tr align=right><td>-1.1</td> <td>-2</td>
167.116 + *<tr align=right><td>-1.6</td> <td>-2</td>
167.117 + *<tr align=right><td>-2.5</td> <td>-3</td>
167.118 + *<tr align=right><td>-5.5</td> <td>-6</td>
167.119 + *</table>
167.120 + */
167.121 + UP(BigDecimal.ROUND_UP),
167.122 +
167.123 + /**
167.124 + * Rounding mode to round towards zero. Never increments the digit
167.125 + * prior to a discarded fraction (i.e., truncates). Note that this
167.126 + * rounding mode never increases the magnitude of the calculated value.
167.127 + *
167.128 + *<p>Example:
167.129 + *<table border>
167.130 + *<tr valign=top><th>Input Number</th>
167.131 + * <th>Input rounded to one digit<br> with {@code DOWN} rounding
167.132 + *<tr align=right><td>5.5</td> <td>5</td>
167.133 + *<tr align=right><td>2.5</td> <td>2</td>
167.134 + *<tr align=right><td>1.6</td> <td>1</td>
167.135 + *<tr align=right><td>1.1</td> <td>1</td>
167.136 + *<tr align=right><td>1.0</td> <td>1</td>
167.137 + *<tr align=right><td>-1.0</td> <td>-1</td>
167.138 + *<tr align=right><td>-1.1</td> <td>-1</td>
167.139 + *<tr align=right><td>-1.6</td> <td>-1</td>
167.140 + *<tr align=right><td>-2.5</td> <td>-2</td>
167.141 + *<tr align=right><td>-5.5</td> <td>-5</td>
167.142 + *</table>
167.143 + */
167.144 + DOWN(BigDecimal.ROUND_DOWN),
167.145 +
167.146 + /**
167.147 + * Rounding mode to round towards positive infinity. If the
167.148 + * result is positive, behaves as for {@code RoundingMode.UP};
167.149 + * if negative, behaves as for {@code RoundingMode.DOWN}. Note
167.150 + * that this rounding mode never decreases the calculated value.
167.151 + *
167.152 + *<p>Example:
167.153 + *<table border>
167.154 + *<tr valign=top><th>Input Number</th>
167.155 + * <th>Input rounded to one digit<br> with {@code CEILING} rounding
167.156 + *<tr align=right><td>5.5</td> <td>6</td>
167.157 + *<tr align=right><td>2.5</td> <td>3</td>
167.158 + *<tr align=right><td>1.6</td> <td>2</td>
167.159 + *<tr align=right><td>1.1</td> <td>2</td>
167.160 + *<tr align=right><td>1.0</td> <td>1</td>
167.161 + *<tr align=right><td>-1.0</td> <td>-1</td>
167.162 + *<tr align=right><td>-1.1</td> <td>-1</td>
167.163 + *<tr align=right><td>-1.6</td> <td>-1</td>
167.164 + *<tr align=right><td>-2.5</td> <td>-2</td>
167.165 + *<tr align=right><td>-5.5</td> <td>-5</td>
167.166 + *</table>
167.167 + */
167.168 + CEILING(BigDecimal.ROUND_CEILING),
167.169 +
167.170 + /**
167.171 + * Rounding mode to round towards negative infinity. If the
167.172 + * result is positive, behave as for {@code RoundingMode.DOWN};
167.173 + * if negative, behave as for {@code RoundingMode.UP}. Note that
167.174 + * this rounding mode never increases the calculated value.
167.175 + *
167.176 + *<p>Example:
167.177 + *<table border>
167.178 + *<tr valign=top><th>Input Number</th>
167.179 + * <th>Input rounded to one digit<br> with {@code FLOOR} rounding
167.180 + *<tr align=right><td>5.5</td> <td>5</td>
167.181 + *<tr align=right><td>2.5</td> <td>2</td>
167.182 + *<tr align=right><td>1.6</td> <td>1</td>
167.183 + *<tr align=right><td>1.1</td> <td>1</td>
167.184 + *<tr align=right><td>1.0</td> <td>1</td>
167.185 + *<tr align=right><td>-1.0</td> <td>-1</td>
167.186 + *<tr align=right><td>-1.1</td> <td>-2</td>
167.187 + *<tr align=right><td>-1.6</td> <td>-2</td>
167.188 + *<tr align=right><td>-2.5</td> <td>-3</td>
167.189 + *<tr align=right><td>-5.5</td> <td>-6</td>
167.190 + *</table>
167.191 + */
167.192 + FLOOR(BigDecimal.ROUND_FLOOR),
167.193 +
167.194 + /**
167.195 + * Rounding mode to round towards {@literal "nearest neighbor"}
167.196 + * unless both neighbors are equidistant, in which case round up.
167.197 + * Behaves as for {@code RoundingMode.UP} if the discarded
167.198 + * fraction is ≥ 0.5; otherwise, behaves as for
167.199 + * {@code RoundingMode.DOWN}. Note that this is the rounding
167.200 + * mode commonly taught at school.
167.201 + *
167.202 + *<p>Example:
167.203 + *<table border>
167.204 + *<tr valign=top><th>Input Number</th>
167.205 + * <th>Input rounded to one digit<br> with {@code HALF_UP} rounding
167.206 + *<tr align=right><td>5.5</td> <td>6</td>
167.207 + *<tr align=right><td>2.5</td> <td>3</td>
167.208 + *<tr align=right><td>1.6</td> <td>2</td>
167.209 + *<tr align=right><td>1.1</td> <td>1</td>
167.210 + *<tr align=right><td>1.0</td> <td>1</td>
167.211 + *<tr align=right><td>-1.0</td> <td>-1</td>
167.212 + *<tr align=right><td>-1.1</td> <td>-1</td>
167.213 + *<tr align=right><td>-1.6</td> <td>-2</td>
167.214 + *<tr align=right><td>-2.5</td> <td>-3</td>
167.215 + *<tr align=right><td>-5.5</td> <td>-6</td>
167.216 + *</table>
167.217 + */
167.218 + HALF_UP(BigDecimal.ROUND_HALF_UP),
167.219 +
167.220 + /**
167.221 + * Rounding mode to round towards {@literal "nearest neighbor"}
167.222 + * unless both neighbors are equidistant, in which case round
167.223 + * down. Behaves as for {@code RoundingMode.UP} if the discarded
167.224 + * fraction is > 0.5; otherwise, behaves as for
167.225 + * {@code RoundingMode.DOWN}.
167.226 + *
167.227 + *<p>Example:
167.228 + *<table border>
167.229 + *<tr valign=top><th>Input Number</th>
167.230 + * <th>Input rounded to one digit<br> with {@code HALF_DOWN} rounding
167.231 + *<tr align=right><td>5.5</td> <td>5</td>
167.232 + *<tr align=right><td>2.5</td> <td>2</td>
167.233 + *<tr align=right><td>1.6</td> <td>2</td>
167.234 + *<tr align=right><td>1.1</td> <td>1</td>
167.235 + *<tr align=right><td>1.0</td> <td>1</td>
167.236 + *<tr align=right><td>-1.0</td> <td>-1</td>
167.237 + *<tr align=right><td>-1.1</td> <td>-1</td>
167.238 + *<tr align=right><td>-1.6</td> <td>-2</td>
167.239 + *<tr align=right><td>-2.5</td> <td>-2</td>
167.240 + *<tr align=right><td>-5.5</td> <td>-5</td>
167.241 + *</table>
167.242 + */
167.243 + HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
167.244 +
167.245 + /**
167.246 + * Rounding mode to round towards the {@literal "nearest neighbor"}
167.247 + * unless both neighbors are equidistant, in which case, round
167.248 + * towards the even neighbor. Behaves as for
167.249 + * {@code RoundingMode.HALF_UP} if the digit to the left of the
167.250 + * discarded fraction is odd; behaves as for
167.251 + * {@code RoundingMode.HALF_DOWN} if it's even. Note that this
167.252 + * is the rounding mode that statistically minimizes cumulative
167.253 + * error when applied repeatedly over a sequence of calculations.
167.254 + * It is sometimes known as {@literal "Banker's rounding,"} and is
167.255 + * chiefly used in the USA. This rounding mode is analogous to
167.256 + * the rounding policy used for {@code float} and {@code double}
167.257 + * arithmetic in Java.
167.258 + *
167.259 + *<p>Example:
167.260 + *<table border>
167.261 + *<tr valign=top><th>Input Number</th>
167.262 + * <th>Input rounded to one digit<br> with {@code HALF_EVEN} rounding
167.263 + *<tr align=right><td>5.5</td> <td>6</td>
167.264 + *<tr align=right><td>2.5</td> <td>2</td>
167.265 + *<tr align=right><td>1.6</td> <td>2</td>
167.266 + *<tr align=right><td>1.1</td> <td>1</td>
167.267 + *<tr align=right><td>1.0</td> <td>1</td>
167.268 + *<tr align=right><td>-1.0</td> <td>-1</td>
167.269 + *<tr align=right><td>-1.1</td> <td>-1</td>
167.270 + *<tr align=right><td>-1.6</td> <td>-2</td>
167.271 + *<tr align=right><td>-2.5</td> <td>-2</td>
167.272 + *<tr align=right><td>-5.5</td> <td>-6</td>
167.273 + *</table>
167.274 + */
167.275 + HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
167.276 +
167.277 + /**
167.278 + * Rounding mode to assert that the requested operation has an exact
167.279 + * result, hence no rounding is necessary. If this rounding mode is
167.280 + * specified on an operation that yields an inexact result, an
167.281 + * {@code ArithmeticException} is thrown.
167.282 + *<p>Example:
167.283 + *<table border>
167.284 + *<tr valign=top><th>Input Number</th>
167.285 + * <th>Input rounded to one digit<br> with {@code UNNECESSARY} rounding
167.286 + *<tr align=right><td>5.5</td> <td>throw {@code ArithmeticException}</td>
167.287 + *<tr align=right><td>2.5</td> <td>throw {@code ArithmeticException}</td>
167.288 + *<tr align=right><td>1.6</td> <td>throw {@code ArithmeticException}</td>
167.289 + *<tr align=right><td>1.1</td> <td>throw {@code ArithmeticException}</td>
167.290 + *<tr align=right><td>1.0</td> <td>1</td>
167.291 + *<tr align=right><td>-1.0</td> <td>-1</td>
167.292 + *<tr align=right><td>-1.1</td> <td>throw {@code ArithmeticException}</td>
167.293 + *<tr align=right><td>-1.6</td> <td>throw {@code ArithmeticException}</td>
167.294 + *<tr align=right><td>-2.5</td> <td>throw {@code ArithmeticException}</td>
167.295 + *<tr align=right><td>-5.5</td> <td>throw {@code ArithmeticException}</td>
167.296 + *</table>
167.297 + */
167.298 + UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);
167.299 +
167.300 + // Corresponding BigDecimal rounding constant
167.301 + final int oldMode;
167.302 +
167.303 + /**
167.304 + * Constructor
167.305 + *
167.306 + * @param oldMode The {@code BigDecimal} constant corresponding to
167.307 + * this mode
167.308 + */
167.309 + private RoundingMode(int oldMode) {
167.310 + this.oldMode = oldMode;
167.311 + }
167.312 +
167.313 + /**
167.314 + * Returns the {@code RoundingMode} object corresponding to a
167.315 + * legacy integer rounding mode constant in {@link BigDecimal}.
167.316 + *
167.317 + * @param rm legacy integer rounding mode to convert
167.318 + * @return {@code RoundingMode} corresponding to the given integer.
167.319 + * @throws IllegalArgumentException integer is out of range
167.320 + */
167.321 + public static RoundingMode valueOf(int rm) {
167.322 + switch(rm) {
167.323 +
167.324 + case BigDecimal.ROUND_UP:
167.325 + return UP;
167.326 +
167.327 + case BigDecimal.ROUND_DOWN:
167.328 + return DOWN;
167.329 +
167.330 + case BigDecimal.ROUND_CEILING:
167.331 + return CEILING;
167.332 +
167.333 + case BigDecimal.ROUND_FLOOR:
167.334 + return FLOOR;
167.335 +
167.336 + case BigDecimal.ROUND_HALF_UP:
167.337 + return HALF_UP;
167.338 +
167.339 + case BigDecimal.ROUND_HALF_DOWN:
167.340 + return HALF_DOWN;
167.341 +
167.342 + case BigDecimal.ROUND_HALF_EVEN:
167.343 + return HALF_EVEN;
167.344 +
167.345 + case BigDecimal.ROUND_UNNECESSARY:
167.346 + return UNNECESSARY;
167.347 +
167.348 + default:
167.349 + throw new IllegalArgumentException("argument out of range");
167.350 + }
167.351 + }
167.352 +}
168.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
168.2 +++ b/rt/emul/compact/src/main/java/java/math/SignedMutableBigInteger.java Wed Apr 30 15:04:10 2014 +0200
168.3 @@ -0,0 +1,135 @@
168.4 +/*
168.5 + * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
168.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
168.7 + *
168.8 + * This code is free software; you can redistribute it and/or modify it
168.9 + * under the terms of the GNU General Public License version 2 only, as
168.10 + * published by the Free Software Foundation. Oracle designates this
168.11 + * particular file as subject to the "Classpath" exception as provided
168.12 + * by Oracle in the LICENSE file that accompanied this code.
168.13 + *
168.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
168.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
168.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
168.17 + * version 2 for more details (a copy is included in the LICENSE file that
168.18 + * accompanied this code).
168.19 + *
168.20 + * You should have received a copy of the GNU General Public License version
168.21 + * 2 along with this work; if not, write to the Free Software Foundation,
168.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
168.23 + *
168.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
168.25 + * or visit www.oracle.com if you need additional information or have any
168.26 + * questions.
168.27 + */
168.28 +
168.29 +package java.math;
168.30 +
168.31 +/**
168.32 + * A class used to represent multiprecision integers that makes efficient
168.33 + * use of allocated space by allowing a number to occupy only part of
168.34 + * an array so that the arrays do not have to be reallocated as often.
168.35 + * When performing an operation with many iterations the array used to
168.36 + * hold a number is only increased when necessary and does not have to
168.37 + * be the same size as the number it represents. A mutable number allows
168.38 + * calculations to occur on the same number without having to create
168.39 + * a new number for every step of the calculation as occurs with
168.40 + * BigIntegers.
168.41 + *
168.42 + * Note that SignedMutableBigIntegers only support signed addition and
168.43 + * subtraction. All other operations occur as with MutableBigIntegers.
168.44 + *
168.45 + * @see BigInteger
168.46 + * @author Michael McCloskey
168.47 + * @since 1.3
168.48 + */
168.49 +
168.50 +class SignedMutableBigInteger extends MutableBigInteger {
168.51 +
168.52 + /**
168.53 + * The sign of this MutableBigInteger.
168.54 + */
168.55 + int sign = 1;
168.56 +
168.57 + // Constructors
168.58 +
168.59 + /**
168.60 + * The default constructor. An empty MutableBigInteger is created with
168.61 + * a one word capacity.
168.62 + */
168.63 + SignedMutableBigInteger() {
168.64 + super();
168.65 + }
168.66 +
168.67 + /**
168.68 + * Construct a new MutableBigInteger with a magnitude specified by
168.69 + * the int val.
168.70 + */
168.71 + SignedMutableBigInteger(int val) {
168.72 + super(val);
168.73 + }
168.74 +
168.75 + /**
168.76 + * Construct a new MutableBigInteger with a magnitude equal to the
168.77 + * specified MutableBigInteger.
168.78 + */
168.79 + SignedMutableBigInteger(MutableBigInteger val) {
168.80 + super(val);
168.81 + }
168.82 +
168.83 + // Arithmetic Operations
168.84 +
168.85 + /**
168.86 + * Signed addition built upon unsigned add and subtract.
168.87 + */
168.88 + void signedAdd(SignedMutableBigInteger addend) {
168.89 + if (sign == addend.sign)
168.90 + add(addend);
168.91 + else
168.92 + sign = sign * subtract(addend);
168.93 +
168.94 + }
168.95 +
168.96 + /**
168.97 + * Signed addition built upon unsigned add and subtract.
168.98 + */
168.99 + void signedAdd(MutableBigInteger addend) {
168.100 + if (sign == 1)
168.101 + add(addend);
168.102 + else
168.103 + sign = sign * subtract(addend);
168.104 +
168.105 + }
168.106 +
168.107 + /**
168.108 + * Signed subtraction built upon unsigned add and subtract.
168.109 + */
168.110 + void signedSubtract(SignedMutableBigInteger addend) {
168.111 + if (sign == addend.sign)
168.112 + sign = sign * subtract(addend);
168.113 + else
168.114 + add(addend);
168.115 +
168.116 + }
168.117 +
168.118 + /**
168.119 + * Signed subtraction built upon unsigned add and subtract.
168.120 + */
168.121 + void signedSubtract(MutableBigInteger addend) {
168.122 + if (sign == 1)
168.123 + sign = sign * subtract(addend);
168.124 + else
168.125 + add(addend);
168.126 + if (intLen == 0)
168.127 + sign = 1;
168.128 + }
168.129 +
168.130 + /**
168.131 + * Print out the first intLen ints of this MutableBigInteger's value
168.132 + * array starting at offset.
168.133 + */
168.134 + public String toString() {
168.135 + return this.toBigInteger(sign).toString();
168.136 + }
168.137 +
168.138 +}
169.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
169.2 +++ b/rt/emul/compact/src/main/java/java/math/package-info.java Wed Apr 30 15:04:10 2014 +0200
169.3 @@ -0,0 +1,45 @@
169.4 +/*
169.5 + * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
169.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
169.7 + *
169.8 + * This code is free software; you can redistribute it and/or modify it
169.9 + * under the terms of the GNU General Public License version 2 only, as
169.10 + * published by the Free Software Foundation. Oracle designates this
169.11 + * particular file as subject to the "Classpath" exception as provided
169.12 + * by Oracle in the LICENSE file that accompanied this code.
169.13 + *
169.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
169.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
169.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
169.17 + * version 2 for more details (a copy is included in the LICENSE file that
169.18 + * accompanied this code).
169.19 + *
169.20 + * You should have received a copy of the GNU General Public License version
169.21 + * 2 along with this work; if not, write to the Free Software Foundation,
169.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
169.23 + *
169.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
169.25 + * or visit www.oracle.com if you need additional information or have any
169.26 + * questions.
169.27 + */
169.28 +
169.29 +/**
169.30 + * Provides classes for performing arbitrary-precision integer
169.31 + * arithmetic ({@code BigInteger}) and arbitrary-precision decimal
169.32 + * arithmetic ({@code BigDecimal}). {@code BigInteger} is analogous
169.33 + * to the primitive integer types except that it provides arbitrary
169.34 + * precision, hence operations on {@code BigInteger}s do not overflow
169.35 + * or lose precision. In addition to standard arithmetic operations,
169.36 + * {@code BigInteger} provides modular arithmetic, GCD calculation,
169.37 + * primality testing, prime generation, bit manipulation, and a few
169.38 + * other miscellaneous operations.
169.39 + *
169.40 + * {@code BigDecimal} provides arbitrary-precision signed decimal
169.41 + * numbers suitable for currency calculations and the like. {@code
169.42 + * BigDecimal} gives the user complete control over rounding behavior,
169.43 + * allowing the user to choose from a comprehensive set of eight
169.44 + * rounding modes.
169.45 + *
169.46 + * @since JDK1.1
169.47 + */
169.48 +package java.math;
170.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
170.2 +++ b/rt/emul/compact/src/main/java/java/net/URI.java Wed Apr 30 15:04:10 2014 +0200
170.3 @@ -0,0 +1,3520 @@
170.4 +/*
170.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
170.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
170.7 + *
170.8 + * This code is free software; you can redistribute it and/or modify it
170.9 + * under the terms of the GNU General Public License version 2 only, as
170.10 + * published by the Free Software Foundation. Oracle designates this
170.11 + * particular file as subject to the "Classpath" exception as provided
170.12 + * by Oracle in the LICENSE file that accompanied this code.
170.13 + *
170.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
170.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
170.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
170.17 + * version 2 for more details (a copy is included in the LICENSE file that
170.18 + * accompanied this code).
170.19 + *
170.20 + * You should have received a copy of the GNU General Public License version
170.21 + * 2 along with this work; if not, write to the Free Software Foundation,
170.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
170.23 + *
170.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
170.25 + * or visit www.oracle.com if you need additional information or have any
170.26 + * questions.
170.27 + */
170.28 +
170.29 +package java.net;
170.30 +
170.31 +import java.io.IOException;
170.32 +import java.io.InvalidObjectException;
170.33 +import java.io.ObjectInputStream;
170.34 +import java.io.ObjectOutputStream;
170.35 +import java.io.Serializable;
170.36 +
170.37 +import java.lang.Character; // for javadoc
170.38 +import java.lang.NullPointerException; // for javadoc
170.39 +
170.40 +
170.41 +/**
170.42 + * Represents a Uniform Resource Identifier (URI) reference.
170.43 + *
170.44 + * <p> Aside from some minor deviations noted below, an instance of this
170.45 + * class represents a URI reference as defined by
170.46 + * <a href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC 2396: Uniform
170.47 + * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
170.48 + * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC 2732: Format for
170.49 + * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
170.50 + * also supports scope_ids. The syntax and usage of scope_ids is described
170.51 + * <a href="Inet6Address.html#scoped">here</a>.
170.52 + * This class provides constructors for creating URI instances from
170.53 + * their components or by parsing their string forms, methods for accessing the
170.54 + * various components of an instance, and methods for normalizing, resolving,
170.55 + * and relativizing URI instances. Instances of this class are immutable.
170.56 + *
170.57 + *
170.58 + * <h4> URI syntax and components </h4>
170.59 + *
170.60 + * At the highest level a URI reference (hereinafter simply "URI") in string
170.61 + * form has the syntax
170.62 + *
170.63 + * <blockquote>
170.64 + * [<i>scheme</i><tt><b>:</b></tt><i></i>]<i>scheme-specific-part</i>[<tt><b>#</b></tt><i>fragment</i>]
170.65 + * </blockquote>
170.66 + *
170.67 + * where square brackets [...] delineate optional components and the characters
170.68 + * <tt><b>:</b></tt> and <tt><b>#</b></tt> stand for themselves.
170.69 + *
170.70 + * <p> An <i>absolute</i> URI specifies a scheme; a URI that is not absolute is
170.71 + * said to be <i>relative</i>. URIs are also classified according to whether
170.72 + * they are <i>opaque</i> or <i>hierarchical</i>.
170.73 + *
170.74 + * <p> An <i>opaque</i> URI is an absolute URI whose scheme-specific part does
170.75 + * not begin with a slash character (<tt>'/'</tt>). Opaque URIs are not
170.76 + * subject to further parsing. Some examples of opaque URIs are:
170.77 + *
170.78 + * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
170.79 + * <tr><td><tt>mailto:java-net@java.sun.com</tt><td></tr>
170.80 + * <tr><td><tt>news:comp.lang.java</tt><td></tr>
170.81 + * <tr><td><tt>urn:isbn:096139210x</tt></td></tr>
170.82 + * </table></blockquote>
170.83 + *
170.84 + * <p> A <i>hierarchical</i> URI is either an absolute URI whose
170.85 + * scheme-specific part begins with a slash character, or a relative URI, that
170.86 + * is, a URI that does not specify a scheme. Some examples of hierarchical
170.87 + * URIs are:
170.88 + *
170.89 + * <blockquote>
170.90 + * <tt>http://java.sun.com/j2se/1.3/</tt><br>
170.91 + * <tt>docs/guide/collections/designfaq.html#28</tt><br>
170.92 + * <tt>../../../demo/jfc/SwingSet2/src/SwingSet2.java</tt><br>
170.93 + * <tt>file:///~/calendar</tt>
170.94 + * </blockquote>
170.95 + *
170.96 + * <p> A hierarchical URI is subject to further parsing according to the syntax
170.97 + *
170.98 + * <blockquote>
170.99 + * [<i>scheme</i><tt><b>:</b></tt>][<tt><b>//</b></tt><i>authority</i>][<i>path</i>][<tt><b>?</b></tt><i>query</i>][<tt><b>#</b></tt><i>fragment</i>]
170.100 + * </blockquote>
170.101 + *
170.102 + * where the characters <tt><b>:</b></tt>, <tt><b>/</b></tt>,
170.103 + * <tt><b>?</b></tt>, and <tt><b>#</b></tt> stand for themselves. The
170.104 + * scheme-specific part of a hierarchical URI consists of the characters
170.105 + * between the scheme and fragment components.
170.106 + *
170.107 + * <p> The authority component of a hierarchical URI is, if specified, either
170.108 + * <i>server-based</i> or <i>registry-based</i>. A server-based authority
170.109 + * parses according to the familiar syntax
170.110 + *
170.111 + * <blockquote>
170.112 + * [<i>user-info</i><tt><b>@</b></tt>]<i>host</i>[<tt><b>:</b></tt><i>port</i>]
170.113 + * </blockquote>
170.114 + *
170.115 + * where the characters <tt><b>@</b></tt> and <tt><b>:</b></tt> stand for
170.116 + * themselves. Nearly all URI schemes currently in use are server-based. An
170.117 + * authority component that does not parse in this way is considered to be
170.118 + * registry-based.
170.119 + *
170.120 + * <p> The path component of a hierarchical URI is itself said to be absolute
170.121 + * if it begins with a slash character (<tt>'/'</tt>); otherwise it is
170.122 + * relative. The path of a hierarchical URI that is either absolute or
170.123 + * specifies an authority is always absolute.
170.124 + *
170.125 + * <p> All told, then, a URI instance has the following nine components:
170.126 + *
170.127 + * <blockquote><table summary="Describes the components of a URI:scheme,scheme-specific-part,authority,user-info,host,port,path,query,fragment">
170.128 + * <tr><th><i>Component</i></th><th><i>Type</i></th></tr>
170.129 + * <tr><td>scheme</td><td><tt>String</tt></td></tr>
170.130 + * <tr><td>scheme-specific-part </td><td><tt>String</tt></td></tr>
170.131 + * <tr><td>authority</td><td><tt>String</tt></td></tr>
170.132 + * <tr><td>user-info</td><td><tt>String</tt></td></tr>
170.133 + * <tr><td>host</td><td><tt>String</tt></td></tr>
170.134 + * <tr><td>port</td><td><tt>int</tt></td></tr>
170.135 + * <tr><td>path</td><td><tt>String</tt></td></tr>
170.136 + * <tr><td>query</td><td><tt>String</tt></td></tr>
170.137 + * <tr><td>fragment</td><td><tt>String</tt></td></tr>
170.138 + * </table></blockquote>
170.139 + *
170.140 + * In a given instance any particular component is either <i>undefined</i> or
170.141 + * <i>defined</i> with a distinct value. Undefined string components are
170.142 + * represented by <tt>null</tt>, while undefined integer components are
170.143 + * represented by <tt>-1</tt>. A string component may be defined to have the
170.144 + * empty string as its value; this is not equivalent to that component being
170.145 + * undefined.
170.146 + *
170.147 + * <p> Whether a particular component is or is not defined in an instance
170.148 + * depends upon the type of the URI being represented. An absolute URI has a
170.149 + * scheme component. An opaque URI has a scheme, a scheme-specific part, and
170.150 + * possibly a fragment, but has no other components. A hierarchical URI always
170.151 + * has a path (though it may be empty) and a scheme-specific-part (which at
170.152 + * least contains the path), and may have any of the other components. If the
170.153 + * authority component is present and is server-based then the host component
170.154 + * will be defined and the user-information and port components may be defined.
170.155 + *
170.156 + *
170.157 + * <h4> Operations on URI instances </h4>
170.158 + *
170.159 + * The key operations supported by this class are those of
170.160 + * <i>normalization</i>, <i>resolution</i>, and <i>relativization</i>.
170.161 + *
170.162 + * <p> <i>Normalization</i> is the process of removing unnecessary <tt>"."</tt>
170.163 + * and <tt>".."</tt> segments from the path component of a hierarchical URI.
170.164 + * Each <tt>"."</tt> segment is simply removed. A <tt>".."</tt> segment is
170.165 + * removed only if it is preceded by a non-<tt>".."</tt> segment.
170.166 + * Normalization has no effect upon opaque URIs.
170.167 + *
170.168 + * <p> <i>Resolution</i> is the process of resolving one URI against another,
170.169 + * <i>base</i> URI. The resulting URI is constructed from components of both
170.170 + * URIs in the manner specified by RFC 2396, taking components from the
170.171 + * base URI for those not specified in the original. For hierarchical URIs,
170.172 + * the path of the original is resolved against the path of the base and then
170.173 + * normalized. The result, for example, of resolving
170.174 + *
170.175 + * <blockquote>
170.176 + * <tt>docs/guide/collections/designfaq.html#28 </tt>(1)
170.177 + * </blockquote>
170.178 + *
170.179 + * against the base URI <tt>http://java.sun.com/j2se/1.3/</tt> is the result
170.180 + * URI
170.181 + *
170.182 + * <blockquote>
170.183 + * <tt>http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html#28</tt>
170.184 + * </blockquote>
170.185 + *
170.186 + * Resolving the relative URI
170.187 + *
170.188 + * <blockquote>
170.189 + * <tt>../../../demo/jfc/SwingSet2/src/SwingSet2.java </tt>(2)
170.190 + * </blockquote>
170.191 + *
170.192 + * against this result yields, in turn,
170.193 + *
170.194 + * <blockquote>
170.195 + * <tt>http://java.sun.com/j2se/1.3/demo/jfc/SwingSet2/src/SwingSet2.java</tt>
170.196 + * </blockquote>
170.197 + *
170.198 + * Resolution of both absolute and relative URIs, and of both absolute and
170.199 + * relative paths in the case of hierarchical URIs, is supported. Resolving
170.200 + * the URI <tt>file:///~calendar</tt> against any other URI simply yields the
170.201 + * original URI, since it is absolute. Resolving the relative URI (2) above
170.202 + * against the relative base URI (1) yields the normalized, but still relative,
170.203 + * URI
170.204 + *
170.205 + * <blockquote>
170.206 + * <tt>demo/jfc/SwingSet2/src/SwingSet2.java</tt>
170.207 + * </blockquote>
170.208 + *
170.209 + * <p> <i>Relativization</i>, finally, is the inverse of resolution: For any
170.210 + * two normalized URIs <i>u</i> and <i>v</i>,
170.211 + *
170.212 + * <blockquote>
170.213 + * <i>u</i><tt>.relativize(</tt><i>u</i><tt>.resolve(</tt><i>v</i><tt>)).equals(</tt><i>v</i><tt>)</tt> and<br>
170.214 + * <i>u</i><tt>.resolve(</tt><i>u</i><tt>.relativize(</tt><i>v</i><tt>)).equals(</tt><i>v</i><tt>)</tt> .<br>
170.215 + * </blockquote>
170.216 + *
170.217 + * This operation is often useful when constructing a document containing URIs
170.218 + * that must be made relative to the base URI of the document wherever
170.219 + * possible. For example, relativizing the URI
170.220 + *
170.221 + * <blockquote>
170.222 + * <tt>http://java.sun.com/j2se/1.3/docs/guide/index.html</tt>
170.223 + * </blockquote>
170.224 + *
170.225 + * against the base URI
170.226 + *
170.227 + * <blockquote>
170.228 + * <tt>http://java.sun.com/j2se/1.3</tt>
170.229 + * </blockquote>
170.230 + *
170.231 + * yields the relative URI <tt>docs/guide/index.html</tt>.
170.232 + *
170.233 + *
170.234 + * <h4> Character categories </h4>
170.235 + *
170.236 + * RFC 2396 specifies precisely which characters are permitted in the
170.237 + * various components of a URI reference. The following categories, most of
170.238 + * which are taken from that specification, are used below to describe these
170.239 + * constraints:
170.240 + *
170.241 + * <blockquote><table cellspacing=2 summary="Describes categories alpha,digit,alphanum,unreserved,punct,reserved,escaped,and other">
170.242 + * <tr><th valign=top><i>alpha</i></th>
170.243 + * <td>The US-ASCII alphabetic characters,
170.244 + * <tt>'A'</tt> through <tt>'Z'</tt>
170.245 + * and <tt>'a'</tt> through <tt>'z'</tt></td></tr>
170.246 + * <tr><th valign=top><i>digit</i></th>
170.247 + * <td>The US-ASCII decimal digit characters,
170.248 + * <tt>'0'</tt> through <tt>'9'</tt></td></tr>
170.249 + * <tr><th valign=top><i>alphanum</i></th>
170.250 + * <td>All <i>alpha</i> and <i>digit</i> characters</td></tr>
170.251 + * <tr><th valign=top><i>unreserved</i> </th>
170.252 + * <td>All <i>alphanum</i> characters together with those in the string
170.253 + * <tt>"_-!.~'()*"</tt></td></tr>
170.254 + * <tr><th valign=top><i>punct</i></th>
170.255 + * <td>The characters in the string <tt>",;:$&+="</tt></td></tr>
170.256 + * <tr><th valign=top><i>reserved</i></th>
170.257 + * <td>All <i>punct</i> characters together with those in the string
170.258 + * <tt>"?/[]@"</tt></td></tr>
170.259 + * <tr><th valign=top><i>escaped</i></th>
170.260 + * <td>Escaped octets, that is, triplets consisting of the percent
170.261 + * character (<tt>'%'</tt>) followed by two hexadecimal digits
170.262 + * (<tt>'0'</tt>-<tt>'9'</tt>, <tt>'A'</tt>-<tt>'F'</tt>, and
170.263 + * <tt>'a'</tt>-<tt>'f'</tt>)</td></tr>
170.264 + * <tr><th valign=top><i>other</i></th>
170.265 + * <td>The Unicode characters that are not in the US-ASCII character set,
170.266 + * are not control characters (according to the {@link
170.267 + * java.lang.Character#isISOControl(char) Character.isISOControl}
170.268 + * method), and are not space characters (according to the {@link
170.269 + * java.lang.Character#isSpaceChar(char) Character.isSpaceChar}
170.270 + * method) <i>(<b>Deviation from RFC 2396</b>, which is
170.271 + * limited to US-ASCII)</i></td></tr>
170.272 + * </table></blockquote>
170.273 + *
170.274 + * <p><a name="legal-chars"></a> The set of all legal URI characters consists of
170.275 + * the <i>unreserved</i>, <i>reserved</i>, <i>escaped</i>, and <i>other</i>
170.276 + * characters.
170.277 + *
170.278 + *
170.279 + * <h4> Escaped octets, quotation, encoding, and decoding </h4>
170.280 + *
170.281 + * RFC 2396 allows escaped octets to appear in the user-info, path, query, and
170.282 + * fragment components. Escaping serves two purposes in URIs:
170.283 + *
170.284 + * <ul>
170.285 + *
170.286 + * <li><p> To <i>encode</i> non-US-ASCII characters when a URI is required to
170.287 + * conform strictly to RFC 2396 by not containing any <i>other</i>
170.288 + * characters. </p></li>
170.289 + *
170.290 + * <li><p> To <i>quote</i> characters that are otherwise illegal in a
170.291 + * component. The user-info, path, query, and fragment components differ
170.292 + * slightly in terms of which characters are considered legal and illegal.
170.293 + * </p></li>
170.294 + *
170.295 + * </ul>
170.296 + *
170.297 + * These purposes are served in this class by three related operations:
170.298 + *
170.299 + * <ul>
170.300 + *
170.301 + * <li><p><a name="encode"></a> A character is <i>encoded</i> by replacing it
170.302 + * with the sequence of escaped octets that represent that character in the
170.303 + * UTF-8 character set. The Euro currency symbol (<tt>'\u20AC'</tt>),
170.304 + * for example, is encoded as <tt>"%E2%82%AC"</tt>. <i>(<b>Deviation from
170.305 + * RFC 2396</b>, which does not specify any particular character
170.306 + * set.)</i> </p></li>
170.307 + *
170.308 + * <li><p><a name="quote"></a> An illegal character is <i>quoted</i> simply by
170.309 + * encoding it. The space character, for example, is quoted by replacing it
170.310 + * with <tt>"%20"</tt>. UTF-8 contains US-ASCII, hence for US-ASCII
170.311 + * characters this transformation has exactly the effect required by
170.312 + * RFC 2396. </p></li>
170.313 + *
170.314 + * <li><p><a name="decode"></a>
170.315 + * A sequence of escaped octets is <i>decoded</i> by
170.316 + * replacing it with the sequence of characters that it represents in the
170.317 + * UTF-8 character set. UTF-8 contains US-ASCII, hence decoding has the
170.318 + * effect of de-quoting any quoted US-ASCII characters as well as that of
170.319 + * decoding any encoded non-US-ASCII characters. If a <a
170.320 + * href="../nio/charset/CharsetDecoder.html#ce">decoding error</a> occurs
170.321 + * when decoding the escaped octets then the erroneous octets are replaced by
170.322 + * <tt>'\uFFFD'</tt>, the Unicode replacement character. </p></li>
170.323 + *
170.324 + * </ul>
170.325 + *
170.326 + * These operations are exposed in the constructors and methods of this class
170.327 + * as follows:
170.328 + *
170.329 + * <ul>
170.330 + *
170.331 + * <li><p> The {@link #URI(java.lang.String) <code>single-argument
170.332 + * constructor</code>} requires any illegal characters in its argument to be
170.333 + * quoted and preserves any escaped octets and <i>other</i> characters that
170.334 + * are present. </p></li>
170.335 + *
170.336 + * <li><p> The {@link
170.337 + * #URI(java.lang.String,java.lang.String,java.lang.String,int,java.lang.String,java.lang.String,java.lang.String)
170.338 + * <code>multi-argument constructors</code>} quote illegal characters as
170.339 + * required by the components in which they appear. The percent character
170.340 + * (<tt>'%'</tt>) is always quoted by these constructors. Any <i>other</i>
170.341 + * characters are preserved. </p></li>
170.342 + *
170.343 + * <li><p> The {@link #getRawUserInfo() getRawUserInfo}, {@link #getRawPath()
170.344 + * getRawPath}, {@link #getRawQuery() getRawQuery}, {@link #getRawFragment()
170.345 + * getRawFragment}, {@link #getRawAuthority() getRawAuthority}, and {@link
170.346 + * #getRawSchemeSpecificPart() getRawSchemeSpecificPart} methods return the
170.347 + * values of their corresponding components in raw form, without interpreting
170.348 + * any escaped octets. The strings returned by these methods may contain
170.349 + * both escaped octets and <i>other</i> characters, and will not contain any
170.350 + * illegal characters. </p></li>
170.351 + *
170.352 + * <li><p> The {@link #getUserInfo() getUserInfo}, {@link #getPath()
170.353 + * getPath}, {@link #getQuery() getQuery}, {@link #getFragment()
170.354 + * getFragment}, {@link #getAuthority() getAuthority}, and {@link
170.355 + * #getSchemeSpecificPart() getSchemeSpecificPart} methods decode any escaped
170.356 + * octets in their corresponding components. The strings returned by these
170.357 + * methods may contain both <i>other</i> characters and illegal characters,
170.358 + * and will not contain any escaped octets. </p></li>
170.359 + *
170.360 + * <li><p> The {@link #toString() toString} method returns a URI string with
170.361 + * all necessary quotation but which may contain <i>other</i> characters.
170.362 + * </p></li>
170.363 + *
170.364 + * <li><p> The {@link #toASCIIString() toASCIIString} method returns a fully
170.365 + * quoted and encoded URI string that does not contain any <i>other</i>
170.366 + * characters. </p></li>
170.367 + *
170.368 + * </ul>
170.369 + *
170.370 + *
170.371 + * <h4> Identities </h4>
170.372 + *
170.373 + * For any URI <i>u</i>, it is always the case that
170.374 + *
170.375 + * <blockquote>
170.376 + * <tt>new URI(</tt><i>u</i><tt>.toString()).equals(</tt><i>u</i><tt>)</tt> .
170.377 + * </blockquote>
170.378 + *
170.379 + * For any URI <i>u</i> that does not contain redundant syntax such as two
170.380 + * slashes before an empty authority (as in <tt>file:///tmp/</tt> ) or a
170.381 + * colon following a host name but no port (as in
170.382 + * <tt>http://java.sun.com:</tt> ), and that does not encode characters
170.383 + * except those that must be quoted, the following identities also hold:
170.384 + *
170.385 + * <blockquote>
170.386 + * <tt>new URI(</tt><i>u</i><tt>.getScheme(),<br>
170.387 + * </tt><i>u</i><tt>.getSchemeSpecificPart(),<br>
170.388 + * </tt><i>u</i><tt>.getFragment())<br>
170.389 + * .equals(</tt><i>u</i><tt>)</tt>
170.390 + * </blockquote>
170.391 + *
170.392 + * in all cases,
170.393 + *
170.394 + * <blockquote>
170.395 + * <tt>new URI(</tt><i>u</i><tt>.getScheme(),<br>
170.396 + * </tt><i>u</i><tt>.getUserInfo(), </tt><i>u</i><tt>.getAuthority(),<br>
170.397 + * </tt><i>u</i><tt>.getPath(), </tt><i>u</i><tt>.getQuery(),<br>
170.398 + * </tt><i>u</i><tt>.getFragment())<br>
170.399 + * .equals(</tt><i>u</i><tt>)</tt>
170.400 + * </blockquote>
170.401 + *
170.402 + * if <i>u</i> is hierarchical, and
170.403 + *
170.404 + * <blockquote>
170.405 + * <tt>new URI(</tt><i>u</i><tt>.getScheme(),<br>
170.406 + * </tt><i>u</i><tt>.getUserInfo(), </tt><i>u</i><tt>.getHost(), </tt><i>u</i><tt>.getPort(),<br>
170.407 + * </tt><i>u</i><tt>.getPath(), </tt><i>u</i><tt>.getQuery(),<br>
170.408 + * </tt><i>u</i><tt>.getFragment())<br>
170.409 + * .equals(</tt><i>u</i><tt>)</tt>
170.410 + * </blockquote>
170.411 + *
170.412 + * if <i>u</i> is hierarchical and has either no authority or a server-based
170.413 + * authority.
170.414 + *
170.415 + *
170.416 + * <h4> URIs, URLs, and URNs </h4>
170.417 + *
170.418 + * A URI is a uniform resource <i>identifier</i> while a URL is a uniform
170.419 + * resource <i>locator</i>. Hence every URL is a URI, abstractly speaking, but
170.420 + * not every URI is a URL. This is because there is another subcategory of
170.421 + * URIs, uniform resource <i>names</i> (URNs), which name resources but do not
170.422 + * specify how to locate them. The <tt>mailto</tt>, <tt>news</tt>, and
170.423 + * <tt>isbn</tt> URIs shown above are examples of URNs.
170.424 + *
170.425 + * <p> The conceptual distinction between URIs and URLs is reflected in the
170.426 + * differences between this class and the {@link URL} class.
170.427 + *
170.428 + * <p> An instance of this class represents a URI reference in the syntactic
170.429 + * sense defined by RFC 2396. A URI may be either absolute or relative.
170.430 + * A URI string is parsed according to the generic syntax without regard to the
170.431 + * scheme, if any, that it specifies. No lookup of the host, if any, is
170.432 + * performed, and no scheme-dependent stream handler is constructed. Equality,
170.433 + * hashing, and comparison are defined strictly in terms of the character
170.434 + * content of the instance. In other words, a URI instance is little more than
170.435 + * a structured string that supports the syntactic, scheme-independent
170.436 + * operations of comparison, normalization, resolution, and relativization.
170.437 + *
170.438 + * <p> An instance of the {@link URL} class, by contrast, represents the
170.439 + * syntactic components of a URL together with some of the information required
170.440 + * to access the resource that it describes. A URL must be absolute, that is,
170.441 + * it must always specify a scheme. A URL string is parsed according to its
170.442 + * scheme. A stream handler is always established for a URL, and in fact it is
170.443 + * impossible to create a URL instance for a scheme for which no handler is
170.444 + * available. Equality and hashing depend upon both the scheme and the
170.445 + * Internet address of the host, if any; comparison is not defined. In other
170.446 + * words, a URL is a structured string that supports the syntactic operation of
170.447 + * resolution as well as the network I/O operations of looking up the host and
170.448 + * opening a connection to the specified resource.
170.449 + *
170.450 + *
170.451 + * @author Mark Reinhold
170.452 + * @since 1.4
170.453 + *
170.454 + * @see <a href="http://www.ietf.org/rfc/rfc2279.txt"><i>RFC 2279: UTF-8, a
170.455 + * transformation format of ISO 10646</i></a>, <br><a
170.456 + * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC 2373: IPv6 Addressing
170.457 + * Architecture</i></a>, <br><a
170.458 + * href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC 2396: Uniform
170.459 + * Resource Identifiers (URI): Generic Syntax</i></a>, <br><a
170.460 + * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC 2732: Format for
170.461 + * Literal IPv6 Addresses in URLs</i></a>, <br><a
170.462 + * href="URISyntaxException.html">URISyntaxException</a>
170.463 + */
170.464 +
170.465 +public final class URI
170.466 + implements Comparable<URI>, Serializable
170.467 +{
170.468 +
170.469 + // Note: Comments containing the word "ASSERT" indicate places where a
170.470 + // throw of an InternalError should be replaced by an appropriate assertion
170.471 + // statement once asserts are enabled in the build.
170.472 +
170.473 + static final long serialVersionUID = -6052424284110960213L;
170.474 +
170.475 +
170.476 + // -- Properties and components of this instance --
170.477 +
170.478 + // Components of all URIs: [<scheme>:]<scheme-specific-part>[#<fragment>]
170.479 + private transient String scheme; // null ==> relative URI
170.480 + private transient String fragment;
170.481 +
170.482 + // Hierarchical URI components: [//<authority>]<path>[?<query>]
170.483 + private transient String authority; // Registry or server
170.484 +
170.485 + // Server-based authority: [<userInfo>@]<host>[:<port>]
170.486 + private transient String userInfo;
170.487 + private transient String host; // null ==> registry-based
170.488 + private transient int port = -1; // -1 ==> undefined
170.489 +
170.490 + // Remaining components of hierarchical URIs
170.491 + private transient String path; // null ==> opaque
170.492 + private transient String query;
170.493 +
170.494 + // The remaining fields may be computed on demand
170.495 +
170.496 + private volatile transient String schemeSpecificPart;
170.497 + private volatile transient int hash; // Zero ==> undefined
170.498 +
170.499 + private volatile transient String decodedUserInfo = null;
170.500 + private volatile transient String decodedAuthority = null;
170.501 + private volatile transient String decodedPath = null;
170.502 + private volatile transient String decodedQuery = null;
170.503 + private volatile transient String decodedFragment = null;
170.504 + private volatile transient String decodedSchemeSpecificPart = null;
170.505 +
170.506 + /**
170.507 + * The string form of this URI.
170.508 + *
170.509 + * @serial
170.510 + */
170.511 + private volatile String string; // The only serializable field
170.512 +
170.513 +
170.514 +
170.515 + // -- Constructors and factories --
170.516 +
170.517 + private URI() { } // Used internally
170.518 +
170.519 + /**
170.520 + * Constructs a URI by parsing the given string.
170.521 + *
170.522 + * <p> This constructor parses the given string exactly as specified by the
170.523 + * grammar in <a
170.524 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
170.525 + * Appendix A, <b><i>except for the following deviations:</i></b> </p>
170.526 + *
170.527 + * <ul type=disc>
170.528 + *
170.529 + * <li><p> An empty authority component is permitted as long as it is
170.530 + * followed by a non-empty path, a query component, or a fragment
170.531 + * component. This allows the parsing of URIs such as
170.532 + * <tt>"file:///foo/bar"</tt>, which seems to be the intent of
170.533 + * RFC 2396 although the grammar does not permit it. If the
170.534 + * authority component is empty then the user-information, host, and port
170.535 + * components are undefined. </p></li>
170.536 + *
170.537 + * <li><p> Empty relative paths are permitted; this seems to be the
170.538 + * intent of RFC 2396 although the grammar does not permit it. The
170.539 + * primary consequence of this deviation is that a standalone fragment
170.540 + * such as <tt>"#foo"</tt> parses as a relative URI with an empty path
170.541 + * and the given fragment, and can be usefully <a
170.542 + * href="#resolve-frag">resolved</a> against a base URI.
170.543 + *
170.544 + * <li><p> IPv4 addresses in host components are parsed rigorously, as
170.545 + * specified by <a
170.546 + * href="http://www.ietf.org/rfc/rfc2732.txt">RFC 2732</a>: Each
170.547 + * element of a dotted-quad address must contain no more than three
170.548 + * decimal digits. Each element is further constrained to have a value
170.549 + * no greater than 255. </p></li>
170.550 + *
170.551 + * <li> <p> Hostnames in host components that comprise only a single
170.552 + * domain label are permitted to start with an <i>alphanum</i>
170.553 + * character. This seems to be the intent of <a
170.554 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>
170.555 + * section 3.2.2 although the grammar does not permit it. The
170.556 + * consequence of this deviation is that the authority component of a
170.557 + * hierarchical URI such as <tt>s://123</tt>, will parse as a server-based
170.558 + * authority. </p></li>
170.559 + *
170.560 + * <li><p> IPv6 addresses are permitted for the host component. An IPv6
170.561 + * address must be enclosed in square brackets (<tt>'['</tt> and
170.562 + * <tt>']'</tt>) as specified by <a
170.563 + * href="http://www.ietf.org/rfc/rfc2732.txt">RFC 2732</a>. The
170.564 + * IPv6 address itself must parse according to <a
170.565 + * href="http://www.ietf.org/rfc/rfc2373.txt">RFC 2373</a>. IPv6
170.566 + * addresses are further constrained to describe no more than sixteen
170.567 + * bytes of address information, a constraint implicit in RFC 2373
170.568 + * but not expressible in the grammar. </p></li>
170.569 + *
170.570 + * <li><p> Characters in the <i>other</i> category are permitted wherever
170.571 + * RFC 2396 permits <i>escaped</i> octets, that is, in the
170.572 + * user-information, path, query, and fragment components, as well as in
170.573 + * the authority component if the authority is registry-based. This
170.574 + * allows URIs to contain Unicode characters beyond those in the US-ASCII
170.575 + * character set. </p></li>
170.576 + *
170.577 + * </ul>
170.578 + *
170.579 + * @param str The string to be parsed into a URI
170.580 + *
170.581 + * @throws NullPointerException
170.582 + * If <tt>str</tt> is <tt>null</tt>
170.583 + *
170.584 + * @throws URISyntaxException
170.585 + * If the given string violates RFC 2396, as augmented
170.586 + * by the above deviations
170.587 + */
170.588 + public URI(String str) throws URISyntaxException {
170.589 + new Parser(str).parse(false);
170.590 + }
170.591 +
170.592 + /**
170.593 + * Constructs a hierarchical URI from the given components.
170.594 + *
170.595 + * <p> If a scheme is given then the path, if also given, must either be
170.596 + * empty or begin with a slash character (<tt>'/'</tt>). Otherwise a
170.597 + * component of the new URI may be left undefined by passing <tt>null</tt>
170.598 + * for the corresponding parameter or, in the case of the <tt>port</tt>
170.599 + * parameter, by passing <tt>-1</tt>.
170.600 + *
170.601 + * <p> This constructor first builds a URI string from the given components
170.602 + * according to the rules specified in <a
170.603 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
170.604 + * section 5.2, step 7: </p>
170.605 + *
170.606 + * <ol>
170.607 + *
170.608 + * <li><p> Initially, the result string is empty. </p></li>
170.609 + *
170.610 + * <li><p> If a scheme is given then it is appended to the result,
170.611 + * followed by a colon character (<tt>':'</tt>). </p></li>
170.612 + *
170.613 + * <li><p> If user information, a host, or a port are given then the
170.614 + * string <tt>"//"</tt> is appended. </p></li>
170.615 + *
170.616 + * <li><p> If user information is given then it is appended, followed by
170.617 + * a commercial-at character (<tt>'@'</tt>). Any character not in the
170.618 + * <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
170.619 + * categories is <a href="#quote">quoted</a>. </p></li>
170.620 + *
170.621 + * <li><p> If a host is given then it is appended. If the host is a
170.622 + * literal IPv6 address but is not enclosed in square brackets
170.623 + * (<tt>'['</tt> and <tt>']'</tt>) then the square brackets are added.
170.624 + * </p></li>
170.625 + *
170.626 + * <li><p> If a port number is given then a colon character
170.627 + * (<tt>':'</tt>) is appended, followed by the port number in decimal.
170.628 + * </p></li>
170.629 + *
170.630 + * <li><p> If a path is given then it is appended. Any character not in
170.631 + * the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
170.632 + * categories, and not equal to the slash character (<tt>'/'</tt>) or the
170.633 + * commercial-at character (<tt>'@'</tt>), is quoted. </p></li>
170.634 + *
170.635 + * <li><p> If a query is given then a question-mark character
170.636 + * (<tt>'?'</tt>) is appended, followed by the query. Any character that
170.637 + * is not a <a href="#legal-chars">legal URI character</a> is quoted.
170.638 + * </p></li>
170.639 + *
170.640 + * <li><p> Finally, if a fragment is given then a hash character
170.641 + * (<tt>'#'</tt>) is appended, followed by the fragment. Any character
170.642 + * that is not a legal URI character is quoted. </p></li>
170.643 + *
170.644 + * </ol>
170.645 + *
170.646 + * <p> The resulting URI string is then parsed as if by invoking the {@link
170.647 + * #URI(String)} constructor and then invoking the {@link
170.648 + * #parseServerAuthority()} method upon the result; this may cause a {@link
170.649 + * URISyntaxException} to be thrown. </p>
170.650 + *
170.651 + * @param scheme Scheme name
170.652 + * @param userInfo User name and authorization information
170.653 + * @param host Host name
170.654 + * @param port Port number
170.655 + * @param path Path
170.656 + * @param query Query
170.657 + * @param fragment Fragment
170.658 + *
170.659 + * @throws URISyntaxException
170.660 + * If both a scheme and a path are given but the path is relative,
170.661 + * if the URI string constructed from the given components violates
170.662 + * RFC 2396, or if the authority component of the string is
170.663 + * present but cannot be parsed as a server-based authority
170.664 + */
170.665 + public URI(String scheme,
170.666 + String userInfo, String host, int port,
170.667 + String path, String query, String fragment)
170.668 + throws URISyntaxException
170.669 + {
170.670 + String s = toString(scheme, null,
170.671 + null, userInfo, host, port,
170.672 + path, query, fragment);
170.673 + checkPath(s, scheme, path);
170.674 + new Parser(s).parse(true);
170.675 + }
170.676 +
170.677 + /**
170.678 + * Constructs a hierarchical URI from the given components.
170.679 + *
170.680 + * <p> If a scheme is given then the path, if also given, must either be
170.681 + * empty or begin with a slash character (<tt>'/'</tt>). Otherwise a
170.682 + * component of the new URI may be left undefined by passing <tt>null</tt>
170.683 + * for the corresponding parameter.
170.684 + *
170.685 + * <p> This constructor first builds a URI string from the given components
170.686 + * according to the rules specified in <a
170.687 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
170.688 + * section 5.2, step 7: </p>
170.689 + *
170.690 + * <ol>
170.691 + *
170.692 + * <li><p> Initially, the result string is empty. </p></li>
170.693 + *
170.694 + * <li><p> If a scheme is given then it is appended to the result,
170.695 + * followed by a colon character (<tt>':'</tt>). </p></li>
170.696 + *
170.697 + * <li><p> If an authority is given then the string <tt>"//"</tt> is
170.698 + * appended, followed by the authority. If the authority contains a
170.699 + * literal IPv6 address then the address must be enclosed in square
170.700 + * brackets (<tt>'['</tt> and <tt>']'</tt>). Any character not in the
170.701 + * <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
170.702 + * categories, and not equal to the commercial-at character
170.703 + * (<tt>'@'</tt>), is <a href="#quote">quoted</a>. </p></li>
170.704 + *
170.705 + * <li><p> If a path is given then it is appended. Any character not in
170.706 + * the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
170.707 + * categories, and not equal to the slash character (<tt>'/'</tt>) or the
170.708 + * commercial-at character (<tt>'@'</tt>), is quoted. </p></li>
170.709 + *
170.710 + * <li><p> If a query is given then a question-mark character
170.711 + * (<tt>'?'</tt>) is appended, followed by the query. Any character that
170.712 + * is not a <a href="#legal-chars">legal URI character</a> is quoted.
170.713 + * </p></li>
170.714 + *
170.715 + * <li><p> Finally, if a fragment is given then a hash character
170.716 + * (<tt>'#'</tt>) is appended, followed by the fragment. Any character
170.717 + * that is not a legal URI character is quoted. </p></li>
170.718 + *
170.719 + * </ol>
170.720 + *
170.721 + * <p> The resulting URI string is then parsed as if by invoking the {@link
170.722 + * #URI(String)} constructor and then invoking the {@link
170.723 + * #parseServerAuthority()} method upon the result; this may cause a {@link
170.724 + * URISyntaxException} to be thrown. </p>
170.725 + *
170.726 + * @param scheme Scheme name
170.727 + * @param authority Authority
170.728 + * @param path Path
170.729 + * @param query Query
170.730 + * @param fragment Fragment
170.731 + *
170.732 + * @throws URISyntaxException
170.733 + * If both a scheme and a path are given but the path is relative,
170.734 + * if the URI string constructed from the given components violates
170.735 + * RFC 2396, or if the authority component of the string is
170.736 + * present but cannot be parsed as a server-based authority
170.737 + */
170.738 + public URI(String scheme,
170.739 + String authority,
170.740 + String path, String query, String fragment)
170.741 + throws URISyntaxException
170.742 + {
170.743 + String s = toString(scheme, null,
170.744 + authority, null, null, -1,
170.745 + path, query, fragment);
170.746 + checkPath(s, scheme, path);
170.747 + new Parser(s).parse(false);
170.748 + }
170.749 +
170.750 + /**
170.751 + * Constructs a hierarchical URI from the given components.
170.752 + *
170.753 + * <p> A component may be left undefined by passing <tt>null</tt>.
170.754 + *
170.755 + * <p> This convenience constructor works as if by invoking the
170.756 + * seven-argument constructor as follows:
170.757 + *
170.758 + * <blockquote><tt>
170.759 + * new {@link #URI(String, String, String, int, String, String, String)
170.760 + * URI}(scheme, null, host, -1, path, null, fragment);
170.761 + * </tt></blockquote>
170.762 + *
170.763 + * @param scheme Scheme name
170.764 + * @param host Host name
170.765 + * @param path Path
170.766 + * @param fragment Fragment
170.767 + *
170.768 + * @throws URISyntaxException
170.769 + * If the URI string constructed from the given components
170.770 + * violates RFC 2396
170.771 + */
170.772 + public URI(String scheme, String host, String path, String fragment)
170.773 + throws URISyntaxException
170.774 + {
170.775 + this(scheme, null, host, -1, path, null, fragment);
170.776 + }
170.777 +
170.778 + /**
170.779 + * Constructs a URI from the given components.
170.780 + *
170.781 + * <p> A component may be left undefined by passing <tt>null</tt>.
170.782 + *
170.783 + * <p> This constructor first builds a URI in string form using the given
170.784 + * components as follows: </p>
170.785 + *
170.786 + * <ol>
170.787 + *
170.788 + * <li><p> Initially, the result string is empty. </p></li>
170.789 + *
170.790 + * <li><p> If a scheme is given then it is appended to the result,
170.791 + * followed by a colon character (<tt>':'</tt>). </p></li>
170.792 + *
170.793 + * <li><p> If a scheme-specific part is given then it is appended. Any
170.794 + * character that is not a <a href="#legal-chars">legal URI character</a>
170.795 + * is <a href="#quote">quoted</a>. </p></li>
170.796 + *
170.797 + * <li><p> Finally, if a fragment is given then a hash character
170.798 + * (<tt>'#'</tt>) is appended to the string, followed by the fragment.
170.799 + * Any character that is not a legal URI character is quoted. </p></li>
170.800 + *
170.801 + * </ol>
170.802 + *
170.803 + * <p> The resulting URI string is then parsed in order to create the new
170.804 + * URI instance as if by invoking the {@link #URI(String)} constructor;
170.805 + * this may cause a {@link URISyntaxException} to be thrown. </p>
170.806 + *
170.807 + * @param scheme Scheme name
170.808 + * @param ssp Scheme-specific part
170.809 + * @param fragment Fragment
170.810 + *
170.811 + * @throws URISyntaxException
170.812 + * If the URI string constructed from the given components
170.813 + * violates RFC 2396
170.814 + */
170.815 + public URI(String scheme, String ssp, String fragment)
170.816 + throws URISyntaxException
170.817 + {
170.818 + new Parser(toString(scheme, ssp,
170.819 + null, null, null, -1,
170.820 + null, null, fragment))
170.821 + .parse(false);
170.822 + }
170.823 +
170.824 + /**
170.825 + * Creates a URI by parsing the given string.
170.826 + *
170.827 + * <p> This convenience factory method works as if by invoking the {@link
170.828 + * #URI(String)} constructor; any {@link URISyntaxException} thrown by the
170.829 + * constructor is caught and wrapped in a new {@link
170.830 + * IllegalArgumentException} object, which is then thrown.
170.831 + *
170.832 + * <p> This method is provided for use in situations where it is known that
170.833 + * the given string is a legal URI, for example for URI constants declared
170.834 + * within in a program, and so it would be considered a programming error
170.835 + * for the string not to parse as such. The constructors, which throw
170.836 + * {@link URISyntaxException} directly, should be used situations where a
170.837 + * URI is being constructed from user input or from some other source that
170.838 + * may be prone to errors. </p>
170.839 + *
170.840 + * @param str The string to be parsed into a URI
170.841 + * @return The new URI
170.842 + *
170.843 + * @throws NullPointerException
170.844 + * If <tt>str</tt> is <tt>null</tt>
170.845 + *
170.846 + * @throws IllegalArgumentException
170.847 + * If the given string violates RFC 2396
170.848 + */
170.849 + public static URI create(String str) {
170.850 + try {
170.851 + return new URI(str);
170.852 + } catch (URISyntaxException x) {
170.853 + throw new IllegalArgumentException(x.getMessage(), x);
170.854 + }
170.855 + }
170.856 +
170.857 +
170.858 + // -- Operations --
170.859 +
170.860 + /**
170.861 + * Attempts to parse this URI's authority component, if defined, into
170.862 + * user-information, host, and port components.
170.863 + *
170.864 + * <p> If this URI's authority component has already been recognized as
170.865 + * being server-based then it will already have been parsed into
170.866 + * user-information, host, and port components. In this case, or if this
170.867 + * URI has no authority component, this method simply returns this URI.
170.868 + *
170.869 + * <p> Otherwise this method attempts once more to parse the authority
170.870 + * component into user-information, host, and port components, and throws
170.871 + * an exception describing why the authority component could not be parsed
170.872 + * in that way.
170.873 + *
170.874 + * <p> This method is provided because the generic URI syntax specified in
170.875 + * <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>
170.876 + * cannot always distinguish a malformed server-based authority from a
170.877 + * legitimate registry-based authority. It must therefore treat some
170.878 + * instances of the former as instances of the latter. The authority
170.879 + * component in the URI string <tt>"//foo:bar"</tt>, for example, is not a
170.880 + * legal server-based authority but it is legal as a registry-based
170.881 + * authority.
170.882 + *
170.883 + * <p> In many common situations, for example when working URIs that are
170.884 + * known to be either URNs or URLs, the hierarchical URIs being used will
170.885 + * always be server-based. They therefore must either be parsed as such or
170.886 + * treated as an error. In these cases a statement such as
170.887 + *
170.888 + * <blockquote>
170.889 + * <tt>URI </tt><i>u</i><tt> = new URI(str).parseServerAuthority();</tt>
170.890 + * </blockquote>
170.891 + *
170.892 + * <p> can be used to ensure that <i>u</i> always refers to a URI that, if
170.893 + * it has an authority component, has a server-based authority with proper
170.894 + * user-information, host, and port components. Invoking this method also
170.895 + * ensures that if the authority could not be parsed in that way then an
170.896 + * appropriate diagnostic message can be issued based upon the exception
170.897 + * that is thrown. </p>
170.898 + *
170.899 + * @return A URI whose authority field has been parsed
170.900 + * as a server-based authority
170.901 + *
170.902 + * @throws URISyntaxException
170.903 + * If the authority component of this URI is defined
170.904 + * but cannot be parsed as a server-based authority
170.905 + * according to RFC 2396
170.906 + */
170.907 + public URI parseServerAuthority()
170.908 + throws URISyntaxException
170.909 + {
170.910 + // We could be clever and cache the error message and index from the
170.911 + // exception thrown during the original parse, but that would require
170.912 + // either more fields or a more-obscure representation.
170.913 + if ((host != null) || (authority == null))
170.914 + return this;
170.915 + defineString();
170.916 + new Parser(string).parse(true);
170.917 + return this;
170.918 + }
170.919 +
170.920 + /**
170.921 + * Normalizes this URI's path.
170.922 + *
170.923 + * <p> If this URI is opaque, or if its path is already in normal form,
170.924 + * then this URI is returned. Otherwise a new URI is constructed that is
170.925 + * identical to this URI except that its path is computed by normalizing
170.926 + * this URI's path in a manner consistent with <a
170.927 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
170.928 + * section 5.2, step 6, sub-steps c through f; that is:
170.929 + * </p>
170.930 + *
170.931 + * <ol>
170.932 + *
170.933 + * <li><p> All <tt>"."</tt> segments are removed. </p></li>
170.934 + *
170.935 + * <li><p> If a <tt>".."</tt> segment is preceded by a non-<tt>".."</tt>
170.936 + * segment then both of these segments are removed. This step is
170.937 + * repeated until it is no longer applicable. </p></li>
170.938 + *
170.939 + * <li><p> If the path is relative, and if its first segment contains a
170.940 + * colon character (<tt>':'</tt>), then a <tt>"."</tt> segment is
170.941 + * prepended. This prevents a relative URI with a path such as
170.942 + * <tt>"a:b/c/d"</tt> from later being re-parsed as an opaque URI with a
170.943 + * scheme of <tt>"a"</tt> and a scheme-specific part of <tt>"b/c/d"</tt>.
170.944 + * <b><i>(Deviation from RFC 2396)</i></b> </p></li>
170.945 + *
170.946 + * </ol>
170.947 + *
170.948 + * <p> A normalized path will begin with one or more <tt>".."</tt> segments
170.949 + * if there were insufficient non-<tt>".."</tt> segments preceding them to
170.950 + * allow their removal. A normalized path will begin with a <tt>"."</tt>
170.951 + * segment if one was inserted by step 3 above. Otherwise, a normalized
170.952 + * path will not contain any <tt>"."</tt> or <tt>".."</tt> segments. </p>
170.953 + *
170.954 + * @return A URI equivalent to this URI,
170.955 + * but whose path is in normal form
170.956 + */
170.957 + public URI normalize() {
170.958 + return normalize(this);
170.959 + }
170.960 +
170.961 + /**
170.962 + * Resolves the given URI against this URI.
170.963 + *
170.964 + * <p> If the given URI is already absolute, or if this URI is opaque, then
170.965 + * the given URI is returned.
170.966 + *
170.967 + * <p><a name="resolve-frag"></a> If the given URI's fragment component is
170.968 + * defined, its path component is empty, and its scheme, authority, and
170.969 + * query components are undefined, then a URI with the given fragment but
170.970 + * with all other components equal to those of this URI is returned. This
170.971 + * allows a URI representing a standalone fragment reference, such as
170.972 + * <tt>"#foo"</tt>, to be usefully resolved against a base URI.
170.973 + *
170.974 + * <p> Otherwise this method constructs a new hierarchical URI in a manner
170.975 + * consistent with <a
170.976 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
170.977 + * section 5.2; that is: </p>
170.978 + *
170.979 + * <ol>
170.980 + *
170.981 + * <li><p> A new URI is constructed with this URI's scheme and the given
170.982 + * URI's query and fragment components. </p></li>
170.983 + *
170.984 + * <li><p> If the given URI has an authority component then the new URI's
170.985 + * authority and path are taken from the given URI. </p></li>
170.986 + *
170.987 + * <li><p> Otherwise the new URI's authority component is copied from
170.988 + * this URI, and its path is computed as follows: </p>
170.989 + *
170.990 + * <ol type=a>
170.991 + *
170.992 + * <li><p> If the given URI's path is absolute then the new URI's path
170.993 + * is taken from the given URI. </p></li>
170.994 + *
170.995 + * <li><p> Otherwise the given URI's path is relative, and so the new
170.996 + * URI's path is computed by resolving the path of the given URI
170.997 + * against the path of this URI. This is done by concatenating all but
170.998 + * the last segment of this URI's path, if any, with the given URI's
170.999 + * path and then normalizing the result as if by invoking the {@link
170.1000 + * #normalize() normalize} method. </p></li>
170.1001 + *
170.1002 + * </ol></li>
170.1003 + *
170.1004 + * </ol>
170.1005 + *
170.1006 + * <p> The result of this method is absolute if, and only if, either this
170.1007 + * URI is absolute or the given URI is absolute. </p>
170.1008 + *
170.1009 + * @param uri The URI to be resolved against this URI
170.1010 + * @return The resulting URI
170.1011 + *
170.1012 + * @throws NullPointerException
170.1013 + * If <tt>uri</tt> is <tt>null</tt>
170.1014 + */
170.1015 + public URI resolve(URI uri) {
170.1016 + return resolve(this, uri);
170.1017 + }
170.1018 +
170.1019 + /**
170.1020 + * Constructs a new URI by parsing the given string and then resolving it
170.1021 + * against this URI.
170.1022 + *
170.1023 + * <p> This convenience method works as if invoking it were equivalent to
170.1024 + * evaluating the expression <tt>{@link #resolve(java.net.URI)
170.1025 + * resolve}(URI.{@link #create(String) create}(str))</tt>. </p>
170.1026 + *
170.1027 + * @param str The string to be parsed into a URI
170.1028 + * @return The resulting URI
170.1029 + *
170.1030 + * @throws NullPointerException
170.1031 + * If <tt>str</tt> is <tt>null</tt>
170.1032 + *
170.1033 + * @throws IllegalArgumentException
170.1034 + * If the given string violates RFC 2396
170.1035 + */
170.1036 + public URI resolve(String str) {
170.1037 + return resolve(URI.create(str));
170.1038 + }
170.1039 +
170.1040 + /**
170.1041 + * Relativizes the given URI against this URI.
170.1042 + *
170.1043 + * <p> The relativization of the given URI against this URI is computed as
170.1044 + * follows: </p>
170.1045 + *
170.1046 + * <ol>
170.1047 + *
170.1048 + * <li><p> If either this URI or the given URI are opaque, or if the
170.1049 + * scheme and authority components of the two URIs are not identical, or
170.1050 + * if the path of this URI is not a prefix of the path of the given URI,
170.1051 + * then the given URI is returned. </p></li>
170.1052 + *
170.1053 + * <li><p> Otherwise a new relative hierarchical URI is constructed with
170.1054 + * query and fragment components taken from the given URI and with a path
170.1055 + * component computed by removing this URI's path from the beginning of
170.1056 + * the given URI's path. </p></li>
170.1057 + *
170.1058 + * </ol>
170.1059 + *
170.1060 + * @param uri The URI to be relativized against this URI
170.1061 + * @return The resulting URI
170.1062 + *
170.1063 + * @throws NullPointerException
170.1064 + * If <tt>uri</tt> is <tt>null</tt>
170.1065 + */
170.1066 + public URI relativize(URI uri) {
170.1067 + return relativize(this, uri);
170.1068 + }
170.1069 +
170.1070 + /**
170.1071 + * Constructs a URL from this URI.
170.1072 + *
170.1073 + * <p> This convenience method works as if invoking it were equivalent to
170.1074 + * evaluating the expression <tt>new URL(this.toString())</tt> after
170.1075 + * first checking that this URI is absolute. </p>
170.1076 + *
170.1077 + * @return A URL constructed from this URI
170.1078 + *
170.1079 + * @throws IllegalArgumentException
170.1080 + * If this URL is not absolute
170.1081 + *
170.1082 + * @throws MalformedURLException
170.1083 + * If a protocol handler for the URL could not be found,
170.1084 + * or if some other error occurred while constructing the URL
170.1085 + */
170.1086 + public URL toURL()
170.1087 + throws MalformedURLException {
170.1088 + if (!isAbsolute())
170.1089 + throw new IllegalArgumentException("URI is not absolute");
170.1090 + return new URL(toString());
170.1091 + }
170.1092 +
170.1093 + // -- Component access methods --
170.1094 +
170.1095 + /**
170.1096 + * Returns the scheme component of this URI.
170.1097 + *
170.1098 + * <p> The scheme component of a URI, if defined, only contains characters
170.1099 + * in the <i>alphanum</i> category and in the string <tt>"-.+"</tt>. A
170.1100 + * scheme always starts with an <i>alpha</i> character. <p>
170.1101 + *
170.1102 + * The scheme component of a URI cannot contain escaped octets, hence this
170.1103 + * method does not perform any decoding.
170.1104 + *
170.1105 + * @return The scheme component of this URI,
170.1106 + * or <tt>null</tt> if the scheme is undefined
170.1107 + */
170.1108 + public String getScheme() {
170.1109 + return scheme;
170.1110 + }
170.1111 +
170.1112 + /**
170.1113 + * Tells whether or not this URI is absolute.
170.1114 + *
170.1115 + * <p> A URI is absolute if, and only if, it has a scheme component. </p>
170.1116 + *
170.1117 + * @return <tt>true</tt> if, and only if, this URI is absolute
170.1118 + */
170.1119 + public boolean isAbsolute() {
170.1120 + return scheme != null;
170.1121 + }
170.1122 +
170.1123 + /**
170.1124 + * Tells whether or not this URI is opaque.
170.1125 + *
170.1126 + * <p> A URI is opaque if, and only if, it is absolute and its
170.1127 + * scheme-specific part does not begin with a slash character ('/').
170.1128 + * An opaque URI has a scheme, a scheme-specific part, and possibly
170.1129 + * a fragment; all other components are undefined. </p>
170.1130 + *
170.1131 + * @return <tt>true</tt> if, and only if, this URI is opaque
170.1132 + */
170.1133 + public boolean isOpaque() {
170.1134 + return path == null;
170.1135 + }
170.1136 +
170.1137 + /**
170.1138 + * Returns the raw scheme-specific part of this URI. The scheme-specific
170.1139 + * part is never undefined, though it may be empty.
170.1140 + *
170.1141 + * <p> The scheme-specific part of a URI only contains legal URI
170.1142 + * characters. </p>
170.1143 + *
170.1144 + * @return The raw scheme-specific part of this URI
170.1145 + * (never <tt>null</tt>)
170.1146 + */
170.1147 + public String getRawSchemeSpecificPart() {
170.1148 + defineSchemeSpecificPart();
170.1149 + return schemeSpecificPart;
170.1150 + }
170.1151 +
170.1152 + /**
170.1153 + * Returns the decoded scheme-specific part of this URI.
170.1154 + *
170.1155 + * <p> The string returned by this method is equal to that returned by the
170.1156 + * {@link #getRawSchemeSpecificPart() getRawSchemeSpecificPart} method
170.1157 + * except that all sequences of escaped octets are <a
170.1158 + * href="#decode">decoded</a>. </p>
170.1159 + *
170.1160 + * @return The decoded scheme-specific part of this URI
170.1161 + * (never <tt>null</tt>)
170.1162 + */
170.1163 + public String getSchemeSpecificPart() {
170.1164 + if (decodedSchemeSpecificPart == null)
170.1165 + decodedSchemeSpecificPart = decode(getRawSchemeSpecificPart());
170.1166 + return decodedSchemeSpecificPart;
170.1167 + }
170.1168 +
170.1169 + /**
170.1170 + * Returns the raw authority component of this URI.
170.1171 + *
170.1172 + * <p> The authority component of a URI, if defined, only contains the
170.1173 + * commercial-at character (<tt>'@'</tt>) and characters in the
170.1174 + * <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and <i>other</i>
170.1175 + * categories. If the authority is server-based then it is further
170.1176 + * constrained to have valid user-information, host, and port
170.1177 + * components. </p>
170.1178 + *
170.1179 + * @return The raw authority component of this URI,
170.1180 + * or <tt>null</tt> if the authority is undefined
170.1181 + */
170.1182 + public String getRawAuthority() {
170.1183 + return authority;
170.1184 + }
170.1185 +
170.1186 + /**
170.1187 + * Returns the decoded authority component of this URI.
170.1188 + *
170.1189 + * <p> The string returned by this method is equal to that returned by the
170.1190 + * {@link #getRawAuthority() getRawAuthority} method except that all
170.1191 + * sequences of escaped octets are <a href="#decode">decoded</a>. </p>
170.1192 + *
170.1193 + * @return The decoded authority component of this URI,
170.1194 + * or <tt>null</tt> if the authority is undefined
170.1195 + */
170.1196 + public String getAuthority() {
170.1197 + if (decodedAuthority == null)
170.1198 + decodedAuthority = decode(authority);
170.1199 + return decodedAuthority;
170.1200 + }
170.1201 +
170.1202 + /**
170.1203 + * Returns the raw user-information component of this URI.
170.1204 + *
170.1205 + * <p> The user-information component of a URI, if defined, only contains
170.1206 + * characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and
170.1207 + * <i>other</i> categories. </p>
170.1208 + *
170.1209 + * @return The raw user-information component of this URI,
170.1210 + * or <tt>null</tt> if the user information is undefined
170.1211 + */
170.1212 + public String getRawUserInfo() {
170.1213 + return userInfo;
170.1214 + }
170.1215 +
170.1216 + /**
170.1217 + * Returns the decoded user-information component of this URI.
170.1218 + *
170.1219 + * <p> The string returned by this method is equal to that returned by the
170.1220 + * {@link #getRawUserInfo() getRawUserInfo} method except that all
170.1221 + * sequences of escaped octets are <a href="#decode">decoded</a>. </p>
170.1222 + *
170.1223 + * @return The decoded user-information component of this URI,
170.1224 + * or <tt>null</tt> if the user information is undefined
170.1225 + */
170.1226 + public String getUserInfo() {
170.1227 + if ((decodedUserInfo == null) && (userInfo != null))
170.1228 + decodedUserInfo = decode(userInfo);
170.1229 + return decodedUserInfo;
170.1230 + }
170.1231 +
170.1232 + /**
170.1233 + * Returns the host component of this URI.
170.1234 + *
170.1235 + * <p> The host component of a URI, if defined, will have one of the
170.1236 + * following forms: </p>
170.1237 + *
170.1238 + * <ul type=disc>
170.1239 + *
170.1240 + * <li><p> A domain name consisting of one or more <i>labels</i>
170.1241 + * separated by period characters (<tt>'.'</tt>), optionally followed by
170.1242 + * a period character. Each label consists of <i>alphanum</i> characters
170.1243 + * as well as hyphen characters (<tt>'-'</tt>), though hyphens never
170.1244 + * occur as the first or last characters in a label. The rightmost
170.1245 + * label of a domain name consisting of two or more labels, begins
170.1246 + * with an <i>alpha</i> character. </li>
170.1247 + *
170.1248 + * <li><p> A dotted-quad IPv4 address of the form
170.1249 + * <i>digit</i><tt>+.</tt><i>digit</i><tt>+.</tt><i>digit</i><tt>+.</tt><i>digit</i><tt>+</tt>,
170.1250 + * where no <i>digit</i> sequence is longer than three characters and no
170.1251 + * sequence has a value larger than 255. </p></li>
170.1252 + *
170.1253 + * <li><p> An IPv6 address enclosed in square brackets (<tt>'['</tt> and
170.1254 + * <tt>']'</tt>) and consisting of hexadecimal digits, colon characters
170.1255 + * (<tt>':'</tt>), and possibly an embedded IPv4 address. The full
170.1256 + * syntax of IPv6 addresses is specified in <a
170.1257 + * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC 2373: IPv6
170.1258 + * Addressing Architecture</i></a>. </p></li>
170.1259 + *
170.1260 + * </ul>
170.1261 + *
170.1262 + * The host component of a URI cannot contain escaped octets, hence this
170.1263 + * method does not perform any decoding.
170.1264 + *
170.1265 + * @return The host component of this URI,
170.1266 + * or <tt>null</tt> if the host is undefined
170.1267 + */
170.1268 + public String getHost() {
170.1269 + return host;
170.1270 + }
170.1271 +
170.1272 + /**
170.1273 + * Returns the port number of this URI.
170.1274 + *
170.1275 + * <p> The port component of a URI, if defined, is a non-negative
170.1276 + * integer. </p>
170.1277 + *
170.1278 + * @return The port component of this URI,
170.1279 + * or <tt>-1</tt> if the port is undefined
170.1280 + */
170.1281 + public int getPort() {
170.1282 + return port;
170.1283 + }
170.1284 +
170.1285 + /**
170.1286 + * Returns the raw path component of this URI.
170.1287 + *
170.1288 + * <p> The path component of a URI, if defined, only contains the slash
170.1289 + * character (<tt>'/'</tt>), the commercial-at character (<tt>'@'</tt>),
170.1290 + * and characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>,
170.1291 + * and <i>other</i> categories. </p>
170.1292 + *
170.1293 + * @return The path component of this URI,
170.1294 + * or <tt>null</tt> if the path is undefined
170.1295 + */
170.1296 + public String getRawPath() {
170.1297 + return path;
170.1298 + }
170.1299 +
170.1300 + /**
170.1301 + * Returns the decoded path component of this URI.
170.1302 + *
170.1303 + * <p> The string returned by this method is equal to that returned by the
170.1304 + * {@link #getRawPath() getRawPath} method except that all sequences of
170.1305 + * escaped octets are <a href="#decode">decoded</a>. </p>
170.1306 + *
170.1307 + * @return The decoded path component of this URI,
170.1308 + * or <tt>null</tt> if the path is undefined
170.1309 + */
170.1310 + public String getPath() {
170.1311 + if ((decodedPath == null) && (path != null))
170.1312 + decodedPath = decode(path);
170.1313 + return decodedPath;
170.1314 + }
170.1315 +
170.1316 + /**
170.1317 + * Returns the raw query component of this URI.
170.1318 + *
170.1319 + * <p> The query component of a URI, if defined, only contains legal URI
170.1320 + * characters. </p>
170.1321 + *
170.1322 + * @return The raw query component of this URI,
170.1323 + * or <tt>null</tt> if the query is undefined
170.1324 + */
170.1325 + public String getRawQuery() {
170.1326 + return query;
170.1327 + }
170.1328 +
170.1329 + /**
170.1330 + * Returns the decoded query component of this URI.
170.1331 + *
170.1332 + * <p> The string returned by this method is equal to that returned by the
170.1333 + * {@link #getRawQuery() getRawQuery} method except that all sequences of
170.1334 + * escaped octets are <a href="#decode">decoded</a>. </p>
170.1335 + *
170.1336 + * @return The decoded query component of this URI,
170.1337 + * or <tt>null</tt> if the query is undefined
170.1338 + */
170.1339 + public String getQuery() {
170.1340 + if ((decodedQuery == null) && (query != null))
170.1341 + decodedQuery = decode(query);
170.1342 + return decodedQuery;
170.1343 + }
170.1344 +
170.1345 + /**
170.1346 + * Returns the raw fragment component of this URI.
170.1347 + *
170.1348 + * <p> The fragment component of a URI, if defined, only contains legal URI
170.1349 + * characters. </p>
170.1350 + *
170.1351 + * @return The raw fragment component of this URI,
170.1352 + * or <tt>null</tt> if the fragment is undefined
170.1353 + */
170.1354 + public String getRawFragment() {
170.1355 + return fragment;
170.1356 + }
170.1357 +
170.1358 + /**
170.1359 + * Returns the decoded fragment component of this URI.
170.1360 + *
170.1361 + * <p> The string returned by this method is equal to that returned by the
170.1362 + * {@link #getRawFragment() getRawFragment} method except that all
170.1363 + * sequences of escaped octets are <a href="#decode">decoded</a>. </p>
170.1364 + *
170.1365 + * @return The decoded fragment component of this URI,
170.1366 + * or <tt>null</tt> if the fragment is undefined
170.1367 + */
170.1368 + public String getFragment() {
170.1369 + if ((decodedFragment == null) && (fragment != null))
170.1370 + decodedFragment = decode(fragment);
170.1371 + return decodedFragment;
170.1372 + }
170.1373 +
170.1374 +
170.1375 + // -- Equality, comparison, hash code, toString, and serialization --
170.1376 +
170.1377 + /**
170.1378 + * Tests this URI for equality with another object.
170.1379 + *
170.1380 + * <p> If the given object is not a URI then this method immediately
170.1381 + * returns <tt>false</tt>.
170.1382 + *
170.1383 + * <p> For two URIs to be considered equal requires that either both are
170.1384 + * opaque or both are hierarchical. Their schemes must either both be
170.1385 + * undefined or else be equal without regard to case. Their fragments
170.1386 + * must either both be undefined or else be equal.
170.1387 + *
170.1388 + * <p> For two opaque URIs to be considered equal, their scheme-specific
170.1389 + * parts must be equal.
170.1390 + *
170.1391 + * <p> For two hierarchical URIs to be considered equal, their paths must
170.1392 + * be equal and their queries must either both be undefined or else be
170.1393 + * equal. Their authorities must either both be undefined, or both be
170.1394 + * registry-based, or both be server-based. If their authorities are
170.1395 + * defined and are registry-based, then they must be equal. If their
170.1396 + * authorities are defined and are server-based, then their hosts must be
170.1397 + * equal without regard to case, their port numbers must be equal, and
170.1398 + * their user-information components must be equal.
170.1399 + *
170.1400 + * <p> When testing the user-information, path, query, fragment, authority,
170.1401 + * or scheme-specific parts of two URIs for equality, the raw forms rather
170.1402 + * than the encoded forms of these components are compared and the
170.1403 + * hexadecimal digits of escaped octets are compared without regard to
170.1404 + * case.
170.1405 + *
170.1406 + * <p> This method satisfies the general contract of the {@link
170.1407 + * java.lang.Object#equals(Object) Object.equals} method. </p>
170.1408 + *
170.1409 + * @param ob The object to which this object is to be compared
170.1410 + *
170.1411 + * @return <tt>true</tt> if, and only if, the given object is a URI that
170.1412 + * is identical to this URI
170.1413 + */
170.1414 + public boolean equals(Object ob) {
170.1415 + if (ob == this)
170.1416 + return true;
170.1417 + if (!(ob instanceof URI))
170.1418 + return false;
170.1419 + URI that = (URI)ob;
170.1420 + if (this.isOpaque() != that.isOpaque()) return false;
170.1421 + if (!equalIgnoringCase(this.scheme, that.scheme)) return false;
170.1422 + if (!equal(this.fragment, that.fragment)) return false;
170.1423 +
170.1424 + // Opaque
170.1425 + if (this.isOpaque())
170.1426 + return equal(this.schemeSpecificPart, that.schemeSpecificPart);
170.1427 +
170.1428 + // Hierarchical
170.1429 + if (!equal(this.path, that.path)) return false;
170.1430 + if (!equal(this.query, that.query)) return false;
170.1431 +
170.1432 + // Authorities
170.1433 + if (this.authority == that.authority) return true;
170.1434 + if (this.host != null) {
170.1435 + // Server-based
170.1436 + if (!equal(this.userInfo, that.userInfo)) return false;
170.1437 + if (!equalIgnoringCase(this.host, that.host)) return false;
170.1438 + if (this.port != that.port) return false;
170.1439 + } else if (this.authority != null) {
170.1440 + // Registry-based
170.1441 + if (!equal(this.authority, that.authority)) return false;
170.1442 + } else if (this.authority != that.authority) {
170.1443 + return false;
170.1444 + }
170.1445 +
170.1446 + return true;
170.1447 + }
170.1448 +
170.1449 + /**
170.1450 + * Returns a hash-code value for this URI. The hash code is based upon all
170.1451 + * of the URI's components, and satisfies the general contract of the
170.1452 + * {@link java.lang.Object#hashCode() Object.hashCode} method.
170.1453 + *
170.1454 + * @return A hash-code value for this URI
170.1455 + */
170.1456 + public int hashCode() {
170.1457 + if (hash != 0)
170.1458 + return hash;
170.1459 + int h = hashIgnoringCase(0, scheme);
170.1460 + h = hash(h, fragment);
170.1461 + if (isOpaque()) {
170.1462 + h = hash(h, schemeSpecificPart);
170.1463 + } else {
170.1464 + h = hash(h, path);
170.1465 + h = hash(h, query);
170.1466 + if (host != null) {
170.1467 + h = hash(h, userInfo);
170.1468 + h = hashIgnoringCase(h, host);
170.1469 + h += 1949 * port;
170.1470 + } else {
170.1471 + h = hash(h, authority);
170.1472 + }
170.1473 + }
170.1474 + hash = h;
170.1475 + return h;
170.1476 + }
170.1477 +
170.1478 + /**
170.1479 + * Compares this URI to another object, which must be a URI.
170.1480 + *
170.1481 + * <p> When comparing corresponding components of two URIs, if one
170.1482 + * component is undefined but the other is defined then the first is
170.1483 + * considered to be less than the second. Unless otherwise noted, string
170.1484 + * components are ordered according to their natural, case-sensitive
170.1485 + * ordering as defined by the {@link java.lang.String#compareTo(Object)
170.1486 + * String.compareTo} method. String components that are subject to
170.1487 + * encoding are compared by comparing their raw forms rather than their
170.1488 + * encoded forms.
170.1489 + *
170.1490 + * <p> The ordering of URIs is defined as follows: </p>
170.1491 + *
170.1492 + * <ul type=disc>
170.1493 + *
170.1494 + * <li><p> Two URIs with different schemes are ordered according the
170.1495 + * ordering of their schemes, without regard to case. </p></li>
170.1496 + *
170.1497 + * <li><p> A hierarchical URI is considered to be less than an opaque URI
170.1498 + * with an identical scheme. </p></li>
170.1499 + *
170.1500 + * <li><p> Two opaque URIs with identical schemes are ordered according
170.1501 + * to the ordering of their scheme-specific parts. </p></li>
170.1502 + *
170.1503 + * <li><p> Two opaque URIs with identical schemes and scheme-specific
170.1504 + * parts are ordered according to the ordering of their
170.1505 + * fragments. </p></li>
170.1506 + *
170.1507 + * <li><p> Two hierarchical URIs with identical schemes are ordered
170.1508 + * according to the ordering of their authority components: </p>
170.1509 + *
170.1510 + * <ul type=disc>
170.1511 + *
170.1512 + * <li><p> If both authority components are server-based then the URIs
170.1513 + * are ordered according to their user-information components; if these
170.1514 + * components are identical then the URIs are ordered according to the
170.1515 + * ordering of their hosts, without regard to case; if the hosts are
170.1516 + * identical then the URIs are ordered according to the ordering of
170.1517 + * their ports. </p></li>
170.1518 + *
170.1519 + * <li><p> If one or both authority components are registry-based then
170.1520 + * the URIs are ordered according to the ordering of their authority
170.1521 + * components. </p></li>
170.1522 + *
170.1523 + * </ul></li>
170.1524 + *
170.1525 + * <li><p> Finally, two hierarchical URIs with identical schemes and
170.1526 + * authority components are ordered according to the ordering of their
170.1527 + * paths; if their paths are identical then they are ordered according to
170.1528 + * the ordering of their queries; if the queries are identical then they
170.1529 + * are ordered according to the order of their fragments. </p></li>
170.1530 + *
170.1531 + * </ul>
170.1532 + *
170.1533 + * <p> This method satisfies the general contract of the {@link
170.1534 + * java.lang.Comparable#compareTo(Object) Comparable.compareTo}
170.1535 + * method. </p>
170.1536 + *
170.1537 + * @param that
170.1538 + * The object to which this URI is to be compared
170.1539 + *
170.1540 + * @return A negative integer, zero, or a positive integer as this URI is
170.1541 + * less than, equal to, or greater than the given URI
170.1542 + *
170.1543 + * @throws ClassCastException
170.1544 + * If the given object is not a URI
170.1545 + */
170.1546 + public int compareTo(URI that) {
170.1547 + int c;
170.1548 +
170.1549 + if ((c = compareIgnoringCase(this.scheme, that.scheme)) != 0)
170.1550 + return c;
170.1551 +
170.1552 + if (this.isOpaque()) {
170.1553 + if (that.isOpaque()) {
170.1554 + // Both opaque
170.1555 + if ((c = compare(this.schemeSpecificPart,
170.1556 + that.schemeSpecificPart)) != 0)
170.1557 + return c;
170.1558 + return compare(this.fragment, that.fragment);
170.1559 + }
170.1560 + return +1; // Opaque > hierarchical
170.1561 + } else if (that.isOpaque()) {
170.1562 + return -1; // Hierarchical < opaque
170.1563 + }
170.1564 +
170.1565 + // Hierarchical
170.1566 + if ((this.host != null) && (that.host != null)) {
170.1567 + // Both server-based
170.1568 + if ((c = compare(this.userInfo, that.userInfo)) != 0)
170.1569 + return c;
170.1570 + if ((c = compareIgnoringCase(this.host, that.host)) != 0)
170.1571 + return c;
170.1572 + if ((c = this.port - that.port) != 0)
170.1573 + return c;
170.1574 + } else {
170.1575 + // If one or both authorities are registry-based then we simply
170.1576 + // compare them in the usual, case-sensitive way. If one is
170.1577 + // registry-based and one is server-based then the strings are
170.1578 + // guaranteed to be unequal, hence the comparison will never return
170.1579 + // zero and the compareTo and equals methods will remain
170.1580 + // consistent.
170.1581 + if ((c = compare(this.authority, that.authority)) != 0) return c;
170.1582 + }
170.1583 +
170.1584 + if ((c = compare(this.path, that.path)) != 0) return c;
170.1585 + if ((c = compare(this.query, that.query)) != 0) return c;
170.1586 + return compare(this.fragment, that.fragment);
170.1587 + }
170.1588 +
170.1589 + /**
170.1590 + * Returns the content of this URI as a string.
170.1591 + *
170.1592 + * <p> If this URI was created by invoking one of the constructors in this
170.1593 + * class then a string equivalent to the original input string, or to the
170.1594 + * string computed from the originally-given components, as appropriate, is
170.1595 + * returned. Otherwise this URI was created by normalization, resolution,
170.1596 + * or relativization, and so a string is constructed from this URI's
170.1597 + * components according to the rules specified in <a
170.1598 + * href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>,
170.1599 + * section 5.2, step 7. </p>
170.1600 + *
170.1601 + * @return The string form of this URI
170.1602 + */
170.1603 + public String toString() {
170.1604 + defineString();
170.1605 + return string;
170.1606 + }
170.1607 +
170.1608 + /**
170.1609 + * Returns the content of this URI as a US-ASCII string.
170.1610 + *
170.1611 + * <p> If this URI does not contain any characters in the <i>other</i>
170.1612 + * category then an invocation of this method will return the same value as
170.1613 + * an invocation of the {@link #toString() toString} method. Otherwise
170.1614 + * this method works as if by invoking that method and then <a
170.1615 + * href="#encode">encoding</a> the result. </p>
170.1616 + *
170.1617 + * @return The string form of this URI, encoded as needed
170.1618 + * so that it only contains characters in the US-ASCII
170.1619 + * charset
170.1620 + */
170.1621 + public String toASCIIString() {
170.1622 + defineString();
170.1623 + return encode(string);
170.1624 + }
170.1625 +
170.1626 +
170.1627 + // -- Serialization support --
170.1628 +
170.1629 + /**
170.1630 + * Saves the content of this URI to the given serial stream.
170.1631 + *
170.1632 + * <p> The only serializable field of a URI instance is its <tt>string</tt>
170.1633 + * field. That field is given a value, if it does not have one already,
170.1634 + * and then the {@link java.io.ObjectOutputStream#defaultWriteObject()}
170.1635 + * method of the given object-output stream is invoked. </p>
170.1636 + *
170.1637 + * @param os The object-output stream to which this object
170.1638 + * is to be written
170.1639 + */
170.1640 + private void writeObject(ObjectOutputStream os)
170.1641 + throws IOException
170.1642 + {
170.1643 + defineString();
170.1644 + os.defaultWriteObject(); // Writes the string field only
170.1645 + }
170.1646 +
170.1647 + /**
170.1648 + * Reconstitutes a URI from the given serial stream.
170.1649 + *
170.1650 + * <p> The {@link java.io.ObjectInputStream#defaultReadObject()} method is
170.1651 + * invoked to read the value of the <tt>string</tt> field. The result is
170.1652 + * then parsed in the usual way.
170.1653 + *
170.1654 + * @param is The object-input stream from which this object
170.1655 + * is being read
170.1656 + */
170.1657 + private void readObject(ObjectInputStream is)
170.1658 + throws ClassNotFoundException, IOException
170.1659 + {
170.1660 + port = -1; // Argh
170.1661 + is.defaultReadObject();
170.1662 + try {
170.1663 + new Parser(string).parse(false);
170.1664 + } catch (URISyntaxException x) {
170.1665 + IOException y = new InvalidObjectException("Invalid URI");
170.1666 + y.initCause(x);
170.1667 + throw y;
170.1668 + }
170.1669 + }
170.1670 +
170.1671 +
170.1672 + // -- End of public methods --
170.1673 +
170.1674 +
170.1675 + // -- Utility methods for string-field comparison and hashing --
170.1676 +
170.1677 + // These methods return appropriate values for null string arguments,
170.1678 + // thereby simplifying the equals, hashCode, and compareTo methods.
170.1679 + //
170.1680 + // The case-ignoring methods should only be applied to strings whose
170.1681 + // characters are all known to be US-ASCII. Because of this restriction,
170.1682 + // these methods are faster than the similar methods in the String class.
170.1683 +
170.1684 + // US-ASCII only
170.1685 + private static int toLower(char c) {
170.1686 + if ((c >= 'A') && (c <= 'Z'))
170.1687 + return c + ('a' - 'A');
170.1688 + return c;
170.1689 + }
170.1690 +
170.1691 + private static boolean equal(String s, String t) {
170.1692 + if (s == t) return true;
170.1693 + if ((s != null) && (t != null)) {
170.1694 + if (s.length() != t.length())
170.1695 + return false;
170.1696 + if (s.indexOf('%') < 0)
170.1697 + return s.equals(t);
170.1698 + int n = s.length();
170.1699 + for (int i = 0; i < n;) {
170.1700 + char c = s.charAt(i);
170.1701 + char d = t.charAt(i);
170.1702 + if (c != '%') {
170.1703 + if (c != d)
170.1704 + return false;
170.1705 + i++;
170.1706 + continue;
170.1707 + }
170.1708 + i++;
170.1709 + if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
170.1710 + return false;
170.1711 + i++;
170.1712 + if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
170.1713 + return false;
170.1714 + i++;
170.1715 + }
170.1716 + return true;
170.1717 + }
170.1718 + return false;
170.1719 + }
170.1720 +
170.1721 + // US-ASCII only
170.1722 + private static boolean equalIgnoringCase(String s, String t) {
170.1723 + if (s == t) return true;
170.1724 + if ((s != null) && (t != null)) {
170.1725 + int n = s.length();
170.1726 + if (t.length() != n)
170.1727 + return false;
170.1728 + for (int i = 0; i < n; i++) {
170.1729 + if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
170.1730 + return false;
170.1731 + }
170.1732 + return true;
170.1733 + }
170.1734 + return false;
170.1735 + }
170.1736 +
170.1737 + private static int hash(int hash, String s) {
170.1738 + if (s == null) return hash;
170.1739 + return hash * 127 + s.hashCode();
170.1740 + }
170.1741 +
170.1742 + // US-ASCII only
170.1743 + private static int hashIgnoringCase(int hash, String s) {
170.1744 + if (s == null) return hash;
170.1745 + int h = hash;
170.1746 + int n = s.length();
170.1747 + for (int i = 0; i < n; i++)
170.1748 + h = 31 * h + toLower(s.charAt(i));
170.1749 + return h;
170.1750 + }
170.1751 +
170.1752 + private static int compare(String s, String t) {
170.1753 + if (s == t) return 0;
170.1754 + if (s != null) {
170.1755 + if (t != null)
170.1756 + return s.compareTo(t);
170.1757 + else
170.1758 + return +1;
170.1759 + } else {
170.1760 + return -1;
170.1761 + }
170.1762 + }
170.1763 +
170.1764 + // US-ASCII only
170.1765 + private static int compareIgnoringCase(String s, String t) {
170.1766 + if (s == t) return 0;
170.1767 + if (s != null) {
170.1768 + if (t != null) {
170.1769 + int sn = s.length();
170.1770 + int tn = t.length();
170.1771 + int n = sn < tn ? sn : tn;
170.1772 + for (int i = 0; i < n; i++) {
170.1773 + int c = toLower(s.charAt(i)) - toLower(t.charAt(i));
170.1774 + if (c != 0)
170.1775 + return c;
170.1776 + }
170.1777 + return sn - tn;
170.1778 + }
170.1779 + return +1;
170.1780 + } else {
170.1781 + return -1;
170.1782 + }
170.1783 + }
170.1784 +
170.1785 +
170.1786 + // -- String construction --
170.1787 +
170.1788 + // If a scheme is given then the path, if given, must be absolute
170.1789 + //
170.1790 + private static void checkPath(String s, String scheme, String path)
170.1791 + throws URISyntaxException
170.1792 + {
170.1793 + if (scheme != null) {
170.1794 + if ((path != null)
170.1795 + && ((path.length() > 0) && (path.charAt(0) != '/')))
170.1796 + throw new URISyntaxException(s,
170.1797 + "Relative path in absolute URI");
170.1798 + }
170.1799 + }
170.1800 +
170.1801 + private void appendAuthority(StringBuffer sb,
170.1802 + String authority,
170.1803 + String userInfo,
170.1804 + String host,
170.1805 + int port)
170.1806 + {
170.1807 + if (host != null) {
170.1808 + sb.append("//");
170.1809 + if (userInfo != null) {
170.1810 + sb.append(quote(userInfo, L_USERINFO, H_USERINFO));
170.1811 + sb.append('@');
170.1812 + }
170.1813 + boolean needBrackets = ((host.indexOf(':') >= 0)
170.1814 + && !host.startsWith("[")
170.1815 + && !host.endsWith("]"));
170.1816 + if (needBrackets) sb.append('[');
170.1817 + sb.append(host);
170.1818 + if (needBrackets) sb.append(']');
170.1819 + if (port != -1) {
170.1820 + sb.append(':');
170.1821 + sb.append(port);
170.1822 + }
170.1823 + } else if (authority != null) {
170.1824 + sb.append("//");
170.1825 + if (authority.startsWith("[")) {
170.1826 + // authority should (but may not) contain an embedded IPv6 address
170.1827 + int end = authority.indexOf("]");
170.1828 + String doquote = authority, dontquote = "";
170.1829 + if (end != -1 && authority.indexOf(":") != -1) {
170.1830 + // the authority contains an IPv6 address
170.1831 + if (end == authority.length()) {
170.1832 + dontquote = authority;
170.1833 + doquote = "";
170.1834 + } else {
170.1835 + dontquote = authority.substring(0 , end + 1);
170.1836 + doquote = authority.substring(end + 1);
170.1837 + }
170.1838 + }
170.1839 + sb.append(dontquote);
170.1840 + sb.append(quote(doquote,
170.1841 + L_REG_NAME | L_SERVER,
170.1842 + H_REG_NAME | H_SERVER));
170.1843 + } else {
170.1844 + sb.append(quote(authority,
170.1845 + L_REG_NAME | L_SERVER,
170.1846 + H_REG_NAME | H_SERVER));
170.1847 + }
170.1848 + }
170.1849 + }
170.1850 +
170.1851 + private void appendSchemeSpecificPart(StringBuffer sb,
170.1852 + String opaquePart,
170.1853 + String authority,
170.1854 + String userInfo,
170.1855 + String host,
170.1856 + int port,
170.1857 + String path,
170.1858 + String query)
170.1859 + {
170.1860 + if (opaquePart != null) {
170.1861 + /* check if SSP begins with an IPv6 address
170.1862 + * because we must not quote a literal IPv6 address
170.1863 + */
170.1864 + if (opaquePart.startsWith("//[")) {
170.1865 + int end = opaquePart.indexOf("]");
170.1866 + if (end != -1 && opaquePart.indexOf(":")!=-1) {
170.1867 + String doquote, dontquote;
170.1868 + if (end == opaquePart.length()) {
170.1869 + dontquote = opaquePart;
170.1870 + doquote = "";
170.1871 + } else {
170.1872 + dontquote = opaquePart.substring(0,end+1);
170.1873 + doquote = opaquePart.substring(end+1);
170.1874 + }
170.1875 + sb.append (dontquote);
170.1876 + sb.append(quote(doquote, L_URIC, H_URIC));
170.1877 + }
170.1878 + } else {
170.1879 + sb.append(quote(opaquePart, L_URIC, H_URIC));
170.1880 + }
170.1881 + } else {
170.1882 + appendAuthority(sb, authority, userInfo, host, port);
170.1883 + if (path != null)
170.1884 + sb.append(quote(path, L_PATH, H_PATH));
170.1885 + if (query != null) {
170.1886 + sb.append('?');
170.1887 + sb.append(quote(query, L_URIC, H_URIC));
170.1888 + }
170.1889 + }
170.1890 + }
170.1891 +
170.1892 + private void appendFragment(StringBuffer sb, String fragment) {
170.1893 + if (fragment != null) {
170.1894 + sb.append('#');
170.1895 + sb.append(quote(fragment, L_URIC, H_URIC));
170.1896 + }
170.1897 + }
170.1898 +
170.1899 + private String toString(String scheme,
170.1900 + String opaquePart,
170.1901 + String authority,
170.1902 + String userInfo,
170.1903 + String host,
170.1904 + int port,
170.1905 + String path,
170.1906 + String query,
170.1907 + String fragment)
170.1908 + {
170.1909 + StringBuffer sb = new StringBuffer();
170.1910 + if (scheme != null) {
170.1911 + sb.append(scheme);
170.1912 + sb.append(':');
170.1913 + }
170.1914 + appendSchemeSpecificPart(sb, opaquePart,
170.1915 + authority, userInfo, host, port,
170.1916 + path, query);
170.1917 + appendFragment(sb, fragment);
170.1918 + return sb.toString();
170.1919 + }
170.1920 +
170.1921 + private void defineSchemeSpecificPart() {
170.1922 + if (schemeSpecificPart != null) return;
170.1923 + StringBuffer sb = new StringBuffer();
170.1924 + appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(),
170.1925 + host, port, getPath(), getQuery());
170.1926 + if (sb.length() == 0) return;
170.1927 + schemeSpecificPart = sb.toString();
170.1928 + }
170.1929 +
170.1930 + private void defineString() {
170.1931 + if (string != null) return;
170.1932 +
170.1933 + StringBuffer sb = new StringBuffer();
170.1934 + if (scheme != null) {
170.1935 + sb.append(scheme);
170.1936 + sb.append(':');
170.1937 + }
170.1938 + if (isOpaque()) {
170.1939 + sb.append(schemeSpecificPart);
170.1940 + } else {
170.1941 + if (host != null) {
170.1942 + sb.append("//");
170.1943 + if (userInfo != null) {
170.1944 + sb.append(userInfo);
170.1945 + sb.append('@');
170.1946 + }
170.1947 + boolean needBrackets = ((host.indexOf(':') >= 0)
170.1948 + && !host.startsWith("[")
170.1949 + && !host.endsWith("]"));
170.1950 + if (needBrackets) sb.append('[');
170.1951 + sb.append(host);
170.1952 + if (needBrackets) sb.append(']');
170.1953 + if (port != -1) {
170.1954 + sb.append(':');
170.1955 + sb.append(port);
170.1956 + }
170.1957 + } else if (authority != null) {
170.1958 + sb.append("//");
170.1959 + sb.append(authority);
170.1960 + }
170.1961 + if (path != null)
170.1962 + sb.append(path);
170.1963 + if (query != null) {
170.1964 + sb.append('?');
170.1965 + sb.append(query);
170.1966 + }
170.1967 + }
170.1968 + if (fragment != null) {
170.1969 + sb.append('#');
170.1970 + sb.append(fragment);
170.1971 + }
170.1972 + string = sb.toString();
170.1973 + }
170.1974 +
170.1975 +
170.1976 + // -- Normalization, resolution, and relativization --
170.1977 +
170.1978 + // RFC2396 5.2 (6)
170.1979 + private static String resolvePath(String base, String child,
170.1980 + boolean absolute)
170.1981 + {
170.1982 + int i = base.lastIndexOf('/');
170.1983 + int cn = child.length();
170.1984 + String path = "";
170.1985 +
170.1986 + if (cn == 0) {
170.1987 + // 5.2 (6a)
170.1988 + if (i >= 0)
170.1989 + path = base.substring(0, i + 1);
170.1990 + } else {
170.1991 + StringBuffer sb = new StringBuffer(base.length() + cn);
170.1992 + // 5.2 (6a)
170.1993 + if (i >= 0)
170.1994 + sb.append(base.substring(0, i + 1));
170.1995 + // 5.2 (6b)
170.1996 + sb.append(child);
170.1997 + path = sb.toString();
170.1998 + }
170.1999 +
170.2000 + // 5.2 (6c-f)
170.2001 + String np = normalize(path);
170.2002 +
170.2003 + // 5.2 (6g): If the result is absolute but the path begins with "../",
170.2004 + // then we simply leave the path as-is
170.2005 +
170.2006 + return np;
170.2007 + }
170.2008 +
170.2009 + // RFC2396 5.2
170.2010 + private static URI resolve(URI base, URI child) {
170.2011 + // check if child if opaque first so that NPE is thrown
170.2012 + // if child is null.
170.2013 + if (child.isOpaque() || base.isOpaque())
170.2014 + return child;
170.2015 +
170.2016 + // 5.2 (2): Reference to current document (lone fragment)
170.2017 + if ((child.scheme == null) && (child.authority == null)
170.2018 + && child.path.equals("") && (child.fragment != null)
170.2019 + && (child.query == null)) {
170.2020 + if ((base.fragment != null)
170.2021 + && child.fragment.equals(base.fragment)) {
170.2022 + return base;
170.2023 + }
170.2024 + URI ru = new URI();
170.2025 + ru.scheme = base.scheme;
170.2026 + ru.authority = base.authority;
170.2027 + ru.userInfo = base.userInfo;
170.2028 + ru.host = base.host;
170.2029 + ru.port = base.port;
170.2030 + ru.path = base.path;
170.2031 + ru.fragment = child.fragment;
170.2032 + ru.query = base.query;
170.2033 + return ru;
170.2034 + }
170.2035 +
170.2036 + // 5.2 (3): Child is absolute
170.2037 + if (child.scheme != null)
170.2038 + return child;
170.2039 +
170.2040 + URI ru = new URI(); // Resolved URI
170.2041 + ru.scheme = base.scheme;
170.2042 + ru.query = child.query;
170.2043 + ru.fragment = child.fragment;
170.2044 +
170.2045 + // 5.2 (4): Authority
170.2046 + if (child.authority == null) {
170.2047 + ru.authority = base.authority;
170.2048 + ru.host = base.host;
170.2049 + ru.userInfo = base.userInfo;
170.2050 + ru.port = base.port;
170.2051 +
170.2052 + String cp = (child.path == null) ? "" : child.path;
170.2053 + if ((cp.length() > 0) && (cp.charAt(0) == '/')) {
170.2054 + // 5.2 (5): Child path is absolute
170.2055 + ru.path = child.path;
170.2056 + } else {
170.2057 + // 5.2 (6): Resolve relative path
170.2058 + ru.path = resolvePath(base.path, cp, base.isAbsolute());
170.2059 + }
170.2060 + } else {
170.2061 + ru.authority = child.authority;
170.2062 + ru.host = child.host;
170.2063 + ru.userInfo = child.userInfo;
170.2064 + ru.host = child.host;
170.2065 + ru.port = child.port;
170.2066 + ru.path = child.path;
170.2067 + }
170.2068 +
170.2069 + // 5.2 (7): Recombine (nothing to do here)
170.2070 + return ru;
170.2071 + }
170.2072 +
170.2073 + // If the given URI's path is normal then return the URI;
170.2074 + // o.w., return a new URI containing the normalized path.
170.2075 + //
170.2076 + private static URI normalize(URI u) {
170.2077 + if (u.isOpaque() || (u.path == null) || (u.path.length() == 0))
170.2078 + return u;
170.2079 +
170.2080 + String np = normalize(u.path);
170.2081 + if (np == u.path)
170.2082 + return u;
170.2083 +
170.2084 + URI v = new URI();
170.2085 + v.scheme = u.scheme;
170.2086 + v.fragment = u.fragment;
170.2087 + v.authority = u.authority;
170.2088 + v.userInfo = u.userInfo;
170.2089 + v.host = u.host;
170.2090 + v.port = u.port;
170.2091 + v.path = np;
170.2092 + v.query = u.query;
170.2093 + return v;
170.2094 + }
170.2095 +
170.2096 + // If both URIs are hierarchical, their scheme and authority components are
170.2097 + // identical, and the base path is a prefix of the child's path, then
170.2098 + // return a relative URI that, when resolved against the base, yields the
170.2099 + // child; otherwise, return the child.
170.2100 + //
170.2101 + private static URI relativize(URI base, URI child) {
170.2102 + // check if child if opaque first so that NPE is thrown
170.2103 + // if child is null.
170.2104 + if (child.isOpaque() || base.isOpaque())
170.2105 + return child;
170.2106 + if (!equalIgnoringCase(base.scheme, child.scheme)
170.2107 + || !equal(base.authority, child.authority))
170.2108 + return child;
170.2109 +
170.2110 + String bp = normalize(base.path);
170.2111 + String cp = normalize(child.path);
170.2112 + if (!bp.equals(cp)) {
170.2113 + if (!bp.endsWith("/"))
170.2114 + bp = bp + "/";
170.2115 + if (!cp.startsWith(bp))
170.2116 + return child;
170.2117 + }
170.2118 +
170.2119 + URI v = new URI();
170.2120 + v.path = cp.substring(bp.length());
170.2121 + v.query = child.query;
170.2122 + v.fragment = child.fragment;
170.2123 + return v;
170.2124 + }
170.2125 +
170.2126 +
170.2127 +
170.2128 + // -- Path normalization --
170.2129 +
170.2130 + // The following algorithm for path normalization avoids the creation of a
170.2131 + // string object for each segment, as well as the use of a string buffer to
170.2132 + // compute the final result, by using a single char array and editing it in
170.2133 + // place. The array is first split into segments, replacing each slash
170.2134 + // with '\0' and creating a segment-index array, each element of which is
170.2135 + // the index of the first char in the corresponding segment. We then walk
170.2136 + // through both arrays, removing ".", "..", and other segments as necessary
170.2137 + // by setting their entries in the index array to -1. Finally, the two
170.2138 + // arrays are used to rejoin the segments and compute the final result.
170.2139 + //
170.2140 + // This code is based upon src/solaris/native/java/io/canonicalize_md.c
170.2141 +
170.2142 +
170.2143 + // Check the given path to see if it might need normalization. A path
170.2144 + // might need normalization if it contains duplicate slashes, a "."
170.2145 + // segment, or a ".." segment. Return -1 if no further normalization is
170.2146 + // possible, otherwise return the number of segments found.
170.2147 + //
170.2148 + // This method takes a string argument rather than a char array so that
170.2149 + // this test can be performed without invoking path.toCharArray().
170.2150 + //
170.2151 + static private int needsNormalization(String path) {
170.2152 + boolean normal = true;
170.2153 + int ns = 0; // Number of segments
170.2154 + int end = path.length() - 1; // Index of last char in path
170.2155 + int p = 0; // Index of next char in path
170.2156 +
170.2157 + // Skip initial slashes
170.2158 + while (p <= end) {
170.2159 + if (path.charAt(p) != '/') break;
170.2160 + p++;
170.2161 + }
170.2162 + if (p > 1) normal = false;
170.2163 +
170.2164 + // Scan segments
170.2165 + while (p <= end) {
170.2166 +
170.2167 + // Looking at "." or ".." ?
170.2168 + if ((path.charAt(p) == '.')
170.2169 + && ((p == end)
170.2170 + || ((path.charAt(p + 1) == '/')
170.2171 + || ((path.charAt(p + 1) == '.')
170.2172 + && ((p + 1 == end)
170.2173 + || (path.charAt(p + 2) == '/')))))) {
170.2174 + normal = false;
170.2175 + }
170.2176 + ns++;
170.2177 +
170.2178 + // Find beginning of next segment
170.2179 + while (p <= end) {
170.2180 + if (path.charAt(p++) != '/')
170.2181 + continue;
170.2182 +
170.2183 + // Skip redundant slashes
170.2184 + while (p <= end) {
170.2185 + if (path.charAt(p) != '/') break;
170.2186 + normal = false;
170.2187 + p++;
170.2188 + }
170.2189 +
170.2190 + break;
170.2191 + }
170.2192 + }
170.2193 +
170.2194 + return normal ? -1 : ns;
170.2195 + }
170.2196 +
170.2197 +
170.2198 + // Split the given path into segments, replacing slashes with nulls and
170.2199 + // filling in the given segment-index array.
170.2200 + //
170.2201 + // Preconditions:
170.2202 + // segs.length == Number of segments in path
170.2203 + //
170.2204 + // Postconditions:
170.2205 + // All slashes in path replaced by '\0'
170.2206 + // segs[i] == Index of first char in segment i (0 <= i < segs.length)
170.2207 + //
170.2208 + static private void split(char[] path, int[] segs) {
170.2209 + int end = path.length - 1; // Index of last char in path
170.2210 + int p = 0; // Index of next char in path
170.2211 + int i = 0; // Index of current segment
170.2212 +
170.2213 + // Skip initial slashes
170.2214 + while (p <= end) {
170.2215 + if (path[p] != '/') break;
170.2216 + path[p] = '\0';
170.2217 + p++;
170.2218 + }
170.2219 +
170.2220 + while (p <= end) {
170.2221 +
170.2222 + // Note start of segment
170.2223 + segs[i++] = p++;
170.2224 +
170.2225 + // Find beginning of next segment
170.2226 + while (p <= end) {
170.2227 + if (path[p++] != '/')
170.2228 + continue;
170.2229 + path[p - 1] = '\0';
170.2230 +
170.2231 + // Skip redundant slashes
170.2232 + while (p <= end) {
170.2233 + if (path[p] != '/') break;
170.2234 + path[p++] = '\0';
170.2235 + }
170.2236 + break;
170.2237 + }
170.2238 + }
170.2239 +
170.2240 + if (i != segs.length)
170.2241 + throw new InternalError(); // ASSERT
170.2242 + }
170.2243 +
170.2244 +
170.2245 + // Join the segments in the given path according to the given segment-index
170.2246 + // array, ignoring those segments whose index entries have been set to -1,
170.2247 + // and inserting slashes as needed. Return the length of the resulting
170.2248 + // path.
170.2249 + //
170.2250 + // Preconditions:
170.2251 + // segs[i] == -1 implies segment i is to be ignored
170.2252 + // path computed by split, as above, with '\0' having replaced '/'
170.2253 + //
170.2254 + // Postconditions:
170.2255 + // path[0] .. path[return value] == Resulting path
170.2256 + //
170.2257 + static private int join(char[] path, int[] segs) {
170.2258 + int ns = segs.length; // Number of segments
170.2259 + int end = path.length - 1; // Index of last char in path
170.2260 + int p = 0; // Index of next path char to write
170.2261 +
170.2262 + if (path[p] == '\0') {
170.2263 + // Restore initial slash for absolute paths
170.2264 + path[p++] = '/';
170.2265 + }
170.2266 +
170.2267 + for (int i = 0; i < ns; i++) {
170.2268 + int q = segs[i]; // Current segment
170.2269 + if (q == -1)
170.2270 + // Ignore this segment
170.2271 + continue;
170.2272 +
170.2273 + if (p == q) {
170.2274 + // We're already at this segment, so just skip to its end
170.2275 + while ((p <= end) && (path[p] != '\0'))
170.2276 + p++;
170.2277 + if (p <= end) {
170.2278 + // Preserve trailing slash
170.2279 + path[p++] = '/';
170.2280 + }
170.2281 + } else if (p < q) {
170.2282 + // Copy q down to p
170.2283 + while ((q <= end) && (path[q] != '\0'))
170.2284 + path[p++] = path[q++];
170.2285 + if (q <= end) {
170.2286 + // Preserve trailing slash
170.2287 + path[p++] = '/';
170.2288 + }
170.2289 + } else
170.2290 + throw new InternalError(); // ASSERT false
170.2291 + }
170.2292 +
170.2293 + return p;
170.2294 + }
170.2295 +
170.2296 +
170.2297 + // Remove "." segments from the given path, and remove segment pairs
170.2298 + // consisting of a non-".." segment followed by a ".." segment.
170.2299 + //
170.2300 + private static void removeDots(char[] path, int[] segs) {
170.2301 + int ns = segs.length;
170.2302 + int end = path.length - 1;
170.2303 +
170.2304 + for (int i = 0; i < ns; i++) {
170.2305 + int dots = 0; // Number of dots found (0, 1, or 2)
170.2306 +
170.2307 + // Find next occurrence of "." or ".."
170.2308 + do {
170.2309 + int p = segs[i];
170.2310 + if (path[p] == '.') {
170.2311 + if (p == end) {
170.2312 + dots = 1;
170.2313 + break;
170.2314 + } else if (path[p + 1] == '\0') {
170.2315 + dots = 1;
170.2316 + break;
170.2317 + } else if ((path[p + 1] == '.')
170.2318 + && ((p + 1 == end)
170.2319 + || (path[p + 2] == '\0'))) {
170.2320 + dots = 2;
170.2321 + break;
170.2322 + }
170.2323 + }
170.2324 + i++;
170.2325 + } while (i < ns);
170.2326 + if ((i > ns) || (dots == 0))
170.2327 + break;
170.2328 +
170.2329 + if (dots == 1) {
170.2330 + // Remove this occurrence of "."
170.2331 + segs[i] = -1;
170.2332 + } else {
170.2333 + // If there is a preceding non-".." segment, remove both that
170.2334 + // segment and this occurrence of ".."; otherwise, leave this
170.2335 + // ".." segment as-is.
170.2336 + int j;
170.2337 + for (j = i - 1; j >= 0; j--) {
170.2338 + if (segs[j] != -1) break;
170.2339 + }
170.2340 + if (j >= 0) {
170.2341 + int q = segs[j];
170.2342 + if (!((path[q] == '.')
170.2343 + && (path[q + 1] == '.')
170.2344 + && (path[q + 2] == '\0'))) {
170.2345 + segs[i] = -1;
170.2346 + segs[j] = -1;
170.2347 + }
170.2348 + }
170.2349 + }
170.2350 + }
170.2351 + }
170.2352 +
170.2353 +
170.2354 + // DEVIATION: If the normalized path is relative, and if the first
170.2355 + // segment could be parsed as a scheme name, then prepend a "." segment
170.2356 + //
170.2357 + private static void maybeAddLeadingDot(char[] path, int[] segs) {
170.2358 +
170.2359 + if (path[0] == '\0')
170.2360 + // The path is absolute
170.2361 + return;
170.2362 +
170.2363 + int ns = segs.length;
170.2364 + int f = 0; // Index of first segment
170.2365 + while (f < ns) {
170.2366 + if (segs[f] >= 0)
170.2367 + break;
170.2368 + f++;
170.2369 + }
170.2370 + if ((f >= ns) || (f == 0))
170.2371 + // The path is empty, or else the original first segment survived,
170.2372 + // in which case we already know that no leading "." is needed
170.2373 + return;
170.2374 +
170.2375 + int p = segs[f];
170.2376 + while ((p < path.length) && (path[p] != ':') && (path[p] != '\0')) p++;
170.2377 + if (p >= path.length || path[p] == '\0')
170.2378 + // No colon in first segment, so no "." needed
170.2379 + return;
170.2380 +
170.2381 + // At this point we know that the first segment is unused,
170.2382 + // hence we can insert a "." segment at that position
170.2383 + path[0] = '.';
170.2384 + path[1] = '\0';
170.2385 + segs[0] = 0;
170.2386 + }
170.2387 +
170.2388 +
170.2389 + // Normalize the given path string. A normal path string has no empty
170.2390 + // segments (i.e., occurrences of "//"), no segments equal to ".", and no
170.2391 + // segments equal to ".." that are preceded by a segment not equal to "..".
170.2392 + // In contrast to Unix-style pathname normalization, for URI paths we
170.2393 + // always retain trailing slashes.
170.2394 + //
170.2395 + private static String normalize(String ps) {
170.2396 +
170.2397 + // Does this path need normalization?
170.2398 + int ns = needsNormalization(ps); // Number of segments
170.2399 + if (ns < 0)
170.2400 + // Nope -- just return it
170.2401 + return ps;
170.2402 +
170.2403 + char[] path = ps.toCharArray(); // Path in char-array form
170.2404 +
170.2405 + // Split path into segments
170.2406 + int[] segs = new int[ns]; // Segment-index array
170.2407 + split(path, segs);
170.2408 +
170.2409 + // Remove dots
170.2410 + removeDots(path, segs);
170.2411 +
170.2412 + // Prevent scheme-name confusion
170.2413 + maybeAddLeadingDot(path, segs);
170.2414 +
170.2415 + // Join the remaining segments and return the result
170.2416 + String s = new String(path, 0, join(path, segs));
170.2417 + if (s.equals(ps)) {
170.2418 + // string was already normalized
170.2419 + return ps;
170.2420 + }
170.2421 + return s;
170.2422 + }
170.2423 +
170.2424 +
170.2425 +
170.2426 + // -- Character classes for parsing --
170.2427 +
170.2428 + // RFC2396 precisely specifies which characters in the US-ASCII charset are
170.2429 + // permissible in the various components of a URI reference. We here
170.2430 + // define a set of mask pairs to aid in enforcing these restrictions. Each
170.2431 + // mask pair consists of two longs, a low mask and a high mask. Taken
170.2432 + // together they represent a 128-bit mask, where bit i is set iff the
170.2433 + // character with value i is permitted.
170.2434 + //
170.2435 + // This approach is more efficient than sequentially searching arrays of
170.2436 + // permitted characters. It could be made still more efficient by
170.2437 + // precompiling the mask information so that a character's presence in a
170.2438 + // given mask could be determined by a single table lookup.
170.2439 +
170.2440 + // Compute the low-order mask for the characters in the given string
170.2441 + private static long lowMask(String chars) {
170.2442 + int n = chars.length();
170.2443 + long m = 0;
170.2444 + for (int i = 0; i < n; i++) {
170.2445 + char c = chars.charAt(i);
170.2446 + if (c < 64)
170.2447 + m |= (1L << c);
170.2448 + }
170.2449 + return m;
170.2450 + }
170.2451 +
170.2452 + // Compute the high-order mask for the characters in the given string
170.2453 + private static long highMask(String chars) {
170.2454 + int n = chars.length();
170.2455 + long m = 0;
170.2456 + for (int i = 0; i < n; i++) {
170.2457 + char c = chars.charAt(i);
170.2458 + if ((c >= 64) && (c < 128))
170.2459 + m |= (1L << (c - 64));
170.2460 + }
170.2461 + return m;
170.2462 + }
170.2463 +
170.2464 + // Compute a low-order mask for the characters
170.2465 + // between first and last, inclusive
170.2466 + private static long lowMask(char first, char last) {
170.2467 + long m = 0;
170.2468 + int f = Math.max(Math.min(first, 63), 0);
170.2469 + int l = Math.max(Math.min(last, 63), 0);
170.2470 + for (int i = f; i <= l; i++)
170.2471 + m |= 1L << i;
170.2472 + return m;
170.2473 + }
170.2474 +
170.2475 + // Compute a high-order mask for the characters
170.2476 + // between first and last, inclusive
170.2477 + private static long highMask(char first, char last) {
170.2478 + long m = 0;
170.2479 + int f = Math.max(Math.min(first, 127), 64) - 64;
170.2480 + int l = Math.max(Math.min(last, 127), 64) - 64;
170.2481 + for (int i = f; i <= l; i++)
170.2482 + m |= 1L << i;
170.2483 + return m;
170.2484 + }
170.2485 +
170.2486 + // Tell whether the given character is permitted by the given mask pair
170.2487 + private static boolean match(char c, long lowMask, long highMask) {
170.2488 + if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
170.2489 + return false;
170.2490 + if (c < 64)
170.2491 + return ((1L << c) & lowMask) != 0;
170.2492 + if (c < 128)
170.2493 + return ((1L << (c - 64)) & highMask) != 0;
170.2494 + return false;
170.2495 + }
170.2496 +
170.2497 + // Character-class masks, in reverse order from RFC2396 because
170.2498 + // initializers for static fields cannot make forward references.
170.2499 +
170.2500 + // digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
170.2501 + // "8" | "9"
170.2502 + private static final long L_DIGIT = lowMask('0', '9');
170.2503 + private static final long H_DIGIT = 0L;
170.2504 +
170.2505 + // upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
170.2506 + // "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
170.2507 + // "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
170.2508 + private static final long L_UPALPHA = 0L;
170.2509 + private static final long H_UPALPHA = highMask('A', 'Z');
170.2510 +
170.2511 + // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
170.2512 + // "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
170.2513 + // "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
170.2514 + private static final long L_LOWALPHA = 0L;
170.2515 + private static final long H_LOWALPHA = highMask('a', 'z');
170.2516 +
170.2517 + // alpha = lowalpha | upalpha
170.2518 + private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
170.2519 + private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
170.2520 +
170.2521 + // alphanum = alpha | digit
170.2522 + private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
170.2523 + private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
170.2524 +
170.2525 + // hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
170.2526 + // "a" | "b" | "c" | "d" | "e" | "f"
170.2527 + private static final long L_HEX = L_DIGIT;
170.2528 + private static final long H_HEX = highMask('A', 'F') | highMask('a', 'f');
170.2529 +
170.2530 + // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
170.2531 + // "(" | ")"
170.2532 + private static final long L_MARK = lowMask("-_.!~*'()");
170.2533 + private static final long H_MARK = highMask("-_.!~*'()");
170.2534 +
170.2535 + // unreserved = alphanum | mark
170.2536 + private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
170.2537 + private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
170.2538 +
170.2539 + // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
170.2540 + // "$" | "," | "[" | "]"
170.2541 + // Added per RFC2732: "[", "]"
170.2542 + private static final long L_RESERVED = lowMask(";/?:@&=+$,[]");
170.2543 + private static final long H_RESERVED = highMask(";/?:@&=+$,[]");
170.2544 +
170.2545 + // The zero'th bit is used to indicate that escape pairs and non-US-ASCII
170.2546 + // characters are allowed; this is handled by the scanEscape method below.
170.2547 + private static final long L_ESCAPED = 1L;
170.2548 + private static final long H_ESCAPED = 0L;
170.2549 +
170.2550 + // uric = reserved | unreserved | escaped
170.2551 + private static final long L_URIC = L_RESERVED | L_UNRESERVED | L_ESCAPED;
170.2552 + private static final long H_URIC = H_RESERVED | H_UNRESERVED | H_ESCAPED;
170.2553 +
170.2554 + // pchar = unreserved | escaped |
170.2555 + // ":" | "@" | "&" | "=" | "+" | "$" | ","
170.2556 + private static final long L_PCHAR
170.2557 + = L_UNRESERVED | L_ESCAPED | lowMask(":@&=+$,");
170.2558 + private static final long H_PCHAR
170.2559 + = H_UNRESERVED | H_ESCAPED | highMask(":@&=+$,");
170.2560 +
170.2561 + // All valid path characters
170.2562 + private static final long L_PATH = L_PCHAR | lowMask(";/");
170.2563 + private static final long H_PATH = H_PCHAR | highMask(";/");
170.2564 +
170.2565 + // Dash, for use in domainlabel and toplabel
170.2566 + private static final long L_DASH = lowMask("-");
170.2567 + private static final long H_DASH = highMask("-");
170.2568 +
170.2569 + // Dot, for use in hostnames
170.2570 + private static final long L_DOT = lowMask(".");
170.2571 + private static final long H_DOT = highMask(".");
170.2572 +
170.2573 + // userinfo = *( unreserved | escaped |
170.2574 + // ";" | ":" | "&" | "=" | "+" | "$" | "," )
170.2575 + private static final long L_USERINFO
170.2576 + = L_UNRESERVED | L_ESCAPED | lowMask(";:&=+$,");
170.2577 + private static final long H_USERINFO
170.2578 + = H_UNRESERVED | H_ESCAPED | highMask(";:&=+$,");
170.2579 +
170.2580 + // reg_name = 1*( unreserved | escaped | "$" | "," |
170.2581 + // ";" | ":" | "@" | "&" | "=" | "+" )
170.2582 + private static final long L_REG_NAME
170.2583 + = L_UNRESERVED | L_ESCAPED | lowMask("$,;:@&=+");
170.2584 + private static final long H_REG_NAME
170.2585 + = H_UNRESERVED | H_ESCAPED | highMask("$,;:@&=+");
170.2586 +
170.2587 + // All valid characters for server-based authorities
170.2588 + private static final long L_SERVER
170.2589 + = L_USERINFO | L_ALPHANUM | L_DASH | lowMask(".:@[]");
170.2590 + private static final long H_SERVER
170.2591 + = H_USERINFO | H_ALPHANUM | H_DASH | highMask(".:@[]");
170.2592 +
170.2593 + // Special case of server authority that represents an IPv6 address
170.2594 + // In this case, a % does not signify an escape sequence
170.2595 + private static final long L_SERVER_PERCENT
170.2596 + = L_SERVER | lowMask("%");
170.2597 + private static final long H_SERVER_PERCENT
170.2598 + = H_SERVER | highMask("%");
170.2599 + private static final long L_LEFT_BRACKET = lowMask("[");
170.2600 + private static final long H_LEFT_BRACKET = highMask("[");
170.2601 +
170.2602 + // scheme = alpha *( alpha | digit | "+" | "-" | "." )
170.2603 + private static final long L_SCHEME = L_ALPHA | L_DIGIT | lowMask("+-.");
170.2604 + private static final long H_SCHEME = H_ALPHA | H_DIGIT | highMask("+-.");
170.2605 +
170.2606 + // uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
170.2607 + // "&" | "=" | "+" | "$" | ","
170.2608 + private static final long L_URIC_NO_SLASH
170.2609 + = L_UNRESERVED | L_ESCAPED | lowMask(";?:@&=+$,");
170.2610 + private static final long H_URIC_NO_SLASH
170.2611 + = H_UNRESERVED | H_ESCAPED | highMask(";?:@&=+$,");
170.2612 +
170.2613 +
170.2614 + // -- Escaping and encoding --
170.2615 +
170.2616 + private final static char[] hexDigits = {
170.2617 + '0', '1', '2', '3', '4', '5', '6', '7',
170.2618 + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
170.2619 + };
170.2620 +
170.2621 + private static void appendEscape(StringBuffer sb, byte b) {
170.2622 + sb.append('%');
170.2623 + sb.append(hexDigits[(b >> 4) & 0x0f]);
170.2624 + sb.append(hexDigits[(b >> 0) & 0x0f]);
170.2625 + }
170.2626 +
170.2627 + private static void appendEncoded(StringBuffer sb, char c) {
170.2628 + /*
170.2629 + ByteBuffer bb = null;
170.2630 + try {
170.2631 + bb = ThreadLocalCoders.encoderFor("UTF-8")
170.2632 + .encode(CharBuffer.wrap("" + c));
170.2633 + } catch (CharacterCodingException x) {
170.2634 + assert false;
170.2635 + }
170.2636 + while (bb.hasRemaining()) {
170.2637 + int b = bb.get() & 0xff;
170.2638 + if (b >= 0x80)
170.2639 + appendEscape(sb, (byte)b);
170.2640 + else
170.2641 + sb.append((char)b);
170.2642 + }
170.2643 + */
170.2644 + }
170.2645 +
170.2646 + // Quote any characters in s that are not permitted
170.2647 + // by the given mask pair
170.2648 + //
170.2649 + private static String quote(String s, long lowMask, long highMask) {
170.2650 + int n = s.length();
170.2651 + StringBuffer sb = null;
170.2652 + boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0);
170.2653 + for (int i = 0; i < s.length(); i++) {
170.2654 + char c = s.charAt(i);
170.2655 + if (c < '\u0080') {
170.2656 + if (!match(c, lowMask, highMask)) {
170.2657 + if (sb == null) {
170.2658 + sb = new StringBuffer();
170.2659 + sb.append(s.substring(0, i));
170.2660 + }
170.2661 + appendEscape(sb, (byte)c);
170.2662 + } else {
170.2663 + if (sb != null)
170.2664 + sb.append(c);
170.2665 + }
170.2666 + } else if (allowNonASCII
170.2667 + && (Character.isSpaceChar(c)
170.2668 + || Character.isISOControl(c))) {
170.2669 + if (sb == null) {
170.2670 + sb = new StringBuffer();
170.2671 + sb.append(s.substring(0, i));
170.2672 + }
170.2673 + appendEncoded(sb, c);
170.2674 + } else {
170.2675 + if (sb != null)
170.2676 + sb.append(c);
170.2677 + }
170.2678 + }
170.2679 + return (sb == null) ? s : sb.toString();
170.2680 + }
170.2681 +
170.2682 + // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets,
170.2683 + // assuming that s is otherwise legal
170.2684 + //
170.2685 + private static String encode(String s) {
170.2686 + int n = s.length();
170.2687 + if (n == 0)
170.2688 + return s;
170.2689 +
170.2690 + // First check whether we actually need to encode
170.2691 + for (int i = 0;;) {
170.2692 + if (s.charAt(i) >= '\u0080')
170.2693 + break;
170.2694 + if (++i >= n)
170.2695 + return s;
170.2696 + }
170.2697 +/*
170.2698 + String ns = Normalizer.normalize(s, Normalizer.Form.NFC);
170.2699 + ByteBuffer bb = null;
170.2700 + try {
170.2701 + bb = ThreadLocalCoders.encoderFor("UTF-8")
170.2702 + .encode(CharBuffer.wrap(ns));
170.2703 + } catch (CharacterCodingException x) {
170.2704 + assert false;
170.2705 + }
170.2706 +*/
170.2707 + StringBuffer sb = new StringBuffer();
170.2708 + /*
170.2709 + while (bb.hasRemaining()) {
170.2710 + int b = bb.get() & 0xff;
170.2711 + if (b >= 0x80)
170.2712 + appendEscape(sb, (byte)b);
170.2713 + else
170.2714 + sb.append((char)b);
170.2715 + }
170.2716 + */
170.2717 + return sb.toString();
170.2718 + }
170.2719 +
170.2720 + private static int decode(char c) {
170.2721 + if ((c >= '0') && (c <= '9'))
170.2722 + return c - '0';
170.2723 + if ((c >= 'a') && (c <= 'f'))
170.2724 + return c - 'a' + 10;
170.2725 + if ((c >= 'A') && (c <= 'F'))
170.2726 + return c - 'A' + 10;
170.2727 + assert false;
170.2728 + return -1;
170.2729 + }
170.2730 +
170.2731 + private static byte decode(char c1, char c2) {
170.2732 + return (byte)( ((decode(c1) & 0xf) << 4)
170.2733 + | ((decode(c2) & 0xf) << 0));
170.2734 + }
170.2735 +
170.2736 + // Evaluates all escapes in s, applying UTF-8 decoding if needed. Assumes
170.2737 + // that escapes are well-formed syntactically, i.e., of the form %XX. If a
170.2738 + // sequence of escaped octets is not valid UTF-8 then the erroneous octets
170.2739 + // are replaced with '\uFFFD'.
170.2740 + // Exception: any "%" found between "[]" is left alone. It is an IPv6 literal
170.2741 + // with a scope_id
170.2742 + //
170.2743 + private static String decode(String s) {
170.2744 + if (s == null)
170.2745 + return s;
170.2746 + int n = s.length();
170.2747 + if (n == 0)
170.2748 + return s;
170.2749 + if (s.indexOf('%') < 0)
170.2750 + return s;
170.2751 +
170.2752 + StringBuffer sb = new StringBuffer(n);
170.2753 + /*
170.2754 + ByteBuffer bb = ByteBuffer.allocate(n);
170.2755 + CharBuffer cb = CharBuffer.allocate(n);
170.2756 + CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8")
170.2757 + .onMalformedInput(CodingErrorAction.REPLACE)
170.2758 + .onUnmappableCharacter(CodingErrorAction.REPLACE);
170.2759 +
170.2760 + // This is not horribly efficient, but it will do for now
170.2761 + char c = s.charAt(0);
170.2762 + boolean betweenBrackets = false;
170.2763 +
170.2764 + for (int i = 0; i < n;) {
170.2765 + assert c == s.charAt(i); // Loop invariant
170.2766 + if (c == '[') {
170.2767 + betweenBrackets = true;
170.2768 + } else if (betweenBrackets && c == ']') {
170.2769 + betweenBrackets = false;
170.2770 + }
170.2771 + if (c != '%' || betweenBrackets) {
170.2772 + sb.append(c);
170.2773 + if (++i >= n)
170.2774 + break;
170.2775 + c = s.charAt(i);
170.2776 + continue;
170.2777 + }
170.2778 + bb.clear();
170.2779 + int ui = i;
170.2780 + for (;;) {
170.2781 + assert (n - i >= 2);
170.2782 + bb.put(decode(s.charAt(++i), s.charAt(++i)));
170.2783 + if (++i >= n)
170.2784 + break;
170.2785 + c = s.charAt(i);
170.2786 + if (c != '%')
170.2787 + break;
170.2788 + }
170.2789 + bb.flip();
170.2790 + cb.clear();
170.2791 + dec.reset();
170.2792 + CoderResult cr = dec.decode(bb, cb, true);
170.2793 + assert cr.isUnderflow();
170.2794 + cr = dec.flush(cb);
170.2795 + assert cr.isUnderflow();
170.2796 + sb.append(cb.flip().toString());
170.2797 + }
170.2798 +*/
170.2799 + return sb.toString();
170.2800 + }
170.2801 +
170.2802 +
170.2803 + // -- Parsing --
170.2804 +
170.2805 + // For convenience we wrap the input URI string in a new instance of the
170.2806 + // following internal class. This saves always having to pass the input
170.2807 + // string as an argument to each internal scan/parse method.
170.2808 +
170.2809 + private class Parser {
170.2810 +
170.2811 + private String input; // URI input string
170.2812 + private boolean requireServerAuthority = false;
170.2813 +
170.2814 + Parser(String s) {
170.2815 + input = s;
170.2816 + string = s;
170.2817 + }
170.2818 +
170.2819 + // -- Methods for throwing URISyntaxException in various ways --
170.2820 +
170.2821 + private void fail(String reason) throws URISyntaxException {
170.2822 + throw new URISyntaxException(input, reason);
170.2823 + }
170.2824 +
170.2825 + private void fail(String reason, int p) throws URISyntaxException {
170.2826 + throw new URISyntaxException(input, reason, p);
170.2827 + }
170.2828 +
170.2829 + private void failExpecting(String expected, int p)
170.2830 + throws URISyntaxException
170.2831 + {
170.2832 + fail("Expected " + expected, p);
170.2833 + }
170.2834 +
170.2835 + private void failExpecting(String expected, String prior, int p)
170.2836 + throws URISyntaxException
170.2837 + {
170.2838 + fail("Expected " + expected + " following " + prior, p);
170.2839 + }
170.2840 +
170.2841 +
170.2842 + // -- Simple access to the input string --
170.2843 +
170.2844 + // Return a substring of the input string
170.2845 + //
170.2846 + private String substring(int start, int end) {
170.2847 + return input.substring(start, end);
170.2848 + }
170.2849 +
170.2850 + // Return the char at position p,
170.2851 + // assuming that p < input.length()
170.2852 + //
170.2853 + private char charAt(int p) {
170.2854 + return input.charAt(p);
170.2855 + }
170.2856 +
170.2857 + // Tells whether start < end and, if so, whether charAt(start) == c
170.2858 + //
170.2859 + private boolean at(int start, int end, char c) {
170.2860 + return (start < end) && (charAt(start) == c);
170.2861 + }
170.2862 +
170.2863 + // Tells whether start + s.length() < end and, if so,
170.2864 + // whether the chars at the start position match s exactly
170.2865 + //
170.2866 + private boolean at(int start, int end, String s) {
170.2867 + int p = start;
170.2868 + int sn = s.length();
170.2869 + if (sn > end - p)
170.2870 + return false;
170.2871 + int i = 0;
170.2872 + while (i < sn) {
170.2873 + if (charAt(p++) != s.charAt(i)) {
170.2874 + break;
170.2875 + }
170.2876 + i++;
170.2877 + }
170.2878 + return (i == sn);
170.2879 + }
170.2880 +
170.2881 +
170.2882 + // -- Scanning --
170.2883 +
170.2884 + // The various scan and parse methods that follow use a uniform
170.2885 + // convention of taking the current start position and end index as
170.2886 + // their first two arguments. The start is inclusive while the end is
170.2887 + // exclusive, just as in the String class, i.e., a start/end pair
170.2888 + // denotes the left-open interval [start, end) of the input string.
170.2889 + //
170.2890 + // These methods never proceed past the end position. They may return
170.2891 + // -1 to indicate outright failure, but more often they simply return
170.2892 + // the position of the first char after the last char scanned. Thus
170.2893 + // a typical idiom is
170.2894 + //
170.2895 + // int p = start;
170.2896 + // int q = scan(p, end, ...);
170.2897 + // if (q > p)
170.2898 + // // We scanned something
170.2899 + // ...;
170.2900 + // else if (q == p)
170.2901 + // // We scanned nothing
170.2902 + // ...;
170.2903 + // else if (q == -1)
170.2904 + // // Something went wrong
170.2905 + // ...;
170.2906 +
170.2907 +
170.2908 + // Scan a specific char: If the char at the given start position is
170.2909 + // equal to c, return the index of the next char; otherwise, return the
170.2910 + // start position.
170.2911 + //
170.2912 + private int scan(int start, int end, char c) {
170.2913 + if ((start < end) && (charAt(start) == c))
170.2914 + return start + 1;
170.2915 + return start;
170.2916 + }
170.2917 +
170.2918 + // Scan forward from the given start position. Stop at the first char
170.2919 + // in the err string (in which case -1 is returned), or the first char
170.2920 + // in the stop string (in which case the index of the preceding char is
170.2921 + // returned), or the end of the input string (in which case the length
170.2922 + // of the input string is returned). May return the start position if
170.2923 + // nothing matches.
170.2924 + //
170.2925 + private int scan(int start, int end, String err, String stop) {
170.2926 + int p = start;
170.2927 + while (p < end) {
170.2928 + char c = charAt(p);
170.2929 + if (err.indexOf(c) >= 0)
170.2930 + return -1;
170.2931 + if (stop.indexOf(c) >= 0)
170.2932 + break;
170.2933 + p++;
170.2934 + }
170.2935 + return p;
170.2936 + }
170.2937 +
170.2938 + // Scan a potential escape sequence, starting at the given position,
170.2939 + // with the given first char (i.e., charAt(start) == c).
170.2940 + //
170.2941 + // This method assumes that if escapes are allowed then visible
170.2942 + // non-US-ASCII chars are also allowed.
170.2943 + //
170.2944 + private int scanEscape(int start, int n, char first)
170.2945 + throws URISyntaxException
170.2946 + {
170.2947 + int p = start;
170.2948 + char c = first;
170.2949 + if (c == '%') {
170.2950 + // Process escape pair
170.2951 + if ((p + 3 <= n)
170.2952 + && match(charAt(p + 1), L_HEX, H_HEX)
170.2953 + && match(charAt(p + 2), L_HEX, H_HEX)) {
170.2954 + return p + 3;
170.2955 + }
170.2956 + fail("Malformed escape pair", p);
170.2957 + } else if ((c > 128)
170.2958 + && !Character.isSpaceChar(c)
170.2959 + && !Character.isISOControl(c)) {
170.2960 + // Allow unescaped but visible non-US-ASCII chars
170.2961 + return p + 1;
170.2962 + }
170.2963 + return p;
170.2964 + }
170.2965 +
170.2966 + // Scan chars that match the given mask pair
170.2967 + //
170.2968 + private int scan(int start, int n, long lowMask, long highMask)
170.2969 + throws URISyntaxException
170.2970 + {
170.2971 + int p = start;
170.2972 + while (p < n) {
170.2973 + char c = charAt(p);
170.2974 + if (match(c, lowMask, highMask)) {
170.2975 + p++;
170.2976 + continue;
170.2977 + }
170.2978 + if ((lowMask & L_ESCAPED) != 0) {
170.2979 + int q = scanEscape(p, n, c);
170.2980 + if (q > p) {
170.2981 + p = q;
170.2982 + continue;
170.2983 + }
170.2984 + }
170.2985 + break;
170.2986 + }
170.2987 + return p;
170.2988 + }
170.2989 +
170.2990 + // Check that each of the chars in [start, end) matches the given mask
170.2991 + //
170.2992 + private void checkChars(int start, int end,
170.2993 + long lowMask, long highMask,
170.2994 + String what)
170.2995 + throws URISyntaxException
170.2996 + {
170.2997 + int p = scan(start, end, lowMask, highMask);
170.2998 + if (p < end)
170.2999 + fail("Illegal character in " + what, p);
170.3000 + }
170.3001 +
170.3002 + // Check that the char at position p matches the given mask
170.3003 + //
170.3004 + private void checkChar(int p,
170.3005 + long lowMask, long highMask,
170.3006 + String what)
170.3007 + throws URISyntaxException
170.3008 + {
170.3009 + checkChars(p, p + 1, lowMask, highMask, what);
170.3010 + }
170.3011 +
170.3012 +
170.3013 + // -- Parsing --
170.3014 +
170.3015 + // [<scheme>:]<scheme-specific-part>[#<fragment>]
170.3016 + //
170.3017 + void parse(boolean rsa) throws URISyntaxException {
170.3018 + requireServerAuthority = rsa;
170.3019 + int ssp; // Start of scheme-specific part
170.3020 + int n = input.length();
170.3021 + int p = scan(0, n, "/?#", ":");
170.3022 + if ((p >= 0) && at(p, n, ':')) {
170.3023 + if (p == 0)
170.3024 + failExpecting("scheme name", 0);
170.3025 + checkChar(0, L_ALPHA, H_ALPHA, "scheme name");
170.3026 + checkChars(1, p, L_SCHEME, H_SCHEME, "scheme name");
170.3027 + scheme = substring(0, p);
170.3028 + p++; // Skip ':'
170.3029 + ssp = p;
170.3030 + if (at(p, n, '/')) {
170.3031 + p = parseHierarchical(p, n);
170.3032 + } else {
170.3033 + int q = scan(p, n, "", "#");
170.3034 + if (q <= p)
170.3035 + failExpecting("scheme-specific part", p);
170.3036 + checkChars(p, q, L_URIC, H_URIC, "opaque part");
170.3037 + p = q;
170.3038 + }
170.3039 + } else {
170.3040 + ssp = 0;
170.3041 + p = parseHierarchical(0, n);
170.3042 + }
170.3043 + schemeSpecificPart = substring(ssp, p);
170.3044 + if (at(p, n, '#')) {
170.3045 + checkChars(p + 1, n, L_URIC, H_URIC, "fragment");
170.3046 + fragment = substring(p + 1, n);
170.3047 + p = n;
170.3048 + }
170.3049 + if (p < n)
170.3050 + fail("end of URI", p);
170.3051 + }
170.3052 +
170.3053 + // [//authority]<path>[?<query>]
170.3054 + //
170.3055 + // DEVIATION from RFC2396: We allow an empty authority component as
170.3056 + // long as it's followed by a non-empty path, query component, or
170.3057 + // fragment component. This is so that URIs such as "file:///foo/bar"
170.3058 + // will parse. This seems to be the intent of RFC2396, though the
170.3059 + // grammar does not permit it. If the authority is empty then the
170.3060 + // userInfo, host, and port components are undefined.
170.3061 + //
170.3062 + // DEVIATION from RFC2396: We allow empty relative paths. This seems
170.3063 + // to be the intent of RFC2396, but the grammar does not permit it.
170.3064 + // The primary consequence of this deviation is that "#f" parses as a
170.3065 + // relative URI with an empty path.
170.3066 + //
170.3067 + private int parseHierarchical(int start, int n)
170.3068 + throws URISyntaxException
170.3069 + {
170.3070 + int p = start;
170.3071 + if (at(p, n, '/') && at(p + 1, n, '/')) {
170.3072 + p += 2;
170.3073 + int q = scan(p, n, "", "/?#");
170.3074 + if (q > p) {
170.3075 + p = parseAuthority(p, q);
170.3076 + } else if (q < n) {
170.3077 + // DEVIATION: Allow empty authority prior to non-empty
170.3078 + // path, query component or fragment identifier
170.3079 + } else
170.3080 + failExpecting("authority", p);
170.3081 + }
170.3082 + int q = scan(p, n, "", "?#"); // DEVIATION: May be empty
170.3083 + checkChars(p, q, L_PATH, H_PATH, "path");
170.3084 + path = substring(p, q);
170.3085 + p = q;
170.3086 + if (at(p, n, '?')) {
170.3087 + p++;
170.3088 + q = scan(p, n, "", "#");
170.3089 + checkChars(p, q, L_URIC, H_URIC, "query");
170.3090 + query = substring(p, q);
170.3091 + p = q;
170.3092 + }
170.3093 + return p;
170.3094 + }
170.3095 +
170.3096 + // authority = server | reg_name
170.3097 + //
170.3098 + // Ambiguity: An authority that is a registry name rather than a server
170.3099 + // might have a prefix that parses as a server. We use the fact that
170.3100 + // the authority component is always followed by '/' or the end of the
170.3101 + // input string to resolve this: If the complete authority did not
170.3102 + // parse as a server then we try to parse it as a registry name.
170.3103 + //
170.3104 + private int parseAuthority(int start, int n)
170.3105 + throws URISyntaxException
170.3106 + {
170.3107 + int p = start;
170.3108 + int q = p;
170.3109 + URISyntaxException ex = null;
170.3110 +
170.3111 + boolean serverChars;
170.3112 + boolean regChars;
170.3113 +
170.3114 + if (scan(p, n, "", "]") > p) {
170.3115 + // contains a literal IPv6 address, therefore % is allowed
170.3116 + serverChars = (scan(p, n, L_SERVER_PERCENT, H_SERVER_PERCENT) == n);
170.3117 + } else {
170.3118 + serverChars = (scan(p, n, L_SERVER, H_SERVER) == n);
170.3119 + }
170.3120 + regChars = (scan(p, n, L_REG_NAME, H_REG_NAME) == n);
170.3121 +
170.3122 + if (regChars && !serverChars) {
170.3123 + // Must be a registry-based authority
170.3124 + authority = substring(p, n);
170.3125 + return n;
170.3126 + }
170.3127 +
170.3128 + if (serverChars) {
170.3129 + // Might be (probably is) a server-based authority, so attempt
170.3130 + // to parse it as such. If the attempt fails, try to treat it
170.3131 + // as a registry-based authority.
170.3132 + try {
170.3133 + q = parseServer(p, n);
170.3134 + if (q < n)
170.3135 + failExpecting("end of authority", q);
170.3136 + authority = substring(p, n);
170.3137 + } catch (URISyntaxException x) {
170.3138 + // Undo results of failed parse
170.3139 + userInfo = null;
170.3140 + host = null;
170.3141 + port = -1;
170.3142 + if (requireServerAuthority) {
170.3143 + // If we're insisting upon a server-based authority,
170.3144 + // then just re-throw the exception
170.3145 + throw x;
170.3146 + } else {
170.3147 + // Save the exception in case it doesn't parse as a
170.3148 + // registry either
170.3149 + ex = x;
170.3150 + q = p;
170.3151 + }
170.3152 + }
170.3153 + }
170.3154 +
170.3155 + if (q < n) {
170.3156 + if (regChars) {
170.3157 + // Registry-based authority
170.3158 + authority = substring(p, n);
170.3159 + } else if (ex != null) {
170.3160 + // Re-throw exception; it was probably due to
170.3161 + // a malformed IPv6 address
170.3162 + throw ex;
170.3163 + } else {
170.3164 + fail("Illegal character in authority", q);
170.3165 + }
170.3166 + }
170.3167 +
170.3168 + return n;
170.3169 + }
170.3170 +
170.3171 +
170.3172 + // [<userinfo>@]<host>[:<port>]
170.3173 + //
170.3174 + private int parseServer(int start, int n)
170.3175 + throws URISyntaxException
170.3176 + {
170.3177 + int p = start;
170.3178 + int q;
170.3179 +
170.3180 + // userinfo
170.3181 + q = scan(p, n, "/?#", "@");
170.3182 + if ((q >= p) && at(q, n, '@')) {
170.3183 + checkChars(p, q, L_USERINFO, H_USERINFO, "user info");
170.3184 + userInfo = substring(p, q);
170.3185 + p = q + 1; // Skip '@'
170.3186 + }
170.3187 +
170.3188 + // hostname, IPv4 address, or IPv6 address
170.3189 + if (at(p, n, '[')) {
170.3190 + // DEVIATION from RFC2396: Support IPv6 addresses, per RFC2732
170.3191 + p++;
170.3192 + q = scan(p, n, "/?#", "]");
170.3193 + if ((q > p) && at(q, n, ']')) {
170.3194 + // look for a "%" scope id
170.3195 + int r = scan (p, q, "", "%");
170.3196 + if (r > p) {
170.3197 + parseIPv6Reference(p, r);
170.3198 + if (r+1 == q) {
170.3199 + fail ("scope id expected");
170.3200 + }
170.3201 + checkChars (r+1, q, L_ALPHANUM, H_ALPHANUM,
170.3202 + "scope id");
170.3203 + } else {
170.3204 + parseIPv6Reference(p, q);
170.3205 + }
170.3206 + host = substring(p-1, q+1);
170.3207 + p = q + 1;
170.3208 + } else {
170.3209 + failExpecting("closing bracket for IPv6 address", q);
170.3210 + }
170.3211 + } else {
170.3212 + q = parseIPv4Address(p, n);
170.3213 + if (q <= p)
170.3214 + q = parseHostname(p, n);
170.3215 + p = q;
170.3216 + }
170.3217 +
170.3218 + // port
170.3219 + if (at(p, n, ':')) {
170.3220 + p++;
170.3221 + q = scan(p, n, "", "/");
170.3222 + if (q > p) {
170.3223 + checkChars(p, q, L_DIGIT, H_DIGIT, "port number");
170.3224 + try {
170.3225 + port = Integer.parseInt(substring(p, q));
170.3226 + } catch (NumberFormatException x) {
170.3227 + fail("Malformed port number", p);
170.3228 + }
170.3229 + p = q;
170.3230 + }
170.3231 + }
170.3232 + if (p < n)
170.3233 + failExpecting("port number", p);
170.3234 +
170.3235 + return p;
170.3236 + }
170.3237 +
170.3238 + // Scan a string of decimal digits whose value fits in a byte
170.3239 + //
170.3240 + private int scanByte(int start, int n)
170.3241 + throws URISyntaxException
170.3242 + {
170.3243 + int p = start;
170.3244 + int q = scan(p, n, L_DIGIT, H_DIGIT);
170.3245 + if (q <= p) return q;
170.3246 + if (Integer.parseInt(substring(p, q)) > 255) return p;
170.3247 + return q;
170.3248 + }
170.3249 +
170.3250 + // Scan an IPv4 address.
170.3251 + //
170.3252 + // If the strict argument is true then we require that the given
170.3253 + // interval contain nothing besides an IPv4 address; if it is false
170.3254 + // then we only require that it start with an IPv4 address.
170.3255 + //
170.3256 + // If the interval does not contain or start with (depending upon the
170.3257 + // strict argument) a legal IPv4 address characters then we return -1
170.3258 + // immediately; otherwise we insist that these characters parse as a
170.3259 + // legal IPv4 address and throw an exception on failure.
170.3260 + //
170.3261 + // We assume that any string of decimal digits and dots must be an IPv4
170.3262 + // address. It won't parse as a hostname anyway, so making that
170.3263 + // assumption here allows more meaningful exceptions to be thrown.
170.3264 + //
170.3265 + private int scanIPv4Address(int start, int n, boolean strict)
170.3266 + throws URISyntaxException
170.3267 + {
170.3268 + int p = start;
170.3269 + int q;
170.3270 + int m = scan(p, n, L_DIGIT | L_DOT, H_DIGIT | H_DOT);
170.3271 + if ((m <= p) || (strict && (m != n)))
170.3272 + return -1;
170.3273 + for (;;) {
170.3274 + // Per RFC2732: At most three digits per byte
170.3275 + // Further constraint: Each element fits in a byte
170.3276 + if ((q = scanByte(p, m)) <= p) break; p = q;
170.3277 + if ((q = scan(p, m, '.')) <= p) break; p = q;
170.3278 + if ((q = scanByte(p, m)) <= p) break; p = q;
170.3279 + if ((q = scan(p, m, '.')) <= p) break; p = q;
170.3280 + if ((q = scanByte(p, m)) <= p) break; p = q;
170.3281 + if ((q = scan(p, m, '.')) <= p) break; p = q;
170.3282 + if ((q = scanByte(p, m)) <= p) break; p = q;
170.3283 + if (q < m) break;
170.3284 + return q;
170.3285 + }
170.3286 + fail("Malformed IPv4 address", q);
170.3287 + return -1;
170.3288 + }
170.3289 +
170.3290 + // Take an IPv4 address: Throw an exception if the given interval
170.3291 + // contains anything except an IPv4 address
170.3292 + //
170.3293 + private int takeIPv4Address(int start, int n, String expected)
170.3294 + throws URISyntaxException
170.3295 + {
170.3296 + int p = scanIPv4Address(start, n, true);
170.3297 + if (p <= start)
170.3298 + failExpecting(expected, start);
170.3299 + return p;
170.3300 + }
170.3301 +
170.3302 + // Attempt to parse an IPv4 address, returning -1 on failure but
170.3303 + // allowing the given interval to contain [:<characters>] after
170.3304 + // the IPv4 address.
170.3305 + //
170.3306 + private int parseIPv4Address(int start, int n) {
170.3307 + int p;
170.3308 +
170.3309 + try {
170.3310 + p = scanIPv4Address(start, n, false);
170.3311 + } catch (URISyntaxException x) {
170.3312 + return -1;
170.3313 + } catch (NumberFormatException nfe) {
170.3314 + return -1;
170.3315 + }
170.3316 +
170.3317 + if (p > start && p < n) {
170.3318 + // IPv4 address is followed by something - check that
170.3319 + // it's a ":" as this is the only valid character to
170.3320 + // follow an address.
170.3321 + if (charAt(p) != ':') {
170.3322 + p = -1;
170.3323 + }
170.3324 + }
170.3325 +
170.3326 + if (p > start)
170.3327 + host = substring(start, p);
170.3328 +
170.3329 + return p;
170.3330 + }
170.3331 +
170.3332 + // hostname = domainlabel [ "." ] | 1*( domainlabel "." ) toplabel [ "." ]
170.3333 + // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
170.3334 + // toplabel = alpha | alpha *( alphanum | "-" ) alphanum
170.3335 + //
170.3336 + private int parseHostname(int start, int n)
170.3337 + throws URISyntaxException
170.3338 + {
170.3339 + int p = start;
170.3340 + int q;
170.3341 + int l = -1; // Start of last parsed label
170.3342 +
170.3343 + do {
170.3344 + // domainlabel = alphanum [ *( alphanum | "-" ) alphanum ]
170.3345 + q = scan(p, n, L_ALPHANUM, H_ALPHANUM);
170.3346 + if (q <= p)
170.3347 + break;
170.3348 + l = p;
170.3349 + if (q > p) {
170.3350 + p = q;
170.3351 + q = scan(p, n, L_ALPHANUM | L_DASH, H_ALPHANUM | H_DASH);
170.3352 + if (q > p) {
170.3353 + if (charAt(q - 1) == '-')
170.3354 + fail("Illegal character in hostname", q - 1);
170.3355 + p = q;
170.3356 + }
170.3357 + }
170.3358 + q = scan(p, n, '.');
170.3359 + if (q <= p)
170.3360 + break;
170.3361 + p = q;
170.3362 + } while (p < n);
170.3363 +
170.3364 + if ((p < n) && !at(p, n, ':'))
170.3365 + fail("Illegal character in hostname", p);
170.3366 +
170.3367 + if (l < 0)
170.3368 + failExpecting("hostname", start);
170.3369 +
170.3370 + // for a fully qualified hostname check that the rightmost
170.3371 + // label starts with an alpha character.
170.3372 + if (l > start && !match(charAt(l), L_ALPHA, H_ALPHA)) {
170.3373 + fail("Illegal character in hostname", l);
170.3374 + }
170.3375 +
170.3376 + host = substring(start, p);
170.3377 + return p;
170.3378 + }
170.3379 +
170.3380 +
170.3381 + // IPv6 address parsing, from RFC2373: IPv6 Addressing Architecture
170.3382 + //
170.3383 + // Bug: The grammar in RFC2373 Appendix B does not allow addresses of
170.3384 + // the form ::12.34.56.78, which are clearly shown in the examples
170.3385 + // earlier in the document. Here is the original grammar:
170.3386 + //
170.3387 + // IPv6address = hexpart [ ":" IPv4address ]
170.3388 + // hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
170.3389 + // hexseq = hex4 *( ":" hex4)
170.3390 + // hex4 = 1*4HEXDIG
170.3391 + //
170.3392 + // We therefore use the following revised grammar:
170.3393 + //
170.3394 + // IPv6address = hexseq [ ":" IPv4address ]
170.3395 + // | hexseq [ "::" [ hexpost ] ]
170.3396 + // | "::" [ hexpost ]
170.3397 + // hexpost = hexseq | hexseq ":" IPv4address | IPv4address
170.3398 + // hexseq = hex4 *( ":" hex4)
170.3399 + // hex4 = 1*4HEXDIG
170.3400 + //
170.3401 + // This covers all and only the following cases:
170.3402 + //
170.3403 + // hexseq
170.3404 + // hexseq : IPv4address
170.3405 + // hexseq ::
170.3406 + // hexseq :: hexseq
170.3407 + // hexseq :: hexseq : IPv4address
170.3408 + // hexseq :: IPv4address
170.3409 + // :: hexseq
170.3410 + // :: hexseq : IPv4address
170.3411 + // :: IPv4address
170.3412 + // ::
170.3413 + //
170.3414 + // Additionally we constrain the IPv6 address as follows :-
170.3415 + //
170.3416 + // i. IPv6 addresses without compressed zeros should contain
170.3417 + // exactly 16 bytes.
170.3418 + //
170.3419 + // ii. IPv6 addresses with compressed zeros should contain
170.3420 + // less than 16 bytes.
170.3421 +
170.3422 + private int ipv6byteCount = 0;
170.3423 +
170.3424 + private int parseIPv6Reference(int start, int n)
170.3425 + throws URISyntaxException
170.3426 + {
170.3427 + int p = start;
170.3428 + int q;
170.3429 + boolean compressedZeros = false;
170.3430 +
170.3431 + q = scanHexSeq(p, n);
170.3432 +
170.3433 + if (q > p) {
170.3434 + p = q;
170.3435 + if (at(p, n, "::")) {
170.3436 + compressedZeros = true;
170.3437 + p = scanHexPost(p + 2, n);
170.3438 + } else if (at(p, n, ':')) {
170.3439 + p = takeIPv4Address(p + 1, n, "IPv4 address");
170.3440 + ipv6byteCount += 4;
170.3441 + }
170.3442 + } else if (at(p, n, "::")) {
170.3443 + compressedZeros = true;
170.3444 + p = scanHexPost(p + 2, n);
170.3445 + }
170.3446 + if (p < n)
170.3447 + fail("Malformed IPv6 address", start);
170.3448 + if (ipv6byteCount > 16)
170.3449 + fail("IPv6 address too long", start);
170.3450 + if (!compressedZeros && ipv6byteCount < 16)
170.3451 + fail("IPv6 address too short", start);
170.3452 + if (compressedZeros && ipv6byteCount == 16)
170.3453 + fail("Malformed IPv6 address", start);
170.3454 +
170.3455 + return p;
170.3456 + }
170.3457 +
170.3458 + private int scanHexPost(int start, int n)
170.3459 + throws URISyntaxException
170.3460 + {
170.3461 + int p = start;
170.3462 + int q;
170.3463 +
170.3464 + if (p == n)
170.3465 + return p;
170.3466 +
170.3467 + q = scanHexSeq(p, n);
170.3468 + if (q > p) {
170.3469 + p = q;
170.3470 + if (at(p, n, ':')) {
170.3471 + p++;
170.3472 + p = takeIPv4Address(p, n, "hex digits or IPv4 address");
170.3473 + ipv6byteCount += 4;
170.3474 + }
170.3475 + } else {
170.3476 + p = takeIPv4Address(p, n, "hex digits or IPv4 address");
170.3477 + ipv6byteCount += 4;
170.3478 + }
170.3479 + return p;
170.3480 + }
170.3481 +
170.3482 + // Scan a hex sequence; return -1 if one could not be scanned
170.3483 + //
170.3484 + private int scanHexSeq(int start, int n)
170.3485 + throws URISyntaxException
170.3486 + {
170.3487 + int p = start;
170.3488 + int q;
170.3489 +
170.3490 + q = scan(p, n, L_HEX, H_HEX);
170.3491 + if (q <= p)
170.3492 + return -1;
170.3493 + if (at(q, n, '.')) // Beginning of IPv4 address
170.3494 + return -1;
170.3495 + if (q > p + 4)
170.3496 + fail("IPv6 hexadecimal digit sequence too long", p);
170.3497 + ipv6byteCount += 2;
170.3498 + p = q;
170.3499 + while (p < n) {
170.3500 + if (!at(p, n, ':'))
170.3501 + break;
170.3502 + if (at(p + 1, n, ':'))
170.3503 + break; // "::"
170.3504 + p++;
170.3505 + q = scan(p, n, L_HEX, H_HEX);
170.3506 + if (q <= p)
170.3507 + failExpecting("digits for an IPv6 address", p);
170.3508 + if (at(q, n, '.')) { // Beginning of IPv4 address
170.3509 + p--;
170.3510 + break;
170.3511 + }
170.3512 + if (q > p + 4)
170.3513 + fail("IPv6 hexadecimal digit sequence too long", p);
170.3514 + ipv6byteCount += 2;
170.3515 + p = q;
170.3516 + }
170.3517 +
170.3518 + return p;
170.3519 + }
170.3520 +
170.3521 + }
170.3522 +
170.3523 +}
171.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
171.2 +++ b/rt/emul/compact/src/main/java/java/net/URISyntaxException.java Wed Apr 30 15:04:10 2014 +0200
171.3 @@ -0,0 +1,135 @@
171.4 +/*
171.5 + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
171.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
171.7 + *
171.8 + * This code is free software; you can redistribute it and/or modify it
171.9 + * under the terms of the GNU General Public License version 2 only, as
171.10 + * published by the Free Software Foundation. Oracle designates this
171.11 + * particular file as subject to the "Classpath" exception as provided
171.12 + * by Oracle in the LICENSE file that accompanied this code.
171.13 + *
171.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
171.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
171.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
171.17 + * version 2 for more details (a copy is included in the LICENSE file that
171.18 + * accompanied this code).
171.19 + *
171.20 + * You should have received a copy of the GNU General Public License version
171.21 + * 2 along with this work; if not, write to the Free Software Foundation,
171.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
171.23 + *
171.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
171.25 + * or visit www.oracle.com if you need additional information or have any
171.26 + * questions.
171.27 + */
171.28 +
171.29 +package java.net;
171.30 +
171.31 +
171.32 +/**
171.33 + * Checked exception thrown to indicate that a string could not be parsed as a
171.34 + * URI reference.
171.35 + *
171.36 + * @author Mark Reinhold
171.37 + * @see URI
171.38 + * @since 1.4
171.39 + */
171.40 +
171.41 +public class URISyntaxException
171.42 + extends Exception
171.43 +{
171.44 + private static final long serialVersionUID = 2137979680897488891L;
171.45 +
171.46 + private String input;
171.47 + private int index;
171.48 +
171.49 + /**
171.50 + * Constructs an instance from the given input string, reason, and error
171.51 + * index.
171.52 + *
171.53 + * @param input The input string
171.54 + * @param reason A string explaining why the input could not be parsed
171.55 + * @param index The index at which the parse error occurred,
171.56 + * or <tt>-1</tt> if the index is not known
171.57 + *
171.58 + * @throws NullPointerException
171.59 + * If either the input or reason strings are <tt>null</tt>
171.60 + *
171.61 + * @throws IllegalArgumentException
171.62 + * If the error index is less than <tt>-1</tt>
171.63 + */
171.64 + public URISyntaxException(String input, String reason, int index) {
171.65 + super(reason);
171.66 + if ((input == null) || (reason == null))
171.67 + throw new NullPointerException();
171.68 + if (index < -1)
171.69 + throw new IllegalArgumentException();
171.70 + this.input = input;
171.71 + this.index = index;
171.72 + }
171.73 +
171.74 + /**
171.75 + * Constructs an instance from the given input string and reason. The
171.76 + * resulting object will have an error index of <tt>-1</tt>.
171.77 + *
171.78 + * @param input The input string
171.79 + * @param reason A string explaining why the input could not be parsed
171.80 + *
171.81 + * @throws NullPointerException
171.82 + * If either the input or reason strings are <tt>null</tt>
171.83 + */
171.84 + public URISyntaxException(String input, String reason) {
171.85 + this(input, reason, -1);
171.86 + }
171.87 +
171.88 + /**
171.89 + * Returns the input string.
171.90 + *
171.91 + * @return The input string
171.92 + */
171.93 + public String getInput() {
171.94 + return input;
171.95 + }
171.96 +
171.97 + /**
171.98 + * Returns a string explaining why the input string could not be parsed.
171.99 + *
171.100 + * @return The reason string
171.101 + */
171.102 + public String getReason() {
171.103 + return super.getMessage();
171.104 + }
171.105 +
171.106 + /**
171.107 + * Returns an index into the input string of the position at which the
171.108 + * parse error occurred, or <tt>-1</tt> if this position is not known.
171.109 + *
171.110 + * @return The error index
171.111 + */
171.112 + public int getIndex() {
171.113 + return index;
171.114 + }
171.115 +
171.116 + /**
171.117 + * Returns a string describing the parse error. The resulting string
171.118 + * consists of the reason string followed by a colon character
171.119 + * (<tt>':'</tt>), a space, and the input string. If the error index is
171.120 + * defined then the string <tt>" at index "</tt> followed by the index, in
171.121 + * decimal, is inserted after the reason string and before the colon
171.122 + * character.
171.123 + *
171.124 + * @return A string describing the parse error
171.125 + */
171.126 + public String getMessage() {
171.127 + StringBuffer sb = new StringBuffer();
171.128 + sb.append(getReason());
171.129 + if (index > -1) {
171.130 + sb.append(" at index ");
171.131 + sb.append(index);
171.132 + }
171.133 + sb.append(": ");
171.134 + sb.append(input);
171.135 + return sb.toString();
171.136 + }
171.137 +
171.138 +}
172.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
172.2 +++ b/rt/emul/compact/src/main/java/java/net/URLConnection.java Wed Apr 30 15:04:10 2014 +0200
172.3 @@ -0,0 +1,2314 @@
172.4 +/*
172.5 + * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
172.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
172.7 + *
172.8 + * This code is free software; you can redistribute it and/or modify it
172.9 + * under the terms of the GNU General Public License version 2 only, as
172.10 + * published by the Free Software Foundation. Oracle designates this
172.11 + * particular file as subject to the "Classpath" exception as provided
172.12 + * by Oracle in the LICENSE file that accompanied this code.
172.13 + *
172.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
172.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
172.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
172.17 + * version 2 for more details (a copy is included in the LICENSE file that
172.18 + * accompanied this code).
172.19 + *
172.20 + * You should have received a copy of the GNU General Public License version
172.21 + * 2 along with this work; if not, write to the Free Software Foundation,
172.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
172.23 + *
172.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
172.25 + * or visit www.oracle.com if you need additional information or have any
172.26 + * questions.
172.27 + */
172.28 +
172.29 +package java.net;
172.30 +
172.31 +import java.io.IOException;
172.32 +import java.io.InputStream;
172.33 +import java.io.OutputStream;
172.34 +import java.io.PrintStream;
172.35 +import java.util.ArrayList;
172.36 +import java.util.Date;
172.37 +import java.util.StringTokenizer;
172.38 +import java.util.Collections;
172.39 +import java.util.HashMap;
172.40 +import java.util.Hashtable;
172.41 +import java.util.Iterator;
172.42 +import java.util.Map;
172.43 +import java.util.List;
172.44 +import java.util.NoSuchElementException;
172.45 +
172.46 +/**
172.47 + * The abstract class <code>URLConnection</code> is the superclass
172.48 + * of all classes that represent a communications link between the
172.49 + * application and a URL. Instances of this class can be used both to
172.50 + * read from and to write to the resource referenced by the URL. In
172.51 + * general, creating a connection to a URL is a multistep process:
172.52 + * <p>
172.53 + * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time.">
172.54 + * <tr><th><code>openConnection()</code></th>
172.55 + * <th><code>connect()</code></th></tr>
172.56 + * <tr><td>Manipulate parameters that affect the connection to the remote
172.57 + * resource.</td>
172.58 + * <td>Interact with the resource; query header fields and
172.59 + * contents.</td></tr>
172.60 + * </table>
172.61 + * ---------------------------->
172.62 + * <br>time</center>
172.63 + *
172.64 + * <ol>
172.65 + * <li>The connection object is created by invoking the
172.66 + * <code>openConnection</code> method on a URL.
172.67 + * <li>The setup parameters and general request properties are manipulated.
172.68 + * <li>The actual connection to the remote object is made, using the
172.69 + * <code>connect</code> method.
172.70 + * <li>The remote object becomes available. The header fields and the contents
172.71 + * of the remote object can be accessed.
172.72 + * </ol>
172.73 + * <p>
172.74 + * The setup parameters are modified using the following methods:
172.75 + * <ul>
172.76 + * <li><code>setAllowUserInteraction</code>
172.77 + * <li><code>setDoInput</code>
172.78 + * <li><code>setDoOutput</code>
172.79 + * <li><code>setIfModifiedSince</code>
172.80 + * <li><code>setUseCaches</code>
172.81 + * </ul>
172.82 + * <p>
172.83 + * and the general request properties are modified using the method:
172.84 + * <ul>
172.85 + * <li><code>setRequestProperty</code>
172.86 + * </ul>
172.87 + * <p>
172.88 + * Default values for the <code>AllowUserInteraction</code> and
172.89 + * <code>UseCaches</code> parameters can be set using the methods
172.90 + * <code>setDefaultAllowUserInteraction</code> and
172.91 + * <code>setDefaultUseCaches</code>.
172.92 + * <p>
172.93 + * Each of the above <code>set</code> methods has a corresponding
172.94 + * <code>get</code> method to retrieve the value of the parameter or
172.95 + * general request property. The specific parameters and general
172.96 + * request properties that are applicable are protocol specific.
172.97 + * <p>
172.98 + * The following methods are used to access the header fields and
172.99 + * the contents after the connection is made to the remote object:
172.100 + * <ul>
172.101 + * <li><code>getContent</code>
172.102 + * <li><code>getHeaderField</code>
172.103 + * <li><code>getInputStream</code>
172.104 + * <li><code>getOutputStream</code>
172.105 + * </ul>
172.106 + * <p>
172.107 + * Certain header fields are accessed frequently. The methods:
172.108 + * <ul>
172.109 + * <li><code>getContentEncoding</code>
172.110 + * <li><code>getContentLength</code>
172.111 + * <li><code>getContentType</code>
172.112 + * <li><code>getDate</code>
172.113 + * <li><code>getExpiration</code>
172.114 + * <li><code>getLastModifed</code>
172.115 + * </ul>
172.116 + * <p>
172.117 + * provide convenient access to these fields. The
172.118 + * <code>getContentType</code> method is used by the
172.119 + * <code>getContent</code> method to determine the type of the remote
172.120 + * object; subclasses may find it convenient to override the
172.121 + * <code>getContentType</code> method.
172.122 + * <p>
172.123 + * In the common case, all of the pre-connection parameters and
172.124 + * general request properties can be ignored: the pre-connection
172.125 + * parameters and request properties default to sensible values. For
172.126 + * most clients of this interface, there are only two interesting
172.127 + * methods: <code>getInputStream</code> and <code>getContent</code>,
172.128 + * which are mirrored in the <code>URL</code> class by convenience methods.
172.129 + * <p>
172.130 + * More information on the request properties and header fields of
172.131 + * an <code>http</code> connection can be found at:
172.132 + * <blockquote><pre>
172.133 + * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
172.134 + * </pre></blockquote>
172.135 + *
172.136 + * Note about <code>fileNameMap</code>: In versions prior to JDK 1.1.6,
172.137 + * field <code>fileNameMap</code> of <code>URLConnection</code> was public.
172.138 + * In JDK 1.1.6 and later, <code>fileNameMap</code> is private; accessor
172.139 + * and mutator methods {@link #getFileNameMap() getFileNameMap} and
172.140 + * {@link #setFileNameMap(java.net.FileNameMap) setFileNameMap} are added
172.141 + * to access it. This change is also described on the <a href=
172.142 + * "http://java.sun.com/products/jdk/1.2/compatibility.html">
172.143 + * Compatibility</a> page.
172.144 + *
172.145 + * Invoking the <tt>close()</tt> methods on the <tt>InputStream</tt> or <tt>OutputStream</tt> of an
172.146 + * <tt>URLConnection</tt> after a request may free network resources associated with this
172.147 + * instance, unless particular protocol specifications specify different behaviours
172.148 + * for it.
172.149 + *
172.150 + * @author James Gosling
172.151 + * @see java.net.URL#openConnection()
172.152 + * @see java.net.URLConnection#connect()
172.153 + * @see java.net.URLConnection#getContent()
172.154 + * @see java.net.URLConnection#getContentEncoding()
172.155 + * @see java.net.URLConnection#getContentLength()
172.156 + * @see java.net.URLConnection#getContentType()
172.157 + * @see java.net.URLConnection#getDate()
172.158 + * @see java.net.URLConnection#getExpiration()
172.159 + * @see java.net.URLConnection#getHeaderField(int)
172.160 + * @see java.net.URLConnection#getHeaderField(java.lang.String)
172.161 + * @see java.net.URLConnection#getInputStream()
172.162 + * @see java.net.URLConnection#getLastModified()
172.163 + * @see java.net.URLConnection#getOutputStream()
172.164 + * @see java.net.URLConnection#setAllowUserInteraction(boolean)
172.165 + * @see java.net.URLConnection#setDefaultUseCaches(boolean)
172.166 + * @see java.net.URLConnection#setDoInput(boolean)
172.167 + * @see java.net.URLConnection#setDoOutput(boolean)
172.168 + * @see java.net.URLConnection#setIfModifiedSince(long)
172.169 + * @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
172.170 + * @see java.net.URLConnection#setUseCaches(boolean)
172.171 + * @since JDK1.0
172.172 + */
172.173 +public abstract class URLConnection {
172.174 +
172.175 + /**
172.176 + * The URL represents the remote object on the World Wide Web to
172.177 + * which this connection is opened.
172.178 + * <p>
172.179 + * The value of this field can be accessed by the
172.180 + * <code>getURL</code> method.
172.181 + * <p>
172.182 + * The default value of this variable is the value of the URL
172.183 + * argument in the <code>URLConnection</code> constructor.
172.184 + *
172.185 + * @see java.net.URLConnection#getURL()
172.186 + * @see java.net.URLConnection#url
172.187 + */
172.188 + protected URL url;
172.189 +
172.190 + /**
172.191 + * This variable is set by the <code>setDoInput</code> method. Its
172.192 + * value is returned by the <code>getDoInput</code> method.
172.193 + * <p>
172.194 + * A URL connection can be used for input and/or output. Setting the
172.195 + * <code>doInput</code> flag to <code>true</code> indicates that
172.196 + * the application intends to read data from the URL connection.
172.197 + * <p>
172.198 + * The default value of this field is <code>true</code>.
172.199 + *
172.200 + * @see java.net.URLConnection#getDoInput()
172.201 + * @see java.net.URLConnection#setDoInput(boolean)
172.202 + */
172.203 + protected boolean doInput = true;
172.204 +
172.205 + /**
172.206 + * This variable is set by the <code>setDoOutput</code> method. Its
172.207 + * value is returned by the <code>getDoOutput</code> method.
172.208 + * <p>
172.209 + * A URL connection can be used for input and/or output. Setting the
172.210 + * <code>doOutput</code> flag to <code>true</code> indicates
172.211 + * that the application intends to write data to the URL connection.
172.212 + * <p>
172.213 + * The default value of this field is <code>false</code>.
172.214 + *
172.215 + * @see java.net.URLConnection#getDoOutput()
172.216 + * @see java.net.URLConnection#setDoOutput(boolean)
172.217 + */
172.218 + protected boolean doOutput = false;
172.219 +
172.220 + private static boolean defaultAllowUserInteraction = false;
172.221 +
172.222 + /**
172.223 + * If <code>true</code>, this <code>URL</code> is being examined in
172.224 + * a context in which it makes sense to allow user interactions such
172.225 + * as popping up an authentication dialog. If <code>false</code>,
172.226 + * then no user interaction is allowed.
172.227 + * <p>
172.228 + * The value of this field can be set by the
172.229 + * <code>setAllowUserInteraction</code> method.
172.230 + * Its value is returned by the
172.231 + * <code>getAllowUserInteraction</code> method.
172.232 + * Its default value is the value of the argument in the last invocation
172.233 + * of the <code>setDefaultAllowUserInteraction</code> method.
172.234 + *
172.235 + * @see java.net.URLConnection#getAllowUserInteraction()
172.236 + * @see java.net.URLConnection#setAllowUserInteraction(boolean)
172.237 + * @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
172.238 + */
172.239 + protected boolean allowUserInteraction = defaultAllowUserInteraction;
172.240 +
172.241 + private static boolean defaultUseCaches = true;
172.242 +
172.243 + /**
172.244 + * If <code>true</code>, the protocol is allowed to use caching
172.245 + * whenever it can. If <code>false</code>, the protocol must always
172.246 + * try to get a fresh copy of the object.
172.247 + * <p>
172.248 + * This field is set by the <code>setUseCaches</code> method. Its
172.249 + * value is returned by the <code>getUseCaches</code> method.
172.250 + * <p>
172.251 + * Its default value is the value given in the last invocation of the
172.252 + * <code>setDefaultUseCaches</code> method.
172.253 + *
172.254 + * @see java.net.URLConnection#setUseCaches(boolean)
172.255 + * @see java.net.URLConnection#getUseCaches()
172.256 + * @see java.net.URLConnection#setDefaultUseCaches(boolean)
172.257 + */
172.258 + protected boolean useCaches = defaultUseCaches;
172.259 +
172.260 + /**
172.261 + * Some protocols support skipping the fetching of the object unless
172.262 + * the object has been modified more recently than a certain time.
172.263 + * <p>
172.264 + * A nonzero value gives a time as the number of milliseconds since
172.265 + * January 1, 1970, GMT. The object is fetched only if it has been
172.266 + * modified more recently than that time.
172.267 + * <p>
172.268 + * This variable is set by the <code>setIfModifiedSince</code>
172.269 + * method. Its value is returned by the
172.270 + * <code>getIfModifiedSince</code> method.
172.271 + * <p>
172.272 + * The default value of this field is <code>0</code>, indicating
172.273 + * that the fetching must always occur.
172.274 + *
172.275 + * @see java.net.URLConnection#getIfModifiedSince()
172.276 + * @see java.net.URLConnection#setIfModifiedSince(long)
172.277 + */
172.278 + protected long ifModifiedSince = 0;
172.279 +
172.280 + /**
172.281 + * If <code>false</code>, this connection object has not created a
172.282 + * communications link to the specified URL. If <code>true</code>,
172.283 + * the communications link has been established.
172.284 + */
172.285 + protected boolean connected = false;
172.286 +
172.287 + /**
172.288 + * @since 1.5
172.289 + */
172.290 + private int connectTimeout;
172.291 + private int readTimeout;
172.292 +
172.293 + /**
172.294 + * @since 1.6
172.295 + */
172.296 + private MessageHeader requests;
172.297 +
172.298 + /**
172.299 + * @since JDK1.1
172.300 + */
172.301 + private static FileNameMap fileNameMap;
172.302 +
172.303 + /**
172.304 + * @since 1.2.2
172.305 + */
172.306 + private static boolean fileNameMapLoaded = false;
172.307 +
172.308 + /**
172.309 + * Loads filename map (a mimetable) from a data file. It will
172.310 + * first try to load the user-specific table, defined
172.311 + * by "content.types.user.table" property. If that fails,
172.312 + * it tries to load the default built-in table at
172.313 + * lib/content-types.properties under java home.
172.314 + *
172.315 + * @return the FileNameMap
172.316 + * @since 1.2
172.317 + * @see #setFileNameMap(java.net.FileNameMap)
172.318 + */
172.319 + public static synchronized FileNameMap getFileNameMap() {
172.320 + if ((fileNameMap == null) && !fileNameMapLoaded) {
172.321 + fileNameMap = new FileNameMap() {
172.322 + @Override
172.323 + public String getContentTypeFor(String fileName) {
172.324 + return "text/plain";
172.325 + }
172.326 + };
172.327 + fileNameMapLoaded = true;
172.328 + }
172.329 +
172.330 + return new FileNameMap() {
172.331 + private FileNameMap map = fileNameMap;
172.332 + public String getContentTypeFor(String fileName) {
172.333 + return map.getContentTypeFor(fileName);
172.334 + }
172.335 + };
172.336 + }
172.337 +
172.338 + /**
172.339 + * Sets the FileNameMap.
172.340 + * <p>
172.341 + * If there is a security manager, this method first calls
172.342 + * the security manager's <code>checkSetFactory</code> method
172.343 + * to ensure the operation is allowed.
172.344 + * This could result in a SecurityException.
172.345 + *
172.346 + * @param map the FileNameMap to be set
172.347 + * @exception SecurityException if a security manager exists and its
172.348 + * <code>checkSetFactory</code> method doesn't allow the operation.
172.349 + * @see SecurityManager#checkSetFactory
172.350 + * @see #getFileNameMap()
172.351 + * @since 1.2
172.352 + */
172.353 + public static void setFileNameMap(FileNameMap map) {
172.354 + throw new SecurityException();
172.355 + }
172.356 +
172.357 + /**
172.358 + * Opens a communications link to the resource referenced by this
172.359 + * URL, if such a connection has not already been established.
172.360 + * <p>
172.361 + * If the <code>connect</code> method is called when the connection
172.362 + * has already been opened (indicated by the <code>connected</code>
172.363 + * field having the value <code>true</code>), the call is ignored.
172.364 + * <p>
172.365 + * URLConnection objects go through two phases: first they are
172.366 + * created, then they are connected. After being created, and
172.367 + * before being connected, various options can be specified
172.368 + * (e.g., doInput and UseCaches). After connecting, it is an
172.369 + * error to try to set them. Operations that depend on being
172.370 + * connected, like getContentLength, will implicitly perform the
172.371 + * connection, if necessary.
172.372 + *
172.373 + * @throws SocketTimeoutException if the timeout expires before
172.374 + * the connection can be established
172.375 + * @exception IOException if an I/O error occurs while opening the
172.376 + * connection.
172.377 + * @see java.net.URLConnection#connected
172.378 + * @see #getConnectTimeout()
172.379 + * @see #setConnectTimeout(int)
172.380 + */
172.381 + abstract public void connect() throws IOException;
172.382 +
172.383 + /**
172.384 + * Sets a specified timeout value, in milliseconds, to be used
172.385 + * when opening a communications link to the resource referenced
172.386 + * by this URLConnection. If the timeout expires before the
172.387 + * connection can be established, a
172.388 + * java.net.SocketTimeoutException is raised. A timeout of zero is
172.389 + * interpreted as an infinite timeout.
172.390 +
172.391 + * <p> Some non-standard implmentation of this method may ignore
172.392 + * the specified timeout. To see the connect timeout set, please
172.393 + * call getConnectTimeout().
172.394 + *
172.395 + * @param timeout an <code>int</code> that specifies the connect
172.396 + * timeout value in milliseconds
172.397 + * @throws IllegalArgumentException if the timeout parameter is negative
172.398 + *
172.399 + * @see #getConnectTimeout()
172.400 + * @see #connect()
172.401 + * @since 1.5
172.402 + */
172.403 + public void setConnectTimeout(int timeout) {
172.404 + if (timeout < 0) {
172.405 + throw new IllegalArgumentException("timeout can not be negative");
172.406 + }
172.407 + connectTimeout = timeout;
172.408 + }
172.409 +
172.410 + /**
172.411 + * Returns setting for connect timeout.
172.412 + * <p>
172.413 + * 0 return implies that the option is disabled
172.414 + * (i.e., timeout of infinity).
172.415 + *
172.416 + * @return an <code>int</code> that indicates the connect timeout
172.417 + * value in milliseconds
172.418 + * @see #setConnectTimeout(int)
172.419 + * @see #connect()
172.420 + * @since 1.5
172.421 + */
172.422 + public int getConnectTimeout() {
172.423 + return connectTimeout;
172.424 + }
172.425 +
172.426 + /**
172.427 + * Sets the read timeout to a specified timeout, in
172.428 + * milliseconds. A non-zero value specifies the timeout when
172.429 + * reading from Input stream when a connection is established to a
172.430 + * resource. If the timeout expires before there is data available
172.431 + * for read, a java.net.SocketTimeoutException is raised. A
172.432 + * timeout of zero is interpreted as an infinite timeout.
172.433 + *
172.434 + *<p> Some non-standard implementation of this method ignores the
172.435 + * specified timeout. To see the read timeout set, please call
172.436 + * getReadTimeout().
172.437 + *
172.438 + * @param timeout an <code>int</code> that specifies the timeout
172.439 + * value to be used in milliseconds
172.440 + * @throws IllegalArgumentException if the timeout parameter is negative
172.441 + *
172.442 + * @see #getReadTimeout()
172.443 + * @see InputStream#read()
172.444 + * @since 1.5
172.445 + */
172.446 + public void setReadTimeout(int timeout) {
172.447 + if (timeout < 0) {
172.448 + throw new IllegalArgumentException("timeout can not be negative");
172.449 + }
172.450 + readTimeout = timeout;
172.451 + }
172.452 +
172.453 + /**
172.454 + * Returns setting for read timeout. 0 return implies that the
172.455 + * option is disabled (i.e., timeout of infinity).
172.456 + *
172.457 + * @return an <code>int</code> that indicates the read timeout
172.458 + * value in milliseconds
172.459 + *
172.460 + * @see #setReadTimeout(int)
172.461 + * @see InputStream#read()
172.462 + * @since 1.5
172.463 + */
172.464 + public int getReadTimeout() {
172.465 + return readTimeout;
172.466 + }
172.467 +
172.468 + /**
172.469 + * Constructs a URL connection to the specified URL. A connection to
172.470 + * the object referenced by the URL is not created.
172.471 + *
172.472 + * @param url the specified URL.
172.473 + */
172.474 + protected URLConnection(URL url) {
172.475 + this.url = url;
172.476 + }
172.477 +
172.478 + /**
172.479 + * Returns the value of this <code>URLConnection</code>'s <code>URL</code>
172.480 + * field.
172.481 + *
172.482 + * @return the value of this <code>URLConnection</code>'s <code>URL</code>
172.483 + * field.
172.484 + * @see java.net.URLConnection#url
172.485 + */
172.486 + public URL getURL() {
172.487 + return url;
172.488 + }
172.489 +
172.490 + /**
172.491 + * Returns the value of the <code>content-length</code> header field.
172.492 + * <P>
172.493 + * <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()}
172.494 + * should be preferred over this method, since it returns a {@code long}
172.495 + * instead and is therefore more portable.</P>
172.496 + *
172.497 + * @return the content length of the resource that this connection's URL
172.498 + * references, {@code -1} if the content length is not known,
172.499 + * or if the content length is greater than Integer.MAX_VALUE.
172.500 + */
172.501 + public int getContentLength() {
172.502 + long l = getContentLengthLong();
172.503 + if (l > Integer.MAX_VALUE)
172.504 + return -1;
172.505 + return (int) l;
172.506 + }
172.507 +
172.508 + /**
172.509 + * Returns the value of the <code>content-length</code> header field as a
172.510 + * long.
172.511 + *
172.512 + * @return the content length of the resource that this connection's URL
172.513 + * references, or <code>-1</code> if the content length is
172.514 + * not known.
172.515 + * @since 7.0
172.516 + */
172.517 + public long getContentLengthLong() {
172.518 + return getHeaderFieldLong("content-length", -1);
172.519 + }
172.520 +
172.521 + /**
172.522 + * Returns the value of the <code>content-type</code> header field.
172.523 + *
172.524 + * @return the content type of the resource that the URL references,
172.525 + * or <code>null</code> if not known.
172.526 + * @see java.net.URLConnection#getHeaderField(java.lang.String)
172.527 + */
172.528 + public String getContentType() {
172.529 + return getHeaderField("content-type");
172.530 + }
172.531 +
172.532 + /**
172.533 + * Returns the value of the <code>content-encoding</code> header field.
172.534 + *
172.535 + * @return the content encoding of the resource that the URL references,
172.536 + * or <code>null</code> if not known.
172.537 + * @see java.net.URLConnection#getHeaderField(java.lang.String)
172.538 + */
172.539 + public String getContentEncoding() {
172.540 + return getHeaderField("content-encoding");
172.541 + }
172.542 +
172.543 + /**
172.544 + * Returns the value of the <code>expires</code> header field.
172.545 + *
172.546 + * @return the expiration date of the resource that this URL references,
172.547 + * or 0 if not known. The value is the number of milliseconds since
172.548 + * January 1, 1970 GMT.
172.549 + * @see java.net.URLConnection#getHeaderField(java.lang.String)
172.550 + */
172.551 + public long getExpiration() {
172.552 + return getHeaderFieldDate("expires", 0);
172.553 + }
172.554 +
172.555 + /**
172.556 + * Returns the value of the <code>date</code> header field.
172.557 + *
172.558 + * @return the sending date of the resource that the URL references,
172.559 + * or <code>0</code> if not known. The value returned is the
172.560 + * number of milliseconds since January 1, 1970 GMT.
172.561 + * @see java.net.URLConnection#getHeaderField(java.lang.String)
172.562 + */
172.563 + public long getDate() {
172.564 + return getHeaderFieldDate("date", 0);
172.565 + }
172.566 +
172.567 + /**
172.568 + * Returns the value of the <code>last-modified</code> header field.
172.569 + * The result is the number of milliseconds since January 1, 1970 GMT.
172.570 + *
172.571 + * @return the date the resource referenced by this
172.572 + * <code>URLConnection</code> was last modified, or 0 if not known.
172.573 + * @see java.net.URLConnection#getHeaderField(java.lang.String)
172.574 + */
172.575 + public long getLastModified() {
172.576 + return getHeaderFieldDate("last-modified", 0);
172.577 + }
172.578 +
172.579 + /**
172.580 + * Returns the value of the named header field.
172.581 + * <p>
172.582 + * If called on a connection that sets the same header multiple times
172.583 + * with possibly different values, only the last value is returned.
172.584 + *
172.585 + *
172.586 + * @param name the name of a header field.
172.587 + * @return the value of the named header field, or <code>null</code>
172.588 + * if there is no such field in the header.
172.589 + */
172.590 + public String getHeaderField(String name) {
172.591 + return null;
172.592 + }
172.593 +
172.594 + /**
172.595 + * Returns an unmodifiable Map of the header fields.
172.596 + * The Map keys are Strings that represent the
172.597 + * response-header field names. Each Map value is an
172.598 + * unmodifiable List of Strings that represents
172.599 + * the corresponding field values.
172.600 + *
172.601 + * @return a Map of header fields
172.602 + * @since 1.4
172.603 + */
172.604 + public Map<String,List<String>> getHeaderFields() {
172.605 + return Collections.EMPTY_MAP;
172.606 + }
172.607 +
172.608 + /**
172.609 + * Returns the value of the named field parsed as a number.
172.610 + * <p>
172.611 + * This form of <code>getHeaderField</code> exists because some
172.612 + * connection types (e.g., <code>http-ng</code>) have pre-parsed
172.613 + * headers. Classes for that connection type can override this method
172.614 + * and short-circuit the parsing.
172.615 + *
172.616 + * @param name the name of the header field.
172.617 + * @param Default the default value.
172.618 + * @return the value of the named field, parsed as an integer. The
172.619 + * <code>Default</code> value is returned if the field is
172.620 + * missing or malformed.
172.621 + */
172.622 + public int getHeaderFieldInt(String name, int Default) {
172.623 + String value = getHeaderField(name);
172.624 + try {
172.625 + return Integer.parseInt(value);
172.626 + } catch (Exception e) { }
172.627 + return Default;
172.628 + }
172.629 +
172.630 + /**
172.631 + * Returns the value of the named field parsed as a number.
172.632 + * <p>
172.633 + * This form of <code>getHeaderField</code> exists because some
172.634 + * connection types (e.g., <code>http-ng</code>) have pre-parsed
172.635 + * headers. Classes for that connection type can override this method
172.636 + * and short-circuit the parsing.
172.637 + *
172.638 + * @param name the name of the header field.
172.639 + * @param Default the default value.
172.640 + * @return the value of the named field, parsed as a long. The
172.641 + * <code>Default</code> value is returned if the field is
172.642 + * missing or malformed.
172.643 + * @since 7.0
172.644 + */
172.645 + public long getHeaderFieldLong(String name, long Default) {
172.646 + String value = getHeaderField(name);
172.647 + try {
172.648 + return Long.parseLong(value);
172.649 + } catch (Exception e) { }
172.650 + return Default;
172.651 + }
172.652 +
172.653 + /**
172.654 + * Returns the value of the named field parsed as date.
172.655 + * The result is the number of milliseconds since January 1, 1970 GMT
172.656 + * represented by the named field.
172.657 + * <p>
172.658 + * This form of <code>getHeaderField</code> exists because some
172.659 + * connection types (e.g., <code>http-ng</code>) have pre-parsed
172.660 + * headers. Classes for that connection type can override this method
172.661 + * and short-circuit the parsing.
172.662 + *
172.663 + * @param name the name of the header field.
172.664 + * @param Default a default value.
172.665 + * @return the value of the field, parsed as a date. The value of the
172.666 + * <code>Default</code> argument is returned if the field is
172.667 + * missing or malformed.
172.668 + */
172.669 + public long getHeaderFieldDate(String name, long Default) {
172.670 + String value = getHeaderField(name);
172.671 + try {
172.672 + return Date.parse(value);
172.673 + } catch (Exception e) { }
172.674 + return Default;
172.675 + }
172.676 +
172.677 + /**
172.678 + * Returns the key for the <code>n</code><sup>th</sup> header field.
172.679 + * It returns <code>null</code> if there are fewer than <code>n+1</code> fields.
172.680 + *
172.681 + * @param n an index, where n>=0
172.682 + * @return the key for the <code>n</code><sup>th</sup> header field,
172.683 + * or <code>null</code> if there are fewer than <code>n+1</code>
172.684 + * fields.
172.685 + */
172.686 + public String getHeaderFieldKey(int n) {
172.687 + return null;
172.688 + }
172.689 +
172.690 + /**
172.691 + * Returns the value for the <code>n</code><sup>th</sup> header field.
172.692 + * It returns <code>null</code> if there are fewer than
172.693 + * <code>n+1</code>fields.
172.694 + * <p>
172.695 + * This method can be used in conjunction with the
172.696 + * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
172.697 + * the headers in the message.
172.698 + *
172.699 + * @param n an index, where n>=0
172.700 + * @return the value of the <code>n</code><sup>th</sup> header field
172.701 + * or <code>null</code> if there are fewer than <code>n+1</code> fields
172.702 + * @see java.net.URLConnection#getHeaderFieldKey(int)
172.703 + */
172.704 + public String getHeaderField(int n) {
172.705 + return null;
172.706 + }
172.707 +
172.708 + /**
172.709 + * Retrieves the contents of this URL connection.
172.710 + * <p>
172.711 + * This method first determines the content type of the object by
172.712 + * calling the <code>getContentType</code> method. If this is
172.713 + * the first time that the application has seen that specific content
172.714 + * type, a content handler for that content type is created:
172.715 + * <ol>
172.716 + * <li>If the application has set up a content handler factory instance
172.717 + * using the <code>setContentHandlerFactory</code> method, the
172.718 + * <code>createContentHandler</code> method of that instance is called
172.719 + * with the content type as an argument; the result is a content
172.720 + * handler for that content type.
172.721 + * <li>If no content handler factory has yet been set up, or if the
172.722 + * factory's <code>createContentHandler</code> method returns
172.723 + * <code>null</code>, then the application loads the class named:
172.724 + * <blockquote><pre>
172.725 + * sun.net.www.content.<<i>contentType</i>>
172.726 + * </pre></blockquote>
172.727 + * where <<i>contentType</i>> is formed by taking the
172.728 + * content-type string, replacing all slash characters with a
172.729 + * <code>period</code> ('.'), and all other non-alphanumeric characters
172.730 + * with the underscore character '<code>_</code>'. The alphanumeric
172.731 + * characters are specifically the 26 uppercase ASCII letters
172.732 + * '<code>A</code>' through '<code>Z</code>', the 26 lowercase ASCII
172.733 + * letters '<code>a</code>' through '<code>z</code>', and the 10 ASCII
172.734 + * digits '<code>0</code>' through '<code>9</code>'. If the specified
172.735 + * class does not exist, or is not a subclass of
172.736 + * <code>ContentHandler</code>, then an
172.737 + * <code>UnknownServiceException</code> is thrown.
172.738 + * </ol>
172.739 + *
172.740 + * @return the object fetched. The <code>instanceof</code> operator
172.741 + * should be used to determine the specific kind of object
172.742 + * returned.
172.743 + * @exception IOException if an I/O error occurs while
172.744 + * getting the content.
172.745 + * @exception UnknownServiceException if the protocol does not support
172.746 + * the content type.
172.747 + * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
172.748 + * @see java.net.URLConnection#getContentType()
172.749 + * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
172.750 + */
172.751 + public Object getContent() throws IOException {
172.752 + // Must call getInputStream before GetHeaderField gets called
172.753 + // so that FileNotFoundException has a chance to be thrown up
172.754 + // from here without being caught.
172.755 + getInputStream();
172.756 + return getContentHandler().getContent(this);
172.757 + }
172.758 +
172.759 + /**
172.760 + * Retrieves the contents of this URL connection.
172.761 + *
172.762 + * @param classes the <code>Class</code> array
172.763 + * indicating the requested types
172.764 + * @return the object fetched that is the first match of the type
172.765 + * specified in the classes array. null if none of
172.766 + * the requested types are supported.
172.767 + * The <code>instanceof</code> operator should be used to
172.768 + * determine the specific kind of object returned.
172.769 + * @exception IOException if an I/O error occurs while
172.770 + * getting the content.
172.771 + * @exception UnknownServiceException if the protocol does not support
172.772 + * the content type.
172.773 + * @see java.net.URLConnection#getContent()
172.774 + * @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
172.775 + * @see java.net.URLConnection#getContent(java.lang.Class[])
172.776 + * @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
172.777 + * @since 1.3
172.778 + */
172.779 + public Object getContent(Class[] classes) throws IOException {
172.780 + // Must call getInputStream before GetHeaderField gets called
172.781 + // so that FileNotFoundException has a chance to be thrown up
172.782 + // from here without being caught.
172.783 + getInputStream();
172.784 + return getContentHandler().getContent(this, classes);
172.785 + }
172.786 +
172.787 + /**
172.788 + * Returns a permission object representing the permission
172.789 + * necessary to make the connection represented by this
172.790 + * object. This method returns null if no permission is
172.791 + * required to make the connection. By default, this method
172.792 + * returns <code>java.security.AllPermission</code>. Subclasses
172.793 + * should override this method and return the permission
172.794 + * that best represents the permission required to make a
172.795 + * a connection to the URL. For example, a <code>URLConnection</code>
172.796 + * representing a <code>file:</code> URL would return a
172.797 + * <code>java.io.FilePermission</code> object.
172.798 + *
172.799 + * <p>The permission returned may dependent upon the state of the
172.800 + * connection. For example, the permission before connecting may be
172.801 + * different from that after connecting. For example, an HTTP
172.802 + * sever, say foo.com, may redirect the connection to a different
172.803 + * host, say bar.com. Before connecting the permission returned by
172.804 + * the connection will represent the permission needed to connect
172.805 + * to foo.com, while the permission returned after connecting will
172.806 + * be to bar.com.
172.807 + *
172.808 + * <p>Permissions are generally used for two purposes: to protect
172.809 + * caches of objects obtained through URLConnections, and to check
172.810 + * the right of a recipient to learn about a particular URL. In
172.811 + * the first case, the permission should be obtained
172.812 + * <em>after</em> the object has been obtained. For example, in an
172.813 + * HTTP connection, this will represent the permission to connect
172.814 + * to the host from which the data was ultimately fetched. In the
172.815 + * second case, the permission should be obtained and tested
172.816 + * <em>before</em> connecting.
172.817 + *
172.818 + * @return the permission object representing the permission
172.819 + * necessary to make the connection represented by this
172.820 + * URLConnection.
172.821 + *
172.822 + * @exception IOException if the computation of the permission
172.823 + * requires network or file I/O and an exception occurs while
172.824 + * computing it.
172.825 + */
172.826 +// public Permission getPermission() throws IOException {
172.827 +// return SecurityConstants.ALL_PERMISSION;
172.828 +// }
172.829 +
172.830 + /**
172.831 + * Returns an input stream that reads from this open connection.
172.832 + *
172.833 + * A SocketTimeoutException can be thrown when reading from the
172.834 + * returned input stream if the read timeout expires before data
172.835 + * is available for read.
172.836 + *
172.837 + * @return an input stream that reads from this open connection.
172.838 + * @exception IOException if an I/O error occurs while
172.839 + * creating the input stream.
172.840 + * @exception UnknownServiceException if the protocol does not support
172.841 + * input.
172.842 + * @see #setReadTimeout(int)
172.843 + * @see #getReadTimeout()
172.844 + */
172.845 + public InputStream getInputStream() throws IOException {
172.846 + throw new UnknownServiceException("protocol doesn't support input");
172.847 + }
172.848 +
172.849 + /**
172.850 + * Returns an output stream that writes to this connection.
172.851 + *
172.852 + * @return an output stream that writes to this connection.
172.853 + * @exception IOException if an I/O error occurs while
172.854 + * creating the output stream.
172.855 + * @exception UnknownServiceException if the protocol does not support
172.856 + * output.
172.857 + */
172.858 + public OutputStream getOutputStream() throws IOException {
172.859 + throw new UnknownServiceException("protocol doesn't support output");
172.860 + }
172.861 +
172.862 + /**
172.863 + * Returns a <code>String</code> representation of this URL connection.
172.864 + *
172.865 + * @return a string representation of this <code>URLConnection</code>.
172.866 + */
172.867 + public String toString() {
172.868 + return this.getClass().getName() + ":" + url;
172.869 + }
172.870 +
172.871 + /**
172.872 + * Sets the value of the <code>doInput</code> field for this
172.873 + * <code>URLConnection</code> to the specified value.
172.874 + * <p>
172.875 + * A URL connection can be used for input and/or output. Set the DoInput
172.876 + * flag to true if you intend to use the URL connection for input,
172.877 + * false if not. The default is true.
172.878 + *
172.879 + * @param doinput the new value.
172.880 + * @throws IllegalStateException if already connected
172.881 + * @see java.net.URLConnection#doInput
172.882 + * @see #getDoInput()
172.883 + */
172.884 + public void setDoInput(boolean doinput) {
172.885 + if (connected)
172.886 + throw new IllegalStateException("Already connected");
172.887 + doInput = doinput;
172.888 + }
172.889 +
172.890 + /**
172.891 + * Returns the value of this <code>URLConnection</code>'s
172.892 + * <code>doInput</code> flag.
172.893 + *
172.894 + * @return the value of this <code>URLConnection</code>'s
172.895 + * <code>doInput</code> flag.
172.896 + * @see #setDoInput(boolean)
172.897 + */
172.898 + public boolean getDoInput() {
172.899 + return doInput;
172.900 + }
172.901 +
172.902 + /**
172.903 + * Sets the value of the <code>doOutput</code> field for this
172.904 + * <code>URLConnection</code> to the specified value.
172.905 + * <p>
172.906 + * A URL connection can be used for input and/or output. Set the DoOutput
172.907 + * flag to true if you intend to use the URL connection for output,
172.908 + * false if not. The default is false.
172.909 + *
172.910 + * @param dooutput the new value.
172.911 + * @throws IllegalStateException if already connected
172.912 + * @see #getDoOutput()
172.913 + */
172.914 + public void setDoOutput(boolean dooutput) {
172.915 + if (connected)
172.916 + throw new IllegalStateException("Already connected");
172.917 + doOutput = dooutput;
172.918 + }
172.919 +
172.920 + /**
172.921 + * Returns the value of this <code>URLConnection</code>'s
172.922 + * <code>doOutput</code> flag.
172.923 + *
172.924 + * @return the value of this <code>URLConnection</code>'s
172.925 + * <code>doOutput</code> flag.
172.926 + * @see #setDoOutput(boolean)
172.927 + */
172.928 + public boolean getDoOutput() {
172.929 + return doOutput;
172.930 + }
172.931 +
172.932 + /**
172.933 + * Set the value of the <code>allowUserInteraction</code> field of
172.934 + * this <code>URLConnection</code>.
172.935 + *
172.936 + * @param allowuserinteraction the new value.
172.937 + * @throws IllegalStateException if already connected
172.938 + * @see #getAllowUserInteraction()
172.939 + */
172.940 + public void setAllowUserInteraction(boolean allowuserinteraction) {
172.941 + if (connected)
172.942 + throw new IllegalStateException("Already connected");
172.943 + allowUserInteraction = allowuserinteraction;
172.944 + }
172.945 +
172.946 + /**
172.947 + * Returns the value of the <code>allowUserInteraction</code> field for
172.948 + * this object.
172.949 + *
172.950 + * @return the value of the <code>allowUserInteraction</code> field for
172.951 + * this object.
172.952 + * @see #setAllowUserInteraction(boolean)
172.953 + */
172.954 + public boolean getAllowUserInteraction() {
172.955 + return allowUserInteraction;
172.956 + }
172.957 +
172.958 + /**
172.959 + * Sets the default value of the
172.960 + * <code>allowUserInteraction</code> field for all future
172.961 + * <code>URLConnection</code> objects to the specified value.
172.962 + *
172.963 + * @param defaultallowuserinteraction the new value.
172.964 + * @see #getDefaultAllowUserInteraction()
172.965 + */
172.966 + public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
172.967 + defaultAllowUserInteraction = defaultallowuserinteraction;
172.968 + }
172.969 +
172.970 + /**
172.971 + * Returns the default value of the <code>allowUserInteraction</code>
172.972 + * field.
172.973 + * <p>
172.974 + * Ths default is "sticky", being a part of the static state of all
172.975 + * URLConnections. This flag applies to the next, and all following
172.976 + * URLConnections that are created.
172.977 + *
172.978 + * @return the default value of the <code>allowUserInteraction</code>
172.979 + * field.
172.980 + * @see #setDefaultAllowUserInteraction(boolean)
172.981 + */
172.982 + public static boolean getDefaultAllowUserInteraction() {
172.983 + return defaultAllowUserInteraction;
172.984 + }
172.985 +
172.986 + /**
172.987 + * Sets the value of the <code>useCaches</code> field of this
172.988 + * <code>URLConnection</code> to the specified value.
172.989 + * <p>
172.990 + * Some protocols do caching of documents. Occasionally, it is important
172.991 + * to be able to "tunnel through" and ignore the caches (e.g., the
172.992 + * "reload" button in a browser). If the UseCaches flag on a connection
172.993 + * is true, the connection is allowed to use whatever caches it can.
172.994 + * If false, caches are to be ignored.
172.995 + * The default value comes from DefaultUseCaches, which defaults to
172.996 + * true.
172.997 + *
172.998 + * @param usecaches a <code>boolean</code> indicating whether
172.999 + * or not to allow caching
172.1000 + * @throws IllegalStateException if already connected
172.1001 + * @see #getUseCaches()
172.1002 + */
172.1003 + public void setUseCaches(boolean usecaches) {
172.1004 + if (connected)
172.1005 + throw new IllegalStateException("Already connected");
172.1006 + useCaches = usecaches;
172.1007 + }
172.1008 +
172.1009 + /**
172.1010 + * Returns the value of this <code>URLConnection</code>'s
172.1011 + * <code>useCaches</code> field.
172.1012 + *
172.1013 + * @return the value of this <code>URLConnection</code>'s
172.1014 + * <code>useCaches</code> field.
172.1015 + * @see #setUseCaches(boolean)
172.1016 + */
172.1017 + public boolean getUseCaches() {
172.1018 + return useCaches;
172.1019 + }
172.1020 +
172.1021 + /**
172.1022 + * Sets the value of the <code>ifModifiedSince</code> field of
172.1023 + * this <code>URLConnection</code> to the specified value.
172.1024 + *
172.1025 + * @param ifmodifiedsince the new value.
172.1026 + * @throws IllegalStateException if already connected
172.1027 + * @see #getIfModifiedSince()
172.1028 + */
172.1029 + public void setIfModifiedSince(long ifmodifiedsince) {
172.1030 + if (connected)
172.1031 + throw new IllegalStateException("Already connected");
172.1032 + ifModifiedSince = ifmodifiedsince;
172.1033 + }
172.1034 +
172.1035 + /**
172.1036 + * Returns the value of this object's <code>ifModifiedSince</code> field.
172.1037 + *
172.1038 + * @return the value of this object's <code>ifModifiedSince</code> field.
172.1039 + * @see #setIfModifiedSince(long)
172.1040 + */
172.1041 + public long getIfModifiedSince() {
172.1042 + return ifModifiedSince;
172.1043 + }
172.1044 +
172.1045 + /**
172.1046 + * Returns the default value of a <code>URLConnection</code>'s
172.1047 + * <code>useCaches</code> flag.
172.1048 + * <p>
172.1049 + * Ths default is "sticky", being a part of the static state of all
172.1050 + * URLConnections. This flag applies to the next, and all following
172.1051 + * URLConnections that are created.
172.1052 + *
172.1053 + * @return the default value of a <code>URLConnection</code>'s
172.1054 + * <code>useCaches</code> flag.
172.1055 + * @see #setDefaultUseCaches(boolean)
172.1056 + */
172.1057 + public boolean getDefaultUseCaches() {
172.1058 + return defaultUseCaches;
172.1059 + }
172.1060 +
172.1061 + /**
172.1062 + * Sets the default value of the <code>useCaches</code> field to the
172.1063 + * specified value.
172.1064 + *
172.1065 + * @param defaultusecaches the new value.
172.1066 + * @see #getDefaultUseCaches()
172.1067 + */
172.1068 + public void setDefaultUseCaches(boolean defaultusecaches) {
172.1069 + defaultUseCaches = defaultusecaches;
172.1070 + }
172.1071 +
172.1072 + /**
172.1073 + * Sets the general request property. If a property with the key already
172.1074 + * exists, overwrite its value with the new value.
172.1075 + *
172.1076 + * <p> NOTE: HTTP requires all request properties which can
172.1077 + * legally have multiple instances with the same key
172.1078 + * to use a comma-seperated list syntax which enables multiple
172.1079 + * properties to be appended into a single property.
172.1080 + *
172.1081 + * @param key the keyword by which the request is known
172.1082 + * (e.g., "<code>Accept</code>").
172.1083 + * @param value the value associated with it.
172.1084 + * @throws IllegalStateException if already connected
172.1085 + * @throws NullPointerException if key is <CODE>null</CODE>
172.1086 + * @see #getRequestProperty(java.lang.String)
172.1087 + */
172.1088 + public void setRequestProperty(String key, String value) {
172.1089 + if (connected)
172.1090 + throw new IllegalStateException("Already connected");
172.1091 + if (key == null)
172.1092 + throw new NullPointerException ("key is null");
172.1093 +
172.1094 + if (requests == null)
172.1095 + requests = new MessageHeader();
172.1096 +
172.1097 + requests.set(key, value);
172.1098 + }
172.1099 +
172.1100 + /**
172.1101 + * Adds a general request property specified by a
172.1102 + * key-value pair. This method will not overwrite
172.1103 + * existing values associated with the same key.
172.1104 + *
172.1105 + * @param key the keyword by which the request is known
172.1106 + * (e.g., "<code>Accept</code>").
172.1107 + * @param value the value associated with it.
172.1108 + * @throws IllegalStateException if already connected
172.1109 + * @throws NullPointerException if key is null
172.1110 + * @see #getRequestProperties()
172.1111 + * @since 1.4
172.1112 + */
172.1113 + public void addRequestProperty(String key, String value) {
172.1114 + if (connected)
172.1115 + throw new IllegalStateException("Already connected");
172.1116 + if (key == null)
172.1117 + throw new NullPointerException ("key is null");
172.1118 +
172.1119 + if (requests == null)
172.1120 + requests = new MessageHeader();
172.1121 +
172.1122 + requests.add(key, value);
172.1123 + }
172.1124 +
172.1125 +
172.1126 + /**
172.1127 + * Returns the value of the named general request property for this
172.1128 + * connection.
172.1129 + *
172.1130 + * @param key the keyword by which the request is known (e.g., "Accept").
172.1131 + * @return the value of the named general request property for this
172.1132 + * connection. If key is null, then null is returned.
172.1133 + * @throws IllegalStateException if already connected
172.1134 + * @see #setRequestProperty(java.lang.String, java.lang.String)
172.1135 + */
172.1136 + public String getRequestProperty(String key) {
172.1137 + if (connected)
172.1138 + throw new IllegalStateException("Already connected");
172.1139 +
172.1140 + if (requests == null)
172.1141 + return null;
172.1142 +
172.1143 + return requests.findValue(key);
172.1144 + }
172.1145 +
172.1146 + /**
172.1147 + * Returns an unmodifiable Map of general request
172.1148 + * properties for this connection. The Map keys
172.1149 + * are Strings that represent the request-header
172.1150 + * field names. Each Map value is a unmodifiable List
172.1151 + * of Strings that represents the corresponding
172.1152 + * field values.
172.1153 + *
172.1154 + * @return a Map of the general request properties for this connection.
172.1155 + * @throws IllegalStateException if already connected
172.1156 + * @since 1.4
172.1157 + */
172.1158 + public Map<String,List<String>> getRequestProperties() {
172.1159 + if (connected)
172.1160 + throw new IllegalStateException("Already connected");
172.1161 +
172.1162 + if (requests == null)
172.1163 + return Collections.EMPTY_MAP;
172.1164 +
172.1165 + return requests.getHeaders(null);
172.1166 + }
172.1167 +
172.1168 + /**
172.1169 + * Sets the default value of a general request property. When a
172.1170 + * <code>URLConnection</code> is created, it is initialized with
172.1171 + * these properties.
172.1172 + *
172.1173 + * @param key the keyword by which the request is known
172.1174 + * (e.g., "<code>Accept</code>").
172.1175 + * @param value the value associated with the key.
172.1176 + *
172.1177 + * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
172.1178 + *
172.1179 + * @deprecated The instance specific setRequestProperty method
172.1180 + * should be used after an appropriate instance of URLConnection
172.1181 + * is obtained. Invoking this method will have no effect.
172.1182 + *
172.1183 + * @see #getDefaultRequestProperty(java.lang.String)
172.1184 + */
172.1185 + @Deprecated
172.1186 + public static void setDefaultRequestProperty(String key, String value) {
172.1187 + }
172.1188 +
172.1189 + /**
172.1190 + * Returns the value of the default request property. Default request
172.1191 + * properties are set for every connection.
172.1192 + *
172.1193 + * @param key the keyword by which the request is known (e.g., "Accept").
172.1194 + * @return the value of the default request property
172.1195 + * for the specified key.
172.1196 + *
172.1197 + * @see java.net.URLConnection#getRequestProperty(java.lang.String)
172.1198 + *
172.1199 + * @deprecated The instance specific getRequestProperty method
172.1200 + * should be used after an appropriate instance of URLConnection
172.1201 + * is obtained.
172.1202 + *
172.1203 + * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
172.1204 + */
172.1205 + @Deprecated
172.1206 + public static String getDefaultRequestProperty(String key) {
172.1207 + return null;
172.1208 + }
172.1209 +
172.1210 + /**
172.1211 + * The ContentHandler factory.
172.1212 + */
172.1213 + static ContentHandlerFactory factory;
172.1214 +
172.1215 + /**
172.1216 + * Sets the <code>ContentHandlerFactory</code> of an
172.1217 + * application. It can be called at most once by an application.
172.1218 + * <p>
172.1219 + * The <code>ContentHandlerFactory</code> instance is used to
172.1220 + * construct a content handler from a content type
172.1221 + * <p>
172.1222 + * If there is a security manager, this method first calls
172.1223 + * the security manager's <code>checkSetFactory</code> method
172.1224 + * to ensure the operation is allowed.
172.1225 + * This could result in a SecurityException.
172.1226 + *
172.1227 + * @param fac the desired factory.
172.1228 + * @exception Error if the factory has already been defined.
172.1229 + * @exception SecurityException if a security manager exists and its
172.1230 + * <code>checkSetFactory</code> method doesn't allow the operation.
172.1231 + * @see java.net.ContentHandlerFactory
172.1232 + * @see java.net.URLConnection#getContent()
172.1233 + * @see SecurityManager#checkSetFactory
172.1234 + */
172.1235 + public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
172.1236 + throw new SecurityException();
172.1237 + }
172.1238 +
172.1239 + private static Hashtable handlers = new Hashtable();
172.1240 +
172.1241 + /**
172.1242 + * Gets the Content Handler appropriate for this connection.
172.1243 + * @param connection the connection to use.
172.1244 + */
172.1245 + synchronized ContentHandler getContentHandler()
172.1246 + throws UnknownServiceException
172.1247 + {
172.1248 + String contentType = stripOffParameters(getContentType());
172.1249 + ContentHandler handler = null;
172.1250 + if (contentType == null)
172.1251 + throw new UnknownServiceException("no content-type");
172.1252 + try {
172.1253 + handler = (ContentHandler) handlers.get(contentType);
172.1254 + if (handler != null)
172.1255 + return handler;
172.1256 + } catch(Exception e) {
172.1257 + }
172.1258 +
172.1259 + if (factory != null)
172.1260 + handler = factory.createContentHandler(contentType);
172.1261 + if (handler == null) {
172.1262 + try {
172.1263 + handler = lookupContentHandlerClassFor(contentType);
172.1264 + } catch(Exception e) {
172.1265 + e.printStackTrace();
172.1266 + handler = UnknownContentHandler.INSTANCE;
172.1267 + }
172.1268 + handlers.put(contentType, handler);
172.1269 + }
172.1270 + return handler;
172.1271 + }
172.1272 +
172.1273 + /*
172.1274 + * Media types are in the format: type/subtype*(; parameter).
172.1275 + * For looking up the content handler, we should ignore those
172.1276 + * parameters.
172.1277 + */
172.1278 + private String stripOffParameters(String contentType)
172.1279 + {
172.1280 + if (contentType == null)
172.1281 + return null;
172.1282 + int index = contentType.indexOf(';');
172.1283 +
172.1284 + if (index > 0)
172.1285 + return contentType.substring(0, index);
172.1286 + else
172.1287 + return contentType;
172.1288 + }
172.1289 +
172.1290 + private static final String contentClassPrefix = "sun.net.www.content";
172.1291 + private static final String contentPathProp = "java.content.handler.pkgs";
172.1292 +
172.1293 + /**
172.1294 + * Looks for a content handler in a user-defineable set of places.
172.1295 + * By default it looks in sun.net.www.content, but users can define a
172.1296 + * vertical-bar delimited set of class prefixes to search through in
172.1297 + * addition by defining the java.content.handler.pkgs property.
172.1298 + * The class name must be of the form:
172.1299 + * <pre>
172.1300 + * {package-prefix}.{major}.{minor}
172.1301 + * e.g.
172.1302 + * YoyoDyne.experimental.text.plain
172.1303 + * </pre>
172.1304 + */
172.1305 + private ContentHandler lookupContentHandlerClassFor(String contentType)
172.1306 + throws InstantiationException, IllegalAccessException, ClassNotFoundException {
172.1307 + String contentHandlerClassName = typeToPackageName(contentType);
172.1308 +
172.1309 + String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
172.1310 +
172.1311 + StringTokenizer packagePrefixIter =
172.1312 + new StringTokenizer(contentHandlerPkgPrefixes, "|");
172.1313 +
172.1314 + while (packagePrefixIter.hasMoreTokens()) {
172.1315 + String packagePrefix = packagePrefixIter.nextToken().trim();
172.1316 +
172.1317 + try {
172.1318 + String clsName = packagePrefix + "." + contentHandlerClassName;
172.1319 + Class cls = null;
172.1320 + try {
172.1321 + cls = Class.forName(clsName);
172.1322 + } catch (ClassNotFoundException e) {
172.1323 + ClassLoader cl = ClassLoader.getSystemClassLoader();
172.1324 + if (cl != null) {
172.1325 + cls = cl.loadClass(clsName);
172.1326 + }
172.1327 + }
172.1328 + if (cls != null) {
172.1329 + ContentHandler handler =
172.1330 + (ContentHandler)cls.newInstance();
172.1331 + return handler;
172.1332 + }
172.1333 + } catch(Exception e) {
172.1334 + }
172.1335 + }
172.1336 +
172.1337 + return UnknownContentHandler.INSTANCE;
172.1338 + }
172.1339 +
172.1340 + /**
172.1341 + * Utility function to map a MIME content type into an equivalent
172.1342 + * pair of class name components. For example: "text/html" would
172.1343 + * be returned as "text.html"
172.1344 + */
172.1345 + private String typeToPackageName(String contentType) {
172.1346 + // make sure we canonicalize the class name: all lower case
172.1347 + contentType = contentType.toLowerCase();
172.1348 + int len = contentType.length();
172.1349 + char nm[] = new char[len];
172.1350 + contentType.getChars(0, len, nm, 0);
172.1351 + for (int i = 0; i < len; i++) {
172.1352 + char c = nm[i];
172.1353 + if (c == '/') {
172.1354 + nm[i] = '.';
172.1355 + } else if (!('A' <= c && c <= 'Z' ||
172.1356 + 'a' <= c && c <= 'z' ||
172.1357 + '0' <= c && c <= '9')) {
172.1358 + nm[i] = '_';
172.1359 + }
172.1360 + }
172.1361 + return new String(nm);
172.1362 + }
172.1363 +
172.1364 +
172.1365 + /**
172.1366 + * Returns a vertical bar separated list of package prefixes for potential
172.1367 + * content handlers. Tries to get the java.content.handler.pkgs property
172.1368 + * to use as a set of package prefixes to search. Whether or not
172.1369 + * that property has been defined, the sun.net.www.content is always
172.1370 + * the last one on the returned package list.
172.1371 + */
172.1372 + private String getContentHandlerPkgPrefixes() {
172.1373 + String packagePrefixList = "";
172.1374 +
172.1375 + if (packagePrefixList != "") {
172.1376 + packagePrefixList += "|";
172.1377 + }
172.1378 +
172.1379 + return packagePrefixList + contentClassPrefix;
172.1380 + }
172.1381 +
172.1382 + /**
172.1383 + * Tries to determine the content type of an object, based
172.1384 + * on the specified "file" component of a URL.
172.1385 + * This is a convenience method that can be used by
172.1386 + * subclasses that override the <code>getContentType</code> method.
172.1387 + *
172.1388 + * @param fname a filename.
172.1389 + * @return a guess as to what the content type of the object is,
172.1390 + * based upon its file name.
172.1391 + * @see java.net.URLConnection#getContentType()
172.1392 + */
172.1393 + public static String guessContentTypeFromName(String fname) {
172.1394 + return getFileNameMap().getContentTypeFor(fname);
172.1395 + }
172.1396 +
172.1397 + /**
172.1398 + * Tries to determine the type of an input stream based on the
172.1399 + * characters at the beginning of the input stream. This method can
172.1400 + * be used by subclasses that override the
172.1401 + * <code>getContentType</code> method.
172.1402 + * <p>
172.1403 + * Ideally, this routine would not be needed. But many
172.1404 + * <code>http</code> servers return the incorrect content type; in
172.1405 + * addition, there are many nonstandard extensions. Direct inspection
172.1406 + * of the bytes to determine the content type is often more accurate
172.1407 + * than believing the content type claimed by the <code>http</code> server.
172.1408 + *
172.1409 + * @param is an input stream that supports marks.
172.1410 + * @return a guess at the content type, or <code>null</code> if none
172.1411 + * can be determined.
172.1412 + * @exception IOException if an I/O error occurs while reading the
172.1413 + * input stream.
172.1414 + * @see java.io.InputStream#mark(int)
172.1415 + * @see java.io.InputStream#markSupported()
172.1416 + * @see java.net.URLConnection#getContentType()
172.1417 + */
172.1418 + static public String guessContentTypeFromStream(InputStream is)
172.1419 + throws IOException {
172.1420 + // If we can't read ahead safely, just give up on guessing
172.1421 + if (!is.markSupported())
172.1422 + return null;
172.1423 +
172.1424 + is.mark(16);
172.1425 + int c1 = is.read();
172.1426 + int c2 = is.read();
172.1427 + int c3 = is.read();
172.1428 + int c4 = is.read();
172.1429 + int c5 = is.read();
172.1430 + int c6 = is.read();
172.1431 + int c7 = is.read();
172.1432 + int c8 = is.read();
172.1433 + int c9 = is.read();
172.1434 + int c10 = is.read();
172.1435 + int c11 = is.read();
172.1436 + int c12 = is.read();
172.1437 + int c13 = is.read();
172.1438 + int c14 = is.read();
172.1439 + int c15 = is.read();
172.1440 + int c16 = is.read();
172.1441 + is.reset();
172.1442 +
172.1443 + if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
172.1444 + return "application/java-vm";
172.1445 + }
172.1446 +
172.1447 + if (c1 == 0xAC && c2 == 0xED) {
172.1448 + // next two bytes are version number, currently 0x00 0x05
172.1449 + return "application/x-java-serialized-object";
172.1450 + }
172.1451 +
172.1452 + if (c1 == '<') {
172.1453 + if (c2 == '!'
172.1454 + || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
172.1455 + c3 == 'e' && c4 == 'a' && c5 == 'd') ||
172.1456 + (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
172.1457 + ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||
172.1458 + c3 == 'E' && c4 == 'A' && c5 == 'D') ||
172.1459 + (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
172.1460 + return "text/html";
172.1461 + }
172.1462 +
172.1463 + if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
172.1464 + return "application/xml";
172.1465 + }
172.1466 + }
172.1467 +
172.1468 + // big and little (identical) endian UTF-8 encodings, with BOM
172.1469 + if (c1 == 0xef && c2 == 0xbb && c3 == 0xbf) {
172.1470 + if (c4 == '<' && c5 == '?' && c6 == 'x') {
172.1471 + return "application/xml";
172.1472 + }
172.1473 + }
172.1474 +
172.1475 + // big and little endian UTF-16 encodings, with byte order mark
172.1476 + if (c1 == 0xfe && c2 == 0xff) {
172.1477 + if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&
172.1478 + c7 == 0 && c8 == 'x') {
172.1479 + return "application/xml";
172.1480 + }
172.1481 + }
172.1482 +
172.1483 + if (c1 == 0xff && c2 == 0xfe) {
172.1484 + if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&
172.1485 + c7 == 'x' && c8 == 0) {
172.1486 + return "application/xml";
172.1487 + }
172.1488 + }
172.1489 +
172.1490 + // big and little endian UTF-32 encodings, with BOM
172.1491 + if (c1 == 0x00 && c2 == 0x00 && c3 == 0xfe && c4 == 0xff) {
172.1492 + if (c5 == 0 && c6 == 0 && c7 == 0 && c8 == '<' &&
172.1493 + c9 == 0 && c10 == 0 && c11 == 0 && c12 == '?' &&
172.1494 + c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') {
172.1495 + return "application/xml";
172.1496 + }
172.1497 + }
172.1498 +
172.1499 + if (c1 == 0xff && c2 == 0xfe && c3 == 0x00 && c4 == 0x00) {
172.1500 + if (c5 == '<' && c6 == 0 && c7 == 0 && c8 == 0 &&
172.1501 + c9 == '?' && c10 == 0 && c11 == 0 && c12 == 0 &&
172.1502 + c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) {
172.1503 + return "application/xml";
172.1504 + }
172.1505 + }
172.1506 +
172.1507 + if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
172.1508 + return "image/gif";
172.1509 + }
172.1510 +
172.1511 + if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
172.1512 + return "image/x-bitmap";
172.1513 + }
172.1514 +
172.1515 + if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
172.1516 + c5 == 'M' && c6 == '2') {
172.1517 + return "image/x-pixmap";
172.1518 + }
172.1519 +
172.1520 + if (c1 == 137 && c2 == 80 && c3 == 78 &&
172.1521 + c4 == 71 && c5 == 13 && c6 == 10 &&
172.1522 + c7 == 26 && c8 == 10) {
172.1523 + return "image/png";
172.1524 + }
172.1525 +
172.1526 + if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
172.1527 + if (c4 == 0xE0) {
172.1528 + return "image/jpeg";
172.1529 + }
172.1530 +
172.1531 + /**
172.1532 + * File format used by digital cameras to store images.
172.1533 + * Exif Format can be read by any application supporting
172.1534 + * JPEG. Exif Spec can be found at:
172.1535 + * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
172.1536 + */
172.1537 + if ((c4 == 0xE1) &&
172.1538 + (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&
172.1539 + c11 == 0)) {
172.1540 + return "image/jpeg";
172.1541 + }
172.1542 +
172.1543 + if (c4 == 0xEE) {
172.1544 + return "image/jpg";
172.1545 + }
172.1546 + }
172.1547 +
172.1548 + if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
172.1549 + c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
172.1550 +
172.1551 + /* Above is signature of Microsoft Structured Storage.
172.1552 + * Below this, could have tests for various SS entities.
172.1553 + * For now, just test for FlashPix.
172.1554 + */
172.1555 + if (checkfpx(is)) {
172.1556 + return "image/vnd.fpx";
172.1557 + }
172.1558 + }
172.1559 +
172.1560 + if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
172.1561 + return "audio/basic"; // .au format, big endian
172.1562 + }
172.1563 +
172.1564 + if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
172.1565 + return "audio/basic"; // .au format, little endian
172.1566 + }
172.1567 +
172.1568 + if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
172.1569 + /* I don't know if this is official but evidence
172.1570 + * suggests that .wav files start with "RIFF" - brown
172.1571 + */
172.1572 + return "audio/x-wav";
172.1573 + }
172.1574 + return null;
172.1575 + }
172.1576 +
172.1577 + /**
172.1578 + * Check for FlashPix image data in InputStream is. Return true if
172.1579 + * the stream has FlashPix data, false otherwise. Before calling this
172.1580 + * method, the stream should have already been checked to be sure it
172.1581 + * contains Microsoft Structured Storage data.
172.1582 + */
172.1583 + static private boolean checkfpx(InputStream is) throws IOException {
172.1584 +
172.1585 + /* Test for FlashPix image data in Microsoft Structured Storage format.
172.1586 + * In general, should do this with calls to an SS implementation.
172.1587 + * Lacking that, need to dig via offsets to get to the FlashPix
172.1588 + * ClassID. Details:
172.1589 + *
172.1590 + * Offset to Fpx ClsID from beginning of stream should be:
172.1591 + *
172.1592 + * FpxClsidOffset = rootEntryOffset + clsidOffset
172.1593 + *
172.1594 + * where: clsidOffset = 0x50.
172.1595 + * rootEntryOffset = headerSize + sectorSize*sectDirStart
172.1596 + * + 128*rootEntryDirectory
172.1597 + *
172.1598 + * where: headerSize = 0x200 (always)
172.1599 + * sectorSize = 2 raised to power of uSectorShift,
172.1600 + * which is found in the header at
172.1601 + * offset 0x1E.
172.1602 + * sectDirStart = found in the header at offset 0x30.
172.1603 + * rootEntryDirectory = in general, should search for
172.1604 + * directory labelled as root.
172.1605 + * We will assume value of 0 (i.e.,
172.1606 + * rootEntry is in first directory)
172.1607 + */
172.1608 +
172.1609 + // Mark the stream so we can reset it. 0x100 is enough for the first
172.1610 + // few reads, but the mark will have to be reset and set again once
172.1611 + // the offset to the root directory entry is computed. That offset
172.1612 + // can be very large and isn't know until the stream has been read from
172.1613 + is.mark(0x100);
172.1614 +
172.1615 + // Get the byte ordering located at 0x1E. 0xFE is Intel,
172.1616 + // 0xFF is other
172.1617 + long toSkip = (long)0x1C;
172.1618 + long posn;
172.1619 +
172.1620 + if ((posn = skipForward(is, toSkip)) < toSkip) {
172.1621 + is.reset();
172.1622 + return false;
172.1623 + }
172.1624 +
172.1625 + int c[] = new int[16];
172.1626 + if (readBytes(c, 2, is) < 0) {
172.1627 + is.reset();
172.1628 + return false;
172.1629 + }
172.1630 +
172.1631 + int byteOrder = c[0];
172.1632 +
172.1633 + posn+=2;
172.1634 + int uSectorShift;
172.1635 + if (readBytes(c, 2, is) < 0) {
172.1636 + is.reset();
172.1637 + return false;
172.1638 + }
172.1639 +
172.1640 + if(byteOrder == 0xFE) {
172.1641 + uSectorShift = c[0];
172.1642 + uSectorShift += c[1] << 8;
172.1643 + }
172.1644 + else {
172.1645 + uSectorShift = c[0] << 8;
172.1646 + uSectorShift += c[1];
172.1647 + }
172.1648 +
172.1649 + posn += 2;
172.1650 + toSkip = (long)0x30 - posn;
172.1651 + long skipped = 0;
172.1652 + if ((skipped = skipForward(is, toSkip)) < toSkip) {
172.1653 + is.reset();
172.1654 + return false;
172.1655 + }
172.1656 + posn += skipped;
172.1657 +
172.1658 + if (readBytes(c, 4, is) < 0) {
172.1659 + is.reset();
172.1660 + return false;
172.1661 + }
172.1662 +
172.1663 + int sectDirStart;
172.1664 + if(byteOrder == 0xFE) {
172.1665 + sectDirStart = c[0];
172.1666 + sectDirStart += c[1] << 8;
172.1667 + sectDirStart += c[2] << 16;
172.1668 + sectDirStart += c[3] << 24;
172.1669 + } else {
172.1670 + sectDirStart = c[0] << 24;
172.1671 + sectDirStart += c[1] << 16;
172.1672 + sectDirStart += c[2] << 8;
172.1673 + sectDirStart += c[3];
172.1674 + }
172.1675 + posn += 4;
172.1676 + is.reset(); // Reset back to the beginning
172.1677 +
172.1678 + toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L;
172.1679 +
172.1680 + // Sanity check!
172.1681 + if (toSkip < 0) {
172.1682 + return false;
172.1683 + }
172.1684 +
172.1685 + /*
172.1686 + * How far can we skip? Is there any performance problem here?
172.1687 + * This skip can be fairly long, at least 0x4c650 in at least
172.1688 + * one case. Have to assume that the skip will fit in an int.
172.1689 + * Leave room to read whole root dir
172.1690 + */
172.1691 + is.mark((int)toSkip+0x30);
172.1692 +
172.1693 + if ((skipForward(is, toSkip)) < toSkip) {
172.1694 + is.reset();
172.1695 + return false;
172.1696 + }
172.1697 +
172.1698 + /* should be at beginning of ClassID, which is as follows
172.1699 + * (in Intel byte order):
172.1700 + * 00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
172.1701 + *
172.1702 + * This is stored from Windows as long,short,short,char[8]
172.1703 + * so for byte order changes, the order only changes for
172.1704 + * the first 8 bytes in the ClassID.
172.1705 + *
172.1706 + * Test against this, ignoring second byte (Intel) since
172.1707 + * this could change depending on part of Fpx file we have.
172.1708 + */
172.1709 +
172.1710 + if (readBytes(c, 16, is) < 0) {
172.1711 + is.reset();
172.1712 + return false;
172.1713 + }
172.1714 +
172.1715 + // intel byte order
172.1716 + if (byteOrder == 0xFE &&
172.1717 + c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&
172.1718 + c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&
172.1719 + c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
172.1720 + c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
172.1721 + c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
172.1722 + is.reset();
172.1723 + return true;
172.1724 + }
172.1725 +
172.1726 + // non-intel byte order
172.1727 + else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&
172.1728 + c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&
172.1729 + c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
172.1730 + c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
172.1731 + c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
172.1732 + is.reset();
172.1733 + return true;
172.1734 + }
172.1735 + is.reset();
172.1736 + return false;
172.1737 + }
172.1738 +
172.1739 + /**
172.1740 + * Tries to read the specified number of bytes from the stream
172.1741 + * Returns -1, If EOF is reached before len bytes are read, returns 0
172.1742 + * otherwise
172.1743 + */
172.1744 + static private int readBytes(int c[], int len, InputStream is)
172.1745 + throws IOException {
172.1746 +
172.1747 + byte buf[] = new byte[len];
172.1748 + if (is.read(buf, 0, len) < len) {
172.1749 + return -1;
172.1750 + }
172.1751 +
172.1752 + // fill the passed in int array
172.1753 + for (int i = 0; i < len; i++) {
172.1754 + c[i] = buf[i] & 0xff;
172.1755 + }
172.1756 + return 0;
172.1757 + }
172.1758 +
172.1759 +
172.1760 + /**
172.1761 + * Skips through the specified number of bytes from the stream
172.1762 + * until either EOF is reached, or the specified
172.1763 + * number of bytes have been skipped
172.1764 + */
172.1765 + static private long skipForward(InputStream is, long toSkip)
172.1766 + throws IOException {
172.1767 +
172.1768 + long eachSkip = 0;
172.1769 + long skipped = 0;
172.1770 +
172.1771 + while (skipped != toSkip) {
172.1772 + eachSkip = is.skip(toSkip - skipped);
172.1773 +
172.1774 + // check if EOF is reached
172.1775 + if (eachSkip <= 0) {
172.1776 + if (is.read() == -1) {
172.1777 + return skipped ;
172.1778 + } else {
172.1779 + skipped++;
172.1780 + }
172.1781 + }
172.1782 + skipped += eachSkip;
172.1783 + }
172.1784 + return skipped;
172.1785 + }
172.1786 +
172.1787 +}
172.1788 +
172.1789 +
172.1790 +class UnknownContentHandler extends ContentHandler {
172.1791 + static final ContentHandler INSTANCE = new UnknownContentHandler();
172.1792 +
172.1793 + public Object getContent(URLConnection uc) throws IOException {
172.1794 + return uc.getInputStream();
172.1795 + }
172.1796 +}
172.1797 +
172.1798 +/** An RFC 844 or MIME message header. Includes methods
172.1799 + for parsing headers from incoming streams, fetching
172.1800 + values, setting values, and printing headers.
172.1801 + Key values of null are legal: they indicate lines in
172.1802 + the header that don't have a valid key, but do have
172.1803 + a value (this isn't legal according to the standard,
172.1804 + but lines like this are everywhere). */
172.1805 +class MessageHeader {
172.1806 + private String keys[];
172.1807 + private String values[];
172.1808 + private int nkeys;
172.1809 +
172.1810 + public MessageHeader () {
172.1811 + grow();
172.1812 + }
172.1813 +
172.1814 + public MessageHeader (InputStream is) throws java.io.IOException {
172.1815 + parseHeader(is);
172.1816 + }
172.1817 +
172.1818 + /**
172.1819 + * Reset a message header (all key/values removed)
172.1820 + */
172.1821 + public synchronized void reset() {
172.1822 + keys = null;
172.1823 + values = null;
172.1824 + nkeys = 0;
172.1825 + grow();
172.1826 + }
172.1827 +
172.1828 + /**
172.1829 + * Find the value that corresponds to this key.
172.1830 + * It finds only the first occurrence of the key.
172.1831 + * @param k the key to find.
172.1832 + * @return null if not found.
172.1833 + */
172.1834 + public synchronized String findValue(String k) {
172.1835 + if (k == null) {
172.1836 + for (int i = nkeys; --i >= 0;)
172.1837 + if (keys[i] == null)
172.1838 + return values[i];
172.1839 + } else
172.1840 + for (int i = nkeys; --i >= 0;) {
172.1841 + if (k.equalsIgnoreCase(keys[i]))
172.1842 + return values[i];
172.1843 + }
172.1844 + return null;
172.1845 + }
172.1846 +
172.1847 + // return the location of the key
172.1848 + public synchronized int getKey(String k) {
172.1849 + for (int i = nkeys; --i >= 0;)
172.1850 + if ((keys[i] == k) ||
172.1851 + (k != null && k.equalsIgnoreCase(keys[i])))
172.1852 + return i;
172.1853 + return -1;
172.1854 + }
172.1855 +
172.1856 + public synchronized String getKey(int n) {
172.1857 + if (n < 0 || n >= nkeys) return null;
172.1858 + return keys[n];
172.1859 + }
172.1860 +
172.1861 + public synchronized String getValue(int n) {
172.1862 + if (n < 0 || n >= nkeys) return null;
172.1863 + return values[n];
172.1864 + }
172.1865 +
172.1866 + /** Deprecated: Use multiValueIterator() instead.
172.1867 + *
172.1868 + * Find the next value that corresponds to this key.
172.1869 + * It finds the first value that follows v. To iterate
172.1870 + * over all the values of a key use:
172.1871 + * <pre>
172.1872 + * for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
172.1873 + * ...
172.1874 + * }
172.1875 + * </pre>
172.1876 + */
172.1877 + public synchronized String findNextValue(String k, String v) {
172.1878 + boolean foundV = false;
172.1879 + if (k == null) {
172.1880 + for (int i = nkeys; --i >= 0;)
172.1881 + if (keys[i] == null)
172.1882 + if (foundV)
172.1883 + return values[i];
172.1884 + else if (values[i] == v)
172.1885 + foundV = true;
172.1886 + } else
172.1887 + for (int i = nkeys; --i >= 0;)
172.1888 + if (k.equalsIgnoreCase(keys[i]))
172.1889 + if (foundV)
172.1890 + return values[i];
172.1891 + else if (values[i] == v)
172.1892 + foundV = true;
172.1893 + return null;
172.1894 + }
172.1895 +
172.1896 + class HeaderIterator implements Iterator<String> {
172.1897 + int index = 0;
172.1898 + int next = -1;
172.1899 + String key;
172.1900 + boolean haveNext = false;
172.1901 + Object lock;
172.1902 +
172.1903 + public HeaderIterator (String k, Object lock) {
172.1904 + key = k;
172.1905 + this.lock = lock;
172.1906 + }
172.1907 + public boolean hasNext () {
172.1908 + synchronized (lock) {
172.1909 + if (haveNext) {
172.1910 + return true;
172.1911 + }
172.1912 + while (index < nkeys) {
172.1913 + if (key.equalsIgnoreCase (keys[index])) {
172.1914 + haveNext = true;
172.1915 + next = index++;
172.1916 + return true;
172.1917 + }
172.1918 + index ++;
172.1919 + }
172.1920 + return false;
172.1921 + }
172.1922 + }
172.1923 + public String next() {
172.1924 + synchronized (lock) {
172.1925 + if (haveNext) {
172.1926 + haveNext = false;
172.1927 + return values [next];
172.1928 + }
172.1929 + if (hasNext()) {
172.1930 + return next();
172.1931 + } else {
172.1932 + throw new NoSuchElementException ("No more elements");
172.1933 + }
172.1934 + }
172.1935 + }
172.1936 + public void remove () {
172.1937 + throw new UnsupportedOperationException ("remove not allowed");
172.1938 + }
172.1939 + }
172.1940 +
172.1941 + /**
172.1942 + * return an Iterator that returns all values of a particular
172.1943 + * key in sequence
172.1944 + */
172.1945 + public Iterator<String> multiValueIterator (String k) {
172.1946 + return new HeaderIterator (k, this);
172.1947 + }
172.1948 +
172.1949 + public synchronized Map<String, List<String>> getHeaders() {
172.1950 + return getHeaders(null);
172.1951 + }
172.1952 +
172.1953 + public synchronized Map<String, List<String>> getHeaders(String[] excludeList) {
172.1954 + return filterAndAddHeaders(excludeList, null);
172.1955 + }
172.1956 +
172.1957 + public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>> include) {
172.1958 + boolean skipIt = false;
172.1959 + Map<String, List<String>> m = new HashMap<String, List<String>>();
172.1960 + for (int i = nkeys; --i >= 0;) {
172.1961 + if (excludeList != null) {
172.1962 + // check if the key is in the excludeList.
172.1963 + // if so, don't include it in the Map.
172.1964 + for (int j = 0; j < excludeList.length; j++) {
172.1965 + if ((excludeList[j] != null) &&
172.1966 + (excludeList[j].equalsIgnoreCase(keys[i]))) {
172.1967 + skipIt = true;
172.1968 + break;
172.1969 + }
172.1970 + }
172.1971 + }
172.1972 + if (!skipIt) {
172.1973 + List<String> l = m.get(keys[i]);
172.1974 + if (l == null) {
172.1975 + l = new ArrayList<String>();
172.1976 + m.put(keys[i], l);
172.1977 + }
172.1978 + l.add(values[i]);
172.1979 + } else {
172.1980 + // reset the flag
172.1981 + skipIt = false;
172.1982 + }
172.1983 + }
172.1984 +
172.1985 + if (include != null) {
172.1986 + Iterator entries = include.entrySet().iterator();
172.1987 + while (entries.hasNext()) {
172.1988 + Map.Entry entry = (Map.Entry)entries.next();
172.1989 + List l = (List)m.get(entry.getKey());
172.1990 + if (l == null) {
172.1991 + l = new ArrayList();
172.1992 + m.put((String)entry.getKey(), l);
172.1993 + }
172.1994 + l.add(entry.getValue());
172.1995 + }
172.1996 + }
172.1997 +
172.1998 + for (String key : m.keySet()) {
172.1999 + m.put(key, Collections.unmodifiableList(m.get(key)));
172.2000 + }
172.2001 +
172.2002 + return Collections.unmodifiableMap(m);
172.2003 + }
172.2004 +
172.2005 + /** Prints the key-value pairs represented by this
172.2006 + header. Also prints the RFC required blank line
172.2007 + at the end. Omits pairs with a null key. */
172.2008 + public synchronized void print(PrintStream p) {
172.2009 + for (int i = 0; i < nkeys; i++)
172.2010 + if (keys[i] != null) {
172.2011 + p.print(keys[i] +
172.2012 + (values[i] != null ? ": "+values[i]: "") + "\r\n");
172.2013 + }
172.2014 + p.print("\r\n");
172.2015 + p.flush();
172.2016 + }
172.2017 +
172.2018 + /** Adds a key value pair to the end of the
172.2019 + header. Duplicates are allowed */
172.2020 + public synchronized void add(String k, String v) {
172.2021 + grow();
172.2022 + keys[nkeys] = k;
172.2023 + values[nkeys] = v;
172.2024 + nkeys++;
172.2025 + }
172.2026 +
172.2027 + /** Prepends a key value pair to the beginning of the
172.2028 + header. Duplicates are allowed */
172.2029 + public synchronized void prepend(String k, String v) {
172.2030 + grow();
172.2031 + for (int i = nkeys; i > 0; i--) {
172.2032 + keys[i] = keys[i-1];
172.2033 + values[i] = values[i-1];
172.2034 + }
172.2035 + keys[0] = k;
172.2036 + values[0] = v;
172.2037 + nkeys++;
172.2038 + }
172.2039 +
172.2040 + /** Overwrite the previous key/val pair at location 'i'
172.2041 + * with the new k/v. If the index didn't exist before
172.2042 + * the key/val is simply tacked onto the end.
172.2043 + */
172.2044 +
172.2045 + public synchronized void set(int i, String k, String v) {
172.2046 + grow();
172.2047 + if (i < 0) {
172.2048 + return;
172.2049 + } else if (i >= nkeys) {
172.2050 + add(k, v);
172.2051 + } else {
172.2052 + keys[i] = k;
172.2053 + values[i] = v;
172.2054 + }
172.2055 + }
172.2056 +
172.2057 +
172.2058 + /** grow the key/value arrays as needed */
172.2059 +
172.2060 + private void grow() {
172.2061 + if (keys == null || nkeys >= keys.length) {
172.2062 + String[] nk = new String[nkeys + 4];
172.2063 + String[] nv = new String[nkeys + 4];
172.2064 + if (keys != null)
172.2065 + System.arraycopy(keys, 0, nk, 0, nkeys);
172.2066 + if (values != null)
172.2067 + System.arraycopy(values, 0, nv, 0, nkeys);
172.2068 + keys = nk;
172.2069 + values = nv;
172.2070 + }
172.2071 + }
172.2072 +
172.2073 + /**
172.2074 + * Remove the key from the header. If there are multiple values under
172.2075 + * the same key, they are all removed.
172.2076 + * Nothing is done if the key doesn't exist.
172.2077 + * After a remove, the other pairs' order are not changed.
172.2078 + * @param k the key to remove
172.2079 + */
172.2080 + public synchronized void remove(String k) {
172.2081 + if(k == null) {
172.2082 + for (int i = 0; i < nkeys; i++) {
172.2083 + while (keys[i] == null && i < nkeys) {
172.2084 + for(int j=i; j<nkeys-1; j++) {
172.2085 + keys[j] = keys[j+1];
172.2086 + values[j] = values[j+1];
172.2087 + }
172.2088 + nkeys--;
172.2089 + }
172.2090 + }
172.2091 + } else {
172.2092 + for (int i = 0; i < nkeys; i++) {
172.2093 + while (k.equalsIgnoreCase(keys[i]) && i < nkeys) {
172.2094 + for(int j=i; j<nkeys-1; j++) {
172.2095 + keys[j] = keys[j+1];
172.2096 + values[j] = values[j+1];
172.2097 + }
172.2098 + nkeys--;
172.2099 + }
172.2100 + }
172.2101 + }
172.2102 + }
172.2103 +
172.2104 + /** Sets the value of a key. If the key already
172.2105 + exists in the header, it's value will be
172.2106 + changed. Otherwise a new key/value pair will
172.2107 + be added to the end of the header. */
172.2108 + public synchronized void set(String k, String v) {
172.2109 + for (int i = nkeys; --i >= 0;)
172.2110 + if (k.equalsIgnoreCase(keys[i])) {
172.2111 + values[i] = v;
172.2112 + return;
172.2113 + }
172.2114 + add(k, v);
172.2115 + }
172.2116 +
172.2117 + /** Set's the value of a key only if there is no
172.2118 + * key with that value already.
172.2119 + */
172.2120 +
172.2121 + public synchronized void setIfNotSet(String k, String v) {
172.2122 + if (findValue(k) == null) {
172.2123 + add(k, v);
172.2124 + }
172.2125 + }
172.2126 +
172.2127 + /** Convert a message-id string to canonical form (strips off
172.2128 + leading and trailing <>s) */
172.2129 + public static String canonicalID(String id) {
172.2130 + if (id == null)
172.2131 + return "";
172.2132 + int st = 0;
172.2133 + int len = id.length();
172.2134 + boolean substr = false;
172.2135 + int c;
172.2136 + while (st < len && ((c = id.charAt(st)) == '<' ||
172.2137 + c <= ' ')) {
172.2138 + st++;
172.2139 + substr = true;
172.2140 + }
172.2141 + while (st < len && ((c = id.charAt(len - 1)) == '>' ||
172.2142 + c <= ' ')) {
172.2143 + len--;
172.2144 + substr = true;
172.2145 + }
172.2146 + return substr ? id.substring(st, len) : id;
172.2147 + }
172.2148 +
172.2149 + /** Parse a MIME header from an input stream. */
172.2150 + public void parseHeader(InputStream is) throws java.io.IOException {
172.2151 + synchronized (this) {
172.2152 + nkeys = 0;
172.2153 + }
172.2154 + mergeHeader(is);
172.2155 + }
172.2156 +
172.2157 + /** Parse and merge a MIME header from an input stream. */
172.2158 + public void mergeHeader(InputStream is) throws java.io.IOException {
172.2159 + if (is == null)
172.2160 + return;
172.2161 + char s[] = new char[10];
172.2162 + int firstc = is.read();
172.2163 + while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
172.2164 + int len = 0;
172.2165 + int keyend = -1;
172.2166 + int c;
172.2167 + boolean inKey = firstc > ' ';
172.2168 + s[len++] = (char) firstc;
172.2169 + parseloop:{
172.2170 + while ((c = is.read()) >= 0) {
172.2171 + switch (c) {
172.2172 + case ':':
172.2173 + if (inKey && len > 0)
172.2174 + keyend = len;
172.2175 + inKey = false;
172.2176 + break;
172.2177 + case '\t':
172.2178 + c = ' ';
172.2179 + case ' ':
172.2180 + inKey = false;
172.2181 + break;
172.2182 + case '\r':
172.2183 + case '\n':
172.2184 + firstc = is.read();
172.2185 + if (c == '\r' && firstc == '\n') {
172.2186 + firstc = is.read();
172.2187 + if (firstc == '\r')
172.2188 + firstc = is.read();
172.2189 + }
172.2190 + if (firstc == '\n' || firstc == '\r' || firstc > ' ')
172.2191 + break parseloop;
172.2192 + /* continuation */
172.2193 + c = ' ';
172.2194 + break;
172.2195 + }
172.2196 + if (len >= s.length) {
172.2197 + char ns[] = new char[s.length * 2];
172.2198 + System.arraycopy(s, 0, ns, 0, len);
172.2199 + s = ns;
172.2200 + }
172.2201 + s[len++] = (char) c;
172.2202 + }
172.2203 + firstc = -1;
172.2204 + }
172.2205 + while (len > 0 && s[len - 1] <= ' ')
172.2206 + len--;
172.2207 + String k;
172.2208 + if (keyend <= 0) {
172.2209 + k = null;
172.2210 + keyend = 0;
172.2211 + } else {
172.2212 + k = String.copyValueOf(s, 0, keyend);
172.2213 + if (keyend < len && s[keyend] == ':')
172.2214 + keyend++;
172.2215 + while (keyend < len && s[keyend] <= ' ')
172.2216 + keyend++;
172.2217 + }
172.2218 + String v;
172.2219 + if (keyend >= len)
172.2220 + v = new String();
172.2221 + else
172.2222 + v = String.copyValueOf(s, keyend, len - keyend);
172.2223 + add(k, v);
172.2224 + }
172.2225 + }
172.2226 +
172.2227 + public synchronized String toString() {
172.2228 + String result = super.toString() + nkeys + " pairs: ";
172.2229 + for (int i = 0; i < keys.length && i < nkeys; i++) {
172.2230 + result += "{"+keys[i]+": "+values[i]+"}";
172.2231 + }
172.2232 + return result;
172.2233 + }
172.2234 +}
172.2235 +
172.2236 +interface ContentHandlerFactory {
172.2237 +
172.2238 + public ContentHandler createContentHandler(String contentType);
172.2239 +}
172.2240 +
172.2241 +abstract class ContentHandler {
172.2242 + /**
172.2243 + * Given a URL connect stream positioned at the beginning of the
172.2244 + * representation of an object, this method reads that stream and
172.2245 + * creates an object from it.
172.2246 + *
172.2247 + * @param urlc a URL connection.
172.2248 + * @return the object read by the <code>ContentHandler</code>.
172.2249 + * @exception IOException if an I/O error occurs while reading the object.
172.2250 + */
172.2251 + abstract public Object getContent(URLConnection urlc) throws IOException;
172.2252 +
172.2253 + /**
172.2254 + * Given a URL connect stream positioned at the beginning of the
172.2255 + * representation of an object, this method reads that stream and
172.2256 + * creates an object that matches one of the types specified.
172.2257 + *
172.2258 + * The default implementation of this method should call getContent()
172.2259 + * and screen the return type for a match of the suggested types.
172.2260 + *
172.2261 + * @param urlc a URL connection.
172.2262 + * @param classes an array of types requested
172.2263 + * @return the object read by the <code>ContentHandler</code> that is
172.2264 + * the first match of the suggested types.
172.2265 + * null if none of the requested are supported.
172.2266 + * @exception IOException if an I/O error occurs while reading the object.
172.2267 + * @since 1.3
172.2268 + */
172.2269 + public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
172.2270 + Object obj = getContent(urlc);
172.2271 +
172.2272 + for (int i = 0; i < classes.length; i++) {
172.2273 + if (classes[i].isInstance(obj)) {
172.2274 + return obj;
172.2275 + }
172.2276 + }
172.2277 + return null;
172.2278 + }
172.2279 +
172.2280 +}
172.2281 +class UnknownServiceException extends IOException {
172.2282 + private static final long serialVersionUID = -4169033248853639508L;
172.2283 +
172.2284 + /**
172.2285 + * Constructs a new <code>UnknownServiceException</code> with no
172.2286 + * detail message.
172.2287 + */
172.2288 + public UnknownServiceException() {
172.2289 + }
172.2290 +
172.2291 + /**
172.2292 + * Constructs a new <code>UnknownServiceException</code> with the
172.2293 + * specified detail message.
172.2294 + *
172.2295 + * @param msg the detail message.
172.2296 + */
172.2297 + public UnknownServiceException(String msg) {
172.2298 + super(msg);
172.2299 + }
172.2300 +}
172.2301 +/**
172.2302 + * A simple interface which provides a mechanism to map
172.2303 + * between a file name and a MIME type string.
172.2304 + *
172.2305 + * @author Steven B. Byrne
172.2306 + * @since JDK1.1
172.2307 + */
172.2308 +interface FileNameMap {
172.2309 +
172.2310 + /**
172.2311 + * Gets the MIME type for the specified file name.
172.2312 + * @param fileName the specified file name
172.2313 + * @return a <code>String</code> indicating the MIME
172.2314 + * type for the specified file name.
172.2315 + */
172.2316 + public String getContentTypeFor(String fileName);
172.2317 +}
173.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
173.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/Charset.java Wed Apr 30 15:04:10 2014 +0200
173.3 @@ -0,0 +1,765 @@
173.4 +/*
173.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
173.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
173.7 + *
173.8 + * This code is free software; you can redistribute it and/or modify it
173.9 + * under the terms of the GNU General Public License version 2 only, as
173.10 + * published by the Free Software Foundation. Oracle designates this
173.11 + * particular file as subject to the "Classpath" exception as provided
173.12 + * by Oracle in the LICENSE file that accompanied this code.
173.13 + *
173.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
173.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
173.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
173.17 + * version 2 for more details (a copy is included in the LICENSE file that
173.18 + * accompanied this code).
173.19 + *
173.20 + * You should have received a copy of the GNU General Public License version
173.21 + * 2 along with this work; if not, write to the Free Software Foundation,
173.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
173.23 + *
173.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
173.25 + * or visit www.oracle.com if you need additional information or have any
173.26 + * questions.
173.27 + */
173.28 +
173.29 +package java.nio.charset;
173.30 +
173.31 +//import java.nio.ByteBuffer;
173.32 +//import java.nio.CharBuffer;
173.33 +import java.util.Collections;
173.34 +import java.util.HashSet;
173.35 +import java.util.Iterator;
173.36 +import java.util.Locale;
173.37 +import java.util.Map;
173.38 +import java.util.Set;
173.39 +import java.util.SortedMap;
173.40 +import java.util.TreeMap;
173.41 +
173.42 +
173.43 +/**
173.44 + * A named mapping between sequences of sixteen-bit Unicode <a
173.45 + * href="../../lang/Character.html#unicode">code units</a> and sequences of
173.46 + * bytes. This class defines methods for creating decoders and encoders and
173.47 + * for retrieving the various names associated with a charset. Instances of
173.48 + * this class are immutable.
173.49 + *
173.50 + * <p> This class also defines static methods for testing whether a particular
173.51 + * charset is supported, for locating charset instances by name, and for
173.52 + * constructing a map that contains every charset for which support is
173.53 + * available in the current Java virtual machine. Support for new charsets can
173.54 + * be added via the service-provider interface defined in the {@link
173.55 + * java.nio.charset.spi.CharsetProvider} class.
173.56 + *
173.57 + * <p> All of the methods defined in this class are safe for use by multiple
173.58 + * concurrent threads.
173.59 + *
173.60 + *
173.61 + * <a name="names"><a name="charenc">
173.62 + * <h4>Charset names</h4>
173.63 + *
173.64 + * <p> Charsets are named by strings composed of the following characters:
173.65 + *
173.66 + * <ul>
173.67 + *
173.68 + * <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
173.69 + * (<tt>'\u0041'</tt> through <tt>'\u005a'</tt>),
173.70 + *
173.71 + * <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
173.72 + * (<tt>'\u0061'</tt> through <tt>'\u007a'</tt>),
173.73 + *
173.74 + * <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
173.75 + * (<tt>'\u0030'</tt> through <tt>'\u0039'</tt>),
173.76 + *
173.77 + * <li> The dash character <tt>'-'</tt>
173.78 + * (<tt>'\u002d'</tt>, <small>HYPHEN-MINUS</small>),
173.79 + *
173.80 + * <li> The plus character <tt>'+'</tt>
173.81 + * (<tt>'\u002b'</tt>, <small>PLUS SIGN</small>),
173.82 + *
173.83 + * <li> The period character <tt>'.'</tt>
173.84 + * (<tt>'\u002e'</tt>, <small>FULL STOP</small>),
173.85 + *
173.86 + * <li> The colon character <tt>':'</tt>
173.87 + * (<tt>'\u003a'</tt>, <small>COLON</small>), and
173.88 + *
173.89 + * <li> The underscore character <tt>'_'</tt>
173.90 + * (<tt>'\u005f'</tt>, <small>LOW LINE</small>).
173.91 + *
173.92 + * </ul>
173.93 + *
173.94 + * A charset name must begin with either a letter or a digit. The empty string
173.95 + * is not a legal charset name. Charset names are not case-sensitive; that is,
173.96 + * case is always ignored when comparing charset names. Charset names
173.97 + * generally follow the conventions documented in <a
173.98 + * href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC 2278: IANA Charset
173.99 + * Registration Procedures</i></a>.
173.100 + *
173.101 + * <p> Every charset has a <i>canonical name</i> and may also have one or more
173.102 + * <i>aliases</i>. The canonical name is returned by the {@link #name() name} method
173.103 + * of this class. Canonical names are, by convention, usually in upper case.
173.104 + * The aliases of a charset are returned by the {@link #aliases() aliases}
173.105 + * method.
173.106 + *
173.107 + * <a name="hn">
173.108 + *
173.109 + * <p> Some charsets have an <i>historical name</i> that is defined for
173.110 + * compatibility with previous versions of the Java platform. A charset's
173.111 + * historical name is either its canonical name or one of its aliases. The
173.112 + * historical name is returned by the <tt>getEncoding()</tt> methods of the
173.113 + * {@link java.io.InputStreamReader#getEncoding InputStreamReader} and {@link
173.114 + * java.io.OutputStreamWriter#getEncoding OutputStreamWriter} classes.
173.115 + *
173.116 + * <a name="iana">
173.117 + *
173.118 + * <p> If a charset listed in the <a
173.119 + * href="http://www.iana.org/assignments/character-sets"><i>IANA Charset
173.120 + * Registry</i></a> is supported by an implementation of the Java platform then
173.121 + * its canonical name must be the name listed in the registry. Many charsets
173.122 + * are given more than one name in the registry, in which case the registry
173.123 + * identifies one of the names as <i>MIME-preferred</i>. If a charset has more
173.124 + * than one registry name then its canonical name must be the MIME-preferred
173.125 + * name and the other names in the registry must be valid aliases. If a
173.126 + * supported charset is not listed in the IANA registry then its canonical name
173.127 + * must begin with one of the strings <tt>"X-"</tt> or <tt>"x-"</tt>.
173.128 + *
173.129 + * <p> The IANA charset registry does change over time, and so the canonical
173.130 + * name and the aliases of a particular charset may also change over time. To
173.131 + * ensure compatibility it is recommended that no alias ever be removed from a
173.132 + * charset, and that if the canonical name of a charset is changed then its
173.133 + * previous canonical name be made into an alias.
173.134 + *
173.135 + *
173.136 + * <h4>Standard charsets</h4>
173.137 + *
173.138 + * <a name="standard">
173.139 + *
173.140 + * <p> Every implementation of the Java platform is required to support the
173.141 + * following standard charsets. Consult the release documentation for your
173.142 + * implementation to see if any other charsets are supported. The behavior
173.143 + * of such optional charsets may differ between implementations.
173.144 + *
173.145 + * <blockquote><table width="80%" summary="Description of standard charsets">
173.146 + * <tr><th><p align="left">Charset</p></th><th><p align="left">Description</p></th></tr>
173.147 + * <tr><td valign=top><tt>US-ASCII</tt></td>
173.148 + * <td>Seven-bit ASCII, a.k.a. <tt>ISO646-US</tt>,
173.149 + * a.k.a. the Basic Latin block of the Unicode character set</td></tr>
173.150 + * <tr><td valign=top><tt>ISO-8859-1 </tt></td>
173.151 + * <td>ISO Latin Alphabet No. 1, a.k.a. <tt>ISO-LATIN-1</tt></td></tr>
173.152 + * <tr><td valign=top><tt>UTF-8</tt></td>
173.153 + * <td>Eight-bit UCS Transformation Format</td></tr>
173.154 + * <tr><td valign=top><tt>UTF-16BE</tt></td>
173.155 + * <td>Sixteen-bit UCS Transformation Format,
173.156 + * big-endian byte order</td></tr>
173.157 + * <tr><td valign=top><tt>UTF-16LE</tt></td>
173.158 + * <td>Sixteen-bit UCS Transformation Format,
173.159 + * little-endian byte order</td></tr>
173.160 + * <tr><td valign=top><tt>UTF-16</tt></td>
173.161 + * <td>Sixteen-bit UCS Transformation Format,
173.162 + * byte order identified by an optional byte-order mark</td></tr>
173.163 + * </table></blockquote>
173.164 + *
173.165 + * <p> The <tt>UTF-8</tt> charset is specified by <a
173.166 + * href="http://www.ietf.org/rfc/rfc2279.txt"><i>RFC 2279</i></a>; the
173.167 + * transformation format upon which it is based is specified in
173.168 + * Amendment 2 of ISO 10646-1 and is also described in the <a
173.169 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
173.170 + * Standard</i></a>.
173.171 + *
173.172 + * <p> The <tt>UTF-16</tt> charsets are specified by <a
173.173 + * href="http://www.ietf.org/rfc/rfc2781.txt"><i>RFC 2781</i></a>; the
173.174 + * transformation formats upon which they are based are specified in
173.175 + * Amendment 1 of ISO 10646-1 and are also described in the <a
173.176 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
173.177 + * Standard</i></a>.
173.178 + *
173.179 + * <p> The <tt>UTF-16</tt> charsets use sixteen-bit quantities and are
173.180 + * therefore sensitive to byte order. In these encodings the byte order of a
173.181 + * stream may be indicated by an initial <i>byte-order mark</i> represented by
173.182 + * the Unicode character <tt>'\uFEFF'</tt>. Byte-order marks are handled
173.183 + * as follows:
173.184 + *
173.185 + * <ul>
173.186 + *
173.187 + * <li><p> When decoding, the <tt>UTF-16BE</tt> and <tt>UTF-16LE</tt>
173.188 + * charsets interpret the initial byte-order marks as a <small>ZERO-WIDTH
173.189 + * NON-BREAKING SPACE</small>; when encoding, they do not write
173.190 + * byte-order marks. </p></li>
173.191 +
173.192 + *
173.193 + * <li><p> When decoding, the <tt>UTF-16</tt> charset interprets the
173.194 + * byte-order mark at the beginning of the input stream to indicate the
173.195 + * byte-order of the stream but defaults to big-endian if there is no
173.196 + * byte-order mark; when encoding, it uses big-endian byte order and writes
173.197 + * a big-endian byte-order mark. </p></li>
173.198 + *
173.199 + * </ul>
173.200 + *
173.201 + * In any case, byte order marks occuring after the first element of an
173.202 + * input sequence are not omitted since the same code is used to represent
173.203 + * <small>ZERO-WIDTH NON-BREAKING SPACE</small>.
173.204 + *
173.205 + * <p> Every instance of the Java virtual machine has a default charset, which
173.206 + * may or may not be one of the standard charsets. The default charset is
173.207 + * determined during virtual-machine startup and typically depends upon the
173.208 + * locale and charset being used by the underlying operating system. </p>
173.209 + *
173.210 + * <p>The {@link StandardCharsets} class defines constants for each of the
173.211 + * standard charsets.
173.212 + *
173.213 + * <h4>Terminology</h4>
173.214 + *
173.215 + * <p> The name of this class is taken from the terms used in
173.216 + * <a href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC 2278</i></a>.
173.217 + * In that document a <i>charset</i> is defined as the combination of
173.218 + * one or more coded character sets and a character-encoding scheme.
173.219 + * (This definition is confusing; some other software systems define
173.220 + * <i>charset</i> as a synonym for <i>coded character set</i>.)
173.221 + *
173.222 + * <p> A <i>coded character set</i> is a mapping between a set of abstract
173.223 + * characters and a set of integers. US-ASCII, ISO 8859-1,
173.224 + * JIS X 0201, and Unicode are examples of coded character sets.
173.225 + *
173.226 + * <p> Some standards have defined a <i>character set</i> to be simply a
173.227 + * set of abstract characters without an associated assigned numbering.
173.228 + * An alphabet is an example of such a character set. However, the subtle
173.229 + * distinction between <i>character set</i> and <i>coded character set</i>
173.230 + * is rarely used in practice; the former has become a short form for the
173.231 + * latter, including in the Java API specification.
173.232 + *
173.233 + * <p> A <i>character-encoding scheme</i> is a mapping between one or more
173.234 + * coded character sets and a set of octet (eight-bit byte) sequences.
173.235 + * UTF-8, UTF-16, ISO 2022, and EUC are examples of
173.236 + * character-encoding schemes. Encoding schemes are often associated with
173.237 + * a particular coded character set; UTF-8, for example, is used only to
173.238 + * encode Unicode. Some schemes, however, are associated with multiple
173.239 + * coded character sets; EUC, for example, can be used to encode
173.240 + * characters in a variety of Asian coded character sets.
173.241 + *
173.242 + * <p> When a coded character set is used exclusively with a single
173.243 + * character-encoding scheme then the corresponding charset is usually
173.244 + * named for the coded character set; otherwise a charset is usually named
173.245 + * for the encoding scheme and, possibly, the locale of the coded
173.246 + * character sets that it supports. Hence <tt>US-ASCII</tt> is both the
173.247 + * name of a coded character set and of the charset that encodes it, while
173.248 + * <tt>EUC-JP</tt> is the name of the charset that encodes the
173.249 + * JIS X 0201, JIS X 0208, and JIS X 0212
173.250 + * coded character sets for the Japanese language.
173.251 + *
173.252 + * <p> The native character encoding of the Java programming language is
173.253 + * UTF-16. A charset in the Java platform therefore defines a mapping
173.254 + * between sequences of sixteen-bit UTF-16 code units (that is, sequences
173.255 + * of chars) and sequences of bytes. </p>
173.256 + *
173.257 + *
173.258 + * @author Mark Reinhold
173.259 + * @author JSR-51 Expert Group
173.260 + * @since 1.4
173.261 + *
173.262 + * @see CharsetDecoder
173.263 + * @see CharsetEncoder
173.264 + * @see java.nio.charset.spi.CharsetProvider
173.265 + * @see java.lang.Character
173.266 + */
173.267 +
173.268 +public abstract class Charset
173.269 + implements Comparable<Charset>
173.270 +{
173.271 +
173.272 + /* -- Static methods -- */
173.273 +
173.274 + private static volatile String bugLevel = null;
173.275 +
173.276 + /**
173.277 + * Checks that the given string is a legal charset name. </p>
173.278 + *
173.279 + * @param s
173.280 + * A purported charset name
173.281 + *
173.282 + * @throws IllegalCharsetNameException
173.283 + * If the given name is not a legal charset name
173.284 + */
173.285 + private static void checkName(String s) {
173.286 + int n = s.length();
173.287 + if (n == 0)
173.288 + throw new IllegalCharsetNameException(s);
173.289 + for (int i = 0; i < n; i++) {
173.290 + char c = s.charAt(i);
173.291 + if (c >= 'A' && c <= 'Z') continue;
173.292 + if (c >= 'a' && c <= 'z') continue;
173.293 + if (c >= '0' && c <= '9') continue;
173.294 + if (c == '-' && i != 0) continue;
173.295 + if (c == '+' && i != 0) continue;
173.296 + if (c == ':' && i != 0) continue;
173.297 + if (c == '_' && i != 0) continue;
173.298 + if (c == '.' && i != 0) continue;
173.299 + throw new IllegalCharsetNameException(s);
173.300 + }
173.301 + }
173.302 +
173.303 + // Cache of the most-recently-returned charsets,
173.304 + // along with the names that were used to find them
173.305 + //
173.306 + private static volatile Object[] cache1 = null; // "Level 1" cache
173.307 + private static volatile Object[] cache2 = null; // "Level 2" cache
173.308 +
173.309 + private static void cache(String charsetName, Charset cs) {
173.310 + cache2 = cache1;
173.311 + cache1 = new Object[] { charsetName, cs };
173.312 + }
173.313 +
173.314 + // Creates an iterator that walks over the available providers, ignoring
173.315 + // those whose lookup or instantiation causes a security exception to be
173.316 + // thrown. Should be invoked with full privileges.
173.317 + //
173.318 + private static Iterator providers() {
173.319 + return Collections.emptyIterator();
173.320 + }
173.321 +
173.322 + // Thread-local gate to prevent recursive provider lookups
173.323 + private static ThreadLocal<ThreadLocal> gate = new ThreadLocal<ThreadLocal>();
173.324 +
173.325 + private static Charset lookupViaProviders(final String charsetName) {
173.326 + return null;
173.327 + }
173.328 +
173.329 + /* The extended set of charsets */
173.330 + private static Object extendedProviderLock = new Object();
173.331 + private static boolean extendedProviderProbed = false;
173.332 +
173.333 +
173.334 + private static Charset lookupExtendedCharset(String charsetName) {
173.335 + return null;
173.336 + }
173.337 +
173.338 + private static Charset lookup(String charsetName) {
173.339 + if (charsetName == null)
173.340 + throw new IllegalArgumentException("Null charset name");
173.341 +
173.342 + Object[] a;
173.343 + if ((a = cache1) != null && charsetName.equals(a[0]))
173.344 + return (Charset)a[1];
173.345 + // We expect most programs to use one Charset repeatedly.
173.346 + // We convey a hint to this effect to the VM by putting the
173.347 + // level 1 cache miss code in a separate method.
173.348 + return lookup2(charsetName);
173.349 + }
173.350 +
173.351 + private static Charset lookup2(String charsetName) {
173.352 + Object[] a;
173.353 + if ((a = cache2) != null && charsetName.equals(a[0])) {
173.354 + cache2 = cache1;
173.355 + cache1 = a;
173.356 + return (Charset)a[1];
173.357 + }
173.358 +
173.359 + /* Only need to check the name if we didn't find a charset for it */
173.360 + checkName(charsetName);
173.361 + return null;
173.362 + }
173.363 +
173.364 + /**
173.365 + * Tells whether the named charset is supported. </p>
173.366 + *
173.367 + * @param charsetName
173.368 + * The name of the requested charset; may be either
173.369 + * a canonical name or an alias
173.370 + *
173.371 + * @return <tt>true</tt> if, and only if, support for the named charset
173.372 + * is available in the current Java virtual machine
173.373 + *
173.374 + * @throws IllegalCharsetNameException
173.375 + * If the given charset name is illegal
173.376 + *
173.377 + * @throws IllegalArgumentException
173.378 + * If the given <tt>charsetName</tt> is null
173.379 + */
173.380 + public static boolean isSupported(String charsetName) {
173.381 + return (lookup(charsetName) != null);
173.382 + }
173.383 +
173.384 + /**
173.385 + * Returns a charset object for the named charset. </p>
173.386 + *
173.387 + * @param charsetName
173.388 + * The name of the requested charset; may be either
173.389 + * a canonical name or an alias
173.390 + *
173.391 + * @return A charset object for the named charset
173.392 + *
173.393 + * @throws IllegalCharsetNameException
173.394 + * If the given charset name is illegal
173.395 + *
173.396 + * @throws IllegalArgumentException
173.397 + * If the given <tt>charsetName</tt> is null
173.398 + *
173.399 + * @throws UnsupportedCharsetException
173.400 + * If no support for the named charset is available
173.401 + * in this instance of the Java virtual machine
173.402 + */
173.403 + public static Charset forName(String charsetName) {
173.404 + Charset cs = lookup(charsetName);
173.405 + if (cs != null)
173.406 + return cs;
173.407 + throw new UnsupportedCharsetException(charsetName);
173.408 + }
173.409 +
173.410 + // Fold charsets from the given iterator into the given map, ignoring
173.411 + // charsets whose names already have entries in the map.
173.412 + //
173.413 + private static void put(Iterator<Charset> i, Map<String,Charset> m) {
173.414 + while (i.hasNext()) {
173.415 + Charset cs = i.next();
173.416 + if (!m.containsKey(cs.name()))
173.417 + m.put(cs.name(), cs);
173.418 + }
173.419 + }
173.420 +
173.421 + /**
173.422 + * Constructs a sorted map from canonical charset names to charset objects.
173.423 + *
173.424 + * <p> The map returned by this method will have one entry for each charset
173.425 + * for which support is available in the current Java virtual machine. If
173.426 + * two or more supported charsets have the same canonical name then the
173.427 + * resulting map will contain just one of them; which one it will contain
173.428 + * is not specified. </p>
173.429 + *
173.430 + * <p> The invocation of this method, and the subsequent use of the
173.431 + * resulting map, may cause time-consuming disk or network I/O operations
173.432 + * to occur. This method is provided for applications that need to
173.433 + * enumerate all of the available charsets, for example to allow user
173.434 + * charset selection. This method is not used by the {@link #forName
173.435 + * forName} method, which instead employs an efficient incremental lookup
173.436 + * algorithm.
173.437 + *
173.438 + * <p> This method may return different results at different times if new
173.439 + * charset providers are dynamically made available to the current Java
173.440 + * virtual machine. In the absence of such changes, the charsets returned
173.441 + * by this method are exactly those that can be retrieved via the {@link
173.442 + * #forName forName} method. </p>
173.443 + *
173.444 + * @return An immutable, case-insensitive map from canonical charset names
173.445 + * to charset objects
173.446 + */
173.447 + public static SortedMap<String,Charset> availableCharsets() {
173.448 + TreeMap<String, Charset> tm = new TreeMap<String,Charset>();
173.449 + tm.put("UTF-8", Charset.defaultCharset());
173.450 + return tm;
173.451 + }
173.452 +
173.453 + private static volatile Charset defaultCharset;
173.454 +
173.455 + /**
173.456 + * Returns the default charset of this Java virtual machine.
173.457 + *
173.458 + * <p> The default charset is determined during virtual-machine startup and
173.459 + * typically depends upon the locale and charset of the underlying
173.460 + * operating system.
173.461 + *
173.462 + * @return A charset object for the default charset
173.463 + *
173.464 + * @since 1.5
173.465 + */
173.466 + public static Charset defaultCharset() {
173.467 + if (defaultCharset == null) {
173.468 + defaultCharset = forName("UTF-8");
173.469 + }
173.470 + return defaultCharset;
173.471 + }
173.472 +
173.473 +
173.474 + /* -- Instance fields and methods -- */
173.475 +
173.476 + private final String name; // tickles a bug in oldjavac
173.477 + private final String[] aliases; // tickles a bug in oldjavac
173.478 + private Set<String> aliasSet = null;
173.479 +
173.480 + /**
173.481 + * Initializes a new charset with the given canonical name and alias
173.482 + * set. </p>
173.483 + *
173.484 + * @param canonicalName
173.485 + * The canonical name of this charset
173.486 + *
173.487 + * @param aliases
173.488 + * An array of this charset's aliases, or null if it has no aliases
173.489 + *
173.490 + * @throws IllegalCharsetNameException
173.491 + * If the canonical name or any of the aliases are illegal
173.492 + */
173.493 + protected Charset(String canonicalName, String[] aliases) {
173.494 + checkName(canonicalName);
173.495 + String[] as = (aliases == null) ? new String[0] : aliases;
173.496 + for (int i = 0; i < as.length; i++)
173.497 + checkName(as[i]);
173.498 + this.name = canonicalName;
173.499 + this.aliases = as;
173.500 + }
173.501 +
173.502 + /**
173.503 + * Returns this charset's canonical name. </p>
173.504 + *
173.505 + * @return The canonical name of this charset
173.506 + */
173.507 + public final String name() {
173.508 + return name;
173.509 + }
173.510 +
173.511 + /**
173.512 + * Returns a set containing this charset's aliases. </p>
173.513 + *
173.514 + * @return An immutable set of this charset's aliases
173.515 + */
173.516 + public final Set<String> aliases() {
173.517 + if (aliasSet != null)
173.518 + return aliasSet;
173.519 + int n = aliases.length;
173.520 + HashSet<String> hs = new HashSet<String>(n);
173.521 + for (int i = 0; i < n; i++)
173.522 + hs.add(aliases[i]);
173.523 + aliasSet = Collections.unmodifiableSet(hs);
173.524 + return aliasSet;
173.525 + }
173.526 +
173.527 + /**
173.528 + * Returns this charset's human-readable name for the default locale.
173.529 + *
173.530 + * <p> The default implementation of this method simply returns this
173.531 + * charset's canonical name. Concrete subclasses of this class may
173.532 + * override this method in order to provide a localized display name. </p>
173.533 + *
173.534 + * @return The display name of this charset in the default locale
173.535 + */
173.536 + public String displayName() {
173.537 + return name;
173.538 + }
173.539 +
173.540 + /**
173.541 + * Tells whether or not this charset is registered in the <a
173.542 + * href="http://www.iana.org/assignments/character-sets">IANA Charset
173.543 + * Registry</a>. </p>
173.544 + *
173.545 + * @return <tt>true</tt> if, and only if, this charset is known by its
173.546 + * implementor to be registered with the IANA
173.547 + */
173.548 + public final boolean isRegistered() {
173.549 + return !name.startsWith("X-") && !name.startsWith("x-");
173.550 + }
173.551 +
173.552 + /**
173.553 + * Returns this charset's human-readable name for the given locale.
173.554 + *
173.555 + * <p> The default implementation of this method simply returns this
173.556 + * charset's canonical name. Concrete subclasses of this class may
173.557 + * override this method in order to provide a localized display name. </p>
173.558 + *
173.559 + * @param locale
173.560 + * The locale for which the display name is to be retrieved
173.561 + *
173.562 + * @return The display name of this charset in the given locale
173.563 + */
173.564 + public String displayName(Locale locale) {
173.565 + return name;
173.566 + }
173.567 +
173.568 + /**
173.569 + * Tells whether or not this charset contains the given charset.
173.570 + *
173.571 + * <p> A charset <i>C</i> is said to <i>contain</i> a charset <i>D</i> if,
173.572 + * and only if, every character representable in <i>D</i> is also
173.573 + * representable in <i>C</i>. If this relationship holds then it is
173.574 + * guaranteed that every string that can be encoded in <i>D</i> can also be
173.575 + * encoded in <i>C</i> without performing any replacements.
173.576 + *
173.577 + * <p> That <i>C</i> contains <i>D</i> does not imply that each character
173.578 + * representable in <i>C</i> by a particular byte sequence is represented
173.579 + * in <i>D</i> by the same byte sequence, although sometimes this is the
173.580 + * case.
173.581 + *
173.582 + * <p> Every charset contains itself.
173.583 + *
173.584 + * <p> This method computes an approximation of the containment relation:
173.585 + * If it returns <tt>true</tt> then the given charset is known to be
173.586 + * contained by this charset; if it returns <tt>false</tt>, however, then
173.587 + * it is not necessarily the case that the given charset is not contained
173.588 + * in this charset.
173.589 + *
173.590 + * @return <tt>true</tt> if the given charset is contained in this charset
173.591 + */
173.592 + public abstract boolean contains(Charset cs);
173.593 +
173.594 + /**
173.595 + * Constructs a new decoder for this charset. </p>
173.596 + *
173.597 + * @return A new decoder for this charset
173.598 + */
173.599 + public abstract CharsetDecoder newDecoder();
173.600 +
173.601 + /**
173.602 + * Constructs a new encoder for this charset. </p>
173.603 + *
173.604 + * @return A new encoder for this charset
173.605 + *
173.606 + * @throws UnsupportedOperationException
173.607 + * If this charset does not support encoding
173.608 + */
173.609 + public abstract CharsetEncoder newEncoder();
173.610 +
173.611 + /**
173.612 + * Tells whether or not this charset supports encoding.
173.613 + *
173.614 + * <p> Nearly all charsets support encoding. The primary exceptions are
173.615 + * special-purpose <i>auto-detect</i> charsets whose decoders can determine
173.616 + * which of several possible encoding schemes is in use by examining the
173.617 + * input byte sequence. Such charsets do not support encoding because
173.618 + * there is no way to determine which encoding should be used on output.
173.619 + * Implementations of such charsets should override this method to return
173.620 + * <tt>false</tt>. </p>
173.621 + *
173.622 + * @return <tt>true</tt> if, and only if, this charset supports encoding
173.623 + */
173.624 + public boolean canEncode() {
173.625 + return true;
173.626 + }
173.627 +
173.628 + /**
173.629 + * Convenience method that decodes bytes in this charset into Unicode
173.630 + * characters.
173.631 + *
173.632 + * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
173.633 + * same result as the expression
173.634 + *
173.635 + * <pre>
173.636 + * cs.newDecoder()
173.637 + * .onMalformedInput(CodingErrorAction.REPLACE)
173.638 + * .onUnmappableCharacter(CodingErrorAction.REPLACE)
173.639 + * .decode(bb); </pre>
173.640 + *
173.641 + * except that it is potentially more efficient because it can cache
173.642 + * decoders between successive invocations.
173.643 + *
173.644 + * <p> This method always replaces malformed-input and unmappable-character
173.645 + * sequences with this charset's default replacement byte array. In order
173.646 + * to detect such sequences, use the {@link
173.647 + * CharsetDecoder#decode(java.nio.ByteBuffer)} method directly. </p>
173.648 + *
173.649 + * @param bb The byte buffer to be decoded
173.650 + *
173.651 + * @return A char buffer containing the decoded characters
173.652 + */
173.653 +// public final CharBuffer decode(ByteBuffer bb) {
173.654 +// try {
173.655 +// return ThreadLocalCoders.decoderFor(this)
173.656 +// .onMalformedInput(CodingErrorAction.REPLACE)
173.657 +// .onUnmappableCharacter(CodingErrorAction.REPLACE)
173.658 +// .decode(bb);
173.659 +// } catch (CharacterCodingException x) {
173.660 +// throw new Error(x); // Can't happen
173.661 +// }
173.662 +// }
173.663 +
173.664 + /**
173.665 + * Convenience method that encodes Unicode characters into bytes in this
173.666 + * charset.
173.667 + *
173.668 + * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
173.669 + * same result as the expression
173.670 + *
173.671 + * <pre>
173.672 + * cs.newEncoder()
173.673 + * .onMalformedInput(CodingErrorAction.REPLACE)
173.674 + * .onUnmappableCharacter(CodingErrorAction.REPLACE)
173.675 + * .encode(bb); </pre>
173.676 + *
173.677 + * except that it is potentially more efficient because it can cache
173.678 + * encoders between successive invocations.
173.679 + *
173.680 + * <p> This method always replaces malformed-input and unmappable-character
173.681 + * sequences with this charset's default replacement string. In order to
173.682 + * detect such sequences, use the {@link
173.683 + * CharsetEncoder#encode(java.nio.CharBuffer)} method directly. </p>
173.684 + *
173.685 + * @param cb The char buffer to be encoded
173.686 + *
173.687 + * @return A byte buffer containing the encoded characters
173.688 + */
173.689 +// public final ByteBuffer encode(CharBuffer cb) {
173.690 +// try {
173.691 +// return ThreadLocalCoders.encoderFor(this)
173.692 +// .onMalformedInput(CodingErrorAction.REPLACE)
173.693 +// .onUnmappableCharacter(CodingErrorAction.REPLACE)
173.694 +// .encode(cb);
173.695 +// } catch (CharacterCodingException x) {
173.696 +// throw new Error(x); // Can't happen
173.697 +// }
173.698 +// }
173.699 +
173.700 + /**
173.701 + * Convenience method that encodes a string into bytes in this charset.
173.702 + *
173.703 + * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
173.704 + * same result as the expression
173.705 + *
173.706 + * <pre>
173.707 + * cs.encode(CharBuffer.wrap(s)); </pre>
173.708 + *
173.709 + * @param str The string to be encoded
173.710 + *
173.711 + * @return A byte buffer containing the encoded characters
173.712 + */
173.713 +// public final ByteBuffer encode(String str) {
173.714 +// return encode(CharBuffer.wrap(str));
173.715 +// }
173.716 +
173.717 + /**
173.718 + * Compares this charset to another.
173.719 + *
173.720 + * <p> Charsets are ordered by their canonical names, without regard to
173.721 + * case. </p>
173.722 + *
173.723 + * @param that
173.724 + * The charset to which this charset is to be compared
173.725 + *
173.726 + * @return A negative integer, zero, or a positive integer as this charset
173.727 + * is less than, equal to, or greater than the specified charset
173.728 + */
173.729 + public final int compareTo(Charset that) {
173.730 + return (name().compareToIgnoreCase(that.name()));
173.731 + }
173.732 +
173.733 + /**
173.734 + * Computes a hashcode for this charset. </p>
173.735 + *
173.736 + * @return An integer hashcode
173.737 + */
173.738 + public final int hashCode() {
173.739 + return name().hashCode();
173.740 + }
173.741 +
173.742 + /**
173.743 + * Tells whether or not this object is equal to another.
173.744 + *
173.745 + * <p> Two charsets are equal if, and only if, they have the same canonical
173.746 + * names. A charset is never equal to any other type of object. </p>
173.747 + *
173.748 + * @return <tt>true</tt> if, and only if, this charset is equal to the
173.749 + * given object
173.750 + */
173.751 + public final boolean equals(Object ob) {
173.752 + if (!(ob instanceof Charset))
173.753 + return false;
173.754 + if (this == ob)
173.755 + return true;
173.756 + return name.equals(((Charset)ob).name());
173.757 + }
173.758 +
173.759 + /**
173.760 + * Returns a string describing this charset. </p>
173.761 + *
173.762 + * @return A string describing this charset
173.763 + */
173.764 + public final String toString() {
173.765 + return name();
173.766 + }
173.767 +
173.768 +}
174.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
174.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetDecoder.java Wed Apr 30 15:04:10 2014 +0200
174.3 @@ -0,0 +1,970 @@
174.4 +/*
174.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
174.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
174.7 + *
174.8 + * This code is free software; you can redistribute it and/or modify it
174.9 + * under the terms of the GNU General Public License version 2 only, as
174.10 + * published by the Free Software Foundation. Oracle designates this
174.11 + * particular file as subject to the "Classpath" exception as provided
174.12 + * by Oracle in the LICENSE file that accompanied this code.
174.13 + *
174.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
174.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
174.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
174.17 + * version 2 for more details (a copy is included in the LICENSE file that
174.18 + * accompanied this code).
174.19 + *
174.20 + * You should have received a copy of the GNU General Public License version
174.21 + * 2 along with this work; if not, write to the Free Software Foundation,
174.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
174.23 + *
174.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
174.25 + * or visit www.oracle.com if you need additional information or have any
174.26 + * questions.
174.27 + */
174.28 +
174.29 +// -- This file was mechanically generated: Do not edit! -- //
174.30 +
174.31 +package java.nio.charset;
174.32 +
174.33 +//import java.nio.Buffer;
174.34 +//import java.nio.ByteBuffer;
174.35 +//import java.nio.CharBuffer;
174.36 +//import java.nio.BufferOverflowException;
174.37 +//import java.nio.BufferUnderflowException;
174.38 +import java.lang.ref.WeakReference;
174.39 +//import java.nio.charset.CoderMalfunctionError; // javadoc
174.40 +
174.41 +
174.42 +/**
174.43 + * An engine that can transform a sequence of bytes in a specific charset into a sequence of
174.44 + * sixteen-bit Unicode characters.
174.45 + *
174.46 + * <a name="steps">
174.47 + *
174.48 + * <p> The input byte sequence is provided in a byte buffer or a series
174.49 + * of such buffers. The output character sequence is written to a character buffer
174.50 + * or a series of such buffers. A decoder should always be used by making
174.51 + * the following sequence of method invocations, hereinafter referred to as a
174.52 + * <i>decoding operation</i>:
174.53 + *
174.54 + * <ol>
174.55 + *
174.56 + * <li><p> Reset the decoder via the {@link #reset reset} method, unless it
174.57 + * has not been used before; </p></li>
174.58 + *
174.59 + * <li><p> Invoke the {@link #decode decode} method zero or more times, as
174.60 + * long as additional input may be available, passing <tt>false</tt> for the
174.61 + * <tt>endOfInput</tt> argument and filling the input buffer and flushing the
174.62 + * output buffer between invocations; </p></li>
174.63 + *
174.64 + * <li><p> Invoke the {@link #decode decode} method one final time, passing
174.65 + * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
174.66 + *
174.67 + * <li><p> Invoke the {@link #flush flush} method so that the decoder can
174.68 + * flush any internal state to the output buffer. </p></li>
174.69 + *
174.70 + * </ol>
174.71 + *
174.72 + * Each invocation of the {@link #decode decode} method will decode as many
174.73 + * bytes as possible from the input buffer, writing the resulting characters
174.74 + * to the output buffer. The {@link #decode decode} method returns when more
174.75 + * input is required, when there is not enough room in the output buffer, or
174.76 + * when a decoding error has occurred. In each case a {@link CoderResult}
174.77 + * object is returned to describe the reason for termination. An invoker can
174.78 + * examine this object and fill the input buffer, flush the output buffer, or
174.79 + * attempt to recover from a decoding error, as appropriate, and try again.
174.80 + *
174.81 + * <a name="ce">
174.82 + *
174.83 + * <p> There are two general types of decoding errors. If the input byte
174.84 + * sequence is not legal for this charset then the input is considered <i>malformed</i>. If
174.85 + * the input byte sequence is legal but cannot be mapped to a valid
174.86 + * Unicode character then an <i>unmappable character</i> has been encountered.
174.87 + *
174.88 + * <a name="cae">
174.89 + *
174.90 + * <p> How a decoding error is handled depends upon the action requested for
174.91 + * that type of error, which is described by an instance of the {@link
174.92 + * CodingErrorAction} class. The possible error actions are to {@link
174.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
174.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
174.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
174.96 + * </code>replace<code>} the erroneous input with the current value of the
174.97 + * replacement string. The replacement
174.98 + *
174.99 +
174.100 +
174.101 +
174.102 +
174.103 +
174.104 + * has the initial value <tt>"\uFFFD"</tt>;
174.105 +
174.106 + *
174.107 + * its value may be changed via the {@link #replaceWith(java.lang.String)
174.108 + * replaceWith} method.
174.109 + *
174.110 + * <p> The default action for malformed-input and unmappable-character errors
174.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The
174.112 + * malformed-input error action may be changed via the {@link
174.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
174.114 + * unmappable-character action may be changed via the {@link
174.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
174.116 + *
174.117 + * <p> This class is designed to handle many of the details of the decoding
174.118 + * process, including the implementation of error actions. A decoder for a
174.119 + * specific charset, which is a concrete subclass of this class, need only
174.120 + * implement the abstract {@link #decodeLoop decodeLoop} method, which
174.121 + * encapsulates the basic decoding loop. A subclass that maintains internal
174.122 + * state should, additionally, override the {@link #implFlush implFlush} and
174.123 + * {@link #implReset implReset} methods.
174.124 + *
174.125 + * <p> Instances of this class are not safe for use by multiple concurrent
174.126 + * threads. </p>
174.127 + *
174.128 + *
174.129 + * @author Mark Reinhold
174.130 + * @author JSR-51 Expert Group
174.131 + * @since 1.4
174.132 + *
174.133 + * @see ByteBuffer
174.134 + * @see CharBuffer
174.135 + * @see Charset
174.136 + * @see CharsetEncoder
174.137 + */
174.138 +
174.139 +public abstract class CharsetDecoder {
174.140 +
174.141 + private final Charset charset;
174.142 + private final float averageCharsPerByte;
174.143 + private final float maxCharsPerByte;
174.144 +
174.145 + private String replacement;
174.146 +// private CodingErrorAction malformedInputAction
174.147 +// = CodingErrorAction.REPORT;
174.148 +// private CodingErrorAction unmappableCharacterAction
174.149 +// = CodingErrorAction.REPORT;
174.150 +
174.151 + // Internal states
174.152 + //
174.153 + private static final int ST_RESET = 0;
174.154 + private static final int ST_CODING = 1;
174.155 + private static final int ST_END = 2;
174.156 + private static final int ST_FLUSHED = 3;
174.157 +
174.158 + private int state = ST_RESET;
174.159 +
174.160 + private static String stateNames[]
174.161 + = { "RESET", "CODING", "CODING_END", "FLUSHED" };
174.162 +
174.163 +
174.164 + /**
174.165 + * Initializes a new decoder. The new decoder will have the given
174.166 + * chars-per-byte and replacement values. </p>
174.167 + *
174.168 + * @param averageCharsPerByte
174.169 + * A positive float value indicating the expected number of
174.170 + * characters that will be produced for each input byte
174.171 + *
174.172 + * @param maxCharsPerByte
174.173 + * A positive float value indicating the maximum number of
174.174 + * characters that will be produced for each input byte
174.175 + *
174.176 + * @param replacement
174.177 + * The initial replacement; must not be <tt>null</tt>, must have
174.178 + * non-zero length, must not be longer than maxCharsPerByte,
174.179 + * and must be {@link #isLegalReplacement </code>legal<code>}
174.180 + *
174.181 + * @throws IllegalArgumentException
174.182 + * If the preconditions on the parameters do not hold
174.183 + */
174.184 + private
174.185 + CharsetDecoder(Charset cs,
174.186 + float averageCharsPerByte,
174.187 + float maxCharsPerByte,
174.188 + String replacement)
174.189 + {
174.190 + this.charset = cs;
174.191 + if (averageCharsPerByte <= 0.0f)
174.192 + throw new IllegalArgumentException("Non-positive "
174.193 + + "averageCharsPerByte");
174.194 + if (maxCharsPerByte <= 0.0f)
174.195 + throw new IllegalArgumentException("Non-positive "
174.196 + + "maxCharsPerByte");
174.197 + if (averageCharsPerByte > maxCharsPerByte)
174.198 + throw new IllegalArgumentException("averageCharsPerByte"
174.199 + + " exceeds "
174.200 + + "maxCharsPerByte");
174.201 + this.replacement = replacement;
174.202 + this.averageCharsPerByte = averageCharsPerByte;
174.203 + this.maxCharsPerByte = maxCharsPerByte;
174.204 + replaceWith(replacement);
174.205 + }
174.206 +
174.207 + /**
174.208 + * Initializes a new decoder. The new decoder will have the given
174.209 + * chars-per-byte values and its replacement will be the
174.210 + * string <tt>"\uFFFD"</tt>. </p>
174.211 + *
174.212 + * @param averageCharsPerByte
174.213 + * A positive float value indicating the expected number of
174.214 + * characters that will be produced for each input byte
174.215 + *
174.216 + * @param maxCharsPerByte
174.217 + * A positive float value indicating the maximum number of
174.218 + * characters that will be produced for each input byte
174.219 + *
174.220 + * @throws IllegalArgumentException
174.221 + * If the preconditions on the parameters do not hold
174.222 + */
174.223 + protected CharsetDecoder(Charset cs,
174.224 + float averageCharsPerByte,
174.225 + float maxCharsPerByte)
174.226 + {
174.227 + this(cs,
174.228 + averageCharsPerByte, maxCharsPerByte,
174.229 + "\uFFFD");
174.230 + }
174.231 +
174.232 + /**
174.233 + * Returns the charset that created this decoder. </p>
174.234 + *
174.235 + * @return This decoder's charset
174.236 + */
174.237 + public final Charset charset() {
174.238 + return charset;
174.239 + }
174.240 +
174.241 + /**
174.242 + * Returns this decoder's replacement value. </p>
174.243 + *
174.244 + * @return This decoder's current replacement,
174.245 + * which is never <tt>null</tt> and is never empty
174.246 + */
174.247 + public final String replacement() {
174.248 + return replacement;
174.249 + }
174.250 +
174.251 + /**
174.252 + * Changes this decoder's replacement value.
174.253 + *
174.254 + * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
174.255 + * method, passing the new replacement, after checking that the new
174.256 + * replacement is acceptable. </p>
174.257 + *
174.258 + * @param newReplacement
174.259 + *
174.260 +
174.261 + * The new replacement; must not be <tt>null</tt>
174.262 + * and must have non-zero length
174.263 +
174.264 +
174.265 +
174.266 +
174.267 +
174.268 +
174.269 +
174.270 + *
174.271 + * @return This decoder
174.272 + *
174.273 + * @throws IllegalArgumentException
174.274 + * If the preconditions on the parameter do not hold
174.275 + */
174.276 + public final CharsetDecoder replaceWith(String newReplacement) {
174.277 + if (newReplacement == null)
174.278 + throw new IllegalArgumentException("Null replacement");
174.279 + int len = newReplacement.length();
174.280 + if (len == 0)
174.281 + throw new IllegalArgumentException("Empty replacement");
174.282 + if (len > maxCharsPerByte)
174.283 + throw new IllegalArgumentException("Replacement too long");
174.284 +
174.285 +
174.286 +
174.287 +
174.288 + this.replacement = newReplacement;
174.289 + implReplaceWith(newReplacement);
174.290 + return this;
174.291 + }
174.292 +
174.293 + /**
174.294 + * Reports a change to this decoder's replacement value.
174.295 + *
174.296 + * <p> The default implementation of this method does nothing. This method
174.297 + * should be overridden by decoders that require notification of changes to
174.298 + * the replacement. </p>
174.299 + *
174.300 + * @param newReplacement
174.301 + */
174.302 + protected void implReplaceWith(String newReplacement) {
174.303 + }
174.304 +
174.305 +
174.306 +
174.307 +
174.308 +
174.309 +
174.310 +
174.311 +
174.312 +
174.313 +
174.314 +
174.315 +
174.316 +
174.317 +
174.318 +
174.319 +
174.320 +
174.321 +
174.322 +
174.323 +
174.324 +
174.325 +
174.326 +
174.327 +
174.328 +
174.329 +
174.330 +
174.331 +
174.332 +
174.333 +
174.334 +
174.335 +
174.336 +
174.337 +
174.338 +
174.339 +
174.340 +
174.341 +
174.342 +
174.343 +
174.344 +
174.345 + /**
174.346 + * Returns this decoder's current action for malformed-input errors. </p>
174.347 + *
174.348 + * @return The current malformed-input action, which is never <tt>null</tt>
174.349 + */
174.350 +// public CodingErrorAction malformedInputAction() {
174.351 +// return malformedInputAction;
174.352 +// }
174.353 +
174.354 + /**
174.355 + * Changes this decoder's action for malformed-input errors. </p>
174.356 + *
174.357 + * <p> This method invokes the {@link #implOnMalformedInput
174.358 + * implOnMalformedInput} method, passing the new action. </p>
174.359 + *
174.360 + * @param newAction The new action; must not be <tt>null</tt>
174.361 + *
174.362 + * @return This decoder
174.363 + *
174.364 + * @throws IllegalArgumentException
174.365 + * If the precondition on the parameter does not hold
174.366 + */
174.367 +// public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) {
174.368 +// if (newAction == null)
174.369 +// throw new IllegalArgumentException("Null action");
174.370 +// malformedInputAction = newAction;
174.371 +// implOnMalformedInput(newAction);
174.372 +// return this;
174.373 +// }
174.374 +
174.375 + /**
174.376 + * Reports a change to this decoder's malformed-input action.
174.377 + *
174.378 + * <p> The default implementation of this method does nothing. This method
174.379 + * should be overridden by decoders that require notification of changes to
174.380 + * the malformed-input action. </p>
174.381 + */
174.382 +// protected void implOnMalformedInput(CodingErrorAction newAction) { }
174.383 +
174.384 + /**
174.385 + * Returns this decoder's current action for unmappable-character errors.
174.386 + * </p>
174.387 + *
174.388 + * @return The current unmappable-character action, which is never
174.389 + * <tt>null</tt>
174.390 + */
174.391 +// public CodingErrorAction unmappableCharacterAction() {
174.392 +// return unmappableCharacterAction;
174.393 +// }
174.394 +
174.395 + /**
174.396 + * Changes this decoder's action for unmappable-character errors.
174.397 + *
174.398 + * <p> This method invokes the {@link #implOnUnmappableCharacter
174.399 + * implOnUnmappableCharacter} method, passing the new action. </p>
174.400 + *
174.401 + * @param newAction The new action; must not be <tt>null</tt>
174.402 + *
174.403 + * @return This decoder
174.404 + *
174.405 + * @throws IllegalArgumentException
174.406 + * If the precondition on the parameter does not hold
174.407 + */
174.408 +// public final CharsetDecoder onUnmappableCharacter(CodingErrorAction
174.409 +// newAction)
174.410 +// {
174.411 +// if (newAction == null)
174.412 +// throw new IllegalArgumentException("Null action");
174.413 +// unmappableCharacterAction = newAction;
174.414 +// implOnUnmappableCharacter(newAction);
174.415 +// return this;
174.416 +// }
174.417 +
174.418 + /**
174.419 + * Reports a change to this decoder's unmappable-character action.
174.420 + *
174.421 + * <p> The default implementation of this method does nothing. This method
174.422 + * should be overridden by decoders that require notification of changes to
174.423 + * the unmappable-character action. </p>
174.424 + */
174.425 +// protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
174.426 +
174.427 + /**
174.428 + * Returns the average number of characters that will be produced for each
174.429 + * byte of input. This heuristic value may be used to estimate the size
174.430 + * of the output buffer required for a given input sequence. </p>
174.431 + *
174.432 + * @return The average number of characters produced
174.433 + * per byte of input
174.434 + */
174.435 + public final float averageCharsPerByte() {
174.436 + return averageCharsPerByte;
174.437 + }
174.438 +
174.439 + /**
174.440 + * Returns the maximum number of characters that will be produced for each
174.441 + * byte of input. This value may be used to compute the worst-case size
174.442 + * of the output buffer required for a given input sequence. </p>
174.443 + *
174.444 + * @return The maximum number of characters that will be produced per
174.445 + * byte of input
174.446 + */
174.447 + public final float maxCharsPerByte() {
174.448 + return maxCharsPerByte;
174.449 + }
174.450 +
174.451 + /**
174.452 + * Decodes as many bytes as possible from the given input buffer,
174.453 + * writing the results to the given output buffer.
174.454 + *
174.455 + * <p> The buffers are read from, and written to, starting at their current
174.456 + * positions. At most {@link Buffer#remaining in.remaining()} bytes
174.457 + * will be read and at most {@link Buffer#remaining out.remaining()}
174.458 + * characters will be written. The buffers' positions will be advanced to
174.459 + * reflect the bytes read and the characters written, but their marks and
174.460 + * limits will not be modified.
174.461 + *
174.462 + * <p> In addition to reading bytes from the input buffer and writing
174.463 + * characters to the output buffer, this method returns a {@link CoderResult}
174.464 + * object to describe its reason for termination:
174.465 + *
174.466 + * <ul>
174.467 + *
174.468 + * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
174.469 + * input buffer as possible has been decoded. If there is no further
174.470 + * input then the invoker can proceed to the next step of the
174.471 + * <a href="#steps">decoding operation</a>. Otherwise this method
174.472 + * should be invoked again with further input. </p></li>
174.473 + *
174.474 + * <li><p> {@link CoderResult#OVERFLOW} indicates that there is
174.475 + * insufficient space in the output buffer to decode any more bytes.
174.476 + * This method should be invoked again with an output buffer that has
174.477 + * more {@linkplain Buffer#remaining remaining} characters. This is
174.478 + * typically done by draining any decoded characters from the output
174.479 + * buffer. </p></li>
174.480 + *
174.481 + * <li><p> A {@link CoderResult#malformedForLength
174.482 + * </code>malformed-input<code>} result indicates that a malformed-input
174.483 + * error has been detected. The malformed bytes begin at the input
174.484 + * buffer's (possibly incremented) position; the number of malformed
174.485 + * bytes may be determined by invoking the result object's {@link
174.486 + * CoderResult#length() length} method. This case applies only if the
174.487 + * {@link #onMalformedInput </code>malformed action<code>} of this decoder
174.488 + * is {@link CodingErrorAction#REPORT}; otherwise the malformed input
174.489 + * will be ignored or replaced, as requested. </p></li>
174.490 + *
174.491 + * <li><p> An {@link CoderResult#unmappableForLength
174.492 + * </code>unmappable-character<code>} result indicates that an
174.493 + * unmappable-character error has been detected. The bytes that
174.494 + * decode the unmappable character begin at the input buffer's (possibly
174.495 + * incremented) position; the number of such bytes may be determined
174.496 + * by invoking the result object's {@link CoderResult#length() length}
174.497 + * method. This case applies only if the {@link #onUnmappableCharacter
174.498 + * </code>unmappable action<code>} of this decoder is {@link
174.499 + * CodingErrorAction#REPORT}; otherwise the unmappable character will be
174.500 + * ignored or replaced, as requested. </p></li>
174.501 + *
174.502 + * </ul>
174.503 + *
174.504 + * In any case, if this method is to be reinvoked in the same decoding
174.505 + * operation then care should be taken to preserve any bytes remaining
174.506 + * in the input buffer so that they are available to the next invocation.
174.507 + *
174.508 + * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
174.509 + * the invoker can provide further input beyond that contained in the given
174.510 + * input buffer. If there is a possibility of providing additional input
174.511 + * then the invoker should pass <tt>false</tt> for this parameter; if there
174.512 + * is no possibility of providing further input then the invoker should
174.513 + * pass <tt>true</tt>. It is not erroneous, and in fact it is quite
174.514 + * common, to pass <tt>false</tt> in one invocation and later discover that
174.515 + * no further input was actually available. It is critical, however, that
174.516 + * the final invocation of this method in a sequence of invocations always
174.517 + * pass <tt>true</tt> so that any remaining undecoded input will be treated
174.518 + * as being malformed.
174.519 + *
174.520 + * <p> This method works by invoking the {@link #decodeLoop decodeLoop}
174.521 + * method, interpreting its results, handling error conditions, and
174.522 + * reinvoking it as necessary. </p>
174.523 + *
174.524 + *
174.525 + * @param in
174.526 + * The input byte buffer
174.527 + *
174.528 + * @param out
174.529 + * The output character buffer
174.530 + *
174.531 + * @param endOfInput
174.532 + * <tt>true</tt> if, and only if, the invoker can provide no
174.533 + * additional input bytes beyond those in the given buffer
174.534 + *
174.535 + * @return A coder-result object describing the reason for termination
174.536 + *
174.537 + * @throws IllegalStateException
174.538 + * If a decoding operation is already in progress and the previous
174.539 + * step was an invocation neither of the {@link #reset reset}
174.540 + * method, nor of this method with a value of <tt>false</tt> for
174.541 + * the <tt>endOfInput</tt> parameter, nor of this method with a
174.542 + * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
174.543 + * but a return value indicating an incomplete decoding operation
174.544 + *
174.545 + * @throws CoderMalfunctionError
174.546 + * If an invocation of the decodeLoop method threw
174.547 + * an unexpected exception
174.548 + */
174.549 +// public final CoderResult decode(ByteBuffer in, CharBuffer out,
174.550 +// boolean endOfInput)
174.551 +// {
174.552 +// int newState = endOfInput ? ST_END : ST_CODING;
174.553 +// if ((state != ST_RESET) && (state != ST_CODING)
174.554 +// && !(endOfInput && (state == ST_END)))
174.555 +// throwIllegalStateException(state, newState);
174.556 +// state = newState;
174.557 +//
174.558 +// for (;;) {
174.559 +//
174.560 +// CoderResult cr;
174.561 +// try {
174.562 +// cr = decodeLoop(in, out);
174.563 +// } catch (BufferUnderflowException x) {
174.564 +// throw new CoderMalfunctionError(x);
174.565 +// } catch (BufferOverflowException x) {
174.566 +// throw new CoderMalfunctionError(x);
174.567 +// }
174.568 +//
174.569 +// if (cr.isOverflow())
174.570 +// return cr;
174.571 +//
174.572 +// if (cr.isUnderflow()) {
174.573 +// if (endOfInput && in.hasRemaining()) {
174.574 +// cr = CoderResult.malformedForLength(in.remaining());
174.575 +// // Fall through to malformed-input case
174.576 +// } else {
174.577 +// return cr;
174.578 +// }
174.579 +// }
174.580 +//
174.581 +// CodingErrorAction action = null;
174.582 +// if (cr.isMalformed())
174.583 +// action = malformedInputAction;
174.584 +// else if (cr.isUnmappable())
174.585 +// action = unmappableCharacterAction;
174.586 +// else
174.587 +// assert false : cr.toString();
174.588 +//
174.589 +// if (action == CodingErrorAction.REPORT)
174.590 +// return cr;
174.591 +//
174.592 +// if (action == CodingErrorAction.REPLACE) {
174.593 +// if (out.remaining() < replacement.length())
174.594 +// return CoderResult.OVERFLOW;
174.595 +// out.put(replacement);
174.596 +// }
174.597 +//
174.598 +// if ((action == CodingErrorAction.IGNORE)
174.599 +// || (action == CodingErrorAction.REPLACE)) {
174.600 +// // Skip erroneous input either way
174.601 +// in.position(in.position() + cr.length());
174.602 +// continue;
174.603 +// }
174.604 +//
174.605 +// assert false;
174.606 +// }
174.607 +//
174.608 +// }
174.609 +
174.610 + /**
174.611 + * Flushes this decoder.
174.612 + *
174.613 + * <p> Some decoders maintain internal state and may need to write some
174.614 + * final characters to the output buffer once the overall input sequence has
174.615 + * been read.
174.616 + *
174.617 + * <p> Any additional output is written to the output buffer beginning at
174.618 + * its current position. At most {@link Buffer#remaining out.remaining()}
174.619 + * characters will be written. The buffer's position will be advanced
174.620 + * appropriately, but its mark and limit will not be modified.
174.621 + *
174.622 + * <p> If this method completes successfully then it returns {@link
174.623 + * CoderResult#UNDERFLOW}. If there is insufficient room in the output
174.624 + * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens
174.625 + * then this method must be invoked again, with an output buffer that has
174.626 + * more room, in order to complete the current <a href="#steps">decoding
174.627 + * operation</a>.
174.628 + *
174.629 + * <p> If this decoder has already been flushed then invoking this method
174.630 + * has no effect.
174.631 + *
174.632 + * <p> This method invokes the {@link #implFlush implFlush} method to
174.633 + * perform the actual flushing operation. </p>
174.634 + *
174.635 + * @param out
174.636 + * The output character buffer
174.637 + *
174.638 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
174.639 + * {@link CoderResult#OVERFLOW}
174.640 + *
174.641 + * @throws IllegalStateException
174.642 + * If the previous step of the current decoding operation was an
174.643 + * invocation neither of the {@link #flush flush} method nor of
174.644 + * the three-argument {@link
174.645 + * #decode(ByteBuffer,CharBuffer,boolean) decode} method
174.646 + * with a value of <tt>true</tt> for the <tt>endOfInput</tt>
174.647 + * parameter
174.648 + */
174.649 +// public final CoderResult flush(CharBuffer out) {
174.650 +// if (state == ST_END) {
174.651 +// CoderResult cr = implFlush(out);
174.652 +// if (cr.isUnderflow())
174.653 +// state = ST_FLUSHED;
174.654 +// return cr;
174.655 +// }
174.656 +//
174.657 +// if (state != ST_FLUSHED)
174.658 +// throwIllegalStateException(state, ST_FLUSHED);
174.659 +//
174.660 +// return CoderResult.UNDERFLOW; // Already flushed
174.661 +// }
174.662 +
174.663 + /**
174.664 + * Flushes this decoder.
174.665 + *
174.666 + * <p> The default implementation of this method does nothing, and always
174.667 + * returns {@link CoderResult#UNDERFLOW}. This method should be overridden
174.668 + * by decoders that may need to write final characters to the output buffer
174.669 + * once the entire input sequence has been read. </p>
174.670 + *
174.671 + * @param out
174.672 + * The output character buffer
174.673 + *
174.674 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
174.675 + * {@link CoderResult#OVERFLOW}
174.676 + */
174.677 +// protected CoderResult implFlush(CharBuffer out) {
174.678 +// return CoderResult.UNDERFLOW;
174.679 +// }
174.680 +
174.681 + /**
174.682 + * Resets this decoder, clearing any internal state.
174.683 + *
174.684 + * <p> This method resets charset-independent state and also invokes the
174.685 + * {@link #implReset() implReset} method in order to perform any
174.686 + * charset-specific reset actions. </p>
174.687 + *
174.688 + * @return This decoder
174.689 + *
174.690 + */
174.691 + public final CharsetDecoder reset() {
174.692 + implReset();
174.693 + state = ST_RESET;
174.694 + return this;
174.695 + }
174.696 +
174.697 + /**
174.698 + * Resets this decoder, clearing any charset-specific internal state.
174.699 + *
174.700 + * <p> The default implementation of this method does nothing. This method
174.701 + * should be overridden by decoders that maintain internal state. </p>
174.702 + */
174.703 + protected void implReset() { }
174.704 +
174.705 + /**
174.706 + * Decodes one or more bytes into one or more characters.
174.707 + *
174.708 + * <p> This method encapsulates the basic decoding loop, decoding as many
174.709 + * bytes as possible until it either runs out of input, runs out of room
174.710 + * in the output buffer, or encounters a decoding error. This method is
174.711 + * invoked by the {@link #decode decode} method, which handles result
174.712 + * interpretation and error recovery.
174.713 + *
174.714 + * <p> The buffers are read from, and written to, starting at their current
174.715 + * positions. At most {@link Buffer#remaining in.remaining()} bytes
174.716 + * will be read, and at most {@link Buffer#remaining out.remaining()}
174.717 + * characters will be written. The buffers' positions will be advanced to
174.718 + * reflect the bytes read and the characters written, but their marks and
174.719 + * limits will not be modified.
174.720 + *
174.721 + * <p> This method returns a {@link CoderResult} object to describe its
174.722 + * reason for termination, in the same manner as the {@link #decode decode}
174.723 + * method. Most implementations of this method will handle decoding errors
174.724 + * by returning an appropriate result object for interpretation by the
174.725 + * {@link #decode decode} method. An optimized implementation may instead
174.726 + * examine the relevant error action and implement that action itself.
174.727 + *
174.728 + * <p> An implementation of this method may perform arbitrary lookahead by
174.729 + * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
174.730 + * input. </p>
174.731 + *
174.732 + * @param in
174.733 + * The input byte buffer
174.734 + *
174.735 + * @param out
174.736 + * The output character buffer
174.737 + *
174.738 + * @return A coder-result object describing the reason for termination
174.739 + */
174.740 +// protected abstract CoderResult decodeLoop(ByteBuffer in,
174.741 +// CharBuffer out);
174.742 +
174.743 + /**
174.744 + * Convenience method that decodes the remaining content of a single input
174.745 + * byte buffer into a newly-allocated character buffer.
174.746 + *
174.747 + * <p> This method implements an entire <a href="#steps">decoding
174.748 + * operation</a>; that is, it resets this decoder, then it decodes the
174.749 + * bytes in the given byte buffer, and finally it flushes this
174.750 + * decoder. This method should therefore not be invoked if a decoding
174.751 + * operation is already in progress. </p>
174.752 + *
174.753 + * @param in
174.754 + * The input byte buffer
174.755 + *
174.756 + * @return A newly-allocated character buffer containing the result of the
174.757 + * decoding operation. The buffer's position will be zero and its
174.758 + * limit will follow the last character written.
174.759 + *
174.760 + * @throws IllegalStateException
174.761 + * If a decoding operation is already in progress
174.762 + *
174.763 + * @throws MalformedInputException
174.764 + * If the byte sequence starting at the input buffer's current
174.765 + * position is not legal for this charset and the current malformed-input action
174.766 + * is {@link CodingErrorAction#REPORT}
174.767 + *
174.768 + * @throws UnmappableCharacterException
174.769 + * If the byte sequence starting at the input buffer's current
174.770 + * position cannot be mapped to an equivalent character sequence and
174.771 + * the current unmappable-character action is {@link
174.772 + * CodingErrorAction#REPORT}
174.773 + */
174.774 +// public final CharBuffer decode(ByteBuffer in)
174.775 +// throws CharacterCodingException
174.776 +// {
174.777 +// int n = (int)(in.remaining() * averageCharsPerByte());
174.778 +// CharBuffer out = CharBuffer.allocate(n);
174.779 +//
174.780 +// if ((n == 0) && (in.remaining() == 0))
174.781 +// return out;
174.782 +// reset();
174.783 +// for (;;) {
174.784 +// CoderResult cr = in.hasRemaining() ?
174.785 +// decode(in, out, true) : CoderResult.UNDERFLOW;
174.786 +// if (cr.isUnderflow())
174.787 +// cr = flush(out);
174.788 +//
174.789 +// if (cr.isUnderflow())
174.790 +// break;
174.791 +// if (cr.isOverflow()) {
174.792 +// n = 2*n + 1; // Ensure progress; n might be 0!
174.793 +// CharBuffer o = CharBuffer.allocate(n);
174.794 +// out.flip();
174.795 +// o.put(out);
174.796 +// out = o;
174.797 +// continue;
174.798 +// }
174.799 +// cr.throwException();
174.800 +// }
174.801 +// out.flip();
174.802 +// return out;
174.803 +// }
174.804 +
174.805 +
174.806 +
174.807 + /**
174.808 + * Tells whether or not this decoder implements an auto-detecting charset.
174.809 + *
174.810 + * <p> The default implementation of this method always returns
174.811 + * <tt>false</tt>; it should be overridden by auto-detecting decoders to
174.812 + * return <tt>true</tt>. </p>
174.813 + *
174.814 + * @return <tt>true</tt> if, and only if, this decoder implements an
174.815 + * auto-detecting charset
174.816 + */
174.817 + public boolean isAutoDetecting() {
174.818 + return false;
174.819 + }
174.820 +
174.821 + /**
174.822 + * Tells whether or not this decoder has yet detected a
174.823 + * charset <i>(optional operation)</i>.
174.824 + *
174.825 + * <p> If this decoder implements an auto-detecting charset then at a
174.826 + * single point during a decoding operation this method may start returning
174.827 + * <tt>true</tt> to indicate that a specific charset has been detected in
174.828 + * the input byte sequence. Once this occurs, the {@link #detectedCharset
174.829 + * detectedCharset} method may be invoked to retrieve the detected charset.
174.830 + *
174.831 + * <p> That this method returns <tt>false</tt> does not imply that no bytes
174.832 + * have yet been decoded. Some auto-detecting decoders are capable of
174.833 + * decoding some, or even all, of an input byte sequence without fixing on
174.834 + * a particular charset.
174.835 + *
174.836 + * <p> The default implementation of this method always throws an {@link
174.837 + * UnsupportedOperationException}; it should be overridden by
174.838 + * auto-detecting decoders to return <tt>true</tt> once the input charset
174.839 + * has been determined. </p>
174.840 + *
174.841 + * @return <tt>true</tt> if, and only if, this decoder has detected a
174.842 + * specific charset
174.843 + *
174.844 + * @throws UnsupportedOperationException
174.845 + * If this decoder does not implement an auto-detecting charset
174.846 + */
174.847 + public boolean isCharsetDetected() {
174.848 + throw new UnsupportedOperationException();
174.849 + }
174.850 +
174.851 + /**
174.852 + * Retrieves the charset that was detected by this
174.853 + * decoder <i>(optional operation)</i>.
174.854 + *
174.855 + * <p> If this decoder implements an auto-detecting charset then this
174.856 + * method returns the actual charset once it has been detected. After that
174.857 + * point, this method returns the same value for the duration of the
174.858 + * current decoding operation. If not enough input bytes have yet been
174.859 + * read to determine the actual charset then this method throws an {@link
174.860 + * IllegalStateException}.
174.861 + *
174.862 + * <p> The default implementation of this method always throws an {@link
174.863 + * UnsupportedOperationException}; it should be overridden by
174.864 + * auto-detecting decoders to return the appropriate value. </p>
174.865 + *
174.866 + * @return The charset detected by this auto-detecting decoder,
174.867 + * or <tt>null</tt> if the charset has not yet been determined
174.868 + *
174.869 + * @throws IllegalStateException
174.870 + * If insufficient bytes have been read to determine a charset
174.871 + *
174.872 + * @throws UnsupportedOperationException
174.873 + * If this decoder does not implement an auto-detecting charset
174.874 + */
174.875 + public Charset detectedCharset() {
174.876 + throw new UnsupportedOperationException();
174.877 + }
174.878 +
174.879 +
174.880 +
174.881 +
174.882 +
174.883 +
174.884 +
174.885 +
174.886 +
174.887 +
174.888 +
174.889 +
174.890 +
174.891 +
174.892 +
174.893 +
174.894 +
174.895 +
174.896 +
174.897 +
174.898 +
174.899 +
174.900 +
174.901 +
174.902 +
174.903 +
174.904 +
174.905 +
174.906 +
174.907 +
174.908 +
174.909 +
174.910 +
174.911 +
174.912 +
174.913 +
174.914 +
174.915 +
174.916 +
174.917 +
174.918 +
174.919 +
174.920 +
174.921 +
174.922 +
174.923 +
174.924 +
174.925 +
174.926 +
174.927 +
174.928 +
174.929 +
174.930 +
174.931 +
174.932 +
174.933 +
174.934 +
174.935 +
174.936 +
174.937 +
174.938 +
174.939 +
174.940 +
174.941 +
174.942 +
174.943 +
174.944 +
174.945 +
174.946 +
174.947 +
174.948 +
174.949 +
174.950 +
174.951 +
174.952 +
174.953 +
174.954 +
174.955 +
174.956 +
174.957 +
174.958 +
174.959 +
174.960 +
174.961 +
174.962 +
174.963 +
174.964 +
174.965 +
174.966 +
174.967 +
174.968 + private void throwIllegalStateException(int from, int to) {
174.969 + throw new IllegalStateException("Current state = " + stateNames[from]
174.970 + + ", new state = " + stateNames[to]);
174.971 + }
174.972 +
174.973 +}
175.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
175.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetEncoder.java Wed Apr 30 15:04:10 2014 +0200
175.3 @@ -0,0 +1,970 @@
175.4 +/*
175.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
175.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
175.7 + *
175.8 + * This code is free software; you can redistribute it and/or modify it
175.9 + * under the terms of the GNU General Public License version 2 only, as
175.10 + * published by the Free Software Foundation. Oracle designates this
175.11 + * particular file as subject to the "Classpath" exception as provided
175.12 + * by Oracle in the LICENSE file that accompanied this code.
175.13 + *
175.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
175.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
175.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
175.17 + * version 2 for more details (a copy is included in the LICENSE file that
175.18 + * accompanied this code).
175.19 + *
175.20 + * You should have received a copy of the GNU General Public License version
175.21 + * 2 along with this work; if not, write to the Free Software Foundation,
175.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
175.23 + *
175.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
175.25 + * or visit www.oracle.com if you need additional information or have any
175.26 + * questions.
175.27 + */
175.28 +
175.29 +// -- This file was mechanically generated: Do not edit! -- //
175.30 +
175.31 +package java.nio.charset;
175.32 +
175.33 +//import java.nio.Buffer;
175.34 +//import java.nio.ByteBuffer;
175.35 +//import java.nio.CharBuffer;
175.36 +//import java.nio.BufferOverflowException;
175.37 +//import java.nio.BufferUnderflowException;
175.38 +import java.lang.ref.WeakReference;
175.39 +//import java.nio.charset.CoderMalfunctionError; // javadoc
175.40 +
175.41 +
175.42 +/**
175.43 + * An engine that can transform a sequence of sixteen-bit Unicode characters into a sequence of
175.44 + * bytes in a specific charset.
175.45 + *
175.46 + * <a name="steps">
175.47 + *
175.48 + * <p> The input character sequence is provided in a character buffer or a series
175.49 + * of such buffers. The output byte sequence is written to a byte buffer
175.50 + * or a series of such buffers. An encoder should always be used by making
175.51 + * the following sequence of method invocations, hereinafter referred to as an
175.52 + * <i>encoding operation</i>:
175.53 + *
175.54 + * <ol>
175.55 + *
175.56 + * <li><p> Reset the encoder via the {@link #reset reset} method, unless it
175.57 + * has not been used before; </p></li>
175.58 + *
175.59 + * <li><p> Invoke the {@link #encode encode} method zero or more times, as
175.60 + * long as additional input may be available, passing <tt>false</tt> for the
175.61 + * <tt>endOfInput</tt> argument and filling the input buffer and flushing the
175.62 + * output buffer between invocations; </p></li>
175.63 + *
175.64 + * <li><p> Invoke the {@link #encode encode} method one final time, passing
175.65 + * <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
175.66 + *
175.67 + * <li><p> Invoke the {@link #flush flush} method so that the encoder can
175.68 + * flush any internal state to the output buffer. </p></li>
175.69 + *
175.70 + * </ol>
175.71 + *
175.72 + * Each invocation of the {@link #encode encode} method will encode as many
175.73 + * characters as possible from the input buffer, writing the resulting bytes
175.74 + * to the output buffer. The {@link #encode encode} method returns when more
175.75 + * input is required, when there is not enough room in the output buffer, or
175.76 + * when an encoding error has occurred. In each case a {@link CoderResult}
175.77 + * object is returned to describe the reason for termination. An invoker can
175.78 + * examine this object and fill the input buffer, flush the output buffer, or
175.79 + * attempt to recover from an encoding error, as appropriate, and try again.
175.80 + *
175.81 + * <a name="ce">
175.82 + *
175.83 + * <p> There are two general types of encoding errors. If the input character
175.84 + * sequence is not a legal sixteen-bit Unicode sequence then the input is considered <i>malformed</i>. If
175.85 + * the input character sequence is legal but cannot be mapped to a valid
175.86 + * byte sequence in the given charset then an <i>unmappable character</i> has been encountered.
175.87 + *
175.88 + * <a name="cae">
175.89 + *
175.90 + * <p> How an encoding error is handled depends upon the action requested for
175.91 + * that type of error, which is described by an instance of the {@link
175.92 + * CodingErrorAction} class. The possible error actions are to {@link
175.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
175.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
175.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
175.96 + * </code>replace<code>} the erroneous input with the current value of the
175.97 + * replacement byte array. The replacement
175.98 + *
175.99 +
175.100 + * is initially set to the encoder's default replacement, which often
175.101 + * (but not always) has the initial value <tt>{</tt> <tt>(byte)'?'</tt> <tt>}</tt>;
175.102 +
175.103 +
175.104 +
175.105 +
175.106 + *
175.107 + * its value may be changed via the {@link #replaceWith(byte[])
175.108 + * replaceWith} method.
175.109 + *
175.110 + * <p> The default action for malformed-input and unmappable-character errors
175.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them. The
175.112 + * malformed-input error action may be changed via the {@link
175.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
175.114 + * unmappable-character action may be changed via the {@link
175.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
175.116 + *
175.117 + * <p> This class is designed to handle many of the details of the encoding
175.118 + * process, including the implementation of error actions. An encoder for a
175.119 + * specific charset, which is a concrete subclass of this class, need only
175.120 + * implement the abstract {@link #encodeLoop encodeLoop} method, which
175.121 + * encapsulates the basic encoding loop. A subclass that maintains internal
175.122 + * state should, additionally, override the {@link #implFlush implFlush} and
175.123 + * {@link #implReset implReset} methods.
175.124 + *
175.125 + * <p> Instances of this class are not safe for use by multiple concurrent
175.126 + * threads. </p>
175.127 + *
175.128 + *
175.129 + * @author Mark Reinhold
175.130 + * @author JSR-51 Expert Group
175.131 + * @since 1.4
175.132 + *
175.133 + * @see ByteBuffer
175.134 + * @see CharBuffer
175.135 + * @see Charset
175.136 + * @see CharsetDecoder
175.137 + */
175.138 +
175.139 +public abstract class CharsetEncoder {
175.140 +
175.141 + private final Charset charset;
175.142 + private final float averageBytesPerChar;
175.143 + private final float maxBytesPerChar;
175.144 +
175.145 + private byte[] replacement;
175.146 +// private CodingErrorAction malformedInputAction
175.147 +// = CodingErrorAction.REPORT;
175.148 +// private CodingErrorAction unmappableCharacterAction
175.149 +// = CodingErrorAction.REPORT;
175.150 +
175.151 + // Internal states
175.152 + //
175.153 + private static final int ST_RESET = 0;
175.154 + private static final int ST_CODING = 1;
175.155 + private static final int ST_END = 2;
175.156 + private static final int ST_FLUSHED = 3;
175.157 +
175.158 + private int state = ST_RESET;
175.159 +
175.160 + private static String stateNames[]
175.161 + = { "RESET", "CODING", "CODING_END", "FLUSHED" };
175.162 +
175.163 +
175.164 + /**
175.165 + * Initializes a new encoder. The new encoder will have the given
175.166 + * bytes-per-char and replacement values. </p>
175.167 + *
175.168 + * @param averageBytesPerChar
175.169 + * A positive float value indicating the expected number of
175.170 + * bytes that will be produced for each input character
175.171 + *
175.172 + * @param maxBytesPerChar
175.173 + * A positive float value indicating the maximum number of
175.174 + * bytes that will be produced for each input character
175.175 + *
175.176 + * @param replacement
175.177 + * The initial replacement; must not be <tt>null</tt>, must have
175.178 + * non-zero length, must not be longer than maxBytesPerChar,
175.179 + * and must be {@link #isLegalReplacement </code>legal<code>}
175.180 + *
175.181 + * @throws IllegalArgumentException
175.182 + * If the preconditions on the parameters do not hold
175.183 + */
175.184 + protected
175.185 + CharsetEncoder(Charset cs,
175.186 + float averageBytesPerChar,
175.187 + float maxBytesPerChar,
175.188 + byte[] replacement)
175.189 + {
175.190 + this.charset = cs;
175.191 + if (averageBytesPerChar <= 0.0f)
175.192 + throw new IllegalArgumentException("Non-positive "
175.193 + + "averageBytesPerChar");
175.194 + if (maxBytesPerChar <= 0.0f)
175.195 + throw new IllegalArgumentException("Non-positive "
175.196 + + "maxBytesPerChar");
175.197 + if (averageBytesPerChar > maxBytesPerChar)
175.198 + throw new IllegalArgumentException("averageBytesPerChar"
175.199 + + " exceeds "
175.200 + + "maxBytesPerChar");
175.201 + this.replacement = replacement;
175.202 + this.averageBytesPerChar = averageBytesPerChar;
175.203 + this.maxBytesPerChar = maxBytesPerChar;
175.204 + replaceWith(replacement);
175.205 + }
175.206 +
175.207 + /**
175.208 + * Initializes a new encoder. The new encoder will have the given
175.209 + * bytes-per-char values and its replacement will be the
175.210 + * byte array <tt>{</tt> <tt>(byte)'?'</tt> <tt>}</tt>. </p>
175.211 + *
175.212 + * @param averageBytesPerChar
175.213 + * A positive float value indicating the expected number of
175.214 + * bytes that will be produced for each input character
175.215 + *
175.216 + * @param maxBytesPerChar
175.217 + * A positive float value indicating the maximum number of
175.218 + * bytes that will be produced for each input character
175.219 + *
175.220 + * @throws IllegalArgumentException
175.221 + * If the preconditions on the parameters do not hold
175.222 + */
175.223 + protected CharsetEncoder(Charset cs,
175.224 + float averageBytesPerChar,
175.225 + float maxBytesPerChar)
175.226 + {
175.227 + this(cs,
175.228 + averageBytesPerChar, maxBytesPerChar,
175.229 + new byte[] { (byte)'?' });
175.230 + }
175.231 +
175.232 + /**
175.233 + * Returns the charset that created this encoder. </p>
175.234 + *
175.235 + * @return This encoder's charset
175.236 + */
175.237 + public final Charset charset() {
175.238 + return charset;
175.239 + }
175.240 +
175.241 + /**
175.242 + * Returns this encoder's replacement value. </p>
175.243 + *
175.244 + * @return This encoder's current replacement,
175.245 + * which is never <tt>null</tt> and is never empty
175.246 + */
175.247 + public final byte[] replacement() {
175.248 + return replacement;
175.249 + }
175.250 +
175.251 + /**
175.252 + * Changes this encoder's replacement value.
175.253 + *
175.254 + * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
175.255 + * method, passing the new replacement, after checking that the new
175.256 + * replacement is acceptable. </p>
175.257 + *
175.258 + * @param newReplacement
175.259 + *
175.260 +
175.261 +
175.262 +
175.263 +
175.264 +
175.265 + * The new replacement; must not be <tt>null</tt>, must have
175.266 + * non-zero length, must not be longer than the value returned by
175.267 + * the {@link #maxBytesPerChar() maxBytesPerChar} method, and
175.268 + * must be {@link #isLegalReplacement </code>legal<code>}
175.269 +
175.270 + *
175.271 + * @return This encoder
175.272 + *
175.273 + * @throws IllegalArgumentException
175.274 + * If the preconditions on the parameter do not hold
175.275 + */
175.276 + public final CharsetEncoder replaceWith(byte[] newReplacement) {
175.277 + if (newReplacement == null)
175.278 + throw new IllegalArgumentException("Null replacement");
175.279 + int len = newReplacement.length;
175.280 + if (len == 0)
175.281 + throw new IllegalArgumentException("Empty replacement");
175.282 + if (len > maxBytesPerChar)
175.283 + throw new IllegalArgumentException("Replacement too long");
175.284 +
175.285 +// if (!isLegalReplacement(newReplacement))
175.286 +// throw new IllegalArgumentException("Illegal replacement");
175.287 +
175.288 + this.replacement = newReplacement;
175.289 + implReplaceWith(newReplacement);
175.290 + return this;
175.291 + }
175.292 +
175.293 + /**
175.294 + * Reports a change to this encoder's replacement value.
175.295 + *
175.296 + * <p> The default implementation of this method does nothing. This method
175.297 + * should be overridden by encoders that require notification of changes to
175.298 + * the replacement. </p>
175.299 + *
175.300 + * @param newReplacement
175.301 + */
175.302 + protected void implReplaceWith(byte[] newReplacement) {
175.303 + }
175.304 +
175.305 +
175.306 +
175.307 + private WeakReference<CharsetDecoder> cachedDecoder = null;
175.308 +
175.309 + /**
175.310 + * Tells whether or not the given byte array is a legal replacement value
175.311 + * for this encoder.
175.312 + *
175.313 + * <p> A replacement is legal if, and only if, it is a legal sequence of
175.314 + * bytes in this encoder's charset; that is, it must be possible to decode
175.315 + * the replacement into one or more sixteen-bit Unicode characters.
175.316 + *
175.317 + * <p> The default implementation of this method is not very efficient; it
175.318 + * should generally be overridden to improve performance. </p>
175.319 + *
175.320 + * @param repl The byte array to be tested
175.321 + *
175.322 + * @return <tt>true</tt> if, and only if, the given byte array
175.323 + * is a legal replacement value for this encoder
175.324 + */
175.325 +// public boolean isLegalReplacement(byte[] repl) {
175.326 +// WeakReference<CharsetDecoder> wr = cachedDecoder;
175.327 +// CharsetDecoder dec = null;
175.328 +// if ((wr == null) || ((dec = wr.get()) == null)) {
175.329 +// dec = charset().newDecoder();
175.330 +// dec.onMalformedInput(CodingErrorAction.REPORT);
175.331 +// dec.onUnmappableCharacter(CodingErrorAction.REPORT);
175.332 +// cachedDecoder = new WeakReference<CharsetDecoder>(dec);
175.333 +// } else {
175.334 +// dec.reset();
175.335 +// }
175.336 +// ByteBuffer bb = ByteBuffer.wrap(repl);
175.337 +// CharBuffer cb = CharBuffer.allocate((int)(bb.remaining()
175.338 +// * dec.maxCharsPerByte()));
175.339 +// CoderResult cr = dec.decode(bb, cb, true);
175.340 +// return !cr.isError();
175.341 +// }
175.342 +
175.343 +
175.344 +
175.345 + /**
175.346 + * Returns this encoder's current action for malformed-input errors. </p>
175.347 + *
175.348 + * @return The current malformed-input action, which is never <tt>null</tt>
175.349 + */
175.350 +// public CodingErrorAction malformedInputAction() {
175.351 +// return malformedInputAction;
175.352 +// }
175.353 +
175.354 + /**
175.355 + * Changes this encoder's action for malformed-input errors. </p>
175.356 + *
175.357 + * <p> This method invokes the {@link #implOnMalformedInput
175.358 + * implOnMalformedInput} method, passing the new action. </p>
175.359 + *
175.360 + * @param newAction The new action; must not be <tt>null</tt>
175.361 + *
175.362 + * @return This encoder
175.363 + *
175.364 + * @throws IllegalArgumentException
175.365 + * If the precondition on the parameter does not hold
175.366 + */
175.367 +// public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
175.368 +// if (newAction == null)
175.369 +// throw new IllegalArgumentException("Null action");
175.370 +// malformedInputAction = newAction;
175.371 +// implOnMalformedInput(newAction);
175.372 +// return this;
175.373 +// }
175.374 +
175.375 + /**
175.376 + * Reports a change to this encoder's malformed-input action.
175.377 + *
175.378 + * <p> The default implementation of this method does nothing. This method
175.379 + * should be overridden by encoders that require notification of changes to
175.380 + * the malformed-input action. </p>
175.381 + */
175.382 +// protected void implOnMalformedInput(CodingErrorAction newAction) { }
175.383 +
175.384 + /**
175.385 + * Returns this encoder's current action for unmappable-character errors.
175.386 + * </p>
175.387 + *
175.388 + * @return The current unmappable-character action, which is never
175.389 + * <tt>null</tt>
175.390 + */
175.391 +// public CodingErrorAction unmappableCharacterAction() {
175.392 +// return unmappableCharacterAction;
175.393 +// }
175.394 +
175.395 + /**
175.396 + * Changes this encoder's action for unmappable-character errors.
175.397 + *
175.398 + * <p> This method invokes the {@link #implOnUnmappableCharacter
175.399 + * implOnUnmappableCharacter} method, passing the new action. </p>
175.400 + *
175.401 + * @param newAction The new action; must not be <tt>null</tt>
175.402 + *
175.403 + * @return This encoder
175.404 + *
175.405 + * @throws IllegalArgumentException
175.406 + * If the precondition on the parameter does not hold
175.407 + */
175.408 +// public final CharsetEncoder onUnmappableCharacter(CodingErrorAction
175.409 +// newAction)
175.410 +// {
175.411 +// if (newAction == null)
175.412 +// throw new IllegalArgumentException("Null action");
175.413 +// unmappableCharacterAction = newAction;
175.414 +// implOnUnmappableCharacter(newAction);
175.415 +// return this;
175.416 +// }
175.417 +
175.418 + /**
175.419 + * Reports a change to this encoder's unmappable-character action.
175.420 + *
175.421 + * <p> The default implementation of this method does nothing. This method
175.422 + * should be overridden by encoders that require notification of changes to
175.423 + * the unmappable-character action. </p>
175.424 + */
175.425 +// protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
175.426 +
175.427 + /**
175.428 + * Returns the average number of bytes that will be produced for each
175.429 + * character of input. This heuristic value may be used to estimate the size
175.430 + * of the output buffer required for a given input sequence. </p>
175.431 + *
175.432 + * @return The average number of bytes produced
175.433 + * per character of input
175.434 + */
175.435 + public final float averageBytesPerChar() {
175.436 + return averageBytesPerChar;
175.437 + }
175.438 +
175.439 + /**
175.440 + * Returns the maximum number of bytes that will be produced for each
175.441 + * character of input. This value may be used to compute the worst-case size
175.442 + * of the output buffer required for a given input sequence. </p>
175.443 + *
175.444 + * @return The maximum number of bytes that will be produced per
175.445 + * character of input
175.446 + */
175.447 + public final float maxBytesPerChar() {
175.448 + return maxBytesPerChar;
175.449 + }
175.450 +
175.451 + /**
175.452 + * Encodes as many characters as possible from the given input buffer,
175.453 + * writing the results to the given output buffer.
175.454 + *
175.455 + * <p> The buffers are read from, and written to, starting at their current
175.456 + * positions. At most {@link Buffer#remaining in.remaining()} characters
175.457 + * will be read and at most {@link Buffer#remaining out.remaining()}
175.458 + * bytes will be written. The buffers' positions will be advanced to
175.459 + * reflect the characters read and the bytes written, but their marks and
175.460 + * limits will not be modified.
175.461 + *
175.462 + * <p> In addition to reading characters from the input buffer and writing
175.463 + * bytes to the output buffer, this method returns a {@link CoderResult}
175.464 + * object to describe its reason for termination:
175.465 + *
175.466 + * <ul>
175.467 + *
175.468 + * <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
175.469 + * input buffer as possible has been encoded. If there is no further
175.470 + * input then the invoker can proceed to the next step of the
175.471 + * <a href="#steps">encoding operation</a>. Otherwise this method
175.472 + * should be invoked again with further input. </p></li>
175.473 + *
175.474 + * <li><p> {@link CoderResult#OVERFLOW} indicates that there is
175.475 + * insufficient space in the output buffer to encode any more characters.
175.476 + * This method should be invoked again with an output buffer that has
175.477 + * more {@linkplain Buffer#remaining remaining} bytes. This is
175.478 + * typically done by draining any encoded bytes from the output
175.479 + * buffer. </p></li>
175.480 + *
175.481 + * <li><p> A {@link CoderResult#malformedForLength
175.482 + * </code>malformed-input<code>} result indicates that a malformed-input
175.483 + * error has been detected. The malformed characters begin at the input
175.484 + * buffer's (possibly incremented) position; the number of malformed
175.485 + * characters may be determined by invoking the result object's {@link
175.486 + * CoderResult#length() length} method. This case applies only if the
175.487 + * {@link #onMalformedInput </code>malformed action<code>} of this encoder
175.488 + * is {@link CodingErrorAction#REPORT}; otherwise the malformed input
175.489 + * will be ignored or replaced, as requested. </p></li>
175.490 + *
175.491 + * <li><p> An {@link CoderResult#unmappableForLength
175.492 + * </code>unmappable-character<code>} result indicates that an
175.493 + * unmappable-character error has been detected. The characters that
175.494 + * encode the unmappable character begin at the input buffer's (possibly
175.495 + * incremented) position; the number of such characters may be determined
175.496 + * by invoking the result object's {@link CoderResult#length() length}
175.497 + * method. This case applies only if the {@link #onUnmappableCharacter
175.498 + * </code>unmappable action<code>} of this encoder is {@link
175.499 + * CodingErrorAction#REPORT}; otherwise the unmappable character will be
175.500 + * ignored or replaced, as requested. </p></li>
175.501 + *
175.502 + * </ul>
175.503 + *
175.504 + * In any case, if this method is to be reinvoked in the same encoding
175.505 + * operation then care should be taken to preserve any characters remaining
175.506 + * in the input buffer so that they are available to the next invocation.
175.507 + *
175.508 + * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
175.509 + * the invoker can provide further input beyond that contained in the given
175.510 + * input buffer. If there is a possibility of providing additional input
175.511 + * then the invoker should pass <tt>false</tt> for this parameter; if there
175.512 + * is no possibility of providing further input then the invoker should
175.513 + * pass <tt>true</tt>. It is not erroneous, and in fact it is quite
175.514 + * common, to pass <tt>false</tt> in one invocation and later discover that
175.515 + * no further input was actually available. It is critical, however, that
175.516 + * the final invocation of this method in a sequence of invocations always
175.517 + * pass <tt>true</tt> so that any remaining unencoded input will be treated
175.518 + * as being malformed.
175.519 + *
175.520 + * <p> This method works by invoking the {@link #encodeLoop encodeLoop}
175.521 + * method, interpreting its results, handling error conditions, and
175.522 + * reinvoking it as necessary. </p>
175.523 + *
175.524 + *
175.525 + * @param in
175.526 + * The input character buffer
175.527 + *
175.528 + * @param out
175.529 + * The output byte buffer
175.530 + *
175.531 + * @param endOfInput
175.532 + * <tt>true</tt> if, and only if, the invoker can provide no
175.533 + * additional input characters beyond those in the given buffer
175.534 + *
175.535 + * @return A coder-result object describing the reason for termination
175.536 + *
175.537 + * @throws IllegalStateException
175.538 + * If an encoding operation is already in progress and the previous
175.539 + * step was an invocation neither of the {@link #reset reset}
175.540 + * method, nor of this method with a value of <tt>false</tt> for
175.541 + * the <tt>endOfInput</tt> parameter, nor of this method with a
175.542 + * value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
175.543 + * but a return value indicating an incomplete encoding operation
175.544 + *
175.545 + * @throws CoderMalfunctionError
175.546 + * If an invocation of the encodeLoop method threw
175.547 + * an unexpected exception
175.548 + */
175.549 +// public final CoderResult encode(CharBuffer in, ByteBuffer out,
175.550 +// boolean endOfInput)
175.551 +// {
175.552 +// int newState = endOfInput ? ST_END : ST_CODING;
175.553 +// if ((state != ST_RESET) && (state != ST_CODING)
175.554 +// && !(endOfInput && (state == ST_END)))
175.555 +// throwIllegalStateException(state, newState);
175.556 +// state = newState;
175.557 +//
175.558 +// for (;;) {
175.559 +//
175.560 +// CoderResult cr;
175.561 +// try {
175.562 +// cr = encodeLoop(in, out);
175.563 +// } catch (BufferUnderflowException x) {
175.564 +// throw new CoderMalfunctionError(x);
175.565 +// } catch (BufferOverflowException x) {
175.566 +// throw new CoderMalfunctionError(x);
175.567 +// }
175.568 +//
175.569 +// if (cr.isOverflow())
175.570 +// return cr;
175.571 +//
175.572 +// if (cr.isUnderflow()) {
175.573 +// if (endOfInput && in.hasRemaining()) {
175.574 +// cr = CoderResult.malformedForLength(in.remaining());
175.575 +// // Fall through to malformed-input case
175.576 +// } else {
175.577 +// return cr;
175.578 +// }
175.579 +// }
175.580 +//
175.581 +// CodingErrorAction action = null;
175.582 +// if (cr.isMalformed())
175.583 +// action = malformedInputAction;
175.584 +// else if (cr.isUnmappable())
175.585 +// action = unmappableCharacterAction;
175.586 +// else
175.587 +// assert false : cr.toString();
175.588 +//
175.589 +// if (action == CodingErrorAction.REPORT)
175.590 +// return cr;
175.591 +//
175.592 +// if (action == CodingErrorAction.REPLACE) {
175.593 +// if (out.remaining() < replacement.length)
175.594 +// return CoderResult.OVERFLOW;
175.595 +// out.put(replacement);
175.596 +// }
175.597 +//
175.598 +// if ((action == CodingErrorAction.IGNORE)
175.599 +// || (action == CodingErrorAction.REPLACE)) {
175.600 +// // Skip erroneous input either way
175.601 +// in.position(in.position() + cr.length());
175.602 +// continue;
175.603 +// }
175.604 +//
175.605 +// assert false;
175.606 +// }
175.607 +//
175.608 +// }
175.609 +
175.610 + /**
175.611 + * Flushes this encoder.
175.612 + *
175.613 + * <p> Some encoders maintain internal state and may need to write some
175.614 + * final bytes to the output buffer once the overall input sequence has
175.615 + * been read.
175.616 + *
175.617 + * <p> Any additional output is written to the output buffer beginning at
175.618 + * its current position. At most {@link Buffer#remaining out.remaining()}
175.619 + * bytes will be written. The buffer's position will be advanced
175.620 + * appropriately, but its mark and limit will not be modified.
175.621 + *
175.622 + * <p> If this method completes successfully then it returns {@link
175.623 + * CoderResult#UNDERFLOW}. If there is insufficient room in the output
175.624 + * buffer then it returns {@link CoderResult#OVERFLOW}. If this happens
175.625 + * then this method must be invoked again, with an output buffer that has
175.626 + * more room, in order to complete the current <a href="#steps">encoding
175.627 + * operation</a>.
175.628 + *
175.629 + * <p> If this encoder has already been flushed then invoking this method
175.630 + * has no effect.
175.631 + *
175.632 + * <p> This method invokes the {@link #implFlush implFlush} method to
175.633 + * perform the actual flushing operation. </p>
175.634 + *
175.635 + * @param out
175.636 + * The output byte buffer
175.637 + *
175.638 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
175.639 + * {@link CoderResult#OVERFLOW}
175.640 + *
175.641 + * @throws IllegalStateException
175.642 + * If the previous step of the current encoding operation was an
175.643 + * invocation neither of the {@link #flush flush} method nor of
175.644 + * the three-argument {@link
175.645 + * #encode(CharBuffer,ByteBuffer,boolean) encode} method
175.646 + * with a value of <tt>true</tt> for the <tt>endOfInput</tt>
175.647 + * parameter
175.648 + */
175.649 +// public final CoderResult flush(ByteBuffer out) {
175.650 +// if (state == ST_END) {
175.651 +// CoderResult cr = implFlush(out);
175.652 +// if (cr.isUnderflow())
175.653 +// state = ST_FLUSHED;
175.654 +// return cr;
175.655 +// }
175.656 +//
175.657 +// if (state != ST_FLUSHED)
175.658 +// throwIllegalStateException(state, ST_FLUSHED);
175.659 +//
175.660 +// return CoderResult.UNDERFLOW; // Already flushed
175.661 +// }
175.662 +
175.663 + /**
175.664 + * Flushes this encoder.
175.665 + *
175.666 + * <p> The default implementation of this method does nothing, and always
175.667 + * returns {@link CoderResult#UNDERFLOW}. This method should be overridden
175.668 + * by encoders that may need to write final bytes to the output buffer
175.669 + * once the entire input sequence has been read. </p>
175.670 + *
175.671 + * @param out
175.672 + * The output byte buffer
175.673 + *
175.674 + * @return A coder-result object, either {@link CoderResult#UNDERFLOW} or
175.675 + * {@link CoderResult#OVERFLOW}
175.676 + */
175.677 +// protected CoderResult implFlush(ByteBuffer out) {
175.678 +// return CoderResult.UNDERFLOW;
175.679 +// }
175.680 +
175.681 + /**
175.682 + * Resets this encoder, clearing any internal state.
175.683 + *
175.684 + * <p> This method resets charset-independent state and also invokes the
175.685 + * {@link #implReset() implReset} method in order to perform any
175.686 + * charset-specific reset actions. </p>
175.687 + *
175.688 + * @return This encoder
175.689 + *
175.690 + */
175.691 + public final CharsetEncoder reset() {
175.692 + implReset();
175.693 + state = ST_RESET;
175.694 + return this;
175.695 + }
175.696 +
175.697 + /**
175.698 + * Resets this encoder, clearing any charset-specific internal state.
175.699 + *
175.700 + * <p> The default implementation of this method does nothing. This method
175.701 + * should be overridden by encoders that maintain internal state. </p>
175.702 + */
175.703 + protected void implReset() { }
175.704 +
175.705 + /**
175.706 + * Encodes one or more characters into one or more bytes.
175.707 + *
175.708 + * <p> This method encapsulates the basic encoding loop, encoding as many
175.709 + * characters as possible until it either runs out of input, runs out of room
175.710 + * in the output buffer, or encounters an encoding error. This method is
175.711 + * invoked by the {@link #encode encode} method, which handles result
175.712 + * interpretation and error recovery.
175.713 + *
175.714 + * <p> The buffers are read from, and written to, starting at their current
175.715 + * positions. At most {@link Buffer#remaining in.remaining()} characters
175.716 + * will be read, and at most {@link Buffer#remaining out.remaining()}
175.717 + * bytes will be written. The buffers' positions will be advanced to
175.718 + * reflect the characters read and the bytes written, but their marks and
175.719 + * limits will not be modified.
175.720 + *
175.721 + * <p> This method returns a {@link CoderResult} object to describe its
175.722 + * reason for termination, in the same manner as the {@link #encode encode}
175.723 + * method. Most implementations of this method will handle encoding errors
175.724 + * by returning an appropriate result object for interpretation by the
175.725 + * {@link #encode encode} method. An optimized implementation may instead
175.726 + * examine the relevant error action and implement that action itself.
175.727 + *
175.728 + * <p> An implementation of this method may perform arbitrary lookahead by
175.729 + * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
175.730 + * input. </p>
175.731 + *
175.732 + * @param in
175.733 + * The input character buffer
175.734 + *
175.735 + * @param out
175.736 + * The output byte buffer
175.737 + *
175.738 + * @return A coder-result object describing the reason for termination
175.739 + */
175.740 +// protected abstract CoderResult encodeLoop(CharBuffer in,
175.741 +// ByteBuffer out);
175.742 +
175.743 + /**
175.744 + * Convenience method that encodes the remaining content of a single input
175.745 + * character buffer into a newly-allocated byte buffer.
175.746 + *
175.747 + * <p> This method implements an entire <a href="#steps">encoding
175.748 + * operation</a>; that is, it resets this encoder, then it encodes the
175.749 + * characters in the given character buffer, and finally it flushes this
175.750 + * encoder. This method should therefore not be invoked if an encoding
175.751 + * operation is already in progress. </p>
175.752 + *
175.753 + * @param in
175.754 + * The input character buffer
175.755 + *
175.756 + * @return A newly-allocated byte buffer containing the result of the
175.757 + * encoding operation. The buffer's position will be zero and its
175.758 + * limit will follow the last byte written.
175.759 + *
175.760 + * @throws IllegalStateException
175.761 + * If an encoding operation is already in progress
175.762 + *
175.763 + * @throws MalformedInputException
175.764 + * If the character sequence starting at the input buffer's current
175.765 + * position is not a legal sixteen-bit Unicode sequence and the current malformed-input action
175.766 + * is {@link CodingErrorAction#REPORT}
175.767 + *
175.768 + * @throws UnmappableCharacterException
175.769 + * If the character sequence starting at the input buffer's current
175.770 + * position cannot be mapped to an equivalent byte sequence and
175.771 + * the current unmappable-character action is {@link
175.772 + * CodingErrorAction#REPORT}
175.773 + */
175.774 +// public final ByteBuffer encode(CharBuffer in)
175.775 +// throws CharacterCodingException
175.776 +// {
175.777 +// int n = (int)(in.remaining() * averageBytesPerChar());
175.778 +// ByteBuffer out = ByteBuffer.allocate(n);
175.779 +//
175.780 +// if ((n == 0) && (in.remaining() == 0))
175.781 +// return out;
175.782 +// reset();
175.783 +// for (;;) {
175.784 +// CoderResult cr = in.hasRemaining() ?
175.785 +// encode(in, out, true) : CoderResult.UNDERFLOW;
175.786 +// if (cr.isUnderflow())
175.787 +// cr = flush(out);
175.788 +//
175.789 +// if (cr.isUnderflow())
175.790 +// break;
175.791 +// if (cr.isOverflow()) {
175.792 +// n = 2*n + 1; // Ensure progress; n might be 0!
175.793 +// ByteBuffer o = ByteBuffer.allocate(n);
175.794 +// out.flip();
175.795 +// o.put(out);
175.796 +// out = o;
175.797 +// continue;
175.798 +// }
175.799 +// cr.throwException();
175.800 +// }
175.801 +// out.flip();
175.802 +// return out;
175.803 +// }
175.804 +
175.805 +
175.806 +
175.807 +
175.808 +
175.809 +
175.810 +
175.811 +
175.812 +
175.813 +
175.814 +
175.815 +
175.816 +
175.817 +
175.818 +
175.819 +
175.820 +
175.821 +
175.822 +
175.823 +
175.824 +
175.825 +
175.826 +
175.827 +
175.828 +
175.829 +
175.830 +
175.831 +
175.832 +
175.833 +
175.834 +
175.835 +
175.836 +
175.837 +
175.838 +
175.839 +
175.840 +
175.841 +
175.842 +
175.843 +
175.844 +
175.845 +
175.846 +
175.847 +
175.848 +
175.849 +
175.850 +
175.851 +
175.852 +
175.853 +
175.854 +
175.855 +
175.856 +
175.857 +
175.858 +
175.859 +
175.860 +
175.861 +
175.862 +
175.863 +
175.864 +
175.865 +
175.866 +
175.867 +
175.868 +
175.869 +
175.870 +
175.871 +
175.872 +
175.873 +
175.874 +
175.875 +
175.876 +
175.877 +
175.878 +
175.879 +
175.880 +
175.881 +
175.882 +
175.883 +// private boolean canEncode(CharBuffer cb) {
175.884 +// if (state == ST_FLUSHED)
175.885 +// reset();
175.886 +// else if (state != ST_RESET)
175.887 +// throwIllegalStateException(state, ST_CODING);
175.888 +// CodingErrorAction ma = malformedInputAction();
175.889 +// CodingErrorAction ua = unmappableCharacterAction();
175.890 +// try {
175.891 +// onMalformedInput(CodingErrorAction.REPORT);
175.892 +// onUnmappableCharacter(CodingErrorAction.REPORT);
175.893 +// encode(cb);
175.894 +// } catch (CharacterCodingException x) {
175.895 +// return false;
175.896 +// } finally {
175.897 +// onMalformedInput(ma);
175.898 +// onUnmappableCharacter(ua);
175.899 +// reset();
175.900 +// }
175.901 +// return true;
175.902 +// }
175.903 +
175.904 + /**
175.905 + * Tells whether or not this encoder can encode the given character.
175.906 + *
175.907 + * <p> This method returns <tt>false</tt> if the given character is a
175.908 + * surrogate character; such characters can be interpreted only when they
175.909 + * are members of a pair consisting of a high surrogate followed by a low
175.910 + * surrogate. The {@link #canEncode(java.lang.CharSequence)
175.911 + * canEncode(CharSequence)} method may be used to test whether or not a
175.912 + * character sequence can be encoded.
175.913 + *
175.914 + * <p> This method may modify this encoder's state; it should therefore not
175.915 + * be invoked if an <a href="#steps">encoding operation</a> is already in
175.916 + * progress.
175.917 + *
175.918 + * <p> The default implementation of this method is not very efficient; it
175.919 + * should generally be overridden to improve performance. </p>
175.920 + *
175.921 + * @return <tt>true</tt> if, and only if, this encoder can encode
175.922 + * the given character
175.923 + *
175.924 + * @throws IllegalStateException
175.925 + * If an encoding operation is already in progress
175.926 + */
175.927 +// public boolean canEncode(char c) {
175.928 +// CharBuffer cb = CharBuffer.allocate(1);
175.929 +// cb.put(c);
175.930 +// cb.flip();
175.931 +// return canEncode(cb);
175.932 +// }
175.933 +
175.934 + /**
175.935 + * Tells whether or not this encoder can encode the given character
175.936 + * sequence.
175.937 + *
175.938 + * <p> If this method returns <tt>false</tt> for a particular character
175.939 + * sequence then more information about why the sequence cannot be encoded
175.940 + * may be obtained by performing a full <a href="#steps">encoding
175.941 + * operation</a>.
175.942 + *
175.943 + * <p> This method may modify this encoder's state; it should therefore not
175.944 + * be invoked if an encoding operation is already in progress.
175.945 + *
175.946 + * <p> The default implementation of this method is not very efficient; it
175.947 + * should generally be overridden to improve performance. </p>
175.948 + *
175.949 + * @return <tt>true</tt> if, and only if, this encoder can encode
175.950 + * the given character without throwing any exceptions and without
175.951 + * performing any replacements
175.952 + *
175.953 + * @throws IllegalStateException
175.954 + * If an encoding operation is already in progress
175.955 + */
175.956 +// public boolean canEncode(CharSequence cs) {
175.957 +// CharBuffer cb;
175.958 +// if (cs instanceof CharBuffer)
175.959 +// cb = ((CharBuffer)cs).duplicate();
175.960 +// else
175.961 +// cb = CharBuffer.wrap(cs.toString());
175.962 +// return canEncode(cb);
175.963 +// }
175.964 +
175.965 +
175.966 +
175.967 +
175.968 + private void throwIllegalStateException(int from, int to) {
175.969 + throw new IllegalStateException("Current state = " + stateNames[from]
175.970 + + ", new state = " + stateNames[to]);
175.971 + }
175.972 +
175.973 +}
176.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
176.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/IllegalCharsetNameException.java Wed Apr 30 15:04:10 2014 +0200
176.3 @@ -0,0 +1,68 @@
176.4 +/*
176.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
176.6 + *
176.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
176.8 + *
176.9 + *
176.10 + *
176.11 + *
176.12 + *
176.13 + *
176.14 + *
176.15 + *
176.16 + *
176.17 + *
176.18 + *
176.19 + *
176.20 + *
176.21 + *
176.22 + *
176.23 + *
176.24 + *
176.25 + *
176.26 + *
176.27 + *
176.28 + *
176.29 + */
176.30 +
176.31 +// -- This file was mechanically generated: Do not edit! -- //
176.32 +
176.33 +package java.nio.charset;
176.34 +
176.35 +
176.36 +/**
176.37 + * Unchecked exception thrown when a string that is not a
176.38 + * <a href=Charset.html#names>legal charset name</a> is used as such.
176.39 + *
176.40 + * @since 1.4
176.41 + */
176.42 +
176.43 +public class IllegalCharsetNameException
176.44 + extends IllegalArgumentException
176.45 +{
176.46 +
176.47 + private static final long serialVersionUID = 1457525358470002989L;
176.48 +
176.49 + private String charsetName;
176.50 +
176.51 + /**
176.52 + * Constructs an instance of this class. </p>
176.53 + *
176.54 + * @param charsetName
176.55 + * The illegal charset name
176.56 + */
176.57 + public IllegalCharsetNameException(String charsetName) {
176.58 + super(String.valueOf(charsetName));
176.59 + this.charsetName = charsetName;
176.60 + }
176.61 +
176.62 + /**
176.63 + * Retrieves the illegal charset name. </p>
176.64 + *
176.65 + * @return The illegal charset name
176.66 + */
176.67 + public String getCharsetName() {
176.68 + return charsetName;
176.69 + }
176.70 +
176.71 +}
177.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
177.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/UnsupportedCharsetException.java Wed Apr 30 15:04:10 2014 +0200
177.3 @@ -0,0 +1,68 @@
177.4 +/*
177.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
177.6 + *
177.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
177.8 + *
177.9 + *
177.10 + *
177.11 + *
177.12 + *
177.13 + *
177.14 + *
177.15 + *
177.16 + *
177.17 + *
177.18 + *
177.19 + *
177.20 + *
177.21 + *
177.22 + *
177.23 + *
177.24 + *
177.25 + *
177.26 + *
177.27 + *
177.28 + *
177.29 + */
177.30 +
177.31 +// -- This file was mechanically generated: Do not edit! -- //
177.32 +
177.33 +package java.nio.charset;
177.34 +
177.35 +
177.36 +/**
177.37 + * Unchecked exception thrown when no support is available
177.38 + * for a requested charset.
177.39 + *
177.40 + * @since 1.4
177.41 + */
177.42 +
177.43 +public class UnsupportedCharsetException
177.44 + extends IllegalArgumentException
177.45 +{
177.46 +
177.47 + private static final long serialVersionUID = 1490765524727386367L;
177.48 +
177.49 + private String charsetName;
177.50 +
177.51 + /**
177.52 + * Constructs an instance of this class. </p>
177.53 + *
177.54 + * @param charsetName
177.55 + * The name of the unsupported charset
177.56 + */
177.57 + public UnsupportedCharsetException(String charsetName) {
177.58 + super(String.valueOf(charsetName));
177.59 + this.charsetName = charsetName;
177.60 + }
177.61 +
177.62 + /**
177.63 + * Retrieves the name of the unsupported charset. </p>
177.64 + *
177.65 + * @return The name of the unsupported charset
177.66 + */
177.67 + public String getCharsetName() {
177.68 + return charsetName;
177.69 + }
177.70 +
177.71 +}
178.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
178.2 +++ b/rt/emul/compact/src/main/java/java/security/AccessController.java Wed Apr 30 15:04:10 2014 +0200
178.3 @@ -0,0 +1,504 @@
178.4 +/*
178.5 + * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
178.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
178.7 + *
178.8 + * This code is free software; you can redistribute it and/or modify it
178.9 + * under the terms of the GNU General Public License version 2 only, as
178.10 + * published by the Free Software Foundation. Oracle designates this
178.11 + * particular file as subject to the "Classpath" exception as provided
178.12 + * by Oracle in the LICENSE file that accompanied this code.
178.13 + *
178.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
178.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
178.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
178.17 + * version 2 for more details (a copy is included in the LICENSE file that
178.18 + * accompanied this code).
178.19 + *
178.20 + * You should have received a copy of the GNU General Public License version
178.21 + * 2 along with this work; if not, write to the Free Software Foundation,
178.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
178.23 + *
178.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
178.25 + * or visit www.oracle.com if you need additional information or have any
178.26 + * questions.
178.27 + */
178.28 +
178.29 +package java.security;
178.30 +
178.31 +/**
178.32 + * <p> The AccessController class is used for access control operations
178.33 + * and decisions.
178.34 + *
178.35 + * <p> More specifically, the AccessController class is used for
178.36 + * three purposes:
178.37 + *
178.38 + * <ul>
178.39 + * <li> to decide whether an access to a critical system
178.40 + * resource is to be allowed or denied, based on the security policy
178.41 + * currently in effect,<p>
178.42 + * <li>to mark code as being "privileged", thus affecting subsequent
178.43 + * access determinations, and<p>
178.44 + * <li>to obtain a "snapshot" of the current calling context so
178.45 + * access-control decisions from a different context can be made with
178.46 + * respect to the saved context. </ul>
178.47 + *
178.48 + * <p> The {@link #checkPermission(Permission) checkPermission} method
178.49 + * determines whether the access request indicated by a specified
178.50 + * permission should be granted or denied. A sample call appears
178.51 + * below. In this example, <code>checkPermission</code> will determine
178.52 + * whether or not to grant "read" access to the file named "testFile" in
178.53 + * the "/temp" directory.
178.54 + *
178.55 + * <pre>
178.56 + *
178.57 + * FilePermission perm = new FilePermission("/temp/testFile", "read");
178.58 + * AccessController.checkPermission(perm);
178.59 + *
178.60 + * </pre>
178.61 + *
178.62 + * <p> If a requested access is allowed,
178.63 + * <code>checkPermission</code> returns quietly. If denied, an
178.64 + * AccessControlException is
178.65 + * thrown. AccessControlException can also be thrown if the requested
178.66 + * permission is of an incorrect type or contains an invalid value.
178.67 + * Such information is given whenever possible.
178.68 + *
178.69 + * Suppose the current thread traversed m callers, in the order of caller 1
178.70 + * to caller 2 to caller m. Then caller m invoked the
178.71 + * <code>checkPermission</code> method.
178.72 + * The <code>checkPermission </code>method determines whether access
178.73 + * is granted or denied based on the following algorithm:
178.74 + *
178.75 + * <pre> {@code
178.76 + * for (int i = m; i > 0; i--) {
178.77 + *
178.78 + * if (caller i's domain does not have the permission)
178.79 + * throw AccessControlException
178.80 + *
178.81 + * else if (caller i is marked as privileged) {
178.82 + * if (a context was specified in the call to doPrivileged)
178.83 + * context.checkPermission(permission)
178.84 + * return;
178.85 + * }
178.86 + * };
178.87 + *
178.88 + * // Next, check the context inherited when the thread was created.
178.89 + * // Whenever a new thread is created, the AccessControlContext at
178.90 + * // that time is stored and associated with the new thread, as the
178.91 + * // "inherited" context.
178.92 + *
178.93 + * inheritedContext.checkPermission(permission);
178.94 + * }</pre>
178.95 + *
178.96 + * <p> A caller can be marked as being "privileged"
178.97 + * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
178.98 + * When making access control decisions, the <code>checkPermission</code>
178.99 + * method stops checking if it reaches a caller that
178.100 + * was marked as "privileged" via a <code>doPrivileged</code>
178.101 + * call without a context argument (see below for information about a
178.102 + * context argument). If that caller's domain has the
178.103 + * specified permission, no further checking is done and
178.104 + * <code>checkPermission</code>
178.105 + * returns quietly, indicating that the requested access is allowed.
178.106 + * If that domain does not have the specified permission, an exception
178.107 + * is thrown, as usual.
178.108 + *
178.109 + * <p> The normal use of the "privileged" feature is as follows. If you
178.110 + * don't need to return a value from within the "privileged" block, do
178.111 + * the following:
178.112 + *
178.113 + * <pre> {@code
178.114 + * somemethod() {
178.115 + * ...normal code here...
178.116 + * AccessController.doPrivileged(new PrivilegedAction<Void>() {
178.117 + * public Void run() {
178.118 + * // privileged code goes here, for example:
178.119 + * System.loadLibrary("awt");
178.120 + * return null; // nothing to return
178.121 + * }
178.122 + * });
178.123 + * ...normal code here...
178.124 + * }}</pre>
178.125 + *
178.126 + * <p>
178.127 + * PrivilegedAction is an interface with a single method, named
178.128 + * <code>run</code>.
178.129 + * The above example shows creation of an implementation
178.130 + * of that interface; a concrete implementation of the
178.131 + * <code>run</code> method is supplied.
178.132 + * When the call to <code>doPrivileged</code> is made, an
178.133 + * instance of the PrivilegedAction implementation is passed
178.134 + * to it. The <code>doPrivileged</code> method calls the
178.135 + * <code>run</code> method from the PrivilegedAction
178.136 + * implementation after enabling privileges, and returns the
178.137 + * <code>run</code> method's return value as the
178.138 + * <code>doPrivileged</code> return value (which is
178.139 + * ignored in this example).
178.140 + *
178.141 + * <p> If you need to return a value, you can do something like the following:
178.142 + *
178.143 + * <pre> {@code
178.144 + * somemethod() {
178.145 + * ...normal code here...
178.146 + * String user = AccessController.doPrivileged(
178.147 + * new PrivilegedAction<String>() {
178.148 + * public String run() {
178.149 + * return System.getProperty("user.name");
178.150 + * }
178.151 + * });
178.152 + * ...normal code here...
178.153 + * }}</pre>
178.154 + *
178.155 + * <p>If the action performed in your <code>run</code> method could
178.156 + * throw a "checked" exception (those listed in the <code>throws</code> clause
178.157 + * of a method), then you need to use the
178.158 + * <code>PrivilegedExceptionAction</code> interface instead of the
178.159 + * <code>PrivilegedAction</code> interface:
178.160 + *
178.161 + * <pre> {@code
178.162 + * somemethod() throws FileNotFoundException {
178.163 + * ...normal code here...
178.164 + * try {
178.165 + * FileInputStream fis = AccessController.doPrivileged(
178.166 + * new PrivilegedExceptionAction<FileInputStream>() {
178.167 + * public FileInputStream run() throws FileNotFoundException {
178.168 + * return new FileInputStream("someFile");
178.169 + * }
178.170 + * });
178.171 + * } catch (PrivilegedActionException e) {
178.172 + * // e.getException() should be an instance of FileNotFoundException,
178.173 + * // as only "checked" exceptions will be "wrapped" in a
178.174 + * // PrivilegedActionException.
178.175 + * throw (FileNotFoundException) e.getException();
178.176 + * }
178.177 + * ...normal code here...
178.178 + * }}</pre>
178.179 + *
178.180 + * <p> Be *very* careful in your use of the "privileged" construct, and
178.181 + * always remember to make the privileged code section as small as possible.
178.182 + *
178.183 + * <p> Note that <code>checkPermission</code> always performs security checks
178.184 + * within the context of the currently executing thread.
178.185 + * Sometimes a security check that should be made within a given context
178.186 + * will actually need to be done from within a
178.187 + * <i>different</i> context (for example, from within a worker thread).
178.188 + * The {@link #getContext() getContext} method and
178.189 + * AccessControlContext class are provided
178.190 + * for this situation. The <code>getContext</code> method takes a "snapshot"
178.191 + * of the current calling context, and places
178.192 + * it in an AccessControlContext object, which it returns. A sample call is
178.193 + * the following:
178.194 + *
178.195 + * <pre>
178.196 + *
178.197 + * AccessControlContext acc = AccessController.getContext()
178.198 + *
178.199 + * </pre>
178.200 + *
178.201 + * <p>
178.202 + * AccessControlContext itself has a <code>checkPermission</code> method
178.203 + * that makes access decisions based on the context <i>it</i> encapsulates,
178.204 + * rather than that of the current execution thread.
178.205 + * Code within a different context can thus call that method on the
178.206 + * previously-saved AccessControlContext object. A sample call is the
178.207 + * following:
178.208 + *
178.209 + * <pre>
178.210 + *
178.211 + * acc.checkPermission(permission)
178.212 + *
178.213 + * </pre>
178.214 + *
178.215 + * <p> There are also times where you don't know a priori which permissions
178.216 + * to check the context against. In these cases you can use the
178.217 + * doPrivileged method that takes a context:
178.218 + *
178.219 + * <pre> {@code
178.220 + * somemethod() {
178.221 + * AccessController.doPrivileged(new PrivilegedAction<Object>() {
178.222 + * public Object run() {
178.223 + * // Code goes here. Any permission checks within this
178.224 + * // run method will require that the intersection of the
178.225 + * // callers protection domain and the snapshot's
178.226 + * // context have the desired permission.
178.227 + * }
178.228 + * }, acc);
178.229 + * ...normal code here...
178.230 + * }}</pre>
178.231 + *
178.232 + * @see AccessControlContext
178.233 + *
178.234 + * @author Li Gong
178.235 + * @author Roland Schemers
178.236 + */
178.237 +
178.238 +public final class AccessController {
178.239 +
178.240 + /**
178.241 + * Don't allow anyone to instantiate an AccessController
178.242 + */
178.243 + private AccessController() { }
178.244 +
178.245 + /**
178.246 + * Performs the specified <code>PrivilegedAction</code> with privileges
178.247 + * enabled. The action is performed with <i>all</i> of the permissions
178.248 + * possessed by the caller's protection domain.
178.249 + *
178.250 + * <p> If the action's <code>run</code> method throws an (unchecked)
178.251 + * exception, it will propagate through this method.
178.252 + *
178.253 + * <p> Note that any DomainCombiner associated with the current
178.254 + * AccessControlContext will be ignored while the action is performed.
178.255 + *
178.256 + * @param action the action to be performed.
178.257 + *
178.258 + * @return the value returned by the action's <code>run</code> method.
178.259 + *
178.260 + * @exception NullPointerException if the action is <code>null</code>
178.261 + *
178.262 + * @see #doPrivileged(PrivilegedAction,AccessControlContext)
178.263 + * @see #doPrivileged(PrivilegedExceptionAction)
178.264 + * @see #doPrivilegedWithCombiner(PrivilegedAction)
178.265 + * @see java.security.DomainCombiner
178.266 + */
178.267 +
178.268 + public static <T> T doPrivileged(PrivilegedAction<T> action) {
178.269 + return action.run();
178.270 + }
178.271 +
178.272 + /**
178.273 + * Performs the specified <code>PrivilegedAction</code> with privileges
178.274 + * enabled. The action is performed with <i>all</i> of the permissions
178.275 + * possessed by the caller's protection domain.
178.276 + *
178.277 + * <p> If the action's <code>run</code> method throws an (unchecked)
178.278 + * exception, it will propagate through this method.
178.279 + *
178.280 + * <p> This method preserves the current AccessControlContext's
178.281 + * DomainCombiner (which may be null) while the action is performed.
178.282 + *
178.283 + * @param action the action to be performed.
178.284 + *
178.285 + * @return the value returned by the action's <code>run</code> method.
178.286 + *
178.287 + * @exception NullPointerException if the action is <code>null</code>
178.288 + *
178.289 + * @see #doPrivileged(PrivilegedAction)
178.290 + * @see java.security.DomainCombiner
178.291 + *
178.292 + * @since 1.6
178.293 + */
178.294 + public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
178.295 + return action.run();
178.296 + }
178.297 +
178.298 +
178.299 + /**
178.300 + * Performs the specified <code>PrivilegedAction</code> with privileges
178.301 + * enabled and restricted by the specified
178.302 + * <code>AccessControlContext</code>.
178.303 + * The action is performed with the intersection of the permissions
178.304 + * possessed by the caller's protection domain, and those possessed
178.305 + * by the domains represented by the specified
178.306 + * <code>AccessControlContext</code>.
178.307 + * <p>
178.308 + * If the action's <code>run</code> method throws an (unchecked) exception,
178.309 + * it will propagate through this method.
178.310 + *
178.311 + * @param action the action to be performed.
178.312 + * @param context an <i>access control context</i>
178.313 + * representing the restriction to be applied to the
178.314 + * caller's domain's privileges before performing
178.315 + * the specified action. If the context is
178.316 + * <code>null</code>,
178.317 + * then no additional restriction is applied.
178.318 + *
178.319 + * @return the value returned by the action's <code>run</code> method.
178.320 + *
178.321 + * @exception NullPointerException if the action is <code>null</code>
178.322 + *
178.323 + * @see #doPrivileged(PrivilegedAction)
178.324 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
178.325 + */
178.326 +// public static native <T> T doPrivileged(PrivilegedAction<T> action,
178.327 +// AccessControlContext context);
178.328 +
178.329 + /**
178.330 + * Performs the specified <code>PrivilegedExceptionAction</code> with
178.331 + * privileges enabled. The action is performed with <i>all</i> of the
178.332 + * permissions possessed by the caller's protection domain.
178.333 + *
178.334 + * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
178.335 + * exception, it will propagate through this method.
178.336 + *
178.337 + * <p> Note that any DomainCombiner associated with the current
178.338 + * AccessControlContext will be ignored while the action is performed.
178.339 + *
178.340 + * @param action the action to be performed
178.341 + *
178.342 + * @return the value returned by the action's <code>run</code> method
178.343 + *
178.344 + * @exception PrivilegedActionException if the specified action's
178.345 + * <code>run</code> method threw a <i>checked</i> exception
178.346 + * @exception NullPointerException if the action is <code>null</code>
178.347 + *
178.348 + * @see #doPrivileged(PrivilegedAction)
178.349 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
178.350 + * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
178.351 + * @see java.security.DomainCombiner
178.352 + */
178.353 + public static <T> T
178.354 + doPrivileged(PrivilegedExceptionAction<T> action)
178.355 + throws PrivilegedActionException {
178.356 + try {
178.357 + return action.run();
178.358 + } catch (Exception ex) {
178.359 + throw new PrivilegedActionException(ex);
178.360 + }
178.361 + }
178.362 +
178.363 +
178.364 + /**
178.365 + * Performs the specified <code>PrivilegedExceptionAction</code> with
178.366 + * privileges enabled. The action is performed with <i>all</i> of the
178.367 + * permissions possessed by the caller's protection domain.
178.368 + *
178.369 + * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
178.370 + * exception, it will propagate through this method.
178.371 + *
178.372 + * <p> This method preserves the current AccessControlContext's
178.373 + * DomainCombiner (which may be null) while the action is performed.
178.374 + *
178.375 + * @param action the action to be performed.
178.376 + *
178.377 + * @return the value returned by the action's <code>run</code> method
178.378 + *
178.379 + * @exception PrivilegedActionException if the specified action's
178.380 + * <code>run</code> method threw a <i>checked</i> exception
178.381 + * @exception NullPointerException if the action is <code>null</code>
178.382 + *
178.383 + * @see #doPrivileged(PrivilegedAction)
178.384 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
178.385 + * @see java.security.DomainCombiner
178.386 + *
178.387 + * @since 1.6
178.388 + */
178.389 + public static <T> T doPrivilegedWithCombiner
178.390 + (PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
178.391 + return doPrivileged(action);
178.392 + }
178.393 +
178.394 + /**
178.395 + * Performs the specified <code>PrivilegedExceptionAction</code> with
178.396 + * privileges enabled and restricted by the specified
178.397 + * <code>AccessControlContext</code>. The action is performed with the
178.398 + * intersection of the permissions possessed by the caller's
178.399 + * protection domain, and those possessed by the domains represented by the
178.400 + * specified <code>AccessControlContext</code>.
178.401 + * <p>
178.402 + * If the action's <code>run</code> method throws an <i>unchecked</i>
178.403 + * exception, it will propagate through this method.
178.404 + *
178.405 + * @param action the action to be performed
178.406 + * @param context an <i>access control context</i>
178.407 + * representing the restriction to be applied to the
178.408 + * caller's domain's privileges before performing
178.409 + * the specified action. If the context is
178.410 + * <code>null</code>,
178.411 + * then no additional restriction is applied.
178.412 + *
178.413 + * @return the value returned by the action's <code>run</code> method
178.414 + *
178.415 + * @exception PrivilegedActionException if the specified action's
178.416 + * <code>run</code> method
178.417 + * threw a <i>checked</i> exception
178.418 + * @exception NullPointerException if the action is <code>null</code>
178.419 + *
178.420 + * @see #doPrivileged(PrivilegedAction)
178.421 + * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
178.422 + */
178.423 +// public static native <T> T
178.424 +// doPrivileged(PrivilegedExceptionAction<T> action,
178.425 +// AccessControlContext context)
178.426 +// throws PrivilegedActionException;
178.427 +
178.428 + /**
178.429 + * This method takes a "snapshot" of the current calling context, which
178.430 + * includes the current Thread's inherited AccessControlContext,
178.431 + * and places it in an AccessControlContext object. This context may then
178.432 + * be checked at a later point, possibly in another thread.
178.433 + *
178.434 + * @see AccessControlContext
178.435 + *
178.436 + * @return the AccessControlContext based on the current context.
178.437 + */
178.438 +
178.439 +// public static AccessControlContext getContext()
178.440 +// {
178.441 +// AccessControlContext acc = getStackAccessControlContext();
178.442 +// if (acc == null) {
178.443 +// // all we had was privileged system code. We don't want
178.444 +// // to return null though, so we construct a real ACC.
178.445 +// return new AccessControlContext(null, true);
178.446 +// } else {
178.447 +// return acc.optimize();
178.448 +// }
178.449 +// }
178.450 +
178.451 + /**
178.452 + * Determines whether the access request indicated by the
178.453 + * specified permission should be allowed or denied, based on
178.454 + * the current AccessControlContext and security policy.
178.455 + * This method quietly returns if the access request
178.456 + * is permitted, or throws an AccessControlException otherwise. The
178.457 + * getPermission method of the AccessControlException returns the
178.458 + * <code>perm</code> Permission object instance.
178.459 + *
178.460 + * @param perm the requested permission.
178.461 + *
178.462 + * @exception AccessControlException if the specified permission
178.463 + * is not permitted, based on the current security policy.
178.464 + * @exception NullPointerException if the specified permission
178.465 + * is <code>null</code> and is checked based on the
178.466 + * security policy currently in effect.
178.467 + */
178.468 +
178.469 +// public static void checkPermission(Permission perm)
178.470 +// throws AccessControlException
178.471 +// {
178.472 +// //System.err.println("checkPermission "+perm);
178.473 +// //Thread.currentThread().dumpStack();
178.474 +//
178.475 +// if (perm == null) {
178.476 +// throw new NullPointerException("permission can't be null");
178.477 +// }
178.478 +//
178.479 +// AccessControlContext stack = getStackAccessControlContext();
178.480 +// // if context is null, we had privileged system code on the stack.
178.481 +// if (stack == null) {
178.482 +// Debug debug = AccessControlContext.getDebug();
178.483 +// boolean dumpDebug = false;
178.484 +// if (debug != null) {
178.485 +// dumpDebug = !Debug.isOn("codebase=");
178.486 +// dumpDebug &= !Debug.isOn("permission=") ||
178.487 +// Debug.isOn("permission=" + perm.getClass().getCanonicalName());
178.488 +// }
178.489 +//
178.490 +// if (dumpDebug && Debug.isOn("stack")) {
178.491 +// Thread.currentThread().dumpStack();
178.492 +// }
178.493 +//
178.494 +// if (dumpDebug && Debug.isOn("domain")) {
178.495 +// debug.println("domain (context is null)");
178.496 +// }
178.497 +//
178.498 +// if (dumpDebug) {
178.499 +// debug.println("access allowed "+perm);
178.500 +// }
178.501 +// return;
178.502 +// }
178.503 +//
178.504 +// AccessControlContext acc = stack.optimize();
178.505 +// acc.checkPermission(perm);
178.506 +// }
178.507 +}
179.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
179.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedAction.java Wed Apr 30 15:04:10 2014 +0200
179.3 @@ -0,0 +1,56 @@
179.4 +/*
179.5 + * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
179.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
179.7 + *
179.8 + * This code is free software; you can redistribute it and/or modify it
179.9 + * under the terms of the GNU General Public License version 2 only, as
179.10 + * published by the Free Software Foundation. Oracle designates this
179.11 + * particular file as subject to the "Classpath" exception as provided
179.12 + * by Oracle in the LICENSE file that accompanied this code.
179.13 + *
179.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
179.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
179.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
179.17 + * version 2 for more details (a copy is included in the LICENSE file that
179.18 + * accompanied this code).
179.19 + *
179.20 + * You should have received a copy of the GNU General Public License version
179.21 + * 2 along with this work; if not, write to the Free Software Foundation,
179.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
179.23 + *
179.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
179.25 + * or visit www.oracle.com if you need additional information or have any
179.26 + * questions.
179.27 + */
179.28 +
179.29 +package java.security;
179.30 +
179.31 +
179.32 +/**
179.33 + * A computation to be performed with privileges enabled. The computation is
179.34 + * performed by invoking <code>AccessController.doPrivileged</code> on the
179.35 + * <code>PrivilegedAction</code> object. This interface is used only for
179.36 + * computations that do not throw checked exceptions; computations that
179.37 + * throw checked exceptions must use <code>PrivilegedExceptionAction</code>
179.38 + * instead.
179.39 + *
179.40 + * @see AccessController
179.41 + * @see AccessController#doPrivileged(PrivilegedAction)
179.42 + * @see PrivilegedExceptionAction
179.43 + */
179.44 +
179.45 +public interface PrivilegedAction<T> {
179.46 + /**
179.47 + * Performs the computation. This method will be called by
179.48 + * <code>AccessController.doPrivileged</code> after enabling privileges.
179.49 + *
179.50 + * @return a class-dependent value that may represent the results of the
179.51 + * computation. Each class that implements
179.52 + * <code>PrivilegedAction</code>
179.53 + * should document what (if anything) this value represents.
179.54 + * @see AccessController#doPrivileged(PrivilegedAction)
179.55 + * @see AccessController#doPrivileged(PrivilegedAction,
179.56 + * AccessControlContext)
179.57 + */
179.58 + T run();
179.59 +}
180.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
180.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedActionException.java Wed Apr 30 15:04:10 2014 +0200
180.3 @@ -0,0 +1,105 @@
180.4 +/*
180.5 + * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
180.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
180.7 + *
180.8 + * This code is free software; you can redistribute it and/or modify it
180.9 + * under the terms of the GNU General Public License version 2 only, as
180.10 + * published by the Free Software Foundation. Oracle designates this
180.11 + * particular file as subject to the "Classpath" exception as provided
180.12 + * by Oracle in the LICENSE file that accompanied this code.
180.13 + *
180.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
180.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
180.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
180.17 + * version 2 for more details (a copy is included in the LICENSE file that
180.18 + * accompanied this code).
180.19 + *
180.20 + * You should have received a copy of the GNU General Public License version
180.21 + * 2 along with this work; if not, write to the Free Software Foundation,
180.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
180.23 + *
180.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
180.25 + * or visit www.oracle.com if you need additional information or have any
180.26 + * questions.
180.27 + */
180.28 +
180.29 +package java.security;
180.30 +
180.31 +/**
180.32 + * This exception is thrown by
180.33 + * <code>doPrivileged(PrivilegedExceptionAction)</code> and
180.34 + * <code>doPrivileged(PrivilegedExceptionAction,
180.35 + * AccessControlContext context)</code> to indicate
180.36 + * that the action being performed threw a checked exception. The exception
180.37 + * thrown by the action can be obtained by calling the
180.38 + * <code>getException</code> method. In effect, an
180.39 + * <code>PrivilegedActionException</code> is a "wrapper"
180.40 + * for an exception thrown by a privileged action.
180.41 + *
180.42 + * <p>As of release 1.4, this exception has been retrofitted to conform to
180.43 + * the general purpose exception-chaining mechanism. The "exception thrown
180.44 + * by the privileged computation" that is provided at construction time and
180.45 + * accessed via the {@link #getException()} method is now known as the
180.46 + * <i>cause</i>, and may be accessed via the {@link Throwable#getCause()}
180.47 + * method, as well as the aforementioned "legacy method."
180.48 + *
180.49 + * @see PrivilegedExceptionAction
180.50 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
180.51 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
180.52 + */
180.53 +public class PrivilegedActionException extends Exception {
180.54 + // use serialVersionUID from JDK 1.2.2 for interoperability
180.55 + private static final long serialVersionUID = 4724086851538908602L;
180.56 +
180.57 + /**
180.58 + * @serial
180.59 + */
180.60 + private Exception exception;
180.61 +
180.62 + /**
180.63 + * Constructs a new PrivilegedActionException "wrapping"
180.64 + * the specific Exception.
180.65 + *
180.66 + * @param exception The exception thrown
180.67 + */
180.68 + public PrivilegedActionException(Exception exception) {
180.69 + super((Throwable)null); // Disallow initCause
180.70 + this.exception = exception;
180.71 + }
180.72 +
180.73 + /**
180.74 + * Returns the exception thrown by the privileged computation that
180.75 + * resulted in this <code>PrivilegedActionException</code>.
180.76 + *
180.77 + * <p>This method predates the general-purpose exception chaining facility.
180.78 + * The {@link Throwable#getCause()} method is now the preferred means of
180.79 + * obtaining this information.
180.80 + *
180.81 + * @return the exception thrown by the privileged computation that
180.82 + * resulted in this <code>PrivilegedActionException</code>.
180.83 + * @see PrivilegedExceptionAction
180.84 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
180.85 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,
180.86 + * AccessControlContext)
180.87 + */
180.88 + public Exception getException() {
180.89 + return exception;
180.90 + }
180.91 +
180.92 + /**
180.93 + * Returns the cause of this exception (the exception thrown by
180.94 + * the privileged computation that resulted in this
180.95 + * <code>PrivilegedActionException</code>).
180.96 + *
180.97 + * @return the cause of this exception.
180.98 + * @since 1.4
180.99 + */
180.100 + public Throwable getCause() {
180.101 + return exception;
180.102 + }
180.103 +
180.104 + public String toString() {
180.105 + String s = getClass().getName();
180.106 + return (exception != null) ? (s + ": " + exception.toString()) : s;
180.107 + }
180.108 +}
181.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
181.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedExceptionAction.java Wed Apr 30 15:04:10 2014 +0200
181.3 @@ -0,0 +1,62 @@
181.4 +/*
181.5 + * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
181.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
181.7 + *
181.8 + * This code is free software; you can redistribute it and/or modify it
181.9 + * under the terms of the GNU General Public License version 2 only, as
181.10 + * published by the Free Software Foundation. Oracle designates this
181.11 + * particular file as subject to the "Classpath" exception as provided
181.12 + * by Oracle in the LICENSE file that accompanied this code.
181.13 + *
181.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
181.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
181.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
181.17 + * version 2 for more details (a copy is included in the LICENSE file that
181.18 + * accompanied this code).
181.19 + *
181.20 + * You should have received a copy of the GNU General Public License version
181.21 + * 2 along with this work; if not, write to the Free Software Foundation,
181.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
181.23 + *
181.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
181.25 + * or visit www.oracle.com if you need additional information or have any
181.26 + * questions.
181.27 + */
181.28 +
181.29 +package java.security;
181.30 +
181.31 +
181.32 +/**
181.33 + * A computation to be performed with privileges enabled, that throws one or
181.34 + * more checked exceptions. The computation is performed by invoking
181.35 + * <code>AccessController.doPrivileged</code> on the
181.36 + * <code>PrivilegedExceptionAction</code> object. This interface is
181.37 + * used only for computations that throw checked exceptions;
181.38 + * computations that do not throw
181.39 + * checked exceptions should use <code>PrivilegedAction</code> instead.
181.40 + *
181.41 + * @see AccessController
181.42 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
181.43 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,
181.44 + * AccessControlContext)
181.45 + * @see PrivilegedAction
181.46 + */
181.47 +
181.48 +public interface PrivilegedExceptionAction<T> {
181.49 + /**
181.50 + * Performs the computation. This method will be called by
181.51 + * <code>AccessController.doPrivileged</code> after enabling privileges.
181.52 + *
181.53 + * @return a class-dependent value that may represent the results of the
181.54 + * computation. Each class that implements
181.55 + * <code>PrivilegedExceptionAction</code> should document what
181.56 + * (if anything) this value represents.
181.57 + * @throws Exception an exceptional condition has occurred. Each class
181.58 + * that implements <code>PrivilegedExceptionAction</code> should
181.59 + * document the exceptions that its run method can throw.
181.60 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
181.61 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
181.62 + */
181.63 +
181.64 + T run() throws Exception;
181.65 +}
182.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
182.2 +++ b/rt/emul/compact/src/main/java/java/text/Annotation.java Wed Apr 30 15:04:10 2014 +0200
182.3 @@ -0,0 +1,84 @@
182.4 +/*
182.5 + * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
182.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
182.7 + *
182.8 + * This code is free software; you can redistribute it and/or modify it
182.9 + * under the terms of the GNU General Public License version 2 only, as
182.10 + * published by the Free Software Foundation. Oracle designates this
182.11 + * particular file as subject to the "Classpath" exception as provided
182.12 + * by Oracle in the LICENSE file that accompanied this code.
182.13 + *
182.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
182.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
182.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
182.17 + * version 2 for more details (a copy is included in the LICENSE file that
182.18 + * accompanied this code).
182.19 + *
182.20 + * You should have received a copy of the GNU General Public License version
182.21 + * 2 along with this work; if not, write to the Free Software Foundation,
182.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
182.23 + *
182.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
182.25 + * or visit www.oracle.com if you need additional information or have any
182.26 + * questions.
182.27 + */
182.28 +
182.29 +package java.text;
182.30 +
182.31 +/**
182.32 +* An Annotation object is used as a wrapper for a text attribute value if
182.33 +* the attribute has annotation characteristics. These characteristics are:
182.34 +* <ul>
182.35 +* <li>The text range that the attribute is applied to is critical to the
182.36 +* semantics of the range. That means, the attribute cannot be applied to subranges
182.37 +* of the text range that it applies to, and, if two adjacent text ranges have
182.38 +* the same value for this attribute, the attribute still cannot be applied to
182.39 +* the combined range as a whole with this value.
182.40 +* <li>The attribute or its value usually do no longer apply if the underlying text is
182.41 +* changed.
182.42 +* </ul>
182.43 +*
182.44 +* An example is grammatical information attached to a sentence:
182.45 +* For the previous sentence, you can say that "an example"
182.46 +* is the subject, but you cannot say the same about "an", "example", or "exam".
182.47 +* When the text is changed, the grammatical information typically becomes invalid.
182.48 +* Another example is Japanese reading information (yomi).
182.49 +*
182.50 +* <p>
182.51 +* Wrapping the attribute value into an Annotation object guarantees that
182.52 +* adjacent text runs don't get merged even if the attribute values are equal,
182.53 +* and indicates to text containers that the attribute should be discarded if
182.54 +* the underlying text is modified.
182.55 +*
182.56 +* @see AttributedCharacterIterator
182.57 +* @since 1.2
182.58 +*/
182.59 +
182.60 +public class Annotation {
182.61 +
182.62 + /**
182.63 + * Constructs an annotation record with the given value, which
182.64 + * may be null.
182.65 + * @param value The value of the attribute
182.66 + */
182.67 + public Annotation(Object value) {
182.68 + this.value = value;
182.69 + }
182.70 +
182.71 + /**
182.72 + * Returns the value of the attribute, which may be null.
182.73 + */
182.74 + public Object getValue() {
182.75 + return value;
182.76 + }
182.77 +
182.78 + /**
182.79 + * Returns the String representation of this Annotation.
182.80 + */
182.81 + public String toString() {
182.82 + return getClass().getName() + "[value=" + value + "]";
182.83 + }
182.84 +
182.85 + private Object value;
182.86 +
182.87 +};
183.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
183.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedCharacterIterator.java Wed Apr 30 15:04:10 2014 +0200
183.3 @@ -0,0 +1,254 @@
183.4 +/*
183.5 + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
183.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
183.7 + *
183.8 + * This code is free software; you can redistribute it and/or modify it
183.9 + * under the terms of the GNU General Public License version 2 only, as
183.10 + * published by the Free Software Foundation. Oracle designates this
183.11 + * particular file as subject to the "Classpath" exception as provided
183.12 + * by Oracle in the LICENSE file that accompanied this code.
183.13 + *
183.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
183.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
183.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
183.17 + * version 2 for more details (a copy is included in the LICENSE file that
183.18 + * accompanied this code).
183.19 + *
183.20 + * You should have received a copy of the GNU General Public License version
183.21 + * 2 along with this work; if not, write to the Free Software Foundation,
183.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
183.23 + *
183.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
183.25 + * or visit www.oracle.com if you need additional information or have any
183.26 + * questions.
183.27 + */
183.28 +
183.29 +package java.text;
183.30 +
183.31 +import java.io.InvalidObjectException;
183.32 +import java.io.Serializable;
183.33 +import java.util.HashMap;
183.34 +import java.util.Map;
183.35 +import java.util.Set;
183.36 +
183.37 +/**
183.38 + * An {@code AttributedCharacterIterator} allows iteration through both text and
183.39 + * related attribute information.
183.40 + *
183.41 + * <p>
183.42 + * An attribute is a key/value pair, identified by the key. No two
183.43 + * attributes on a given character can have the same key.
183.44 + *
183.45 + * <p>The values for an attribute are immutable, or must not be mutated
183.46 + * by clients or storage. They are always passed by reference, and not
183.47 + * cloned.
183.48 + *
183.49 + * <p>A <em>run with respect to an attribute</em> is a maximum text range for
183.50 + * which:
183.51 + * <ul>
183.52 + * <li>the attribute is undefined or {@code null} for the entire range, or
183.53 + * <li>the attribute value is defined and has the same non-{@code null} value for the
183.54 + * entire range.
183.55 + * </ul>
183.56 + *
183.57 + * <p>A <em>run with respect to a set of attributes</em> is a maximum text range for
183.58 + * which this condition is met for each member attribute.
183.59 + *
183.60 + * <p>When getting a run with no explicit attributes specified (i.e.,
183.61 + * calling {@link #getRunStart()} and {@link #getRunLimit()}), any
183.62 + * contiguous text segments having the same attributes (the same set
183.63 + * of attribute/value pairs) are treated as separate runs if the
183.64 + * attributes have been given to those text segments separately.
183.65 + *
183.66 + * <p>The returned indexes are limited to the range of the iterator.
183.67 + *
183.68 + * <p>The returned attribute information is limited to runs that contain
183.69 + * the current character.
183.70 + *
183.71 + * <p>
183.72 + * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} and its
183.73 + * subclasses, such as {@link java.awt.font.TextAttribute}.
183.74 + *
183.75 + * @see AttributedCharacterIterator.Attribute
183.76 + * @see java.awt.font.TextAttribute
183.77 + * @see AttributedString
183.78 + * @see Annotation
183.79 + * @since 1.2
183.80 + */
183.81 +
183.82 +public interface AttributedCharacterIterator extends CharacterIterator {
183.83 +
183.84 + /**
183.85 + * Defines attribute keys that are used to identify text attributes. These
183.86 + * keys are used in {@code AttributedCharacterIterator} and {@code AttributedString}.
183.87 + * @see AttributedCharacterIterator
183.88 + * @see AttributedString
183.89 + * @since 1.2
183.90 + */
183.91 +
183.92 + public static class Attribute implements Serializable {
183.93 +
183.94 + /**
183.95 + * The name of this {@code Attribute}. The name is used primarily by {@code readResolve}
183.96 + * to look up the corresponding predefined instance when deserializing
183.97 + * an instance.
183.98 + * @serial
183.99 + */
183.100 + private String name;
183.101 +
183.102 + // table of all instances in this class, used by readResolve
183.103 + private static final Map instanceMap = new HashMap(7);
183.104 +
183.105 + /**
183.106 + * Constructs an {@code Attribute} with the given name.
183.107 + */
183.108 + protected Attribute(String name) {
183.109 + this.name = name;
183.110 + if (this.getClass() == Attribute.class) {
183.111 + instanceMap.put(name, this);
183.112 + }
183.113 + }
183.114 +
183.115 + /**
183.116 + * Compares two objects for equality. This version only returns true
183.117 + * for <code>x.equals(y)</code> if <code>x</code> and <code>y</code> refer
183.118 + * to the same object, and guarantees this for all subclasses.
183.119 + */
183.120 + public final boolean equals(Object obj) {
183.121 + return super.equals(obj);
183.122 + }
183.123 +
183.124 + /**
183.125 + * Returns a hash code value for the object. This version is identical to
183.126 + * the one in {@code Object}, but is also final.
183.127 + */
183.128 + public final int hashCode() {
183.129 + return super.hashCode();
183.130 + }
183.131 +
183.132 + /**
183.133 + * Returns a string representation of the object. This version returns the
183.134 + * concatenation of class name, {@code "("}, a name identifying the attribute
183.135 + * and {@code ")"}.
183.136 + */
183.137 + public String toString() {
183.138 + return getClass().getName() + "(" + name + ")";
183.139 + }
183.140 +
183.141 + /**
183.142 + * Returns the name of the attribute.
183.143 + */
183.144 + protected String getName() {
183.145 + return name;
183.146 + }
183.147 +
183.148 + /**
183.149 + * Resolves instances being deserialized to the predefined constants.
183.150 + */
183.151 + protected Object readResolve() throws InvalidObjectException {
183.152 + if (this.getClass() != Attribute.class) {
183.153 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
183.154 + }
183.155 +
183.156 + Attribute instance = (Attribute) instanceMap.get(getName());
183.157 + if (instance != null) {
183.158 + return instance;
183.159 + } else {
183.160 + throw new InvalidObjectException("unknown attribute name");
183.161 + }
183.162 + }
183.163 +
183.164 + /**
183.165 + * Attribute key for the language of some text.
183.166 + * <p> Values are instances of {@link java.util.Locale Locale}.
183.167 + * @see java.util.Locale
183.168 + */
183.169 + public static final Attribute LANGUAGE = new Attribute("language");
183.170 +
183.171 + /**
183.172 + * Attribute key for the reading of some text. In languages where the written form
183.173 + * and the pronunciation of a word are only loosely related (such as Japanese),
183.174 + * it is often necessary to store the reading (pronunciation) along with the
183.175 + * written form.
183.176 + * <p>Values are instances of {@link Annotation} holding instances of {@link String}.
183.177 + * @see Annotation
183.178 + * @see java.lang.String
183.179 + */
183.180 + public static final Attribute READING = new Attribute("reading");
183.181 +
183.182 + /**
183.183 + * Attribute key for input method segments. Input methods often break
183.184 + * up text into segments, which usually correspond to words.
183.185 + * <p>Values are instances of {@link Annotation} holding a {@code null} reference.
183.186 + * @see Annotation
183.187 + */
183.188 + public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment");
183.189 +
183.190 + // make sure the serial version doesn't change between compiler versions
183.191 + private static final long serialVersionUID = -9142742483513960612L;
183.192 +
183.193 + };
183.194 +
183.195 + /**
183.196 + * Returns the index of the first character of the run
183.197 + * with respect to all attributes containing the current character.
183.198 + *
183.199 + * <p>Any contiguous text segments having the same attributes (the
183.200 + * same set of attribute/value pairs) are treated as separate runs
183.201 + * if the attributes have been given to those text segments separately.
183.202 + */
183.203 + public int getRunStart();
183.204 +
183.205 + /**
183.206 + * Returns the index of the first character of the run
183.207 + * with respect to the given {@code attribute} containing the current character.
183.208 + */
183.209 + public int getRunStart(Attribute attribute);
183.210 +
183.211 + /**
183.212 + * Returns the index of the first character of the run
183.213 + * with respect to the given {@code attributes} containing the current character.
183.214 + */
183.215 + public int getRunStart(Set<? extends Attribute> attributes);
183.216 +
183.217 + /**
183.218 + * Returns the index of the first character following the run
183.219 + * with respect to all attributes containing the current character.
183.220 + *
183.221 + * <p>Any contiguous text segments having the same attributes (the
183.222 + * same set of attribute/value pairs) are treated as separate runs
183.223 + * if the attributes have been given to those text segments separately.
183.224 + */
183.225 + public int getRunLimit();
183.226 +
183.227 + /**
183.228 + * Returns the index of the first character following the run
183.229 + * with respect to the given {@code attribute} containing the current character.
183.230 + */
183.231 + public int getRunLimit(Attribute attribute);
183.232 +
183.233 + /**
183.234 + * Returns the index of the first character following the run
183.235 + * with respect to the given {@code attributes} containing the current character.
183.236 + */
183.237 + public int getRunLimit(Set<? extends Attribute> attributes);
183.238 +
183.239 + /**
183.240 + * Returns a map with the attributes defined on the current
183.241 + * character.
183.242 + */
183.243 + public Map<Attribute,Object> getAttributes();
183.244 +
183.245 + /**
183.246 + * Returns the value of the named {@code attribute} for the current character.
183.247 + * Returns {@code null} if the {@code attribute} is not defined.
183.248 + */
183.249 + public Object getAttribute(Attribute attribute);
183.250 +
183.251 + /**
183.252 + * Returns the keys of all attributes defined on the
183.253 + * iterator's text range. The set is empty if no
183.254 + * attributes are defined.
183.255 + */
183.256 + public Set<Attribute> getAllAttributeKeys();
183.257 +};
184.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
184.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedString.java Wed Apr 30 15:04:10 2014 +0200
184.3 @@ -0,0 +1,1120 @@
184.4 +/*
184.5 + * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
184.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
184.7 + *
184.8 + * This code is free software; you can redistribute it and/or modify it
184.9 + * under the terms of the GNU General Public License version 2 only, as
184.10 + * published by the Free Software Foundation. Oracle designates this
184.11 + * particular file as subject to the "Classpath" exception as provided
184.12 + * by Oracle in the LICENSE file that accompanied this code.
184.13 + *
184.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
184.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
184.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
184.17 + * version 2 for more details (a copy is included in the LICENSE file that
184.18 + * accompanied this code).
184.19 + *
184.20 + * You should have received a copy of the GNU General Public License version
184.21 + * 2 along with this work; if not, write to the Free Software Foundation,
184.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
184.23 + *
184.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
184.25 + * or visit www.oracle.com if you need additional information or have any
184.26 + * questions.
184.27 + */
184.28 +
184.29 +package java.text;
184.30 +
184.31 +import java.util.*;
184.32 +import java.text.AttributedCharacterIterator.Attribute;
184.33 +
184.34 +/**
184.35 + * An AttributedString holds text and related attribute information. It
184.36 + * may be used as the actual data storage in some cases where a text
184.37 + * reader wants to access attributed text through the AttributedCharacterIterator
184.38 + * interface.
184.39 + *
184.40 + * <p>
184.41 + * An attribute is a key/value pair, identified by the key. No two
184.42 + * attributes on a given character can have the same key.
184.43 + *
184.44 + * <p>The values for an attribute are immutable, or must not be mutated
184.45 + * by clients or storage. They are always passed by reference, and not
184.46 + * cloned.
184.47 + *
184.48 + * @see AttributedCharacterIterator
184.49 + * @see Annotation
184.50 + * @since 1.2
184.51 + */
184.52 +
184.53 +public class AttributedString {
184.54 +
184.55 + // since there are no vectors of int, we have to use arrays.
184.56 + // We allocate them in chunks of 10 elements so we don't have to allocate all the time.
184.57 + private static final int ARRAY_SIZE_INCREMENT = 10;
184.58 +
184.59 + // field holding the text
184.60 + String text;
184.61 +
184.62 + // fields holding run attribute information
184.63 + // run attributes are organized by run
184.64 + int runArraySize; // current size of the arrays
184.65 + int runCount; // actual number of runs, <= runArraySize
184.66 + int runStarts[]; // start index for each run
184.67 + Vector runAttributes[]; // vector of attribute keys for each run
184.68 + Vector runAttributeValues[]; // parallel vector of attribute values for each run
184.69 +
184.70 + /**
184.71 + * Constructs an AttributedString instance with the given
184.72 + * AttributedCharacterIterators.
184.73 + *
184.74 + * @param iterators AttributedCharacterIterators to construct
184.75 + * AttributedString from.
184.76 + * @throws NullPointerException if iterators is null
184.77 + */
184.78 + AttributedString(AttributedCharacterIterator[] iterators) {
184.79 + if (iterators == null) {
184.80 + throw new NullPointerException("Iterators must not be null");
184.81 + }
184.82 + if (iterators.length == 0) {
184.83 + text = "";
184.84 + }
184.85 + else {
184.86 + // Build the String contents
184.87 + StringBuffer buffer = new StringBuffer();
184.88 + for (int counter = 0; counter < iterators.length; counter++) {
184.89 + appendContents(buffer, iterators[counter]);
184.90 + }
184.91 +
184.92 + text = buffer.toString();
184.93 +
184.94 + if (text.length() > 0) {
184.95 + // Determine the runs, creating a new run when the attributes
184.96 + // differ.
184.97 + int offset = 0;
184.98 + Map last = null;
184.99 +
184.100 + for (int counter = 0; counter < iterators.length; counter++) {
184.101 + AttributedCharacterIterator iterator = iterators[counter];
184.102 + int start = iterator.getBeginIndex();
184.103 + int end = iterator.getEndIndex();
184.104 + int index = start;
184.105 +
184.106 + while (index < end) {
184.107 + iterator.setIndex(index);
184.108 +
184.109 + Map attrs = iterator.getAttributes();
184.110 +
184.111 + if (mapsDiffer(last, attrs)) {
184.112 + setAttributes(attrs, index - start + offset);
184.113 + }
184.114 + last = attrs;
184.115 + index = iterator.getRunLimit();
184.116 + }
184.117 + offset += (end - start);
184.118 + }
184.119 + }
184.120 + }
184.121 + }
184.122 +
184.123 + /**
184.124 + * Constructs an AttributedString instance with the given text.
184.125 + * @param text The text for this attributed string.
184.126 + * @exception NullPointerException if <code>text</code> is null.
184.127 + */
184.128 + public AttributedString(String text) {
184.129 + if (text == null) {
184.130 + throw new NullPointerException();
184.131 + }
184.132 + this.text = text;
184.133 + }
184.134 +
184.135 + /**
184.136 + * Constructs an AttributedString instance with the given text and attributes.
184.137 + * @param text The text for this attributed string.
184.138 + * @param attributes The attributes that apply to the entire string.
184.139 + * @exception NullPointerException if <code>text</code> or
184.140 + * <code>attributes</code> is null.
184.141 + * @exception IllegalArgumentException if the text has length 0
184.142 + * and the attributes parameter is not an empty Map (attributes
184.143 + * cannot be applied to a 0-length range).
184.144 + */
184.145 + public AttributedString(String text,
184.146 + Map<? extends Attribute, ?> attributes)
184.147 + {
184.148 + if (text == null || attributes == null) {
184.149 + throw new NullPointerException();
184.150 + }
184.151 + this.text = text;
184.152 +
184.153 + if (text.length() == 0) {
184.154 + if (attributes.isEmpty())
184.155 + return;
184.156 + throw new IllegalArgumentException("Can't add attribute to 0-length text");
184.157 + }
184.158 +
184.159 + int attributeCount = attributes.size();
184.160 + if (attributeCount > 0) {
184.161 + createRunAttributeDataVectors();
184.162 + Vector newRunAttributes = new Vector(attributeCount);
184.163 + Vector newRunAttributeValues = new Vector(attributeCount);
184.164 + runAttributes[0] = newRunAttributes;
184.165 + runAttributeValues[0] = newRunAttributeValues;
184.166 + Iterator iterator = attributes.entrySet().iterator();
184.167 + while (iterator.hasNext()) {
184.168 + Map.Entry entry = (Map.Entry) iterator.next();
184.169 + newRunAttributes.addElement(entry.getKey());
184.170 + newRunAttributeValues.addElement(entry.getValue());
184.171 + }
184.172 + }
184.173 + }
184.174 +
184.175 + /**
184.176 + * Constructs an AttributedString instance with the given attributed
184.177 + * text represented by AttributedCharacterIterator.
184.178 + * @param text The text for this attributed string.
184.179 + * @exception NullPointerException if <code>text</code> is null.
184.180 + */
184.181 + public AttributedString(AttributedCharacterIterator text) {
184.182 + // If performance is critical, this constructor should be
184.183 + // implemented here rather than invoking the constructor for a
184.184 + // subrange. We can avoid some range checking in the loops.
184.185 + this(text, text.getBeginIndex(), text.getEndIndex(), null);
184.186 + }
184.187 +
184.188 + /**
184.189 + * Constructs an AttributedString instance with the subrange of
184.190 + * the given attributed text represented by
184.191 + * AttributedCharacterIterator. If the given range produces an
184.192 + * empty text, all attributes will be discarded. Note that any
184.193 + * attributes wrapped by an Annotation object are discarded for a
184.194 + * subrange of the original attribute range.
184.195 + *
184.196 + * @param text The text for this attributed string.
184.197 + * @param beginIndex Index of the first character of the range.
184.198 + * @param endIndex Index of the character following the last character
184.199 + * of the range.
184.200 + * @exception NullPointerException if <code>text</code> is null.
184.201 + * @exception IllegalArgumentException if the subrange given by
184.202 + * beginIndex and endIndex is out of the text range.
184.203 + * @see java.text.Annotation
184.204 + */
184.205 + public AttributedString(AttributedCharacterIterator text,
184.206 + int beginIndex,
184.207 + int endIndex) {
184.208 + this(text, beginIndex, endIndex, null);
184.209 + }
184.210 +
184.211 + /**
184.212 + * Constructs an AttributedString instance with the subrange of
184.213 + * the given attributed text represented by
184.214 + * AttributedCharacterIterator. Only attributes that match the
184.215 + * given attributes will be incorporated into the instance. If the
184.216 + * given range produces an empty text, all attributes will be
184.217 + * discarded. Note that any attributes wrapped by an Annotation
184.218 + * object are discarded for a subrange of the original attribute
184.219 + * range.
184.220 + *
184.221 + * @param text The text for this attributed string.
184.222 + * @param beginIndex Index of the first character of the range.
184.223 + * @param endIndex Index of the character following the last character
184.224 + * of the range.
184.225 + * @param attributes Specifies attributes to be extracted
184.226 + * from the text. If null is specified, all available attributes will
184.227 + * be used.
184.228 + * @exception NullPointerException if <code>text</code> is null.
184.229 + * @exception IllegalArgumentException if the subrange given by
184.230 + * beginIndex and endIndex is out of the text range.
184.231 + * @see java.text.Annotation
184.232 + */
184.233 + public AttributedString(AttributedCharacterIterator text,
184.234 + int beginIndex,
184.235 + int endIndex,
184.236 + Attribute[] attributes) {
184.237 + if (text == null) {
184.238 + throw new NullPointerException();
184.239 + }
184.240 +
184.241 + // Validate the given subrange
184.242 + int textBeginIndex = text.getBeginIndex();
184.243 + int textEndIndex = text.getEndIndex();
184.244 + if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex)
184.245 + throw new IllegalArgumentException("Invalid substring range");
184.246 +
184.247 + // Copy the given string
184.248 + StringBuffer textBuffer = new StringBuffer();
184.249 + text.setIndex(beginIndex);
184.250 + for (char c = text.current(); text.getIndex() < endIndex; c = text.next())
184.251 + textBuffer.append(c);
184.252 + this.text = textBuffer.toString();
184.253 +
184.254 + if (beginIndex == endIndex)
184.255 + return;
184.256 +
184.257 + // Select attribute keys to be taken care of
184.258 + HashSet keys = new HashSet();
184.259 + if (attributes == null) {
184.260 + keys.addAll(text.getAllAttributeKeys());
184.261 + } else {
184.262 + for (int i = 0; i < attributes.length; i++)
184.263 + keys.add(attributes[i]);
184.264 + keys.retainAll(text.getAllAttributeKeys());
184.265 + }
184.266 + if (keys.isEmpty())
184.267 + return;
184.268 +
184.269 + // Get and set attribute runs for each attribute name. Need to
184.270 + // scan from the top of the text so that we can discard any
184.271 + // Annotation that is no longer applied to a subset text segment.
184.272 + Iterator itr = keys.iterator();
184.273 + while (itr.hasNext()) {
184.274 + Attribute attributeKey = (Attribute)itr.next();
184.275 + text.setIndex(textBeginIndex);
184.276 + while (text.getIndex() < endIndex) {
184.277 + int start = text.getRunStart(attributeKey);
184.278 + int limit = text.getRunLimit(attributeKey);
184.279 + Object value = text.getAttribute(attributeKey);
184.280 +
184.281 + if (value != null) {
184.282 + if (value instanceof Annotation) {
184.283 + if (start >= beginIndex && limit <= endIndex) {
184.284 + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
184.285 + } else {
184.286 + if (limit > endIndex)
184.287 + break;
184.288 + }
184.289 + } else {
184.290 + // if the run is beyond the given (subset) range, we
184.291 + // don't need to process further.
184.292 + if (start >= endIndex)
184.293 + break;
184.294 + if (limit > beginIndex) {
184.295 + // attribute is applied to any subrange
184.296 + if (start < beginIndex)
184.297 + start = beginIndex;
184.298 + if (limit > endIndex)
184.299 + limit = endIndex;
184.300 + if (start != limit) {
184.301 + addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
184.302 + }
184.303 + }
184.304 + }
184.305 + }
184.306 + text.setIndex(limit);
184.307 + }
184.308 + }
184.309 + }
184.310 +
184.311 + /**
184.312 + * Adds an attribute to the entire string.
184.313 + * @param attribute the attribute key
184.314 + * @param value the value of the attribute; may be null
184.315 + * @exception NullPointerException if <code>attribute</code> is null.
184.316 + * @exception IllegalArgumentException if the AttributedString has length 0
184.317 + * (attributes cannot be applied to a 0-length range).
184.318 + */
184.319 + public void addAttribute(Attribute attribute, Object value) {
184.320 +
184.321 + if (attribute == null) {
184.322 + throw new NullPointerException();
184.323 + }
184.324 +
184.325 + int len = length();
184.326 + if (len == 0) {
184.327 + throw new IllegalArgumentException("Can't add attribute to 0-length text");
184.328 + }
184.329 +
184.330 + addAttributeImpl(attribute, value, 0, len);
184.331 + }
184.332 +
184.333 + /**
184.334 + * Adds an attribute to a subrange of the string.
184.335 + * @param attribute the attribute key
184.336 + * @param value The value of the attribute. May be null.
184.337 + * @param beginIndex Index of the first character of the range.
184.338 + * @param endIndex Index of the character following the last character of the range.
184.339 + * @exception NullPointerException if <code>attribute</code> is null.
184.340 + * @exception IllegalArgumentException if beginIndex is less then 0, endIndex is
184.341 + * greater than the length of the string, or beginIndex and endIndex together don't
184.342 + * define a non-empty subrange of the string.
184.343 + */
184.344 + public void addAttribute(Attribute attribute, Object value,
184.345 + int beginIndex, int endIndex) {
184.346 +
184.347 + if (attribute == null) {
184.348 + throw new NullPointerException();
184.349 + }
184.350 +
184.351 + if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) {
184.352 + throw new IllegalArgumentException("Invalid substring range");
184.353 + }
184.354 +
184.355 + addAttributeImpl(attribute, value, beginIndex, endIndex);
184.356 + }
184.357 +
184.358 + /**
184.359 + * Adds a set of attributes to a subrange of the string.
184.360 + * @param attributes The attributes to be added to the string.
184.361 + * @param beginIndex Index of the first character of the range.
184.362 + * @param endIndex Index of the character following the last
184.363 + * character of the range.
184.364 + * @exception NullPointerException if <code>attributes</code> is null.
184.365 + * @exception IllegalArgumentException if beginIndex is less then
184.366 + * 0, endIndex is greater than the length of the string, or
184.367 + * beginIndex and endIndex together don't define a non-empty
184.368 + * subrange of the string and the attributes parameter is not an
184.369 + * empty Map.
184.370 + */
184.371 + public void addAttributes(Map<? extends Attribute, ?> attributes,
184.372 + int beginIndex, int endIndex)
184.373 + {
184.374 + if (attributes == null) {
184.375 + throw new NullPointerException();
184.376 + }
184.377 +
184.378 + if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) {
184.379 + throw new IllegalArgumentException("Invalid substring range");
184.380 + }
184.381 + if (beginIndex == endIndex) {
184.382 + if (attributes.isEmpty())
184.383 + return;
184.384 + throw new IllegalArgumentException("Can't add attribute to 0-length text");
184.385 + }
184.386 +
184.387 + // make sure we have run attribute data vectors
184.388 + if (runCount == 0) {
184.389 + createRunAttributeDataVectors();
184.390 + }
184.391 +
184.392 + // break up runs if necessary
184.393 + int beginRunIndex = ensureRunBreak(beginIndex);
184.394 + int endRunIndex = ensureRunBreak(endIndex);
184.395 +
184.396 + Iterator iterator = attributes.entrySet().iterator();
184.397 + while (iterator.hasNext()) {
184.398 + Map.Entry entry = (Map.Entry) iterator.next();
184.399 + addAttributeRunData((Attribute) entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex);
184.400 + }
184.401 + }
184.402 +
184.403 + private synchronized void addAttributeImpl(Attribute attribute, Object value,
184.404 + int beginIndex, int endIndex) {
184.405 +
184.406 + // make sure we have run attribute data vectors
184.407 + if (runCount == 0) {
184.408 + createRunAttributeDataVectors();
184.409 + }
184.410 +
184.411 + // break up runs if necessary
184.412 + int beginRunIndex = ensureRunBreak(beginIndex);
184.413 + int endRunIndex = ensureRunBreak(endIndex);
184.414 +
184.415 + addAttributeRunData(attribute, value, beginRunIndex, endRunIndex);
184.416 + }
184.417 +
184.418 + private final void createRunAttributeDataVectors() {
184.419 + // use temporary variables so things remain consistent in case of an exception
184.420 + int newRunStarts[] = new int[ARRAY_SIZE_INCREMENT];
184.421 + Vector newRunAttributes[] = new Vector[ARRAY_SIZE_INCREMENT];
184.422 + Vector newRunAttributeValues[] = new Vector[ARRAY_SIZE_INCREMENT];
184.423 + runStarts = newRunStarts;
184.424 + runAttributes = newRunAttributes;
184.425 + runAttributeValues = newRunAttributeValues;
184.426 + runArraySize = ARRAY_SIZE_INCREMENT;
184.427 + runCount = 1; // assume initial run starting at index 0
184.428 + }
184.429 +
184.430 + // ensure there's a run break at offset, return the index of the run
184.431 + private final int ensureRunBreak(int offset) {
184.432 + return ensureRunBreak(offset, true);
184.433 + }
184.434 +
184.435 + /**
184.436 + * Ensures there is a run break at offset, returning the index of
184.437 + * the run. If this results in splitting a run, two things can happen:
184.438 + * <ul>
184.439 + * <li>If copyAttrs is true, the attributes from the existing run
184.440 + * will be placed in both of the newly created runs.
184.441 + * <li>If copyAttrs is false, the attributes from the existing run
184.442 + * will NOT be copied to the run to the right (>= offset) of the break,
184.443 + * but will exist on the run to the left (< offset).
184.444 + * </ul>
184.445 + */
184.446 + private final int ensureRunBreak(int offset, boolean copyAttrs) {
184.447 + if (offset == length()) {
184.448 + return runCount;
184.449 + }
184.450 +
184.451 + // search for the run index where this offset should be
184.452 + int runIndex = 0;
184.453 + while (runIndex < runCount && runStarts[runIndex] < offset) {
184.454 + runIndex++;
184.455 + }
184.456 +
184.457 + // if the offset is at a run start already, we're done
184.458 + if (runIndex < runCount && runStarts[runIndex] == offset) {
184.459 + return runIndex;
184.460 + }
184.461 +
184.462 + // we'll have to break up a run
184.463 + // first, make sure we have enough space in our arrays
184.464 + if (runCount == runArraySize) {
184.465 + int newArraySize = runArraySize + ARRAY_SIZE_INCREMENT;
184.466 + int newRunStarts[] = new int[newArraySize];
184.467 + Vector newRunAttributes[] = new Vector[newArraySize];
184.468 + Vector newRunAttributeValues[] = new Vector[newArraySize];
184.469 + for (int i = 0; i < runArraySize; i++) {
184.470 + newRunStarts[i] = runStarts[i];
184.471 + newRunAttributes[i] = runAttributes[i];
184.472 + newRunAttributeValues[i] = runAttributeValues[i];
184.473 + }
184.474 + runStarts = newRunStarts;
184.475 + runAttributes = newRunAttributes;
184.476 + runAttributeValues = newRunAttributeValues;
184.477 + runArraySize = newArraySize;
184.478 + }
184.479 +
184.480 + // make copies of the attribute information of the old run that the new one used to be part of
184.481 + // use temporary variables so things remain consistent in case of an exception
184.482 + Vector newRunAttributes = null;
184.483 + Vector newRunAttributeValues = null;
184.484 +
184.485 + if (copyAttrs) {
184.486 + Vector oldRunAttributes = runAttributes[runIndex - 1];
184.487 + Vector oldRunAttributeValues = runAttributeValues[runIndex - 1];
184.488 + if (oldRunAttributes != null) {
184.489 + newRunAttributes = (Vector) oldRunAttributes.clone();
184.490 + }
184.491 + if (oldRunAttributeValues != null) {
184.492 + newRunAttributeValues = (Vector) oldRunAttributeValues.clone();
184.493 + }
184.494 + }
184.495 +
184.496 + // now actually break up the run
184.497 + runCount++;
184.498 + for (int i = runCount - 1; i > runIndex; i--) {
184.499 + runStarts[i] = runStarts[i - 1];
184.500 + runAttributes[i] = runAttributes[i - 1];
184.501 + runAttributeValues[i] = runAttributeValues[i - 1];
184.502 + }
184.503 + runStarts[runIndex] = offset;
184.504 + runAttributes[runIndex] = newRunAttributes;
184.505 + runAttributeValues[runIndex] = newRunAttributeValues;
184.506 +
184.507 + return runIndex;
184.508 + }
184.509 +
184.510 + // add the attribute attribute/value to all runs where beginRunIndex <= runIndex < endRunIndex
184.511 + private void addAttributeRunData(Attribute attribute, Object value,
184.512 + int beginRunIndex, int endRunIndex) {
184.513 +
184.514 + for (int i = beginRunIndex; i < endRunIndex; i++) {
184.515 + int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet
184.516 + if (runAttributes[i] == null) {
184.517 + Vector newRunAttributes = new Vector();
184.518 + Vector newRunAttributeValues = new Vector();
184.519 + runAttributes[i] = newRunAttributes;
184.520 + runAttributeValues[i] = newRunAttributeValues;
184.521 + } else {
184.522 + // check whether we have an entry already
184.523 + keyValueIndex = runAttributes[i].indexOf(attribute);
184.524 + }
184.525 +
184.526 + if (keyValueIndex == -1) {
184.527 + // create new entry
184.528 + int oldSize = runAttributes[i].size();
184.529 + runAttributes[i].addElement(attribute);
184.530 + try {
184.531 + runAttributeValues[i].addElement(value);
184.532 + }
184.533 + catch (Exception e) {
184.534 + runAttributes[i].setSize(oldSize);
184.535 + runAttributeValues[i].setSize(oldSize);
184.536 + }
184.537 + } else {
184.538 + // update existing entry
184.539 + runAttributeValues[i].set(keyValueIndex, value);
184.540 + }
184.541 + }
184.542 + }
184.543 +
184.544 + /**
184.545 + * Creates an AttributedCharacterIterator instance that provides access to the entire contents of
184.546 + * this string.
184.547 + *
184.548 + * @return An iterator providing access to the text and its attributes.
184.549 + */
184.550 + public AttributedCharacterIterator getIterator() {
184.551 + return getIterator(null, 0, length());
184.552 + }
184.553 +
184.554 + /**
184.555 + * Creates an AttributedCharacterIterator instance that provides access to
184.556 + * selected contents of this string.
184.557 + * Information about attributes not listed in attributes that the
184.558 + * implementor may have need not be made accessible through the iterator.
184.559 + * If the list is null, all available attribute information should be made
184.560 + * accessible.
184.561 + *
184.562 + * @param attributes a list of attributes that the client is interested in
184.563 + * @return an iterator providing access to the entire text and its selected attributes
184.564 + */
184.565 + public AttributedCharacterIterator getIterator(Attribute[] attributes) {
184.566 + return getIterator(attributes, 0, length());
184.567 + }
184.568 +
184.569 + /**
184.570 + * Creates an AttributedCharacterIterator instance that provides access to
184.571 + * selected contents of this string.
184.572 + * Information about attributes not listed in attributes that the
184.573 + * implementor may have need not be made accessible through the iterator.
184.574 + * If the list is null, all available attribute information should be made
184.575 + * accessible.
184.576 + *
184.577 + * @param attributes a list of attributes that the client is interested in
184.578 + * @param beginIndex the index of the first character
184.579 + * @param endIndex the index of the character following the last character
184.580 + * @return an iterator providing access to the text and its attributes
184.581 + * @exception IllegalArgumentException if beginIndex is less then 0,
184.582 + * endIndex is greater than the length of the string, or beginIndex is
184.583 + * greater than endIndex.
184.584 + */
184.585 + public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) {
184.586 + return new AttributedStringIterator(attributes, beginIndex, endIndex);
184.587 + }
184.588 +
184.589 + // all (with the exception of length) reading operations are private,
184.590 + // since AttributedString instances are accessed through iterators.
184.591 +
184.592 + // length is package private so that CharacterIteratorFieldDelegate can
184.593 + // access it without creating an AttributedCharacterIterator.
184.594 + int length() {
184.595 + return text.length();
184.596 + }
184.597 +
184.598 + private char charAt(int index) {
184.599 + return text.charAt(index);
184.600 + }
184.601 +
184.602 + private synchronized Object getAttribute(Attribute attribute, int runIndex) {
184.603 + Vector currentRunAttributes = runAttributes[runIndex];
184.604 + Vector currentRunAttributeValues = runAttributeValues[runIndex];
184.605 + if (currentRunAttributes == null) {
184.606 + return null;
184.607 + }
184.608 + int attributeIndex = currentRunAttributes.indexOf(attribute);
184.609 + if (attributeIndex != -1) {
184.610 + return currentRunAttributeValues.elementAt(attributeIndex);
184.611 + }
184.612 + else {
184.613 + return null;
184.614 + }
184.615 + }
184.616 +
184.617 + // gets an attribute value, but returns an annotation only if it's range does not extend outside the range beginIndex..endIndex
184.618 + private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) {
184.619 + Object value = getAttribute(attribute, runIndex);
184.620 + if (value instanceof Annotation) {
184.621 + // need to check whether the annotation's range extends outside the iterator's range
184.622 + if (beginIndex > 0) {
184.623 + int currIndex = runIndex;
184.624 + int runStart = runStarts[currIndex];
184.625 + while (runStart >= beginIndex &&
184.626 + valuesMatch(value, getAttribute(attribute, currIndex - 1))) {
184.627 + currIndex--;
184.628 + runStart = runStarts[currIndex];
184.629 + }
184.630 + if (runStart < beginIndex) {
184.631 + // annotation's range starts before iterator's range
184.632 + return null;
184.633 + }
184.634 + }
184.635 + int textLength = length();
184.636 + if (endIndex < textLength) {
184.637 + int currIndex = runIndex;
184.638 + int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
184.639 + while (runLimit <= endIndex &&
184.640 + valuesMatch(value, getAttribute(attribute, currIndex + 1))) {
184.641 + currIndex++;
184.642 + runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
184.643 + }
184.644 + if (runLimit > endIndex) {
184.645 + // annotation's range ends after iterator's range
184.646 + return null;
184.647 + }
184.648 + }
184.649 + // annotation's range is subrange of iterator's range,
184.650 + // so we can return the value
184.651 + }
184.652 + return value;
184.653 + }
184.654 +
184.655 + // returns whether all specified attributes have equal values in the runs with the given indices
184.656 + private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) {
184.657 + Iterator iterator = attributes.iterator();
184.658 + while (iterator.hasNext()) {
184.659 + Attribute key = (Attribute) iterator.next();
184.660 + if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) {
184.661 + return false;
184.662 + }
184.663 + }
184.664 + return true;
184.665 + }
184.666 +
184.667 + // returns whether the two objects are either both null or equal
184.668 + private final static boolean valuesMatch(Object value1, Object value2) {
184.669 + if (value1 == null) {
184.670 + return value2 == null;
184.671 + } else {
184.672 + return value1.equals(value2);
184.673 + }
184.674 + }
184.675 +
184.676 + /**
184.677 + * Appends the contents of the CharacterIterator iterator into the
184.678 + * StringBuffer buf.
184.679 + */
184.680 + private final void appendContents(StringBuffer buf,
184.681 + CharacterIterator iterator) {
184.682 + int index = iterator.getBeginIndex();
184.683 + int end = iterator.getEndIndex();
184.684 +
184.685 + while (index < end) {
184.686 + iterator.setIndex(index++);
184.687 + buf.append(iterator.current());
184.688 + }
184.689 + }
184.690 +
184.691 + /**
184.692 + * Sets the attributes for the range from offset to the next run break
184.693 + * (typically the end of the text) to the ones specified in attrs.
184.694 + * This is only meant to be called from the constructor!
184.695 + */
184.696 + private void setAttributes(Map attrs, int offset) {
184.697 + if (runCount == 0) {
184.698 + createRunAttributeDataVectors();
184.699 + }
184.700 +
184.701 + int index = ensureRunBreak(offset, false);
184.702 + int size;
184.703 +
184.704 + if (attrs != null && (size = attrs.size()) > 0) {
184.705 + Vector runAttrs = new Vector(size);
184.706 + Vector runValues = new Vector(size);
184.707 + Iterator iterator = attrs.entrySet().iterator();
184.708 +
184.709 + while (iterator.hasNext()) {
184.710 + Map.Entry entry = (Map.Entry)iterator.next();
184.711 +
184.712 + runAttrs.add(entry.getKey());
184.713 + runValues.add(entry.getValue());
184.714 + }
184.715 + runAttributes[index] = runAttrs;
184.716 + runAttributeValues[index] = runValues;
184.717 + }
184.718 + }
184.719 +
184.720 + /**
184.721 + * Returns true if the attributes specified in last and attrs differ.
184.722 + */
184.723 + private static boolean mapsDiffer(Map last, Map attrs) {
184.724 + if (last == null) {
184.725 + return (attrs != null && attrs.size() > 0);
184.726 + }
184.727 + return (!last.equals(attrs));
184.728 + }
184.729 +
184.730 +
184.731 + // the iterator class associated with this string class
184.732 +
184.733 + final private class AttributedStringIterator implements AttributedCharacterIterator {
184.734 +
184.735 + // note on synchronization:
184.736 + // we don't synchronize on the iterator, assuming that an iterator is only used in one thread.
184.737 + // we do synchronize access to the AttributedString however, since it's more likely to be shared between threads.
184.738 +
184.739 + // start and end index for our iteration
184.740 + private int beginIndex;
184.741 + private int endIndex;
184.742 +
184.743 + // attributes that our client is interested in
184.744 + private Attribute[] relevantAttributes;
184.745 +
184.746 + // the current index for our iteration
184.747 + // invariant: beginIndex <= currentIndex <= endIndex
184.748 + private int currentIndex;
184.749 +
184.750 + // information about the run that includes currentIndex
184.751 + private int currentRunIndex;
184.752 + private int currentRunStart;
184.753 + private int currentRunLimit;
184.754 +
184.755 + // constructor
184.756 + AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) {
184.757 +
184.758 + if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
184.759 + throw new IllegalArgumentException("Invalid substring range");
184.760 + }
184.761 +
184.762 + this.beginIndex = beginIndex;
184.763 + this.endIndex = endIndex;
184.764 + this.currentIndex = beginIndex;
184.765 + updateRunInfo();
184.766 + if (attributes != null) {
184.767 + relevantAttributes = (Attribute[]) attributes.clone();
184.768 + }
184.769 + }
184.770 +
184.771 + // Object methods. See documentation in that class.
184.772 +
184.773 + public boolean equals(Object obj) {
184.774 + if (this == obj) {
184.775 + return true;
184.776 + }
184.777 + if (!(obj instanceof AttributedStringIterator)) {
184.778 + return false;
184.779 + }
184.780 +
184.781 + AttributedStringIterator that = (AttributedStringIterator) obj;
184.782 +
184.783 + if (AttributedString.this != that.getString())
184.784 + return false;
184.785 + if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex)
184.786 + return false;
184.787 + return true;
184.788 + }
184.789 +
184.790 + public int hashCode() {
184.791 + return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex;
184.792 + }
184.793 +
184.794 + public Object clone() {
184.795 + try {
184.796 + AttributedStringIterator other = (AttributedStringIterator) super.clone();
184.797 + return other;
184.798 + }
184.799 + catch (CloneNotSupportedException e) {
184.800 + throw new InternalError();
184.801 + }
184.802 + }
184.803 +
184.804 + // CharacterIterator methods. See documentation in that interface.
184.805 +
184.806 + public char first() {
184.807 + return internalSetIndex(beginIndex);
184.808 + }
184.809 +
184.810 + public char last() {
184.811 + if (endIndex == beginIndex) {
184.812 + return internalSetIndex(endIndex);
184.813 + } else {
184.814 + return internalSetIndex(endIndex - 1);
184.815 + }
184.816 + }
184.817 +
184.818 + public char current() {
184.819 + if (currentIndex == endIndex) {
184.820 + return DONE;
184.821 + } else {
184.822 + return charAt(currentIndex);
184.823 + }
184.824 + }
184.825 +
184.826 + public char next() {
184.827 + if (currentIndex < endIndex) {
184.828 + return internalSetIndex(currentIndex + 1);
184.829 + }
184.830 + else {
184.831 + return DONE;
184.832 + }
184.833 + }
184.834 +
184.835 + public char previous() {
184.836 + if (currentIndex > beginIndex) {
184.837 + return internalSetIndex(currentIndex - 1);
184.838 + }
184.839 + else {
184.840 + return DONE;
184.841 + }
184.842 + }
184.843 +
184.844 + public char setIndex(int position) {
184.845 + if (position < beginIndex || position > endIndex)
184.846 + throw new IllegalArgumentException("Invalid index");
184.847 + return internalSetIndex(position);
184.848 + }
184.849 +
184.850 + public int getBeginIndex() {
184.851 + return beginIndex;
184.852 + }
184.853 +
184.854 + public int getEndIndex() {
184.855 + return endIndex;
184.856 + }
184.857 +
184.858 + public int getIndex() {
184.859 + return currentIndex;
184.860 + }
184.861 +
184.862 + // AttributedCharacterIterator methods. See documentation in that interface.
184.863 +
184.864 + public int getRunStart() {
184.865 + return currentRunStart;
184.866 + }
184.867 +
184.868 + public int getRunStart(Attribute attribute) {
184.869 + if (currentRunStart == beginIndex || currentRunIndex == -1) {
184.870 + return currentRunStart;
184.871 + } else {
184.872 + Object value = getAttribute(attribute);
184.873 + int runStart = currentRunStart;
184.874 + int runIndex = currentRunIndex;
184.875 + while (runStart > beginIndex &&
184.876 + valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) {
184.877 + runIndex--;
184.878 + runStart = runStarts[runIndex];
184.879 + }
184.880 + if (runStart < beginIndex) {
184.881 + runStart = beginIndex;
184.882 + }
184.883 + return runStart;
184.884 + }
184.885 + }
184.886 +
184.887 + public int getRunStart(Set<? extends Attribute> attributes) {
184.888 + if (currentRunStart == beginIndex || currentRunIndex == -1) {
184.889 + return currentRunStart;
184.890 + } else {
184.891 + int runStart = currentRunStart;
184.892 + int runIndex = currentRunIndex;
184.893 + while (runStart > beginIndex &&
184.894 + AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) {
184.895 + runIndex--;
184.896 + runStart = runStarts[runIndex];
184.897 + }
184.898 + if (runStart < beginIndex) {
184.899 + runStart = beginIndex;
184.900 + }
184.901 + return runStart;
184.902 + }
184.903 + }
184.904 +
184.905 + public int getRunLimit() {
184.906 + return currentRunLimit;
184.907 + }
184.908 +
184.909 + public int getRunLimit(Attribute attribute) {
184.910 + if (currentRunLimit == endIndex || currentRunIndex == -1) {
184.911 + return currentRunLimit;
184.912 + } else {
184.913 + Object value = getAttribute(attribute);
184.914 + int runLimit = currentRunLimit;
184.915 + int runIndex = currentRunIndex;
184.916 + while (runLimit < endIndex &&
184.917 + valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) {
184.918 + runIndex++;
184.919 + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
184.920 + }
184.921 + if (runLimit > endIndex) {
184.922 + runLimit = endIndex;
184.923 + }
184.924 + return runLimit;
184.925 + }
184.926 + }
184.927 +
184.928 + public int getRunLimit(Set<? extends Attribute> attributes) {
184.929 + if (currentRunLimit == endIndex || currentRunIndex == -1) {
184.930 + return currentRunLimit;
184.931 + } else {
184.932 + int runLimit = currentRunLimit;
184.933 + int runIndex = currentRunIndex;
184.934 + while (runLimit < endIndex &&
184.935 + AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) {
184.936 + runIndex++;
184.937 + runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
184.938 + }
184.939 + if (runLimit > endIndex) {
184.940 + runLimit = endIndex;
184.941 + }
184.942 + return runLimit;
184.943 + }
184.944 + }
184.945 +
184.946 + public Map<Attribute,Object> getAttributes() {
184.947 + if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) {
184.948 + // ??? would be nice to return null, but current spec doesn't allow it
184.949 + // returning Hashtable saves AttributeMap from dealing with emptiness
184.950 + return new Hashtable();
184.951 + }
184.952 + return new AttributeMap(currentRunIndex, beginIndex, endIndex);
184.953 + }
184.954 +
184.955 + public Set<Attribute> getAllAttributeKeys() {
184.956 + // ??? This should screen out attribute keys that aren't relevant to the client
184.957 + if (runAttributes == null) {
184.958 + // ??? would be nice to return null, but current spec doesn't allow it
184.959 + // returning HashSet saves us from dealing with emptiness
184.960 + return new HashSet();
184.961 + }
184.962 + synchronized (AttributedString.this) {
184.963 + // ??? should try to create this only once, then update if necessary,
184.964 + // and give callers read-only view
184.965 + Set keys = new HashSet();
184.966 + int i = 0;
184.967 + while (i < runCount) {
184.968 + if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) {
184.969 + Vector currentRunAttributes = runAttributes[i];
184.970 + if (currentRunAttributes != null) {
184.971 + int j = currentRunAttributes.size();
184.972 + while (j-- > 0) {
184.973 + keys.add(currentRunAttributes.get(j));
184.974 + }
184.975 + }
184.976 + }
184.977 + i++;
184.978 + }
184.979 + return keys;
184.980 + }
184.981 + }
184.982 +
184.983 + public Object getAttribute(Attribute attribute) {
184.984 + int runIndex = currentRunIndex;
184.985 + if (runIndex < 0) {
184.986 + return null;
184.987 + }
184.988 + return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex);
184.989 + }
184.990 +
184.991 + // internally used methods
184.992 +
184.993 + private AttributedString getString() {
184.994 + return AttributedString.this;
184.995 + }
184.996 +
184.997 + // set the current index, update information about the current run if necessary,
184.998 + // return the character at the current index
184.999 + private char internalSetIndex(int position) {
184.1000 + currentIndex = position;
184.1001 + if (position < currentRunStart || position >= currentRunLimit) {
184.1002 + updateRunInfo();
184.1003 + }
184.1004 + if (currentIndex == endIndex) {
184.1005 + return DONE;
184.1006 + } else {
184.1007 + return charAt(position);
184.1008 + }
184.1009 + }
184.1010 +
184.1011 + // update the information about the current run
184.1012 + private void updateRunInfo() {
184.1013 + if (currentIndex == endIndex) {
184.1014 + currentRunStart = currentRunLimit = endIndex;
184.1015 + currentRunIndex = -1;
184.1016 + } else {
184.1017 + synchronized (AttributedString.this) {
184.1018 + int runIndex = -1;
184.1019 + while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex)
184.1020 + runIndex++;
184.1021 + currentRunIndex = runIndex;
184.1022 + if (runIndex >= 0) {
184.1023 + currentRunStart = runStarts[runIndex];
184.1024 + if (currentRunStart < beginIndex)
184.1025 + currentRunStart = beginIndex;
184.1026 + }
184.1027 + else {
184.1028 + currentRunStart = beginIndex;
184.1029 + }
184.1030 + if (runIndex < runCount - 1) {
184.1031 + currentRunLimit = runStarts[runIndex + 1];
184.1032 + if (currentRunLimit > endIndex)
184.1033 + currentRunLimit = endIndex;
184.1034 + }
184.1035 + else {
184.1036 + currentRunLimit = endIndex;
184.1037 + }
184.1038 + }
184.1039 + }
184.1040 + }
184.1041 +
184.1042 + }
184.1043 +
184.1044 + // the map class associated with this string class, giving access to the attributes of one run
184.1045 +
184.1046 + final private class AttributeMap extends AbstractMap<Attribute,Object> {
184.1047 +
184.1048 + int runIndex;
184.1049 + int beginIndex;
184.1050 + int endIndex;
184.1051 +
184.1052 + AttributeMap(int runIndex, int beginIndex, int endIndex) {
184.1053 + this.runIndex = runIndex;
184.1054 + this.beginIndex = beginIndex;
184.1055 + this.endIndex = endIndex;
184.1056 + }
184.1057 +
184.1058 + public Set entrySet() {
184.1059 + HashSet set = new HashSet();
184.1060 + synchronized (AttributedString.this) {
184.1061 + int size = runAttributes[runIndex].size();
184.1062 + for (int i = 0; i < size; i++) {
184.1063 + Attribute key = (Attribute) runAttributes[runIndex].get(i);
184.1064 + Object value = runAttributeValues[runIndex].get(i);
184.1065 + if (value instanceof Annotation) {
184.1066 + value = AttributedString.this.getAttributeCheckRange(key,
184.1067 + runIndex, beginIndex, endIndex);
184.1068 + if (value == null) {
184.1069 + continue;
184.1070 + }
184.1071 + }
184.1072 + Map.Entry entry = new AttributeEntry(key, value);
184.1073 + set.add(entry);
184.1074 + }
184.1075 + }
184.1076 + return set;
184.1077 + }
184.1078 +
184.1079 + public Object get(Object key) {
184.1080 + return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex);
184.1081 + }
184.1082 + }
184.1083 +}
184.1084 +
184.1085 +class AttributeEntry implements Map.Entry {
184.1086 +
184.1087 + private Attribute key;
184.1088 + private Object value;
184.1089 +
184.1090 + AttributeEntry(Attribute key, Object value) {
184.1091 + this.key = key;
184.1092 + this.value = value;
184.1093 + }
184.1094 +
184.1095 + public boolean equals(Object o) {
184.1096 + if (!(o instanceof AttributeEntry)) {
184.1097 + return false;
184.1098 + }
184.1099 + AttributeEntry other = (AttributeEntry) o;
184.1100 + return other.key.equals(key) &&
184.1101 + (value == null ? other.value == null : other.value.equals(value));
184.1102 + }
184.1103 +
184.1104 + public Object getKey() {
184.1105 + return key;
184.1106 + }
184.1107 +
184.1108 + public Object getValue() {
184.1109 + return value;
184.1110 + }
184.1111 +
184.1112 + public Object setValue(Object newValue) {
184.1113 + throw new UnsupportedOperationException();
184.1114 + }
184.1115 +
184.1116 + public int hashCode() {
184.1117 + return key.hashCode() ^ (value==null ? 0 : value.hashCode());
184.1118 + }
184.1119 +
184.1120 + public String toString() {
184.1121 + return key.toString()+"="+value.toString();
184.1122 + }
184.1123 +}
185.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
185.2 +++ b/rt/emul/compact/src/main/java/java/text/CalendarBuilder.java Wed Apr 30 15:04:10 2014 +0200
185.3 @@ -0,0 +1,170 @@
185.4 +/*
185.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
185.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
185.7 + *
185.8 + * This code is free software; you can redistribute it and/or modify it
185.9 + * under the terms of the GNU General Public License version 2 only, as
185.10 + * published by the Free Software Foundation. Oracle designates this
185.11 + * particular file as subject to the "Classpath" exception as provided
185.12 + * by Oracle in the LICENSE file that accompanied this code.
185.13 + *
185.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
185.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
185.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
185.17 + * version 2 for more details (a copy is included in the LICENSE file that
185.18 + * accompanied this code).
185.19 + *
185.20 + * You should have received a copy of the GNU General Public License version
185.21 + * 2 along with this work; if not, write to the Free Software Foundation,
185.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
185.23 + *
185.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
185.25 + * or visit www.oracle.com if you need additional information or have any
185.26 + * questions.
185.27 + */
185.28 +
185.29 +package java.text;
185.30 +
185.31 +import java.util.Calendar;
185.32 +import static java.util.Calendar.*;
185.33 +
185.34 +/**
185.35 + * {@code CalendarBuilder} keeps field-value pairs for setting
185.36 + * the calendar fields of the given {@code Calendar}. It has the
185.37 + * {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
185.38 + * support. Also {@code ISO_DAY_OF_WEEK} is used to specify
185.39 + * {@code DAY_OF_WEEK} in the ISO day of week numbering.
185.40 + *
185.41 + * <p>{@code CalendarBuilder} retains the semantic of the pseudo
185.42 + * timestamp for fields. {@code CalendarBuilder} uses a single
185.43 + * int array combining fields[] and stamp[] of {@code Calendar}.
185.44 + *
185.45 + * @author Masayoshi Okutsu
185.46 + */
185.47 +class CalendarBuilder {
185.48 + /*
185.49 + * Pseudo time stamp constants used in java.util.Calendar
185.50 + */
185.51 + private static final int UNSET = 0;
185.52 + private static final int COMPUTED = 1;
185.53 + private static final int MINIMUM_USER_STAMP = 2;
185.54 +
185.55 + private static final int MAX_FIELD = FIELD_COUNT + 1;
185.56 +
185.57 + public static final int WEEK_YEAR = FIELD_COUNT;
185.58 + public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
185.59 +
185.60 + // stamp[] (lower half) and field[] (upper half) combined
185.61 + private final int[] field;
185.62 + private int nextStamp;
185.63 + private int maxFieldIndex;
185.64 +
185.65 + CalendarBuilder() {
185.66 + field = new int[MAX_FIELD * 2];
185.67 + nextStamp = MINIMUM_USER_STAMP;
185.68 + maxFieldIndex = -1;
185.69 + }
185.70 +
185.71 + CalendarBuilder set(int index, int value) {
185.72 + if (index == ISO_DAY_OF_WEEK) {
185.73 + index = DAY_OF_WEEK;
185.74 + value = toCalendarDayOfWeek(value);
185.75 + }
185.76 + field[index] = nextStamp++;
185.77 + field[MAX_FIELD + index] = value;
185.78 + if (index > maxFieldIndex && index < FIELD_COUNT) {
185.79 + maxFieldIndex = index;
185.80 + }
185.81 + return this;
185.82 + }
185.83 +
185.84 + CalendarBuilder addYear(int value) {
185.85 + field[MAX_FIELD + YEAR] += value;
185.86 + field[MAX_FIELD + WEEK_YEAR] += value;
185.87 + return this;
185.88 + }
185.89 +
185.90 + boolean isSet(int index) {
185.91 + if (index == ISO_DAY_OF_WEEK) {
185.92 + index = DAY_OF_WEEK;
185.93 + }
185.94 + return field[index] > UNSET;
185.95 + }
185.96 +
185.97 + Calendar establish(Calendar cal) {
185.98 + boolean weekDate = isSet(WEEK_YEAR)
185.99 + && field[WEEK_YEAR] > field[YEAR];
185.100 + if (weekDate && !cal.isWeekDateSupported()) {
185.101 + // Use YEAR instead
185.102 + if (!isSet(YEAR)) {
185.103 + set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
185.104 + }
185.105 + weekDate = false;
185.106 + }
185.107 +
185.108 + cal.clear();
185.109 + // Set the fields from the min stamp to the max stamp so that
185.110 + // the field resolution works in the Calendar.
185.111 + for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
185.112 + for (int index = 0; index <= maxFieldIndex; index++) {
185.113 + if (field[index] == stamp) {
185.114 + cal.set(index, field[MAX_FIELD + index]);
185.115 + break;
185.116 + }
185.117 + }
185.118 + }
185.119 +
185.120 + if (weekDate) {
185.121 + int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
185.122 + int dayOfWeek = isSet(DAY_OF_WEEK) ?
185.123 + field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
185.124 + if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
185.125 + if (dayOfWeek >= 8) {
185.126 + dayOfWeek--;
185.127 + weekOfYear += dayOfWeek / 7;
185.128 + dayOfWeek = (dayOfWeek % 7) + 1;
185.129 + } else {
185.130 + while (dayOfWeek <= 0) {
185.131 + dayOfWeek += 7;
185.132 + weekOfYear--;
185.133 + }
185.134 + }
185.135 + dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
185.136 + }
185.137 + cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
185.138 + }
185.139 + return cal;
185.140 + }
185.141 +
185.142 + public String toString() {
185.143 + StringBuilder sb = new StringBuilder();
185.144 + sb.append("CalendarBuilder:[");
185.145 + for (int i = 0; i < field.length; i++) {
185.146 + if (isSet(i)) {
185.147 + sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
185.148 + }
185.149 + }
185.150 + int lastIndex = sb.length() - 1;
185.151 + if (sb.charAt(lastIndex) == ',') {
185.152 + sb.setLength(lastIndex);
185.153 + }
185.154 + sb.append(']');
185.155 + return sb.toString();
185.156 + }
185.157 +
185.158 + static int toISODayOfWeek(int calendarDayOfWeek) {
185.159 + return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
185.160 + }
185.161 +
185.162 + static int toCalendarDayOfWeek(int isoDayOfWeek) {
185.163 + if (!isValidDayOfWeek(isoDayOfWeek)) {
185.164 + // adjust later for lenient mode
185.165 + return isoDayOfWeek;
185.166 + }
185.167 + return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
185.168 + }
185.169 +
185.170 + static boolean isValidDayOfWeek(int dayOfWeek) {
185.171 + return dayOfWeek > 0 && dayOfWeek <= 7;
185.172 + }
185.173 +}
186.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
186.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIterator.java Wed Apr 30 15:04:10 2014 +0200
186.3 @@ -0,0 +1,193 @@
186.4 +/*
186.5 + * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
186.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
186.7 + *
186.8 + * This code is free software; you can redistribute it and/or modify it
186.9 + * under the terms of the GNU General Public License version 2 only, as
186.10 + * published by the Free Software Foundation. Oracle designates this
186.11 + * particular file as subject to the "Classpath" exception as provided
186.12 + * by Oracle in the LICENSE file that accompanied this code.
186.13 + *
186.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
186.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
186.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
186.17 + * version 2 for more details (a copy is included in the LICENSE file that
186.18 + * accompanied this code).
186.19 + *
186.20 + * You should have received a copy of the GNU General Public License version
186.21 + * 2 along with this work; if not, write to the Free Software Foundation,
186.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
186.23 + *
186.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
186.25 + * or visit www.oracle.com if you need additional information or have any
186.26 + * questions.
186.27 + */
186.28 +
186.29 +/*
186.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
186.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
186.32 + *
186.33 + * The original version of this source code and documentation
186.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
186.35 + * subsidiary of IBM. These materials are provided under terms
186.36 + * of a License Agreement between Taligent and Sun. This technology
186.37 + * is protected by multiple US and International patents.
186.38 + *
186.39 + * This notice and attribution to Taligent may not be removed.
186.40 + * Taligent is a registered trademark of Taligent, Inc.
186.41 + *
186.42 + */
186.43 +
186.44 +package java.text;
186.45 +
186.46 +
186.47 +/**
186.48 + * This interface defines a protocol for bidirectional iteration over text.
186.49 + * The iterator iterates over a bounded sequence of characters. Characters
186.50 + * are indexed with values beginning with the value returned by getBeginIndex() and
186.51 + * continuing through the value returned by getEndIndex()-1.
186.52 + * <p>
186.53 + * Iterators maintain a current character index, whose valid range is from
186.54 + * getBeginIndex() to getEndIndex(); the value getEndIndex() is included to allow
186.55 + * handling of zero-length text ranges and for historical reasons.
186.56 + * The current index can be retrieved by calling getIndex() and set directly
186.57 + * by calling setIndex(), first(), and last().
186.58 + * <p>
186.59 + * The methods previous() and next() are used for iteration. They return DONE if
186.60 + * they would move outside the range from getBeginIndex() to getEndIndex() -1,
186.61 + * signaling that the iterator has reached the end of the sequence. DONE is
186.62 + * also returned by other methods to indicate that the current index is
186.63 + * outside this range.
186.64 + *
186.65 + * <P>Examples:<P>
186.66 + *
186.67 + * Traverse the text from start to finish
186.68 + * <pre>
186.69 + * public void traverseForward(CharacterIterator iter) {
186.70 + * for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
186.71 + * processChar(c);
186.72 + * }
186.73 + * }
186.74 + * </pre>
186.75 + *
186.76 + * Traverse the text backwards, from end to start
186.77 + * <pre>
186.78 + * public void traverseBackward(CharacterIterator iter) {
186.79 + * for(char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
186.80 + * processChar(c);
186.81 + * }
186.82 + * }
186.83 + * </pre>
186.84 + *
186.85 + * Traverse both forward and backward from a given position in the text.
186.86 + * Calls to notBoundary() in this example represents some
186.87 + * additional stopping criteria.
186.88 + * <pre>
186.89 + * public void traverseOut(CharacterIterator iter, int pos) {
186.90 + * for (char c = iter.setIndex(pos);
186.91 + * c != CharacterIterator.DONE && notBoundary(c);
186.92 + * c = iter.next()) {
186.93 + * }
186.94 + * int end = iter.getIndex();
186.95 + * for (char c = iter.setIndex(pos);
186.96 + * c != CharacterIterator.DONE && notBoundary(c);
186.97 + * c = iter.previous()) {
186.98 + * }
186.99 + * int start = iter.getIndex();
186.100 + * processSection(start, end);
186.101 + * }
186.102 + * </pre>
186.103 + *
186.104 + * @see StringCharacterIterator
186.105 + * @see AttributedCharacterIterator
186.106 + */
186.107 +
186.108 +public interface CharacterIterator extends Cloneable
186.109 +{
186.110 +
186.111 + /**
186.112 + * Constant that is returned when the iterator has reached either the end
186.113 + * or the beginning of the text. The value is '\\uFFFF', the "not a
186.114 + * character" value which should not occur in any valid Unicode string.
186.115 + */
186.116 + public static final char DONE = '\uFFFF';
186.117 +
186.118 + /**
186.119 + * Sets the position to getBeginIndex() and returns the character at that
186.120 + * position.
186.121 + * @return the first character in the text, or DONE if the text is empty
186.122 + * @see #getBeginIndex()
186.123 + */
186.124 + public char first();
186.125 +
186.126 + /**
186.127 + * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
186.128 + * and returns the character at that position.
186.129 + * @return the last character in the text, or DONE if the text is empty
186.130 + * @see #getEndIndex()
186.131 + */
186.132 + public char last();
186.133 +
186.134 + /**
186.135 + * Gets the character at the current position (as returned by getIndex()).
186.136 + * @return the character at the current position or DONE if the current
186.137 + * position is off the end of the text.
186.138 + * @see #getIndex()
186.139 + */
186.140 + public char current();
186.141 +
186.142 + /**
186.143 + * Increments the iterator's index by one and returns the character
186.144 + * at the new index. If the resulting index is greater or equal
186.145 + * to getEndIndex(), the current index is reset to getEndIndex() and
186.146 + * a value of DONE is returned.
186.147 + * @return the character at the new position or DONE if the new
186.148 + * position is off the end of the text range.
186.149 + */
186.150 + public char next();
186.151 +
186.152 + /**
186.153 + * Decrements the iterator's index by one and returns the character
186.154 + * at the new index. If the current index is getBeginIndex(), the index
186.155 + * remains at getBeginIndex() and a value of DONE is returned.
186.156 + * @return the character at the new position or DONE if the current
186.157 + * position is equal to getBeginIndex().
186.158 + */
186.159 + public char previous();
186.160 +
186.161 + /**
186.162 + * Sets the position to the specified position in the text and returns that
186.163 + * character.
186.164 + * @param position the position within the text. Valid values range from
186.165 + * getBeginIndex() to getEndIndex(). An IllegalArgumentException is thrown
186.166 + * if an invalid value is supplied.
186.167 + * @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
186.168 + */
186.169 + public char setIndex(int position);
186.170 +
186.171 + /**
186.172 + * Returns the start index of the text.
186.173 + * @return the index at which the text begins.
186.174 + */
186.175 + public int getBeginIndex();
186.176 +
186.177 + /**
186.178 + * Returns the end index of the text. This index is the index of the first
186.179 + * character following the end of the text.
186.180 + * @return the index after the last character in the text
186.181 + */
186.182 + public int getEndIndex();
186.183 +
186.184 + /**
186.185 + * Returns the current index.
186.186 + * @return the current index.
186.187 + */
186.188 + public int getIndex();
186.189 +
186.190 + /**
186.191 + * Create a copy of this iterator
186.192 + * @return A copy of this
186.193 + */
186.194 + public Object clone();
186.195 +
186.196 +}
187.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
187.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIteratorFieldDelegate.java Wed Apr 30 15:04:10 2014 +0200
187.3 @@ -0,0 +1,124 @@
187.4 +/*
187.5 + * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
187.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
187.7 + *
187.8 + * This code is free software; you can redistribute it and/or modify it
187.9 + * under the terms of the GNU General Public License version 2 only, as
187.10 + * published by the Free Software Foundation. Oracle designates this
187.11 + * particular file as subject to the "Classpath" exception as provided
187.12 + * by Oracle in the LICENSE file that accompanied this code.
187.13 + *
187.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
187.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
187.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
187.17 + * version 2 for more details (a copy is included in the LICENSE file that
187.18 + * accompanied this code).
187.19 + *
187.20 + * You should have received a copy of the GNU General Public License version
187.21 + * 2 along with this work; if not, write to the Free Software Foundation,
187.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
187.23 + *
187.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
187.25 + * or visit www.oracle.com if you need additional information or have any
187.26 + * questions.
187.27 + */
187.28 +package java.text;
187.29 +
187.30 +import java.util.ArrayList;
187.31 +
187.32 +/**
187.33 + * CharacterIteratorFieldDelegate combines the notifications from a Format
187.34 + * into a resulting <code>AttributedCharacterIterator</code>. The resulting
187.35 + * <code>AttributedCharacterIterator</code> can be retrieved by way of
187.36 + * the <code>getIterator</code> method.
187.37 + *
187.38 + */
187.39 +class CharacterIteratorFieldDelegate implements Format.FieldDelegate {
187.40 + /**
187.41 + * Array of AttributeStrings. Whenever <code>formatted</code> is invoked
187.42 + * for a region > size, a new instance of AttributedString is added to
187.43 + * attributedStrings. Subsequent invocations of <code>formatted</code>
187.44 + * for existing regions result in invoking addAttribute on the existing
187.45 + * AttributedStrings.
187.46 + */
187.47 + private ArrayList attributedStrings;
187.48 + /**
187.49 + * Running count of the number of characters that have
187.50 + * been encountered.
187.51 + */
187.52 + private int size;
187.53 +
187.54 +
187.55 + CharacterIteratorFieldDelegate() {
187.56 + attributedStrings = new ArrayList();
187.57 + }
187.58 +
187.59 + public void formatted(Format.Field attr, Object value, int start, int end,
187.60 + StringBuffer buffer) {
187.61 + if (start != end) {
187.62 + if (start < size) {
187.63 + // Adjust attributes of existing runs
187.64 + int index = size;
187.65 + int asIndex = attributedStrings.size() - 1;
187.66 +
187.67 + while (start < index) {
187.68 + AttributedString as = (AttributedString)attributedStrings.
187.69 + get(asIndex--);
187.70 + int newIndex = index - as.length();
187.71 + int aStart = Math.max(0, start - newIndex);
187.72 +
187.73 + as.addAttribute(attr, value, aStart, Math.min(
187.74 + end - start, as.length() - aStart) +
187.75 + aStart);
187.76 + index = newIndex;
187.77 + }
187.78 + }
187.79 + if (size < start) {
187.80 + // Pad attributes
187.81 + attributedStrings.add(new AttributedString(
187.82 + buffer.substring(size, start)));
187.83 + size = start;
187.84 + }
187.85 + if (size < end) {
187.86 + // Add new string
187.87 + int aStart = Math.max(start, size);
187.88 + AttributedString string = new AttributedString(
187.89 + buffer.substring(aStart, end));
187.90 +
187.91 + string.addAttribute(attr, value);
187.92 + attributedStrings.add(string);
187.93 + size = end;
187.94 + }
187.95 + }
187.96 + }
187.97 +
187.98 + public void formatted(int fieldID, Format.Field attr, Object value,
187.99 + int start, int end, StringBuffer buffer) {
187.100 + formatted(attr, value, start, end, buffer);
187.101 + }
187.102 +
187.103 + /**
187.104 + * Returns an <code>AttributedCharacterIterator</code> that can be used
187.105 + * to iterate over the resulting formatted String.
187.106 + *
187.107 + * @pararm string Result of formatting.
187.108 + */
187.109 + public AttributedCharacterIterator getIterator(String string) {
187.110 + // Add the last AttributedCharacterIterator if necessary
187.111 + // assert(size <= string.length());
187.112 + if (string.length() > size) {
187.113 + attributedStrings.add(new AttributedString(
187.114 + string.substring(size)));
187.115 + size = string.length();
187.116 + }
187.117 + int iCount = attributedStrings.size();
187.118 + AttributedCharacterIterator iterators[] = new
187.119 + AttributedCharacterIterator[iCount];
187.120 +
187.121 + for (int counter = 0; counter < iCount; counter++) {
187.122 + iterators[counter] = ((AttributedString)attributedStrings.
187.123 + get(counter)).getIterator();
187.124 + }
187.125 + return new AttributedString(iterators).getIterator();
187.126 + }
187.127 +}
188.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
188.2 +++ b/rt/emul/compact/src/main/java/java/text/ChoiceFormat.java Wed Apr 30 15:04:10 2014 +0200
188.3 @@ -0,0 +1,619 @@
188.4 +/*
188.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
188.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
188.7 + *
188.8 + * This code is free software; you can redistribute it and/or modify it
188.9 + * under the terms of the GNU General Public License version 2 only, as
188.10 + * published by the Free Software Foundation. Oracle designates this
188.11 + * particular file as subject to the "Classpath" exception as provided
188.12 + * by Oracle in the LICENSE file that accompanied this code.
188.13 + *
188.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
188.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
188.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
188.17 + * version 2 for more details (a copy is included in the LICENSE file that
188.18 + * accompanied this code).
188.19 + *
188.20 + * You should have received a copy of the GNU General Public License version
188.21 + * 2 along with this work; if not, write to the Free Software Foundation,
188.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
188.23 + *
188.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
188.25 + * or visit www.oracle.com if you need additional information or have any
188.26 + * questions.
188.27 + */
188.28 +
188.29 +/*
188.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
188.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
188.32 + *
188.33 + * The original version of this source code and documentation is copyrighted
188.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
188.35 + * materials are provided under terms of a License Agreement between Taligent
188.36 + * and Sun. This technology is protected by multiple US and International
188.37 + * patents. This notice and attribution to Taligent may not be removed.
188.38 + * Taligent is a registered trademark of Taligent, Inc.
188.39 + *
188.40 + */
188.41 +
188.42 +package java.text;
188.43 +
188.44 +import java.io.InvalidObjectException;
188.45 +import java.io.IOException;
188.46 +import java.io.ObjectInputStream;
188.47 +import java.util.Arrays;
188.48 +
188.49 +/**
188.50 + * A <code>ChoiceFormat</code> allows you to attach a format to a range of numbers.
188.51 + * It is generally used in a <code>MessageFormat</code> for handling plurals.
188.52 + * The choice is specified with an ascending list of doubles, where each item
188.53 + * specifies a half-open interval up to the next item:
188.54 + * <blockquote>
188.55 + * <pre>
188.56 + * X matches j if and only if limit[j] <= X < limit[j+1]
188.57 + * </pre>
188.58 + * </blockquote>
188.59 + * If there is no match, then either the first or last index is used, depending
188.60 + * on whether the number (X) is too low or too high. If the limit array is not
188.61 + * in ascending order, the results of formatting will be incorrect. ChoiceFormat
188.62 + * also accepts <code>\u221E</code> as equivalent to infinity(INF).
188.63 + *
188.64 + * <p>
188.65 + * <strong>Note:</strong>
188.66 + * <code>ChoiceFormat</code> differs from the other <code>Format</code>
188.67 + * classes in that you create a <code>ChoiceFormat</code> object with a
188.68 + * constructor (not with a <code>getInstance</code> style factory
188.69 + * method). The factory methods aren't necessary because <code>ChoiceFormat</code>
188.70 + * doesn't require any complex setup for a given locale. In fact,
188.71 + * <code>ChoiceFormat</code> doesn't implement any locale specific behavior.
188.72 + *
188.73 + * <p>
188.74 + * When creating a <code>ChoiceFormat</code>, you must specify an array of formats
188.75 + * and an array of limits. The length of these arrays must be the same.
188.76 + * For example,
188.77 + * <ul>
188.78 + * <li>
188.79 + * <em>limits</em> = {1,2,3,4,5,6,7}<br>
188.80 + * <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
188.81 + * <li>
188.82 + * <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
188.83 + * <em>formats</em> = {"no files", "one file", "many files"}<br>
188.84 + * (<code>nextDouble</code> can be used to get the next higher double, to
188.85 + * make the half-open interval.)
188.86 + * </ul>
188.87 + *
188.88 + * <p>
188.89 + * Here is a simple example that shows formatting and parsing:
188.90 + * <blockquote>
188.91 + * <pre>
188.92 + * double[] limits = {1,2,3,4,5,6,7};
188.93 + * String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
188.94 + * ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
188.95 + * ParsePosition status = new ParsePosition(0);
188.96 + * for (double i = 0.0; i <= 8.0; ++i) {
188.97 + * status.setIndex(0);
188.98 + * System.out.println(i + " -> " + form.format(i) + " -> "
188.99 + * + form.parse(form.format(i),status));
188.100 + * }
188.101 + * </pre>
188.102 + * </blockquote>
188.103 + * Here is a more complex example, with a pattern format:
188.104 + * <blockquote>
188.105 + * <pre>
188.106 + * double[] filelimits = {0,1,2};
188.107 + * String[] filepart = {"are no files","is one file","are {2} files"};
188.108 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
188.109 + * Format[] testFormats = {fileform, null, NumberFormat.getInstance()};
188.110 + * MessageFormat pattform = new MessageFormat("There {0} on {1}");
188.111 + * pattform.setFormats(testFormats);
188.112 + * Object[] testArgs = {null, "ADisk", null};
188.113 + * for (int i = 0; i < 4; ++i) {
188.114 + * testArgs[0] = new Integer(i);
188.115 + * testArgs[2] = testArgs[0];
188.116 + * System.out.println(pattform.format(testArgs));
188.117 + * }
188.118 + * </pre>
188.119 + * </blockquote>
188.120 + * <p>
188.121 + * Specifying a pattern for ChoiceFormat objects is fairly straightforward.
188.122 + * For example:
188.123 + * <blockquote>
188.124 + * <pre>
188.125 + * ChoiceFormat fmt = new ChoiceFormat(
188.126 + * "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2.");
188.127 + * System.out.println("Formatter Pattern : " + fmt.toPattern());
188.128 + *
188.129 + * System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
188.130 + * System.out.println("Format with -1.0 : " + fmt.format(-1.0));
188.131 + * System.out.println("Format with 0 : " + fmt.format(0));
188.132 + * System.out.println("Format with 0.9 : " + fmt.format(0.9));
188.133 + * System.out.println("Format with 1.0 : " + fmt.format(1));
188.134 + * System.out.println("Format with 1.5 : " + fmt.format(1.5));
188.135 + * System.out.println("Format with 2 : " + fmt.format(2));
188.136 + * System.out.println("Format with 2.1 : " + fmt.format(2.1));
188.137 + * System.out.println("Format with NaN : " + fmt.format(Double.NaN));
188.138 + * System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
188.139 + * </pre>
188.140 + * </blockquote>
188.141 + * And the output result would be like the following:
188.142 + * <blockquote>
188.143 + * <pre>
188.144 + * Format with -INF : is negative
188.145 + * Format with -1.0 : is negative
188.146 + * Format with 0 : is zero or fraction
188.147 + * Format with 0.9 : is zero or fraction
188.148 + * Format with 1.0 : is one
188.149 + * Format with 1.5 : is 1+
188.150 + * Format with 2 : is two
188.151 + * Format with 2.1 : is more than 2.
188.152 + * Format with NaN : is negative
188.153 + * Format with +INF : is more than 2.
188.154 + * </pre>
188.155 + * </blockquote>
188.156 + *
188.157 + * <h4><a name="synchronization">Synchronization</a></h4>
188.158 + *
188.159 + * <p>
188.160 + * Choice formats are not synchronized.
188.161 + * It is recommended to create separate format instances for each thread.
188.162 + * If multiple threads access a format concurrently, it must be synchronized
188.163 + * externally.
188.164 + *
188.165 + *
188.166 + * @see DecimalFormat
188.167 + * @see MessageFormat
188.168 + * @author Mark Davis
188.169 + */
188.170 +public class ChoiceFormat extends NumberFormat {
188.171 +
188.172 + // Proclaim serial compatibility with 1.1 FCS
188.173 + private static final long serialVersionUID = 1795184449645032964L;
188.174 +
188.175 + /**
188.176 + * Sets the pattern.
188.177 + * @param newPattern See the class description.
188.178 + */
188.179 + public void applyPattern(String newPattern) {
188.180 + StringBuffer[] segments = new StringBuffer[2];
188.181 + for (int i = 0; i < segments.length; ++i) {
188.182 + segments[i] = new StringBuffer();
188.183 + }
188.184 + double[] newChoiceLimits = new double[30];
188.185 + String[] newChoiceFormats = new String[30];
188.186 + int count = 0;
188.187 + int part = 0;
188.188 + double startValue = 0;
188.189 + double oldStartValue = Double.NaN;
188.190 + boolean inQuote = false;
188.191 + for (int i = 0; i < newPattern.length(); ++i) {
188.192 + char ch = newPattern.charAt(i);
188.193 + if (ch=='\'') {
188.194 + // Check for "''" indicating a literal quote
188.195 + if ((i+1)<newPattern.length() && newPattern.charAt(i+1)==ch) {
188.196 + segments[part].append(ch);
188.197 + ++i;
188.198 + } else {
188.199 + inQuote = !inQuote;
188.200 + }
188.201 + } else if (inQuote) {
188.202 + segments[part].append(ch);
188.203 + } else if (ch == '<' || ch == '#' || ch == '\u2264') {
188.204 + if (segments[0].length() == 0) {
188.205 + throw new IllegalArgumentException();
188.206 + }
188.207 + try {
188.208 + String tempBuffer = segments[0].toString();
188.209 + if (tempBuffer.equals("\u221E")) {
188.210 + startValue = Double.POSITIVE_INFINITY;
188.211 + } else if (tempBuffer.equals("-\u221E")) {
188.212 + startValue = Double.NEGATIVE_INFINITY;
188.213 + } else {
188.214 + startValue = Double.valueOf(segments[0].toString()).doubleValue();
188.215 + }
188.216 + } catch (Exception e) {
188.217 + throw new IllegalArgumentException();
188.218 + }
188.219 + if (ch == '<' && startValue != Double.POSITIVE_INFINITY &&
188.220 + startValue != Double.NEGATIVE_INFINITY) {
188.221 + startValue = nextDouble(startValue);
188.222 + }
188.223 + if (startValue <= oldStartValue) {
188.224 + throw new IllegalArgumentException();
188.225 + }
188.226 + segments[0].setLength(0);
188.227 + part = 1;
188.228 + } else if (ch == '|') {
188.229 + if (count == newChoiceLimits.length) {
188.230 + newChoiceLimits = doubleArraySize(newChoiceLimits);
188.231 + newChoiceFormats = doubleArraySize(newChoiceFormats);
188.232 + }
188.233 + newChoiceLimits[count] = startValue;
188.234 + newChoiceFormats[count] = segments[1].toString();
188.235 + ++count;
188.236 + oldStartValue = startValue;
188.237 + segments[1].setLength(0);
188.238 + part = 0;
188.239 + } else {
188.240 + segments[part].append(ch);
188.241 + }
188.242 + }
188.243 + // clean up last one
188.244 + if (part == 1) {
188.245 + if (count == newChoiceLimits.length) {
188.246 + newChoiceLimits = doubleArraySize(newChoiceLimits);
188.247 + newChoiceFormats = doubleArraySize(newChoiceFormats);
188.248 + }
188.249 + newChoiceLimits[count] = startValue;
188.250 + newChoiceFormats[count] = segments[1].toString();
188.251 + ++count;
188.252 + }
188.253 + choiceLimits = new double[count];
188.254 + System.arraycopy(newChoiceLimits, 0, choiceLimits, 0, count);
188.255 + choiceFormats = new String[count];
188.256 + System.arraycopy(newChoiceFormats, 0, choiceFormats, 0, count);
188.257 + }
188.258 +
188.259 + /**
188.260 + * Gets the pattern.
188.261 + */
188.262 + public String toPattern() {
188.263 + StringBuffer result = new StringBuffer();
188.264 + for (int i = 0; i < choiceLimits.length; ++i) {
188.265 + if (i != 0) {
188.266 + result.append('|');
188.267 + }
188.268 + // choose based upon which has less precision
188.269 + // approximate that by choosing the closest one to an integer.
188.270 + // could do better, but it's not worth it.
188.271 + double less = previousDouble(choiceLimits[i]);
188.272 + double tryLessOrEqual = Math.abs(Math.IEEEremainder(choiceLimits[i], 1.0d));
188.273 + double tryLess = Math.abs(Math.IEEEremainder(less, 1.0d));
188.274 +
188.275 + if (tryLessOrEqual < tryLess) {
188.276 + result.append(""+choiceLimits[i]);
188.277 + result.append('#');
188.278 + } else {
188.279 + if (choiceLimits[i] == Double.POSITIVE_INFINITY) {
188.280 + result.append("\u221E");
188.281 + } else if (choiceLimits[i] == Double.NEGATIVE_INFINITY) {
188.282 + result.append("-\u221E");
188.283 + } else {
188.284 + result.append(""+less);
188.285 + }
188.286 + result.append('<');
188.287 + }
188.288 + // Append choiceFormats[i], using quotes if there are special characters.
188.289 + // Single quotes themselves must be escaped in either case.
188.290 + String text = choiceFormats[i];
188.291 + boolean needQuote = text.indexOf('<') >= 0
188.292 + || text.indexOf('#') >= 0
188.293 + || text.indexOf('\u2264') >= 0
188.294 + || text.indexOf('|') >= 0;
188.295 + if (needQuote) result.append('\'');
188.296 + if (text.indexOf('\'') < 0) result.append(text);
188.297 + else {
188.298 + for (int j=0; j<text.length(); ++j) {
188.299 + char c = text.charAt(j);
188.300 + result.append(c);
188.301 + if (c == '\'') result.append(c);
188.302 + }
188.303 + }
188.304 + if (needQuote) result.append('\'');
188.305 + }
188.306 + return result.toString();
188.307 + }
188.308 +
188.309 + /**
188.310 + * Constructs with limits and corresponding formats based on the pattern.
188.311 + * @see #applyPattern
188.312 + */
188.313 + public ChoiceFormat(String newPattern) {
188.314 + applyPattern(newPattern);
188.315 + }
188.316 +
188.317 + /**
188.318 + * Constructs with the limits and the corresponding formats.
188.319 + * @see #setChoices
188.320 + */
188.321 + public ChoiceFormat(double[] limits, String[] formats) {
188.322 + setChoices(limits, formats);
188.323 + }
188.324 +
188.325 + /**
188.326 + * Set the choices to be used in formatting.
188.327 + * @param limits contains the top value that you want
188.328 + * parsed with that format,and should be in ascending sorted order. When
188.329 + * formatting X, the choice will be the i, where
188.330 + * limit[i] <= X < limit[i+1].
188.331 + * If the limit array is not in ascending order, the results of formatting
188.332 + * will be incorrect.
188.333 + * @param formats are the formats you want to use for each limit.
188.334 + * They can be either Format objects or Strings.
188.335 + * When formatting with object Y,
188.336 + * if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
188.337 + * is called. Otherwise Y.toString() is called.
188.338 + */
188.339 + public void setChoices(double[] limits, String formats[]) {
188.340 + if (limits.length != formats.length) {
188.341 + throw new IllegalArgumentException(
188.342 + "Array and limit arrays must be of the same length.");
188.343 + }
188.344 + choiceLimits = limits;
188.345 + choiceFormats = formats;
188.346 + }
188.347 +
188.348 + /**
188.349 + * Get the limits passed in the constructor.
188.350 + * @return the limits.
188.351 + */
188.352 + public double[] getLimits() {
188.353 + return choiceLimits;
188.354 + }
188.355 +
188.356 + /**
188.357 + * Get the formats passed in the constructor.
188.358 + * @return the formats.
188.359 + */
188.360 + public Object[] getFormats() {
188.361 + return choiceFormats;
188.362 + }
188.363 +
188.364 + // Overrides
188.365 +
188.366 + /**
188.367 + * Specialization of format. This method really calls
188.368 + * <code>format(double, StringBuffer, FieldPosition)</code>
188.369 + * thus the range of longs that are supported is only equal to
188.370 + * the range that can be stored by double. This will never be
188.371 + * a practical limitation.
188.372 + */
188.373 + public StringBuffer format(long number, StringBuffer toAppendTo,
188.374 + FieldPosition status) {
188.375 + return format((double)number, toAppendTo, status);
188.376 + }
188.377 +
188.378 + /**
188.379 + * Returns pattern with formatted double.
188.380 + * @param number number to be formatted & substituted.
188.381 + * @param toAppendTo where text is appended.
188.382 + * @param status ignore no useful status is returned.
188.383 + */
188.384 + public StringBuffer format(double number, StringBuffer toAppendTo,
188.385 + FieldPosition status) {
188.386 + // find the number
188.387 + int i;
188.388 + for (i = 0; i < choiceLimits.length; ++i) {
188.389 + if (!(number >= choiceLimits[i])) {
188.390 + // same as number < choiceLimits, except catchs NaN
188.391 + break;
188.392 + }
188.393 + }
188.394 + --i;
188.395 + if (i < 0) i = 0;
188.396 + // return either a formatted number, or a string
188.397 + return toAppendTo.append(choiceFormats[i]);
188.398 + }
188.399 +
188.400 + /**
188.401 + * Parses a Number from the input text.
188.402 + * @param text the source text.
188.403 + * @param status an input-output parameter. On input, the
188.404 + * status.index field indicates the first character of the
188.405 + * source text that should be parsed. On exit, if no error
188.406 + * occured, status.index is set to the first unparsed character
188.407 + * in the source text. On exit, if an error did occur,
188.408 + * status.index is unchanged and status.errorIndex is set to the
188.409 + * first index of the character that caused the parse to fail.
188.410 + * @return A Number representing the value of the number parsed.
188.411 + */
188.412 + public Number parse(String text, ParsePosition status) {
188.413 + // find the best number (defined as the one with the longest parse)
188.414 + int start = status.index;
188.415 + int furthest = start;
188.416 + double bestNumber = Double.NaN;
188.417 + double tempNumber = 0.0;
188.418 + for (int i = 0; i < choiceFormats.length; ++i) {
188.419 + String tempString = choiceFormats[i];
188.420 + if (text.regionMatches(start, tempString, 0, tempString.length())) {
188.421 + status.index = start + tempString.length();
188.422 + tempNumber = choiceLimits[i];
188.423 + if (status.index > furthest) {
188.424 + furthest = status.index;
188.425 + bestNumber = tempNumber;
188.426 + if (furthest == text.length()) break;
188.427 + }
188.428 + }
188.429 + }
188.430 + status.index = furthest;
188.431 + if (status.index == start) {
188.432 + status.errorIndex = furthest;
188.433 + }
188.434 + return new Double(bestNumber);
188.435 + }
188.436 +
188.437 + /**
188.438 + * Finds the least double greater than d.
188.439 + * If NaN, returns same value.
188.440 + * <p>Used to make half-open intervals.
188.441 + * @see #previousDouble
188.442 + */
188.443 + public static final double nextDouble (double d) {
188.444 + return nextDouble(d,true);
188.445 + }
188.446 +
188.447 + /**
188.448 + * Finds the greatest double less than d.
188.449 + * If NaN, returns same value.
188.450 + * @see #nextDouble
188.451 + */
188.452 + public static final double previousDouble (double d) {
188.453 + return nextDouble(d,false);
188.454 + }
188.455 +
188.456 + /**
188.457 + * Overrides Cloneable
188.458 + */
188.459 + public Object clone()
188.460 + {
188.461 + ChoiceFormat other = (ChoiceFormat) super.clone();
188.462 + // for primitives or immutables, shallow clone is enough
188.463 + other.choiceLimits = (double[]) choiceLimits.clone();
188.464 + other.choiceFormats = (String[]) choiceFormats.clone();
188.465 + return other;
188.466 + }
188.467 +
188.468 + /**
188.469 + * Generates a hash code for the message format object.
188.470 + */
188.471 + public int hashCode() {
188.472 + int result = choiceLimits.length;
188.473 + if (choiceFormats.length > 0) {
188.474 + // enough for reasonable distribution
188.475 + result ^= choiceFormats[choiceFormats.length-1].hashCode();
188.476 + }
188.477 + return result;
188.478 + }
188.479 +
188.480 + /**
188.481 + * Equality comparision between two
188.482 + */
188.483 + public boolean equals(Object obj) {
188.484 + if (obj == null) return false;
188.485 + if (this == obj) // quick check
188.486 + return true;
188.487 + if (getClass() != obj.getClass())
188.488 + return false;
188.489 + ChoiceFormat other = (ChoiceFormat) obj;
188.490 + return (Arrays.equals(choiceLimits, other.choiceLimits)
188.491 + && Arrays.equals(choiceFormats, other.choiceFormats));
188.492 + }
188.493 +
188.494 + /**
188.495 + * After reading an object from the input stream, do a simple verification
188.496 + * to maintain class invariants.
188.497 + * @throws InvalidObjectException if the objects read from the stream is invalid.
188.498 + */
188.499 + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
188.500 + in.defaultReadObject();
188.501 + if (choiceLimits.length != choiceFormats.length) {
188.502 + throw new InvalidObjectException(
188.503 + "limits and format arrays of different length.");
188.504 + }
188.505 + }
188.506 +
188.507 + // ===============privates===========================
188.508 +
188.509 + /**
188.510 + * A list of lower bounds for the choices. The formatter will return
188.511 + * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
188.512 + * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
188.513 + * @serial
188.514 + */
188.515 + private double[] choiceLimits;
188.516 +
188.517 + /**
188.518 + * A list of choice strings. The formatter will return
188.519 + * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
188.520 + * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
188.521 + * @serial
188.522 + */
188.523 + private String[] choiceFormats;
188.524 +
188.525 + /*
188.526 + static final long SIGN = 0x8000000000000000L;
188.527 + static final long EXPONENT = 0x7FF0000000000000L;
188.528 + static final long SIGNIFICAND = 0x000FFFFFFFFFFFFFL;
188.529 +
188.530 + private static double nextDouble (double d, boolean positive) {
188.531 + if (Double.isNaN(d) || Double.isInfinite(d)) {
188.532 + return d;
188.533 + }
188.534 + long bits = Double.doubleToLongBits(d);
188.535 + long significand = bits & SIGNIFICAND;
188.536 + if (bits < 0) {
188.537 + significand |= (SIGN | EXPONENT);
188.538 + }
188.539 + long exponent = bits & EXPONENT;
188.540 + if (positive) {
188.541 + significand += 1;
188.542 + // FIXME fix overflow & underflow
188.543 + } else {
188.544 + significand -= 1;
188.545 + // FIXME fix overflow & underflow
188.546 + }
188.547 + bits = exponent | (significand & ~EXPONENT);
188.548 + return Double.longBitsToDouble(bits);
188.549 + }
188.550 + */
188.551 +
188.552 + static final long SIGN = 0x8000000000000000L;
188.553 + static final long EXPONENT = 0x7FF0000000000000L;
188.554 + static final long POSITIVEINFINITY = 0x7FF0000000000000L;
188.555 +
188.556 + /**
188.557 + * Finds the least double greater than d (if positive == true),
188.558 + * or the greatest double less than d (if positive == false).
188.559 + * If NaN, returns same value.
188.560 + *
188.561 + * Does not affect floating-point flags,
188.562 + * provided these member functions do not:
188.563 + * Double.longBitsToDouble(long)
188.564 + * Double.doubleToLongBits(double)
188.565 + * Double.isNaN(double)
188.566 + */
188.567 + public static double nextDouble (double d, boolean positive) {
188.568 +
188.569 + /* filter out NaN's */
188.570 + if (Double.isNaN(d)) {
188.571 + return d;
188.572 + }
188.573 +
188.574 + /* zero's are also a special case */
188.575 + if (d == 0.0) {
188.576 + double smallestPositiveDouble = Double.longBitsToDouble(1L);
188.577 + if (positive) {
188.578 + return smallestPositiveDouble;
188.579 + } else {
188.580 + return -smallestPositiveDouble;
188.581 + }
188.582 + }
188.583 +
188.584 + /* if entering here, d is a nonzero value */
188.585 +
188.586 + /* hold all bits in a long for later use */
188.587 + long bits = Double.doubleToLongBits(d);
188.588 +
188.589 + /* strip off the sign bit */
188.590 + long magnitude = bits & ~SIGN;
188.591 +
188.592 + /* if next double away from zero, increase magnitude */
188.593 + if ((bits > 0) == positive) {
188.594 + if (magnitude != POSITIVEINFINITY) {
188.595 + magnitude += 1;
188.596 + }
188.597 + }
188.598 + /* else decrease magnitude */
188.599 + else {
188.600 + magnitude -= 1;
188.601 + }
188.602 +
188.603 + /* restore sign bit and return */
188.604 + long signbit = bits & SIGN;
188.605 + return Double.longBitsToDouble (magnitude | signbit);
188.606 + }
188.607 +
188.608 + private static double[] doubleArraySize(double[] array) {
188.609 + int oldSize = array.length;
188.610 + double[] newArray = new double[oldSize * 2];
188.611 + System.arraycopy(array, 0, newArray, 0, oldSize);
188.612 + return newArray;
188.613 + }
188.614 +
188.615 + private String[] doubleArraySize(String[] array) {
188.616 + int oldSize = array.length;
188.617 + String[] newArray = new String[oldSize * 2];
188.618 + System.arraycopy(array, 0, newArray, 0, oldSize);
188.619 + return newArray;
188.620 + }
188.621 +
188.622 +}
189.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
189.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormat.java Wed Apr 30 15:04:10 2014 +0200
189.3 @@ -0,0 +1,1025 @@
189.4 +/*
189.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
189.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
189.7 + *
189.8 + * This code is free software; you can redistribute it and/or modify it
189.9 + * under the terms of the GNU General Public License version 2 only, as
189.10 + * published by the Free Software Foundation. Oracle designates this
189.11 + * particular file as subject to the "Classpath" exception as provided
189.12 + * by Oracle in the LICENSE file that accompanied this code.
189.13 + *
189.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
189.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
189.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
189.17 + * version 2 for more details (a copy is included in the LICENSE file that
189.18 + * accompanied this code).
189.19 + *
189.20 + * You should have received a copy of the GNU General Public License version
189.21 + * 2 along with this work; if not, write to the Free Software Foundation,
189.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
189.23 + *
189.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
189.25 + * or visit www.oracle.com if you need additional information or have any
189.26 + * questions.
189.27 + */
189.28 +
189.29 +/*
189.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
189.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
189.32 + *
189.33 + * The original version of this source code and documentation is copyrighted
189.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
189.35 + * materials are provided under terms of a License Agreement between Taligent
189.36 + * and Sun. This technology is protected by multiple US and International
189.37 + * patents. This notice and attribution to Taligent may not be removed.
189.38 + * Taligent is a registered trademark of Taligent, Inc.
189.39 + *
189.40 + */
189.41 +
189.42 +package java.text;
189.43 +
189.44 +import java.io.InvalidObjectException;
189.45 +import java.util.Calendar;
189.46 +import java.util.Date;
189.47 +import java.util.HashMap;
189.48 +import java.util.Locale;
189.49 +import java.util.Map;
189.50 +import java.util.MissingResourceException;
189.51 +import java.util.TimeZone;
189.52 +
189.53 +/**
189.54 + * {@code DateFormat} is an abstract class for date/time formatting subclasses which
189.55 + * formats and parses dates or time in a language-independent manner.
189.56 + * The date/time formatting subclass, such as {@link SimpleDateFormat}, allows for
189.57 + * formatting (i.e., date -> text), parsing (text -> date), and
189.58 + * normalization. The date is represented as a <code>Date</code> object or
189.59 + * as the milliseconds since January 1, 1970, 00:00:00 GMT.
189.60 + *
189.61 + * <p>{@code DateFormat} provides many class methods for obtaining default date/time
189.62 + * formatters based on the default or a given locale and a number of formatting
189.63 + * styles. The formatting styles include {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, and {@link #SHORT}. More
189.64 + * detail and examples of using these styles are provided in the method
189.65 + * descriptions.
189.66 + *
189.67 + * <p>{@code DateFormat} helps you to format and parse dates for any locale.
189.68 + * Your code can be completely independent of the locale conventions for
189.69 + * months, days of the week, or even the calendar format: lunar vs. solar.
189.70 + *
189.71 + * <p>To format a date for the current Locale, use one of the
189.72 + * static factory methods:
189.73 + * <pre>
189.74 + * myString = DateFormat.getDateInstance().format(myDate);
189.75 + * </pre>
189.76 + * <p>If you are formatting multiple dates, it is
189.77 + * more efficient to get the format and use it multiple times so that
189.78 + * the system doesn't have to fetch the information about the local
189.79 + * language and country conventions multiple times.
189.80 + * <pre>
189.81 + * DateFormat df = DateFormat.getDateInstance();
189.82 + * for (int i = 0; i < myDate.length; ++i) {
189.83 + * output.println(df.format(myDate[i]) + "; ");
189.84 + * }
189.85 + * </pre>
189.86 + * <p>To format a date for a different Locale, specify it in the
189.87 + * call to {@link #getDateInstance(int, Locale) getDateInstance()}.
189.88 + * <pre>
189.89 + * DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
189.90 + * </pre>
189.91 + * <p>You can use a DateFormat to parse also.
189.92 + * <pre>
189.93 + * myDate = df.parse(myString);
189.94 + * </pre>
189.95 + * <p>Use {@code getDateInstance} to get the normal date format for that country.
189.96 + * There are other static factory methods available.
189.97 + * Use {@code getTimeInstance} to get the time format for that country.
189.98 + * Use {@code getDateTimeInstance} to get a date and time format. You can pass in
189.99 + * different options to these factory methods to control the length of the
189.100 + * result; from {@link #SHORT} to {@link #MEDIUM} to {@link #LONG} to {@link #FULL}. The exact result depends
189.101 + * on the locale, but generally:
189.102 + * <ul><li>{@link #SHORT} is completely numeric, such as {@code 12.13.52} or {@code 3:30pm}
189.103 + * <li>{@link #MEDIUM} is longer, such as {@code Jan 12, 1952}
189.104 + * <li>{@link #LONG} is longer, such as {@code January 12, 1952} or {@code 3:30:32pm}
189.105 + * <li>{@link #FULL} is pretty completely specified, such as
189.106 + * {@code Tuesday, April 12, 1952 AD or 3:30:42pm PST}.
189.107 + * </ul>
189.108 + *
189.109 + * <p>You can also set the time zone on the format if you wish.
189.110 + * If you want even more control over the format or parsing,
189.111 + * (or want to give your users more control),
189.112 + * you can try casting the {@code DateFormat} you get from the factory methods
189.113 + * to a {@link SimpleDateFormat}. This will work for the majority
189.114 + * of countries; just remember to put it in a {@code try} block in case you
189.115 + * encounter an unusual one.
189.116 + *
189.117 + * <p>You can also use forms of the parse and format methods with
189.118 + * {@link ParsePosition} and {@link FieldPosition} to
189.119 + * allow you to
189.120 + * <ul><li>progressively parse through pieces of a string.
189.121 + * <li>align any particular field, or find out where it is for selection
189.122 + * on the screen.
189.123 + * </ul>
189.124 + *
189.125 + * <h4><a name="synchronization">Synchronization</a></h4>
189.126 + *
189.127 + * <p>
189.128 + * Date formats are not synchronized.
189.129 + * It is recommended to create separate format instances for each thread.
189.130 + * If multiple threads access a format concurrently, it must be synchronized
189.131 + * externally.
189.132 + *
189.133 + * @see Format
189.134 + * @see NumberFormat
189.135 + * @see SimpleDateFormat
189.136 + * @see java.util.Calendar
189.137 + * @see java.util.GregorianCalendar
189.138 + * @see java.util.TimeZone
189.139 + * @author Mark Davis, Chen-Lieh Huang, Alan Liu
189.140 + */
189.141 +public abstract class DateFormat extends Format {
189.142 +
189.143 + /**
189.144 + * The {@link Calendar} instance used for calculating the date-time fields
189.145 + * and the instant of time. This field is used for both formatting and
189.146 + * parsing.
189.147 + *
189.148 + * <p>Subclasses should initialize this field to a {@link Calendar}
189.149 + * appropriate for the {@link Locale} associated with this
189.150 + * <code>DateFormat</code>.
189.151 + * @serial
189.152 + */
189.153 + protected Calendar calendar;
189.154 +
189.155 + /**
189.156 + * The number formatter that <code>DateFormat</code> uses to format numbers
189.157 + * in dates and times. Subclasses should initialize this to a number format
189.158 + * appropriate for the locale associated with this <code>DateFormat</code>.
189.159 + * @serial
189.160 + */
189.161 + protected NumberFormat numberFormat;
189.162 +
189.163 + /**
189.164 + * Useful constant for ERA field alignment.
189.165 + * Used in FieldPosition of date/time formatting.
189.166 + */
189.167 + public final static int ERA_FIELD = 0;
189.168 + /**
189.169 + * Useful constant for YEAR field alignment.
189.170 + * Used in FieldPosition of date/time formatting.
189.171 + */
189.172 + public final static int YEAR_FIELD = 1;
189.173 + /**
189.174 + * Useful constant for MONTH field alignment.
189.175 + * Used in FieldPosition of date/time formatting.
189.176 + */
189.177 + public final static int MONTH_FIELD = 2;
189.178 + /**
189.179 + * Useful constant for DATE field alignment.
189.180 + * Used in FieldPosition of date/time formatting.
189.181 + */
189.182 + public final static int DATE_FIELD = 3;
189.183 + /**
189.184 + * Useful constant for one-based HOUR_OF_DAY field alignment.
189.185 + * Used in FieldPosition of date/time formatting.
189.186 + * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
189.187 + * For example, 23:59 + 01:00 results in 24:59.
189.188 + */
189.189 + public final static int HOUR_OF_DAY1_FIELD = 4;
189.190 + /**
189.191 + * Useful constant for zero-based HOUR_OF_DAY field alignment.
189.192 + * Used in FieldPosition of date/time formatting.
189.193 + * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
189.194 + * For example, 23:59 + 01:00 results in 00:59.
189.195 + */
189.196 + public final static int HOUR_OF_DAY0_FIELD = 5;
189.197 + /**
189.198 + * Useful constant for MINUTE field alignment.
189.199 + * Used in FieldPosition of date/time formatting.
189.200 + */
189.201 + public final static int MINUTE_FIELD = 6;
189.202 + /**
189.203 + * Useful constant for SECOND field alignment.
189.204 + * Used in FieldPosition of date/time formatting.
189.205 + */
189.206 + public final static int SECOND_FIELD = 7;
189.207 + /**
189.208 + * Useful constant for MILLISECOND field alignment.
189.209 + * Used in FieldPosition of date/time formatting.
189.210 + */
189.211 + public final static int MILLISECOND_FIELD = 8;
189.212 + /**
189.213 + * Useful constant for DAY_OF_WEEK field alignment.
189.214 + * Used in FieldPosition of date/time formatting.
189.215 + */
189.216 + public final static int DAY_OF_WEEK_FIELD = 9;
189.217 + /**
189.218 + * Useful constant for DAY_OF_YEAR field alignment.
189.219 + * Used in FieldPosition of date/time formatting.
189.220 + */
189.221 + public final static int DAY_OF_YEAR_FIELD = 10;
189.222 + /**
189.223 + * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
189.224 + * Used in FieldPosition of date/time formatting.
189.225 + */
189.226 + public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
189.227 + /**
189.228 + * Useful constant for WEEK_OF_YEAR field alignment.
189.229 + * Used in FieldPosition of date/time formatting.
189.230 + */
189.231 + public final static int WEEK_OF_YEAR_FIELD = 12;
189.232 + /**
189.233 + * Useful constant for WEEK_OF_MONTH field alignment.
189.234 + * Used in FieldPosition of date/time formatting.
189.235 + */
189.236 + public final static int WEEK_OF_MONTH_FIELD = 13;
189.237 + /**
189.238 + * Useful constant for AM_PM field alignment.
189.239 + * Used in FieldPosition of date/time formatting.
189.240 + */
189.241 + public final static int AM_PM_FIELD = 14;
189.242 + /**
189.243 + * Useful constant for one-based HOUR field alignment.
189.244 + * Used in FieldPosition of date/time formatting.
189.245 + * HOUR1_FIELD is used for the one-based 12-hour clock.
189.246 + * For example, 11:30 PM + 1 hour results in 12:30 AM.
189.247 + */
189.248 + public final static int HOUR1_FIELD = 15;
189.249 + /**
189.250 + * Useful constant for zero-based HOUR field alignment.
189.251 + * Used in FieldPosition of date/time formatting.
189.252 + * HOUR0_FIELD is used for the zero-based 12-hour clock.
189.253 + * For example, 11:30 PM + 1 hour results in 00:30 AM.
189.254 + */
189.255 + public final static int HOUR0_FIELD = 16;
189.256 + /**
189.257 + * Useful constant for TIMEZONE field alignment.
189.258 + * Used in FieldPosition of date/time formatting.
189.259 + */
189.260 + public final static int TIMEZONE_FIELD = 17;
189.261 +
189.262 + // Proclaim serial compatibility with 1.1 FCS
189.263 + private static final long serialVersionUID = 7218322306649953788L;
189.264 +
189.265 + /**
189.266 + * Overrides Format.
189.267 + * Formats a time object into a time string. Examples of time objects
189.268 + * are a time value expressed in milliseconds and a Date object.
189.269 + * @param obj must be a Number or a Date.
189.270 + * @param toAppendTo the string buffer for the returning time string.
189.271 + * @return the string buffer passed in as toAppendTo, with formatted text appended.
189.272 + * @param fieldPosition keeps track of the position of the field
189.273 + * within the returned string.
189.274 + * On input: an alignment field,
189.275 + * if desired. On output: the offsets of the alignment field. For
189.276 + * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
189.277 + * if the given fieldPosition is DateFormat.YEAR_FIELD, the
189.278 + * begin index and end index of fieldPosition will be set to
189.279 + * 0 and 4, respectively.
189.280 + * Notice that if the same time field appears
189.281 + * more than once in a pattern, the fieldPosition will be set for the first
189.282 + * occurrence of that time field. For instance, formatting a Date to
189.283 + * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
189.284 + * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
189.285 + * the begin index and end index of fieldPosition will be set to
189.286 + * 5 and 8, respectively, for the first occurrence of the timezone
189.287 + * pattern character 'z'.
189.288 + * @see java.text.Format
189.289 + */
189.290 + public final StringBuffer format(Object obj, StringBuffer toAppendTo,
189.291 + FieldPosition fieldPosition)
189.292 + {
189.293 + if (obj instanceof Date)
189.294 + return format( (Date)obj, toAppendTo, fieldPosition );
189.295 + else if (obj instanceof Number)
189.296 + return format( new Date(((Number)obj).longValue()),
189.297 + toAppendTo, fieldPosition );
189.298 + else
189.299 + throw new IllegalArgumentException("Cannot format given Object as a Date");
189.300 + }
189.301 +
189.302 + /**
189.303 + * Formats a Date into a date/time string.
189.304 + * @param date a Date to be formatted into a date/time string.
189.305 + * @param toAppendTo the string buffer for the returning date/time string.
189.306 + * @param fieldPosition keeps track of the position of the field
189.307 + * within the returned string.
189.308 + * On input: an alignment field,
189.309 + * if desired. On output: the offsets of the alignment field. For
189.310 + * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
189.311 + * if the given fieldPosition is DateFormat.YEAR_FIELD, the
189.312 + * begin index and end index of fieldPosition will be set to
189.313 + * 0 and 4, respectively.
189.314 + * Notice that if the same time field appears
189.315 + * more than once in a pattern, the fieldPosition will be set for the first
189.316 + * occurrence of that time field. For instance, formatting a Date to
189.317 + * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
189.318 + * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
189.319 + * the begin index and end index of fieldPosition will be set to
189.320 + * 5 and 8, respectively, for the first occurrence of the timezone
189.321 + * pattern character 'z'.
189.322 + * @return the string buffer passed in as toAppendTo, with formatted text appended.
189.323 + */
189.324 + public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
189.325 + FieldPosition fieldPosition);
189.326 +
189.327 + /**
189.328 + * Formats a Date into a date/time string.
189.329 + * @param date the time value to be formatted into a time string.
189.330 + * @return the formatted time string.
189.331 + */
189.332 + public final String format(Date date)
189.333 + {
189.334 + return format(date, new StringBuffer(),
189.335 + DontCareFieldPosition.INSTANCE).toString();
189.336 + }
189.337 +
189.338 + /**
189.339 + * Parses text from the beginning of the given string to produce a date.
189.340 + * The method may not use the entire text of the given string.
189.341 + * <p>
189.342 + * See the {@link #parse(String, ParsePosition)} method for more information
189.343 + * on date parsing.
189.344 + *
189.345 + * @param source A <code>String</code> whose beginning should be parsed.
189.346 + * @return A <code>Date</code> parsed from the string.
189.347 + * @exception ParseException if the beginning of the specified string
189.348 + * cannot be parsed.
189.349 + */
189.350 + public Date parse(String source) throws ParseException
189.351 + {
189.352 + ParsePosition pos = new ParsePosition(0);
189.353 + Date result = parse(source, pos);
189.354 + if (pos.index == 0)
189.355 + throw new ParseException("Unparseable date: \"" + source + "\"" ,
189.356 + pos.errorIndex);
189.357 + return result;
189.358 + }
189.359 +
189.360 + /**
189.361 + * Parse a date/time string according to the given parse position. For
189.362 + * example, a time text {@code "07/10/96 4:5 PM, PDT"} will be parsed into a {@code Date}
189.363 + * that is equivalent to {@code Date(837039900000L)}.
189.364 + *
189.365 + * <p> By default, parsing is lenient: If the input is not in the form used
189.366 + * by this object's format method but can still be parsed as a date, then
189.367 + * the parse succeeds. Clients may insist on strict adherence to the
189.368 + * format by calling {@link #setLenient(boolean) setLenient(false)}.
189.369 + *
189.370 + * <p>This parsing operation uses the {@link #calendar} to produce
189.371 + * a {@code Date}. As a result, the {@code calendar}'s date-time
189.372 + * fields and the {@code TimeZone} value may have been
189.373 + * overwritten, depending on subclass implementations. Any {@code
189.374 + * TimeZone} value that has previously been set by a call to
189.375 + * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
189.376 + * to be restored for further operations.
189.377 + *
189.378 + * @param source The date/time string to be parsed
189.379 + *
189.380 + * @param pos On input, the position at which to start parsing; on
189.381 + * output, the position at which parsing terminated, or the
189.382 + * start position if the parse failed.
189.383 + *
189.384 + * @return A {@code Date}, or {@code null} if the input could not be parsed
189.385 + */
189.386 + public abstract Date parse(String source, ParsePosition pos);
189.387 +
189.388 + /**
189.389 + * Parses text from a string to produce a <code>Date</code>.
189.390 + * <p>
189.391 + * The method attempts to parse text starting at the index given by
189.392 + * <code>pos</code>.
189.393 + * If parsing succeeds, then the index of <code>pos</code> is updated
189.394 + * to the index after the last character used (parsing does not necessarily
189.395 + * use all characters up to the end of the string), and the parsed
189.396 + * date is returned. The updated <code>pos</code> can be used to
189.397 + * indicate the starting point for the next call to this method.
189.398 + * If an error occurs, then the index of <code>pos</code> is not
189.399 + * changed, the error index of <code>pos</code> is set to the index of
189.400 + * the character where the error occurred, and null is returned.
189.401 + * <p>
189.402 + * See the {@link #parse(String, ParsePosition)} method for more information
189.403 + * on date parsing.
189.404 + *
189.405 + * @param source A <code>String</code>, part of which should be parsed.
189.406 + * @param pos A <code>ParsePosition</code> object with index and error
189.407 + * index information as described above.
189.408 + * @return A <code>Date</code> parsed from the string. In case of
189.409 + * error, returns null.
189.410 + * @exception NullPointerException if <code>pos</code> is null.
189.411 + */
189.412 + public Object parseObject(String source, ParsePosition pos) {
189.413 + return parse(source, pos);
189.414 + }
189.415 +
189.416 + /**
189.417 + * Constant for full style pattern.
189.418 + */
189.419 + public static final int FULL = 0;
189.420 + /**
189.421 + * Constant for long style pattern.
189.422 + */
189.423 + public static final int LONG = 1;
189.424 + /**
189.425 + * Constant for medium style pattern.
189.426 + */
189.427 + public static final int MEDIUM = 2;
189.428 + /**
189.429 + * Constant for short style pattern.
189.430 + */
189.431 + public static final int SHORT = 3;
189.432 + /**
189.433 + * Constant for default style pattern. Its value is MEDIUM.
189.434 + */
189.435 + public static final int DEFAULT = MEDIUM;
189.436 +
189.437 + /**
189.438 + * Gets the time formatter with the default formatting style
189.439 + * for the default locale.
189.440 + * @return a time formatter.
189.441 + */
189.442 + public final static DateFormat getTimeInstance()
189.443 + {
189.444 + return get(DEFAULT, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
189.445 + }
189.446 +
189.447 + /**
189.448 + * Gets the time formatter with the given formatting style
189.449 + * for the default locale.
189.450 + * @param style the given formatting style. For example,
189.451 + * SHORT for "h:mm a" in the US locale.
189.452 + * @return a time formatter.
189.453 + */
189.454 + public final static DateFormat getTimeInstance(int style)
189.455 + {
189.456 + return get(style, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
189.457 + }
189.458 +
189.459 + /**
189.460 + * Gets the time formatter with the given formatting style
189.461 + * for the given locale.
189.462 + * @param style the given formatting style. For example,
189.463 + * SHORT for "h:mm a" in the US locale.
189.464 + * @param aLocale the given locale.
189.465 + * @return a time formatter.
189.466 + */
189.467 + public final static DateFormat getTimeInstance(int style,
189.468 + Locale aLocale)
189.469 + {
189.470 + return get(style, 0, 1, aLocale);
189.471 + }
189.472 +
189.473 + /**
189.474 + * Gets the date formatter with the default formatting style
189.475 + * for the default locale.
189.476 + * @return a date formatter.
189.477 + */
189.478 + public final static DateFormat getDateInstance()
189.479 + {
189.480 + return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
189.481 + }
189.482 +
189.483 + /**
189.484 + * Gets the date formatter with the given formatting style
189.485 + * for the default locale.
189.486 + * @param style the given formatting style. For example,
189.487 + * SHORT for "M/d/yy" in the US locale.
189.488 + * @return a date formatter.
189.489 + */
189.490 + public final static DateFormat getDateInstance(int style)
189.491 + {
189.492 + return get(0, style, 2, Locale.getDefault(Locale.Category.FORMAT));
189.493 + }
189.494 +
189.495 + /**
189.496 + * Gets the date formatter with the given formatting style
189.497 + * for the given locale.
189.498 + * @param style the given formatting style. For example,
189.499 + * SHORT for "M/d/yy" in the US locale.
189.500 + * @param aLocale the given locale.
189.501 + * @return a date formatter.
189.502 + */
189.503 + public final static DateFormat getDateInstance(int style,
189.504 + Locale aLocale)
189.505 + {
189.506 + return get(0, style, 2, aLocale);
189.507 + }
189.508 +
189.509 + /**
189.510 + * Gets the date/time formatter with the default formatting style
189.511 + * for the default locale.
189.512 + * @return a date/time formatter.
189.513 + */
189.514 + public final static DateFormat getDateTimeInstance()
189.515 + {
189.516 + return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT));
189.517 + }
189.518 +
189.519 + /**
189.520 + * Gets the date/time formatter with the given date and time
189.521 + * formatting styles for the default locale.
189.522 + * @param dateStyle the given date formatting style. For example,
189.523 + * SHORT for "M/d/yy" in the US locale.
189.524 + * @param timeStyle the given time formatting style. For example,
189.525 + * SHORT for "h:mm a" in the US locale.
189.526 + * @return a date/time formatter.
189.527 + */
189.528 + public final static DateFormat getDateTimeInstance(int dateStyle,
189.529 + int timeStyle)
189.530 + {
189.531 + return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT));
189.532 + }
189.533 +
189.534 + /**
189.535 + * Gets the date/time formatter with the given formatting styles
189.536 + * for the given locale.
189.537 + * @param dateStyle the given date formatting style.
189.538 + * @param timeStyle the given time formatting style.
189.539 + * @param aLocale the given locale.
189.540 + * @return a date/time formatter.
189.541 + */
189.542 + public final static DateFormat
189.543 + getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
189.544 + {
189.545 + return get(timeStyle, dateStyle, 3, aLocale);
189.546 + }
189.547 +
189.548 + /**
189.549 + * Get a default date/time formatter that uses the SHORT style for both the
189.550 + * date and the time.
189.551 + */
189.552 + public final static DateFormat getInstance() {
189.553 + return getDateTimeInstance(SHORT, SHORT);
189.554 + }
189.555 +
189.556 + /**
189.557 + * Returns an array of all locales for which the
189.558 + * <code>get*Instance</code> methods of this class can return
189.559 + * localized instances.
189.560 + * The returned array represents the union of locales supported by the Java
189.561 + * runtime and by installed
189.562 + * {@link java.text.spi.DateFormatProvider DateFormatProvider} implementations.
189.563 + * It must contain at least a <code>Locale</code> instance equal to
189.564 + * {@link java.util.Locale#US Locale.US}.
189.565 + *
189.566 + * @return An array of locales for which localized
189.567 + * <code>DateFormat</code> instances are available.
189.568 + */
189.569 + public static Locale[] getAvailableLocales()
189.570 + {
189.571 + return new Locale[] { Locale.US };
189.572 + }
189.573 +
189.574 + /**
189.575 + * Set the calendar to be used by this date format. Initially, the default
189.576 + * calendar for the specified or default locale is used.
189.577 + *
189.578 + * <p>Any {@link java.util.TimeZone TimeZone} and {@linkplain
189.579 + * #isLenient() leniency} values that have previously been set are
189.580 + * overwritten by {@code newCalendar}'s values.
189.581 + *
189.582 + * @param newCalendar the new {@code Calendar} to be used by the date format
189.583 + */
189.584 + public void setCalendar(Calendar newCalendar)
189.585 + {
189.586 + this.calendar = newCalendar;
189.587 + }
189.588 +
189.589 + /**
189.590 + * Gets the calendar associated with this date/time formatter.
189.591 + *
189.592 + * @return the calendar associated with this date/time formatter.
189.593 + */
189.594 + public Calendar getCalendar()
189.595 + {
189.596 + return calendar;
189.597 + }
189.598 +
189.599 + /**
189.600 + * Allows you to set the number formatter.
189.601 + * @param newNumberFormat the given new NumberFormat.
189.602 + */
189.603 + public void setNumberFormat(NumberFormat newNumberFormat)
189.604 + {
189.605 + this.numberFormat = newNumberFormat;
189.606 + }
189.607 +
189.608 + /**
189.609 + * Gets the number formatter which this date/time formatter uses to
189.610 + * format and parse a time.
189.611 + * @return the number formatter which this date/time formatter uses.
189.612 + */
189.613 + public NumberFormat getNumberFormat()
189.614 + {
189.615 + return numberFormat;
189.616 + }
189.617 +
189.618 + /**
189.619 + * Sets the time zone for the calendar of this {@code DateFormat} object.
189.620 + * This method is equivalent to the following call.
189.621 + * <blockquote><pre>
189.622 + * getCalendar().setTimeZone(zone)
189.623 + * </pre></blockquote>
189.624 + *
189.625 + * <p>The {@code TimeZone} set by this method is overwritten by a
189.626 + * {@link #setCalendar(java.util.Calendar) setCalendar} call.
189.627 + *
189.628 + * <p>The {@code TimeZone} set by this method may be overwritten as
189.629 + * a result of a call to the parse method.
189.630 + *
189.631 + * @param zone the given new time zone.
189.632 + */
189.633 + public void setTimeZone(TimeZone zone)
189.634 + {
189.635 + calendar.setTimeZone(zone);
189.636 + }
189.637 +
189.638 + /**
189.639 + * Gets the time zone.
189.640 + * This method is equivalent to the following call.
189.641 + * <blockquote><pre>
189.642 + * getCalendar().getTimeZone()
189.643 + * </pre></blockquote>
189.644 + *
189.645 + * @return the time zone associated with the calendar of DateFormat.
189.646 + */
189.647 + public TimeZone getTimeZone()
189.648 + {
189.649 + return calendar.getTimeZone();
189.650 + }
189.651 +
189.652 + /**
189.653 + * Specify whether or not date/time parsing is to be lenient. With
189.654 + * lenient parsing, the parser may use heuristics to interpret inputs that
189.655 + * do not precisely match this object's format. With strict parsing,
189.656 + * inputs must match this object's format.
189.657 + *
189.658 + * <p>This method is equivalent to the following call.
189.659 + * <blockquote><pre>
189.660 + * getCalendar().setLenient(lenient)
189.661 + * </pre></blockquote>
189.662 + *
189.663 + * <p>This leniency value is overwritten by a call to {@link
189.664 + * #setCalendar(java.util.Calendar) setCalendar()}.
189.665 + *
189.666 + * @param lenient when {@code true}, parsing is lenient
189.667 + * @see java.util.Calendar#setLenient(boolean)
189.668 + */
189.669 + public void setLenient(boolean lenient)
189.670 + {
189.671 + calendar.setLenient(lenient);
189.672 + }
189.673 +
189.674 + /**
189.675 + * Tell whether date/time parsing is to be lenient.
189.676 + * This method is equivalent to the following call.
189.677 + * <blockquote><pre>
189.678 + * getCalendar().isLenient()
189.679 + * </pre></blockquote>
189.680 + *
189.681 + * @return {@code true} if the {@link #calendar} is lenient;
189.682 + * {@code false} otherwise.
189.683 + * @see java.util.Calendar#isLenient()
189.684 + */
189.685 + public boolean isLenient()
189.686 + {
189.687 + return calendar.isLenient();
189.688 + }
189.689 +
189.690 + /**
189.691 + * Overrides hashCode
189.692 + */
189.693 + public int hashCode() {
189.694 + return numberFormat.hashCode();
189.695 + // just enough fields for a reasonable distribution
189.696 + }
189.697 +
189.698 + /**
189.699 + * Overrides equals
189.700 + */
189.701 + public boolean equals(Object obj) {
189.702 + if (this == obj) return true;
189.703 + if (obj == null || getClass() != obj.getClass()) return false;
189.704 + DateFormat other = (DateFormat) obj;
189.705 + return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
189.706 + calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
189.707 + calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
189.708 + calendar.isLenient() == other.calendar.isLenient() &&
189.709 + calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
189.710 + numberFormat.equals(other.numberFormat));
189.711 + }
189.712 +
189.713 + /**
189.714 + * Overrides Cloneable
189.715 + */
189.716 + public Object clone()
189.717 + {
189.718 + DateFormat other = (DateFormat) super.clone();
189.719 + other.calendar = (Calendar) calendar.clone();
189.720 + other.numberFormat = (NumberFormat) numberFormat.clone();
189.721 + return other;
189.722 + }
189.723 +
189.724 + /**
189.725 + * Creates a DateFormat with the given time and/or date style in the given
189.726 + * locale.
189.727 + * @param timeStyle a value from 0 to 3 indicating the time format,
189.728 + * ignored if flags is 2
189.729 + * @param dateStyle a value from 0 to 3 indicating the time format,
189.730 + * ignored if flags is 1
189.731 + * @param flags either 1 for a time format, 2 for a date format,
189.732 + * or 3 for a date/time format
189.733 + * @param loc the locale for the format
189.734 + */
189.735 + private static DateFormat get(int timeStyle, int dateStyle,
189.736 + int flags, Locale loc) {
189.737 + if ((flags & 1) != 0) {
189.738 + if (timeStyle < 0 || timeStyle > 3) {
189.739 + throw new IllegalArgumentException("Illegal time style " + timeStyle);
189.740 + }
189.741 + } else {
189.742 + timeStyle = -1;
189.743 + }
189.744 + if ((flags & 2) != 0) {
189.745 + if (dateStyle < 0 || dateStyle > 3) {
189.746 + throw new IllegalArgumentException("Illegal date style " + dateStyle);
189.747 + }
189.748 + } else {
189.749 + dateStyle = -1;
189.750 + }
189.751 + try {
189.752 + // Check whether a provider can provide an implementation that's closer
189.753 + // to the requested locale than what the Java runtime itself can provide.
189.754 + /*
189.755 + LocaleServiceProviderPool pool =
189.756 + LocaleServiceProviderPool.getPool(DateFormatProvider.class);
189.757 + if (pool.hasProviders()) {
189.758 + DateFormat providersInstance = pool.getLocalizedObject(
189.759 + DateFormatGetter.INSTANCE,
189.760 + loc,
189.761 + timeStyle,
189.762 + dateStyle,
189.763 + flags);
189.764 + if (providersInstance != null) {
189.765 + return providersInstance;
189.766 + }
189.767 + }
189.768 + */
189.769 +
189.770 + return new SimpleDateFormat(timeStyle, dateStyle, loc);
189.771 + } catch (MissingResourceException e) {
189.772 + return new SimpleDateFormat("M/d/yy h:mm a");
189.773 + }
189.774 + }
189.775 +
189.776 + /**
189.777 + * Create a new date format.
189.778 + */
189.779 + protected DateFormat() {}
189.780 +
189.781 + /**
189.782 + * Defines constants that are used as attribute keys in the
189.783 + * <code>AttributedCharacterIterator</code> returned
189.784 + * from <code>DateFormat.formatToCharacterIterator</code> and as
189.785 + * field identifiers in <code>FieldPosition</code>.
189.786 + * <p>
189.787 + * The class also provides two methods to map
189.788 + * between its constants and the corresponding Calendar constants.
189.789 + *
189.790 + * @since 1.4
189.791 + * @see java.util.Calendar
189.792 + */
189.793 + public static class Field extends Format.Field {
189.794 +
189.795 + // Proclaim serial compatibility with 1.4 FCS
189.796 + private static final long serialVersionUID = 7441350119349544720L;
189.797 +
189.798 + // table of all instances in this class, used by readResolve
189.799 + private static final Map instanceMap = new HashMap(18);
189.800 + // Maps from Calendar constant (such as Calendar.ERA) to Field
189.801 + // constant (such as Field.ERA).
189.802 + private static final Field[] calendarToFieldMapping =
189.803 + new Field[Calendar.FIELD_COUNT];
189.804 +
189.805 + /** Calendar field. */
189.806 + private int calendarField;
189.807 +
189.808 + /**
189.809 + * Returns the <code>Field</code> constant that corresponds to
189.810 + * the <code>Calendar</code> constant <code>calendarField</code>.
189.811 + * If there is no direct mapping between the <code>Calendar</code>
189.812 + * constant and a <code>Field</code>, null is returned.
189.813 + *
189.814 + * @throws IllegalArgumentException if <code>calendarField</code> is
189.815 + * not the value of a <code>Calendar</code> field constant.
189.816 + * @param calendarField Calendar field constant
189.817 + * @return Field instance representing calendarField.
189.818 + * @see java.util.Calendar
189.819 + */
189.820 + public static Field ofCalendarField(int calendarField) {
189.821 + if (calendarField < 0 || calendarField >=
189.822 + calendarToFieldMapping.length) {
189.823 + throw new IllegalArgumentException("Unknown Calendar constant "
189.824 + + calendarField);
189.825 + }
189.826 + return calendarToFieldMapping[calendarField];
189.827 + }
189.828 +
189.829 + /**
189.830 + * Creates a <code>Field</code>.
189.831 + *
189.832 + * @param name the name of the <code>Field</code>
189.833 + * @param calendarField the <code>Calendar</code> constant this
189.834 + * <code>Field</code> corresponds to; any value, even one
189.835 + * outside the range of legal <code>Calendar</code> values may
189.836 + * be used, but <code>-1</code> should be used for values
189.837 + * that don't correspond to legal <code>Calendar</code> values
189.838 + */
189.839 + protected Field(String name, int calendarField) {
189.840 + super(name);
189.841 + this.calendarField = calendarField;
189.842 + if (this.getClass() == DateFormat.Field.class) {
189.843 + instanceMap.put(name, this);
189.844 + if (calendarField >= 0) {
189.845 + // assert(calendarField < Calendar.FIELD_COUNT);
189.846 + calendarToFieldMapping[calendarField] = this;
189.847 + }
189.848 + }
189.849 + }
189.850 +
189.851 + /**
189.852 + * Returns the <code>Calendar</code> field associated with this
189.853 + * attribute. For example, if this represents the hours field of
189.854 + * a <code>Calendar</code>, this would return
189.855 + * <code>Calendar.HOUR</code>. If there is no corresponding
189.856 + * <code>Calendar</code> constant, this will return -1.
189.857 + *
189.858 + * @return Calendar constant for this field
189.859 + * @see java.util.Calendar
189.860 + */
189.861 + public int getCalendarField() {
189.862 + return calendarField;
189.863 + }
189.864 +
189.865 + /**
189.866 + * Resolves instances being deserialized to the predefined constants.
189.867 + *
189.868 + * @throws InvalidObjectException if the constant could not be
189.869 + * resolved.
189.870 + * @return resolved DateFormat.Field constant
189.871 + */
189.872 + protected Object readResolve() throws InvalidObjectException {
189.873 + if (this.getClass() != DateFormat.Field.class) {
189.874 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
189.875 + }
189.876 +
189.877 + Object instance = instanceMap.get(getName());
189.878 + if (instance != null) {
189.879 + return instance;
189.880 + } else {
189.881 + throw new InvalidObjectException("unknown attribute name");
189.882 + }
189.883 + }
189.884 +
189.885 + //
189.886 + // The constants
189.887 + //
189.888 +
189.889 + /**
189.890 + * Constant identifying the era field.
189.891 + */
189.892 + public final static Field ERA = new Field("era", Calendar.ERA);
189.893 +
189.894 + /**
189.895 + * Constant identifying the year field.
189.896 + */
189.897 + public final static Field YEAR = new Field("year", Calendar.YEAR);
189.898 +
189.899 + /**
189.900 + * Constant identifying the month field.
189.901 + */
189.902 + public final static Field MONTH = new Field("month", Calendar.MONTH);
189.903 +
189.904 + /**
189.905 + * Constant identifying the day of month field.
189.906 + */
189.907 + public final static Field DAY_OF_MONTH = new
189.908 + Field("day of month", Calendar.DAY_OF_MONTH);
189.909 +
189.910 + /**
189.911 + * Constant identifying the hour of day field, where the legal values
189.912 + * are 1 to 24.
189.913 + */
189.914 + public final static Field HOUR_OF_DAY1 = new Field("hour of day 1",-1);
189.915 +
189.916 + /**
189.917 + * Constant identifying the hour of day field, where the legal values
189.918 + * are 0 to 23.
189.919 + */
189.920 + public final static Field HOUR_OF_DAY0 = new
189.921 + Field("hour of day", Calendar.HOUR_OF_DAY);
189.922 +
189.923 + /**
189.924 + * Constant identifying the minute field.
189.925 + */
189.926 + public final static Field MINUTE =new Field("minute", Calendar.MINUTE);
189.927 +
189.928 + /**
189.929 + * Constant identifying the second field.
189.930 + */
189.931 + public final static Field SECOND =new Field("second", Calendar.SECOND);
189.932 +
189.933 + /**
189.934 + * Constant identifying the millisecond field.
189.935 + */
189.936 + public final static Field MILLISECOND = new
189.937 + Field("millisecond", Calendar.MILLISECOND);
189.938 +
189.939 + /**
189.940 + * Constant identifying the day of week field.
189.941 + */
189.942 + public final static Field DAY_OF_WEEK = new
189.943 + Field("day of week", Calendar.DAY_OF_WEEK);
189.944 +
189.945 + /**
189.946 + * Constant identifying the day of year field.
189.947 + */
189.948 + public final static Field DAY_OF_YEAR = new
189.949 + Field("day of year", Calendar.DAY_OF_YEAR);
189.950 +
189.951 + /**
189.952 + * Constant identifying the day of week field.
189.953 + */
189.954 + public final static Field DAY_OF_WEEK_IN_MONTH =
189.955 + new Field("day of week in month",
189.956 + Calendar.DAY_OF_WEEK_IN_MONTH);
189.957 +
189.958 + /**
189.959 + * Constant identifying the week of year field.
189.960 + */
189.961 + public final static Field WEEK_OF_YEAR = new
189.962 + Field("week of year", Calendar.WEEK_OF_YEAR);
189.963 +
189.964 + /**
189.965 + * Constant identifying the week of month field.
189.966 + */
189.967 + public final static Field WEEK_OF_MONTH = new
189.968 + Field("week of month", Calendar.WEEK_OF_MONTH);
189.969 +
189.970 + /**
189.971 + * Constant identifying the time of day indicator
189.972 + * (e.g. "a.m." or "p.m.") field.
189.973 + */
189.974 + public final static Field AM_PM = new
189.975 + Field("am pm", Calendar.AM_PM);
189.976 +
189.977 + /**
189.978 + * Constant identifying the hour field, where the legal values are
189.979 + * 1 to 12.
189.980 + */
189.981 + public final static Field HOUR1 = new Field("hour 1", -1);
189.982 +
189.983 + /**
189.984 + * Constant identifying the hour field, where the legal values are
189.985 + * 0 to 11.
189.986 + */
189.987 + public final static Field HOUR0 = new
189.988 + Field("hour", Calendar.HOUR);
189.989 +
189.990 + /**
189.991 + * Constant identifying the time zone field.
189.992 + */
189.993 + public final static Field TIME_ZONE = new Field("time zone", -1);
189.994 + }
189.995 +
189.996 + /**
189.997 + * Obtains a DateFormat instance from a DateFormatProvider
189.998 + * implementation.
189.999 + private static class DateFormatGetter
189.1000 + implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatProvider, DateFormat> {
189.1001 + private static final DateFormatGetter INSTANCE = new DateFormatGetter();
189.1002 +
189.1003 + public DateFormat getObject(DateFormatProvider dateFormatProvider,
189.1004 + Locale locale,
189.1005 + String key,
189.1006 + Object... params) {
189.1007 + assert params.length == 3;
189.1008 +
189.1009 + int timeStyle = (Integer)params[0];
189.1010 + int dateStyle = (Integer)params[1];
189.1011 + int flags = (Integer)params[2];
189.1012 +
189.1013 + switch (flags) {
189.1014 + case 1:
189.1015 + return dateFormatProvider.getTimeInstance(timeStyle, locale);
189.1016 + case 2:
189.1017 + return dateFormatProvider.getDateInstance(dateStyle, locale);
189.1018 + case 3:
189.1019 + return dateFormatProvider.getDateTimeInstance(dateStyle, timeStyle, locale);
189.1020 + default:
189.1021 + assert false : "should not happen";
189.1022 + }
189.1023 +
189.1024 + return null;
189.1025 + }
189.1026 + }
189.1027 + */
189.1028 +}
190.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
190.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormatSymbols.java Wed Apr 30 15:04:10 2014 +0200
190.3 @@ -0,0 +1,786 @@
190.4 +/*
190.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
190.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
190.7 + *
190.8 + * This code is free software; you can redistribute it and/or modify it
190.9 + * under the terms of the GNU General Public License version 2 only, as
190.10 + * published by the Free Software Foundation. Oracle designates this
190.11 + * particular file as subject to the "Classpath" exception as provided
190.12 + * by Oracle in the LICENSE file that accompanied this code.
190.13 + *
190.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
190.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
190.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
190.17 + * version 2 for more details (a copy is included in the LICENSE file that
190.18 + * accompanied this code).
190.19 + *
190.20 + * You should have received a copy of the GNU General Public License version
190.21 + * 2 along with this work; if not, write to the Free Software Foundation,
190.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
190.23 + *
190.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
190.25 + * or visit www.oracle.com if you need additional information or have any
190.26 + * questions.
190.27 + */
190.28 +
190.29 +/*
190.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
190.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
190.32 + *
190.33 + * The original version of this source code and documentation is copyrighted
190.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
190.35 + * materials are provided under terms of a License Agreement between Taligent
190.36 + * and Sun. This technology is protected by multiple US and International
190.37 + * patents. This notice and attribution to Taligent may not be removed.
190.38 + * Taligent is a registered trademark of Taligent, Inc.
190.39 + *
190.40 + */
190.41 +
190.42 +package java.text;
190.43 +
190.44 +import java.io.IOException;
190.45 +import java.io.ObjectOutputStream;
190.46 +import java.io.Serializable;
190.47 +import java.lang.ref.SoftReference;
190.48 +import java.util.Arrays;
190.49 +import java.util.Locale;
190.50 +import java.util.ResourceBundle;
190.51 +import java.util.concurrent.ConcurrentHashMap;
190.52 +import java.util.concurrent.ConcurrentMap;
190.53 +
190.54 +/**
190.55 + * <code>DateFormatSymbols</code> is a public class for encapsulating
190.56 + * localizable date-time formatting data, such as the names of the
190.57 + * months, the names of the days of the week, and the time zone data.
190.58 + * <code>DateFormat</code> and <code>SimpleDateFormat</code> both use
190.59 + * <code>DateFormatSymbols</code> to encapsulate this information.
190.60 + *
190.61 + * <p>
190.62 + * Typically you shouldn't use <code>DateFormatSymbols</code> directly.
190.63 + * Rather, you are encouraged to create a date-time formatter with the
190.64 + * <code>DateFormat</code> class's factory methods: <code>getTimeInstance</code>,
190.65 + * <code>getDateInstance</code>, or <code>getDateTimeInstance</code>.
190.66 + * These methods automatically create a <code>DateFormatSymbols</code> for
190.67 + * the formatter so that you don't have to. After the
190.68 + * formatter is created, you may modify its format pattern using the
190.69 + * <code>setPattern</code> method. For more information about
190.70 + * creating formatters using <code>DateFormat</code>'s factory methods,
190.71 + * see {@link DateFormat}.
190.72 + *
190.73 + * <p>
190.74 + * If you decide to create a date-time formatter with a specific
190.75 + * format pattern for a specific locale, you can do so with:
190.76 + * <blockquote>
190.77 + * <pre>
190.78 + * new SimpleDateFormat(aPattern, DateFormatSymbols.getInstance(aLocale)).
190.79 + * </pre>
190.80 + * </blockquote>
190.81 + *
190.82 + * <p>
190.83 + * <code>DateFormatSymbols</code> objects are cloneable. When you obtain
190.84 + * a <code>DateFormatSymbols</code> object, feel free to modify the
190.85 + * date-time formatting data. For instance, you can replace the localized
190.86 + * date-time format pattern characters with the ones that you feel easy
190.87 + * to remember. Or you can change the representative cities
190.88 + * to your favorite ones.
190.89 + *
190.90 + * <p>
190.91 + * New <code>DateFormatSymbols</code> subclasses may be added to support
190.92 + * <code>SimpleDateFormat</code> for date-time formatting for additional locales.
190.93 +
190.94 + * @see DateFormat
190.95 + * @see SimpleDateFormat
190.96 + * @see java.util.SimpleTimeZone
190.97 + * @author Chen-Lieh Huang
190.98 + */
190.99 +public class DateFormatSymbols implements Serializable, Cloneable {
190.100 +
190.101 + /**
190.102 + * Construct a DateFormatSymbols object by loading format data from
190.103 + * resources for the default locale. This constructor can only
190.104 + * construct instances for the locales supported by the Java
190.105 + * runtime environment, not for those supported by installed
190.106 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
190.107 + * implementations. For full locale coverage, use the
190.108 + * {@link #getInstance(Locale) getInstance} method.
190.109 + *
190.110 + * @see #getInstance()
190.111 + * @exception java.util.MissingResourceException
190.112 + * if the resources for the default locale cannot be
190.113 + * found or cannot be loaded.
190.114 + */
190.115 + public DateFormatSymbols()
190.116 + {
190.117 + initializeData(Locale.getDefault(Locale.Category.FORMAT));
190.118 + }
190.119 +
190.120 + /**
190.121 + * Construct a DateFormatSymbols object by loading format data from
190.122 + * resources for the given locale. This constructor can only
190.123 + * construct instances for the locales supported by the Java
190.124 + * runtime environment, not for those supported by installed
190.125 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
190.126 + * implementations. For full locale coverage, use the
190.127 + * {@link #getInstance(Locale) getInstance} method.
190.128 + *
190.129 + * @see #getInstance(Locale)
190.130 + * @exception java.util.MissingResourceException
190.131 + * if the resources for the specified locale cannot be
190.132 + * found or cannot be loaded.
190.133 + */
190.134 + public DateFormatSymbols(Locale locale)
190.135 + {
190.136 + initializeData(locale);
190.137 + }
190.138 +
190.139 + /**
190.140 + * Era strings. For example: "AD" and "BC". An array of 2 strings,
190.141 + * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
190.142 + * @serial
190.143 + */
190.144 + String eras[] = null;
190.145 +
190.146 + /**
190.147 + * Month strings. For example: "January", "February", etc. An array
190.148 + * of 13 strings (some calendars have 13 months), indexed by
190.149 + * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
190.150 + * @serial
190.151 + */
190.152 + String months[] = null;
190.153 +
190.154 + /**
190.155 + * Short month strings. For example: "Jan", "Feb", etc. An array of
190.156 + * 13 strings (some calendars have 13 months), indexed by
190.157 + * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
190.158 +
190.159 + * @serial
190.160 + */
190.161 + String shortMonths[] = null;
190.162 +
190.163 + /**
190.164 + * Weekday strings. For example: "Sunday", "Monday", etc. An array
190.165 + * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
190.166 + * <code>Calendar.MONDAY</code>, etc.
190.167 + * The element <code>weekdays[0]</code> is ignored.
190.168 + * @serial
190.169 + */
190.170 + String weekdays[] = null;
190.171 +
190.172 + /**
190.173 + * Short weekday strings. For example: "Sun", "Mon", etc. An array
190.174 + * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
190.175 + * <code>Calendar.MONDAY</code>, etc.
190.176 + * The element <code>shortWeekdays[0]</code> is ignored.
190.177 + * @serial
190.178 + */
190.179 + String shortWeekdays[] = null;
190.180 +
190.181 + /**
190.182 + * AM and PM strings. For example: "AM" and "PM". An array of
190.183 + * 2 strings, indexed by <code>Calendar.AM</code> and
190.184 + * <code>Calendar.PM</code>.
190.185 + * @serial
190.186 + */
190.187 + String ampms[] = null;
190.188 +
190.189 + /**
190.190 + * Localized names of time zones in this locale. This is a
190.191 + * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
190.192 + * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
190.193 + * entry containing the localized names for a single <code>TimeZone</code>.
190.194 + * Each such row contains (with <code>i</code> ranging from
190.195 + * 0..<em>n</em>-1):
190.196 + * <ul>
190.197 + * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
190.198 + * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
190.199 + * time</li>
190.200 + * <li><code>zoneStrings[i][2]</code> - short name of zone in
190.201 + * standard time</li>
190.202 + * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
190.203 + * saving time</li>
190.204 + * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
190.205 + * saving time</li>
190.206 + * </ul>
190.207 + * The zone ID is <em>not</em> localized; it's one of the valid IDs of
190.208 + * the {@link java.util.TimeZone TimeZone} class that are not
190.209 + * <a href="../java/util/TimeZone.html#CustomID">custom IDs</a>.
190.210 + * All other entries are localized names.
190.211 + * @see java.util.TimeZone
190.212 + * @serial
190.213 + */
190.214 + String zoneStrings[][] = null;
190.215 +
190.216 + /**
190.217 + * Indicates that zoneStrings is set externally with setZoneStrings() method.
190.218 + */
190.219 + transient boolean isZoneStringsSet = false;
190.220 +
190.221 + /**
190.222 + * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
190.223 + * All locales use the same these unlocalized pattern characters.
190.224 + */
190.225 + static final String patternChars = "GyMdkHmsSEDFwWahKzZYuX";
190.226 +
190.227 + static final int PATTERN_ERA = 0; // G
190.228 + static final int PATTERN_YEAR = 1; // y
190.229 + static final int PATTERN_MONTH = 2; // M
190.230 + static final int PATTERN_DAY_OF_MONTH = 3; // d
190.231 + static final int PATTERN_HOUR_OF_DAY1 = 4; // k
190.232 + static final int PATTERN_HOUR_OF_DAY0 = 5; // H
190.233 + static final int PATTERN_MINUTE = 6; // m
190.234 + static final int PATTERN_SECOND = 7; // s
190.235 + static final int PATTERN_MILLISECOND = 8; // S
190.236 + static final int PATTERN_DAY_OF_WEEK = 9; // E
190.237 + static final int PATTERN_DAY_OF_YEAR = 10; // D
190.238 + static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
190.239 + static final int PATTERN_WEEK_OF_YEAR = 12; // w
190.240 + static final int PATTERN_WEEK_OF_MONTH = 13; // W
190.241 + static final int PATTERN_AM_PM = 14; // a
190.242 + static final int PATTERN_HOUR1 = 15; // h
190.243 + static final int PATTERN_HOUR0 = 16; // K
190.244 + static final int PATTERN_ZONE_NAME = 17; // z
190.245 + static final int PATTERN_ZONE_VALUE = 18; // Z
190.246 + static final int PATTERN_WEEK_YEAR = 19; // Y
190.247 + static final int PATTERN_ISO_DAY_OF_WEEK = 20; // u
190.248 + static final int PATTERN_ISO_ZONE = 21; // X
190.249 +
190.250 + /**
190.251 + * Localized date-time pattern characters. For example, a locale may
190.252 + * wish to use 'u' rather than 'y' to represent years in its date format
190.253 + * pattern strings.
190.254 + * This string must be exactly 18 characters long, with the index of
190.255 + * the characters described by <code>DateFormat.ERA_FIELD</code>,
190.256 + * <code>DateFormat.YEAR_FIELD</code>, etc. Thus, if the string were
190.257 + * "Xz...", then localized patterns would use 'X' for era and 'z' for year.
190.258 + * @serial
190.259 + */
190.260 + String localPatternChars = null;
190.261 +
190.262 + /**
190.263 + * The locale which is used for initializing this DateFormatSymbols object.
190.264 + *
190.265 + * @since 1.6
190.266 + * @serial
190.267 + */
190.268 + Locale locale = null;
190.269 +
190.270 + /* use serialVersionUID from JDK 1.1.4 for interoperability */
190.271 + static final long serialVersionUID = -5987973545549424702L;
190.272 +
190.273 + /**
190.274 + * Returns an array of all locales for which the
190.275 + * <code>getInstance</code> methods of this class can return
190.276 + * localized instances.
190.277 + * The returned array represents the union of locales supported by the
190.278 + * Java runtime and by installed
190.279 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
190.280 + * implementations. It must contain at least a <code>Locale</code>
190.281 + * instance equal to {@link java.util.Locale#US Locale.US}.
190.282 + *
190.283 + * @return An array of locales for which localized
190.284 + * <code>DateFormatSymbols</code> instances are available.
190.285 + * @since 1.6
190.286 + */
190.287 + public static Locale[] getAvailableLocales() {
190.288 + return new Locale[] { Locale.US };
190.289 +// LocaleServiceProviderPool pool=
190.290 +// LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
190.291 +// return pool.getAvailableLocales();
190.292 + }
190.293 +
190.294 + /**
190.295 + * Gets the <code>DateFormatSymbols</code> instance for the default
190.296 + * locale. This method provides access to <code>DateFormatSymbols</code>
190.297 + * instances for locales supported by the Java runtime itself as well
190.298 + * as for those supported by installed
190.299 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
190.300 + * implementations.
190.301 + * @return a <code>DateFormatSymbols</code> instance.
190.302 + * @since 1.6
190.303 + */
190.304 + public static final DateFormatSymbols getInstance() {
190.305 + return getInstance(Locale.getDefault(Locale.Category.FORMAT));
190.306 + }
190.307 +
190.308 + /**
190.309 + * Gets the <code>DateFormatSymbols</code> instance for the specified
190.310 + * locale. This method provides access to <code>DateFormatSymbols</code>
190.311 + * instances for locales supported by the Java runtime itself as well
190.312 + * as for those supported by installed
190.313 + * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
190.314 + * implementations.
190.315 + * @param locale the given locale.
190.316 + * @return a <code>DateFormatSymbols</code> instance.
190.317 + * @exception NullPointerException if <code>locale</code> is null
190.318 + * @since 1.6
190.319 + */
190.320 + public static final DateFormatSymbols getInstance(Locale locale) {
190.321 + DateFormatSymbols dfs = getProviderInstance(locale);
190.322 + if (dfs != null) {
190.323 + return dfs;
190.324 + }
190.325 + return (DateFormatSymbols) getCachedInstance(locale).clone();
190.326 + }
190.327 +
190.328 + /**
190.329 + * Returns a DateFormatSymbols provided by a provider or found in
190.330 + * the cache. Note that this method returns a cached instance,
190.331 + * not its clone. Therefore, the instance should never be given to
190.332 + * an application.
190.333 + */
190.334 + static final DateFormatSymbols getInstanceRef(Locale locale) {
190.335 + DateFormatSymbols dfs = getProviderInstance(locale);
190.336 + if (dfs != null) {
190.337 + return dfs;
190.338 + }
190.339 + return getCachedInstance(locale);
190.340 + }
190.341 +
190.342 + private static DateFormatSymbols getProviderInstance(Locale locale) {
190.343 + DateFormatSymbols providersInstance = null;
190.344 +
190.345 + // Check whether a provider can provide an implementation that's closer
190.346 + // to the requested locale than what the Java runtime itself can provide.
190.347 +// LocaleServiceProviderPool pool =
190.348 +// LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
190.349 +// if (pool.hasProviders()) {
190.350 +// providersInstance = pool.getLocalizedObject(
190.351 +// DateFormatSymbolsGetter.INSTANCE, locale);
190.352 +// }
190.353 + return providersInstance;
190.354 + }
190.355 +
190.356 + /**
190.357 + * Returns a cached DateFormatSymbols if it's found in the
190.358 + * cache. Otherwise, this method returns a newly cached instance
190.359 + * for the given locale.
190.360 + */
190.361 + private static DateFormatSymbols getCachedInstance(Locale locale) {
190.362 + SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
190.363 + DateFormatSymbols dfs = null;
190.364 + if (ref == null || (dfs = ref.get()) == null) {
190.365 + dfs = new DateFormatSymbols(locale);
190.366 + ref = new SoftReference<DateFormatSymbols>(dfs);
190.367 + SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
190.368 + if (x != null) {
190.369 + DateFormatSymbols y = x.get();
190.370 + if (y != null) {
190.371 + dfs = y;
190.372 + } else {
190.373 + // Replace the empty SoftReference with ref.
190.374 + cachedInstances.put(locale, ref);
190.375 + }
190.376 + }
190.377 + }
190.378 + return dfs;
190.379 + }
190.380 +
190.381 + /**
190.382 + * Gets era strings. For example: "AD" and "BC".
190.383 + * @return the era strings.
190.384 + */
190.385 + public String[] getEras() {
190.386 + return Arrays.copyOf(eras, eras.length);
190.387 + }
190.388 +
190.389 + /**
190.390 + * Sets era strings. For example: "AD" and "BC".
190.391 + * @param newEras the new era strings.
190.392 + */
190.393 + public void setEras(String[] newEras) {
190.394 + eras = Arrays.copyOf(newEras, newEras.length);
190.395 + }
190.396 +
190.397 + /**
190.398 + * Gets month strings. For example: "January", "February", etc.
190.399 + * @return the month strings.
190.400 + */
190.401 + public String[] getMonths() {
190.402 + return Arrays.copyOf(months, months.length);
190.403 + }
190.404 +
190.405 + /**
190.406 + * Sets month strings. For example: "January", "February", etc.
190.407 + * @param newMonths the new month strings.
190.408 + */
190.409 + public void setMonths(String[] newMonths) {
190.410 + months = Arrays.copyOf(newMonths, newMonths.length);
190.411 + }
190.412 +
190.413 + /**
190.414 + * Gets short month strings. For example: "Jan", "Feb", etc.
190.415 + * @return the short month strings.
190.416 + */
190.417 + public String[] getShortMonths() {
190.418 + return Arrays.copyOf(shortMonths, shortMonths.length);
190.419 + }
190.420 +
190.421 + /**
190.422 + * Sets short month strings. For example: "Jan", "Feb", etc.
190.423 + * @param newShortMonths the new short month strings.
190.424 + */
190.425 + public void setShortMonths(String[] newShortMonths) {
190.426 + shortMonths = Arrays.copyOf(newShortMonths, newShortMonths.length);
190.427 + }
190.428 +
190.429 + /**
190.430 + * Gets weekday strings. For example: "Sunday", "Monday", etc.
190.431 + * @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
190.432 + * <code>Calendar.MONDAY</code>, etc. to index the result array.
190.433 + */
190.434 + public String[] getWeekdays() {
190.435 + return Arrays.copyOf(weekdays, weekdays.length);
190.436 + }
190.437 +
190.438 + /**
190.439 + * Sets weekday strings. For example: "Sunday", "Monday", etc.
190.440 + * @param newWeekdays the new weekday strings. The array should
190.441 + * be indexed by <code>Calendar.SUNDAY</code>,
190.442 + * <code>Calendar.MONDAY</code>, etc.
190.443 + */
190.444 + public void setWeekdays(String[] newWeekdays) {
190.445 + weekdays = Arrays.copyOf(newWeekdays, newWeekdays.length);
190.446 + }
190.447 +
190.448 + /**
190.449 + * Gets short weekday strings. For example: "Sun", "Mon", etc.
190.450 + * @return the short weekday strings. Use <code>Calendar.SUNDAY</code>,
190.451 + * <code>Calendar.MONDAY</code>, etc. to index the result array.
190.452 + */
190.453 + public String[] getShortWeekdays() {
190.454 + return Arrays.copyOf(shortWeekdays, shortWeekdays.length);
190.455 + }
190.456 +
190.457 + /**
190.458 + * Sets short weekday strings. For example: "Sun", "Mon", etc.
190.459 + * @param newShortWeekdays the new short weekday strings. The array should
190.460 + * be indexed by <code>Calendar.SUNDAY</code>,
190.461 + * <code>Calendar.MONDAY</code>, etc.
190.462 + */
190.463 + public void setShortWeekdays(String[] newShortWeekdays) {
190.464 + shortWeekdays = Arrays.copyOf(newShortWeekdays, newShortWeekdays.length);
190.465 + }
190.466 +
190.467 + /**
190.468 + * Gets ampm strings. For example: "AM" and "PM".
190.469 + * @return the ampm strings.
190.470 + */
190.471 + public String[] getAmPmStrings() {
190.472 + return Arrays.copyOf(ampms, ampms.length);
190.473 + }
190.474 +
190.475 + /**
190.476 + * Sets ampm strings. For example: "AM" and "PM".
190.477 + * @param newAmpms the new ampm strings.
190.478 + */
190.479 + public void setAmPmStrings(String[] newAmpms) {
190.480 + ampms = Arrays.copyOf(newAmpms, newAmpms.length);
190.481 + }
190.482 +
190.483 + /**
190.484 + * Gets time zone strings. Use of this method is discouraged; use
190.485 + * {@link java.util.TimeZone#getDisplayName() TimeZone.getDisplayName()}
190.486 + * instead.
190.487 + * <p>
190.488 + * The value returned is a
190.489 + * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
190.490 + * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
190.491 + * entry containing the localized names for a single <code>TimeZone</code>.
190.492 + * Each such row contains (with <code>i</code> ranging from
190.493 + * 0..<em>n</em>-1):
190.494 + * <ul>
190.495 + * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
190.496 + * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
190.497 + * time</li>
190.498 + * <li><code>zoneStrings[i][2]</code> - short name of zone in
190.499 + * standard time</li>
190.500 + * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
190.501 + * saving time</li>
190.502 + * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
190.503 + * saving time</li>
190.504 + * </ul>
190.505 + * The zone ID is <em>not</em> localized; it's one of the valid IDs of
190.506 + * the {@link java.util.TimeZone TimeZone} class that are not
190.507 + * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
190.508 + * All other entries are localized names. If a zone does not implement
190.509 + * daylight saving time, the daylight saving time names should not be used.
190.510 + * <p>
190.511 + * If {@link #setZoneStrings(String[][]) setZoneStrings} has been called
190.512 + * on this <code>DateFormatSymbols</code> instance, then the strings
190.513 + * provided by that call are returned. Otherwise, the returned array
190.514 + * contains names provided by the Java runtime and by installed
190.515 + * {@link java.util.spi.TimeZoneNameProvider TimeZoneNameProvider}
190.516 + * implementations.
190.517 + *
190.518 + * @return the time zone strings.
190.519 + * @see #setZoneStrings(String[][])
190.520 + */
190.521 + public String[][] getZoneStrings() {
190.522 + return getZoneStringsImpl(true);
190.523 + }
190.524 +
190.525 + /**
190.526 + * Sets time zone strings. The argument must be a
190.527 + * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
190.528 + * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
190.529 + * entry containing the localized names for a single <code>TimeZone</code>.
190.530 + * Each such row contains (with <code>i</code> ranging from
190.531 + * 0..<em>n</em>-1):
190.532 + * <ul>
190.533 + * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
190.534 + * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
190.535 + * time</li>
190.536 + * <li><code>zoneStrings[i][2]</code> - short name of zone in
190.537 + * standard time</li>
190.538 + * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
190.539 + * saving time</li>
190.540 + * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
190.541 + * saving time</li>
190.542 + * </ul>
190.543 + * The zone ID is <em>not</em> localized; it's one of the valid IDs of
190.544 + * the {@link java.util.TimeZone TimeZone} class that are not
190.545 + * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
190.546 + * All other entries are localized names.
190.547 + *
190.548 + * @param newZoneStrings the new time zone strings.
190.549 + * @exception IllegalArgumentException if the length of any row in
190.550 + * <code>newZoneStrings</code> is less than 5
190.551 + * @exception NullPointerException if <code>newZoneStrings</code> is null
190.552 + * @see #getZoneStrings()
190.553 + */
190.554 + public void setZoneStrings(String[][] newZoneStrings) {
190.555 + String[][] aCopy = new String[newZoneStrings.length][];
190.556 + for (int i = 0; i < newZoneStrings.length; ++i) {
190.557 + int len = newZoneStrings[i].length;
190.558 + if (len < 5) {
190.559 + throw new IllegalArgumentException();
190.560 + }
190.561 + aCopy[i] = Arrays.copyOf(newZoneStrings[i], len);
190.562 + }
190.563 + zoneStrings = aCopy;
190.564 + isZoneStringsSet = true;
190.565 + }
190.566 +
190.567 + /**
190.568 + * Gets localized date-time pattern characters. For example: 'u', 't', etc.
190.569 + * @return the localized date-time pattern characters.
190.570 + */
190.571 + public String getLocalPatternChars() {
190.572 + return localPatternChars;
190.573 + }
190.574 +
190.575 + /**
190.576 + * Sets localized date-time pattern characters. For example: 'u', 't', etc.
190.577 + * @param newLocalPatternChars the new localized date-time
190.578 + * pattern characters.
190.579 + */
190.580 + public void setLocalPatternChars(String newLocalPatternChars) {
190.581 + // Call toString() to throw an NPE in case the argument is null
190.582 + localPatternChars = newLocalPatternChars.toString();
190.583 + }
190.584 +
190.585 + /**
190.586 + * Overrides Cloneable
190.587 + */
190.588 + public Object clone()
190.589 + {
190.590 + try
190.591 + {
190.592 + DateFormatSymbols other = (DateFormatSymbols)super.clone();
190.593 + copyMembers(this, other);
190.594 + return other;
190.595 + } catch (CloneNotSupportedException e) {
190.596 + throw new InternalError();
190.597 + }
190.598 + }
190.599 +
190.600 + /**
190.601 + * Override hashCode.
190.602 + * Generates a hash code for the DateFormatSymbols object.
190.603 + */
190.604 + public int hashCode() {
190.605 + int hashcode = 0;
190.606 + String[][] zoneStrings = getZoneStringsWrapper();
190.607 + for (int index = 0; index < zoneStrings[0].length; ++index)
190.608 + hashcode ^= zoneStrings[0][index].hashCode();
190.609 + return hashcode;
190.610 + }
190.611 +
190.612 + /**
190.613 + * Override equals
190.614 + */
190.615 + public boolean equals(Object obj)
190.616 + {
190.617 + if (this == obj) return true;
190.618 + if (obj == null || getClass() != obj.getClass()) return false;
190.619 + DateFormatSymbols that = (DateFormatSymbols) obj;
190.620 + return (Arrays.equals(eras, that.eras)
190.621 + && Arrays.equals(months, that.months)
190.622 + && Arrays.equals(shortMonths, that.shortMonths)
190.623 + && Arrays.equals(weekdays, that.weekdays)
190.624 + && Arrays.equals(shortWeekdays, that.shortWeekdays)
190.625 + && Arrays.equals(ampms, that.ampms)
190.626 + && Arrays.deepEquals(getZoneStringsWrapper(), that.getZoneStringsWrapper())
190.627 + && ((localPatternChars != null
190.628 + && localPatternChars.equals(that.localPatternChars))
190.629 + || (localPatternChars == null
190.630 + && that.localPatternChars == null)));
190.631 + }
190.632 +
190.633 + // =======================privates===============================
190.634 +
190.635 + /**
190.636 + * Useful constant for defining time zone offsets.
190.637 + */
190.638 + static final int millisPerHour = 60*60*1000;
190.639 +
190.640 + /**
190.641 + * Cache to hold DateFormatSymbols instances per Locale.
190.642 + */
190.643 + private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
190.644 + = new ConcurrentHashMap<Locale, SoftReference<DateFormatSymbols>>(3);
190.645 +
190.646 + private void initializeData(Locale desiredLocale) {
190.647 + locale = desiredLocale;
190.648 +
190.649 + // Copy values of a cached instance if any.
190.650 + SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
190.651 + DateFormatSymbols dfs;
190.652 + if (ref != null && (dfs = ref.get()) != null) {
190.653 + copyMembers(dfs, this);
190.654 + return;
190.655 + }
190.656 +
190.657 + // Initialize the fields from the ResourceBundle for locale.
190.658 +// ResourceBundle resource = LocaleData.getDateFormatData(locale);
190.659 +//
190.660 +// eras = resource.getStringArray("Eras");
190.661 +// months = resource.getStringArray("MonthNames");
190.662 +// shortMonths = resource.getStringArray("MonthAbbreviations");
190.663 +// ampms = resource.getStringArray("AmPmMarkers");
190.664 +// localPatternChars = resource.getString("DateTimePatternChars");
190.665 +//
190.666 +// // Day of week names are stored in a 1-based array.
190.667 +// weekdays = toOneBasedArray(resource.getStringArray("DayNames"));
190.668 +// shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations"));
190.669 + }
190.670 +
190.671 + private static String[] toOneBasedArray(String[] src) {
190.672 + int len = src.length;
190.673 + String[] dst = new String[len + 1];
190.674 + dst[0] = "";
190.675 + for (int i = 0; i < len; i++) {
190.676 + dst[i + 1] = src[i];
190.677 + }
190.678 + return dst;
190.679 + }
190.680 +
190.681 + /**
190.682 + * Package private: used by SimpleDateFormat
190.683 + * Gets the index for the given time zone ID to obtain the time zone
190.684 + * strings for formatting. The time zone ID is just for programmatic
190.685 + * lookup. NOT LOCALIZED!!!
190.686 + * @param ID the given time zone ID.
190.687 + * @return the index of the given time zone ID. Returns -1 if
190.688 + * the given time zone ID can't be located in the DateFormatSymbols object.
190.689 + * @see java.util.SimpleTimeZone
190.690 + */
190.691 + final int getZoneIndex(String ID)
190.692 + {
190.693 + String[][] zoneStrings = getZoneStringsWrapper();
190.694 + for (int index=0; index<zoneStrings.length; index++)
190.695 + {
190.696 + if (ID.equals(zoneStrings[index][0])) return index;
190.697 + }
190.698 +
190.699 + return -1;
190.700 + }
190.701 +
190.702 + /**
190.703 + * Wrapper method to the getZoneStrings(), which is called from inside
190.704 + * the java.text package and not to mutate the returned arrays, so that
190.705 + * it does not need to create a defensive copy.
190.706 + */
190.707 + final String[][] getZoneStringsWrapper() {
190.708 + if (isSubclassObject()) {
190.709 + return getZoneStrings();
190.710 + } else {
190.711 + return getZoneStringsImpl(false);
190.712 + }
190.713 + }
190.714 +
190.715 + private final String[][] getZoneStringsImpl(boolean needsCopy) {
190.716 + if (zoneStrings == null) {
190.717 +// zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
190.718 + }
190.719 +
190.720 + if (!needsCopy) {
190.721 + return zoneStrings;
190.722 + }
190.723 +
190.724 + int len = zoneStrings.length;
190.725 + String[][] aCopy = new String[len][];
190.726 + for (int i = 0; i < len; i++) {
190.727 + aCopy[i] = Arrays.copyOf(zoneStrings[i], zoneStrings[i].length);
190.728 + }
190.729 + return aCopy;
190.730 + }
190.731 +
190.732 + private final boolean isSubclassObject() {
190.733 + return !getClass().getName().equals("java.text.DateFormatSymbols");
190.734 + }
190.735 +
190.736 + /**
190.737 + * Clones all the data members from the source DateFormatSymbols to
190.738 + * the target DateFormatSymbols. This is only for subclasses.
190.739 + * @param src the source DateFormatSymbols.
190.740 + * @param dst the target DateFormatSymbols.
190.741 + */
190.742 + private final void copyMembers(DateFormatSymbols src, DateFormatSymbols dst)
190.743 + {
190.744 + dst.eras = Arrays.copyOf(src.eras, src.eras.length);
190.745 + dst.months = Arrays.copyOf(src.months, src.months.length);
190.746 + dst.shortMonths = Arrays.copyOf(src.shortMonths, src.shortMonths.length);
190.747 + dst.weekdays = Arrays.copyOf(src.weekdays, src.weekdays.length);
190.748 + dst.shortWeekdays = Arrays.copyOf(src.shortWeekdays, src.shortWeekdays.length);
190.749 + dst.ampms = Arrays.copyOf(src.ampms, src.ampms.length);
190.750 + if (src.zoneStrings != null) {
190.751 + dst.zoneStrings = src.getZoneStringsImpl(true);
190.752 + } else {
190.753 + dst.zoneStrings = null;
190.754 + }
190.755 + dst.localPatternChars = src.localPatternChars;
190.756 + }
190.757 +
190.758 + /**
190.759 + * Write out the default serializable data, after ensuring the
190.760 + * <code>zoneStrings</code> field is initialized in order to make
190.761 + * sure the backward compatibility.
190.762 + *
190.763 + * @since 1.6
190.764 + private void writeObject(ObjectOutputStream stream) throws IOException {
190.765 + if (zoneStrings == null) {
190.766 + zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
190.767 + }
190.768 + stream.defaultWriteObject();
190.769 + }
190.770 +
190.771 + /**
190.772 + * Obtains a DateFormatSymbols instance from a DateFormatSymbolsProvider
190.773 + * implementation.
190.774 + private static class DateFormatSymbolsGetter
190.775 + implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatSymbolsProvider,
190.776 + DateFormatSymbols> {
190.777 + private static final DateFormatSymbolsGetter INSTANCE =
190.778 + new DateFormatSymbolsGetter();
190.779 +
190.780 + public DateFormatSymbols getObject(DateFormatSymbolsProvider dateFormatSymbolsProvider,
190.781 + Locale locale,
190.782 + String key,
190.783 + Object... params) {
190.784 + assert params.length == 0;
190.785 + return dateFormatSymbolsProvider.getInstance(locale);
190.786 + }
190.787 + }
190.788 + */
190.789 +}
191.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
191.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormat.java Wed Apr 30 15:04:10 2014 +0200
191.3 @@ -0,0 +1,3277 @@
191.4 +/*
191.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
191.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
191.7 + *
191.8 + * This code is free software; you can redistribute it and/or modify it
191.9 + * under the terms of the GNU General Public License version 2 only, as
191.10 + * published by the Free Software Foundation. Oracle designates this
191.11 + * particular file as subject to the "Classpath" exception as provided
191.12 + * by Oracle in the LICENSE file that accompanied this code.
191.13 + *
191.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
191.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
191.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
191.17 + * version 2 for more details (a copy is included in the LICENSE file that
191.18 + * accompanied this code).
191.19 + *
191.20 + * You should have received a copy of the GNU General Public License version
191.21 + * 2 along with this work; if not, write to the Free Software Foundation,
191.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
191.23 + *
191.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
191.25 + * or visit www.oracle.com if you need additional information or have any
191.26 + * questions.
191.27 + */
191.28 +
191.29 +/*
191.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
191.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
191.32 + *
191.33 + * The original version of this source code and documentation is copyrighted
191.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
191.35 + * materials are provided under terms of a License Agreement between Taligent
191.36 + * and Sun. This technology is protected by multiple US and International
191.37 + * patents. This notice and attribution to Taligent may not be removed.
191.38 + * Taligent is a registered trademark of Taligent, Inc.
191.39 + *
191.40 + */
191.41 +
191.42 +package java.text;
191.43 +
191.44 +import java.io.InvalidObjectException;
191.45 +import java.io.IOException;
191.46 +import java.io.ObjectInputStream;
191.47 +import java.math.BigDecimal;
191.48 +import java.math.BigInteger;
191.49 +import java.math.RoundingMode;
191.50 +import java.util.ArrayList;
191.51 +import java.util.Currency;
191.52 +import java.util.Locale;
191.53 +import java.util.ResourceBundle;
191.54 +import java.util.concurrent.ConcurrentHashMap;
191.55 +import java.util.concurrent.ConcurrentMap;
191.56 +import java.util.concurrent.atomic.AtomicInteger;
191.57 +import java.util.concurrent.atomic.AtomicLong;
191.58 +
191.59 +/**
191.60 + * <code>DecimalFormat</code> is a concrete subclass of
191.61 + * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
191.62 + * features designed to make it possible to parse and format numbers in any
191.63 + * locale, including support for Western, Arabic, and Indic digits. It also
191.64 + * supports different kinds of numbers, including integers (123), fixed-point
191.65 + * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
191.66 + * currency amounts ($123). All of these can be localized.
191.67 + *
191.68 + * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
191.69 + * default locale, call one of <code>NumberFormat</code>'s factory methods, such
191.70 + * as <code>getInstance()</code>. In general, do not call the
191.71 + * <code>DecimalFormat</code> constructors directly, since the
191.72 + * <code>NumberFormat</code> factory methods may return subclasses other than
191.73 + * <code>DecimalFormat</code>. If you need to customize the format object, do
191.74 + * something like this:
191.75 + *
191.76 + * <blockquote><pre>
191.77 + * NumberFormat f = NumberFormat.getInstance(loc);
191.78 + * if (f instanceof DecimalFormat) {
191.79 + * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
191.80 + * }
191.81 + * </pre></blockquote>
191.82 + *
191.83 + * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
191.84 + * <em>symbols</em>. The pattern may be set directly using
191.85 + * <code>applyPattern()</code>, or indirectly using the API methods. The
191.86 + * symbols are stored in a <code>DecimalFormatSymbols</code> object. When using
191.87 + * the <code>NumberFormat</code> factory methods, the pattern and symbols are
191.88 + * read from localized <code>ResourceBundle</code>s.
191.89 + *
191.90 + * <h4>Patterns</h4>
191.91 + *
191.92 + * <code>DecimalFormat</code> patterns have the following syntax:
191.93 + * <blockquote><pre>
191.94 + * <i>Pattern:</i>
191.95 + * <i>PositivePattern</i>
191.96 + * <i>PositivePattern</i> ; <i>NegativePattern</i>
191.97 + * <i>PositivePattern:</i>
191.98 + * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
191.99 + * <i>NegativePattern:</i>
191.100 + * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
191.101 + * <i>Prefix:</i>
191.102 + * any Unicode characters except \uFFFE, \uFFFF, and special characters
191.103 + * <i>Suffix:</i>
191.104 + * any Unicode characters except \uFFFE, \uFFFF, and special characters
191.105 + * <i>Number:</i>
191.106 + * <i>Integer</i> <i>Exponent<sub>opt</sub></i>
191.107 + * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
191.108 + * <i>Integer:</i>
191.109 + * <i>MinimumInteger</i>
191.110 + * #
191.111 + * # <i>Integer</i>
191.112 + * # , <i>Integer</i>
191.113 + * <i>MinimumInteger:</i>
191.114 + * 0
191.115 + * 0 <i>MinimumInteger</i>
191.116 + * 0 , <i>MinimumInteger</i>
191.117 + * <i>Fraction:</i>
191.118 + * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
191.119 + * <i>MinimumFraction:</i>
191.120 + * 0 <i>MinimumFraction<sub>opt</sub></i>
191.121 + * <i>OptionalFraction:</i>
191.122 + * # <i>OptionalFraction<sub>opt</sub></i>
191.123 + * <i>Exponent:</i>
191.124 + * E <i>MinimumExponent</i>
191.125 + * <i>MinimumExponent:</i>
191.126 + * 0 <i>MinimumExponent<sub>opt</sub></i>
191.127 + * </pre></blockquote>
191.128 + *
191.129 + * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
191.130 + * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>. Each
191.131 + * subpattern has a prefix, numeric part, and suffix. The negative subpattern
191.132 + * is optional; if absent, then the positive subpattern prefixed with the
191.133 + * localized minus sign (<code>'-'</code> in most locales) is used as the
191.134 + * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
191.135 + * <code>"0.00;-0.00"</code>. If there is an explicit negative subpattern, it
191.136 + * serves only to specify the negative prefix and suffix; the number of digits,
191.137 + * minimal digits, and other characteristics are all the same as the positive
191.138 + * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
191.139 + * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
191.140 + *
191.141 + * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
191.142 + * thousands separators, decimal separators, etc. may be set to arbitrary
191.143 + * values, and they will appear properly during formatting. However, care must
191.144 + * be taken that the symbols and strings do not conflict, or parsing will be
191.145 + * unreliable. For example, either the positive and negative prefixes or the
191.146 + * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
191.147 + * to distinguish positive from negative values. (If they are identical, then
191.148 + * <code>DecimalFormat</code> will behave as if no negative subpattern was
191.149 + * specified.) Another example is that the decimal separator and thousands
191.150 + * separator should be distinct characters, or parsing will be impossible.
191.151 + *
191.152 + * <p>The grouping separator is commonly used for thousands, but in some
191.153 + * countries it separates ten-thousands. The grouping size is a constant number
191.154 + * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
191.155 + * 1,0000,0000. If you supply a pattern with multiple grouping characters, the
191.156 + * interval between the last one and the end of the integer is the one that is
191.157 + * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
191.158 + * <code>"##,####,####"</code>.
191.159 + *
191.160 + * <h4>Special Pattern Characters</h4>
191.161 + *
191.162 + * <p>Many characters in a pattern are taken literally; they are matched during
191.163 + * parsing and output unchanged during formatting. Special characters, on the
191.164 + * other hand, stand for other characters, strings, or classes of characters.
191.165 + * They must be quoted, unless noted otherwise, if they are to appear in the
191.166 + * prefix or suffix as literals.
191.167 + *
191.168 + * <p>The characters listed here are used in non-localized patterns. Localized
191.169 + * patterns use the corresponding characters taken from this formatter's
191.170 + * <code>DecimalFormatSymbols</code> object instead, and these characters lose
191.171 + * their special status. Two exceptions are the currency sign and quote, which
191.172 + * are not localized.
191.173 + *
191.174 + * <blockquote>
191.175 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
191.176 + * location, localized, and meaning.">
191.177 + * <tr bgcolor="#ccccff">
191.178 + * <th align=left>Symbol
191.179 + * <th align=left>Location
191.180 + * <th align=left>Localized?
191.181 + * <th align=left>Meaning
191.182 + * <tr valign=top>
191.183 + * <td><code>0</code>
191.184 + * <td>Number
191.185 + * <td>Yes
191.186 + * <td>Digit
191.187 + * <tr valign=top bgcolor="#eeeeff">
191.188 + * <td><code>#</code>
191.189 + * <td>Number
191.190 + * <td>Yes
191.191 + * <td>Digit, zero shows as absent
191.192 + * <tr valign=top>
191.193 + * <td><code>.</code>
191.194 + * <td>Number
191.195 + * <td>Yes
191.196 + * <td>Decimal separator or monetary decimal separator
191.197 + * <tr valign=top bgcolor="#eeeeff">
191.198 + * <td><code>-</code>
191.199 + * <td>Number
191.200 + * <td>Yes
191.201 + * <td>Minus sign
191.202 + * <tr valign=top>
191.203 + * <td><code>,</code>
191.204 + * <td>Number
191.205 + * <td>Yes
191.206 + * <td>Grouping separator
191.207 + * <tr valign=top bgcolor="#eeeeff">
191.208 + * <td><code>E</code>
191.209 + * <td>Number
191.210 + * <td>Yes
191.211 + * <td>Separates mantissa and exponent in scientific notation.
191.212 + * <em>Need not be quoted in prefix or suffix.</em>
191.213 + * <tr valign=top>
191.214 + * <td><code>;</code>
191.215 + * <td>Subpattern boundary
191.216 + * <td>Yes
191.217 + * <td>Separates positive and negative subpatterns
191.218 + * <tr valign=top bgcolor="#eeeeff">
191.219 + * <td><code>%</code>
191.220 + * <td>Prefix or suffix
191.221 + * <td>Yes
191.222 + * <td>Multiply by 100 and show as percentage
191.223 + * <tr valign=top>
191.224 + * <td><code>\u2030</code>
191.225 + * <td>Prefix or suffix
191.226 + * <td>Yes
191.227 + * <td>Multiply by 1000 and show as per mille value
191.228 + * <tr valign=top bgcolor="#eeeeff">
191.229 + * <td><code>¤</code> (<code>\u00A4</code>)
191.230 + * <td>Prefix or suffix
191.231 + * <td>No
191.232 + * <td>Currency sign, replaced by currency symbol. If
191.233 + * doubled, replaced by international currency symbol.
191.234 + * If present in a pattern, the monetary decimal separator
191.235 + * is used instead of the decimal separator.
191.236 + * <tr valign=top>
191.237 + * <td><code>'</code>
191.238 + * <td>Prefix or suffix
191.239 + * <td>No
191.240 + * <td>Used to quote special characters in a prefix or suffix,
191.241 + * for example, <code>"'#'#"</code> formats 123 to
191.242 + * <code>"#123"</code>. To create a single quote
191.243 + * itself, use two in a row: <code>"# o''clock"</code>.
191.244 + * </table>
191.245 + * </blockquote>
191.246 + *
191.247 + * <h4>Scientific Notation</h4>
191.248 + *
191.249 + * <p>Numbers in scientific notation are expressed as the product of a mantissa
191.250 + * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The
191.251 + * mantissa is often in the range 1.0 <= x < 10.0, but it need not be.
191.252 + * <code>DecimalFormat</code> can be instructed to format and parse scientific
191.253 + * notation <em>only via a pattern</em>; there is currently no factory method
191.254 + * that creates a scientific notation format. In a pattern, the exponent
191.255 + * character immediately followed by one or more digit characters indicates
191.256 + * scientific notation. Example: <code>"0.###E0"</code> formats the number
191.257 + * 1234 as <code>"1.234E3"</code>.
191.258 + *
191.259 + * <ul>
191.260 + * <li>The number of digit characters after the exponent character gives the
191.261 + * minimum exponent digit count. There is no maximum. Negative exponents are
191.262 + * formatted using the localized minus sign, <em>not</em> the prefix and suffix
191.263 + * from the pattern. This allows patterns such as <code>"0.###E0 m/s"</code>.
191.264 + *
191.265 + * <li>The minimum and maximum number of integer digits are interpreted
191.266 + * together:
191.267 + *
191.268 + * <ul>
191.269 + * <li>If the maximum number of integer digits is greater than their minimum number
191.270 + * and greater than 1, it forces the exponent to be a multiple of the maximum
191.271 + * number of integer digits, and the minimum number of integer digits to be
191.272 + * interpreted as 1. The most common use of this is to generate
191.273 + * <em>engineering notation</em>, in which the exponent is a multiple of three,
191.274 + * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
191.275 + * formats to <code>"12.345E3"</code>, and 123456 formats to
191.276 + * <code>"123.456E3"</code>.
191.277 + *
191.278 + * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
191.279 + * exponent. Example: 0.00123 formatted with <code>"00.###E0"</code> yields
191.280 + * <code>"12.3E-4"</code>.
191.281 + * </ul>
191.282 + *
191.283 + * <li>The number of significant digits in the mantissa is the sum of the
191.284 + * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
191.285 + * unaffected by the maximum integer digits. For example, 12345 formatted with
191.286 + * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
191.287 + * the significant digits count to zero. The number of significant digits
191.288 + * does not affect parsing.
191.289 + *
191.290 + * <li>Exponential patterns may not contain grouping separators.
191.291 + * </ul>
191.292 + *
191.293 + * <h4>Rounding</h4>
191.294 + *
191.295 + * <code>DecimalFormat</code> provides rounding modes defined in
191.296 + * {@link java.math.RoundingMode} for formatting. By default, it uses
191.297 + * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
191.298 + *
191.299 + * <h4>Digits</h4>
191.300 + *
191.301 + * For formatting, <code>DecimalFormat</code> uses the ten consecutive
191.302 + * characters starting with the localized zero digit defined in the
191.303 + * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
191.304 + * digits as well as all Unicode decimal digits, as defined by
191.305 + * {@link Character#digit Character.digit}, are recognized.
191.306 + *
191.307 + * <h4>Special Values</h4>
191.308 + *
191.309 + * <p><code>NaN</code> is formatted as a string, which typically has a single character
191.310 + * <code>\uFFFD</code>. This string is determined by the
191.311 + * <code>DecimalFormatSymbols</code> object. This is the only value for which
191.312 + * the prefixes and suffixes are not used.
191.313 + *
191.314 + * <p>Infinity is formatted as a string, which typically has a single character
191.315 + * <code>\u221E</code>, with the positive or negative prefixes and suffixes
191.316 + * applied. The infinity string is determined by the
191.317 + * <code>DecimalFormatSymbols</code> object.
191.318 + *
191.319 + * <p>Negative zero (<code>"-0"</code>) parses to
191.320 + * <ul>
191.321 + * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is
191.322 + * true,
191.323 + * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false
191.324 + * and <code>isParseIntegerOnly()</code> is true,
191.325 + * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code>
191.326 + * and <code>isParseIntegerOnly()</code> are false.
191.327 + * </ul>
191.328 + *
191.329 + * <h4><a name="synchronization">Synchronization</a></h4>
191.330 + *
191.331 + * <p>
191.332 + * Decimal formats are generally not synchronized.
191.333 + * It is recommended to create separate format instances for each thread.
191.334 + * If multiple threads access a format concurrently, it must be synchronized
191.335 + * externally.
191.336 + *
191.337 + * <h4>Example</h4>
191.338 + *
191.339 + * <blockquote><pre>
191.340 + * <strong>// Print out a number using the localized number, integer, currency,
191.341 + * // and percent format for each locale</strong>
191.342 + * Locale[] locales = NumberFormat.getAvailableLocales();
191.343 + * double myNumber = -1234.56;
191.344 + * NumberFormat form;
191.345 + * for (int j=0; j<4; ++j) {
191.346 + * System.out.println("FORMAT");
191.347 + * for (int i = 0; i < locales.length; ++i) {
191.348 + * if (locales[i].getCountry().length() == 0) {
191.349 + * continue; // Skip language-only locales
191.350 + * }
191.351 + * System.out.print(locales[i].getDisplayName());
191.352 + * switch (j) {
191.353 + * case 0:
191.354 + * form = NumberFormat.getInstance(locales[i]); break;
191.355 + * case 1:
191.356 + * form = NumberFormat.getIntegerInstance(locales[i]); break;
191.357 + * case 2:
191.358 + * form = NumberFormat.getCurrencyInstance(locales[i]); break;
191.359 + * default:
191.360 + * form = NumberFormat.getPercentInstance(locales[i]); break;
191.361 + * }
191.362 + * if (form instanceof DecimalFormat) {
191.363 + * System.out.print(": " + ((DecimalFormat) form).toPattern());
191.364 + * }
191.365 + * System.out.print(" -> " + form.format(myNumber));
191.366 + * try {
191.367 + * System.out.println(" -> " + form.parse(form.format(myNumber)));
191.368 + * } catch (ParseException e) {}
191.369 + * }
191.370 + * }
191.371 + * </pre></blockquote>
191.372 + *
191.373 + * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
191.374 + * @see NumberFormat
191.375 + * @see DecimalFormatSymbols
191.376 + * @see ParsePosition
191.377 + * @author Mark Davis
191.378 + * @author Alan Liu
191.379 + */
191.380 +public class DecimalFormat extends NumberFormat {
191.381 +
191.382 + /**
191.383 + * Creates a DecimalFormat using the default pattern and symbols
191.384 + * for the default locale. This is a convenient way to obtain a
191.385 + * DecimalFormat when internationalization is not the main concern.
191.386 + * <p>
191.387 + * To obtain standard formats for a given locale, use the factory methods
191.388 + * on NumberFormat such as getNumberInstance. These factories will
191.389 + * return the most appropriate sub-class of NumberFormat for a given
191.390 + * locale.
191.391 + *
191.392 + * @see java.text.NumberFormat#getInstance
191.393 + * @see java.text.NumberFormat#getNumberInstance
191.394 + * @see java.text.NumberFormat#getCurrencyInstance
191.395 + * @see java.text.NumberFormat#getPercentInstance
191.396 + */
191.397 + public DecimalFormat() {
191.398 + Locale def = Locale.getDefault(Locale.Category.FORMAT);
191.399 + // try to get the pattern from the cache
191.400 + String pattern = cachedLocaleData.get(def);
191.401 + if (pattern == null) { /* cache miss */
191.402 + // Get the pattern for the default locale.
191.403 +// ResourceBundle rb = LocaleData.getNumberFormatData(def);
191.404 +// String[] all = rb.getStringArray("NumberPatterns");
191.405 +// pattern = all[0];
191.406 +// /* update cache */
191.407 +// cachedLocaleData.putIfAbsent(def, pattern);
191.408 + }
191.409 +
191.410 + // Always applyPattern after the symbols are set
191.411 + this.symbols = new DecimalFormatSymbols(def);
191.412 + applyPattern(pattern, false);
191.413 + }
191.414 +
191.415 +
191.416 + /**
191.417 + * Creates a DecimalFormat using the given pattern and the symbols
191.418 + * for the default locale. This is a convenient way to obtain a
191.419 + * DecimalFormat when internationalization is not the main concern.
191.420 + * <p>
191.421 + * To obtain standard formats for a given locale, use the factory methods
191.422 + * on NumberFormat such as getNumberInstance. These factories will
191.423 + * return the most appropriate sub-class of NumberFormat for a given
191.424 + * locale.
191.425 + *
191.426 + * @param pattern A non-localized pattern string.
191.427 + * @exception NullPointerException if <code>pattern</code> is null
191.428 + * @exception IllegalArgumentException if the given pattern is invalid.
191.429 + * @see java.text.NumberFormat#getInstance
191.430 + * @see java.text.NumberFormat#getNumberInstance
191.431 + * @see java.text.NumberFormat#getCurrencyInstance
191.432 + * @see java.text.NumberFormat#getPercentInstance
191.433 + */
191.434 + public DecimalFormat(String pattern) {
191.435 + // Always applyPattern after the symbols are set
191.436 + this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT));
191.437 + applyPattern(pattern, false);
191.438 + }
191.439 +
191.440 +
191.441 + /**
191.442 + * Creates a DecimalFormat using the given pattern and symbols.
191.443 + * Use this constructor when you need to completely customize the
191.444 + * behavior of the format.
191.445 + * <p>
191.446 + * To obtain standard formats for a given
191.447 + * locale, use the factory methods on NumberFormat such as
191.448 + * getInstance or getCurrencyInstance. If you need only minor adjustments
191.449 + * to a standard format, you can modify the format returned by
191.450 + * a NumberFormat factory method.
191.451 + *
191.452 + * @param pattern a non-localized pattern string
191.453 + * @param symbols the set of symbols to be used
191.454 + * @exception NullPointerException if any of the given arguments is null
191.455 + * @exception IllegalArgumentException if the given pattern is invalid
191.456 + * @see java.text.NumberFormat#getInstance
191.457 + * @see java.text.NumberFormat#getNumberInstance
191.458 + * @see java.text.NumberFormat#getCurrencyInstance
191.459 + * @see java.text.NumberFormat#getPercentInstance
191.460 + * @see java.text.DecimalFormatSymbols
191.461 + */
191.462 + public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
191.463 + // Always applyPattern after the symbols are set
191.464 + this.symbols = (DecimalFormatSymbols)symbols.clone();
191.465 + applyPattern(pattern, false);
191.466 + }
191.467 +
191.468 +
191.469 + // Overrides
191.470 + /**
191.471 + * Formats a number and appends the resulting text to the given string
191.472 + * buffer.
191.473 + * The number can be of any subclass of {@link java.lang.Number}.
191.474 + * <p>
191.475 + * This implementation uses the maximum precision permitted.
191.476 + * @param number the number to format
191.477 + * @param toAppendTo the <code>StringBuffer</code> to which the formatted
191.478 + * text is to be appended
191.479 + * @param pos On input: an alignment field, if desired.
191.480 + * On output: the offsets of the alignment field.
191.481 + * @return the value passed in as <code>toAppendTo</code>
191.482 + * @exception IllegalArgumentException if <code>number</code> is
191.483 + * null or not an instance of <code>Number</code>.
191.484 + * @exception NullPointerException if <code>toAppendTo</code> or
191.485 + * <code>pos</code> is null
191.486 + * @exception ArithmeticException if rounding is needed with rounding
191.487 + * mode being set to RoundingMode.UNNECESSARY
191.488 + * @see java.text.FieldPosition
191.489 + */
191.490 + public final StringBuffer format(Object number,
191.491 + StringBuffer toAppendTo,
191.492 + FieldPosition pos) {
191.493 + if (number instanceof Long || number instanceof Integer ||
191.494 + number instanceof Short || number instanceof Byte ||
191.495 + number instanceof AtomicInteger ||
191.496 + number instanceof AtomicLong ||
191.497 + (number instanceof BigInteger &&
191.498 + ((BigInteger)number).bitLength () < 64)) {
191.499 + return format(((Number)number).longValue(), toAppendTo, pos);
191.500 + } else if (number instanceof BigDecimal) {
191.501 + return format((BigDecimal)number, toAppendTo, pos);
191.502 + } else if (number instanceof BigInteger) {
191.503 + return format((BigInteger)number, toAppendTo, pos);
191.504 + } else if (number instanceof Number) {
191.505 + return format(((Number)number).doubleValue(), toAppendTo, pos);
191.506 + } else {
191.507 + throw new IllegalArgumentException("Cannot format given Object as a Number");
191.508 + }
191.509 + }
191.510 +
191.511 + /**
191.512 + * Formats a double to produce a string.
191.513 + * @param number The double to format
191.514 + * @param result where the text is to be appended
191.515 + * @param fieldPosition On input: an alignment field, if desired.
191.516 + * On output: the offsets of the alignment field.
191.517 + * @exception ArithmeticException if rounding is needed with rounding
191.518 + * mode being set to RoundingMode.UNNECESSARY
191.519 + * @return The formatted number string
191.520 + * @see java.text.FieldPosition
191.521 + */
191.522 + public StringBuffer format(double number, StringBuffer result,
191.523 + FieldPosition fieldPosition) {
191.524 + fieldPosition.setBeginIndex(0);
191.525 + fieldPosition.setEndIndex(0);
191.526 +
191.527 + return format(number, result, fieldPosition.getFieldDelegate());
191.528 + }
191.529 +
191.530 + /**
191.531 + * Formats a double to produce a string.
191.532 + * @param number The double to format
191.533 + * @param result where the text is to be appended
191.534 + * @param delegate notified of locations of sub fields
191.535 + * @exception ArithmeticException if rounding is needed with rounding
191.536 + * mode being set to RoundingMode.UNNECESSARY
191.537 + * @return The formatted number string
191.538 + */
191.539 + private StringBuffer format(double number, StringBuffer result,
191.540 + FieldDelegate delegate) {
191.541 + if (Double.isNaN(number) ||
191.542 + (Double.isInfinite(number) && multiplier == 0)) {
191.543 + int iFieldStart = result.length();
191.544 + result.append(symbols.getNaN());
191.545 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
191.546 + iFieldStart, result.length(), result);
191.547 + return result;
191.548 + }
191.549 +
191.550 + /* Detecting whether a double is negative is easy with the exception of
191.551 + * the value -0.0. This is a double which has a zero mantissa (and
191.552 + * exponent), but a negative sign bit. It is semantically distinct from
191.553 + * a zero with a positive sign bit, and this distinction is important
191.554 + * to certain kinds of computations. However, it's a little tricky to
191.555 + * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
191.556 + * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
191.557 + * -Infinity. Proper detection of -0.0 is needed to deal with the
191.558 + * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
191.559 + */
191.560 + boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
191.561 +
191.562 + if (multiplier != 1) {
191.563 + number *= multiplier;
191.564 + }
191.565 +
191.566 + if (Double.isInfinite(number)) {
191.567 + if (isNegative) {
191.568 + append(result, negativePrefix, delegate,
191.569 + getNegativePrefixFieldPositions(), Field.SIGN);
191.570 + } else {
191.571 + append(result, positivePrefix, delegate,
191.572 + getPositivePrefixFieldPositions(), Field.SIGN);
191.573 + }
191.574 +
191.575 + int iFieldStart = result.length();
191.576 + result.append(symbols.getInfinity());
191.577 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
191.578 + iFieldStart, result.length(), result);
191.579 +
191.580 + if (isNegative) {
191.581 + append(result, negativeSuffix, delegate,
191.582 + getNegativeSuffixFieldPositions(), Field.SIGN);
191.583 + } else {
191.584 + append(result, positiveSuffix, delegate,
191.585 + getPositiveSuffixFieldPositions(), Field.SIGN);
191.586 + }
191.587 +
191.588 + return result;
191.589 + }
191.590 +
191.591 + if (isNegative) {
191.592 + number = -number;
191.593 + }
191.594 +
191.595 + // at this point we are guaranteed a nonnegative finite number.
191.596 + assert(number >= 0 && !Double.isInfinite(number));
191.597 +
191.598 + synchronized(digitList) {
191.599 + int maxIntDigits = super.getMaximumIntegerDigits();
191.600 + int minIntDigits = super.getMinimumIntegerDigits();
191.601 + int maxFraDigits = super.getMaximumFractionDigits();
191.602 + int minFraDigits = super.getMinimumFractionDigits();
191.603 +
191.604 + digitList.set(isNegative, number, useExponentialNotation ?
191.605 + maxIntDigits + maxFraDigits : maxFraDigits,
191.606 + !useExponentialNotation);
191.607 + return subformat(result, delegate, isNegative, false,
191.608 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
191.609 + }
191.610 + }
191.611 +
191.612 + /**
191.613 + * Format a long to produce a string.
191.614 + * @param number The long to format
191.615 + * @param result where the text is to be appended
191.616 + * @param fieldPosition On input: an alignment field, if desired.
191.617 + * On output: the offsets of the alignment field.
191.618 + * @exception ArithmeticException if rounding is needed with rounding
191.619 + * mode being set to RoundingMode.UNNECESSARY
191.620 + * @return The formatted number string
191.621 + * @see java.text.FieldPosition
191.622 + */
191.623 + public StringBuffer format(long number, StringBuffer result,
191.624 + FieldPosition fieldPosition) {
191.625 + fieldPosition.setBeginIndex(0);
191.626 + fieldPosition.setEndIndex(0);
191.627 +
191.628 + return format(number, result, fieldPosition.getFieldDelegate());
191.629 + }
191.630 +
191.631 + /**
191.632 + * Format a long to produce a string.
191.633 + * @param number The long to format
191.634 + * @param result where the text is to be appended
191.635 + * @param delegate notified of locations of sub fields
191.636 + * @return The formatted number string
191.637 + * @exception ArithmeticException if rounding is needed with rounding
191.638 + * mode being set to RoundingMode.UNNECESSARY
191.639 + * @see java.text.FieldPosition
191.640 + */
191.641 + private StringBuffer format(long number, StringBuffer result,
191.642 + FieldDelegate delegate) {
191.643 + boolean isNegative = (number < 0);
191.644 + if (isNegative) {
191.645 + number = -number;
191.646 + }
191.647 +
191.648 + // In general, long values always represent real finite numbers, so
191.649 + // we don't have to check for +/- Infinity or NaN. However, there
191.650 + // is one case we have to be careful of: The multiplier can push
191.651 + // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
191.652 + // check for this before multiplying, and if it happens we use
191.653 + // BigInteger instead.
191.654 + boolean useBigInteger = false;
191.655 + if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
191.656 + if (multiplier != 0) {
191.657 + useBigInteger = true;
191.658 + }
191.659 + } else if (multiplier != 1 && multiplier != 0) {
191.660 + long cutoff = Long.MAX_VALUE / multiplier;
191.661 + if (cutoff < 0) {
191.662 + cutoff = -cutoff;
191.663 + }
191.664 + useBigInteger = (number > cutoff);
191.665 + }
191.666 +
191.667 + if (useBigInteger) {
191.668 + if (isNegative) {
191.669 + number = -number;
191.670 + }
191.671 + BigInteger bigIntegerValue = BigInteger.valueOf(number);
191.672 + return format(bigIntegerValue, result, delegate, true);
191.673 + }
191.674 +
191.675 + number *= multiplier;
191.676 + if (number == 0) {
191.677 + isNegative = false;
191.678 + } else {
191.679 + if (multiplier < 0) {
191.680 + number = -number;
191.681 + isNegative = !isNegative;
191.682 + }
191.683 + }
191.684 +
191.685 + synchronized(digitList) {
191.686 + int maxIntDigits = super.getMaximumIntegerDigits();
191.687 + int minIntDigits = super.getMinimumIntegerDigits();
191.688 + int maxFraDigits = super.getMaximumFractionDigits();
191.689 + int minFraDigits = super.getMinimumFractionDigits();
191.690 +
191.691 + digitList.set(isNegative, number,
191.692 + useExponentialNotation ? maxIntDigits + maxFraDigits : 0);
191.693 +
191.694 + return subformat(result, delegate, isNegative, true,
191.695 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
191.696 + }
191.697 + }
191.698 +
191.699 + /**
191.700 + * Formats a BigDecimal to produce a string.
191.701 + * @param number The BigDecimal to format
191.702 + * @param result where the text is to be appended
191.703 + * @param fieldPosition On input: an alignment field, if desired.
191.704 + * On output: the offsets of the alignment field.
191.705 + * @return The formatted number string
191.706 + * @exception ArithmeticException if rounding is needed with rounding
191.707 + * mode being set to RoundingMode.UNNECESSARY
191.708 + * @see java.text.FieldPosition
191.709 + */
191.710 + private StringBuffer format(BigDecimal number, StringBuffer result,
191.711 + FieldPosition fieldPosition) {
191.712 + fieldPosition.setBeginIndex(0);
191.713 + fieldPosition.setEndIndex(0);
191.714 + return format(number, result, fieldPosition.getFieldDelegate());
191.715 + }
191.716 +
191.717 + /**
191.718 + * Formats a BigDecimal to produce a string.
191.719 + * @param number The BigDecimal to format
191.720 + * @param result where the text is to be appended
191.721 + * @param delegate notified of locations of sub fields
191.722 + * @exception ArithmeticException if rounding is needed with rounding
191.723 + * mode being set to RoundingMode.UNNECESSARY
191.724 + * @return The formatted number string
191.725 + */
191.726 + private StringBuffer format(BigDecimal number, StringBuffer result,
191.727 + FieldDelegate delegate) {
191.728 + if (multiplier != 1) {
191.729 + number = number.multiply(getBigDecimalMultiplier());
191.730 + }
191.731 + boolean isNegative = number.signum() == -1;
191.732 + if (isNegative) {
191.733 + number = number.negate();
191.734 + }
191.735 +
191.736 + synchronized(digitList) {
191.737 + int maxIntDigits = getMaximumIntegerDigits();
191.738 + int minIntDigits = getMinimumIntegerDigits();
191.739 + int maxFraDigits = getMaximumFractionDigits();
191.740 + int minFraDigits = getMinimumFractionDigits();
191.741 + int maximumDigits = maxIntDigits + maxFraDigits;
191.742 +
191.743 + digitList.set(isNegative, number, useExponentialNotation ?
191.744 + ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
191.745 + maxFraDigits, !useExponentialNotation);
191.746 +
191.747 + return subformat(result, delegate, isNegative, false,
191.748 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
191.749 + }
191.750 + }
191.751 +
191.752 + /**
191.753 + * Format a BigInteger to produce a string.
191.754 + * @param number The BigInteger to format
191.755 + * @param result where the text is to be appended
191.756 + * @param fieldPosition On input: an alignment field, if desired.
191.757 + * On output: the offsets of the alignment field.
191.758 + * @return The formatted number string
191.759 + * @exception ArithmeticException if rounding is needed with rounding
191.760 + * mode being set to RoundingMode.UNNECESSARY
191.761 + * @see java.text.FieldPosition
191.762 + */
191.763 + private StringBuffer format(BigInteger number, StringBuffer result,
191.764 + FieldPosition fieldPosition) {
191.765 + fieldPosition.setBeginIndex(0);
191.766 + fieldPosition.setEndIndex(0);
191.767 +
191.768 + return format(number, result, fieldPosition.getFieldDelegate(), false);
191.769 + }
191.770 +
191.771 + /**
191.772 + * Format a BigInteger to produce a string.
191.773 + * @param number The BigInteger to format
191.774 + * @param result where the text is to be appended
191.775 + * @param delegate notified of locations of sub fields
191.776 + * @return The formatted number string
191.777 + * @exception ArithmeticException if rounding is needed with rounding
191.778 + * mode being set to RoundingMode.UNNECESSARY
191.779 + * @see java.text.FieldPosition
191.780 + */
191.781 + private StringBuffer format(BigInteger number, StringBuffer result,
191.782 + FieldDelegate delegate, boolean formatLong) {
191.783 + if (multiplier != 1) {
191.784 + number = number.multiply(getBigIntegerMultiplier());
191.785 + }
191.786 + boolean isNegative = number.signum() == -1;
191.787 + if (isNegative) {
191.788 + number = number.negate();
191.789 + }
191.790 +
191.791 + synchronized(digitList) {
191.792 + int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
191.793 + if (formatLong) {
191.794 + maxIntDigits = super.getMaximumIntegerDigits();
191.795 + minIntDigits = super.getMinimumIntegerDigits();
191.796 + maxFraDigits = super.getMaximumFractionDigits();
191.797 + minFraDigits = super.getMinimumFractionDigits();
191.798 + maximumDigits = maxIntDigits + maxFraDigits;
191.799 + } else {
191.800 + maxIntDigits = getMaximumIntegerDigits();
191.801 + minIntDigits = getMinimumIntegerDigits();
191.802 + maxFraDigits = getMaximumFractionDigits();
191.803 + minFraDigits = getMinimumFractionDigits();
191.804 + maximumDigits = maxIntDigits + maxFraDigits;
191.805 + if (maximumDigits < 0) {
191.806 + maximumDigits = Integer.MAX_VALUE;
191.807 + }
191.808 + }
191.809 +
191.810 + digitList.set(isNegative, number,
191.811 + useExponentialNotation ? maximumDigits : 0);
191.812 +
191.813 + return subformat(result, delegate, isNegative, true,
191.814 + maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
191.815 + }
191.816 + }
191.817 +
191.818 + /**
191.819 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
191.820 + * You can use the returned <code>AttributedCharacterIterator</code>
191.821 + * to build the resulting String, as well as to determine information
191.822 + * about the resulting String.
191.823 + * <p>
191.824 + * Each attribute key of the AttributedCharacterIterator will be of type
191.825 + * <code>NumberFormat.Field</code>, with the attribute value being the
191.826 + * same as the attribute key.
191.827 + *
191.828 + * @exception NullPointerException if obj is null.
191.829 + * @exception IllegalArgumentException when the Format cannot format the
191.830 + * given object.
191.831 + * @exception ArithmeticException if rounding is needed with rounding
191.832 + * mode being set to RoundingMode.UNNECESSARY
191.833 + * @param obj The object to format
191.834 + * @return AttributedCharacterIterator describing the formatted value.
191.835 + * @since 1.4
191.836 + */
191.837 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
191.838 + CharacterIteratorFieldDelegate delegate =
191.839 + new CharacterIteratorFieldDelegate();
191.840 + StringBuffer sb = new StringBuffer();
191.841 +
191.842 + if (obj instanceof Double || obj instanceof Float) {
191.843 + format(((Number)obj).doubleValue(), sb, delegate);
191.844 + } else if (obj instanceof Long || obj instanceof Integer ||
191.845 + obj instanceof Short || obj instanceof Byte ||
191.846 + obj instanceof AtomicInteger || obj instanceof AtomicLong) {
191.847 + format(((Number)obj).longValue(), sb, delegate);
191.848 + } else if (obj instanceof BigDecimal) {
191.849 + format((BigDecimal)obj, sb, delegate);
191.850 + } else if (obj instanceof BigInteger) {
191.851 + format((BigInteger)obj, sb, delegate, false);
191.852 + } else if (obj == null) {
191.853 + throw new NullPointerException(
191.854 + "formatToCharacterIterator must be passed non-null object");
191.855 + } else {
191.856 + throw new IllegalArgumentException(
191.857 + "Cannot format given Object as a Number");
191.858 + }
191.859 + return delegate.getIterator(sb.toString());
191.860 + }
191.861 +
191.862 + /**
191.863 + * Complete the formatting of a finite number. On entry, the digitList must
191.864 + * be filled in with the correct digits.
191.865 + */
191.866 + private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
191.867 + boolean isNegative, boolean isInteger,
191.868 + int maxIntDigits, int minIntDigits,
191.869 + int maxFraDigits, int minFraDigits) {
191.870 + // NOTE: This isn't required anymore because DigitList takes care of this.
191.871 + //
191.872 + // // The negative of the exponent represents the number of leading
191.873 + // // zeros between the decimal and the first non-zero digit, for
191.874 + // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
191.875 + // // is more than the maximum fraction digits, then we have an underflow
191.876 + // // for the printed representation. We recognize this here and set
191.877 + // // the DigitList representation to zero in this situation.
191.878 + //
191.879 + // if (-digitList.decimalAt >= getMaximumFractionDigits())
191.880 + // {
191.881 + // digitList.count = 0;
191.882 + // }
191.883 +
191.884 + char zero = symbols.getZeroDigit();
191.885 + int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
191.886 + char grouping = symbols.getGroupingSeparator();
191.887 + char decimal = isCurrencyFormat ?
191.888 + symbols.getMonetaryDecimalSeparator() :
191.889 + symbols.getDecimalSeparator();
191.890 +
191.891 + /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
191.892 + * format as zero. This allows sensible computations and preserves
191.893 + * relations such as signum(1/x) = signum(x), where x is +Infinity or
191.894 + * -Infinity. Prior to this fix, we always formatted zero values as if
191.895 + * they were positive. Liu 7/6/98.
191.896 + */
191.897 + if (digitList.isZero()) {
191.898 + digitList.decimalAt = 0; // Normalize
191.899 + }
191.900 +
191.901 + if (isNegative) {
191.902 + append(result, negativePrefix, delegate,
191.903 + getNegativePrefixFieldPositions(), Field.SIGN);
191.904 + } else {
191.905 + append(result, positivePrefix, delegate,
191.906 + getPositivePrefixFieldPositions(), Field.SIGN);
191.907 + }
191.908 +
191.909 + if (useExponentialNotation) {
191.910 + int iFieldStart = result.length();
191.911 + int iFieldEnd = -1;
191.912 + int fFieldStart = -1;
191.913 +
191.914 + // Minimum integer digits are handled in exponential format by
191.915 + // adjusting the exponent. For example, 0.01234 with 3 minimum
191.916 + // integer digits is "123.4E-4".
191.917 +
191.918 + // Maximum integer digits are interpreted as indicating the
191.919 + // repeating range. This is useful for engineering notation, in
191.920 + // which the exponent is restricted to a multiple of 3. For
191.921 + // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
191.922 + // If maximum integer digits are > 1 and are larger than
191.923 + // minimum integer digits, then minimum integer digits are
191.924 + // ignored.
191.925 + int exponent = digitList.decimalAt;
191.926 + int repeat = maxIntDigits;
191.927 + int minimumIntegerDigits = minIntDigits;
191.928 + if (repeat > 1 && repeat > minIntDigits) {
191.929 + // A repeating range is defined; adjust to it as follows.
191.930 + // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
191.931 + // -3,-4,-5=>-6, etc. This takes into account that the
191.932 + // exponent we have here is off by one from what we expect;
191.933 + // it is for the format 0.MMMMMx10^n.
191.934 + if (exponent >= 1) {
191.935 + exponent = ((exponent - 1) / repeat) * repeat;
191.936 + } else {
191.937 + // integer division rounds towards 0
191.938 + exponent = ((exponent - repeat) / repeat) * repeat;
191.939 + }
191.940 + minimumIntegerDigits = 1;
191.941 + } else {
191.942 + // No repeating range is defined; use minimum integer digits.
191.943 + exponent -= minimumIntegerDigits;
191.944 + }
191.945 +
191.946 + // We now output a minimum number of digits, and more if there
191.947 + // are more digits, up to the maximum number of digits. We
191.948 + // place the decimal point after the "integer" digits, which
191.949 + // are the first (decimalAt - exponent) digits.
191.950 + int minimumDigits = minIntDigits + minFraDigits;
191.951 + if (minimumDigits < 0) { // overflow?
191.952 + minimumDigits = Integer.MAX_VALUE;
191.953 + }
191.954 +
191.955 + // The number of integer digits is handled specially if the number
191.956 + // is zero, since then there may be no digits.
191.957 + int integerDigits = digitList.isZero() ? minimumIntegerDigits :
191.958 + digitList.decimalAt - exponent;
191.959 + if (minimumDigits < integerDigits) {
191.960 + minimumDigits = integerDigits;
191.961 + }
191.962 + int totalDigits = digitList.count;
191.963 + if (minimumDigits > totalDigits) {
191.964 + totalDigits = minimumDigits;
191.965 + }
191.966 + boolean addedDecimalSeparator = false;
191.967 +
191.968 + for (int i=0; i<totalDigits; ++i) {
191.969 + if (i == integerDigits) {
191.970 + // Record field information for caller.
191.971 + iFieldEnd = result.length();
191.972 +
191.973 + result.append(decimal);
191.974 + addedDecimalSeparator = true;
191.975 +
191.976 + // Record field information for caller.
191.977 + fFieldStart = result.length();
191.978 + }
191.979 + result.append((i < digitList.count) ?
191.980 + (char)(digitList.digits[i] + zeroDelta) :
191.981 + zero);
191.982 + }
191.983 +
191.984 + if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
191.985 + // Record field information for caller.
191.986 + iFieldEnd = result.length();
191.987 +
191.988 + result.append(decimal);
191.989 + addedDecimalSeparator = true;
191.990 +
191.991 + // Record field information for caller.
191.992 + fFieldStart = result.length();
191.993 + }
191.994 +
191.995 + // Record field information
191.996 + if (iFieldEnd == -1) {
191.997 + iFieldEnd = result.length();
191.998 + }
191.999 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
191.1000 + iFieldStart, iFieldEnd, result);
191.1001 + if (addedDecimalSeparator) {
191.1002 + delegate.formatted(Field.DECIMAL_SEPARATOR,
191.1003 + Field.DECIMAL_SEPARATOR,
191.1004 + iFieldEnd, fFieldStart, result);
191.1005 + }
191.1006 + if (fFieldStart == -1) {
191.1007 + fFieldStart = result.length();
191.1008 + }
191.1009 + delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
191.1010 + fFieldStart, result.length(), result);
191.1011 +
191.1012 + // The exponent is output using the pattern-specified minimum
191.1013 + // exponent digits. There is no maximum limit to the exponent
191.1014 + // digits, since truncating the exponent would result in an
191.1015 + // unacceptable inaccuracy.
191.1016 + int fieldStart = result.length();
191.1017 +
191.1018 + result.append(symbols.getExponentSeparator());
191.1019 +
191.1020 + delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
191.1021 + fieldStart, result.length(), result);
191.1022 +
191.1023 + // For zero values, we force the exponent to zero. We
191.1024 + // must do this here, and not earlier, because the value
191.1025 + // is used to determine integer digit count above.
191.1026 + if (digitList.isZero()) {
191.1027 + exponent = 0;
191.1028 + }
191.1029 +
191.1030 + boolean negativeExponent = exponent < 0;
191.1031 + if (negativeExponent) {
191.1032 + exponent = -exponent;
191.1033 + fieldStart = result.length();
191.1034 + result.append(symbols.getMinusSign());
191.1035 + delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
191.1036 + fieldStart, result.length(), result);
191.1037 + }
191.1038 + digitList.set(negativeExponent, exponent);
191.1039 +
191.1040 + int eFieldStart = result.length();
191.1041 +
191.1042 + for (int i=digitList.decimalAt; i<minExponentDigits; ++i) {
191.1043 + result.append(zero);
191.1044 + }
191.1045 + for (int i=0; i<digitList.decimalAt; ++i) {
191.1046 + result.append((i < digitList.count) ?
191.1047 + (char)(digitList.digits[i] + zeroDelta) : zero);
191.1048 + }
191.1049 + delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
191.1050 + result.length(), result);
191.1051 + } else {
191.1052 + int iFieldStart = result.length();
191.1053 +
191.1054 + // Output the integer portion. Here 'count' is the total
191.1055 + // number of integer digits we will display, including both
191.1056 + // leading zeros required to satisfy getMinimumIntegerDigits,
191.1057 + // and actual digits present in the number.
191.1058 + int count = minIntDigits;
191.1059 + int digitIndex = 0; // Index into digitList.fDigits[]
191.1060 + if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
191.1061 + count = digitList.decimalAt;
191.1062 + }
191.1063 +
191.1064 + // Handle the case where getMaximumIntegerDigits() is smaller
191.1065 + // than the real number of integer digits. If this is so, we
191.1066 + // output the least significant max integer digits. For example,
191.1067 + // the value 1997 printed with 2 max integer digits is just "97".
191.1068 + if (count > maxIntDigits) {
191.1069 + count = maxIntDigits;
191.1070 + digitIndex = digitList.decimalAt - count;
191.1071 + }
191.1072 +
191.1073 + int sizeBeforeIntegerPart = result.length();
191.1074 + for (int i=count-1; i>=0; --i) {
191.1075 + if (i < digitList.decimalAt && digitIndex < digitList.count) {
191.1076 + // Output a real digit
191.1077 + result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
191.1078 + } else {
191.1079 + // Output a leading zero
191.1080 + result.append(zero);
191.1081 + }
191.1082 +
191.1083 + // Output grouping separator if necessary. Don't output a
191.1084 + // grouping separator if i==0 though; that's at the end of
191.1085 + // the integer part.
191.1086 + if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
191.1087 + (i % groupingSize == 0)) {
191.1088 + int gStart = result.length();
191.1089 + result.append(grouping);
191.1090 + delegate.formatted(Field.GROUPING_SEPARATOR,
191.1091 + Field.GROUPING_SEPARATOR, gStart,
191.1092 + result.length(), result);
191.1093 + }
191.1094 + }
191.1095 +
191.1096 + // Determine whether or not there are any printable fractional
191.1097 + // digits. If we've used up the digits we know there aren't.
191.1098 + boolean fractionPresent = (minFraDigits > 0) ||
191.1099 + (!isInteger && digitIndex < digitList.count);
191.1100 +
191.1101 + // If there is no fraction present, and we haven't printed any
191.1102 + // integer digits, then print a zero. Otherwise we won't print
191.1103 + // _any_ digits, and we won't be able to parse this string.
191.1104 + if (!fractionPresent && result.length() == sizeBeforeIntegerPart) {
191.1105 + result.append(zero);
191.1106 + }
191.1107 +
191.1108 + delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
191.1109 + iFieldStart, result.length(), result);
191.1110 +
191.1111 + // Output the decimal separator if we always do so.
191.1112 + int sStart = result.length();
191.1113 + if (decimalSeparatorAlwaysShown || fractionPresent) {
191.1114 + result.append(decimal);
191.1115 + }
191.1116 +
191.1117 + if (sStart != result.length()) {
191.1118 + delegate.formatted(Field.DECIMAL_SEPARATOR,
191.1119 + Field.DECIMAL_SEPARATOR,
191.1120 + sStart, result.length(), result);
191.1121 + }
191.1122 + int fFieldStart = result.length();
191.1123 +
191.1124 + for (int i=0; i < maxFraDigits; ++i) {
191.1125 + // Here is where we escape from the loop. We escape if we've
191.1126 + // output the maximum fraction digits (specified in the for
191.1127 + // expression above).
191.1128 + // We also stop when we've output the minimum digits and either:
191.1129 + // we have an integer, so there is no fractional stuff to
191.1130 + // display, or we're out of significant digits.
191.1131 + if (i >= minFraDigits &&
191.1132 + (isInteger || digitIndex >= digitList.count)) {
191.1133 + break;
191.1134 + }
191.1135 +
191.1136 + // Output leading fractional zeros. These are zeros that come
191.1137 + // after the decimal but before any significant digits. These
191.1138 + // are only output if abs(number being formatted) < 1.0.
191.1139 + if (-1-i > (digitList.decimalAt-1)) {
191.1140 + result.append(zero);
191.1141 + continue;
191.1142 + }
191.1143 +
191.1144 + // Output a digit, if we have any precision left, or a
191.1145 + // zero if we don't. We don't want to output noise digits.
191.1146 + if (!isInteger && digitIndex < digitList.count) {
191.1147 + result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
191.1148 + } else {
191.1149 + result.append(zero);
191.1150 + }
191.1151 + }
191.1152 +
191.1153 + // Record field information for caller.
191.1154 + delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
191.1155 + fFieldStart, result.length(), result);
191.1156 + }
191.1157 +
191.1158 + if (isNegative) {
191.1159 + append(result, negativeSuffix, delegate,
191.1160 + getNegativeSuffixFieldPositions(), Field.SIGN);
191.1161 + }
191.1162 + else {
191.1163 + append(result, positiveSuffix, delegate,
191.1164 + getPositiveSuffixFieldPositions(), Field.SIGN);
191.1165 + }
191.1166 +
191.1167 + return result;
191.1168 + }
191.1169 +
191.1170 + /**
191.1171 + * Appends the String <code>string</code> to <code>result</code>.
191.1172 + * <code>delegate</code> is notified of all the
191.1173 + * <code>FieldPosition</code>s in <code>positions</code>.
191.1174 + * <p>
191.1175 + * If one of the <code>FieldPosition</code>s in <code>positions</code>
191.1176 + * identifies a <code>SIGN</code> attribute, it is mapped to
191.1177 + * <code>signAttribute</code>. This is used
191.1178 + * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
191.1179 + * attribute as necessary.
191.1180 + * <p>
191.1181 + * This is used by <code>subformat</code> to add the prefix/suffix.
191.1182 + */
191.1183 + private void append(StringBuffer result, String string,
191.1184 + FieldDelegate delegate,
191.1185 + FieldPosition[] positions,
191.1186 + Format.Field signAttribute) {
191.1187 + int start = result.length();
191.1188 +
191.1189 + if (string.length() > 0) {
191.1190 + result.append(string);
191.1191 + for (int counter = 0, max = positions.length; counter < max;
191.1192 + counter++) {
191.1193 + FieldPosition fp = positions[counter];
191.1194 + Format.Field attribute = fp.getFieldAttribute();
191.1195 +
191.1196 + if (attribute == Field.SIGN) {
191.1197 + attribute = signAttribute;
191.1198 + }
191.1199 + delegate.formatted(attribute, attribute,
191.1200 + start + fp.getBeginIndex(),
191.1201 + start + fp.getEndIndex(), result);
191.1202 + }
191.1203 + }
191.1204 + }
191.1205 +
191.1206 + /**
191.1207 + * Parses text from a string to produce a <code>Number</code>.
191.1208 + * <p>
191.1209 + * The method attempts to parse text starting at the index given by
191.1210 + * <code>pos</code>.
191.1211 + * If parsing succeeds, then the index of <code>pos</code> is updated
191.1212 + * to the index after the last character used (parsing does not necessarily
191.1213 + * use all characters up to the end of the string), and the parsed
191.1214 + * number is returned. The updated <code>pos</code> can be used to
191.1215 + * indicate the starting point for the next call to this method.
191.1216 + * If an error occurs, then the index of <code>pos</code> is not
191.1217 + * changed, the error index of <code>pos</code> is set to the index of
191.1218 + * the character where the error occurred, and null is returned.
191.1219 + * <p>
191.1220 + * The subclass returned depends on the value of {@link #isParseBigDecimal}
191.1221 + * as well as on the string being parsed.
191.1222 + * <ul>
191.1223 + * <li>If <code>isParseBigDecimal()</code> is false (the default),
191.1224 + * most integer values are returned as <code>Long</code>
191.1225 + * objects, no matter how they are written: <code>"17"</code> and
191.1226 + * <code>"17.000"</code> both parse to <code>Long(17)</code>.
191.1227 + * Values that cannot fit into a <code>Long</code> are returned as
191.1228 + * <code>Double</code>s. This includes values with a fractional part,
191.1229 + * infinite values, <code>NaN</code>, and the value -0.0.
191.1230 + * <code>DecimalFormat</code> does <em>not</em> decide whether to
191.1231 + * return a <code>Double</code> or a <code>Long</code> based on the
191.1232 + * presence of a decimal separator in the source string. Doing so
191.1233 + * would prevent integers that overflow the mantissa of a double,
191.1234 + * such as <code>"-9,223,372,036,854,775,808.00"</code>, from being
191.1235 + * parsed accurately.
191.1236 + * <p>
191.1237 + * Callers may use the <code>Number</code> methods
191.1238 + * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain
191.1239 + * the type they want.
191.1240 + * <li>If <code>isParseBigDecimal()</code> is true, values are returned
191.1241 + * as <code>BigDecimal</code> objects. The values are the ones
191.1242 + * constructed by {@link java.math.BigDecimal#BigDecimal(String)}
191.1243 + * for corresponding strings in locale-independent format. The
191.1244 + * special cases negative and positive infinity and NaN are returned
191.1245 + * as <code>Double</code> instances holding the values of the
191.1246 + * corresponding <code>Double</code> constants.
191.1247 + * </ul>
191.1248 + * <p>
191.1249 + * <code>DecimalFormat</code> parses all Unicode characters that represent
191.1250 + * decimal digits, as defined by <code>Character.digit()</code>. In
191.1251 + * addition, <code>DecimalFormat</code> also recognizes as digits the ten
191.1252 + * consecutive characters starting with the localized zero digit defined in
191.1253 + * the <code>DecimalFormatSymbols</code> object.
191.1254 + *
191.1255 + * @param text the string to be parsed
191.1256 + * @param pos A <code>ParsePosition</code> object with index and error
191.1257 + * index information as described above.
191.1258 + * @return the parsed value, or <code>null</code> if the parse fails
191.1259 + * @exception NullPointerException if <code>text</code> or
191.1260 + * <code>pos</code> is null.
191.1261 + */
191.1262 + public Number parse(String text, ParsePosition pos) {
191.1263 + // special case NaN
191.1264 + if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) {
191.1265 + pos.index = pos.index + symbols.getNaN().length();
191.1266 + return new Double(Double.NaN);
191.1267 + }
191.1268 +
191.1269 + boolean[] status = new boolean[STATUS_LENGTH];
191.1270 + if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) {
191.1271 + return null;
191.1272 + }
191.1273 +
191.1274 + // special case INFINITY
191.1275 + if (status[STATUS_INFINITE]) {
191.1276 + if (status[STATUS_POSITIVE] == (multiplier >= 0)) {
191.1277 + return new Double(Double.POSITIVE_INFINITY);
191.1278 + } else {
191.1279 + return new Double(Double.NEGATIVE_INFINITY);
191.1280 + }
191.1281 + }
191.1282 +
191.1283 + if (multiplier == 0) {
191.1284 + if (digitList.isZero()) {
191.1285 + return new Double(Double.NaN);
191.1286 + } else if (status[STATUS_POSITIVE]) {
191.1287 + return new Double(Double.POSITIVE_INFINITY);
191.1288 + } else {
191.1289 + return new Double(Double.NEGATIVE_INFINITY);
191.1290 + }
191.1291 + }
191.1292 +
191.1293 + if (isParseBigDecimal()) {
191.1294 + BigDecimal bigDecimalResult = digitList.getBigDecimal();
191.1295 +
191.1296 + if (multiplier != 1) {
191.1297 + try {
191.1298 + bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier());
191.1299 + }
191.1300 + catch (ArithmeticException e) { // non-terminating decimal expansion
191.1301 + bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode);
191.1302 + }
191.1303 + }
191.1304 +
191.1305 + if (!status[STATUS_POSITIVE]) {
191.1306 + bigDecimalResult = bigDecimalResult.negate();
191.1307 + }
191.1308 + return bigDecimalResult;
191.1309 + } else {
191.1310 + boolean gotDouble = true;
191.1311 + boolean gotLongMinimum = false;
191.1312 + double doubleResult = 0.0;
191.1313 + long longResult = 0;
191.1314 +
191.1315 + // Finally, have DigitList parse the digits into a value.
191.1316 + if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) {
191.1317 + gotDouble = false;
191.1318 + longResult = digitList.getLong();
191.1319 + if (longResult < 0) { // got Long.MIN_VALUE
191.1320 + gotLongMinimum = true;
191.1321 + }
191.1322 + } else {
191.1323 + doubleResult = digitList.getDouble();
191.1324 + }
191.1325 +
191.1326 + // Divide by multiplier. We have to be careful here not to do
191.1327 + // unneeded conversions between double and long.
191.1328 + if (multiplier != 1) {
191.1329 + if (gotDouble) {
191.1330 + doubleResult /= multiplier;
191.1331 + } else {
191.1332 + // Avoid converting to double if we can
191.1333 + if (longResult % multiplier == 0) {
191.1334 + longResult /= multiplier;
191.1335 + } else {
191.1336 + doubleResult = ((double)longResult) / multiplier;
191.1337 + gotDouble = true;
191.1338 + }
191.1339 + }
191.1340 + }
191.1341 +
191.1342 + if (!status[STATUS_POSITIVE] && !gotLongMinimum) {
191.1343 + doubleResult = -doubleResult;
191.1344 + longResult = -longResult;
191.1345 + }
191.1346 +
191.1347 + // At this point, if we divided the result by the multiplier, the
191.1348 + // result may fit into a long. We check for this case and return
191.1349 + // a long if possible.
191.1350 + // We must do this AFTER applying the negative (if appropriate)
191.1351 + // in order to handle the case of LONG_MIN; otherwise, if we do
191.1352 + // this with a positive value -LONG_MIN, the double is > 0, but
191.1353 + // the long is < 0. We also must retain a double in the case of
191.1354 + // -0.0, which will compare as == to a long 0 cast to a double
191.1355 + // (bug 4162852).
191.1356 + if (multiplier != 1 && gotDouble) {
191.1357 + longResult = (long)doubleResult;
191.1358 + gotDouble = ((doubleResult != (double)longResult) ||
191.1359 + (doubleResult == 0.0 && 1/doubleResult < 0.0)) &&
191.1360 + !isParseIntegerOnly();
191.1361 + }
191.1362 +
191.1363 + return gotDouble ?
191.1364 + (Number)new Double(doubleResult) : (Number)new Long(longResult);
191.1365 + }
191.1366 + }
191.1367 +
191.1368 + /**
191.1369 + * Return a BigInteger multiplier.
191.1370 + */
191.1371 + private BigInteger getBigIntegerMultiplier() {
191.1372 + if (bigIntegerMultiplier == null) {
191.1373 + bigIntegerMultiplier = BigInteger.valueOf(multiplier);
191.1374 + }
191.1375 + return bigIntegerMultiplier;
191.1376 + }
191.1377 + private transient BigInteger bigIntegerMultiplier;
191.1378 +
191.1379 + /**
191.1380 + * Return a BigDecimal multiplier.
191.1381 + */
191.1382 + private BigDecimal getBigDecimalMultiplier() {
191.1383 + if (bigDecimalMultiplier == null) {
191.1384 + bigDecimalMultiplier = new BigDecimal(multiplier);
191.1385 + }
191.1386 + return bigDecimalMultiplier;
191.1387 + }
191.1388 + private transient BigDecimal bigDecimalMultiplier;
191.1389 +
191.1390 + private static final int STATUS_INFINITE = 0;
191.1391 + private static final int STATUS_POSITIVE = 1;
191.1392 + private static final int STATUS_LENGTH = 2;
191.1393 +
191.1394 + /**
191.1395 + * Parse the given text into a number. The text is parsed beginning at
191.1396 + * parsePosition, until an unparseable character is seen.
191.1397 + * @param text The string to parse.
191.1398 + * @param parsePosition The position at which to being parsing. Upon
191.1399 + * return, the first unparseable character.
191.1400 + * @param digits The DigitList to set to the parsed value.
191.1401 + * @param isExponent If true, parse an exponent. This means no
191.1402 + * infinite values and integer only.
191.1403 + * @param status Upon return contains boolean status flags indicating
191.1404 + * whether the value was infinite and whether it was positive.
191.1405 + */
191.1406 + private final boolean subparse(String text, ParsePosition parsePosition,
191.1407 + String positivePrefix, String negativePrefix,
191.1408 + DigitList digits, boolean isExponent,
191.1409 + boolean status[]) {
191.1410 + int position = parsePosition.index;
191.1411 + int oldStart = parsePosition.index;
191.1412 + int backup;
191.1413 + boolean gotPositive, gotNegative;
191.1414 +
191.1415 + // check for positivePrefix; take longest
191.1416 + gotPositive = text.regionMatches(position, positivePrefix, 0,
191.1417 + positivePrefix.length());
191.1418 + gotNegative = text.regionMatches(position, negativePrefix, 0,
191.1419 + negativePrefix.length());
191.1420 +
191.1421 + if (gotPositive && gotNegative) {
191.1422 + if (positivePrefix.length() > negativePrefix.length()) {
191.1423 + gotNegative = false;
191.1424 + } else if (positivePrefix.length() < negativePrefix.length()) {
191.1425 + gotPositive = false;
191.1426 + }
191.1427 + }
191.1428 +
191.1429 + if (gotPositive) {
191.1430 + position += positivePrefix.length();
191.1431 + } else if (gotNegative) {
191.1432 + position += negativePrefix.length();
191.1433 + } else {
191.1434 + parsePosition.errorIndex = position;
191.1435 + return false;
191.1436 + }
191.1437 +
191.1438 + // process digits or Inf, find decimal position
191.1439 + status[STATUS_INFINITE] = false;
191.1440 + if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
191.1441 + symbols.getInfinity().length())) {
191.1442 + position += symbols.getInfinity().length();
191.1443 + status[STATUS_INFINITE] = true;
191.1444 + } else {
191.1445 + // We now have a string of digits, possibly with grouping symbols,
191.1446 + // and decimal points. We want to process these into a DigitList.
191.1447 + // We don't want to put a bunch of leading zeros into the DigitList
191.1448 + // though, so we keep track of the location of the decimal point,
191.1449 + // put only significant digits into the DigitList, and adjust the
191.1450 + // exponent as needed.
191.1451 +
191.1452 + digits.decimalAt = digits.count = 0;
191.1453 + char zero = symbols.getZeroDigit();
191.1454 + char decimal = isCurrencyFormat ?
191.1455 + symbols.getMonetaryDecimalSeparator() :
191.1456 + symbols.getDecimalSeparator();
191.1457 + char grouping = symbols.getGroupingSeparator();
191.1458 + String exponentString = symbols.getExponentSeparator();
191.1459 + boolean sawDecimal = false;
191.1460 + boolean sawExponent = false;
191.1461 + boolean sawDigit = false;
191.1462 + int exponent = 0; // Set to the exponent value, if any
191.1463 +
191.1464 + // We have to track digitCount ourselves, because digits.count will
191.1465 + // pin when the maximum allowable digits is reached.
191.1466 + int digitCount = 0;
191.1467 +
191.1468 + backup = -1;
191.1469 + for (; position < text.length(); ++position) {
191.1470 + char ch = text.charAt(position);
191.1471 +
191.1472 + /* We recognize all digit ranges, not only the Latin digit range
191.1473 + * '0'..'9'. We do so by using the Character.digit() method,
191.1474 + * which converts a valid Unicode digit to the range 0..9.
191.1475 + *
191.1476 + * The character 'ch' may be a digit. If so, place its value
191.1477 + * from 0 to 9 in 'digit'. First try using the locale digit,
191.1478 + * which may or MAY NOT be a standard Unicode digit range. If
191.1479 + * this fails, try using the standard Unicode digit ranges by
191.1480 + * calling Character.digit(). If this also fails, digit will
191.1481 + * have a value outside the range 0..9.
191.1482 + */
191.1483 + int digit = ch - zero;
191.1484 + if (digit < 0 || digit > 9) {
191.1485 + digit = Character.digit(ch, 10);
191.1486 + }
191.1487 +
191.1488 + if (digit == 0) {
191.1489 + // Cancel out backup setting (see grouping handler below)
191.1490 + backup = -1; // Do this BEFORE continue statement below!!!
191.1491 + sawDigit = true;
191.1492 +
191.1493 + // Handle leading zeros
191.1494 + if (digits.count == 0) {
191.1495 + // Ignore leading zeros in integer part of number.
191.1496 + if (!sawDecimal) {
191.1497 + continue;
191.1498 + }
191.1499 +
191.1500 + // If we have seen the decimal, but no significant
191.1501 + // digits yet, then we account for leading zeros by
191.1502 + // decrementing the digits.decimalAt into negative
191.1503 + // values.
191.1504 + --digits.decimalAt;
191.1505 + } else {
191.1506 + ++digitCount;
191.1507 + digits.append((char)(digit + '0'));
191.1508 + }
191.1509 + } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
191.1510 + sawDigit = true;
191.1511 + ++digitCount;
191.1512 + digits.append((char)(digit + '0'));
191.1513 +
191.1514 + // Cancel out backup setting (see grouping handler below)
191.1515 + backup = -1;
191.1516 + } else if (!isExponent && ch == decimal) {
191.1517 + // If we're only parsing integers, or if we ALREADY saw the
191.1518 + // decimal, then don't parse this one.
191.1519 + if (isParseIntegerOnly() || sawDecimal) {
191.1520 + break;
191.1521 + }
191.1522 + digits.decimalAt = digitCount; // Not digits.count!
191.1523 + sawDecimal = true;
191.1524 + } else if (!isExponent && ch == grouping && isGroupingUsed()) {
191.1525 + if (sawDecimal) {
191.1526 + break;
191.1527 + }
191.1528 + // Ignore grouping characters, if we are using them, but
191.1529 + // require that they be followed by a digit. Otherwise
191.1530 + // we backup and reprocess them.
191.1531 + backup = position;
191.1532 + } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
191.1533 + && !sawExponent) {
191.1534 + // Process the exponent by recursively calling this method.
191.1535 + ParsePosition pos = new ParsePosition(position + exponentString.length());
191.1536 + boolean[] stat = new boolean[STATUS_LENGTH];
191.1537 + DigitList exponentDigits = new DigitList();
191.1538 +
191.1539 + if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
191.1540 + exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
191.1541 + position = pos.index; // Advance past the exponent
191.1542 + exponent = (int)exponentDigits.getLong();
191.1543 + if (!stat[STATUS_POSITIVE]) {
191.1544 + exponent = -exponent;
191.1545 + }
191.1546 + sawExponent = true;
191.1547 + }
191.1548 + break; // Whether we fail or succeed, we exit this loop
191.1549 + }
191.1550 + else {
191.1551 + break;
191.1552 + }
191.1553 + }
191.1554 +
191.1555 + if (backup != -1) {
191.1556 + position = backup;
191.1557 + }
191.1558 +
191.1559 + // If there was no decimal point we have an integer
191.1560 + if (!sawDecimal) {
191.1561 + digits.decimalAt = digitCount; // Not digits.count!
191.1562 + }
191.1563 +
191.1564 + // Adjust for exponent, if any
191.1565 + digits.decimalAt += exponent;
191.1566 +
191.1567 + // If none of the text string was recognized. For example, parse
191.1568 + // "x" with pattern "#0.00" (return index and error index both 0)
191.1569 + // parse "$" with pattern "$#0.00". (return index 0 and error
191.1570 + // index 1).
191.1571 + if (!sawDigit && digitCount == 0) {
191.1572 + parsePosition.index = oldStart;
191.1573 + parsePosition.errorIndex = oldStart;
191.1574 + return false;
191.1575 + }
191.1576 + }
191.1577 +
191.1578 + // check for suffix
191.1579 + if (!isExponent) {
191.1580 + if (gotPositive) {
191.1581 + gotPositive = text.regionMatches(position,positiveSuffix,0,
191.1582 + positiveSuffix.length());
191.1583 + }
191.1584 + if (gotNegative) {
191.1585 + gotNegative = text.regionMatches(position,negativeSuffix,0,
191.1586 + negativeSuffix.length());
191.1587 + }
191.1588 +
191.1589 + // if both match, take longest
191.1590 + if (gotPositive && gotNegative) {
191.1591 + if (positiveSuffix.length() > negativeSuffix.length()) {
191.1592 + gotNegative = false;
191.1593 + } else if (positiveSuffix.length() < negativeSuffix.length()) {
191.1594 + gotPositive = false;
191.1595 + }
191.1596 + }
191.1597 +
191.1598 + // fail if neither or both
191.1599 + if (gotPositive == gotNegative) {
191.1600 + parsePosition.errorIndex = position;
191.1601 + return false;
191.1602 + }
191.1603 +
191.1604 + parsePosition.index = position +
191.1605 + (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
191.1606 + } else {
191.1607 + parsePosition.index = position;
191.1608 + }
191.1609 +
191.1610 + status[STATUS_POSITIVE] = gotPositive;
191.1611 + if (parsePosition.index == oldStart) {
191.1612 + parsePosition.errorIndex = position;
191.1613 + return false;
191.1614 + }
191.1615 + return true;
191.1616 + }
191.1617 +
191.1618 + /**
191.1619 + * Returns a copy of the decimal format symbols, which is generally not
191.1620 + * changed by the programmer or user.
191.1621 + * @return a copy of the desired DecimalFormatSymbols
191.1622 + * @see java.text.DecimalFormatSymbols
191.1623 + */
191.1624 + public DecimalFormatSymbols getDecimalFormatSymbols() {
191.1625 + try {
191.1626 + // don't allow multiple references
191.1627 + return (DecimalFormatSymbols) symbols.clone();
191.1628 + } catch (Exception foo) {
191.1629 + return null; // should never happen
191.1630 + }
191.1631 + }
191.1632 +
191.1633 +
191.1634 + /**
191.1635 + * Sets the decimal format symbols, which is generally not changed
191.1636 + * by the programmer or user.
191.1637 + * @param newSymbols desired DecimalFormatSymbols
191.1638 + * @see java.text.DecimalFormatSymbols
191.1639 + */
191.1640 + public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
191.1641 + try {
191.1642 + // don't allow multiple references
191.1643 + symbols = (DecimalFormatSymbols) newSymbols.clone();
191.1644 + expandAffixes();
191.1645 + } catch (Exception foo) {
191.1646 + // should never happen
191.1647 + }
191.1648 + }
191.1649 +
191.1650 + /**
191.1651 + * Get the positive prefix.
191.1652 + * <P>Examples: +123, $123, sFr123
191.1653 + */
191.1654 + public String getPositivePrefix () {
191.1655 + return positivePrefix;
191.1656 + }
191.1657 +
191.1658 + /**
191.1659 + * Set the positive prefix.
191.1660 + * <P>Examples: +123, $123, sFr123
191.1661 + */
191.1662 + public void setPositivePrefix (String newValue) {
191.1663 + positivePrefix = newValue;
191.1664 + posPrefixPattern = null;
191.1665 + positivePrefixFieldPositions = null;
191.1666 + }
191.1667 +
191.1668 + /**
191.1669 + * Returns the FieldPositions of the fields in the prefix used for
191.1670 + * positive numbers. This is not used if the user has explicitly set
191.1671 + * a positive prefix via <code>setPositivePrefix</code>. This is
191.1672 + * lazily created.
191.1673 + *
191.1674 + * @return FieldPositions in positive prefix
191.1675 + */
191.1676 + private FieldPosition[] getPositivePrefixFieldPositions() {
191.1677 + if (positivePrefixFieldPositions == null) {
191.1678 + if (posPrefixPattern != null) {
191.1679 + positivePrefixFieldPositions = expandAffix(posPrefixPattern);
191.1680 + }
191.1681 + else {
191.1682 + positivePrefixFieldPositions = EmptyFieldPositionArray;
191.1683 + }
191.1684 + }
191.1685 + return positivePrefixFieldPositions;
191.1686 + }
191.1687 +
191.1688 + /**
191.1689 + * Get the negative prefix.
191.1690 + * <P>Examples: -123, ($123) (with negative suffix), sFr-123
191.1691 + */
191.1692 + public String getNegativePrefix () {
191.1693 + return negativePrefix;
191.1694 + }
191.1695 +
191.1696 + /**
191.1697 + * Set the negative prefix.
191.1698 + * <P>Examples: -123, ($123) (with negative suffix), sFr-123
191.1699 + */
191.1700 + public void setNegativePrefix (String newValue) {
191.1701 + negativePrefix = newValue;
191.1702 + negPrefixPattern = null;
191.1703 + }
191.1704 +
191.1705 + /**
191.1706 + * Returns the FieldPositions of the fields in the prefix used for
191.1707 + * negative numbers. This is not used if the user has explicitly set
191.1708 + * a negative prefix via <code>setNegativePrefix</code>. This is
191.1709 + * lazily created.
191.1710 + *
191.1711 + * @return FieldPositions in positive prefix
191.1712 + */
191.1713 + private FieldPosition[] getNegativePrefixFieldPositions() {
191.1714 + if (negativePrefixFieldPositions == null) {
191.1715 + if (negPrefixPattern != null) {
191.1716 + negativePrefixFieldPositions = expandAffix(negPrefixPattern);
191.1717 + }
191.1718 + else {
191.1719 + negativePrefixFieldPositions = EmptyFieldPositionArray;
191.1720 + }
191.1721 + }
191.1722 + return negativePrefixFieldPositions;
191.1723 + }
191.1724 +
191.1725 + /**
191.1726 + * Get the positive suffix.
191.1727 + * <P>Example: 123%
191.1728 + */
191.1729 + public String getPositiveSuffix () {
191.1730 + return positiveSuffix;
191.1731 + }
191.1732 +
191.1733 + /**
191.1734 + * Set the positive suffix.
191.1735 + * <P>Example: 123%
191.1736 + */
191.1737 + public void setPositiveSuffix (String newValue) {
191.1738 + positiveSuffix = newValue;
191.1739 + posSuffixPattern = null;
191.1740 + }
191.1741 +
191.1742 + /**
191.1743 + * Returns the FieldPositions of the fields in the suffix used for
191.1744 + * positive numbers. This is not used if the user has explicitly set
191.1745 + * a positive suffix via <code>setPositiveSuffix</code>. This is
191.1746 + * lazily created.
191.1747 + *
191.1748 + * @return FieldPositions in positive prefix
191.1749 + */
191.1750 + private FieldPosition[] getPositiveSuffixFieldPositions() {
191.1751 + if (positiveSuffixFieldPositions == null) {
191.1752 + if (posSuffixPattern != null) {
191.1753 + positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
191.1754 + }
191.1755 + else {
191.1756 + positiveSuffixFieldPositions = EmptyFieldPositionArray;
191.1757 + }
191.1758 + }
191.1759 + return positiveSuffixFieldPositions;
191.1760 + }
191.1761 +
191.1762 + /**
191.1763 + * Get the negative suffix.
191.1764 + * <P>Examples: -123%, ($123) (with positive suffixes)
191.1765 + */
191.1766 + public String getNegativeSuffix () {
191.1767 + return negativeSuffix;
191.1768 + }
191.1769 +
191.1770 + /**
191.1771 + * Set the negative suffix.
191.1772 + * <P>Examples: 123%
191.1773 + */
191.1774 + public void setNegativeSuffix (String newValue) {
191.1775 + negativeSuffix = newValue;
191.1776 + negSuffixPattern = null;
191.1777 + }
191.1778 +
191.1779 + /**
191.1780 + * Returns the FieldPositions of the fields in the suffix used for
191.1781 + * negative numbers. This is not used if the user has explicitly set
191.1782 + * a negative suffix via <code>setNegativeSuffix</code>. This is
191.1783 + * lazily created.
191.1784 + *
191.1785 + * @return FieldPositions in positive prefix
191.1786 + */
191.1787 + private FieldPosition[] getNegativeSuffixFieldPositions() {
191.1788 + if (negativeSuffixFieldPositions == null) {
191.1789 + if (negSuffixPattern != null) {
191.1790 + negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
191.1791 + }
191.1792 + else {
191.1793 + negativeSuffixFieldPositions = EmptyFieldPositionArray;
191.1794 + }
191.1795 + }
191.1796 + return negativeSuffixFieldPositions;
191.1797 + }
191.1798 +
191.1799 + /**
191.1800 + * Gets the multiplier for use in percent, per mille, and similar
191.1801 + * formats.
191.1802 + *
191.1803 + * @see #setMultiplier(int)
191.1804 + */
191.1805 + public int getMultiplier () {
191.1806 + return multiplier;
191.1807 + }
191.1808 +
191.1809 + /**
191.1810 + * Sets the multiplier for use in percent, per mille, and similar
191.1811 + * formats.
191.1812 + * For a percent format, set the multiplier to 100 and the suffixes to
191.1813 + * have '%' (for Arabic, use the Arabic percent sign).
191.1814 + * For a per mille format, set the multiplier to 1000 and the suffixes to
191.1815 + * have '\u2030'.
191.1816 + *
191.1817 + * <P>Example: with multiplier 100, 1.23 is formatted as "123", and
191.1818 + * "123" is parsed into 1.23.
191.1819 + *
191.1820 + * @see #getMultiplier
191.1821 + */
191.1822 + public void setMultiplier (int newValue) {
191.1823 + multiplier = newValue;
191.1824 + bigDecimalMultiplier = null;
191.1825 + bigIntegerMultiplier = null;
191.1826 + }
191.1827 +
191.1828 + /**
191.1829 + * Return the grouping size. Grouping size is the number of digits between
191.1830 + * grouping separators in the integer portion of a number. For example,
191.1831 + * in the number "123,456.78", the grouping size is 3.
191.1832 + * @see #setGroupingSize
191.1833 + * @see java.text.NumberFormat#isGroupingUsed
191.1834 + * @see java.text.DecimalFormatSymbols#getGroupingSeparator
191.1835 + */
191.1836 + public int getGroupingSize () {
191.1837 + return groupingSize;
191.1838 + }
191.1839 +
191.1840 + /**
191.1841 + * Set the grouping size. Grouping size is the number of digits between
191.1842 + * grouping separators in the integer portion of a number. For example,
191.1843 + * in the number "123,456.78", the grouping size is 3.
191.1844 + * <br>
191.1845 + * The value passed in is converted to a byte, which may lose information.
191.1846 + * @see #getGroupingSize
191.1847 + * @see java.text.NumberFormat#setGroupingUsed
191.1848 + * @see java.text.DecimalFormatSymbols#setGroupingSeparator
191.1849 + */
191.1850 + public void setGroupingSize (int newValue) {
191.1851 + groupingSize = (byte)newValue;
191.1852 + }
191.1853 +
191.1854 + /**
191.1855 + * Allows you to get the behavior of the decimal separator with integers.
191.1856 + * (The decimal separator will always appear with decimals.)
191.1857 + * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
191.1858 + */
191.1859 + public boolean isDecimalSeparatorAlwaysShown() {
191.1860 + return decimalSeparatorAlwaysShown;
191.1861 + }
191.1862 +
191.1863 + /**
191.1864 + * Allows you to set the behavior of the decimal separator with integers.
191.1865 + * (The decimal separator will always appear with decimals.)
191.1866 + * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
191.1867 + */
191.1868 + public void setDecimalSeparatorAlwaysShown(boolean newValue) {
191.1869 + decimalSeparatorAlwaysShown = newValue;
191.1870 + }
191.1871 +
191.1872 + /**
191.1873 + * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
191.1874 + * method returns <code>BigDecimal</code>. The default value is false.
191.1875 + * @see #setParseBigDecimal
191.1876 + * @since 1.5
191.1877 + */
191.1878 + public boolean isParseBigDecimal() {
191.1879 + return parseBigDecimal;
191.1880 + }
191.1881 +
191.1882 + /**
191.1883 + * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
191.1884 + * method returns <code>BigDecimal</code>.
191.1885 + * @see #isParseBigDecimal
191.1886 + * @since 1.5
191.1887 + */
191.1888 + public void setParseBigDecimal(boolean newValue) {
191.1889 + parseBigDecimal = newValue;
191.1890 + }
191.1891 +
191.1892 + /**
191.1893 + * Standard override; no change in semantics.
191.1894 + */
191.1895 + public Object clone() {
191.1896 + try {
191.1897 + DecimalFormat other = (DecimalFormat) super.clone();
191.1898 + other.symbols = (DecimalFormatSymbols) symbols.clone();
191.1899 + other.digitList = (DigitList) digitList.clone();
191.1900 + return other;
191.1901 + } catch (Exception e) {
191.1902 + throw new InternalError();
191.1903 + }
191.1904 + }
191.1905 +
191.1906 + /**
191.1907 + * Overrides equals
191.1908 + */
191.1909 + public boolean equals(Object obj)
191.1910 + {
191.1911 + if (obj == null) return false;
191.1912 + if (!super.equals(obj)) return false; // super does class check
191.1913 + DecimalFormat other = (DecimalFormat) obj;
191.1914 + return ((posPrefixPattern == other.posPrefixPattern &&
191.1915 + positivePrefix.equals(other.positivePrefix))
191.1916 + || (posPrefixPattern != null &&
191.1917 + posPrefixPattern.equals(other.posPrefixPattern)))
191.1918 + && ((posSuffixPattern == other.posSuffixPattern &&
191.1919 + positiveSuffix.equals(other.positiveSuffix))
191.1920 + || (posSuffixPattern != null &&
191.1921 + posSuffixPattern.equals(other.posSuffixPattern)))
191.1922 + && ((negPrefixPattern == other.negPrefixPattern &&
191.1923 + negativePrefix.equals(other.negativePrefix))
191.1924 + || (negPrefixPattern != null &&
191.1925 + negPrefixPattern.equals(other.negPrefixPattern)))
191.1926 + && ((negSuffixPattern == other.negSuffixPattern &&
191.1927 + negativeSuffix.equals(other.negativeSuffix))
191.1928 + || (negSuffixPattern != null &&
191.1929 + negSuffixPattern.equals(other.negSuffixPattern)))
191.1930 + && multiplier == other.multiplier
191.1931 + && groupingSize == other.groupingSize
191.1932 + && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
191.1933 + && parseBigDecimal == other.parseBigDecimal
191.1934 + && useExponentialNotation == other.useExponentialNotation
191.1935 + && (!useExponentialNotation ||
191.1936 + minExponentDigits == other.minExponentDigits)
191.1937 + && maximumIntegerDigits == other.maximumIntegerDigits
191.1938 + && minimumIntegerDigits == other.minimumIntegerDigits
191.1939 + && maximumFractionDigits == other.maximumFractionDigits
191.1940 + && minimumFractionDigits == other.minimumFractionDigits
191.1941 + && roundingMode == other.roundingMode
191.1942 + && symbols.equals(other.symbols);
191.1943 + }
191.1944 +
191.1945 + /**
191.1946 + * Overrides hashCode
191.1947 + */
191.1948 + public int hashCode() {
191.1949 + return super.hashCode() * 37 + positivePrefix.hashCode();
191.1950 + // just enough fields for a reasonable distribution
191.1951 + }
191.1952 +
191.1953 + /**
191.1954 + * Synthesizes a pattern string that represents the current state
191.1955 + * of this Format object.
191.1956 + * @see #applyPattern
191.1957 + */
191.1958 + public String toPattern() {
191.1959 + return toPattern( false );
191.1960 + }
191.1961 +
191.1962 + /**
191.1963 + * Synthesizes a localized pattern string that represents the current
191.1964 + * state of this Format object.
191.1965 + * @see #applyPattern
191.1966 + */
191.1967 + public String toLocalizedPattern() {
191.1968 + return toPattern( true );
191.1969 + }
191.1970 +
191.1971 + /**
191.1972 + * Expand the affix pattern strings into the expanded affix strings. If any
191.1973 + * affix pattern string is null, do not expand it. This method should be
191.1974 + * called any time the symbols or the affix patterns change in order to keep
191.1975 + * the expanded affix strings up to date.
191.1976 + */
191.1977 + private void expandAffixes() {
191.1978 + // Reuse one StringBuffer for better performance
191.1979 + StringBuffer buffer = new StringBuffer();
191.1980 + if (posPrefixPattern != null) {
191.1981 + positivePrefix = expandAffix(posPrefixPattern, buffer);
191.1982 + positivePrefixFieldPositions = null;
191.1983 + }
191.1984 + if (posSuffixPattern != null) {
191.1985 + positiveSuffix = expandAffix(posSuffixPattern, buffer);
191.1986 + positiveSuffixFieldPositions = null;
191.1987 + }
191.1988 + if (negPrefixPattern != null) {
191.1989 + negativePrefix = expandAffix(negPrefixPattern, buffer);
191.1990 + negativePrefixFieldPositions = null;
191.1991 + }
191.1992 + if (negSuffixPattern != null) {
191.1993 + negativeSuffix = expandAffix(negSuffixPattern, buffer);
191.1994 + negativeSuffixFieldPositions = null;
191.1995 + }
191.1996 + }
191.1997 +
191.1998 + /**
191.1999 + * Expand an affix pattern into an affix string. All characters in the
191.2000 + * pattern are literal unless prefixed by QUOTE. The following characters
191.2001 + * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
191.2002 + * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
191.2003 + * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
191.2004 + * currency code. Any other character after a QUOTE represents itself.
191.2005 + * QUOTE must be followed by another character; QUOTE may not occur by
191.2006 + * itself at the end of the pattern.
191.2007 + *
191.2008 + * @param pattern the non-null, possibly empty pattern
191.2009 + * @param buffer a scratch StringBuffer; its contents will be lost
191.2010 + * @return the expanded equivalent of pattern
191.2011 + */
191.2012 + private String expandAffix(String pattern, StringBuffer buffer) {
191.2013 + buffer.setLength(0);
191.2014 + for (int i=0; i<pattern.length(); ) {
191.2015 + char c = pattern.charAt(i++);
191.2016 + if (c == QUOTE) {
191.2017 + c = pattern.charAt(i++);
191.2018 + switch (c) {
191.2019 + case CURRENCY_SIGN:
191.2020 + if (i<pattern.length() &&
191.2021 + pattern.charAt(i) == CURRENCY_SIGN) {
191.2022 + ++i;
191.2023 + buffer.append(symbols.getInternationalCurrencySymbol());
191.2024 + } else {
191.2025 + buffer.append(symbols.getCurrencySymbol());
191.2026 + }
191.2027 + continue;
191.2028 + case PATTERN_PERCENT:
191.2029 + c = symbols.getPercent();
191.2030 + break;
191.2031 + case PATTERN_PER_MILLE:
191.2032 + c = symbols.getPerMill();
191.2033 + break;
191.2034 + case PATTERN_MINUS:
191.2035 + c = symbols.getMinusSign();
191.2036 + break;
191.2037 + }
191.2038 + }
191.2039 + buffer.append(c);
191.2040 + }
191.2041 + return buffer.toString();
191.2042 + }
191.2043 +
191.2044 + /**
191.2045 + * Expand an affix pattern into an array of FieldPositions describing
191.2046 + * how the pattern would be expanded.
191.2047 + * All characters in the
191.2048 + * pattern are literal unless prefixed by QUOTE. The following characters
191.2049 + * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
191.2050 + * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
191.2051 + * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
191.2052 + * currency code. Any other character after a QUOTE represents itself.
191.2053 + * QUOTE must be followed by another character; QUOTE may not occur by
191.2054 + * itself at the end of the pattern.
191.2055 + *
191.2056 + * @param pattern the non-null, possibly empty pattern
191.2057 + * @return FieldPosition array of the resulting fields.
191.2058 + */
191.2059 + private FieldPosition[] expandAffix(String pattern) {
191.2060 + ArrayList positions = null;
191.2061 + int stringIndex = 0;
191.2062 + for (int i=0; i<pattern.length(); ) {
191.2063 + char c = pattern.charAt(i++);
191.2064 + if (c == QUOTE) {
191.2065 + int field = -1;
191.2066 + Format.Field fieldID = null;
191.2067 + c = pattern.charAt(i++);
191.2068 + switch (c) {
191.2069 + case CURRENCY_SIGN:
191.2070 + String string;
191.2071 + if (i<pattern.length() &&
191.2072 + pattern.charAt(i) == CURRENCY_SIGN) {
191.2073 + ++i;
191.2074 + string = symbols.getInternationalCurrencySymbol();
191.2075 + } else {
191.2076 + string = symbols.getCurrencySymbol();
191.2077 + }
191.2078 + if (string.length() > 0) {
191.2079 + if (positions == null) {
191.2080 + positions = new ArrayList(2);
191.2081 + }
191.2082 + FieldPosition fp = new FieldPosition(Field.CURRENCY);
191.2083 + fp.setBeginIndex(stringIndex);
191.2084 + fp.setEndIndex(stringIndex + string.length());
191.2085 + positions.add(fp);
191.2086 + stringIndex += string.length();
191.2087 + }
191.2088 + continue;
191.2089 + case PATTERN_PERCENT:
191.2090 + c = symbols.getPercent();
191.2091 + field = -1;
191.2092 + fieldID = Field.PERCENT;
191.2093 + break;
191.2094 + case PATTERN_PER_MILLE:
191.2095 + c = symbols.getPerMill();
191.2096 + field = -1;
191.2097 + fieldID = Field.PERMILLE;
191.2098 + break;
191.2099 + case PATTERN_MINUS:
191.2100 + c = symbols.getMinusSign();
191.2101 + field = -1;
191.2102 + fieldID = Field.SIGN;
191.2103 + break;
191.2104 + }
191.2105 + if (fieldID != null) {
191.2106 + if (positions == null) {
191.2107 + positions = new ArrayList(2);
191.2108 + }
191.2109 + FieldPosition fp = new FieldPosition(fieldID, field);
191.2110 + fp.setBeginIndex(stringIndex);
191.2111 + fp.setEndIndex(stringIndex + 1);
191.2112 + positions.add(fp);
191.2113 + }
191.2114 + }
191.2115 + stringIndex++;
191.2116 + }
191.2117 + if (positions != null) {
191.2118 + return (FieldPosition[])positions.toArray(EmptyFieldPositionArray);
191.2119 + }
191.2120 + return EmptyFieldPositionArray;
191.2121 + }
191.2122 +
191.2123 + /**
191.2124 + * Appends an affix pattern to the given StringBuffer, quoting special
191.2125 + * characters as needed. Uses the internal affix pattern, if that exists,
191.2126 + * or the literal affix, if the internal affix pattern is null. The
191.2127 + * appended string will generate the same affix pattern (or literal affix)
191.2128 + * when passed to toPattern().
191.2129 + *
191.2130 + * @param buffer the affix string is appended to this
191.2131 + * @param affixPattern a pattern such as posPrefixPattern; may be null
191.2132 + * @param expAffix a corresponding expanded affix, such as positivePrefix.
191.2133 + * Ignored unless affixPattern is null. If affixPattern is null, then
191.2134 + * expAffix is appended as a literal affix.
191.2135 + * @param localized true if the appended pattern should contain localized
191.2136 + * pattern characters; otherwise, non-localized pattern chars are appended
191.2137 + */
191.2138 + private void appendAffix(StringBuffer buffer, String affixPattern,
191.2139 + String expAffix, boolean localized) {
191.2140 + if (affixPattern == null) {
191.2141 + appendAffix(buffer, expAffix, localized);
191.2142 + } else {
191.2143 + int i;
191.2144 + for (int pos=0; pos<affixPattern.length(); pos=i) {
191.2145 + i = affixPattern.indexOf(QUOTE, pos);
191.2146 + if (i < 0) {
191.2147 + appendAffix(buffer, affixPattern.substring(pos), localized);
191.2148 + break;
191.2149 + }
191.2150 + if (i > pos) {
191.2151 + appendAffix(buffer, affixPattern.substring(pos, i), localized);
191.2152 + }
191.2153 + char c = affixPattern.charAt(++i);
191.2154 + ++i;
191.2155 + if (c == QUOTE) {
191.2156 + buffer.append(c);
191.2157 + // Fall through and append another QUOTE below
191.2158 + } else if (c == CURRENCY_SIGN &&
191.2159 + i<affixPattern.length() &&
191.2160 + affixPattern.charAt(i) == CURRENCY_SIGN) {
191.2161 + ++i;
191.2162 + buffer.append(c);
191.2163 + // Fall through and append another CURRENCY_SIGN below
191.2164 + } else if (localized) {
191.2165 + switch (c) {
191.2166 + case PATTERN_PERCENT:
191.2167 + c = symbols.getPercent();
191.2168 + break;
191.2169 + case PATTERN_PER_MILLE:
191.2170 + c = symbols.getPerMill();
191.2171 + break;
191.2172 + case PATTERN_MINUS:
191.2173 + c = symbols.getMinusSign();
191.2174 + break;
191.2175 + }
191.2176 + }
191.2177 + buffer.append(c);
191.2178 + }
191.2179 + }
191.2180 + }
191.2181 +
191.2182 + /**
191.2183 + * Append an affix to the given StringBuffer, using quotes if
191.2184 + * there are special characters. Single quotes themselves must be
191.2185 + * escaped in either case.
191.2186 + */
191.2187 + private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
191.2188 + boolean needQuote;
191.2189 + if (localized) {
191.2190 + needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
191.2191 + || affix.indexOf(symbols.getGroupingSeparator()) >= 0
191.2192 + || affix.indexOf(symbols.getDecimalSeparator()) >= 0
191.2193 + || affix.indexOf(symbols.getPercent()) >= 0
191.2194 + || affix.indexOf(symbols.getPerMill()) >= 0
191.2195 + || affix.indexOf(symbols.getDigit()) >= 0
191.2196 + || affix.indexOf(symbols.getPatternSeparator()) >= 0
191.2197 + || affix.indexOf(symbols.getMinusSign()) >= 0
191.2198 + || affix.indexOf(CURRENCY_SIGN) >= 0;
191.2199 + }
191.2200 + else {
191.2201 + needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
191.2202 + || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
191.2203 + || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
191.2204 + || affix.indexOf(PATTERN_PERCENT) >= 0
191.2205 + || affix.indexOf(PATTERN_PER_MILLE) >= 0
191.2206 + || affix.indexOf(PATTERN_DIGIT) >= 0
191.2207 + || affix.indexOf(PATTERN_SEPARATOR) >= 0
191.2208 + || affix.indexOf(PATTERN_MINUS) >= 0
191.2209 + || affix.indexOf(CURRENCY_SIGN) >= 0;
191.2210 + }
191.2211 + if (needQuote) buffer.append('\'');
191.2212 + if (affix.indexOf('\'') < 0) buffer.append(affix);
191.2213 + else {
191.2214 + for (int j=0; j<affix.length(); ++j) {
191.2215 + char c = affix.charAt(j);
191.2216 + buffer.append(c);
191.2217 + if (c == '\'') buffer.append(c);
191.2218 + }
191.2219 + }
191.2220 + if (needQuote) buffer.append('\'');
191.2221 + }
191.2222 +
191.2223 + /**
191.2224 + * Does the real work of generating a pattern. */
191.2225 + private String toPattern(boolean localized) {
191.2226 + StringBuffer result = new StringBuffer();
191.2227 + for (int j = 1; j >= 0; --j) {
191.2228 + if (j == 1)
191.2229 + appendAffix(result, posPrefixPattern, positivePrefix, localized);
191.2230 + else appendAffix(result, negPrefixPattern, negativePrefix, localized);
191.2231 + int i;
191.2232 + int digitCount = useExponentialNotation
191.2233 + ? getMaximumIntegerDigits()
191.2234 + : Math.max(groupingSize, getMinimumIntegerDigits())+1;
191.2235 + for (i = digitCount; i > 0; --i) {
191.2236 + if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
191.2237 + i % groupingSize == 0) {
191.2238 + result.append(localized ? symbols.getGroupingSeparator() :
191.2239 + PATTERN_GROUPING_SEPARATOR);
191.2240 + }
191.2241 + result.append(i <= getMinimumIntegerDigits()
191.2242 + ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
191.2243 + : (localized ? symbols.getDigit() : PATTERN_DIGIT));
191.2244 + }
191.2245 + if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
191.2246 + result.append(localized ? symbols.getDecimalSeparator() :
191.2247 + PATTERN_DECIMAL_SEPARATOR);
191.2248 + for (i = 0; i < getMaximumFractionDigits(); ++i) {
191.2249 + if (i < getMinimumFractionDigits()) {
191.2250 + result.append(localized ? symbols.getZeroDigit() :
191.2251 + PATTERN_ZERO_DIGIT);
191.2252 + } else {
191.2253 + result.append(localized ? symbols.getDigit() :
191.2254 + PATTERN_DIGIT);
191.2255 + }
191.2256 + }
191.2257 + if (useExponentialNotation)
191.2258 + {
191.2259 + result.append(localized ? symbols.getExponentSeparator() :
191.2260 + PATTERN_EXPONENT);
191.2261 + for (i=0; i<minExponentDigits; ++i)
191.2262 + result.append(localized ? symbols.getZeroDigit() :
191.2263 + PATTERN_ZERO_DIGIT);
191.2264 + }
191.2265 + if (j == 1) {
191.2266 + appendAffix(result, posSuffixPattern, positiveSuffix, localized);
191.2267 + if ((negSuffixPattern == posSuffixPattern && // n == p == null
191.2268 + negativeSuffix.equals(positiveSuffix))
191.2269 + || (negSuffixPattern != null &&
191.2270 + negSuffixPattern.equals(posSuffixPattern))) {
191.2271 + if ((negPrefixPattern != null && posPrefixPattern != null &&
191.2272 + negPrefixPattern.equals("'-" + posPrefixPattern)) ||
191.2273 + (negPrefixPattern == posPrefixPattern && // n == p == null
191.2274 + negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
191.2275 + break;
191.2276 + }
191.2277 + result.append(localized ? symbols.getPatternSeparator() :
191.2278 + PATTERN_SEPARATOR);
191.2279 + } else appendAffix(result, negSuffixPattern, negativeSuffix, localized);
191.2280 + }
191.2281 + return result.toString();
191.2282 + }
191.2283 +
191.2284 + /**
191.2285 + * Apply the given pattern to this Format object. A pattern is a
191.2286 + * short-hand specification for the various formatting properties.
191.2287 + * These properties can also be changed individually through the
191.2288 + * various setter methods.
191.2289 + * <p>
191.2290 + * There is no limit to integer digits set
191.2291 + * by this routine, since that is the typical end-user desire;
191.2292 + * use setMaximumInteger if you want to set a real value.
191.2293 + * For negative numbers, use a second pattern, separated by a semicolon
191.2294 + * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
191.2295 + * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
191.2296 + * a maximum of 2 fraction digits.
191.2297 + * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
191.2298 + * parentheses.
191.2299 + * <p>In negative patterns, the minimum and maximum counts are ignored;
191.2300 + * these are presumed to be set in the positive pattern.
191.2301 + *
191.2302 + * @exception NullPointerException if <code>pattern</code> is null
191.2303 + * @exception IllegalArgumentException if the given pattern is invalid.
191.2304 + */
191.2305 + public void applyPattern(String pattern) {
191.2306 + applyPattern(pattern, false);
191.2307 + }
191.2308 +
191.2309 + /**
191.2310 + * Apply the given pattern to this Format object. The pattern
191.2311 + * is assumed to be in a localized notation. A pattern is a
191.2312 + * short-hand specification for the various formatting properties.
191.2313 + * These properties can also be changed individually through the
191.2314 + * various setter methods.
191.2315 + * <p>
191.2316 + * There is no limit to integer digits set
191.2317 + * by this routine, since that is the typical end-user desire;
191.2318 + * use setMaximumInteger if you want to set a real value.
191.2319 + * For negative numbers, use a second pattern, separated by a semicolon
191.2320 + * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
191.2321 + * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
191.2322 + * a maximum of 2 fraction digits.
191.2323 + * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
191.2324 + * parentheses.
191.2325 + * <p>In negative patterns, the minimum and maximum counts are ignored;
191.2326 + * these are presumed to be set in the positive pattern.
191.2327 + *
191.2328 + * @exception NullPointerException if <code>pattern</code> is null
191.2329 + * @exception IllegalArgumentException if the given pattern is invalid.
191.2330 + */
191.2331 + public void applyLocalizedPattern(String pattern) {
191.2332 + applyPattern(pattern, true);
191.2333 + }
191.2334 +
191.2335 + /**
191.2336 + * Does the real work of applying a pattern.
191.2337 + */
191.2338 + private void applyPattern(String pattern, boolean localized) {
191.2339 + char zeroDigit = PATTERN_ZERO_DIGIT;
191.2340 + char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
191.2341 + char decimalSeparator = PATTERN_DECIMAL_SEPARATOR;
191.2342 + char percent = PATTERN_PERCENT;
191.2343 + char perMill = PATTERN_PER_MILLE;
191.2344 + char digit = PATTERN_DIGIT;
191.2345 + char separator = PATTERN_SEPARATOR;
191.2346 + String exponent = PATTERN_EXPONENT;
191.2347 + char minus = PATTERN_MINUS;
191.2348 + if (localized) {
191.2349 + zeroDigit = symbols.getZeroDigit();
191.2350 + groupingSeparator = symbols.getGroupingSeparator();
191.2351 + decimalSeparator = symbols.getDecimalSeparator();
191.2352 + percent = symbols.getPercent();
191.2353 + perMill = symbols.getPerMill();
191.2354 + digit = symbols.getDigit();
191.2355 + separator = symbols.getPatternSeparator();
191.2356 + exponent = symbols.getExponentSeparator();
191.2357 + minus = symbols.getMinusSign();
191.2358 + }
191.2359 + boolean gotNegative = false;
191.2360 + decimalSeparatorAlwaysShown = false;
191.2361 + isCurrencyFormat = false;
191.2362 + useExponentialNotation = false;
191.2363 +
191.2364 + // Two variables are used to record the subrange of the pattern
191.2365 + // occupied by phase 1. This is used during the processing of the
191.2366 + // second pattern (the one representing negative numbers) to ensure
191.2367 + // that no deviation exists in phase 1 between the two patterns.
191.2368 + int phaseOneStart = 0;
191.2369 + int phaseOneLength = 0;
191.2370 +
191.2371 + int start = 0;
191.2372 + for (int j = 1; j >= 0 && start < pattern.length(); --j) {
191.2373 + boolean inQuote = false;
191.2374 + StringBuffer prefix = new StringBuffer();
191.2375 + StringBuffer suffix = new StringBuffer();
191.2376 + int decimalPos = -1;
191.2377 + int multiplier = 1;
191.2378 + int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
191.2379 + byte groupingCount = -1;
191.2380 +
191.2381 + // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is
191.2382 + // the section of the pattern with digits, decimal separator,
191.2383 + // grouping characters. Phase 2 is the suffix. In phases 0 and 2,
191.2384 + // percent, per mille, and currency symbols are recognized and
191.2385 + // translated. The separation of the characters into phases is
191.2386 + // strictly enforced; if phase 1 characters are to appear in the
191.2387 + // suffix, for example, they must be quoted.
191.2388 + int phase = 0;
191.2389 +
191.2390 + // The affix is either the prefix or the suffix.
191.2391 + StringBuffer affix = prefix;
191.2392 +
191.2393 + for (int pos = start; pos < pattern.length(); ++pos) {
191.2394 + char ch = pattern.charAt(pos);
191.2395 + switch (phase) {
191.2396 + case 0:
191.2397 + case 2:
191.2398 + // Process the prefix / suffix characters
191.2399 + if (inQuote) {
191.2400 + // A quote within quotes indicates either the closing
191.2401 + // quote or two quotes, which is a quote literal. That
191.2402 + // is, we have the second quote in 'do' or 'don''t'.
191.2403 + if (ch == QUOTE) {
191.2404 + if ((pos+1) < pattern.length() &&
191.2405 + pattern.charAt(pos+1) == QUOTE) {
191.2406 + ++pos;
191.2407 + affix.append("''"); // 'don''t'
191.2408 + } else {
191.2409 + inQuote = false; // 'do'
191.2410 + }
191.2411 + continue;
191.2412 + }
191.2413 + } else {
191.2414 + // Process unquoted characters seen in prefix or suffix
191.2415 + // phase.
191.2416 + if (ch == digit ||
191.2417 + ch == zeroDigit ||
191.2418 + ch == groupingSeparator ||
191.2419 + ch == decimalSeparator) {
191.2420 + phase = 1;
191.2421 + if (j == 1) {
191.2422 + phaseOneStart = pos;
191.2423 + }
191.2424 + --pos; // Reprocess this character
191.2425 + continue;
191.2426 + } else if (ch == CURRENCY_SIGN) {
191.2427 + // Use lookahead to determine if the currency sign
191.2428 + // is doubled or not.
191.2429 + boolean doubled = (pos + 1) < pattern.length() &&
191.2430 + pattern.charAt(pos + 1) == CURRENCY_SIGN;
191.2431 + if (doubled) { // Skip over the doubled character
191.2432 + ++pos;
191.2433 + }
191.2434 + isCurrencyFormat = true;
191.2435 + affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4");
191.2436 + continue;
191.2437 + } else if (ch == QUOTE) {
191.2438 + // A quote outside quotes indicates either the
191.2439 + // opening quote or two quotes, which is a quote
191.2440 + // literal. That is, we have the first quote in 'do'
191.2441 + // or o''clock.
191.2442 + if (ch == QUOTE) {
191.2443 + if ((pos+1) < pattern.length() &&
191.2444 + pattern.charAt(pos+1) == QUOTE) {
191.2445 + ++pos;
191.2446 + affix.append("''"); // o''clock
191.2447 + } else {
191.2448 + inQuote = true; // 'do'
191.2449 + }
191.2450 + continue;
191.2451 + }
191.2452 + } else if (ch == separator) {
191.2453 + // Don't allow separators before we see digit
191.2454 + // characters of phase 1, and don't allow separators
191.2455 + // in the second pattern (j == 0).
191.2456 + if (phase == 0 || j == 0) {
191.2457 + throw new IllegalArgumentException("Unquoted special character '" +
191.2458 + ch + "' in pattern \"" + pattern + '"');
191.2459 + }
191.2460 + start = pos + 1;
191.2461 + pos = pattern.length();
191.2462 + continue;
191.2463 + }
191.2464 +
191.2465 + // Next handle characters which are appended directly.
191.2466 + else if (ch == percent) {
191.2467 + if (multiplier != 1) {
191.2468 + throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
191.2469 + pattern + '"');
191.2470 + }
191.2471 + multiplier = 100;
191.2472 + affix.append("'%");
191.2473 + continue;
191.2474 + } else if (ch == perMill) {
191.2475 + if (multiplier != 1) {
191.2476 + throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
191.2477 + pattern + '"');
191.2478 + }
191.2479 + multiplier = 1000;
191.2480 + affix.append("'\u2030");
191.2481 + continue;
191.2482 + } else if (ch == minus) {
191.2483 + affix.append("'-");
191.2484 + continue;
191.2485 + }
191.2486 + }
191.2487 + // Note that if we are within quotes, or if this is an
191.2488 + // unquoted, non-special character, then we usually fall
191.2489 + // through to here.
191.2490 + affix.append(ch);
191.2491 + break;
191.2492 +
191.2493 + case 1:
191.2494 + // Phase one must be identical in the two sub-patterns. We
191.2495 + // enforce this by doing a direct comparison. While
191.2496 + // processing the first sub-pattern, we just record its
191.2497 + // length. While processing the second, we compare
191.2498 + // characters.
191.2499 + if (j == 1) {
191.2500 + ++phaseOneLength;
191.2501 + } else {
191.2502 + if (--phaseOneLength == 0) {
191.2503 + phase = 2;
191.2504 + affix = suffix;
191.2505 + }
191.2506 + continue;
191.2507 + }
191.2508 +
191.2509 + // Process the digits, decimal, and grouping characters. We
191.2510 + // record five pieces of information. We expect the digits
191.2511 + // to occur in the pattern ####0000.####, and we record the
191.2512 + // number of left digits, zero (central) digits, and right
191.2513 + // digits. The position of the last grouping character is
191.2514 + // recorded (should be somewhere within the first two blocks
191.2515 + // of characters), as is the position of the decimal point,
191.2516 + // if any (should be in the zero digits). If there is no
191.2517 + // decimal point, then there should be no right digits.
191.2518 + if (ch == digit) {
191.2519 + if (zeroDigitCount > 0) {
191.2520 + ++digitRightCount;
191.2521 + } else {
191.2522 + ++digitLeftCount;
191.2523 + }
191.2524 + if (groupingCount >= 0 && decimalPos < 0) {
191.2525 + ++groupingCount;
191.2526 + }
191.2527 + } else if (ch == zeroDigit) {
191.2528 + if (digitRightCount > 0) {
191.2529 + throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
191.2530 + pattern + '"');
191.2531 + }
191.2532 + ++zeroDigitCount;
191.2533 + if (groupingCount >= 0 && decimalPos < 0) {
191.2534 + ++groupingCount;
191.2535 + }
191.2536 + } else if (ch == groupingSeparator) {
191.2537 + groupingCount = 0;
191.2538 + } else if (ch == decimalSeparator) {
191.2539 + if (decimalPos >= 0) {
191.2540 + throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
191.2541 + pattern + '"');
191.2542 + }
191.2543 + decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
191.2544 + } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){
191.2545 + if (useExponentialNotation) {
191.2546 + throw new IllegalArgumentException("Multiple exponential " +
191.2547 + "symbols in pattern \"" + pattern + '"');
191.2548 + }
191.2549 + useExponentialNotation = true;
191.2550 + minExponentDigits = 0;
191.2551 +
191.2552 + // Use lookahead to parse out the exponential part
191.2553 + // of the pattern, then jump into phase 2.
191.2554 + pos = pos+exponent.length();
191.2555 + while (pos < pattern.length() &&
191.2556 + pattern.charAt(pos) == zeroDigit) {
191.2557 + ++minExponentDigits;
191.2558 + ++phaseOneLength;
191.2559 + ++pos;
191.2560 + }
191.2561 +
191.2562 + if ((digitLeftCount + zeroDigitCount) < 1 ||
191.2563 + minExponentDigits < 1) {
191.2564 + throw new IllegalArgumentException("Malformed exponential " +
191.2565 + "pattern \"" + pattern + '"');
191.2566 + }
191.2567 +
191.2568 + // Transition to phase 2
191.2569 + phase = 2;
191.2570 + affix = suffix;
191.2571 + --pos;
191.2572 + continue;
191.2573 + } else {
191.2574 + phase = 2;
191.2575 + affix = suffix;
191.2576 + --pos;
191.2577 + --phaseOneLength;
191.2578 + continue;
191.2579 + }
191.2580 + break;
191.2581 + }
191.2582 + }
191.2583 +
191.2584 + // Handle patterns with no '0' pattern character. These patterns
191.2585 + // are legal, but must be interpreted. "##.###" -> "#0.###".
191.2586 + // ".###" -> ".0##".
191.2587 + /* We allow patterns of the form "####" to produce a zeroDigitCount
191.2588 + * of zero (got that?); although this seems like it might make it
191.2589 + * possible for format() to produce empty strings, format() checks
191.2590 + * for this condition and outputs a zero digit in this situation.
191.2591 + * Having a zeroDigitCount of zero yields a minimum integer digits
191.2592 + * of zero, which allows proper round-trip patterns. That is, we
191.2593 + * don't want "#" to become "#0" when toPattern() is called (even
191.2594 + * though that's what it really is, semantically).
191.2595 + */
191.2596 + if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
191.2597 + // Handle "###.###" and "###." and ".###"
191.2598 + int n = decimalPos;
191.2599 + if (n == 0) { // Handle ".###"
191.2600 + ++n;
191.2601 + }
191.2602 + digitRightCount = digitLeftCount - n;
191.2603 + digitLeftCount = n - 1;
191.2604 + zeroDigitCount = 1;
191.2605 + }
191.2606 +
191.2607 + // Do syntax checking on the digits.
191.2608 + if ((decimalPos < 0 && digitRightCount > 0) ||
191.2609 + (decimalPos >= 0 && (decimalPos < digitLeftCount ||
191.2610 + decimalPos > (digitLeftCount + zeroDigitCount))) ||
191.2611 + groupingCount == 0 || inQuote) {
191.2612 + throw new IllegalArgumentException("Malformed pattern \"" +
191.2613 + pattern + '"');
191.2614 + }
191.2615 +
191.2616 + if (j == 1) {
191.2617 + posPrefixPattern = prefix.toString();
191.2618 + posSuffixPattern = suffix.toString();
191.2619 + negPrefixPattern = posPrefixPattern; // assume these for now
191.2620 + negSuffixPattern = posSuffixPattern;
191.2621 + int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
191.2622 + /* The effectiveDecimalPos is the position the decimal is at or
191.2623 + * would be at if there is no decimal. Note that if decimalPos<0,
191.2624 + * then digitTotalCount == digitLeftCount + zeroDigitCount.
191.2625 + */
191.2626 + int effectiveDecimalPos = decimalPos >= 0 ?
191.2627 + decimalPos : digitTotalCount;
191.2628 + setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
191.2629 + setMaximumIntegerDigits(useExponentialNotation ?
191.2630 + digitLeftCount + getMinimumIntegerDigits() :
191.2631 + MAXIMUM_INTEGER_DIGITS);
191.2632 + setMaximumFractionDigits(decimalPos >= 0 ?
191.2633 + (digitTotalCount - decimalPos) : 0);
191.2634 + setMinimumFractionDigits(decimalPos >= 0 ?
191.2635 + (digitLeftCount + zeroDigitCount - decimalPos) : 0);
191.2636 + setGroupingUsed(groupingCount > 0);
191.2637 + this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
191.2638 + this.multiplier = multiplier;
191.2639 + setDecimalSeparatorAlwaysShown(decimalPos == 0 ||
191.2640 + decimalPos == digitTotalCount);
191.2641 + } else {
191.2642 + negPrefixPattern = prefix.toString();
191.2643 + negSuffixPattern = suffix.toString();
191.2644 + gotNegative = true;
191.2645 + }
191.2646 + }
191.2647 +
191.2648 + if (pattern.length() == 0) {
191.2649 + posPrefixPattern = posSuffixPattern = "";
191.2650 + setMinimumIntegerDigits(0);
191.2651 + setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
191.2652 + setMinimumFractionDigits(0);
191.2653 + setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
191.2654 + }
191.2655 +
191.2656 + // If there was no negative pattern, or if the negative pattern is
191.2657 + // identical to the positive pattern, then prepend the minus sign to
191.2658 + // the positive pattern to form the negative pattern.
191.2659 + if (!gotNegative ||
191.2660 + (negPrefixPattern.equals(posPrefixPattern)
191.2661 + && negSuffixPattern.equals(posSuffixPattern))) {
191.2662 + negSuffixPattern = posSuffixPattern;
191.2663 + negPrefixPattern = "'-" + posPrefixPattern;
191.2664 + }
191.2665 +
191.2666 + expandAffixes();
191.2667 + }
191.2668 +
191.2669 + /**
191.2670 + * Sets the maximum number of digits allowed in the integer portion of a
191.2671 + * number.
191.2672 + * For formatting numbers other than <code>BigInteger</code> and
191.2673 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
191.2674 + * 309 is used. Negative input values are replaced with 0.
191.2675 + * @see NumberFormat#setMaximumIntegerDigits
191.2676 + */
191.2677 + public void setMaximumIntegerDigits(int newValue) {
191.2678 + maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
191.2679 + super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
191.2680 + DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
191.2681 + if (minimumIntegerDigits > maximumIntegerDigits) {
191.2682 + minimumIntegerDigits = maximumIntegerDigits;
191.2683 + super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
191.2684 + DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
191.2685 + }
191.2686 + }
191.2687 +
191.2688 + /**
191.2689 + * Sets the minimum number of digits allowed in the integer portion of a
191.2690 + * number.
191.2691 + * For formatting numbers other than <code>BigInteger</code> and
191.2692 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
191.2693 + * 309 is used. Negative input values are replaced with 0.
191.2694 + * @see NumberFormat#setMinimumIntegerDigits
191.2695 + */
191.2696 + public void setMinimumIntegerDigits(int newValue) {
191.2697 + minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
191.2698 + super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
191.2699 + DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
191.2700 + if (minimumIntegerDigits > maximumIntegerDigits) {
191.2701 + maximumIntegerDigits = minimumIntegerDigits;
191.2702 + super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
191.2703 + DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
191.2704 + }
191.2705 + }
191.2706 +
191.2707 + /**
191.2708 + * Sets the maximum number of digits allowed in the fraction portion of a
191.2709 + * number.
191.2710 + * For formatting numbers other than <code>BigInteger</code> and
191.2711 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
191.2712 + * 340 is used. Negative input values are replaced with 0.
191.2713 + * @see NumberFormat#setMaximumFractionDigits
191.2714 + */
191.2715 + public void setMaximumFractionDigits(int newValue) {
191.2716 + maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
191.2717 + super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
191.2718 + DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
191.2719 + if (minimumFractionDigits > maximumFractionDigits) {
191.2720 + minimumFractionDigits = maximumFractionDigits;
191.2721 + super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
191.2722 + DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
191.2723 + }
191.2724 + }
191.2725 +
191.2726 + /**
191.2727 + * Sets the minimum number of digits allowed in the fraction portion of a
191.2728 + * number.
191.2729 + * For formatting numbers other than <code>BigInteger</code> and
191.2730 + * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
191.2731 + * 340 is used. Negative input values are replaced with 0.
191.2732 + * @see NumberFormat#setMinimumFractionDigits
191.2733 + */
191.2734 + public void setMinimumFractionDigits(int newValue) {
191.2735 + minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
191.2736 + super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
191.2737 + DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
191.2738 + if (minimumFractionDigits > maximumFractionDigits) {
191.2739 + maximumFractionDigits = minimumFractionDigits;
191.2740 + super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
191.2741 + DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
191.2742 + }
191.2743 + }
191.2744 +
191.2745 + /**
191.2746 + * Gets the maximum number of digits allowed in the integer portion of a
191.2747 + * number.
191.2748 + * For formatting numbers other than <code>BigInteger</code> and
191.2749 + * <code>BigDecimal</code> objects, the lower of the return value and
191.2750 + * 309 is used.
191.2751 + * @see #setMaximumIntegerDigits
191.2752 + */
191.2753 + public int getMaximumIntegerDigits() {
191.2754 + return maximumIntegerDigits;
191.2755 + }
191.2756 +
191.2757 + /**
191.2758 + * Gets the minimum number of digits allowed in the integer portion of a
191.2759 + * number.
191.2760 + * For formatting numbers other than <code>BigInteger</code> and
191.2761 + * <code>BigDecimal</code> objects, the lower of the return value and
191.2762 + * 309 is used.
191.2763 + * @see #setMinimumIntegerDigits
191.2764 + */
191.2765 + public int getMinimumIntegerDigits() {
191.2766 + return minimumIntegerDigits;
191.2767 + }
191.2768 +
191.2769 + /**
191.2770 + * Gets the maximum number of digits allowed in the fraction portion of a
191.2771 + * number.
191.2772 + * For formatting numbers other than <code>BigInteger</code> and
191.2773 + * <code>BigDecimal</code> objects, the lower of the return value and
191.2774 + * 340 is used.
191.2775 + * @see #setMaximumFractionDigits
191.2776 + */
191.2777 + public int getMaximumFractionDigits() {
191.2778 + return maximumFractionDigits;
191.2779 + }
191.2780 +
191.2781 + /**
191.2782 + * Gets the minimum number of digits allowed in the fraction portion of a
191.2783 + * number.
191.2784 + * For formatting numbers other than <code>BigInteger</code> and
191.2785 + * <code>BigDecimal</code> objects, the lower of the return value and
191.2786 + * 340 is used.
191.2787 + * @see #setMinimumFractionDigits
191.2788 + */
191.2789 + public int getMinimumFractionDigits() {
191.2790 + return minimumFractionDigits;
191.2791 + }
191.2792 +
191.2793 + /**
191.2794 + * Gets the currency used by this decimal format when formatting
191.2795 + * currency values.
191.2796 + * The currency is obtained by calling
191.2797 + * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
191.2798 + * on this number format's symbols.
191.2799 + *
191.2800 + * @return the currency used by this decimal format, or <code>null</code>
191.2801 + * @since 1.4
191.2802 + */
191.2803 + public Currency getCurrency() {
191.2804 + return symbols.getCurrency();
191.2805 + }
191.2806 +
191.2807 + /**
191.2808 + * Sets the currency used by this number format when formatting
191.2809 + * currency values. This does not update the minimum or maximum
191.2810 + * number of fraction digits used by the number format.
191.2811 + * The currency is set by calling
191.2812 + * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
191.2813 + * on this number format's symbols.
191.2814 + *
191.2815 + * @param currency the new currency to be used by this decimal format
191.2816 + * @exception NullPointerException if <code>currency</code> is null
191.2817 + * @since 1.4
191.2818 + */
191.2819 + public void setCurrency(Currency currency) {
191.2820 + if (currency != symbols.getCurrency()) {
191.2821 + symbols.setCurrency(currency);
191.2822 + if (isCurrencyFormat) {
191.2823 + expandAffixes();
191.2824 + }
191.2825 + }
191.2826 + }
191.2827 +
191.2828 + /**
191.2829 + * Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
191.2830 + *
191.2831 + * @return The <code>RoundingMode</code> used for this DecimalFormat.
191.2832 + * @see #setRoundingMode(RoundingMode)
191.2833 + * @since 1.6
191.2834 + */
191.2835 + public RoundingMode getRoundingMode() {
191.2836 + return roundingMode;
191.2837 + }
191.2838 +
191.2839 + /**
191.2840 + * Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
191.2841 + *
191.2842 + * @param roundingMode The <code>RoundingMode</code> to be used
191.2843 + * @see #getRoundingMode()
191.2844 + * @exception NullPointerException if <code>roundingMode</code> is null.
191.2845 + * @since 1.6
191.2846 + */
191.2847 + public void setRoundingMode(RoundingMode roundingMode) {
191.2848 + if (roundingMode == null) {
191.2849 + throw new NullPointerException();
191.2850 + }
191.2851 +
191.2852 + this.roundingMode = roundingMode;
191.2853 + digitList.setRoundingMode(roundingMode);
191.2854 + }
191.2855 +
191.2856 + /**
191.2857 + * Adjusts the minimum and maximum fraction digits to values that
191.2858 + * are reasonable for the currency's default fraction digits.
191.2859 + */
191.2860 + void adjustForCurrencyDefaultFractionDigits() {
191.2861 + Currency currency = symbols.getCurrency();
191.2862 + if (currency == null) {
191.2863 + try {
191.2864 + currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
191.2865 + } catch (IllegalArgumentException e) {
191.2866 + }
191.2867 + }
191.2868 + if (currency != null) {
191.2869 + int digits = currency.getDefaultFractionDigits();
191.2870 + if (digits != -1) {
191.2871 + int oldMinDigits = getMinimumFractionDigits();
191.2872 + // Common patterns are "#.##", "#.00", "#".
191.2873 + // Try to adjust all of them in a reasonable way.
191.2874 + if (oldMinDigits == getMaximumFractionDigits()) {
191.2875 + setMinimumFractionDigits(digits);
191.2876 + setMaximumFractionDigits(digits);
191.2877 + } else {
191.2878 + setMinimumFractionDigits(Math.min(digits, oldMinDigits));
191.2879 + setMaximumFractionDigits(digits);
191.2880 + }
191.2881 + }
191.2882 + }
191.2883 + }
191.2884 +
191.2885 + /**
191.2886 + * Reads the default serializable fields from the stream and performs
191.2887 + * validations and adjustments for older serialized versions. The
191.2888 + * validations and adjustments are:
191.2889 + * <ol>
191.2890 + * <li>
191.2891 + * Verify that the superclass's digit count fields correctly reflect
191.2892 + * the limits imposed on formatting numbers other than
191.2893 + * <code>BigInteger</code> and <code>BigDecimal</code> objects. These
191.2894 + * limits are stored in the superclass for serialization compatibility
191.2895 + * with older versions, while the limits for <code>BigInteger</code> and
191.2896 + * <code>BigDecimal</code> objects are kept in this class.
191.2897 + * If, in the superclass, the minimum or maximum integer digit count is
191.2898 + * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or
191.2899 + * maximum fraction digit count is larger than
191.2900 + * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid
191.2901 + * and this method throws an <code>InvalidObjectException</code>.
191.2902 + * <li>
191.2903 + * If <code>serialVersionOnStream</code> is less than 4, initialize
191.2904 + * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN
191.2905 + * RoundingMode.HALF_EVEN}. This field is new with version 4.
191.2906 + * <li>
191.2907 + * If <code>serialVersionOnStream</code> is less than 3, then call
191.2908 + * the setters for the minimum and maximum integer and fraction digits with
191.2909 + * the values of the corresponding superclass getters to initialize the
191.2910 + * fields in this class. The fields in this class are new with version 3.
191.2911 + * <li>
191.2912 + * If <code>serialVersionOnStream</code> is less than 1, indicating that
191.2913 + * the stream was written by JDK 1.1, initialize
191.2914 + * <code>useExponentialNotation</code>
191.2915 + * to false, since it was not present in JDK 1.1.
191.2916 + * <li>
191.2917 + * Set <code>serialVersionOnStream</code> to the maximum allowed value so
191.2918 + * that default serialization will work properly if this object is streamed
191.2919 + * out again.
191.2920 + * </ol>
191.2921 + *
191.2922 + * <p>Stream versions older than 2 will not have the affix pattern variables
191.2923 + * <code>posPrefixPattern</code> etc. As a result, they will be initialized
191.2924 + * to <code>null</code>, which means the affix strings will be taken as
191.2925 + * literal values. This is exactly what we want, since that corresponds to
191.2926 + * the pre-version-2 behavior.
191.2927 + */
191.2928 + private void readObject(ObjectInputStream stream)
191.2929 + throws IOException, ClassNotFoundException
191.2930 + {
191.2931 + stream.defaultReadObject();
191.2932 + digitList = new DigitList();
191.2933 +
191.2934 + if (serialVersionOnStream < 4) {
191.2935 + setRoundingMode(RoundingMode.HALF_EVEN);
191.2936 + }
191.2937 + // We only need to check the maximum counts because NumberFormat
191.2938 + // .readObject has already ensured that the maximum is greater than the
191.2939 + // minimum count.
191.2940 + if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
191.2941 + super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
191.2942 + throw new InvalidObjectException("Digit count out of range");
191.2943 + }
191.2944 + if (serialVersionOnStream < 3) {
191.2945 + setMaximumIntegerDigits(super.getMaximumIntegerDigits());
191.2946 + setMinimumIntegerDigits(super.getMinimumIntegerDigits());
191.2947 + setMaximumFractionDigits(super.getMaximumFractionDigits());
191.2948 + setMinimumFractionDigits(super.getMinimumFractionDigits());
191.2949 + }
191.2950 + if (serialVersionOnStream < 1) {
191.2951 + // Didn't have exponential fields
191.2952 + useExponentialNotation = false;
191.2953 + }
191.2954 + serialVersionOnStream = currentSerialVersion;
191.2955 + }
191.2956 +
191.2957 + //----------------------------------------------------------------------
191.2958 + // INSTANCE VARIABLES
191.2959 + //----------------------------------------------------------------------
191.2960 +
191.2961 + private transient DigitList digitList = new DigitList();
191.2962 +
191.2963 + /**
191.2964 + * The symbol used as a prefix when formatting positive numbers, e.g. "+".
191.2965 + *
191.2966 + * @serial
191.2967 + * @see #getPositivePrefix
191.2968 + */
191.2969 + private String positivePrefix = "";
191.2970 +
191.2971 + /**
191.2972 + * The symbol used as a suffix when formatting positive numbers.
191.2973 + * This is often an empty string.
191.2974 + *
191.2975 + * @serial
191.2976 + * @see #getPositiveSuffix
191.2977 + */
191.2978 + private String positiveSuffix = "";
191.2979 +
191.2980 + /**
191.2981 + * The symbol used as a prefix when formatting negative numbers, e.g. "-".
191.2982 + *
191.2983 + * @serial
191.2984 + * @see #getNegativePrefix
191.2985 + */
191.2986 + private String negativePrefix = "-";
191.2987 +
191.2988 + /**
191.2989 + * The symbol used as a suffix when formatting negative numbers.
191.2990 + * This is often an empty string.
191.2991 + *
191.2992 + * @serial
191.2993 + * @see #getNegativeSuffix
191.2994 + */
191.2995 + private String negativeSuffix = "";
191.2996 +
191.2997 + /**
191.2998 + * The prefix pattern for non-negative numbers. This variable corresponds
191.2999 + * to <code>positivePrefix</code>.
191.3000 + *
191.3001 + * <p>This pattern is expanded by the method <code>expandAffix()</code> to
191.3002 + * <code>positivePrefix</code> to update the latter to reflect changes in
191.3003 + * <code>symbols</code>. If this variable is <code>null</code> then
191.3004 + * <code>positivePrefix</code> is taken as a literal value that does not
191.3005 + * change when <code>symbols</code> changes. This variable is always
191.3006 + * <code>null</code> for <code>DecimalFormat</code> objects older than
191.3007 + * stream version 2 restored from stream.
191.3008 + *
191.3009 + * @serial
191.3010 + * @since 1.3
191.3011 + */
191.3012 + private String posPrefixPattern;
191.3013 +
191.3014 + /**
191.3015 + * The suffix pattern for non-negative numbers. This variable corresponds
191.3016 + * to <code>positiveSuffix</code>. This variable is analogous to
191.3017 + * <code>posPrefixPattern</code>; see that variable for further
191.3018 + * documentation.
191.3019 + *
191.3020 + * @serial
191.3021 + * @since 1.3
191.3022 + */
191.3023 + private String posSuffixPattern;
191.3024 +
191.3025 + /**
191.3026 + * The prefix pattern for negative numbers. This variable corresponds
191.3027 + * to <code>negativePrefix</code>. This variable is analogous to
191.3028 + * <code>posPrefixPattern</code>; see that variable for further
191.3029 + * documentation.
191.3030 + *
191.3031 + * @serial
191.3032 + * @since 1.3
191.3033 + */
191.3034 + private String negPrefixPattern;
191.3035 +
191.3036 + /**
191.3037 + * The suffix pattern for negative numbers. This variable corresponds
191.3038 + * to <code>negativeSuffix</code>. This variable is analogous to
191.3039 + * <code>posPrefixPattern</code>; see that variable for further
191.3040 + * documentation.
191.3041 + *
191.3042 + * @serial
191.3043 + * @since 1.3
191.3044 + */
191.3045 + private String negSuffixPattern;
191.3046 +
191.3047 + /**
191.3048 + * The multiplier for use in percent, per mille, etc.
191.3049 + *
191.3050 + * @serial
191.3051 + * @see #getMultiplier
191.3052 + */
191.3053 + private int multiplier = 1;
191.3054 +
191.3055 + /**
191.3056 + * The number of digits between grouping separators in the integer
191.3057 + * portion of a number. Must be greater than 0 if
191.3058 + * <code>NumberFormat.groupingUsed</code> is true.
191.3059 + *
191.3060 + * @serial
191.3061 + * @see #getGroupingSize
191.3062 + * @see java.text.NumberFormat#isGroupingUsed
191.3063 + */
191.3064 + private byte groupingSize = 3; // invariant, > 0 if useThousands
191.3065 +
191.3066 + /**
191.3067 + * If true, forces the decimal separator to always appear in a formatted
191.3068 + * number, even if the fractional part of the number is zero.
191.3069 + *
191.3070 + * @serial
191.3071 + * @see #isDecimalSeparatorAlwaysShown
191.3072 + */
191.3073 + private boolean decimalSeparatorAlwaysShown = false;
191.3074 +
191.3075 + /**
191.3076 + * If true, parse returns BigDecimal wherever possible.
191.3077 + *
191.3078 + * @serial
191.3079 + * @see #isParseBigDecimal
191.3080 + * @since 1.5
191.3081 + */
191.3082 + private boolean parseBigDecimal = false;
191.3083 +
191.3084 +
191.3085 + /**
191.3086 + * True if this object represents a currency format. This determines
191.3087 + * whether the monetary decimal separator is used instead of the normal one.
191.3088 + */
191.3089 + private transient boolean isCurrencyFormat = false;
191.3090 +
191.3091 + /**
191.3092 + * The <code>DecimalFormatSymbols</code> object used by this format.
191.3093 + * It contains the symbols used to format numbers, e.g. the grouping separator,
191.3094 + * decimal separator, and so on.
191.3095 + *
191.3096 + * @serial
191.3097 + * @see #setDecimalFormatSymbols
191.3098 + * @see java.text.DecimalFormatSymbols
191.3099 + */
191.3100 + private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
191.3101 +
191.3102 + /**
191.3103 + * True to force the use of exponential (i.e. scientific) notation when formatting
191.3104 + * numbers.
191.3105 + *
191.3106 + * @serial
191.3107 + * @since 1.2
191.3108 + */
191.3109 + private boolean useExponentialNotation; // Newly persistent in the Java 2 platform v.1.2
191.3110 +
191.3111 + /**
191.3112 + * FieldPositions describing the positive prefix String. This is
191.3113 + * lazily created. Use <code>getPositivePrefixFieldPositions</code>
191.3114 + * when needed.
191.3115 + */
191.3116 + private transient FieldPosition[] positivePrefixFieldPositions;
191.3117 +
191.3118 + /**
191.3119 + * FieldPositions describing the positive suffix String. This is
191.3120 + * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
191.3121 + * when needed.
191.3122 + */
191.3123 + private transient FieldPosition[] positiveSuffixFieldPositions;
191.3124 +
191.3125 + /**
191.3126 + * FieldPositions describing the negative prefix String. This is
191.3127 + * lazily created. Use <code>getNegativePrefixFieldPositions</code>
191.3128 + * when needed.
191.3129 + */
191.3130 + private transient FieldPosition[] negativePrefixFieldPositions;
191.3131 +
191.3132 + /**
191.3133 + * FieldPositions describing the negative suffix String. This is
191.3134 + * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
191.3135 + * when needed.
191.3136 + */
191.3137 + private transient FieldPosition[] negativeSuffixFieldPositions;
191.3138 +
191.3139 + /**
191.3140 + * The minimum number of digits used to display the exponent when a number is
191.3141 + * formatted in exponential notation. This field is ignored if
191.3142 + * <code>useExponentialNotation</code> is not true.
191.3143 + *
191.3144 + * @serial
191.3145 + * @since 1.2
191.3146 + */
191.3147 + private byte minExponentDigits; // Newly persistent in the Java 2 platform v.1.2
191.3148 +
191.3149 + /**
191.3150 + * The maximum number of digits allowed in the integer portion of a
191.3151 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
191.3152 + * <code>maximumIntegerDigits</code> must be greater than or equal to
191.3153 + * <code>minimumIntegerDigits</code>.
191.3154 + *
191.3155 + * @serial
191.3156 + * @see #getMaximumIntegerDigits
191.3157 + * @since 1.5
191.3158 + */
191.3159 + private int maximumIntegerDigits = super.getMaximumIntegerDigits();
191.3160 +
191.3161 + /**
191.3162 + * The minimum number of digits allowed in the integer portion of a
191.3163 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
191.3164 + * <code>minimumIntegerDigits</code> must be less than or equal to
191.3165 + * <code>maximumIntegerDigits</code>.
191.3166 + *
191.3167 + * @serial
191.3168 + * @see #getMinimumIntegerDigits
191.3169 + * @since 1.5
191.3170 + */
191.3171 + private int minimumIntegerDigits = super.getMinimumIntegerDigits();
191.3172 +
191.3173 + /**
191.3174 + * The maximum number of digits allowed in the fractional portion of a
191.3175 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
191.3176 + * <code>maximumFractionDigits</code> must be greater than or equal to
191.3177 + * <code>minimumFractionDigits</code>.
191.3178 + *
191.3179 + * @serial
191.3180 + * @see #getMaximumFractionDigits
191.3181 + * @since 1.5
191.3182 + */
191.3183 + private int maximumFractionDigits = super.getMaximumFractionDigits();
191.3184 +
191.3185 + /**
191.3186 + * The minimum number of digits allowed in the fractional portion of a
191.3187 + * <code>BigInteger</code> or <code>BigDecimal</code> number.
191.3188 + * <code>minimumFractionDigits</code> must be less than or equal to
191.3189 + * <code>maximumFractionDigits</code>.
191.3190 + *
191.3191 + * @serial
191.3192 + * @see #getMinimumFractionDigits
191.3193 + * @since 1.5
191.3194 + */
191.3195 + private int minimumFractionDigits = super.getMinimumFractionDigits();
191.3196 +
191.3197 + /**
191.3198 + * The {@link java.math.RoundingMode} used in this DecimalFormat.
191.3199 + *
191.3200 + * @serial
191.3201 + * @since 1.6
191.3202 + */
191.3203 + private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
191.3204 +
191.3205 + //----------------------------------------------------------------------
191.3206 +
191.3207 + static final int currentSerialVersion = 4;
191.3208 +
191.3209 + /**
191.3210 + * The internal serial version which says which version was written.
191.3211 + * Possible values are:
191.3212 + * <ul>
191.3213 + * <li><b>0</b> (default): versions before the Java 2 platform v1.2
191.3214 + * <li><b>1</b>: version for 1.2, which includes the two new fields
191.3215 + * <code>useExponentialNotation</code> and
191.3216 + * <code>minExponentDigits</code>.
191.3217 + * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
191.3218 + * <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
191.3219 + * <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
191.3220 + * <li><b>3</b>: version for 1.5 and later, which adds five new fields:
191.3221 + * <code>maximumIntegerDigits</code>,
191.3222 + * <code>minimumIntegerDigits</code>,
191.3223 + * <code>maximumFractionDigits</code>,
191.3224 + * <code>minimumFractionDigits</code>, and
191.3225 + * <code>parseBigDecimal</code>.
191.3226 + * <li><b>4</b>: version for 1.6 and later, which adds one new field:
191.3227 + * <code>roundingMode</code>.
191.3228 + * </ul>
191.3229 + * @since 1.2
191.3230 + * @serial
191.3231 + */
191.3232 + private int serialVersionOnStream = currentSerialVersion;
191.3233 +
191.3234 + //----------------------------------------------------------------------
191.3235 + // CONSTANTS
191.3236 + //----------------------------------------------------------------------
191.3237 +
191.3238 + // Constants for characters used in programmatic (unlocalized) patterns.
191.3239 + private static final char PATTERN_ZERO_DIGIT = '0';
191.3240 + private static final char PATTERN_GROUPING_SEPARATOR = ',';
191.3241 + private static final char PATTERN_DECIMAL_SEPARATOR = '.';
191.3242 + private static final char PATTERN_PER_MILLE = '\u2030';
191.3243 + private static final char PATTERN_PERCENT = '%';
191.3244 + private static final char PATTERN_DIGIT = '#';
191.3245 + private static final char PATTERN_SEPARATOR = ';';
191.3246 + private static final String PATTERN_EXPONENT = "E";
191.3247 + private static final char PATTERN_MINUS = '-';
191.3248 +
191.3249 + /**
191.3250 + * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
191.3251 + * is used in patterns and substituted with either the currency symbol,
191.3252 + * or if it is doubled, with the international currency symbol. If the
191.3253 + * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
191.3254 + * replaced with the monetary decimal separator.
191.3255 + *
191.3256 + * The CURRENCY_SIGN is not localized.
191.3257 + */
191.3258 + private static final char CURRENCY_SIGN = '\u00A4';
191.3259 +
191.3260 + private static final char QUOTE = '\'';
191.3261 +
191.3262 + private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
191.3263 +
191.3264 + // Upper limit on integer and fraction digits for a Java double
191.3265 + static final int DOUBLE_INTEGER_DIGITS = 309;
191.3266 + static final int DOUBLE_FRACTION_DIGITS = 340;
191.3267 +
191.3268 + // Upper limit on integer and fraction digits for BigDecimal and BigInteger
191.3269 + static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE;
191.3270 + static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE;
191.3271 +
191.3272 + // Proclaim JDK 1.1 serial compatibility.
191.3273 + static final long serialVersionUID = 864413376551465018L;
191.3274 +
191.3275 + /**
191.3276 + * Cache to hold the NumberPattern of a Locale.
191.3277 + */
191.3278 + private static final ConcurrentMap<Locale, String> cachedLocaleData
191.3279 + = new ConcurrentHashMap<Locale, String>(3);
191.3280 +}
192.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
192.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormatSymbols.java Wed Apr 30 15:04:10 2014 +0200
192.3 @@ -0,0 +1,834 @@
192.4 +/*
192.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
192.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
192.7 + *
192.8 + * This code is free software; you can redistribute it and/or modify it
192.9 + * under the terms of the GNU General Public License version 2 only, as
192.10 + * published by the Free Software Foundation. Oracle designates this
192.11 + * particular file as subject to the "Classpath" exception as provided
192.12 + * by Oracle in the LICENSE file that accompanied this code.
192.13 + *
192.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
192.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
192.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
192.17 + * version 2 for more details (a copy is included in the LICENSE file that
192.18 + * accompanied this code).
192.19 + *
192.20 + * You should have received a copy of the GNU General Public License version
192.21 + * 2 along with this work; if not, write to the Free Software Foundation,
192.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
192.23 + *
192.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
192.25 + * or visit www.oracle.com if you need additional information or have any
192.26 + * questions.
192.27 + */
192.28 +
192.29 +/*
192.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
192.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
192.32 + *
192.33 + * The original version of this source code and documentation is copyrighted
192.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
192.35 + * materials are provided under terms of a License Agreement between Taligent
192.36 + * and Sun. This technology is protected by multiple US and International
192.37 + * patents. This notice and attribution to Taligent may not be removed.
192.38 + * Taligent is a registered trademark of Taligent, Inc.
192.39 + *
192.40 + */
192.41 +
192.42 +package java.text;
192.43 +
192.44 +import java.io.IOException;
192.45 +import java.io.ObjectInputStream;
192.46 +import java.io.Serializable;
192.47 +import java.util.Currency;
192.48 +import java.util.Locale;
192.49 +import java.util.ResourceBundle;
192.50 +import java.util.concurrent.ConcurrentHashMap;
192.51 +
192.52 +/**
192.53 + * This class represents the set of symbols (such as the decimal separator,
192.54 + * the grouping separator, and so on) needed by <code>DecimalFormat</code>
192.55 + * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
192.56 + * <code>DecimalFormatSymbols</code> from its locale data. If you need to change any
192.57 + * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
192.58 + * your <code>DecimalFormat</code> and modify it.
192.59 + *
192.60 + * @see java.util.Locale
192.61 + * @see DecimalFormat
192.62 + * @author Mark Davis
192.63 + * @author Alan Liu
192.64 + */
192.65 +
192.66 +public class DecimalFormatSymbols implements Cloneable, Serializable {
192.67 +
192.68 + /**
192.69 + * Create a DecimalFormatSymbols object for the default locale.
192.70 + * This constructor can only construct instances for the locales
192.71 + * supported by the Java runtime environment, not for those
192.72 + * supported by installed
192.73 + * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
192.74 + * implementations. For full locale coverage, use the
192.75 + * {@link #getInstance(Locale) getInstance} method.
192.76 + */
192.77 + public DecimalFormatSymbols() {
192.78 + initialize( Locale.getDefault(Locale.Category.FORMAT) );
192.79 + }
192.80 +
192.81 + /**
192.82 + * Create a DecimalFormatSymbols object for the given locale.
192.83 + * This constructor can only construct instances for the locales
192.84 + * supported by the Java runtime environment, not for those
192.85 + * supported by installed
192.86 + * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
192.87 + * implementations. For full locale coverage, use the
192.88 + * {@link #getInstance(Locale) getInstance} method.
192.89 + *
192.90 + * @exception NullPointerException if <code>locale</code> is null
192.91 + */
192.92 + public DecimalFormatSymbols( Locale locale ) {
192.93 + initialize( locale );
192.94 + }
192.95 +
192.96 + /**
192.97 + * Returns an array of all locales for which the
192.98 + * <code>getInstance</code> methods of this class can return
192.99 + * localized instances.
192.100 + * The returned array represents the union of locales supported by the Java
192.101 + * runtime and by installed
192.102 + * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
192.103 + * implementations. It must contain at least a <code>Locale</code>
192.104 + * instance equal to {@link java.util.Locale#US Locale.US}.
192.105 + *
192.106 + * @return An array of locales for which localized
192.107 + * <code>DecimalFormatSymbols</code> instances are available.
192.108 + * @since 1.6
192.109 + */
192.110 + public static Locale[] getAvailableLocales() {
192.111 + return new Locale[] { Locale.US };
192.112 +// LocaleServiceProviderPool pool =
192.113 +// LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
192.114 +// return pool.getAvailableLocales();
192.115 + }
192.116 +
192.117 + /**
192.118 + * Gets the <code>DecimalFormatSymbols</code> instance for the default
192.119 + * locale. This method provides access to <code>DecimalFormatSymbols</code>
192.120 + * instances for locales supported by the Java runtime itself as well
192.121 + * as for those supported by installed
192.122 + * {@link java.text.spi.DecimalFormatSymbolsProvider
192.123 + * DecimalFormatSymbolsProvider} implementations.
192.124 + * @return a <code>DecimalFormatSymbols</code> instance.
192.125 + * @since 1.6
192.126 + */
192.127 + public static final DecimalFormatSymbols getInstance() {
192.128 + return getInstance(Locale.getDefault(Locale.Category.FORMAT));
192.129 + }
192.130 +
192.131 + /**
192.132 + * Gets the <code>DecimalFormatSymbols</code> instance for the specified
192.133 + * locale. This method provides access to <code>DecimalFormatSymbols</code>
192.134 + * instances for locales supported by the Java runtime itself as well
192.135 + * as for those supported by installed
192.136 + * {@link java.text.spi.DecimalFormatSymbolsProvider
192.137 + * DecimalFormatSymbolsProvider} implementations.
192.138 + * @param locale the desired locale.
192.139 + * @return a <code>DecimalFormatSymbols</code> instance.
192.140 + * @exception NullPointerException if <code>locale</code> is null
192.141 + * @since 1.6
192.142 + */
192.143 + public static final DecimalFormatSymbols getInstance(Locale locale) {
192.144 +/*
192.145 + // Check whether a provider can provide an implementation that's closer
192.146 + // to the requested locale than what the Java runtime itself can provide.
192.147 + LocaleServiceProviderPool pool =
192.148 + LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
192.149 + if (pool.hasProviders()) {
192.150 + DecimalFormatSymbols providersInstance = pool.getLocalizedObject(
192.151 + DecimalFormatSymbolsGetter.INSTANCE, locale);
192.152 + if (providersInstance != null) {
192.153 + return providersInstance;
192.154 + }
192.155 + }
192.156 +*/
192.157 + return new DecimalFormatSymbols(locale);
192.158 + }
192.159 +
192.160 + /**
192.161 + * Gets the character used for zero. Different for Arabic, etc.
192.162 + */
192.163 + public char getZeroDigit() {
192.164 + return zeroDigit;
192.165 + }
192.166 +
192.167 + /**
192.168 + * Sets the character used for zero. Different for Arabic, etc.
192.169 + */
192.170 + public void setZeroDigit(char zeroDigit) {
192.171 + this.zeroDigit = zeroDigit;
192.172 + }
192.173 +
192.174 + /**
192.175 + * Gets the character used for thousands separator. Different for French, etc.
192.176 + */
192.177 + public char getGroupingSeparator() {
192.178 + return groupingSeparator;
192.179 + }
192.180 +
192.181 + /**
192.182 + * Sets the character used for thousands separator. Different for French, etc.
192.183 + */
192.184 + public void setGroupingSeparator(char groupingSeparator) {
192.185 + this.groupingSeparator = groupingSeparator;
192.186 + }
192.187 +
192.188 + /**
192.189 + * Gets the character used for decimal sign. Different for French, etc.
192.190 + */
192.191 + public char getDecimalSeparator() {
192.192 + return decimalSeparator;
192.193 + }
192.194 +
192.195 + /**
192.196 + * Sets the character used for decimal sign. Different for French, etc.
192.197 + */
192.198 + public void setDecimalSeparator(char decimalSeparator) {
192.199 + this.decimalSeparator = decimalSeparator;
192.200 + }
192.201 +
192.202 + /**
192.203 + * Gets the character used for per mille sign. Different for Arabic, etc.
192.204 + */
192.205 + public char getPerMill() {
192.206 + return perMill;
192.207 + }
192.208 +
192.209 + /**
192.210 + * Sets the character used for per mille sign. Different for Arabic, etc.
192.211 + */
192.212 + public void setPerMill(char perMill) {
192.213 + this.perMill = perMill;
192.214 + }
192.215 +
192.216 + /**
192.217 + * Gets the character used for percent sign. Different for Arabic, etc.
192.218 + */
192.219 + public char getPercent() {
192.220 + return percent;
192.221 + }
192.222 +
192.223 + /**
192.224 + * Sets the character used for percent sign. Different for Arabic, etc.
192.225 + */
192.226 + public void setPercent(char percent) {
192.227 + this.percent = percent;
192.228 + }
192.229 +
192.230 + /**
192.231 + * Gets the character used for a digit in a pattern.
192.232 + */
192.233 + public char getDigit() {
192.234 + return digit;
192.235 + }
192.236 +
192.237 + /**
192.238 + * Sets the character used for a digit in a pattern.
192.239 + */
192.240 + public void setDigit(char digit) {
192.241 + this.digit = digit;
192.242 + }
192.243 +
192.244 + /**
192.245 + * Gets the character used to separate positive and negative subpatterns
192.246 + * in a pattern.
192.247 + */
192.248 + public char getPatternSeparator() {
192.249 + return patternSeparator;
192.250 + }
192.251 +
192.252 + /**
192.253 + * Sets the character used to separate positive and negative subpatterns
192.254 + * in a pattern.
192.255 + */
192.256 + public void setPatternSeparator(char patternSeparator) {
192.257 + this.patternSeparator = patternSeparator;
192.258 + }
192.259 +
192.260 + /**
192.261 + * Gets the string used to represent infinity. Almost always left
192.262 + * unchanged.
192.263 + */
192.264 + public String getInfinity() {
192.265 + return infinity;
192.266 + }
192.267 +
192.268 + /**
192.269 + * Sets the string used to represent infinity. Almost always left
192.270 + * unchanged.
192.271 + */
192.272 + public void setInfinity(String infinity) {
192.273 + this.infinity = infinity;
192.274 + }
192.275 +
192.276 + /**
192.277 + * Gets the string used to represent "not a number". Almost always left
192.278 + * unchanged.
192.279 + */
192.280 + public String getNaN() {
192.281 + return NaN;
192.282 + }
192.283 +
192.284 + /**
192.285 + * Sets the string used to represent "not a number". Almost always left
192.286 + * unchanged.
192.287 + */
192.288 + public void setNaN(String NaN) {
192.289 + this.NaN = NaN;
192.290 + }
192.291 +
192.292 + /**
192.293 + * Gets the character used to represent minus sign. If no explicit
192.294 + * negative format is specified, one is formed by prefixing
192.295 + * minusSign to the positive format.
192.296 + */
192.297 + public char getMinusSign() {
192.298 + return minusSign;
192.299 + }
192.300 +
192.301 + /**
192.302 + * Sets the character used to represent minus sign. If no explicit
192.303 + * negative format is specified, one is formed by prefixing
192.304 + * minusSign to the positive format.
192.305 + */
192.306 + public void setMinusSign(char minusSign) {
192.307 + this.minusSign = minusSign;
192.308 + }
192.309 +
192.310 + /**
192.311 + * Returns the currency symbol for the currency of these
192.312 + * DecimalFormatSymbols in their locale.
192.313 + * @since 1.2
192.314 + */
192.315 + public String getCurrencySymbol()
192.316 + {
192.317 + return currencySymbol;
192.318 + }
192.319 +
192.320 + /**
192.321 + * Sets the currency symbol for the currency of these
192.322 + * DecimalFormatSymbols in their locale.
192.323 + * @since 1.2
192.324 + */
192.325 + public void setCurrencySymbol(String currency)
192.326 + {
192.327 + currencySymbol = currency;
192.328 + }
192.329 +
192.330 + /**
192.331 + * Returns the ISO 4217 currency code of the currency of these
192.332 + * DecimalFormatSymbols.
192.333 + * @since 1.2
192.334 + */
192.335 + public String getInternationalCurrencySymbol()
192.336 + {
192.337 + return intlCurrencySymbol;
192.338 + }
192.339 +
192.340 + /**
192.341 + * Sets the ISO 4217 currency code of the currency of these
192.342 + * DecimalFormatSymbols.
192.343 + * If the currency code is valid (as defined by
192.344 + * {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
192.345 + * this also sets the currency attribute to the corresponding Currency
192.346 + * instance and the currency symbol attribute to the currency's symbol
192.347 + * in the DecimalFormatSymbols' locale. If the currency code is not valid,
192.348 + * then the currency attribute is set to null and the currency symbol
192.349 + * attribute is not modified.
192.350 + *
192.351 + * @see #setCurrency
192.352 + * @see #setCurrencySymbol
192.353 + * @since 1.2
192.354 + */
192.355 + public void setInternationalCurrencySymbol(String currencyCode)
192.356 + {
192.357 + intlCurrencySymbol = currencyCode;
192.358 + currency = null;
192.359 + if (currencyCode != null) {
192.360 + try {
192.361 + currency = Currency.getInstance(currencyCode);
192.362 + currencySymbol = currency.getSymbol();
192.363 + } catch (IllegalArgumentException e) {
192.364 + }
192.365 + }
192.366 + }
192.367 +
192.368 + /**
192.369 + * Gets the currency of these DecimalFormatSymbols. May be null if the
192.370 + * currency symbol attribute was previously set to a value that's not
192.371 + * a valid ISO 4217 currency code.
192.372 + *
192.373 + * @return the currency used, or null
192.374 + * @since 1.4
192.375 + */
192.376 + public Currency getCurrency() {
192.377 + return currency;
192.378 + }
192.379 +
192.380 + /**
192.381 + * Sets the currency of these DecimalFormatSymbols.
192.382 + * This also sets the currency symbol attribute to the currency's symbol
192.383 + * in the DecimalFormatSymbols' locale, and the international currency
192.384 + * symbol attribute to the currency's ISO 4217 currency code.
192.385 + *
192.386 + * @param currency the new currency to be used
192.387 + * @exception NullPointerException if <code>currency</code> is null
192.388 + * @since 1.4
192.389 + * @see #setCurrencySymbol
192.390 + * @see #setInternationalCurrencySymbol
192.391 + */
192.392 + public void setCurrency(Currency currency) {
192.393 + if (currency == null) {
192.394 + throw new NullPointerException();
192.395 + }
192.396 + this.currency = currency;
192.397 + intlCurrencySymbol = currency.getCurrencyCode();
192.398 + currencySymbol = currency.getSymbol(locale);
192.399 + }
192.400 +
192.401 +
192.402 + /**
192.403 + * Returns the monetary decimal separator.
192.404 + * @since 1.2
192.405 + */
192.406 + public char getMonetaryDecimalSeparator()
192.407 + {
192.408 + return monetarySeparator;
192.409 + }
192.410 +
192.411 + /**
192.412 + * Sets the monetary decimal separator.
192.413 + * @since 1.2
192.414 + */
192.415 + public void setMonetaryDecimalSeparator(char sep)
192.416 + {
192.417 + monetarySeparator = sep;
192.418 + }
192.419 +
192.420 + //------------------------------------------------------------
192.421 + // BEGIN Package Private methods ... to be made public later
192.422 + //------------------------------------------------------------
192.423 +
192.424 + /**
192.425 + * Returns the character used to separate the mantissa from the exponent.
192.426 + */
192.427 + char getExponentialSymbol()
192.428 + {
192.429 + return exponential;
192.430 + }
192.431 + /**
192.432 + * Returns the string used to separate the mantissa from the exponent.
192.433 + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
192.434 + *
192.435 + * @return the exponent separator string
192.436 + * @see #setExponentSeparator(java.lang.String)
192.437 + * @since 1.6
192.438 + */
192.439 + public String getExponentSeparator()
192.440 + {
192.441 + return exponentialSeparator;
192.442 + }
192.443 +
192.444 + /**
192.445 + * Sets the character used to separate the mantissa from the exponent.
192.446 + */
192.447 + void setExponentialSymbol(char exp)
192.448 + {
192.449 + exponential = exp;
192.450 + }
192.451 +
192.452 + /**
192.453 + * Sets the string used to separate the mantissa from the exponent.
192.454 + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
192.455 + *
192.456 + * @param exp the exponent separator string
192.457 + * @exception NullPointerException if <code>exp</code> is null
192.458 + * @see #getExponentSeparator()
192.459 + * @since 1.6
192.460 + */
192.461 + public void setExponentSeparator(String exp)
192.462 + {
192.463 + if (exp == null) {
192.464 + throw new NullPointerException();
192.465 + }
192.466 + exponentialSeparator = exp;
192.467 + }
192.468 +
192.469 +
192.470 + //------------------------------------------------------------
192.471 + // END Package Private methods ... to be made public later
192.472 + //------------------------------------------------------------
192.473 +
192.474 + /**
192.475 + * Standard override.
192.476 + */
192.477 + public Object clone() {
192.478 + try {
192.479 + return (DecimalFormatSymbols)super.clone();
192.480 + // other fields are bit-copied
192.481 + } catch (CloneNotSupportedException e) {
192.482 + throw new InternalError();
192.483 + }
192.484 + }
192.485 +
192.486 + /**
192.487 + * Override equals.
192.488 + */
192.489 + public boolean equals(Object obj) {
192.490 + if (obj == null) return false;
192.491 + if (this == obj) return true;
192.492 + if (getClass() != obj.getClass()) return false;
192.493 + DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
192.494 + return (zeroDigit == other.zeroDigit &&
192.495 + groupingSeparator == other.groupingSeparator &&
192.496 + decimalSeparator == other.decimalSeparator &&
192.497 + percent == other.percent &&
192.498 + perMill == other.perMill &&
192.499 + digit == other.digit &&
192.500 + minusSign == other.minusSign &&
192.501 + patternSeparator == other.patternSeparator &&
192.502 + infinity.equals(other.infinity) &&
192.503 + NaN.equals(other.NaN) &&
192.504 + currencySymbol.equals(other.currencySymbol) &&
192.505 + intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
192.506 + currency == other.currency &&
192.507 + monetarySeparator == other.monetarySeparator &&
192.508 + exponentialSeparator.equals(other.exponentialSeparator) &&
192.509 + locale.equals(other.locale));
192.510 + }
192.511 +
192.512 + /**
192.513 + * Override hashCode.
192.514 + */
192.515 + public int hashCode() {
192.516 + int result = zeroDigit;
192.517 + result = result * 37 + groupingSeparator;
192.518 + result = result * 37 + decimalSeparator;
192.519 + return result;
192.520 + }
192.521 +
192.522 + /**
192.523 + * Initializes the symbols from the FormatData resource bundle.
192.524 + */
192.525 + private void initialize( Locale locale ) {
192.526 + this.locale = locale;
192.527 +
192.528 + // get resource bundle data - try the cache first
192.529 + boolean needCacheUpdate = false;
192.530 + Object[] data = cachedLocaleData.get(locale);
192.531 + if (data == null) { /* cache miss */
192.532 + // When numbering system is thai (Locale's extension contains u-nu-thai),
192.533 + // we read the data from th_TH_TH.
192.534 + Locale lookupLocale = locale;
192.535 + String numberType = locale.getUnicodeLocaleType("nu");
192.536 + if (numberType != null && numberType.equals("thai")) {
192.537 + lookupLocale = new Locale("th", "TH", "TH");
192.538 + }
192.539 + data = new Object[3];
192.540 +// ResourceBundle rb = LocaleData.getNumberFormatData(lookupLocale);
192.541 +// data[0] = rb.getStringArray("NumberElements");
192.542 + needCacheUpdate = true;
192.543 + }
192.544 +
192.545 + String[] numberElements = (String[]) data[0];
192.546 +
192.547 + decimalSeparator = numberElements[0].charAt(0);
192.548 + groupingSeparator = numberElements[1].charAt(0);
192.549 + patternSeparator = numberElements[2].charAt(0);
192.550 + percent = numberElements[3].charAt(0);
192.551 + zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
192.552 + digit = numberElements[5].charAt(0);
192.553 + minusSign = numberElements[6].charAt(0);
192.554 + exponential = numberElements[7].charAt(0);
192.555 + exponentialSeparator = numberElements[7]; //string representation new since 1.6
192.556 + perMill = numberElements[8].charAt(0);
192.557 + infinity = numberElements[9];
192.558 + NaN = numberElements[10];
192.559 +
192.560 + // Try to obtain the currency used in the locale's country.
192.561 + // Check for empty country string separately because it's a valid
192.562 + // country ID for Locale (and used for the C locale), but not a valid
192.563 + // ISO 3166 country code, and exceptions are expensive.
192.564 + if (!"".equals(locale.getCountry())) {
192.565 + try {
192.566 + currency = Currency.getInstance(locale);
192.567 + } catch (IllegalArgumentException e) {
192.568 + // use default values below for compatibility
192.569 + }
192.570 + }
192.571 + if (currency != null) {
192.572 + intlCurrencySymbol = currency.getCurrencyCode();
192.573 + if (data[1] != null && data[1] == intlCurrencySymbol) {
192.574 + currencySymbol = (String) data[2];
192.575 + } else {
192.576 + currencySymbol = currency.getSymbol(locale);
192.577 + data[1] = intlCurrencySymbol;
192.578 + data[2] = currencySymbol;
192.579 + needCacheUpdate = true;
192.580 + }
192.581 + } else {
192.582 + // default values
192.583 + intlCurrencySymbol = "XXX";
192.584 + try {
192.585 + currency = Currency.getInstance(intlCurrencySymbol);
192.586 + } catch (IllegalArgumentException e) {
192.587 + }
192.588 + currencySymbol = "\u00A4";
192.589 + }
192.590 + // Currently the monetary decimal separator is the same as the
192.591 + // standard decimal separator for all locales that we support.
192.592 + // If that changes, add a new entry to NumberElements.
192.593 + monetarySeparator = decimalSeparator;
192.594 +
192.595 + if (needCacheUpdate) {
192.596 + cachedLocaleData.putIfAbsent(locale, data);
192.597 + }
192.598 + }
192.599 +
192.600 + /**
192.601 + * Reads the default serializable fields, provides default values for objects
192.602 + * in older serial versions, and initializes non-serializable fields.
192.603 + * If <code>serialVersionOnStream</code>
192.604 + * is less than 1, initializes <code>monetarySeparator</code> to be
192.605 + * the same as <code>decimalSeparator</code> and <code>exponential</code>
192.606 + * to be 'E'.
192.607 + * If <code>serialVersionOnStream</code> is less than 2,
192.608 + * initializes <code>locale</code>to the root locale, and initializes
192.609 + * If <code>serialVersionOnStream</code> is less than 3, it initializes
192.610 + * <code>exponentialSeparator</code> using <code>exponential</code>.
192.611 + * Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
192.612 + * default serialization will work properly if this object is streamed out again.
192.613 + * Initializes the currency from the intlCurrencySymbol field.
192.614 + *
192.615 + * @since JDK 1.1.6
192.616 + */
192.617 + private void readObject(ObjectInputStream stream)
192.618 + throws IOException, ClassNotFoundException {
192.619 + stream.defaultReadObject();
192.620 + if (serialVersionOnStream < 1) {
192.621 + // Didn't have monetarySeparator or exponential field;
192.622 + // use defaults.
192.623 + monetarySeparator = decimalSeparator;
192.624 + exponential = 'E';
192.625 + }
192.626 + if (serialVersionOnStream < 2) {
192.627 + // didn't have locale; use root locale
192.628 + locale = Locale.ROOT;
192.629 + }
192.630 + if (serialVersionOnStream < 3) {
192.631 + // didn't have exponentialSeparator. Create one using exponential
192.632 + exponentialSeparator = Character.toString(exponential);
192.633 + }
192.634 + serialVersionOnStream = currentSerialVersion;
192.635 +
192.636 + if (intlCurrencySymbol != null) {
192.637 + try {
192.638 + currency = Currency.getInstance(intlCurrencySymbol);
192.639 + } catch (IllegalArgumentException e) {
192.640 + }
192.641 + }
192.642 + }
192.643 +
192.644 + /**
192.645 + * Character used for zero.
192.646 + *
192.647 + * @serial
192.648 + * @see #getZeroDigit
192.649 + */
192.650 + private char zeroDigit;
192.651 +
192.652 + /**
192.653 + * Character used for thousands separator.
192.654 + *
192.655 + * @serial
192.656 + * @see #getGroupingSeparator
192.657 + */
192.658 + private char groupingSeparator;
192.659 +
192.660 + /**
192.661 + * Character used for decimal sign.
192.662 + *
192.663 + * @serial
192.664 + * @see #getDecimalSeparator
192.665 + */
192.666 + private char decimalSeparator;
192.667 +
192.668 + /**
192.669 + * Character used for per mille sign.
192.670 + *
192.671 + * @serial
192.672 + * @see #getPerMill
192.673 + */
192.674 + private char perMill;
192.675 +
192.676 + /**
192.677 + * Character used for percent sign.
192.678 + * @serial
192.679 + * @see #getPercent
192.680 + */
192.681 + private char percent;
192.682 +
192.683 + /**
192.684 + * Character used for a digit in a pattern.
192.685 + *
192.686 + * @serial
192.687 + * @see #getDigit
192.688 + */
192.689 + private char digit;
192.690 +
192.691 + /**
192.692 + * Character used to separate positive and negative subpatterns
192.693 + * in a pattern.
192.694 + *
192.695 + * @serial
192.696 + * @see #getPatternSeparator
192.697 + */
192.698 + private char patternSeparator;
192.699 +
192.700 + /**
192.701 + * String used to represent infinity.
192.702 + * @serial
192.703 + * @see #getInfinity
192.704 + */
192.705 + private String infinity;
192.706 +
192.707 + /**
192.708 + * String used to represent "not a number".
192.709 + * @serial
192.710 + * @see #getNaN
192.711 + */
192.712 + private String NaN;
192.713 +
192.714 + /**
192.715 + * Character used to represent minus sign.
192.716 + * @serial
192.717 + * @see #getMinusSign
192.718 + */
192.719 + private char minusSign;
192.720 +
192.721 + /**
192.722 + * String denoting the local currency, e.g. "$".
192.723 + * @serial
192.724 + * @see #getCurrencySymbol
192.725 + */
192.726 + private String currencySymbol;
192.727 +
192.728 + /**
192.729 + * ISO 4217 currency code denoting the local currency, e.g. "USD".
192.730 + * @serial
192.731 + * @see #getInternationalCurrencySymbol
192.732 + */
192.733 + private String intlCurrencySymbol;
192.734 +
192.735 + /**
192.736 + * The decimal separator used when formatting currency values.
192.737 + * @serial
192.738 + * @since JDK 1.1.6
192.739 + * @see #getMonetaryDecimalSeparator
192.740 + */
192.741 + private char monetarySeparator; // Field new in JDK 1.1.6
192.742 +
192.743 + /**
192.744 + * The character used to distinguish the exponent in a number formatted
192.745 + * in exponential notation, e.g. 'E' for a number such as "1.23E45".
192.746 + * <p>
192.747 + * Note that the public API provides no way to set this field,
192.748 + * even though it is supported by the implementation and the stream format.
192.749 + * The intent is that this will be added to the API in the future.
192.750 + *
192.751 + * @serial
192.752 + * @since JDK 1.1.6
192.753 + */
192.754 + private char exponential; // Field new in JDK 1.1.6
192.755 +
192.756 + /**
192.757 + * The string used to separate the mantissa from the exponent.
192.758 + * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
192.759 + * <p>
192.760 + * If both <code>exponential</code> and <code>exponentialSeparator</code>
192.761 + * exist, this <code>exponentialSeparator</code> has the precedence.
192.762 + *
192.763 + * @serial
192.764 + * @since 1.6
192.765 + */
192.766 + private String exponentialSeparator; // Field new in JDK 1.6
192.767 +
192.768 + /**
192.769 + * The locale of these currency format symbols.
192.770 + *
192.771 + * @serial
192.772 + * @since 1.4
192.773 + */
192.774 + private Locale locale;
192.775 +
192.776 + // currency; only the ISO code is serialized.
192.777 + private transient Currency currency;
192.778 +
192.779 + // Proclaim JDK 1.1 FCS compatibility
192.780 + static final long serialVersionUID = 5772796243397350300L;
192.781 +
192.782 + // The internal serial version which says which version was written
192.783 + // - 0 (default) for version up to JDK 1.1.5
192.784 + // - 1 for version from JDK 1.1.6, which includes two new fields:
192.785 + // monetarySeparator and exponential.
192.786 + // - 2 for version from J2SE 1.4, which includes locale field.
192.787 + // - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
192.788 + private static final int currentSerialVersion = 3;
192.789 +
192.790 + /**
192.791 + * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
192.792 + * Possible values are:
192.793 + * <ul>
192.794 + * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
192.795 + *
192.796 + * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
192.797 + * two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
192.798 + * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
192.799 + * new <code>locale</code> field.
192.800 + * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
192.801 + * new <code>exponentialSeparator</code> field.
192.802 + * </ul>
192.803 + * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
192.804 + * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
192.805 + * is always written.
192.806 + *
192.807 + * @serial
192.808 + * @since JDK 1.1.6
192.809 + */
192.810 + private int serialVersionOnStream = currentSerialVersion;
192.811 +
192.812 + /**
192.813 + * cache to hold the NumberElements and the Currency
192.814 + * of a Locale.
192.815 + */
192.816 + private static final ConcurrentHashMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<Locale, Object[]>(3);
192.817 +
192.818 + /**
192.819 + * Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider
192.820 + * implementation.
192.821 + private static class DecimalFormatSymbolsGetter
192.822 + implements LocaleServiceProviderPool.LocalizedObjectGetter<DecimalFormatSymbolsProvider,
192.823 + DecimalFormatSymbols> {
192.824 + private static final DecimalFormatSymbolsGetter INSTANCE =
192.825 + new DecimalFormatSymbolsGetter();
192.826 +
192.827 + public DecimalFormatSymbols getObject(
192.828 + DecimalFormatSymbolsProvider decimalFormatSymbolsProvider,
192.829 + Locale locale,
192.830 + String key,
192.831 + Object... params) {
192.832 + assert params.length == 0;
192.833 + return decimalFormatSymbolsProvider.getInstance(locale);
192.834 + }
192.835 + }
192.836 + */
192.837 +}
193.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
193.2 +++ b/rt/emul/compact/src/main/java/java/text/DigitList.java Wed Apr 30 15:04:10 2014 +0200
193.3 @@ -0,0 +1,715 @@
193.4 +/*
193.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
193.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
193.7 + *
193.8 + * This code is free software; you can redistribute it and/or modify it
193.9 + * under the terms of the GNU General Public License version 2 only, as
193.10 + * published by the Free Software Foundation. Oracle designates this
193.11 + * particular file as subject to the "Classpath" exception as provided
193.12 + * by Oracle in the LICENSE file that accompanied this code.
193.13 + *
193.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
193.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
193.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
193.17 + * version 2 for more details (a copy is included in the LICENSE file that
193.18 + * accompanied this code).
193.19 + *
193.20 + * You should have received a copy of the GNU General Public License version
193.21 + * 2 along with this work; if not, write to the Free Software Foundation,
193.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
193.23 + *
193.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
193.25 + * or visit www.oracle.com if you need additional information or have any
193.26 + * questions.
193.27 + */
193.28 +
193.29 +/*
193.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
193.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
193.32 + *
193.33 + * The original version of this source code and documentation is copyrighted
193.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
193.35 + * materials are provided under terms of a License Agreement between Taligent
193.36 + * and Sun. This technology is protected by multiple US and International
193.37 + * patents. This notice and attribution to Taligent may not be removed.
193.38 + * Taligent is a registered trademark of Taligent, Inc.
193.39 + *
193.40 + */
193.41 +
193.42 +package java.text;
193.43 +
193.44 +import java.math.BigDecimal;
193.45 +import java.math.BigInteger;
193.46 +import java.math.RoundingMode;
193.47 +
193.48 +/**
193.49 + * Digit List. Private to DecimalFormat.
193.50 + * Handles the transcoding
193.51 + * between numeric values and strings of characters. Only handles
193.52 + * non-negative numbers. The division of labor between DigitList and
193.53 + * DecimalFormat is that DigitList handles the radix 10 representation
193.54 + * issues; DecimalFormat handles the locale-specific issues such as
193.55 + * positive/negative, grouping, decimal point, currency, and so on.
193.56 + *
193.57 + * A DigitList is really a representation of a floating point value.
193.58 + * It may be an integer value; we assume that a double has sufficient
193.59 + * precision to represent all digits of a long.
193.60 + *
193.61 + * The DigitList representation consists of a string of characters,
193.62 + * which are the digits radix 10, from '0' to '9'. It also has a radix
193.63 + * 10 exponent associated with it. The value represented by a DigitList
193.64 + * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
193.65 + * derived by placing all the digits of the list to the right of the
193.66 + * decimal point, by 10^exponent.
193.67 + *
193.68 + * @see Locale
193.69 + * @see Format
193.70 + * @see NumberFormat
193.71 + * @see DecimalFormat
193.72 + * @see ChoiceFormat
193.73 + * @see MessageFormat
193.74 + * @author Mark Davis, Alan Liu
193.75 + */
193.76 +final class DigitList implements Cloneable {
193.77 + /**
193.78 + * The maximum number of significant digits in an IEEE 754 double, that
193.79 + * is, in a Java double. This must not be increased, or garbage digits
193.80 + * will be generated, and should not be decreased, or accuracy will be lost.
193.81 + */
193.82 + public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
193.83 +
193.84 + /**
193.85 + * These data members are intentionally public and can be set directly.
193.86 + *
193.87 + * The value represented is given by placing the decimal point before
193.88 + * digits[decimalAt]. If decimalAt is < 0, then leading zeros between
193.89 + * the decimal point and the first nonzero digit are implied. If decimalAt
193.90 + * is > count, then trailing zeros between the digits[count-1] and the
193.91 + * decimal point are implied.
193.92 + *
193.93 + * Equivalently, the represented value is given by f * 10^decimalAt. Here
193.94 + * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
193.95 + * the right of the decimal.
193.96 + *
193.97 + * DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We
193.98 + * don't allow denormalized numbers because our exponent is effectively of
193.99 + * unlimited magnitude. The count value contains the number of significant
193.100 + * digits present in digits[].
193.101 + *
193.102 + * Zero is represented by any DigitList with count == 0 or with each digits[i]
193.103 + * for all i <= count == '0'.
193.104 + */
193.105 + public int decimalAt = 0;
193.106 + public int count = 0;
193.107 + public char[] digits = new char[MAX_COUNT];
193.108 +
193.109 + private char[] data;
193.110 + private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
193.111 + private boolean isNegative = false;
193.112 +
193.113 + /**
193.114 + * Return true if the represented number is zero.
193.115 + */
193.116 + boolean isZero() {
193.117 + for (int i=0; i < count; ++i) {
193.118 + if (digits[i] != '0') {
193.119 + return false;
193.120 + }
193.121 + }
193.122 + return true;
193.123 + }
193.124 +
193.125 + /**
193.126 + * Set the rounding mode
193.127 + */
193.128 + void setRoundingMode(RoundingMode r) {
193.129 + roundingMode = r;
193.130 + }
193.131 +
193.132 + /**
193.133 + * Clears out the digits.
193.134 + * Use before appending them.
193.135 + * Typically, you set a series of digits with append, then at the point
193.136 + * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
193.137 + * then go on appending digits.
193.138 + */
193.139 + public void clear () {
193.140 + decimalAt = 0;
193.141 + count = 0;
193.142 + }
193.143 +
193.144 + /**
193.145 + * Appends a digit to the list, extending the list when necessary.
193.146 + */
193.147 + public void append(char digit) {
193.148 + if (count == digits.length) {
193.149 + char[] data = new char[count + 100];
193.150 + System.arraycopy(digits, 0, data, 0, count);
193.151 + digits = data;
193.152 + }
193.153 + digits[count++] = digit;
193.154 + }
193.155 +
193.156 + /**
193.157 + * Utility routine to get the value of the digit list
193.158 + * If (count == 0) this throws a NumberFormatException, which
193.159 + * mimics Long.parseLong().
193.160 + */
193.161 + public final double getDouble() {
193.162 + if (count == 0) {
193.163 + return 0.0;
193.164 + }
193.165 +
193.166 + StringBuffer temp = getStringBuffer();
193.167 + temp.append('.');
193.168 + temp.append(digits, 0, count);
193.169 + temp.append('E');
193.170 + temp.append(decimalAt);
193.171 + return Double.parseDouble(temp.toString());
193.172 + }
193.173 +
193.174 + /**
193.175 + * Utility routine to get the value of the digit list.
193.176 + * If (count == 0) this returns 0, unlike Long.parseLong().
193.177 + */
193.178 + public final long getLong() {
193.179 + // for now, simple implementation; later, do proper IEEE native stuff
193.180 +
193.181 + if (count == 0) {
193.182 + return 0;
193.183 + }
193.184 +
193.185 + // We have to check for this, because this is the one NEGATIVE value
193.186 + // we represent. If we tried to just pass the digits off to parseLong,
193.187 + // we'd get a parse failure.
193.188 + if (isLongMIN_VALUE()) {
193.189 + return Long.MIN_VALUE;
193.190 + }
193.191 +
193.192 + StringBuffer temp = getStringBuffer();
193.193 + temp.append(digits, 0, count);
193.194 + for (int i = count; i < decimalAt; ++i) {
193.195 + temp.append('0');
193.196 + }
193.197 + return Long.parseLong(temp.toString());
193.198 + }
193.199 +
193.200 + public final BigDecimal getBigDecimal() {
193.201 + if (count == 0) {
193.202 + if (decimalAt == 0) {
193.203 + return BigDecimal.ZERO;
193.204 + } else {
193.205 + return new BigDecimal("0E" + decimalAt);
193.206 + }
193.207 + }
193.208 +
193.209 + if (decimalAt == count) {
193.210 + return new BigDecimal(digits, 0, count);
193.211 + } else {
193.212 + return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
193.213 + }
193.214 + }
193.215 +
193.216 + /**
193.217 + * Return true if the number represented by this object can fit into
193.218 + * a long.
193.219 + * @param isPositive true if this number should be regarded as positive
193.220 + * @param ignoreNegativeZero true if -0 should be regarded as identical to
193.221 + * +0; otherwise they are considered distinct
193.222 + * @return true if this number fits into a Java long
193.223 + */
193.224 + boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) {
193.225 + // Figure out if the result will fit in a long. We have to
193.226 + // first look for nonzero digits after the decimal point;
193.227 + // then check the size. If the digit count is 18 or less, then
193.228 + // the value can definitely be represented as a long. If it is 19
193.229 + // then it may be too large.
193.230 +
193.231 + // Trim trailing zeros. This does not change the represented value.
193.232 + while (count > 0 && digits[count - 1] == '0') {
193.233 + --count;
193.234 + }
193.235 +
193.236 + if (count == 0) {
193.237 + // Positive zero fits into a long, but negative zero can only
193.238 + // be represented as a double. - bug 4162852
193.239 + return isPositive || ignoreNegativeZero;
193.240 + }
193.241 +
193.242 + if (decimalAt < count || decimalAt > MAX_COUNT) {
193.243 + return false;
193.244 + }
193.245 +
193.246 + if (decimalAt < MAX_COUNT) return true;
193.247 +
193.248 + // At this point we have decimalAt == count, and count == MAX_COUNT.
193.249 + // The number will overflow if it is larger than 9223372036854775807
193.250 + // or smaller than -9223372036854775808.
193.251 + for (int i=0; i<count; ++i) {
193.252 + char dig = digits[i], max = LONG_MIN_REP[i];
193.253 + if (dig > max) return false;
193.254 + if (dig < max) return true;
193.255 + }
193.256 +
193.257 + // At this point the first count digits match. If decimalAt is less
193.258 + // than count, then the remaining digits are zero, and we return true.
193.259 + if (count < decimalAt) return true;
193.260 +
193.261 + // Now we have a representation of Long.MIN_VALUE, without the leading
193.262 + // negative sign. If this represents a positive value, then it does
193.263 + // not fit; otherwise it fits.
193.264 + return !isPositive;
193.265 + }
193.266 +
193.267 + /**
193.268 + * Set the digit list to a representation of the given double value.
193.269 + * This method supports fixed-point notation.
193.270 + * @param isNegative Boolean value indicating whether the number is negative.
193.271 + * @param source Value to be converted; must not be Inf, -Inf, Nan,
193.272 + * or a value <= 0.
193.273 + * @param maximumFractionDigits The most fractional digits which should
193.274 + * be converted.
193.275 + */
193.276 + public final void set(boolean isNegative, double source, int maximumFractionDigits) {
193.277 + set(isNegative, source, maximumFractionDigits, true);
193.278 + }
193.279 +
193.280 + /**
193.281 + * Set the digit list to a representation of the given double value.
193.282 + * This method supports both fixed-point and exponential notation.
193.283 + * @param isNegative Boolean value indicating whether the number is negative.
193.284 + * @param source Value to be converted; must not be Inf, -Inf, Nan,
193.285 + * or a value <= 0.
193.286 + * @param maximumDigits The most fractional or total digits which should
193.287 + * be converted.
193.288 + * @param fixedPoint If true, then maximumDigits is the maximum
193.289 + * fractional digits to be converted. If false, total digits.
193.290 + */
193.291 + final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
193.292 + set(isNegative, Double.toString(source), maximumDigits, fixedPoint);
193.293 + }
193.294 +
193.295 + /**
193.296 + * Generate a representation of the form DDDDD, DDDDD.DDDDD, or
193.297 + * DDDDDE+/-DDDDD.
193.298 + */
193.299 + final void set(boolean isNegative, String s, int maximumDigits, boolean fixedPoint) {
193.300 + this.isNegative = isNegative;
193.301 + int len = s.length();
193.302 + char[] source = getDataChars(len);
193.303 + s.getChars(0, len, source, 0);
193.304 +
193.305 + decimalAt = -1;
193.306 + count = 0;
193.307 + int exponent = 0;
193.308 + // Number of zeros between decimal point and first non-zero digit after
193.309 + // decimal point, for numbers < 1.
193.310 + int leadingZerosAfterDecimal = 0;
193.311 + boolean nonZeroDigitSeen = false;
193.312 +
193.313 + for (int i = 0; i < len; ) {
193.314 + char c = source[i++];
193.315 + if (c == '.') {
193.316 + decimalAt = count;
193.317 + } else if (c == 'e' || c == 'E') {
193.318 + exponent = parseInt(source, i, len);
193.319 + break;
193.320 + } else {
193.321 + if (!nonZeroDigitSeen) {
193.322 + nonZeroDigitSeen = (c != '0');
193.323 + if (!nonZeroDigitSeen && decimalAt != -1)
193.324 + ++leadingZerosAfterDecimal;
193.325 + }
193.326 + if (nonZeroDigitSeen) {
193.327 + digits[count++] = c;
193.328 + }
193.329 + }
193.330 + }
193.331 + if (decimalAt == -1) {
193.332 + decimalAt = count;
193.333 + }
193.334 + if (nonZeroDigitSeen) {
193.335 + decimalAt += exponent - leadingZerosAfterDecimal;
193.336 + }
193.337 +
193.338 + if (fixedPoint) {
193.339 + // The negative of the exponent represents the number of leading
193.340 + // zeros between the decimal and the first non-zero digit, for
193.341 + // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
193.342 + // is more than the maximum fraction digits, then we have an underflow
193.343 + // for the printed representation.
193.344 + if (-decimalAt > maximumDigits) {
193.345 + // Handle an underflow to zero when we round something like
193.346 + // 0.0009 to 2 fractional digits.
193.347 + count = 0;
193.348 + return;
193.349 + } else if (-decimalAt == maximumDigits) {
193.350 + // If we round 0.0009 to 3 fractional digits, then we have to
193.351 + // create a new one digit in the least significant location.
193.352 + if (shouldRoundUp(0)) {
193.353 + count = 1;
193.354 + ++decimalAt;
193.355 + digits[0] = '1';
193.356 + } else {
193.357 + count = 0;
193.358 + }
193.359 + return;
193.360 + }
193.361 + // else fall through
193.362 + }
193.363 +
193.364 + // Eliminate trailing zeros.
193.365 + while (count > 1 && digits[count - 1] == '0') {
193.366 + --count;
193.367 + }
193.368 +
193.369 + // Eliminate digits beyond maximum digits to be displayed.
193.370 + // Round up if appropriate.
193.371 + round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
193.372 + }
193.373 +
193.374 + /**
193.375 + * Round the representation to the given number of digits.
193.376 + * @param maximumDigits The maximum number of digits to be shown.
193.377 + * Upon return, count will be less than or equal to maximumDigits.
193.378 + */
193.379 + private final void round(int maximumDigits) {
193.380 + // Eliminate digits beyond maximum digits to be displayed.
193.381 + // Round up if appropriate.
193.382 + if (maximumDigits >= 0 && maximumDigits < count) {
193.383 + if (shouldRoundUp(maximumDigits)) {
193.384 + // Rounding up involved incrementing digits from LSD to MSD.
193.385 + // In most cases this is simple, but in a worst case situation
193.386 + // (9999..99) we have to adjust the decimalAt value.
193.387 + for (;;) {
193.388 + --maximumDigits;
193.389 + if (maximumDigits < 0) {
193.390 + // We have all 9's, so we increment to a single digit
193.391 + // of one and adjust the exponent.
193.392 + digits[0] = '1';
193.393 + ++decimalAt;
193.394 + maximumDigits = 0; // Adjust the count
193.395 + break;
193.396 + }
193.397 +
193.398 + ++digits[maximumDigits];
193.399 + if (digits[maximumDigits] <= '9') break;
193.400 + // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
193.401 + }
193.402 + ++maximumDigits; // Increment for use as count
193.403 + }
193.404 + count = maximumDigits;
193.405 +
193.406 + // Eliminate trailing zeros.
193.407 + while (count > 1 && digits[count-1] == '0') {
193.408 + --count;
193.409 + }
193.410 + }
193.411 + }
193.412 +
193.413 +
193.414 + /**
193.415 + * Return true if truncating the representation to the given number
193.416 + * of digits will result in an increment to the last digit. This
193.417 + * method implements the rounding modes defined in the
193.418 + * java.math.RoundingMode class.
193.419 + * [bnf]
193.420 + * @param maximumDigits the number of digits to keep, from 0 to
193.421 + * <code>count-1</code>. If 0, then all digits are rounded away, and
193.422 + * this method returns true if a one should be generated (e.g., formatting
193.423 + * 0.09 with "#.#").
193.424 + * @exception ArithmeticException if rounding is needed with rounding
193.425 + * mode being set to RoundingMode.UNNECESSARY
193.426 + * @return true if digit <code>maximumDigits-1</code> should be
193.427 + * incremented
193.428 + */
193.429 + private boolean shouldRoundUp(int maximumDigits) {
193.430 + if (maximumDigits < count) {
193.431 + switch(roundingMode) {
193.432 + case UP:
193.433 + for (int i=maximumDigits; i<count; ++i) {
193.434 + if (digits[i] != '0') {
193.435 + return true;
193.436 + }
193.437 + }
193.438 + break;
193.439 + case DOWN:
193.440 + break;
193.441 + case CEILING:
193.442 + for (int i=maximumDigits; i<count; ++i) {
193.443 + if (digits[i] != '0') {
193.444 + return !isNegative;
193.445 + }
193.446 + }
193.447 + break;
193.448 + case FLOOR:
193.449 + for (int i=maximumDigits; i<count; ++i) {
193.450 + if (digits[i] != '0') {
193.451 + return isNegative;
193.452 + }
193.453 + }
193.454 + break;
193.455 + case HALF_UP:
193.456 + if (digits[maximumDigits] >= '5') {
193.457 + return true;
193.458 + }
193.459 + break;
193.460 + case HALF_DOWN:
193.461 + if (digits[maximumDigits] > '5') {
193.462 + return true;
193.463 + } else if (digits[maximumDigits] == '5' ) {
193.464 + for (int i=maximumDigits+1; i<count; ++i) {
193.465 + if (digits[i] != '0') {
193.466 + return true;
193.467 + }
193.468 + }
193.469 + }
193.470 + break;
193.471 + case HALF_EVEN:
193.472 + // Implement IEEE half-even rounding
193.473 + if (digits[maximumDigits] > '5') {
193.474 + return true;
193.475 + } else if (digits[maximumDigits] == '5' ) {
193.476 + for (int i=maximumDigits+1; i<count; ++i) {
193.477 + if (digits[i] != '0') {
193.478 + return true;
193.479 + }
193.480 + }
193.481 + return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
193.482 + }
193.483 + break;
193.484 + case UNNECESSARY:
193.485 + for (int i=maximumDigits; i<count; ++i) {
193.486 + if (digits[i] != '0') {
193.487 + throw new ArithmeticException(
193.488 + "Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
193.489 + }
193.490 + }
193.491 + break;
193.492 + default:
193.493 + assert false;
193.494 + }
193.495 + }
193.496 + return false;
193.497 + }
193.498 +
193.499 + /**
193.500 + * Utility routine to set the value of the digit list from a long
193.501 + */
193.502 + public final void set(boolean isNegative, long source) {
193.503 + set(isNegative, source, 0);
193.504 + }
193.505 +
193.506 + /**
193.507 + * Set the digit list to a representation of the given long value.
193.508 + * @param isNegative Boolean value indicating whether the number is negative.
193.509 + * @param source Value to be converted; must be >= 0 or ==
193.510 + * Long.MIN_VALUE.
193.511 + * @param maximumDigits The most digits which should be converted.
193.512 + * If maximumDigits is lower than the number of significant digits
193.513 + * in source, the representation will be rounded. Ignored if <= 0.
193.514 + */
193.515 + public final void set(boolean isNegative, long source, int maximumDigits) {
193.516 + this.isNegative = isNegative;
193.517 +
193.518 + // This method does not expect a negative number. However,
193.519 + // "source" can be a Long.MIN_VALUE (-9223372036854775808),
193.520 + // if the number being formatted is a Long.MIN_VALUE. In that
193.521 + // case, it will be formatted as -Long.MIN_VALUE, a number
193.522 + // which is outside the legal range of a long, but which can
193.523 + // be represented by DigitList.
193.524 + if (source <= 0) {
193.525 + if (source == Long.MIN_VALUE) {
193.526 + decimalAt = count = MAX_COUNT;
193.527 + System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
193.528 + } else {
193.529 + decimalAt = count = 0; // Values <= 0 format as zero
193.530 + }
193.531 + } else {
193.532 + // Rewritten to improve performance. I used to call
193.533 + // Long.toString(), which was about 4x slower than this code.
193.534 + int left = MAX_COUNT;
193.535 + int right;
193.536 + while (source > 0) {
193.537 + digits[--left] = (char)('0' + (source % 10));
193.538 + source /= 10;
193.539 + }
193.540 + decimalAt = MAX_COUNT - left;
193.541 + // Don't copy trailing zeros. We are guaranteed that there is at
193.542 + // least one non-zero digit, so we don't have to check lower bounds.
193.543 + for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
193.544 + ;
193.545 + count = right - left + 1;
193.546 + System.arraycopy(digits, left, digits, 0, count);
193.547 + }
193.548 + if (maximumDigits > 0) round(maximumDigits);
193.549 + }
193.550 +
193.551 + /**
193.552 + * Set the digit list to a representation of the given BigDecimal value.
193.553 + * This method supports both fixed-point and exponential notation.
193.554 + * @param isNegative Boolean value indicating whether the number is negative.
193.555 + * @param source Value to be converted; must not be a value <= 0.
193.556 + * @param maximumDigits The most fractional or total digits which should
193.557 + * be converted.
193.558 + * @param fixedPoint If true, then maximumDigits is the maximum
193.559 + * fractional digits to be converted. If false, total digits.
193.560 + */
193.561 + final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
193.562 + String s = source.toString();
193.563 + extendDigits(s.length());
193.564 +
193.565 + set(isNegative, s, maximumDigits, fixedPoint);
193.566 + }
193.567 +
193.568 + /**
193.569 + * Set the digit list to a representation of the given BigInteger value.
193.570 + * @param isNegative Boolean value indicating whether the number is negative.
193.571 + * @param source Value to be converted; must be >= 0.
193.572 + * @param maximumDigits The most digits which should be converted.
193.573 + * If maximumDigits is lower than the number of significant digits
193.574 + * in source, the representation will be rounded. Ignored if <= 0.
193.575 + */
193.576 + final void set(boolean isNegative, BigInteger source, int maximumDigits) {
193.577 + this.isNegative = isNegative;
193.578 + String s = source.toString();
193.579 + int len = s.length();
193.580 + extendDigits(len);
193.581 + s.getChars(0, len, digits, 0);
193.582 +
193.583 + decimalAt = len;
193.584 + int right;
193.585 + for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
193.586 + ;
193.587 + count = right + 1;
193.588 +
193.589 + if (maximumDigits > 0) {
193.590 + round(maximumDigits);
193.591 + }
193.592 + }
193.593 +
193.594 + /**
193.595 + * equality test between two digit lists.
193.596 + */
193.597 + public boolean equals(Object obj) {
193.598 + if (this == obj) // quick check
193.599 + return true;
193.600 + if (!(obj instanceof DigitList)) // (1) same object?
193.601 + return false;
193.602 + DigitList other = (DigitList) obj;
193.603 + if (count != other.count ||
193.604 + decimalAt != other.decimalAt)
193.605 + return false;
193.606 + for (int i = 0; i < count; i++)
193.607 + if (digits[i] != other.digits[i])
193.608 + return false;
193.609 + return true;
193.610 + }
193.611 +
193.612 + /**
193.613 + * Generates the hash code for the digit list.
193.614 + */
193.615 + public int hashCode() {
193.616 + int hashcode = decimalAt;
193.617 +
193.618 + for (int i = 0; i < count; i++) {
193.619 + hashcode = hashcode * 37 + digits[i];
193.620 + }
193.621 +
193.622 + return hashcode;
193.623 + }
193.624 +
193.625 + /**
193.626 + * Creates a copy of this object.
193.627 + * @return a clone of this instance.
193.628 + */
193.629 + public Object clone() {
193.630 + try {
193.631 + DigitList other = (DigitList) super.clone();
193.632 + char[] newDigits = new char[digits.length];
193.633 + System.arraycopy(digits, 0, newDigits, 0, digits.length);
193.634 + other.digits = newDigits;
193.635 + other.tempBuffer = null;
193.636 + return other;
193.637 + } catch (CloneNotSupportedException e) {
193.638 + throw new InternalError();
193.639 + }
193.640 + }
193.641 +
193.642 + /**
193.643 + * Returns true if this DigitList represents Long.MIN_VALUE;
193.644 + * false, otherwise. This is required so that getLong() works.
193.645 + */
193.646 + private boolean isLongMIN_VALUE() {
193.647 + if (decimalAt != count || count != MAX_COUNT) {
193.648 + return false;
193.649 + }
193.650 +
193.651 + for (int i = 0; i < count; ++i) {
193.652 + if (digits[i] != LONG_MIN_REP[i]) return false;
193.653 + }
193.654 +
193.655 + return true;
193.656 + }
193.657 +
193.658 + private static final int parseInt(char[] str, int offset, int strLen) {
193.659 + char c;
193.660 + boolean positive = true;
193.661 + if ((c = str[offset]) == '-') {
193.662 + positive = false;
193.663 + offset++;
193.664 + } else if (c == '+') {
193.665 + offset++;
193.666 + }
193.667 +
193.668 + int value = 0;
193.669 + while (offset < strLen) {
193.670 + c = str[offset++];
193.671 + if (c >= '0' && c <= '9') {
193.672 + value = value * 10 + (c - '0');
193.673 + } else {
193.674 + break;
193.675 + }
193.676 + }
193.677 + return positive ? value : -value;
193.678 + }
193.679 +
193.680 + // The digit part of -9223372036854775808L
193.681 + private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
193.682 +
193.683 + public String toString() {
193.684 + if (isZero()) {
193.685 + return "0";
193.686 + }
193.687 + StringBuffer buf = getStringBuffer();
193.688 + buf.append("0.");
193.689 + buf.append(digits, 0, count);
193.690 + buf.append("x10^");
193.691 + buf.append(decimalAt);
193.692 + return buf.toString();
193.693 + }
193.694 +
193.695 + private StringBuffer tempBuffer;
193.696 +
193.697 + private StringBuffer getStringBuffer() {
193.698 + if (tempBuffer == null) {
193.699 + tempBuffer = new StringBuffer(MAX_COUNT);
193.700 + } else {
193.701 + tempBuffer.setLength(0);
193.702 + }
193.703 + return tempBuffer;
193.704 + }
193.705 +
193.706 + private void extendDigits(int len) {
193.707 + if (len > digits.length) {
193.708 + digits = new char[len];
193.709 + }
193.710 + }
193.711 +
193.712 + private final char[] getDataChars(int length) {
193.713 + if (data == null || data.length < length) {
193.714 + data = new char[length];
193.715 + }
193.716 + return data;
193.717 + }
193.718 +}
194.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
194.2 +++ b/rt/emul/compact/src/main/java/java/text/DontCareFieldPosition.java Wed Apr 30 15:04:10 2014 +0200
194.3 @@ -0,0 +1,53 @@
194.4 +/*
194.5 + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
194.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
194.7 + *
194.8 + * This code is free software; you can redistribute it and/or modify it
194.9 + * under the terms of the GNU General Public License version 2 only, as
194.10 + * published by the Free Software Foundation. Oracle designates this
194.11 + * particular file as subject to the "Classpath" exception as provided
194.12 + * by Oracle in the LICENSE file that accompanied this code.
194.13 + *
194.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
194.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
194.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
194.17 + * version 2 for more details (a copy is included in the LICENSE file that
194.18 + * accompanied this code).
194.19 + *
194.20 + * You should have received a copy of the GNU General Public License version
194.21 + * 2 along with this work; if not, write to the Free Software Foundation,
194.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
194.23 + *
194.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
194.25 + * or visit www.oracle.com if you need additional information or have any
194.26 + * questions.
194.27 + */
194.28 +
194.29 +package java.text;
194.30 +
194.31 +/**
194.32 + * DontCareFieldPosition defines no-op FieldDelegate. Its
194.33 + * singleton is used for the format methods that don't take a
194.34 + * FieldPosition.
194.35 + */
194.36 +class DontCareFieldPosition extends FieldPosition {
194.37 + // The singleton of DontCareFieldPosition.
194.38 + static final FieldPosition INSTANCE = new DontCareFieldPosition();
194.39 +
194.40 + private final Format.FieldDelegate noDelegate = new Format.FieldDelegate() {
194.41 + public void formatted(Format.Field attr, Object value, int start,
194.42 + int end, StringBuffer buffer) {
194.43 + }
194.44 + public void formatted(int fieldID, Format.Field attr, Object value,
194.45 + int start, int end, StringBuffer buffer) {
194.46 + }
194.47 + };
194.48 +
194.49 + private DontCareFieldPosition() {
194.50 + super(0);
194.51 + }
194.52 +
194.53 + Format.FieldDelegate getFieldDelegate() {
194.54 + return noDelegate;
194.55 + }
194.56 +}
195.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
195.2 +++ b/rt/emul/compact/src/main/java/java/text/FieldPosition.java Wed Apr 30 15:04:10 2014 +0200
195.3 @@ -0,0 +1,303 @@
195.4 +/*
195.5 + * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
195.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
195.7 + *
195.8 + * This code is free software; you can redistribute it and/or modify it
195.9 + * under the terms of the GNU General Public License version 2 only, as
195.10 + * published by the Free Software Foundation. Oracle designates this
195.11 + * particular file as subject to the "Classpath" exception as provided
195.12 + * by Oracle in the LICENSE file that accompanied this code.
195.13 + *
195.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
195.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
195.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
195.17 + * version 2 for more details (a copy is included in the LICENSE file that
195.18 + * accompanied this code).
195.19 + *
195.20 + * You should have received a copy of the GNU General Public License version
195.21 + * 2 along with this work; if not, write to the Free Software Foundation,
195.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
195.23 + *
195.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
195.25 + * or visit www.oracle.com if you need additional information or have any
195.26 + * questions.
195.27 + */
195.28 +
195.29 +/*
195.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
195.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
195.32 + *
195.33 + * The original version of this source code and documentation is copyrighted
195.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
195.35 + * materials are provided under terms of a License Agreement between Taligent
195.36 + * and Sun. This technology is protected by multiple US and International
195.37 + * patents. This notice and attribution to Taligent may not be removed.
195.38 + * Taligent is a registered trademark of Taligent, Inc.
195.39 + *
195.40 + */
195.41 +
195.42 +package java.text;
195.43 +
195.44 +/**
195.45 + * <code>FieldPosition</code> is a simple class used by <code>Format</code>
195.46 + * and its subclasses to identify fields in formatted output. Fields can
195.47 + * be identified in two ways:
195.48 + * <ul>
195.49 + * <li>By an integer constant, whose names typically end with
195.50 + * <code>_FIELD</code>. The constants are defined in the various
195.51 + * subclasses of <code>Format</code>.
195.52 + * <li>By a <code>Format.Field</code> constant, see <code>ERA_FIELD</code>
195.53 + * and its friends in <code>DateFormat</code> for an example.
195.54 + * </ul>
195.55 + * <p>
195.56 + * <code>FieldPosition</code> keeps track of the position of the
195.57 + * field within the formatted output with two indices: the index
195.58 + * of the first character of the field and the index of the last
195.59 + * character of the field.
195.60 + *
195.61 + * <p>
195.62 + * One version of the <code>format</code> method in the various
195.63 + * <code>Format</code> classes requires a <code>FieldPosition</code>
195.64 + * object as an argument. You use this <code>format</code> method
195.65 + * to perform partial formatting or to get information about the
195.66 + * formatted output (such as the position of a field).
195.67 + *
195.68 + * <p>
195.69 + * If you are interested in the positions of all attributes in the
195.70 + * formatted string use the <code>Format</code> method
195.71 + * <code>formatToCharacterIterator</code>.
195.72 + *
195.73 + * @author Mark Davis
195.74 + * @see java.text.Format
195.75 + */
195.76 +public class FieldPosition {
195.77 +
195.78 + /**
195.79 + * Input: Desired field to determine start and end offsets for.
195.80 + * The meaning depends on the subclass of Format.
195.81 + */
195.82 + int field = 0;
195.83 +
195.84 + /**
195.85 + * Output: End offset of field in text.
195.86 + * If the field does not occur in the text, 0 is returned.
195.87 + */
195.88 + int endIndex = 0;
195.89 +
195.90 + /**
195.91 + * Output: Start offset of field in text.
195.92 + * If the field does not occur in the text, 0 is returned.
195.93 + */
195.94 + int beginIndex = 0;
195.95 +
195.96 + /**
195.97 + * Desired field this FieldPosition is for.
195.98 + */
195.99 + private Format.Field attribute;
195.100 +
195.101 + /**
195.102 + * Creates a FieldPosition object for the given field. Fields are
195.103 + * identified by constants, whose names typically end with _FIELD,
195.104 + * in the various subclasses of Format.
195.105 + *
195.106 + * @see java.text.NumberFormat#INTEGER_FIELD
195.107 + * @see java.text.NumberFormat#FRACTION_FIELD
195.108 + * @see java.text.DateFormat#YEAR_FIELD
195.109 + * @see java.text.DateFormat#MONTH_FIELD
195.110 + */
195.111 + public FieldPosition(int field) {
195.112 + this.field = field;
195.113 + }
195.114 +
195.115 + /**
195.116 + * Creates a FieldPosition object for the given field constant. Fields are
195.117 + * identified by constants defined in the various <code>Format</code>
195.118 + * subclasses. This is equivalent to calling
195.119 + * <code>new FieldPosition(attribute, -1)</code>.
195.120 + *
195.121 + * @param attribute Format.Field constant identifying a field
195.122 + * @since 1.4
195.123 + */
195.124 + public FieldPosition(Format.Field attribute) {
195.125 + this(attribute, -1);
195.126 + }
195.127 +
195.128 + /**
195.129 + * Creates a <code>FieldPosition</code> object for the given field.
195.130 + * The field is identified by an attribute constant from one of the
195.131 + * <code>Field</code> subclasses as well as an integer field ID
195.132 + * defined by the <code>Format</code> subclasses. <code>Format</code>
195.133 + * subclasses that are aware of <code>Field</code> should give precedence
195.134 + * to <code>attribute</code> and ignore <code>fieldID</code> if
195.135 + * <code>attribute</code> is not null. However, older <code>Format</code>
195.136 + * subclasses may not be aware of <code>Field</code> and rely on
195.137 + * <code>fieldID</code>. If the field has no corresponding integer
195.138 + * constant, <code>fieldID</code> should be -1.
195.139 + *
195.140 + * @param attribute Format.Field constant identifying a field
195.141 + * @param fieldID integer constantce identifying a field
195.142 + * @since 1.4
195.143 + */
195.144 + public FieldPosition(Format.Field attribute, int fieldID) {
195.145 + this.attribute = attribute;
195.146 + this.field = fieldID;
195.147 + }
195.148 +
195.149 + /**
195.150 + * Returns the field identifier as an attribute constant
195.151 + * from one of the <code>Field</code> subclasses. May return null if
195.152 + * the field is specified only by an integer field ID.
195.153 + *
195.154 + * @return Identifier for the field
195.155 + * @since 1.4
195.156 + */
195.157 + public Format.Field getFieldAttribute() {
195.158 + return attribute;
195.159 + }
195.160 +
195.161 + /**
195.162 + * Retrieves the field identifier.
195.163 + */
195.164 + public int getField() {
195.165 + return field;
195.166 + }
195.167 +
195.168 + /**
195.169 + * Retrieves the index of the first character in the requested field.
195.170 + */
195.171 + public int getBeginIndex() {
195.172 + return beginIndex;
195.173 + }
195.174 +
195.175 + /**
195.176 + * Retrieves the index of the character following the last character in the
195.177 + * requested field.
195.178 + */
195.179 + public int getEndIndex() {
195.180 + return endIndex;
195.181 + }
195.182 +
195.183 + /**
195.184 + * Sets the begin index. For use by subclasses of Format.
195.185 + * @since 1.2
195.186 + */
195.187 + public void setBeginIndex(int bi) {
195.188 + beginIndex = bi;
195.189 + }
195.190 +
195.191 + /**
195.192 + * Sets the end index. For use by subclasses of Format.
195.193 + * @since 1.2
195.194 + */
195.195 + public void setEndIndex(int ei) {
195.196 + endIndex = ei;
195.197 + }
195.198 +
195.199 + /**
195.200 + * Returns a <code>Format.FieldDelegate</code> instance that is associated
195.201 + * with the FieldPosition. When the delegate is notified of the same
195.202 + * field the FieldPosition is associated with, the begin/end will be
195.203 + * adjusted.
195.204 + */
195.205 + Format.FieldDelegate getFieldDelegate() {
195.206 + return new Delegate();
195.207 + }
195.208 +
195.209 + /**
195.210 + * Overrides equals
195.211 + */
195.212 + public boolean equals(Object obj)
195.213 + {
195.214 + if (obj == null) return false;
195.215 + if (!(obj instanceof FieldPosition))
195.216 + return false;
195.217 + FieldPosition other = (FieldPosition) obj;
195.218 + if (attribute == null) {
195.219 + if (other.attribute != null) {
195.220 + return false;
195.221 + }
195.222 + }
195.223 + else if (!attribute.equals(other.attribute)) {
195.224 + return false;
195.225 + }
195.226 + return (beginIndex == other.beginIndex
195.227 + && endIndex == other.endIndex
195.228 + && field == other.field);
195.229 + }
195.230 +
195.231 + /**
195.232 + * Returns a hash code for this FieldPosition.
195.233 + * @return a hash code value for this object
195.234 + */
195.235 + public int hashCode() {
195.236 + return (field << 24) | (beginIndex << 16) | endIndex;
195.237 + }
195.238 +
195.239 + /**
195.240 + * Return a string representation of this FieldPosition.
195.241 + * @return a string representation of this object
195.242 + */
195.243 + public String toString() {
195.244 + return getClass().getName() +
195.245 + "[field=" + field + ",attribute=" + attribute +
195.246 + ",beginIndex=" + beginIndex +
195.247 + ",endIndex=" + endIndex + ']';
195.248 + }
195.249 +
195.250 +
195.251 + /**
195.252 + * Return true if the receiver wants a <code>Format.Field</code> value and
195.253 + * <code>attribute</code> is equal to it.
195.254 + */
195.255 + private boolean matchesField(Format.Field attribute) {
195.256 + if (this.attribute != null) {
195.257 + return this.attribute.equals(attribute);
195.258 + }
195.259 + return false;
195.260 + }
195.261 +
195.262 + /**
195.263 + * Return true if the receiver wants a <code>Format.Field</code> value and
195.264 + * <code>attribute</code> is equal to it, or true if the receiver
195.265 + * represents an inteter constant and <code>field</code> equals it.
195.266 + */
195.267 + private boolean matchesField(Format.Field attribute, int field) {
195.268 + if (this.attribute != null) {
195.269 + return this.attribute.equals(attribute);
195.270 + }
195.271 + return (field == this.field);
195.272 + }
195.273 +
195.274 +
195.275 + /**
195.276 + * An implementation of FieldDelegate that will adjust the begin/end
195.277 + * of the FieldPosition if the arguments match the field of
195.278 + * the FieldPosition.
195.279 + */
195.280 + private class Delegate implements Format.FieldDelegate {
195.281 + /**
195.282 + * Indicates whether the field has been encountered before. If this
195.283 + * is true, and <code>formatted</code> is invoked, the begin/end
195.284 + * are not updated.
195.285 + */
195.286 + private boolean encounteredField;
195.287 +
195.288 + public void formatted(Format.Field attr, Object value, int start,
195.289 + int end, StringBuffer buffer) {
195.290 + if (!encounteredField && matchesField(attr)) {
195.291 + setBeginIndex(start);
195.292 + setEndIndex(end);
195.293 + encounteredField = (start != end);
195.294 + }
195.295 + }
195.296 +
195.297 + public void formatted(int fieldID, Format.Field attr, Object value,
195.298 + int start, int end, StringBuffer buffer) {
195.299 + if (!encounteredField && matchesField(attr, fieldID)) {
195.300 + setBeginIndex(start);
195.301 + setEndIndex(end);
195.302 + encounteredField = (start != end);
195.303 + }
195.304 + }
195.305 + }
195.306 +}
196.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
196.2 +++ b/rt/emul/compact/src/main/java/java/text/Format.java Wed Apr 30 15:04:10 2014 +0200
196.3 @@ -0,0 +1,406 @@
196.4 +/*
196.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
196.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
196.7 + *
196.8 + * This code is free software; you can redistribute it and/or modify it
196.9 + * under the terms of the GNU General Public License version 2 only, as
196.10 + * published by the Free Software Foundation. Oracle designates this
196.11 + * particular file as subject to the "Classpath" exception as provided
196.12 + * by Oracle in the LICENSE file that accompanied this code.
196.13 + *
196.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
196.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
196.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
196.17 + * version 2 for more details (a copy is included in the LICENSE file that
196.18 + * accompanied this code).
196.19 + *
196.20 + * You should have received a copy of the GNU General Public License version
196.21 + * 2 along with this work; if not, write to the Free Software Foundation,
196.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
196.23 + *
196.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
196.25 + * or visit www.oracle.com if you need additional information or have any
196.26 + * questions.
196.27 + */
196.28 +
196.29 +/*
196.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
196.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
196.32 + *
196.33 + * The original version of this source code and documentation is copyrighted
196.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
196.35 + * materials are provided under terms of a License Agreement between Taligent
196.36 + * and Sun. This technology is protected by multiple US and International
196.37 + * patents. This notice and attribution to Taligent may not be removed.
196.38 + * Taligent is a registered trademark of Taligent, Inc.
196.39 + *
196.40 + */
196.41 +
196.42 +package java.text;
196.43 +
196.44 +import java.io.Serializable;
196.45 +
196.46 +/**
196.47 + * <code>Format</code> is an abstract base class for formatting locale-sensitive
196.48 + * information such as dates, messages, and numbers.
196.49 + *
196.50 + * <p>
196.51 + * <code>Format</code> defines the programming interface for formatting
196.52 + * locale-sensitive objects into <code>String</code>s (the
196.53 + * <code>format</code> method) and for parsing <code>String</code>s back
196.54 + * into objects (the <code>parseObject</code> method).
196.55 + *
196.56 + * <p>
196.57 + * Generally, a format's <code>parseObject</code> method must be able to parse
196.58 + * any string formatted by its <code>format</code> method. However, there may
196.59 + * be exceptional cases where this is not possible. For example, a
196.60 + * <code>format</code> method might create two adjacent integer numbers with
196.61 + * no separator in between, and in this case the <code>parseObject</code> could
196.62 + * not tell which digits belong to which number.
196.63 + *
196.64 + * <h4>Subclassing</h4>
196.65 + *
196.66 + * <p>
196.67 + * The Java Platform provides three specialized subclasses of <code>Format</code>--
196.68 + * <code>DateFormat</code>, <code>MessageFormat</code>, and
196.69 + * <code>NumberFormat</code>--for formatting dates, messages, and numbers,
196.70 + * respectively.
196.71 + * <p>
196.72 + * Concrete subclasses must implement three methods:
196.73 + * <ol>
196.74 + * <li> <code>format(Object obj, StringBuffer toAppendTo, FieldPosition pos)</code>
196.75 + * <li> <code>formatToCharacterIterator(Object obj)</code>
196.76 + * <li> <code>parseObject(String source, ParsePosition pos)</code>
196.77 + * </ol>
196.78 + * These general methods allow polymorphic parsing and formatting of objects
196.79 + * and are used, for example, by <code>MessageFormat</code>.
196.80 + * Subclasses often also provide additional <code>format</code> methods for
196.81 + * specific input types as well as <code>parse</code> methods for specific
196.82 + * result types. Any <code>parse</code> method that does not take a
196.83 + * <code>ParsePosition</code> argument should throw <code>ParseException</code>
196.84 + * when no text in the required format is at the beginning of the input text.
196.85 + *
196.86 + * <p>
196.87 + * Most subclasses will also implement the following factory methods:
196.88 + * <ol>
196.89 + * <li>
196.90 + * <code>getInstance</code> for getting a useful format object appropriate
196.91 + * for the current locale
196.92 + * <li>
196.93 + * <code>getInstance(Locale)</code> for getting a useful format
196.94 + * object appropriate for the specified locale
196.95 + * </ol>
196.96 + * In addition, some subclasses may also implement other
196.97 + * <code>getXxxxInstance</code> methods for more specialized control. For
196.98 + * example, the <code>NumberFormat</code> class provides
196.99 + * <code>getPercentInstance</code> and <code>getCurrencyInstance</code>
196.100 + * methods for getting specialized number formatters.
196.101 + *
196.102 + * <p>
196.103 + * Subclasses of <code>Format</code> that allow programmers to create objects
196.104 + * for locales (with <code>getInstance(Locale)</code> for example)
196.105 + * must also implement the following class method:
196.106 + * <blockquote>
196.107 + * <pre>
196.108 + * public static Locale[] getAvailableLocales()
196.109 + * </pre>
196.110 + * </blockquote>
196.111 + *
196.112 + * <p>
196.113 + * And finally subclasses may define a set of constants to identify the various
196.114 + * fields in the formatted output. These constants are used to create a FieldPosition
196.115 + * object which identifies what information is contained in the field and its
196.116 + * position in the formatted result. These constants should be named
196.117 + * <code><em>item</em>_FIELD</code> where <code><em>item</em></code> identifies
196.118 + * the field. For examples of these constants, see <code>ERA_FIELD</code> and its
196.119 + * friends in {@link DateFormat}.
196.120 + *
196.121 + * <h4><a name="synchronization">Synchronization</a></h4>
196.122 + *
196.123 + * <p>
196.124 + * Formats are generally not synchronized.
196.125 + * It is recommended to create separate format instances for each thread.
196.126 + * If multiple threads access a format concurrently, it must be synchronized
196.127 + * externally.
196.128 + *
196.129 + * @see java.text.ParsePosition
196.130 + * @see java.text.FieldPosition
196.131 + * @see java.text.NumberFormat
196.132 + * @see java.text.DateFormat
196.133 + * @see java.text.MessageFormat
196.134 + * @author Mark Davis
196.135 + */
196.136 +public abstract class Format implements Serializable, Cloneable {
196.137 +
196.138 + private static final long serialVersionUID = -299282585814624189L;
196.139 +
196.140 + /**
196.141 + * Sole constructor. (For invocation by subclass constructors, typically
196.142 + * implicit.)
196.143 + */
196.144 + protected Format() {
196.145 + }
196.146 +
196.147 + /**
196.148 + * Formats an object to produce a string. This is equivalent to
196.149 + * <blockquote>
196.150 + * {@link #format(Object, StringBuffer, FieldPosition) format}<code>(obj,
196.151 + * new StringBuffer(), new FieldPosition(0)).toString();</code>
196.152 + * </blockquote>
196.153 + *
196.154 + * @param obj The object to format
196.155 + * @return Formatted string.
196.156 + * @exception IllegalArgumentException if the Format cannot format the given
196.157 + * object
196.158 + */
196.159 + public final String format (Object obj) {
196.160 + return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
196.161 + }
196.162 +
196.163 + /**
196.164 + * Formats an object and appends the resulting text to a given string
196.165 + * buffer.
196.166 + * If the <code>pos</code> argument identifies a field used by the format,
196.167 + * then its indices are set to the beginning and end of the first such
196.168 + * field encountered.
196.169 + *
196.170 + * @param obj The object to format
196.171 + * @param toAppendTo where the text is to be appended
196.172 + * @param pos A <code>FieldPosition</code> identifying a field
196.173 + * in the formatted text
196.174 + * @return the string buffer passed in as <code>toAppendTo</code>,
196.175 + * with formatted text appended
196.176 + * @exception NullPointerException if <code>toAppendTo</code> or
196.177 + * <code>pos</code> is null
196.178 + * @exception IllegalArgumentException if the Format cannot format the given
196.179 + * object
196.180 + */
196.181 + public abstract StringBuffer format(Object obj,
196.182 + StringBuffer toAppendTo,
196.183 + FieldPosition pos);
196.184 +
196.185 + /**
196.186 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
196.187 + * You can use the returned <code>AttributedCharacterIterator</code>
196.188 + * to build the resulting String, as well as to determine information
196.189 + * about the resulting String.
196.190 + * <p>
196.191 + * Each attribute key of the AttributedCharacterIterator will be of type
196.192 + * <code>Field</code>. It is up to each <code>Format</code> implementation
196.193 + * to define what the legal values are for each attribute in the
196.194 + * <code>AttributedCharacterIterator</code>, but typically the attribute
196.195 + * key is also used as the attribute value.
196.196 + * <p>The default implementation creates an
196.197 + * <code>AttributedCharacterIterator</code> with no attributes. Subclasses
196.198 + * that support fields should override this and create an
196.199 + * <code>AttributedCharacterIterator</code> with meaningful attributes.
196.200 + *
196.201 + * @exception NullPointerException if obj is null.
196.202 + * @exception IllegalArgumentException when the Format cannot format the
196.203 + * given object.
196.204 + * @param obj The object to format
196.205 + * @return AttributedCharacterIterator describing the formatted value.
196.206 + * @since 1.4
196.207 + */
196.208 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
196.209 + return createAttributedCharacterIterator(format(obj));
196.210 + }
196.211 +
196.212 + /**
196.213 + * Parses text from a string to produce an object.
196.214 + * <p>
196.215 + * The method attempts to parse text starting at the index given by
196.216 + * <code>pos</code>.
196.217 + * If parsing succeeds, then the index of <code>pos</code> is updated
196.218 + * to the index after the last character used (parsing does not necessarily
196.219 + * use all characters up to the end of the string), and the parsed
196.220 + * object is returned. The updated <code>pos</code> can be used to
196.221 + * indicate the starting point for the next call to this method.
196.222 + * If an error occurs, then the index of <code>pos</code> is not
196.223 + * changed, the error index of <code>pos</code> is set to the index of
196.224 + * the character where the error occurred, and null is returned.
196.225 + *
196.226 + * @param source A <code>String</code>, part of which should be parsed.
196.227 + * @param pos A <code>ParsePosition</code> object with index and error
196.228 + * index information as described above.
196.229 + * @return An <code>Object</code> parsed from the string. In case of
196.230 + * error, returns null.
196.231 + * @exception NullPointerException if <code>pos</code> is null.
196.232 + */
196.233 + public abstract Object parseObject (String source, ParsePosition pos);
196.234 +
196.235 + /**
196.236 + * Parses text from the beginning of the given string to produce an object.
196.237 + * The method may not use the entire text of the given string.
196.238 + *
196.239 + * @param source A <code>String</code> whose beginning should be parsed.
196.240 + * @return An <code>Object</code> parsed from the string.
196.241 + * @exception ParseException if the beginning of the specified string
196.242 + * cannot be parsed.
196.243 + */
196.244 + public Object parseObject(String source) throws ParseException {
196.245 + ParsePosition pos = new ParsePosition(0);
196.246 + Object result = parseObject(source, pos);
196.247 + if (pos.index == 0) {
196.248 + throw new ParseException("Format.parseObject(String) failed",
196.249 + pos.errorIndex);
196.250 + }
196.251 + return result;
196.252 + }
196.253 +
196.254 + /**
196.255 + * Creates and returns a copy of this object.
196.256 + *
196.257 + * @return a clone of this instance.
196.258 + */
196.259 + public Object clone() {
196.260 + try {
196.261 + return super.clone();
196.262 + } catch (CloneNotSupportedException e) {
196.263 + // will never happen
196.264 + return null;
196.265 + }
196.266 + }
196.267 +
196.268 + //
196.269 + // Convenience methods for creating AttributedCharacterIterators from
196.270 + // different parameters.
196.271 + //
196.272 +
196.273 + /**
196.274 + * Creates an <code>AttributedCharacterIterator</code> for the String
196.275 + * <code>s</code>.
196.276 + *
196.277 + * @param s String to create AttributedCharacterIterator from
196.278 + * @return AttributedCharacterIterator wrapping s
196.279 + */
196.280 + AttributedCharacterIterator createAttributedCharacterIterator(String s) {
196.281 + AttributedString as = new AttributedString(s);
196.282 +
196.283 + return as.getIterator();
196.284 + }
196.285 +
196.286 + /**
196.287 + * Creates an <code>AttributedCharacterIterator</code> containg the
196.288 + * concatenated contents of the passed in
196.289 + * <code>AttributedCharacterIterator</code>s.
196.290 + *
196.291 + * @param iterators AttributedCharacterIterators used to create resulting
196.292 + * AttributedCharacterIterators
196.293 + * @return AttributedCharacterIterator wrapping passed in
196.294 + * AttributedCharacterIterators
196.295 + */
196.296 + AttributedCharacterIterator createAttributedCharacterIterator(
196.297 + AttributedCharacterIterator[] iterators) {
196.298 + AttributedString as = new AttributedString(iterators);
196.299 +
196.300 + return as.getIterator();
196.301 + }
196.302 +
196.303 + /**
196.304 + * Returns an AttributedCharacterIterator with the String
196.305 + * <code>string</code> and additional key/value pair <code>key</code>,
196.306 + * <code>value</code>.
196.307 + *
196.308 + * @param string String to create AttributedCharacterIterator from
196.309 + * @param key Key for AttributedCharacterIterator
196.310 + * @param value Value associated with key in AttributedCharacterIterator
196.311 + * @return AttributedCharacterIterator wrapping args
196.312 + */
196.313 + AttributedCharacterIterator createAttributedCharacterIterator(
196.314 + String string, AttributedCharacterIterator.Attribute key,
196.315 + Object value) {
196.316 + AttributedString as = new AttributedString(string);
196.317 +
196.318 + as.addAttribute(key, value);
196.319 + return as.getIterator();
196.320 + }
196.321 +
196.322 + /**
196.323 + * Creates an AttributedCharacterIterator with the contents of
196.324 + * <code>iterator</code> and the additional attribute <code>key</code>
196.325 + * <code>value</code>.
196.326 + *
196.327 + * @param iterator Initial AttributedCharacterIterator to add arg to
196.328 + * @param key Key for AttributedCharacterIterator
196.329 + * @param value Value associated with key in AttributedCharacterIterator
196.330 + * @return AttributedCharacterIterator wrapping args
196.331 + */
196.332 + AttributedCharacterIterator createAttributedCharacterIterator(
196.333 + AttributedCharacterIterator iterator,
196.334 + AttributedCharacterIterator.Attribute key, Object value) {
196.335 + AttributedString as = new AttributedString(iterator);
196.336 +
196.337 + as.addAttribute(key, value);
196.338 + return as.getIterator();
196.339 + }
196.340 +
196.341 +
196.342 + /**
196.343 + * Defines constants that are used as attribute keys in the
196.344 + * <code>AttributedCharacterIterator</code> returned
196.345 + * from <code>Format.formatToCharacterIterator</code> and as
196.346 + * field identifiers in <code>FieldPosition</code>.
196.347 + *
196.348 + * @since 1.4
196.349 + */
196.350 + public static class Field extends AttributedCharacterIterator.Attribute {
196.351 +
196.352 + // Proclaim serial compatibility with 1.4 FCS
196.353 + private static final long serialVersionUID = 276966692217360283L;
196.354 +
196.355 + /**
196.356 + * Creates a Field with the specified name.
196.357 + *
196.358 + * @param name Name of the attribute
196.359 + */
196.360 + protected Field(String name) {
196.361 + super(name);
196.362 + }
196.363 + }
196.364 +
196.365 +
196.366 + /**
196.367 + * FieldDelegate is notified by the various <code>Format</code>
196.368 + * implementations as they are formatting the Objects. This allows for
196.369 + * storage of the individual sections of the formatted String for
196.370 + * later use, such as in a <code>FieldPosition</code> or for an
196.371 + * <code>AttributedCharacterIterator</code>.
196.372 + * <p>
196.373 + * Delegates should NOT assume that the <code>Format</code> will notify
196.374 + * the delegate of fields in any particular order.
196.375 + *
196.376 + * @see FieldPosition.Delegate
196.377 + * @see CharacterIteratorFieldDelegate
196.378 + */
196.379 + interface FieldDelegate {
196.380 + /**
196.381 + * Notified when a particular region of the String is formatted. This
196.382 + * method will be invoked if there is no corresponding integer field id
196.383 + * matching <code>attr</code>.
196.384 + *
196.385 + * @param attr Identifies the field matched
196.386 + * @param value Value associated with the field
196.387 + * @param start Beginning location of the field, will be >= 0
196.388 + * @param end End of the field, will be >= start and <= buffer.length()
196.389 + * @param buffer Contains current formatted value, receiver should
196.390 + * NOT modify it.
196.391 + */
196.392 + public void formatted(Format.Field attr, Object value, int start,
196.393 + int end, StringBuffer buffer);
196.394 +
196.395 + /**
196.396 + * Notified when a particular region of the String is formatted.
196.397 + *
196.398 + * @param fieldID Identifies the field by integer
196.399 + * @param attr Identifies the field matched
196.400 + * @param value Value associated with the field
196.401 + * @param start Beginning location of the field, will be >= 0
196.402 + * @param end End of the field, will be >= start and <= buffer.length()
196.403 + * @param buffer Contains current formatted value, receiver should
196.404 + * NOT modify it.
196.405 + */
196.406 + public void formatted(int fieldID, Format.Field attr, Object value,
196.407 + int start, int end, StringBuffer buffer);
196.408 + }
196.409 +}
197.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
197.2 +++ b/rt/emul/compact/src/main/java/java/text/MessageFormat.java Wed Apr 30 15:04:10 2014 +0200
197.3 @@ -0,0 +1,1594 @@
197.4 +/*
197.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
197.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
197.7 + *
197.8 + * This code is free software; you can redistribute it and/or modify it
197.9 + * under the terms of the GNU General Public License version 2 only, as
197.10 + * published by the Free Software Foundation. Oracle designates this
197.11 + * particular file as subject to the "Classpath" exception as provided
197.12 + * by Oracle in the LICENSE file that accompanied this code.
197.13 + *
197.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
197.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
197.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
197.17 + * version 2 for more details (a copy is included in the LICENSE file that
197.18 + * accompanied this code).
197.19 + *
197.20 + * You should have received a copy of the GNU General Public License version
197.21 + * 2 along with this work; if not, write to the Free Software Foundation,
197.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
197.23 + *
197.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
197.25 + * or visit www.oracle.com if you need additional information or have any
197.26 + * questions.
197.27 + */
197.28 +
197.29 +/*
197.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
197.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
197.32 + *
197.33 + * The original version of this source code and documentation is copyrighted
197.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
197.35 + * materials are provided under terms of a License Agreement between Taligent
197.36 + * and Sun. This technology is protected by multiple US and International
197.37 + * patents. This notice and attribution to Taligent may not be removed.
197.38 + * Taligent is a registered trademark of Taligent, Inc.
197.39 + *
197.40 + */
197.41 +
197.42 +package java.text;
197.43 +
197.44 +import java.io.InvalidObjectException;
197.45 +import java.io.IOException;
197.46 +import java.io.ObjectInputStream;
197.47 +import java.text.DecimalFormat;
197.48 +import java.util.ArrayList;
197.49 +import java.util.Arrays;
197.50 +import java.util.Date;
197.51 +import java.util.List;
197.52 +import java.util.Locale;
197.53 +
197.54 +
197.55 +/**
197.56 + * <code>MessageFormat</code> provides a means to produce concatenated
197.57 + * messages in a language-neutral way. Use this to construct messages
197.58 + * displayed for end users.
197.59 + *
197.60 + * <p>
197.61 + * <code>MessageFormat</code> takes a set of objects, formats them, then
197.62 + * inserts the formatted strings into the pattern at the appropriate places.
197.63 + *
197.64 + * <p>
197.65 + * <strong>Note:</strong>
197.66 + * <code>MessageFormat</code> differs from the other <code>Format</code>
197.67 + * classes in that you create a <code>MessageFormat</code> object with one
197.68 + * of its constructors (not with a <code>getInstance</code> style factory
197.69 + * method). The factory methods aren't necessary because <code>MessageFormat</code>
197.70 + * itself doesn't implement locale specific behavior. Any locale specific
197.71 + * behavior is defined by the pattern that you provide as well as the
197.72 + * subformats used for inserted arguments.
197.73 + *
197.74 + * <h4><a name="patterns">Patterns and Their Interpretation</a></h4>
197.75 + *
197.76 + * <code>MessageFormat</code> uses patterns of the following form:
197.77 + * <blockquote><pre>
197.78 + * <i>MessageFormatPattern:</i>
197.79 + * <i>String</i>
197.80 + * <i>MessageFormatPattern</i> <i>FormatElement</i> <i>String</i>
197.81 + *
197.82 + * <i>FormatElement:</i>
197.83 + * { <i>ArgumentIndex</i> }
197.84 + * { <i>ArgumentIndex</i> , <i>FormatType</i> }
197.85 + * { <i>ArgumentIndex</i> , <i>FormatType</i> , <i>FormatStyle</i> }
197.86 + *
197.87 + * <i>FormatType: one of </i>
197.88 + * number date time choice
197.89 + *
197.90 + * <i>FormatStyle:</i>
197.91 + * short
197.92 + * medium
197.93 + * long
197.94 + * full
197.95 + * integer
197.96 + * currency
197.97 + * percent
197.98 + * <i>SubformatPattern</i>
197.99 + * </pre></blockquote>
197.100 + *
197.101 + * <p>Within a <i>String</i>, a pair of single quotes can be used to
197.102 + * quote any arbitrary characters except single quotes. For example,
197.103 + * pattern string <code>"'{0}'"</code> represents string
197.104 + * <code>"{0}"</code>, not a <i>FormatElement</i>. A single quote itself
197.105 + * must be represented by doubled single quotes {@code ''} throughout a
197.106 + * <i>String</i>. For example, pattern string <code>"'{''}'"</code> is
197.107 + * interpreted as a sequence of <code>'{</code> (start of quoting and a
197.108 + * left curly brace), <code>''</code> (a single quote), and
197.109 + * <code>}'</code> (a right curly brace and end of quoting),
197.110 + * <em>not</em> <code>'{'</code> and <code>'}'</code> (quoted left and
197.111 + * right curly braces): representing string <code>"{'}"</code>,
197.112 + * <em>not</em> <code>"{}"</code>.
197.113 + *
197.114 + * <p>A <i>SubformatPattern</i> is interpreted by its corresponding
197.115 + * subformat, and subformat-dependent pattern rules apply. For example,
197.116 + * pattern string <code>"{1,number,<u>$'#',##</u>}"</code>
197.117 + * (<i>SubformatPattern</i> with underline) will produce a number format
197.118 + * with the pound-sign quoted, with a result such as: {@code
197.119 + * "$#31,45"}. Refer to each {@code Format} subclass documentation for
197.120 + * details.
197.121 + *
197.122 + * <p>Any unmatched quote is treated as closed at the end of the given
197.123 + * pattern. For example, pattern string {@code "'{0}"} is treated as
197.124 + * pattern {@code "'{0}'"}.
197.125 + *
197.126 + * <p>Any curly braces within an unquoted pattern must be balanced. For
197.127 + * example, <code>"ab {0} de"</code> and <code>"ab '}' de"</code> are
197.128 + * valid patterns, but <code>"ab {0'}' de"</code>, <code>"ab } de"</code>
197.129 + * and <code>"''{''"</code> are not.
197.130 + *
197.131 + * <p>
197.132 + * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
197.133 + * format patterns unfortunately have shown to be somewhat confusing.
197.134 + * In particular, it isn't always obvious to localizers whether single
197.135 + * quotes need to be doubled or not. Make sure to inform localizers about
197.136 + * the rules, and tell them (for example, by using comments in resource
197.137 + * bundle source files) which strings will be processed by {@code MessageFormat}.
197.138 + * Note that localizers may need to use single quotes in translated
197.139 + * strings where the original version doesn't have them.
197.140 + * </dl>
197.141 + * <p>
197.142 + * The <i>ArgumentIndex</i> value is a non-negative integer written
197.143 + * using the digits {@code '0'} through {@code '9'}, and represents an index into the
197.144 + * {@code arguments} array passed to the {@code format} methods
197.145 + * or the result array returned by the {@code parse} methods.
197.146 + * <p>
197.147 + * The <i>FormatType</i> and <i>FormatStyle</i> values are used to create
197.148 + * a {@code Format} instance for the format element. The following
197.149 + * table shows how the values map to {@code Format} instances. Combinations not
197.150 + * shown in the table are illegal. A <i>SubformatPattern</i> must
197.151 + * be a valid pattern string for the {@code Format} subclass used.
197.152 + * <p>
197.153 + * <table border=1 summary="Shows how FormatType and FormatStyle values map to Format instances">
197.154 + * <tr>
197.155 + * <th id="ft" class="TableHeadingColor">FormatType
197.156 + * <th id="fs" class="TableHeadingColor">FormatStyle
197.157 + * <th id="sc" class="TableHeadingColor">Subformat Created
197.158 + * <tr>
197.159 + * <td headers="ft"><i>(none)</i>
197.160 + * <td headers="fs"><i>(none)</i>
197.161 + * <td headers="sc"><code>null</code>
197.162 + * <tr>
197.163 + * <td headers="ft" rowspan=5><code>number</code>
197.164 + * <td headers="fs"><i>(none)</i>
197.165 + * <td headers="sc">{@link NumberFormat#getInstance(Locale) NumberFormat.getInstance}{@code (getLocale())}
197.166 + * <tr>
197.167 + * <td headers="fs"><code>integer</code>
197.168 + * <td headers="sc">{@link NumberFormat#getIntegerInstance(Locale) NumberFormat.getIntegerInstance}{@code (getLocale())}
197.169 + * <tr>
197.170 + * <td headers="fs"><code>currency</code>
197.171 + * <td headers="sc">{@link NumberFormat#getCurrencyInstance(Locale) NumberFormat.getCurrencyInstance}{@code (getLocale())}
197.172 + * <tr>
197.173 + * <td headers="fs"><code>percent</code>
197.174 + * <td headers="sc">{@link NumberFormat#getPercentInstance(Locale) NumberFormat.getPercentInstance}{@code (getLocale())}
197.175 + * <tr>
197.176 + * <td headers="fs"><i>SubformatPattern</i>
197.177 + * <td headers="sc">{@code new} {@link DecimalFormat#DecimalFormat(String,DecimalFormatSymbols) DecimalFormat}{@code (subformatPattern,} {@link DecimalFormatSymbols#getInstance(Locale) DecimalFormatSymbols.getInstance}{@code (getLocale()))}
197.178 + * <tr>
197.179 + * <td headers="ft" rowspan=6><code>date</code>
197.180 + * <td headers="fs"><i>(none)</i>
197.181 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
197.182 + * <tr>
197.183 + * <td headers="fs"><code>short</code>
197.184 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
197.185 + * <tr>
197.186 + * <td headers="fs"><code>medium</code>
197.187 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
197.188 + * <tr>
197.189 + * <td headers="fs"><code>long</code>
197.190 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
197.191 + * <tr>
197.192 + * <td headers="fs"><code>full</code>
197.193 + * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
197.194 + * <tr>
197.195 + * <td headers="fs"><i>SubformatPattern</i>
197.196 + * <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
197.197 + * <tr>
197.198 + * <td headers="ft" rowspan=6><code>time</code>
197.199 + * <td headers="fs"><i>(none)</i>
197.200 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
197.201 + * <tr>
197.202 + * <td headers="fs"><code>short</code>
197.203 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
197.204 + * <tr>
197.205 + * <td headers="fs"><code>medium</code>
197.206 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
197.207 + * <tr>
197.208 + * <td headers="fs"><code>long</code>
197.209 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
197.210 + * <tr>
197.211 + * <td headers="fs"><code>full</code>
197.212 + * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
197.213 + * <tr>
197.214 + * <td headers="fs"><i>SubformatPattern</i>
197.215 + * <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
197.216 + * <tr>
197.217 + * <td headers="ft"><code>choice</code>
197.218 + * <td headers="fs"><i>SubformatPattern</i>
197.219 + * <td headers="sc">{@code new} {@link ChoiceFormat#ChoiceFormat(String) ChoiceFormat}{@code (subformatPattern)}
197.220 + * </table>
197.221 + * <p>
197.222 + *
197.223 + * <h4>Usage Information</h4>
197.224 + *
197.225 + * <p>
197.226 + * Here are some examples of usage.
197.227 + * In real internationalized programs, the message format pattern and other
197.228 + * static strings will, of course, be obtained from resource bundles.
197.229 + * Other parameters will be dynamically determined at runtime.
197.230 + * <p>
197.231 + * The first example uses the static method <code>MessageFormat.format</code>,
197.232 + * which internally creates a <code>MessageFormat</code> for one-time use:
197.233 + * <blockquote><pre>
197.234 + * int planet = 7;
197.235 + * String event = "a disturbance in the Force";
197.236 + *
197.237 + * String result = MessageFormat.format(
197.238 + * "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
197.239 + * planet, new Date(), event);
197.240 + * </pre></blockquote>
197.241 + * The output is:
197.242 + * <blockquote><pre>
197.243 + * At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
197.244 + * </pre></blockquote>
197.245 + *
197.246 + * <p>
197.247 + * The following example creates a <code>MessageFormat</code> instance that
197.248 + * can be used repeatedly:
197.249 + * <blockquote><pre>
197.250 + * int fileCount = 1273;
197.251 + * String diskName = "MyDisk";
197.252 + * Object[] testArgs = {new Long(fileCount), diskName};
197.253 + *
197.254 + * MessageFormat form = new MessageFormat(
197.255 + * "The disk \"{1}\" contains {0} file(s).");
197.256 + *
197.257 + * System.out.println(form.format(testArgs));
197.258 + * </pre></blockquote>
197.259 + * The output with different values for <code>fileCount</code>:
197.260 + * <blockquote><pre>
197.261 + * The disk "MyDisk" contains 0 file(s).
197.262 + * The disk "MyDisk" contains 1 file(s).
197.263 + * The disk "MyDisk" contains 1,273 file(s).
197.264 + * </pre></blockquote>
197.265 + *
197.266 + * <p>
197.267 + * For more sophisticated patterns, you can use a <code>ChoiceFormat</code>
197.268 + * to produce correct forms for singular and plural:
197.269 + * <blockquote><pre>
197.270 + * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
197.271 + * double[] filelimits = {0,1,2};
197.272 + * String[] filepart = {"no files","one file","{0,number} files"};
197.273 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
197.274 + * form.setFormatByArgumentIndex(0, fileform);
197.275 + *
197.276 + * int fileCount = 1273;
197.277 + * String diskName = "MyDisk";
197.278 + * Object[] testArgs = {new Long(fileCount), diskName};
197.279 + *
197.280 + * System.out.println(form.format(testArgs));
197.281 + * </pre></blockquote>
197.282 + * The output with different values for <code>fileCount</code>:
197.283 + * <blockquote><pre>
197.284 + * The disk "MyDisk" contains no files.
197.285 + * The disk "MyDisk" contains one file.
197.286 + * The disk "MyDisk" contains 1,273 files.
197.287 + * </pre></blockquote>
197.288 + *
197.289 + * <p>
197.290 + * You can create the <code>ChoiceFormat</code> programmatically, as in the
197.291 + * above example, or by using a pattern. See {@link ChoiceFormat}
197.292 + * for more information.
197.293 + * <blockquote><pre>
197.294 + * form.applyPattern(
197.295 + * "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.");
197.296 + * </pre></blockquote>
197.297 + *
197.298 + * <p>
197.299 + * <strong>Note:</strong> As we see above, the string produced
197.300 + * by a <code>ChoiceFormat</code> in <code>MessageFormat</code> is treated as special;
197.301 + * occurrences of '{' are used to indicate subformats, and cause recursion.
197.302 + * If you create both a <code>MessageFormat</code> and <code>ChoiceFormat</code>
197.303 + * programmatically (instead of using the string patterns), then be careful not to
197.304 + * produce a format that recurses on itself, which will cause an infinite loop.
197.305 + * <p>
197.306 + * When a single argument is parsed more than once in the string, the last match
197.307 + * will be the final result of the parsing. For example,
197.308 + * <blockquote><pre>
197.309 + * MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
197.310 + * Object[] objs = {new Double(3.1415)};
197.311 + * String result = mf.format( objs );
197.312 + * // result now equals "3.14, 3.1"
197.313 + * objs = null;
197.314 + * objs = mf.parse(result, new ParsePosition(0));
197.315 + * // objs now equals {new Double(3.1)}
197.316 + * </pre></blockquote>
197.317 + *
197.318 + * <p>
197.319 + * Likewise, parsing with a {@code MessageFormat} object using patterns containing
197.320 + * multiple occurrences of the same argument would return the last match. For
197.321 + * example,
197.322 + * <blockquote><pre>
197.323 + * MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
197.324 + * String forParsing = "x, y, z";
197.325 + * Object[] objs = mf.parse(forParsing, new ParsePosition(0));
197.326 + * // result now equals {new String("z")}
197.327 + * </pre></blockquote>
197.328 + *
197.329 + * <h4><a name="synchronization">Synchronization</a></h4>
197.330 + *
197.331 + * <p>
197.332 + * Message formats are not synchronized.
197.333 + * It is recommended to create separate format instances for each thread.
197.334 + * If multiple threads access a format concurrently, it must be synchronized
197.335 + * externally.
197.336 + *
197.337 + * @see java.util.Locale
197.338 + * @see Format
197.339 + * @see NumberFormat
197.340 + * @see DecimalFormat
197.341 + * @see DecimalFormatSymbols
197.342 + * @see ChoiceFormat
197.343 + * @see DateFormat
197.344 + * @see SimpleDateFormat
197.345 + *
197.346 + * @author Mark Davis
197.347 + */
197.348 +
197.349 +public class MessageFormat extends Format {
197.350 +
197.351 + private static final long serialVersionUID = 6479157306784022952L;
197.352 +
197.353 + /**
197.354 + * Constructs a MessageFormat for the default locale and the
197.355 + * specified pattern.
197.356 + * The constructor first sets the locale, then parses the pattern and
197.357 + * creates a list of subformats for the format elements contained in it.
197.358 + * Patterns and their interpretation are specified in the
197.359 + * <a href="#patterns">class description</a>.
197.360 + *
197.361 + * @param pattern the pattern for this message format
197.362 + * @exception IllegalArgumentException if the pattern is invalid
197.363 + */
197.364 + public MessageFormat(String pattern) {
197.365 + this.locale = Locale.getDefault(Locale.Category.FORMAT);
197.366 + applyPattern(pattern);
197.367 + }
197.368 +
197.369 + /**
197.370 + * Constructs a MessageFormat for the specified locale and
197.371 + * pattern.
197.372 + * The constructor first sets the locale, then parses the pattern and
197.373 + * creates a list of subformats for the format elements contained in it.
197.374 + * Patterns and their interpretation are specified in the
197.375 + * <a href="#patterns">class description</a>.
197.376 + *
197.377 + * @param pattern the pattern for this message format
197.378 + * @param locale the locale for this message format
197.379 + * @exception IllegalArgumentException if the pattern is invalid
197.380 + * @since 1.4
197.381 + */
197.382 + public MessageFormat(String pattern, Locale locale) {
197.383 + this.locale = locale;
197.384 + applyPattern(pattern);
197.385 + }
197.386 +
197.387 + /**
197.388 + * Sets the locale to be used when creating or comparing subformats.
197.389 + * This affects subsequent calls
197.390 + * <ul>
197.391 + * <li>to the {@link #applyPattern applyPattern}
197.392 + * and {@link #toPattern toPattern} methods if format elements specify
197.393 + * a format type and therefore have the subformats created in the
197.394 + * <code>applyPattern</code> method, as well as
197.395 + * <li>to the <code>format</code> and
197.396 + * {@link #formatToCharacterIterator formatToCharacterIterator} methods
197.397 + * if format elements do not specify a format type and therefore have
197.398 + * the subformats created in the formatting methods.
197.399 + * </ul>
197.400 + * Subformats that have already been created are not affected.
197.401 + *
197.402 + * @param locale the locale to be used when creating or comparing subformats
197.403 + */
197.404 + public void setLocale(Locale locale) {
197.405 + this.locale = locale;
197.406 + }
197.407 +
197.408 + /**
197.409 + * Gets the locale that's used when creating or comparing subformats.
197.410 + *
197.411 + * @return the locale used when creating or comparing subformats
197.412 + */
197.413 + public Locale getLocale() {
197.414 + return locale;
197.415 + }
197.416 +
197.417 +
197.418 + /**
197.419 + * Sets the pattern used by this message format.
197.420 + * The method parses the pattern and creates a list of subformats
197.421 + * for the format elements contained in it.
197.422 + * Patterns and their interpretation are specified in the
197.423 + * <a href="#patterns">class description</a>.
197.424 + *
197.425 + * @param pattern the pattern for this message format
197.426 + * @exception IllegalArgumentException if the pattern is invalid
197.427 + */
197.428 + public void applyPattern(String pattern) {
197.429 + StringBuilder[] segments = new StringBuilder[4];
197.430 + // Allocate only segments[SEG_RAW] here. The rest are
197.431 + // allocated on demand.
197.432 + segments[SEG_RAW] = new StringBuilder();
197.433 +
197.434 + int part = SEG_RAW;
197.435 + int formatNumber = 0;
197.436 + boolean inQuote = false;
197.437 + int braceStack = 0;
197.438 + maxOffset = -1;
197.439 + for (int i = 0; i < pattern.length(); ++i) {
197.440 + char ch = pattern.charAt(i);
197.441 + if (part == SEG_RAW) {
197.442 + if (ch == '\'') {
197.443 + if (i + 1 < pattern.length()
197.444 + && pattern.charAt(i+1) == '\'') {
197.445 + segments[part].append(ch); // handle doubles
197.446 + ++i;
197.447 + } else {
197.448 + inQuote = !inQuote;
197.449 + }
197.450 + } else if (ch == '{' && !inQuote) {
197.451 + part = SEG_INDEX;
197.452 + if (segments[SEG_INDEX] == null) {
197.453 + segments[SEG_INDEX] = new StringBuilder();
197.454 + }
197.455 + } else {
197.456 + segments[part].append(ch);
197.457 + }
197.458 + } else {
197.459 + if (inQuote) { // just copy quotes in parts
197.460 + segments[part].append(ch);
197.461 + if (ch == '\'') {
197.462 + inQuote = false;
197.463 + }
197.464 + } else {
197.465 + switch (ch) {
197.466 + case ',':
197.467 + if (part < SEG_MODIFIER) {
197.468 + if (segments[++part] == null) {
197.469 + segments[part] = new StringBuilder();
197.470 + }
197.471 + } else {
197.472 + segments[part].append(ch);
197.473 + }
197.474 + break;
197.475 + case '{':
197.476 + ++braceStack;
197.477 + segments[part].append(ch);
197.478 + break;
197.479 + case '}':
197.480 + if (braceStack == 0) {
197.481 + part = SEG_RAW;
197.482 + makeFormat(i, formatNumber, segments);
197.483 + formatNumber++;
197.484 + // throw away other segments
197.485 + segments[SEG_INDEX] = null;
197.486 + segments[SEG_TYPE] = null;
197.487 + segments[SEG_MODIFIER] = null;
197.488 + } else {
197.489 + --braceStack;
197.490 + segments[part].append(ch);
197.491 + }
197.492 + break;
197.493 + case ' ':
197.494 + // Skip any leading space chars for SEG_TYPE.
197.495 + if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
197.496 + segments[part].append(ch);
197.497 + }
197.498 + break;
197.499 + case '\'':
197.500 + inQuote = true;
197.501 + // fall through, so we keep quotes in other parts
197.502 + default:
197.503 + segments[part].append(ch);
197.504 + break;
197.505 + }
197.506 + }
197.507 + }
197.508 + }
197.509 + if (braceStack == 0 && part != 0) {
197.510 + maxOffset = -1;
197.511 + throw new IllegalArgumentException("Unmatched braces in the pattern.");
197.512 + }
197.513 + this.pattern = segments[0].toString();
197.514 + }
197.515 +
197.516 +
197.517 + /**
197.518 + * Returns a pattern representing the current state of the message format.
197.519 + * The string is constructed from internal information and therefore
197.520 + * does not necessarily equal the previously applied pattern.
197.521 + *
197.522 + * @return a pattern representing the current state of the message format
197.523 + */
197.524 + public String toPattern() {
197.525 + // later, make this more extensible
197.526 + int lastOffset = 0;
197.527 + StringBuilder result = new StringBuilder();
197.528 + for (int i = 0; i <= maxOffset; ++i) {
197.529 + copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
197.530 + lastOffset = offsets[i];
197.531 + result.append('{').append(argumentNumbers[i]);
197.532 + Format fmt = formats[i];
197.533 + if (fmt == null) {
197.534 + // do nothing, string format
197.535 + } else if (fmt instanceof NumberFormat) {
197.536 + if (fmt.equals(NumberFormat.getInstance(locale))) {
197.537 + result.append(",number");
197.538 + } else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
197.539 + result.append(",number,currency");
197.540 + } else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
197.541 + result.append(",number,percent");
197.542 + } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
197.543 + result.append(",number,integer");
197.544 + } else {
197.545 + if (fmt instanceof DecimalFormat) {
197.546 + result.append(",number,").append(((DecimalFormat)fmt).toPattern());
197.547 + } else if (fmt instanceof ChoiceFormat) {
197.548 + result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
197.549 + } else {
197.550 + // UNKNOWN
197.551 + }
197.552 + }
197.553 + } else if (fmt instanceof DateFormat) {
197.554 + int index;
197.555 + for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
197.556 + DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
197.557 + locale);
197.558 + if (fmt.equals(df)) {
197.559 + result.append(",date");
197.560 + break;
197.561 + }
197.562 + df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
197.563 + locale);
197.564 + if (fmt.equals(df)) {
197.565 + result.append(",time");
197.566 + break;
197.567 + }
197.568 + }
197.569 + if (index >= DATE_TIME_MODIFIERS.length) {
197.570 + if (fmt instanceof SimpleDateFormat) {
197.571 + result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
197.572 + } else {
197.573 + // UNKNOWN
197.574 + }
197.575 + } else if (index != MODIFIER_DEFAULT) {
197.576 + result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
197.577 + }
197.578 + } else {
197.579 + //result.append(", unknown");
197.580 + }
197.581 + result.append('}');
197.582 + }
197.583 + copyAndFixQuotes(pattern, lastOffset, pattern.length(), result);
197.584 + return result.toString();
197.585 + }
197.586 +
197.587 + /**
197.588 + * Sets the formats to use for the values passed into
197.589 + * <code>format</code> methods or returned from <code>parse</code>
197.590 + * methods. The indices of elements in <code>newFormats</code>
197.591 + * correspond to the argument indices used in the previously set
197.592 + * pattern string.
197.593 + * The order of formats in <code>newFormats</code> thus corresponds to
197.594 + * the order of elements in the <code>arguments</code> array passed
197.595 + * to the <code>format</code> methods or the result array returned
197.596 + * by the <code>parse</code> methods.
197.597 + * <p>
197.598 + * If an argument index is used for more than one format element
197.599 + * in the pattern string, then the corresponding new format is used
197.600 + * for all such format elements. If an argument index is not used
197.601 + * for any format element in the pattern string, then the
197.602 + * corresponding new format is ignored. If fewer formats are provided
197.603 + * than needed, then only the formats for argument indices less
197.604 + * than <code>newFormats.length</code> are replaced.
197.605 + *
197.606 + * @param newFormats the new formats to use
197.607 + * @exception NullPointerException if <code>newFormats</code> is null
197.608 + * @since 1.4
197.609 + */
197.610 + public void setFormatsByArgumentIndex(Format[] newFormats) {
197.611 + for (int i = 0; i <= maxOffset; i++) {
197.612 + int j = argumentNumbers[i];
197.613 + if (j < newFormats.length) {
197.614 + formats[i] = newFormats[j];
197.615 + }
197.616 + }
197.617 + }
197.618 +
197.619 + /**
197.620 + * Sets the formats to use for the format elements in the
197.621 + * previously set pattern string.
197.622 + * The order of formats in <code>newFormats</code> corresponds to
197.623 + * the order of format elements in the pattern string.
197.624 + * <p>
197.625 + * If more formats are provided than needed by the pattern string,
197.626 + * the remaining ones are ignored. If fewer formats are provided
197.627 + * than needed, then only the first <code>newFormats.length</code>
197.628 + * formats are replaced.
197.629 + * <p>
197.630 + * Since the order of format elements in a pattern string often
197.631 + * changes during localization, it is generally better to use the
197.632 + * {@link #setFormatsByArgumentIndex setFormatsByArgumentIndex}
197.633 + * method, which assumes an order of formats corresponding to the
197.634 + * order of elements in the <code>arguments</code> array passed to
197.635 + * the <code>format</code> methods or the result array returned by
197.636 + * the <code>parse</code> methods.
197.637 + *
197.638 + * @param newFormats the new formats to use
197.639 + * @exception NullPointerException if <code>newFormats</code> is null
197.640 + */
197.641 + public void setFormats(Format[] newFormats) {
197.642 + int runsToCopy = newFormats.length;
197.643 + if (runsToCopy > maxOffset + 1) {
197.644 + runsToCopy = maxOffset + 1;
197.645 + }
197.646 + for (int i = 0; i < runsToCopy; i++) {
197.647 + formats[i] = newFormats[i];
197.648 + }
197.649 + }
197.650 +
197.651 + /**
197.652 + * Sets the format to use for the format elements within the
197.653 + * previously set pattern string that use the given argument
197.654 + * index.
197.655 + * The argument index is part of the format element definition and
197.656 + * represents an index into the <code>arguments</code> array passed
197.657 + * to the <code>format</code> methods or the result array returned
197.658 + * by the <code>parse</code> methods.
197.659 + * <p>
197.660 + * If the argument index is used for more than one format element
197.661 + * in the pattern string, then the new format is used for all such
197.662 + * format elements. If the argument index is not used for any format
197.663 + * element in the pattern string, then the new format is ignored.
197.664 + *
197.665 + * @param argumentIndex the argument index for which to use the new format
197.666 + * @param newFormat the new format to use
197.667 + * @since 1.4
197.668 + */
197.669 + public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
197.670 + for (int j = 0; j <= maxOffset; j++) {
197.671 + if (argumentNumbers[j] == argumentIndex) {
197.672 + formats[j] = newFormat;
197.673 + }
197.674 + }
197.675 + }
197.676 +
197.677 + /**
197.678 + * Sets the format to use for the format element with the given
197.679 + * format element index within the previously set pattern string.
197.680 + * The format element index is the zero-based number of the format
197.681 + * element counting from the start of the pattern string.
197.682 + * <p>
197.683 + * Since the order of format elements in a pattern string often
197.684 + * changes during localization, it is generally better to use the
197.685 + * {@link #setFormatByArgumentIndex setFormatByArgumentIndex}
197.686 + * method, which accesses format elements based on the argument
197.687 + * index they specify.
197.688 + *
197.689 + * @param formatElementIndex the index of a format element within the pattern
197.690 + * @param newFormat the format to use for the specified format element
197.691 + * @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
197.692 + * larger than the number of format elements in the pattern string
197.693 + */
197.694 + public void setFormat(int formatElementIndex, Format newFormat) {
197.695 + formats[formatElementIndex] = newFormat;
197.696 + }
197.697 +
197.698 + /**
197.699 + * Gets the formats used for the values passed into
197.700 + * <code>format</code> methods or returned from <code>parse</code>
197.701 + * methods. The indices of elements in the returned array
197.702 + * correspond to the argument indices used in the previously set
197.703 + * pattern string.
197.704 + * The order of formats in the returned array thus corresponds to
197.705 + * the order of elements in the <code>arguments</code> array passed
197.706 + * to the <code>format</code> methods or the result array returned
197.707 + * by the <code>parse</code> methods.
197.708 + * <p>
197.709 + * If an argument index is used for more than one format element
197.710 + * in the pattern string, then the format used for the last such
197.711 + * format element is returned in the array. If an argument index
197.712 + * is not used for any format element in the pattern string, then
197.713 + * null is returned in the array.
197.714 + *
197.715 + * @return the formats used for the arguments within the pattern
197.716 + * @since 1.4
197.717 + */
197.718 + public Format[] getFormatsByArgumentIndex() {
197.719 + int maximumArgumentNumber = -1;
197.720 + for (int i = 0; i <= maxOffset; i++) {
197.721 + if (argumentNumbers[i] > maximumArgumentNumber) {
197.722 + maximumArgumentNumber = argumentNumbers[i];
197.723 + }
197.724 + }
197.725 + Format[] resultArray = new Format[maximumArgumentNumber + 1];
197.726 + for (int i = 0; i <= maxOffset; i++) {
197.727 + resultArray[argumentNumbers[i]] = formats[i];
197.728 + }
197.729 + return resultArray;
197.730 + }
197.731 +
197.732 + /**
197.733 + * Gets the formats used for the format elements in the
197.734 + * previously set pattern string.
197.735 + * The order of formats in the returned array corresponds to
197.736 + * the order of format elements in the pattern string.
197.737 + * <p>
197.738 + * Since the order of format elements in a pattern string often
197.739 + * changes during localization, it's generally better to use the
197.740 + * {@link #getFormatsByArgumentIndex getFormatsByArgumentIndex}
197.741 + * method, which assumes an order of formats corresponding to the
197.742 + * order of elements in the <code>arguments</code> array passed to
197.743 + * the <code>format</code> methods or the result array returned by
197.744 + * the <code>parse</code> methods.
197.745 + *
197.746 + * @return the formats used for the format elements in the pattern
197.747 + */
197.748 + public Format[] getFormats() {
197.749 + Format[] resultArray = new Format[maxOffset + 1];
197.750 + System.arraycopy(formats, 0, resultArray, 0, maxOffset + 1);
197.751 + return resultArray;
197.752 + }
197.753 +
197.754 + /**
197.755 + * Formats an array of objects and appends the <code>MessageFormat</code>'s
197.756 + * pattern, with format elements replaced by the formatted objects, to the
197.757 + * provided <code>StringBuffer</code>.
197.758 + * <p>
197.759 + * The text substituted for the individual format elements is derived from
197.760 + * the current subformat of the format element and the
197.761 + * <code>arguments</code> element at the format element's argument index
197.762 + * as indicated by the first matching line of the following table. An
197.763 + * argument is <i>unavailable</i> if <code>arguments</code> is
197.764 + * <code>null</code> or has fewer than argumentIndex+1 elements.
197.765 + * <p>
197.766 + * <table border=1 summary="Examples of subformat,argument,and formatted text">
197.767 + * <tr>
197.768 + * <th>Subformat
197.769 + * <th>Argument
197.770 + * <th>Formatted Text
197.771 + * <tr>
197.772 + * <td><i>any</i>
197.773 + * <td><i>unavailable</i>
197.774 + * <td><code>"{" + argumentIndex + "}"</code>
197.775 + * <tr>
197.776 + * <td><i>any</i>
197.777 + * <td><code>null</code>
197.778 + * <td><code>"null"</code>
197.779 + * <tr>
197.780 + * <td><code>instanceof ChoiceFormat</code>
197.781 + * <td><i>any</i>
197.782 + * <td><code>subformat.format(argument).indexOf('{') >= 0 ?<br>
197.783 + * (new MessageFormat(subformat.format(argument), getLocale())).format(argument) :
197.784 + * subformat.format(argument)</code>
197.785 + * <tr>
197.786 + * <td><code>!= null</code>
197.787 + * <td><i>any</i>
197.788 + * <td><code>subformat.format(argument)</code>
197.789 + * <tr>
197.790 + * <td><code>null</code>
197.791 + * <td><code>instanceof Number</code>
197.792 + * <td><code>NumberFormat.getInstance(getLocale()).format(argument)</code>
197.793 + * <tr>
197.794 + * <td><code>null</code>
197.795 + * <td><code>instanceof Date</code>
197.796 + * <td><code>DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()).format(argument)</code>
197.797 + * <tr>
197.798 + * <td><code>null</code>
197.799 + * <td><code>instanceof String</code>
197.800 + * <td><code>argument</code>
197.801 + * <tr>
197.802 + * <td><code>null</code>
197.803 + * <td><i>any</i>
197.804 + * <td><code>argument.toString()</code>
197.805 + * </table>
197.806 + * <p>
197.807 + * If <code>pos</code> is non-null, and refers to
197.808 + * <code>Field.ARGUMENT</code>, the location of the first formatted
197.809 + * string will be returned.
197.810 + *
197.811 + * @param arguments an array of objects to be formatted and substituted.
197.812 + * @param result where text is appended.
197.813 + * @param pos On input: an alignment field, if desired.
197.814 + * On output: the offsets of the alignment field.
197.815 + * @exception IllegalArgumentException if an argument in the
197.816 + * <code>arguments</code> array is not of the type
197.817 + * expected by the format element(s) that use it.
197.818 + */
197.819 + public final StringBuffer format(Object[] arguments, StringBuffer result,
197.820 + FieldPosition pos)
197.821 + {
197.822 + return subformat(arguments, result, pos, null);
197.823 + }
197.824 +
197.825 + /**
197.826 + * Creates a MessageFormat with the given pattern and uses it
197.827 + * to format the given arguments. This is equivalent to
197.828 + * <blockquote>
197.829 + * <code>(new {@link #MessageFormat(String) MessageFormat}(pattern)).{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
197.830 + * </blockquote>
197.831 + *
197.832 + * @exception IllegalArgumentException if the pattern is invalid,
197.833 + * or if an argument in the <code>arguments</code> array
197.834 + * is not of the type expected by the format element(s)
197.835 + * that use it.
197.836 + */
197.837 + public static String format(String pattern, Object ... arguments) {
197.838 + MessageFormat temp = new MessageFormat(pattern);
197.839 + return temp.format(arguments);
197.840 + }
197.841 +
197.842 + // Overrides
197.843 + /**
197.844 + * Formats an array of objects and appends the <code>MessageFormat</code>'s
197.845 + * pattern, with format elements replaced by the formatted objects, to the
197.846 + * provided <code>StringBuffer</code>.
197.847 + * This is equivalent to
197.848 + * <blockquote>
197.849 + * <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}((Object[]) arguments, result, pos)</code>
197.850 + * </blockquote>
197.851 + *
197.852 + * @param arguments an array of objects to be formatted and substituted.
197.853 + * @param result where text is appended.
197.854 + * @param pos On input: an alignment field, if desired.
197.855 + * On output: the offsets of the alignment field.
197.856 + * @exception IllegalArgumentException if an argument in the
197.857 + * <code>arguments</code> array is not of the type
197.858 + * expected by the format element(s) that use it.
197.859 + */
197.860 + public final StringBuffer format(Object arguments, StringBuffer result,
197.861 + FieldPosition pos)
197.862 + {
197.863 + return subformat((Object[]) arguments, result, pos, null);
197.864 + }
197.865 +
197.866 + /**
197.867 + * Formats an array of objects and inserts them into the
197.868 + * <code>MessageFormat</code>'s pattern, producing an
197.869 + * <code>AttributedCharacterIterator</code>.
197.870 + * You can use the returned <code>AttributedCharacterIterator</code>
197.871 + * to build the resulting String, as well as to determine information
197.872 + * about the resulting String.
197.873 + * <p>
197.874 + * The text of the returned <code>AttributedCharacterIterator</code> is
197.875 + * the same that would be returned by
197.876 + * <blockquote>
197.877 + * <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
197.878 + * </blockquote>
197.879 + * <p>
197.880 + * In addition, the <code>AttributedCharacterIterator</code> contains at
197.881 + * least attributes indicating where text was generated from an
197.882 + * argument in the <code>arguments</code> array. The keys of these attributes are of
197.883 + * type <code>MessageFormat.Field</code>, their values are
197.884 + * <code>Integer</code> objects indicating the index in the <code>arguments</code>
197.885 + * array of the argument from which the text was generated.
197.886 + * <p>
197.887 + * The attributes/value from the underlying <code>Format</code>
197.888 + * instances that <code>MessageFormat</code> uses will also be
197.889 + * placed in the resulting <code>AttributedCharacterIterator</code>.
197.890 + * This allows you to not only find where an argument is placed in the
197.891 + * resulting String, but also which fields it contains in turn.
197.892 + *
197.893 + * @param arguments an array of objects to be formatted and substituted.
197.894 + * @return AttributedCharacterIterator describing the formatted value.
197.895 + * @exception NullPointerException if <code>arguments</code> is null.
197.896 + * @exception IllegalArgumentException if an argument in the
197.897 + * <code>arguments</code> array is not of the type
197.898 + * expected by the format element(s) that use it.
197.899 + * @since 1.4
197.900 + */
197.901 + public AttributedCharacterIterator formatToCharacterIterator(Object arguments) {
197.902 + StringBuffer result = new StringBuffer();
197.903 + ArrayList iterators = new ArrayList();
197.904 +
197.905 + if (arguments == null) {
197.906 + throw new NullPointerException(
197.907 + "formatToCharacterIterator must be passed non-null object");
197.908 + }
197.909 + subformat((Object[]) arguments, result, null, iterators);
197.910 + if (iterators.size() == 0) {
197.911 + return createAttributedCharacterIterator("");
197.912 + }
197.913 + return createAttributedCharacterIterator(
197.914 + (AttributedCharacterIterator[])iterators.toArray(
197.915 + new AttributedCharacterIterator[iterators.size()]));
197.916 + }
197.917 +
197.918 + /**
197.919 + * Parses the string.
197.920 + *
197.921 + * <p>Caveats: The parse may fail in a number of circumstances.
197.922 + * For example:
197.923 + * <ul>
197.924 + * <li>If one of the arguments does not occur in the pattern.
197.925 + * <li>If the format of an argument loses information, such as
197.926 + * with a choice format where a large number formats to "many".
197.927 + * <li>Does not yet handle recursion (where
197.928 + * the substituted strings contain {n} references.)
197.929 + * <li>Will not always find a match (or the correct match)
197.930 + * if some part of the parse is ambiguous.
197.931 + * For example, if the pattern "{1},{2}" is used with the
197.932 + * string arguments {"a,b", "c"}, it will format as "a,b,c".
197.933 + * When the result is parsed, it will return {"a", "b,c"}.
197.934 + * <li>If a single argument is parsed more than once in the string,
197.935 + * then the later parse wins.
197.936 + * </ul>
197.937 + * When the parse fails, use ParsePosition.getErrorIndex() to find out
197.938 + * where in the string the parsing failed. The returned error
197.939 + * index is the starting offset of the sub-patterns that the string
197.940 + * is comparing with. For example, if the parsing string "AAA {0} BBB"
197.941 + * is comparing against the pattern "AAD {0} BBB", the error index is
197.942 + * 0. When an error occurs, the call to this method will return null.
197.943 + * If the source is null, return an empty array.
197.944 + */
197.945 + public Object[] parse(String source, ParsePosition pos) {
197.946 + if (source == null) {
197.947 + Object[] empty = {};
197.948 + return empty;
197.949 + }
197.950 +
197.951 + int maximumArgumentNumber = -1;
197.952 + for (int i = 0; i <= maxOffset; i++) {
197.953 + if (argumentNumbers[i] > maximumArgumentNumber) {
197.954 + maximumArgumentNumber = argumentNumbers[i];
197.955 + }
197.956 + }
197.957 + Object[] resultArray = new Object[maximumArgumentNumber + 1];
197.958 +
197.959 + int patternOffset = 0;
197.960 + int sourceOffset = pos.index;
197.961 + ParsePosition tempStatus = new ParsePosition(0);
197.962 + for (int i = 0; i <= maxOffset; ++i) {
197.963 + // match up to format
197.964 + int len = offsets[i] - patternOffset;
197.965 + if (len == 0 || pattern.regionMatches(patternOffset,
197.966 + source, sourceOffset, len)) {
197.967 + sourceOffset += len;
197.968 + patternOffset += len;
197.969 + } else {
197.970 + pos.errorIndex = sourceOffset;
197.971 + return null; // leave index as is to signal error
197.972 + }
197.973 +
197.974 + // now use format
197.975 + if (formats[i] == null) { // string format
197.976 + // if at end, use longest possible match
197.977 + // otherwise uses first match to intervening string
197.978 + // does NOT recursively try all possibilities
197.979 + int tempLength = (i != maxOffset) ? offsets[i+1] : pattern.length();
197.980 +
197.981 + int next;
197.982 + if (patternOffset >= tempLength) {
197.983 + next = source.length();
197.984 + }else{
197.985 + next = source.indexOf(pattern.substring(patternOffset, tempLength),
197.986 + sourceOffset);
197.987 + }
197.988 +
197.989 + if (next < 0) {
197.990 + pos.errorIndex = sourceOffset;
197.991 + return null; // leave index as is to signal error
197.992 + } else {
197.993 + String strValue= source.substring(sourceOffset,next);
197.994 + if (!strValue.equals("{"+argumentNumbers[i]+"}"))
197.995 + resultArray[argumentNumbers[i]]
197.996 + = source.substring(sourceOffset,next);
197.997 + sourceOffset = next;
197.998 + }
197.999 + } else {
197.1000 + tempStatus.index = sourceOffset;
197.1001 + resultArray[argumentNumbers[i]]
197.1002 + = formats[i].parseObject(source,tempStatus);
197.1003 + if (tempStatus.index == sourceOffset) {
197.1004 + pos.errorIndex = sourceOffset;
197.1005 + return null; // leave index as is to signal error
197.1006 + }
197.1007 + sourceOffset = tempStatus.index; // update
197.1008 + }
197.1009 + }
197.1010 + int len = pattern.length() - patternOffset;
197.1011 + if (len == 0 || pattern.regionMatches(patternOffset,
197.1012 + source, sourceOffset, len)) {
197.1013 + pos.index = sourceOffset + len;
197.1014 + } else {
197.1015 + pos.errorIndex = sourceOffset;
197.1016 + return null; // leave index as is to signal error
197.1017 + }
197.1018 + return resultArray;
197.1019 + }
197.1020 +
197.1021 + /**
197.1022 + * Parses text from the beginning of the given string to produce an object
197.1023 + * array.
197.1024 + * The method may not use the entire text of the given string.
197.1025 + * <p>
197.1026 + * See the {@link #parse(String, ParsePosition)} method for more information
197.1027 + * on message parsing.
197.1028 + *
197.1029 + * @param source A <code>String</code> whose beginning should be parsed.
197.1030 + * @return An <code>Object</code> array parsed from the string.
197.1031 + * @exception ParseException if the beginning of the specified string
197.1032 + * cannot be parsed.
197.1033 + */
197.1034 + public Object[] parse(String source) throws ParseException {
197.1035 + ParsePosition pos = new ParsePosition(0);
197.1036 + Object[] result = parse(source, pos);
197.1037 + if (pos.index == 0) // unchanged, returned object is null
197.1038 + throw new ParseException("MessageFormat parse error!", pos.errorIndex);
197.1039 +
197.1040 + return result;
197.1041 + }
197.1042 +
197.1043 + /**
197.1044 + * Parses text from a string to produce an object array.
197.1045 + * <p>
197.1046 + * The method attempts to parse text starting at the index given by
197.1047 + * <code>pos</code>.
197.1048 + * If parsing succeeds, then the index of <code>pos</code> is updated
197.1049 + * to the index after the last character used (parsing does not necessarily
197.1050 + * use all characters up to the end of the string), and the parsed
197.1051 + * object array is returned. The updated <code>pos</code> can be used to
197.1052 + * indicate the starting point for the next call to this method.
197.1053 + * If an error occurs, then the index of <code>pos</code> is not
197.1054 + * changed, the error index of <code>pos</code> is set to the index of
197.1055 + * the character where the error occurred, and null is returned.
197.1056 + * <p>
197.1057 + * See the {@link #parse(String, ParsePosition)} method for more information
197.1058 + * on message parsing.
197.1059 + *
197.1060 + * @param source A <code>String</code>, part of which should be parsed.
197.1061 + * @param pos A <code>ParsePosition</code> object with index and error
197.1062 + * index information as described above.
197.1063 + * @return An <code>Object</code> array parsed from the string. In case of
197.1064 + * error, returns null.
197.1065 + * @exception NullPointerException if <code>pos</code> is null.
197.1066 + */
197.1067 + public Object parseObject(String source, ParsePosition pos) {
197.1068 + return parse(source, pos);
197.1069 + }
197.1070 +
197.1071 + /**
197.1072 + * Creates and returns a copy of this object.
197.1073 + *
197.1074 + * @return a clone of this instance.
197.1075 + */
197.1076 + public Object clone() {
197.1077 + MessageFormat other = (MessageFormat) super.clone();
197.1078 +
197.1079 + // clone arrays. Can't do with utility because of bug in Cloneable
197.1080 + other.formats = (Format[]) formats.clone(); // shallow clone
197.1081 + for (int i = 0; i < formats.length; ++i) {
197.1082 + if (formats[i] != null)
197.1083 + other.formats[i] = (Format)formats[i].clone();
197.1084 + }
197.1085 + // for primitives or immutables, shallow clone is enough
197.1086 + other.offsets = (int[]) offsets.clone();
197.1087 + other.argumentNumbers = (int[]) argumentNumbers.clone();
197.1088 +
197.1089 + return other;
197.1090 + }
197.1091 +
197.1092 + /**
197.1093 + * Equality comparison between two message format objects
197.1094 + */
197.1095 + public boolean equals(Object obj) {
197.1096 + if (this == obj) // quick check
197.1097 + return true;
197.1098 + if (obj == null || getClass() != obj.getClass())
197.1099 + return false;
197.1100 + MessageFormat other = (MessageFormat) obj;
197.1101 + return (maxOffset == other.maxOffset
197.1102 + && pattern.equals(other.pattern)
197.1103 + && ((locale != null && locale.equals(other.locale))
197.1104 + || (locale == null && other.locale == null))
197.1105 + && Arrays.equals(offsets,other.offsets)
197.1106 + && Arrays.equals(argumentNumbers,other.argumentNumbers)
197.1107 + && Arrays.equals(formats,other.formats));
197.1108 + }
197.1109 +
197.1110 + /**
197.1111 + * Generates a hash code for the message format object.
197.1112 + */
197.1113 + public int hashCode() {
197.1114 + return pattern.hashCode(); // enough for reasonable distribution
197.1115 + }
197.1116 +
197.1117 +
197.1118 + /**
197.1119 + * Defines constants that are used as attribute keys in the
197.1120 + * <code>AttributedCharacterIterator</code> returned
197.1121 + * from <code>MessageFormat.formatToCharacterIterator</code>.
197.1122 + *
197.1123 + * @since 1.4
197.1124 + */
197.1125 + public static class Field extends Format.Field {
197.1126 +
197.1127 + // Proclaim serial compatibility with 1.4 FCS
197.1128 + private static final long serialVersionUID = 7899943957617360810L;
197.1129 +
197.1130 + /**
197.1131 + * Creates a Field with the specified name.
197.1132 + *
197.1133 + * @param name Name of the attribute
197.1134 + */
197.1135 + protected Field(String name) {
197.1136 + super(name);
197.1137 + }
197.1138 +
197.1139 + /**
197.1140 + * Resolves instances being deserialized to the predefined constants.
197.1141 + *
197.1142 + * @throws InvalidObjectException if the constant could not be
197.1143 + * resolved.
197.1144 + * @return resolved MessageFormat.Field constant
197.1145 + */
197.1146 + protected Object readResolve() throws InvalidObjectException {
197.1147 + if (this.getClass() != MessageFormat.Field.class) {
197.1148 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
197.1149 + }
197.1150 +
197.1151 + return ARGUMENT;
197.1152 + }
197.1153 +
197.1154 + //
197.1155 + // The constants
197.1156 + //
197.1157 +
197.1158 + /**
197.1159 + * Constant identifying a portion of a message that was generated
197.1160 + * from an argument passed into <code>formatToCharacterIterator</code>.
197.1161 + * The value associated with the key will be an <code>Integer</code>
197.1162 + * indicating the index in the <code>arguments</code> array of the
197.1163 + * argument from which the text was generated.
197.1164 + */
197.1165 + public final static Field ARGUMENT =
197.1166 + new Field("message argument field");
197.1167 + }
197.1168 +
197.1169 + // ===========================privates============================
197.1170 +
197.1171 + /**
197.1172 + * The locale to use for formatting numbers and dates.
197.1173 + * @serial
197.1174 + */
197.1175 + private Locale locale;
197.1176 +
197.1177 + /**
197.1178 + * The string that the formatted values are to be plugged into. In other words, this
197.1179 + * is the pattern supplied on construction with all of the {} expressions taken out.
197.1180 + * @serial
197.1181 + */
197.1182 + private String pattern = "";
197.1183 +
197.1184 + /** The initially expected number of subformats in the format */
197.1185 + private static final int INITIAL_FORMATS = 10;
197.1186 +
197.1187 + /**
197.1188 + * An array of formatters, which are used to format the arguments.
197.1189 + * @serial
197.1190 + */
197.1191 + private Format[] formats = new Format[INITIAL_FORMATS];
197.1192 +
197.1193 + /**
197.1194 + * The positions where the results of formatting each argument are to be inserted
197.1195 + * into the pattern.
197.1196 + * @serial
197.1197 + */
197.1198 + private int[] offsets = new int[INITIAL_FORMATS];
197.1199 +
197.1200 + /**
197.1201 + * The argument numbers corresponding to each formatter. (The formatters are stored
197.1202 + * in the order they occur in the pattern, not in the order in which the arguments
197.1203 + * are specified.)
197.1204 + * @serial
197.1205 + */
197.1206 + private int[] argumentNumbers = new int[INITIAL_FORMATS];
197.1207 +
197.1208 + /**
197.1209 + * One less than the number of entries in <code>offsets</code>. Can also be thought of
197.1210 + * as the index of the highest-numbered element in <code>offsets</code> that is being used.
197.1211 + * All of these arrays should have the same number of elements being used as <code>offsets</code>
197.1212 + * does, and so this variable suffices to tell us how many entries are in all of them.
197.1213 + * @serial
197.1214 + */
197.1215 + private int maxOffset = -1;
197.1216 +
197.1217 + /**
197.1218 + * Internal routine used by format. If <code>characterIterators</code> is
197.1219 + * non-null, AttributedCharacterIterator will be created from the
197.1220 + * subformats as necessary. If <code>characterIterators</code> is null
197.1221 + * and <code>fp</code> is non-null and identifies
197.1222 + * <code>Field.MESSAGE_ARGUMENT</code>, the location of
197.1223 + * the first replaced argument will be set in it.
197.1224 + *
197.1225 + * @exception IllegalArgumentException if an argument in the
197.1226 + * <code>arguments</code> array is not of the type
197.1227 + * expected by the format element(s) that use it.
197.1228 + */
197.1229 + private StringBuffer subformat(Object[] arguments, StringBuffer result,
197.1230 + FieldPosition fp, List characterIterators) {
197.1231 + // note: this implementation assumes a fast substring & index.
197.1232 + // if this is not true, would be better to append chars one by one.
197.1233 + int lastOffset = 0;
197.1234 + int last = result.length();
197.1235 + for (int i = 0; i <= maxOffset; ++i) {
197.1236 + result.append(pattern.substring(lastOffset, offsets[i]));
197.1237 + lastOffset = offsets[i];
197.1238 + int argumentNumber = argumentNumbers[i];
197.1239 + if (arguments == null || argumentNumber >= arguments.length) {
197.1240 + result.append('{').append(argumentNumber).append('}');
197.1241 + continue;
197.1242 + }
197.1243 + // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
197.1244 + if (false) { // if (argRecursion == 3){
197.1245 + // prevent loop!!!
197.1246 + result.append('\uFFFD');
197.1247 + } else {
197.1248 + Object obj = arguments[argumentNumber];
197.1249 + String arg = null;
197.1250 + Format subFormatter = null;
197.1251 + if (obj == null) {
197.1252 + arg = "null";
197.1253 + } else if (formats[i] != null) {
197.1254 + subFormatter = formats[i];
197.1255 + if (subFormatter instanceof ChoiceFormat) {
197.1256 + arg = formats[i].format(obj);
197.1257 + if (arg.indexOf('{') >= 0) {
197.1258 + subFormatter = new MessageFormat(arg, locale);
197.1259 + obj = arguments;
197.1260 + arg = null;
197.1261 + }
197.1262 + }
197.1263 + } else if (obj instanceof Number) {
197.1264 + // format number if can
197.1265 + subFormatter = NumberFormat.getInstance(locale);
197.1266 + } else if (obj instanceof Date) {
197.1267 + // format a Date if can
197.1268 + subFormatter = DateFormat.getDateTimeInstance(
197.1269 + DateFormat.SHORT, DateFormat.SHORT, locale);//fix
197.1270 + } else if (obj instanceof String) {
197.1271 + arg = (String) obj;
197.1272 +
197.1273 + } else {
197.1274 + arg = obj.toString();
197.1275 + if (arg == null) arg = "null";
197.1276 + }
197.1277 +
197.1278 + // At this point we are in two states, either subFormatter
197.1279 + // is non-null indicating we should format obj using it,
197.1280 + // or arg is non-null and we should use it as the value.
197.1281 +
197.1282 + if (characterIterators != null) {
197.1283 + // If characterIterators is non-null, it indicates we need
197.1284 + // to get the CharacterIterator from the child formatter.
197.1285 + if (last != result.length()) {
197.1286 + characterIterators.add(
197.1287 + createAttributedCharacterIterator(result.substring
197.1288 + (last)));
197.1289 + last = result.length();
197.1290 + }
197.1291 + if (subFormatter != null) {
197.1292 + AttributedCharacterIterator subIterator =
197.1293 + subFormatter.formatToCharacterIterator(obj);
197.1294 +
197.1295 + append(result, subIterator);
197.1296 + if (last != result.length()) {
197.1297 + characterIterators.add(
197.1298 + createAttributedCharacterIterator(
197.1299 + subIterator, Field.ARGUMENT,
197.1300 + Integer.valueOf(argumentNumber)));
197.1301 + last = result.length();
197.1302 + }
197.1303 + arg = null;
197.1304 + }
197.1305 + if (arg != null && arg.length() > 0) {
197.1306 + result.append(arg);
197.1307 + characterIterators.add(
197.1308 + createAttributedCharacterIterator(
197.1309 + arg, Field.ARGUMENT,
197.1310 + Integer.valueOf(argumentNumber)));
197.1311 + last = result.length();
197.1312 + }
197.1313 + }
197.1314 + else {
197.1315 + if (subFormatter != null) {
197.1316 + arg = subFormatter.format(obj);
197.1317 + }
197.1318 + last = result.length();
197.1319 + result.append(arg);
197.1320 + if (i == 0 && fp != null && Field.ARGUMENT.equals(
197.1321 + fp.getFieldAttribute())) {
197.1322 + fp.setBeginIndex(last);
197.1323 + fp.setEndIndex(result.length());
197.1324 + }
197.1325 + last = result.length();
197.1326 + }
197.1327 + }
197.1328 + }
197.1329 + result.append(pattern.substring(lastOffset, pattern.length()));
197.1330 + if (characterIterators != null && last != result.length()) {
197.1331 + characterIterators.add(createAttributedCharacterIterator(
197.1332 + result.substring(last)));
197.1333 + }
197.1334 + return result;
197.1335 + }
197.1336 +
197.1337 + /**
197.1338 + * Convenience method to append all the characters in
197.1339 + * <code>iterator</code> to the StringBuffer <code>result</code>.
197.1340 + */
197.1341 + private void append(StringBuffer result, CharacterIterator iterator) {
197.1342 + if (iterator.first() != CharacterIterator.DONE) {
197.1343 + char aChar;
197.1344 +
197.1345 + result.append(iterator.first());
197.1346 + while ((aChar = iterator.next()) != CharacterIterator.DONE) {
197.1347 + result.append(aChar);
197.1348 + }
197.1349 + }
197.1350 + }
197.1351 +
197.1352 + // Indices for segments
197.1353 + private static final int SEG_RAW = 0;
197.1354 + private static final int SEG_INDEX = 1;
197.1355 + private static final int SEG_TYPE = 2;
197.1356 + private static final int SEG_MODIFIER = 3; // modifier or subformat
197.1357 +
197.1358 + // Indices for type keywords
197.1359 + private static final int TYPE_NULL = 0;
197.1360 + private static final int TYPE_NUMBER = 1;
197.1361 + private static final int TYPE_DATE = 2;
197.1362 + private static final int TYPE_TIME = 3;
197.1363 + private static final int TYPE_CHOICE = 4;
197.1364 +
197.1365 + private static final String[] TYPE_KEYWORDS = {
197.1366 + "",
197.1367 + "number",
197.1368 + "date",
197.1369 + "time",
197.1370 + "choice"
197.1371 + };
197.1372 +
197.1373 + // Indices for number modifiers
197.1374 + private static final int MODIFIER_DEFAULT = 0; // common in number and date-time
197.1375 + private static final int MODIFIER_CURRENCY = 1;
197.1376 + private static final int MODIFIER_PERCENT = 2;
197.1377 + private static final int MODIFIER_INTEGER = 3;
197.1378 +
197.1379 + private static final String[] NUMBER_MODIFIER_KEYWORDS = {
197.1380 + "",
197.1381 + "currency",
197.1382 + "percent",
197.1383 + "integer"
197.1384 + };
197.1385 +
197.1386 + // Indices for date-time modifiers
197.1387 + private static final int MODIFIER_SHORT = 1;
197.1388 + private static final int MODIFIER_MEDIUM = 2;
197.1389 + private static final int MODIFIER_LONG = 3;
197.1390 + private static final int MODIFIER_FULL = 4;
197.1391 +
197.1392 + private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
197.1393 + "",
197.1394 + "short",
197.1395 + "medium",
197.1396 + "long",
197.1397 + "full"
197.1398 + };
197.1399 +
197.1400 + // Date-time style values corresponding to the date-time modifiers.
197.1401 + private static final int[] DATE_TIME_MODIFIERS = {
197.1402 + DateFormat.DEFAULT,
197.1403 + DateFormat.SHORT,
197.1404 + DateFormat.MEDIUM,
197.1405 + DateFormat.LONG,
197.1406 + DateFormat.FULL,
197.1407 + };
197.1408 +
197.1409 + private void makeFormat(int position, int offsetNumber,
197.1410 + StringBuilder[] textSegments)
197.1411 + {
197.1412 + String[] segments = new String[textSegments.length];
197.1413 + for (int i = 0; i < textSegments.length; i++) {
197.1414 + StringBuilder oneseg = textSegments[i];
197.1415 + segments[i] = (oneseg != null) ? oneseg.toString() : "";
197.1416 + }
197.1417 +
197.1418 + // get the argument number
197.1419 + int argumentNumber;
197.1420 + try {
197.1421 + argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
197.1422 + } catch (NumberFormatException e) {
197.1423 + throw new IllegalArgumentException("can't parse argument number: "
197.1424 + + segments[SEG_INDEX], e);
197.1425 + }
197.1426 + if (argumentNumber < 0) {
197.1427 + throw new IllegalArgumentException("negative argument number: "
197.1428 + + argumentNumber);
197.1429 + }
197.1430 +
197.1431 + // resize format information arrays if necessary
197.1432 + if (offsetNumber >= formats.length) {
197.1433 + int newLength = formats.length * 2;
197.1434 + Format[] newFormats = new Format[newLength];
197.1435 + int[] newOffsets = new int[newLength];
197.1436 + int[] newArgumentNumbers = new int[newLength];
197.1437 + System.arraycopy(formats, 0, newFormats, 0, maxOffset + 1);
197.1438 + System.arraycopy(offsets, 0, newOffsets, 0, maxOffset + 1);
197.1439 + System.arraycopy(argumentNumbers, 0, newArgumentNumbers, 0, maxOffset + 1);
197.1440 + formats = newFormats;
197.1441 + offsets = newOffsets;
197.1442 + argumentNumbers = newArgumentNumbers;
197.1443 + }
197.1444 + int oldMaxOffset = maxOffset;
197.1445 + maxOffset = offsetNumber;
197.1446 + offsets[offsetNumber] = segments[SEG_RAW].length();
197.1447 + argumentNumbers[offsetNumber] = argumentNumber;
197.1448 +
197.1449 + // now get the format
197.1450 + Format newFormat = null;
197.1451 + if (segments[SEG_TYPE].length() != 0) {
197.1452 + int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
197.1453 + switch (type) {
197.1454 + case TYPE_NULL:
197.1455 + // Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
197.1456 + // are treated as "{0}".
197.1457 + break;
197.1458 +
197.1459 + case TYPE_NUMBER:
197.1460 + switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
197.1461 + case MODIFIER_DEFAULT:
197.1462 + newFormat = NumberFormat.getInstance(locale);
197.1463 + break;
197.1464 + case MODIFIER_CURRENCY:
197.1465 + newFormat = NumberFormat.getCurrencyInstance(locale);
197.1466 + break;
197.1467 + case MODIFIER_PERCENT:
197.1468 + newFormat = NumberFormat.getPercentInstance(locale);
197.1469 + break;
197.1470 + case MODIFIER_INTEGER:
197.1471 + newFormat = NumberFormat.getIntegerInstance(locale);
197.1472 + break;
197.1473 + default: // DecimalFormat pattern
197.1474 + try {
197.1475 + newFormat = new DecimalFormat(segments[SEG_MODIFIER],
197.1476 + DecimalFormatSymbols.getInstance(locale));
197.1477 + } catch (IllegalArgumentException e) {
197.1478 + maxOffset = oldMaxOffset;
197.1479 + throw e;
197.1480 + }
197.1481 + break;
197.1482 + }
197.1483 + break;
197.1484 +
197.1485 + case TYPE_DATE:
197.1486 + case TYPE_TIME:
197.1487 + int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
197.1488 + if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
197.1489 + if (type == TYPE_DATE) {
197.1490 + newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
197.1491 + locale);
197.1492 + } else {
197.1493 + newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
197.1494 + locale);
197.1495 + }
197.1496 + } else {
197.1497 + // SimpleDateFormat pattern
197.1498 + try {
197.1499 + newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
197.1500 + } catch (IllegalArgumentException e) {
197.1501 + maxOffset = oldMaxOffset;
197.1502 + throw e;
197.1503 + }
197.1504 + }
197.1505 + break;
197.1506 +
197.1507 + case TYPE_CHOICE:
197.1508 + try {
197.1509 + // ChoiceFormat pattern
197.1510 + newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
197.1511 + } catch (Exception e) {
197.1512 + maxOffset = oldMaxOffset;
197.1513 + throw new IllegalArgumentException("Choice Pattern incorrect: "
197.1514 + + segments[SEG_MODIFIER], e);
197.1515 + }
197.1516 + break;
197.1517 +
197.1518 + default:
197.1519 + maxOffset = oldMaxOffset;
197.1520 + throw new IllegalArgumentException("unknown format type: " +
197.1521 + segments[SEG_TYPE]);
197.1522 + }
197.1523 + }
197.1524 + formats[offsetNumber] = newFormat;
197.1525 + }
197.1526 +
197.1527 + private static final int findKeyword(String s, String[] list) {
197.1528 + for (int i = 0; i < list.length; ++i) {
197.1529 + if (s.equals(list[i]))
197.1530 + return i;
197.1531 + }
197.1532 +
197.1533 + // Try trimmed lowercase.
197.1534 + String ls = s.trim().toLowerCase(Locale.ROOT);
197.1535 + if (ls != s) {
197.1536 + for (int i = 0; i < list.length; ++i) {
197.1537 + if (ls.equals(list[i]))
197.1538 + return i;
197.1539 + }
197.1540 + }
197.1541 + return -1;
197.1542 + }
197.1543 +
197.1544 + private static final void copyAndFixQuotes(String source, int start, int end,
197.1545 + StringBuilder target) {
197.1546 + boolean quoted = false;
197.1547 +
197.1548 + for (int i = start; i < end; ++i) {
197.1549 + char ch = source.charAt(i);
197.1550 + if (ch == '{') {
197.1551 + if (!quoted) {
197.1552 + target.append('\'');
197.1553 + quoted = true;
197.1554 + }
197.1555 + target.append(ch);
197.1556 + } else if (ch == '\'') {
197.1557 + target.append("''");
197.1558 + } else {
197.1559 + if (quoted) {
197.1560 + target.append('\'');
197.1561 + quoted = false;
197.1562 + }
197.1563 + target.append(ch);
197.1564 + }
197.1565 + }
197.1566 + if (quoted) {
197.1567 + target.append('\'');
197.1568 + }
197.1569 + }
197.1570 +
197.1571 + /**
197.1572 + * After reading an object from the input stream, do a simple verification
197.1573 + * to maintain class invariants.
197.1574 + * @throws InvalidObjectException if the objects read from the stream is invalid.
197.1575 + */
197.1576 + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
197.1577 + in.defaultReadObject();
197.1578 + boolean isValid = maxOffset >= -1
197.1579 + && formats.length > maxOffset
197.1580 + && offsets.length > maxOffset
197.1581 + && argumentNumbers.length > maxOffset;
197.1582 + if (isValid) {
197.1583 + int lastOffset = pattern.length() + 1;
197.1584 + for (int i = maxOffset; i >= 0; --i) {
197.1585 + if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
197.1586 + isValid = false;
197.1587 + break;
197.1588 + } else {
197.1589 + lastOffset = offsets[i];
197.1590 + }
197.1591 + }
197.1592 + }
197.1593 + if (!isValid) {
197.1594 + throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
197.1595 + }
197.1596 + }
197.1597 +}
198.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
198.2 +++ b/rt/emul/compact/src/main/java/java/text/NumberFormat.java Wed Apr 30 15:04:10 2014 +0200
198.3 @@ -0,0 +1,1159 @@
198.4 +/*
198.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
198.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
198.7 + *
198.8 + * This code is free software; you can redistribute it and/or modify it
198.9 + * under the terms of the GNU General Public License version 2 only, as
198.10 + * published by the Free Software Foundation. Oracle designates this
198.11 + * particular file as subject to the "Classpath" exception as provided
198.12 + * by Oracle in the LICENSE file that accompanied this code.
198.13 + *
198.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
198.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
198.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
198.17 + * version 2 for more details (a copy is included in the LICENSE file that
198.18 + * accompanied this code).
198.19 + *
198.20 + * You should have received a copy of the GNU General Public License version
198.21 + * 2 along with this work; if not, write to the Free Software Foundation,
198.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
198.23 + *
198.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
198.25 + * or visit www.oracle.com if you need additional information or have any
198.26 + * questions.
198.27 + */
198.28 +
198.29 +/*
198.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
198.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
198.32 + *
198.33 + * The original version of this source code and documentation is copyrighted
198.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
198.35 + * materials are provided under terms of a License Agreement between Taligent
198.36 + * and Sun. This technology is protected by multiple US and International
198.37 + * patents. This notice and attribution to Taligent may not be removed.
198.38 + * Taligent is a registered trademark of Taligent, Inc.
198.39 + *
198.40 + */
198.41 +
198.42 +package java.text;
198.43 +
198.44 +import java.io.InvalidObjectException;
198.45 +import java.io.IOException;
198.46 +import java.io.ObjectInputStream;
198.47 +import java.io.ObjectOutputStream;
198.48 +import java.math.BigInteger;
198.49 +import java.math.RoundingMode;
198.50 +import java.util.Currency;
198.51 +import java.util.HashMap;
198.52 +import java.util.Hashtable;
198.53 +import java.util.Locale;
198.54 +import java.util.Map;
198.55 +import java.util.ResourceBundle;
198.56 +import java.util.concurrent.atomic.AtomicInteger;
198.57 +import java.util.concurrent.atomic.AtomicLong;
198.58 +
198.59 +/**
198.60 + * <code>NumberFormat</code> is the abstract base class for all number
198.61 + * formats. This class provides the interface for formatting and parsing
198.62 + * numbers. <code>NumberFormat</code> also provides methods for determining
198.63 + * which locales have number formats, and what their names are.
198.64 + *
198.65 + * <p>
198.66 + * <code>NumberFormat</code> helps you to format and parse numbers for any locale.
198.67 + * Your code can be completely independent of the locale conventions for
198.68 + * decimal points, thousands-separators, or even the particular decimal
198.69 + * digits used, or whether the number format is even decimal.
198.70 + *
198.71 + * <p>
198.72 + * To format a number for the current Locale, use one of the factory
198.73 + * class methods:
198.74 + * <blockquote>
198.75 + * <pre>
198.76 + * myString = NumberFormat.getInstance().format(myNumber);
198.77 + * </pre>
198.78 + * </blockquote>
198.79 + * If you are formatting multiple numbers, it is
198.80 + * more efficient to get the format and use it multiple times so that
198.81 + * the system doesn't have to fetch the information about the local
198.82 + * language and country conventions multiple times.
198.83 + * <blockquote>
198.84 + * <pre>
198.85 + * NumberFormat nf = NumberFormat.getInstance();
198.86 + * for (int i = 0; i < myNumber.length; ++i) {
198.87 + * output.println(nf.format(myNumber[i]) + "; ");
198.88 + * }
198.89 + * </pre>
198.90 + * </blockquote>
198.91 + * To format a number for a different Locale, specify it in the
198.92 + * call to <code>getInstance</code>.
198.93 + * <blockquote>
198.94 + * <pre>
198.95 + * NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
198.96 + * </pre>
198.97 + * </blockquote>
198.98 + * You can also use a <code>NumberFormat</code> to parse numbers:
198.99 + * <blockquote>
198.100 + * <pre>
198.101 + * myNumber = nf.parse(myString);
198.102 + * </pre>
198.103 + * </blockquote>
198.104 + * Use <code>getInstance</code> or <code>getNumberInstance</code> to get the
198.105 + * normal number format. Use <code>getIntegerInstance</code> to get an
198.106 + * integer number format. Use <code>getCurrencyInstance</code> to get the
198.107 + * currency number format. And use <code>getPercentInstance</code> to get a
198.108 + * format for displaying percentages. With this format, a fraction like
198.109 + * 0.53 is displayed as 53%.
198.110 + *
198.111 + * <p>
198.112 + * You can also control the display of numbers with such methods as
198.113 + * <code>setMinimumFractionDigits</code>.
198.114 + * If you want even more control over the format or parsing,
198.115 + * or want to give your users more control,
198.116 + * you can try casting the <code>NumberFormat</code> you get from the factory methods
198.117 + * to a <code>DecimalFormat</code>. This will work for the vast majority
198.118 + * of locales; just remember to put it in a <code>try</code> block in case you
198.119 + * encounter an unusual one.
198.120 + *
198.121 + * <p>
198.122 + * NumberFormat and DecimalFormat are designed such that some controls
198.123 + * work for formatting and others work for parsing. The following is
198.124 + * the detailed description for each these control methods,
198.125 + * <p>
198.126 + * setParseIntegerOnly : only affects parsing, e.g.
198.127 + * if true, "3456.78" -> 3456 (and leaves the parse position just after index 6)
198.128 + * if false, "3456.78" -> 3456.78 (and leaves the parse position just after index 8)
198.129 + * This is independent of formatting. If you want to not show a decimal point
198.130 + * where there might be no digits after the decimal point, use
198.131 + * setDecimalSeparatorAlwaysShown.
198.132 + * <p>
198.133 + * setDecimalSeparatorAlwaysShown : only affects formatting, and only where
198.134 + * there might be no digits after the decimal point, such as with a pattern
198.135 + * like "#,##0.##", e.g.,
198.136 + * if true, 3456.00 -> "3,456."
198.137 + * if false, 3456.00 -> "3456"
198.138 + * This is independent of parsing. If you want parsing to stop at the decimal
198.139 + * point, use setParseIntegerOnly.
198.140 + *
198.141 + * <p>
198.142 + * You can also use forms of the <code>parse</code> and <code>format</code>
198.143 + * methods with <code>ParsePosition</code> and <code>FieldPosition</code> to
198.144 + * allow you to:
198.145 + * <ul>
198.146 + * <li> progressively parse through pieces of a string
198.147 + * <li> align the decimal point and other areas
198.148 + * </ul>
198.149 + * For example, you can align numbers in two ways:
198.150 + * <ol>
198.151 + * <li> If you are using a monospaced font with spacing for alignment,
198.152 + * you can pass the <code>FieldPosition</code> in your format call, with
198.153 + * <code>field</code> = <code>INTEGER_FIELD</code>. On output,
198.154 + * <code>getEndIndex</code> will be set to the offset between the
198.155 + * last character of the integer and the decimal. Add
198.156 + * (desiredSpaceCount - getEndIndex) spaces at the front of the string.
198.157 + *
198.158 + * <li> If you are using proportional fonts,
198.159 + * instead of padding with spaces, measure the width
198.160 + * of the string in pixels from the start to <code>getEndIndex</code>.
198.161 + * Then move the pen by
198.162 + * (desiredPixelWidth - widthToAlignmentPoint) before drawing the text.
198.163 + * It also works where there is no decimal, but possibly additional
198.164 + * characters at the end, e.g., with parentheses in negative
198.165 + * numbers: "(12)" for -12.
198.166 + * </ol>
198.167 + *
198.168 + * <h4><a name="synchronization">Synchronization</a></h4>
198.169 + *
198.170 + * <p>
198.171 + * Number formats are generally not synchronized.
198.172 + * It is recommended to create separate format instances for each thread.
198.173 + * If multiple threads access a format concurrently, it must be synchronized
198.174 + * externally.
198.175 + *
198.176 + * @see DecimalFormat
198.177 + * @see ChoiceFormat
198.178 + * @author Mark Davis
198.179 + * @author Helena Shih
198.180 + */
198.181 +public abstract class NumberFormat extends Format {
198.182 +
198.183 + /**
198.184 + * Field constant used to construct a FieldPosition object. Signifies that
198.185 + * the position of the integer part of a formatted number should be returned.
198.186 + * @see java.text.FieldPosition
198.187 + */
198.188 + public static final int INTEGER_FIELD = 0;
198.189 +
198.190 + /**
198.191 + * Field constant used to construct a FieldPosition object. Signifies that
198.192 + * the position of the fraction part of a formatted number should be returned.
198.193 + * @see java.text.FieldPosition
198.194 + */
198.195 + public static final int FRACTION_FIELD = 1;
198.196 +
198.197 + /**
198.198 + * Sole constructor. (For invocation by subclass constructors, typically
198.199 + * implicit.)
198.200 + */
198.201 + protected NumberFormat() {
198.202 + }
198.203 +
198.204 + /**
198.205 + * Formats a number and appends the resulting text to the given string
198.206 + * buffer.
198.207 + * The number can be of any subclass of {@link java.lang.Number}.
198.208 + * <p>
198.209 + * This implementation extracts the number's value using
198.210 + * {@link java.lang.Number#longValue()} for all integral type values that
198.211 + * can be converted to <code>long</code> without loss of information,
198.212 + * including <code>BigInteger</code> values with a
198.213 + * {@link java.math.BigInteger#bitLength() bit length} of less than 64,
198.214 + * and {@link java.lang.Number#doubleValue()} for all other types. It
198.215 + * then calls
198.216 + * {@link #format(long,java.lang.StringBuffer,java.text.FieldPosition)}
198.217 + * or {@link #format(double,java.lang.StringBuffer,java.text.FieldPosition)}.
198.218 + * This may result in loss of magnitude information and precision for
198.219 + * <code>BigInteger</code> and <code>BigDecimal</code> values.
198.220 + * @param number the number to format
198.221 + * @param toAppendTo the <code>StringBuffer</code> to which the formatted
198.222 + * text is to be appended
198.223 + * @param pos On input: an alignment field, if desired.
198.224 + * On output: the offsets of the alignment field.
198.225 + * @return the value passed in as <code>toAppendTo</code>
198.226 + * @exception IllegalArgumentException if <code>number</code> is
198.227 + * null or not an instance of <code>Number</code>.
198.228 + * @exception NullPointerException if <code>toAppendTo</code> or
198.229 + * <code>pos</code> is null
198.230 + * @exception ArithmeticException if rounding is needed with rounding
198.231 + * mode being set to RoundingMode.UNNECESSARY
198.232 + * @see java.text.FieldPosition
198.233 + */
198.234 + public StringBuffer format(Object number,
198.235 + StringBuffer toAppendTo,
198.236 + FieldPosition pos) {
198.237 + if (number instanceof Long || number instanceof Integer ||
198.238 + number instanceof Short || number instanceof Byte ||
198.239 + number instanceof AtomicInteger || number instanceof AtomicLong ||
198.240 + (number instanceof BigInteger &&
198.241 + ((BigInteger)number).bitLength() < 64)) {
198.242 + return format(((Number)number).longValue(), toAppendTo, pos);
198.243 + } else if (number instanceof Number) {
198.244 + return format(((Number)number).doubleValue(), toAppendTo, pos);
198.245 + } else {
198.246 + throw new IllegalArgumentException("Cannot format given Object as a Number");
198.247 + }
198.248 + }
198.249 +
198.250 + /**
198.251 + * Parses text from a string to produce a <code>Number</code>.
198.252 + * <p>
198.253 + * The method attempts to parse text starting at the index given by
198.254 + * <code>pos</code>.
198.255 + * If parsing succeeds, then the index of <code>pos</code> is updated
198.256 + * to the index after the last character used (parsing does not necessarily
198.257 + * use all characters up to the end of the string), and the parsed
198.258 + * number is returned. The updated <code>pos</code> can be used to
198.259 + * indicate the starting point for the next call to this method.
198.260 + * If an error occurs, then the index of <code>pos</code> is not
198.261 + * changed, the error index of <code>pos</code> is set to the index of
198.262 + * the character where the error occurred, and null is returned.
198.263 + * <p>
198.264 + * See the {@link #parse(String, ParsePosition)} method for more information
198.265 + * on number parsing.
198.266 + *
198.267 + * @param source A <code>String</code>, part of which should be parsed.
198.268 + * @param pos A <code>ParsePosition</code> object with index and error
198.269 + * index information as described above.
198.270 + * @return A <code>Number</code> parsed from the string. In case of
198.271 + * error, returns null.
198.272 + * @exception NullPointerException if <code>pos</code> is null.
198.273 + */
198.274 + public final Object parseObject(String source, ParsePosition pos) {
198.275 + return parse(source, pos);
198.276 + }
198.277 +
198.278 + /**
198.279 + * Specialization of format.
198.280 + * @exception ArithmeticException if rounding is needed with rounding
198.281 + * mode being set to RoundingMode.UNNECESSARY
198.282 + * @see java.text.Format#format
198.283 + */
198.284 + public final String format(double number) {
198.285 + return format(number, new StringBuffer(),
198.286 + DontCareFieldPosition.INSTANCE).toString();
198.287 + }
198.288 +
198.289 + /**
198.290 + * Specialization of format.
198.291 + * @exception ArithmeticException if rounding is needed with rounding
198.292 + * mode being set to RoundingMode.UNNECESSARY
198.293 + * @see java.text.Format#format
198.294 + */
198.295 + public final String format(long number) {
198.296 + return format(number, new StringBuffer(),
198.297 + DontCareFieldPosition.INSTANCE).toString();
198.298 + }
198.299 +
198.300 + /**
198.301 + * Specialization of format.
198.302 + * @exception ArithmeticException if rounding is needed with rounding
198.303 + * mode being set to RoundingMode.UNNECESSARY
198.304 + * @see java.text.Format#format
198.305 + */
198.306 + public abstract StringBuffer format(double number,
198.307 + StringBuffer toAppendTo,
198.308 + FieldPosition pos);
198.309 +
198.310 + /**
198.311 + * Specialization of format.
198.312 + * @exception ArithmeticException if rounding is needed with rounding
198.313 + * mode being set to RoundingMode.UNNECESSARY
198.314 + * @see java.text.Format#format
198.315 + */
198.316 + public abstract StringBuffer format(long number,
198.317 + StringBuffer toAppendTo,
198.318 + FieldPosition pos);
198.319 +
198.320 + /**
198.321 + * Returns a Long if possible (e.g., within the range [Long.MIN_VALUE,
198.322 + * Long.MAX_VALUE] and with no decimals), otherwise a Double.
198.323 + * If IntegerOnly is set, will stop at a decimal
198.324 + * point (or equivalent; e.g., for rational numbers "1 2/3", will stop
198.325 + * after the 1).
198.326 + * Does not throw an exception; if no object can be parsed, index is
198.327 + * unchanged!
198.328 + * @see java.text.NumberFormat#isParseIntegerOnly
198.329 + * @see java.text.Format#parseObject
198.330 + */
198.331 + public abstract Number parse(String source, ParsePosition parsePosition);
198.332 +
198.333 + /**
198.334 + * Parses text from the beginning of the given string to produce a number.
198.335 + * The method may not use the entire text of the given string.
198.336 + * <p>
198.337 + * See the {@link #parse(String, ParsePosition)} method for more information
198.338 + * on number parsing.
198.339 + *
198.340 + * @param source A <code>String</code> whose beginning should be parsed.
198.341 + * @return A <code>Number</code> parsed from the string.
198.342 + * @exception ParseException if the beginning of the specified string
198.343 + * cannot be parsed.
198.344 + */
198.345 + public Number parse(String source) throws ParseException {
198.346 + ParsePosition parsePosition = new ParsePosition(0);
198.347 + Number result = parse(source, parsePosition);
198.348 + if (parsePosition.index == 0) {
198.349 + throw new ParseException("Unparseable number: \"" + source + "\"",
198.350 + parsePosition.errorIndex);
198.351 + }
198.352 + return result;
198.353 + }
198.354 +
198.355 + /**
198.356 + * Returns true if this format will parse numbers as integers only.
198.357 + * For example in the English locale, with ParseIntegerOnly true, the
198.358 + * string "1234." would be parsed as the integer value 1234 and parsing
198.359 + * would stop at the "." character. Of course, the exact format accepted
198.360 + * by the parse operation is locale dependant and determined by sub-classes
198.361 + * of NumberFormat.
198.362 + */
198.363 + public boolean isParseIntegerOnly() {
198.364 + return parseIntegerOnly;
198.365 + }
198.366 +
198.367 + /**
198.368 + * Sets whether or not numbers should be parsed as integers only.
198.369 + * @see #isParseIntegerOnly
198.370 + */
198.371 + public void setParseIntegerOnly(boolean value) {
198.372 + parseIntegerOnly = value;
198.373 + }
198.374 +
198.375 + //============== Locale Stuff =====================
198.376 +
198.377 + /**
198.378 + * Returns a general-purpose number format for the current default locale.
198.379 + * This is the same as calling
198.380 + * {@link #getNumberInstance() getNumberInstance()}.
198.381 + */
198.382 + public final static NumberFormat getInstance() {
198.383 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
198.384 + }
198.385 +
198.386 + /**
198.387 + * Returns a general-purpose number format for the specified locale.
198.388 + * This is the same as calling
198.389 + * {@link #getNumberInstance(java.util.Locale) getNumberInstance(inLocale)}.
198.390 + */
198.391 + public static NumberFormat getInstance(Locale inLocale) {
198.392 + return getInstance(inLocale, NUMBERSTYLE);
198.393 + }
198.394 +
198.395 + /** * Returns a general-purpose number format for the current default locale.
198.396 + */
198.397 + public final static NumberFormat getNumberInstance() {
198.398 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
198.399 + }
198.400 +
198.401 + /**
198.402 + * Returns a general-purpose number format for the specified locale.
198.403 + */
198.404 + public static NumberFormat getNumberInstance(Locale inLocale) {
198.405 + return getInstance(inLocale, NUMBERSTYLE);
198.406 + }
198.407 +
198.408 + /**
198.409 + * Returns an integer number format for the current default locale. The
198.410 + * returned number format is configured to round floating point numbers
198.411 + * to the nearest integer using half-even rounding (see {@link
198.412 + * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
198.413 + * and to parse only the integer part of an input string (see {@link
198.414 + * #isParseIntegerOnly isParseIntegerOnly}).
198.415 + *
198.416 + * @see #getRoundingMode()
198.417 + * @return a number format for integer values
198.418 + * @since 1.4
198.419 + */
198.420 + public final static NumberFormat getIntegerInstance() {
198.421 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), INTEGERSTYLE);
198.422 + }
198.423 +
198.424 + /**
198.425 + * Returns an integer number format for the specified locale. The
198.426 + * returned number format is configured to round floating point numbers
198.427 + * to the nearest integer using half-even rounding (see {@link
198.428 + * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
198.429 + * and to parse only the integer part of an input string (see {@link
198.430 + * #isParseIntegerOnly isParseIntegerOnly}).
198.431 + *
198.432 + * @see #getRoundingMode()
198.433 + * @return a number format for integer values
198.434 + * @since 1.4
198.435 + */
198.436 + public static NumberFormat getIntegerInstance(Locale inLocale) {
198.437 + return getInstance(inLocale, INTEGERSTYLE);
198.438 + }
198.439 +
198.440 + /**
198.441 + * Returns a currency format for the current default locale.
198.442 + */
198.443 + public final static NumberFormat getCurrencyInstance() {
198.444 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE);
198.445 + }
198.446 +
198.447 + /**
198.448 + * Returns a currency format for the specified locale.
198.449 + */
198.450 + public static NumberFormat getCurrencyInstance(Locale inLocale) {
198.451 + return getInstance(inLocale, CURRENCYSTYLE);
198.452 + }
198.453 +
198.454 + /**
198.455 + * Returns a percentage format for the current default locale.
198.456 + */
198.457 + public final static NumberFormat getPercentInstance() {
198.458 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE);
198.459 + }
198.460 +
198.461 + /**
198.462 + * Returns a percentage format for the specified locale.
198.463 + */
198.464 + public static NumberFormat getPercentInstance(Locale inLocale) {
198.465 + return getInstance(inLocale, PERCENTSTYLE);
198.466 + }
198.467 +
198.468 + /**
198.469 + * Returns a scientific format for the current default locale.
198.470 + */
198.471 + /*public*/ final static NumberFormat getScientificInstance() {
198.472 + return getInstance(Locale.getDefault(Locale.Category.FORMAT), SCIENTIFICSTYLE);
198.473 + }
198.474 +
198.475 + /**
198.476 + * Returns a scientific format for the specified locale.
198.477 + */
198.478 + /*public*/ static NumberFormat getScientificInstance(Locale inLocale) {
198.479 + return getInstance(inLocale, SCIENTIFICSTYLE);
198.480 + }
198.481 +
198.482 + /**
198.483 + * Returns an array of all locales for which the
198.484 + * <code>get*Instance</code> methods of this class can return
198.485 + * localized instances.
198.486 + * The returned array represents the union of locales supported by the Java
198.487 + * runtime and by installed
198.488 + * {@link java.text.spi.NumberFormatProvider NumberFormatProvider} implementations.
198.489 + * It must contain at least a <code>Locale</code> instance equal to
198.490 + * {@link java.util.Locale#US Locale.US}.
198.491 + *
198.492 + * @return An array of locales for which localized
198.493 + * <code>NumberFormat</code> instances are available.
198.494 + */
198.495 + public static Locale[] getAvailableLocales() {
198.496 + return new Locale[] { Locale.US };
198.497 +// LocaleServiceProviderPool pool =
198.498 +// LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
198.499 +// return pool.getAvailableLocales();
198.500 + }
198.501 +
198.502 + /**
198.503 + * Overrides hashCode
198.504 + */
198.505 + public int hashCode() {
198.506 + return maximumIntegerDigits * 37 + maxFractionDigits;
198.507 + // just enough fields for a reasonable distribution
198.508 + }
198.509 +
198.510 + /**
198.511 + * Overrides equals
198.512 + */
198.513 + public boolean equals(Object obj) {
198.514 + if (obj == null) {
198.515 + return false;
198.516 + }
198.517 + if (this == obj) {
198.518 + return true;
198.519 + }
198.520 + if (getClass() != obj.getClass()) {
198.521 + return false;
198.522 + }
198.523 + NumberFormat other = (NumberFormat) obj;
198.524 + return (maximumIntegerDigits == other.maximumIntegerDigits
198.525 + && minimumIntegerDigits == other.minimumIntegerDigits
198.526 + && maximumFractionDigits == other.maximumFractionDigits
198.527 + && minimumFractionDigits == other.minimumFractionDigits
198.528 + && groupingUsed == other.groupingUsed
198.529 + && parseIntegerOnly == other.parseIntegerOnly);
198.530 + }
198.531 +
198.532 + /**
198.533 + * Overrides Cloneable
198.534 + */
198.535 + public Object clone() {
198.536 + NumberFormat other = (NumberFormat) super.clone();
198.537 + return other;
198.538 + }
198.539 +
198.540 + /**
198.541 + * Returns true if grouping is used in this format. For example, in the
198.542 + * English locale, with grouping on, the number 1234567 might be formatted
198.543 + * as "1,234,567". The grouping separator as well as the size of each group
198.544 + * is locale dependant and is determined by sub-classes of NumberFormat.
198.545 + * @see #setGroupingUsed
198.546 + */
198.547 + public boolean isGroupingUsed() {
198.548 + return groupingUsed;
198.549 + }
198.550 +
198.551 + /**
198.552 + * Set whether or not grouping will be used in this format.
198.553 + * @see #isGroupingUsed
198.554 + */
198.555 + public void setGroupingUsed(boolean newValue) {
198.556 + groupingUsed = newValue;
198.557 + }
198.558 +
198.559 + /**
198.560 + * Returns the maximum number of digits allowed in the integer portion of a
198.561 + * number.
198.562 + * @see #setMaximumIntegerDigits
198.563 + */
198.564 + public int getMaximumIntegerDigits() {
198.565 + return maximumIntegerDigits;
198.566 + }
198.567 +
198.568 + /**
198.569 + * Sets the maximum number of digits allowed in the integer portion of a
198.570 + * number. maximumIntegerDigits must be >= minimumIntegerDigits. If the
198.571 + * new value for maximumIntegerDigits is less than the current value
198.572 + * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
198.573 + * the new value.
198.574 + * @param newValue the maximum number of integer digits to be shown; if
198.575 + * less than zero, then zero is used. The concrete subclass may enforce an
198.576 + * upper limit to this value appropriate to the numeric type being formatted.
198.577 + * @see #getMaximumIntegerDigits
198.578 + */
198.579 + public void setMaximumIntegerDigits(int newValue) {
198.580 + maximumIntegerDigits = Math.max(0,newValue);
198.581 + if (minimumIntegerDigits > maximumIntegerDigits) {
198.582 + minimumIntegerDigits = maximumIntegerDigits;
198.583 + }
198.584 + }
198.585 +
198.586 + /**
198.587 + * Returns the minimum number of digits allowed in the integer portion of a
198.588 + * number.
198.589 + * @see #setMinimumIntegerDigits
198.590 + */
198.591 + public int getMinimumIntegerDigits() {
198.592 + return minimumIntegerDigits;
198.593 + }
198.594 +
198.595 + /**
198.596 + * Sets the minimum number of digits allowed in the integer portion of a
198.597 + * number. minimumIntegerDigits must be <= maximumIntegerDigits. If the
198.598 + * new value for minimumIntegerDigits exceeds the current value
198.599 + * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
198.600 + * the new value
198.601 + * @param newValue the minimum number of integer digits to be shown; if
198.602 + * less than zero, then zero is used. The concrete subclass may enforce an
198.603 + * upper limit to this value appropriate to the numeric type being formatted.
198.604 + * @see #getMinimumIntegerDigits
198.605 + */
198.606 + public void setMinimumIntegerDigits(int newValue) {
198.607 + minimumIntegerDigits = Math.max(0,newValue);
198.608 + if (minimumIntegerDigits > maximumIntegerDigits) {
198.609 + maximumIntegerDigits = minimumIntegerDigits;
198.610 + }
198.611 + }
198.612 +
198.613 + /**
198.614 + * Returns the maximum number of digits allowed in the fraction portion of a
198.615 + * number.
198.616 + * @see #setMaximumFractionDigits
198.617 + */
198.618 + public int getMaximumFractionDigits() {
198.619 + return maximumFractionDigits;
198.620 + }
198.621 +
198.622 + /**
198.623 + * Sets the maximum number of digits allowed in the fraction portion of a
198.624 + * number. maximumFractionDigits must be >= minimumFractionDigits. If the
198.625 + * new value for maximumFractionDigits is less than the current value
198.626 + * of minimumFractionDigits, then minimumFractionDigits will also be set to
198.627 + * the new value.
198.628 + * @param newValue the maximum number of fraction digits to be shown; if
198.629 + * less than zero, then zero is used. The concrete subclass may enforce an
198.630 + * upper limit to this value appropriate to the numeric type being formatted.
198.631 + * @see #getMaximumFractionDigits
198.632 + */
198.633 + public void setMaximumFractionDigits(int newValue) {
198.634 + maximumFractionDigits = Math.max(0,newValue);
198.635 + if (maximumFractionDigits < minimumFractionDigits) {
198.636 + minimumFractionDigits = maximumFractionDigits;
198.637 + }
198.638 + }
198.639 +
198.640 + /**
198.641 + * Returns the minimum number of digits allowed in the fraction portion of a
198.642 + * number.
198.643 + * @see #setMinimumFractionDigits
198.644 + */
198.645 + public int getMinimumFractionDigits() {
198.646 + return minimumFractionDigits;
198.647 + }
198.648 +
198.649 + /**
198.650 + * Sets the minimum number of digits allowed in the fraction portion of a
198.651 + * number. minimumFractionDigits must be <= maximumFractionDigits. If the
198.652 + * new value for minimumFractionDigits exceeds the current value
198.653 + * of maximumFractionDigits, then maximumIntegerDigits will also be set to
198.654 + * the new value
198.655 + * @param newValue the minimum number of fraction digits to be shown; if
198.656 + * less than zero, then zero is used. The concrete subclass may enforce an
198.657 + * upper limit to this value appropriate to the numeric type being formatted.
198.658 + * @see #getMinimumFractionDigits
198.659 + */
198.660 + public void setMinimumFractionDigits(int newValue) {
198.661 + minimumFractionDigits = Math.max(0,newValue);
198.662 + if (maximumFractionDigits < minimumFractionDigits) {
198.663 + maximumFractionDigits = minimumFractionDigits;
198.664 + }
198.665 + }
198.666 +
198.667 + /**
198.668 + * Gets the currency used by this number format when formatting
198.669 + * currency values. The initial value is derived in a locale dependent
198.670 + * way. The returned value may be null if no valid
198.671 + * currency could be determined and no currency has been set using
198.672 + * {@link #setCurrency(java.util.Currency) setCurrency}.
198.673 + * <p>
198.674 + * The default implementation throws
198.675 + * <code>UnsupportedOperationException</code>.
198.676 + *
198.677 + * @return the currency used by this number format, or <code>null</code>
198.678 + * @exception UnsupportedOperationException if the number format class
198.679 + * doesn't implement currency formatting
198.680 + * @since 1.4
198.681 + */
198.682 + public Currency getCurrency() {
198.683 + throw new UnsupportedOperationException();
198.684 + }
198.685 +
198.686 + /**
198.687 + * Sets the currency used by this number format when formatting
198.688 + * currency values. This does not update the minimum or maximum
198.689 + * number of fraction digits used by the number format.
198.690 + * <p>
198.691 + * The default implementation throws
198.692 + * <code>UnsupportedOperationException</code>.
198.693 + *
198.694 + * @param currency the new currency to be used by this number format
198.695 + * @exception UnsupportedOperationException if the number format class
198.696 + * doesn't implement currency formatting
198.697 + * @exception NullPointerException if <code>currency</code> is null
198.698 + * @since 1.4
198.699 + */
198.700 + public void setCurrency(Currency currency) {
198.701 + throw new UnsupportedOperationException();
198.702 + }
198.703 +
198.704 + /**
198.705 + * Gets the {@link java.math.RoundingMode} used in this NumberFormat.
198.706 + * The default implementation of this method in NumberFormat
198.707 + * always throws {@link java.lang.UnsupportedOperationException}.
198.708 + * Subclasses which handle different rounding modes should override
198.709 + * this method.
198.710 + *
198.711 + * @exception UnsupportedOperationException The default implementation
198.712 + * always throws this exception
198.713 + * @return The <code>RoundingMode</code> used for this NumberFormat.
198.714 + * @see #setRoundingMode(RoundingMode)
198.715 + * @since 1.6
198.716 + */
198.717 + public RoundingMode getRoundingMode() {
198.718 + throw new UnsupportedOperationException();
198.719 + }
198.720 +
198.721 + /**
198.722 + * Sets the {@link java.math.RoundingMode} used in this NumberFormat.
198.723 + * The default implementation of this method in NumberFormat always
198.724 + * throws {@link java.lang.UnsupportedOperationException}.
198.725 + * Subclasses which handle different rounding modes should override
198.726 + * this method.
198.727 + *
198.728 + * @exception UnsupportedOperationException The default implementation
198.729 + * always throws this exception
198.730 + * @exception NullPointerException if <code>roundingMode</code> is null
198.731 + * @param roundingMode The <code>RoundingMode</code> to be used
198.732 + * @see #getRoundingMode()
198.733 + * @since 1.6
198.734 + */
198.735 + public void setRoundingMode(RoundingMode roundingMode) {
198.736 + throw new UnsupportedOperationException();
198.737 + }
198.738 +
198.739 + // =======================privates===============================
198.740 +
198.741 + private static NumberFormat getInstance(Locale desiredLocale,
198.742 + int choice) {
198.743 + // Check whether a provider can provide an implementation that's closer
198.744 + // to the requested locale than what the Java runtime itself can provide.
198.745 +// LocaleServiceProviderPool pool =
198.746 +// LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
198.747 +// if (pool.hasProviders()) {
198.748 +// NumberFormat providersInstance = pool.getLocalizedObject(
198.749 +// NumberFormatGetter.INSTANCE,
198.750 +// desiredLocale,
198.751 +// choice);
198.752 +// if (providersInstance != null) {
198.753 +// return providersInstance;
198.754 +// }
198.755 +// }
198.756 +
198.757 + /* try the cache first */
198.758 + String[] numberPatterns = (String[])cachedLocaleData.get(desiredLocale);
198.759 +// if (numberPatterns == null) { /* cache miss */
198.760 +// ResourceBundle resource = LocaleData.getNumberFormatData(desiredLocale);
198.761 +// numberPatterns = resource.getStringArray("NumberPatterns");
198.762 +// /* update cache */
198.763 +// cachedLocaleData.put(desiredLocale, numberPatterns);
198.764 +// }
198.765 +
198.766 + DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(desiredLocale);
198.767 + int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
198.768 + DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
198.769 +
198.770 + if (choice == INTEGERSTYLE) {
198.771 + format.setMaximumFractionDigits(0);
198.772 + format.setDecimalSeparatorAlwaysShown(false);
198.773 + format.setParseIntegerOnly(true);
198.774 + } else if (choice == CURRENCYSTYLE) {
198.775 + format.adjustForCurrencyDefaultFractionDigits();
198.776 + }
198.777 +
198.778 + return format;
198.779 + }
198.780 +
198.781 + /**
198.782 + * First, read in the default serializable data.
198.783 + *
198.784 + * Then, if <code>serialVersionOnStream</code> is less than 1, indicating that
198.785 + * the stream was written by JDK 1.1,
198.786 + * set the <code>int</code> fields such as <code>maximumIntegerDigits</code>
198.787 + * to be equal to the <code>byte</code> fields such as <code>maxIntegerDigits</code>,
198.788 + * since the <code>int</code> fields were not present in JDK 1.1.
198.789 + * Finally, set serialVersionOnStream back to the maximum allowed value so that
198.790 + * default serialization will work properly if this object is streamed out again.
198.791 + *
198.792 + * <p>If <code>minimumIntegerDigits</code> is greater than
198.793 + * <code>maximumIntegerDigits</code> or <code>minimumFractionDigits</code>
198.794 + * is greater than <code>maximumFractionDigits</code>, then the stream data
198.795 + * is invalid and this method throws an <code>InvalidObjectException</code>.
198.796 + * In addition, if any of these values is negative, then this method throws
198.797 + * an <code>InvalidObjectException</code>.
198.798 + *
198.799 + * @since 1.2
198.800 + */
198.801 + private void readObject(ObjectInputStream stream)
198.802 + throws IOException, ClassNotFoundException
198.803 + {
198.804 + stream.defaultReadObject();
198.805 + if (serialVersionOnStream < 1) {
198.806 + // Didn't have additional int fields, reassign to use them.
198.807 + maximumIntegerDigits = maxIntegerDigits;
198.808 + minimumIntegerDigits = minIntegerDigits;
198.809 + maximumFractionDigits = maxFractionDigits;
198.810 + minimumFractionDigits = minFractionDigits;
198.811 + }
198.812 + if (minimumIntegerDigits > maximumIntegerDigits ||
198.813 + minimumFractionDigits > maximumFractionDigits ||
198.814 + minimumIntegerDigits < 0 || minimumFractionDigits < 0) {
198.815 + throw new InvalidObjectException("Digit count range invalid");
198.816 + }
198.817 + serialVersionOnStream = currentSerialVersion;
198.818 + }
198.819 +
198.820 + /**
198.821 + * Write out the default serializable data, after first setting
198.822 + * the <code>byte</code> fields such as <code>maxIntegerDigits</code> to be
198.823 + * equal to the <code>int</code> fields such as <code>maximumIntegerDigits</code>
198.824 + * (or to <code>Byte.MAX_VALUE</code>, whichever is smaller), for compatibility
198.825 + * with the JDK 1.1 version of the stream format.
198.826 + *
198.827 + * @since 1.2
198.828 + */
198.829 + private void writeObject(ObjectOutputStream stream)
198.830 + throws IOException
198.831 + {
198.832 + maxIntegerDigits = (maximumIntegerDigits > Byte.MAX_VALUE) ?
198.833 + Byte.MAX_VALUE : (byte)maximumIntegerDigits;
198.834 + minIntegerDigits = (minimumIntegerDigits > Byte.MAX_VALUE) ?
198.835 + Byte.MAX_VALUE : (byte)minimumIntegerDigits;
198.836 + maxFractionDigits = (maximumFractionDigits > Byte.MAX_VALUE) ?
198.837 + Byte.MAX_VALUE : (byte)maximumFractionDigits;
198.838 + minFractionDigits = (minimumFractionDigits > Byte.MAX_VALUE) ?
198.839 + Byte.MAX_VALUE : (byte)minimumFractionDigits;
198.840 + stream.defaultWriteObject();
198.841 + }
198.842 +
198.843 + /**
198.844 + * Cache to hold the NumberPatterns of a Locale.
198.845 + */
198.846 + private static final Hashtable cachedLocaleData = new Hashtable(3);
198.847 +
198.848 + // Constants used by factory methods to specify a style of format.
198.849 + private static final int NUMBERSTYLE = 0;
198.850 + private static final int CURRENCYSTYLE = 1;
198.851 + private static final int PERCENTSTYLE = 2;
198.852 + private static final int SCIENTIFICSTYLE = 3;
198.853 + private static final int INTEGERSTYLE = 4;
198.854 +
198.855 + /**
198.856 + * True if the grouping (i.e. thousands) separator is used when
198.857 + * formatting and parsing numbers.
198.858 + *
198.859 + * @serial
198.860 + * @see #isGroupingUsed
198.861 + */
198.862 + private boolean groupingUsed = true;
198.863 +
198.864 + /**
198.865 + * The maximum number of digits allowed in the integer portion of a
198.866 + * number. <code>maxIntegerDigits</code> must be greater than or equal to
198.867 + * <code>minIntegerDigits</code>.
198.868 + * <p>
198.869 + * <strong>Note:</strong> This field exists only for serialization
198.870 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
198.871 + * <code>int</code> field <code>maximumIntegerDigits</code> is used instead.
198.872 + * When writing to a stream, <code>maxIntegerDigits</code> is set to
198.873 + * <code>maximumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
198.874 + * whichever is smaller. When reading from a stream, this field is used
198.875 + * only if <code>serialVersionOnStream</code> is less than 1.
198.876 + *
198.877 + * @serial
198.878 + * @see #getMaximumIntegerDigits
198.879 + */
198.880 + private byte maxIntegerDigits = 40;
198.881 +
198.882 + /**
198.883 + * The minimum number of digits allowed in the integer portion of a
198.884 + * number. <code>minimumIntegerDigits</code> must be less than or equal to
198.885 + * <code>maximumIntegerDigits</code>.
198.886 + * <p>
198.887 + * <strong>Note:</strong> This field exists only for serialization
198.888 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
198.889 + * <code>int</code> field <code>minimumIntegerDigits</code> is used instead.
198.890 + * When writing to a stream, <code>minIntegerDigits</code> is set to
198.891 + * <code>minimumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
198.892 + * whichever is smaller. When reading from a stream, this field is used
198.893 + * only if <code>serialVersionOnStream</code> is less than 1.
198.894 + *
198.895 + * @serial
198.896 + * @see #getMinimumIntegerDigits
198.897 + */
198.898 + private byte minIntegerDigits = 1;
198.899 +
198.900 + /**
198.901 + * The maximum number of digits allowed in the fractional portion of a
198.902 + * number. <code>maximumFractionDigits</code> must be greater than or equal to
198.903 + * <code>minimumFractionDigits</code>.
198.904 + * <p>
198.905 + * <strong>Note:</strong> This field exists only for serialization
198.906 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
198.907 + * <code>int</code> field <code>maximumFractionDigits</code> is used instead.
198.908 + * When writing to a stream, <code>maxFractionDigits</code> is set to
198.909 + * <code>maximumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
198.910 + * whichever is smaller. When reading from a stream, this field is used
198.911 + * only if <code>serialVersionOnStream</code> is less than 1.
198.912 + *
198.913 + * @serial
198.914 + * @see #getMaximumFractionDigits
198.915 + */
198.916 + private byte maxFractionDigits = 3; // invariant, >= minFractionDigits
198.917 +
198.918 + /**
198.919 + * The minimum number of digits allowed in the fractional portion of a
198.920 + * number. <code>minimumFractionDigits</code> must be less than or equal to
198.921 + * <code>maximumFractionDigits</code>.
198.922 + * <p>
198.923 + * <strong>Note:</strong> This field exists only for serialization
198.924 + * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
198.925 + * <code>int</code> field <code>minimumFractionDigits</code> is used instead.
198.926 + * When writing to a stream, <code>minFractionDigits</code> is set to
198.927 + * <code>minimumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
198.928 + * whichever is smaller. When reading from a stream, this field is used
198.929 + * only if <code>serialVersionOnStream</code> is less than 1.
198.930 + *
198.931 + * @serial
198.932 + * @see #getMinimumFractionDigits
198.933 + */
198.934 + private byte minFractionDigits = 0;
198.935 +
198.936 + /**
198.937 + * True if this format will parse numbers as integers only.
198.938 + *
198.939 + * @serial
198.940 + * @see #isParseIntegerOnly
198.941 + */
198.942 + private boolean parseIntegerOnly = false;
198.943 +
198.944 + // new fields for 1.2. byte is too small for integer digits.
198.945 +
198.946 + /**
198.947 + * The maximum number of digits allowed in the integer portion of a
198.948 + * number. <code>maximumIntegerDigits</code> must be greater than or equal to
198.949 + * <code>minimumIntegerDigits</code>.
198.950 + *
198.951 + * @serial
198.952 + * @since 1.2
198.953 + * @see #getMaximumIntegerDigits
198.954 + */
198.955 + private int maximumIntegerDigits = 40;
198.956 +
198.957 + /**
198.958 + * The minimum number of digits allowed in the integer portion of a
198.959 + * number. <code>minimumIntegerDigits</code> must be less than or equal to
198.960 + * <code>maximumIntegerDigits</code>.
198.961 + *
198.962 + * @serial
198.963 + * @since 1.2
198.964 + * @see #getMinimumIntegerDigits
198.965 + */
198.966 + private int minimumIntegerDigits = 1;
198.967 +
198.968 + /**
198.969 + * The maximum number of digits allowed in the fractional portion of a
198.970 + * number. <code>maximumFractionDigits</code> must be greater than or equal to
198.971 + * <code>minimumFractionDigits</code>.
198.972 + *
198.973 + * @serial
198.974 + * @since 1.2
198.975 + * @see #getMaximumFractionDigits
198.976 + */
198.977 + private int maximumFractionDigits = 3; // invariant, >= minFractionDigits
198.978 +
198.979 + /**
198.980 + * The minimum number of digits allowed in the fractional portion of a
198.981 + * number. <code>minimumFractionDigits</code> must be less than or equal to
198.982 + * <code>maximumFractionDigits</code>.
198.983 + *
198.984 + * @serial
198.985 + * @since 1.2
198.986 + * @see #getMinimumFractionDigits
198.987 + */
198.988 + private int minimumFractionDigits = 0;
198.989 +
198.990 + static final int currentSerialVersion = 1;
198.991 +
198.992 + /**
198.993 + * Describes the version of <code>NumberFormat</code> present on the stream.
198.994 + * Possible values are:
198.995 + * <ul>
198.996 + * <li><b>0</b> (or uninitialized): the JDK 1.1 version of the stream format.
198.997 + * In this version, the <code>int</code> fields such as
198.998 + * <code>maximumIntegerDigits</code> were not present, and the <code>byte</code>
198.999 + * fields such as <code>maxIntegerDigits</code> are used instead.
198.1000 + *
198.1001 + * <li><b>1</b>: the 1.2 version of the stream format. The values of the
198.1002 + * <code>byte</code> fields such as <code>maxIntegerDigits</code> are ignored,
198.1003 + * and the <code>int</code> fields such as <code>maximumIntegerDigits</code>
198.1004 + * are used instead.
198.1005 + * </ul>
198.1006 + * When streaming out a <code>NumberFormat</code>, the most recent format
198.1007 + * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
198.1008 + * is always written.
198.1009 + *
198.1010 + * @serial
198.1011 + * @since 1.2
198.1012 + */
198.1013 + private int serialVersionOnStream = currentSerialVersion;
198.1014 +
198.1015 + // Removed "implements Cloneable" clause. Needs to update serialization
198.1016 + // ID for backward compatibility.
198.1017 + static final long serialVersionUID = -2308460125733713944L;
198.1018 +
198.1019 +
198.1020 + //
198.1021 + // class for AttributedCharacterIterator attributes
198.1022 + //
198.1023 + /**
198.1024 + * Defines constants that are used as attribute keys in the
198.1025 + * <code>AttributedCharacterIterator</code> returned
198.1026 + * from <code>NumberFormat.formatToCharacterIterator</code> and as
198.1027 + * field identifiers in <code>FieldPosition</code>.
198.1028 + *
198.1029 + * @since 1.4
198.1030 + */
198.1031 + public static class Field extends Format.Field {
198.1032 +
198.1033 + // Proclaim serial compatibility with 1.4 FCS
198.1034 + private static final long serialVersionUID = 7494728892700160890L;
198.1035 +
198.1036 + // table of all instances in this class, used by readResolve
198.1037 + private static final Map instanceMap = new HashMap(11);
198.1038 +
198.1039 + /**
198.1040 + * Creates a Field instance with the specified
198.1041 + * name.
198.1042 + *
198.1043 + * @param name Name of the attribute
198.1044 + */
198.1045 + protected Field(String name) {
198.1046 + super(name);
198.1047 + if (this.getClass() == NumberFormat.Field.class) {
198.1048 + instanceMap.put(name, this);
198.1049 + }
198.1050 + }
198.1051 +
198.1052 + /**
198.1053 + * Resolves instances being deserialized to the predefined constants.
198.1054 + *
198.1055 + * @throws InvalidObjectException if the constant could not be resolved.
198.1056 + * @return resolved NumberFormat.Field constant
198.1057 + */
198.1058 + protected Object readResolve() throws InvalidObjectException {
198.1059 + if (this.getClass() != NumberFormat.Field.class) {
198.1060 + throw new InvalidObjectException("subclass didn't correctly implement readResolve");
198.1061 + }
198.1062 +
198.1063 + Object instance = instanceMap.get(getName());
198.1064 + if (instance != null) {
198.1065 + return instance;
198.1066 + } else {
198.1067 + throw new InvalidObjectException("unknown attribute name");
198.1068 + }
198.1069 + }
198.1070 +
198.1071 + /**
198.1072 + * Constant identifying the integer field.
198.1073 + */
198.1074 + public static final Field INTEGER = new Field("integer");
198.1075 +
198.1076 + /**
198.1077 + * Constant identifying the fraction field.
198.1078 + */
198.1079 + public static final Field FRACTION = new Field("fraction");
198.1080 +
198.1081 + /**
198.1082 + * Constant identifying the exponent field.
198.1083 + */
198.1084 + public static final Field EXPONENT = new Field("exponent");
198.1085 +
198.1086 + /**
198.1087 + * Constant identifying the decimal separator field.
198.1088 + */
198.1089 + public static final Field DECIMAL_SEPARATOR =
198.1090 + new Field("decimal separator");
198.1091 +
198.1092 + /**
198.1093 + * Constant identifying the sign field.
198.1094 + */
198.1095 + public static final Field SIGN = new Field("sign");
198.1096 +
198.1097 + /**
198.1098 + * Constant identifying the grouping separator field.
198.1099 + */
198.1100 + public static final Field GROUPING_SEPARATOR =
198.1101 + new Field("grouping separator");
198.1102 +
198.1103 + /**
198.1104 + * Constant identifying the exponent symbol field.
198.1105 + */
198.1106 + public static final Field EXPONENT_SYMBOL = new
198.1107 + Field("exponent symbol");
198.1108 +
198.1109 + /**
198.1110 + * Constant identifying the percent field.
198.1111 + */
198.1112 + public static final Field PERCENT = new Field("percent");
198.1113 +
198.1114 + /**
198.1115 + * Constant identifying the permille field.
198.1116 + */
198.1117 + public static final Field PERMILLE = new Field("per mille");
198.1118 +
198.1119 + /**
198.1120 + * Constant identifying the currency field.
198.1121 + */
198.1122 + public static final Field CURRENCY = new Field("currency");
198.1123 +
198.1124 + /**
198.1125 + * Constant identifying the exponent sign field.
198.1126 + */
198.1127 + public static final Field EXPONENT_SIGN = new Field("exponent sign");
198.1128 + }
198.1129 +
198.1130 + /**
198.1131 + * Obtains a NumberFormat instance from a NumberFormatProvider implementation.
198.1132 + *
198.1133 + private static class NumberFormatGetter
198.1134 + implements LocaleServiceProviderPool.LocalizedObjectGetter<NumberFormatProvider,
198.1135 + NumberFormat> {
198.1136 + private static final NumberFormatGetter INSTANCE = new NumberFormatGetter();
198.1137 +
198.1138 + public NumberFormat getObject(NumberFormatProvider numberFormatProvider,
198.1139 + Locale locale,
198.1140 + String key,
198.1141 + Object... params) {
198.1142 + assert params.length == 1;
198.1143 + int choice = (Integer)params[0];
198.1144 +
198.1145 + switch (choice) {
198.1146 + case NUMBERSTYLE:
198.1147 + return numberFormatProvider.getNumberInstance(locale);
198.1148 + case PERCENTSTYLE:
198.1149 + return numberFormatProvider.getPercentInstance(locale);
198.1150 + case CURRENCYSTYLE:
198.1151 + return numberFormatProvider.getCurrencyInstance(locale);
198.1152 + case INTEGERSTYLE:
198.1153 + return numberFormatProvider.getIntegerInstance(locale);
198.1154 + default:
198.1155 + assert false : choice;
198.1156 + }
198.1157 +
198.1158 + return null;
198.1159 + }
198.1160 + }
198.1161 + */
198.1162 +}
199.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
199.2 +++ b/rt/emul/compact/src/main/java/java/text/ParseException.java Wed Apr 30 15:04:10 2014 +0200
199.3 @@ -0,0 +1,78 @@
199.4 +/*
199.5 + * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
199.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
199.7 + *
199.8 + * This code is free software; you can redistribute it and/or modify it
199.9 + * under the terms of the GNU General Public License version 2 only, as
199.10 + * published by the Free Software Foundation. Oracle designates this
199.11 + * particular file as subject to the "Classpath" exception as provided
199.12 + * by Oracle in the LICENSE file that accompanied this code.
199.13 + *
199.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
199.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
199.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
199.17 + * version 2 for more details (a copy is included in the LICENSE file that
199.18 + * accompanied this code).
199.19 + *
199.20 + * You should have received a copy of the GNU General Public License version
199.21 + * 2 along with this work; if not, write to the Free Software Foundation,
199.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
199.23 + *
199.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
199.25 + * or visit www.oracle.com if you need additional information or have any
199.26 + * questions.
199.27 + */
199.28 +
199.29 +/*
199.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
199.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
199.32 + *
199.33 + * The original version of this source code and documentation is copyrighted
199.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
199.35 + * materials are provided under terms of a License Agreement between Taligent
199.36 + * and Sun. This technology is protected by multiple US and International
199.37 + * patents. This notice and attribution to Taligent may not be removed.
199.38 + * Taligent is a registered trademark of Taligent, Inc.
199.39 + *
199.40 + */
199.41 +
199.42 +package java.text;
199.43 +
199.44 +/**
199.45 + * Signals that an error has been reached unexpectedly
199.46 + * while parsing.
199.47 + * @see java.lang.Exception
199.48 + * @see java.text.Format
199.49 + * @see java.text.FieldPosition
199.50 + * @author Mark Davis
199.51 + */
199.52 +public
199.53 +class ParseException extends Exception {
199.54 +
199.55 + /**
199.56 + * Constructs a ParseException with the specified detail message and
199.57 + * offset.
199.58 + * A detail message is a String that describes this particular exception.
199.59 + * @param s the detail message
199.60 + * @param errorOffset the position where the error is found while parsing.
199.61 + */
199.62 + public ParseException(String s, int errorOffset) {
199.63 + super(s);
199.64 + this.errorOffset = errorOffset;
199.65 + }
199.66 +
199.67 + /**
199.68 + * Returns the position where the error was found.
199.69 + */
199.70 + public int getErrorOffset () {
199.71 + return errorOffset;
199.72 + }
199.73 +
199.74 + //============ privates ============
199.75 + /**
199.76 + * The zero-based character offset into the string being parsed at which
199.77 + * the error was found during parsing.
199.78 + * @serial
199.79 + */
199.80 + private int errorOffset;
199.81 +}
200.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
200.2 +++ b/rt/emul/compact/src/main/java/java/text/ParsePosition.java Wed Apr 30 15:04:10 2014 +0200
200.3 @@ -0,0 +1,139 @@
200.4 +/*
200.5 + * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
200.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
200.7 + *
200.8 + * This code is free software; you can redistribute it and/or modify it
200.9 + * under the terms of the GNU General Public License version 2 only, as
200.10 + * published by the Free Software Foundation. Oracle designates this
200.11 + * particular file as subject to the "Classpath" exception as provided
200.12 + * by Oracle in the LICENSE file that accompanied this code.
200.13 + *
200.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
200.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
200.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
200.17 + * version 2 for more details (a copy is included in the LICENSE file that
200.18 + * accompanied this code).
200.19 + *
200.20 + * You should have received a copy of the GNU General Public License version
200.21 + * 2 along with this work; if not, write to the Free Software Foundation,
200.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
200.23 + *
200.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
200.25 + * or visit www.oracle.com if you need additional information or have any
200.26 + * questions.
200.27 + */
200.28 +
200.29 +/*
200.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
200.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
200.32 + *
200.33 + * The original version of this source code and documentation is copyrighted
200.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
200.35 + * materials are provided under terms of a License Agreement between Taligent
200.36 + * and Sun. This technology is protected by multiple US and International
200.37 + * patents. This notice and attribution to Taligent may not be removed.
200.38 + * Taligent is a registered trademark of Taligent, Inc.
200.39 + *
200.40 + */
200.41 +
200.42 +package java.text;
200.43 +
200.44 +
200.45 +/**
200.46 + * <code>ParsePosition</code> is a simple class used by <code>Format</code>
200.47 + * and its subclasses to keep track of the current position during parsing.
200.48 + * The <code>parseObject</code> method in the various <code>Format</code>
200.49 + * classes requires a <code>ParsePosition</code> object as an argument.
200.50 + *
200.51 + * <p>
200.52 + * By design, as you parse through a string with different formats,
200.53 + * you can use the same <code>ParsePosition</code>, since the index parameter
200.54 + * records the current position.
200.55 + *
200.56 + * @author Mark Davis
200.57 + * @see java.text.Format
200.58 + */
200.59 +
200.60 +public class ParsePosition {
200.61 +
200.62 + /**
200.63 + * Input: the place you start parsing.
200.64 + * <br>Output: position where the parse stopped.
200.65 + * This is designed to be used serially,
200.66 + * with each call setting index up for the next one.
200.67 + */
200.68 + int index = 0;
200.69 + int errorIndex = -1;
200.70 +
200.71 + /**
200.72 + * Retrieve the current parse position. On input to a parse method, this
200.73 + * is the index of the character at which parsing will begin; on output, it
200.74 + * is the index of the character following the last character parsed.
200.75 + */
200.76 + public int getIndex() {
200.77 + return index;
200.78 + }
200.79 +
200.80 + /**
200.81 + * Set the current parse position.
200.82 + */
200.83 + public void setIndex(int index) {
200.84 + this.index = index;
200.85 + }
200.86 +
200.87 + /**
200.88 + * Create a new ParsePosition with the given initial index.
200.89 + */
200.90 + public ParsePosition(int index) {
200.91 + this.index = index;
200.92 + }
200.93 + /**
200.94 + * Set the index at which a parse error occurred. Formatters
200.95 + * should set this before returning an error code from their
200.96 + * parseObject method. The default value is -1 if this is not set.
200.97 + * @since 1.2
200.98 + */
200.99 + public void setErrorIndex(int ei)
200.100 + {
200.101 + errorIndex = ei;
200.102 + }
200.103 +
200.104 + /**
200.105 + * Retrieve the index at which an error occurred, or -1 if the
200.106 + * error index has not been set.
200.107 + * @since 1.2
200.108 + */
200.109 + public int getErrorIndex()
200.110 + {
200.111 + return errorIndex;
200.112 + }
200.113 + /**
200.114 + * Overrides equals
200.115 + */
200.116 + public boolean equals(Object obj)
200.117 + {
200.118 + if (obj == null) return false;
200.119 + if (!(obj instanceof ParsePosition))
200.120 + return false;
200.121 + ParsePosition other = (ParsePosition) obj;
200.122 + return (index == other.index && errorIndex == other.errorIndex);
200.123 + }
200.124 +
200.125 + /**
200.126 + * Returns a hash code for this ParsePosition.
200.127 + * @return a hash code value for this object
200.128 + */
200.129 + public int hashCode() {
200.130 + return (errorIndex << 16) | index;
200.131 + }
200.132 +
200.133 + /**
200.134 + * Return a string representation of this ParsePosition.
200.135 + * @return a string representation of this object
200.136 + */
200.137 + public String toString() {
200.138 + return getClass().getName() +
200.139 + "[index=" + index +
200.140 + ",errorIndex=" + errorIndex + ']';
200.141 + }
200.142 +}
201.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
201.2 +++ b/rt/emul/compact/src/main/java/java/text/SimpleDateFormat.java Wed Apr 30 15:04:10 2014 +0200
201.3 @@ -0,0 +1,2383 @@
201.4 +/*
201.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
201.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
201.7 + *
201.8 + * This code is free software; you can redistribute it and/or modify it
201.9 + * under the terms of the GNU General Public License version 2 only, as
201.10 + * published by the Free Software Foundation. Oracle designates this
201.11 + * particular file as subject to the "Classpath" exception as provided
201.12 + * by Oracle in the LICENSE file that accompanied this code.
201.13 + *
201.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
201.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
201.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
201.17 + * version 2 for more details (a copy is included in the LICENSE file that
201.18 + * accompanied this code).
201.19 + *
201.20 + * You should have received a copy of the GNU General Public License version
201.21 + * 2 along with this work; if not, write to the Free Software Foundation,
201.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
201.23 + *
201.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
201.25 + * or visit www.oracle.com if you need additional information or have any
201.26 + * questions.
201.27 + */
201.28 +
201.29 +/*
201.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
201.31 + * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
201.32 + *
201.33 + * The original version of this source code and documentation is copyrighted
201.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
201.35 + * materials are provided under terms of a License Agreement between Taligent
201.36 + * and Sun. This technology is protected by multiple US and International
201.37 + * patents. This notice and attribution to Taligent may not be removed.
201.38 + * Taligent is a registered trademark of Taligent, Inc.
201.39 + *
201.40 + */
201.41 +
201.42 +package java.text;
201.43 +
201.44 +import java.io.IOException;
201.45 +import java.io.InvalidObjectException;
201.46 +import java.io.ObjectInputStream;
201.47 +import java.util.Calendar;
201.48 +import java.util.Date;
201.49 +import java.util.Locale;
201.50 +import java.util.Map;
201.51 +import java.util.MissingResourceException;
201.52 +import java.util.ResourceBundle;
201.53 +import java.util.SimpleTimeZone;
201.54 +import java.util.TimeZone;
201.55 +import java.util.concurrent.ConcurrentHashMap;
201.56 +import java.util.concurrent.ConcurrentMap;
201.57 +
201.58 +import static java.text.DateFormatSymbols.*;
201.59 +
201.60 +/**
201.61 + * <code>SimpleDateFormat</code> is a concrete class for formatting and
201.62 + * parsing dates in a locale-sensitive manner. It allows for formatting
201.63 + * (date -> text), parsing (text -> date), and normalization.
201.64 + *
201.65 + * <p>
201.66 + * <code>SimpleDateFormat</code> allows you to start by choosing
201.67 + * any user-defined patterns for date-time formatting. However, you
201.68 + * are encouraged to create a date-time formatter with either
201.69 + * <code>getTimeInstance</code>, <code>getDateInstance</code>, or
201.70 + * <code>getDateTimeInstance</code> in <code>DateFormat</code>. Each
201.71 + * of these class methods can return a date/time formatter initialized
201.72 + * with a default format pattern. You may modify the format pattern
201.73 + * using the <code>applyPattern</code> methods as desired.
201.74 + * For more information on using these methods, see
201.75 + * {@link DateFormat}.
201.76 + *
201.77 + * <h4>Date and Time Patterns</h4>
201.78 + * <p>
201.79 + * Date and time formats are specified by <em>date and time pattern</em>
201.80 + * strings.
201.81 + * Within date and time pattern strings, unquoted letters from
201.82 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
201.83 + * <code>'z'</code> are interpreted as pattern letters representing the
201.84 + * components of a date or time string.
201.85 + * Text can be quoted using single quotes (<code>'</code>) to avoid
201.86 + * interpretation.
201.87 + * <code>"''"</code> represents a single quote.
201.88 + * All other characters are not interpreted; they're simply copied into the
201.89 + * output string during formatting or matched against the input string
201.90 + * during parsing.
201.91 + * <p>
201.92 + * The following pattern letters are defined (all other characters from
201.93 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
201.94 + * <code>'z'</code> are reserved):
201.95 + * <blockquote>
201.96 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart shows pattern letters, date/time component, presentation, and examples.">
201.97 + * <tr bgcolor="#ccccff">
201.98 + * <th align=left>Letter
201.99 + * <th align=left>Date or Time Component
201.100 + * <th align=left>Presentation
201.101 + * <th align=left>Examples
201.102 + * <tr>
201.103 + * <td><code>G</code>
201.104 + * <td>Era designator
201.105 + * <td><a href="#text">Text</a>
201.106 + * <td><code>AD</code>
201.107 + * <tr bgcolor="#eeeeff">
201.108 + * <td><code>y</code>
201.109 + * <td>Year
201.110 + * <td><a href="#year">Year</a>
201.111 + * <td><code>1996</code>; <code>96</code>
201.112 + * <tr>
201.113 + * <td><code>Y</code>
201.114 + * <td>Week year
201.115 + * <td><a href="#year">Year</a>
201.116 + * <td><code>2009</code>; <code>09</code>
201.117 + * <tr bgcolor="#eeeeff">
201.118 + * <td><code>M</code>
201.119 + * <td>Month in year
201.120 + * <td><a href="#month">Month</a>
201.121 + * <td><code>July</code>; <code>Jul</code>; <code>07</code>
201.122 + * <tr>
201.123 + * <td><code>w</code>
201.124 + * <td>Week in year
201.125 + * <td><a href="#number">Number</a>
201.126 + * <td><code>27</code>
201.127 + * <tr bgcolor="#eeeeff">
201.128 + * <td><code>W</code>
201.129 + * <td>Week in month
201.130 + * <td><a href="#number">Number</a>
201.131 + * <td><code>2</code>
201.132 + * <tr>
201.133 + * <td><code>D</code>
201.134 + * <td>Day in year
201.135 + * <td><a href="#number">Number</a>
201.136 + * <td><code>189</code>
201.137 + * <tr bgcolor="#eeeeff">
201.138 + * <td><code>d</code>
201.139 + * <td>Day in month
201.140 + * <td><a href="#number">Number</a>
201.141 + * <td><code>10</code>
201.142 + * <tr>
201.143 + * <td><code>F</code>
201.144 + * <td>Day of week in month
201.145 + * <td><a href="#number">Number</a>
201.146 + * <td><code>2</code>
201.147 + * <tr bgcolor="#eeeeff">
201.148 + * <td><code>E</code>
201.149 + * <td>Day name in week
201.150 + * <td><a href="#text">Text</a>
201.151 + * <td><code>Tuesday</code>; <code>Tue</code>
201.152 + * <tr>
201.153 + * <td><code>u</code>
201.154 + * <td>Day number of week (1 = Monday, ..., 7 = Sunday)
201.155 + * <td><a href="#number">Number</a>
201.156 + * <td><code>1</code>
201.157 + * <tr bgcolor="#eeeeff">
201.158 + * <td><code>a</code>
201.159 + * <td>Am/pm marker
201.160 + * <td><a href="#text">Text</a>
201.161 + * <td><code>PM</code>
201.162 + * <tr>
201.163 + * <td><code>H</code>
201.164 + * <td>Hour in day (0-23)
201.165 + * <td><a href="#number">Number</a>
201.166 + * <td><code>0</code>
201.167 + * <tr bgcolor="#eeeeff">
201.168 + * <td><code>k</code>
201.169 + * <td>Hour in day (1-24)
201.170 + * <td><a href="#number">Number</a>
201.171 + * <td><code>24</code>
201.172 + * <tr>
201.173 + * <td><code>K</code>
201.174 + * <td>Hour in am/pm (0-11)
201.175 + * <td><a href="#number">Number</a>
201.176 + * <td><code>0</code>
201.177 + * <tr bgcolor="#eeeeff">
201.178 + * <td><code>h</code>
201.179 + * <td>Hour in am/pm (1-12)
201.180 + * <td><a href="#number">Number</a>
201.181 + * <td><code>12</code>
201.182 + * <tr>
201.183 + * <td><code>m</code>
201.184 + * <td>Minute in hour
201.185 + * <td><a href="#number">Number</a>
201.186 + * <td><code>30</code>
201.187 + * <tr bgcolor="#eeeeff">
201.188 + * <td><code>s</code>
201.189 + * <td>Second in minute
201.190 + * <td><a href="#number">Number</a>
201.191 + * <td><code>55</code>
201.192 + * <tr>
201.193 + * <td><code>S</code>
201.194 + * <td>Millisecond
201.195 + * <td><a href="#number">Number</a>
201.196 + * <td><code>978</code>
201.197 + * <tr bgcolor="#eeeeff">
201.198 + * <td><code>z</code>
201.199 + * <td>Time zone
201.200 + * <td><a href="#timezone">General time zone</a>
201.201 + * <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code>
201.202 + * <tr>
201.203 + * <td><code>Z</code>
201.204 + * <td>Time zone
201.205 + * <td><a href="#rfc822timezone">RFC 822 time zone</a>
201.206 + * <td><code>-0800</code>
201.207 + * <tr bgcolor="#eeeeff">
201.208 + * <td><code>X</code>
201.209 + * <td>Time zone
201.210 + * <td><a href="#iso8601timezone">ISO 8601 time zone</a>
201.211 + * <td><code>-08</code>; <code>-0800</code>; <code>-08:00</code>
201.212 + * </table>
201.213 + * </blockquote>
201.214 + * Pattern letters are usually repeated, as their number determines the
201.215 + * exact presentation:
201.216 + * <ul>
201.217 + * <li><strong><a name="text">Text:</a></strong>
201.218 + * For formatting, if the number of pattern letters is 4 or more,
201.219 + * the full form is used; otherwise a short or abbreviated form
201.220 + * is used if available.
201.221 + * For parsing, both forms are accepted, independent of the number
201.222 + * of pattern letters.<br><br></li>
201.223 + * <li><strong><a name="number">Number:</a></strong>
201.224 + * For formatting, the number of pattern letters is the minimum
201.225 + * number of digits, and shorter numbers are zero-padded to this amount.
201.226 + * For parsing, the number of pattern letters is ignored unless
201.227 + * it's needed to separate two adjacent fields.<br><br></li>
201.228 + * <li><strong><a name="year">Year:</a></strong>
201.229 + * If the formatter's {@link #getCalendar() Calendar} is the Gregorian
201.230 + * calendar, the following rules are applied.<br>
201.231 + * <ul>
201.232 + * <li>For formatting, if the number of pattern letters is 2, the year
201.233 + * is truncated to 2 digits; otherwise it is interpreted as a
201.234 + * <a href="#number">number</a>.
201.235 + * <li>For parsing, if the number of pattern letters is more than 2,
201.236 + * the year is interpreted literally, regardless of the number of
201.237 + * digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to
201.238 + * Jan 11, 12 A.D.
201.239 + * <li>For parsing with the abbreviated year pattern ("y" or "yy"),
201.240 + * <code>SimpleDateFormat</code> must interpret the abbreviated year
201.241 + * relative to some century. It does this by adjusting dates to be
201.242 + * within 80 years before and 20 years after the time the <code>SimpleDateFormat</code>
201.243 + * instance is created. For example, using a pattern of "MM/dd/yy" and a
201.244 + * <code>SimpleDateFormat</code> instance created on Jan 1, 1997, the string
201.245 + * "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
201.246 + * would be interpreted as May 4, 1964.
201.247 + * During parsing, only strings consisting of exactly two digits, as defined by
201.248 + * {@link Character#isDigit(char)}, will be parsed into the default century.
201.249 + * Any other numeric string, such as a one digit string, a three or more digit
201.250 + * string, or a two digit string that isn't all digits (for example, "-1"), is
201.251 + * interpreted literally. So "01/02/3" or "01/02/003" are parsed, using the
201.252 + * same pattern, as Jan 2, 3 AD. Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
201.253 + * </ul>
201.254 + * Otherwise, calendar system specific forms are applied.
201.255 + * For both formatting and parsing, if the number of pattern
201.256 + * letters is 4 or more, a calendar specific {@linkplain
201.257 + * Calendar#LONG long form} is used. Otherwise, a calendar
201.258 + * specific {@linkplain Calendar#SHORT short or abbreviated form}
201.259 + * is used.<br>
201.260 + * <br>
201.261 + * If week year {@code 'Y'} is specified and the {@linkplain
201.262 + * #getCalendar() calendar} doesn't support any <a
201.263 + * href="../util/GregorianCalendar.html#week_year"> week
201.264 + * years</a>, the calendar year ({@code 'y'}) is used instead. The
201.265 + * support of week years can be tested with a call to {@link
201.266 + * DateFormat#getCalendar() getCalendar()}.{@link
201.267 + * java.util.Calendar#isWeekDateSupported()
201.268 + * isWeekDateSupported()}.<br><br></li>
201.269 + * <li><strong><a name="month">Month:</a></strong>
201.270 + * If the number of pattern letters is 3 or more, the month is
201.271 + * interpreted as <a href="#text">text</a>; otherwise,
201.272 + * it is interpreted as a <a href="#number">number</a>.<br><br></li>
201.273 + * <li><strong><a name="timezone">General time zone:</a></strong>
201.274 + * Time zones are interpreted as <a href="#text">text</a> if they have
201.275 + * names. For time zones representing a GMT offset value, the
201.276 + * following syntax is used:
201.277 + * <pre>
201.278 + * <a name="GMTOffsetTimeZone"><i>GMTOffsetTimeZone:</i></a>
201.279 + * <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
201.280 + * <i>Sign:</i> one of
201.281 + * <code>+ -</code>
201.282 + * <i>Hours:</i>
201.283 + * <i>Digit</i>
201.284 + * <i>Digit</i> <i>Digit</i>
201.285 + * <i>Minutes:</i>
201.286 + * <i>Digit</i> <i>Digit</i>
201.287 + * <i>Digit:</i> one of
201.288 + * <code>0 1 2 3 4 5 6 7 8 9</code></pre>
201.289 + * <i>Hours</i> must be between 0 and 23, and <i>Minutes</i> must be between
201.290 + * 00 and 59. The format is locale independent and digits must be taken
201.291 + * from the Basic Latin block of the Unicode standard.
201.292 + * <p>For parsing, <a href="#rfc822timezone">RFC 822 time zones</a> are also
201.293 + * accepted.<br><br></li>
201.294 + * <li><strong><a name="rfc822timezone">RFC 822 time zone:</a></strong>
201.295 + * For formatting, the RFC 822 4-digit time zone format is used:
201.296 + *
201.297 + * <pre>
201.298 + * <i>RFC822TimeZone:</i>
201.299 + * <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
201.300 + * <i>TwoDigitHours:</i>
201.301 + * <i>Digit Digit</i></pre>
201.302 + * <i>TwoDigitHours</i> must be between 00 and 23. Other definitions
201.303 + * are as for <a href="#timezone">general time zones</a>.
201.304 + *
201.305 + * <p>For parsing, <a href="#timezone">general time zones</a> are also
201.306 + * accepted.
201.307 + * <li><strong><a name="iso8601timezone">ISO 8601 Time zone:</a></strong>
201.308 + * The number of pattern letters designates the format for both formatting
201.309 + * and parsing as follows:
201.310 + * <pre>
201.311 + * <i>ISO8601TimeZone:</i>
201.312 + * <i>OneLetterISO8601TimeZone</i>
201.313 + * <i>TwoLetterISO8601TimeZone</i>
201.314 + * <i>ThreeLetterISO8601TimeZone</i>
201.315 + * <i>OneLetterISO8601TimeZone:</i>
201.316 + * <i>Sign</i> <i>TwoDigitHours</i>
201.317 + * {@code Z}
201.318 + * <i>TwoLetterISO8601TimeZone:</i>
201.319 + * <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
201.320 + * {@code Z}
201.321 + * <i>ThreeLetterISO8601TimeZone:</i>
201.322 + * <i>Sign</i> <i>TwoDigitHours</i> {@code :} <i>Minutes</i>
201.323 + * {@code Z}</pre>
201.324 + * Other definitions are as for <a href="#timezone">general time zones</a> or
201.325 + * <a href="#rfc822timezone">RFC 822 time zones</a>.
201.326 + *
201.327 + * <p>For formatting, if the offset value from GMT is 0, {@code "Z"} is
201.328 + * produced. If the number of pattern letters is 1, any fraction of an hour
201.329 + * is ignored. For example, if the pattern is {@code "X"} and the time zone is
201.330 + * {@code "GMT+05:30"}, {@code "+05"} is produced.
201.331 + *
201.332 + * <p>For parsing, {@code "Z"} is parsed as the UTC time zone designator.
201.333 + * <a href="#timezone">General time zones</a> are <em>not</em> accepted.
201.334 + *
201.335 + * <p>If the number of pattern letters is 4 or more, {@link
201.336 + * IllegalArgumentException} is thrown when constructing a {@code
201.337 + * SimpleDateFormat} or {@linkplain #applyPattern(String) applying a
201.338 + * pattern}.
201.339 + * </ul>
201.340 + * <code>SimpleDateFormat</code> also supports <em>localized date and time
201.341 + * pattern</em> strings. In these strings, the pattern letters described above
201.342 + * may be replaced with other, locale dependent, pattern letters.
201.343 + * <code>SimpleDateFormat</code> does not deal with the localization of text
201.344 + * other than the pattern letters; that's up to the client of the class.
201.345 + * <p>
201.346 + *
201.347 + * <h4>Examples</h4>
201.348 + *
201.349 + * The following examples show how date and time patterns are interpreted in
201.350 + * the U.S. locale. The given date and time are 2001-07-04 12:08:56 local time
201.351 + * in the U.S. Pacific Time time zone.
201.352 + * <blockquote>
201.353 + * <table border=0 cellspacing=3 cellpadding=0 summary="Examples of date and time patterns interpreted in the U.S. locale">
201.354 + * <tr bgcolor="#ccccff">
201.355 + * <th align=left>Date and Time Pattern
201.356 + * <th align=left>Result
201.357 + * <tr>
201.358 + * <td><code>"yyyy.MM.dd G 'at' HH:mm:ss z"</code>
201.359 + * <td><code>2001.07.04 AD at 12:08:56 PDT</code>
201.360 + * <tr bgcolor="#eeeeff">
201.361 + * <td><code>"EEE, MMM d, ''yy"</code>
201.362 + * <td><code>Wed, Jul 4, '01</code>
201.363 + * <tr>
201.364 + * <td><code>"h:mm a"</code>
201.365 + * <td><code>12:08 PM</code>
201.366 + * <tr bgcolor="#eeeeff">
201.367 + * <td><code>"hh 'o''clock' a, zzzz"</code>
201.368 + * <td><code>12 o'clock PM, Pacific Daylight Time</code>
201.369 + * <tr>
201.370 + * <td><code>"K:mm a, z"</code>
201.371 + * <td><code>0:08 PM, PDT</code>
201.372 + * <tr bgcolor="#eeeeff">
201.373 + * <td><code>"yyyyy.MMMMM.dd GGG hh:mm aaa"</code>
201.374 + * <td><code>02001.July.04 AD 12:08 PM</code>
201.375 + * <tr>
201.376 + * <td><code>"EEE, d MMM yyyy HH:mm:ss Z"</code>
201.377 + * <td><code>Wed, 4 Jul 2001 12:08:56 -0700</code>
201.378 + * <tr bgcolor="#eeeeff">
201.379 + * <td><code>"yyMMddHHmmssZ"</code>
201.380 + * <td><code>010704120856-0700</code>
201.381 + * <tr>
201.382 + * <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSZ"</code>
201.383 + * <td><code>2001-07-04T12:08:56.235-0700</code>
201.384 + * <tr bgcolor="#eeeeff">
201.385 + * <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"</code>
201.386 + * <td><code>2001-07-04T12:08:56.235-07:00</code>
201.387 + * <tr>
201.388 + * <td><code>"YYYY-'W'ww-u"</code>
201.389 + * <td><code>2001-W27-3</code>
201.390 + * </table>
201.391 + * </blockquote>
201.392 + *
201.393 + * <h4><a name="synchronization">Synchronization</a></h4>
201.394 + *
201.395 + * <p>
201.396 + * Date formats are not synchronized.
201.397 + * It is recommended to create separate format instances for each thread.
201.398 + * If multiple threads access a format concurrently, it must be synchronized
201.399 + * externally.
201.400 + *
201.401 + * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/simpleDateFormat.html">Java Tutorial</a>
201.402 + * @see java.util.Calendar
201.403 + * @see java.util.TimeZone
201.404 + * @see DateFormat
201.405 + * @see DateFormatSymbols
201.406 + * @author Mark Davis, Chen-Lieh Huang, Alan Liu
201.407 + */
201.408 +public class SimpleDateFormat extends DateFormat {
201.409 +
201.410 + // the official serial version ID which says cryptically
201.411 + // which version we're compatible with
201.412 + static final long serialVersionUID = 4774881970558875024L;
201.413 +
201.414 + // the internal serial version which says which version was written
201.415 + // - 0 (default) for version up to JDK 1.1.3
201.416 + // - 1 for version from JDK 1.1.4, which includes a new field
201.417 + static final int currentSerialVersion = 1;
201.418 +
201.419 + /**
201.420 + * The version of the serialized data on the stream. Possible values:
201.421 + * <ul>
201.422 + * <li><b>0</b> or not present on stream: JDK 1.1.3. This version
201.423 + * has no <code>defaultCenturyStart</code> on stream.
201.424 + * <li><b>1</b> JDK 1.1.4 or later. This version adds
201.425 + * <code>defaultCenturyStart</code>.
201.426 + * </ul>
201.427 + * When streaming out this class, the most recent format
201.428 + * and the highest allowable <code>serialVersionOnStream</code>
201.429 + * is written.
201.430 + * @serial
201.431 + * @since JDK1.1.4
201.432 + */
201.433 + private int serialVersionOnStream = currentSerialVersion;
201.434 +
201.435 + /**
201.436 + * The pattern string of this formatter. This is always a non-localized
201.437 + * pattern. May not be null. See class documentation for details.
201.438 + * @serial
201.439 + */
201.440 + private String pattern;
201.441 +
201.442 + /**
201.443 + * Saved numberFormat and pattern.
201.444 + * @see SimpleDateFormat#checkNegativeNumberExpression
201.445 + */
201.446 + transient private NumberFormat originalNumberFormat;
201.447 + transient private String originalNumberPattern;
201.448 +
201.449 + /**
201.450 + * The minus sign to be used with format and parse.
201.451 + */
201.452 + transient private char minusSign = '-';
201.453 +
201.454 + /**
201.455 + * True when a negative sign follows a number.
201.456 + * (True as default in Arabic.)
201.457 + */
201.458 + transient private boolean hasFollowingMinusSign = false;
201.459 +
201.460 + /**
201.461 + * The compiled pattern.
201.462 + */
201.463 + transient private char[] compiledPattern;
201.464 +
201.465 + /**
201.466 + * Tags for the compiled pattern.
201.467 + */
201.468 + private final static int TAG_QUOTE_ASCII_CHAR = 100;
201.469 + private final static int TAG_QUOTE_CHARS = 101;
201.470 +
201.471 + /**
201.472 + * Locale dependent digit zero.
201.473 + * @see #zeroPaddingNumber
201.474 + * @see java.text.DecimalFormatSymbols#getZeroDigit
201.475 + */
201.476 + transient private char zeroDigit;
201.477 +
201.478 + /**
201.479 + * The symbols used by this formatter for week names, month names,
201.480 + * etc. May not be null.
201.481 + * @serial
201.482 + * @see java.text.DateFormatSymbols
201.483 + */
201.484 + private DateFormatSymbols formatData;
201.485 +
201.486 + /**
201.487 + * We map dates with two-digit years into the century starting at
201.488 + * <code>defaultCenturyStart</code>, which may be any date. May
201.489 + * not be null.
201.490 + * @serial
201.491 + * @since JDK1.1.4
201.492 + */
201.493 + private Date defaultCenturyStart;
201.494 +
201.495 + transient private int defaultCenturyStartYear;
201.496 +
201.497 + private static final int MILLIS_PER_MINUTE = 60 * 1000;
201.498 +
201.499 + // For time zones that have no names, use strings GMT+minutes and
201.500 + // GMT-minutes. For instance, in France the time zone is GMT+60.
201.501 + private static final String GMT = "GMT";
201.502 +
201.503 + /**
201.504 + * Cache to hold the DateTimePatterns of a Locale.
201.505 + */
201.506 + private static final ConcurrentMap<Locale, String[]> cachedLocaleData
201.507 + = new ConcurrentHashMap<Locale, String[]>(3);
201.508 +
201.509 + /**
201.510 + * Cache NumberFormat instances with Locale key.
201.511 + */
201.512 + private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
201.513 + = new ConcurrentHashMap<Locale, NumberFormat>(3);
201.514 +
201.515 + /**
201.516 + * The Locale used to instantiate this
201.517 + * <code>SimpleDateFormat</code>. The value may be null if this object
201.518 + * has been created by an older <code>SimpleDateFormat</code> and
201.519 + * deserialized.
201.520 + *
201.521 + * @serial
201.522 + * @since 1.6
201.523 + */
201.524 + private Locale locale;
201.525 +
201.526 + /**
201.527 + * Indicates whether this <code>SimpleDateFormat</code> should use
201.528 + * the DateFormatSymbols. If true, the format and parse methods
201.529 + * use the DateFormatSymbols values. If false, the format and
201.530 + * parse methods call Calendar.getDisplayName or
201.531 + * Calendar.getDisplayNames.
201.532 + */
201.533 + transient boolean useDateFormatSymbols;
201.534 +
201.535 + /**
201.536 + * Constructs a <code>SimpleDateFormat</code> using the default pattern and
201.537 + * date format symbols for the default locale.
201.538 + * <b>Note:</b> This constructor may not support all locales.
201.539 + * For full coverage, use the factory methods in the {@link DateFormat}
201.540 + * class.
201.541 + */
201.542 + public SimpleDateFormat() {
201.543 + this(SHORT, SHORT, Locale.getDefault(Locale.Category.FORMAT));
201.544 + }
201.545 +
201.546 + /**
201.547 + * Constructs a <code>SimpleDateFormat</code> using the given pattern and
201.548 + * the default date format symbols for the default locale.
201.549 + * <b>Note:</b> This constructor may not support all locales.
201.550 + * For full coverage, use the factory methods in the {@link DateFormat}
201.551 + * class.
201.552 + *
201.553 + * @param pattern the pattern describing the date and time format
201.554 + * @exception NullPointerException if the given pattern is null
201.555 + * @exception IllegalArgumentException if the given pattern is invalid
201.556 + */
201.557 + public SimpleDateFormat(String pattern)
201.558 + {
201.559 + this(pattern, Locale.getDefault(Locale.Category.FORMAT));
201.560 + }
201.561 +
201.562 + /**
201.563 + * Constructs a <code>SimpleDateFormat</code> using the given pattern and
201.564 + * the default date format symbols for the given locale.
201.565 + * <b>Note:</b> This constructor may not support all locales.
201.566 + * For full coverage, use the factory methods in the {@link DateFormat}
201.567 + * class.
201.568 + *
201.569 + * @param pattern the pattern describing the date and time format
201.570 + * @param locale the locale whose date format symbols should be used
201.571 + * @exception NullPointerException if the given pattern or locale is null
201.572 + * @exception IllegalArgumentException if the given pattern is invalid
201.573 + */
201.574 + public SimpleDateFormat(String pattern, Locale locale)
201.575 + {
201.576 + if (pattern == null || locale == null) {
201.577 + throw new NullPointerException();
201.578 + }
201.579 +
201.580 + initializeCalendar(locale);
201.581 + this.pattern = pattern;
201.582 + this.formatData = DateFormatSymbols.getInstanceRef(locale);
201.583 + this.locale = locale;
201.584 + initialize(locale);
201.585 + }
201.586 +
201.587 + /**
201.588 + * Constructs a <code>SimpleDateFormat</code> using the given pattern and
201.589 + * date format symbols.
201.590 + *
201.591 + * @param pattern the pattern describing the date and time format
201.592 + * @param formatSymbols the date format symbols to be used for formatting
201.593 + * @exception NullPointerException if the given pattern or formatSymbols is null
201.594 + * @exception IllegalArgumentException if the given pattern is invalid
201.595 + */
201.596 + public SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)
201.597 + {
201.598 + if (pattern == null || formatSymbols == null) {
201.599 + throw new NullPointerException();
201.600 + }
201.601 +
201.602 + this.pattern = pattern;
201.603 + this.formatData = (DateFormatSymbols) formatSymbols.clone();
201.604 + this.locale = Locale.getDefault(Locale.Category.FORMAT);
201.605 + initializeCalendar(this.locale);
201.606 + initialize(this.locale);
201.607 + useDateFormatSymbols = true;
201.608 + }
201.609 +
201.610 + /* Package-private, called by DateFormat factory methods */
201.611 + SimpleDateFormat(int timeStyle, int dateStyle, Locale loc) {
201.612 + if (loc == null) {
201.613 + throw new NullPointerException();
201.614 + }
201.615 +
201.616 + this.locale = loc;
201.617 + // initialize calendar and related fields
201.618 + initializeCalendar(loc);
201.619 +
201.620 + /* try the cache first */
201.621 + String[] dateTimePatterns = cachedLocaleData.get(loc);
201.622 + if (dateTimePatterns == null) { /* cache miss */
201.623 + ResourceBundle r = null; // LocaleData.getDateFormatData(loc);
201.624 + if (!isGregorianCalendar()) {
201.625 + try {
201.626 + dateTimePatterns = r.getStringArray(getCalendarName() + ".DateTimePatterns");
201.627 + } catch (MissingResourceException e) {
201.628 + }
201.629 + }
201.630 + if (dateTimePatterns == null) {
201.631 + dateTimePatterns = r.getStringArray("DateTimePatterns");
201.632 + }
201.633 + /* update cache */
201.634 + cachedLocaleData.putIfAbsent(loc, dateTimePatterns);
201.635 + }
201.636 + formatData = DateFormatSymbols.getInstanceRef(loc);
201.637 + if ((timeStyle >= 0) && (dateStyle >= 0)) {
201.638 + Object[] dateTimeArgs = {dateTimePatterns[timeStyle],
201.639 + dateTimePatterns[dateStyle + 4]};
201.640 + pattern = MessageFormat.format(dateTimePatterns[8], dateTimeArgs);
201.641 + }
201.642 + else if (timeStyle >= 0) {
201.643 + pattern = dateTimePatterns[timeStyle];
201.644 + }
201.645 + else if (dateStyle >= 0) {
201.646 + pattern = dateTimePatterns[dateStyle + 4];
201.647 + }
201.648 + else {
201.649 + throw new IllegalArgumentException("No date or time style specified");
201.650 + }
201.651 +
201.652 + initialize(loc);
201.653 + }
201.654 +
201.655 + /* Initialize compiledPattern and numberFormat fields */
201.656 + private void initialize(Locale loc) {
201.657 + // Verify and compile the given pattern.
201.658 + compiledPattern = compile(pattern);
201.659 +
201.660 + /* try the cache first */
201.661 + numberFormat = cachedNumberFormatData.get(loc);
201.662 + if (numberFormat == null) { /* cache miss */
201.663 + numberFormat = NumberFormat.getIntegerInstance(loc);
201.664 + numberFormat.setGroupingUsed(false);
201.665 +
201.666 + /* update cache */
201.667 + cachedNumberFormatData.putIfAbsent(loc, numberFormat);
201.668 + }
201.669 + numberFormat = (NumberFormat) numberFormat.clone();
201.670 +
201.671 + initializeDefaultCentury();
201.672 + }
201.673 +
201.674 + private void initializeCalendar(Locale loc) {
201.675 + if (calendar == null) {
201.676 + assert loc != null;
201.677 + // The format object must be constructed using the symbols for this zone.
201.678 + // However, the calendar should use the current default TimeZone.
201.679 + // If this is not contained in the locale zone strings, then the zone
201.680 + // will be formatted using generic GMT+/-H:MM nomenclature.
201.681 + calendar = Calendar.getInstance(TimeZone.getDefault(), loc);
201.682 + }
201.683 + }
201.684 +
201.685 + /**
201.686 + * Returns the compiled form of the given pattern. The syntax of
201.687 + * the compiled pattern is:
201.688 + * <blockquote>
201.689 + * CompiledPattern:
201.690 + * EntryList
201.691 + * EntryList:
201.692 + * Entry
201.693 + * EntryList Entry
201.694 + * Entry:
201.695 + * TagField
201.696 + * TagField data
201.697 + * TagField:
201.698 + * Tag Length
201.699 + * TaggedData
201.700 + * Tag:
201.701 + * pattern_char_index
201.702 + * TAG_QUOTE_CHARS
201.703 + * Length:
201.704 + * short_length
201.705 + * long_length
201.706 + * TaggedData:
201.707 + * TAG_QUOTE_ASCII_CHAR ascii_char
201.708 + *
201.709 + * </blockquote>
201.710 + *
201.711 + * where `short_length' is an 8-bit unsigned integer between 0 and
201.712 + * 254. `long_length' is a sequence of an 8-bit integer 255 and a
201.713 + * 32-bit signed integer value which is split into upper and lower
201.714 + * 16-bit fields in two char's. `pattern_char_index' is an 8-bit
201.715 + * integer between 0 and 18. `ascii_char' is an 7-bit ASCII
201.716 + * character value. `data' depends on its Tag value.
201.717 + * <p>
201.718 + * If Length is short_length, Tag and short_length are packed in a
201.719 + * single char, as illustrated below.
201.720 + * <blockquote>
201.721 + * char[0] = (Tag << 8) | short_length;
201.722 + * </blockquote>
201.723 + *
201.724 + * If Length is long_length, Tag and 255 are packed in the first
201.725 + * char and a 32-bit integer, as illustrated below.
201.726 + * <blockquote>
201.727 + * char[0] = (Tag << 8) | 255;
201.728 + * char[1] = (char) (long_length >>> 16);
201.729 + * char[2] = (char) (long_length & 0xffff);
201.730 + * </blockquote>
201.731 + * <p>
201.732 + * If Tag is a pattern_char_index, its Length is the number of
201.733 + * pattern characters. For example, if the given pattern is
201.734 + * "yyyy", Tag is 1 and Length is 4, followed by no data.
201.735 + * <p>
201.736 + * If Tag is TAG_QUOTE_CHARS, its Length is the number of char's
201.737 + * following the TagField. For example, if the given pattern is
201.738 + * "'o''clock'", Length is 7 followed by a char sequence of
201.739 + * <code>o&nbs;'&nbs;c&nbs;l&nbs;o&nbs;c&nbs;k</code>.
201.740 + * <p>
201.741 + * TAG_QUOTE_ASCII_CHAR is a special tag and has an ASCII
201.742 + * character in place of Length. For example, if the given pattern
201.743 + * is "'o'", the TaggedData entry is
201.744 + * <code>((TAG_QUOTE_ASCII_CHAR&nbs;<<&nbs;8)&nbs;|&nbs;'o')</code>.
201.745 + *
201.746 + * @exception NullPointerException if the given pattern is null
201.747 + * @exception IllegalArgumentException if the given pattern is invalid
201.748 + */
201.749 + private char[] compile(String pattern) {
201.750 + int length = pattern.length();
201.751 + boolean inQuote = false;
201.752 + StringBuilder compiledPattern = new StringBuilder(length * 2);
201.753 + StringBuilder tmpBuffer = null;
201.754 + int count = 0;
201.755 + int lastTag = -1;
201.756 +
201.757 + for (int i = 0; i < length; i++) {
201.758 + char c = pattern.charAt(i);
201.759 +
201.760 + if (c == '\'') {
201.761 + // '' is treated as a single quote regardless of being
201.762 + // in a quoted section.
201.763 + if ((i + 1) < length) {
201.764 + c = pattern.charAt(i + 1);
201.765 + if (c == '\'') {
201.766 + i++;
201.767 + if (count != 0) {
201.768 + encode(lastTag, count, compiledPattern);
201.769 + lastTag = -1;
201.770 + count = 0;
201.771 + }
201.772 + if (inQuote) {
201.773 + tmpBuffer.append(c);
201.774 + } else {
201.775 + compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
201.776 + }
201.777 + continue;
201.778 + }
201.779 + }
201.780 + if (!inQuote) {
201.781 + if (count != 0) {
201.782 + encode(lastTag, count, compiledPattern);
201.783 + lastTag = -1;
201.784 + count = 0;
201.785 + }
201.786 + if (tmpBuffer == null) {
201.787 + tmpBuffer = new StringBuilder(length);
201.788 + } else {
201.789 + tmpBuffer.setLength(0);
201.790 + }
201.791 + inQuote = true;
201.792 + } else {
201.793 + int len = tmpBuffer.length();
201.794 + if (len == 1) {
201.795 + char ch = tmpBuffer.charAt(0);
201.796 + if (ch < 128) {
201.797 + compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | ch));
201.798 + } else {
201.799 + compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | 1));
201.800 + compiledPattern.append(ch);
201.801 + }
201.802 + } else {
201.803 + encode(TAG_QUOTE_CHARS, len, compiledPattern);
201.804 + compiledPattern.append(tmpBuffer);
201.805 + }
201.806 + inQuote = false;
201.807 + }
201.808 + continue;
201.809 + }
201.810 + if (inQuote) {
201.811 + tmpBuffer.append(c);
201.812 + continue;
201.813 + }
201.814 + if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
201.815 + if (count != 0) {
201.816 + encode(lastTag, count, compiledPattern);
201.817 + lastTag = -1;
201.818 + count = 0;
201.819 + }
201.820 + if (c < 128) {
201.821 + // In most cases, c would be a delimiter, such as ':'.
201.822 + compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
201.823 + } else {
201.824 + // Take any contiguous non-ASCII alphabet characters and
201.825 + // put them in a single TAG_QUOTE_CHARS.
201.826 + int j;
201.827 + for (j = i + 1; j < length; j++) {
201.828 + char d = pattern.charAt(j);
201.829 + if (d == '\'' || (d >= 'a' && d <= 'z' || d >= 'A' && d <= 'Z')) {
201.830 + break;
201.831 + }
201.832 + }
201.833 + compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | (j - i)));
201.834 + for (; i < j; i++) {
201.835 + compiledPattern.append(pattern.charAt(i));
201.836 + }
201.837 + i--;
201.838 + }
201.839 + continue;
201.840 + }
201.841 +
201.842 + int tag;
201.843 + if ((tag = DateFormatSymbols.patternChars.indexOf(c)) == -1) {
201.844 + throw new IllegalArgumentException("Illegal pattern character " +
201.845 + "'" + c + "'");
201.846 + }
201.847 + if (lastTag == -1 || lastTag == tag) {
201.848 + lastTag = tag;
201.849 + count++;
201.850 + continue;
201.851 + }
201.852 + encode(lastTag, count, compiledPattern);
201.853 + lastTag = tag;
201.854 + count = 1;
201.855 + }
201.856 +
201.857 + if (inQuote) {
201.858 + throw new IllegalArgumentException("Unterminated quote");
201.859 + }
201.860 +
201.861 + if (count != 0) {
201.862 + encode(lastTag, count, compiledPattern);
201.863 + }
201.864 +
201.865 + // Copy the compiled pattern to a char array
201.866 + int len = compiledPattern.length();
201.867 + char[] r = new char[len];
201.868 + compiledPattern.getChars(0, len, r, 0);
201.869 + return r;
201.870 + }
201.871 +
201.872 + /**
201.873 + * Encodes the given tag and length and puts encoded char(s) into buffer.
201.874 + */
201.875 + private static final void encode(int tag, int length, StringBuilder buffer) {
201.876 + if (tag == PATTERN_ISO_ZONE && length >= 4) {
201.877 + throw new IllegalArgumentException("invalid ISO 8601 format: length=" + length);
201.878 + }
201.879 + if (length < 255) {
201.880 + buffer.append((char)(tag << 8 | length));
201.881 + } else {
201.882 + buffer.append((char)((tag << 8) | 0xff));
201.883 + buffer.append((char)(length >>> 16));
201.884 + buffer.append((char)(length & 0xffff));
201.885 + }
201.886 + }
201.887 +
201.888 + /* Initialize the fields we use to disambiguate ambiguous years. Separate
201.889 + * so we can call it from readObject().
201.890 + */
201.891 + private void initializeDefaultCentury() {
201.892 + calendar.setTimeInMillis(System.currentTimeMillis());
201.893 + calendar.add( Calendar.YEAR, -80 );
201.894 + parseAmbiguousDatesAsAfter(calendar.getTime());
201.895 + }
201.896 +
201.897 + /* Define one-century window into which to disambiguate dates using
201.898 + * two-digit years.
201.899 + */
201.900 + private void parseAmbiguousDatesAsAfter(Date startDate) {
201.901 + defaultCenturyStart = startDate;
201.902 + calendar.setTime(startDate);
201.903 + defaultCenturyStartYear = calendar.get(Calendar.YEAR);
201.904 + }
201.905 +
201.906 + /**
201.907 + * Sets the 100-year period 2-digit years will be interpreted as being in
201.908 + * to begin on the date the user specifies.
201.909 + *
201.910 + * @param startDate During parsing, two digit years will be placed in the range
201.911 + * <code>startDate</code> to <code>startDate + 100 years</code>.
201.912 + * @see #get2DigitYearStart
201.913 + * @since 1.2
201.914 + */
201.915 + public void set2DigitYearStart(Date startDate) {
201.916 + parseAmbiguousDatesAsAfter(new Date(startDate.getTime()));
201.917 + }
201.918 +
201.919 + /**
201.920 + * Returns the beginning date of the 100-year period 2-digit years are interpreted
201.921 + * as being within.
201.922 + *
201.923 + * @return the start of the 100-year period into which two digit years are
201.924 + * parsed
201.925 + * @see #set2DigitYearStart
201.926 + * @since 1.2
201.927 + */
201.928 + public Date get2DigitYearStart() {
201.929 + return (Date) defaultCenturyStart.clone();
201.930 + }
201.931 +
201.932 + /**
201.933 + * Formats the given <code>Date</code> into a date/time string and appends
201.934 + * the result to the given <code>StringBuffer</code>.
201.935 + *
201.936 + * @param date the date-time value to be formatted into a date-time string.
201.937 + * @param toAppendTo where the new date-time text is to be appended.
201.938 + * @param pos the formatting position. On input: an alignment field,
201.939 + * if desired. On output: the offsets of the alignment field.
201.940 + * @return the formatted date-time string.
201.941 + * @exception NullPointerException if the given {@code date} is {@code null}.
201.942 + */
201.943 + public StringBuffer format(Date date, StringBuffer toAppendTo,
201.944 + FieldPosition pos)
201.945 + {
201.946 + pos.beginIndex = pos.endIndex = 0;
201.947 + return format(date, toAppendTo, pos.getFieldDelegate());
201.948 + }
201.949 +
201.950 + // Called from Format after creating a FieldDelegate
201.951 + private StringBuffer format(Date date, StringBuffer toAppendTo,
201.952 + FieldDelegate delegate) {
201.953 + // Convert input date to time field list
201.954 + calendar.setTime(date);
201.955 +
201.956 + boolean useDateFormatSymbols = useDateFormatSymbols();
201.957 +
201.958 + for (int i = 0; i < compiledPattern.length; ) {
201.959 + int tag = compiledPattern[i] >>> 8;
201.960 + int count = compiledPattern[i++] & 0xff;
201.961 + if (count == 255) {
201.962 + count = compiledPattern[i++] << 16;
201.963 + count |= compiledPattern[i++];
201.964 + }
201.965 +
201.966 + switch (tag) {
201.967 + case TAG_QUOTE_ASCII_CHAR:
201.968 + toAppendTo.append((char)count);
201.969 + break;
201.970 +
201.971 + case TAG_QUOTE_CHARS:
201.972 + toAppendTo.append(compiledPattern, i, count);
201.973 + i += count;
201.974 + break;
201.975 +
201.976 + default:
201.977 + subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
201.978 + break;
201.979 + }
201.980 + }
201.981 + return toAppendTo;
201.982 + }
201.983 +
201.984 + /**
201.985 + * Formats an Object producing an <code>AttributedCharacterIterator</code>.
201.986 + * You can use the returned <code>AttributedCharacterIterator</code>
201.987 + * to build the resulting String, as well as to determine information
201.988 + * about the resulting String.
201.989 + * <p>
201.990 + * Each attribute key of the AttributedCharacterIterator will be of type
201.991 + * <code>DateFormat.Field</code>, with the corresponding attribute value
201.992 + * being the same as the attribute key.
201.993 + *
201.994 + * @exception NullPointerException if obj is null.
201.995 + * @exception IllegalArgumentException if the Format cannot format the
201.996 + * given object, or if the Format's pattern string is invalid.
201.997 + * @param obj The object to format
201.998 + * @return AttributedCharacterIterator describing the formatted value.
201.999 + * @since 1.4
201.1000 + */
201.1001 + public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
201.1002 + StringBuffer sb = new StringBuffer();
201.1003 + CharacterIteratorFieldDelegate delegate = new
201.1004 + CharacterIteratorFieldDelegate();
201.1005 +
201.1006 + if (obj instanceof Date) {
201.1007 + format((Date)obj, sb, delegate);
201.1008 + }
201.1009 + else if (obj instanceof Number) {
201.1010 + format(new Date(((Number)obj).longValue()), sb, delegate);
201.1011 + }
201.1012 + else if (obj == null) {
201.1013 + throw new NullPointerException(
201.1014 + "formatToCharacterIterator must be passed non-null object");
201.1015 + }
201.1016 + else {
201.1017 + throw new IllegalArgumentException(
201.1018 + "Cannot format given Object as a Date");
201.1019 + }
201.1020 + return delegate.getIterator(sb.toString());
201.1021 + }
201.1022 +
201.1023 + // Map index into pattern character string to Calendar field number
201.1024 + private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD =
201.1025 + {
201.1026 + Calendar.ERA, Calendar.YEAR, Calendar.MONTH, Calendar.DATE,
201.1027 + Calendar.HOUR_OF_DAY, Calendar.HOUR_OF_DAY, Calendar.MINUTE,
201.1028 + Calendar.SECOND, Calendar.MILLISECOND, Calendar.DAY_OF_WEEK,
201.1029 + Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH,
201.1030 + Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH,
201.1031 + Calendar.AM_PM, Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET,
201.1032 + Calendar.ZONE_OFFSET,
201.1033 + // Pseudo Calendar fields
201.1034 + CalendarBuilder.WEEK_YEAR,
201.1035 + CalendarBuilder.ISO_DAY_OF_WEEK,
201.1036 + Calendar.ZONE_OFFSET
201.1037 + };
201.1038 +
201.1039 + // Map index into pattern character string to DateFormat field number
201.1040 + private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = {
201.1041 + DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD, DateFormat.MONTH_FIELD,
201.1042 + DateFormat.DATE_FIELD, DateFormat.HOUR_OF_DAY1_FIELD,
201.1043 + DateFormat.HOUR_OF_DAY0_FIELD, DateFormat.MINUTE_FIELD,
201.1044 + DateFormat.SECOND_FIELD, DateFormat.MILLISECOND_FIELD,
201.1045 + DateFormat.DAY_OF_WEEK_FIELD, DateFormat.DAY_OF_YEAR_FIELD,
201.1046 + DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD, DateFormat.WEEK_OF_YEAR_FIELD,
201.1047 + DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD,
201.1048 + DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD,
201.1049 + DateFormat.TIMEZONE_FIELD, DateFormat.TIMEZONE_FIELD,
201.1050 + DateFormat.YEAR_FIELD, DateFormat.DAY_OF_WEEK_FIELD,
201.1051 + DateFormat.TIMEZONE_FIELD
201.1052 + };
201.1053 +
201.1054 + // Maps from DecimalFormatSymbols index to Field constant
201.1055 + private static final Field[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID = {
201.1056 + Field.ERA, Field.YEAR, Field.MONTH, Field.DAY_OF_MONTH,
201.1057 + Field.HOUR_OF_DAY1, Field.HOUR_OF_DAY0, Field.MINUTE,
201.1058 + Field.SECOND, Field.MILLISECOND, Field.DAY_OF_WEEK,
201.1059 + Field.DAY_OF_YEAR, Field.DAY_OF_WEEK_IN_MONTH,
201.1060 + Field.WEEK_OF_YEAR, Field.WEEK_OF_MONTH,
201.1061 + Field.AM_PM, Field.HOUR1, Field.HOUR0, Field.TIME_ZONE,
201.1062 + Field.TIME_ZONE,
201.1063 + Field.YEAR, Field.DAY_OF_WEEK,
201.1064 + Field.TIME_ZONE
201.1065 + };
201.1066 +
201.1067 + /**
201.1068 + * Private member function that does the real date/time formatting.
201.1069 + */
201.1070 + private void subFormat(int patternCharIndex, int count,
201.1071 + FieldDelegate delegate, StringBuffer buffer,
201.1072 + boolean useDateFormatSymbols)
201.1073 + {
201.1074 + int maxIntCount = Integer.MAX_VALUE;
201.1075 + String current = null;
201.1076 + int beginOffset = buffer.length();
201.1077 +
201.1078 + int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
201.1079 + int value;
201.1080 + if (field == CalendarBuilder.WEEK_YEAR) {
201.1081 + if (calendar.isWeekDateSupported()) {
201.1082 + value = calendar.getWeekYear();
201.1083 + } else {
201.1084 + // use calendar year 'y' instead
201.1085 + patternCharIndex = PATTERN_YEAR;
201.1086 + field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
201.1087 + value = calendar.get(field);
201.1088 + }
201.1089 + } else if (field == CalendarBuilder.ISO_DAY_OF_WEEK) {
201.1090 + value = CalendarBuilder.toISODayOfWeek(calendar.get(Calendar.DAY_OF_WEEK));
201.1091 + } else {
201.1092 + value = calendar.get(field);
201.1093 + }
201.1094 +
201.1095 + int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
201.1096 + if (!useDateFormatSymbols && field != CalendarBuilder.ISO_DAY_OF_WEEK) {
201.1097 + current = calendar.getDisplayName(field, style, locale);
201.1098 + }
201.1099 +
201.1100 + // Note: zeroPaddingNumber() assumes that maxDigits is either
201.1101 + // 2 or maxIntCount. If we make any changes to this,
201.1102 + // zeroPaddingNumber() must be fixed.
201.1103 +
201.1104 + switch (patternCharIndex) {
201.1105 + case PATTERN_ERA: // 'G'
201.1106 + if (useDateFormatSymbols) {
201.1107 + String[] eras = formatData.getEras();
201.1108 + if (value < eras.length)
201.1109 + current = eras[value];
201.1110 + }
201.1111 + if (current == null)
201.1112 + current = "";
201.1113 + break;
201.1114 +
201.1115 + case PATTERN_WEEK_YEAR: // 'Y'
201.1116 + case PATTERN_YEAR: // 'y'
201.1117 + if (calendar instanceof GregorianCalendar) {
201.1118 + if (count != 2)
201.1119 + zeroPaddingNumber(value, count, maxIntCount, buffer);
201.1120 + else // count == 2
201.1121 + zeroPaddingNumber(value, 2, 2, buffer); // clip 1996 to 96
201.1122 + } else {
201.1123 + if (current == null) {
201.1124 + zeroPaddingNumber(value, style == Calendar.LONG ? 1 : count,
201.1125 + maxIntCount, buffer);
201.1126 + }
201.1127 + }
201.1128 + break;
201.1129 +
201.1130 + case PATTERN_MONTH: // 'M'
201.1131 + if (useDateFormatSymbols) {
201.1132 + String[] months;
201.1133 + if (count >= 4) {
201.1134 + months = formatData.getMonths();
201.1135 + current = months[value];
201.1136 + } else if (count == 3) {
201.1137 + months = formatData.getShortMonths();
201.1138 + current = months[value];
201.1139 + }
201.1140 + } else {
201.1141 + if (count < 3) {
201.1142 + current = null;
201.1143 + }
201.1144 + }
201.1145 + if (current == null) {
201.1146 + zeroPaddingNumber(value+1, count, maxIntCount, buffer);
201.1147 + }
201.1148 + break;
201.1149 +
201.1150 + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59
201.1151 + if (current == null) {
201.1152 + if (value == 0)
201.1153 + zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY)+1,
201.1154 + count, maxIntCount, buffer);
201.1155 + else
201.1156 + zeroPaddingNumber(value, count, maxIntCount, buffer);
201.1157 + }
201.1158 + break;
201.1159 +
201.1160 + case PATTERN_DAY_OF_WEEK: // 'E'
201.1161 + if (useDateFormatSymbols) {
201.1162 + String[] weekdays;
201.1163 + if (count >= 4) {
201.1164 + weekdays = formatData.getWeekdays();
201.1165 + current = weekdays[value];
201.1166 + } else { // count < 4, use abbreviated form if exists
201.1167 + weekdays = formatData.getShortWeekdays();
201.1168 + current = weekdays[value];
201.1169 + }
201.1170 + }
201.1171 + break;
201.1172 +
201.1173 + case PATTERN_AM_PM: // 'a'
201.1174 + if (useDateFormatSymbols) {
201.1175 + String[] ampm = formatData.getAmPmStrings();
201.1176 + current = ampm[value];
201.1177 + }
201.1178 + break;
201.1179 +
201.1180 + case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM
201.1181 + if (current == null) {
201.1182 + if (value == 0)
201.1183 + zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR)+1,
201.1184 + count, maxIntCount, buffer);
201.1185 + else
201.1186 + zeroPaddingNumber(value, count, maxIntCount, buffer);
201.1187 + }
201.1188 + break;
201.1189 +
201.1190 + case PATTERN_ZONE_NAME: // 'z'
201.1191 + if (current == null) {
201.1192 + if (formatData.locale == null || formatData.isZoneStringsSet) {
201.1193 + int zoneIndex =
201.1194 + formatData.getZoneIndex(calendar.getTimeZone().getID());
201.1195 + if (zoneIndex == -1) {
201.1196 + value = calendar.get(Calendar.ZONE_OFFSET) +
201.1197 + calendar.get(Calendar.DST_OFFSET);
201.1198 +// buffer.append(ZoneInfoFile.toCustomID(value));
201.1199 + } else {
201.1200 + int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3;
201.1201 + if (count < 4) {
201.1202 + // Use the short name
201.1203 + index++;
201.1204 + }
201.1205 + String[][] zoneStrings = formatData.getZoneStringsWrapper();
201.1206 + buffer.append(zoneStrings[zoneIndex][index]);
201.1207 + }
201.1208 + } else {
201.1209 + TimeZone tz = calendar.getTimeZone();
201.1210 + boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
201.1211 + int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG);
201.1212 + buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale));
201.1213 + }
201.1214 + }
201.1215 + break;
201.1216 +
201.1217 + case PATTERN_ZONE_VALUE: // 'Z' ("-/+hhmm" form)
201.1218 + value = (calendar.get(Calendar.ZONE_OFFSET) +
201.1219 + calendar.get(Calendar.DST_OFFSET)) / 60000;
201.1220 +
201.1221 + int width = 4;
201.1222 + if (value >= 0) {
201.1223 + buffer.append('+');
201.1224 + } else {
201.1225 + width++;
201.1226 + }
201.1227 +
201.1228 + int num = (value / 60) * 100 + (value % 60);
201.1229 +// CalendarUtils.sprintf0d(buffer, num, width);
201.1230 + break;
201.1231 +
201.1232 + case PATTERN_ISO_ZONE: // 'X'
201.1233 + value = calendar.get(Calendar.ZONE_OFFSET)
201.1234 + + calendar.get(Calendar.DST_OFFSET);
201.1235 +
201.1236 + if (value == 0) {
201.1237 + buffer.append('Z');
201.1238 + break;
201.1239 + }
201.1240 +
201.1241 + value /= 60000;
201.1242 + if (value >= 0) {
201.1243 + buffer.append('+');
201.1244 + } else {
201.1245 + buffer.append('-');
201.1246 + value = -value;
201.1247 + }
201.1248 +
201.1249 +// CalendarUtils.sprintf0d(buffer, value / 60, 2);
201.1250 + if (count == 1) {
201.1251 + break;
201.1252 + }
201.1253 +
201.1254 + if (count == 3) {
201.1255 + buffer.append(':');
201.1256 + }
201.1257 +// CalendarUtils.sprintf0d(buffer, value % 60, 2);
201.1258 + break;
201.1259 +
201.1260 + default:
201.1261 + // case PATTERN_DAY_OF_MONTH: // 'd'
201.1262 + // case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59
201.1263 + // case PATTERN_MINUTE: // 'm'
201.1264 + // case PATTERN_SECOND: // 's'
201.1265 + // case PATTERN_MILLISECOND: // 'S'
201.1266 + // case PATTERN_DAY_OF_YEAR: // 'D'
201.1267 + // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
201.1268 + // case PATTERN_WEEK_OF_YEAR: // 'w'
201.1269 + // case PATTERN_WEEK_OF_MONTH: // 'W'
201.1270 + // case PATTERN_HOUR0: // 'K' eg, 11PM + 1 hour =>> 0 AM
201.1271 + // case PATTERN_ISO_DAY_OF_WEEK: // 'u' pseudo field, Monday = 1, ..., Sunday = 7
201.1272 + if (current == null) {
201.1273 + zeroPaddingNumber(value, count, maxIntCount, buffer);
201.1274 + }
201.1275 + break;
201.1276 + } // switch (patternCharIndex)
201.1277 +
201.1278 + if (current != null) {
201.1279 + buffer.append(current);
201.1280 + }
201.1281 +
201.1282 + int fieldID = PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex];
201.1283 + Field f = PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID[patternCharIndex];
201.1284 +
201.1285 + delegate.formatted(fieldID, f, f, beginOffset, buffer.length(), buffer);
201.1286 + }
201.1287 +
201.1288 + /**
201.1289 + * Formats a number with the specified minimum and maximum number of digits.
201.1290 + */
201.1291 + private final void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer)
201.1292 + {
201.1293 + // Optimization for 1, 2 and 4 digit numbers. This should
201.1294 + // cover most cases of formatting date/time related items.
201.1295 + // Note: This optimization code assumes that maxDigits is
201.1296 + // either 2 or Integer.MAX_VALUE (maxIntCount in format()).
201.1297 + try {
201.1298 + if (zeroDigit == 0) {
201.1299 + zeroDigit = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getZeroDigit();
201.1300 + }
201.1301 + if (value >= 0) {
201.1302 + if (value < 100 && minDigits >= 1 && minDigits <= 2) {
201.1303 + if (value < 10) {
201.1304 + if (minDigits == 2) {
201.1305 + buffer.append(zeroDigit);
201.1306 + }
201.1307 + buffer.append((char)(zeroDigit + value));
201.1308 + } else {
201.1309 + buffer.append((char)(zeroDigit + value / 10));
201.1310 + buffer.append((char)(zeroDigit + value % 10));
201.1311 + }
201.1312 + return;
201.1313 + } else if (value >= 1000 && value < 10000) {
201.1314 + if (minDigits == 4) {
201.1315 + buffer.append((char)(zeroDigit + value / 1000));
201.1316 + value %= 1000;
201.1317 + buffer.append((char)(zeroDigit + value / 100));
201.1318 + value %= 100;
201.1319 + buffer.append((char)(zeroDigit + value / 10));
201.1320 + buffer.append((char)(zeroDigit + value % 10));
201.1321 + return;
201.1322 + }
201.1323 + if (minDigits == 2 && maxDigits == 2) {
201.1324 + zeroPaddingNumber(value % 100, 2, 2, buffer);
201.1325 + return;
201.1326 + }
201.1327 + }
201.1328 + }
201.1329 + } catch (Exception e) {
201.1330 + }
201.1331 +
201.1332 + numberFormat.setMinimumIntegerDigits(minDigits);
201.1333 + numberFormat.setMaximumIntegerDigits(maxDigits);
201.1334 + numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE);
201.1335 + }
201.1336 +
201.1337 +
201.1338 + /**
201.1339 + * Parses text from a string to produce a <code>Date</code>.
201.1340 + * <p>
201.1341 + * The method attempts to parse text starting at the index given by
201.1342 + * <code>pos</code>.
201.1343 + * If parsing succeeds, then the index of <code>pos</code> is updated
201.1344 + * to the index after the last character used (parsing does not necessarily
201.1345 + * use all characters up to the end of the string), and the parsed
201.1346 + * date is returned. The updated <code>pos</code> can be used to
201.1347 + * indicate the starting point for the next call to this method.
201.1348 + * If an error occurs, then the index of <code>pos</code> is not
201.1349 + * changed, the error index of <code>pos</code> is set to the index of
201.1350 + * the character where the error occurred, and null is returned.
201.1351 + *
201.1352 + * <p>This parsing operation uses the {@link DateFormat#calendar
201.1353 + * calendar} to produce a {@code Date}. All of the {@code
201.1354 + * calendar}'s date-time fields are {@linkplain Calendar#clear()
201.1355 + * cleared} before parsing, and the {@code calendar}'s default
201.1356 + * values of the date-time fields are used for any missing
201.1357 + * date-time information. For example, the year value of the
201.1358 + * parsed {@code Date} is 1970 with {@link GregorianCalendar} if
201.1359 + * no year value is given from the parsing operation. The {@code
201.1360 + * TimeZone} value may be overwritten, depending on the given
201.1361 + * pattern and the time zone value in {@code text}. Any {@code
201.1362 + * TimeZone} value that has previously been set by a call to
201.1363 + * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
201.1364 + * to be restored for further operations.
201.1365 + *
201.1366 + * @param text A <code>String</code>, part of which should be parsed.
201.1367 + * @param pos A <code>ParsePosition</code> object with index and error
201.1368 + * index information as described above.
201.1369 + * @return A <code>Date</code> parsed from the string. In case of
201.1370 + * error, returns null.
201.1371 + * @exception NullPointerException if <code>text</code> or <code>pos</code> is null.
201.1372 + */
201.1373 + public Date parse(String text, ParsePosition pos)
201.1374 + {
201.1375 + checkNegativeNumberExpression();
201.1376 +
201.1377 + int start = pos.index;
201.1378 + int oldStart = start;
201.1379 + int textLength = text.length();
201.1380 +
201.1381 + boolean[] ambiguousYear = {false};
201.1382 +
201.1383 + CalendarBuilder calb = new CalendarBuilder();
201.1384 +
201.1385 + for (int i = 0; i < compiledPattern.length; ) {
201.1386 + int tag = compiledPattern[i] >>> 8;
201.1387 + int count = compiledPattern[i++] & 0xff;
201.1388 + if (count == 255) {
201.1389 + count = compiledPattern[i++] << 16;
201.1390 + count |= compiledPattern[i++];
201.1391 + }
201.1392 +
201.1393 + switch (tag) {
201.1394 + case TAG_QUOTE_ASCII_CHAR:
201.1395 + if (start >= textLength || text.charAt(start) != (char)count) {
201.1396 + pos.index = oldStart;
201.1397 + pos.errorIndex = start;
201.1398 + return null;
201.1399 + }
201.1400 + start++;
201.1401 + break;
201.1402 +
201.1403 + case TAG_QUOTE_CHARS:
201.1404 + while (count-- > 0) {
201.1405 + if (start >= textLength || text.charAt(start) != compiledPattern[i++]) {
201.1406 + pos.index = oldStart;
201.1407 + pos.errorIndex = start;
201.1408 + return null;
201.1409 + }
201.1410 + start++;
201.1411 + }
201.1412 + break;
201.1413 +
201.1414 + default:
201.1415 + // Peek the next pattern to determine if we need to
201.1416 + // obey the number of pattern letters for
201.1417 + // parsing. It's required when parsing contiguous
201.1418 + // digit text (e.g., "20010704") with a pattern which
201.1419 + // has no delimiters between fields, like "yyyyMMdd".
201.1420 + boolean obeyCount = false;
201.1421 +
201.1422 + // In Arabic, a minus sign for a negative number is put after
201.1423 + // the number. Even in another locale, a minus sign can be
201.1424 + // put after a number using DateFormat.setNumberFormat().
201.1425 + // If both the minus sign and the field-delimiter are '-',
201.1426 + // subParse() needs to determine whether a '-' after a number
201.1427 + // in the given text is a delimiter or is a minus sign for the
201.1428 + // preceding number. We give subParse() a clue based on the
201.1429 + // information in compiledPattern.
201.1430 + boolean useFollowingMinusSignAsDelimiter = false;
201.1431 +
201.1432 + if (i < compiledPattern.length) {
201.1433 + int nextTag = compiledPattern[i] >>> 8;
201.1434 + if (!(nextTag == TAG_QUOTE_ASCII_CHAR ||
201.1435 + nextTag == TAG_QUOTE_CHARS)) {
201.1436 + obeyCount = true;
201.1437 + }
201.1438 +
201.1439 + if (hasFollowingMinusSign &&
201.1440 + (nextTag == TAG_QUOTE_ASCII_CHAR ||
201.1441 + nextTag == TAG_QUOTE_CHARS)) {
201.1442 + int c;
201.1443 + if (nextTag == TAG_QUOTE_ASCII_CHAR) {
201.1444 + c = compiledPattern[i] & 0xff;
201.1445 + } else {
201.1446 + c = compiledPattern[i+1];
201.1447 + }
201.1448 +
201.1449 + if (c == minusSign) {
201.1450 + useFollowingMinusSignAsDelimiter = true;
201.1451 + }
201.1452 + }
201.1453 + }
201.1454 + start = subParse(text, start, tag, count, obeyCount,
201.1455 + ambiguousYear, pos,
201.1456 + useFollowingMinusSignAsDelimiter, calb);
201.1457 + if (start < 0) {
201.1458 + pos.index = oldStart;
201.1459 + return null;
201.1460 + }
201.1461 + }
201.1462 + }
201.1463 +
201.1464 + // At this point the fields of Calendar have been set. Calendar
201.1465 + // will fill in default values for missing fields when the time
201.1466 + // is computed.
201.1467 +
201.1468 + pos.index = start;
201.1469 +
201.1470 + Date parsedDate;
201.1471 + try {
201.1472 + parsedDate = calb.establish(calendar).getTime();
201.1473 + // If the year value is ambiguous,
201.1474 + // then the two-digit year == the default start year
201.1475 + if (ambiguousYear[0]) {
201.1476 + if (parsedDate.before(defaultCenturyStart)) {
201.1477 + parsedDate = calb.addYear(100).establish(calendar).getTime();
201.1478 + }
201.1479 + }
201.1480 + }
201.1481 + // An IllegalArgumentException will be thrown by Calendar.getTime()
201.1482 + // if any fields are out of range, e.g., MONTH == 17.
201.1483 + catch (IllegalArgumentException e) {
201.1484 + pos.errorIndex = start;
201.1485 + pos.index = oldStart;
201.1486 + return null;
201.1487 + }
201.1488 +
201.1489 + return parsedDate;
201.1490 + }
201.1491 +
201.1492 + /**
201.1493 + * Private code-size reduction function used by subParse.
201.1494 + * @param text the time text being parsed.
201.1495 + * @param start where to start parsing.
201.1496 + * @param field the date field being parsed.
201.1497 + * @param data the string array to parsed.
201.1498 + * @return the new start position if matching succeeded; a negative number
201.1499 + * indicating matching failure, otherwise.
201.1500 + */
201.1501 + private int matchString(String text, int start, int field, String[] data, CalendarBuilder calb)
201.1502 + {
201.1503 + int i = 0;
201.1504 + int count = data.length;
201.1505 +
201.1506 + if (field == Calendar.DAY_OF_WEEK) i = 1;
201.1507 +
201.1508 + // There may be multiple strings in the data[] array which begin with
201.1509 + // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
201.1510 + // We keep track of the longest match, and return that. Note that this
201.1511 + // unfortunately requires us to test all array elements.
201.1512 + int bestMatchLength = 0, bestMatch = -1;
201.1513 + for (; i<count; ++i)
201.1514 + {
201.1515 + int length = data[i].length();
201.1516 + // Always compare if we have no match yet; otherwise only compare
201.1517 + // against potentially better matches (longer strings).
201.1518 + if (length > bestMatchLength &&
201.1519 + text.regionMatches(true, start, data[i], 0, length))
201.1520 + {
201.1521 + bestMatch = i;
201.1522 + bestMatchLength = length;
201.1523 + }
201.1524 + }
201.1525 + if (bestMatch >= 0)
201.1526 + {
201.1527 + calb.set(field, bestMatch);
201.1528 + return start + bestMatchLength;
201.1529 + }
201.1530 + return -start;
201.1531 + }
201.1532 +
201.1533 + /**
201.1534 + * Performs the same thing as matchString(String, int, int,
201.1535 + * String[]). This method takes a Map<String, Integer> instead of
201.1536 + * String[].
201.1537 + */
201.1538 + private int matchString(String text, int start, int field,
201.1539 + Map<String,Integer> data, CalendarBuilder calb) {
201.1540 + if (data != null) {
201.1541 + String bestMatch = null;
201.1542 +
201.1543 + for (String name : data.keySet()) {
201.1544 + int length = name.length();
201.1545 + if (bestMatch == null || length > bestMatch.length()) {
201.1546 + if (text.regionMatches(true, start, name, 0, length)) {
201.1547 + bestMatch = name;
201.1548 + }
201.1549 + }
201.1550 + }
201.1551 +
201.1552 + if (bestMatch != null) {
201.1553 + calb.set(field, data.get(bestMatch));
201.1554 + return start + bestMatch.length();
201.1555 + }
201.1556 + }
201.1557 + return -start;
201.1558 + }
201.1559 +
201.1560 + private int matchZoneString(String text, int start, String[] zoneNames) {
201.1561 + for (int i = 1; i <= 4; ++i) {
201.1562 + // Checking long and short zones [1 & 2],
201.1563 + // and long and short daylight [3 & 4].
201.1564 + String zoneName = zoneNames[i];
201.1565 + if (text.regionMatches(true, start,
201.1566 + zoneName, 0, zoneName.length())) {
201.1567 + return i;
201.1568 + }
201.1569 + }
201.1570 + return -1;
201.1571 + }
201.1572 +
201.1573 + private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex,
201.1574 + String[][] zoneStrings) {
201.1575 + int index = standardIndex + 2;
201.1576 + String zoneName = zoneStrings[zoneIndex][index];
201.1577 + if (text.regionMatches(true, start,
201.1578 + zoneName, 0, zoneName.length())) {
201.1579 + return true;
201.1580 + }
201.1581 + return false;
201.1582 + }
201.1583 +
201.1584 + /**
201.1585 + * find time zone 'text' matched zoneStrings and set to internal
201.1586 + * calendar.
201.1587 + */
201.1588 + private int subParseZoneString(String text, int start, CalendarBuilder calb) {
201.1589 + boolean useSameName = false; // true if standard and daylight time use the same abbreviation.
201.1590 + TimeZone currentTimeZone = getTimeZone();
201.1591 +
201.1592 + // At this point, check for named time zones by looking through
201.1593 + // the locale data from the TimeZoneNames strings.
201.1594 + // Want to be able to parse both short and long forms.
201.1595 + int zoneIndex = formatData.getZoneIndex(currentTimeZone.getID());
201.1596 + TimeZone tz = null;
201.1597 + String[][] zoneStrings = formatData.getZoneStringsWrapper();
201.1598 + String[] zoneNames = null;
201.1599 + int nameIndex = 0;
201.1600 + if (zoneIndex != -1) {
201.1601 + zoneNames = zoneStrings[zoneIndex];
201.1602 + if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
201.1603 + if (nameIndex <= 2) {
201.1604 + // Check if the standard name (abbr) and the daylight name are the same.
201.1605 + useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
201.1606 + }
201.1607 + tz = TimeZone.getTimeZone(zoneNames[0]);
201.1608 + }
201.1609 + }
201.1610 + if (tz == null) {
201.1611 + zoneIndex = formatData.getZoneIndex(TimeZone.getDefault().getID());
201.1612 + if (zoneIndex != -1) {
201.1613 + zoneNames = zoneStrings[zoneIndex];
201.1614 + if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
201.1615 + if (nameIndex <= 2) {
201.1616 + useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
201.1617 + }
201.1618 + tz = TimeZone.getTimeZone(zoneNames[0]);
201.1619 + }
201.1620 + }
201.1621 + }
201.1622 +
201.1623 + if (tz == null) {
201.1624 + int len = zoneStrings.length;
201.1625 + for (int i = 0; i < len; i++) {
201.1626 + zoneNames = zoneStrings[i];
201.1627 + if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
201.1628 + if (nameIndex <= 2) {
201.1629 + useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
201.1630 + }
201.1631 + tz = TimeZone.getTimeZone(zoneNames[0]);
201.1632 + break;
201.1633 + }
201.1634 + }
201.1635 + }
201.1636 + if (tz != null) { // Matched any ?
201.1637 + if (!tz.equals(currentTimeZone)) {
201.1638 + setTimeZone(tz);
201.1639 + }
201.1640 + // If the time zone matched uses the same name
201.1641 + // (abbreviation) for both standard and daylight time,
201.1642 + // let the time zone in the Calendar decide which one.
201.1643 + //
201.1644 + // Also if tz.getDSTSaving() returns 0 for DST, use tz to
201.1645 + // determine the local time. (6645292)
201.1646 + int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0;
201.1647 + if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) {
201.1648 + calb.set(Calendar.ZONE_OFFSET, tz.getRawOffset())
201.1649 + .set(Calendar.DST_OFFSET, dstAmount);
201.1650 + }
201.1651 + return (start + zoneNames[nameIndex].length());
201.1652 + }
201.1653 + return 0;
201.1654 + }
201.1655 +
201.1656 + /**
201.1657 + * Parses numeric forms of time zone offset, such as "hh:mm", and
201.1658 + * sets calb to the parsed value.
201.1659 + *
201.1660 + * @param text the text to be parsed
201.1661 + * @param start the character position to start parsing
201.1662 + * @param sign 1: positive; -1: negative
201.1663 + * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
201.1664 + * @param colon true - colon required between hh and mm; false - no colon required
201.1665 + * @param calb a CalendarBuilder in which the parsed value is stored
201.1666 + * @return updated parsed position, or its negative value to indicate a parsing error
201.1667 + */
201.1668 + private int subParseNumericZone(String text, int start, int sign, int count,
201.1669 + boolean colon, CalendarBuilder calb) {
201.1670 + int index = start;
201.1671 +
201.1672 + parse:
201.1673 + try {
201.1674 + char c = text.charAt(index++);
201.1675 + // Parse hh
201.1676 + int hours;
201.1677 + if (!isDigit(c)) {
201.1678 + break parse;
201.1679 + }
201.1680 + hours = c - '0';
201.1681 + c = text.charAt(index++);
201.1682 + if (isDigit(c)) {
201.1683 + hours = hours * 10 + (c - '0');
201.1684 + } else {
201.1685 + // If no colon in RFC 822 or 'X' (ISO), two digits are
201.1686 + // required.
201.1687 + if (count > 0 || !colon) {
201.1688 + break parse;
201.1689 + }
201.1690 + --index;
201.1691 + }
201.1692 + if (hours > 23) {
201.1693 + break parse;
201.1694 + }
201.1695 + int minutes = 0;
201.1696 + if (count != 1) {
201.1697 + // Proceed with parsing mm
201.1698 + c = text.charAt(index++);
201.1699 + if (colon) {
201.1700 + if (c != ':') {
201.1701 + break parse;
201.1702 + }
201.1703 + c = text.charAt(index++);
201.1704 + }
201.1705 + if (!isDigit(c)) {
201.1706 + break parse;
201.1707 + }
201.1708 + minutes = c - '0';
201.1709 + c = text.charAt(index++);
201.1710 + if (!isDigit(c)) {
201.1711 + break parse;
201.1712 + }
201.1713 + minutes = minutes * 10 + (c - '0');
201.1714 + if (minutes > 59) {
201.1715 + break parse;
201.1716 + }
201.1717 + }
201.1718 + minutes += hours * 60;
201.1719 + calb.set(Calendar.ZONE_OFFSET, minutes * MILLIS_PER_MINUTE * sign)
201.1720 + .set(Calendar.DST_OFFSET, 0);
201.1721 + return index;
201.1722 + } catch (IndexOutOfBoundsException e) {
201.1723 + }
201.1724 + return 1 - index; // -(index - 1)
201.1725 + }
201.1726 +
201.1727 + private boolean isDigit(char c) {
201.1728 + return c >= '0' && c <= '9';
201.1729 + }
201.1730 +
201.1731 + /**
201.1732 + * Private member function that converts the parsed date strings into
201.1733 + * timeFields. Returns -start (for ParsePosition) if failed.
201.1734 + * @param text the time text to be parsed.
201.1735 + * @param start where to start parsing.
201.1736 + * @param ch the pattern character for the date field text to be parsed.
201.1737 + * @param count the count of a pattern character.
201.1738 + * @param obeyCount if true, then the next field directly abuts this one,
201.1739 + * and we should use the count to know when to stop parsing.
201.1740 + * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
201.1741 + * is true, then a two-digit year was parsed and may need to be readjusted.
201.1742 + * @param origPos origPos.errorIndex is used to return an error index
201.1743 + * at which a parse error occurred, if matching failure occurs.
201.1744 + * @return the new start position if matching succeeded; -1 indicating
201.1745 + * matching failure, otherwise. In case matching failure occurred,
201.1746 + * an error index is set to origPos.errorIndex.
201.1747 + */
201.1748 + private int subParse(String text, int start, int patternCharIndex, int count,
201.1749 + boolean obeyCount, boolean[] ambiguousYear,
201.1750 + ParsePosition origPos,
201.1751 + boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) {
201.1752 + Number number = null;
201.1753 + int value = 0;
201.1754 + ParsePosition pos = new ParsePosition(0);
201.1755 + pos.index = start;
201.1756 + if (patternCharIndex == PATTERN_WEEK_YEAR && !calendar.isWeekDateSupported()) {
201.1757 + // use calendar year 'y' instead
201.1758 + patternCharIndex = PATTERN_YEAR;
201.1759 + }
201.1760 + int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
201.1761 +
201.1762 + // If there are any spaces here, skip over them. If we hit the end
201.1763 + // of the string, then fail.
201.1764 + for (;;) {
201.1765 + if (pos.index >= text.length()) {
201.1766 + origPos.errorIndex = start;
201.1767 + return -1;
201.1768 + }
201.1769 + char c = text.charAt(pos.index);
201.1770 + if (c != ' ' && c != '\t') break;
201.1771 + ++pos.index;
201.1772 + }
201.1773 +
201.1774 + parsing:
201.1775 + {
201.1776 + // We handle a few special cases here where we need to parse
201.1777 + // a number value. We handle further, more generic cases below. We need
201.1778 + // to handle some of them here because some fields require extra processing on
201.1779 + // the parsed value.
201.1780 + if (patternCharIndex == PATTERN_HOUR_OF_DAY1 ||
201.1781 + patternCharIndex == PATTERN_HOUR1 ||
201.1782 + (patternCharIndex == PATTERN_MONTH && count <= 2) ||
201.1783 + patternCharIndex == PATTERN_YEAR ||
201.1784 + patternCharIndex == PATTERN_WEEK_YEAR) {
201.1785 + // It would be good to unify this with the obeyCount logic below,
201.1786 + // but that's going to be difficult.
201.1787 + if (obeyCount) {
201.1788 + if ((start+count) > text.length()) {
201.1789 + break parsing;
201.1790 + }
201.1791 + number = numberFormat.parse(text.substring(0, start+count), pos);
201.1792 + } else {
201.1793 + number = numberFormat.parse(text, pos);
201.1794 + }
201.1795 + if (number == null) {
201.1796 + if (patternCharIndex != PATTERN_YEAR || calendar instanceof GregorianCalendar) {
201.1797 + break parsing;
201.1798 + }
201.1799 + } else {
201.1800 + value = number.intValue();
201.1801 +
201.1802 + if (useFollowingMinusSignAsDelimiter && (value < 0) &&
201.1803 + (((pos.index < text.length()) &&
201.1804 + (text.charAt(pos.index) != minusSign)) ||
201.1805 + ((pos.index == text.length()) &&
201.1806 + (text.charAt(pos.index-1) == minusSign)))) {
201.1807 + value = -value;
201.1808 + pos.index--;
201.1809 + }
201.1810 + }
201.1811 + }
201.1812 +
201.1813 + boolean useDateFormatSymbols = useDateFormatSymbols();
201.1814 +
201.1815 + int index;
201.1816 + switch (patternCharIndex) {
201.1817 + case PATTERN_ERA: // 'G'
201.1818 + if (useDateFormatSymbols) {
201.1819 + if ((index = matchString(text, start, Calendar.ERA, formatData.getEras(), calb)) > 0) {
201.1820 + return index;
201.1821 + }
201.1822 + } else {
201.1823 + Map<String, Integer> map = calendar.getDisplayNames(field,
201.1824 + Calendar.ALL_STYLES,
201.1825 + locale);
201.1826 + if ((index = matchString(text, start, field, map, calb)) > 0) {
201.1827 + return index;
201.1828 + }
201.1829 + }
201.1830 + break parsing;
201.1831 +
201.1832 + case PATTERN_WEEK_YEAR: // 'Y'
201.1833 + case PATTERN_YEAR: // 'y'
201.1834 + if (!(calendar instanceof GregorianCalendar)) {
201.1835 + // calendar might have text representations for year values,
201.1836 + // such as "\u5143" in JapaneseImperialCalendar.
201.1837 + int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
201.1838 + Map<String, Integer> map = calendar.getDisplayNames(field, style, locale);
201.1839 + if (map != null) {
201.1840 + if ((index = matchString(text, start, field, map, calb)) > 0) {
201.1841 + return index;
201.1842 + }
201.1843 + }
201.1844 + calb.set(field, value);
201.1845 + return pos.index;
201.1846 + }
201.1847 +
201.1848 + // If there are 3 or more YEAR pattern characters, this indicates
201.1849 + // that the year value is to be treated literally, without any
201.1850 + // two-digit year adjustments (e.g., from "01" to 2001). Otherwise
201.1851 + // we made adjustments to place the 2-digit year in the proper
201.1852 + // century, for parsed strings from "00" to "99". Any other string
201.1853 + // is treated literally: "2250", "-1", "1", "002".
201.1854 + if (count <= 2 && (pos.index - start) == 2
201.1855 + && Character.isDigit(text.charAt(start))
201.1856 + && Character.isDigit(text.charAt(start+1))) {
201.1857 + // Assume for example that the defaultCenturyStart is 6/18/1903.
201.1858 + // This means that two-digit years will be forced into the range
201.1859 + // 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02
201.1860 + // correspond to 2000, 2001, and 2002. Years 04, 05, etc. correspond
201.1861 + // to 1904, 1905, etc. If the year is 03, then it is 2003 if the
201.1862 + // other fields specify a date before 6/18, or 1903 if they specify a
201.1863 + // date afterwards. As a result, 03 is an ambiguous year. All other
201.1864 + // two-digit years are unambiguous.
201.1865 + int ambiguousTwoDigitYear = defaultCenturyStartYear % 100;
201.1866 + ambiguousYear[0] = value == ambiguousTwoDigitYear;
201.1867 + value += (defaultCenturyStartYear/100)*100 +
201.1868 + (value < ambiguousTwoDigitYear ? 100 : 0);
201.1869 + }
201.1870 + calb.set(field, value);
201.1871 + return pos.index;
201.1872 +
201.1873 + case PATTERN_MONTH: // 'M'
201.1874 + if (count <= 2) // i.e., M or MM.
201.1875 + {
201.1876 + // Don't want to parse the month if it is a string
201.1877 + // while pattern uses numeric style: M or MM.
201.1878 + // [We computed 'value' above.]
201.1879 + calb.set(Calendar.MONTH, value - 1);
201.1880 + return pos.index;
201.1881 + }
201.1882 +
201.1883 + if (useDateFormatSymbols) {
201.1884 + // count >= 3 // i.e., MMM or MMMM
201.1885 + // Want to be able to parse both short and long forms.
201.1886 + // Try count == 4 first:
201.1887 + int newStart = 0;
201.1888 + if ((newStart = matchString(text, start, Calendar.MONTH,
201.1889 + formatData.getMonths(), calb)) > 0) {
201.1890 + return newStart;
201.1891 + }
201.1892 + // count == 4 failed, now try count == 3
201.1893 + if ((index = matchString(text, start, Calendar.MONTH,
201.1894 + formatData.getShortMonths(), calb)) > 0) {
201.1895 + return index;
201.1896 + }
201.1897 + } else {
201.1898 + Map<String, Integer> map = calendar.getDisplayNames(field,
201.1899 + Calendar.ALL_STYLES,
201.1900 + locale);
201.1901 + if ((index = matchString(text, start, field, map, calb)) > 0) {
201.1902 + return index;
201.1903 + }
201.1904 + }
201.1905 + break parsing;
201.1906 +
201.1907 + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59
201.1908 + if (!isLenient()) {
201.1909 + // Validate the hour value in non-lenient
201.1910 + if (value < 1 || value > 24) {
201.1911 + break parsing;
201.1912 + }
201.1913 + }
201.1914 + // [We computed 'value' above.]
201.1915 + if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY)+1)
201.1916 + value = 0;
201.1917 + calb.set(Calendar.HOUR_OF_DAY, value);
201.1918 + return pos.index;
201.1919 +
201.1920 + case PATTERN_DAY_OF_WEEK: // 'E'
201.1921 + {
201.1922 + if (useDateFormatSymbols) {
201.1923 + // Want to be able to parse both short and long forms.
201.1924 + // Try count == 4 (DDDD) first:
201.1925 + int newStart = 0;
201.1926 + if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK,
201.1927 + formatData.getWeekdays(), calb)) > 0) {
201.1928 + return newStart;
201.1929 + }
201.1930 + // DDDD failed, now try DDD
201.1931 + if ((index = matchString(text, start, Calendar.DAY_OF_WEEK,
201.1932 + formatData.getShortWeekdays(), calb)) > 0) {
201.1933 + return index;
201.1934 + }
201.1935 + } else {
201.1936 + int[] styles = { Calendar.LONG, Calendar.SHORT };
201.1937 + for (int style : styles) {
201.1938 + Map<String,Integer> map = calendar.getDisplayNames(field, style, locale);
201.1939 + if ((index = matchString(text, start, field, map, calb)) > 0) {
201.1940 + return index;
201.1941 + }
201.1942 + }
201.1943 + }
201.1944 + }
201.1945 + break parsing;
201.1946 +
201.1947 + case PATTERN_AM_PM: // 'a'
201.1948 + if (useDateFormatSymbols) {
201.1949 + if ((index = matchString(text, start, Calendar.AM_PM,
201.1950 + formatData.getAmPmStrings(), calb)) > 0) {
201.1951 + return index;
201.1952 + }
201.1953 + } else {
201.1954 + Map<String,Integer> map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale);
201.1955 + if ((index = matchString(text, start, field, map, calb)) > 0) {
201.1956 + return index;
201.1957 + }
201.1958 + }
201.1959 + break parsing;
201.1960 +
201.1961 + case PATTERN_HOUR1: // 'h' 1-based. eg, 11PM + 1 hour =>> 12 AM
201.1962 + if (!isLenient()) {
201.1963 + // Validate the hour value in non-lenient
201.1964 + if (value < 1 || value > 12) {
201.1965 + break parsing;
201.1966 + }
201.1967 + }
201.1968 + // [We computed 'value' above.]
201.1969 + if (value == calendar.getLeastMaximum(Calendar.HOUR)+1)
201.1970 + value = 0;
201.1971 + calb.set(Calendar.HOUR, value);
201.1972 + return pos.index;
201.1973 +
201.1974 + case PATTERN_ZONE_NAME: // 'z'
201.1975 + case PATTERN_ZONE_VALUE: // 'Z'
201.1976 + {
201.1977 + int sign = 0;
201.1978 + try {
201.1979 + char c = text.charAt(pos.index);
201.1980 + if (c == '+') {
201.1981 + sign = 1;
201.1982 + } else if (c == '-') {
201.1983 + sign = -1;
201.1984 + }
201.1985 + if (sign == 0) {
201.1986 + // Try parsing a custom time zone "GMT+hh:mm" or "GMT".
201.1987 + if ((c == 'G' || c == 'g')
201.1988 + && (text.length() - start) >= GMT.length()
201.1989 + && text.regionMatches(true, start, GMT, 0, GMT.length())) {
201.1990 + pos.index = start + GMT.length();
201.1991 +
201.1992 + if ((text.length() - pos.index) > 0) {
201.1993 + c = text.charAt(pos.index);
201.1994 + if (c == '+') {
201.1995 + sign = 1;
201.1996 + } else if (c == '-') {
201.1997 + sign = -1;
201.1998 + }
201.1999 + }
201.2000 +
201.2001 + if (sign == 0) { /* "GMT" without offset */
201.2002 + calb.set(Calendar.ZONE_OFFSET, 0)
201.2003 + .set(Calendar.DST_OFFSET, 0);
201.2004 + return pos.index;
201.2005 + }
201.2006 +
201.2007 + // Parse the rest as "hh:mm"
201.2008 + int i = subParseNumericZone(text, ++pos.index,
201.2009 + sign, 0, true, calb);
201.2010 + if (i > 0) {
201.2011 + return i;
201.2012 + }
201.2013 + pos.index = -i;
201.2014 + } else {
201.2015 + // Try parsing the text as a time zone
201.2016 + // name or abbreviation.
201.2017 + int i = subParseZoneString(text, pos.index, calb);
201.2018 + if (i > 0) {
201.2019 + return i;
201.2020 + }
201.2021 + pos.index = -i;
201.2022 + }
201.2023 + } else {
201.2024 + // Parse the rest as "hhmm" (RFC 822)
201.2025 + int i = subParseNumericZone(text, ++pos.index,
201.2026 + sign, 0, false, calb);
201.2027 + if (i > 0) {
201.2028 + return i;
201.2029 + }
201.2030 + pos.index = -i;
201.2031 + }
201.2032 + } catch (IndexOutOfBoundsException e) {
201.2033 + }
201.2034 + }
201.2035 + break parsing;
201.2036 +
201.2037 + case PATTERN_ISO_ZONE: // 'X'
201.2038 + {
201.2039 + if ((text.length() - pos.index) <= 0) {
201.2040 + break parsing;
201.2041 + }
201.2042 +
201.2043 + int sign = 0;
201.2044 + char c = text.charAt(pos.index);
201.2045 + if (c == 'Z') {
201.2046 + calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
201.2047 + return ++pos.index;
201.2048 + }
201.2049 +
201.2050 + // parse text as "+/-hh[[:]mm]" based on count
201.2051 + if (c == '+') {
201.2052 + sign = 1;
201.2053 + } else if (c == '-') {
201.2054 + sign = -1;
201.2055 + } else {
201.2056 + ++pos.index;
201.2057 + break parsing;
201.2058 + }
201.2059 + int i = subParseNumericZone(text, ++pos.index, sign, count,
201.2060 + count == 3, calb);
201.2061 + if (i > 0) {
201.2062 + return i;
201.2063 + }
201.2064 + pos.index = -i;
201.2065 + }
201.2066 + break parsing;
201.2067 +
201.2068 + default:
201.2069 + // case PATTERN_DAY_OF_MONTH: // 'd'
201.2070 + // case PATTERN_HOUR_OF_DAY0: // 'H' 0-based. eg, 23:59 + 1 hour =>> 00:59
201.2071 + // case PATTERN_MINUTE: // 'm'
201.2072 + // case PATTERN_SECOND: // 's'
201.2073 + // case PATTERN_MILLISECOND: // 'S'
201.2074 + // case PATTERN_DAY_OF_YEAR: // 'D'
201.2075 + // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
201.2076 + // case PATTERN_WEEK_OF_YEAR: // 'w'
201.2077 + // case PATTERN_WEEK_OF_MONTH: // 'W'
201.2078 + // case PATTERN_HOUR0: // 'K' 0-based. eg, 11PM + 1 hour =>> 0 AM
201.2079 + // case PATTERN_ISO_DAY_OF_WEEK: // 'u' (pseudo field);
201.2080 +
201.2081 + // Handle "generic" fields
201.2082 + if (obeyCount) {
201.2083 + if ((start+count) > text.length()) {
201.2084 + break parsing;
201.2085 + }
201.2086 + number = numberFormat.parse(text.substring(0, start+count), pos);
201.2087 + } else {
201.2088 + number = numberFormat.parse(text, pos);
201.2089 + }
201.2090 + if (number != null) {
201.2091 + value = number.intValue();
201.2092 +
201.2093 + if (useFollowingMinusSignAsDelimiter && (value < 0) &&
201.2094 + (((pos.index < text.length()) &&
201.2095 + (text.charAt(pos.index) != minusSign)) ||
201.2096 + ((pos.index == text.length()) &&
201.2097 + (text.charAt(pos.index-1) == minusSign)))) {
201.2098 + value = -value;
201.2099 + pos.index--;
201.2100 + }
201.2101 +
201.2102 + calb.set(field, value);
201.2103 + return pos.index;
201.2104 + }
201.2105 + break parsing;
201.2106 + }
201.2107 + }
201.2108 +
201.2109 + // Parsing failed.
201.2110 + origPos.errorIndex = pos.index;
201.2111 + return -1;
201.2112 + }
201.2113 +
201.2114 + private final String getCalendarName() {
201.2115 + return calendar.getClass().getName();
201.2116 + }
201.2117 +
201.2118 + private boolean useDateFormatSymbols() {
201.2119 + if (useDateFormatSymbols) {
201.2120 + return true;
201.2121 + }
201.2122 + return isGregorianCalendar() || locale == null;
201.2123 + }
201.2124 +
201.2125 + private boolean isGregorianCalendar() {
201.2126 + return "java.util.GregorianCalendar".equals(getCalendarName());
201.2127 + }
201.2128 +
201.2129 + /**
201.2130 + * Translates a pattern, mapping each character in the from string to the
201.2131 + * corresponding character in the to string.
201.2132 + *
201.2133 + * @exception IllegalArgumentException if the given pattern is invalid
201.2134 + */
201.2135 + private String translatePattern(String pattern, String from, String to) {
201.2136 + StringBuilder result = new StringBuilder();
201.2137 + boolean inQuote = false;
201.2138 + for (int i = 0; i < pattern.length(); ++i) {
201.2139 + char c = pattern.charAt(i);
201.2140 + if (inQuote) {
201.2141 + if (c == '\'')
201.2142 + inQuote = false;
201.2143 + }
201.2144 + else {
201.2145 + if (c == '\'')
201.2146 + inQuote = true;
201.2147 + else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
201.2148 + int ci = from.indexOf(c);
201.2149 + if (ci >= 0) {
201.2150 + // patternChars is longer than localPatternChars due
201.2151 + // to serialization compatibility. The pattern letters
201.2152 + // unsupported by localPatternChars pass through.
201.2153 + if (ci < to.length()) {
201.2154 + c = to.charAt(ci);
201.2155 + }
201.2156 + } else {
201.2157 + throw new IllegalArgumentException("Illegal pattern " +
201.2158 + " character '" +
201.2159 + c + "'");
201.2160 + }
201.2161 + }
201.2162 + }
201.2163 + result.append(c);
201.2164 + }
201.2165 + if (inQuote)
201.2166 + throw new IllegalArgumentException("Unfinished quote in pattern");
201.2167 + return result.toString();
201.2168 + }
201.2169 +
201.2170 + /**
201.2171 + * Returns a pattern string describing this date format.
201.2172 + *
201.2173 + * @return a pattern string describing this date format.
201.2174 + */
201.2175 + public String toPattern() {
201.2176 + return pattern;
201.2177 + }
201.2178 +
201.2179 + /**
201.2180 + * Returns a localized pattern string describing this date format.
201.2181 + *
201.2182 + * @return a localized pattern string describing this date format.
201.2183 + */
201.2184 + public String toLocalizedPattern() {
201.2185 + return translatePattern(pattern,
201.2186 + DateFormatSymbols.patternChars,
201.2187 + formatData.getLocalPatternChars());
201.2188 + }
201.2189 +
201.2190 + /**
201.2191 + * Applies the given pattern string to this date format.
201.2192 + *
201.2193 + * @param pattern the new date and time pattern for this date format
201.2194 + * @exception NullPointerException if the given pattern is null
201.2195 + * @exception IllegalArgumentException if the given pattern is invalid
201.2196 + */
201.2197 + public void applyPattern(String pattern)
201.2198 + {
201.2199 + compiledPattern = compile(pattern);
201.2200 + this.pattern = pattern;
201.2201 + }
201.2202 +
201.2203 + /**
201.2204 + * Applies the given localized pattern string to this date format.
201.2205 + *
201.2206 + * @param pattern a String to be mapped to the new date and time format
201.2207 + * pattern for this format
201.2208 + * @exception NullPointerException if the given pattern is null
201.2209 + * @exception IllegalArgumentException if the given pattern is invalid
201.2210 + */
201.2211 + public void applyLocalizedPattern(String pattern) {
201.2212 + String p = translatePattern(pattern,
201.2213 + formatData.getLocalPatternChars(),
201.2214 + DateFormatSymbols.patternChars);
201.2215 + compiledPattern = compile(p);
201.2216 + this.pattern = p;
201.2217 + }
201.2218 +
201.2219 + /**
201.2220 + * Gets a copy of the date and time format symbols of this date format.
201.2221 + *
201.2222 + * @return the date and time format symbols of this date format
201.2223 + * @see #setDateFormatSymbols
201.2224 + */
201.2225 + public DateFormatSymbols getDateFormatSymbols()
201.2226 + {
201.2227 + return (DateFormatSymbols)formatData.clone();
201.2228 + }
201.2229 +
201.2230 + /**
201.2231 + * Sets the date and time format symbols of this date format.
201.2232 + *
201.2233 + * @param newFormatSymbols the new date and time format symbols
201.2234 + * @exception NullPointerException if the given newFormatSymbols is null
201.2235 + * @see #getDateFormatSymbols
201.2236 + */
201.2237 + public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols)
201.2238 + {
201.2239 + this.formatData = (DateFormatSymbols)newFormatSymbols.clone();
201.2240 + useDateFormatSymbols = true;
201.2241 + }
201.2242 +
201.2243 + /**
201.2244 + * Creates a copy of this <code>SimpleDateFormat</code>. This also
201.2245 + * clones the format's date format symbols.
201.2246 + *
201.2247 + * @return a clone of this <code>SimpleDateFormat</code>
201.2248 + */
201.2249 + public Object clone() {
201.2250 + SimpleDateFormat other = (SimpleDateFormat) super.clone();
201.2251 + other.formatData = (DateFormatSymbols) formatData.clone();
201.2252 + return other;
201.2253 + }
201.2254 +
201.2255 + /**
201.2256 + * Returns the hash code value for this <code>SimpleDateFormat</code> object.
201.2257 + *
201.2258 + * @return the hash code value for this <code>SimpleDateFormat</code> object.
201.2259 + */
201.2260 + public int hashCode()
201.2261 + {
201.2262 + return pattern.hashCode();
201.2263 + // just enough fields for a reasonable distribution
201.2264 + }
201.2265 +
201.2266 + /**
201.2267 + * Compares the given object with this <code>SimpleDateFormat</code> for
201.2268 + * equality.
201.2269 + *
201.2270 + * @return true if the given object is equal to this
201.2271 + * <code>SimpleDateFormat</code>
201.2272 + */
201.2273 + public boolean equals(Object obj)
201.2274 + {
201.2275 + if (!super.equals(obj)) return false; // super does class check
201.2276 + SimpleDateFormat that = (SimpleDateFormat) obj;
201.2277 + return (pattern.equals(that.pattern)
201.2278 + && formatData.equals(that.formatData));
201.2279 + }
201.2280 +
201.2281 + /**
201.2282 + * After reading an object from the input stream, the format
201.2283 + * pattern in the object is verified.
201.2284 + * <p>
201.2285 + * @exception InvalidObjectException if the pattern is invalid
201.2286 + */
201.2287 + private void readObject(ObjectInputStream stream)
201.2288 + throws IOException, ClassNotFoundException {
201.2289 + stream.defaultReadObject();
201.2290 +
201.2291 + try {
201.2292 + compiledPattern = compile(pattern);
201.2293 + } catch (Exception e) {
201.2294 + throw new InvalidObjectException("invalid pattern");
201.2295 + }
201.2296 +
201.2297 + if (serialVersionOnStream < 1) {
201.2298 + // didn't have defaultCenturyStart field
201.2299 + initializeDefaultCentury();
201.2300 + }
201.2301 + else {
201.2302 + // fill in dependent transient field
201.2303 + parseAmbiguousDatesAsAfter(defaultCenturyStart);
201.2304 + }
201.2305 + serialVersionOnStream = currentSerialVersion;
201.2306 +
201.2307 + // If the deserialized object has a SimpleTimeZone, try
201.2308 + // to replace it with a ZoneInfo equivalent in order to
201.2309 + // be compatible with the SimpleTimeZone-based
201.2310 + // implementation as much as possible.
201.2311 + TimeZone tz = getTimeZone();
201.2312 + if (tz instanceof SimpleTimeZone) {
201.2313 + String id = tz.getID();
201.2314 + TimeZone zi = TimeZone.getTimeZone(id);
201.2315 + if (zi != null && zi.hasSameRules(tz) && zi.getID().equals(id)) {
201.2316 + setTimeZone(zi);
201.2317 + }
201.2318 + }
201.2319 + }
201.2320 +
201.2321 + /**
201.2322 + * Analyze the negative subpattern of DecimalFormat and set/update values
201.2323 + * as necessary.
201.2324 + */
201.2325 + private void checkNegativeNumberExpression() {
201.2326 + if ((numberFormat instanceof DecimalFormat) &&
201.2327 + !numberFormat.equals(originalNumberFormat)) {
201.2328 + String numberPattern = ((DecimalFormat)numberFormat).toPattern();
201.2329 + if (!numberPattern.equals(originalNumberPattern)) {
201.2330 + hasFollowingMinusSign = false;
201.2331 +
201.2332 + int separatorIndex = numberPattern.indexOf(';');
201.2333 + // If the negative subpattern is not absent, we have to analayze
201.2334 + // it in order to check if it has a following minus sign.
201.2335 + if (separatorIndex > -1) {
201.2336 + int minusIndex = numberPattern.indexOf('-', separatorIndex);
201.2337 + if ((minusIndex > numberPattern.lastIndexOf('0')) &&
201.2338 + (minusIndex > numberPattern.lastIndexOf('#'))) {
201.2339 + hasFollowingMinusSign = true;
201.2340 + minusSign = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getMinusSign();
201.2341 + }
201.2342 + }
201.2343 + originalNumberPattern = numberPattern;
201.2344 + }
201.2345 + originalNumberFormat = numberFormat;
201.2346 + }
201.2347 + }
201.2348 +
201.2349 + private static final class GregorianCalendar extends Calendar {
201.2350 + @Override
201.2351 + protected void computeTime() {
201.2352 + }
201.2353 +
201.2354 + @Override
201.2355 + protected void computeFields() {
201.2356 + }
201.2357 +
201.2358 + @Override
201.2359 + public void add(int field, int amount) {
201.2360 + }
201.2361 +
201.2362 + @Override
201.2363 + public void roll(int field, boolean up) {
201.2364 + }
201.2365 +
201.2366 + @Override
201.2367 + public int getMinimum(int field) {
201.2368 + return 0;
201.2369 + }
201.2370 +
201.2371 + @Override
201.2372 + public int getMaximum(int field) {
201.2373 + return 0;
201.2374 + }
201.2375 +
201.2376 + @Override
201.2377 + public int getGreatestMinimum(int field) {
201.2378 + return 0;
201.2379 + }
201.2380 +
201.2381 + @Override
201.2382 + public int getLeastMaximum(int field) {
201.2383 + return 0;
201.2384 + }
201.2385 + }
201.2386 +}
202.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
202.2 +++ b/rt/emul/compact/src/main/java/java/util/BitSet.java Wed Apr 30 15:04:10 2014 +0200
202.3 @@ -0,0 +1,1188 @@
202.4 +/*
202.5 + * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved.
202.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
202.7 + *
202.8 + * This code is free software; you can redistribute it and/or modify it
202.9 + * under the terms of the GNU General Public License version 2 only, as
202.10 + * published by the Free Software Foundation. Oracle designates this
202.11 + * particular file as subject to the "Classpath" exception as provided
202.12 + * by Oracle in the LICENSE file that accompanied this code.
202.13 + *
202.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
202.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
202.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
202.17 + * version 2 for more details (a copy is included in the LICENSE file that
202.18 + * accompanied this code).
202.19 + *
202.20 + * You should have received a copy of the GNU General Public License version
202.21 + * 2 along with this work; if not, write to the Free Software Foundation,
202.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
202.23 + *
202.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
202.25 + * or visit www.oracle.com if you need additional information or have any
202.26 + * questions.
202.27 + */
202.28 +
202.29 +package java.util;
202.30 +
202.31 +import java.io.*;
202.32 +
202.33 +/**
202.34 + * This class implements a vector of bits that grows as needed. Each
202.35 + * component of the bit set has a {@code boolean} value. The
202.36 + * bits of a {@code BitSet} are indexed by nonnegative integers.
202.37 + * Individual indexed bits can be examined, set, or cleared. One
202.38 + * {@code BitSet} may be used to modify the contents of another
202.39 + * {@code BitSet} through logical AND, logical inclusive OR, and
202.40 + * logical exclusive OR operations.
202.41 + *
202.42 + * <p>By default, all bits in the set initially have the value
202.43 + * {@code false}.
202.44 + *
202.45 + * <p>Every bit set has a current size, which is the number of bits
202.46 + * of space currently in use by the bit set. Note that the size is
202.47 + * related to the implementation of a bit set, so it may change with
202.48 + * implementation. The length of a bit set relates to logical length
202.49 + * of a bit set and is defined independently of implementation.
202.50 + *
202.51 + * <p>Unless otherwise noted, passing a null parameter to any of the
202.52 + * methods in a {@code BitSet} will result in a
202.53 + * {@code NullPointerException}.
202.54 + *
202.55 + * <p>A {@code BitSet} is not safe for multithreaded use without
202.56 + * external synchronization.
202.57 + *
202.58 + * @author Arthur van Hoff
202.59 + * @author Michael McCloskey
202.60 + * @author Martin Buchholz
202.61 + * @since JDK1.0
202.62 + */
202.63 +public class BitSet implements Cloneable, java.io.Serializable {
202.64 + /*
202.65 + * BitSets are packed into arrays of "words." Currently a word is
202.66 + * a long, which consists of 64 bits, requiring 6 address bits.
202.67 + * The choice of word size is determined purely by performance concerns.
202.68 + */
202.69 + private final static int ADDRESS_BITS_PER_WORD = 6;
202.70 + private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
202.71 + private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;
202.72 +
202.73 + /* Used to shift left or right for a partial word mask */
202.74 + private static final long WORD_MASK = 0xffffffffffffffffL;
202.75 +
202.76 + /**
202.77 + * @serialField bits long[]
202.78 + *
202.79 + * The bits in this BitSet. The ith bit is stored in bits[i/64] at
202.80 + * bit position i % 64 (where bit position 0 refers to the least
202.81 + * significant bit and 63 refers to the most significant bit).
202.82 + */
202.83 + private static final ObjectStreamField[] serialPersistentFields = {
202.84 + new ObjectStreamField("bits", long[].class),
202.85 + };
202.86 +
202.87 + /**
202.88 + * The internal field corresponding to the serialField "bits".
202.89 + */
202.90 + private long[] words;
202.91 +
202.92 + /**
202.93 + * The number of words in the logical size of this BitSet.
202.94 + */
202.95 + private transient int wordsInUse = 0;
202.96 +
202.97 + /**
202.98 + * Whether the size of "words" is user-specified. If so, we assume
202.99 + * the user knows what he's doing and try harder to preserve it.
202.100 + */
202.101 + private transient boolean sizeIsSticky = false;
202.102 +
202.103 + /* use serialVersionUID from JDK 1.0.2 for interoperability */
202.104 + private static final long serialVersionUID = 7997698588986878753L;
202.105 +
202.106 + /**
202.107 + * Given a bit index, return word index containing it.
202.108 + */
202.109 + private static int wordIndex(int bitIndex) {
202.110 + return bitIndex >> ADDRESS_BITS_PER_WORD;
202.111 + }
202.112 +
202.113 + /**
202.114 + * Every public method must preserve these invariants.
202.115 + */
202.116 + private void checkInvariants() {
202.117 + assert(wordsInUse == 0 || words[wordsInUse - 1] != 0);
202.118 + assert(wordsInUse >= 0 && wordsInUse <= words.length);
202.119 + assert(wordsInUse == words.length || words[wordsInUse] == 0);
202.120 + }
202.121 +
202.122 + /**
202.123 + * Sets the field wordsInUse to the logical size in words of the bit set.
202.124 + * WARNING:This method assumes that the number of words actually in use is
202.125 + * less than or equal to the current value of wordsInUse!
202.126 + */
202.127 + private void recalculateWordsInUse() {
202.128 + // Traverse the bitset until a used word is found
202.129 + int i;
202.130 + for (i = wordsInUse-1; i >= 0; i--)
202.131 + if (words[i] != 0)
202.132 + break;
202.133 +
202.134 + wordsInUse = i+1; // The new logical size
202.135 + }
202.136 +
202.137 + /**
202.138 + * Creates a new bit set. All bits are initially {@code false}.
202.139 + */
202.140 + public BitSet() {
202.141 + initWords(BITS_PER_WORD);
202.142 + sizeIsSticky = false;
202.143 + }
202.144 +
202.145 + /**
202.146 + * Creates a bit set whose initial size is large enough to explicitly
202.147 + * represent bits with indices in the range {@code 0} through
202.148 + * {@code nbits-1}. All bits are initially {@code false}.
202.149 + *
202.150 + * @param nbits the initial size of the bit set
202.151 + * @throws NegativeArraySizeException if the specified initial size
202.152 + * is negative
202.153 + */
202.154 + public BitSet(int nbits) {
202.155 + // nbits can't be negative; size 0 is OK
202.156 + if (nbits < 0)
202.157 + throw new NegativeArraySizeException("nbits < 0: " + nbits);
202.158 +
202.159 + initWords(nbits);
202.160 + sizeIsSticky = true;
202.161 + }
202.162 +
202.163 + private void initWords(int nbits) {
202.164 + words = new long[wordIndex(nbits-1) + 1];
202.165 + }
202.166 +
202.167 + /**
202.168 + * Creates a bit set using words as the internal representation.
202.169 + * The last word (if there is one) must be non-zero.
202.170 + */
202.171 + private BitSet(long[] words) {
202.172 + this.words = words;
202.173 + this.wordsInUse = words.length;
202.174 + checkInvariants();
202.175 + }
202.176 +
202.177 + /**
202.178 + * Returns a new bit set containing all the bits in the given long array.
202.179 + *
202.180 + * <p>More precisely,
202.181 + * <br>{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
202.182 + * <br>for all {@code n < 64 * longs.length}.
202.183 + *
202.184 + * <p>This method is equivalent to
202.185 + * {@code BitSet.valueOf(LongBuffer.wrap(longs))}.
202.186 + *
202.187 + * @param longs a long array containing a little-endian representation
202.188 + * of a sequence of bits to be used as the initial bits of the
202.189 + * new bit set
202.190 + * @since 1.7
202.191 + */
202.192 + public static BitSet valueOf(long[] longs) {
202.193 + int n;
202.194 + for (n = longs.length; n > 0 && longs[n - 1] == 0; n--)
202.195 + ;
202.196 + return new BitSet(Arrays.copyOf(longs, n));
202.197 + }
202.198 +
202.199 + /**
202.200 + * Returns a new bit set containing all the bits in the given long
202.201 + * buffer between its position and limit.
202.202 + *
202.203 + * <p>More precisely,
202.204 + * <br>{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)}
202.205 + * <br>for all {@code n < 64 * lb.remaining()}.
202.206 + *
202.207 + * <p>The long buffer is not modified by this method, and no
202.208 + * reference to the buffer is retained by the bit set.
202.209 + *
202.210 + * @param lb a long buffer containing a little-endian representation
202.211 + * of a sequence of bits between its position and limit, to be
202.212 + * used as the initial bits of the new bit set
202.213 + * @since 1.7
202.214 + */
202.215 +// public static BitSet valueOf(LongBuffer lb) {
202.216 +// lb = lb.slice();
202.217 +// int n;
202.218 +// for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--)
202.219 +// ;
202.220 +// long[] words = new long[n];
202.221 +// lb.get(words);
202.222 +// return new BitSet(words);
202.223 +// }
202.224 +
202.225 + /**
202.226 + * Returns a new bit set containing all the bits in the given byte array.
202.227 + *
202.228 + * <p>More precisely,
202.229 + * <br>{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
202.230 + * <br>for all {@code n < 8 * bytes.length}.
202.231 + *
202.232 + * <p>This method is equivalent to
202.233 + * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}.
202.234 + *
202.235 + * @param bytes a byte array containing a little-endian
202.236 + * representation of a sequence of bits to be used as the
202.237 + * initial bits of the new bit set
202.238 + * @since 1.7
202.239 + */
202.240 +// public static BitSet valueOf(byte[] bytes) {
202.241 +// return BitSet.valueOf(ByteBuffer.wrap(bytes));
202.242 +// }
202.243 +
202.244 + /**
202.245 + * Returns a new bit set containing all the bits in the given byte
202.246 + * buffer between its position and limit.
202.247 + *
202.248 + * <p>More precisely,
202.249 + * <br>{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)}
202.250 + * <br>for all {@code n < 8 * bb.remaining()}.
202.251 + *
202.252 + * <p>The byte buffer is not modified by this method, and no
202.253 + * reference to the buffer is retained by the bit set.
202.254 + *
202.255 + * @param bb a byte buffer containing a little-endian representation
202.256 + * of a sequence of bits between its position and limit, to be
202.257 + * used as the initial bits of the new bit set
202.258 + * @since 1.7
202.259 + */
202.260 +// public static BitSet valueOf(ByteBuffer bb) {
202.261 +// bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
202.262 +// int n;
202.263 +// for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--)
202.264 +// ;
202.265 +// long[] words = new long[(n + 7) / 8];
202.266 +// bb.limit(n);
202.267 +// int i = 0;
202.268 +// while (bb.remaining() >= 8)
202.269 +// words[i++] = bb.getLong();
202.270 +// for (int remaining = bb.remaining(), j = 0; j < remaining; j++)
202.271 +// words[i] |= (bb.get() & 0xffL) << (8 * j);
202.272 +// return new BitSet(words);
202.273 +// }
202.274 +
202.275 + /**
202.276 + * Returns a new byte array containing all the bits in this bit set.
202.277 + *
202.278 + * <p>More precisely, if
202.279 + * <br>{@code byte[] bytes = s.toByteArray();}
202.280 + * <br>then {@code bytes.length == (s.length()+7)/8} and
202.281 + * <br>{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
202.282 + * <br>for all {@code n < 8 * bytes.length}.
202.283 + *
202.284 + * @return a byte array containing a little-endian representation
202.285 + * of all the bits in this bit set
202.286 + * @since 1.7
202.287 + */
202.288 +// public byte[] toByteArray() {
202.289 +// int n = wordsInUse;
202.290 +// if (n == 0)
202.291 +// return new byte[0];
202.292 +// int len = 8 * (n-1);
202.293 +// for (long x = words[n - 1]; x != 0; x >>>= 8)
202.294 +// len++;
202.295 +// byte[] bytes = new byte[len];
202.296 +// ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
202.297 +// for (int i = 0; i < n - 1; i++)
202.298 +// bb.putLong(words[i]);
202.299 +// for (long x = words[n - 1]; x != 0; x >>>= 8)
202.300 +// bb.put((byte) (x & 0xff));
202.301 +// return bytes;
202.302 +// }
202.303 +
202.304 + /**
202.305 + * Returns a new long array containing all the bits in this bit set.
202.306 + *
202.307 + * <p>More precisely, if
202.308 + * <br>{@code long[] longs = s.toLongArray();}
202.309 + * <br>then {@code longs.length == (s.length()+63)/64} and
202.310 + * <br>{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
202.311 + * <br>for all {@code n < 64 * longs.length}.
202.312 + *
202.313 + * @return a long array containing a little-endian representation
202.314 + * of all the bits in this bit set
202.315 + * @since 1.7
202.316 + */
202.317 + public long[] toLongArray() {
202.318 + return Arrays.copyOf(words, wordsInUse);
202.319 + }
202.320 +
202.321 + /**
202.322 + * Ensures that the BitSet can hold enough words.
202.323 + * @param wordsRequired the minimum acceptable number of words.
202.324 + */
202.325 + private void ensureCapacity(int wordsRequired) {
202.326 + if (words.length < wordsRequired) {
202.327 + // Allocate larger of doubled size or required size
202.328 + int request = Math.max(2 * words.length, wordsRequired);
202.329 + words = Arrays.copyOf(words, request);
202.330 + sizeIsSticky = false;
202.331 + }
202.332 + }
202.333 +
202.334 + /**
202.335 + * Ensures that the BitSet can accommodate a given wordIndex,
202.336 + * temporarily violating the invariants. The caller must
202.337 + * restore the invariants before returning to the user,
202.338 + * possibly using recalculateWordsInUse().
202.339 + * @param wordIndex the index to be accommodated.
202.340 + */
202.341 + private void expandTo(int wordIndex) {
202.342 + int wordsRequired = wordIndex+1;
202.343 + if (wordsInUse < wordsRequired) {
202.344 + ensureCapacity(wordsRequired);
202.345 + wordsInUse = wordsRequired;
202.346 + }
202.347 + }
202.348 +
202.349 + /**
202.350 + * Checks that fromIndex ... toIndex is a valid range of bit indices.
202.351 + */
202.352 + private static void checkRange(int fromIndex, int toIndex) {
202.353 + if (fromIndex < 0)
202.354 + throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
202.355 + if (toIndex < 0)
202.356 + throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
202.357 + if (fromIndex > toIndex)
202.358 + throw new IndexOutOfBoundsException("fromIndex: " + fromIndex +
202.359 + " > toIndex: " + toIndex);
202.360 + }
202.361 +
202.362 + /**
202.363 + * Sets the bit at the specified index to the complement of its
202.364 + * current value.
202.365 + *
202.366 + * @param bitIndex the index of the bit to flip
202.367 + * @throws IndexOutOfBoundsException if the specified index is negative
202.368 + * @since 1.4
202.369 + */
202.370 + public void flip(int bitIndex) {
202.371 + if (bitIndex < 0)
202.372 + throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
202.373 +
202.374 + int wordIndex = wordIndex(bitIndex);
202.375 + expandTo(wordIndex);
202.376 +
202.377 + words[wordIndex] ^= (1L << bitIndex);
202.378 +
202.379 + recalculateWordsInUse();
202.380 + checkInvariants();
202.381 + }
202.382 +
202.383 + /**
202.384 + * Sets each bit from the specified {@code fromIndex} (inclusive) to the
202.385 + * specified {@code toIndex} (exclusive) to the complement of its current
202.386 + * value.
202.387 + *
202.388 + * @param fromIndex index of the first bit to flip
202.389 + * @param toIndex index after the last bit to flip
202.390 + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
202.391 + * or {@code toIndex} is negative, or {@code fromIndex} is
202.392 + * larger than {@code toIndex}
202.393 + * @since 1.4
202.394 + */
202.395 + public void flip(int fromIndex, int toIndex) {
202.396 + checkRange(fromIndex, toIndex);
202.397 +
202.398 + if (fromIndex == toIndex)
202.399 + return;
202.400 +
202.401 + int startWordIndex = wordIndex(fromIndex);
202.402 + int endWordIndex = wordIndex(toIndex - 1);
202.403 + expandTo(endWordIndex);
202.404 +
202.405 + long firstWordMask = WORD_MASK << fromIndex;
202.406 + long lastWordMask = WORD_MASK >>> -toIndex;
202.407 + if (startWordIndex == endWordIndex) {
202.408 + // Case 1: One word
202.409 + words[startWordIndex] ^= (firstWordMask & lastWordMask);
202.410 + } else {
202.411 + // Case 2: Multiple words
202.412 + // Handle first word
202.413 + words[startWordIndex] ^= firstWordMask;
202.414 +
202.415 + // Handle intermediate words, if any
202.416 + for (int i = startWordIndex+1; i < endWordIndex; i++)
202.417 + words[i] ^= WORD_MASK;
202.418 +
202.419 + // Handle last word
202.420 + words[endWordIndex] ^= lastWordMask;
202.421 + }
202.422 +
202.423 + recalculateWordsInUse();
202.424 + checkInvariants();
202.425 + }
202.426 +
202.427 + /**
202.428 + * Sets the bit at the specified index to {@code true}.
202.429 + *
202.430 + * @param bitIndex a bit index
202.431 + * @throws IndexOutOfBoundsException if the specified index is negative
202.432 + * @since JDK1.0
202.433 + */
202.434 + public void set(int bitIndex) {
202.435 + if (bitIndex < 0)
202.436 + throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
202.437 +
202.438 + int wordIndex = wordIndex(bitIndex);
202.439 + expandTo(wordIndex);
202.440 +
202.441 + words[wordIndex] |= (1L << bitIndex); // Restores invariants
202.442 +
202.443 + checkInvariants();
202.444 + }
202.445 +
202.446 + /**
202.447 + * Sets the bit at the specified index to the specified value.
202.448 + *
202.449 + * @param bitIndex a bit index
202.450 + * @param value a boolean value to set
202.451 + * @throws IndexOutOfBoundsException if the specified index is negative
202.452 + * @since 1.4
202.453 + */
202.454 + public void set(int bitIndex, boolean value) {
202.455 + if (value)
202.456 + set(bitIndex);
202.457 + else
202.458 + clear(bitIndex);
202.459 + }
202.460 +
202.461 + /**
202.462 + * Sets the bits from the specified {@code fromIndex} (inclusive) to the
202.463 + * specified {@code toIndex} (exclusive) to {@code true}.
202.464 + *
202.465 + * @param fromIndex index of the first bit to be set
202.466 + * @param toIndex index after the last bit to be set
202.467 + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
202.468 + * or {@code toIndex} is negative, or {@code fromIndex} is
202.469 + * larger than {@code toIndex}
202.470 + * @since 1.4
202.471 + */
202.472 + public void set(int fromIndex, int toIndex) {
202.473 + checkRange(fromIndex, toIndex);
202.474 +
202.475 + if (fromIndex == toIndex)
202.476 + return;
202.477 +
202.478 + // Increase capacity if necessary
202.479 + int startWordIndex = wordIndex(fromIndex);
202.480 + int endWordIndex = wordIndex(toIndex - 1);
202.481 + expandTo(endWordIndex);
202.482 +
202.483 + long firstWordMask = WORD_MASK << fromIndex;
202.484 + long lastWordMask = WORD_MASK >>> -toIndex;
202.485 + if (startWordIndex == endWordIndex) {
202.486 + // Case 1: One word
202.487 + words[startWordIndex] |= (firstWordMask & lastWordMask);
202.488 + } else {
202.489 + // Case 2: Multiple words
202.490 + // Handle first word
202.491 + words[startWordIndex] |= firstWordMask;
202.492 +
202.493 + // Handle intermediate words, if any
202.494 + for (int i = startWordIndex+1; i < endWordIndex; i++)
202.495 + words[i] = WORD_MASK;
202.496 +
202.497 + // Handle last word (restores invariants)
202.498 + words[endWordIndex] |= lastWordMask;
202.499 + }
202.500 +
202.501 + checkInvariants();
202.502 + }
202.503 +
202.504 + /**
202.505 + * Sets the bits from the specified {@code fromIndex} (inclusive) to the
202.506 + * specified {@code toIndex} (exclusive) to the specified value.
202.507 + *
202.508 + * @param fromIndex index of the first bit to be set
202.509 + * @param toIndex index after the last bit to be set
202.510 + * @param value value to set the selected bits to
202.511 + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
202.512 + * or {@code toIndex} is negative, or {@code fromIndex} is
202.513 + * larger than {@code toIndex}
202.514 + * @since 1.4
202.515 + */
202.516 + public void set(int fromIndex, int toIndex, boolean value) {
202.517 + if (value)
202.518 + set(fromIndex, toIndex);
202.519 + else
202.520 + clear(fromIndex, toIndex);
202.521 + }
202.522 +
202.523 + /**
202.524 + * Sets the bit specified by the index to {@code false}.
202.525 + *
202.526 + * @param bitIndex the index of the bit to be cleared
202.527 + * @throws IndexOutOfBoundsException if the specified index is negative
202.528 + * @since JDK1.0
202.529 + */
202.530 + public void clear(int bitIndex) {
202.531 + if (bitIndex < 0)
202.532 + throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
202.533 +
202.534 + int wordIndex = wordIndex(bitIndex);
202.535 + if (wordIndex >= wordsInUse)
202.536 + return;
202.537 +
202.538 + words[wordIndex] &= ~(1L << bitIndex);
202.539 +
202.540 + recalculateWordsInUse();
202.541 + checkInvariants();
202.542 + }
202.543 +
202.544 + /**
202.545 + * Sets the bits from the specified {@code fromIndex} (inclusive) to the
202.546 + * specified {@code toIndex} (exclusive) to {@code false}.
202.547 + *
202.548 + * @param fromIndex index of the first bit to be cleared
202.549 + * @param toIndex index after the last bit to be cleared
202.550 + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
202.551 + * or {@code toIndex} is negative, or {@code fromIndex} is
202.552 + * larger than {@code toIndex}
202.553 + * @since 1.4
202.554 + */
202.555 + public void clear(int fromIndex, int toIndex) {
202.556 + checkRange(fromIndex, toIndex);
202.557 +
202.558 + if (fromIndex == toIndex)
202.559 + return;
202.560 +
202.561 + int startWordIndex = wordIndex(fromIndex);
202.562 + if (startWordIndex >= wordsInUse)
202.563 + return;
202.564 +
202.565 + int endWordIndex = wordIndex(toIndex - 1);
202.566 + if (endWordIndex >= wordsInUse) {
202.567 + toIndex = length();
202.568 + endWordIndex = wordsInUse - 1;
202.569 + }
202.570 +
202.571 + long firstWordMask = WORD_MASK << fromIndex;
202.572 + long lastWordMask = WORD_MASK >>> -toIndex;
202.573 + if (startWordIndex == endWordIndex) {
202.574 + // Case 1: One word
202.575 + words[startWordIndex] &= ~(firstWordMask & lastWordMask);
202.576 + } else {
202.577 + // Case 2: Multiple words
202.578 + // Handle first word
202.579 + words[startWordIndex] &= ~firstWordMask;
202.580 +
202.581 + // Handle intermediate words, if any
202.582 + for (int i = startWordIndex+1; i < endWordIndex; i++)
202.583 + words[i] = 0;
202.584 +
202.585 + // Handle last word
202.586 + words[endWordIndex] &= ~lastWordMask;
202.587 + }
202.588 +
202.589 + recalculateWordsInUse();
202.590 + checkInvariants();
202.591 + }
202.592 +
202.593 + /**
202.594 + * Sets all of the bits in this BitSet to {@code false}.
202.595 + *
202.596 + * @since 1.4
202.597 + */
202.598 + public void clear() {
202.599 + while (wordsInUse > 0)
202.600 + words[--wordsInUse] = 0;
202.601 + }
202.602 +
202.603 + /**
202.604 + * Returns the value of the bit with the specified index. The value
202.605 + * is {@code true} if the bit with the index {@code bitIndex}
202.606 + * is currently set in this {@code BitSet}; otherwise, the result
202.607 + * is {@code false}.
202.608 + *
202.609 + * @param bitIndex the bit index
202.610 + * @return the value of the bit with the specified index
202.611 + * @throws IndexOutOfBoundsException if the specified index is negative
202.612 + */
202.613 + public boolean get(int bitIndex) {
202.614 + if (bitIndex < 0)
202.615 + throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
202.616 +
202.617 + checkInvariants();
202.618 +
202.619 + int wordIndex = wordIndex(bitIndex);
202.620 + return (wordIndex < wordsInUse)
202.621 + && ((words[wordIndex] & (1L << bitIndex)) != 0);
202.622 + }
202.623 +
202.624 + /**
202.625 + * Returns a new {@code BitSet} composed of bits from this {@code BitSet}
202.626 + * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive).
202.627 + *
202.628 + * @param fromIndex index of the first bit to include
202.629 + * @param toIndex index after the last bit to include
202.630 + * @return a new {@code BitSet} from a range of this {@code BitSet}
202.631 + * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
202.632 + * or {@code toIndex} is negative, or {@code fromIndex} is
202.633 + * larger than {@code toIndex}
202.634 + * @since 1.4
202.635 + */
202.636 + public BitSet get(int fromIndex, int toIndex) {
202.637 + checkRange(fromIndex, toIndex);
202.638 +
202.639 + checkInvariants();
202.640 +
202.641 + int len = length();
202.642 +
202.643 + // If no set bits in range return empty bitset
202.644 + if (len <= fromIndex || fromIndex == toIndex)
202.645 + return new BitSet(0);
202.646 +
202.647 + // An optimization
202.648 + if (toIndex > len)
202.649 + toIndex = len;
202.650 +
202.651 + BitSet result = new BitSet(toIndex - fromIndex);
202.652 + int targetWords = wordIndex(toIndex - fromIndex - 1) + 1;
202.653 + int sourceIndex = wordIndex(fromIndex);
202.654 + boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0);
202.655 +
202.656 + // Process all words but the last word
202.657 + for (int i = 0; i < targetWords - 1; i++, sourceIndex++)
202.658 + result.words[i] = wordAligned ? words[sourceIndex] :
202.659 + (words[sourceIndex] >>> fromIndex) |
202.660 + (words[sourceIndex+1] << -fromIndex);
202.661 +
202.662 + // Process the last word
202.663 + long lastWordMask = WORD_MASK >>> -toIndex;
202.664 + result.words[targetWords - 1] =
202.665 + ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK)
202.666 + ? /* straddles source words */
202.667 + ((words[sourceIndex] >>> fromIndex) |
202.668 + (words[sourceIndex+1] & lastWordMask) << -fromIndex)
202.669 + :
202.670 + ((words[sourceIndex] & lastWordMask) >>> fromIndex);
202.671 +
202.672 + // Set wordsInUse correctly
202.673 + result.wordsInUse = targetWords;
202.674 + result.recalculateWordsInUse();
202.675 + result.checkInvariants();
202.676 +
202.677 + return result;
202.678 + }
202.679 +
202.680 + /**
202.681 + * Returns the index of the first bit that is set to {@code true}
202.682 + * that occurs on or after the specified starting index. If no such
202.683 + * bit exists then {@code -1} is returned.
202.684 + *
202.685 + * <p>To iterate over the {@code true} bits in a {@code BitSet},
202.686 + * use the following loop:
202.687 + *
202.688 + * <pre> {@code
202.689 + * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
202.690 + * // operate on index i here
202.691 + * }}</pre>
202.692 + *
202.693 + * @param fromIndex the index to start checking from (inclusive)
202.694 + * @return the index of the next set bit, or {@code -1} if there
202.695 + * is no such bit
202.696 + * @throws IndexOutOfBoundsException if the specified index is negative
202.697 + * @since 1.4
202.698 + */
202.699 + public int nextSetBit(int fromIndex) {
202.700 + if (fromIndex < 0)
202.701 + throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
202.702 +
202.703 + checkInvariants();
202.704 +
202.705 + int u = wordIndex(fromIndex);
202.706 + if (u >= wordsInUse)
202.707 + return -1;
202.708 +
202.709 + long word = words[u] & (WORD_MASK << fromIndex);
202.710 +
202.711 + while (true) {
202.712 + if (word != 0)
202.713 + return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
202.714 + if (++u == wordsInUse)
202.715 + return -1;
202.716 + word = words[u];
202.717 + }
202.718 + }
202.719 +
202.720 + /**
202.721 + * Returns the index of the first bit that is set to {@code false}
202.722 + * that occurs on or after the specified starting index.
202.723 + *
202.724 + * @param fromIndex the index to start checking from (inclusive)
202.725 + * @return the index of the next clear bit
202.726 + * @throws IndexOutOfBoundsException if the specified index is negative
202.727 + * @since 1.4
202.728 + */
202.729 + public int nextClearBit(int fromIndex) {
202.730 + // Neither spec nor implementation handle bitsets of maximal length.
202.731 + // See 4816253.
202.732 + if (fromIndex < 0)
202.733 + throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
202.734 +
202.735 + checkInvariants();
202.736 +
202.737 + int u = wordIndex(fromIndex);
202.738 + if (u >= wordsInUse)
202.739 + return fromIndex;
202.740 +
202.741 + long word = ~words[u] & (WORD_MASK << fromIndex);
202.742 +
202.743 + while (true) {
202.744 + if (word != 0)
202.745 + return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
202.746 + if (++u == wordsInUse)
202.747 + return wordsInUse * BITS_PER_WORD;
202.748 + word = ~words[u];
202.749 + }
202.750 + }
202.751 +
202.752 + /**
202.753 + * Returns the index of the nearest bit that is set to {@code true}
202.754 + * that occurs on or before the specified starting index.
202.755 + * If no such bit exists, or if {@code -1} is given as the
202.756 + * starting index, then {@code -1} is returned.
202.757 + *
202.758 + * <p>To iterate over the {@code true} bits in a {@code BitSet},
202.759 + * use the following loop:
202.760 + *
202.761 + * <pre> {@code
202.762 + * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
202.763 + * // operate on index i here
202.764 + * }}</pre>
202.765 + *
202.766 + * @param fromIndex the index to start checking from (inclusive)
202.767 + * @return the index of the previous set bit, or {@code -1} if there
202.768 + * is no such bit
202.769 + * @throws IndexOutOfBoundsException if the specified index is less
202.770 + * than {@code -1}
202.771 + * @since 1.7
202.772 + */
202.773 + public int previousSetBit(int fromIndex) {
202.774 + if (fromIndex < 0) {
202.775 + if (fromIndex == -1)
202.776 + return -1;
202.777 + throw new IndexOutOfBoundsException(
202.778 + "fromIndex < -1: " + fromIndex);
202.779 + }
202.780 +
202.781 + checkInvariants();
202.782 +
202.783 + int u = wordIndex(fromIndex);
202.784 + if (u >= wordsInUse)
202.785 + return length() - 1;
202.786 +
202.787 + long word = words[u] & (WORD_MASK >>> -(fromIndex+1));
202.788 +
202.789 + while (true) {
202.790 + if (word != 0)
202.791 + return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word);
202.792 + if (u-- == 0)
202.793 + return -1;
202.794 + word = words[u];
202.795 + }
202.796 + }
202.797 +
202.798 + /**
202.799 + * Returns the index of the nearest bit that is set to {@code false}
202.800 + * that occurs on or before the specified starting index.
202.801 + * If no such bit exists, or if {@code -1} is given as the
202.802 + * starting index, then {@code -1} is returned.
202.803 + *
202.804 + * @param fromIndex the index to start checking from (inclusive)
202.805 + * @return the index of the previous clear bit, or {@code -1} if there
202.806 + * is no such bit
202.807 + * @throws IndexOutOfBoundsException if the specified index is less
202.808 + * than {@code -1}
202.809 + * @since 1.7
202.810 + */
202.811 + public int previousClearBit(int fromIndex) {
202.812 + if (fromIndex < 0) {
202.813 + if (fromIndex == -1)
202.814 + return -1;
202.815 + throw new IndexOutOfBoundsException(
202.816 + "fromIndex < -1: " + fromIndex);
202.817 + }
202.818 +
202.819 + checkInvariants();
202.820 +
202.821 + int u = wordIndex(fromIndex);
202.822 + if (u >= wordsInUse)
202.823 + return fromIndex;
202.824 +
202.825 + long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1));
202.826 +
202.827 + while (true) {
202.828 + if (word != 0)
202.829 + return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word);
202.830 + if (u-- == 0)
202.831 + return -1;
202.832 + word = ~words[u];
202.833 + }
202.834 + }
202.835 +
202.836 + /**
202.837 + * Returns the "logical size" of this {@code BitSet}: the index of
202.838 + * the highest set bit in the {@code BitSet} plus one. Returns zero
202.839 + * if the {@code BitSet} contains no set bits.
202.840 + *
202.841 + * @return the logical size of this {@code BitSet}
202.842 + * @since 1.2
202.843 + */
202.844 + public int length() {
202.845 + if (wordsInUse == 0)
202.846 + return 0;
202.847 +
202.848 + return BITS_PER_WORD * (wordsInUse - 1) +
202.849 + (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1]));
202.850 + }
202.851 +
202.852 + /**
202.853 + * Returns true if this {@code BitSet} contains no bits that are set
202.854 + * to {@code true}.
202.855 + *
202.856 + * @return boolean indicating whether this {@code BitSet} is empty
202.857 + * @since 1.4
202.858 + */
202.859 + public boolean isEmpty() {
202.860 + return wordsInUse == 0;
202.861 + }
202.862 +
202.863 + /**
202.864 + * Returns true if the specified {@code BitSet} has any bits set to
202.865 + * {@code true} that are also set to {@code true} in this {@code BitSet}.
202.866 + *
202.867 + * @param set {@code BitSet} to intersect with
202.868 + * @return boolean indicating whether this {@code BitSet} intersects
202.869 + * the specified {@code BitSet}
202.870 + * @since 1.4
202.871 + */
202.872 + public boolean intersects(BitSet set) {
202.873 + for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
202.874 + if ((words[i] & set.words[i]) != 0)
202.875 + return true;
202.876 + return false;
202.877 + }
202.878 +
202.879 + /**
202.880 + * Returns the number of bits set to {@code true} in this {@code BitSet}.
202.881 + *
202.882 + * @return the number of bits set to {@code true} in this {@code BitSet}
202.883 + * @since 1.4
202.884 + */
202.885 + public int cardinality() {
202.886 + int sum = 0;
202.887 + for (int i = 0; i < wordsInUse; i++)
202.888 + sum += Long.bitCount(words[i]);
202.889 + return sum;
202.890 + }
202.891 +
202.892 + /**
202.893 + * Performs a logical <b>AND</b> of this target bit set with the
202.894 + * argument bit set. This bit set is modified so that each bit in it
202.895 + * has the value {@code true} if and only if it both initially
202.896 + * had the value {@code true} and the corresponding bit in the
202.897 + * bit set argument also had the value {@code true}.
202.898 + *
202.899 + * @param set a bit set
202.900 + */
202.901 + public void and(BitSet set) {
202.902 + if (this == set)
202.903 + return;
202.904 +
202.905 + while (wordsInUse > set.wordsInUse)
202.906 + words[--wordsInUse] = 0;
202.907 +
202.908 + // Perform logical AND on words in common
202.909 + for (int i = 0; i < wordsInUse; i++)
202.910 + words[i] &= set.words[i];
202.911 +
202.912 + recalculateWordsInUse();
202.913 + checkInvariants();
202.914 + }
202.915 +
202.916 + /**
202.917 + * Performs a logical <b>OR</b> of this bit set with the bit set
202.918 + * argument. This bit set is modified so that a bit in it has the
202.919 + * value {@code true} if and only if it either already had the
202.920 + * value {@code true} or the corresponding bit in the bit set
202.921 + * argument has the value {@code true}.
202.922 + *
202.923 + * @param set a bit set
202.924 + */
202.925 + public void or(BitSet set) {
202.926 + if (this == set)
202.927 + return;
202.928 +
202.929 + int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
202.930 +
202.931 + if (wordsInUse < set.wordsInUse) {
202.932 + ensureCapacity(set.wordsInUse);
202.933 + wordsInUse = set.wordsInUse;
202.934 + }
202.935 +
202.936 + // Perform logical OR on words in common
202.937 + for (int i = 0; i < wordsInCommon; i++)
202.938 + words[i] |= set.words[i];
202.939 +
202.940 + // Copy any remaining words
202.941 + if (wordsInCommon < set.wordsInUse)
202.942 + System.arraycopy(set.words, wordsInCommon,
202.943 + words, wordsInCommon,
202.944 + wordsInUse - wordsInCommon);
202.945 +
202.946 + // recalculateWordsInUse() is unnecessary
202.947 + checkInvariants();
202.948 + }
202.949 +
202.950 + /**
202.951 + * Performs a logical <b>XOR</b> of this bit set with the bit set
202.952 + * argument. This bit set is modified so that a bit in it has the
202.953 + * value {@code true} if and only if one of the following
202.954 + * statements holds:
202.955 + * <ul>
202.956 + * <li>The bit initially has the value {@code true}, and the
202.957 + * corresponding bit in the argument has the value {@code false}.
202.958 + * <li>The bit initially has the value {@code false}, and the
202.959 + * corresponding bit in the argument has the value {@code true}.
202.960 + * </ul>
202.961 + *
202.962 + * @param set a bit set
202.963 + */
202.964 + public void xor(BitSet set) {
202.965 + int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
202.966 +
202.967 + if (wordsInUse < set.wordsInUse) {
202.968 + ensureCapacity(set.wordsInUse);
202.969 + wordsInUse = set.wordsInUse;
202.970 + }
202.971 +
202.972 + // Perform logical XOR on words in common
202.973 + for (int i = 0; i < wordsInCommon; i++)
202.974 + words[i] ^= set.words[i];
202.975 +
202.976 + // Copy any remaining words
202.977 + if (wordsInCommon < set.wordsInUse)
202.978 + System.arraycopy(set.words, wordsInCommon,
202.979 + words, wordsInCommon,
202.980 + set.wordsInUse - wordsInCommon);
202.981 +
202.982 + recalculateWordsInUse();
202.983 + checkInvariants();
202.984 + }
202.985 +
202.986 + /**
202.987 + * Clears all of the bits in this {@code BitSet} whose corresponding
202.988 + * bit is set in the specified {@code BitSet}.
202.989 + *
202.990 + * @param set the {@code BitSet} with which to mask this
202.991 + * {@code BitSet}
202.992 + * @since 1.2
202.993 + */
202.994 + public void andNot(BitSet set) {
202.995 + // Perform logical (a & !b) on words in common
202.996 + for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
202.997 + words[i] &= ~set.words[i];
202.998 +
202.999 + recalculateWordsInUse();
202.1000 + checkInvariants();
202.1001 + }
202.1002 +
202.1003 + /**
202.1004 + * Returns the hash code value for this bit set. The hash code depends
202.1005 + * only on which bits are set within this {@code BitSet}.
202.1006 + *
202.1007 + * <p>The hash code is defined to be the result of the following
202.1008 + * calculation:
202.1009 + * <pre> {@code
202.1010 + * public int hashCode() {
202.1011 + * long h = 1234;
202.1012 + * long[] words = toLongArray();
202.1013 + * for (int i = words.length; --i >= 0; )
202.1014 + * h ^= words[i] * (i + 1);
202.1015 + * return (int)((h >> 32) ^ h);
202.1016 + * }}</pre>
202.1017 + * Note that the hash code changes if the set of bits is altered.
202.1018 + *
202.1019 + * @return the hash code value for this bit set
202.1020 + */
202.1021 + public int hashCode() {
202.1022 + long h = 1234;
202.1023 + for (int i = wordsInUse; --i >= 0; )
202.1024 + h ^= words[i] * (i + 1);
202.1025 +
202.1026 + return (int)((h >> 32) ^ h);
202.1027 + }
202.1028 +
202.1029 + /**
202.1030 + * Returns the number of bits of space actually in use by this
202.1031 + * {@code BitSet} to represent bit values.
202.1032 + * The maximum element in the set is the size - 1st element.
202.1033 + *
202.1034 + * @return the number of bits currently in this bit set
202.1035 + */
202.1036 + public int size() {
202.1037 + return words.length * BITS_PER_WORD;
202.1038 + }
202.1039 +
202.1040 + /**
202.1041 + * Compares this object against the specified object.
202.1042 + * The result is {@code true} if and only if the argument is
202.1043 + * not {@code null} and is a {@code Bitset} object that has
202.1044 + * exactly the same set of bits set to {@code true} as this bit
202.1045 + * set. That is, for every nonnegative {@code int} index {@code k},
202.1046 + * <pre>((BitSet)obj).get(k) == this.get(k)</pre>
202.1047 + * must be true. The current sizes of the two bit sets are not compared.
202.1048 + *
202.1049 + * @param obj the object to compare with
202.1050 + * @return {@code true} if the objects are the same;
202.1051 + * {@code false} otherwise
202.1052 + * @see #size()
202.1053 + */
202.1054 + public boolean equals(Object obj) {
202.1055 + if (!(obj instanceof BitSet))
202.1056 + return false;
202.1057 + if (this == obj)
202.1058 + return true;
202.1059 +
202.1060 + BitSet set = (BitSet) obj;
202.1061 +
202.1062 + checkInvariants();
202.1063 + set.checkInvariants();
202.1064 +
202.1065 + if (wordsInUse != set.wordsInUse)
202.1066 + return false;
202.1067 +
202.1068 + // Check words in use by both BitSets
202.1069 + for (int i = 0; i < wordsInUse; i++)
202.1070 + if (words[i] != set.words[i])
202.1071 + return false;
202.1072 +
202.1073 + return true;
202.1074 + }
202.1075 +
202.1076 + /**
202.1077 + * Cloning this {@code BitSet} produces a new {@code BitSet}
202.1078 + * that is equal to it.
202.1079 + * The clone of the bit set is another bit set that has exactly the
202.1080 + * same bits set to {@code true} as this bit set.
202.1081 + *
202.1082 + * @return a clone of this bit set
202.1083 + * @see #size()
202.1084 + */
202.1085 + public Object clone() {
202.1086 + if (! sizeIsSticky)
202.1087 + trimToSize();
202.1088 +
202.1089 + try {
202.1090 + BitSet result = (BitSet) super.clone();
202.1091 + result.words = words.clone();
202.1092 + result.checkInvariants();
202.1093 + return result;
202.1094 + } catch (CloneNotSupportedException e) {
202.1095 + throw new InternalError();
202.1096 + }
202.1097 + }
202.1098 +
202.1099 + /**
202.1100 + * Attempts to reduce internal storage used for the bits in this bit set.
202.1101 + * Calling this method may, but is not required to, affect the value
202.1102 + * returned by a subsequent call to the {@link #size()} method.
202.1103 + */
202.1104 + private void trimToSize() {
202.1105 + if (wordsInUse != words.length) {
202.1106 + words = Arrays.copyOf(words, wordsInUse);
202.1107 + checkInvariants();
202.1108 + }
202.1109 + }
202.1110 +
202.1111 + /**
202.1112 + * Save the state of the {@code BitSet} instance to a stream (i.e.,
202.1113 + * serialize it).
202.1114 + */
202.1115 + private void writeObject(ObjectOutputStream s)
202.1116 + throws IOException {
202.1117 +
202.1118 + checkInvariants();
202.1119 +
202.1120 + if (! sizeIsSticky)
202.1121 + trimToSize();
202.1122 +
202.1123 + ObjectOutputStream.PutField fields = s.putFields();
202.1124 + fields.put("bits", words);
202.1125 + s.writeFields();
202.1126 + }
202.1127 +
202.1128 + /**
202.1129 + * Reconstitute the {@code BitSet} instance from a stream (i.e.,
202.1130 + * deserialize it).
202.1131 + */
202.1132 + private void readObject(ObjectInputStream s)
202.1133 + throws IOException, ClassNotFoundException {
202.1134 +
202.1135 + ObjectInputStream.GetField fields = s.readFields();
202.1136 + words = (long[]) fields.get("bits", null);
202.1137 +
202.1138 + // Assume maximum length then find real length
202.1139 + // because recalculateWordsInUse assumes maintenance
202.1140 + // or reduction in logical size
202.1141 + wordsInUse = words.length;
202.1142 + recalculateWordsInUse();
202.1143 + sizeIsSticky = (words.length > 0 && words[words.length-1] == 0L); // heuristic
202.1144 + checkInvariants();
202.1145 + }
202.1146 +
202.1147 + /**
202.1148 + * Returns a string representation of this bit set. For every index
202.1149 + * for which this {@code BitSet} contains a bit in the set
202.1150 + * state, the decimal representation of that index is included in
202.1151 + * the result. Such indices are listed in order from lowest to
202.1152 + * highest, separated by ", " (a comma and a space) and
202.1153 + * surrounded by braces, resulting in the usual mathematical
202.1154 + * notation for a set of integers.
202.1155 + *
202.1156 + * <p>Example:
202.1157 + * <pre>
202.1158 + * BitSet drPepper = new BitSet();</pre>
202.1159 + * Now {@code drPepper.toString()} returns "{@code {}}".<p>
202.1160 + * <pre>
202.1161 + * drPepper.set(2);</pre>
202.1162 + * Now {@code drPepper.toString()} returns "{@code {2}}".<p>
202.1163 + * <pre>
202.1164 + * drPepper.set(4);
202.1165 + * drPepper.set(10);</pre>
202.1166 + * Now {@code drPepper.toString()} returns "{@code {2, 4, 10}}".
202.1167 + *
202.1168 + * @return a string representation of this bit set
202.1169 + */
202.1170 + public String toString() {
202.1171 + checkInvariants();
202.1172 +
202.1173 + int numBits = (wordsInUse > 128) ?
202.1174 + cardinality() : wordsInUse * BITS_PER_WORD;
202.1175 + StringBuilder b = new StringBuilder(6*numBits + 2);
202.1176 + b.append('{');
202.1177 +
202.1178 + int i = nextSetBit(0);
202.1179 + if (i != -1) {
202.1180 + b.append(i);
202.1181 + for (i = nextSetBit(i+1); i >= 0; i = nextSetBit(i+1)) {
202.1182 + int endOfRun = nextClearBit(i);
202.1183 + do { b.append(", ").append(i); }
202.1184 + while (++i < endOfRun);
202.1185 + }
202.1186 + }
202.1187 +
202.1188 + b.append('}');
202.1189 + return b.toString();
202.1190 + }
202.1191 +}
203.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
203.2 +++ b/rt/emul/compact/src/main/java/java/util/Calendar.java Wed Apr 30 15:04:10 2014 +0200
203.3 @@ -0,0 +1,2806 @@
203.4 +/*
203.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
203.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
203.7 + *
203.8 + * This code is free software; you can redistribute it and/or modify it
203.9 + * under the terms of the GNU General Public License version 2 only, as
203.10 + * published by the Free Software Foundation. Oracle designates this
203.11 + * particular file as subject to the "Classpath" exception as provided
203.12 + * by Oracle in the LICENSE file that accompanied this code.
203.13 + *
203.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
203.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
203.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
203.17 + * version 2 for more details (a copy is included in the LICENSE file that
203.18 + * accompanied this code).
203.19 + *
203.20 + * You should have received a copy of the GNU General Public License version
203.21 + * 2 along with this work; if not, write to the Free Software Foundation,
203.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
203.23 + *
203.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
203.25 + * or visit www.oracle.com if you need additional information or have any
203.26 + * questions.
203.27 + */
203.28 +
203.29 +/*
203.30 + * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
203.31 + * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
203.32 + *
203.33 + * The original version of this source code and documentation is copyrighted
203.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
203.35 + * materials are provided under terms of a License Agreement between Taligent
203.36 + * and Sun. This technology is protected by multiple US and International
203.37 + * patents. This notice and attribution to Taligent may not be removed.
203.38 + * Taligent is a registered trademark of Taligent, Inc.
203.39 + *
203.40 + */
203.41 +
203.42 +package java.util;
203.43 +
203.44 +import java.io.IOException;
203.45 +import java.io.ObjectInputStream;
203.46 +import java.io.ObjectOutputStream;
203.47 +import java.io.OptionalDataException;
203.48 +import java.io.Serializable;
203.49 +import java.security.AccessController;
203.50 +import java.security.PrivilegedActionException;
203.51 +import java.security.PrivilegedExceptionAction;
203.52 +import java.text.DateFormat;
203.53 +import java.text.DateFormatSymbols;
203.54 +import java.util.concurrent.ConcurrentHashMap;
203.55 +import java.util.concurrent.ConcurrentMap;
203.56 +
203.57 +/**
203.58 + * The <code>Calendar</code> class is an abstract class that provides methods
203.59 + * for converting between a specific instant in time and a set of {@link
203.60 + * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
203.61 + * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
203.62 + * manipulating the calendar fields, such as getting the date of the next
203.63 + * week. An instant in time can be represented by a millisecond value that is
203.64 + * an offset from the <a name="Epoch"><em>Epoch</em></a>, January 1, 1970
203.65 + * 00:00:00.000 GMT (Gregorian).
203.66 + *
203.67 + * <p>The class also provides additional fields and methods for
203.68 + * implementing a concrete calendar system outside the package. Those
203.69 + * fields and methods are defined as <code>protected</code>.
203.70 + *
203.71 + * <p>
203.72 + * Like other locale-sensitive classes, <code>Calendar</code> provides a
203.73 + * class method, <code>getInstance</code>, for getting a generally useful
203.74 + * object of this type. <code>Calendar</code>'s <code>getInstance</code> method
203.75 + * returns a <code>Calendar</code> object whose
203.76 + * calendar fields have been initialized with the current date and time:
203.77 + * <blockquote>
203.78 + * <pre>
203.79 + * Calendar rightNow = Calendar.getInstance();
203.80 + * </pre>
203.81 + * </blockquote>
203.82 + *
203.83 + * <p>A <code>Calendar</code> object can produce all the calendar field values
203.84 + * needed to implement the date-time formatting for a particular language and
203.85 + * calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
203.86 + * <code>Calendar</code> defines the range of values returned by
203.87 + * certain calendar fields, as well as their meaning. For example,
203.88 + * the first month of the calendar system has value <code>MONTH ==
203.89 + * JANUARY</code> for all calendars. Other values are defined by the
203.90 + * concrete subclass, such as <code>ERA</code>. See individual field
203.91 + * documentation and subclass documentation for details.
203.92 + *
203.93 + * <h4>Getting and Setting Calendar Field Values</h4>
203.94 + *
203.95 + * <p>The calendar field values can be set by calling the <code>set</code>
203.96 + * methods. Any field values set in a <code>Calendar</code> will not be
203.97 + * interpreted until it needs to calculate its time value (milliseconds from
203.98 + * the Epoch) or values of the calendar fields. Calling the
203.99 + * <code>get</code>, <code>getTimeInMillis</code>, <code>getTime</code>,
203.100 + * <code>add</code> and <code>roll</code> involves such calculation.
203.101 + *
203.102 + * <h4>Leniency</h4>
203.103 + *
203.104 + * <p><code>Calendar</code> has two modes for interpreting the calendar
203.105 + * fields, <em>lenient</em> and <em>non-lenient</em>. When a
203.106 + * <code>Calendar</code> is in lenient mode, it accepts a wider range of
203.107 + * calendar field values than it produces. When a <code>Calendar</code>
203.108 + * recomputes calendar field values for return by <code>get()</code>, all of
203.109 + * the calendar fields are normalized. For example, a lenient
203.110 + * <code>GregorianCalendar</code> interprets <code>MONTH == JANUARY</code>,
203.111 + * <code>DAY_OF_MONTH == 32</code> as February 1.
203.112 +
203.113 + * <p>When a <code>Calendar</code> is in non-lenient mode, it throws an
203.114 + * exception if there is any inconsistency in its calendar fields. For
203.115 + * example, a <code>GregorianCalendar</code> always produces
203.116 + * <code>DAY_OF_MONTH</code> values between 1 and the length of the month. A
203.117 + * non-lenient <code>GregorianCalendar</code> throws an exception upon
203.118 + * calculating its time or calendar field values if any out-of-range field
203.119 + * value has been set.
203.120 + *
203.121 + * <h4><a name="first_week">First Week</a></h4>
203.122 + *
203.123 + * <code>Calendar</code> defines a locale-specific seven day week using two
203.124 + * parameters: the first day of the week and the minimal days in first week
203.125 + * (from 1 to 7). These numbers are taken from the locale resource data when a
203.126 + * <code>Calendar</code> is constructed. They may also be specified explicitly
203.127 + * through the methods for setting their values.
203.128 + *
203.129 + * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
203.130 + * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
203.131 + * first week of the month or year as a reference point. The first week of a
203.132 + * month or year is defined as the earliest seven day period beginning on
203.133 + * <code>getFirstDayOfWeek()</code> and containing at least
203.134 + * <code>getMinimalDaysInFirstWeek()</code> days of that month or year. Weeks
203.135 + * numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
203.136 + * it. Note that the normalized numbering returned by <code>get()</code> may be
203.137 + * different. For example, a specific <code>Calendar</code> subclass may
203.138 + * designate the week before week 1 of a year as week <code><i>n</i></code> of
203.139 + * the previous year.
203.140 + *
203.141 + * <h4>Calendar Fields Resolution</h4>
203.142 + *
203.143 + * When computing a date and time from the calendar fields, there
203.144 + * may be insufficient information for the computation (such as only
203.145 + * year and month with no day of month), or there may be inconsistent
203.146 + * information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
203.147 + * 1996 is actually a Monday). <code>Calendar</code> will resolve
203.148 + * calendar field values to determine the date and time in the
203.149 + * following way.
203.150 + *
203.151 + * <p>If there is any conflict in calendar field values,
203.152 + * <code>Calendar</code> gives priorities to calendar fields that have been set
203.153 + * more recently. The following are the default combinations of the
203.154 + * calendar fields. The most recent combination, as determined by the
203.155 + * most recently set single field, will be used.
203.156 + *
203.157 + * <p><a name="date_resolution">For the date fields</a>:
203.158 + * <blockquote>
203.159 + * <pre>
203.160 + * YEAR + MONTH + DAY_OF_MONTH
203.161 + * YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
203.162 + * YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
203.163 + * YEAR + DAY_OF_YEAR
203.164 + * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
203.165 + * </pre></blockquote>
203.166 + *
203.167 + * <a name="time_resolution">For the time of day fields</a>:
203.168 + * <blockquote>
203.169 + * <pre>
203.170 + * HOUR_OF_DAY
203.171 + * AM_PM + HOUR
203.172 + * </pre></blockquote>
203.173 + *
203.174 + * <p>If there are any calendar fields whose values haven't been set in the selected
203.175 + * field combination, <code>Calendar</code> uses their default values. The default
203.176 + * value of each field may vary by concrete calendar systems. For example, in
203.177 + * <code>GregorianCalendar</code>, the default of a field is the same as that
203.178 + * of the start of the Epoch: i.e., <code>YEAR = 1970</code>, <code>MONTH =
203.179 + * JANUARY</code>, <code>DAY_OF_MONTH = 1</code>, etc.
203.180 + *
203.181 + * <p>
203.182 + * <strong>Note:</strong> There are certain possible ambiguities in
203.183 + * interpretation of certain singular times, which are resolved in the
203.184 + * following ways:
203.185 + * <ol>
203.186 + * <li> 23:59 is the last minute of the day and 00:00 is the first
203.187 + * minute of the next day. Thus, 23:59 on Dec 31, 1999 < 00:00 on
203.188 + * Jan 1, 2000 < 00:01 on Jan 1, 2000.
203.189 + *
203.190 + * <li> Although historically not precise, midnight also belongs to "am",
203.191 + * and noon belongs to "pm", so on the same day,
203.192 + * 12:00 am (midnight) < 12:01 am, and 12:00 pm (noon) < 12:01 pm
203.193 + * </ol>
203.194 + *
203.195 + * <p>
203.196 + * The date or time format strings are not part of the definition of a
203.197 + * calendar, as those must be modifiable or overridable by the user at
203.198 + * runtime. Use {@link DateFormat}
203.199 + * to format dates.
203.200 + *
203.201 + * <h4>Field Manipulation</h4>
203.202 + *
203.203 + * The calendar fields can be changed using three methods:
203.204 + * <code>set()</code>, <code>add()</code>, and <code>roll()</code>.</p>
203.205 + *
203.206 + * <p><strong><code>set(f, value)</code></strong> changes calendar field
203.207 + * <code>f</code> to <code>value</code>. In addition, it sets an
203.208 + * internal member variable to indicate that calendar field <code>f</code> has
203.209 + * been changed. Although calendar field <code>f</code> is changed immediately,
203.210 + * the calendar's time value in milliseconds is not recomputed until the next call to
203.211 + * <code>get()</code>, <code>getTime()</code>, <code>getTimeInMillis()</code>,
203.212 + * <code>add()</code>, or <code>roll()</code> is made. Thus, multiple calls to
203.213 + * <code>set()</code> do not trigger multiple, unnecessary
203.214 + * computations. As a result of changing a calendar field using
203.215 + * <code>set()</code>, other calendar fields may also change, depending on the
203.216 + * calendar field, the calendar field value, and the calendar system. In addition,
203.217 + * <code>get(f)</code> will not necessarily return <code>value</code> set by
203.218 + * the call to the <code>set</code> method
203.219 + * after the calendar fields have been recomputed. The specifics are determined by
203.220 + * the concrete calendar class.</p>
203.221 + *
203.222 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
203.223 + * originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
203.224 + * Calendar.SEPTEMBER)</code> sets the date to September 31,
203.225 + * 1999. This is a temporary internal representation that resolves to
203.226 + * October 1, 1999 if <code>getTime()</code>is then called. However, a
203.227 + * call to <code>set(Calendar.DAY_OF_MONTH, 30)</code> before the call to
203.228 + * <code>getTime()</code> sets the date to September 30, 1999, since
203.229 + * no recomputation occurs after <code>set()</code> itself.</p>
203.230 + *
203.231 + * <p><strong><code>add(f, delta)</code></strong> adds <code>delta</code>
203.232 + * to field <code>f</code>. This is equivalent to calling <code>set(f,
203.233 + * get(f) + delta)</code> with two adjustments:</p>
203.234 + *
203.235 + * <blockquote>
203.236 + * <p><strong>Add rule 1</strong>. The value of field <code>f</code>
203.237 + * after the call minus the value of field <code>f</code> before the
203.238 + * call is <code>delta</code>, modulo any overflow that has occurred in
203.239 + * field <code>f</code>. Overflow occurs when a field value exceeds its
203.240 + * range and, as a result, the next larger field is incremented or
203.241 + * decremented and the field value is adjusted back into its range.</p>
203.242 + *
203.243 + * <p><strong>Add rule 2</strong>. If a smaller field is expected to be
203.244 + * invariant, but it is impossible for it to be equal to its
203.245 + * prior value because of changes in its minimum or maximum after field
203.246 + * <code>f</code> is changed or other constraints, such as time zone
203.247 + * offset changes, then its value is adjusted to be as close
203.248 + * as possible to its expected value. A smaller field represents a
203.249 + * smaller unit of time. <code>HOUR</code> is a smaller field than
203.250 + * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
203.251 + * that are not expected to be invariant. The calendar system
203.252 + * determines what fields are expected to be invariant.</p>
203.253 + * </blockquote>
203.254 + *
203.255 + * <p>In addition, unlike <code>set()</code>, <code>add()</code> forces
203.256 + * an immediate recomputation of the calendar's milliseconds and all
203.257 + * fields.</p>
203.258 + *
203.259 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
203.260 + * originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
203.261 + * 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
203.262 + * 1</strong> sets the <code>MONTH</code> field to September, since
203.263 + * adding 13 months to August gives September of the next year. Since
203.264 + * <code>DAY_OF_MONTH</code> cannot be 31 in September in a
203.265 + * <code>GregorianCalendar</code>, <strong>add rule 2</strong> sets the
203.266 + * <code>DAY_OF_MONTH</code> to 30, the closest possible value. Although
203.267 + * it is a smaller field, <code>DAY_OF_WEEK</code> is not adjusted by
203.268 + * rule 2, since it is expected to change when the month changes in a
203.269 + * <code>GregorianCalendar</code>.</p>
203.270 + *
203.271 + * <p><strong><code>roll(f, delta)</code></strong> adds
203.272 + * <code>delta</code> to field <code>f</code> without changing larger
203.273 + * fields. This is equivalent to calling <code>add(f, delta)</code> with
203.274 + * the following adjustment:</p>
203.275 + *
203.276 + * <blockquote>
203.277 + * <p><strong>Roll rule</strong>. Larger fields are unchanged after the
203.278 + * call. A larger field represents a larger unit of
203.279 + * time. <code>DAY_OF_MONTH</code> is a larger field than
203.280 + * <code>HOUR</code>.</p>
203.281 + * </blockquote>
203.282 + *
203.283 + * <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
203.284 + *
203.285 + * <p><strong>Usage model</strong>. To motivate the behavior of
203.286 + * <code>add()</code> and <code>roll()</code>, consider a user interface
203.287 + * component with increment and decrement buttons for the month, day, and
203.288 + * year, and an underlying <code>GregorianCalendar</code>. If the
203.289 + * interface reads January 31, 1999 and the user presses the month
203.290 + * increment button, what should it read? If the underlying
203.291 + * implementation uses <code>set()</code>, it might read March 3, 1999. A
203.292 + * better result would be February 28, 1999. Furthermore, if the user
203.293 + * presses the month increment button again, it should read March 31,
203.294 + * 1999, not March 28, 1999. By saving the original date and using either
203.295 + * <code>add()</code> or <code>roll()</code>, depending on whether larger
203.296 + * fields should be affected, the user interface can behave as most users
203.297 + * will intuitively expect.</p>
203.298 + *
203.299 + * @see java.lang.System#currentTimeMillis()
203.300 + * @see Date
203.301 + * @see GregorianCalendar
203.302 + * @see TimeZone
203.303 + * @see java.text.DateFormat
203.304 + * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
203.305 + * @since JDK1.1
203.306 + */
203.307 +public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
203.308 +
203.309 + // Data flow in Calendar
203.310 + // ---------------------
203.311 +
203.312 + // The current time is represented in two ways by Calendar: as UTC
203.313 + // milliseconds from the epoch (1 January 1970 0:00 UTC), and as local
203.314 + // fields such as MONTH, HOUR, AM_PM, etc. It is possible to compute the
203.315 + // millis from the fields, and vice versa. The data needed to do this
203.316 + // conversion is encapsulated by a TimeZone object owned by the Calendar.
203.317 + // The data provided by the TimeZone object may also be overridden if the
203.318 + // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
203.319 + // keeps track of what information was most recently set by the caller, and
203.320 + // uses that to compute any other information as needed.
203.321 +
203.322 + // If the user sets the fields using set(), the data flow is as follows.
203.323 + // This is implemented by the Calendar subclass's computeTime() method.
203.324 + // During this process, certain fields may be ignored. The disambiguation
203.325 + // algorithm for resolving which fields to pay attention to is described
203.326 + // in the class documentation.
203.327 +
203.328 + // local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
203.329 + // |
203.330 + // | Using Calendar-specific algorithm
203.331 + // V
203.332 + // local standard millis
203.333 + // |
203.334 + // | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
203.335 + // V
203.336 + // UTC millis (in time data member)
203.337 +
203.338 + // If the user sets the UTC millis using setTime() or setTimeInMillis(),
203.339 + // the data flow is as follows. This is implemented by the Calendar
203.340 + // subclass's computeFields() method.
203.341 +
203.342 + // UTC millis (in time data member)
203.343 + // |
203.344 + // | Using TimeZone getOffset()
203.345 + // V
203.346 + // local standard millis
203.347 + // |
203.348 + // | Using Calendar-specific algorithm
203.349 + // V
203.350 + // local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
203.351 +
203.352 + // In general, a round trip from fields, through local and UTC millis, and
203.353 + // back out to fields is made when necessary. This is implemented by the
203.354 + // complete() method. Resolving a partial set of fields into a UTC millis
203.355 + // value allows all remaining fields to be generated from that value. If
203.356 + // the Calendar is lenient, the fields are also renormalized to standard
203.357 + // ranges when they are regenerated.
203.358 +
203.359 + /**
203.360 + * Field number for <code>get</code> and <code>set</code> indicating the
203.361 + * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
203.362 + * value; see subclass documentation.
203.363 + *
203.364 + * @see GregorianCalendar#AD
203.365 + * @see GregorianCalendar#BC
203.366 + */
203.367 + public final static int ERA = 0;
203.368 +
203.369 + /**
203.370 + * Field number for <code>get</code> and <code>set</code> indicating the
203.371 + * year. This is a calendar-specific value; see subclass documentation.
203.372 + */
203.373 + public final static int YEAR = 1;
203.374 +
203.375 + /**
203.376 + * Field number for <code>get</code> and <code>set</code> indicating the
203.377 + * month. This is a calendar-specific value. The first month of
203.378 + * the year in the Gregorian and Julian calendars is
203.379 + * <code>JANUARY</code> which is 0; the last depends on the number
203.380 + * of months in a year.
203.381 + *
203.382 + * @see #JANUARY
203.383 + * @see #FEBRUARY
203.384 + * @see #MARCH
203.385 + * @see #APRIL
203.386 + * @see #MAY
203.387 + * @see #JUNE
203.388 + * @see #JULY
203.389 + * @see #AUGUST
203.390 + * @see #SEPTEMBER
203.391 + * @see #OCTOBER
203.392 + * @see #NOVEMBER
203.393 + * @see #DECEMBER
203.394 + * @see #UNDECIMBER
203.395 + */
203.396 + public final static int MONTH = 2;
203.397 +
203.398 + /**
203.399 + * Field number for <code>get</code> and <code>set</code> indicating the
203.400 + * week number within the current year. The first week of the year, as
203.401 + * defined by <code>getFirstDayOfWeek()</code> and
203.402 + * <code>getMinimalDaysInFirstWeek()</code>, has value 1. Subclasses define
203.403 + * the value of <code>WEEK_OF_YEAR</code> for days before the first week of
203.404 + * the year.
203.405 + *
203.406 + * @see #getFirstDayOfWeek
203.407 + * @see #getMinimalDaysInFirstWeek
203.408 + */
203.409 + public final static int WEEK_OF_YEAR = 3;
203.410 +
203.411 + /**
203.412 + * Field number for <code>get</code> and <code>set</code> indicating the
203.413 + * week number within the current month. The first week of the month, as
203.414 + * defined by <code>getFirstDayOfWeek()</code> and
203.415 + * <code>getMinimalDaysInFirstWeek()</code>, has value 1. Subclasses define
203.416 + * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
203.417 + * the month.
203.418 + *
203.419 + * @see #getFirstDayOfWeek
203.420 + * @see #getMinimalDaysInFirstWeek
203.421 + */
203.422 + public final static int WEEK_OF_MONTH = 4;
203.423 +
203.424 + /**
203.425 + * Field number for <code>get</code> and <code>set</code> indicating the
203.426 + * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
203.427 + * The first day of the month has value 1.
203.428 + *
203.429 + * @see #DAY_OF_MONTH
203.430 + */
203.431 + public final static int DATE = 5;
203.432 +
203.433 + /**
203.434 + * Field number for <code>get</code> and <code>set</code> indicating the
203.435 + * day of the month. This is a synonym for <code>DATE</code>.
203.436 + * The first day of the month has value 1.
203.437 + *
203.438 + * @see #DATE
203.439 + */
203.440 + public final static int DAY_OF_MONTH = 5;
203.441 +
203.442 + /**
203.443 + * Field number for <code>get</code> and <code>set</code> indicating the day
203.444 + * number within the current year. The first day of the year has value 1.
203.445 + */
203.446 + public final static int DAY_OF_YEAR = 6;
203.447 +
203.448 + /**
203.449 + * Field number for <code>get</code> and <code>set</code> indicating the day
203.450 + * of the week. This field takes values <code>SUNDAY</code>,
203.451 + * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
203.452 + * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
203.453 + *
203.454 + * @see #SUNDAY
203.455 + * @see #MONDAY
203.456 + * @see #TUESDAY
203.457 + * @see #WEDNESDAY
203.458 + * @see #THURSDAY
203.459 + * @see #FRIDAY
203.460 + * @see #SATURDAY
203.461 + */
203.462 + public final static int DAY_OF_WEEK = 7;
203.463 +
203.464 + /**
203.465 + * Field number for <code>get</code> and <code>set</code> indicating the
203.466 + * ordinal number of the day of the week within the current month. Together
203.467 + * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
203.468 + * within a month. Unlike <code>WEEK_OF_MONTH</code> and
203.469 + * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
203.470 + * <code>getFirstDayOfWeek()</code> or
203.471 + * <code>getMinimalDaysInFirstWeek()</code>. <code>DAY_OF_MONTH 1</code>
203.472 + * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
203.473 + * 1</code>; <code>8</code> through <code>14</code> correspond to
203.474 + * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
203.475 + * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
203.476 + * <code>DAY_OF_WEEK_IN_MONTH 1</code>. Negative values count back from the
203.477 + * end of the month, so the last Sunday of a month is specified as
203.478 + * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>. Because
203.479 + * negative values count backward they will usually be aligned differently
203.480 + * within the month than positive values. For example, if a month has 31
203.481 + * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
203.482 + * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
203.483 + *
203.484 + * @see #DAY_OF_WEEK
203.485 + * @see #WEEK_OF_MONTH
203.486 + */
203.487 + public final static int DAY_OF_WEEK_IN_MONTH = 8;
203.488 +
203.489 + /**
203.490 + * Field number for <code>get</code> and <code>set</code> indicating
203.491 + * whether the <code>HOUR</code> is before or after noon.
203.492 + * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
203.493 + *
203.494 + * @see #AM
203.495 + * @see #PM
203.496 + * @see #HOUR
203.497 + */
203.498 + public final static int AM_PM = 9;
203.499 +
203.500 + /**
203.501 + * Field number for <code>get</code> and <code>set</code> indicating the
203.502 + * hour of the morning or afternoon. <code>HOUR</code> is used for the
203.503 + * 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
203.504 + * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
203.505 + *
203.506 + * @see #AM_PM
203.507 + * @see #HOUR_OF_DAY
203.508 + */
203.509 + public final static int HOUR = 10;
203.510 +
203.511 + /**
203.512 + * Field number for <code>get</code> and <code>set</code> indicating the
203.513 + * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
203.514 + * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
203.515 + *
203.516 + * @see #HOUR
203.517 + */
203.518 + public final static int HOUR_OF_DAY = 11;
203.519 +
203.520 + /**
203.521 + * Field number for <code>get</code> and <code>set</code> indicating the
203.522 + * minute within the hour.
203.523 + * E.g., at 10:04:15.250 PM the <code>MINUTE</code> is 4.
203.524 + */
203.525 + public final static int MINUTE = 12;
203.526 +
203.527 + /**
203.528 + * Field number for <code>get</code> and <code>set</code> indicating the
203.529 + * second within the minute.
203.530 + * E.g., at 10:04:15.250 PM the <code>SECOND</code> is 15.
203.531 + */
203.532 + public final static int SECOND = 13;
203.533 +
203.534 + /**
203.535 + * Field number for <code>get</code> and <code>set</code> indicating the
203.536 + * millisecond within the second.
203.537 + * E.g., at 10:04:15.250 PM the <code>MILLISECOND</code> is 250.
203.538 + */
203.539 + public final static int MILLISECOND = 14;
203.540 +
203.541 + /**
203.542 + * Field number for <code>get</code> and <code>set</code>
203.543 + * indicating the raw offset from GMT in milliseconds.
203.544 + * <p>
203.545 + * This field reflects the correct GMT offset value of the time
203.546 + * zone of this <code>Calendar</code> if the
203.547 + * <code>TimeZone</code> implementation subclass supports
203.548 + * historical GMT offset changes.
203.549 + */
203.550 + public final static int ZONE_OFFSET = 15;
203.551 +
203.552 + /**
203.553 + * Field number for <code>get</code> and <code>set</code> indicating the
203.554 + * daylight saving offset in milliseconds.
203.555 + * <p>
203.556 + * This field reflects the correct daylight saving offset value of
203.557 + * the time zone of this <code>Calendar</code> if the
203.558 + * <code>TimeZone</code> implementation subclass supports
203.559 + * historical Daylight Saving Time schedule changes.
203.560 + */
203.561 + public final static int DST_OFFSET = 16;
203.562 +
203.563 + /**
203.564 + * The number of distinct fields recognized by <code>get</code> and <code>set</code>.
203.565 + * Field numbers range from <code>0..FIELD_COUNT-1</code>.
203.566 + */
203.567 + public final static int FIELD_COUNT = 17;
203.568 +
203.569 + /**
203.570 + * Value of the {@link #DAY_OF_WEEK} field indicating
203.571 + * Sunday.
203.572 + */
203.573 + public final static int SUNDAY = 1;
203.574 +
203.575 + /**
203.576 + * Value of the {@link #DAY_OF_WEEK} field indicating
203.577 + * Monday.
203.578 + */
203.579 + public final static int MONDAY = 2;
203.580 +
203.581 + /**
203.582 + * Value of the {@link #DAY_OF_WEEK} field indicating
203.583 + * Tuesday.
203.584 + */
203.585 + public final static int TUESDAY = 3;
203.586 +
203.587 + /**
203.588 + * Value of the {@link #DAY_OF_WEEK} field indicating
203.589 + * Wednesday.
203.590 + */
203.591 + public final static int WEDNESDAY = 4;
203.592 +
203.593 + /**
203.594 + * Value of the {@link #DAY_OF_WEEK} field indicating
203.595 + * Thursday.
203.596 + */
203.597 + public final static int THURSDAY = 5;
203.598 +
203.599 + /**
203.600 + * Value of the {@link #DAY_OF_WEEK} field indicating
203.601 + * Friday.
203.602 + */
203.603 + public final static int FRIDAY = 6;
203.604 +
203.605 + /**
203.606 + * Value of the {@link #DAY_OF_WEEK} field indicating
203.607 + * Saturday.
203.608 + */
203.609 + public final static int SATURDAY = 7;
203.610 +
203.611 + /**
203.612 + * Value of the {@link #MONTH} field indicating the
203.613 + * first month of the year in the Gregorian and Julian calendars.
203.614 + */
203.615 + public final static int JANUARY = 0;
203.616 +
203.617 + /**
203.618 + * Value of the {@link #MONTH} field indicating the
203.619 + * second month of the year in the Gregorian and Julian calendars.
203.620 + */
203.621 + public final static int FEBRUARY = 1;
203.622 +
203.623 + /**
203.624 + * Value of the {@link #MONTH} field indicating the
203.625 + * third month of the year in the Gregorian and Julian calendars.
203.626 + */
203.627 + public final static int MARCH = 2;
203.628 +
203.629 + /**
203.630 + * Value of the {@link #MONTH} field indicating the
203.631 + * fourth month of the year in the Gregorian and Julian calendars.
203.632 + */
203.633 + public final static int APRIL = 3;
203.634 +
203.635 + /**
203.636 + * Value of the {@link #MONTH} field indicating the
203.637 + * fifth month of the year in the Gregorian and Julian calendars.
203.638 + */
203.639 + public final static int MAY = 4;
203.640 +
203.641 + /**
203.642 + * Value of the {@link #MONTH} field indicating the
203.643 + * sixth month of the year in the Gregorian and Julian calendars.
203.644 + */
203.645 + public final static int JUNE = 5;
203.646 +
203.647 + /**
203.648 + * Value of the {@link #MONTH} field indicating the
203.649 + * seventh month of the year in the Gregorian and Julian calendars.
203.650 + */
203.651 + public final static int JULY = 6;
203.652 +
203.653 + /**
203.654 + * Value of the {@link #MONTH} field indicating the
203.655 + * eighth month of the year in the Gregorian and Julian calendars.
203.656 + */
203.657 + public final static int AUGUST = 7;
203.658 +
203.659 + /**
203.660 + * Value of the {@link #MONTH} field indicating the
203.661 + * ninth month of the year in the Gregorian and Julian calendars.
203.662 + */
203.663 + public final static int SEPTEMBER = 8;
203.664 +
203.665 + /**
203.666 + * Value of the {@link #MONTH} field indicating the
203.667 + * tenth month of the year in the Gregorian and Julian calendars.
203.668 + */
203.669 + public final static int OCTOBER = 9;
203.670 +
203.671 + /**
203.672 + * Value of the {@link #MONTH} field indicating the
203.673 + * eleventh month of the year in the Gregorian and Julian calendars.
203.674 + */
203.675 + public final static int NOVEMBER = 10;
203.676 +
203.677 + /**
203.678 + * Value of the {@link #MONTH} field indicating the
203.679 + * twelfth month of the year in the Gregorian and Julian calendars.
203.680 + */
203.681 + public final static int DECEMBER = 11;
203.682 +
203.683 + /**
203.684 + * Value of the {@link #MONTH} field indicating the
203.685 + * thirteenth month of the year. Although <code>GregorianCalendar</code>
203.686 + * does not use this value, lunar calendars do.
203.687 + */
203.688 + public final static int UNDECIMBER = 12;
203.689 +
203.690 + /**
203.691 + * Value of the {@link #AM_PM} field indicating the
203.692 + * period of the day from midnight to just before noon.
203.693 + */
203.694 + public final static int AM = 0;
203.695 +
203.696 + /**
203.697 + * Value of the {@link #AM_PM} field indicating the
203.698 + * period of the day from noon to just before midnight.
203.699 + */
203.700 + public final static int PM = 1;
203.701 +
203.702 + /**
203.703 + * A style specifier for {@link #getDisplayNames(int, int, Locale)
203.704 + * getDisplayNames} indicating names in all styles, such as
203.705 + * "January" and "Jan".
203.706 + *
203.707 + * @see #SHORT
203.708 + * @see #LONG
203.709 + * @since 1.6
203.710 + */
203.711 + public static final int ALL_STYLES = 0;
203.712 +
203.713 + /**
203.714 + * A style specifier for {@link #getDisplayName(int, int, Locale)
203.715 + * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
203.716 + * getDisplayNames} indicating a short name, such as "Jan".
203.717 + *
203.718 + * @see #LONG
203.719 + * @since 1.6
203.720 + */
203.721 + public static final int SHORT = 1;
203.722 +
203.723 + /**
203.724 + * A style specifier for {@link #getDisplayName(int, int, Locale)
203.725 + * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
203.726 + * getDisplayNames} indicating a long name, such as "January".
203.727 + *
203.728 + * @see #SHORT
203.729 + * @since 1.6
203.730 + */
203.731 + public static final int LONG = 2;
203.732 +
203.733 + // Internal notes:
203.734 + // Calendar contains two kinds of time representations: current "time" in
203.735 + // milliseconds, and a set of calendar "fields" representing the current time.
203.736 + // The two representations are usually in sync, but can get out of sync
203.737 + // as follows.
203.738 + // 1. Initially, no fields are set, and the time is invalid.
203.739 + // 2. If the time is set, all fields are computed and in sync.
203.740 + // 3. If a single field is set, the time is invalid.
203.741 + // Recomputation of the time and fields happens when the object needs
203.742 + // to return a result to the user, or use a result for a computation.
203.743 +
203.744 + /**
203.745 + * The calendar field values for the currently set time for this calendar.
203.746 + * This is an array of <code>FIELD_COUNT</code> integers, with index values
203.747 + * <code>ERA</code> through <code>DST_OFFSET</code>.
203.748 + * @serial
203.749 + */
203.750 + protected int fields[];
203.751 +
203.752 + /**
203.753 + * The flags which tell if a specified calendar field for the calendar is set.
203.754 + * A new object has no fields set. After the first call to a method
203.755 + * which generates the fields, they all remain set after that.
203.756 + * This is an array of <code>FIELD_COUNT</code> booleans, with index values
203.757 + * <code>ERA</code> through <code>DST_OFFSET</code>.
203.758 + * @serial
203.759 + */
203.760 + protected boolean isSet[];
203.761 +
203.762 + /**
203.763 + * Pseudo-time-stamps which specify when each field was set. There
203.764 + * are two special values, UNSET and COMPUTED. Values from
203.765 + * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
203.766 + */
203.767 + transient private int stamp[];
203.768 +
203.769 + /**
203.770 + * The currently set time for this calendar, expressed in milliseconds after
203.771 + * January 1, 1970, 0:00:00 GMT.
203.772 + * @see #isTimeSet
203.773 + * @serial
203.774 + */
203.775 + protected long time;
203.776 +
203.777 + /**
203.778 + * True if then the value of <code>time</code> is valid.
203.779 + * The time is made invalid by a change to an item of <code>field[]</code>.
203.780 + * @see #time
203.781 + * @serial
203.782 + */
203.783 + protected boolean isTimeSet;
203.784 +
203.785 + /**
203.786 + * True if <code>fields[]</code> are in sync with the currently set time.
203.787 + * If false, then the next attempt to get the value of a field will
203.788 + * force a recomputation of all fields from the current value of
203.789 + * <code>time</code>.
203.790 + * @serial
203.791 + */
203.792 + protected boolean areFieldsSet;
203.793 +
203.794 + /**
203.795 + * True if all fields have been set.
203.796 + * @serial
203.797 + */
203.798 + transient boolean areAllFieldsSet;
203.799 +
203.800 + /**
203.801 + * <code>True</code> if this calendar allows out-of-range field values during computation
203.802 + * of <code>time</code> from <code>fields[]</code>.
203.803 + * @see #setLenient
203.804 + * @see #isLenient
203.805 + * @serial
203.806 + */
203.807 + private boolean lenient = true;
203.808 +
203.809 + /**
203.810 + * The <code>TimeZone</code> used by this calendar. <code>Calendar</code>
203.811 + * uses the time zone data to translate between locale and GMT time.
203.812 + * @serial
203.813 + */
203.814 + private TimeZone zone;
203.815 +
203.816 + /**
203.817 + * <code>True</code> if zone references to a shared TimeZone object.
203.818 + */
203.819 + transient private boolean sharedZone = false;
203.820 +
203.821 + /**
203.822 + * The first day of the week, with possible values <code>SUNDAY</code>,
203.823 + * <code>MONDAY</code>, etc. This is a locale-dependent value.
203.824 + * @serial
203.825 + */
203.826 + private int firstDayOfWeek;
203.827 +
203.828 + /**
203.829 + * The number of days required for the first week in a month or year,
203.830 + * with possible values from 1 to 7. This is a locale-dependent value.
203.831 + * @serial
203.832 + */
203.833 + private int minimalDaysInFirstWeek;
203.834 +
203.835 + /**
203.836 + * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
203.837 + * of a Locale.
203.838 + */
203.839 + private static final ConcurrentMap<Locale, int[]> cachedLocaleData
203.840 + = new ConcurrentHashMap<Locale, int[]>(3);
203.841 +
203.842 + // Special values of stamp[]
203.843 + /**
203.844 + * The corresponding fields[] has no value.
203.845 + */
203.846 + private static final int UNSET = 0;
203.847 +
203.848 + /**
203.849 + * The value of the corresponding fields[] has been calculated internally.
203.850 + */
203.851 + private static final int COMPUTED = 1;
203.852 +
203.853 + /**
203.854 + * The value of the corresponding fields[] has been set externally. Stamp
203.855 + * values which are greater than 1 represents the (pseudo) time when the
203.856 + * corresponding fields[] value was set.
203.857 + */
203.858 + private static final int MINIMUM_USER_STAMP = 2;
203.859 +
203.860 + /**
203.861 + * The mask value that represents all of the fields.
203.862 + */
203.863 + static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
203.864 +
203.865 + /**
203.866 + * The next available value for <code>stamp[]</code>, an internal array.
203.867 + * This actually should not be written out to the stream, and will probably
203.868 + * be removed from the stream in the near future. In the meantime,
203.869 + * a value of <code>MINIMUM_USER_STAMP</code> should be used.
203.870 + * @serial
203.871 + */
203.872 + private int nextStamp = MINIMUM_USER_STAMP;
203.873 +
203.874 + // the internal serial version which says which version was written
203.875 + // - 0 (default) for version up to JDK 1.1.5
203.876 + // - 1 for version from JDK 1.1.6, which writes a correct 'time' value
203.877 + // as well as compatible values for other fields. This is a
203.878 + // transitional format.
203.879 + // - 2 (not implemented yet) a future version, in which fields[],
203.880 + // areFieldsSet, and isTimeSet become transient, and isSet[] is
203.881 + // removed. In JDK 1.1.6 we write a format compatible with version 2.
203.882 + static final int currentSerialVersion = 1;
203.883 +
203.884 + /**
203.885 + * The version of the serialized data on the stream. Possible values:
203.886 + * <dl>
203.887 + * <dt><b>0</b> or not present on stream</dt>
203.888 + * <dd>
203.889 + * JDK 1.1.5 or earlier.
203.890 + * </dd>
203.891 + * <dt><b>1</b></dt>
203.892 + * <dd>
203.893 + * JDK 1.1.6 or later. Writes a correct 'time' value
203.894 + * as well as compatible values for other fields. This is a
203.895 + * transitional format.
203.896 + * </dd>
203.897 + * </dl>
203.898 + * When streaming out this class, the most recent format
203.899 + * and the highest allowable <code>serialVersionOnStream</code>
203.900 + * is written.
203.901 + * @serial
203.902 + * @since JDK1.1.6
203.903 + */
203.904 + private int serialVersionOnStream = currentSerialVersion;
203.905 +
203.906 + // Proclaim serialization compatibility with JDK 1.1
203.907 + static final long serialVersionUID = -1807547505821590642L;
203.908 +
203.909 + // Mask values for calendar fields
203.910 + final static int ERA_MASK = (1 << ERA);
203.911 + final static int YEAR_MASK = (1 << YEAR);
203.912 + final static int MONTH_MASK = (1 << MONTH);
203.913 + final static int WEEK_OF_YEAR_MASK = (1 << WEEK_OF_YEAR);
203.914 + final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
203.915 + final static int DAY_OF_MONTH_MASK = (1 << DAY_OF_MONTH);
203.916 + final static int DATE_MASK = DAY_OF_MONTH_MASK;
203.917 + final static int DAY_OF_YEAR_MASK = (1 << DAY_OF_YEAR);
203.918 + final static int DAY_OF_WEEK_MASK = (1 << DAY_OF_WEEK);
203.919 + final static int DAY_OF_WEEK_IN_MONTH_MASK = (1 << DAY_OF_WEEK_IN_MONTH);
203.920 + final static int AM_PM_MASK = (1 << AM_PM);
203.921 + final static int HOUR_MASK = (1 << HOUR);
203.922 + final static int HOUR_OF_DAY_MASK = (1 << HOUR_OF_DAY);
203.923 + final static int MINUTE_MASK = (1 << MINUTE);
203.924 + final static int SECOND_MASK = (1 << SECOND);
203.925 + final static int MILLISECOND_MASK = (1 << MILLISECOND);
203.926 + final static int ZONE_OFFSET_MASK = (1 << ZONE_OFFSET);
203.927 + final static int DST_OFFSET_MASK = (1 << DST_OFFSET);
203.928 +
203.929 + /**
203.930 + * Constructs a Calendar with the default time zone
203.931 + * and locale.
203.932 + * @see TimeZone#getDefault
203.933 + */
203.934 + protected Calendar()
203.935 + {
203.936 + this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
203.937 + sharedZone = true;
203.938 + }
203.939 +
203.940 + /**
203.941 + * Constructs a calendar with the specified time zone and locale.
203.942 + *
203.943 + * @param zone the time zone to use
203.944 + * @param aLocale the locale for the week data
203.945 + */
203.946 + protected Calendar(TimeZone zone, Locale aLocale)
203.947 + {
203.948 + fields = new int[FIELD_COUNT];
203.949 + isSet = new boolean[FIELD_COUNT];
203.950 + stamp = new int[FIELD_COUNT];
203.951 +
203.952 + this.zone = zone;
203.953 + setWeekCountData(aLocale);
203.954 + }
203.955 +
203.956 + /**
203.957 + * Gets a calendar using the default time zone and locale. The
203.958 + * <code>Calendar</code> returned is based on the current time
203.959 + * in the default time zone with the default locale.
203.960 + *
203.961 + * @return a Calendar.
203.962 + */
203.963 + public static Calendar getInstance()
203.964 + {
203.965 + Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
203.966 + cal.sharedZone = true;
203.967 + return cal;
203.968 + }
203.969 +
203.970 + /**
203.971 + * Gets a calendar using the specified time zone and default locale.
203.972 + * The <code>Calendar</code> returned is based on the current time
203.973 + * in the given time zone with the default locale.
203.974 + *
203.975 + * @param zone the time zone to use
203.976 + * @return a Calendar.
203.977 + */
203.978 + public static Calendar getInstance(TimeZone zone)
203.979 + {
203.980 + return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
203.981 + }
203.982 +
203.983 + /**
203.984 + * Gets a calendar using the default time zone and specified locale.
203.985 + * The <code>Calendar</code> returned is based on the current time
203.986 + * in the default time zone with the given locale.
203.987 + *
203.988 + * @param aLocale the locale for the week data
203.989 + * @return a Calendar.
203.990 + */
203.991 + public static Calendar getInstance(Locale aLocale)
203.992 + {
203.993 + Calendar cal = createCalendar(TimeZone.getDefaultRef(), aLocale);
203.994 + cal.sharedZone = true;
203.995 + return cal;
203.996 + }
203.997 +
203.998 + /**
203.999 + * Gets a calendar with the specified time zone and locale.
203.1000 + * The <code>Calendar</code> returned is based on the current time
203.1001 + * in the given time zone with the given locale.
203.1002 + *
203.1003 + * @param zone the time zone to use
203.1004 + * @param aLocale the locale for the week data
203.1005 + * @return a Calendar.
203.1006 + */
203.1007 + public static Calendar getInstance(TimeZone zone,
203.1008 + Locale aLocale)
203.1009 + {
203.1010 + return createCalendar(zone, aLocale);
203.1011 + }
203.1012 +
203.1013 + private static Calendar createCalendar(TimeZone zone,
203.1014 + Locale aLocale)
203.1015 + {
203.1016 + Calendar cal = null;
203.1017 +
203.1018 + String caltype = aLocale.getUnicodeLocaleType("ca");
203.1019 + if (caltype == null) {
203.1020 + // Calendar type is not specified.
203.1021 + // If the specified locale is a Thai locale,
203.1022 + // returns a BuddhistCalendar instance.
203.1023 + if ("th".equals(aLocale.getLanguage())
203.1024 + && ("TH".equals(aLocale.getCountry()))) {
203.1025 +// cal = new BuddhistCalendar(zone, aLocale);
203.1026 + } else {
203.1027 +// cal = new GregorianCalendar(zone, aLocale);
203.1028 + }
203.1029 + } else if (caltype.equals("japanese")) {
203.1030 +// cal = new JapaneseImperialCalendar(zone, aLocale);
203.1031 + } else if (caltype.equals("buddhist")) {
203.1032 +// cal = new BuddhistCalendar(zone, aLocale);
203.1033 + } else {
203.1034 + // Unsupported calendar type.
203.1035 + // Use Gregorian calendar as a fallback.
203.1036 +// cal = new GregorianCalendar(zone, aLocale);
203.1037 + }
203.1038 +
203.1039 + return cal;
203.1040 + }
203.1041 +
203.1042 + /**
203.1043 + * Returns an array of all locales for which the <code>getInstance</code>
203.1044 + * methods of this class can return localized instances.
203.1045 + * The array returned must contain at least a <code>Locale</code>
203.1046 + * instance equal to {@link java.util.Locale#US Locale.US}.
203.1047 + *
203.1048 + * @return An array of locales for which localized
203.1049 + * <code>Calendar</code> instances are available.
203.1050 + */
203.1051 + public static synchronized Locale[] getAvailableLocales()
203.1052 + {
203.1053 + return DateFormat.getAvailableLocales();
203.1054 + }
203.1055 +
203.1056 + /**
203.1057 + * Converts the current calendar field values in {@link #fields fields[]}
203.1058 + * to the millisecond time value
203.1059 + * {@link #time}.
203.1060 + *
203.1061 + * @see #complete()
203.1062 + * @see #computeFields()
203.1063 + */
203.1064 + protected abstract void computeTime();
203.1065 +
203.1066 + /**
203.1067 + * Converts the current millisecond time value {@link #time}
203.1068 + * to calendar field values in {@link #fields fields[]}.
203.1069 + * This allows you to sync up the calendar field values with
203.1070 + * a new time that is set for the calendar. The time is <em>not</em>
203.1071 + * recomputed first; to recompute the time, then the fields, call the
203.1072 + * {@link #complete()} method.
203.1073 + *
203.1074 + * @see #computeTime()
203.1075 + */
203.1076 + protected abstract void computeFields();
203.1077 +
203.1078 + /**
203.1079 + * Returns a <code>Date</code> object representing this
203.1080 + * <code>Calendar</code>'s time value (millisecond offset from the <a
203.1081 + * href="#Epoch">Epoch</a>").
203.1082 + *
203.1083 + * @return a <code>Date</code> representing the time value.
203.1084 + * @see #setTime(Date)
203.1085 + * @see #getTimeInMillis()
203.1086 + */
203.1087 + public final Date getTime() {
203.1088 + return new Date(getTimeInMillis());
203.1089 + }
203.1090 +
203.1091 + /**
203.1092 + * Sets this Calendar's time with the given <code>Date</code>.
203.1093 + * <p>
203.1094 + * Note: Calling <code>setTime()</code> with
203.1095 + * <code>Date(Long.MAX_VALUE)</code> or <code>Date(Long.MIN_VALUE)</code>
203.1096 + * may yield incorrect field values from <code>get()</code>.
203.1097 + *
203.1098 + * @param date the given Date.
203.1099 + * @see #getTime()
203.1100 + * @see #setTimeInMillis(long)
203.1101 + */
203.1102 + public final void setTime(Date date) {
203.1103 + setTimeInMillis(date.getTime());
203.1104 + }
203.1105 +
203.1106 + /**
203.1107 + * Returns this Calendar's time value in milliseconds.
203.1108 + *
203.1109 + * @return the current time as UTC milliseconds from the epoch.
203.1110 + * @see #getTime()
203.1111 + * @see #setTimeInMillis(long)
203.1112 + */
203.1113 + public long getTimeInMillis() {
203.1114 + if (!isTimeSet) {
203.1115 + updateTime();
203.1116 + }
203.1117 + return time;
203.1118 + }
203.1119 +
203.1120 + /**
203.1121 + * Sets this Calendar's current time from the given long value.
203.1122 + *
203.1123 + * @param millis the new time in UTC milliseconds from the epoch.
203.1124 + * @see #setTime(Date)
203.1125 + * @see #getTimeInMillis()
203.1126 + */
203.1127 + public void setTimeInMillis(long millis) {
203.1128 + // If we don't need to recalculate the calendar field values,
203.1129 + // do nothing.
203.1130 +// if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
203.1131 +// && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
203.1132 +// return;
203.1133 +// }
203.1134 + time = millis;
203.1135 + isTimeSet = true;
203.1136 + areFieldsSet = false;
203.1137 + computeFields();
203.1138 + areAllFieldsSet = areFieldsSet = true;
203.1139 + }
203.1140 +
203.1141 + /**
203.1142 + * Returns the value of the given calendar field. In lenient mode,
203.1143 + * all calendar fields are normalized. In non-lenient mode, all
203.1144 + * calendar fields are validated and this method throws an
203.1145 + * exception if any calendar fields have out-of-range values. The
203.1146 + * normalization and validation are handled by the
203.1147 + * {@link #complete()} method, which process is calendar
203.1148 + * system dependent.
203.1149 + *
203.1150 + * @param field the given calendar field.
203.1151 + * @return the value for the given calendar field.
203.1152 + * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
203.1153 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
203.1154 + * @see #set(int,int)
203.1155 + * @see #complete()
203.1156 + */
203.1157 + public int get(int field)
203.1158 + {
203.1159 + complete();
203.1160 + return internalGet(field);
203.1161 + }
203.1162 +
203.1163 + /**
203.1164 + * Returns the value of the given calendar field. This method does
203.1165 + * not involve normalization or validation of the field value.
203.1166 + *
203.1167 + * @param field the given calendar field.
203.1168 + * @return the value for the given calendar field.
203.1169 + * @see #get(int)
203.1170 + */
203.1171 + protected final int internalGet(int field)
203.1172 + {
203.1173 + return fields[field];
203.1174 + }
203.1175 +
203.1176 + /**
203.1177 + * Sets the value of the given calendar field. This method does
203.1178 + * not affect any setting state of the field in this
203.1179 + * <code>Calendar</code> instance.
203.1180 + *
203.1181 + * @throws IndexOutOfBoundsException if the specified field is out of range
203.1182 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
203.1183 + * @see #areFieldsSet
203.1184 + * @see #isTimeSet
203.1185 + * @see #areAllFieldsSet
203.1186 + * @see #set(int,int)
203.1187 + */
203.1188 + final void internalSet(int field, int value)
203.1189 + {
203.1190 + fields[field] = value;
203.1191 + }
203.1192 +
203.1193 + /**
203.1194 + * Sets the given calendar field to the given value. The value is not
203.1195 + * interpreted by this method regardless of the leniency mode.
203.1196 + *
203.1197 + * @param field the given calendar field.
203.1198 + * @param value the value to be set for the given calendar field.
203.1199 + * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
203.1200 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
203.1201 + * in non-lenient mode.
203.1202 + * @see #set(int,int,int)
203.1203 + * @see #set(int,int,int,int,int)
203.1204 + * @see #set(int,int,int,int,int,int)
203.1205 + * @see #get(int)
203.1206 + */
203.1207 + public void set(int field, int value)
203.1208 + {
203.1209 + // If the fields are partially normalized, calculate all the
203.1210 + // fields before changing any fields.
203.1211 + if (areFieldsSet && !areAllFieldsSet) {
203.1212 + computeFields();
203.1213 + }
203.1214 + internalSet(field, value);
203.1215 + isTimeSet = false;
203.1216 + areFieldsSet = false;
203.1217 + isSet[field] = true;
203.1218 + stamp[field] = nextStamp++;
203.1219 + if (nextStamp == Integer.MAX_VALUE) {
203.1220 + adjustStamp();
203.1221 + }
203.1222 + }
203.1223 +
203.1224 + /**
203.1225 + * Sets the values for the calendar fields <code>YEAR</code>,
203.1226 + * <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
203.1227 + * Previous values of other calendar fields are retained. If this is not desired,
203.1228 + * call {@link #clear()} first.
203.1229 + *
203.1230 + * @param year the value used to set the <code>YEAR</code> calendar field.
203.1231 + * @param month the value used to set the <code>MONTH</code> calendar field.
203.1232 + * Month value is 0-based. e.g., 0 for January.
203.1233 + * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
203.1234 + * @see #set(int,int)
203.1235 + * @see #set(int,int,int,int,int)
203.1236 + * @see #set(int,int,int,int,int,int)
203.1237 + */
203.1238 + public final void set(int year, int month, int date)
203.1239 + {
203.1240 + set(YEAR, year);
203.1241 + set(MONTH, month);
203.1242 + set(DATE, date);
203.1243 + }
203.1244 +
203.1245 + /**
203.1246 + * Sets the values for the calendar fields <code>YEAR</code>,
203.1247 + * <code>MONTH</code>, <code>DAY_OF_MONTH</code>,
203.1248 + * <code>HOUR_OF_DAY</code>, and <code>MINUTE</code>.
203.1249 + * Previous values of other fields are retained. If this is not desired,
203.1250 + * call {@link #clear()} first.
203.1251 + *
203.1252 + * @param year the value used to set the <code>YEAR</code> calendar field.
203.1253 + * @param month the value used to set the <code>MONTH</code> calendar field.
203.1254 + * Month value is 0-based. e.g., 0 for January.
203.1255 + * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
203.1256 + * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
203.1257 + * @param minute the value used to set the <code>MINUTE</code> calendar field.
203.1258 + * @see #set(int,int)
203.1259 + * @see #set(int,int,int)
203.1260 + * @see #set(int,int,int,int,int,int)
203.1261 + */
203.1262 + public final void set(int year, int month, int date, int hourOfDay, int minute)
203.1263 + {
203.1264 + set(YEAR, year);
203.1265 + set(MONTH, month);
203.1266 + set(DATE, date);
203.1267 + set(HOUR_OF_DAY, hourOfDay);
203.1268 + set(MINUTE, minute);
203.1269 + }
203.1270 +
203.1271 + /**
203.1272 + * Sets the values for the fields <code>YEAR</code>, <code>MONTH</code>,
203.1273 + * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, <code>MINUTE</code>, and
203.1274 + * <code>SECOND</code>.
203.1275 + * Previous values of other fields are retained. If this is not desired,
203.1276 + * call {@link #clear()} first.
203.1277 + *
203.1278 + * @param year the value used to set the <code>YEAR</code> calendar field.
203.1279 + * @param month the value used to set the <code>MONTH</code> calendar field.
203.1280 + * Month value is 0-based. e.g., 0 for January.
203.1281 + * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
203.1282 + * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
203.1283 + * @param minute the value used to set the <code>MINUTE</code> calendar field.
203.1284 + * @param second the value used to set the <code>SECOND</code> calendar field.
203.1285 + * @see #set(int,int)
203.1286 + * @see #set(int,int,int)
203.1287 + * @see #set(int,int,int,int,int)
203.1288 + */
203.1289 + public final void set(int year, int month, int date, int hourOfDay, int minute,
203.1290 + int second)
203.1291 + {
203.1292 + set(YEAR, year);
203.1293 + set(MONTH, month);
203.1294 + set(DATE, date);
203.1295 + set(HOUR_OF_DAY, hourOfDay);
203.1296 + set(MINUTE, minute);
203.1297 + set(SECOND, second);
203.1298 + }
203.1299 +
203.1300 + /**
203.1301 + * Sets all the calendar field values and the time value
203.1302 + * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
203.1303 + * this <code>Calendar</code> undefined. This means that {@link
203.1304 + * #isSet(int) isSet()} will return <code>false</code> for all the
203.1305 + * calendar fields, and the date and time calculations will treat
203.1306 + * the fields as if they had never been set. A
203.1307 + * <code>Calendar</code> implementation class may use its specific
203.1308 + * default field values for date/time calculations. For example,
203.1309 + * <code>GregorianCalendar</code> uses 1970 if the
203.1310 + * <code>YEAR</code> field value is undefined.
203.1311 + *
203.1312 + * @see #clear(int)
203.1313 + */
203.1314 + public final void clear()
203.1315 + {
203.1316 + for (int i = 0; i < fields.length; ) {
203.1317 + stamp[i] = fields[i] = 0; // UNSET == 0
203.1318 + isSet[i++] = false;
203.1319 + }
203.1320 + areAllFieldsSet = areFieldsSet = false;
203.1321 + isTimeSet = false;
203.1322 + }
203.1323 +
203.1324 + /**
203.1325 + * Sets the given calendar field value and the time value
203.1326 + * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
203.1327 + * this <code>Calendar</code> undefined. This means that {@link
203.1328 + * #isSet(int) isSet(field)} will return <code>false</code>, and
203.1329 + * the date and time calculations will treat the field as if it
203.1330 + * had never been set. A <code>Calendar</code> implementation
203.1331 + * class may use the field's specific default value for date and
203.1332 + * time calculations.
203.1333 + *
203.1334 + * <p>The {@link #HOUR_OF_DAY}, {@link #HOUR} and {@link #AM_PM}
203.1335 + * fields are handled independently and the <a
203.1336 + * href="#time_resolution">the resolution rule for the time of
203.1337 + * day</a> is applied. Clearing one of the fields doesn't reset
203.1338 + * the hour of day value of this <code>Calendar</code>. Use {@link
203.1339 + * #set(int,int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
203.1340 + * value.
203.1341 + *
203.1342 + * @param field the calendar field to be cleared.
203.1343 + * @see #clear()
203.1344 + */
203.1345 + public final void clear(int field)
203.1346 + {
203.1347 + fields[field] = 0;
203.1348 + stamp[field] = UNSET;
203.1349 + isSet[field] = false;
203.1350 +
203.1351 + areAllFieldsSet = areFieldsSet = false;
203.1352 + isTimeSet = false;
203.1353 + }
203.1354 +
203.1355 + /**
203.1356 + * Determines if the given calendar field has a value set,
203.1357 + * including cases that the value has been set by internal fields
203.1358 + * calculations triggered by a <code>get</code> method call.
203.1359 + *
203.1360 + * @return <code>true</code> if the given calendar field has a value set;
203.1361 + * <code>false</code> otherwise.
203.1362 + */
203.1363 + public final boolean isSet(int field)
203.1364 + {
203.1365 + return stamp[field] != UNSET;
203.1366 + }
203.1367 +
203.1368 + /**
203.1369 + * Returns the string representation of the calendar
203.1370 + * <code>field</code> value in the given <code>style</code> and
203.1371 + * <code>locale</code>. If no string representation is
203.1372 + * applicable, <code>null</code> is returned. This method calls
203.1373 + * {@link Calendar#get(int) get(field)} to get the calendar
203.1374 + * <code>field</code> value if the string representation is
203.1375 + * applicable to the given calendar <code>field</code>.
203.1376 + *
203.1377 + * <p>For example, if this <code>Calendar</code> is a
203.1378 + * <code>GregorianCalendar</code> and its date is 2005-01-01, then
203.1379 + * the string representation of the {@link #MONTH} field would be
203.1380 + * "January" in the long style in an English locale or "Jan" in
203.1381 + * the short style. However, no string representation would be
203.1382 + * available for the {@link #DAY_OF_MONTH} field, and this method
203.1383 + * would return <code>null</code>.
203.1384 + *
203.1385 + * <p>The default implementation supports the calendar fields for
203.1386 + * which a {@link DateFormatSymbols} has names in the given
203.1387 + * <code>locale</code>.
203.1388 + *
203.1389 + * @param field
203.1390 + * the calendar field for which the string representation
203.1391 + * is returned
203.1392 + * @param style
203.1393 + * the style applied to the string representation; one of
203.1394 + * {@link #SHORT} or {@link #LONG}.
203.1395 + * @param locale
203.1396 + * the locale for the string representation
203.1397 + * @return the string representation of the given
203.1398 + * <code>field</code> in the given <code>style</code>, or
203.1399 + * <code>null</code> if no string representation is
203.1400 + * applicable.
203.1401 + * @exception IllegalArgumentException
203.1402 + * if <code>field</code> or <code>style</code> is invalid,
203.1403 + * or if this <code>Calendar</code> is non-lenient and any
203.1404 + * of the calendar fields have invalid values
203.1405 + * @exception NullPointerException
203.1406 + * if <code>locale</code> is null
203.1407 + * @since 1.6
203.1408 + */
203.1409 + public String getDisplayName(int field, int style, Locale locale) {
203.1410 + if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
203.1411 + ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
203.1412 + return null;
203.1413 + }
203.1414 +
203.1415 + DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
203.1416 + String[] strings = getFieldStrings(field, style, symbols);
203.1417 + if (strings != null) {
203.1418 + int fieldValue = get(field);
203.1419 + if (fieldValue < strings.length) {
203.1420 + return strings[fieldValue];
203.1421 + }
203.1422 + }
203.1423 + return null;
203.1424 + }
203.1425 +
203.1426 + /**
203.1427 + * Returns a <code>Map</code> containing all names of the calendar
203.1428 + * <code>field</code> in the given <code>style</code> and
203.1429 + * <code>locale</code> and their corresponding field values. For
203.1430 + * example, if this <code>Calendar</code> is a {@link
203.1431 + * GregorianCalendar}, the returned map would contain "Jan" to
203.1432 + * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
203.1433 + * {@linkplain #SHORT short} style in an English locale.
203.1434 + *
203.1435 + * <p>The values of other calendar fields may be taken into
203.1436 + * account to determine a set of display names. For example, if
203.1437 + * this <code>Calendar</code> is a lunisolar calendar system and
203.1438 + * the year value given by the {@link #YEAR} field has a leap
203.1439 + * month, this method would return month names containing the leap
203.1440 + * month name, and month names are mapped to their values specific
203.1441 + * for the year.
203.1442 + *
203.1443 + * <p>The default implementation supports display names contained in
203.1444 + * a {@link DateFormatSymbols}. For example, if <code>field</code>
203.1445 + * is {@link #MONTH} and <code>style</code> is {@link
203.1446 + * #ALL_STYLES}, this method returns a <code>Map</code> containing
203.1447 + * all strings returned by {@link DateFormatSymbols#getShortMonths()}
203.1448 + * and {@link DateFormatSymbols#getMonths()}.
203.1449 + *
203.1450 + * @param field
203.1451 + * the calendar field for which the display names are returned
203.1452 + * @param style
203.1453 + * the style applied to the display names; one of {@link
203.1454 + * #SHORT}, {@link #LONG}, or {@link #ALL_STYLES}.
203.1455 + * @param locale
203.1456 + * the locale for the display names
203.1457 + * @return a <code>Map</code> containing all display names in
203.1458 + * <code>style</code> and <code>locale</code> and their
203.1459 + * field values, or <code>null</code> if no display names
203.1460 + * are defined for <code>field</code>
203.1461 + * @exception IllegalArgumentException
203.1462 + * if <code>field</code> or <code>style</code> is invalid,
203.1463 + * or if this <code>Calendar</code> is non-lenient and any
203.1464 + * of the calendar fields have invalid values
203.1465 + * @exception NullPointerException
203.1466 + * if <code>locale</code> is null
203.1467 + * @since 1.6
203.1468 + */
203.1469 + public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
203.1470 + if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
203.1471 + ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
203.1472 + return null;
203.1473 + }
203.1474 +
203.1475 + // ALL_STYLES
203.1476 + if (style == ALL_STYLES) {
203.1477 + Map<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale);
203.1478 + if (field == ERA || field == AM_PM) {
203.1479 + return shortNames;
203.1480 + }
203.1481 + Map<String,Integer> longNames = getDisplayNamesImpl(field, LONG, locale);
203.1482 + if (shortNames == null) {
203.1483 + return longNames;
203.1484 + }
203.1485 + if (longNames != null) {
203.1486 + shortNames.putAll(longNames);
203.1487 + }
203.1488 + return shortNames;
203.1489 + }
203.1490 +
203.1491 + // SHORT or LONG
203.1492 + return getDisplayNamesImpl(field, style, locale);
203.1493 + }
203.1494 +
203.1495 + private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
203.1496 + DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
203.1497 + String[] strings = getFieldStrings(field, style, symbols);
203.1498 + if (strings != null) {
203.1499 + Map<String,Integer> names = new HashMap<String,Integer>();
203.1500 + for (int i = 0; i < strings.length; i++) {
203.1501 + if (strings[i].length() == 0) {
203.1502 + continue;
203.1503 + }
203.1504 + names.put(strings[i], i);
203.1505 + }
203.1506 + return names;
203.1507 + }
203.1508 + return null;
203.1509 + }
203.1510 +
203.1511 + boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
203.1512 + Locale locale, int fieldMask) {
203.1513 + if (field < 0 || field >= fields.length ||
203.1514 + style < minStyle || style > maxStyle) {
203.1515 + throw new IllegalArgumentException();
203.1516 + }
203.1517 + if (locale == null) {
203.1518 + throw new NullPointerException();
203.1519 + }
203.1520 + return isFieldSet(fieldMask, field);
203.1521 + }
203.1522 +
203.1523 + private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
203.1524 + String[] strings = null;
203.1525 + switch (field) {
203.1526 + case ERA:
203.1527 + strings = symbols.getEras();
203.1528 + break;
203.1529 +
203.1530 + case MONTH:
203.1531 + strings = (style == LONG) ? symbols.getMonths() : symbols.getShortMonths();
203.1532 + break;
203.1533 +
203.1534 + case DAY_OF_WEEK:
203.1535 + strings = (style == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
203.1536 + break;
203.1537 +
203.1538 + case AM_PM:
203.1539 + strings = symbols.getAmPmStrings();
203.1540 + break;
203.1541 + }
203.1542 + return strings;
203.1543 + }
203.1544 +
203.1545 + /**
203.1546 + * Fills in any unset fields in the calendar fields. First, the {@link
203.1547 + * #computeTime()} method is called if the time value (millisecond offset
203.1548 + * from the <a href="#Epoch">Epoch</a>) has not been calculated from
203.1549 + * calendar field values. Then, the {@link #computeFields()} method is
203.1550 + * called to calculate all calendar field values.
203.1551 + */
203.1552 + protected void complete()
203.1553 + {
203.1554 + if (!isTimeSet)
203.1555 + updateTime();
203.1556 + if (!areFieldsSet || !areAllFieldsSet) {
203.1557 + computeFields(); // fills in unset fields
203.1558 + areAllFieldsSet = areFieldsSet = true;
203.1559 + }
203.1560 + }
203.1561 +
203.1562 + /**
203.1563 + * Returns whether the value of the specified calendar field has been set
203.1564 + * externally by calling one of the setter methods rather than by the
203.1565 + * internal time calculation.
203.1566 + *
203.1567 + * @return <code>true</code> if the field has been set externally,
203.1568 + * <code>false</code> otherwise.
203.1569 + * @exception IndexOutOfBoundsException if the specified
203.1570 + * <code>field</code> is out of range
203.1571 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
203.1572 + * @see #selectFields()
203.1573 + * @see #setFieldsComputed(int)
203.1574 + */
203.1575 + final boolean isExternallySet(int field) {
203.1576 + return stamp[field] >= MINIMUM_USER_STAMP;
203.1577 + }
203.1578 +
203.1579 + /**
203.1580 + * Returns a field mask (bit mask) indicating all calendar fields that
203.1581 + * have the state of externally or internally set.
203.1582 + *
203.1583 + * @return a bit mask indicating set state fields
203.1584 + */
203.1585 + final int getSetStateFields() {
203.1586 + int mask = 0;
203.1587 + for (int i = 0; i < fields.length; i++) {
203.1588 + if (stamp[i] != UNSET) {
203.1589 + mask |= 1 << i;
203.1590 + }
203.1591 + }
203.1592 + return mask;
203.1593 + }
203.1594 +
203.1595 + /**
203.1596 + * Sets the state of the specified calendar fields to
203.1597 + * <em>computed</em>. This state means that the specified calendar fields
203.1598 + * have valid values that have been set by internal time calculation
203.1599 + * rather than by calling one of the setter methods.
203.1600 + *
203.1601 + * @param fieldMask the field to be marked as computed.
203.1602 + * @exception IndexOutOfBoundsException if the specified
203.1603 + * <code>field</code> is out of range
203.1604 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
203.1605 + * @see #isExternallySet(int)
203.1606 + * @see #selectFields()
203.1607 + */
203.1608 + final void setFieldsComputed(int fieldMask) {
203.1609 + if (fieldMask == ALL_FIELDS) {
203.1610 + for (int i = 0; i < fields.length; i++) {
203.1611 + stamp[i] = COMPUTED;
203.1612 + isSet[i] = true;
203.1613 + }
203.1614 + areFieldsSet = areAllFieldsSet = true;
203.1615 + } else {
203.1616 + for (int i = 0; i < fields.length; i++) {
203.1617 + if ((fieldMask & 1) == 1) {
203.1618 + stamp[i] = COMPUTED;
203.1619 + isSet[i] = true;
203.1620 + } else {
203.1621 + if (areAllFieldsSet && !isSet[i]) {
203.1622 + areAllFieldsSet = false;
203.1623 + }
203.1624 + }
203.1625 + fieldMask >>>= 1;
203.1626 + }
203.1627 + }
203.1628 + }
203.1629 +
203.1630 + /**
203.1631 + * Sets the state of the calendar fields that are <em>not</em> specified
203.1632 + * by <code>fieldMask</code> to <em>unset</em>. If <code>fieldMask</code>
203.1633 + * specifies all the calendar fields, then the state of this
203.1634 + * <code>Calendar</code> becomes that all the calendar fields are in sync
203.1635 + * with the time value (millisecond offset from the Epoch).
203.1636 + *
203.1637 + * @param fieldMask the field mask indicating which calendar fields are in
203.1638 + * sync with the time value.
203.1639 + * @exception IndexOutOfBoundsException if the specified
203.1640 + * <code>field</code> is out of range
203.1641 + * (<code>field < 0 || field >= FIELD_COUNT</code>).
203.1642 + * @see #isExternallySet(int)
203.1643 + * @see #selectFields()
203.1644 + */
203.1645 + final void setFieldsNormalized(int fieldMask) {
203.1646 + if (fieldMask != ALL_FIELDS) {
203.1647 + for (int i = 0; i < fields.length; i++) {
203.1648 + if ((fieldMask & 1) == 0) {
203.1649 + stamp[i] = fields[i] = 0; // UNSET == 0
203.1650 + isSet[i] = false;
203.1651 + }
203.1652 + fieldMask >>= 1;
203.1653 + }
203.1654 + }
203.1655 +
203.1656 + // Some or all of the fields are in sync with the
203.1657 + // milliseconds, but the stamp values are not normalized yet.
203.1658 + areFieldsSet = true;
203.1659 + areAllFieldsSet = false;
203.1660 + }
203.1661 +
203.1662 + /**
203.1663 + * Returns whether the calendar fields are partially in sync with the time
203.1664 + * value or fully in sync but not stamp values are not normalized yet.
203.1665 + */
203.1666 + final boolean isPartiallyNormalized() {
203.1667 + return areFieldsSet && !areAllFieldsSet;
203.1668 + }
203.1669 +
203.1670 + /**
203.1671 + * Returns whether the calendar fields are fully in sync with the time
203.1672 + * value.
203.1673 + */
203.1674 + final boolean isFullyNormalized() {
203.1675 + return areFieldsSet && areAllFieldsSet;
203.1676 + }
203.1677 +
203.1678 + /**
203.1679 + * Marks this Calendar as not sync'd.
203.1680 + */
203.1681 + final void setUnnormalized() {
203.1682 + areFieldsSet = areAllFieldsSet = false;
203.1683 + }
203.1684 +
203.1685 + /**
203.1686 + * Returns whether the specified <code>field</code> is on in the
203.1687 + * <code>fieldMask</code>.
203.1688 + */
203.1689 + static final boolean isFieldSet(int fieldMask, int field) {
203.1690 + return (fieldMask & (1 << field)) != 0;
203.1691 + }
203.1692 +
203.1693 + /**
203.1694 + * Returns a field mask indicating which calendar field values
203.1695 + * to be used to calculate the time value. The calendar fields are
203.1696 + * returned as a bit mask, each bit of which corresponds to a field, i.e.,
203.1697 + * the mask value of <code>field</code> is <code>(1 <<
203.1698 + * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
203.1699 + * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
203.1700 + * equal to
203.1701 + * <code>(1<<YEAR)|(1<<MONTH)|(1<<DAY_OF_MONTH))</code>.
203.1702 + *
203.1703 + * <p>This method supports the calendar fields resolution as described in
203.1704 + * the class description. If the bit mask for a given field is on and its
203.1705 + * field has not been set (i.e., <code>isSet(field)</code> is
203.1706 + * <code>false</code>), then the default value of the field has to be
203.1707 + * used, which case means that the field has been selected because the
203.1708 + * selected combination involves the field.
203.1709 + *
203.1710 + * @return a bit mask of selected fields
203.1711 + * @see #isExternallySet(int)
203.1712 + * @see #setInternallySetState(int)
203.1713 + */
203.1714 + final int selectFields() {
203.1715 + // This implementation has been taken from the GregorianCalendar class.
203.1716 +
203.1717 + // The YEAR field must always be used regardless of its SET
203.1718 + // state because YEAR is a mandatory field to determine the date
203.1719 + // and the default value (EPOCH_YEAR) may change through the
203.1720 + // normalization process.
203.1721 + int fieldMask = YEAR_MASK;
203.1722 +
203.1723 + if (stamp[ERA] != UNSET) {
203.1724 + fieldMask |= ERA_MASK;
203.1725 + }
203.1726 + // Find the most recent group of fields specifying the day within
203.1727 + // the year. These may be any of the following combinations:
203.1728 + // MONTH + DAY_OF_MONTH
203.1729 + // MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
203.1730 + // MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
203.1731 + // DAY_OF_YEAR
203.1732 + // WEEK_OF_YEAR + DAY_OF_WEEK
203.1733 + // We look for the most recent of the fields in each group to determine
203.1734 + // the age of the group. For groups involving a week-related field such
203.1735 + // as WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR, both the
203.1736 + // week-related field and the DAY_OF_WEEK must be set for the group as a
203.1737 + // whole to be considered. (See bug 4153860 - liu 7/24/98.)
203.1738 + int dowStamp = stamp[DAY_OF_WEEK];
203.1739 + int monthStamp = stamp[MONTH];
203.1740 + int domStamp = stamp[DAY_OF_MONTH];
203.1741 + int womStamp = aggregateStamp(stamp[WEEK_OF_MONTH], dowStamp);
203.1742 + int dowimStamp = aggregateStamp(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
203.1743 + int doyStamp = stamp[DAY_OF_YEAR];
203.1744 + int woyStamp = aggregateStamp(stamp[WEEK_OF_YEAR], dowStamp);
203.1745 +
203.1746 + int bestStamp = domStamp;
203.1747 + if (womStamp > bestStamp) {
203.1748 + bestStamp = womStamp;
203.1749 + }
203.1750 + if (dowimStamp > bestStamp) {
203.1751 + bestStamp = dowimStamp;
203.1752 + }
203.1753 + if (doyStamp > bestStamp) {
203.1754 + bestStamp = doyStamp;
203.1755 + }
203.1756 + if (woyStamp > bestStamp) {
203.1757 + bestStamp = woyStamp;
203.1758 + }
203.1759 +
203.1760 + /* No complete combination exists. Look for WEEK_OF_MONTH,
203.1761 + * DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR alone. Treat DAY_OF_WEEK alone
203.1762 + * as DAY_OF_WEEK_IN_MONTH.
203.1763 + */
203.1764 + if (bestStamp == UNSET) {
203.1765 + womStamp = stamp[WEEK_OF_MONTH];
203.1766 + dowimStamp = Math.max(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
203.1767 + woyStamp = stamp[WEEK_OF_YEAR];
203.1768 + bestStamp = Math.max(Math.max(womStamp, dowimStamp), woyStamp);
203.1769 +
203.1770 + /* Treat MONTH alone or no fields at all as DAY_OF_MONTH. This may
203.1771 + * result in bestStamp = domStamp = UNSET if no fields are set,
203.1772 + * which indicates DAY_OF_MONTH.
203.1773 + */
203.1774 + if (bestStamp == UNSET) {
203.1775 + bestStamp = domStamp = monthStamp;
203.1776 + }
203.1777 + }
203.1778 +
203.1779 + if (bestStamp == domStamp ||
203.1780 + (bestStamp == womStamp && stamp[WEEK_OF_MONTH] >= stamp[WEEK_OF_YEAR]) ||
203.1781 + (bestStamp == dowimStamp && stamp[DAY_OF_WEEK_IN_MONTH] >= stamp[WEEK_OF_YEAR])) {
203.1782 + fieldMask |= MONTH_MASK;
203.1783 + if (bestStamp == domStamp) {
203.1784 + fieldMask |= DAY_OF_MONTH_MASK;
203.1785 + } else {
203.1786 + assert (bestStamp == womStamp || bestStamp == dowimStamp);
203.1787 + if (dowStamp != UNSET) {
203.1788 + fieldMask |= DAY_OF_WEEK_MASK;
203.1789 + }
203.1790 + if (womStamp == dowimStamp) {
203.1791 + // When they are equal, give the priority to
203.1792 + // WEEK_OF_MONTH for compatibility.
203.1793 + if (stamp[WEEK_OF_MONTH] >= stamp[DAY_OF_WEEK_IN_MONTH]) {
203.1794 + fieldMask |= WEEK_OF_MONTH_MASK;
203.1795 + } else {
203.1796 + fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
203.1797 + }
203.1798 + } else {
203.1799 + if (bestStamp == womStamp) {
203.1800 + fieldMask |= WEEK_OF_MONTH_MASK;
203.1801 + } else {
203.1802 + assert (bestStamp == dowimStamp);
203.1803 + if (stamp[DAY_OF_WEEK_IN_MONTH] != UNSET) {
203.1804 + fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
203.1805 + }
203.1806 + }
203.1807 + }
203.1808 + }
203.1809 + } else {
203.1810 + assert (bestStamp == doyStamp || bestStamp == woyStamp ||
203.1811 + bestStamp == UNSET);
203.1812 + if (bestStamp == doyStamp) {
203.1813 + fieldMask |= DAY_OF_YEAR_MASK;
203.1814 + } else {
203.1815 + assert (bestStamp == woyStamp);
203.1816 + if (dowStamp != UNSET) {
203.1817 + fieldMask |= DAY_OF_WEEK_MASK;
203.1818 + }
203.1819 + fieldMask |= WEEK_OF_YEAR_MASK;
203.1820 + }
203.1821 + }
203.1822 +
203.1823 + // Find the best set of fields specifying the time of day. There
203.1824 + // are only two possibilities here; the HOUR_OF_DAY or the
203.1825 + // AM_PM and the HOUR.
203.1826 + int hourOfDayStamp = stamp[HOUR_OF_DAY];
203.1827 + int hourStamp = aggregateStamp(stamp[HOUR], stamp[AM_PM]);
203.1828 + bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
203.1829 +
203.1830 + // if bestStamp is still UNSET, then take HOUR or AM_PM. (See 4846659)
203.1831 + if (bestStamp == UNSET) {
203.1832 + bestStamp = Math.max(stamp[HOUR], stamp[AM_PM]);
203.1833 + }
203.1834 +
203.1835 + // Hours
203.1836 + if (bestStamp != UNSET) {
203.1837 + if (bestStamp == hourOfDayStamp) {
203.1838 + fieldMask |= HOUR_OF_DAY_MASK;
203.1839 + } else {
203.1840 + fieldMask |= HOUR_MASK;
203.1841 + if (stamp[AM_PM] != UNSET) {
203.1842 + fieldMask |= AM_PM_MASK;
203.1843 + }
203.1844 + }
203.1845 + }
203.1846 + if (stamp[MINUTE] != UNSET) {
203.1847 + fieldMask |= MINUTE_MASK;
203.1848 + }
203.1849 + if (stamp[SECOND] != UNSET) {
203.1850 + fieldMask |= SECOND_MASK;
203.1851 + }
203.1852 + if (stamp[MILLISECOND] != UNSET) {
203.1853 + fieldMask |= MILLISECOND_MASK;
203.1854 + }
203.1855 + if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
203.1856 + fieldMask |= ZONE_OFFSET_MASK;
203.1857 + }
203.1858 + if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
203.1859 + fieldMask |= DST_OFFSET_MASK;
203.1860 + }
203.1861 +
203.1862 + return fieldMask;
203.1863 + }
203.1864 +
203.1865 + /**
203.1866 + * Returns the pseudo-time-stamp for two fields, given their
203.1867 + * individual pseudo-time-stamps. If either of the fields
203.1868 + * is unset, then the aggregate is unset. Otherwise, the
203.1869 + * aggregate is the later of the two stamps.
203.1870 + */
203.1871 + private static final int aggregateStamp(int stamp_a, int stamp_b) {
203.1872 + if (stamp_a == UNSET || stamp_b == UNSET) {
203.1873 + return UNSET;
203.1874 + }
203.1875 + return (stamp_a > stamp_b) ? stamp_a : stamp_b;
203.1876 + }
203.1877 +
203.1878 + /**
203.1879 + * Compares this <code>Calendar</code> to the specified
203.1880 + * <code>Object</code>. The result is <code>true</code> if and only if
203.1881 + * the argument is a <code>Calendar</code> object of the same calendar
203.1882 + * system that represents the same time value (millisecond offset from the
203.1883 + * <a href="#Epoch">Epoch</a>) under the same
203.1884 + * <code>Calendar</code> parameters as this object.
203.1885 + *
203.1886 + * <p>The <code>Calendar</code> parameters are the values represented
203.1887 + * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
203.1888 + * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
203.1889 + * methods. If there is any difference in those parameters
203.1890 + * between the two <code>Calendar</code>s, this method returns
203.1891 + * <code>false</code>.
203.1892 + *
203.1893 + * <p>Use the {@link #compareTo(Calendar) compareTo} method to
203.1894 + * compare only the time values.
203.1895 + *
203.1896 + * @param obj the object to compare with.
203.1897 + * @return <code>true</code> if this object is equal to <code>obj</code>;
203.1898 + * <code>false</code> otherwise.
203.1899 + */
203.1900 + public boolean equals(Object obj) {
203.1901 + if (this == obj)
203.1902 + return true;
203.1903 + try {
203.1904 + Calendar that = (Calendar)obj;
203.1905 + return compareTo(getMillisOf(that)) == 0 &&
203.1906 + lenient == that.lenient &&
203.1907 + firstDayOfWeek == that.firstDayOfWeek &&
203.1908 + minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
203.1909 + zone.equals(that.zone);
203.1910 + } catch (Exception e) {
203.1911 + // Note: GregorianCalendar.computeTime throws
203.1912 + // IllegalArgumentException if the ERA value is invalid
203.1913 + // even it's in lenient mode.
203.1914 + }
203.1915 + return false;
203.1916 + }
203.1917 +
203.1918 + /**
203.1919 + * Returns a hash code for this calendar.
203.1920 + *
203.1921 + * @return a hash code value for this object.
203.1922 + * @since 1.2
203.1923 + */
203.1924 + public int hashCode() {
203.1925 + // 'otheritems' represents the hash code for the previous versions.
203.1926 + int otheritems = (lenient ? 1 : 0)
203.1927 + | (firstDayOfWeek << 1)
203.1928 + | (minimalDaysInFirstWeek << 4)
203.1929 + | (zone.hashCode() << 7);
203.1930 + long t = getMillisOf(this);
203.1931 + return (int) t ^ (int)(t >> 32) ^ otheritems;
203.1932 + }
203.1933 +
203.1934 + /**
203.1935 + * Returns whether this <code>Calendar</code> represents a time
203.1936 + * before the time represented by the specified
203.1937 + * <code>Object</code>. This method is equivalent to:
203.1938 + * <pre><blockquote>
203.1939 + * compareTo(when) < 0
203.1940 + * </blockquote></pre>
203.1941 + * if and only if <code>when</code> is a <code>Calendar</code>
203.1942 + * instance. Otherwise, the method returns <code>false</code>.
203.1943 + *
203.1944 + * @param when the <code>Object</code> to be compared
203.1945 + * @return <code>true</code> if the time of this
203.1946 + * <code>Calendar</code> is before the time represented by
203.1947 + * <code>when</code>; <code>false</code> otherwise.
203.1948 + * @see #compareTo(Calendar)
203.1949 + */
203.1950 + public boolean before(Object when) {
203.1951 + return when instanceof Calendar
203.1952 + && compareTo((Calendar)when) < 0;
203.1953 + }
203.1954 +
203.1955 + /**
203.1956 + * Returns whether this <code>Calendar</code> represents a time
203.1957 + * after the time represented by the specified
203.1958 + * <code>Object</code>. This method is equivalent to:
203.1959 + * <pre><blockquote>
203.1960 + * compareTo(when) > 0
203.1961 + * </blockquote></pre>
203.1962 + * if and only if <code>when</code> is a <code>Calendar</code>
203.1963 + * instance. Otherwise, the method returns <code>false</code>.
203.1964 + *
203.1965 + * @param when the <code>Object</code> to be compared
203.1966 + * @return <code>true</code> if the time of this <code>Calendar</code> is
203.1967 + * after the time represented by <code>when</code>; <code>false</code>
203.1968 + * otherwise.
203.1969 + * @see #compareTo(Calendar)
203.1970 + */
203.1971 + public boolean after(Object when) {
203.1972 + return when instanceof Calendar
203.1973 + && compareTo((Calendar)when) > 0;
203.1974 + }
203.1975 +
203.1976 + /**
203.1977 + * Compares the time values (millisecond offsets from the <a
203.1978 + * href="#Epoch">Epoch</a>) represented by two
203.1979 + * <code>Calendar</code> objects.
203.1980 + *
203.1981 + * @param anotherCalendar the <code>Calendar</code> to be compared.
203.1982 + * @return the value <code>0</code> if the time represented by the argument
203.1983 + * is equal to the time represented by this <code>Calendar</code>; a value
203.1984 + * less than <code>0</code> if the time of this <code>Calendar</code> is
203.1985 + * before the time represented by the argument; and a value greater than
203.1986 + * <code>0</code> if the time of this <code>Calendar</code> is after the
203.1987 + * time represented by the argument.
203.1988 + * @exception NullPointerException if the specified <code>Calendar</code> is
203.1989 + * <code>null</code>.
203.1990 + * @exception IllegalArgumentException if the time value of the
203.1991 + * specified <code>Calendar</code> object can't be obtained due to
203.1992 + * any invalid calendar values.
203.1993 + * @since 1.5
203.1994 + */
203.1995 + public int compareTo(Calendar anotherCalendar) {
203.1996 + return compareTo(getMillisOf(anotherCalendar));
203.1997 + }
203.1998 +
203.1999 + /**
203.2000 + * Adds or subtracts the specified amount of time to the given calendar field,
203.2001 + * based on the calendar's rules. For example, to subtract 5 days from
203.2002 + * the current time of the calendar, you can achieve it by calling:
203.2003 + * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
203.2004 + *
203.2005 + * @param field the calendar field.
203.2006 + * @param amount the amount of date or time to be added to the field.
203.2007 + * @see #roll(int,int)
203.2008 + * @see #set(int,int)
203.2009 + */
203.2010 + abstract public void add(int field, int amount);
203.2011 +
203.2012 + /**
203.2013 + * Adds or subtracts (up/down) a single unit of time on the given time
203.2014 + * field without changing larger fields. For example, to roll the current
203.2015 + * date up by one day, you can achieve it by calling:
203.2016 + * <p>roll(Calendar.DATE, true).
203.2017 + * When rolling on the year or Calendar.YEAR field, it will roll the year
203.2018 + * value in the range between 1 and the value returned by calling
203.2019 + * <code>getMaximum(Calendar.YEAR)</code>.
203.2020 + * When rolling on the month or Calendar.MONTH field, other fields like
203.2021 + * date might conflict and, need to be changed. For instance,
203.2022 + * rolling the month on the date 01/31/96 will result in 02/29/96.
203.2023 + * When rolling on the hour-in-day or Calendar.HOUR_OF_DAY field, it will
203.2024 + * roll the hour value in the range between 0 and 23, which is zero-based.
203.2025 + *
203.2026 + * @param field the time field.
203.2027 + * @param up indicates if the value of the specified time field is to be
203.2028 + * rolled up or rolled down. Use true if rolling up, false otherwise.
203.2029 + * @see Calendar#add(int,int)
203.2030 + * @see Calendar#set(int,int)
203.2031 + */
203.2032 + abstract public void roll(int field, boolean up);
203.2033 +
203.2034 + /**
203.2035 + * Adds the specified (signed) amount to the specified calendar field
203.2036 + * without changing larger fields. A negative amount means to roll
203.2037 + * down.
203.2038 + *
203.2039 + * <p>NOTE: This default implementation on <code>Calendar</code> just repeatedly calls the
203.2040 + * version of {@link #roll(int,boolean) roll()} that rolls by one unit. This may not
203.2041 + * always do the right thing. For example, if the <code>DAY_OF_MONTH</code> field is 31,
203.2042 + * rolling through February will leave it set to 28. The <code>GregorianCalendar</code>
203.2043 + * version of this function takes care of this problem. Other subclasses
203.2044 + * should also provide overrides of this function that do the right thing.
203.2045 + *
203.2046 + * @param field the calendar field.
203.2047 + * @param amount the signed amount to add to the calendar <code>field</code>.
203.2048 + * @since 1.2
203.2049 + * @see #roll(int,boolean)
203.2050 + * @see #add(int,int)
203.2051 + * @see #set(int,int)
203.2052 + */
203.2053 + public void roll(int field, int amount)
203.2054 + {
203.2055 + while (amount > 0) {
203.2056 + roll(field, true);
203.2057 + amount--;
203.2058 + }
203.2059 + while (amount < 0) {
203.2060 + roll(field, false);
203.2061 + amount++;
203.2062 + }
203.2063 + }
203.2064 +
203.2065 + /**
203.2066 + * Sets the time zone with the given time zone value.
203.2067 + *
203.2068 + * @param value the given time zone.
203.2069 + */
203.2070 + public void setTimeZone(TimeZone value)
203.2071 + {
203.2072 + zone = value;
203.2073 + sharedZone = false;
203.2074 + /* Recompute the fields from the time using the new zone. This also
203.2075 + * works if isTimeSet is false (after a call to set()). In that case
203.2076 + * the time will be computed from the fields using the new zone, then
203.2077 + * the fields will get recomputed from that. Consider the sequence of
203.2078 + * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
203.2079 + * Is cal set to 1 o'clock EST or 1 o'clock PST? Answer: PST. More
203.2080 + * generally, a call to setTimeZone() affects calls to set() BEFORE AND
203.2081 + * AFTER it up to the next call to complete().
203.2082 + */
203.2083 + areAllFieldsSet = areFieldsSet = false;
203.2084 + }
203.2085 +
203.2086 + /**
203.2087 + * Gets the time zone.
203.2088 + *
203.2089 + * @return the time zone object associated with this calendar.
203.2090 + */
203.2091 + public TimeZone getTimeZone()
203.2092 + {
203.2093 + // If the TimeZone object is shared by other Calendar instances, then
203.2094 + // create a clone.
203.2095 + if (sharedZone) {
203.2096 + zone = (TimeZone) zone.clone();
203.2097 + sharedZone = false;
203.2098 + }
203.2099 + return zone;
203.2100 + }
203.2101 +
203.2102 + /**
203.2103 + * Returns the time zone (without cloning).
203.2104 + */
203.2105 + TimeZone getZone() {
203.2106 + return zone;
203.2107 + }
203.2108 +
203.2109 + /**
203.2110 + * Sets the sharedZone flag to <code>shared</code>.
203.2111 + */
203.2112 + void setZoneShared(boolean shared) {
203.2113 + sharedZone = shared;
203.2114 + }
203.2115 +
203.2116 + /**
203.2117 + * Specifies whether or not date/time interpretation is to be lenient. With
203.2118 + * lenient interpretation, a date such as "February 942, 1996" will be
203.2119 + * treated as being equivalent to the 941st day after February 1, 1996.
203.2120 + * With strict (non-lenient) interpretation, such dates will cause an exception to be
203.2121 + * thrown. The default is lenient.
203.2122 + *
203.2123 + * @param lenient <code>true</code> if the lenient mode is to be turned
203.2124 + * on; <code>false</code> if it is to be turned off.
203.2125 + * @see #isLenient()
203.2126 + * @see java.text.DateFormat#setLenient
203.2127 + */
203.2128 + public void setLenient(boolean lenient)
203.2129 + {
203.2130 + this.lenient = lenient;
203.2131 + }
203.2132 +
203.2133 + /**
203.2134 + * Tells whether date/time interpretation is to be lenient.
203.2135 + *
203.2136 + * @return <code>true</code> if the interpretation mode of this calendar is lenient;
203.2137 + * <code>false</code> otherwise.
203.2138 + * @see #setLenient(boolean)
203.2139 + */
203.2140 + public boolean isLenient()
203.2141 + {
203.2142 + return lenient;
203.2143 + }
203.2144 +
203.2145 + /**
203.2146 + * Sets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
203.2147 + * <code>MONDAY</code> in France.
203.2148 + *
203.2149 + * @param value the given first day of the week.
203.2150 + * @see #getFirstDayOfWeek()
203.2151 + * @see #getMinimalDaysInFirstWeek()
203.2152 + */
203.2153 + public void setFirstDayOfWeek(int value)
203.2154 + {
203.2155 + if (firstDayOfWeek == value) {
203.2156 + return;
203.2157 + }
203.2158 + firstDayOfWeek = value;
203.2159 + invalidateWeekFields();
203.2160 + }
203.2161 +
203.2162 + /**
203.2163 + * Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
203.2164 + * <code>MONDAY</code> in France.
203.2165 + *
203.2166 + * @return the first day of the week.
203.2167 + * @see #setFirstDayOfWeek(int)
203.2168 + * @see #getMinimalDaysInFirstWeek()
203.2169 + */
203.2170 + public int getFirstDayOfWeek()
203.2171 + {
203.2172 + return firstDayOfWeek;
203.2173 + }
203.2174 +
203.2175 + /**
203.2176 + * Sets what the minimal days required in the first week of the year are;
203.2177 + * For example, if the first week is defined as one that contains the first
203.2178 + * day of the first month of a year, call this method with value 1. If it
203.2179 + * must be a full week, use value 7.
203.2180 + *
203.2181 + * @param value the given minimal days required in the first week
203.2182 + * of the year.
203.2183 + * @see #getMinimalDaysInFirstWeek()
203.2184 + */
203.2185 + public void setMinimalDaysInFirstWeek(int value)
203.2186 + {
203.2187 + if (minimalDaysInFirstWeek == value) {
203.2188 + return;
203.2189 + }
203.2190 + minimalDaysInFirstWeek = value;
203.2191 + invalidateWeekFields();
203.2192 + }
203.2193 +
203.2194 + /**
203.2195 + * Gets what the minimal days required in the first week of the year are;
203.2196 + * e.g., if the first week is defined as one that contains the first day
203.2197 + * of the first month of a year, this method returns 1. If
203.2198 + * the minimal days required must be a full week, this method
203.2199 + * returns 7.
203.2200 + *
203.2201 + * @return the minimal days required in the first week of the year.
203.2202 + * @see #setMinimalDaysInFirstWeek(int)
203.2203 + */
203.2204 + public int getMinimalDaysInFirstWeek()
203.2205 + {
203.2206 + return minimalDaysInFirstWeek;
203.2207 + }
203.2208 +
203.2209 + /**
203.2210 + * Returns whether this {@code Calendar} supports week dates.
203.2211 + *
203.2212 + * <p>The default implementation of this method returns {@code false}.
203.2213 + *
203.2214 + * @return {@code true} if this {@code Calendar} supports week dates;
203.2215 + * {@code false} otherwise.
203.2216 + * @see #getWeekYear()
203.2217 + * @see #setWeekDate(int,int,int)
203.2218 + * @see #getWeeksInWeekYear()
203.2219 + * @since 1.7
203.2220 + */
203.2221 + public boolean isWeekDateSupported() {
203.2222 + return false;
203.2223 + }
203.2224 +
203.2225 + /**
203.2226 + * Returns the week year represented by this {@code Calendar}. The
203.2227 + * week year is in sync with the week cycle. The {@linkplain
203.2228 + * #getFirstDayOfWeek() first day of the first week} is the first
203.2229 + * day of the week year.
203.2230 + *
203.2231 + * <p>The default implementation of this method throws an
203.2232 + * {@link UnsupportedOperationException}.
203.2233 + *
203.2234 + * @return the week year of this {@code Calendar}
203.2235 + * @exception UnsupportedOperationException
203.2236 + * if any week year numbering isn't supported
203.2237 + * in this {@code Calendar}.
203.2238 + * @see #isWeekDateSupported()
203.2239 + * @see #getFirstDayOfWeek()
203.2240 + * @see #getMinimalDaysInFirstWeek()
203.2241 + * @since 1.7
203.2242 + */
203.2243 + public int getWeekYear() {
203.2244 + throw new UnsupportedOperationException();
203.2245 + }
203.2246 +
203.2247 + /**
203.2248 + * Sets the date of this {@code Calendar} with the the given date
203.2249 + * specifiers - week year, week of year, and day of week.
203.2250 + *
203.2251 + * <p>Unlike the {@code set} method, all of the calendar fields
203.2252 + * and {@code time} values are calculated upon return.
203.2253 + *
203.2254 + * <p>If {@code weekOfYear} is out of the valid week-of-year range
203.2255 + * in {@code weekYear}, the {@code weekYear} and {@code
203.2256 + * weekOfYear} values are adjusted in lenient mode, or an {@code
203.2257 + * IllegalArgumentException} is thrown in non-lenient mode.
203.2258 + *
203.2259 + * <p>The default implementation of this method throws an
203.2260 + * {@code UnsupportedOperationException}.
203.2261 + *
203.2262 + * @param weekYear the week year
203.2263 + * @param weekOfYear the week number based on {@code weekYear}
203.2264 + * @param dayOfWeek the day of week value: one of the constants
203.2265 + * for the {@link #DAY_OF_WEEK} field: {@link
203.2266 + * #SUNDAY}, ..., {@link #SATURDAY}.
203.2267 + * @exception IllegalArgumentException
203.2268 + * if any of the given date specifiers is invalid
203.2269 + * or any of the calendar fields are inconsistent
203.2270 + * with the given date specifiers in non-lenient mode
203.2271 + * @exception UnsupportedOperationException
203.2272 + * if any week year numbering isn't supported in this
203.2273 + * {@code Calendar}.
203.2274 + * @see #isWeekDateSupported()
203.2275 + * @see #getFirstDayOfWeek()
203.2276 + * @see #getMinimalDaysInFirstWeek()
203.2277 + * @since 1.7
203.2278 + */
203.2279 + public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
203.2280 + throw new UnsupportedOperationException();
203.2281 + }
203.2282 +
203.2283 + /**
203.2284 + * Returns the number of weeks in the week year represented by this
203.2285 + * {@code Calendar}.
203.2286 + *
203.2287 + * <p>The default implementation of this method throws an
203.2288 + * {@code UnsupportedOperationException}.
203.2289 + *
203.2290 + * @return the number of weeks in the week year.
203.2291 + * @exception UnsupportedOperationException
203.2292 + * if any week year numbering isn't supported in this
203.2293 + * {@code Calendar}.
203.2294 + * @see #WEEK_OF_YEAR
203.2295 + * @see #isWeekDateSupported()
203.2296 + * @see #getWeekYear()
203.2297 + * @see #getActualMaximum(int)
203.2298 + * @since 1.7
203.2299 + */
203.2300 + public int getWeeksInWeekYear() {
203.2301 + throw new UnsupportedOperationException();
203.2302 + }
203.2303 +
203.2304 + /**
203.2305 + * Returns the minimum value for the given calendar field of this
203.2306 + * <code>Calendar</code> instance. The minimum value is defined as
203.2307 + * the smallest value returned by the {@link #get(int) get} method
203.2308 + * for any possible time value. The minimum value depends on
203.2309 + * calendar system specific parameters of the instance.
203.2310 + *
203.2311 + * @param field the calendar field.
203.2312 + * @return the minimum value for the given calendar field.
203.2313 + * @see #getMaximum(int)
203.2314 + * @see #getGreatestMinimum(int)
203.2315 + * @see #getLeastMaximum(int)
203.2316 + * @see #getActualMinimum(int)
203.2317 + * @see #getActualMaximum(int)
203.2318 + */
203.2319 + abstract public int getMinimum(int field);
203.2320 +
203.2321 + /**
203.2322 + * Returns the maximum value for the given calendar field of this
203.2323 + * <code>Calendar</code> instance. The maximum value is defined as
203.2324 + * the largest value returned by the {@link #get(int) get} method
203.2325 + * for any possible time value. The maximum value depends on
203.2326 + * calendar system specific parameters of the instance.
203.2327 + *
203.2328 + * @param field the calendar field.
203.2329 + * @return the maximum value for the given calendar field.
203.2330 + * @see #getMinimum(int)
203.2331 + * @see #getGreatestMinimum(int)
203.2332 + * @see #getLeastMaximum(int)
203.2333 + * @see #getActualMinimum(int)
203.2334 + * @see #getActualMaximum(int)
203.2335 + */
203.2336 + abstract public int getMaximum(int field);
203.2337 +
203.2338 + /**
203.2339 + * Returns the highest minimum value for the given calendar field
203.2340 + * of this <code>Calendar</code> instance. The highest minimum
203.2341 + * value is defined as the largest value returned by {@link
203.2342 + * #getActualMinimum(int)} for any possible time value. The
203.2343 + * greatest minimum value depends on calendar system specific
203.2344 + * parameters of the instance.
203.2345 + *
203.2346 + * @param field the calendar field.
203.2347 + * @return the highest minimum value for the given calendar field.
203.2348 + * @see #getMinimum(int)
203.2349 + * @see #getMaximum(int)
203.2350 + * @see #getLeastMaximum(int)
203.2351 + * @see #getActualMinimum(int)
203.2352 + * @see #getActualMaximum(int)
203.2353 + */
203.2354 + abstract public int getGreatestMinimum(int field);
203.2355 +
203.2356 + /**
203.2357 + * Returns the lowest maximum value for the given calendar field
203.2358 + * of this <code>Calendar</code> instance. The lowest maximum
203.2359 + * value is defined as the smallest value returned by {@link
203.2360 + * #getActualMaximum(int)} for any possible time value. The least
203.2361 + * maximum value depends on calendar system specific parameters of
203.2362 + * the instance. For example, a <code>Calendar</code> for the
203.2363 + * Gregorian calendar system returns 28 for the
203.2364 + * <code>DAY_OF_MONTH</code> field, because the 28th is the last
203.2365 + * day of the shortest month of this calendar, February in a
203.2366 + * common year.
203.2367 + *
203.2368 + * @param field the calendar field.
203.2369 + * @return the lowest maximum value for the given calendar field.
203.2370 + * @see #getMinimum(int)
203.2371 + * @see #getMaximum(int)
203.2372 + * @see #getGreatestMinimum(int)
203.2373 + * @see #getActualMinimum(int)
203.2374 + * @see #getActualMaximum(int)
203.2375 + */
203.2376 + abstract public int getLeastMaximum(int field);
203.2377 +
203.2378 + /**
203.2379 + * Returns the minimum value that the specified calendar field
203.2380 + * could have, given the time value of this <code>Calendar</code>.
203.2381 + *
203.2382 + * <p>The default implementation of this method uses an iterative
203.2383 + * algorithm to determine the actual minimum value for the
203.2384 + * calendar field. Subclasses should, if possible, override this
203.2385 + * with a more efficient implementation - in many cases, they can
203.2386 + * simply return <code>getMinimum()</code>.
203.2387 + *
203.2388 + * @param field the calendar field
203.2389 + * @return the minimum of the given calendar field for the time
203.2390 + * value of this <code>Calendar</code>
203.2391 + * @see #getMinimum(int)
203.2392 + * @see #getMaximum(int)
203.2393 + * @see #getGreatestMinimum(int)
203.2394 + * @see #getLeastMaximum(int)
203.2395 + * @see #getActualMaximum(int)
203.2396 + * @since 1.2
203.2397 + */
203.2398 + public int getActualMinimum(int field) {
203.2399 + int fieldValue = getGreatestMinimum(field);
203.2400 + int endValue = getMinimum(field);
203.2401 +
203.2402 + // if we know that the minimum value is always the same, just return it
203.2403 + if (fieldValue == endValue) {
203.2404 + return fieldValue;
203.2405 + }
203.2406 +
203.2407 + // clone the calendar so we don't mess with the real one, and set it to
203.2408 + // accept anything for the field values
203.2409 + Calendar work = (Calendar)this.clone();
203.2410 + work.setLenient(true);
203.2411 +
203.2412 + // now try each value from getLeastMaximum() to getMaximum() one by one until
203.2413 + // we get a value that normalizes to another value. The last value that
203.2414 + // normalizes to itself is the actual minimum for the current date
203.2415 + int result = fieldValue;
203.2416 +
203.2417 + do {
203.2418 + work.set(field, fieldValue);
203.2419 + if (work.get(field) != fieldValue) {
203.2420 + break;
203.2421 + } else {
203.2422 + result = fieldValue;
203.2423 + fieldValue--;
203.2424 + }
203.2425 + } while (fieldValue >= endValue);
203.2426 +
203.2427 + return result;
203.2428 + }
203.2429 +
203.2430 + /**
203.2431 + * Returns the maximum value that the specified calendar field
203.2432 + * could have, given the time value of this
203.2433 + * <code>Calendar</code>. For example, the actual maximum value of
203.2434 + * the <code>MONTH</code> field is 12 in some years, and 13 in
203.2435 + * other years in the Hebrew calendar system.
203.2436 + *
203.2437 + * <p>The default implementation of this method uses an iterative
203.2438 + * algorithm to determine the actual maximum value for the
203.2439 + * calendar field. Subclasses should, if possible, override this
203.2440 + * with a more efficient implementation.
203.2441 + *
203.2442 + * @param field the calendar field
203.2443 + * @return the maximum of the given calendar field for the time
203.2444 + * value of this <code>Calendar</code>
203.2445 + * @see #getMinimum(int)
203.2446 + * @see #getMaximum(int)
203.2447 + * @see #getGreatestMinimum(int)
203.2448 + * @see #getLeastMaximum(int)
203.2449 + * @see #getActualMinimum(int)
203.2450 + * @since 1.2
203.2451 + */
203.2452 + public int getActualMaximum(int field) {
203.2453 + int fieldValue = getLeastMaximum(field);
203.2454 + int endValue = getMaximum(field);
203.2455 +
203.2456 + // if we know that the maximum value is always the same, just return it.
203.2457 + if (fieldValue == endValue) {
203.2458 + return fieldValue;
203.2459 + }
203.2460 +
203.2461 + // clone the calendar so we don't mess with the real one, and set it to
203.2462 + // accept anything for the field values.
203.2463 + Calendar work = (Calendar)this.clone();
203.2464 + work.setLenient(true);
203.2465 +
203.2466 + // if we're counting weeks, set the day of the week to Sunday. We know the
203.2467 + // last week of a month or year will contain the first day of the week.
203.2468 + if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH)
203.2469 + work.set(DAY_OF_WEEK, firstDayOfWeek);
203.2470 +
203.2471 + // now try each value from getLeastMaximum() to getMaximum() one by one until
203.2472 + // we get a value that normalizes to another value. The last value that
203.2473 + // normalizes to itself is the actual maximum for the current date
203.2474 + int result = fieldValue;
203.2475 +
203.2476 + do {
203.2477 + work.set(field, fieldValue);
203.2478 + if (work.get(field) != fieldValue) {
203.2479 + break;
203.2480 + } else {
203.2481 + result = fieldValue;
203.2482 + fieldValue++;
203.2483 + }
203.2484 + } while (fieldValue <= endValue);
203.2485 +
203.2486 + return result;
203.2487 + }
203.2488 +
203.2489 + /**
203.2490 + * Creates and returns a copy of this object.
203.2491 + *
203.2492 + * @return a copy of this object.
203.2493 + */
203.2494 + public Object clone()
203.2495 + {
203.2496 + try {
203.2497 + Calendar other = (Calendar) super.clone();
203.2498 +
203.2499 + other.fields = new int[FIELD_COUNT];
203.2500 + other.isSet = new boolean[FIELD_COUNT];
203.2501 + other.stamp = new int[FIELD_COUNT];
203.2502 + for (int i = 0; i < FIELD_COUNT; i++) {
203.2503 + other.fields[i] = fields[i];
203.2504 + other.stamp[i] = stamp[i];
203.2505 + other.isSet[i] = isSet[i];
203.2506 + }
203.2507 + other.zone = (TimeZone) zone.clone();
203.2508 + return other;
203.2509 + }
203.2510 + catch (CloneNotSupportedException e) {
203.2511 + // this shouldn't happen, since we are Cloneable
203.2512 + throw new InternalError();
203.2513 + }
203.2514 + }
203.2515 +
203.2516 + private static final String[] FIELD_NAME = {
203.2517 + "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
203.2518 + "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
203.2519 + "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
203.2520 + "DST_OFFSET"
203.2521 + };
203.2522 +
203.2523 + /**
203.2524 + * Returns the name of the specified calendar field.
203.2525 + *
203.2526 + * @param field the calendar field
203.2527 + * @return the calendar field name
203.2528 + * @exception IndexOutOfBoundsException if <code>field</code> is negative,
203.2529 + * equal to or greater then <code>FIELD_COUNT</code>.
203.2530 + */
203.2531 + static final String getFieldName(int field) {
203.2532 + return FIELD_NAME[field];
203.2533 + }
203.2534 +
203.2535 + /**
203.2536 + * Return a string representation of this calendar. This method
203.2537 + * is intended to be used only for debugging purposes, and the
203.2538 + * format of the returned string may vary between implementations.
203.2539 + * The returned string may be empty but may not be <code>null</code>.
203.2540 + *
203.2541 + * @return a string representation of this calendar.
203.2542 + */
203.2543 + public String toString() {
203.2544 + // NOTE: BuddhistCalendar.toString() interprets the string
203.2545 + // produced by this method so that the Gregorian year number
203.2546 + // is substituted by its B.E. year value. It relies on
203.2547 + // "...,YEAR=<year>,..." or "...,YEAR=?,...".
203.2548 + StringBuilder buffer = new StringBuilder(800);
203.2549 + buffer.append(getClass().getName()).append('[');
203.2550 + appendValue(buffer, "time", isTimeSet, time);
203.2551 + buffer.append(",areFieldsSet=").append(areFieldsSet);
203.2552 + buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
203.2553 + buffer.append(",lenient=").append(lenient);
203.2554 + buffer.append(",zone=").append(zone);
203.2555 + appendValue(buffer, ",firstDayOfWeek", true, (long) firstDayOfWeek);
203.2556 + appendValue(buffer, ",minimalDaysInFirstWeek", true, (long) minimalDaysInFirstWeek);
203.2557 + for (int i = 0; i < FIELD_COUNT; ++i) {
203.2558 + buffer.append(',');
203.2559 + appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
203.2560 + }
203.2561 + buffer.append(']');
203.2562 + return buffer.toString();
203.2563 + }
203.2564 +
203.2565 + // =======================privates===============================
203.2566 +
203.2567 + private static final void appendValue(StringBuilder sb, String item, boolean valid, long value) {
203.2568 + sb.append(item).append('=');
203.2569 + if (valid) {
203.2570 + sb.append(value);
203.2571 + } else {
203.2572 + sb.append('?');
203.2573 + }
203.2574 + }
203.2575 +
203.2576 + /**
203.2577 + * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
203.2578 + * They are used to figure out the week count for a specific date for
203.2579 + * a given locale. These must be set when a Calendar is constructed.
203.2580 + * @param desiredLocale the given locale.
203.2581 + */
203.2582 + private void setWeekCountData(Locale desiredLocale)
203.2583 + {
203.2584 + /* try to get the Locale data from the cache */
203.2585 + int[] data = cachedLocaleData.get(desiredLocale);
203.2586 + if (data == null) { /* cache miss */
203.2587 +// ResourceBundle bundle = LocaleData.getCalendarData(desiredLocale);
203.2588 + data = new int[2];
203.2589 +// data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek"));
203.2590 +// data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek"));
203.2591 + cachedLocaleData.putIfAbsent(desiredLocale, data);
203.2592 + }
203.2593 + firstDayOfWeek = data[0];
203.2594 + minimalDaysInFirstWeek = data[1];
203.2595 + }
203.2596 +
203.2597 + /**
203.2598 + * Recomputes the time and updates the status fields isTimeSet
203.2599 + * and areFieldsSet. Callers should check isTimeSet and only
203.2600 + * call this method if isTimeSet is false.
203.2601 + */
203.2602 + private void updateTime() {
203.2603 + computeTime();
203.2604 + // The areFieldsSet and areAllFieldsSet values are no longer
203.2605 + // controlled here (as of 1.5).
203.2606 + isTimeSet = true;
203.2607 + }
203.2608 +
203.2609 + private int compareTo(long t) {
203.2610 + long thisTime = getMillisOf(this);
203.2611 + return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
203.2612 + }
203.2613 +
203.2614 + private static final long getMillisOf(Calendar calendar) {
203.2615 + if (calendar.isTimeSet) {
203.2616 + return calendar.time;
203.2617 + }
203.2618 + Calendar cal = (Calendar) calendar.clone();
203.2619 + cal.setLenient(true);
203.2620 + return cal.getTimeInMillis();
203.2621 + }
203.2622 +
203.2623 + /**
203.2624 + * Adjusts the stamp[] values before nextStamp overflow. nextStamp
203.2625 + * is set to the next stamp value upon the return.
203.2626 + */
203.2627 + private final void adjustStamp() {
203.2628 + int max = MINIMUM_USER_STAMP;
203.2629 + int newStamp = MINIMUM_USER_STAMP;
203.2630 +
203.2631 + for (;;) {
203.2632 + int min = Integer.MAX_VALUE;
203.2633 + for (int i = 0; i < stamp.length; i++) {
203.2634 + int v = stamp[i];
203.2635 + if (v >= newStamp && min > v) {
203.2636 + min = v;
203.2637 + }
203.2638 + if (max < v) {
203.2639 + max = v;
203.2640 + }
203.2641 + }
203.2642 + if (max != min && min == Integer.MAX_VALUE) {
203.2643 + break;
203.2644 + }
203.2645 + for (int i = 0; i < stamp.length; i++) {
203.2646 + if (stamp[i] == min) {
203.2647 + stamp[i] = newStamp;
203.2648 + }
203.2649 + }
203.2650 + newStamp++;
203.2651 + if (min == max) {
203.2652 + break;
203.2653 + }
203.2654 + }
203.2655 + nextStamp = newStamp;
203.2656 + }
203.2657 +
203.2658 + /**
203.2659 + * Sets the WEEK_OF_MONTH and WEEK_OF_YEAR fields to new values with the
203.2660 + * new parameter value if they have been calculated internally.
203.2661 + */
203.2662 + private void invalidateWeekFields()
203.2663 + {
203.2664 + if (stamp[WEEK_OF_MONTH] != COMPUTED &&
203.2665 + stamp[WEEK_OF_YEAR] != COMPUTED) {
203.2666 + return;
203.2667 + }
203.2668 +
203.2669 + // We have to check the new values of these fields after changing
203.2670 + // firstDayOfWeek and/or minimalDaysInFirstWeek. If the field values
203.2671 + // have been changed, then set the new values. (4822110)
203.2672 + Calendar cal = (Calendar) clone();
203.2673 + cal.setLenient(true);
203.2674 + cal.clear(WEEK_OF_MONTH);
203.2675 + cal.clear(WEEK_OF_YEAR);
203.2676 +
203.2677 + if (stamp[WEEK_OF_MONTH] == COMPUTED) {
203.2678 + int weekOfMonth = cal.get(WEEK_OF_MONTH);
203.2679 + if (fields[WEEK_OF_MONTH] != weekOfMonth) {
203.2680 + fields[WEEK_OF_MONTH] = weekOfMonth;
203.2681 + }
203.2682 + }
203.2683 +
203.2684 + if (stamp[WEEK_OF_YEAR] == COMPUTED) {
203.2685 + int weekOfYear = cal.get(WEEK_OF_YEAR);
203.2686 + if (fields[WEEK_OF_YEAR] != weekOfYear) {
203.2687 + fields[WEEK_OF_YEAR] = weekOfYear;
203.2688 + }
203.2689 + }
203.2690 + }
203.2691 +
203.2692 + /**
203.2693 + * Save the state of this object to a stream (i.e., serialize it).
203.2694 + *
203.2695 + * Ideally, <code>Calendar</code> would only write out its state data and
203.2696 + * the current time, and not write any field data out, such as
203.2697 + * <code>fields[]</code>, <code>isTimeSet</code>, <code>areFieldsSet</code>,
203.2698 + * and <code>isSet[]</code>. <code>nextStamp</code> also should not be part
203.2699 + * of the persistent state. Unfortunately, this didn't happen before JDK 1.1
203.2700 + * shipped. To be compatible with JDK 1.1, we will always have to write out
203.2701 + * the field values and state flags. However, <code>nextStamp</code> can be
203.2702 + * removed from the serialization stream; this will probably happen in the
203.2703 + * near future.
203.2704 + */
203.2705 + private void writeObject(ObjectOutputStream stream)
203.2706 + throws IOException
203.2707 + {
203.2708 + // Try to compute the time correctly, for the future (stream
203.2709 + // version 2) in which we don't write out fields[] or isSet[].
203.2710 + if (!isTimeSet) {
203.2711 + try {
203.2712 + updateTime();
203.2713 + }
203.2714 + catch (IllegalArgumentException e) {}
203.2715 + }
203.2716 +
203.2717 + // If this Calendar has a ZoneInfo, save it and set a
203.2718 + // SimpleTimeZone equivalent (as a single DST schedule) for
203.2719 + // backward compatibility.
203.2720 + TimeZone savedZone = null;
203.2721 +// if (zone instanceof ZoneInfo) {
203.2722 +// SimpleTimeZone stz = ((ZoneInfo)zone).getLastRuleInstance();
203.2723 +// if (stz == null) {
203.2724 +// stz = new SimpleTimeZone(zone.getRawOffset(), zone.getID());
203.2725 +// }
203.2726 +// savedZone = zone;
203.2727 +// zone = stz;
203.2728 +// }
203.2729 +
203.2730 + // Write out the 1.1 FCS object.
203.2731 + stream.defaultWriteObject();
203.2732 +
203.2733 + // Write out the ZoneInfo object
203.2734 + // 4802409: we write out even if it is null, a temporary workaround
203.2735 + // the real fix for bug 4844924 in corba-iiop
203.2736 + stream.writeObject(savedZone);
203.2737 + if (savedZone != null) {
203.2738 + zone = savedZone;
203.2739 + }
203.2740 + }
203.2741 +
203.2742 + /**
203.2743 + * Reconstitutes this object from a stream (i.e., deserialize it).
203.2744 + */
203.2745 + private void readObject(ObjectInputStream stream)
203.2746 + throws IOException, ClassNotFoundException
203.2747 + {
203.2748 + final ObjectInputStream input = stream;
203.2749 + input.defaultReadObject();
203.2750 +
203.2751 + stamp = new int[FIELD_COUNT];
203.2752 +
203.2753 + // Starting with version 2 (not implemented yet), we expect that
203.2754 + // fields[], isSet[], isTimeSet, and areFieldsSet may not be
203.2755 + // streamed out anymore. We expect 'time' to be correct.
203.2756 + if (serialVersionOnStream >= 2)
203.2757 + {
203.2758 + isTimeSet = true;
203.2759 + if (fields == null) fields = new int[FIELD_COUNT];
203.2760 + if (isSet == null) isSet = new boolean[FIELD_COUNT];
203.2761 + }
203.2762 + else if (serialVersionOnStream >= 0)
203.2763 + {
203.2764 + for (int i=0; i<FIELD_COUNT; ++i)
203.2765 + stamp[i] = isSet[i] ? COMPUTED : UNSET;
203.2766 + }
203.2767 +
203.2768 + serialVersionOnStream = currentSerialVersion;
203.2769 +
203.2770 + // If there's a ZoneInfo object, use it for zone.
203.2771 + TimeZone zi = null;
203.2772 +// try {
203.2773 +// zi = AccessController.doPrivileged(
203.2774 +// new PrivilegedExceptionAction<ZoneInfo>() {
203.2775 +// public ZoneInfo run() throws Exception {
203.2776 +// return (ZoneInfo) input.readObject();
203.2777 +// }
203.2778 +// },
203.2779 +// CalendarAccessControlContext.INSTANCE);
203.2780 +// } catch (PrivilegedActionException pae) {
203.2781 +// Exception e = pae.getException();
203.2782 +// if (!(e instanceof OptionalDataException)) {
203.2783 +// if (e instanceof RuntimeException) {
203.2784 +// throw (RuntimeException) e;
203.2785 +// } else if (e instanceof IOException) {
203.2786 +// throw (IOException) e;
203.2787 +// } else if (e instanceof ClassNotFoundException) {
203.2788 +// throw (ClassNotFoundException) e;
203.2789 +// }
203.2790 +// throw new RuntimeException(e);
203.2791 +// }
203.2792 +// }
203.2793 + if (zi != null) {
203.2794 + zone = zi;
203.2795 + }
203.2796 +
203.2797 + // If the deserialized object has a SimpleTimeZone, try to
203.2798 + // replace it with a ZoneInfo equivalent (as of 1.4) in order
203.2799 + // to be compatible with the SimpleTimeZone-based
203.2800 + // implementation as much as possible.
203.2801 + if (zone instanceof SimpleTimeZone) {
203.2802 + String id = zone.getID();
203.2803 + TimeZone tz = TimeZone.getTimeZone(id);
203.2804 + if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
203.2805 + zone = tz;
203.2806 + }
203.2807 + }
203.2808 + }
203.2809 +}
204.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
204.2 +++ b/rt/emul/compact/src/main/java/java/util/Currency.java Wed Apr 30 15:04:10 2014 +0200
204.3 @@ -0,0 +1,735 @@
204.4 +/*
204.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
204.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
204.7 + *
204.8 + * This code is free software; you can redistribute it and/or modify it
204.9 + * under the terms of the GNU General Public License version 2 only, as
204.10 + * published by the Free Software Foundation. Oracle designates this
204.11 + * particular file as subject to the "Classpath" exception as provided
204.12 + * by Oracle in the LICENSE file that accompanied this code.
204.13 + *
204.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
204.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
204.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
204.17 + * version 2 for more details (a copy is included in the LICENSE file that
204.18 + * accompanied this code).
204.19 + *
204.20 + * You should have received a copy of the GNU General Public License version
204.21 + * 2 along with this work; if not, write to the Free Software Foundation,
204.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
204.23 + *
204.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
204.25 + * or visit www.oracle.com if you need additional information or have any
204.26 + * questions.
204.27 + */
204.28 +
204.29 +package java.util;
204.30 +
204.31 +import java.io.BufferedInputStream;
204.32 +import java.io.DataInputStream;
204.33 +import java.io.File;
204.34 +import java.io.FileInputStream;
204.35 +import java.io.FileReader;
204.36 +import java.io.IOException;
204.37 +import java.io.Serializable;
204.38 +import java.security.AccessController;
204.39 +import java.security.PrivilegedAction;
204.40 +import java.util.logging.Level;
204.41 +import java.util.logging.Logger;
204.42 +
204.43 +
204.44 +/**
204.45 + * Represents a currency. Currencies are identified by their ISO 4217 currency
204.46 + * codes. Visit the <a href="http://www.iso.org/iso/en/prods-services/popstds/currencycodes.html">
204.47 + * ISO web site</a> for more information, including a table of
204.48 + * currency codes.
204.49 + * <p>
204.50 + * The class is designed so that there's never more than one
204.51 + * <code>Currency</code> instance for any given currency. Therefore, there's
204.52 + * no public constructor. You obtain a <code>Currency</code> instance using
204.53 + * the <code>getInstance</code> methods.
204.54 + * <p>
204.55 + * Users can supersede the Java runtime currency data by creating a properties
204.56 + * file named <code><JAVA_HOME>/lib/currency.properties</code>. The contents
204.57 + * of the properties file are key/value pairs of the ISO 3166 country codes
204.58 + * and the ISO 4217 currency data respectively. The value part consists of
204.59 + * three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric
204.60 + * code, and a minor unit. Those three ISO 4217 values are separated by commas.
204.61 + * The lines which start with '#'s are considered comment lines. For example,
204.62 + * <p>
204.63 + * <code>
204.64 + * #Sample currency properties<br>
204.65 + * JP=JPZ,999,0
204.66 + * </code>
204.67 + * <p>
204.68 + * will supersede the currency data for Japan.
204.69 + *
204.70 + * @since 1.4
204.71 + */
204.72 +public final class Currency implements Serializable {
204.73 +
204.74 + private static final long serialVersionUID = -158308464356906721L;
204.75 +
204.76 + /**
204.77 + * ISO 4217 currency code for this currency.
204.78 + *
204.79 + * @serial
204.80 + */
204.81 + private final String currencyCode;
204.82 +
204.83 + /**
204.84 + * Default fraction digits for this currency.
204.85 + * Set from currency data tables.
204.86 + */
204.87 + transient private final int defaultFractionDigits;
204.88 +
204.89 + /**
204.90 + * ISO 4217 numeric code for this currency.
204.91 + * Set from currency data tables.
204.92 + */
204.93 + transient private final int numericCode;
204.94 +
204.95 +
204.96 + // class data: instance map
204.97 +
204.98 + private static HashMap<String, Currency> instances = new HashMap<String, Currency>(7);
204.99 + private static HashSet<Currency> available;
204.100 +
204.101 +
204.102 + // Class data: currency data obtained from currency.data file.
204.103 + // Purpose:
204.104 + // - determine valid country codes
204.105 + // - determine valid currency codes
204.106 + // - map country codes to currency codes
204.107 + // - obtain default fraction digits for currency codes
204.108 + //
204.109 + // sc = special case; dfd = default fraction digits
204.110 + // Simple countries are those where the country code is a prefix of the
204.111 + // currency code, and there are no known plans to change the currency.
204.112 + //
204.113 + // table formats:
204.114 + // - mainTable:
204.115 + // - maps country code to 32-bit int
204.116 + // - 26*26 entries, corresponding to [A-Z]*[A-Z]
204.117 + // - \u007F -> not valid country
204.118 + // - bits 18-31: unused
204.119 + // - bits 8-17: numeric code (0 to 1023)
204.120 + // - bit 7: 1 - special case, bits 0-4 indicate which one
204.121 + // 0 - simple country, bits 0-4 indicate final char of currency code
204.122 + // - bits 5-6: fraction digits for simple countries, 0 for special cases
204.123 + // - bits 0-4: final char for currency code for simple country, or ID of special case
204.124 + // - special case IDs:
204.125 + // - 0: country has no currency
204.126 + // - other: index into sc* arrays + 1
204.127 + // - scCutOverTimes: cut-over time in millis as returned by
204.128 + // System.currentTimeMillis for special case countries that are changing
204.129 + // currencies; Long.MAX_VALUE for countries that are not changing currencies
204.130 + // - scOldCurrencies: old currencies for special case countries
204.131 + // - scNewCurrencies: new currencies for special case countries that are
204.132 + // changing currencies; null for others
204.133 + // - scOldCurrenciesDFD: default fraction digits for old currencies
204.134 + // - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
204.135 + // countries that are not changing currencies
204.136 + // - otherCurrencies: concatenation of all currency codes that are not the
204.137 + // main currency of a simple country, separated by "-"
204.138 + // - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
204.139 +
204.140 + static int formatVersion;
204.141 + static int dataVersion;
204.142 + static int[] mainTable;
204.143 + static long[] scCutOverTimes;
204.144 + static String[] scOldCurrencies;
204.145 + static String[] scNewCurrencies;
204.146 + static int[] scOldCurrenciesDFD;
204.147 + static int[] scNewCurrenciesDFD;
204.148 + static int[] scOldCurrenciesNumericCode;
204.149 + static int[] scNewCurrenciesNumericCode;
204.150 + static String otherCurrencies;
204.151 + static int[] otherCurrenciesDFD;
204.152 + static int[] otherCurrenciesNumericCode;
204.153 +
204.154 + // handy constants - must match definitions in GenerateCurrencyData
204.155 + // magic number
204.156 + private static final int MAGIC_NUMBER = 0x43757244;
204.157 + // number of characters from A to Z
204.158 + private static final int A_TO_Z = ('Z' - 'A') + 1;
204.159 + // entry for invalid country codes
204.160 + private static final int INVALID_COUNTRY_ENTRY = 0x007F;
204.161 + // entry for countries without currency
204.162 + private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x0080;
204.163 + // mask for simple case country entries
204.164 + private static final int SIMPLE_CASE_COUNTRY_MASK = 0x0000;
204.165 + // mask for simple case country entry final character
204.166 + private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x001F;
204.167 + // mask for simple case country entry default currency digits
204.168 + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x0060;
204.169 + // shift count for simple case country entry default currency digits
204.170 + private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
204.171 + // mask for special case country entries
204.172 + private static final int SPECIAL_CASE_COUNTRY_MASK = 0x0080;
204.173 + // mask for special case country index
204.174 + private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x001F;
204.175 + // delta from entry index component in main table to index into special case tables
204.176 + private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
204.177 + // mask for distinguishing simple and special case countries
204.178 + private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
204.179 + // mask for the numeric code of the currency
204.180 + private static final int NUMERIC_CODE_MASK = 0x0003FF00;
204.181 + // shift count for the numeric code of the currency
204.182 + private static final int NUMERIC_CODE_SHIFT = 8;
204.183 +
204.184 + // Currency data format version
204.185 + private static final int VALID_FORMAT_VERSION = 1;
204.186 +
204.187 + static {
204.188 + AccessController.doPrivileged(new PrivilegedAction() {
204.189 + public Object run() {
204.190 + String homeDir = System.getProperty("java.home");
204.191 + try {
204.192 + String dataFile = homeDir + File.separator +
204.193 + "lib" + File.separator + "currency.data";
204.194 + DataInputStream dis = new DataInputStream(
204.195 + new BufferedInputStream(
204.196 + new FileInputStream(dataFile)));
204.197 + if (dis.readInt() != MAGIC_NUMBER) {
204.198 + throw new InternalError("Currency data is possibly corrupted");
204.199 + }
204.200 + formatVersion = dis.readInt();
204.201 + if (formatVersion != VALID_FORMAT_VERSION) {
204.202 + throw new InternalError("Currency data format is incorrect");
204.203 + }
204.204 + dataVersion = dis.readInt();
204.205 + mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
204.206 + int scCount = dis.readInt();
204.207 + scCutOverTimes = readLongArray(dis, scCount);
204.208 + scOldCurrencies = readStringArray(dis, scCount);
204.209 + scNewCurrencies = readStringArray(dis, scCount);
204.210 + scOldCurrenciesDFD = readIntArray(dis, scCount);
204.211 + scNewCurrenciesDFD = readIntArray(dis, scCount);
204.212 + scOldCurrenciesNumericCode = readIntArray(dis, scCount);
204.213 + scNewCurrenciesNumericCode = readIntArray(dis, scCount);
204.214 + int ocCount = dis.readInt();
204.215 + otherCurrencies = dis.readUTF();
204.216 + otherCurrenciesDFD = readIntArray(dis, ocCount);
204.217 + otherCurrenciesNumericCode = readIntArray(dis, ocCount);
204.218 + dis.close();
204.219 + } catch (IOException e) {
204.220 + InternalError ie = new InternalError();
204.221 + ie.initCause(e);
204.222 + throw ie;
204.223 + }
204.224 +
204.225 + // look for the properties file for overrides
204.226 +// try {
204.227 + File propFile = new File(homeDir + File.separator +
204.228 + "lib" + File.separator +
204.229 + "currency.properties");
204.230 +// if (propFile.exists()) {
204.231 +// Properties props = new Properties();
204.232 +// try (FileReader fr = new FileReader(propFile)) {
204.233 +// props.load(fr);
204.234 +// }
204.235 +// Set<String> keys = props.stringPropertyNames();
204.236 +// Pattern propertiesPattern =
204.237 +// Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*([0-3])");
204.238 +// for (String key : keys) {
204.239 +// replaceCurrencyData(propertiesPattern,
204.240 +// key.toUpperCase(Locale.ROOT),
204.241 +// props.getProperty(key).toUpperCase(Locale.ROOT));
204.242 +// }
204.243 +// }
204.244 +// } catch (IOException e) {
204.245 +// info("currency.properties is ignored because of an IOException", e);
204.246 +// }
204.247 + return null;
204.248 + }
204.249 + });
204.250 + }
204.251 +
204.252 + /**
204.253 + * Constants for retrieving localized names from the name providers.
204.254 + */
204.255 + private static final int SYMBOL = 0;
204.256 + private static final int DISPLAYNAME = 1;
204.257 +
204.258 +
204.259 + /**
204.260 + * Constructs a <code>Currency</code> instance. The constructor is private
204.261 + * so that we can insure that there's never more than one instance for a
204.262 + * given currency.
204.263 + */
204.264 + private Currency(String currencyCode, int defaultFractionDigits, int numericCode) {
204.265 + this.currencyCode = currencyCode;
204.266 + this.defaultFractionDigits = defaultFractionDigits;
204.267 + this.numericCode = numericCode;
204.268 + }
204.269 +
204.270 + /**
204.271 + * Returns the <code>Currency</code> instance for the given currency code.
204.272 + *
204.273 + * @param currencyCode the ISO 4217 code of the currency
204.274 + * @return the <code>Currency</code> instance for the given currency code
204.275 + * @exception NullPointerException if <code>currencyCode</code> is null
204.276 + * @exception IllegalArgumentException if <code>currencyCode</code> is not
204.277 + * a supported ISO 4217 code.
204.278 + */
204.279 + public static Currency getInstance(String currencyCode) {
204.280 + return getInstance(currencyCode, Integer.MIN_VALUE, 0);
204.281 + }
204.282 +
204.283 + private static Currency getInstance(String currencyCode, int defaultFractionDigits,
204.284 + int numericCode) {
204.285 + synchronized (instances) {
204.286 + // Try to look up the currency code in the instances table.
204.287 + // This does the null pointer check as a side effect.
204.288 + // Also, if there already is an entry, the currencyCode must be valid.
204.289 + Currency instance = instances.get(currencyCode);
204.290 + if (instance != null) {
204.291 + return instance;
204.292 + }
204.293 +
204.294 + if (defaultFractionDigits == Integer.MIN_VALUE) {
204.295 + // Currency code not internally generated, need to verify first
204.296 + // A currency code must have 3 characters and exist in the main table
204.297 + // or in the list of other currencies.
204.298 + if (currencyCode.length() != 3) {
204.299 + throw new IllegalArgumentException();
204.300 + }
204.301 + char char1 = currencyCode.charAt(0);
204.302 + char char2 = currencyCode.charAt(1);
204.303 + int tableEntry = getMainTableEntry(char1, char2);
204.304 + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
204.305 + && tableEntry != INVALID_COUNTRY_ENTRY
204.306 + && currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
204.307 + defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
204.308 + numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
204.309 + } else {
204.310 + // Check for '-' separately so we don't get false hits in the table.
204.311 + if (currencyCode.charAt(2) == '-') {
204.312 + throw new IllegalArgumentException();
204.313 + }
204.314 + int index = otherCurrencies.indexOf(currencyCode);
204.315 + if (index == -1) {
204.316 + throw new IllegalArgumentException();
204.317 + }
204.318 + defaultFractionDigits = otherCurrenciesDFD[index / 4];
204.319 + numericCode = otherCurrenciesNumericCode[index / 4];
204.320 + }
204.321 + }
204.322 +
204.323 + instance = new Currency(currencyCode, defaultFractionDigits, numericCode);
204.324 + instances.put(currencyCode, instance);
204.325 + return instance;
204.326 + }
204.327 + }
204.328 +
204.329 + /**
204.330 + * Returns the <code>Currency</code> instance for the country of the
204.331 + * given locale. The language and variant components of the locale
204.332 + * are ignored. The result may vary over time, as countries change their
204.333 + * currencies. For example, for the original member countries of the
204.334 + * European Monetary Union, the method returns the old national currencies
204.335 + * until December 31, 2001, and the Euro from January 1, 2002, local time
204.336 + * of the respective countries.
204.337 + * <p>
204.338 + * The method returns <code>null</code> for territories that don't
204.339 + * have a currency, such as Antarctica.
204.340 + *
204.341 + * @param locale the locale for whose country a <code>Currency</code>
204.342 + * instance is needed
204.343 + * @return the <code>Currency</code> instance for the country of the given
204.344 + * locale, or null
204.345 + * @exception NullPointerException if <code>locale</code> or its country
204.346 + * code is null
204.347 + * @exception IllegalArgumentException if the country of the given locale
204.348 + * is not a supported ISO 3166 country code.
204.349 + */
204.350 + public static Currency getInstance(Locale locale) {
204.351 + String country = locale.getCountry();
204.352 + if (country == null) {
204.353 + throw new NullPointerException();
204.354 + }
204.355 +
204.356 + if (country.length() != 2) {
204.357 + throw new IllegalArgumentException();
204.358 + }
204.359 +
204.360 + char char1 = country.charAt(0);
204.361 + char char2 = country.charAt(1);
204.362 + int tableEntry = getMainTableEntry(char1, char2);
204.363 + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
204.364 + && tableEntry != INVALID_COUNTRY_ENTRY) {
204.365 + char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
204.366 + int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
204.367 + int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
204.368 + StringBuffer sb = new StringBuffer(country);
204.369 + sb.append(finalChar);
204.370 + return getInstance(sb.toString(), defaultFractionDigits, numericCode);
204.371 + } else {
204.372 + // special cases
204.373 + if (tableEntry == INVALID_COUNTRY_ENTRY) {
204.374 + throw new IllegalArgumentException();
204.375 + }
204.376 + if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
204.377 + return null;
204.378 + } else {
204.379 + int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
204.380 + if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) {
204.381 + return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index],
204.382 + scOldCurrenciesNumericCode[index]);
204.383 + } else {
204.384 + return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index],
204.385 + scNewCurrenciesNumericCode[index]);
204.386 + }
204.387 + }
204.388 + }
204.389 + }
204.390 +
204.391 + /**
204.392 + * Gets the set of available currencies. The returned set of currencies
204.393 + * contains all of the available currencies, which may include currencies
204.394 + * that represent obsolete ISO 4217 codes. The set can be modified
204.395 + * without affecting the available currencies in the runtime.
204.396 + *
204.397 + * @return the set of available currencies. If there is no currency
204.398 + * available in the runtime, the returned set is empty.
204.399 + * @since 1.7
204.400 + */
204.401 + public static Set<Currency> getAvailableCurrencies() {
204.402 + synchronized(Currency.class) {
204.403 + if (available == null) {
204.404 + available = new HashSet<Currency>(256);
204.405 +
204.406 + // Add simple currencies first
204.407 + for (char c1 = 'A'; c1 <= 'Z'; c1 ++) {
204.408 + for (char c2 = 'A'; c2 <= 'Z'; c2 ++) {
204.409 + int tableEntry = getMainTableEntry(c1, c2);
204.410 + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
204.411 + && tableEntry != INVALID_COUNTRY_ENTRY) {
204.412 + char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
204.413 + int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
204.414 + int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
204.415 + StringBuilder sb = new StringBuilder();
204.416 + sb.append(c1);
204.417 + sb.append(c2);
204.418 + sb.append(finalChar);
204.419 + available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
204.420 + }
204.421 + }
204.422 + }
204.423 +
204.424 + // Now add other currencies
204.425 + StringTokenizer st = new StringTokenizer(otherCurrencies, "-");
204.426 + while (st.hasMoreElements()) {
204.427 + available.add(getInstance((String)st.nextElement()));
204.428 + }
204.429 + }
204.430 + }
204.431 +
204.432 + return (Set<Currency>) available.clone();
204.433 + }
204.434 +
204.435 + /**
204.436 + * Gets the ISO 4217 currency code of this currency.
204.437 + *
204.438 + * @return the ISO 4217 currency code of this currency.
204.439 + */
204.440 + public String getCurrencyCode() {
204.441 + return currencyCode;
204.442 + }
204.443 +
204.444 + /**
204.445 + * Gets the symbol of this currency for the default locale.
204.446 + * For example, for the US Dollar, the symbol is "$" if the default
204.447 + * locale is the US, while for other locales it may be "US$". If no
204.448 + * symbol can be determined, the ISO 4217 currency code is returned.
204.449 + *
204.450 + * @return the symbol of this currency for the default locale
204.451 + */
204.452 + public String getSymbol() {
204.453 + return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
204.454 + }
204.455 +
204.456 + /**
204.457 + * Gets the symbol of this currency for the specified locale.
204.458 + * For example, for the US Dollar, the symbol is "$" if the specified
204.459 + * locale is the US, while for other locales it may be "US$". If no
204.460 + * symbol can be determined, the ISO 4217 currency code is returned.
204.461 + *
204.462 + * @param locale the locale for which a display name for this currency is
204.463 + * needed
204.464 + * @return the symbol of this currency for the specified locale
204.465 + * @exception NullPointerException if <code>locale</code> is null
204.466 + */
204.467 + public String getSymbol(Locale locale) {
204.468 + try {
204.469 + // Check whether a provider can provide an implementation that's closer
204.470 + // to the requested locale than what the Java runtime itself can provide.
204.471 + /*
204.472 + LocaleServiceProviderPool pool =
204.473 + LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
204.474 +
204.475 + if (pool.hasProviders()) {
204.476 + // Assuming that all the country locales include necessary currency
204.477 + // symbols in the Java runtime's resources, so there is no need to
204.478 + // examine whether Java runtime's currency resource bundle is missing
204.479 + // names. Therefore, no resource bundle is provided for calling this
204.480 + // method.
204.481 + String symbol = pool.getLocalizedObject(
204.482 + CurrencyNameGetter.INSTANCE,
204.483 + locale, (OpenListResourceBundle)null,
204.484 + currencyCode, SYMBOL);
204.485 + if (symbol != null) {
204.486 + return symbol;
204.487 + }
204.488 + }
204.489 + */
204.490 + ResourceBundle bundle = null; //LocaleData.getCurrencyNames(locale);
204.491 + return bundle.getString(currencyCode);
204.492 + } catch (MissingResourceException e) {
204.493 + // use currency code as symbol of last resort
204.494 + return currencyCode;
204.495 + }
204.496 + }
204.497 +
204.498 + /**
204.499 + * Gets the default number of fraction digits used with this currency.
204.500 + * For example, the default number of fraction digits for the Euro is 2,
204.501 + * while for the Japanese Yen it's 0.
204.502 + * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
204.503 + * -1 is returned.
204.504 + *
204.505 + * @return the default number of fraction digits used with this currency
204.506 + */
204.507 + public int getDefaultFractionDigits() {
204.508 + return defaultFractionDigits;
204.509 + }
204.510 +
204.511 + /**
204.512 + * Returns the ISO 4217 numeric code of this currency.
204.513 + *
204.514 + * @return the ISO 4217 numeric code of this currency
204.515 + * @since 1.7
204.516 + */
204.517 + public int getNumericCode() {
204.518 + return numericCode;
204.519 + }
204.520 +
204.521 + /**
204.522 + * Gets the name that is suitable for displaying this currency for
204.523 + * the default locale. If there is no suitable display name found
204.524 + * for the default locale, the ISO 4217 currency code is returned.
204.525 + *
204.526 + * @return the display name of this currency for the default locale
204.527 + * @since 1.7
204.528 + */
204.529 + public String getDisplayName() {
204.530 + return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
204.531 + }
204.532 +
204.533 + /**
204.534 + * Gets the name that is suitable for displaying this currency for
204.535 + * the specified locale. If there is no suitable display name found
204.536 + * for the specified locale, the ISO 4217 currency code is returned.
204.537 + *
204.538 + * @param locale the locale for which a display name for this currency is
204.539 + * needed
204.540 + * @return the display name of this currency for the specified locale
204.541 + * @exception NullPointerException if <code>locale</code> is null
204.542 + * @since 1.7
204.543 + */
204.544 + public String getDisplayName(Locale locale) {
204.545 +// try {
204.546 +// OpenListResourceBundle bundle = LocaleData.getCurrencyNames(locale);
204.547 +// String result = null;
204.548 +// String bundleKey = currencyCode.toLowerCase(Locale.ROOT);
204.549 +//
204.550 +// // Check whether a provider can provide an implementation that's closer
204.551 +// // to the requested locale than what the Java runtime itself can provide.
204.552 +// LocaleServiceProviderPool pool =
204.553 +// LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
204.554 +// if (pool.hasProviders()) {
204.555 +// result = pool.getLocalizedObject(
204.556 +// CurrencyNameGetter.INSTANCE,
204.557 +// locale, bundleKey, bundle, currencyCode, DISPLAYNAME);
204.558 +// }
204.559 +//
204.560 +// if (result == null) {
204.561 +// result = bundle.getString(bundleKey);
204.562 +// }
204.563 +//
204.564 +// if (result != null) {
204.565 +// return result;
204.566 +// }
204.567 +// } catch (MissingResourceException e) {
204.568 +// // fall through
204.569 +// }
204.570 +
204.571 + // use currency code as symbol of last resort
204.572 + return currencyCode;
204.573 + }
204.574 +
204.575 + /**
204.576 + * Returns the ISO 4217 currency code of this currency.
204.577 + *
204.578 + * @return the ISO 4217 currency code of this currency
204.579 + */
204.580 + public String toString() {
204.581 + return currencyCode;
204.582 + }
204.583 +
204.584 + /**
204.585 + * Resolves instances being deserialized to a single instance per currency.
204.586 + */
204.587 + private Object readResolve() {
204.588 + return getInstance(currencyCode);
204.589 + }
204.590 +
204.591 + /**
204.592 + * Gets the main table entry for the country whose country code consists
204.593 + * of char1 and char2.
204.594 + */
204.595 + private static int getMainTableEntry(char char1, char char2) {
204.596 + if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
204.597 + throw new IllegalArgumentException();
204.598 + }
204.599 + return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')];
204.600 + }
204.601 +
204.602 + /**
204.603 + * Sets the main table entry for the country whose country code consists
204.604 + * of char1 and char2.
204.605 + */
204.606 + private static void setMainTableEntry(char char1, char char2, int entry) {
204.607 + if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
204.608 + throw new IllegalArgumentException();
204.609 + }
204.610 + mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry;
204.611 + }
204.612 +
204.613 + /**
204.614 + * Obtains a localized currency names from a CurrencyNameProvider
204.615 + * implementation.
204.616 + private static class CurrencyNameGetter
204.617 + implements LocaleServiceProviderPool.LocalizedObjectGetter<CurrencyNameProvider,
204.618 + String> {
204.619 + private static final CurrencyNameGetter INSTANCE = new CurrencyNameGetter();
204.620 +
204.621 + public String getObject(CurrencyNameProvider currencyNameProvider,
204.622 + Locale locale,
204.623 + String key,
204.624 + Object... params) {
204.625 + assert params.length == 1;
204.626 + int type = (Integer)params[0];
204.627 +
204.628 + switch(type) {
204.629 + case SYMBOL:
204.630 + return currencyNameProvider.getSymbol(key, locale);
204.631 + case DISPLAYNAME:
204.632 + return currencyNameProvider.getDisplayName(key, locale);
204.633 + default:
204.634 + assert false; // shouldn't happen
204.635 + }
204.636 +
204.637 + return null;
204.638 + }
204.639 + }
204.640 + */
204.641 +
204.642 + private static int[] readIntArray(DataInputStream dis, int count) throws IOException {
204.643 + int[] ret = new int[count];
204.644 + for (int i = 0; i < count; i++) {
204.645 + ret[i] = dis.readInt();
204.646 + }
204.647 +
204.648 + return ret;
204.649 + }
204.650 +
204.651 + private static long[] readLongArray(DataInputStream dis, int count) throws IOException {
204.652 + long[] ret = new long[count];
204.653 + for (int i = 0; i < count; i++) {
204.654 + ret[i] = dis.readLong();
204.655 + }
204.656 +
204.657 + return ret;
204.658 + }
204.659 +
204.660 + private static String[] readStringArray(DataInputStream dis, int count) throws IOException {
204.661 + String[] ret = new String[count];
204.662 + for (int i = 0; i < count; i++) {
204.663 + ret[i] = dis.readUTF();
204.664 + }
204.665 +
204.666 + return ret;
204.667 + }
204.668 +
204.669 + /**
204.670 + * Replaces currency data found in the currencydata.properties file
204.671 + *
204.672 + * @param pattern regex pattern for the properties
204.673 + * @param ctry country code
204.674 + * @param data currency data. This is a comma separated string that
204.675 + * consists of "three-letter alphabet code", "three-digit numeric code",
204.676 + * and "one-digit (0,1,2, or 3) default fraction digit".
204.677 + * For example, "JPZ,392,0".
204.678 + * @throws
204.679 + private static void replaceCurrencyData(Pattern pattern, String ctry, String curdata) {
204.680 +
204.681 + if (ctry.length() != 2) {
204.682 + // ignore invalid country code
204.683 + String message = new StringBuilder()
204.684 + .append("The entry in currency.properties for ")
204.685 + .append(ctry).append(" is ignored because of the invalid country code.")
204.686 + .toString();
204.687 + info(message, null);
204.688 + return;
204.689 + }
204.690 +
204.691 + Matcher m = pattern.matcher(curdata);
204.692 + if (!m.find()) {
204.693 + // format is not recognized. ignore the data
204.694 + String message = new StringBuilder()
204.695 + .append("The entry in currency.properties for ")
204.696 + .append(ctry)
204.697 + .append(" is ignored because the value format is not recognized.")
204.698 + .toString();
204.699 + info(message, null);
204.700 + return;
204.701 + }
204.702 +
204.703 + String code = m.group(1);
204.704 + int numeric = Integer.parseInt(m.group(2));
204.705 + int fraction = Integer.parseInt(m.group(3));
204.706 + int entry = numeric << NUMERIC_CODE_SHIFT;
204.707 +
204.708 + int index;
204.709 + for (index = 0; index < scOldCurrencies.length; index++) {
204.710 + if (scOldCurrencies[index].equals(code)) {
204.711 + break;
204.712 + }
204.713 + }
204.714 +
204.715 + if (index == scOldCurrencies.length) {
204.716 + // simple case
204.717 + entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) |
204.718 + (code.charAt(2) - 'A');
204.719 + } else {
204.720 + // special case
204.721 + entry |= SPECIAL_CASE_COUNTRY_MASK |
204.722 + (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
204.723 + }
204.724 + setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
204.725 + }
204.726 + */
204.727 +
204.728 + private static void info(String message, Throwable t) {
204.729 + Logger logger = Logger.getLogger("java.util.Currency");
204.730 + if (logger.isLoggable(Level.INFO)) {
204.731 + if (t != null) {
204.732 + logger.log(Level.INFO, message, t);
204.733 + } else {
204.734 + logger.info(message);
204.735 + }
204.736 + }
204.737 + }
204.738 +}
205.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
205.2 +++ b/rt/emul/compact/src/main/java/java/util/CurrencyData.properties Wed Apr 30 15:04:10 2014 +0200
205.3 @@ -0,0 +1,586 @@
205.4 +#
205.5 +# Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
205.6 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
205.7 +#
205.8 +# This code is free software; you can redistribute it and/or modify it
205.9 +# under the terms of the GNU General Public License version 2 only, as
205.10 +# published by the Free Software Foundation. Oracle designates this
205.11 +# particular file as subject to the "Classpath" exception as provided
205.12 +# by Oracle in the LICENSE file that accompanied this code.
205.13 +#
205.14 +# This code is distributed in the hope that it will be useful, but WITHOUT
205.15 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
205.16 +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
205.17 +# version 2 for more details (a copy is included in the LICENSE file that
205.18 +# accompanied this code).
205.19 +#
205.20 +# You should have received a copy of the GNU General Public License version
205.21 +# 2 along with this work; if not, write to the Free Software Foundation,
205.22 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
205.23 +#
205.24 +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
205.25 +# or visit www.oracle.com if you need additional information or have any
205.26 +# questions.
205.27 +#
205.28 +
205.29 +formatVersion=1
205.30 +
205.31 +# Version of the currency code information in this class.
205.32 +# It is a serial number that accompanies with each amendment, such as
205.33 +# 'MAxxx.doc'
205.34 +
205.35 +dataVersion=140
205.36 +
205.37 +# List of all valid ISO 4217 currency codes.
205.38 +# To ensure compatibility, do not remove codes.
205.39 +
205.40 +all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036-\
205.41 + AWG533-AYM945-AZM031-AZN944-BAM977-BBD052-BDT050-BEF056-BGL100-BGN975-BHD048-BIF108-\
205.42 + BMD060-BND096-BOB068-BOV984-BRL986-BSD044-BTN064-BWP072-BYB112-BYR974-\
205.43 + BZD084-CAD124-CDF976-CHF756-CLF990-CLP152-CNY156-COP170-CRC188-CSD891-CUP192-\
205.44 + CVE132-CYP196-CZK203-DEM276-DJF262-DKK208-DOP214-DZD012-EEK233-EGP818-\
205.45 + ERN232-ESP724-ETB230-EUR978-FIM246-FJD242-FKP238-FRF250-GBP826-GEL981-\
205.46 + GHC288-GHS936-GIP292-GMD270-GNF324-GRD300-GTQ320-GWP624-GYD328-HKD344-HNL340-\
205.47 + HRK191-HTG332-HUF348-IDR360-IEP372-ILS376-INR356-IQD368-IRR364-ISK352-\
205.48 + ITL380-JMD388-JOD400-JPY392-KES404-KGS417-KHR116-KMF174-KPW408-KRW410-\
205.49 + KWD414-KYD136-KZT398-LAK418-LBP422-LKR144-LRD430-LSL426-LTL440-LUF442-\
205.50 + LVL428-LYD434-MAD504-MDL498-MGA969-MGF450-MKD807-MMK104-MNT496-MOP446-MRO478-\
205.51 + MTL470-MUR480-MVR462-MWK454-MXN484-MXV979-MYR458-MZM508-MZN943-NAD516-NGN566-\
205.52 + NIO558-NLG528-NOK578-NPR524-NZD554-OMR512-PAB590-PEN604-PGK598-PHP608-\
205.53 + PKR586-PLN985-PTE620-PYG600-QAR634-ROL946-RON946-RSD941-RUB643-RUR810-RWF646-SAR682-\
205.54 + SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLL694-SOS706-\
205.55 + SRD968-SRG740-STD678-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TND788-TOP776-\
205.56 + TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-\
205.57 + UYU858-UZS860-VEB862-VEF937-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\
205.58 + XBB956-XBC957-XBD958-XCD951-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\
205.59 + XPT962-XTS963-XXX999-YER886-YUM891-ZAR710-ZMK894-ZWD716-ZWN942
205.60 +
205.61 +
205.62 +# Mappings from ISO 3166 country codes to ISO 4217 currency codes.
205.63 +#
205.64 +# Three forms are used:
205.65 +# Form 1: <country code>=<currency code>
205.66 +# Form 2: <country code>=<currency code 1>;<time stamp>;<currency code 2>
205.67 +# Form 3: <country code>=
205.68 +# Form 1 is used if no future change in currency is known.
205.69 +# Form 2 indicates that before the specified time currency 1 is used, from
205.70 +# the specified time currency 2. The time is given in SimpleDateFormat's
205.71 +# yyyy-MM-dd-HH-mm-ss format in the GMT time zone.
205.72 +# Form 3 indicates the country doesn't have a currency (the entry is still
205.73 +# needed to verify that the country code is valid).
205.74 +#
205.75 +# The table is based on the following web sites:
205.76 +# http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/db_en.html
205.77 +# http://www.bsi-global.com/iso4217currency
205.78 +# http://www.cia.gov/cia/publications/factbook/indexgeo.html
205.79 +
205.80 +# AFGHANISTAN
205.81 +AF=AFN
205.82 +# \u00c5LAND ISLANDS
205.83 +AX=EUR
205.84 +# ALBANIA
205.85 +AL=ALL
205.86 +# ALGERIA
205.87 +DZ=DZD
205.88 +# AMERICAN SAMOA
205.89 +AS=USD
205.90 +# ANDORRA
205.91 +AD=EUR
205.92 +# ANGOLA
205.93 +AO=AOA
205.94 +# ANGUILLA
205.95 +AI=XCD
205.96 +# ANTARCTICA
205.97 +AQ=
205.98 +# ANTIGUA AND BARBUDA
205.99 +AG=XCD
205.100 +# ARGENTINA
205.101 +AR=ARS
205.102 +# ARMENIA
205.103 +AM=AMD
205.104 +# ARUBA
205.105 +AW=AWG
205.106 +# AUSTRALIA
205.107 +AU=AUD
205.108 +# AUSTRIA
205.109 +AT=EUR
205.110 +# AZERBAIJAN
205.111 +AZ=AZM;2005-12-31-20-00-00;AZN
205.112 +# BAHAMAS
205.113 +BS=BSD
205.114 +# BAHRAIN
205.115 +BH=BHD
205.116 +# BANGLADESH
205.117 +BD=BDT
205.118 +# BARBADOS
205.119 +BB=BBD
205.120 +# BELARUS
205.121 +BY=BYR
205.122 +# BELGIUM
205.123 +BE=EUR
205.124 +# BELIZE
205.125 +BZ=BZD
205.126 +# BENIN
205.127 +BJ=XOF
205.128 +# BERMUDA
205.129 +BM=BMD
205.130 +# BHUTAN
205.131 +BT=BTN
205.132 +# BOLIVIA
205.133 +BO=BOB
205.134 +# BOSNIA AND HERZEGOVINA
205.135 +BA=BAM
205.136 +# BOTSWANA
205.137 +BW=BWP
205.138 +# BOUVET ISLAND
205.139 +BV=NOK
205.140 +# BRAZIL
205.141 +BR=BRL
205.142 +# BRITISH INDIAN OCEAN TERRITORY
205.143 +IO=USD
205.144 +# BRUNEI DARUSSALAM
205.145 +BN=BND
205.146 +# BULGARIA
205.147 +BG=BGN
205.148 +# BURKINA FASO
205.149 +BF=XOF
205.150 +# BURUNDI
205.151 +BI=BIF
205.152 +# CAMBODIA
205.153 +KH=KHR
205.154 +# CAMEROON
205.155 +CM=XAF
205.156 +# CANADA
205.157 +CA=CAD
205.158 +# CAPE VERDE
205.159 +CV=CVE
205.160 +# CAYMAN ISLANDS
205.161 +KY=KYD
205.162 +# CENTRAL AFRICAN REPUBLIC
205.163 +CF=XAF
205.164 +# CHAD
205.165 +TD=XAF
205.166 +# CHILE
205.167 +CL=CLP
205.168 +# CHINA
205.169 +CN=CNY
205.170 +# CHRISTMAS ISLAND
205.171 +CX=AUD
205.172 +# COCOS (KEELING) ISLANDS
205.173 +CC=AUD
205.174 +# COLOMBIA
205.175 +CO=COP
205.176 +# COMOROS
205.177 +KM=KMF
205.178 +# CONGO
205.179 +CG=XAF
205.180 +# CONGO, THE DEMOCRATIC REPUBLIC OF THE
205.181 +CD=CDF
205.182 +# COOK ISLANDS
205.183 +CK=NZD
205.184 +# COSTA RICA
205.185 +CR=CRC
205.186 +# COTE D'IVOIRE
205.187 +CI=XOF
205.188 +# CROATIA
205.189 +HR=HRK
205.190 +# CUBA
205.191 +CU=CUP
205.192 +# CYPRUS
205.193 +CY=EUR
205.194 +# CZECH REPUBLIC
205.195 +CZ=CZK
205.196 +# DENMARK
205.197 +DK=DKK
205.198 +# DJIBOUTI
205.199 +DJ=DJF
205.200 +# DOMINICA
205.201 +DM=XCD
205.202 +# DOMINICAN REPUBLIC
205.203 +DO=DOP
205.204 +# ECUADOR
205.205 +EC=USD
205.206 +# EGYPT
205.207 +EG=EGP
205.208 +# EL SALVADOR
205.209 +# USD is also legal currency as of 2001/01/01
205.210 +SV=SVC
205.211 +# EQUATORIAL GUINEA
205.212 +GQ=XAF
205.213 +# ERITREA
205.214 +ER=ERN
205.215 +# ESTONIA
205.216 +EE=EEK
205.217 +# ETHIOPIA
205.218 +ET=ETB
205.219 +# FALKLAND ISLANDS (MALVINAS)
205.220 +FK=FKP
205.221 +# FAROE ISLANDS
205.222 +FO=DKK
205.223 +# FIJI
205.224 +FJ=FJD
205.225 +# FINLAND
205.226 +FI=EUR
205.227 +# FRANCE
205.228 +FR=EUR
205.229 +# FRENCH GUIANA
205.230 +GF=EUR
205.231 +# FRENCH POLYNESIA
205.232 +PF=XPF
205.233 +# FRENCH SOUTHERN TERRITORIES
205.234 +TF=EUR
205.235 +# GABON
205.236 +GA=XAF
205.237 +# GAMBIA
205.238 +GM=GMD
205.239 +# GEORGIA
205.240 +GE=GEL
205.241 +# GERMANY
205.242 +DE=EUR
205.243 +# GHANA
205.244 +GH=GHS
205.245 +# GIBRALTAR
205.246 +GI=GIP
205.247 +# GREECE
205.248 +GR=EUR
205.249 +# GREENLAND
205.250 +GL=DKK
205.251 +# GRENADA
205.252 +GD=XCD
205.253 +# GUADELOUPE
205.254 +GP=EUR
205.255 +# GUAM
205.256 +GU=USD
205.257 +# GUATEMALA
205.258 +GT=GTQ
205.259 +# GUERNSEY
205.260 +GG=GBP
205.261 +# GUINEA
205.262 +GN=GNF
205.263 +# GUINEA-BISSAU
205.264 +GW=XOF
205.265 +# GUYANA
205.266 +GY=GYD
205.267 +# HAITI
205.268 +HT=HTG
205.269 +# HEARD ISLAND AND MCDONALD ISLANDS
205.270 +HM=AUD
205.271 +# HOLY SEE (VATICAN CITY STATE)
205.272 +VA=EUR
205.273 +# HONDURAS
205.274 +HN=HNL
205.275 +# HONG KONG
205.276 +HK=HKD
205.277 +# HUNGARY
205.278 +HU=HUF
205.279 +# ICELAND
205.280 +IS=ISK
205.281 +# INDIA
205.282 +IN=INR
205.283 +# INDONESIA
205.284 +ID=IDR
205.285 +# IRAN, ISLAMIC REPUBLIC OF
205.286 +IR=IRR
205.287 +# IRAQ
205.288 +IQ=IQD
205.289 +# IRELAND
205.290 +IE=EUR
205.291 +# ISLE OF MAN
205.292 +IM=GBP
205.293 +# ISRAEL
205.294 +IL=ILS
205.295 +# ITALY
205.296 +IT=EUR
205.297 +# JAMAICA
205.298 +JM=JMD
205.299 +# JAPAN
205.300 +JP=JPY
205.301 +# JERSEY
205.302 +JE=GBP
205.303 +# JORDAN
205.304 +JO=JOD
205.305 +# KAZAKSTAN
205.306 +KZ=KZT
205.307 +# KENYA
205.308 +KE=KES
205.309 +# KIRIBATI
205.310 +KI=AUD
205.311 +# KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF
205.312 +KP=KPW
205.313 +# KOREA, REPUBLIC OF
205.314 +KR=KRW
205.315 +# KUWAIT
205.316 +KW=KWD
205.317 +# KYRGYZSTAN
205.318 +KG=KGS
205.319 +# LAO PEOPLE'S DEMOCRATIC REPUBLIC
205.320 +LA=LAK
205.321 +# LATVIA
205.322 +LV=LVL
205.323 +# LEBANON
205.324 +LB=LBP
205.325 +# LESOTHO
205.326 +LS=LSL
205.327 +# LIBERIA
205.328 +LR=LRD
205.329 +# LIBYAN ARAB JAMAHIRIYA
205.330 +LY=LYD
205.331 +# LIECHTENSTEIN
205.332 +LI=CHF
205.333 +# LITHUANIA
205.334 +LT=LTL
205.335 +# LUXEMBOURG
205.336 +LU=EUR
205.337 +# MACAU
205.338 +MO=MOP
205.339 +# MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF
205.340 +MK=MKD
205.341 +# MADAGASCAR
205.342 +MG=MGA
205.343 +# MALAWI
205.344 +MW=MWK
205.345 +# MALAYSIA
205.346 +MY=MYR
205.347 +# MALDIVES
205.348 +MV=MVR
205.349 +# MALI
205.350 +ML=XOF
205.351 +# MALTA
205.352 +MT=EUR
205.353 +# MARSHALL ISLANDS
205.354 +MH=USD
205.355 +# MARTINIQUE
205.356 +MQ=EUR
205.357 +# MAURITANIA
205.358 +MR=MRO
205.359 +# MAURITIUS
205.360 +MU=MUR
205.361 +# MAYOTTE
205.362 +YT=EUR
205.363 +# MEXICO
205.364 +MX=MXN
205.365 +# MICRONESIA, FEDERATED STATES OF
205.366 +FM=USD
205.367 +# MOLDOVA, REPUBLIC OF
205.368 +MD=MDL
205.369 +# MONACO
205.370 +MC=EUR
205.371 +# MONGOLIA
205.372 +MN=MNT
205.373 +# MONTENEGRO
205.374 +ME=EUR
205.375 +# MONTSERRAT
205.376 +MS=XCD
205.377 +# MOROCCO
205.378 +MA=MAD
205.379 +# MOZAMBIQUE
205.380 +MZ=MZM;2006-06-30-22-00-00;MZN
205.381 +# MYANMAR
205.382 +MM=MMK
205.383 +# NAMIBIA
205.384 +NA=NAD
205.385 +# NAURU
205.386 +NR=AUD
205.387 +# NEPAL
205.388 +NP=NPR
205.389 +# NETHERLANDS
205.390 +NL=EUR
205.391 +# NETHERLANDS ANTILLES
205.392 +AN=ANG
205.393 +# NEW CALEDONIA
205.394 +NC=XPF
205.395 +# NEW ZEALAND
205.396 +NZ=NZD
205.397 +# NICARAGUA
205.398 +NI=NIO
205.399 +# NIGER
205.400 +NE=XOF
205.401 +# NIGERIA
205.402 +NG=NGN
205.403 +# NIUE
205.404 +NU=NZD
205.405 +# NORFOLK ISLAND
205.406 +NF=AUD
205.407 +# NORTHERN MARIANA ISLANDS
205.408 +MP=USD
205.409 +# NORWAY
205.410 +NO=NOK
205.411 +# OMAN
205.412 +OM=OMR
205.413 +# PAKISTAN
205.414 +PK=PKR
205.415 +# PALAU
205.416 +PW=USD
205.417 +# PALESTINIAN TERRITORY, OCCUPIED
205.418 +PS=ILS
205.419 +# PANAMA
205.420 +PA=PAB
205.421 +# PAPUA NEW GUINEA
205.422 +PG=PGK
205.423 +# PARAGUAY
205.424 +PY=PYG
205.425 +# PERU
205.426 +PE=PEN
205.427 +# PHILIPPINES
205.428 +PH=PHP
205.429 +# PITCAIRN
205.430 +PN=NZD
205.431 +# POLAND
205.432 +PL=PLN
205.433 +# PORTUGAL
205.434 +PT=EUR
205.435 +# PUERTO RICO
205.436 +PR=USD
205.437 +# QATAR
205.438 +QA=QAR
205.439 +# REUNION
205.440 +RE=EUR
205.441 +# ROMANIA
205.442 +RO=ROL;2005-06-30-21-00-00;RON
205.443 +# RUSSIAN FEDERATION
205.444 +RU=RUB
205.445 +# RWANDA
205.446 +RW=RWF
205.447 +# SAINT BARTHELEMY
205.448 +BL=EUR
205.449 +# SAINT HELENA
205.450 +SH=SHP
205.451 +# SAINT KITTS AND NEVIS
205.452 +KN=XCD
205.453 +# SAINT LUCIA
205.454 +LC=XCD
205.455 +# SAINT MARTIN
205.456 +MF=EUR
205.457 +# SAINT PIERRE AND MIQUELON
205.458 +PM=EUR
205.459 +# SAINT VINCENT AND THE GRENADINES
205.460 +VC=XCD
205.461 +# SAMOA
205.462 +WS=WST
205.463 +# SAN MARINO
205.464 +SM=EUR
205.465 +# SAO TOME AND PRINCIPE
205.466 +ST=STD
205.467 +# SAUDI ARABIA
205.468 +SA=SAR
205.469 +# SENEGAL
205.470 +SN=XOF
205.471 +# SERBIA
205.472 +RS=RSD
205.473 +# SERBIA AND MONTENEGRO
205.474 +CS=CSD
205.475 +# SEYCHELLES
205.476 +SC=SCR
205.477 +# SIERRA LEONE
205.478 +SL=SLL
205.479 +# SINGAPORE
205.480 +SG=SGD
205.481 +# SLOVAKIA
205.482 +SK=SKK
205.483 +# SLOVENIA
205.484 +SI=EUR
205.485 +# SOLOMON ISLANDS
205.486 +SB=SBD
205.487 +# SOMALIA
205.488 +SO=SOS
205.489 +# SOUTH AFRICA
205.490 +ZA=ZAR
205.491 +# SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS
205.492 +GS=GBP
205.493 +# SPAIN
205.494 +ES=EUR
205.495 +# SRI LANKA
205.496 +LK=LKR
205.497 +# SUDAN
205.498 +SD=SDG
205.499 +# SURINAME
205.500 +SR=SRD
205.501 +# SVALBARD AND JAN MAYEN
205.502 +SJ=NOK
205.503 +# SWAZILAND
205.504 +SZ=SZL
205.505 +# SWEDEN
205.506 +SE=SEK
205.507 +# SWITZERLAND
205.508 +CH=CHF
205.509 +# SYRIAN ARAB REPUBLIC
205.510 +SY=SYP
205.511 +# TAIWAN
205.512 +TW=TWD
205.513 +# TAJIKISTAN
205.514 +TJ=TJS
205.515 +# TANZANIA, UNITED REPUBLIC OF
205.516 +TZ=TZS
205.517 +# THAILAND
205.518 +TH=THB
205.519 +# TIMOR-LESTE
205.520 +TL=USD
205.521 +# TOGO
205.522 +TG=XOF
205.523 +# TOKELAU
205.524 +TK=NZD
205.525 +# TONGA
205.526 +TO=TOP
205.527 +# TRINIDAD AND TOBAGO
205.528 +TT=TTD
205.529 +# TUNISIA
205.530 +TN=TND
205.531 +# TURKEY
205.532 +TR=TRL;2004-12-31-22-00-00;TRY
205.533 +# TURKMENISTAN
205.534 +TM=TMM
205.535 +# TURKS AND CAICOS ISLANDS
205.536 +TC=USD
205.537 +# TUVALU
205.538 +TV=AUD
205.539 +# UGANDA
205.540 +UG=UGX
205.541 +# UKRAINE
205.542 +UA=UAH
205.543 +# UNITED ARAB EMIRATES
205.544 +AE=AED
205.545 +# UNITED KINGDOM
205.546 +GB=GBP
205.547 +# UNITED STATES
205.548 +US=USD
205.549 +# UNITED STATES MINOR OUTLYING ISLANDS
205.550 +UM=USD
205.551 +# URUGUAY
205.552 +UY=UYU
205.553 +# UZBEKISTAN
205.554 +UZ=UZS
205.555 +# VANUATU
205.556 +VU=VUV
205.557 +# VENEZUELA
205.558 +VE=VEB;2008-01-01-04-00-00;VEF
205.559 +# VIET NAM
205.560 +VN=VND
205.561 +# VIRGIN ISLANDS, BRITISH
205.562 +VG=USD
205.563 +# VIRGIN ISLANDS, U.S.
205.564 +VI=USD
205.565 +# WALLIS AND FUTUNA
205.566 +WF=XPF
205.567 +# WESTERN SAHARA
205.568 +EH=MAD
205.569 +# YEMEN
205.570 +YE=YER
205.571 +# ZAMBIA
205.572 +ZM=ZMK
205.573 +# ZIMBABWE
205.574 +ZW=ZWD
205.575 +
205.576 +
205.577 +# List of currencies with 0, 1, OR 3 decimals for minor units, or where there
205.578 +# are no minor units defined. All others use 2 decimals.
205.579 +
205.580 +minor0=\
205.581 + ADP-BEF-BIF-BYB-BYR-CLF-CLP-DJF-ESP-GNF-\
205.582 + GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-RWF-\
205.583 + TPE-TRL-VUV-XAF-XOF-XPF
205.584 +minor1=
205.585 +minor3=\
205.586 + BHD-IQD-JOD-KWD-LYD-OMR-TND
205.587 +minorUndefined=\
205.588 + XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-\
205.589 + XPT-XTS-XXX
206.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
206.2 +++ b/rt/emul/compact/src/main/java/java/util/Date.java Wed Apr 30 15:04:10 2014 +0200
206.3 @@ -0,0 +1,1430 @@
206.4 +/*
206.5 + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
206.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
206.7 + *
206.8 + * This code is free software; you can redistribute it and/or modify it
206.9 + * under the terms of the GNU General Public License version 2 only, as
206.10 + * published by the Free Software Foundation. Oracle designates this
206.11 + * particular file as subject to the "Classpath" exception as provided
206.12 + * by Oracle in the LICENSE file that accompanied this code.
206.13 + *
206.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
206.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
206.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
206.17 + * version 2 for more details (a copy is included in the LICENSE file that
206.18 + * accompanied this code).
206.19 + *
206.20 + * You should have received a copy of the GNU General Public License version
206.21 + * 2 along with this work; if not, write to the Free Software Foundation,
206.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
206.23 + *
206.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
206.25 + * or visit www.oracle.com if you need additional information or have any
206.26 + * questions.
206.27 + */
206.28 +
206.29 +package java.util;
206.30 +
206.31 +import java.text.DateFormat;
206.32 +import java.io.IOException;
206.33 +import java.io.ObjectOutputStream;
206.34 +import java.io.ObjectInputStream;
206.35 +
206.36 +/**
206.37 + * The class <code>Date</code> represents a specific instant
206.38 + * in time, with millisecond precision.
206.39 + * <p>
206.40 + * Prior to JDK 1.1, the class <code>Date</code> had two additional
206.41 + * functions. It allowed the interpretation of dates as year, month, day, hour,
206.42 + * minute, and second values. It also allowed the formatting and parsing
206.43 + * of date strings. Unfortunately, the API for these functions was not
206.44 + * amenable to internationalization. As of JDK 1.1, the
206.45 + * <code>Calendar</code> class should be used to convert between dates and time
206.46 + * fields and the <code>DateFormat</code> class should be used to format and
206.47 + * parse date strings.
206.48 + * The corresponding methods in <code>Date</code> are deprecated.
206.49 + * <p>
206.50 + * Although the <code>Date</code> class is intended to reflect
206.51 + * coordinated universal time (UTC), it may not do so exactly,
206.52 + * depending on the host environment of the Java Virtual Machine.
206.53 + * Nearly all modern operating systems assume that 1 day =
206.54 + * 24 × 60 × 60 = 86400 seconds
206.55 + * in all cases. In UTC, however, about once every year or two there
206.56 + * is an extra second, called a "leap second." The leap
206.57 + * second is always added as the last second of the day, and always
206.58 + * on December 31 or June 30. For example, the last minute of the
206.59 + * year 1995 was 61 seconds long, thanks to an added leap second.
206.60 + * Most computer clocks are not accurate enough to be able to reflect
206.61 + * the leap-second distinction.
206.62 + * <p>
206.63 + * Some computer standards are defined in terms of Greenwich mean
206.64 + * time (GMT), which is equivalent to universal time (UT). GMT is
206.65 + * the "civil" name for the standard; UT is the
206.66 + * "scientific" name for the same standard. The
206.67 + * distinction between UTC and UT is that UTC is based on an atomic
206.68 + * clock and UT is based on astronomical observations, which for all
206.69 + * practical purposes is an invisibly fine hair to split. Because the
206.70 + * earth's rotation is not uniform (it slows down and speeds up
206.71 + * in complicated ways), UT does not always flow uniformly. Leap
206.72 + * seconds are introduced as needed into UTC so as to keep UTC within
206.73 + * 0.9 seconds of UT1, which is a version of UT with certain
206.74 + * corrections applied. There are other time and date systems as
206.75 + * well; for example, the time scale used by the satellite-based
206.76 + * global positioning system (GPS) is synchronized to UTC but is
206.77 + * <i>not</i> adjusted for leap seconds. An interesting source of
206.78 + * further information is the U.S. Naval Observatory, particularly
206.79 + * the Directorate of Time at:
206.80 + * <blockquote><pre>
206.81 + * <a href=http://tycho.usno.navy.mil>http://tycho.usno.navy.mil</a>
206.82 + * </pre></blockquote>
206.83 + * <p>
206.84 + * and their definitions of "Systems of Time" at:
206.85 + * <blockquote><pre>
206.86 + * <a href=http://tycho.usno.navy.mil/systime.html>http://tycho.usno.navy.mil/systime.html</a>
206.87 + * </pre></blockquote>
206.88 + * <p>
206.89 + * In all methods of class <code>Date</code> that accept or return
206.90 + * year, month, date, hours, minutes, and seconds values, the
206.91 + * following representations are used:
206.92 + * <ul>
206.93 + * <li>A year <i>y</i> is represented by the integer
206.94 + * <i>y</i> <code>- 1900</code>.
206.95 + * <li>A month is represented by an integer from 0 to 11; 0 is January,
206.96 + * 1 is February, and so forth; thus 11 is December.
206.97 + * <li>A date (day of month) is represented by an integer from 1 to 31
206.98 + * in the usual manner.
206.99 + * <li>An hour is represented by an integer from 0 to 23. Thus, the hour
206.100 + * from midnight to 1 a.m. is hour 0, and the hour from noon to 1
206.101 + * p.m. is hour 12.
206.102 + * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
206.103 + * <li>A second is represented by an integer from 0 to 61; the values 60 and
206.104 + * 61 occur only for leap seconds and even then only in Java
206.105 + * implementations that actually track leap seconds correctly. Because
206.106 + * of the manner in which leap seconds are currently introduced, it is
206.107 + * extremely unlikely that two leap seconds will occur in the same
206.108 + * minute, but this specification follows the date and time conventions
206.109 + * for ISO C.
206.110 + * </ul>
206.111 + * <p>
206.112 + * In all cases, arguments given to methods for these purposes need
206.113 + * not fall within the indicated ranges; for example, a date may be
206.114 + * specified as January 32 and is interpreted as meaning February 1.
206.115 + *
206.116 + * @author James Gosling
206.117 + * @author Arthur van Hoff
206.118 + * @author Alan Liu
206.119 + * @see java.text.DateFormat
206.120 + * @see java.util.Calendar
206.121 + * @see java.util.TimeZone
206.122 + * @since JDK1.0
206.123 + */
206.124 +public class Date
206.125 + implements java.io.Serializable, Cloneable, Comparable<Date>
206.126 +{
206.127 + private static final BaseCalendar gcal = new BaseCalendar();
206.128 +
206.129 + private static BaseCalendar jcal;
206.130 +
206.131 + private transient long fastTime;
206.132 +
206.133 + /*
206.134 + * If cdate is null, then fastTime indicates the time in millis.
206.135 + * If cdate.isNormalized() is true, then fastTime and cdate are in
206.136 + * synch. Otherwise, fastTime is ignored, and cdate indicates the
206.137 + * time.
206.138 + */
206.139 + private transient BaseCalendar.Datum cdate;
206.140 +
206.141 + // Initialized just before the value is used. See parse().
206.142 + private static int defaultCenturyStart;
206.143 +
206.144 + /* use serialVersionUID from modified java.util.Date for
206.145 + * interoperability with JDK1.1. The Date was modified to write
206.146 + * and read only the UTC time.
206.147 + */
206.148 + private static final long serialVersionUID = 7523967970034938905L;
206.149 +
206.150 + /**
206.151 + * Allocates a <code>Date</code> object and initializes it so that
206.152 + * it represents the time at which it was allocated, measured to the
206.153 + * nearest millisecond.
206.154 + *
206.155 + * @see java.lang.System#currentTimeMillis()
206.156 + */
206.157 + public Date() {
206.158 + this(System.currentTimeMillis());
206.159 + }
206.160 +
206.161 + /**
206.162 + * Allocates a <code>Date</code> object and initializes it to
206.163 + * represent the specified number of milliseconds since the
206.164 + * standard base time known as "the epoch", namely January 1,
206.165 + * 1970, 00:00:00 GMT.
206.166 + *
206.167 + * @param date the milliseconds since January 1, 1970, 00:00:00 GMT.
206.168 + * @see java.lang.System#currentTimeMillis()
206.169 + */
206.170 + public Date(long date) {
206.171 + fastTime = date;
206.172 + }
206.173 +
206.174 + /**
206.175 + * Allocates a <code>Date</code> object and initializes it so that
206.176 + * it represents midnight, local time, at the beginning of the day
206.177 + * specified by the <code>year</code>, <code>month</code>, and
206.178 + * <code>date</code> arguments.
206.179 + *
206.180 + * @param year the year minus 1900.
206.181 + * @param month the month between 0-11.
206.182 + * @param date the day of the month between 1-31.
206.183 + * @see java.util.Calendar
206.184 + * @deprecated As of JDK version 1.1,
206.185 + * replaced by <code>Calendar.set(year + 1900, month, date)</code>
206.186 + * or <code>GregorianCalendar(year + 1900, month, date)</code>.
206.187 + */
206.188 + @Deprecated
206.189 + public Date(int year, int month, int date) {
206.190 + this(year, month, date, 0, 0, 0);
206.191 + }
206.192 +
206.193 + /**
206.194 + * Allocates a <code>Date</code> object and initializes it so that
206.195 + * it represents the instant at the start of the minute specified by
206.196 + * the <code>year</code>, <code>month</code>, <code>date</code>,
206.197 + * <code>hrs</code>, and <code>min</code> arguments, in the local
206.198 + * time zone.
206.199 + *
206.200 + * @param year the year minus 1900.
206.201 + * @param month the month between 0-11.
206.202 + * @param date the day of the month between 1-31.
206.203 + * @param hrs the hours between 0-23.
206.204 + * @param min the minutes between 0-59.
206.205 + * @see java.util.Calendar
206.206 + * @deprecated As of JDK version 1.1,
206.207 + * replaced by <code>Calendar.set(year + 1900, month, date,
206.208 + * hrs, min)</code> or <code>GregorianCalendar(year + 1900,
206.209 + * month, date, hrs, min)</code>.
206.210 + */
206.211 + @Deprecated
206.212 + public Date(int year, int month, int date, int hrs, int min) {
206.213 + this(year, month, date, hrs, min, 0);
206.214 + }
206.215 +
206.216 + /**
206.217 + * Allocates a <code>Date</code> object and initializes it so that
206.218 + * it represents the instant at the start of the second specified
206.219 + * by the <code>year</code>, <code>month</code>, <code>date</code>,
206.220 + * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments,
206.221 + * in the local time zone.
206.222 + *
206.223 + * @param year the year minus 1900.
206.224 + * @param month the month between 0-11.
206.225 + * @param date the day of the month between 1-31.
206.226 + * @param hrs the hours between 0-23.
206.227 + * @param min the minutes between 0-59.
206.228 + * @param sec the seconds between 0-59.
206.229 + * @see java.util.Calendar
206.230 + * @deprecated As of JDK version 1.1,
206.231 + * replaced by <code>Calendar.set(year + 1900, month, date,
206.232 + * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
206.233 + * month, date, hrs, min, sec)</code>.
206.234 + */
206.235 + @Deprecated
206.236 + public Date(int year, int month, int date, int hrs, int min, int sec) {
206.237 + int y = year + 1900;
206.238 + // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
206.239 + if (month >= 12) {
206.240 + y += month / 12;
206.241 + month %= 12;
206.242 + } else if (month < 0) {
206.243 + y += month / 12;
206.244 + month = month % 12;
206.245 + }
206.246 + BaseCalendar cal = getCalendarSystem(y);
206.247 + cdate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.getDefaultRef());
206.248 + cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
206.249 + getTimeImpl();
206.250 + cdate = null;
206.251 + }
206.252 +
206.253 + /**
206.254 + * Allocates a <code>Date</code> object and initializes it so that
206.255 + * it represents the date and time indicated by the string
206.256 + * <code>s</code>, which is interpreted as if by the
206.257 + * {@link Date#parse} method.
206.258 + *
206.259 + * @param s a string representation of the date.
206.260 + * @see java.text.DateFormat
206.261 + * @see java.util.Date#parse(java.lang.String)
206.262 + * @deprecated As of JDK version 1.1,
206.263 + * replaced by <code>DateFormat.parse(String s)</code>.
206.264 + */
206.265 + @Deprecated
206.266 + public Date(String s) {
206.267 + this(parse(s));
206.268 + }
206.269 +
206.270 + /**
206.271 + * Return a copy of this object.
206.272 + */
206.273 + public Object clone() {
206.274 + Date d = null;
206.275 + try {
206.276 + d = (Date)super.clone();
206.277 + if (cdate != null) {
206.278 + d.cdate = (BaseCalendar.Datum) cdate.clone();
206.279 + }
206.280 + } catch (CloneNotSupportedException e) {} // Won't happen
206.281 + return d;
206.282 + }
206.283 +
206.284 + /**
206.285 + * Determines the date and time based on the arguments. The
206.286 + * arguments are interpreted as a year, month, day of the month,
206.287 + * hour of the day, minute within the hour, and second within the
206.288 + * minute, exactly as for the <tt>Date</tt> constructor with six
206.289 + * arguments, except that the arguments are interpreted relative
206.290 + * to UTC rather than to the local time zone. The time indicated is
206.291 + * returned represented as the distance, measured in milliseconds,
206.292 + * of that time from the epoch (00:00:00 GMT on January 1, 1970).
206.293 + *
206.294 + * @param year the year minus 1900.
206.295 + * @param month the month between 0-11.
206.296 + * @param date the day of the month between 1-31.
206.297 + * @param hrs the hours between 0-23.
206.298 + * @param min the minutes between 0-59.
206.299 + * @param sec the seconds between 0-59.
206.300 + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT for
206.301 + * the date and time specified by the arguments.
206.302 + * @see java.util.Calendar
206.303 + * @deprecated As of JDK version 1.1,
206.304 + * replaced by <code>Calendar.set(year + 1900, month, date,
206.305 + * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
206.306 + * month, date, hrs, min, sec)</code>, using a UTC
206.307 + * <code>TimeZone</code>, followed by <code>Calendar.getTime().getTime()</code>.
206.308 + */
206.309 + @Deprecated
206.310 + public static long UTC(int year, int month, int date,
206.311 + int hrs, int min, int sec) {
206.312 + int y = year + 1900;
206.313 + // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
206.314 + if (month >= 12) {
206.315 + y += month / 12;
206.316 + month %= 12;
206.317 + } else if (month < 0) {
206.318 + y += month / 12;
206.319 + month = month % 12;
206.320 + }
206.321 + int m = month + 1;
206.322 + BaseCalendar cal = getCalendarSystem(y);
206.323 + BaseCalendar.Datum udate = (BaseCalendar.Datum) cal.newCalendarDate(null);
206.324 + udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
206.325 +
206.326 + // Use a Date instance to perform normalization. Its fastTime
206.327 + // is the UTC value after the normalization.
206.328 + Date d = new Date(0);
206.329 + d.normalize(udate);
206.330 + return d.fastTime;
206.331 + }
206.332 +
206.333 + /**
206.334 + * Attempts to interpret the string <tt>s</tt> as a representation
206.335 + * of a date and time. If the attempt is successful, the time
206.336 + * indicated is returned represented as the distance, measured in
206.337 + * milliseconds, of that time from the epoch (00:00:00 GMT on
206.338 + * January 1, 1970). If the attempt fails, an
206.339 + * <tt>IllegalArgumentException</tt> is thrown.
206.340 + * <p>
206.341 + * It accepts many syntaxes; in particular, it recognizes the IETF
206.342 + * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
206.343 + * understands the continental U.S. time-zone abbreviations, but for
206.344 + * general use, a time-zone offset should be used: "Sat, 12 Aug 1995
206.345 + * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
206.346 + * meridian). If no time zone is specified, the local time zone is
206.347 + * assumed. GMT and UTC are considered equivalent.
206.348 + * <p>
206.349 + * The string <tt>s</tt> is processed from left to right, looking for
206.350 + * data of interest. Any material in <tt>s</tt> that is within the
206.351 + * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored.
206.352 + * Parentheses may be nested. Otherwise, the only characters permitted
206.353 + * within <tt>s</tt> are these ASCII characters:
206.354 + * <blockquote><pre>
206.355 + * abcdefghijklmnopqrstuvwxyz
206.356 + * ABCDEFGHIJKLMNOPQRSTUVWXYZ
206.357 + * 0123456789,+-:/</pre></blockquote>
206.358 + * and whitespace characters.<p>
206.359 + * A consecutive sequence of decimal digits is treated as a decimal
206.360 + * number:<ul>
206.361 + * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year
206.362 + * has already been recognized, then the number is a time-zone
206.363 + * offset. If the number is less than 24, it is an offset measured
206.364 + * in hours. Otherwise, it is regarded as an offset in minutes,
206.365 + * expressed in 24-hour time format without punctuation. A
206.366 + * preceding <tt>-</tt> means a westward offset. Time zone offsets
206.367 + * are always relative to UTC (Greenwich). Thus, for example,
206.368 + * <tt>-5</tt> occurring in the string would mean "five hours west
206.369 + * of Greenwich" and <tt>+0430</tt> would mean "four hours and
206.370 + * thirty minutes east of Greenwich." It is permitted for the
206.371 + * string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt>
206.372 + * redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
206.373 + * <li>The number is regarded as a year number if one of the
206.374 + * following conditions is true:
206.375 + * <ul>
206.376 + * <li>The number is equal to or greater than 70 and followed by a
206.377 + * space, comma, slash, or end of string
206.378 + * <li>The number is less than 70, and both a month and a day of
206.379 + * the month have already been recognized</li>
206.380 + * </ul>
206.381 + * If the recognized year number is less than 100, it is
206.382 + * interpreted as an abbreviated year relative to a century of
206.383 + * which dates are within 80 years before and 19 years after
206.384 + * the time when the Date class is initialized.
206.385 + * After adjusting the year number, 1900 is subtracted from
206.386 + * it. For example, if the current year is 1999 then years in
206.387 + * the range 19 to 99 are assumed to mean 1919 to 1999, while
206.388 + * years from 0 to 18 are assumed to mean 2000 to 2018. Note
206.389 + * that this is slightly different from the interpretation of
206.390 + * years less than 100 that is used in {@link java.text.SimpleDateFormat}.
206.391 + * <li>If the number is followed by a colon, it is regarded as an hour,
206.392 + * unless an hour has already been recognized, in which case it is
206.393 + * regarded as a minute.
206.394 + * <li>If the number is followed by a slash, it is regarded as a month
206.395 + * (it is decreased by 1 to produce a number in the range <tt>0</tt>
206.396 + * to <tt>11</tt>), unless a month has already been recognized, in
206.397 + * which case it is regarded as a day of the month.
206.398 + * <li>If the number is followed by whitespace, a comma, a hyphen, or
206.399 + * end of string, then if an hour has been recognized but not a
206.400 + * minute, it is regarded as a minute; otherwise, if a minute has
206.401 + * been recognized but not a second, it is regarded as a second;
206.402 + * otherwise, it is regarded as a day of the month. </ul><p>
206.403 + * A consecutive sequence of letters is regarded as a word and treated
206.404 + * as follows:<ul>
206.405 + * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but
206.406 + * the parse fails if an hour has not been recognized or is less
206.407 + * than <tt>1</tt> or greater than <tt>12</tt>).
206.408 + * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt>
206.409 + * to the hour (but the parse fails if an hour has not been
206.410 + * recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
206.411 + * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY,
206.412 + * WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring
206.413 + * case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and
206.414 + * <tt>Thurs</tt> are ignored.
206.415 + * <li>Otherwise, any word that matches any prefix of <tt>JANUARY,
206.416 + * FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,
206.417 + * OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and
206.418 + * considering them in the order given here, is recognized as
206.419 + * specifying a month and is converted to a number (<tt>0</tt> to
206.420 + * <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and
206.421 + * <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which
206.422 + * is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
206.423 + * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring
206.424 + * case, is treated as referring to UTC.
206.425 + * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>,
206.426 + * ignoring case, is recognized as referring to the time zone in
206.427 + * North America that is five, six, seven, or eight hours west of
206.428 + * Greenwich, respectively. Any word that matches <tt>EDT, CDT,
206.429 + * MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as
206.430 + * referring to the same time zone, respectively, during daylight
206.431 + * saving time.</ul><p>
206.432 + * Once the entire string s has been scanned, it is converted to a time
206.433 + * result in one of two ways. If a time zone or time-zone offset has been
206.434 + * recognized, then the year, month, day of month, hour, minute, and
206.435 + * second are interpreted in UTC and then the time-zone offset is
206.436 + * applied. Otherwise, the year, month, day of month, hour, minute, and
206.437 + * second are interpreted in the local time zone.
206.438 + *
206.439 + * @param s a string to be parsed as a date.
206.440 + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
206.441 + * represented by the string argument.
206.442 + * @see java.text.DateFormat
206.443 + * @deprecated As of JDK version 1.1,
206.444 + * replaced by <code>DateFormat.parse(String s)</code>.
206.445 + */
206.446 + @Deprecated
206.447 + public static long parse(String s) {
206.448 + int year = Integer.MIN_VALUE;
206.449 + int mon = -1;
206.450 + int mday = -1;
206.451 + int hour = -1;
206.452 + int min = -1;
206.453 + int sec = -1;
206.454 + int millis = -1;
206.455 + int c = -1;
206.456 + int i = 0;
206.457 + int n = -1;
206.458 + int wst = -1;
206.459 + int tzoffset = -1;
206.460 + int prevc = 0;
206.461 + syntax:
206.462 + {
206.463 + if (s == null)
206.464 + break syntax;
206.465 + int limit = s.length();
206.466 + while (i < limit) {
206.467 + c = s.charAt(i);
206.468 + i++;
206.469 + if (c <= ' ' || c == ',')
206.470 + continue;
206.471 + if (c == '(') { // skip comments
206.472 + int depth = 1;
206.473 + while (i < limit) {
206.474 + c = s.charAt(i);
206.475 + i++;
206.476 + if (c == '(') depth++;
206.477 + else if (c == ')')
206.478 + if (--depth <= 0)
206.479 + break;
206.480 + }
206.481 + continue;
206.482 + }
206.483 + if ('0' <= c && c <= '9') {
206.484 + n = c - '0';
206.485 + while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
206.486 + n = n * 10 + c - '0';
206.487 + i++;
206.488 + }
206.489 + if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
206.490 + // timezone offset
206.491 + if (n < 24)
206.492 + n = n * 60; // EG. "GMT-3"
206.493 + else
206.494 + n = n % 100 + n / 100 * 60; // eg "GMT-0430"
206.495 + if (prevc == '+') // plus means east of GMT
206.496 + n = -n;
206.497 + if (tzoffset != 0 && tzoffset != -1)
206.498 + break syntax;
206.499 + tzoffset = n;
206.500 + } else if (n >= 70)
206.501 + if (year != Integer.MIN_VALUE)
206.502 + break syntax;
206.503 + else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
206.504 + // year = n < 1900 ? n : n - 1900;
206.505 + year = n;
206.506 + else
206.507 + break syntax;
206.508 + else if (c == ':')
206.509 + if (hour < 0)
206.510 + hour = (byte) n;
206.511 + else if (min < 0)
206.512 + min = (byte) n;
206.513 + else
206.514 + break syntax;
206.515 + else if (c == '/')
206.516 + if (mon < 0)
206.517 + mon = (byte) (n - 1);
206.518 + else if (mday < 0)
206.519 + mday = (byte) n;
206.520 + else
206.521 + break syntax;
206.522 + else if (i < limit && c != ',' && c > ' ' && c != '-')
206.523 + break syntax;
206.524 + else if (hour >= 0 && min < 0)
206.525 + min = (byte) n;
206.526 + else if (min >= 0 && sec < 0)
206.527 + sec = (byte) n;
206.528 + else if (mday < 0)
206.529 + mday = (byte) n;
206.530 + // Handle two-digit years < 70 (70-99 handled above).
206.531 + else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
206.532 + year = n;
206.533 + else
206.534 + break syntax;
206.535 + prevc = 0;
206.536 + } else if (c == '/' || c == ':' || c == '+' || c == '-')
206.537 + prevc = c;
206.538 + else {
206.539 + int st = i - 1;
206.540 + while (i < limit) {
206.541 + c = s.charAt(i);
206.542 + if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
206.543 + break;
206.544 + i++;
206.545 + }
206.546 + if (i <= st + 1)
206.547 + break syntax;
206.548 + int k;
206.549 + for (k = wtb.length; --k >= 0;)
206.550 + if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
206.551 + int action = ttb[k];
206.552 + if (action != 0) {
206.553 + if (action == 1) { // pm
206.554 + if (hour > 12 || hour < 1)
206.555 + break syntax;
206.556 + else if (hour < 12)
206.557 + hour += 12;
206.558 + } else if (action == 14) { // am
206.559 + if (hour > 12 || hour < 1)
206.560 + break syntax;
206.561 + else if (hour == 12)
206.562 + hour = 0;
206.563 + } else if (action <= 13) { // month!
206.564 + if (mon < 0)
206.565 + mon = (byte) (action - 2);
206.566 + else
206.567 + break syntax;
206.568 + } else {
206.569 + tzoffset = action - 10000;
206.570 + }
206.571 + }
206.572 + break;
206.573 + }
206.574 + if (k < 0)
206.575 + break syntax;
206.576 + prevc = 0;
206.577 + }
206.578 + }
206.579 + if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
206.580 + break syntax;
206.581 + // Parse 2-digit years within the correct default century.
206.582 + if (year < 100) {
206.583 + synchronized (Date.class) {
206.584 + if (defaultCenturyStart == 0) {
206.585 + defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
206.586 + }
206.587 + }
206.588 + year += (defaultCenturyStart / 100) * 100;
206.589 + if (year < defaultCenturyStart) year += 100;
206.590 + }
206.591 + if (sec < 0)
206.592 + sec = 0;
206.593 + if (min < 0)
206.594 + min = 0;
206.595 + if (hour < 0)
206.596 + hour = 0;
206.597 + BaseCalendar cal = getCalendarSystem(year);
206.598 + if (tzoffset == -1) { // no time zone specified, have to use local
206.599 + BaseCalendar.Datum ldate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.getDefaultRef());
206.600 + ldate.setDate(year, mon + 1, mday);
206.601 + ldate.setTimeOfDay(hour, min, sec, 0);
206.602 + return cal.getTime(ldate);
206.603 + }
206.604 + BaseCalendar.Datum udate = (BaseCalendar.Datum) cal.newCalendarDate(null); // no time zone
206.605 + udate.setDate(year, mon + 1, mday);
206.606 + udate.setTimeOfDay(hour, min, sec, 0);
206.607 + return cal.getTime(udate) + tzoffset * (60 * 1000);
206.608 + }
206.609 + // syntax error
206.610 + throw new IllegalArgumentException();
206.611 + }
206.612 + private final static String wtb[] = {
206.613 + "am", "pm",
206.614 + "monday", "tuesday", "wednesday", "thursday", "friday",
206.615 + "saturday", "sunday",
206.616 + "january", "february", "march", "april", "may", "june",
206.617 + "july", "august", "september", "october", "november", "december",
206.618 + "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
206.619 + "mst", "mdt", "pst", "pdt"
206.620 + };
206.621 + private final static int ttb[] = {
206.622 + 14, 1, 0, 0, 0, 0, 0, 0, 0,
206.623 + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
206.624 + 10000 + 0, 10000 + 0, 10000 + 0, // GMT/UT/UTC
206.625 + 10000 + 5 * 60, 10000 + 4 * 60, // EST/EDT
206.626 + 10000 + 6 * 60, 10000 + 5 * 60, // CST/CDT
206.627 + 10000 + 7 * 60, 10000 + 6 * 60, // MST/MDT
206.628 + 10000 + 8 * 60, 10000 + 7 * 60 // PST/PDT
206.629 + };
206.630 +
206.631 + /**
206.632 + * Returns a value that is the result of subtracting 1900 from the
206.633 + * year that contains or begins with the instant in time represented
206.634 + * by this <code>Date</code> object, as interpreted in the local
206.635 + * time zone.
206.636 + *
206.637 + * @return the year represented by this date, minus 1900.
206.638 + * @see java.util.Calendar
206.639 + * @deprecated As of JDK version 1.1,
206.640 + * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
206.641 + */
206.642 + @Deprecated
206.643 + public int getYear() {
206.644 + return normalize().getYear() - 1900;
206.645 + }
206.646 +
206.647 + /**
206.648 + * Sets the year of this <tt>Date</tt> object to be the specified
206.649 + * value plus 1900. This <code>Date</code> object is modified so
206.650 + * that it represents a point in time within the specified year,
206.651 + * with the month, date, hour, minute, and second the same as
206.652 + * before, as interpreted in the local time zone. (Of course, if
206.653 + * the date was February 29, for example, and the year is set to a
206.654 + * non-leap year, then the new date will be treated as if it were
206.655 + * on March 1.)
206.656 + *
206.657 + * @param year the year value.
206.658 + * @see java.util.Calendar
206.659 + * @deprecated As of JDK version 1.1,
206.660 + * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
206.661 + */
206.662 + @Deprecated
206.663 + public void setYear(int year) {
206.664 + getCalendarDate().setNormalizedYear(year + 1900);
206.665 + }
206.666 +
206.667 + /**
206.668 + * Returns a number representing the month that contains or begins
206.669 + * with the instant in time represented by this <tt>Date</tt> object.
206.670 + * The value returned is between <code>0</code> and <code>11</code>,
206.671 + * with the value <code>0</code> representing January.
206.672 + *
206.673 + * @return the month represented by this date.
206.674 + * @see java.util.Calendar
206.675 + * @deprecated As of JDK version 1.1,
206.676 + * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
206.677 + */
206.678 + @Deprecated
206.679 + public int getMonth() {
206.680 + return normalize().getMonth() - 1; // adjust 1-based to 0-based
206.681 + }
206.682 +
206.683 + /**
206.684 + * Sets the month of this date to the specified value. This
206.685 + * <tt>Date</tt> object is modified so that it represents a point
206.686 + * in time within the specified month, with the year, date, hour,
206.687 + * minute, and second the same as before, as interpreted in the
206.688 + * local time zone. If the date was October 31, for example, and
206.689 + * the month is set to June, then the new date will be treated as
206.690 + * if it were on July 1, because June has only 30 days.
206.691 + *
206.692 + * @param month the month value between 0-11.
206.693 + * @see java.util.Calendar
206.694 + * @deprecated As of JDK version 1.1,
206.695 + * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
206.696 + */
206.697 + @Deprecated
206.698 + public void setMonth(int month) {
206.699 + int y = 0;
206.700 + if (month >= 12) {
206.701 + y = month / 12;
206.702 + month %= 12;
206.703 + } else if (month < 0) {
206.704 + y = month / 12;
206.705 + month = month % 12;
206.706 + }
206.707 + BaseCalendar.Datum d = getCalendarDate();
206.708 + if (y != 0) {
206.709 + d.setNormalizedYear(d.getNormalizedYear() + y);
206.710 + }
206.711 + d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
206.712 + }
206.713 +
206.714 + /**
206.715 + * Returns the day of the month represented by this <tt>Date</tt> object.
206.716 + * The value returned is between <code>1</code> and <code>31</code>
206.717 + * representing the day of the month that contains or begins with the
206.718 + * instant in time represented by this <tt>Date</tt> object, as
206.719 + * interpreted in the local time zone.
206.720 + *
206.721 + * @return the day of the month represented by this date.
206.722 + * @see java.util.Calendar
206.723 + * @deprecated As of JDK version 1.1,
206.724 + * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
206.725 + * @deprecated
206.726 + */
206.727 + @Deprecated
206.728 + public int getDate() {
206.729 + return normalize().getDayOfMonth();
206.730 + }
206.731 +
206.732 + /**
206.733 + * Sets the day of the month of this <tt>Date</tt> object to the
206.734 + * specified value. This <tt>Date</tt> object is modified so that
206.735 + * it represents a point in time within the specified day of the
206.736 + * month, with the year, month, hour, minute, and second the same
206.737 + * as before, as interpreted in the local time zone. If the date
206.738 + * was April 30, for example, and the date is set to 31, then it
206.739 + * will be treated as if it were on May 1, because April has only
206.740 + * 30 days.
206.741 + *
206.742 + * @param date the day of the month value between 1-31.
206.743 + * @see java.util.Calendar
206.744 + * @deprecated As of JDK version 1.1,
206.745 + * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
206.746 + */
206.747 + @Deprecated
206.748 + public void setDate(int date) {
206.749 + getCalendarDate().setDayOfMonth(date);
206.750 + }
206.751 +
206.752 + /**
206.753 + * Returns the day of the week represented by this date. The
206.754 + * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday,
206.755 + * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> =
206.756 + * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday)
206.757 + * represents the day of the week that contains or begins with
206.758 + * the instant in time represented by this <tt>Date</tt> object,
206.759 + * as interpreted in the local time zone.
206.760 + *
206.761 + * @return the day of the week represented by this date.
206.762 + * @see java.util.Calendar
206.763 + * @deprecated As of JDK version 1.1,
206.764 + * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
206.765 + */
206.766 + @Deprecated
206.767 + public int getDay() {
206.768 + return normalize().getDayOfWeek() - 7;//gcal.SUNDAY;
206.769 + }
206.770 +
206.771 + /**
206.772 + * Returns the hour represented by this <tt>Date</tt> object. The
206.773 + * returned value is a number (<tt>0</tt> through <tt>23</tt>)
206.774 + * representing the hour within the day that contains or begins
206.775 + * with the instant in time represented by this <tt>Date</tt>
206.776 + * object, as interpreted in the local time zone.
206.777 + *
206.778 + * @return the hour represented by this date.
206.779 + * @see java.util.Calendar
206.780 + * @deprecated As of JDK version 1.1,
206.781 + * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
206.782 + */
206.783 + @Deprecated
206.784 + public int getHours() {
206.785 + return normalize().getHours();
206.786 + }
206.787 +
206.788 + /**
206.789 + * Sets the hour of this <tt>Date</tt> object to the specified value.
206.790 + * This <tt>Date</tt> object is modified so that it represents a point
206.791 + * in time within the specified hour of the day, with the year, month,
206.792 + * date, minute, and second the same as before, as interpreted in the
206.793 + * local time zone.
206.794 + *
206.795 + * @param hours the hour value.
206.796 + * @see java.util.Calendar
206.797 + * @deprecated As of JDK version 1.1,
206.798 + * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
206.799 + */
206.800 + @Deprecated
206.801 + public void setHours(int hours) {
206.802 + getCalendarDate().setHours(hours);
206.803 + }
206.804 +
206.805 + /**
206.806 + * Returns the number of minutes past the hour represented by this date,
206.807 + * as interpreted in the local time zone.
206.808 + * The value returned is between <code>0</code> and <code>59</code>.
206.809 + *
206.810 + * @return the number of minutes past the hour represented by this date.
206.811 + * @see java.util.Calendar
206.812 + * @deprecated As of JDK version 1.1,
206.813 + * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
206.814 + */
206.815 + @Deprecated
206.816 + public int getMinutes() {
206.817 + return normalize().getMinutes();
206.818 + }
206.819 +
206.820 + /**
206.821 + * Sets the minutes of this <tt>Date</tt> object to the specified value.
206.822 + * This <tt>Date</tt> object is modified so that it represents a point
206.823 + * in time within the specified minute of the hour, with the year, month,
206.824 + * date, hour, and second the same as before, as interpreted in the
206.825 + * local time zone.
206.826 + *
206.827 + * @param minutes the value of the minutes.
206.828 + * @see java.util.Calendar
206.829 + * @deprecated As of JDK version 1.1,
206.830 + * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
206.831 + */
206.832 + @Deprecated
206.833 + public void setMinutes(int minutes) {
206.834 + getCalendarDate().setMinutes(minutes);
206.835 + }
206.836 +
206.837 + /**
206.838 + * Returns the number of seconds past the minute represented by this date.
206.839 + * The value returned is between <code>0</code> and <code>61</code>. The
206.840 + * values <code>60</code> and <code>61</code> can only occur on those
206.841 + * Java Virtual Machines that take leap seconds into account.
206.842 + *
206.843 + * @return the number of seconds past the minute represented by this date.
206.844 + * @see java.util.Calendar
206.845 + * @deprecated As of JDK version 1.1,
206.846 + * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
206.847 + */
206.848 + @Deprecated
206.849 + public int getSeconds() {
206.850 + return normalize().getSeconds();
206.851 + }
206.852 +
206.853 + /**
206.854 + * Sets the seconds of this <tt>Date</tt> to the specified value.
206.855 + * This <tt>Date</tt> object is modified so that it represents a
206.856 + * point in time within the specified second of the minute, with
206.857 + * the year, month, date, hour, and minute the same as before, as
206.858 + * interpreted in the local time zone.
206.859 + *
206.860 + * @param seconds the seconds value.
206.861 + * @see java.util.Calendar
206.862 + * @deprecated As of JDK version 1.1,
206.863 + * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>.
206.864 + */
206.865 + @Deprecated
206.866 + public void setSeconds(int seconds) {
206.867 + getCalendarDate().setSeconds(seconds);
206.868 + }
206.869 +
206.870 + /**
206.871 + * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
206.872 + * represented by this <tt>Date</tt> object.
206.873 + *
206.874 + * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT
206.875 + * represented by this date.
206.876 + */
206.877 + public long getTime() {
206.878 + return getTimeImpl();
206.879 + }
206.880 +
206.881 + private final long getTimeImpl() {
206.882 + if (cdate != null && !cdate.isNormalized()) {
206.883 + normalize();
206.884 + }
206.885 + return fastTime;
206.886 + }
206.887 +
206.888 + /**
206.889 + * Sets this <code>Date</code> object to represent a point in time that is
206.890 + * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT.
206.891 + *
206.892 + * @param time the number of milliseconds.
206.893 + */
206.894 + public void setTime(long time) {
206.895 + fastTime = time;
206.896 + cdate = null;
206.897 + }
206.898 +
206.899 + /**
206.900 + * Tests if this date is before the specified date.
206.901 + *
206.902 + * @param when a date.
206.903 + * @return <code>true</code> if and only if the instant of time
206.904 + * represented by this <tt>Date</tt> object is strictly
206.905 + * earlier than the instant represented by <tt>when</tt>;
206.906 + * <code>false</code> otherwise.
206.907 + * @exception NullPointerException if <code>when</code> is null.
206.908 + */
206.909 + public boolean before(Date when) {
206.910 + return getMillisOf(this) < getMillisOf(when);
206.911 + }
206.912 +
206.913 + /**
206.914 + * Tests if this date is after the specified date.
206.915 + *
206.916 + * @param when a date.
206.917 + * @return <code>true</code> if and only if the instant represented
206.918 + * by this <tt>Date</tt> object is strictly later than the
206.919 + * instant represented by <tt>when</tt>;
206.920 + * <code>false</code> otherwise.
206.921 + * @exception NullPointerException if <code>when</code> is null.
206.922 + */
206.923 + public boolean after(Date when) {
206.924 + return getMillisOf(this) > getMillisOf(when);
206.925 + }
206.926 +
206.927 + /**
206.928 + * Compares two dates for equality.
206.929 + * The result is <code>true</code> if and only if the argument is
206.930 + * not <code>null</code> and is a <code>Date</code> object that
206.931 + * represents the same point in time, to the millisecond, as this object.
206.932 + * <p>
206.933 + * Thus, two <code>Date</code> objects are equal if and only if the
206.934 + * <code>getTime</code> method returns the same <code>long</code>
206.935 + * value for both.
206.936 + *
206.937 + * @param obj the object to compare with.
206.938 + * @return <code>true</code> if the objects are the same;
206.939 + * <code>false</code> otherwise.
206.940 + * @see java.util.Date#getTime()
206.941 + */
206.942 + public boolean equals(Object obj) {
206.943 + return obj instanceof Date && getTime() == ((Date) obj).getTime();
206.944 + }
206.945 +
206.946 + /**
206.947 + * Returns the millisecond value of this <code>Date</code> object
206.948 + * without affecting its internal state.
206.949 + */
206.950 + static final long getMillisOf(Date date) {
206.951 + if (date.cdate == null || date.cdate.isNormalized()) {
206.952 + return date.fastTime;
206.953 + }
206.954 + BaseCalendar.Datum d = (BaseCalendar.Datum) date.cdate.clone();
206.955 + return gcal.getTime(d);
206.956 + }
206.957 +
206.958 + /**
206.959 + * Compares two Dates for ordering.
206.960 + *
206.961 + * @param anotherDate the <code>Date</code> to be compared.
206.962 + * @return the value <code>0</code> if the argument Date is equal to
206.963 + * this Date; a value less than <code>0</code> if this Date
206.964 + * is before the Date argument; and a value greater than
206.965 + * <code>0</code> if this Date is after the Date argument.
206.966 + * @since 1.2
206.967 + * @exception NullPointerException if <code>anotherDate</code> is null.
206.968 + */
206.969 + public int compareTo(Date anotherDate) {
206.970 + long thisTime = getMillisOf(this);
206.971 + long anotherTime = getMillisOf(anotherDate);
206.972 + return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
206.973 + }
206.974 +
206.975 + /**
206.976 + * Returns a hash code value for this object. The result is the
206.977 + * exclusive OR of the two halves of the primitive <tt>long</tt>
206.978 + * value returned by the {@link Date#getTime}
206.979 + * method. That is, the hash code is the value of the expression:
206.980 + * <blockquote><pre>
206.981 + * (int)(this.getTime()^(this.getTime() >>> 32))</pre></blockquote>
206.982 + *
206.983 + * @return a hash code value for this object.
206.984 + */
206.985 + public int hashCode() {
206.986 + long ht = this.getTime();
206.987 + return (int) ht ^ (int) (ht >> 32);
206.988 + }
206.989 +
206.990 + /**
206.991 + * Converts this <code>Date</code> object to a <code>String</code>
206.992 + * of the form:
206.993 + * <blockquote><pre>
206.994 + * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
206.995 + * where:<ul>
206.996 + * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
206.997 + * Thu, Fri, Sat</tt>).
206.998 + * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
206.999 + * Jul, Aug, Sep, Oct, Nov, Dec</tt>).
206.1000 + * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
206.1001 + * <tt>31</tt>), as two decimal digits.
206.1002 + * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
206.1003 + * <tt>23</tt>), as two decimal digits.
206.1004 + * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
206.1005 + * <tt>59</tt>), as two decimal digits.
206.1006 + * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
206.1007 + * <tt>61</tt>, as two decimal digits.
206.1008 + * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
206.1009 + * time). Standard time zone abbreviations include those
206.1010 + * recognized by the method <tt>parse</tt>. If time zone
206.1011 + * information is not available, then <tt>zzz</tt> is empty -
206.1012 + * that is, it consists of no characters at all.
206.1013 + * <li><tt>yyyy</tt> is the year, as four decimal digits.
206.1014 + * </ul>
206.1015 + *
206.1016 + * @return a string representation of this date.
206.1017 + * @see java.util.Date#toLocaleString()
206.1018 + * @see java.util.Date#toGMTString()
206.1019 + */
206.1020 + public String toString() {
206.1021 + // "EEE MMM dd HH:mm:ss zzz yyyy";
206.1022 + BaseCalendar.Datum date = normalize();
206.1023 + StringBuilder sb = new StringBuilder(28);
206.1024 + int index = date.getDayOfWeek();
206.1025 + if (index == 7) {
206.1026 + index = 8;
206.1027 + }
206.1028 + convertToAbbr(sb, wtb[index]).append(' '); // EEE
206.1029 + convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
206.1030 +// CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
206.1031 +//
206.1032 +// CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
206.1033 +// CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
206.1034 +// CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
206.1035 +// TimeZone zi = date.getZone();
206.1036 +// if (zi != null) {
206.1037 +// sb.append(zi.getDisplayName(date.isDaylightTime(), zi.SHORT, Locale.US)); // zzz
206.1038 +// } else {
206.1039 +// sb.append("GMT");
206.1040 +// }
206.1041 + sb.append(' ').append(date.getYear()); // yyyy
206.1042 + return sb.toString();
206.1043 + }
206.1044 +
206.1045 + /**
206.1046 + * Converts the given name to its 3-letter abbreviation (e.g.,
206.1047 + * "monday" -> "Mon") and stored the abbreviation in the given
206.1048 + * <code>StringBuilder</code>.
206.1049 + */
206.1050 + private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
206.1051 + sb.append(Character.toUpperCase(name.charAt(0)));
206.1052 + sb.append(name.charAt(1)).append(name.charAt(2));
206.1053 + return sb;
206.1054 + }
206.1055 +
206.1056 + /**
206.1057 + * Creates a string representation of this <tt>Date</tt> object in an
206.1058 + * implementation-dependent form. The intent is that the form should
206.1059 + * be familiar to the user of the Java application, wherever it may
206.1060 + * happen to be running. The intent is comparable to that of the
206.1061 + * "<code>%c</code>" format supported by the <code>strftime()</code>
206.1062 + * function of ISO C.
206.1063 + *
206.1064 + * @return a string representation of this date, using the locale
206.1065 + * conventions.
206.1066 + * @see java.text.DateFormat
206.1067 + * @see java.util.Date#toString()
206.1068 + * @see java.util.Date#toGMTString()
206.1069 + * @deprecated As of JDK version 1.1,
206.1070 + * replaced by <code>DateFormat.format(Date date)</code>.
206.1071 + */
206.1072 + @Deprecated
206.1073 + public String toLocaleString() {
206.1074 + DateFormat formatter = DateFormat.getDateTimeInstance();
206.1075 + return formatter.format(this);
206.1076 + }
206.1077 +
206.1078 + /**
206.1079 + * Creates a string representation of this <tt>Date</tt> object of
206.1080 + * the form:
206.1081 + * <blockquote<pre>
206.1082 + * d mon yyyy hh:mm:ss GMT</pre></blockquote>
206.1083 + * where:<ul>
206.1084 + * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>),
206.1085 + * as one or two decimal digits.
206.1086 + * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul,
206.1087 + * Aug, Sep, Oct, Nov, Dec</tt>).
206.1088 + * <li><i>yyyy</i> is the year, as four decimal digits.
206.1089 + * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>),
206.1090 + * as two decimal digits.
206.1091 + * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through
206.1092 + * <tt>59</tt>), as two decimal digits.
206.1093 + * <li><i>ss</i> is the second within the minute (<tt>00</tt> through
206.1094 + * <tt>61</tt>), as two decimal digits.
206.1095 + * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate
206.1096 + * Greenwich Mean Time.
206.1097 + * </ul><p>
206.1098 + * The result does not depend on the local time zone.
206.1099 + *
206.1100 + * @return a string representation of this date, using the Internet GMT
206.1101 + * conventions.
206.1102 + * @see java.text.DateFormat
206.1103 + * @see java.util.Date#toString()
206.1104 + * @see java.util.Date#toLocaleString()
206.1105 + * @deprecated As of JDK version 1.1,
206.1106 + * replaced by <code>DateFormat.format(Date date)</code>, using a
206.1107 + * GMT <code>TimeZone</code>.
206.1108 + */
206.1109 + @Deprecated
206.1110 + public String toGMTString() {
206.1111 + // d MMM yyyy HH:mm:ss 'GMT'
206.1112 + long t = getTime();
206.1113 + BaseCalendar cal = getCalendarSystem(t);
206.1114 + StringBuilder sb = new StringBuilder(32);
206.1115 +// BaseCalendar.Datum date =
206.1116 +// (BaseCalendar.Datum) cal.getCalendarDate(getTime(), (TimeZone)null);
206.1117 +// CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
206.1118 +// convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' '); // MMM
206.1119 +// sb.append(date.getYear()).append(' '); // yyyy
206.1120 +// CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':'); // HH
206.1121 +// CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
206.1122 +// CalendarUtils.sprintf0d(sb, date.getSeconds(), 2); // ss
206.1123 + sb.append(" GMT"); // ' GMT'
206.1124 + return sb.toString();
206.1125 + }
206.1126 +
206.1127 + /**
206.1128 + * Returns the offset, measured in minutes, for the local time zone
206.1129 + * relative to UTC that is appropriate for the time represented by
206.1130 + * this <code>Date</code> object.
206.1131 + * <p>
206.1132 + * For example, in Massachusetts, five time zones west of Greenwich:
206.1133 + * <blockquote><pre>
206.1134 + * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
206.1135 + * because on February 14, 1996, standard time (Eastern Standard Time)
206.1136 + * is in use, which is offset five hours from UTC; but:
206.1137 + * <blockquote><pre>
206.1138 + * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
206.1139 + * because on June 1, 1996, daylight saving time (Eastern Daylight Time)
206.1140 + * is in use, which is offset only four hours from UTC.<p>
206.1141 + * This method produces the same result as if it computed:
206.1142 + * <blockquote><pre>
206.1143 + * (this.getTime() - UTC(this.getYear(),
206.1144 + * this.getMonth(),
206.1145 + * this.getDate(),
206.1146 + * this.getHours(),
206.1147 + * this.getMinutes(),
206.1148 + * this.getSeconds())) / (60 * 1000)
206.1149 + * </pre></blockquote>
206.1150 + *
206.1151 + * @return the time-zone offset, in minutes, for the current time zone.
206.1152 + * @see java.util.Calendar#ZONE_OFFSET
206.1153 + * @see java.util.Calendar#DST_OFFSET
206.1154 + * @see java.util.TimeZone#getDefault
206.1155 + * @deprecated As of JDK version 1.1,
206.1156 + * replaced by <code>-(Calendar.get(Calendar.ZONE_OFFSET) +
206.1157 + * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)</code>.
206.1158 + */
206.1159 + @Deprecated
206.1160 + public int getTimezoneOffset() {
206.1161 + int zoneOffset;
206.1162 + if (cdate == null) {
206.1163 + TimeZone tz = TimeZone.getDefaultRef();
206.1164 + zoneOffset = tz.getOffset(fastTime);
206.1165 + } else {
206.1166 + normalize();
206.1167 + zoneOffset = cdate.getZoneOffset();
206.1168 + }
206.1169 + return -zoneOffset/60000; // convert to minutes
206.1170 + }
206.1171 +
206.1172 + private final BaseCalendar.Datum getCalendarDate() {
206.1173 + if (cdate == null) {
206.1174 +// BaseCalendar cal = getCalendarSystem(fastTime);
206.1175 +// cdate = (BaseCalendar.Datum) cal.getCalendarDate(fastTime,
206.1176 +// TimeZone.getDefaultRef());
206.1177 + }
206.1178 + return cdate;
206.1179 + }
206.1180 +
206.1181 + private final BaseCalendar.Datum normalize() {
206.1182 + if (cdate == null) {
206.1183 +// BaseCalendar cal = getCalendarSystem(fastTime);
206.1184 +// cdate = (BaseCalendar.Datum) cal.getCalendarDate(fastTime,
206.1185 +// TimeZone.getDefaultRef());
206.1186 +// return cdate;
206.1187 + }
206.1188 +
206.1189 + // Normalize cdate with the TimeZone in cdate first. This is
206.1190 + // required for the compatible behavior.
206.1191 + if (!cdate.isNormalized()) {
206.1192 + cdate = normalize(cdate);
206.1193 + }
206.1194 +
206.1195 + // If the default TimeZone has changed, then recalculate the
206.1196 + // fields with the new TimeZone.
206.1197 + TimeZone tz = TimeZone.getDefaultRef();
206.1198 + if (tz != cdate.getZone()) {
206.1199 +// cdate.setZone(tz);
206.1200 +// CalendarSystem cal = getCalendarSystem(cdate);
206.1201 +// cal.getCalendarDate(fastTime, cdate);
206.1202 + }
206.1203 + return cdate;
206.1204 + }
206.1205 +
206.1206 + // fastTime and the returned data are in sync upon return.
206.1207 + private final BaseCalendar.Datum normalize(BaseCalendar.Datum date) {
206.1208 + int y = date.getNormalizedYear();
206.1209 + int m = date.getMonth();
206.1210 + int d = date.getDayOfMonth();
206.1211 + int hh = date.getHours();
206.1212 + int mm = date.getMinutes();
206.1213 + int ss = date.getSeconds();
206.1214 + int ms = date.getMillis();
206.1215 + TimeZone tz = date.getZone();
206.1216 +
206.1217 + // If the specified year can't be handled using a long value
206.1218 + // in milliseconds, GregorianCalendar is used for full
206.1219 + // compatibility with underflow and overflow. This is required
206.1220 + // by some JCK tests. The limits are based max year values -
206.1221 + // years that can be represented by max values of d, hh, mm,
206.1222 + // ss and ms. Also, let GregorianCalendar handle the default
206.1223 + // cutover year so that we don't need to worry about the
206.1224 + // transition here.
206.1225 +// if (y == 1582 || y > 280000000 || y < -280000000) {
206.1226 +// if (tz == null) {
206.1227 +// tz = TimeZone.getTimeZone("GMT");
206.1228 +// }
206.1229 +// GregorianCalendar gc = new GregorianCalendar(tz);
206.1230 +// gc.clear();
206.1231 +// gc.set(gc.MILLISECOND, ms);
206.1232 +// gc.set(y, m-1, d, hh, mm, ss);
206.1233 +// fastTime = gc.getTimeInMillis();
206.1234 +// BaseCalendar cal = getCalendarSystem(fastTime);
206.1235 +// date = (BaseCalendar.Datum) cal.getCalendarDate(fastTime, tz);
206.1236 +// return date;
206.1237 +// }
206.1238 +
206.1239 + BaseCalendar cal = getCalendarSystem(y);
206.1240 + if (cal != getCalendarSystem(date)) {
206.1241 + date = (BaseCalendar.Datum) cal.newCalendarDate(tz);
206.1242 + date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
206.1243 + }
206.1244 + // Perform the GregorianCalendar-style normalization.
206.1245 + fastTime = cal.getTime(date);
206.1246 +
206.1247 + // In case the normalized date requires the other calendar
206.1248 + // system, we need to recalculate it using the other one.
206.1249 + BaseCalendar ncal = getCalendarSystem(fastTime);
206.1250 + if (ncal != cal) {
206.1251 + date = (BaseCalendar.Datum) ncal.newCalendarDate(tz);
206.1252 + date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
206.1253 + fastTime = ncal.getTime(date);
206.1254 + }
206.1255 + return date;
206.1256 + }
206.1257 +
206.1258 + /**
206.1259 + * Returns the Gregorian or Julian calendar system to use with the
206.1260 + * given date. Use Gregorian from October 15, 1582.
206.1261 + *
206.1262 + * @param year normalized calendar year (not -1900)
206.1263 + * @return the CalendarSystem to use for the specified date
206.1264 + */
206.1265 + private static final BaseCalendar getCalendarSystem(int year) {
206.1266 + if (year >= 1582) {
206.1267 + return gcal;
206.1268 + }
206.1269 + return getJulianCalendar();
206.1270 + }
206.1271 +
206.1272 + private static final BaseCalendar getCalendarSystem(long utc) {
206.1273 + // Quickly check if the time stamp given by `utc' is the Epoch
206.1274 + // or later. If it's before 1970, we convert the cutover to
206.1275 + // local time to compare.
206.1276 +// if (utc >= 0
206.1277 +// || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
206.1278 +// - TimeZone.getDefaultRef().getOffset(utc)) {
206.1279 + return gcal;
206.1280 +// }
206.1281 +// return getJulianCalendar();
206.1282 + }
206.1283 +
206.1284 + private static final BaseCalendar getCalendarSystem(BaseCalendar.Datum cdate) {
206.1285 + if (jcal == null) {
206.1286 + return gcal;
206.1287 + }
206.1288 + if (cdate.getEra() != null) {
206.1289 + return jcal;
206.1290 + }
206.1291 + return gcal;
206.1292 + }
206.1293 +
206.1294 + synchronized private static final BaseCalendar getJulianCalendar() {
206.1295 + if (jcal == null) {
206.1296 +// jcal = (BaseCalendar) CalendarSystem.forName("julian");
206.1297 + }
206.1298 + return jcal;
206.1299 + }
206.1300 +
206.1301 + /**
206.1302 + * Save the state of this object to a stream (i.e., serialize it).
206.1303 + *
206.1304 + * @serialData The value returned by <code>getTime()</code>
206.1305 + * is emitted (long). This represents the offset from
206.1306 + * January 1, 1970, 00:00:00 GMT in milliseconds.
206.1307 + */
206.1308 + private void writeObject(ObjectOutputStream s)
206.1309 + throws IOException
206.1310 + {
206.1311 + s.writeLong(getTimeImpl());
206.1312 + }
206.1313 +
206.1314 + /**
206.1315 + * Reconstitute this object from a stream (i.e., deserialize it).
206.1316 + */
206.1317 + private void readObject(ObjectInputStream s)
206.1318 + throws IOException, ClassNotFoundException
206.1319 + {
206.1320 + fastTime = s.readLong();
206.1321 + }
206.1322 +
206.1323 + static final class BaseCalendar {
206.1324 + Datum newCalendarDate(TimeZone t) {
206.1325 + return new Datum();
206.1326 + }
206.1327 +
206.1328 + Datum getNthDayOfWeek(int a, int b, Datum c) {
206.1329 + return new Datum();
206.1330 + }
206.1331 +
206.1332 + Datum getCalendarDate() {
206.1333 + return new Datum();
206.1334 + }
206.1335 +
206.1336 + int getTime(Datum udate) {
206.1337 + return 0;
206.1338 + }
206.1339 +
206.1340 + int getMonthLength(Datum cdate) {
206.1341 + return 0;
206.1342 + }
206.1343 +
206.1344 + void getCalendarDate(long l, Datum cdate) {
206.1345 + }
206.1346 +
206.1347 + static class Datum implements Cloneable {
206.1348 + public Datum clone() {
206.1349 + return new Datum();
206.1350 + }
206.1351 +
206.1352 + Datum setNormalizedDate(int y, int i, int date) {
206.1353 + return this;
206.1354 + }
206.1355 +
206.1356 + void setTimeOfDay(int hrs, int min, int sec, int i) {
206.1357 + }
206.1358 +
206.1359 + int getYear() {
206.1360 + return 0;
206.1361 + }
206.1362 +
206.1363 + void setDate(int year, int i, int mday) {
206.1364 + }
206.1365 +
206.1366 + void setNormalizedYear(int i) {
206.1367 + }
206.1368 +
206.1369 + int getMonth() {
206.1370 + return 0;
206.1371 + }
206.1372 +
206.1373 + int getNormalizedYear() {
206.1374 + return 0;
206.1375 + }
206.1376 +
206.1377 + void setMonth(int i) {
206.1378 + }
206.1379 +
206.1380 + int getDayOfMonth() {
206.1381 + return 0;
206.1382 + }
206.1383 +
206.1384 + void setDayOfMonth(int date) {
206.1385 + }
206.1386 +
206.1387 + int getDayOfWeek() {
206.1388 + return 0;
206.1389 + }
206.1390 +
206.1391 + int getHours() {
206.1392 + return 0;
206.1393 + }
206.1394 +
206.1395 + void setHours(int hours) {
206.1396 + }
206.1397 +
206.1398 + int getMinutes() {
206.1399 + return 0;
206.1400 + }
206.1401 +
206.1402 + void setMinutes(int minutes) {
206.1403 + }
206.1404 +
206.1405 + int getSeconds() {
206.1406 + return 0;
206.1407 + }
206.1408 +
206.1409 + void setSeconds(int seconds) {
206.1410 + }
206.1411 +
206.1412 + boolean isNormalized() {
206.1413 + return false;
206.1414 + }
206.1415 +
206.1416 + Object getEra() {
206.1417 + return this;
206.1418 + }
206.1419 +
206.1420 + int getMillis() {
206.1421 + return 0;
206.1422 + }
206.1423 +
206.1424 + TimeZone getZone() {
206.1425 + return TimeZone.NO_TIMEZONE;
206.1426 + }
206.1427 +
206.1428 + int getZoneOffset() {
206.1429 + return 0;
206.1430 + }
206.1431 + }
206.1432 + }
206.1433 +}
207.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
207.2 +++ b/rt/emul/compact/src/main/java/java/util/EnumMap.java Wed Apr 30 15:04:10 2014 +0200
207.3 @@ -0,0 +1,797 @@
207.4 +/*
207.5 + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
207.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
207.7 + *
207.8 + * This code is free software; you can redistribute it and/or modify it
207.9 + * under the terms of the GNU General Public License version 2 only, as
207.10 + * published by the Free Software Foundation. Oracle designates this
207.11 + * particular file as subject to the "Classpath" exception as provided
207.12 + * by Oracle in the LICENSE file that accompanied this code.
207.13 + *
207.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
207.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
207.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
207.17 + * version 2 for more details (a copy is included in the LICENSE file that
207.18 + * accompanied this code).
207.19 + *
207.20 + * You should have received a copy of the GNU General Public License version
207.21 + * 2 along with this work; if not, write to the Free Software Foundation,
207.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
207.23 + *
207.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
207.25 + * or visit www.oracle.com if you need additional information or have any
207.26 + * questions.
207.27 + */
207.28 +
207.29 +package java.util;
207.30 +
207.31 +import java.util.Map.Entry;
207.32 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
207.33 +
207.34 +/**
207.35 + * A specialized {@link Map} implementation for use with enum type keys. All
207.36 + * of the keys in an enum map must come from a single enum type that is
207.37 + * specified, explicitly or implicitly, when the map is created. Enum maps
207.38 + * are represented internally as arrays. This representation is extremely
207.39 + * compact and efficient.
207.40 + *
207.41 + * <p>Enum maps are maintained in the <i>natural order</i> of their keys
207.42 + * (the order in which the enum constants are declared). This is reflected
207.43 + * in the iterators returned by the collections views ({@link #keySet()},
207.44 + * {@link #entrySet()}, and {@link #values()}).
207.45 + *
207.46 + * <p>Iterators returned by the collection views are <i>weakly consistent</i>:
207.47 + * they will never throw {@link ConcurrentModificationException} and they may
207.48 + * or may not show the effects of any modifications to the map that occur while
207.49 + * the iteration is in progress.
207.50 + *
207.51 + * <p>Null keys are not permitted. Attempts to insert a null key will
207.52 + * throw {@link NullPointerException}. Attempts to test for the
207.53 + * presence of a null key or to remove one will, however, function properly.
207.54 + * Null values are permitted.
207.55 +
207.56 + * <P>Like most collection implementations <tt>EnumMap</tt> is not
207.57 + * synchronized. If multiple threads access an enum map concurrently, and at
207.58 + * least one of the threads modifies the map, it should be synchronized
207.59 + * externally. This is typically accomplished by synchronizing on some
207.60 + * object that naturally encapsulates the enum map. If no such object exists,
207.61 + * the map should be "wrapped" using the {@link Collections#synchronizedMap}
207.62 + * method. This is best done at creation time, to prevent accidental
207.63 + * unsynchronized access:
207.64 + *
207.65 + * <pre>
207.66 + * Map<EnumKey, V> m
207.67 + * = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));
207.68 + * </pre>
207.69 + *
207.70 + * <p>Implementation note: All basic operations execute in constant time.
207.71 + * They are likely (though not guaranteed) to be faster than their
207.72 + * {@link HashMap} counterparts.
207.73 + *
207.74 + * <p>This class is a member of the
207.75 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
207.76 + * Java Collections Framework</a>.
207.77 + *
207.78 + * @author Josh Bloch
207.79 + * @see EnumSet
207.80 + * @since 1.5
207.81 + */
207.82 +public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
207.83 + implements java.io.Serializable, Cloneable
207.84 +{
207.85 + /**
207.86 + * The <tt>Class</tt> object for the enum type of all the keys of this map.
207.87 + *
207.88 + * @serial
207.89 + */
207.90 + private final Class<K> keyType;
207.91 +
207.92 + /**
207.93 + * All of the values comprising K. (Cached for performance.)
207.94 + */
207.95 + private transient K[] keyUniverse;
207.96 +
207.97 + /**
207.98 + * Array representation of this map. The ith element is the value
207.99 + * to which universe[i] is currently mapped, or null if it isn't
207.100 + * mapped to anything, or NULL if it's mapped to null.
207.101 + */
207.102 + private transient Object[] vals;
207.103 +
207.104 + /**
207.105 + * The number of mappings in this map.
207.106 + */
207.107 + private transient int size = 0;
207.108 +
207.109 + /**
207.110 + * Distinguished non-null value for representing null values.
207.111 + */
207.112 + private static final Object NULL = new Integer(0);
207.113 +
207.114 + private Object maskNull(Object value) {
207.115 + return (value == null ? NULL : value);
207.116 + }
207.117 +
207.118 + private V unmaskNull(Object value) {
207.119 + return (V) (value == NULL ? null : value);
207.120 + }
207.121 +
207.122 + private static final Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
207.123 +
207.124 + /**
207.125 + * Creates an empty enum map with the specified key type.
207.126 + *
207.127 + * @param keyType the class object of the key type for this enum map
207.128 + * @throws NullPointerException if <tt>keyType</tt> is null
207.129 + */
207.130 + public EnumMap(Class<K> keyType) {
207.131 + this.keyType = keyType;
207.132 + keyUniverse = getKeyUniverse(keyType);
207.133 + vals = new Object[keyUniverse.length];
207.134 + }
207.135 +
207.136 + /**
207.137 + * Creates an enum map with the same key type as the specified enum
207.138 + * map, initially containing the same mappings (if any).
207.139 + *
207.140 + * @param m the enum map from which to initialize this enum map
207.141 + * @throws NullPointerException if <tt>m</tt> is null
207.142 + */
207.143 + public EnumMap(EnumMap<K, ? extends V> m) {
207.144 + keyType = m.keyType;
207.145 + keyUniverse = m.keyUniverse;
207.146 + vals = m.vals.clone();
207.147 + size = m.size;
207.148 + }
207.149 +
207.150 + /**
207.151 + * Creates an enum map initialized from the specified map. If the
207.152 + * specified map is an <tt>EnumMap</tt> instance, this constructor behaves
207.153 + * identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map
207.154 + * must contain at least one mapping (in order to determine the new
207.155 + * enum map's key type).
207.156 + *
207.157 + * @param m the map from which to initialize this enum map
207.158 + * @throws IllegalArgumentException if <tt>m</tt> is not an
207.159 + * <tt>EnumMap</tt> instance and contains no mappings
207.160 + * @throws NullPointerException if <tt>m</tt> is null
207.161 + */
207.162 + public EnumMap(Map<K, ? extends V> m) {
207.163 + if (m instanceof EnumMap) {
207.164 + EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
207.165 + keyType = em.keyType;
207.166 + keyUniverse = em.keyUniverse;
207.167 + vals = em.vals.clone();
207.168 + size = em.size;
207.169 + } else {
207.170 + if (m.isEmpty())
207.171 + throw new IllegalArgumentException("Specified map is empty");
207.172 + keyType = m.keySet().iterator().next().getDeclaringClass();
207.173 + keyUniverse = getKeyUniverse(keyType);
207.174 + vals = new Object[keyUniverse.length];
207.175 + putAll(m);
207.176 + }
207.177 + }
207.178 +
207.179 + // Query Operations
207.180 +
207.181 + /**
207.182 + * Returns the number of key-value mappings in this map.
207.183 + *
207.184 + * @return the number of key-value mappings in this map
207.185 + */
207.186 + public int size() {
207.187 + return size;
207.188 + }
207.189 +
207.190 + /**
207.191 + * Returns <tt>true</tt> if this map maps one or more keys to the
207.192 + * specified value.
207.193 + *
207.194 + * @param value the value whose presence in this map is to be tested
207.195 + * @return <tt>true</tt> if this map maps one or more keys to this value
207.196 + */
207.197 + public boolean containsValue(Object value) {
207.198 + value = maskNull(value);
207.199 +
207.200 + for (Object val : vals)
207.201 + if (value.equals(val))
207.202 + return true;
207.203 +
207.204 + return false;
207.205 + }
207.206 +
207.207 + /**
207.208 + * Returns <tt>true</tt> if this map contains a mapping for the specified
207.209 + * key.
207.210 + *
207.211 + * @param key the key whose presence in this map is to be tested
207.212 + * @return <tt>true</tt> if this map contains a mapping for the specified
207.213 + * key
207.214 + */
207.215 + public boolean containsKey(Object key) {
207.216 + return isValidKey(key) && vals[((Enum)key).ordinal()] != null;
207.217 + }
207.218 +
207.219 + private boolean containsMapping(Object key, Object value) {
207.220 + return isValidKey(key) &&
207.221 + maskNull(value).equals(vals[((Enum)key).ordinal()]);
207.222 + }
207.223 +
207.224 + /**
207.225 + * Returns the value to which the specified key is mapped,
207.226 + * or {@code null} if this map contains no mapping for the key.
207.227 + *
207.228 + * <p>More formally, if this map contains a mapping from a key
207.229 + * {@code k} to a value {@code v} such that {@code (key == k)},
207.230 + * then this method returns {@code v}; otherwise it returns
207.231 + * {@code null}. (There can be at most one such mapping.)
207.232 + *
207.233 + * <p>A return value of {@code null} does not <i>necessarily</i>
207.234 + * indicate that the map contains no mapping for the key; it's also
207.235 + * possible that the map explicitly maps the key to {@code null}.
207.236 + * The {@link #containsKey containsKey} operation may be used to
207.237 + * distinguish these two cases.
207.238 + */
207.239 + public V get(Object key) {
207.240 + return (isValidKey(key) ?
207.241 + unmaskNull(vals[((Enum)key).ordinal()]) : null);
207.242 + }
207.243 +
207.244 + // Modification Operations
207.245 +
207.246 + /**
207.247 + * Associates the specified value with the specified key in this map.
207.248 + * If the map previously contained a mapping for this key, the old
207.249 + * value is replaced.
207.250 + *
207.251 + * @param key the key with which the specified value is to be associated
207.252 + * @param value the value to be associated with the specified key
207.253 + *
207.254 + * @return the previous value associated with specified key, or
207.255 + * <tt>null</tt> if there was no mapping for key. (A <tt>null</tt>
207.256 + * return can also indicate that the map previously associated
207.257 + * <tt>null</tt> with the specified key.)
207.258 + * @throws NullPointerException if the specified key is null
207.259 + */
207.260 + public V put(K key, V value) {
207.261 + typeCheck(key);
207.262 +
207.263 + int index = key.ordinal();
207.264 + Object oldValue = vals[index];
207.265 + vals[index] = maskNull(value);
207.266 + if (oldValue == null)
207.267 + size++;
207.268 + return unmaskNull(oldValue);
207.269 + }
207.270 +
207.271 + /**
207.272 + * Removes the mapping for this key from this map if present.
207.273 + *
207.274 + * @param key the key whose mapping is to be removed from the map
207.275 + * @return the previous value associated with specified key, or
207.276 + * <tt>null</tt> if there was no entry for key. (A <tt>null</tt>
207.277 + * return can also indicate that the map previously associated
207.278 + * <tt>null</tt> with the specified key.)
207.279 + */
207.280 + public V remove(Object key) {
207.281 + if (!isValidKey(key))
207.282 + return null;
207.283 + int index = ((Enum)key).ordinal();
207.284 + Object oldValue = vals[index];
207.285 + vals[index] = null;
207.286 + if (oldValue != null)
207.287 + size--;
207.288 + return unmaskNull(oldValue);
207.289 + }
207.290 +
207.291 + private boolean removeMapping(Object key, Object value) {
207.292 + if (!isValidKey(key))
207.293 + return false;
207.294 + int index = ((Enum)key).ordinal();
207.295 + if (maskNull(value).equals(vals[index])) {
207.296 + vals[index] = null;
207.297 + size--;
207.298 + return true;
207.299 + }
207.300 + return false;
207.301 + }
207.302 +
207.303 + /**
207.304 + * Returns true if key is of the proper type to be a key in this
207.305 + * enum map.
207.306 + */
207.307 + private boolean isValidKey(Object key) {
207.308 + if (key == null)
207.309 + return false;
207.310 +
207.311 + // Cheaper than instanceof Enum followed by getDeclaringClass
207.312 + Class keyClass = key.getClass();
207.313 + return keyClass == keyType || keyClass.getSuperclass() == keyType;
207.314 + }
207.315 +
207.316 + // Bulk Operations
207.317 +
207.318 + /**
207.319 + * Copies all of the mappings from the specified map to this map.
207.320 + * These mappings will replace any mappings that this map had for
207.321 + * any of the keys currently in the specified map.
207.322 + *
207.323 + * @param m the mappings to be stored in this map
207.324 + * @throws NullPointerException the specified map is null, or if
207.325 + * one or more keys in the specified map are null
207.326 + */
207.327 + public void putAll(Map<? extends K, ? extends V> m) {
207.328 + if (m instanceof EnumMap) {
207.329 + EnumMap<? extends K, ? extends V> em =
207.330 + (EnumMap<? extends K, ? extends V>)m;
207.331 + if (em.keyType != keyType) {
207.332 + if (em.isEmpty())
207.333 + return;
207.334 + throw new ClassCastException(em.keyType + " != " + keyType);
207.335 + }
207.336 +
207.337 + for (int i = 0; i < keyUniverse.length; i++) {
207.338 + Object emValue = em.vals[i];
207.339 + if (emValue != null) {
207.340 + if (vals[i] == null)
207.341 + size++;
207.342 + vals[i] = emValue;
207.343 + }
207.344 + }
207.345 + } else {
207.346 + super.putAll(m);
207.347 + }
207.348 + }
207.349 +
207.350 + /**
207.351 + * Removes all mappings from this map.
207.352 + */
207.353 + public void clear() {
207.354 + Arrays.fill(vals, null);
207.355 + size = 0;
207.356 + }
207.357 +
207.358 + // Views
207.359 +
207.360 + /**
207.361 + * This field is initialized to contain an instance of the entry set
207.362 + * view the first time this view is requested. The view is stateless,
207.363 + * so there's no reason to create more than one.
207.364 + */
207.365 + private transient Set<Map.Entry<K,V>> entrySet = null;
207.366 +
207.367 + /**
207.368 + * Returns a {@link Set} view of the keys contained in this map.
207.369 + * The returned set obeys the general contract outlined in
207.370 + * {@link Map#keySet()}. The set's iterator will return the keys
207.371 + * in their natural order (the order in which the enum constants
207.372 + * are declared).
207.373 + *
207.374 + * @return a set view of the keys contained in this enum map
207.375 + */
207.376 + public Set<K> keySet() {
207.377 + Set<K> ks = keySet;
207.378 + if (ks != null)
207.379 + return ks;
207.380 + else
207.381 + return keySet = new KeySet();
207.382 + }
207.383 +
207.384 + private class KeySet extends AbstractSet<K> {
207.385 + public Iterator<K> iterator() {
207.386 + return new KeyIterator();
207.387 + }
207.388 + public int size() {
207.389 + return size;
207.390 + }
207.391 + public boolean contains(Object o) {
207.392 + return containsKey(o);
207.393 + }
207.394 + public boolean remove(Object o) {
207.395 + int oldSize = size;
207.396 + EnumMap.this.remove(o);
207.397 + return size != oldSize;
207.398 + }
207.399 + public void clear() {
207.400 + EnumMap.this.clear();
207.401 + }
207.402 + }
207.403 +
207.404 + /**
207.405 + * Returns a {@link Collection} view of the values contained in this map.
207.406 + * The returned collection obeys the general contract outlined in
207.407 + * {@link Map#values()}. The collection's iterator will return the
207.408 + * values in the order their corresponding keys appear in map,
207.409 + * which is their natural order (the order in which the enum constants
207.410 + * are declared).
207.411 + *
207.412 + * @return a collection view of the values contained in this map
207.413 + */
207.414 + public Collection<V> values() {
207.415 + Collection<V> vs = values;
207.416 + if (vs != null)
207.417 + return vs;
207.418 + else
207.419 + return values = new Values();
207.420 + }
207.421 +
207.422 + private class Values extends AbstractCollection<V> {
207.423 + public Iterator<V> iterator() {
207.424 + return new ValueIterator();
207.425 + }
207.426 + public int size() {
207.427 + return size;
207.428 + }
207.429 + public boolean contains(Object o) {
207.430 + return containsValue(o);
207.431 + }
207.432 + public boolean remove(Object o) {
207.433 + o = maskNull(o);
207.434 +
207.435 + for (int i = 0; i < vals.length; i++) {
207.436 + if (o.equals(vals[i])) {
207.437 + vals[i] = null;
207.438 + size--;
207.439 + return true;
207.440 + }
207.441 + }
207.442 + return false;
207.443 + }
207.444 + public void clear() {
207.445 + EnumMap.this.clear();
207.446 + }
207.447 + }
207.448 +
207.449 + /**
207.450 + * Returns a {@link Set} view of the mappings contained in this map.
207.451 + * The returned set obeys the general contract outlined in
207.452 + * {@link Map#keySet()}. The set's iterator will return the
207.453 + * mappings in the order their keys appear in map, which is their
207.454 + * natural order (the order in which the enum constants are declared).
207.455 + *
207.456 + * @return a set view of the mappings contained in this enum map
207.457 + */
207.458 + public Set<Map.Entry<K,V>> entrySet() {
207.459 + Set<Map.Entry<K,V>> es = entrySet;
207.460 + if (es != null)
207.461 + return es;
207.462 + else
207.463 + return entrySet = new EntrySet();
207.464 + }
207.465 +
207.466 + private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
207.467 + public Iterator<Map.Entry<K,V>> iterator() {
207.468 + return new EntryIterator();
207.469 + }
207.470 +
207.471 + public boolean contains(Object o) {
207.472 + if (!(o instanceof Map.Entry))
207.473 + return false;
207.474 + Map.Entry entry = (Map.Entry)o;
207.475 + return containsMapping(entry.getKey(), entry.getValue());
207.476 + }
207.477 + public boolean remove(Object o) {
207.478 + if (!(o instanceof Map.Entry))
207.479 + return false;
207.480 + Map.Entry entry = (Map.Entry)o;
207.481 + return removeMapping(entry.getKey(), entry.getValue());
207.482 + }
207.483 + public int size() {
207.484 + return size;
207.485 + }
207.486 + public void clear() {
207.487 + EnumMap.this.clear();
207.488 + }
207.489 + public Object[] toArray() {
207.490 + return fillEntryArray(new Object[size]);
207.491 + }
207.492 + @SuppressWarnings("unchecked")
207.493 + public <T> T[] toArray(T[] a) {
207.494 + int size = size();
207.495 + if (a.length < size)
207.496 + a = (T[])java.lang.reflect.Array
207.497 + .newInstance(a.getClass().getComponentType(), size);
207.498 + if (a.length > size)
207.499 + a[size] = null;
207.500 + return (T[]) fillEntryArray(a);
207.501 + }
207.502 + private Object[] fillEntryArray(Object[] a) {
207.503 + int j = 0;
207.504 + for (int i = 0; i < vals.length; i++)
207.505 + if (vals[i] != null)
207.506 + a[j++] = new AbstractMap.SimpleEntry<>(
207.507 + keyUniverse[i], unmaskNull(vals[i]));
207.508 + return a;
207.509 + }
207.510 + }
207.511 +
207.512 + private abstract class EnumMapIterator<T> implements Iterator<T> {
207.513 + // Lower bound on index of next element to return
207.514 + int index = 0;
207.515 +
207.516 + // Index of last returned element, or -1 if none
207.517 + int lastReturnedIndex = -1;
207.518 +
207.519 + public boolean hasNext() {
207.520 + while (index < vals.length && vals[index] == null)
207.521 + index++;
207.522 + return index != vals.length;
207.523 + }
207.524 +
207.525 + public void remove() {
207.526 + checkLastReturnedIndex();
207.527 +
207.528 + if (vals[lastReturnedIndex] != null) {
207.529 + vals[lastReturnedIndex] = null;
207.530 + size--;
207.531 + }
207.532 + lastReturnedIndex = -1;
207.533 + }
207.534 +
207.535 + private void checkLastReturnedIndex() {
207.536 + if (lastReturnedIndex < 0)
207.537 + throw new IllegalStateException();
207.538 + }
207.539 + }
207.540 +
207.541 + private class KeyIterator extends EnumMapIterator<K> {
207.542 + public K next() {
207.543 + if (!hasNext())
207.544 + throw new NoSuchElementException();
207.545 + lastReturnedIndex = index++;
207.546 + return keyUniverse[lastReturnedIndex];
207.547 + }
207.548 + }
207.549 +
207.550 + private class ValueIterator extends EnumMapIterator<V> {
207.551 + public V next() {
207.552 + if (!hasNext())
207.553 + throw new NoSuchElementException();
207.554 + lastReturnedIndex = index++;
207.555 + return unmaskNull(vals[lastReturnedIndex]);
207.556 + }
207.557 + }
207.558 +
207.559 + private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
207.560 + private Entry lastReturnedEntry = null;
207.561 +
207.562 + public Map.Entry<K,V> next() {
207.563 + if (!hasNext())
207.564 + throw new NoSuchElementException();
207.565 + lastReturnedEntry = new Entry(index++);
207.566 + return lastReturnedEntry;
207.567 + }
207.568 +
207.569 + public void remove() {
207.570 + lastReturnedIndex =
207.571 + ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
207.572 + super.remove();
207.573 + lastReturnedEntry.index = lastReturnedIndex;
207.574 + lastReturnedEntry = null;
207.575 + }
207.576 +
207.577 + private class Entry implements Map.Entry<K,V> {
207.578 + private int index;
207.579 +
207.580 + private Entry(int index) {
207.581 + this.index = index;
207.582 + }
207.583 +
207.584 + public K getKey() {
207.585 + checkIndexForEntryUse();
207.586 + return keyUniverse[index];
207.587 + }
207.588 +
207.589 + public V getValue() {
207.590 + checkIndexForEntryUse();
207.591 + return unmaskNull(vals[index]);
207.592 + }
207.593 +
207.594 + public V setValue(V value) {
207.595 + checkIndexForEntryUse();
207.596 + V oldValue = unmaskNull(vals[index]);
207.597 + vals[index] = maskNull(value);
207.598 + return oldValue;
207.599 + }
207.600 +
207.601 + public boolean equals(Object o) {
207.602 + if (index < 0)
207.603 + return o == this;
207.604 +
207.605 + if (!(o instanceof Map.Entry))
207.606 + return false;
207.607 +
207.608 + Map.Entry e = (Map.Entry)o;
207.609 + V ourValue = unmaskNull(vals[index]);
207.610 + Object hisValue = e.getValue();
207.611 + return (e.getKey() == keyUniverse[index] &&
207.612 + (ourValue == hisValue ||
207.613 + (ourValue != null && ourValue.equals(hisValue))));
207.614 + }
207.615 +
207.616 + public int hashCode() {
207.617 + if (index < 0)
207.618 + return super.hashCode();
207.619 +
207.620 + return entryHashCode(index);
207.621 + }
207.622 +
207.623 + public String toString() {
207.624 + if (index < 0)
207.625 + return super.toString();
207.626 +
207.627 + return keyUniverse[index] + "="
207.628 + + unmaskNull(vals[index]);
207.629 + }
207.630 +
207.631 + private void checkIndexForEntryUse() {
207.632 + if (index < 0)
207.633 + throw new IllegalStateException("Entry was removed");
207.634 + }
207.635 + }
207.636 + }
207.637 +
207.638 + // Comparison and hashing
207.639 +
207.640 + /**
207.641 + * Compares the specified object with this map for equality. Returns
207.642 + * <tt>true</tt> if the given object is also a map and the two maps
207.643 + * represent the same mappings, as specified in the {@link
207.644 + * Map#equals(Object)} contract.
207.645 + *
207.646 + * @param o the object to be compared for equality with this map
207.647 + * @return <tt>true</tt> if the specified object is equal to this map
207.648 + */
207.649 + public boolean equals(Object o) {
207.650 + if (this == o)
207.651 + return true;
207.652 + if (o instanceof EnumMap)
207.653 + return equals((EnumMap)o);
207.654 + if (!(o instanceof Map))
207.655 + return false;
207.656 +
207.657 + Map<K,V> m = (Map<K,V>)o;
207.658 + if (size != m.size())
207.659 + return false;
207.660 +
207.661 + for (int i = 0; i < keyUniverse.length; i++) {
207.662 + if (null != vals[i]) {
207.663 + K key = keyUniverse[i];
207.664 + V value = unmaskNull(vals[i]);
207.665 + if (null == value) {
207.666 + if (!((null == m.get(key)) && m.containsKey(key)))
207.667 + return false;
207.668 + } else {
207.669 + if (!value.equals(m.get(key)))
207.670 + return false;
207.671 + }
207.672 + }
207.673 + }
207.674 +
207.675 + return true;
207.676 + }
207.677 +
207.678 + private boolean equals(EnumMap em) {
207.679 + if (em.keyType != keyType)
207.680 + return size == 0 && em.size == 0;
207.681 +
207.682 + // Key types match, compare each value
207.683 + for (int i = 0; i < keyUniverse.length; i++) {
207.684 + Object ourValue = vals[i];
207.685 + Object hisValue = em.vals[i];
207.686 + if (hisValue != ourValue &&
207.687 + (hisValue == null || !hisValue.equals(ourValue)))
207.688 + return false;
207.689 + }
207.690 + return true;
207.691 + }
207.692 +
207.693 + /**
207.694 + * Returns the hash code value for this map. The hash code of a map is
207.695 + * defined to be the sum of the hash codes of each entry in the map.
207.696 + */
207.697 + public int hashCode() {
207.698 + int h = 0;
207.699 +
207.700 + for (int i = 0; i < keyUniverse.length; i++) {
207.701 + if (null != vals[i]) {
207.702 + h += entryHashCode(i);
207.703 + }
207.704 + }
207.705 +
207.706 + return h;
207.707 + }
207.708 +
207.709 + private int entryHashCode(int index) {
207.710 + return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
207.711 + }
207.712 +
207.713 + /**
207.714 + * Returns a shallow copy of this enum map. (The values themselves
207.715 + * are not cloned.
207.716 + *
207.717 + * @return a shallow copy of this enum map
207.718 + */
207.719 + public EnumMap<K, V> clone() {
207.720 + EnumMap<K, V> result = null;
207.721 + try {
207.722 + result = (EnumMap<K, V>) super.clone();
207.723 + } catch(CloneNotSupportedException e) {
207.724 + throw new AssertionError();
207.725 + }
207.726 + result.vals = result.vals.clone();
207.727 + return result;
207.728 + }
207.729 +
207.730 + /**
207.731 + * Throws an exception if e is not of the correct type for this enum set.
207.732 + */
207.733 + private void typeCheck(K key) {
207.734 + Class keyClass = key.getClass();
207.735 + if (keyClass != keyType && keyClass.getSuperclass() != keyType)
207.736 + throw new ClassCastException(keyClass + " != " + keyType);
207.737 + }
207.738 +
207.739 + /**
207.740 + * Returns all of the values comprising K.
207.741 + * The result is uncloned, cached, and shared by all callers.
207.742 + */
207.743 + @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.fld_$VALUES;")
207.744 + private static native <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType);
207.745 +
207.746 + private static final long serialVersionUID = 458661240069192865L;
207.747 +
207.748 + /**
207.749 + * Save the state of the <tt>EnumMap</tt> instance to a stream (i.e.,
207.750 + * serialize it).
207.751 + *
207.752 + * @serialData The <i>size</i> of the enum map (the number of key-value
207.753 + * mappings) is emitted (int), followed by the key (Object)
207.754 + * and value (Object) for each key-value mapping represented
207.755 + * by the enum map.
207.756 + */
207.757 + private void writeObject(java.io.ObjectOutputStream s)
207.758 + throws java.io.IOException
207.759 + {
207.760 + // Write out the key type and any hidden stuff
207.761 + s.defaultWriteObject();
207.762 +
207.763 + // Write out size (number of Mappings)
207.764 + s.writeInt(size);
207.765 +
207.766 + // Write out keys and values (alternating)
207.767 + int entriesToBeWritten = size;
207.768 + for (int i = 0; entriesToBeWritten > 0; i++) {
207.769 + if (null != vals[i]) {
207.770 + s.writeObject(keyUniverse[i]);
207.771 + s.writeObject(unmaskNull(vals[i]));
207.772 + entriesToBeWritten--;
207.773 + }
207.774 + }
207.775 + }
207.776 +
207.777 + /**
207.778 + * Reconstitute the <tt>EnumMap</tt> instance from a stream (i.e.,
207.779 + * deserialize it).
207.780 + */
207.781 + private void readObject(java.io.ObjectInputStream s)
207.782 + throws java.io.IOException, ClassNotFoundException
207.783 + {
207.784 + // Read in the key type and any hidden stuff
207.785 + s.defaultReadObject();
207.786 +
207.787 + keyUniverse = getKeyUniverse(keyType);
207.788 + vals = new Object[keyUniverse.length];
207.789 +
207.790 + // Read in size (number of Mappings)
207.791 + int size = s.readInt();
207.792 +
207.793 + // Read the keys and values, and put the mappings in the HashMap
207.794 + for (int i = 0; i < size; i++) {
207.795 + K key = (K) s.readObject();
207.796 + V value = (V) s.readObject();
207.797 + put(key, value);
207.798 + }
207.799 + }
207.800 +}
208.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
208.2 +++ b/rt/emul/compact/src/main/java/java/util/EnumSet.java Wed Apr 30 15:04:10 2014 +0200
208.3 @@ -0,0 +1,441 @@
208.4 +/*
208.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
208.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
208.7 + *
208.8 + * This code is free software; you can redistribute it and/or modify it
208.9 + * under the terms of the GNU General Public License version 2 only, as
208.10 + * published by the Free Software Foundation. Oracle designates this
208.11 + * particular file as subject to the "Classpath" exception as provided
208.12 + * by Oracle in the LICENSE file that accompanied this code.
208.13 + *
208.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
208.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
208.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
208.17 + * version 2 for more details (a copy is included in the LICENSE file that
208.18 + * accompanied this code).
208.19 + *
208.20 + * You should have received a copy of the GNU General Public License version
208.21 + * 2 along with this work; if not, write to the Free Software Foundation,
208.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
208.23 + *
208.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
208.25 + * or visit www.oracle.com if you need additional information or have any
208.26 + * questions.
208.27 + */
208.28 +
208.29 +package java.util;
208.30 +
208.31 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
208.32 +
208.33 +/**
208.34 + * A specialized {@link Set} implementation for use with enum types. All of
208.35 + * the elements in an enum set must come from a single enum type that is
208.36 + * specified, explicitly or implicitly, when the set is created. Enum sets
208.37 + * are represented internally as bit vectors. This representation is
208.38 + * extremely compact and efficient. The space and time performance of this
208.39 + * class should be good enough to allow its use as a high-quality, typesafe
208.40 + * alternative to traditional <tt>int</tt>-based "bit flags." Even bulk
208.41 + * operations (such as <tt>containsAll</tt> and <tt>retainAll</tt>) should
208.42 + * run very quickly if their argument is also an enum set.
208.43 + *
208.44 + * <p>The iterator returned by the <tt>iterator</tt> method traverses the
208.45 + * elements in their <i>natural order</i> (the order in which the enum
208.46 + * constants are declared). The returned iterator is <i>weakly
208.47 + * consistent</i>: it will never throw {@link ConcurrentModificationException}
208.48 + * and it may or may not show the effects of any modifications to the set that
208.49 + * occur while the iteration is in progress.
208.50 + *
208.51 + * <p>Null elements are not permitted. Attempts to insert a null element
208.52 + * will throw {@link NullPointerException}. Attempts to test for the
208.53 + * presence of a null element or to remove one will, however, function
208.54 + * properly.
208.55 + *
208.56 + * <P>Like most collection implementations, <tt>EnumSet</tt> is not
208.57 + * synchronized. If multiple threads access an enum set concurrently, and at
208.58 + * least one of the threads modifies the set, it should be synchronized
208.59 + * externally. This is typically accomplished by synchronizing on some
208.60 + * object that naturally encapsulates the enum set. If no such object exists,
208.61 + * the set should be "wrapped" using the {@link Collections#synchronizedSet}
208.62 + * method. This is best done at creation time, to prevent accidental
208.63 + * unsynchronized access:
208.64 + *
208.65 + * <pre>
208.66 + * Set<MyEnum> s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));
208.67 + * </pre>
208.68 + *
208.69 + * <p>Implementation note: All basic operations execute in constant time.
208.70 + * They are likely (though not guaranteed) to be much faster than their
208.71 + * {@link HashSet} counterparts. Even bulk operations execute in
208.72 + * constant time if their argument is also an enum set.
208.73 + *
208.74 + * <p>This class is a member of the
208.75 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
208.76 + * Java Collections Framework</a>.
208.77 + *
208.78 + * @author Josh Bloch
208.79 + * @since 1.5
208.80 + * @see EnumMap
208.81 + * @serial exclude
208.82 + */
208.83 +public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
208.84 + implements Cloneable, java.io.Serializable
208.85 +{
208.86 + /**
208.87 + * The class of all the elements of this set.
208.88 + */
208.89 + final Class<E> elementType;
208.90 +
208.91 + /**
208.92 + * All of the values comprising T. (Cached for performance.)
208.93 + */
208.94 + final Enum[] universe;
208.95 +
208.96 + private static Enum[] ZERO_LENGTH_ENUM_ARRAY = new Enum[0];
208.97 +
208.98 + EnumSet(Class<E>elementType, Enum[] universe) {
208.99 + this.elementType = elementType;
208.100 + this.universe = universe;
208.101 + }
208.102 +
208.103 + /**
208.104 + * Creates an empty enum set with the specified element type.
208.105 + *
208.106 + * @param elementType the class object of the element type for this enum
208.107 + * set
208.108 + * @throws NullPointerException if <tt>elementType</tt> is null
208.109 + */
208.110 + public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
208.111 + Enum[] universe = getUniverse(elementType);
208.112 + if (universe == null)
208.113 + throw new ClassCastException(elementType + " not an enum");
208.114 +
208.115 + if (universe.length <= 64)
208.116 + return new RegularEnumSet<>(elementType, universe);
208.117 + else
208.118 + return new JumboEnumSet<>(elementType, universe);
208.119 + }
208.120 +
208.121 + /**
208.122 + * Creates an enum set containing all of the elements in the specified
208.123 + * element type.
208.124 + *
208.125 + * @param elementType the class object of the element type for this enum
208.126 + * set
208.127 + * @throws NullPointerException if <tt>elementType</tt> is null
208.128 + */
208.129 + public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
208.130 + EnumSet<E> result = noneOf(elementType);
208.131 + result.addAll();
208.132 + return result;
208.133 + }
208.134 +
208.135 + /**
208.136 + * Adds all of the elements from the appropriate enum type to this enum
208.137 + * set, which is empty prior to the call.
208.138 + */
208.139 + abstract void addAll();
208.140 +
208.141 + /**
208.142 + * Creates an enum set with the same element type as the specified enum
208.143 + * set, initially containing the same elements (if any).
208.144 + *
208.145 + * @param s the enum set from which to initialize this enum set
208.146 + * @throws NullPointerException if <tt>s</tt> is null
208.147 + */
208.148 + public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
208.149 + return s.clone();
208.150 + }
208.151 +
208.152 + /**
208.153 + * Creates an enum set initialized from the specified collection. If
208.154 + * the specified collection is an <tt>EnumSet</tt> instance, this static
208.155 + * factory method behaves identically to {@link #copyOf(EnumSet)}.
208.156 + * Otherwise, the specified collection must contain at least one element
208.157 + * (in order to determine the new enum set's element type).
208.158 + *
208.159 + * @param c the collection from which to initialize this enum set
208.160 + * @throws IllegalArgumentException if <tt>c</tt> is not an
208.161 + * <tt>EnumSet</tt> instance and contains no elements
208.162 + * @throws NullPointerException if <tt>c</tt> is null
208.163 + */
208.164 + public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
208.165 + if (c instanceof EnumSet) {
208.166 + return ((EnumSet<E>)c).clone();
208.167 + } else {
208.168 + if (c.isEmpty())
208.169 + throw new IllegalArgumentException("Collection is empty");
208.170 + Iterator<E> i = c.iterator();
208.171 + E first = i.next();
208.172 + EnumSet<E> result = EnumSet.of(first);
208.173 + while (i.hasNext())
208.174 + result.add(i.next());
208.175 + return result;
208.176 + }
208.177 + }
208.178 +
208.179 + /**
208.180 + * Creates an enum set with the same element type as the specified enum
208.181 + * set, initially containing all the elements of this type that are
208.182 + * <i>not</i> contained in the specified set.
208.183 + *
208.184 + * @param s the enum set from whose complement to initialize this enum set
208.185 + * @throws NullPointerException if <tt>s</tt> is null
208.186 + */
208.187 + public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
208.188 + EnumSet<E> result = copyOf(s);
208.189 + result.complement();
208.190 + return result;
208.191 + }
208.192 +
208.193 + /**
208.194 + * Creates an enum set initially containing the specified element.
208.195 + *
208.196 + * Overloadings of this method exist to initialize an enum set with
208.197 + * one through five elements. A sixth overloading is provided that
208.198 + * uses the varargs feature. This overloading may be used to create
208.199 + * an enum set initially containing an arbitrary number of elements, but
208.200 + * is likely to run slower than the overloadings that do not use varargs.
208.201 + *
208.202 + * @param e the element that this set is to contain initially
208.203 + * @throws NullPointerException if <tt>e</tt> is null
208.204 + * @return an enum set initially containing the specified element
208.205 + */
208.206 + public static <E extends Enum<E>> EnumSet<E> of(E e) {
208.207 + EnumSet<E> result = noneOf(e.getDeclaringClass());
208.208 + result.add(e);
208.209 + return result;
208.210 + }
208.211 +
208.212 + /**
208.213 + * Creates an enum set initially containing the specified elements.
208.214 + *
208.215 + * Overloadings of this method exist to initialize an enum set with
208.216 + * one through five elements. A sixth overloading is provided that
208.217 + * uses the varargs feature. This overloading may be used to create
208.218 + * an enum set initially containing an arbitrary number of elements, but
208.219 + * is likely to run slower than the overloadings that do not use varargs.
208.220 + *
208.221 + * @param e1 an element that this set is to contain initially
208.222 + * @param e2 another element that this set is to contain initially
208.223 + * @throws NullPointerException if any parameters are null
208.224 + * @return an enum set initially containing the specified elements
208.225 + */
208.226 + public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
208.227 + EnumSet<E> result = noneOf(e1.getDeclaringClass());
208.228 + result.add(e1);
208.229 + result.add(e2);
208.230 + return result;
208.231 + }
208.232 +
208.233 + /**
208.234 + * Creates an enum set initially containing the specified elements.
208.235 + *
208.236 + * Overloadings of this method exist to initialize an enum set with
208.237 + * one through five elements. A sixth overloading is provided that
208.238 + * uses the varargs feature. This overloading may be used to create
208.239 + * an enum set initially containing an arbitrary number of elements, but
208.240 + * is likely to run slower than the overloadings that do not use varargs.
208.241 + *
208.242 + * @param e1 an element that this set is to contain initially
208.243 + * @param e2 another element that this set is to contain initially
208.244 + * @param e3 another element that this set is to contain initially
208.245 + * @throws NullPointerException if any parameters are null
208.246 + * @return an enum set initially containing the specified elements
208.247 + */
208.248 + public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
208.249 + EnumSet<E> result = noneOf(e1.getDeclaringClass());
208.250 + result.add(e1);
208.251 + result.add(e2);
208.252 + result.add(e3);
208.253 + return result;
208.254 + }
208.255 +
208.256 + /**
208.257 + * Creates an enum set initially containing the specified elements.
208.258 + *
208.259 + * Overloadings of this method exist to initialize an enum set with
208.260 + * one through five elements. A sixth overloading is provided that
208.261 + * uses the varargs feature. This overloading may be used to create
208.262 + * an enum set initially containing an arbitrary number of elements, but
208.263 + * is likely to run slower than the overloadings that do not use varargs.
208.264 + *
208.265 + * @param e1 an element that this set is to contain initially
208.266 + * @param e2 another element that this set is to contain initially
208.267 + * @param e3 another element that this set is to contain initially
208.268 + * @param e4 another element that this set is to contain initially
208.269 + * @throws NullPointerException if any parameters are null
208.270 + * @return an enum set initially containing the specified elements
208.271 + */
208.272 + public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
208.273 + EnumSet<E> result = noneOf(e1.getDeclaringClass());
208.274 + result.add(e1);
208.275 + result.add(e2);
208.276 + result.add(e3);
208.277 + result.add(e4);
208.278 + return result;
208.279 + }
208.280 +
208.281 + /**
208.282 + * Creates an enum set initially containing the specified elements.
208.283 + *
208.284 + * Overloadings of this method exist to initialize an enum set with
208.285 + * one through five elements. A sixth overloading is provided that
208.286 + * uses the varargs feature. This overloading may be used to create
208.287 + * an enum set initially containing an arbitrary number of elements, but
208.288 + * is likely to run slower than the overloadings that do not use varargs.
208.289 + *
208.290 + * @param e1 an element that this set is to contain initially
208.291 + * @param e2 another element that this set is to contain initially
208.292 + * @param e3 another element that this set is to contain initially
208.293 + * @param e4 another element that this set is to contain initially
208.294 + * @param e5 another element that this set is to contain initially
208.295 + * @throws NullPointerException if any parameters are null
208.296 + * @return an enum set initially containing the specified elements
208.297 + */
208.298 + public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
208.299 + E e5)
208.300 + {
208.301 + EnumSet<E> result = noneOf(e1.getDeclaringClass());
208.302 + result.add(e1);
208.303 + result.add(e2);
208.304 + result.add(e3);
208.305 + result.add(e4);
208.306 + result.add(e5);
208.307 + return result;
208.308 + }
208.309 +
208.310 + /**
208.311 + * Creates an enum set initially containing the specified elements.
208.312 + * This factory, whose parameter list uses the varargs feature, may
208.313 + * be used to create an enum set initially containing an arbitrary
208.314 + * number of elements, but it is likely to run slower than the overloadings
208.315 + * that do not use varargs.
208.316 + *
208.317 + * @param first an element that the set is to contain initially
208.318 + * @param rest the remaining elements the set is to contain initially
208.319 + * @throws NullPointerException if any of the specified elements are null,
208.320 + * or if <tt>rest</tt> is null
208.321 + * @return an enum set initially containing the specified elements
208.322 + */
208.323 + @SafeVarargs
208.324 + public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
208.325 + EnumSet<E> result = noneOf(first.getDeclaringClass());
208.326 + result.add(first);
208.327 + for (E e : rest)
208.328 + result.add(e);
208.329 + return result;
208.330 + }
208.331 +
208.332 + /**
208.333 + * Creates an enum set initially containing all of the elements in the
208.334 + * range defined by the two specified endpoints. The returned set will
208.335 + * contain the endpoints themselves, which may be identical but must not
208.336 + * be out of order.
208.337 + *
208.338 + * @param from the first element in the range
208.339 + * @param to the last element in the range
208.340 + * @throws NullPointerException if {@code from} or {@code to} are null
208.341 + * @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
208.342 + * @return an enum set initially containing all of the elements in the
208.343 + * range defined by the two specified endpoints
208.344 + */
208.345 + public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
208.346 + if (from.compareTo(to) > 0)
208.347 + throw new IllegalArgumentException(from + " > " + to);
208.348 + EnumSet<E> result = noneOf(from.getDeclaringClass());
208.349 + result.addRange(from, to);
208.350 + return result;
208.351 + }
208.352 +
208.353 + /**
208.354 + * Adds the specified range to this enum set, which is empty prior
208.355 + * to the call.
208.356 + */
208.357 + abstract void addRange(E from, E to);
208.358 +
208.359 + /**
208.360 + * Returns a copy of this set.
208.361 + *
208.362 + * @return a copy of this set
208.363 + */
208.364 + public EnumSet<E> clone() {
208.365 + try {
208.366 + return (EnumSet<E>) super.clone();
208.367 + } catch(CloneNotSupportedException e) {
208.368 + throw new AssertionError(e);
208.369 + }
208.370 + }
208.371 +
208.372 + /**
208.373 + * Complements the contents of this enum set.
208.374 + */
208.375 + abstract void complement();
208.376 +
208.377 + /**
208.378 + * Throws an exception if e is not of the correct type for this enum set.
208.379 + */
208.380 + final void typeCheck(E e) {
208.381 + Class eClass = e.getClass();
208.382 + if (eClass != elementType && eClass.getSuperclass() != elementType)
208.383 + throw new ClassCastException(eClass + " != " + elementType);
208.384 + }
208.385 +
208.386 + /**
208.387 + * Returns all of the values comprising E.
208.388 + * The result is uncloned, cached, and shared by all callers.
208.389 + */
208.390 + @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.fld_$VALUES;")
208.391 + private static native <E extends Enum<E>> E[] getUniverse(Class<E> elementType);
208.392 +
208.393 + /**
208.394 + * This class is used to serialize all EnumSet instances, regardless of
208.395 + * implementation type. It captures their "logical contents" and they
208.396 + * are reconstructed using public static factories. This is necessary
208.397 + * to ensure that the existence of a particular implementation type is
208.398 + * an implementation detail.
208.399 + *
208.400 + * @serial include
208.401 + */
208.402 + private static class SerializationProxy <E extends Enum<E>>
208.403 + implements java.io.Serializable
208.404 + {
208.405 + /**
208.406 + * The element type of this enum set.
208.407 + *
208.408 + * @serial
208.409 + */
208.410 + private final Class<E> elementType;
208.411 +
208.412 + /**
208.413 + * The elements contained in this enum set.
208.414 + *
208.415 + * @serial
208.416 + */
208.417 + private final Enum[] elements;
208.418 +
208.419 + SerializationProxy(EnumSet<E> set) {
208.420 + elementType = set.elementType;
208.421 + elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
208.422 + }
208.423 +
208.424 + private Object readResolve() {
208.425 + EnumSet<E> result = EnumSet.noneOf(elementType);
208.426 + for (Enum e : elements)
208.427 + result.add((E)e);
208.428 + return result;
208.429 + }
208.430 +
208.431 + private static final long serialVersionUID = 362491234563181265L;
208.432 + }
208.433 +
208.434 + Object writeReplace() {
208.435 + return new SerializationProxy<>(this);
208.436 + }
208.437 +
208.438 + // readObject method for the serialization proxy pattern
208.439 + // See Effective Java, Second Ed., Item 78.
208.440 + private void readObject(java.io.ObjectInputStream stream)
208.441 + throws java.io.InvalidObjectException {
208.442 + throw new java.io.InvalidObjectException("Proxy required");
208.443 + }
208.444 +}
209.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
209.2 +++ b/rt/emul/compact/src/main/java/java/util/IdentityHashMap.java Wed Apr 30 15:04:10 2014 +0200
209.3 @@ -0,0 +1,1243 @@
209.4 +/*
209.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
209.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
209.7 + *
209.8 + * This code is free software; you can redistribute it and/or modify it
209.9 + * under the terms of the GNU General Public License version 2 only, as
209.10 + * published by the Free Software Foundation. Oracle designates this
209.11 + * particular file as subject to the "Classpath" exception as provided
209.12 + * by Oracle in the LICENSE file that accompanied this code.
209.13 + *
209.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
209.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
209.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
209.17 + * version 2 for more details (a copy is included in the LICENSE file that
209.18 + * accompanied this code).
209.19 + *
209.20 + * You should have received a copy of the GNU General Public License version
209.21 + * 2 along with this work; if not, write to the Free Software Foundation,
209.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
209.23 + *
209.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
209.25 + * or visit www.oracle.com if you need additional information or have any
209.26 + * questions.
209.27 + */
209.28 +
209.29 +package java.util;
209.30 +import java.io.*;
209.31 +
209.32 +/**
209.33 + * This class implements the <tt>Map</tt> interface with a hash table, using
209.34 + * reference-equality in place of object-equality when comparing keys (and
209.35 + * values). In other words, in an <tt>IdentityHashMap</tt>, two keys
209.36 + * <tt>k1</tt> and <tt>k2</tt> are considered equal if and only if
209.37 + * <tt>(k1==k2)</tt>. (In normal <tt>Map</tt> implementations (like
209.38 + * <tt>HashMap</tt>) two keys <tt>k1</tt> and <tt>k2</tt> are considered equal
209.39 + * if and only if <tt>(k1==null ? k2==null : k1.equals(k2))</tt>.)
209.40 + *
209.41 + * <p><b>This class is <i>not</i> a general-purpose <tt>Map</tt>
209.42 + * implementation! While this class implements the <tt>Map</tt> interface, it
209.43 + * intentionally violates <tt>Map's</tt> general contract, which mandates the
209.44 + * use of the <tt>equals</tt> method when comparing objects. This class is
209.45 + * designed for use only in the rare cases wherein reference-equality
209.46 + * semantics are required.</b>
209.47 + *
209.48 + * <p>A typical use of this class is <i>topology-preserving object graph
209.49 + * transformations</i>, such as serialization or deep-copying. To perform such
209.50 + * a transformation, a program must maintain a "node table" that keeps track
209.51 + * of all the object references that have already been processed. The node
209.52 + * table must not equate distinct objects even if they happen to be equal.
209.53 + * Another typical use of this class is to maintain <i>proxy objects</i>. For
209.54 + * example, a debugging facility might wish to maintain a proxy object for
209.55 + * each object in the program being debugged.
209.56 + *
209.57 + * <p>This class provides all of the optional map operations, and permits
209.58 + * <tt>null</tt> values and the <tt>null</tt> key. This class makes no
209.59 + * guarantees as to the order of the map; in particular, it does not guarantee
209.60 + * that the order will remain constant over time.
209.61 + *
209.62 + * <p>This class provides constant-time performance for the basic
209.63 + * operations (<tt>get</tt> and <tt>put</tt>), assuming the system
209.64 + * identity hash function ({@link System#identityHashCode(Object)})
209.65 + * disperses elements properly among the buckets.
209.66 + *
209.67 + * <p>This class has one tuning parameter (which affects performance but not
209.68 + * semantics): <i>expected maximum size</i>. This parameter is the maximum
209.69 + * number of key-value mappings that the map is expected to hold. Internally,
209.70 + * this parameter is used to determine the number of buckets initially
209.71 + * comprising the hash table. The precise relationship between the expected
209.72 + * maximum size and the number of buckets is unspecified.
209.73 + *
209.74 + * <p>If the size of the map (the number of key-value mappings) sufficiently
209.75 + * exceeds the expected maximum size, the number of buckets is increased
209.76 + * Increasing the number of buckets ("rehashing") may be fairly expensive, so
209.77 + * it pays to create identity hash maps with a sufficiently large expected
209.78 + * maximum size. On the other hand, iteration over collection views requires
209.79 + * time proportional to the number of buckets in the hash table, so it
209.80 + * pays not to set the expected maximum size too high if you are especially
209.81 + * concerned with iteration performance or memory usage.
209.82 + *
209.83 + * <p><strong>Note that this implementation is not synchronized.</strong>
209.84 + * If multiple threads access an identity hash map concurrently, and at
209.85 + * least one of the threads modifies the map structurally, it <i>must</i>
209.86 + * be synchronized externally. (A structural modification is any operation
209.87 + * that adds or deletes one or more mappings; merely changing the value
209.88 + * associated with a key that an instance already contains is not a
209.89 + * structural modification.) This is typically accomplished by
209.90 + * synchronizing on some object that naturally encapsulates the map.
209.91 + *
209.92 + * If no such object exists, the map should be "wrapped" using the
209.93 + * {@link Collections#synchronizedMap Collections.synchronizedMap}
209.94 + * method. This is best done at creation time, to prevent accidental
209.95 + * unsynchronized access to the map:<pre>
209.96 + * Map m = Collections.synchronizedMap(new IdentityHashMap(...));</pre>
209.97 + *
209.98 + * <p>The iterators returned by the <tt>iterator</tt> method of the
209.99 + * collections returned by all of this class's "collection view
209.100 + * methods" are <i>fail-fast</i>: if the map is structurally modified
209.101 + * at any time after the iterator is created, in any way except
209.102 + * through the iterator's own <tt>remove</tt> method, the iterator
209.103 + * will throw a {@link ConcurrentModificationException}. Thus, in the
209.104 + * face of concurrent modification, the iterator fails quickly and
209.105 + * cleanly, rather than risking arbitrary, non-deterministic behavior
209.106 + * at an undetermined time in the future.
209.107 + *
209.108 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
209.109 + * as it is, generally speaking, impossible to make any hard guarantees in the
209.110 + * presence of unsynchronized concurrent modification. Fail-fast iterators
209.111 + * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
209.112 + * Therefore, it would be wrong to write a program that depended on this
209.113 + * exception for its correctness: <i>fail-fast iterators should be used only
209.114 + * to detect bugs.</i>
209.115 + *
209.116 + * <p>Implementation note: This is a simple <i>linear-probe</i> hash table,
209.117 + * as described for example in texts by Sedgewick and Knuth. The array
209.118 + * alternates holding keys and values. (This has better locality for large
209.119 + * tables than does using separate arrays.) For many JRE implementations
209.120 + * and operation mixes, this class will yield better performance than
209.121 + * {@link HashMap} (which uses <i>chaining</i> rather than linear-probing).
209.122 + *
209.123 + * <p>This class is a member of the
209.124 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
209.125 + * Java Collections Framework</a>.
209.126 + *
209.127 + * @see System#identityHashCode(Object)
209.128 + * @see Object#hashCode()
209.129 + * @see Collection
209.130 + * @see Map
209.131 + * @see HashMap
209.132 + * @see TreeMap
209.133 + * @author Doug Lea and Josh Bloch
209.134 + * @since 1.4
209.135 + */
209.136 +
209.137 +public class IdentityHashMap<K,V>
209.138 + extends AbstractMap<K,V>
209.139 + implements Map<K,V>, java.io.Serializable, Cloneable
209.140 +{
209.141 + /**
209.142 + * The initial capacity used by the no-args constructor.
209.143 + * MUST be a power of two. The value 32 corresponds to the
209.144 + * (specified) expected maximum size of 21, given a load factor
209.145 + * of 2/3.
209.146 + */
209.147 + private static final int DEFAULT_CAPACITY = 32;
209.148 +
209.149 + /**
209.150 + * The minimum capacity, used if a lower value is implicitly specified
209.151 + * by either of the constructors with arguments. The value 4 corresponds
209.152 + * to an expected maximum size of 2, given a load factor of 2/3.
209.153 + * MUST be a power of two.
209.154 + */
209.155 + private static final int MINIMUM_CAPACITY = 4;
209.156 +
209.157 + /**
209.158 + * The maximum capacity, used if a higher value is implicitly specified
209.159 + * by either of the constructors with arguments.
209.160 + * MUST be a power of two <= 1<<29.
209.161 + */
209.162 + private static final int MAXIMUM_CAPACITY = 1 << 29;
209.163 +
209.164 + /**
209.165 + * The table, resized as necessary. Length MUST always be a power of two.
209.166 + */
209.167 + private transient Object[] table;
209.168 +
209.169 + /**
209.170 + * The number of key-value mappings contained in this identity hash map.
209.171 + *
209.172 + * @serial
209.173 + */
209.174 + private int size;
209.175 +
209.176 + /**
209.177 + * The number of modifications, to support fast-fail iterators
209.178 + */
209.179 + private transient int modCount;
209.180 +
209.181 + /**
209.182 + * The next size value at which to resize (capacity * load factor).
209.183 + */
209.184 + private transient int threshold;
209.185 +
209.186 + /**
209.187 + * Value representing null keys inside tables.
209.188 + */
209.189 + private static final Object NULL_KEY = new Object();
209.190 +
209.191 + /**
209.192 + * Use NULL_KEY for key if it is null.
209.193 + */
209.194 + private static Object maskNull(Object key) {
209.195 + return (key == null ? NULL_KEY : key);
209.196 + }
209.197 +
209.198 + /**
209.199 + * Returns internal representation of null key back to caller as null.
209.200 + */
209.201 + private static Object unmaskNull(Object key) {
209.202 + return (key == NULL_KEY ? null : key);
209.203 + }
209.204 +
209.205 + /**
209.206 + * Constructs a new, empty identity hash map with a default expected
209.207 + * maximum size (21).
209.208 + */
209.209 + public IdentityHashMap() {
209.210 + init(DEFAULT_CAPACITY);
209.211 + }
209.212 +
209.213 + /**
209.214 + * Constructs a new, empty map with the specified expected maximum size.
209.215 + * Putting more than the expected number of key-value mappings into
209.216 + * the map may cause the internal data structure to grow, which may be
209.217 + * somewhat time-consuming.
209.218 + *
209.219 + * @param expectedMaxSize the expected maximum size of the map
209.220 + * @throws IllegalArgumentException if <tt>expectedMaxSize</tt> is negative
209.221 + */
209.222 + public IdentityHashMap(int expectedMaxSize) {
209.223 + if (expectedMaxSize < 0)
209.224 + throw new IllegalArgumentException("expectedMaxSize is negative: "
209.225 + + expectedMaxSize);
209.226 + init(capacity(expectedMaxSize));
209.227 + }
209.228 +
209.229 + /**
209.230 + * Returns the appropriate capacity for the specified expected maximum
209.231 + * size. Returns the smallest power of two between MINIMUM_CAPACITY
209.232 + * and MAXIMUM_CAPACITY, inclusive, that is greater than
209.233 + * (3 * expectedMaxSize)/2, if such a number exists. Otherwise
209.234 + * returns MAXIMUM_CAPACITY. If (3 * expectedMaxSize)/2 is negative, it
209.235 + * is assumed that overflow has occurred, and MAXIMUM_CAPACITY is returned.
209.236 + */
209.237 + private int capacity(int expectedMaxSize) {
209.238 + // Compute min capacity for expectedMaxSize given a load factor of 2/3
209.239 + int minCapacity = (3 * expectedMaxSize)/2;
209.240 +
209.241 + // Compute the appropriate capacity
209.242 + int result;
209.243 + if (minCapacity > MAXIMUM_CAPACITY || minCapacity < 0) {
209.244 + result = MAXIMUM_CAPACITY;
209.245 + } else {
209.246 + result = MINIMUM_CAPACITY;
209.247 + while (result < minCapacity)
209.248 + result <<= 1;
209.249 + }
209.250 + return result;
209.251 + }
209.252 +
209.253 + /**
209.254 + * Initializes object to be an empty map with the specified initial
209.255 + * capacity, which is assumed to be a power of two between
209.256 + * MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive.
209.257 + */
209.258 + private void init(int initCapacity) {
209.259 + // assert (initCapacity & -initCapacity) == initCapacity; // power of 2
209.260 + // assert initCapacity >= MINIMUM_CAPACITY;
209.261 + // assert initCapacity <= MAXIMUM_CAPACITY;
209.262 +
209.263 + threshold = (initCapacity * 2)/3;
209.264 + table = new Object[2 * initCapacity];
209.265 + }
209.266 +
209.267 + /**
209.268 + * Constructs a new identity hash map containing the keys-value mappings
209.269 + * in the specified map.
209.270 + *
209.271 + * @param m the map whose mappings are to be placed into this map
209.272 + * @throws NullPointerException if the specified map is null
209.273 + */
209.274 + public IdentityHashMap(Map<? extends K, ? extends V> m) {
209.275 + // Allow for a bit of growth
209.276 + this((int) ((1 + m.size()) * 1.1));
209.277 + putAll(m);
209.278 + }
209.279 +
209.280 + /**
209.281 + * Returns the number of key-value mappings in this identity hash map.
209.282 + *
209.283 + * @return the number of key-value mappings in this map
209.284 + */
209.285 + public int size() {
209.286 + return size;
209.287 + }
209.288 +
209.289 + /**
209.290 + * Returns <tt>true</tt> if this identity hash map contains no key-value
209.291 + * mappings.
209.292 + *
209.293 + * @return <tt>true</tt> if this identity hash map contains no key-value
209.294 + * mappings
209.295 + */
209.296 + public boolean isEmpty() {
209.297 + return size == 0;
209.298 + }
209.299 +
209.300 + /**
209.301 + * Returns index for Object x.
209.302 + */
209.303 + private static int hash(Object x, int length) {
209.304 + int h = System.identityHashCode(x);
209.305 + // Multiply by -127, and left-shift to use least bit as part of hash
209.306 + return ((h << 1) - (h << 8)) & (length - 1);
209.307 + }
209.308 +
209.309 + /**
209.310 + * Circularly traverses table of size len.
209.311 + */
209.312 + private static int nextKeyIndex(int i, int len) {
209.313 + return (i + 2 < len ? i + 2 : 0);
209.314 + }
209.315 +
209.316 + /**
209.317 + * Returns the value to which the specified key is mapped,
209.318 + * or {@code null} if this map contains no mapping for the key.
209.319 + *
209.320 + * <p>More formally, if this map contains a mapping from a key
209.321 + * {@code k} to a value {@code v} such that {@code (key == k)},
209.322 + * then this method returns {@code v}; otherwise it returns
209.323 + * {@code null}. (There can be at most one such mapping.)
209.324 + *
209.325 + * <p>A return value of {@code null} does not <i>necessarily</i>
209.326 + * indicate that the map contains no mapping for the key; it's also
209.327 + * possible that the map explicitly maps the key to {@code null}.
209.328 + * The {@link #containsKey containsKey} operation may be used to
209.329 + * distinguish these two cases.
209.330 + *
209.331 + * @see #put(Object, Object)
209.332 + */
209.333 + public V get(Object key) {
209.334 + Object k = maskNull(key);
209.335 + Object[] tab = table;
209.336 + int len = tab.length;
209.337 + int i = hash(k, len);
209.338 + while (true) {
209.339 + Object item = tab[i];
209.340 + if (item == k)
209.341 + return (V) tab[i + 1];
209.342 + if (item == null)
209.343 + return null;
209.344 + i = nextKeyIndex(i, len);
209.345 + }
209.346 + }
209.347 +
209.348 + /**
209.349 + * Tests whether the specified object reference is a key in this identity
209.350 + * hash map.
209.351 + *
209.352 + * @param key possible key
209.353 + * @return <code>true</code> if the specified object reference is a key
209.354 + * in this map
209.355 + * @see #containsValue(Object)
209.356 + */
209.357 + public boolean containsKey(Object key) {
209.358 + Object k = maskNull(key);
209.359 + Object[] tab = table;
209.360 + int len = tab.length;
209.361 + int i = hash(k, len);
209.362 + while (true) {
209.363 + Object item = tab[i];
209.364 + if (item == k)
209.365 + return true;
209.366 + if (item == null)
209.367 + return false;
209.368 + i = nextKeyIndex(i, len);
209.369 + }
209.370 + }
209.371 +
209.372 + /**
209.373 + * Tests whether the specified object reference is a value in this identity
209.374 + * hash map.
209.375 + *
209.376 + * @param value value whose presence in this map is to be tested
209.377 + * @return <tt>true</tt> if this map maps one or more keys to the
209.378 + * specified object reference
209.379 + * @see #containsKey(Object)
209.380 + */
209.381 + public boolean containsValue(Object value) {
209.382 + Object[] tab = table;
209.383 + for (int i = 1; i < tab.length; i += 2)
209.384 + if (tab[i] == value && tab[i - 1] != null)
209.385 + return true;
209.386 +
209.387 + return false;
209.388 + }
209.389 +
209.390 + /**
209.391 + * Tests if the specified key-value mapping is in the map.
209.392 + *
209.393 + * @param key possible key
209.394 + * @param value possible value
209.395 + * @return <code>true</code> if and only if the specified key-value
209.396 + * mapping is in the map
209.397 + */
209.398 + private boolean containsMapping(Object key, Object value) {
209.399 + Object k = maskNull(key);
209.400 + Object[] tab = table;
209.401 + int len = tab.length;
209.402 + int i = hash(k, len);
209.403 + while (true) {
209.404 + Object item = tab[i];
209.405 + if (item == k)
209.406 + return tab[i + 1] == value;
209.407 + if (item == null)
209.408 + return false;
209.409 + i = nextKeyIndex(i, len);
209.410 + }
209.411 + }
209.412 +
209.413 + /**
209.414 + * Associates the specified value with the specified key in this identity
209.415 + * hash map. If the map previously contained a mapping for the key, the
209.416 + * old value is replaced.
209.417 + *
209.418 + * @param key the key with which the specified value is to be associated
209.419 + * @param value the value to be associated with the specified key
209.420 + * @return the previous value associated with <tt>key</tt>, or
209.421 + * <tt>null</tt> if there was no mapping for <tt>key</tt>.
209.422 + * (A <tt>null</tt> return can also indicate that the map
209.423 + * previously associated <tt>null</tt> with <tt>key</tt>.)
209.424 + * @see Object#equals(Object)
209.425 + * @see #get(Object)
209.426 + * @see #containsKey(Object)
209.427 + */
209.428 + public V put(K key, V value) {
209.429 + Object k = maskNull(key);
209.430 + Object[] tab = table;
209.431 + int len = tab.length;
209.432 + int i = hash(k, len);
209.433 +
209.434 + Object item;
209.435 + while ( (item = tab[i]) != null) {
209.436 + if (item == k) {
209.437 + V oldValue = (V) tab[i + 1];
209.438 + tab[i + 1] = value;
209.439 + return oldValue;
209.440 + }
209.441 + i = nextKeyIndex(i, len);
209.442 + }
209.443 +
209.444 + modCount++;
209.445 + tab[i] = k;
209.446 + tab[i + 1] = value;
209.447 + if (++size >= threshold)
209.448 + resize(len); // len == 2 * current capacity.
209.449 + return null;
209.450 + }
209.451 +
209.452 + /**
209.453 + * Resize the table to hold given capacity.
209.454 + *
209.455 + * @param newCapacity the new capacity, must be a power of two.
209.456 + */
209.457 + private void resize(int newCapacity) {
209.458 + // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
209.459 + int newLength = newCapacity * 2;
209.460 +
209.461 + Object[] oldTable = table;
209.462 + int oldLength = oldTable.length;
209.463 + if (oldLength == 2*MAXIMUM_CAPACITY) { // can't expand any further
209.464 + if (threshold == MAXIMUM_CAPACITY-1)
209.465 + throw new IllegalStateException("Capacity exhausted.");
209.466 + threshold = MAXIMUM_CAPACITY-1; // Gigantic map!
209.467 + return;
209.468 + }
209.469 + if (oldLength >= newLength)
209.470 + return;
209.471 +
209.472 + Object[] newTable = new Object[newLength];
209.473 + threshold = newLength / 3;
209.474 +
209.475 + for (int j = 0; j < oldLength; j += 2) {
209.476 + Object key = oldTable[j];
209.477 + if (key != null) {
209.478 + Object value = oldTable[j+1];
209.479 + oldTable[j] = null;
209.480 + oldTable[j+1] = null;
209.481 + int i = hash(key, newLength);
209.482 + while (newTable[i] != null)
209.483 + i = nextKeyIndex(i, newLength);
209.484 + newTable[i] = key;
209.485 + newTable[i + 1] = value;
209.486 + }
209.487 + }
209.488 + table = newTable;
209.489 + }
209.490 +
209.491 + /**
209.492 + * Copies all of the mappings from the specified map to this map.
209.493 + * These mappings will replace any mappings that this map had for
209.494 + * any of the keys currently in the specified map.
209.495 + *
209.496 + * @param m mappings to be stored in this map
209.497 + * @throws NullPointerException if the specified map is null
209.498 + */
209.499 + public void putAll(Map<? extends K, ? extends V> m) {
209.500 + int n = m.size();
209.501 + if (n == 0)
209.502 + return;
209.503 + if (n > threshold) // conservatively pre-expand
209.504 + resize(capacity(n));
209.505 +
209.506 + for (Entry<? extends K, ? extends V> e : m.entrySet())
209.507 + put(e.getKey(), e.getValue());
209.508 + }
209.509 +
209.510 + /**
209.511 + * Removes the mapping for this key from this map if present.
209.512 + *
209.513 + * @param key key whose mapping is to be removed from the map
209.514 + * @return the previous value associated with <tt>key</tt>, or
209.515 + * <tt>null</tt> if there was no mapping for <tt>key</tt>.
209.516 + * (A <tt>null</tt> return can also indicate that the map
209.517 + * previously associated <tt>null</tt> with <tt>key</tt>.)
209.518 + */
209.519 + public V remove(Object key) {
209.520 + Object k = maskNull(key);
209.521 + Object[] tab = table;
209.522 + int len = tab.length;
209.523 + int i = hash(k, len);
209.524 +
209.525 + while (true) {
209.526 + Object item = tab[i];
209.527 + if (item == k) {
209.528 + modCount++;
209.529 + size--;
209.530 + V oldValue = (V) tab[i + 1];
209.531 + tab[i + 1] = null;
209.532 + tab[i] = null;
209.533 + closeDeletion(i);
209.534 + return oldValue;
209.535 + }
209.536 + if (item == null)
209.537 + return null;
209.538 + i = nextKeyIndex(i, len);
209.539 + }
209.540 +
209.541 + }
209.542 +
209.543 + /**
209.544 + * Removes the specified key-value mapping from the map if it is present.
209.545 + *
209.546 + * @param key possible key
209.547 + * @param value possible value
209.548 + * @return <code>true</code> if and only if the specified key-value
209.549 + * mapping was in the map
209.550 + */
209.551 + private boolean removeMapping(Object key, Object value) {
209.552 + Object k = maskNull(key);
209.553 + Object[] tab = table;
209.554 + int len = tab.length;
209.555 + int i = hash(k, len);
209.556 +
209.557 + while (true) {
209.558 + Object item = tab[i];
209.559 + if (item == k) {
209.560 + if (tab[i + 1] != value)
209.561 + return false;
209.562 + modCount++;
209.563 + size--;
209.564 + tab[i] = null;
209.565 + tab[i + 1] = null;
209.566 + closeDeletion(i);
209.567 + return true;
209.568 + }
209.569 + if (item == null)
209.570 + return false;
209.571 + i = nextKeyIndex(i, len);
209.572 + }
209.573 + }
209.574 +
209.575 + /**
209.576 + * Rehash all possibly-colliding entries following a
209.577 + * deletion. This preserves the linear-probe
209.578 + * collision properties required by get, put, etc.
209.579 + *
209.580 + * @param d the index of a newly empty deleted slot
209.581 + */
209.582 + private void closeDeletion(int d) {
209.583 + // Adapted from Knuth Section 6.4 Algorithm R
209.584 + Object[] tab = table;
209.585 + int len = tab.length;
209.586 +
209.587 + // Look for items to swap into newly vacated slot
209.588 + // starting at index immediately following deletion,
209.589 + // and continuing until a null slot is seen, indicating
209.590 + // the end of a run of possibly-colliding keys.
209.591 + Object item;
209.592 + for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
209.593 + i = nextKeyIndex(i, len) ) {
209.594 + // The following test triggers if the item at slot i (which
209.595 + // hashes to be at slot r) should take the spot vacated by d.
209.596 + // If so, we swap it in, and then continue with d now at the
209.597 + // newly vacated i. This process will terminate when we hit
209.598 + // the null slot at the end of this run.
209.599 + // The test is messy because we are using a circular table.
209.600 + int r = hash(item, len);
209.601 + if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) {
209.602 + tab[d] = item;
209.603 + tab[d + 1] = tab[i + 1];
209.604 + tab[i] = null;
209.605 + tab[i + 1] = null;
209.606 + d = i;
209.607 + }
209.608 + }
209.609 + }
209.610 +
209.611 + /**
209.612 + * Removes all of the mappings from this map.
209.613 + * The map will be empty after this call returns.
209.614 + */
209.615 + public void clear() {
209.616 + modCount++;
209.617 + Object[] tab = table;
209.618 + for (int i = 0; i < tab.length; i++)
209.619 + tab[i] = null;
209.620 + size = 0;
209.621 + }
209.622 +
209.623 + /**
209.624 + * Compares the specified object with this map for equality. Returns
209.625 + * <tt>true</tt> if the given object is also a map and the two maps
209.626 + * represent identical object-reference mappings. More formally, this
209.627 + * map is equal to another map <tt>m</tt> if and only if
209.628 + * <tt>this.entrySet().equals(m.entrySet())</tt>.
209.629 + *
209.630 + * <p><b>Owing to the reference-equality-based semantics of this map it is
209.631 + * possible that the symmetry and transitivity requirements of the
209.632 + * <tt>Object.equals</tt> contract may be violated if this map is compared
209.633 + * to a normal map. However, the <tt>Object.equals</tt> contract is
209.634 + * guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>
209.635 + *
209.636 + * @param o object to be compared for equality with this map
209.637 + * @return <tt>true</tt> if the specified object is equal to this map
209.638 + * @see Object#equals(Object)
209.639 + */
209.640 + public boolean equals(Object o) {
209.641 + if (o == this) {
209.642 + return true;
209.643 + } else if (o instanceof IdentityHashMap) {
209.644 + IdentityHashMap m = (IdentityHashMap) o;
209.645 + if (m.size() != size)
209.646 + return false;
209.647 +
209.648 + Object[] tab = m.table;
209.649 + for (int i = 0; i < tab.length; i+=2) {
209.650 + Object k = tab[i];
209.651 + if (k != null && !containsMapping(k, tab[i + 1]))
209.652 + return false;
209.653 + }
209.654 + return true;
209.655 + } else if (o instanceof Map) {
209.656 + Map m = (Map)o;
209.657 + return entrySet().equals(m.entrySet());
209.658 + } else {
209.659 + return false; // o is not a Map
209.660 + }
209.661 + }
209.662 +
209.663 + /**
209.664 + * Returns the hash code value for this map. The hash code of a map is
209.665 + * defined to be the sum of the hash codes of each entry in the map's
209.666 + * <tt>entrySet()</tt> view. This ensures that <tt>m1.equals(m2)</tt>
209.667 + * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two
209.668 + * <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as
209.669 + * required by the general contract of {@link Object#hashCode}.
209.670 + *
209.671 + * <p><b>Owing to the reference-equality-based semantics of the
209.672 + * <tt>Map.Entry</tt> instances in the set returned by this map's
209.673 + * <tt>entrySet</tt> method, it is possible that the contractual
209.674 + * requirement of <tt>Object.hashCode</tt> mentioned in the previous
209.675 + * paragraph will be violated if one of the two objects being compared is
209.676 + * an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>
209.677 + *
209.678 + * @return the hash code value for this map
209.679 + * @see Object#equals(Object)
209.680 + * @see #equals(Object)
209.681 + */
209.682 + public int hashCode() {
209.683 + int result = 0;
209.684 + Object[] tab = table;
209.685 + for (int i = 0; i < tab.length; i +=2) {
209.686 + Object key = tab[i];
209.687 + if (key != null) {
209.688 + Object k = unmaskNull(key);
209.689 + result += System.identityHashCode(k) ^
209.690 + System.identityHashCode(tab[i + 1]);
209.691 + }
209.692 + }
209.693 + return result;
209.694 + }
209.695 +
209.696 + /**
209.697 + * Returns a shallow copy of this identity hash map: the keys and values
209.698 + * themselves are not cloned.
209.699 + *
209.700 + * @return a shallow copy of this map
209.701 + */
209.702 + public Object clone() {
209.703 + try {
209.704 + IdentityHashMap<K,V> m = (IdentityHashMap<K,V>) super.clone();
209.705 + m.entrySet = null;
209.706 + m.table = table.clone();
209.707 + return m;
209.708 + } catch (CloneNotSupportedException e) {
209.709 + throw new InternalError();
209.710 + }
209.711 + }
209.712 +
209.713 + private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
209.714 + int index = (size != 0 ? 0 : table.length); // current slot.
209.715 + int expectedModCount = modCount; // to support fast-fail
209.716 + int lastReturnedIndex = -1; // to allow remove()
209.717 + boolean indexValid; // To avoid unnecessary next computation
209.718 + Object[] traversalTable = table; // reference to main table or copy
209.719 +
209.720 + public boolean hasNext() {
209.721 + Object[] tab = traversalTable;
209.722 + for (int i = index; i < tab.length; i+=2) {
209.723 + Object key = tab[i];
209.724 + if (key != null) {
209.725 + index = i;
209.726 + return indexValid = true;
209.727 + }
209.728 + }
209.729 + index = tab.length;
209.730 + return false;
209.731 + }
209.732 +
209.733 + protected int nextIndex() {
209.734 + if (modCount != expectedModCount)
209.735 + throw new ConcurrentModificationException();
209.736 + if (!indexValid && !hasNext())
209.737 + throw new NoSuchElementException();
209.738 +
209.739 + indexValid = false;
209.740 + lastReturnedIndex = index;
209.741 + index += 2;
209.742 + return lastReturnedIndex;
209.743 + }
209.744 +
209.745 + public void remove() {
209.746 + if (lastReturnedIndex == -1)
209.747 + throw new IllegalStateException();
209.748 + if (modCount != expectedModCount)
209.749 + throw new ConcurrentModificationException();
209.750 +
209.751 + expectedModCount = ++modCount;
209.752 + int deletedSlot = lastReturnedIndex;
209.753 + lastReturnedIndex = -1;
209.754 + // back up index to revisit new contents after deletion
209.755 + index = deletedSlot;
209.756 + indexValid = false;
209.757 +
209.758 + // Removal code proceeds as in closeDeletion except that
209.759 + // it must catch the rare case where an element already
209.760 + // seen is swapped into a vacant slot that will be later
209.761 + // traversed by this iterator. We cannot allow future
209.762 + // next() calls to return it again. The likelihood of
209.763 + // this occurring under 2/3 load factor is very slim, but
209.764 + // when it does happen, we must make a copy of the rest of
209.765 + // the table to use for the rest of the traversal. Since
209.766 + // this can only happen when we are near the end of the table,
209.767 + // even in these rare cases, this is not very expensive in
209.768 + // time or space.
209.769 +
209.770 + Object[] tab = traversalTable;
209.771 + int len = tab.length;
209.772 +
209.773 + int d = deletedSlot;
209.774 + K key = (K) tab[d];
209.775 + tab[d] = null; // vacate the slot
209.776 + tab[d + 1] = null;
209.777 +
209.778 + // If traversing a copy, remove in real table.
209.779 + // We can skip gap-closure on copy.
209.780 + if (tab != IdentityHashMap.this.table) {
209.781 + IdentityHashMap.this.remove(key);
209.782 + expectedModCount = modCount;
209.783 + return;
209.784 + }
209.785 +
209.786 + size--;
209.787 +
209.788 + Object item;
209.789 + for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
209.790 + i = nextKeyIndex(i, len)) {
209.791 + int r = hash(item, len);
209.792 + // See closeDeletion for explanation of this conditional
209.793 + if ((i < r && (r <= d || d <= i)) ||
209.794 + (r <= d && d <= i)) {
209.795 +
209.796 + // If we are about to swap an already-seen element
209.797 + // into a slot that may later be returned by next(),
209.798 + // then clone the rest of table for use in future
209.799 + // next() calls. It is OK that our copy will have
209.800 + // a gap in the "wrong" place, since it will never
209.801 + // be used for searching anyway.
209.802 +
209.803 + if (i < deletedSlot && d >= deletedSlot &&
209.804 + traversalTable == IdentityHashMap.this.table) {
209.805 + int remaining = len - deletedSlot;
209.806 + Object[] newTable = new Object[remaining];
209.807 + System.arraycopy(tab, deletedSlot,
209.808 + newTable, 0, remaining);
209.809 + traversalTable = newTable;
209.810 + index = 0;
209.811 + }
209.812 +
209.813 + tab[d] = item;
209.814 + tab[d + 1] = tab[i + 1];
209.815 + tab[i] = null;
209.816 + tab[i + 1] = null;
209.817 + d = i;
209.818 + }
209.819 + }
209.820 + }
209.821 + }
209.822 +
209.823 + private class KeyIterator extends IdentityHashMapIterator<K> {
209.824 + public K next() {
209.825 + return (K) unmaskNull(traversalTable[nextIndex()]);
209.826 + }
209.827 + }
209.828 +
209.829 + private class ValueIterator extends IdentityHashMapIterator<V> {
209.830 + public V next() {
209.831 + return (V) traversalTable[nextIndex() + 1];
209.832 + }
209.833 + }
209.834 +
209.835 + private class EntryIterator
209.836 + extends IdentityHashMapIterator<Map.Entry<K,V>>
209.837 + {
209.838 + private Entry lastReturnedEntry = null;
209.839 +
209.840 + public Map.Entry<K,V> next() {
209.841 + lastReturnedEntry = new Entry(nextIndex());
209.842 + return lastReturnedEntry;
209.843 + }
209.844 +
209.845 + public void remove() {
209.846 + lastReturnedIndex =
209.847 + ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
209.848 + super.remove();
209.849 + lastReturnedEntry.index = lastReturnedIndex;
209.850 + lastReturnedEntry = null;
209.851 + }
209.852 +
209.853 + private class Entry implements Map.Entry<K,V> {
209.854 + private int index;
209.855 +
209.856 + private Entry(int index) {
209.857 + this.index = index;
209.858 + }
209.859 +
209.860 + public K getKey() {
209.861 + checkIndexForEntryUse();
209.862 + return (K) unmaskNull(traversalTable[index]);
209.863 + }
209.864 +
209.865 + public V getValue() {
209.866 + checkIndexForEntryUse();
209.867 + return (V) traversalTable[index+1];
209.868 + }
209.869 +
209.870 + public V setValue(V value) {
209.871 + checkIndexForEntryUse();
209.872 + V oldValue = (V) traversalTable[index+1];
209.873 + traversalTable[index+1] = value;
209.874 + // if shadowing, force into main table
209.875 + if (traversalTable != IdentityHashMap.this.table)
209.876 + put((K) traversalTable[index], value);
209.877 + return oldValue;
209.878 + }
209.879 +
209.880 + public boolean equals(Object o) {
209.881 + if (index < 0)
209.882 + return super.equals(o);
209.883 +
209.884 + if (!(o instanceof Map.Entry))
209.885 + return false;
209.886 + Map.Entry e = (Map.Entry)o;
209.887 + return (e.getKey() == unmaskNull(traversalTable[index]) &&
209.888 + e.getValue() == traversalTable[index+1]);
209.889 + }
209.890 +
209.891 + public int hashCode() {
209.892 + if (lastReturnedIndex < 0)
209.893 + return super.hashCode();
209.894 +
209.895 + return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
209.896 + System.identityHashCode(traversalTable[index+1]));
209.897 + }
209.898 +
209.899 + public String toString() {
209.900 + if (index < 0)
209.901 + return super.toString();
209.902 +
209.903 + return (unmaskNull(traversalTable[index]) + "="
209.904 + + traversalTable[index+1]);
209.905 + }
209.906 +
209.907 + private void checkIndexForEntryUse() {
209.908 + if (index < 0)
209.909 + throw new IllegalStateException("Entry was removed");
209.910 + }
209.911 + }
209.912 + }
209.913 +
209.914 + // Views
209.915 +
209.916 + /**
209.917 + * This field is initialized to contain an instance of the entry set
209.918 + * view the first time this view is requested. The view is stateless,
209.919 + * so there's no reason to create more than one.
209.920 + */
209.921 + private transient Set<Map.Entry<K,V>> entrySet = null;
209.922 +
209.923 + /**
209.924 + * Returns an identity-based set view of the keys contained in this map.
209.925 + * The set is backed by the map, so changes to the map are reflected in
209.926 + * the set, and vice-versa. If the map is modified while an iteration
209.927 + * over the set is in progress, the results of the iteration are
209.928 + * undefined. The set supports element removal, which removes the
209.929 + * corresponding mapping from the map, via the <tt>Iterator.remove</tt>,
209.930 + * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
209.931 + * <tt>clear</tt> methods. It does not support the <tt>add</tt> or
209.932 + * <tt>addAll</tt> methods.
209.933 + *
209.934 + * <p><b>While the object returned by this method implements the
209.935 + * <tt>Set</tt> interface, it does <i>not</i> obey <tt>Set's</tt> general
209.936 + * contract. Like its backing map, the set returned by this method
209.937 + * defines element equality as reference-equality rather than
209.938 + * object-equality. This affects the behavior of its <tt>contains</tt>,
209.939 + * <tt>remove</tt>, <tt>containsAll</tt>, <tt>equals</tt>, and
209.940 + * <tt>hashCode</tt> methods.</b>
209.941 + *
209.942 + * <p><b>The <tt>equals</tt> method of the returned set returns <tt>true</tt>
209.943 + * only if the specified object is a set containing exactly the same
209.944 + * object references as the returned set. The symmetry and transitivity
209.945 + * requirements of the <tt>Object.equals</tt> contract may be violated if
209.946 + * the set returned by this method is compared to a normal set. However,
209.947 + * the <tt>Object.equals</tt> contract is guaranteed to hold among sets
209.948 + * returned by this method.</b>
209.949 + *
209.950 + * <p>The <tt>hashCode</tt> method of the returned set returns the sum of
209.951 + * the <i>identity hashcodes</i> of the elements in the set, rather than
209.952 + * the sum of their hashcodes. This is mandated by the change in the
209.953 + * semantics of the <tt>equals</tt> method, in order to enforce the
209.954 + * general contract of the <tt>Object.hashCode</tt> method among sets
209.955 + * returned by this method.
209.956 + *
209.957 + * @return an identity-based set view of the keys contained in this map
209.958 + * @see Object#equals(Object)
209.959 + * @see System#identityHashCode(Object)
209.960 + */
209.961 + public Set<K> keySet() {
209.962 + Set<K> ks = keySet;
209.963 + if (ks != null)
209.964 + return ks;
209.965 + else
209.966 + return keySet = new KeySet();
209.967 + }
209.968 +
209.969 + private class KeySet extends AbstractSet<K> {
209.970 + public Iterator<K> iterator() {
209.971 + return new KeyIterator();
209.972 + }
209.973 + public int size() {
209.974 + return size;
209.975 + }
209.976 + public boolean contains(Object o) {
209.977 + return containsKey(o);
209.978 + }
209.979 + public boolean remove(Object o) {
209.980 + int oldSize = size;
209.981 + IdentityHashMap.this.remove(o);
209.982 + return size != oldSize;
209.983 + }
209.984 + /*
209.985 + * Must revert from AbstractSet's impl to AbstractCollection's, as
209.986 + * the former contains an optimization that results in incorrect
209.987 + * behavior when c is a smaller "normal" (non-identity-based) Set.
209.988 + */
209.989 + public boolean removeAll(Collection<?> c) {
209.990 + boolean modified = false;
209.991 + for (Iterator<K> i = iterator(); i.hasNext(); ) {
209.992 + if (c.contains(i.next())) {
209.993 + i.remove();
209.994 + modified = true;
209.995 + }
209.996 + }
209.997 + return modified;
209.998 + }
209.999 + public void clear() {
209.1000 + IdentityHashMap.this.clear();
209.1001 + }
209.1002 + public int hashCode() {
209.1003 + int result = 0;
209.1004 + for (K key : this)
209.1005 + result += System.identityHashCode(key);
209.1006 + return result;
209.1007 + }
209.1008 + }
209.1009 +
209.1010 + /**
209.1011 + * Returns a {@link Collection} view of the values contained in this map.
209.1012 + * The collection is backed by the map, so changes to the map are
209.1013 + * reflected in the collection, and vice-versa. If the map is
209.1014 + * modified while an iteration over the collection is in progress,
209.1015 + * the results of the iteration are undefined. The collection
209.1016 + * supports element removal, which removes the corresponding
209.1017 + * mapping from the map, via the <tt>Iterator.remove</tt>,
209.1018 + * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
209.1019 + * <tt>retainAll</tt> and <tt>clear</tt> methods. It does not
209.1020 + * support the <tt>add</tt> or <tt>addAll</tt> methods.
209.1021 + *
209.1022 + * <p><b>While the object returned by this method implements the
209.1023 + * <tt>Collection</tt> interface, it does <i>not</i> obey
209.1024 + * <tt>Collection's</tt> general contract. Like its backing map,
209.1025 + * the collection returned by this method defines element equality as
209.1026 + * reference-equality rather than object-equality. This affects the
209.1027 + * behavior of its <tt>contains</tt>, <tt>remove</tt> and
209.1028 + * <tt>containsAll</tt> methods.</b>
209.1029 + */
209.1030 + public Collection<V> values() {
209.1031 + Collection<V> vs = values;
209.1032 + if (vs != null)
209.1033 + return vs;
209.1034 + else
209.1035 + return values = new Values();
209.1036 + }
209.1037 +
209.1038 + private class Values extends AbstractCollection<V> {
209.1039 + public Iterator<V> iterator() {
209.1040 + return new ValueIterator();
209.1041 + }
209.1042 + public int size() {
209.1043 + return size;
209.1044 + }
209.1045 + public boolean contains(Object o) {
209.1046 + return containsValue(o);
209.1047 + }
209.1048 + public boolean remove(Object o) {
209.1049 + for (Iterator<V> i = iterator(); i.hasNext(); ) {
209.1050 + if (i.next() == o) {
209.1051 + i.remove();
209.1052 + return true;
209.1053 + }
209.1054 + }
209.1055 + return false;
209.1056 + }
209.1057 + public void clear() {
209.1058 + IdentityHashMap.this.clear();
209.1059 + }
209.1060 + }
209.1061 +
209.1062 + /**
209.1063 + * Returns a {@link Set} view of the mappings contained in this map.
209.1064 + * Each element in the returned set is a reference-equality-based
209.1065 + * <tt>Map.Entry</tt>. The set is backed by the map, so changes
209.1066 + * to the map are reflected in the set, and vice-versa. If the
209.1067 + * map is modified while an iteration over the set is in progress,
209.1068 + * the results of the iteration are undefined. The set supports
209.1069 + * element removal, which removes the corresponding mapping from
209.1070 + * the map, via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
209.1071 + * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt>
209.1072 + * methods. It does not support the <tt>add</tt> or
209.1073 + * <tt>addAll</tt> methods.
209.1074 + *
209.1075 + * <p>Like the backing map, the <tt>Map.Entry</tt> objects in the set
209.1076 + * returned by this method define key and value equality as
209.1077 + * reference-equality rather than object-equality. This affects the
209.1078 + * behavior of the <tt>equals</tt> and <tt>hashCode</tt> methods of these
209.1079 + * <tt>Map.Entry</tt> objects. A reference-equality based <tt>Map.Entry
209.1080 + * e</tt> is equal to an object <tt>o</tt> if and only if <tt>o</tt> is a
209.1081 + * <tt>Map.Entry</tt> and <tt>e.getKey()==o.getKey() &&
209.1082 + * e.getValue()==o.getValue()</tt>. To accommodate these equals
209.1083 + * semantics, the <tt>hashCode</tt> method returns
209.1084 + * <tt>System.identityHashCode(e.getKey()) ^
209.1085 + * System.identityHashCode(e.getValue())</tt>.
209.1086 + *
209.1087 + * <p><b>Owing to the reference-equality-based semantics of the
209.1088 + * <tt>Map.Entry</tt> instances in the set returned by this method,
209.1089 + * it is possible that the symmetry and transitivity requirements of
209.1090 + * the {@link Object#equals(Object)} contract may be violated if any of
209.1091 + * the entries in the set is compared to a normal map entry, or if
209.1092 + * the set returned by this method is compared to a set of normal map
209.1093 + * entries (such as would be returned by a call to this method on a normal
209.1094 + * map). However, the <tt>Object.equals</tt> contract is guaranteed to
209.1095 + * hold among identity-based map entries, and among sets of such entries.
209.1096 + * </b>
209.1097 + *
209.1098 + * @return a set view of the identity-mappings contained in this map
209.1099 + */
209.1100 + public Set<Map.Entry<K,V>> entrySet() {
209.1101 + Set<Map.Entry<K,V>> es = entrySet;
209.1102 + if (es != null)
209.1103 + return es;
209.1104 + else
209.1105 + return entrySet = new EntrySet();
209.1106 + }
209.1107 +
209.1108 + private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
209.1109 + public Iterator<Map.Entry<K,V>> iterator() {
209.1110 + return new EntryIterator();
209.1111 + }
209.1112 + public boolean contains(Object o) {
209.1113 + if (!(o instanceof Map.Entry))
209.1114 + return false;
209.1115 + Map.Entry entry = (Map.Entry)o;
209.1116 + return containsMapping(entry.getKey(), entry.getValue());
209.1117 + }
209.1118 + public boolean remove(Object o) {
209.1119 + if (!(o instanceof Map.Entry))
209.1120 + return false;
209.1121 + Map.Entry entry = (Map.Entry)o;
209.1122 + return removeMapping(entry.getKey(), entry.getValue());
209.1123 + }
209.1124 + public int size() {
209.1125 + return size;
209.1126 + }
209.1127 + public void clear() {
209.1128 + IdentityHashMap.this.clear();
209.1129 + }
209.1130 + /*
209.1131 + * Must revert from AbstractSet's impl to AbstractCollection's, as
209.1132 + * the former contains an optimization that results in incorrect
209.1133 + * behavior when c is a smaller "normal" (non-identity-based) Set.
209.1134 + */
209.1135 + public boolean removeAll(Collection<?> c) {
209.1136 + boolean modified = false;
209.1137 + for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
209.1138 + if (c.contains(i.next())) {
209.1139 + i.remove();
209.1140 + modified = true;
209.1141 + }
209.1142 + }
209.1143 + return modified;
209.1144 + }
209.1145 +
209.1146 + public Object[] toArray() {
209.1147 + int size = size();
209.1148 + Object[] result = new Object[size];
209.1149 + Iterator<Map.Entry<K,V>> it = iterator();
209.1150 + for (int i = 0; i < size; i++)
209.1151 + result[i] = new AbstractMap.SimpleEntry<>(it.next());
209.1152 + return result;
209.1153 + }
209.1154 +
209.1155 + @SuppressWarnings("unchecked")
209.1156 + public <T> T[] toArray(T[] a) {
209.1157 + int size = size();
209.1158 + if (a.length < size)
209.1159 + a = (T[])java.lang.reflect.Array
209.1160 + .newInstance(a.getClass().getComponentType(), size);
209.1161 + Iterator<Map.Entry<K,V>> it = iterator();
209.1162 + for (int i = 0; i < size; i++)
209.1163 + a[i] = (T) new AbstractMap.SimpleEntry<>(it.next());
209.1164 + if (a.length > size)
209.1165 + a[size] = null;
209.1166 + return a;
209.1167 + }
209.1168 + }
209.1169 +
209.1170 +
209.1171 + private static final long serialVersionUID = 8188218128353913216L;
209.1172 +
209.1173 + /**
209.1174 + * Save the state of the <tt>IdentityHashMap</tt> instance to a stream
209.1175 + * (i.e., serialize it).
209.1176 + *
209.1177 + * @serialData The <i>size</i> of the HashMap (the number of key-value
209.1178 + * mappings) (<tt>int</tt>), followed by the key (Object) and
209.1179 + * value (Object) for each key-value mapping represented by the
209.1180 + * IdentityHashMap. The key-value mappings are emitted in no
209.1181 + * particular order.
209.1182 + */
209.1183 + private void writeObject(java.io.ObjectOutputStream s)
209.1184 + throws java.io.IOException {
209.1185 + // Write out and any hidden stuff
209.1186 + s.defaultWriteObject();
209.1187 +
209.1188 + // Write out size (number of Mappings)
209.1189 + s.writeInt(size);
209.1190 +
209.1191 + // Write out keys and values (alternating)
209.1192 + Object[] tab = table;
209.1193 + for (int i = 0; i < tab.length; i += 2) {
209.1194 + Object key = tab[i];
209.1195 + if (key != null) {
209.1196 + s.writeObject(unmaskNull(key));
209.1197 + s.writeObject(tab[i + 1]);
209.1198 + }
209.1199 + }
209.1200 + }
209.1201 +
209.1202 + /**
209.1203 + * Reconstitute the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
209.1204 + * deserialize it).
209.1205 + */
209.1206 + private void readObject(java.io.ObjectInputStream s)
209.1207 + throws java.io.IOException, ClassNotFoundException {
209.1208 + // Read in any hidden stuff
209.1209 + s.defaultReadObject();
209.1210 +
209.1211 + // Read in size (number of Mappings)
209.1212 + int size = s.readInt();
209.1213 +
209.1214 + // Allow for 33% growth (i.e., capacity is >= 2* size()).
209.1215 + init(capacity((size*4)/3));
209.1216 +
209.1217 + // Read the keys and values, and put the mappings in the table
209.1218 + for (int i=0; i<size; i++) {
209.1219 + K key = (K) s.readObject();
209.1220 + V value = (V) s.readObject();
209.1221 + putForCreate(key, value);
209.1222 + }
209.1223 + }
209.1224 +
209.1225 + /**
209.1226 + * The put method for readObject. It does not resize the table,
209.1227 + * update modCount, etc.
209.1228 + */
209.1229 + private void putForCreate(K key, V value)
209.1230 + throws IOException
209.1231 + {
209.1232 + K k = (K)maskNull(key);
209.1233 + Object[] tab = table;
209.1234 + int len = tab.length;
209.1235 + int i = hash(k, len);
209.1236 +
209.1237 + Object item;
209.1238 + while ( (item = tab[i]) != null) {
209.1239 + if (item == k)
209.1240 + throw new java.io.StreamCorruptedException();
209.1241 + i = nextKeyIndex(i, len);
209.1242 + }
209.1243 + tab[i] = k;
209.1244 + tab[i + 1] = value;
209.1245 + }
209.1246 +}
210.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
210.2 +++ b/rt/emul/compact/src/main/java/java/util/JumboEnumSet.java Wed Apr 30 15:04:10 2014 +0200
210.3 @@ -0,0 +1,375 @@
210.4 +/*
210.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
210.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
210.7 + *
210.8 + * This code is free software; you can redistribute it and/or modify it
210.9 + * under the terms of the GNU General Public License version 2 only, as
210.10 + * published by the Free Software Foundation. Oracle designates this
210.11 + * particular file as subject to the "Classpath" exception as provided
210.12 + * by Oracle in the LICENSE file that accompanied this code.
210.13 + *
210.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
210.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
210.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
210.17 + * version 2 for more details (a copy is included in the LICENSE file that
210.18 + * accompanied this code).
210.19 + *
210.20 + * You should have received a copy of the GNU General Public License version
210.21 + * 2 along with this work; if not, write to the Free Software Foundation,
210.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
210.23 + *
210.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
210.25 + * or visit www.oracle.com if you need additional information or have any
210.26 + * questions.
210.27 + */
210.28 +
210.29 +package java.util;
210.30 +
210.31 +/**
210.32 + * Private implementation class for EnumSet, for "jumbo" enum types
210.33 + * (i.e., those with more than 64 elements).
210.34 + *
210.35 + * @author Josh Bloch
210.36 + * @since 1.5
210.37 + * @serial exclude
210.38 + */
210.39 +class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
210.40 + private static final long serialVersionUID = 334349849919042784L;
210.41 +
210.42 + /**
210.43 + * Bit vector representation of this set. The ith bit of the jth
210.44 + * element of this array represents the presence of universe[64*j +i]
210.45 + * in this set.
210.46 + */
210.47 + private long elements[];
210.48 +
210.49 + // Redundant - maintained for performance
210.50 + private int size = 0;
210.51 +
210.52 + JumboEnumSet(Class<E>elementType, Enum[] universe) {
210.53 + super(elementType, universe);
210.54 + elements = new long[(universe.length + 63) >>> 6];
210.55 + }
210.56 +
210.57 + void addRange(E from, E to) {
210.58 + int fromIndex = from.ordinal() >>> 6;
210.59 + int toIndex = to.ordinal() >>> 6;
210.60 +
210.61 + if (fromIndex == toIndex) {
210.62 + elements[fromIndex] = (-1L >>> (from.ordinal() - to.ordinal() - 1))
210.63 + << from.ordinal();
210.64 + } else {
210.65 + elements[fromIndex] = (-1L << from.ordinal());
210.66 + for (int i = fromIndex + 1; i < toIndex; i++)
210.67 + elements[i] = -1;
210.68 + elements[toIndex] = -1L >>> (63 - to.ordinal());
210.69 + }
210.70 + size = to.ordinal() - from.ordinal() + 1;
210.71 + }
210.72 +
210.73 + void addAll() {
210.74 + for (int i = 0; i < elements.length; i++)
210.75 + elements[i] = -1;
210.76 + elements[elements.length - 1] >>>= -universe.length;
210.77 + size = universe.length;
210.78 + }
210.79 +
210.80 + void complement() {
210.81 + for (int i = 0; i < elements.length; i++)
210.82 + elements[i] = ~elements[i];
210.83 + elements[elements.length - 1] &= (-1L >>> -universe.length);
210.84 + size = universe.length - size;
210.85 + }
210.86 +
210.87 + /**
210.88 + * Returns an iterator over the elements contained in this set. The
210.89 + * iterator traverses the elements in their <i>natural order</i> (which is
210.90 + * the order in which the enum constants are declared). The returned
210.91 + * Iterator is a "weakly consistent" iterator that will never throw {@link
210.92 + * ConcurrentModificationException}.
210.93 + *
210.94 + * @return an iterator over the elements contained in this set
210.95 + */
210.96 + public Iterator<E> iterator() {
210.97 + return new EnumSetIterator<>();
210.98 + }
210.99 +
210.100 + private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
210.101 + /**
210.102 + * A bit vector representing the elements in the current "word"
210.103 + * of the set not yet returned by this iterator.
210.104 + */
210.105 + long unseen;
210.106 +
210.107 + /**
210.108 + * The index corresponding to unseen in the elements array.
210.109 + */
210.110 + int unseenIndex = 0;
210.111 +
210.112 + /**
210.113 + * The bit representing the last element returned by this iterator
210.114 + * but not removed, or zero if no such element exists.
210.115 + */
210.116 + long lastReturned = 0;
210.117 +
210.118 + /**
210.119 + * The index corresponding to lastReturned in the elements array.
210.120 + */
210.121 + int lastReturnedIndex = 0;
210.122 +
210.123 + EnumSetIterator() {
210.124 + unseen = elements[0];
210.125 + }
210.126 +
210.127 + public boolean hasNext() {
210.128 + while (unseen == 0 && unseenIndex < elements.length - 1)
210.129 + unseen = elements[++unseenIndex];
210.130 + return unseen != 0;
210.131 + }
210.132 +
210.133 + public E next() {
210.134 + if (!hasNext())
210.135 + throw new NoSuchElementException();
210.136 + lastReturned = unseen & -unseen;
210.137 + lastReturnedIndex = unseenIndex;
210.138 + unseen -= lastReturned;
210.139 + return (E) universe[(lastReturnedIndex << 6)
210.140 + + Long.numberOfTrailingZeros(lastReturned)];
210.141 + }
210.142 +
210.143 + public void remove() {
210.144 + if (lastReturned == 0)
210.145 + throw new IllegalStateException();
210.146 + final long oldElements = elements[lastReturnedIndex];
210.147 + elements[lastReturnedIndex] &= ~lastReturned;
210.148 + if (oldElements != elements[lastReturnedIndex]) {
210.149 + size--;
210.150 + }
210.151 + lastReturned = 0;
210.152 + }
210.153 + }
210.154 +
210.155 + /**
210.156 + * Returns the number of elements in this set.
210.157 + *
210.158 + * @return the number of elements in this set
210.159 + */
210.160 + public int size() {
210.161 + return size;
210.162 + }
210.163 +
210.164 + /**
210.165 + * Returns <tt>true</tt> if this set contains no elements.
210.166 + *
210.167 + * @return <tt>true</tt> if this set contains no elements
210.168 + */
210.169 + public boolean isEmpty() {
210.170 + return size == 0;
210.171 + }
210.172 +
210.173 + /**
210.174 + * Returns <tt>true</tt> if this set contains the specified element.
210.175 + *
210.176 + * @param e element to be checked for containment in this collection
210.177 + * @return <tt>true</tt> if this set contains the specified element
210.178 + */
210.179 + public boolean contains(Object e) {
210.180 + if (e == null)
210.181 + return false;
210.182 + Class eClass = e.getClass();
210.183 + if (eClass != elementType && eClass.getSuperclass() != elementType)
210.184 + return false;
210.185 +
210.186 + int eOrdinal = ((Enum)e).ordinal();
210.187 + return (elements[eOrdinal >>> 6] & (1L << eOrdinal)) != 0;
210.188 + }
210.189 +
210.190 + // Modification Operations
210.191 +
210.192 + /**
210.193 + * Adds the specified element to this set if it is not already present.
210.194 + *
210.195 + * @param e element to be added to this set
210.196 + * @return <tt>true</tt> if the set changed as a result of the call
210.197 + *
210.198 + * @throws NullPointerException if <tt>e</tt> is null
210.199 + */
210.200 + public boolean add(E e) {
210.201 + typeCheck(e);
210.202 +
210.203 + int eOrdinal = e.ordinal();
210.204 + int eWordNum = eOrdinal >>> 6;
210.205 +
210.206 + long oldElements = elements[eWordNum];
210.207 + elements[eWordNum] |= (1L << eOrdinal);
210.208 + boolean result = (elements[eWordNum] != oldElements);
210.209 + if (result)
210.210 + size++;
210.211 + return result;
210.212 + }
210.213 +
210.214 + /**
210.215 + * Removes the specified element from this set if it is present.
210.216 + *
210.217 + * @param e element to be removed from this set, if present
210.218 + * @return <tt>true</tt> if the set contained the specified element
210.219 + */
210.220 + public boolean remove(Object e) {
210.221 + if (e == null)
210.222 + return false;
210.223 + Class eClass = e.getClass();
210.224 + if (eClass != elementType && eClass.getSuperclass() != elementType)
210.225 + return false;
210.226 + int eOrdinal = ((Enum)e).ordinal();
210.227 + int eWordNum = eOrdinal >>> 6;
210.228 +
210.229 + long oldElements = elements[eWordNum];
210.230 + elements[eWordNum] &= ~(1L << eOrdinal);
210.231 + boolean result = (elements[eWordNum] != oldElements);
210.232 + if (result)
210.233 + size--;
210.234 + return result;
210.235 + }
210.236 +
210.237 + // Bulk Operations
210.238 +
210.239 + /**
210.240 + * Returns <tt>true</tt> if this set contains all of the elements
210.241 + * in the specified collection.
210.242 + *
210.243 + * @param c collection to be checked for containment in this set
210.244 + * @return <tt>true</tt> if this set contains all of the elements
210.245 + * in the specified collection
210.246 + * @throws NullPointerException if the specified collection is null
210.247 + */
210.248 + public boolean containsAll(Collection<?> c) {
210.249 + if (!(c instanceof JumboEnumSet))
210.250 + return super.containsAll(c);
210.251 +
210.252 + JumboEnumSet es = (JumboEnumSet)c;
210.253 + if (es.elementType != elementType)
210.254 + return es.isEmpty();
210.255 +
210.256 + for (int i = 0; i < elements.length; i++)
210.257 + if ((es.elements[i] & ~elements[i]) != 0)
210.258 + return false;
210.259 + return true;
210.260 + }
210.261 +
210.262 + /**
210.263 + * Adds all of the elements in the specified collection to this set.
210.264 + *
210.265 + * @param c collection whose elements are to be added to this set
210.266 + * @return <tt>true</tt> if this set changed as a result of the call
210.267 + * @throws NullPointerException if the specified collection or any of
210.268 + * its elements are null
210.269 + */
210.270 + public boolean addAll(Collection<? extends E> c) {
210.271 + if (!(c instanceof JumboEnumSet))
210.272 + return super.addAll(c);
210.273 +
210.274 + JumboEnumSet es = (JumboEnumSet)c;
210.275 + if (es.elementType != elementType) {
210.276 + if (es.isEmpty())
210.277 + return false;
210.278 + else
210.279 + throw new ClassCastException(
210.280 + es.elementType + " != " + elementType);
210.281 + }
210.282 +
210.283 + for (int i = 0; i < elements.length; i++)
210.284 + elements[i] |= es.elements[i];
210.285 + return recalculateSize();
210.286 + }
210.287 +
210.288 + /**
210.289 + * Removes from this set all of its elements that are contained in
210.290 + * the specified collection.
210.291 + *
210.292 + * @param c elements to be removed from this set
210.293 + * @return <tt>true</tt> if this set changed as a result of the call
210.294 + * @throws NullPointerException if the specified collection is null
210.295 + */
210.296 + public boolean removeAll(Collection<?> c) {
210.297 + if (!(c instanceof JumboEnumSet))
210.298 + return super.removeAll(c);
210.299 +
210.300 + JumboEnumSet es = (JumboEnumSet)c;
210.301 + if (es.elementType != elementType)
210.302 + return false;
210.303 +
210.304 + for (int i = 0; i < elements.length; i++)
210.305 + elements[i] &= ~es.elements[i];
210.306 + return recalculateSize();
210.307 + }
210.308 +
210.309 + /**
210.310 + * Retains only the elements in this set that are contained in the
210.311 + * specified collection.
210.312 + *
210.313 + * @param c elements to be retained in this set
210.314 + * @return <tt>true</tt> if this set changed as a result of the call
210.315 + * @throws NullPointerException if the specified collection is null
210.316 + */
210.317 + public boolean retainAll(Collection<?> c) {
210.318 + if (!(c instanceof JumboEnumSet))
210.319 + return super.retainAll(c);
210.320 +
210.321 + JumboEnumSet<?> es = (JumboEnumSet<?>)c;
210.322 + if (es.elementType != elementType) {
210.323 + boolean changed = (size != 0);
210.324 + clear();
210.325 + return changed;
210.326 + }
210.327 +
210.328 + for (int i = 0; i < elements.length; i++)
210.329 + elements[i] &= es.elements[i];
210.330 + return recalculateSize();
210.331 + }
210.332 +
210.333 + /**
210.334 + * Removes all of the elements from this set.
210.335 + */
210.336 + public void clear() {
210.337 + Arrays.fill(elements, 0);
210.338 + size = 0;
210.339 + }
210.340 +
210.341 + /**
210.342 + * Compares the specified object with this set for equality. Returns
210.343 + * <tt>true</tt> if the given object is also a set, the two sets have
210.344 + * the same size, and every member of the given set is contained in
210.345 + * this set.
210.346 + *
210.347 + * @param e object to be compared for equality with this set
210.348 + * @return <tt>true</tt> if the specified object is equal to this set
210.349 + */
210.350 + public boolean equals(Object o) {
210.351 + if (!(o instanceof JumboEnumSet))
210.352 + return super.equals(o);
210.353 +
210.354 + JumboEnumSet es = (JumboEnumSet)o;
210.355 + if (es.elementType != elementType)
210.356 + return size == 0 && es.size == 0;
210.357 +
210.358 + return Arrays.equals(es.elements, elements);
210.359 + }
210.360 +
210.361 + /**
210.362 + * Recalculates the size of the set. Returns true if it's changed.
210.363 + */
210.364 + private boolean recalculateSize() {
210.365 + int oldSize = size;
210.366 + size = 0;
210.367 + for (long elt : elements)
210.368 + size += Long.bitCount(elt);
210.369 +
210.370 + return size != oldSize;
210.371 + }
210.372 +
210.373 + public EnumSet<E> clone() {
210.374 + JumboEnumSet<E> result = (JumboEnumSet<E>) super.clone();
210.375 + result.elements = result.elements.clone();
210.376 + return result;
210.377 + }
210.378 +}
211.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
211.2 +++ b/rt/emul/compact/src/main/java/java/util/LinkedHashSet.java Wed Apr 30 15:04:10 2014 +0200
211.3 @@ -0,0 +1,171 @@
211.4 +/*
211.5 + * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
211.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
211.7 + *
211.8 + * This code is free software; you can redistribute it and/or modify it
211.9 + * under the terms of the GNU General Public License version 2 only, as
211.10 + * published by the Free Software Foundation. Oracle designates this
211.11 + * particular file as subject to the "Classpath" exception as provided
211.12 + * by Oracle in the LICENSE file that accompanied this code.
211.13 + *
211.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
211.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
211.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
211.17 + * version 2 for more details (a copy is included in the LICENSE file that
211.18 + * accompanied this code).
211.19 + *
211.20 + * You should have received a copy of the GNU General Public License version
211.21 + * 2 along with this work; if not, write to the Free Software Foundation,
211.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
211.23 + *
211.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
211.25 + * or visit www.oracle.com if you need additional information or have any
211.26 + * questions.
211.27 + */
211.28 +
211.29 +package java.util;
211.30 +
211.31 +/**
211.32 + * <p>Hash table and linked list implementation of the <tt>Set</tt> interface,
211.33 + * with predictable iteration order. This implementation differs from
211.34 + * <tt>HashSet</tt> in that it maintains a doubly-linked list running through
211.35 + * all of its entries. This linked list defines the iteration ordering,
211.36 + * which is the order in which elements were inserted into the set
211.37 + * (<i>insertion-order</i>). Note that insertion order is <i>not</i> affected
211.38 + * if an element is <i>re-inserted</i> into the set. (An element <tt>e</tt>
211.39 + * is reinserted into a set <tt>s</tt> if <tt>s.add(e)</tt> is invoked when
211.40 + * <tt>s.contains(e)</tt> would return <tt>true</tt> immediately prior to
211.41 + * the invocation.)
211.42 + *
211.43 + * <p>This implementation spares its clients from the unspecified, generally
211.44 + * chaotic ordering provided by {@link HashSet}, without incurring the
211.45 + * increased cost associated with {@link TreeSet}. It can be used to
211.46 + * produce a copy of a set that has the same order as the original, regardless
211.47 + * of the original set's implementation:
211.48 + * <pre>
211.49 + * void foo(Set s) {
211.50 + * Set copy = new LinkedHashSet(s);
211.51 + * ...
211.52 + * }
211.53 + * </pre>
211.54 + * This technique is particularly useful if a module takes a set on input,
211.55 + * copies it, and later returns results whose order is determined by that of
211.56 + * the copy. (Clients generally appreciate having things returned in the same
211.57 + * order they were presented.)
211.58 + *
211.59 + * <p>This class provides all of the optional <tt>Set</tt> operations, and
211.60 + * permits null elements. Like <tt>HashSet</tt>, it provides constant-time
211.61 + * performance for the basic operations (<tt>add</tt>, <tt>contains</tt> and
211.62 + * <tt>remove</tt>), assuming the hash function disperses elements
211.63 + * properly among the buckets. Performance is likely to be just slightly
211.64 + * below that of <tt>HashSet</tt>, due to the added expense of maintaining the
211.65 + * linked list, with one exception: Iteration over a <tt>LinkedHashSet</tt>
211.66 + * requires time proportional to the <i>size</i> of the set, regardless of
211.67 + * its capacity. Iteration over a <tt>HashSet</tt> is likely to be more
211.68 + * expensive, requiring time proportional to its <i>capacity</i>.
211.69 + *
211.70 + * <p>A linked hash set has two parameters that affect its performance:
211.71 + * <i>initial capacity</i> and <i>load factor</i>. They are defined precisely
211.72 + * as for <tt>HashSet</tt>. Note, however, that the penalty for choosing an
211.73 + * excessively high value for initial capacity is less severe for this class
211.74 + * than for <tt>HashSet</tt>, as iteration times for this class are unaffected
211.75 + * by capacity.
211.76 + *
211.77 + * <p><strong>Note that this implementation is not synchronized.</strong>
211.78 + * If multiple threads access a linked hash set concurrently, and at least
211.79 + * one of the threads modifies the set, it <em>must</em> be synchronized
211.80 + * externally. This is typically accomplished by synchronizing on some
211.81 + * object that naturally encapsulates the set.
211.82 + *
211.83 + * If no such object exists, the set should be "wrapped" using the
211.84 + * {@link Collections#synchronizedSet Collections.synchronizedSet}
211.85 + * method. This is best done at creation time, to prevent accidental
211.86 + * unsynchronized access to the set: <pre>
211.87 + * Set s = Collections.synchronizedSet(new LinkedHashSet(...));</pre>
211.88 + *
211.89 + * <p>The iterators returned by this class's <tt>iterator</tt> method are
211.90 + * <em>fail-fast</em>: if the set is modified at any time after the iterator
211.91 + * is created, in any way except through the iterator's own <tt>remove</tt>
211.92 + * method, the iterator will throw a {@link ConcurrentModificationException}.
211.93 + * Thus, in the face of concurrent modification, the iterator fails quickly
211.94 + * and cleanly, rather than risking arbitrary, non-deterministic behavior at
211.95 + * an undetermined time in the future.
211.96 + *
211.97 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
211.98 + * as it is, generally speaking, impossible to make any hard guarantees in the
211.99 + * presence of unsynchronized concurrent modification. Fail-fast iterators
211.100 + * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
211.101 + * Therefore, it would be wrong to write a program that depended on this
211.102 + * exception for its correctness: <i>the fail-fast behavior of iterators
211.103 + * should be used only to detect bugs.</i>
211.104 + *
211.105 + * <p>This class is a member of the
211.106 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
211.107 + * Java Collections Framework</a>.
211.108 + *
211.109 + * @param <E> the type of elements maintained by this set
211.110 + *
211.111 + * @author Josh Bloch
211.112 + * @see Object#hashCode()
211.113 + * @see Collection
211.114 + * @see Set
211.115 + * @see HashSet
211.116 + * @see TreeSet
211.117 + * @see Hashtable
211.118 + * @since 1.4
211.119 + */
211.120 +
211.121 +public class LinkedHashSet<E>
211.122 + extends HashSet<E>
211.123 + implements Set<E>, Cloneable, java.io.Serializable {
211.124 +
211.125 + private static final long serialVersionUID = -2851667679971038690L;
211.126 +
211.127 + /**
211.128 + * Constructs a new, empty linked hash set with the specified initial
211.129 + * capacity and load factor.
211.130 + *
211.131 + * @param initialCapacity the initial capacity of the linked hash set
211.132 + * @param loadFactor the load factor of the linked hash set
211.133 + * @throws IllegalArgumentException if the initial capacity is less
211.134 + * than zero, or if the load factor is nonpositive
211.135 + */
211.136 + public LinkedHashSet(int initialCapacity, float loadFactor) {
211.137 + super(initialCapacity, loadFactor, true);
211.138 + }
211.139 +
211.140 + /**
211.141 + * Constructs a new, empty linked hash set with the specified initial
211.142 + * capacity and the default load factor (0.75).
211.143 + *
211.144 + * @param initialCapacity the initial capacity of the LinkedHashSet
211.145 + * @throws IllegalArgumentException if the initial capacity is less
211.146 + * than zero
211.147 + */
211.148 + public LinkedHashSet(int initialCapacity) {
211.149 + super(initialCapacity, .75f, true);
211.150 + }
211.151 +
211.152 + /**
211.153 + * Constructs a new, empty linked hash set with the default initial
211.154 + * capacity (16) and load factor (0.75).
211.155 + */
211.156 + public LinkedHashSet() {
211.157 + super(16, .75f, true);
211.158 + }
211.159 +
211.160 + /**
211.161 + * Constructs a new linked hash set with the same elements as the
211.162 + * specified collection. The linked hash set is created with an initial
211.163 + * capacity sufficient to hold the elements in the specified collection
211.164 + * and the default load factor (0.75).
211.165 + *
211.166 + * @param c the collection whose elements are to be placed into
211.167 + * this set
211.168 + * @throws NullPointerException if the specified collection is null
211.169 + */
211.170 + public LinkedHashSet(Collection<? extends E> c) {
211.171 + super(Math.max(2*c.size(), 11), .75f, true);
211.172 + addAll(c);
211.173 + }
211.174 +}
212.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
212.2 +++ b/rt/emul/compact/src/main/java/java/util/Locale.java Wed Apr 30 15:04:10 2014 +0200
212.3 @@ -0,0 +1,1012 @@
212.4 +/*
212.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
212.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
212.7 + *
212.8 + * This code is free software; you can redistribute it and/or modify it
212.9 + * under the terms of the GNU General Public License version 2 only, as
212.10 + * published by the Free Software Foundation. Oracle designates this
212.11 + * particular file as subject to the "Classpath" exception as provided
212.12 + * by Oracle in the LICENSE file that accompanied this code.
212.13 + *
212.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
212.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
212.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
212.17 + * version 2 for more details (a copy is included in the LICENSE file that
212.18 + * accompanied this code).
212.19 + *
212.20 + * You should have received a copy of the GNU General Public License version
212.21 + * 2 along with this work; if not, write to the Free Software Foundation,
212.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
212.23 + *
212.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
212.25 + * or visit www.oracle.com if you need additional information or have any
212.26 + * questions.
212.27 + */
212.28 +
212.29 +/*
212.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
212.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
212.32 + *
212.33 + * The original version of this source code and documentation
212.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
212.35 + * subsidiary of IBM. These materials are provided under terms
212.36 + * of a License Agreement between Taligent and Sun. This technology
212.37 + * is protected by multiple US and International patents.
212.38 + *
212.39 + * This notice and attribution to Taligent may not be removed.
212.40 + * Taligent is a registered trademark of Taligent, Inc.
212.41 + *
212.42 + */
212.43 +
212.44 +package java.util;
212.45 +
212.46 +import java.io.IOException;
212.47 +import java.io.ObjectInputStream;
212.48 +import java.io.ObjectOutputStream;
212.49 +import java.io.ObjectStreamField;
212.50 +import java.io.Serializable;
212.51 +
212.52 +/**
212.53 + * A <code>Locale</code> object represents a specific geographical, political,
212.54 + * or cultural region. An operation that requires a <code>Locale</code> to perform
212.55 + * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
212.56 + * to tailor information for the user. For example, displaying a number
212.57 + * is a locale-sensitive operation— the number should be formatted
212.58 + * according to the customs and conventions of the user's native country,
212.59 + * region, or culture.
212.60 + *
212.61 + * <p> The <code>Locale</code> class implements identifiers
212.62 + * interchangeable with BCP 47 (IETF BCP 47, "Tags for Identifying
212.63 + * Languages"), with support for the LDML (UTS#35, "Unicode Locale
212.64 + * Data Markup Language") BCP 47-compatible extensions for locale data
212.65 + * exchange.
212.66 + *
212.67 + * <p> A <code>Locale</code> object logically consists of the fields
212.68 + * described below.
212.69 + *
212.70 + * <dl>
212.71 + * <dt><a name="def_language"/><b>language</b></dt>
212.72 + *
212.73 + * <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
212.74 + * language subtags up to 8 alpha letters (for future enhancements).
212.75 + * When a language has both an alpha-2 code and an alpha-3 code, the
212.76 + * alpha-2 code must be used. You can find a full list of valid
212.77 + * language codes in the IANA Language Subtag Registry (search for
212.78 + * "Type: language"). The language field is case insensitive, but
212.79 + * <code>Locale</code> always canonicalizes to lower case.</dd><br>
212.80 + *
212.81 + * <dd>Well-formed language values have the form
212.82 + * <code>[a-zA-Z]{2,8}</code>. Note that this is not the the full
212.83 + * BCP47 language production, since it excludes extlang. They are
212.84 + * not needed since modern three-letter language codes replace
212.85 + * them.</dd><br>
212.86 + *
212.87 + * <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd><br>
212.88 + *
212.89 + * <dt><a name="def_script"/><b>script</b></dt>
212.90 + *
212.91 + * <dd>ISO 15924 alpha-4 script code. You can find a full list of
212.92 + * valid script codes in the IANA Language Subtag Registry (search
212.93 + * for "Type: script"). The script field is case insensitive, but
212.94 + * <code>Locale</code> always canonicalizes to title case (the first
212.95 + * letter is upper case and the rest of the letters are lower
212.96 + * case).</dd><br>
212.97 + *
212.98 + * <dd>Well-formed script values have the form
212.99 + * <code>[a-zA-Z]{4}</code></dd><br>
212.100 + *
212.101 + * <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd><br>
212.102 + *
212.103 + * <dt><a name="def_region"/><b>country (region)</b></dt>
212.104 + *
212.105 + * <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
212.106 + * You can find a full list of valid country and region codes in the
212.107 + * IANA Language Subtag Registry (search for "Type: region"). The
212.108 + * country (region) field is case insensitive, but
212.109 + * <code>Locale</code> always canonicalizes to upper case.</dd><br>
212.110 + *
212.111 + * <dd>Well-formed country/region values have
212.112 + * the form <code>[a-zA-Z]{2} | [0-9]{3}</code></dd><br>
212.113 + *
212.114 + * <dd>Example: "US" (United States), "FR" (France), "029"
212.115 + * (Caribbean)</dd><br>
212.116 + *
212.117 + * <dt><a name="def_variant"/><b>variant</b></dt>
212.118 + *
212.119 + * <dd>Any arbitrary value used to indicate a variation of a
212.120 + * <code>Locale</code>. Where there are two or more variant values
212.121 + * each indicating its own semantics, these values should be ordered
212.122 + * by importance, with most important first, separated by
212.123 + * underscore('_'). The variant field is case sensitive.</dd><br>
212.124 + *
212.125 + * <dd>Note: IETF BCP 47 places syntactic restrictions on variant
212.126 + * subtags. Also BCP 47 subtags are strictly used to indicate
212.127 + * additional variations that define a language or its dialects that
212.128 + * are not covered by any combinations of language, script and
212.129 + * region subtags. You can find a full list of valid variant codes
212.130 + * in the IANA Language Subtag Registry (search for "Type: variant").
212.131 + *
212.132 + * <p>However, the variant field in <code>Locale</code> has
212.133 + * historically been used for any kind of variation, not just
212.134 + * language variations. For example, some supported variants
212.135 + * available in Java SE Runtime Environments indicate alternative
212.136 + * cultural behaviors such as calendar type or number script. In
212.137 + * BCP 47 this kind of information, which does not identify the
212.138 + * language, is supported by extension subtags or private use
212.139 + * subtags.</dd><br>
212.140 + *
212.141 + * <dd>Well-formed variant values have the form <code>SUBTAG
212.142 + * (('_'|'-') SUBTAG)*</code> where <code>SUBTAG =
212.143 + * [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}</code>. (Note: BCP 47 only
212.144 + * uses hyphen ('-') as a delimiter, this is more lenient).</dd><br>
212.145 + *
212.146 + * <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd><br>
212.147 + *
212.148 + * <dt><a name="def_extensions"/><b>extensions</b></dt>
212.149 + *
212.150 + * <dd>A map from single character keys to string values, indicating
212.151 + * extensions apart from language identification. The extensions in
212.152 + * <code>Locale</code> implement the semantics and syntax of BCP 47
212.153 + * extension subtags and private use subtags. The extensions are
212.154 + * case insensitive, but <code>Locale</code> canonicalizes all
212.155 + * extension keys and values to lower case. Note that extensions
212.156 + * cannot have empty values.</dd><br>
212.157 + *
212.158 + * <dd>Well-formed keys are single characters from the set
212.159 + * <code>[0-9a-zA-Z]</code>. Well-formed values have the form
212.160 + * <code>SUBTAG ('-' SUBTAG)*</code> where for the key 'x'
212.161 + * <code>SUBTAG = [0-9a-zA-Z]{1,8}</code> and for other keys
212.162 + * <code>SUBTAG = [0-9a-zA-Z]{2,8}</code> (that is, 'x' allows
212.163 + * single-character subtags).</dd><br>
212.164 + *
212.165 + * <dd>Example: key="u"/value="ca-japanese" (Japanese Calendar),
212.166 + * key="x"/value="java-1-7"</dd>
212.167 + * </dl>
212.168 + *
212.169 + * <b>Note:</b> Although BCP 47 requires field values to be registered
212.170 + * in the IANA Language Subtag Registry, the <code>Locale</code> class
212.171 + * does not provide any validation features. The <code>Builder</code>
212.172 + * only checks if an individual field satisfies the syntactic
212.173 + * requirement (is well-formed), but does not validate the value
212.174 + * itself. See {@link Builder} for details.
212.175 + *
212.176 + * <h4><a name="def_locale_extension">Unicode locale/language extension</h4>
212.177 + *
212.178 + * <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
212.179 + * attributes and keywords to override or refine the default behavior
212.180 + * associated with a locale. A keyword is represented by a pair of
212.181 + * key and type. For example, "nu-thai" indicates that Thai local
212.182 + * digits (value:"thai") should be used for formatting numbers
212.183 + * (key:"nu").
212.184 + *
212.185 + * <p>The keywords are mapped to a BCP 47 extension value using the
212.186 + * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}). The above
212.187 + * example, "nu-thai", becomes the extension "u-nu-thai".code
212.188 + *
212.189 + * <p>Thus, when a <code>Locale</code> object contains Unicode locale
212.190 + * attributes and keywords,
212.191 + * <code>getExtension(UNICODE_LOCALE_EXTENSION)</code> will return a
212.192 + * String representing this information, for example, "nu-thai". The
212.193 + * <code>Locale</code> class also provides {@link
212.194 + * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and
212.195 + * {@link #getUnicodeLocaleType} which allow you to access Unicode
212.196 + * locale attributes and key/type pairs directly. When represented as
212.197 + * a string, the Unicode Locale Extension lists attributes
212.198 + * alphabetically, followed by key/type sequences with keys listed
212.199 + * alphabetically (the order of subtags comprising a key's type is
212.200 + * fixed when the type is defined)
212.201 + *
212.202 + * <p>A well-formed locale key has the form
212.203 + * <code>[0-9a-zA-Z]{2}</code>. A well-formed locale type has the
212.204 + * form <code>"" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})*</code> (it
212.205 + * can be empty, or a series of subtags 3-8 alphanums in length). A
212.206 + * well-formed locale attribute has the form
212.207 + * <code>[0-9a-zA-Z]{3,8}</code> (it is a single subtag with the same
212.208 + * form as a locale type subtag).
212.209 + *
212.210 + * <p>The Unicode locale extension specifies optional behavior in
212.211 + * locale-sensitive services. Although the LDML specification defines
212.212 + * various keys and values, actual locale-sensitive service
212.213 + * implementations in a Java Runtime Environment might not support any
212.214 + * particular Unicode locale attributes or key/type pairs.
212.215 + *
212.216 + * <h4>Creating a Locale</h4>
212.217 + *
212.218 + * <p>There are several different ways to create a <code>Locale</code>
212.219 + * object.
212.220 + *
212.221 + * <h5>Builder</h5>
212.222 + *
212.223 + * <p>Using {@link Builder} you can construct a <code>Locale</code> object
212.224 + * that conforms to BCP 47 syntax.
212.225 + *
212.226 + * <h5>Constructors</h5>
212.227 + *
212.228 + * <p>The <code>Locale</code> class provides three constructors:
212.229 + * <blockquote>
212.230 + * <pre>
212.231 + * {@link #Locale(String language)}
212.232 + * {@link #Locale(String language, String country)}
212.233 + * {@link #Locale(String language, String country, String variant)}
212.234 + * </pre>
212.235 + * </blockquote>
212.236 + * These constructors allow you to create a <code>Locale</code> object
212.237 + * with language, country and variant, but you cannot specify
212.238 + * script or extensions.
212.239 + *
212.240 + * <h5>Factory Methods</h5>
212.241 + *
212.242 + * <p>The method {@link #forLanguageTag} creates a <code>Locale</code>
212.243 + * object for a well-formed BCP 47 language tag.
212.244 + *
212.245 + * <h5>Locale Constants</h5>
212.246 + *
212.247 + * <p>The <code>Locale</code> class provides a number of convenient constants
212.248 + * that you can use to create <code>Locale</code> objects for commonly used
212.249 + * locales. For example, the following creates a <code>Locale</code> object
212.250 + * for the United States:
212.251 + * <blockquote>
212.252 + * <pre>
212.253 + * Locale.US
212.254 + * </pre>
212.255 + * </blockquote>
212.256 + *
212.257 + * <h4>Use of Locale</h4>
212.258 + *
212.259 + * <p>Once you've created a <code>Locale</code> you can query it for information
212.260 + * about itself. Use <code>getCountry</code> to get the country (or region)
212.261 + * code and <code>getLanguage</code> to get the language code.
212.262 + * You can use <code>getDisplayCountry</code> to get the
212.263 + * name of the country suitable for displaying to the user. Similarly,
212.264 + * you can use <code>getDisplayLanguage</code> to get the name of
212.265 + * the language suitable for displaying to the user. Interestingly,
212.266 + * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
212.267 + * and have two versions: one that uses the default locale and one
212.268 + * that uses the locale specified as an argument.
212.269 + *
212.270 + * <p>The Java Platform provides a number of classes that perform locale-sensitive
212.271 + * operations. For example, the <code>NumberFormat</code> class formats
212.272 + * numbers, currency, and percentages in a locale-sensitive manner. Classes
212.273 + * such as <code>NumberFormat</code> have several convenience methods
212.274 + * for creating a default object of that type. For example, the
212.275 + * <code>NumberFormat</code> class provides these three convenience methods
212.276 + * for creating a default <code>NumberFormat</code> object:
212.277 + * <blockquote>
212.278 + * <pre>
212.279 + * NumberFormat.getInstance()
212.280 + * NumberFormat.getCurrencyInstance()
212.281 + * NumberFormat.getPercentInstance()
212.282 + * </pre>
212.283 + * </blockquote>
212.284 + * Each of these methods has two variants; one with an explicit locale
212.285 + * and one without; the latter uses the default locale:
212.286 + * <blockquote>
212.287 + * <pre>
212.288 + * NumberFormat.getInstance(myLocale)
212.289 + * NumberFormat.getCurrencyInstance(myLocale)
212.290 + * NumberFormat.getPercentInstance(myLocale)
212.291 + * </pre>
212.292 + * </blockquote>
212.293 + * A <code>Locale</code> is the mechanism for identifying the kind of object
212.294 + * (<code>NumberFormat</code>) that you would like to get. The locale is
212.295 + * <STRONG>just</STRONG> a mechanism for identifying objects,
212.296 + * <STRONG>not</STRONG> a container for the objects themselves.
212.297 + *
212.298 + * <h4>Compatibility</h4>
212.299 + *
212.300 + * <p>In order to maintain compatibility with existing usage, Locale's
212.301 + * constructors retain their behavior prior to the Java Runtime
212.302 + * Environment version 1.7. The same is largely true for the
212.303 + * <code>toString</code> method. Thus Locale objects can continue to
212.304 + * be used as they were. In particular, clients who parse the output
212.305 + * of toString into language, country, and variant fields can continue
212.306 + * to do so (although this is strongly discouraged), although the
212.307 + * variant field will have additional information in it if script or
212.308 + * extensions are present.
212.309 + *
212.310 + * <p>In addition, BCP 47 imposes syntax restrictions that are not
212.311 + * imposed by Locale's constructors. This means that conversions
212.312 + * between some Locales and BCP 47 language tags cannot be made without
212.313 + * losing information. Thus <code>toLanguageTag</code> cannot
212.314 + * represent the state of locales whose language, country, or variant
212.315 + * do not conform to BCP 47.
212.316 + *
212.317 + * <p>Because of these issues, it is recommended that clients migrate
212.318 + * away from constructing non-conforming locales and use the
212.319 + * <code>forLanguageTag</code> and <code>Locale.Builder</code> APIs instead.
212.320 + * Clients desiring a string representation of the complete locale can
212.321 + * then always rely on <code>toLanguageTag</code> for this purpose.
212.322 + *
212.323 + * <h5><a name="special_cases_constructor"/>Special cases</h5>
212.324 + *
212.325 + * <p>For compatibility reasons, two
212.326 + * non-conforming locales are treated as special cases. These are
212.327 + * <b><tt>ja_JP_JP</tt></b> and <b><tt>th_TH_TH</tt></b>. These are ill-formed
212.328 + * in BCP 47 since the variants are too short. To ease migration to BCP 47,
212.329 + * these are treated specially during construction. These two cases (and only
212.330 + * these) cause a constructor to generate an extension, all other values behave
212.331 + * exactly as they did prior to Java 7.
212.332 + *
212.333 + * <p>Java has used <tt>ja_JP_JP</tt> to represent Japanese as used in
212.334 + * Japan together with the Japanese Imperial calendar. This is now
212.335 + * representable using a Unicode locale extension, by specifying the
212.336 + * Unicode locale key <tt>ca</tt> (for "calendar") and type
212.337 + * <tt>japanese</tt>. When the Locale constructor is called with the
212.338 + * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is
212.339 + * automatically added.
212.340 + *
212.341 + * <p>Java has used <tt>th_TH_TH</tt> to represent Thai as used in
212.342 + * Thailand together with Thai digits. This is also now representable using
212.343 + * a Unicode locale extension, by specifying the Unicode locale key
212.344 + * <tt>nu</tt> (for "number") and value <tt>thai</tt>. When the Locale
212.345 + * constructor is called with the arguments "th", "TH", "TH", the
212.346 + * extension "u-nu-thai" is automatically added.
212.347 + *
212.348 + * <h5>Serialization</h5>
212.349 + *
212.350 + * <p>During serialization, writeObject writes all fields to the output
212.351 + * stream, including extensions.
212.352 + *
212.353 + * <p>During deserialization, readResolve adds extensions as described
212.354 + * in <a href="#special_cases_constructor">Special Cases</a>, only
212.355 + * for the two cases th_TH_TH and ja_JP_JP.
212.356 + *
212.357 + * <h5>Legacy language codes</h5>
212.358 + *
212.359 + * <p>Locale's constructor has always converted three language codes to
212.360 + * their earlier, obsoleted forms: <tt>he</tt> maps to <tt>iw</tt>,
212.361 + * <tt>yi</tt> maps to <tt>ji</tt>, and <tt>id</tt> maps to
212.362 + * <tt>in</tt>. This continues to be the case, in order to not break
212.363 + * backwards compatibility.
212.364 + *
212.365 + * <p>The APIs added in 1.7 map between the old and new language codes,
212.366 + * maintaining the old codes internal to Locale (so that
212.367 + * <code>getLanguage</code> and <code>toString</code> reflect the old
212.368 + * code), but using the new codes in the BCP 47 language tag APIs (so
212.369 + * that <code>toLanguageTag</code> reflects the new one). This
212.370 + * preserves the equivalence between Locales no matter which code or
212.371 + * API is used to construct them. Java's default resource bundle
212.372 + * lookup mechanism also implements this mapping, so that resources
212.373 + * can be named using either convention, see {@link ResourceBundle.Control}.
212.374 + *
212.375 + * <h5>Three-letter language/country(region) codes</h5>
212.376 + *
212.377 + * <p>The Locale constructors have always specified that the language
212.378 + * and the country param be two characters in length, although in
212.379 + * practice they have accepted any length. The specification has now
212.380 + * been relaxed to allow language codes of two to eight characters and
212.381 + * country (region) codes of two to three characters, and in
212.382 + * particular, three-letter language codes and three-digit region
212.383 + * codes as specified in the IANA Language Subtag Registry. For
212.384 + * compatibility, the implementation still does not impose a length
212.385 + * constraint.
212.386 + *
212.387 + * @see Builder
212.388 + * @see ResourceBundle
212.389 + * @see java.text.Format
212.390 + * @see java.text.NumberFormat
212.391 + * @see java.text.Collator
212.392 + * @author Mark Davis
212.393 + * @since 1.1
212.394 + */
212.395 +public final class Locale implements Cloneable, Serializable {
212.396 +
212.397 + /** Useful constant for language.
212.398 + */
212.399 + static public final Locale ENGLISH = createConstant("en", "");
212.400 +
212.401 + /** Useful constant for language.
212.402 + */
212.403 + static public final Locale FRENCH = createConstant("fr", "");
212.404 +
212.405 + /** Useful constant for language.
212.406 + */
212.407 + static public final Locale GERMAN = createConstant("de", "");
212.408 +
212.409 + /** Useful constant for language.
212.410 + */
212.411 + static public final Locale ITALIAN = createConstant("it", "");
212.412 +
212.413 + /** Useful constant for language.
212.414 + */
212.415 + static public final Locale JAPANESE = createConstant("ja", "");
212.416 +
212.417 + /** Useful constant for language.
212.418 + */
212.419 + static public final Locale KOREAN = createConstant("ko", "");
212.420 +
212.421 + /** Useful constant for language.
212.422 + */
212.423 + static public final Locale CHINESE = createConstant("zh", "");
212.424 +
212.425 + /** Useful constant for language.
212.426 + */
212.427 + static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
212.428 +
212.429 + /** Useful constant for language.
212.430 + */
212.431 + static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW");
212.432 +
212.433 + /** Useful constant for country.
212.434 + */
212.435 + static public final Locale FRANCE = createConstant("fr", "FR");
212.436 +
212.437 + /** Useful constant for country.
212.438 + */
212.439 + static public final Locale GERMANY = createConstant("de", "DE");
212.440 +
212.441 + /** Useful constant for country.
212.442 + */
212.443 + static public final Locale ITALY = createConstant("it", "IT");
212.444 +
212.445 + /** Useful constant for country.
212.446 + */
212.447 + static public final Locale JAPAN = createConstant("ja", "JP");
212.448 +
212.449 + /** Useful constant for country.
212.450 + */
212.451 + static public final Locale KOREA = createConstant("ko", "KR");
212.452 +
212.453 + /** Useful constant for country.
212.454 + */
212.455 + static public final Locale CHINA = SIMPLIFIED_CHINESE;
212.456 +
212.457 + /** Useful constant for country.
212.458 + */
212.459 + static public final Locale PRC = SIMPLIFIED_CHINESE;
212.460 +
212.461 + /** Useful constant for country.
212.462 + */
212.463 + static public final Locale TAIWAN = TRADITIONAL_CHINESE;
212.464 +
212.465 + /** Useful constant for country.
212.466 + */
212.467 + static public final Locale UK = createConstant("en", "GB");
212.468 +
212.469 + /** Useful constant for country.
212.470 + */
212.471 + static public final Locale US = createConstant("en", "US");
212.472 +
212.473 + /** Useful constant for country.
212.474 + */
212.475 + static public final Locale CANADA = createConstant("en", "CA");
212.476 +
212.477 + /** Useful constant for country.
212.478 + */
212.479 + static public final Locale CANADA_FRENCH = createConstant("fr", "CA");
212.480 +
212.481 + /**
212.482 + * Useful constant for the root locale. The root locale is the locale whose
212.483 + * language, country, and variant are empty ("") strings. This is regarded
212.484 + * as the base locale of all locales, and is used as the language/country
212.485 + * neutral locale for the locale sensitive operations.
212.486 + *
212.487 + * @since 1.6
212.488 + */
212.489 + static public final Locale ROOT = createConstant("", "");
212.490 +
212.491 + /**
212.492 + * The key for the private use extension ('x').
212.493 + *
212.494 + * @see #getExtension(char)
212.495 + * @see Builder#setExtension(char, String)
212.496 + * @since 1.7
212.497 + */
212.498 + static public final char PRIVATE_USE_EXTENSION = 'x';
212.499 +
212.500 + /**
212.501 + * The key for Unicode locale extension ('u').
212.502 + *
212.503 + * @see #getExtension(char)
212.504 + * @see Builder#setExtension(char, String)
212.505 + * @since 1.7
212.506 + */
212.507 + static public final char UNICODE_LOCALE_EXTENSION = 'u';
212.508 +
212.509 + /** serialization ID
212.510 + */
212.511 + static final long serialVersionUID = 9149081749638150636L;
212.512 +
212.513 + /**
212.514 + * Display types for retrieving localized names from the name providers.
212.515 + */
212.516 + private static final int DISPLAY_LANGUAGE = 0;
212.517 + private static final int DISPLAY_COUNTRY = 1;
212.518 + private static final int DISPLAY_VARIANT = 2;
212.519 + private static final int DISPLAY_SCRIPT = 3;
212.520 +
212.521 + static Locale getInstance(String language, String script, String region, String v, Object object) {
212.522 + return new Locale(language, script, region);
212.523 + }
212.524 +
212.525 + static Locale getInstance(String no, String no0, String ny) {
212.526 + return new Locale(no, no0, ny);
212.527 + }
212.528 +
212.529 + private String language;
212.530 + private String country;
212.531 + private String variant;
212.532 +
212.533 +
212.534 + /**
212.535 + * Construct a locale from language, country and variant.
212.536 + * This constructor normalizes the language value to lowercase and
212.537 + * the country value to uppercase.
212.538 + * <p>
212.539 + * <b>Note:</b>
212.540 + * <ul>
212.541 + * <li>ISO 639 is not a stable standard; some of the language codes it defines
212.542 + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
212.543 + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
212.544 + * API on Locale will return only the OLD codes.
212.545 + * <li>For backward compatibility reasons, this constructor does not make
212.546 + * any syntactic checks on the input.
212.547 + * <li>The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially,
212.548 + * see <a href="#special_cases_constructor">Special Cases</a> for more information.
212.549 + * </ul>
212.550 + *
212.551 + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
212.552 + * up to 8 characters in length. See the <code>Locale</code> class description about
212.553 + * valid language values.
212.554 + * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
212.555 + * See the <code>Locale</code> class description about valid country values.
212.556 + * @param variant Any arbitrary value used to indicate a variation of a <code>Locale</code>.
212.557 + * See the <code>Locale</code> class description for the details.
212.558 + * @exception NullPointerException thrown if any argument is null.
212.559 + */
212.560 + public Locale(String language, String country, String variant) {
212.561 + if (language== null || country == null || variant == null) {
212.562 + throw new NullPointerException();
212.563 + }
212.564 + this.language = language;
212.565 + this.country = country;
212.566 + this.variant = variant;
212.567 + }
212.568 +
212.569 + /**
212.570 + * Construct a locale from language and country.
212.571 + * This constructor normalizes the language value to lowercase and
212.572 + * the country value to uppercase.
212.573 + * <p>
212.574 + * <b>Note:</b>
212.575 + * <ul>
212.576 + * <li>ISO 639 is not a stable standard; some of the language codes it defines
212.577 + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
212.578 + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
212.579 + * API on Locale will return only the OLD codes.
212.580 + * <li>For backward compatibility reasons, this constructor does not make
212.581 + * any syntactic checks on the input.
212.582 + * </ul>
212.583 + *
212.584 + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
212.585 + * up to 8 characters in length. See the <code>Locale</code> class description about
212.586 + * valid language values.
212.587 + * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
212.588 + * See the <code>Locale</code> class description about valid country values.
212.589 + * @exception NullPointerException thrown if either argument is null.
212.590 + */
212.591 + public Locale(String language, String country) {
212.592 + this(language, country, "");
212.593 + }
212.594 +
212.595 + /**
212.596 + * Construct a locale from a language code.
212.597 + * This constructor normalizes the language value to lowercase.
212.598 + * <p>
212.599 + * <b>Note:</b>
212.600 + * <ul>
212.601 + * <li>ISO 639 is not a stable standard; some of the language codes it defines
212.602 + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
212.603 + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
212.604 + * API on Locale will return only the OLD codes.
212.605 + * <li>For backward compatibility reasons, this constructor does not make
212.606 + * any syntactic checks on the input.
212.607 + * </ul>
212.608 + *
212.609 + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
212.610 + * up to 8 characters in length. See the <code>Locale</code> class description about
212.611 + * valid language values.
212.612 + * @exception NullPointerException thrown if argument is null.
212.613 + * @since 1.4
212.614 + */
212.615 + public Locale(String language) {
212.616 + this(language, "", "");
212.617 + }
212.618 +
212.619 + /**
212.620 + * This method must be called only for creating the Locale.*
212.621 + * constants due to making shortcuts.
212.622 + */
212.623 + private static Locale createConstant(String lang, String country) {
212.624 + return new Locale(lang, country);
212.625 + }
212.626 +
212.627 + /**
212.628 + * Gets the current value of the default locale for this instance
212.629 + * of the Java Virtual Machine.
212.630 + * <p>
212.631 + * The Java Virtual Machine sets the default locale during startup
212.632 + * based on the host environment. It is used by many locale-sensitive
212.633 + * methods if no locale is explicitly specified.
212.634 + * It can be changed using the
212.635 + * {@link #setDefault(java.util.Locale) setDefault} method.
212.636 + *
212.637 + * @return the default locale for this instance of the Java Virtual Machine
212.638 + */
212.639 + public static Locale getDefault() {
212.640 + return Locale.US;
212.641 + }
212.642 +
212.643 + /**
212.644 + * Gets the current value of the default locale for the specified Category
212.645 + * for this instance of the Java Virtual Machine.
212.646 + * <p>
212.647 + * The Java Virtual Machine sets the default locale during startup based
212.648 + * on the host environment. It is used by many locale-sensitive methods
212.649 + * if no locale is explicitly specified. It can be changed using the
212.650 + * setDefault(Locale.Category, Locale) method.
212.651 + *
212.652 + * @param category - the specified category to get the default locale
212.653 + * @throws NullPointerException - if category is null
212.654 + * @return the default locale for the specified Category for this instance
212.655 + * of the Java Virtual Machine
212.656 + * @see #setDefault(Locale.Category, Locale)
212.657 + * @since 1.7
212.658 + */
212.659 + public static Locale getDefault(Locale.Category category) {
212.660 + return Locale.US;
212.661 + }
212.662 +
212.663 + /**
212.664 + * Sets the default locale for this instance of the Java Virtual Machine.
212.665 + * This does not affect the host locale.
212.666 + * <p>
212.667 + * If there is a security manager, its <code>checkPermission</code>
212.668 + * method is called with a <code>PropertyPermission("user.language", "write")</code>
212.669 + * permission before the default locale is changed.
212.670 + * <p>
212.671 + * The Java Virtual Machine sets the default locale during startup
212.672 + * based on the host environment. It is used by many locale-sensitive
212.673 + * methods if no locale is explicitly specified.
212.674 + * <p>
212.675 + * Since changing the default locale may affect many different areas
212.676 + * of functionality, this method should only be used if the caller
212.677 + * is prepared to reinitialize locale-sensitive code running
212.678 + * within the same Java Virtual Machine.
212.679 + * <p>
212.680 + * By setting the default locale with this method, all of the default
212.681 + * locales for each Category are also set to the specified default locale.
212.682 + *
212.683 + * @throws SecurityException
212.684 + * if a security manager exists and its
212.685 + * <code>checkPermission</code> method doesn't allow the operation.
212.686 + * @throws NullPointerException if <code>newLocale</code> is null
212.687 + * @param newLocale the new default locale
212.688 + * @see SecurityManager#checkPermission
212.689 + * @see java.util.PropertyPermission
212.690 + */
212.691 + public static void setDefault(Locale newLocale) {
212.692 + throw new SecurityException();
212.693 + }
212.694 +
212.695 + /**
212.696 + * Returns an array of all installed locales.
212.697 + * The returned array represents the union of locales supported
212.698 + * by the Java runtime environment and by installed
212.699 + * {@link java.util.spi.LocaleServiceProvider LocaleServiceProvider}
212.700 + * implementations. It must contain at least a <code>Locale</code>
212.701 + * instance equal to {@link java.util.Locale#US Locale.US}.
212.702 + *
212.703 + * @return An array of installed locales.
212.704 + */
212.705 + public static Locale[] getAvailableLocales() {
212.706 + return new Locale[] { Locale.US };
212.707 + }
212.708 +
212.709 + /**
212.710 + * Returns the language code of this Locale.
212.711 + *
212.712 + * <p><b>Note:</b> ISO 639 is not a stable standard— some languages' codes have changed.
212.713 + * Locale's constructor recognizes both the new and the old codes for the languages
212.714 + * whose codes have changed, but this function always returns the old code. If you
212.715 + * want to check for a specific language whose code has changed, don't do
212.716 + * <pre>
212.717 + * if (locale.getLanguage().equals("he")) // BAD!
212.718 + * ...
212.719 + * </pre>
212.720 + * Instead, do
212.721 + * <pre>
212.722 + * if (locale.getLanguage().equals(new Locale("he").getLanguage()))
212.723 + * ...
212.724 + * </pre>
212.725 + * @return The language code, or the empty string if none is defined.
212.726 + * @see #getDisplayLanguage
212.727 + */
212.728 + public String getLanguage() {
212.729 + return language;
212.730 + }
212.731 +
212.732 + /**
212.733 + * Returns the script for this locale, which should
212.734 + * either be the empty string or an ISO 15924 4-letter script
212.735 + * code. The first letter is uppercase and the rest are
212.736 + * lowercase, for example, 'Latn', 'Cyrl'.
212.737 + *
212.738 + * @return The script code, or the empty string if none is defined.
212.739 + * @see #getDisplayScript
212.740 + * @since 1.7
212.741 + */
212.742 + public String getScript() {
212.743 + return "";
212.744 + }
212.745 +
212.746 + /**
212.747 + * Returns the country/region code for this locale, which should
212.748 + * either be the empty string, an uppercase ISO 3166 2-letter code,
212.749 + * or a UN M.49 3-digit code.
212.750 + *
212.751 + * @return The country/region code, or the empty string if none is defined.
212.752 + * @see #getDisplayCountry
212.753 + */
212.754 + public String getCountry() {
212.755 + return country;
212.756 + }
212.757 +
212.758 + /**
212.759 + * Returns the variant code for this locale.
212.760 + *
212.761 + * @return The variant code, or the empty string if none is defined.
212.762 + * @see #getDisplayVariant
212.763 + */
212.764 + public String getVariant() {
212.765 + return variant;
212.766 + }
212.767 +
212.768 + String getRegion() {
212.769 + return getCountry();
212.770 + }
212.771 +
212.772 + /**
212.773 + * Returns the extension (or private use) value associated with
212.774 + * the specified key, or null if there is no extension
212.775 + * associated with the key. To be well-formed, the key must be one
212.776 + * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
212.777 + * for example 'z' and 'Z' represent the same extension.
212.778 + *
212.779 + * @param key the extension key
212.780 + * @return The extension, or null if this locale defines no
212.781 + * extension for the specified key.
212.782 + * @throws IllegalArgumentException if key is not well-formed
212.783 + * @see #PRIVATE_USE_EXTENSION
212.784 + * @see #UNICODE_LOCALE_EXTENSION
212.785 + * @since 1.7
212.786 + */
212.787 + public String getExtension(char key) {
212.788 + return null;
212.789 + }
212.790 +
212.791 + /**
212.792 + * Returns the set of extension keys associated with this locale, or the
212.793 + * empty set if it has no extensions. The returned set is unmodifiable.
212.794 + * The keys will all be lower-case.
212.795 + *
212.796 + * @return The set of extension keys, or the empty set if this locale has
212.797 + * no extensions.
212.798 + * @since 1.7
212.799 + */
212.800 + public Set<Character> getExtensionKeys() {
212.801 + return Collections.emptySet();
212.802 + }
212.803 +
212.804 + /**
212.805 + * Returns the set of unicode locale attributes associated with
212.806 + * this locale, or the empty set if it has no attributes. The
212.807 + * returned set is unmodifiable.
212.808 + *
212.809 + * @return The set of attributes.
212.810 + * @since 1.7
212.811 + */
212.812 + public Set<String> getUnicodeLocaleAttributes() {
212.813 + return Collections.emptySet();
212.814 + }
212.815 +
212.816 + /**
212.817 + * Returns the Unicode locale type associated with the specified Unicode locale key
212.818 + * for this locale. Returns the empty string for keys that are defined with no type.
212.819 + * Returns null if the key is not defined. Keys are case-insensitive. The key must
212.820 + * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
212.821 + * thrown.
212.822 + *
212.823 + * @param key the Unicode locale key
212.824 + * @return The Unicode locale type associated with the key, or null if the
212.825 + * locale does not define the key.
212.826 + * @throws IllegalArgumentException if the key is not well-formed
212.827 + * @throws NullPointerException if <code>key</code> is null
212.828 + * @since 1.7
212.829 + */
212.830 + public String getUnicodeLocaleType(String key) {
212.831 + return null;
212.832 + }
212.833 +
212.834 + /**
212.835 + * Returns the set of Unicode locale keys defined by this locale, or the empty set if
212.836 + * this locale has none. The returned set is immutable. Keys are all lower case.
212.837 + *
212.838 + * @return The set of Unicode locale keys, or the empty set if this locale has
212.839 + * no Unicode locale keywords.
212.840 + * @since 1.7
212.841 + */
212.842 + public Set<String> getUnicodeLocaleKeys() {
212.843 + return Collections.emptySet();
212.844 + }
212.845 +
212.846 + /**
212.847 + * Returns a string representation of this <code>Locale</code>
212.848 + * object, consisting of language, country, variant, script,
212.849 + * and extensions as below:
212.850 + * <p><blockquote>
212.851 + * language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions
212.852 + * </blockquote>
212.853 + *
212.854 + * Language is always lower case, country is always upper case, script is always title
212.855 + * case, and extensions are always lower case. Extensions and private use subtags
212.856 + * will be in canonical order as explained in {@link #toLanguageTag}.
212.857 + *
212.858 + * <p>When the locale has neither script nor extensions, the result is the same as in
212.859 + * Java 6 and prior.
212.860 + *
212.861 + * <p>If both the language and country fields are missing, this function will return
212.862 + * the empty string, even if the variant, script, or extensions field is present (you
212.863 + * can't have a locale with just a variant, the variant must accompany a well-formed
212.864 + * language or country code).
212.865 + *
212.866 + * <p>If script or extensions are present and variant is missing, no underscore is
212.867 + * added before the "#".
212.868 + *
212.869 + * <p>This behavior is designed to support debugging and to be compatible with
212.870 + * previous uses of <code>toString</code> that expected language, country, and variant
212.871 + * fields only. To represent a Locale as a String for interchange purposes, use
212.872 + * {@link #toLanguageTag}.
212.873 + *
212.874 + * <p>Examples: <ul><tt>
212.875 + * <li>en
212.876 + * <li>de_DE
212.877 + * <li>_GB
212.878 + * <li>en_US_WIN
212.879 + * <li>de__POSIX
212.880 + * <li>zh_CN_#Hans
212.881 + * <li>zh_TW_#Hant-x-java
212.882 + * <li>th_TH_TH_#u-nu-thai</tt></ul>
212.883 + *
212.884 + * @return A string representation of the Locale, for debugging.
212.885 + * @see #getDisplayName
212.886 + * @see #toLanguageTag
212.887 + */
212.888 + @Override
212.889 + public final String toString() {
212.890 + Locale baseLocale = this;
212.891 + boolean l = (baseLocale.getLanguage().length() != 0);
212.892 + boolean s = (baseLocale.getScript().length() != 0);
212.893 + boolean r = (baseLocale.getRegion().length() != 0);
212.894 + boolean v = (baseLocale.getVariant().length() != 0);
212.895 + boolean e = false; //(localeExtensions != null && localeExtensions.getID().length() != 0);
212.896 +
212.897 + StringBuilder result = new StringBuilder(baseLocale.getLanguage());
212.898 + if (r || (l && (v || s || e))) {
212.899 + result.append('_')
212.900 + .append(baseLocale.getRegion()); // This may just append '_'
212.901 + }
212.902 + if (v && (l || r)) {
212.903 + result.append('_')
212.904 + .append(baseLocale.getVariant());
212.905 + }
212.906 +
212.907 + if (s && (l || r)) {
212.908 + result.append("_#")
212.909 + .append(baseLocale.getScript());
212.910 + }
212.911 +
212.912 + if (e && (l || r)) {
212.913 + result.append('_');
212.914 + if (!s) {
212.915 + result.append('#');
212.916 + }
212.917 +// result.append(localeExtensions.getID());
212.918 + }
212.919 +
212.920 + return result.toString();
212.921 + }
212.922 +
212.923 +
212.924 + /**
212.925 + * Overrides Cloneable.
212.926 + */
212.927 + public Object clone()
212.928 + {
212.929 + try {
212.930 + Locale that = (Locale)super.clone();
212.931 + return that;
212.932 + } catch (CloneNotSupportedException e) {
212.933 + throw new InternalError();
212.934 + }
212.935 + }
212.936 +
212.937 + /**
212.938 + * Override hashCode.
212.939 + * Since Locales are often used in hashtables, caches the value
212.940 + * for speed.
212.941 + */
212.942 + @Override
212.943 + public int hashCode() {
212.944 + int hash = 3;
212.945 + hash = 43 * hash + Objects.hashCode(this.language);
212.946 + hash = 43 * hash + Objects.hashCode(this.country);
212.947 + hash = 43 * hash + Objects.hashCode(this.variant);
212.948 + return hash;
212.949 + }
212.950 +
212.951 + // Overrides
212.952 + @Override
212.953 + public boolean equals(Object obj) {
212.954 + if (obj == null) {
212.955 + return false;
212.956 + }
212.957 + if (getClass() != obj.getClass()) {
212.958 + return false;
212.959 + }
212.960 + final Locale other = (Locale) obj;
212.961 + if (!Objects.equals(this.language, other.language)) {
212.962 + return false;
212.963 + }
212.964 + if (!Objects.equals(this.country, other.country)) {
212.965 + return false;
212.966 + }
212.967 + if (!Objects.equals(this.variant, other.variant)) {
212.968 + return false;
212.969 + }
212.970 + return true;
212.971 + }
212.972 +
212.973 + /**
212.974 + * Enum for locale categories. These locale categories are used to get/set
212.975 + * the default locale for the specific functionality represented by the
212.976 + * category.
212.977 + *
212.978 + * @see #getDefault(Locale.Category)
212.979 + * @see #setDefault(Locale.Category, Locale)
212.980 + * @since 1.7
212.981 + */
212.982 + public enum Category {
212.983 +
212.984 + /**
212.985 + * Category used to represent the default locale for
212.986 + * displaying user interfaces.
212.987 + */
212.988 + DISPLAY("user.language.display",
212.989 + "user.script.display",
212.990 + "user.country.display",
212.991 + "user.variant.display"),
212.992 +
212.993 + /**
212.994 + * Category used to represent the default locale for
212.995 + * formatting dates, numbers, and/or currencies.
212.996 + */
212.997 + FORMAT("user.language.format",
212.998 + "user.script.format",
212.999 + "user.country.format",
212.1000 + "user.variant.format");
212.1001 +
212.1002 + Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
212.1003 + this.languageKey = languageKey;
212.1004 + this.scriptKey = scriptKey;
212.1005 + this.countryKey = countryKey;
212.1006 + this.variantKey = variantKey;
212.1007 + }
212.1008 +
212.1009 + final String languageKey;
212.1010 + final String scriptKey;
212.1011 + final String countryKey;
212.1012 + final String variantKey;
212.1013 + }
212.1014 +
212.1015 +}
213.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
213.2 +++ b/rt/emul/compact/src/main/java/java/util/MissingResourceException.java Wed Apr 30 15:04:10 2014 +0200
213.3 @@ -0,0 +1,124 @@
213.4 +/*
213.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
213.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
213.7 + *
213.8 + * This code is free software; you can redistribute it and/or modify it
213.9 + * under the terms of the GNU General Public License version 2 only, as
213.10 + * published by the Free Software Foundation. Oracle designates this
213.11 + * particular file as subject to the "Classpath" exception as provided
213.12 + * by Oracle in the LICENSE file that accompanied this code.
213.13 + *
213.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
213.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
213.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
213.17 + * version 2 for more details (a copy is included in the LICENSE file that
213.18 + * accompanied this code).
213.19 + *
213.20 + * You should have received a copy of the GNU General Public License version
213.21 + * 2 along with this work; if not, write to the Free Software Foundation,
213.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
213.23 + *
213.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
213.25 + * or visit www.oracle.com if you need additional information or have any
213.26 + * questions.
213.27 + */
213.28 +
213.29 +/*
213.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
213.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
213.32 + *
213.33 + * The original version of this source code and documentation
213.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
213.35 + * subsidiary of IBM. These materials are provided under terms
213.36 + * of a License Agreement between Taligent and Sun. This technology
213.37 + * is protected by multiple US and International patents.
213.38 + *
213.39 + * This notice and attribution to Taligent may not be removed.
213.40 + * Taligent is a registered trademark of Taligent, Inc.
213.41 + *
213.42 + */
213.43 +
213.44 +package java.util;
213.45 +
213.46 +/**
213.47 + * Signals that a resource is missing.
213.48 + * @see java.lang.Exception
213.49 + * @see ResourceBundle
213.50 + * @author Mark Davis
213.51 + * @since JDK1.1
213.52 + */
213.53 +public
213.54 +class MissingResourceException extends RuntimeException {
213.55 +
213.56 + /**
213.57 + * Constructs a MissingResourceException with the specified information.
213.58 + * A detail message is a String that describes this particular exception.
213.59 + * @param s the detail message
213.60 + * @param className the name of the resource class
213.61 + * @param key the key for the missing resource.
213.62 + */
213.63 + public MissingResourceException(String s, String className, String key) {
213.64 + super(s);
213.65 + this.className = className;
213.66 + this.key = key;
213.67 + }
213.68 +
213.69 + /**
213.70 + * Constructs a <code>MissingResourceException</code> with
213.71 + * <code>message</code>, <code>className</code>, <code>key</code>,
213.72 + * and <code>cause</code>. This constructor is package private for
213.73 + * use by <code>ResourceBundle.getBundle</code>.
213.74 + *
213.75 + * @param message
213.76 + * the detail message
213.77 + * @param className
213.78 + * the name of the resource class
213.79 + * @param key
213.80 + * the key for the missing resource.
213.81 + * @param cause
213.82 + * the cause (which is saved for later retrieval by the
213.83 + * {@link Throwable.getCause()} method). (A null value is
213.84 + * permitted, and indicates that the cause is nonexistent
213.85 + * or unknown.)
213.86 + */
213.87 + MissingResourceException(String message, String className, String key, Throwable cause) {
213.88 + super(message, cause);
213.89 + this.className = className;
213.90 + this.key = key;
213.91 + }
213.92 +
213.93 + /**
213.94 + * Gets parameter passed by constructor.
213.95 + *
213.96 + * @return the name of the resource class
213.97 + */
213.98 + public String getClassName() {
213.99 + return className;
213.100 + }
213.101 +
213.102 + /**
213.103 + * Gets parameter passed by constructor.
213.104 + *
213.105 + * @return the key for the missing resource
213.106 + */
213.107 + public String getKey() {
213.108 + return key;
213.109 + }
213.110 +
213.111 + //============ privates ============
213.112 +
213.113 + // serialization compatibility with JDK1.1
213.114 + private static final long serialVersionUID = -4876345176062000401L;
213.115 +
213.116 + /**
213.117 + * The class name of the resource bundle requested by the user.
213.118 + * @serial
213.119 + */
213.120 + private String className;
213.121 +
213.122 + /**
213.123 + * The name of the specific resource requested by the user.
213.124 + * @serial
213.125 + */
213.126 + private String key;
213.127 +}
214.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
214.2 +++ b/rt/emul/compact/src/main/java/java/util/NavigableMap.java Wed Apr 30 15:04:10 2014 +0200
214.3 @@ -0,0 +1,424 @@
214.4 +/*
214.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
214.6 + *
214.7 + * This code is free software; you can redistribute it and/or modify it
214.8 + * under the terms of the GNU General Public License version 2 only, as
214.9 + * published by the Free Software Foundation. Oracle designates this
214.10 + * particular file as subject to the "Classpath" exception as provided
214.11 + * by Oracle in the LICENSE file that accompanied this code.
214.12 + *
214.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
214.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
214.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
214.16 + * version 2 for more details (a copy is included in the LICENSE file that
214.17 + * accompanied this code).
214.18 + *
214.19 + * You should have received a copy of the GNU General Public License version
214.20 + * 2 along with this work; if not, write to the Free Software Foundation,
214.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
214.22 + *
214.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
214.24 + * or visit www.oracle.com if you need additional information or have any
214.25 + * questions.
214.26 + */
214.27 +
214.28 +/*
214.29 + * This file is available under and governed by the GNU General Public
214.30 + * License version 2 only, as published by the Free Software Foundation.
214.31 + * However, the following notice accompanied the original version of this
214.32 + * file:
214.33 + *
214.34 + * Written by Doug Lea and Josh Bloch with assistance from members of JCP
214.35 + * JSR-166 Expert Group and released to the public domain, as explained at
214.36 + * http://creativecommons.org/publicdomain/zero/1.0/
214.37 + */
214.38 +
214.39 +package java.util;
214.40 +
214.41 +/**
214.42 + * A {@link SortedMap} extended with navigation methods returning the
214.43 + * closest matches for given search targets. Methods
214.44 + * {@code lowerEntry}, {@code floorEntry}, {@code ceilingEntry},
214.45 + * and {@code higherEntry} return {@code Map.Entry} objects
214.46 + * associated with keys respectively less than, less than or equal,
214.47 + * greater than or equal, and greater than a given key, returning
214.48 + * {@code null} if there is no such key. Similarly, methods
214.49 + * {@code lowerKey}, {@code floorKey}, {@code ceilingKey}, and
214.50 + * {@code higherKey} return only the associated keys. All of these
214.51 + * methods are designed for locating, not traversing entries.
214.52 + *
214.53 + * <p>A {@code NavigableMap} may be accessed and traversed in either
214.54 + * ascending or descending key order. The {@code descendingMap}
214.55 + * method returns a view of the map with the senses of all relational
214.56 + * and directional methods inverted. The performance of ascending
214.57 + * operations and views is likely to be faster than that of descending
214.58 + * ones. Methods {@code subMap}, {@code headMap},
214.59 + * and {@code tailMap} differ from the like-named {@code
214.60 + * SortedMap} methods in accepting additional arguments describing
214.61 + * whether lower and upper bounds are inclusive versus exclusive.
214.62 + * Submaps of any {@code NavigableMap} must implement the {@code
214.63 + * NavigableMap} interface.
214.64 + *
214.65 + * <p>This interface additionally defines methods {@code firstEntry},
214.66 + * {@code pollFirstEntry}, {@code lastEntry}, and
214.67 + * {@code pollLastEntry} that return and/or remove the least and
214.68 + * greatest mappings, if any exist, else returning {@code null}.
214.69 + *
214.70 + * <p>Implementations of entry-returning methods are expected to
214.71 + * return {@code Map.Entry} pairs representing snapshots of mappings
214.72 + * at the time they were produced, and thus generally do <em>not</em>
214.73 + * support the optional {@code Entry.setValue} method. Note however
214.74 + * that it is possible to change mappings in the associated map using
214.75 + * method {@code put}.
214.76 + *
214.77 + * <p>Methods
214.78 + * {@link #subMap(Object, Object) subMap(K, K)},
214.79 + * {@link #headMap(Object) headMap(K)}, and
214.80 + * {@link #tailMap(Object) tailMap(K)}
214.81 + * are specified to return {@code SortedMap} to allow existing
214.82 + * implementations of {@code SortedMap} to be compatibly retrofitted to
214.83 + * implement {@code NavigableMap}, but extensions and implementations
214.84 + * of this interface are encouraged to override these methods to return
214.85 + * {@code NavigableMap}. Similarly,
214.86 + * {@link #keySet()} can be overriden to return {@code NavigableSet}.
214.87 + *
214.88 + * <p>This interface is a member of the
214.89 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
214.90 + * Java Collections Framework</a>.
214.91 + *
214.92 + * @author Doug Lea
214.93 + * @author Josh Bloch
214.94 + * @param <K> the type of keys maintained by this map
214.95 + * @param <V> the type of mapped values
214.96 + * @since 1.6
214.97 + */
214.98 +public interface NavigableMap<K,V> extends SortedMap<K,V> {
214.99 + /**
214.100 + * Returns a key-value mapping associated with the greatest key
214.101 + * strictly less than the given key, or {@code null} if there is
214.102 + * no such key.
214.103 + *
214.104 + * @param key the key
214.105 + * @return an entry with the greatest key less than {@code key},
214.106 + * or {@code null} if there is no such key
214.107 + * @throws ClassCastException if the specified key cannot be compared
214.108 + * with the keys currently in the map
214.109 + * @throws NullPointerException if the specified key is null
214.110 + * and this map does not permit null keys
214.111 + */
214.112 + Map.Entry<K,V> lowerEntry(K key);
214.113 +
214.114 + /**
214.115 + * Returns the greatest key strictly less than the given key, or
214.116 + * {@code null} if there is no such key.
214.117 + *
214.118 + * @param key the key
214.119 + * @return the greatest key less than {@code key},
214.120 + * or {@code null} if there is no such key
214.121 + * @throws ClassCastException if the specified key cannot be compared
214.122 + * with the keys currently in the map
214.123 + * @throws NullPointerException if the specified key is null
214.124 + * and this map does not permit null keys
214.125 + */
214.126 + K lowerKey(K key);
214.127 +
214.128 + /**
214.129 + * Returns a key-value mapping associated with the greatest key
214.130 + * less than or equal to the given key, or {@code null} if there
214.131 + * is no such key.
214.132 + *
214.133 + * @param key the key
214.134 + * @return an entry with the greatest key less than or equal to
214.135 + * {@code key}, or {@code null} if there is no such key
214.136 + * @throws ClassCastException if the specified key cannot be compared
214.137 + * with the keys currently in the map
214.138 + * @throws NullPointerException if the specified key is null
214.139 + * and this map does not permit null keys
214.140 + */
214.141 + Map.Entry<K,V> floorEntry(K key);
214.142 +
214.143 + /**
214.144 + * Returns the greatest key less than or equal to the given key,
214.145 + * or {@code null} if there is no such key.
214.146 + *
214.147 + * @param key the key
214.148 + * @return the greatest key less than or equal to {@code key},
214.149 + * or {@code null} if there is no such key
214.150 + * @throws ClassCastException if the specified key cannot be compared
214.151 + * with the keys currently in the map
214.152 + * @throws NullPointerException if the specified key is null
214.153 + * and this map does not permit null keys
214.154 + */
214.155 + K floorKey(K key);
214.156 +
214.157 + /**
214.158 + * Returns a key-value mapping associated with the least key
214.159 + * greater than or equal to the given key, or {@code null} if
214.160 + * there is no such key.
214.161 + *
214.162 + * @param key the key
214.163 + * @return an entry with the least key greater than or equal to
214.164 + * {@code key}, or {@code null} if there is no such key
214.165 + * @throws ClassCastException if the specified key cannot be compared
214.166 + * with the keys currently in the map
214.167 + * @throws NullPointerException if the specified key is null
214.168 + * and this map does not permit null keys
214.169 + */
214.170 + Map.Entry<K,V> ceilingEntry(K key);
214.171 +
214.172 + /**
214.173 + * Returns the least key greater than or equal to the given key,
214.174 + * or {@code null} if there is no such key.
214.175 + *
214.176 + * @param key the key
214.177 + * @return the least key greater than or equal to {@code key},
214.178 + * or {@code null} if there is no such key
214.179 + * @throws ClassCastException if the specified key cannot be compared
214.180 + * with the keys currently in the map
214.181 + * @throws NullPointerException if the specified key is null
214.182 + * and this map does not permit null keys
214.183 + */
214.184 + K ceilingKey(K key);
214.185 +
214.186 + /**
214.187 + * Returns a key-value mapping associated with the least key
214.188 + * strictly greater than the given key, or {@code null} if there
214.189 + * is no such key.
214.190 + *
214.191 + * @param key the key
214.192 + * @return an entry with the least key greater than {@code key},
214.193 + * or {@code null} if there is no such key
214.194 + * @throws ClassCastException if the specified key cannot be compared
214.195 + * with the keys currently in the map
214.196 + * @throws NullPointerException if the specified key is null
214.197 + * and this map does not permit null keys
214.198 + */
214.199 + Map.Entry<K,V> higherEntry(K key);
214.200 +
214.201 + /**
214.202 + * Returns the least key strictly greater than the given key, or
214.203 + * {@code null} if there is no such key.
214.204 + *
214.205 + * @param key the key
214.206 + * @return the least key greater than {@code key},
214.207 + * or {@code null} if there is no such key
214.208 + * @throws ClassCastException if the specified key cannot be compared
214.209 + * with the keys currently in the map
214.210 + * @throws NullPointerException if the specified key is null
214.211 + * and this map does not permit null keys
214.212 + */
214.213 + K higherKey(K key);
214.214 +
214.215 + /**
214.216 + * Returns a key-value mapping associated with the least
214.217 + * key in this map, or {@code null} if the map is empty.
214.218 + *
214.219 + * @return an entry with the least key,
214.220 + * or {@code null} if this map is empty
214.221 + */
214.222 + Map.Entry<K,V> firstEntry();
214.223 +
214.224 + /**
214.225 + * Returns a key-value mapping associated with the greatest
214.226 + * key in this map, or {@code null} if the map is empty.
214.227 + *
214.228 + * @return an entry with the greatest key,
214.229 + * or {@code null} if this map is empty
214.230 + */
214.231 + Map.Entry<K,V> lastEntry();
214.232 +
214.233 + /**
214.234 + * Removes and returns a key-value mapping associated with
214.235 + * the least key in this map, or {@code null} if the map is empty.
214.236 + *
214.237 + * @return the removed first entry of this map,
214.238 + * or {@code null} if this map is empty
214.239 + */
214.240 + Map.Entry<K,V> pollFirstEntry();
214.241 +
214.242 + /**
214.243 + * Removes and returns a key-value mapping associated with
214.244 + * the greatest key in this map, or {@code null} if the map is empty.
214.245 + *
214.246 + * @return the removed last entry of this map,
214.247 + * or {@code null} if this map is empty
214.248 + */
214.249 + Map.Entry<K,V> pollLastEntry();
214.250 +
214.251 + /**
214.252 + * Returns a reverse order view of the mappings contained in this map.
214.253 + * The descending map is backed by this map, so changes to the map are
214.254 + * reflected in the descending map, and vice-versa. If either map is
214.255 + * modified while an iteration over a collection view of either map
214.256 + * is in progress (except through the iterator's own {@code remove}
214.257 + * operation), the results of the iteration are undefined.
214.258 + *
214.259 + * <p>The returned map has an ordering equivalent to
214.260 + * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>.
214.261 + * The expression {@code m.descendingMap().descendingMap()} returns a
214.262 + * view of {@code m} essentially equivalent to {@code m}.
214.263 + *
214.264 + * @return a reverse order view of this map
214.265 + */
214.266 + NavigableMap<K,V> descendingMap();
214.267 +
214.268 + /**
214.269 + * Returns a {@link NavigableSet} view of the keys contained in this map.
214.270 + * The set's iterator returns the keys in ascending order.
214.271 + * The set is backed by the map, so changes to the map are reflected in
214.272 + * the set, and vice-versa. If the map is modified while an iteration
214.273 + * over the set is in progress (except through the iterator's own {@code
214.274 + * remove} operation), the results of the iteration are undefined. The
214.275 + * set supports element removal, which removes the corresponding mapping
214.276 + * from the map, via the {@code Iterator.remove}, {@code Set.remove},
214.277 + * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
214.278 + * It does not support the {@code add} or {@code addAll} operations.
214.279 + *
214.280 + * @return a navigable set view of the keys in this map
214.281 + */
214.282 + NavigableSet<K> navigableKeySet();
214.283 +
214.284 + /**
214.285 + * Returns a reverse order {@link NavigableSet} view of the keys contained in this map.
214.286 + * The set's iterator returns the keys in descending order.
214.287 + * The set is backed by the map, so changes to the map are reflected in
214.288 + * the set, and vice-versa. If the map is modified while an iteration
214.289 + * over the set is in progress (except through the iterator's own {@code
214.290 + * remove} operation), the results of the iteration are undefined. The
214.291 + * set supports element removal, which removes the corresponding mapping
214.292 + * from the map, via the {@code Iterator.remove}, {@code Set.remove},
214.293 + * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
214.294 + * It does not support the {@code add} or {@code addAll} operations.
214.295 + *
214.296 + * @return a reverse order navigable set view of the keys in this map
214.297 + */
214.298 + NavigableSet<K> descendingKeySet();
214.299 +
214.300 + /**
214.301 + * Returns a view of the portion of this map whose keys range from
214.302 + * {@code fromKey} to {@code toKey}. If {@code fromKey} and
214.303 + * {@code toKey} are equal, the returned map is empty unless
214.304 + * {@code fromInclusive} and {@code toInclusive} are both true. The
214.305 + * returned map is backed by this map, so changes in the returned map are
214.306 + * reflected in this map, and vice-versa. The returned map supports all
214.307 + * optional map operations that this map supports.
214.308 + *
214.309 + * <p>The returned map will throw an {@code IllegalArgumentException}
214.310 + * on an attempt to insert a key outside of its range, or to construct a
214.311 + * submap either of whose endpoints lie outside its range.
214.312 + *
214.313 + * @param fromKey low endpoint of the keys in the returned map
214.314 + * @param fromInclusive {@code true} if the low endpoint
214.315 + * is to be included in the returned view
214.316 + * @param toKey high endpoint of the keys in the returned map
214.317 + * @param toInclusive {@code true} if the high endpoint
214.318 + * is to be included in the returned view
214.319 + * @return a view of the portion of this map whose keys range from
214.320 + * {@code fromKey} to {@code toKey}
214.321 + * @throws ClassCastException if {@code fromKey} and {@code toKey}
214.322 + * cannot be compared to one another using this map's comparator
214.323 + * (or, if the map has no comparator, using natural ordering).
214.324 + * Implementations may, but are not required to, throw this
214.325 + * exception if {@code fromKey} or {@code toKey}
214.326 + * cannot be compared to keys currently in the map.
214.327 + * @throws NullPointerException if {@code fromKey} or {@code toKey}
214.328 + * is null and this map does not permit null keys
214.329 + * @throws IllegalArgumentException if {@code fromKey} is greater than
214.330 + * {@code toKey}; or if this map itself has a restricted
214.331 + * range, and {@code fromKey} or {@code toKey} lies
214.332 + * outside the bounds of the range
214.333 + */
214.334 + NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
214.335 + K toKey, boolean toInclusive);
214.336 +
214.337 + /**
214.338 + * Returns a view of the portion of this map whose keys are less than (or
214.339 + * equal to, if {@code inclusive} is true) {@code toKey}. The returned
214.340 + * map is backed by this map, so changes in the returned map are reflected
214.341 + * in this map, and vice-versa. The returned map supports all optional
214.342 + * map operations that this map supports.
214.343 + *
214.344 + * <p>The returned map will throw an {@code IllegalArgumentException}
214.345 + * on an attempt to insert a key outside its range.
214.346 + *
214.347 + * @param toKey high endpoint of the keys in the returned map
214.348 + * @param inclusive {@code true} if the high endpoint
214.349 + * is to be included in the returned view
214.350 + * @return a view of the portion of this map whose keys are less than
214.351 + * (or equal to, if {@code inclusive} is true) {@code toKey}
214.352 + * @throws ClassCastException if {@code toKey} is not compatible
214.353 + * with this map's comparator (or, if the map has no comparator,
214.354 + * if {@code toKey} does not implement {@link Comparable}).
214.355 + * Implementations may, but are not required to, throw this
214.356 + * exception if {@code toKey} cannot be compared to keys
214.357 + * currently in the map.
214.358 + * @throws NullPointerException if {@code toKey} is null
214.359 + * and this map does not permit null keys
214.360 + * @throws IllegalArgumentException if this map itself has a
214.361 + * restricted range, and {@code toKey} lies outside the
214.362 + * bounds of the range
214.363 + */
214.364 + NavigableMap<K,V> headMap(K toKey, boolean inclusive);
214.365 +
214.366 + /**
214.367 + * Returns a view of the portion of this map whose keys are greater than (or
214.368 + * equal to, if {@code inclusive} is true) {@code fromKey}. The returned
214.369 + * map is backed by this map, so changes in the returned map are reflected
214.370 + * in this map, and vice-versa. The returned map supports all optional
214.371 + * map operations that this map supports.
214.372 + *
214.373 + * <p>The returned map will throw an {@code IllegalArgumentException}
214.374 + * on an attempt to insert a key outside its range.
214.375 + *
214.376 + * @param fromKey low endpoint of the keys in the returned map
214.377 + * @param inclusive {@code true} if the low endpoint
214.378 + * is to be included in the returned view
214.379 + * @return a view of the portion of this map whose keys are greater than
214.380 + * (or equal to, if {@code inclusive} is true) {@code fromKey}
214.381 + * @throws ClassCastException if {@code fromKey} is not compatible
214.382 + * with this map's comparator (or, if the map has no comparator,
214.383 + * if {@code fromKey} does not implement {@link Comparable}).
214.384 + * Implementations may, but are not required to, throw this
214.385 + * exception if {@code fromKey} cannot be compared to keys
214.386 + * currently in the map.
214.387 + * @throws NullPointerException if {@code fromKey} is null
214.388 + * and this map does not permit null keys
214.389 + * @throws IllegalArgumentException if this map itself has a
214.390 + * restricted range, and {@code fromKey} lies outside the
214.391 + * bounds of the range
214.392 + */
214.393 + NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
214.394 +
214.395 + /**
214.396 + * {@inheritDoc}
214.397 + *
214.398 + * <p>Equivalent to {@code subMap(fromKey, true, toKey, false)}.
214.399 + *
214.400 + * @throws ClassCastException {@inheritDoc}
214.401 + * @throws NullPointerException {@inheritDoc}
214.402 + * @throws IllegalArgumentException {@inheritDoc}
214.403 + */
214.404 + SortedMap<K,V> subMap(K fromKey, K toKey);
214.405 +
214.406 + /**
214.407 + * {@inheritDoc}
214.408 + *
214.409 + * <p>Equivalent to {@code headMap(toKey, false)}.
214.410 + *
214.411 + * @throws ClassCastException {@inheritDoc}
214.412 + * @throws NullPointerException {@inheritDoc}
214.413 + * @throws IllegalArgumentException {@inheritDoc}
214.414 + */
214.415 + SortedMap<K,V> headMap(K toKey);
214.416 +
214.417 + /**
214.418 + * {@inheritDoc}
214.419 + *
214.420 + * <p>Equivalent to {@code tailMap(fromKey, true)}.
214.421 + *
214.422 + * @throws ClassCastException {@inheritDoc}
214.423 + * @throws NullPointerException {@inheritDoc}
214.424 + * @throws IllegalArgumentException {@inheritDoc}
214.425 + */
214.426 + SortedMap<K,V> tailMap(K fromKey);
214.427 +}
215.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
215.2 +++ b/rt/emul/compact/src/main/java/java/util/NavigableSet.java Wed Apr 30 15:04:10 2014 +0200
215.3 @@ -0,0 +1,319 @@
215.4 +/*
215.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
215.6 + *
215.7 + * This code is free software; you can redistribute it and/or modify it
215.8 + * under the terms of the GNU General Public License version 2 only, as
215.9 + * published by the Free Software Foundation. Oracle designates this
215.10 + * particular file as subject to the "Classpath" exception as provided
215.11 + * by Oracle in the LICENSE file that accompanied this code.
215.12 + *
215.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
215.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
215.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
215.16 + * version 2 for more details (a copy is included in the LICENSE file that
215.17 + * accompanied this code).
215.18 + *
215.19 + * You should have received a copy of the GNU General Public License version
215.20 + * 2 along with this work; if not, write to the Free Software Foundation,
215.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
215.22 + *
215.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
215.24 + * or visit www.oracle.com if you need additional information or have any
215.25 + * questions.
215.26 + */
215.27 +
215.28 +/*
215.29 + * This file is available under and governed by the GNU General Public
215.30 + * License version 2 only, as published by the Free Software Foundation.
215.31 + * However, the following notice accompanied the original version of this
215.32 + * file:
215.33 + *
215.34 + * Written by Doug Lea and Josh Bloch with assistance from members of JCP
215.35 + * JSR-166 Expert Group and released to the public domain, as explained at
215.36 + * http://creativecommons.org/publicdomain/zero/1.0/
215.37 + */
215.38 +
215.39 +package java.util;
215.40 +
215.41 +/**
215.42 + * A {@link SortedSet} extended with navigation methods reporting
215.43 + * closest matches for given search targets. Methods {@code lower},
215.44 + * {@code floor}, {@code ceiling}, and {@code higher} return elements
215.45 + * respectively less than, less than or equal, greater than or equal,
215.46 + * and greater than a given element, returning {@code null} if there
215.47 + * is no such element. A {@code NavigableSet} may be accessed and
215.48 + * traversed in either ascending or descending order. The {@code
215.49 + * descendingSet} method returns a view of the set with the senses of
215.50 + * all relational and directional methods inverted. The performance of
215.51 + * ascending operations and views is likely to be faster than that of
215.52 + * descending ones. This interface additionally defines methods
215.53 + * {@code pollFirst} and {@code pollLast} that return and remove the
215.54 + * lowest and highest element, if one exists, else returning {@code
215.55 + * null}. Methods {@code subSet}, {@code headSet},
215.56 + * and {@code tailSet} differ from the like-named {@code
215.57 + * SortedSet} methods in accepting additional arguments describing
215.58 + * whether lower and upper bounds are inclusive versus exclusive.
215.59 + * Subsets of any {@code NavigableSet} must implement the {@code
215.60 + * NavigableSet} interface.
215.61 + *
215.62 + * <p> The return values of navigation methods may be ambiguous in
215.63 + * implementations that permit {@code null} elements. However, even
215.64 + * in this case the result can be disambiguated by checking
215.65 + * {@code contains(null)}. To avoid such issues, implementations of
215.66 + * this interface are encouraged to <em>not</em> permit insertion of
215.67 + * {@code null} elements. (Note that sorted sets of {@link
215.68 + * Comparable} elements intrinsically do not permit {@code null}.)
215.69 + *
215.70 + * <p>Methods
215.71 + * {@link #subSet(Object, Object) subSet(E, E)},
215.72 + * {@link #headSet(Object) headSet(E)}, and
215.73 + * {@link #tailSet(Object) tailSet(E)}
215.74 + * are specified to return {@code SortedSet} to allow existing
215.75 + * implementations of {@code SortedSet} to be compatibly retrofitted to
215.76 + * implement {@code NavigableSet}, but extensions and implementations
215.77 + * of this interface are encouraged to override these methods to return
215.78 + * {@code NavigableSet}.
215.79 + *
215.80 + * <p>This interface is a member of the
215.81 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
215.82 + * Java Collections Framework</a>.
215.83 + *
215.84 + * @author Doug Lea
215.85 + * @author Josh Bloch
215.86 + * @param <E> the type of elements maintained by this set
215.87 + * @since 1.6
215.88 + */
215.89 +public interface NavigableSet<E> extends SortedSet<E> {
215.90 + /**
215.91 + * Returns the greatest element in this set strictly less than the
215.92 + * given element, or {@code null} if there is no such element.
215.93 + *
215.94 + * @param e the value to match
215.95 + * @return the greatest element less than {@code e},
215.96 + * or {@code null} if there is no such element
215.97 + * @throws ClassCastException if the specified element cannot be
215.98 + * compared with the elements currently in the set
215.99 + * @throws NullPointerException if the specified element is null
215.100 + * and this set does not permit null elements
215.101 + */
215.102 + E lower(E e);
215.103 +
215.104 + /**
215.105 + * Returns the greatest element in this set less than or equal to
215.106 + * the given element, or {@code null} if there is no such element.
215.107 + *
215.108 + * @param e the value to match
215.109 + * @return the greatest element less than or equal to {@code e},
215.110 + * or {@code null} if there is no such element
215.111 + * @throws ClassCastException if the specified element cannot be
215.112 + * compared with the elements currently in the set
215.113 + * @throws NullPointerException if the specified element is null
215.114 + * and this set does not permit null elements
215.115 + */
215.116 + E floor(E e);
215.117 +
215.118 + /**
215.119 + * Returns the least element in this set greater than or equal to
215.120 + * the given element, or {@code null} if there is no such element.
215.121 + *
215.122 + * @param e the value to match
215.123 + * @return the least element greater than or equal to {@code e},
215.124 + * or {@code null} if there is no such element
215.125 + * @throws ClassCastException if the specified element cannot be
215.126 + * compared with the elements currently in the set
215.127 + * @throws NullPointerException if the specified element is null
215.128 + * and this set does not permit null elements
215.129 + */
215.130 + E ceiling(E e);
215.131 +
215.132 + /**
215.133 + * Returns the least element in this set strictly greater than the
215.134 + * given element, or {@code null} if there is no such element.
215.135 + *
215.136 + * @param e the value to match
215.137 + * @return the least element greater than {@code e},
215.138 + * or {@code null} if there is no such element
215.139 + * @throws ClassCastException if the specified element cannot be
215.140 + * compared with the elements currently in the set
215.141 + * @throws NullPointerException if the specified element is null
215.142 + * and this set does not permit null elements
215.143 + */
215.144 + E higher(E e);
215.145 +
215.146 + /**
215.147 + * Retrieves and removes the first (lowest) element,
215.148 + * or returns {@code null} if this set is empty.
215.149 + *
215.150 + * @return the first element, or {@code null} if this set is empty
215.151 + */
215.152 + E pollFirst();
215.153 +
215.154 + /**
215.155 + * Retrieves and removes the last (highest) element,
215.156 + * or returns {@code null} if this set is empty.
215.157 + *
215.158 + * @return the last element, or {@code null} if this set is empty
215.159 + */
215.160 + E pollLast();
215.161 +
215.162 + /**
215.163 + * Returns an iterator over the elements in this set, in ascending order.
215.164 + *
215.165 + * @return an iterator over the elements in this set, in ascending order
215.166 + */
215.167 + Iterator<E> iterator();
215.168 +
215.169 + /**
215.170 + * Returns a reverse order view of the elements contained in this set.
215.171 + * The descending set is backed by this set, so changes to the set are
215.172 + * reflected in the descending set, and vice-versa. If either set is
215.173 + * modified while an iteration over either set is in progress (except
215.174 + * through the iterator's own {@code remove} operation), the results of
215.175 + * the iteration are undefined.
215.176 + *
215.177 + * <p>The returned set has an ordering equivalent to
215.178 + * <tt>{@link Collections#reverseOrder(Comparator) Collections.reverseOrder}(comparator())</tt>.
215.179 + * The expression {@code s.descendingSet().descendingSet()} returns a
215.180 + * view of {@code s} essentially equivalent to {@code s}.
215.181 + *
215.182 + * @return a reverse order view of this set
215.183 + */
215.184 + NavigableSet<E> descendingSet();
215.185 +
215.186 + /**
215.187 + * Returns an iterator over the elements in this set, in descending order.
215.188 + * Equivalent in effect to {@code descendingSet().iterator()}.
215.189 + *
215.190 + * @return an iterator over the elements in this set, in descending order
215.191 + */
215.192 + Iterator<E> descendingIterator();
215.193 +
215.194 + /**
215.195 + * Returns a view of the portion of this set whose elements range from
215.196 + * {@code fromElement} to {@code toElement}. If {@code fromElement} and
215.197 + * {@code toElement} are equal, the returned set is empty unless {@code
215.198 + * fromInclusive} and {@code toInclusive} are both true. The returned set
215.199 + * is backed by this set, so changes in the returned set are reflected in
215.200 + * this set, and vice-versa. The returned set supports all optional set
215.201 + * operations that this set supports.
215.202 + *
215.203 + * <p>The returned set will throw an {@code IllegalArgumentException}
215.204 + * on an attempt to insert an element outside its range.
215.205 + *
215.206 + * @param fromElement low endpoint of the returned set
215.207 + * @param fromInclusive {@code true} if the low endpoint
215.208 + * is to be included in the returned view
215.209 + * @param toElement high endpoint of the returned set
215.210 + * @param toInclusive {@code true} if the high endpoint
215.211 + * is to be included in the returned view
215.212 + * @return a view of the portion of this set whose elements range from
215.213 + * {@code fromElement}, inclusive, to {@code toElement}, exclusive
215.214 + * @throws ClassCastException if {@code fromElement} and
215.215 + * {@code toElement} cannot be compared to one another using this
215.216 + * set's comparator (or, if the set has no comparator, using
215.217 + * natural ordering). Implementations may, but are not required
215.218 + * to, throw this exception if {@code fromElement} or
215.219 + * {@code toElement} cannot be compared to elements currently in
215.220 + * the set.
215.221 + * @throws NullPointerException if {@code fromElement} or
215.222 + * {@code toElement} is null and this set does
215.223 + * not permit null elements
215.224 + * @throws IllegalArgumentException if {@code fromElement} is
215.225 + * greater than {@code toElement}; or if this set itself
215.226 + * has a restricted range, and {@code fromElement} or
215.227 + * {@code toElement} lies outside the bounds of the range.
215.228 + */
215.229 + NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
215.230 + E toElement, boolean toInclusive);
215.231 +
215.232 + /**
215.233 + * Returns a view of the portion of this set whose elements are less than
215.234 + * (or equal to, if {@code inclusive} is true) {@code toElement}. The
215.235 + * returned set is backed by this set, so changes in the returned set are
215.236 + * reflected in this set, and vice-versa. The returned set supports all
215.237 + * optional set operations that this set supports.
215.238 + *
215.239 + * <p>The returned set will throw an {@code IllegalArgumentException}
215.240 + * on an attempt to insert an element outside its range.
215.241 + *
215.242 + * @param toElement high endpoint of the returned set
215.243 + * @param inclusive {@code true} if the high endpoint
215.244 + * is to be included in the returned view
215.245 + * @return a view of the portion of this set whose elements are less than
215.246 + * (or equal to, if {@code inclusive} is true) {@code toElement}
215.247 + * @throws ClassCastException if {@code toElement} is not compatible
215.248 + * with this set's comparator (or, if the set has no comparator,
215.249 + * if {@code toElement} does not implement {@link Comparable}).
215.250 + * Implementations may, but are not required to, throw this
215.251 + * exception if {@code toElement} cannot be compared to elements
215.252 + * currently in the set.
215.253 + * @throws NullPointerException if {@code toElement} is null and
215.254 + * this set does not permit null elements
215.255 + * @throws IllegalArgumentException if this set itself has a
215.256 + * restricted range, and {@code toElement} lies outside the
215.257 + * bounds of the range
215.258 + */
215.259 + NavigableSet<E> headSet(E toElement, boolean inclusive);
215.260 +
215.261 + /**
215.262 + * Returns a view of the portion of this set whose elements are greater
215.263 + * than (or equal to, if {@code inclusive} is true) {@code fromElement}.
215.264 + * The returned set is backed by this set, so changes in the returned set
215.265 + * are reflected in this set, and vice-versa. The returned set supports
215.266 + * all optional set operations that this set supports.
215.267 + *
215.268 + * <p>The returned set will throw an {@code IllegalArgumentException}
215.269 + * on an attempt to insert an element outside its range.
215.270 + *
215.271 + * @param fromElement low endpoint of the returned set
215.272 + * @param inclusive {@code true} if the low endpoint
215.273 + * is to be included in the returned view
215.274 + * @return a view of the portion of this set whose elements are greater
215.275 + * than or equal to {@code fromElement}
215.276 + * @throws ClassCastException if {@code fromElement} is not compatible
215.277 + * with this set's comparator (or, if the set has no comparator,
215.278 + * if {@code fromElement} does not implement {@link Comparable}).
215.279 + * Implementations may, but are not required to, throw this
215.280 + * exception if {@code fromElement} cannot be compared to elements
215.281 + * currently in the set.
215.282 + * @throws NullPointerException if {@code fromElement} is null
215.283 + * and this set does not permit null elements
215.284 + * @throws IllegalArgumentException if this set itself has a
215.285 + * restricted range, and {@code fromElement} lies outside the
215.286 + * bounds of the range
215.287 + */
215.288 + NavigableSet<E> tailSet(E fromElement, boolean inclusive);
215.289 +
215.290 + /**
215.291 + * {@inheritDoc}
215.292 + *
215.293 + * <p>Equivalent to {@code subSet(fromElement, true, toElement, false)}.
215.294 + *
215.295 + * @throws ClassCastException {@inheritDoc}
215.296 + * @throws NullPointerException {@inheritDoc}
215.297 + * @throws IllegalArgumentException {@inheritDoc}
215.298 + */
215.299 + SortedSet<E> subSet(E fromElement, E toElement);
215.300 +
215.301 + /**
215.302 + * {@inheritDoc}
215.303 + *
215.304 + * <p>Equivalent to {@code headSet(toElement, false)}.
215.305 + *
215.306 + * @throws ClassCastException {@inheritDoc}
215.307 + * @throws NullPointerException {@inheritDoc}
215.308 + * @throws IllegalArgumentException {@inheritDoc}
215.309 +na */
215.310 + SortedSet<E> headSet(E toElement);
215.311 +
215.312 + /**
215.313 + * {@inheritDoc}
215.314 + *
215.315 + * <p>Equivalent to {@code tailSet(fromElement, true)}.
215.316 + *
215.317 + * @throws ClassCastException {@inheritDoc}
215.318 + * @throws NullPointerException {@inheritDoc}
215.319 + * @throws IllegalArgumentException {@inheritDoc}
215.320 + */
215.321 + SortedSet<E> tailSet(E fromElement);
215.322 +}
216.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
216.2 +++ b/rt/emul/compact/src/main/java/java/util/Properties.java Wed Apr 30 15:04:10 2014 +0200
216.3 @@ -0,0 +1,1113 @@
216.4 +/*
216.5 + * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
216.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
216.7 + *
216.8 + * This code is free software; you can redistribute it and/or modify it
216.9 + * under the terms of the GNU General Public License version 2 only, as
216.10 + * published by the Free Software Foundation. Oracle designates this
216.11 + * particular file as subject to the "Classpath" exception as provided
216.12 + * by Oracle in the LICENSE file that accompanied this code.
216.13 + *
216.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
216.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
216.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
216.17 + * version 2 for more details (a copy is included in the LICENSE file that
216.18 + * accompanied this code).
216.19 + *
216.20 + * You should have received a copy of the GNU General Public License version
216.21 + * 2 along with this work; if not, write to the Free Software Foundation,
216.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
216.23 + *
216.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
216.25 + * or visit www.oracle.com if you need additional information or have any
216.26 + * questions.
216.27 + */
216.28 +
216.29 +package java.util;
216.30 +
216.31 +import java.io.IOException;
216.32 +import java.io.PrintStream;
216.33 +import java.io.PrintWriter;
216.34 +import java.io.InputStream;
216.35 +import java.io.OutputStream;
216.36 +import java.io.Reader;
216.37 +import java.io.Writer;
216.38 +import java.io.OutputStreamWriter;
216.39 +import java.io.BufferedWriter;
216.40 +
216.41 +/**
216.42 + * The <code>Properties</code> class represents a persistent set of
216.43 + * properties. The <code>Properties</code> can be saved to a stream
216.44 + * or loaded from a stream. Each key and its corresponding value in
216.45 + * the property list is a string.
216.46 + * <p>
216.47 + * A property list can contain another property list as its
216.48 + * "defaults"; this second property list is searched if
216.49 + * the property key is not found in the original property list.
216.50 + * <p>
216.51 + * Because <code>Properties</code> inherits from <code>Hashtable</code>, the
216.52 + * <code>put</code> and <code>putAll</code> methods can be applied to a
216.53 + * <code>Properties</code> object. Their use is strongly discouraged as they
216.54 + * allow the caller to insert entries whose keys or values are not
216.55 + * <code>Strings</code>. The <code>setProperty</code> method should be used
216.56 + * instead. If the <code>store</code> or <code>save</code> method is called
216.57 + * on a "compromised" <code>Properties</code> object that contains a
216.58 + * non-<code>String</code> key or value, the call will fail. Similarly,
216.59 + * the call to the <code>propertyNames</code> or <code>list</code> method
216.60 + * will fail if it is called on a "compromised" <code>Properties</code>
216.61 + * object that contains a non-<code>String</code> key.
216.62 + *
216.63 + * <p>
216.64 + * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt>
216.65 + * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
216.66 + * methods load and store properties from and to a character based stream
216.67 + * in a simple line-oriented format specified below.
216.68 + *
216.69 + * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt>
216.70 + * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)}
216.71 + * methods work the same way as the load(Reader)/store(Writer, String) pair, except
216.72 + * the input/output stream is encoded in ISO 8859-1 character encoding.
216.73 + * Characters that cannot be directly represented in this encoding can be written using
216.74 + * Unicode escapes as defined in section 3.3 of
216.75 + * <cite>The Java™ Language Specification</cite>;
216.76 + * only a single 'u' character is allowed in an escape
216.77 + * sequence. The native2ascii tool can be used to convert property files to and
216.78 + * from other character encodings.
216.79 + *
216.80 + * <p> The {@link #loadFromXML(InputStream)} and {@link
216.81 + * #storeToXML(OutputStream, String, String)} methods load and store properties
216.82 + * in a simple XML format. By default the UTF-8 character encoding is used,
216.83 + * however a specific encoding may be specified if required. An XML properties
216.84 + * document has the following DOCTYPE declaration:
216.85 + *
216.86 + * <pre>
216.87 + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
216.88 + * </pre>
216.89 + * Note that the system URI (http://java.sun.com/dtd/properties.dtd) is
216.90 + * <i>not</i> accessed when exporting or importing properties; it merely
216.91 + * serves as a string to uniquely identify the DTD, which is:
216.92 + * <pre>
216.93 + * <?xml version="1.0" encoding="UTF-8"?>
216.94 + *
216.95 + * <!-- DTD for properties -->
216.96 + *
216.97 + * <!ELEMENT properties ( comment?, entry* ) >
216.98 + *
216.99 + * <!ATTLIST properties version CDATA #FIXED "1.0">
216.100 + *
216.101 + * <!ELEMENT comment (#PCDATA) >
216.102 + *
216.103 + * <!ELEMENT entry (#PCDATA) >
216.104 + *
216.105 + * <!ATTLIST entry key CDATA #REQUIRED>
216.106 + * </pre>
216.107 + *
216.108 + * <p>This class is thread-safe: multiple threads can share a single
216.109 + * <tt>Properties</tt> object without the need for external synchronization.
216.110 + *
216.111 + * @see <a href="../../../technotes/tools/solaris/native2ascii.html">native2ascii tool for Solaris</a>
216.112 + * @see <a href="../../../technotes/tools/windows/native2ascii.html">native2ascii tool for Windows</a>
216.113 + *
216.114 + * @author Arthur van Hoff
216.115 + * @author Michael McCloskey
216.116 + * @author Xueming Shen
216.117 + * @since JDK1.0
216.118 + */
216.119 +public
216.120 +class Properties extends Hashtable<Object,Object> {
216.121 + /**
216.122 + * use serialVersionUID from JDK 1.1.X for interoperability
216.123 + */
216.124 + private static final long serialVersionUID = 4112578634029874840L;
216.125 +
216.126 + /**
216.127 + * A property list that contains default values for any keys not
216.128 + * found in this property list.
216.129 + *
216.130 + * @serial
216.131 + */
216.132 + protected Properties defaults;
216.133 +
216.134 + /**
216.135 + * Creates an empty property list with no default values.
216.136 + */
216.137 + public Properties() {
216.138 + this(null);
216.139 + }
216.140 +
216.141 + /**
216.142 + * Creates an empty property list with the specified defaults.
216.143 + *
216.144 + * @param defaults the defaults.
216.145 + */
216.146 + public Properties(Properties defaults) {
216.147 + this.defaults = defaults;
216.148 + }
216.149 +
216.150 + /**
216.151 + * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for
216.152 + * parallelism with the <tt>getProperty</tt> method. Enforces use of
216.153 + * strings for property keys and values. The value returned is the
216.154 + * result of the <tt>Hashtable</tt> call to <code>put</code>.
216.155 + *
216.156 + * @param key the key to be placed into this property list.
216.157 + * @param value the value corresponding to <tt>key</tt>.
216.158 + * @return the previous value of the specified key in this property
216.159 + * list, or <code>null</code> if it did not have one.
216.160 + * @see #getProperty
216.161 + * @since 1.2
216.162 + */
216.163 + public synchronized Object setProperty(String key, String value) {
216.164 + return put(key, value);
216.165 + }
216.166 +
216.167 +
216.168 + /**
216.169 + * Reads a property list (key and element pairs) from the input
216.170 + * character stream in a simple line-oriented format.
216.171 + * <p>
216.172 + * Properties are processed in terms of lines. There are two
216.173 + * kinds of line, <i>natural lines</i> and <i>logical lines</i>.
216.174 + * A natural line is defined as a line of
216.175 + * characters that is terminated either by a set of line terminator
216.176 + * characters (<code>\n</code> or <code>\r</code> or <code>\r\n</code>)
216.177 + * or by the end of the stream. A natural line may be either a blank line,
216.178 + * a comment line, or hold all or some of a key-element pair. A logical
216.179 + * line holds all the data of a key-element pair, which may be spread
216.180 + * out across several adjacent natural lines by escaping
216.181 + * the line terminator sequence with a backslash character
216.182 + * <code>\</code>. Note that a comment line cannot be extended
216.183 + * in this manner; every natural line that is a comment must have
216.184 + * its own comment indicator, as described below. Lines are read from
216.185 + * input until the end of the stream is reached.
216.186 + *
216.187 + * <p>
216.188 + * A natural line that contains only white space characters is
216.189 + * considered blank and is ignored. A comment line has an ASCII
216.190 + * <code>'#'</code> or <code>'!'</code> as its first non-white
216.191 + * space character; comment lines are also ignored and do not
216.192 + * encode key-element information. In addition to line
216.193 + * terminators, this format considers the characters space
216.194 + * (<code>' '</code>, <code>'\u0020'</code>), tab
216.195 + * (<code>'\t'</code>, <code>'\u0009'</code>), and form feed
216.196 + * (<code>'\f'</code>, <code>'\u000C'</code>) to be white
216.197 + * space.
216.198 + *
216.199 + * <p>
216.200 + * If a logical line is spread across several natural lines, the
216.201 + * backslash escaping the line terminator sequence, the line
216.202 + * terminator sequence, and any white space at the start of the
216.203 + * following line have no affect on the key or element values.
216.204 + * The remainder of the discussion of key and element parsing
216.205 + * (when loading) will assume all the characters constituting
216.206 + * the key and element appear on a single natural line after
216.207 + * line continuation characters have been removed. Note that
216.208 + * it is <i>not</i> sufficient to only examine the character
216.209 + * preceding a line terminator sequence to decide if the line
216.210 + * terminator is escaped; there must be an odd number of
216.211 + * contiguous backslashes for the line terminator to be escaped.
216.212 + * Since the input is processed from left to right, a
216.213 + * non-zero even number of 2<i>n</i> contiguous backslashes
216.214 + * before a line terminator (or elsewhere) encodes <i>n</i>
216.215 + * backslashes after escape processing.
216.216 + *
216.217 + * <p>
216.218 + * The key contains all of the characters in the line starting
216.219 + * with the first non-white space character and up to, but not
216.220 + * including, the first unescaped <code>'='</code>,
216.221 + * <code>':'</code>, or white space character other than a line
216.222 + * terminator. All of these key termination characters may be
216.223 + * included in the key by escaping them with a preceding backslash
216.224 + * character; for example,<p>
216.225 + *
216.226 + * <code>\:\=</code><p>
216.227 + *
216.228 + * would be the two-character key <code>":="</code>. Line
216.229 + * terminator characters can be included using <code>\r</code> and
216.230 + * <code>\n</code> escape sequences. Any white space after the
216.231 + * key is skipped; if the first non-white space character after
216.232 + * the key is <code>'='</code> or <code>':'</code>, then it is
216.233 + * ignored and any white space characters after it are also
216.234 + * skipped. All remaining characters on the line become part of
216.235 + * the associated element string; if there are no remaining
216.236 + * characters, the element is the empty string
216.237 + * <code>""</code>. Once the raw character sequences
216.238 + * constituting the key and element are identified, escape
216.239 + * processing is performed as described above.
216.240 + *
216.241 + * <p>
216.242 + * As an example, each of the following three lines specifies the key
216.243 + * <code>"Truth"</code> and the associated element value
216.244 + * <code>"Beauty"</code>:
216.245 + * <p>
216.246 + * <pre>
216.247 + * Truth = Beauty
216.248 + * Truth:Beauty
216.249 + * Truth :Beauty
216.250 + * </pre>
216.251 + * As another example, the following three lines specify a single
216.252 + * property:
216.253 + * <p>
216.254 + * <pre>
216.255 + * fruits apple, banana, pear, \
216.256 + * cantaloupe, watermelon, \
216.257 + * kiwi, mango
216.258 + * </pre>
216.259 + * The key is <code>"fruits"</code> and the associated element is:
216.260 + * <p>
216.261 + * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
216.262 + * Note that a space appears before each <code>\</code> so that a space
216.263 + * will appear after each comma in the final result; the <code>\</code>,
216.264 + * line terminator, and leading white space on the continuation line are
216.265 + * merely discarded and are <i>not</i> replaced by one or more other
216.266 + * characters.
216.267 + * <p>
216.268 + * As a third example, the line:
216.269 + * <p>
216.270 + * <pre>cheeses
216.271 + * </pre>
216.272 + * specifies that the key is <code>"cheeses"</code> and the associated
216.273 + * element is the empty string <code>""</code>.<p>
216.274 + * <p>
216.275 + *
216.276 + * <a name="unicodeescapes"></a>
216.277 + * Characters in keys and elements can be represented in escape
216.278 + * sequences similar to those used for character and string literals
216.279 + * (see sections 3.3 and 3.10.6 of
216.280 + * <cite>The Java™ Language Specification</cite>).
216.281 + *
216.282 + * The differences from the character escape sequences and Unicode
216.283 + * escapes used for characters and strings are:
216.284 + *
216.285 + * <ul>
216.286 + * <li> Octal escapes are not recognized.
216.287 + *
216.288 + * <li> The character sequence <code>\b</code> does <i>not</i>
216.289 + * represent a backspace character.
216.290 + *
216.291 + * <li> The method does not treat a backslash character,
216.292 + * <code>\</code>, before a non-valid escape character as an
216.293 + * error; the backslash is silently dropped. For example, in a
216.294 + * Java string the sequence <code>"\z"</code> would cause a
216.295 + * compile time error. In contrast, this method silently drops
216.296 + * the backslash. Therefore, this method treats the two character
216.297 + * sequence <code>"\b"</code> as equivalent to the single
216.298 + * character <code>'b'</code>.
216.299 + *
216.300 + * <li> Escapes are not necessary for single and double quotes;
216.301 + * however, by the rule above, single and double quote characters
216.302 + * preceded by a backslash still yield single and double quote
216.303 + * characters, respectively.
216.304 + *
216.305 + * <li> Only a single 'u' character is allowed in a Uniocde escape
216.306 + * sequence.
216.307 + *
216.308 + * </ul>
216.309 + * <p>
216.310 + * The specified stream remains open after this method returns.
216.311 + *
216.312 + * @param reader the input character stream.
216.313 + * @throws IOException if an error occurred when reading from the
216.314 + * input stream.
216.315 + * @throws IllegalArgumentException if a malformed Unicode escape
216.316 + * appears in the input.
216.317 + * @since 1.6
216.318 + */
216.319 + public synchronized void load(Reader reader) throws IOException {
216.320 + load0(new LineReader(reader));
216.321 + }
216.322 +
216.323 + /**
216.324 + * Reads a property list (key and element pairs) from the input
216.325 + * byte stream. The input stream is in a simple line-oriented
216.326 + * format as specified in
216.327 + * {@link #load(java.io.Reader) load(Reader)} and is assumed to use
216.328 + * the ISO 8859-1 character encoding; that is each byte is one Latin1
216.329 + * character. Characters not in Latin1, and certain special characters,
216.330 + * are represented in keys and elements using Unicode escapes as defined in
216.331 + * section 3.3 of
216.332 + * <cite>The Java™ Language Specification</cite>.
216.333 + * <p>
216.334 + * The specified stream remains open after this method returns.
216.335 + *
216.336 + * @param inStream the input stream.
216.337 + * @exception IOException if an error occurred when reading from the
216.338 + * input stream.
216.339 + * @throws IllegalArgumentException if the input stream contains a
216.340 + * malformed Unicode escape sequence.
216.341 + * @since 1.2
216.342 + */
216.343 + public synchronized void load(InputStream inStream) throws IOException {
216.344 + load0(new LineReader(inStream));
216.345 + }
216.346 +
216.347 + private void load0 (LineReader lr) throws IOException {
216.348 + char[] convtBuf = new char[1024];
216.349 + int limit;
216.350 + int keyLen;
216.351 + int valueStart;
216.352 + char c;
216.353 + boolean hasSep;
216.354 + boolean precedingBackslash;
216.355 +
216.356 + while ((limit = lr.readLine()) >= 0) {
216.357 + c = 0;
216.358 + keyLen = 0;
216.359 + valueStart = limit;
216.360 + hasSep = false;
216.361 +
216.362 + //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
216.363 + precedingBackslash = false;
216.364 + while (keyLen < limit) {
216.365 + c = lr.lineBuf[keyLen];
216.366 + //need check if escaped.
216.367 + if ((c == '=' || c == ':') && !precedingBackslash) {
216.368 + valueStart = keyLen + 1;
216.369 + hasSep = true;
216.370 + break;
216.371 + } else if ((c == ' ' || c == '\t' || c == '\f') && !precedingBackslash) {
216.372 + valueStart = keyLen + 1;
216.373 + break;
216.374 + }
216.375 + if (c == '\\') {
216.376 + precedingBackslash = !precedingBackslash;
216.377 + } else {
216.378 + precedingBackslash = false;
216.379 + }
216.380 + keyLen++;
216.381 + }
216.382 + while (valueStart < limit) {
216.383 + c = lr.lineBuf[valueStart];
216.384 + if (c != ' ' && c != '\t' && c != '\f') {
216.385 + if (!hasSep && (c == '=' || c == ':')) {
216.386 + hasSep = true;
216.387 + } else {
216.388 + break;
216.389 + }
216.390 + }
216.391 + valueStart++;
216.392 + }
216.393 + String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
216.394 + String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
216.395 + put(key, value);
216.396 + }
216.397 + }
216.398 +
216.399 + /* Read in a "logical line" from an InputStream/Reader, skip all comment
216.400 + * and blank lines and filter out those leading whitespace characters
216.401 + * (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
216.402 + * Method returns the char length of the "logical line" and stores
216.403 + * the line in "lineBuf".
216.404 + */
216.405 + class LineReader {
216.406 + public LineReader(InputStream inStream) {
216.407 + this.inStream = inStream;
216.408 + inByteBuf = new byte[8192];
216.409 + }
216.410 +
216.411 + public LineReader(Reader reader) {
216.412 + this.reader = reader;
216.413 + inCharBuf = new char[8192];
216.414 + }
216.415 +
216.416 + byte[] inByteBuf;
216.417 + char[] inCharBuf;
216.418 + char[] lineBuf = new char[1024];
216.419 + int inLimit = 0;
216.420 + int inOff = 0;
216.421 + InputStream inStream;
216.422 + Reader reader;
216.423 +
216.424 + int readLine() throws IOException {
216.425 + int len = 0;
216.426 + char c = 0;
216.427 +
216.428 + boolean skipWhiteSpace = true;
216.429 + boolean isCommentLine = false;
216.430 + boolean isNewLine = true;
216.431 + boolean appendedLineBegin = false;
216.432 + boolean precedingBackslash = false;
216.433 + boolean skipLF = false;
216.434 +
216.435 + while (true) {
216.436 + if (inOff >= inLimit) {
216.437 + inLimit = (inStream==null)?reader.read(inCharBuf)
216.438 + :inStream.read(inByteBuf);
216.439 + inOff = 0;
216.440 + if (inLimit <= 0) {
216.441 + if (len == 0 || isCommentLine) {
216.442 + return -1;
216.443 + }
216.444 + return len;
216.445 + }
216.446 + }
216.447 + if (inStream != null) {
216.448 + //The line below is equivalent to calling a
216.449 + //ISO8859-1 decoder.
216.450 + c = (char) (0xff & inByteBuf[inOff++]);
216.451 + } else {
216.452 + c = inCharBuf[inOff++];
216.453 + }
216.454 + if (skipLF) {
216.455 + skipLF = false;
216.456 + if (c == '\n') {
216.457 + continue;
216.458 + }
216.459 + }
216.460 + if (skipWhiteSpace) {
216.461 + if (c == ' ' || c == '\t' || c == '\f') {
216.462 + continue;
216.463 + }
216.464 + if (!appendedLineBegin && (c == '\r' || c == '\n')) {
216.465 + continue;
216.466 + }
216.467 + skipWhiteSpace = false;
216.468 + appendedLineBegin = false;
216.469 + }
216.470 + if (isNewLine) {
216.471 + isNewLine = false;
216.472 + if (c == '#' || c == '!') {
216.473 + isCommentLine = true;
216.474 + continue;
216.475 + }
216.476 + }
216.477 +
216.478 + if (c != '\n' && c != '\r') {
216.479 + lineBuf[len++] = c;
216.480 + if (len == lineBuf.length) {
216.481 + int newLength = lineBuf.length * 2;
216.482 + if (newLength < 0) {
216.483 + newLength = Integer.MAX_VALUE;
216.484 + }
216.485 + char[] buf = new char[newLength];
216.486 + System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
216.487 + lineBuf = buf;
216.488 + }
216.489 + //flip the preceding backslash flag
216.490 + if (c == '\\') {
216.491 + precedingBackslash = !precedingBackslash;
216.492 + } else {
216.493 + precedingBackslash = false;
216.494 + }
216.495 + }
216.496 + else {
216.497 + // reached EOL
216.498 + if (isCommentLine || len == 0) {
216.499 + isCommentLine = false;
216.500 + isNewLine = true;
216.501 + skipWhiteSpace = true;
216.502 + len = 0;
216.503 + continue;
216.504 + }
216.505 + if (inOff >= inLimit) {
216.506 + inLimit = (inStream==null)
216.507 + ?reader.read(inCharBuf)
216.508 + :inStream.read(inByteBuf);
216.509 + inOff = 0;
216.510 + if (inLimit <= 0) {
216.511 + return len;
216.512 + }
216.513 + }
216.514 + if (precedingBackslash) {
216.515 + len -= 1;
216.516 + //skip the leading whitespace characters in following line
216.517 + skipWhiteSpace = true;
216.518 + appendedLineBegin = true;
216.519 + precedingBackslash = false;
216.520 + if (c == '\r') {
216.521 + skipLF = true;
216.522 + }
216.523 + } else {
216.524 + return len;
216.525 + }
216.526 + }
216.527 + }
216.528 + }
216.529 + }
216.530 +
216.531 + /*
216.532 + * Converts encoded \uxxxx to unicode chars
216.533 + * and changes special saved chars to their original forms
216.534 + */
216.535 + private String loadConvert (char[] in, int off, int len, char[] convtBuf) {
216.536 + if (convtBuf.length < len) {
216.537 + int newLen = len * 2;
216.538 + if (newLen < 0) {
216.539 + newLen = Integer.MAX_VALUE;
216.540 + }
216.541 + convtBuf = new char[newLen];
216.542 + }
216.543 + char aChar;
216.544 + char[] out = convtBuf;
216.545 + int outLen = 0;
216.546 + int end = off + len;
216.547 +
216.548 + while (off < end) {
216.549 + aChar = in[off++];
216.550 + if (aChar == '\\') {
216.551 + aChar = in[off++];
216.552 + if(aChar == 'u') {
216.553 + // Read the xxxx
216.554 + int value=0;
216.555 + for (int i=0; i<4; i++) {
216.556 + aChar = in[off++];
216.557 + switch (aChar) {
216.558 + case '0': case '1': case '2': case '3': case '4':
216.559 + case '5': case '6': case '7': case '8': case '9':
216.560 + value = (value << 4) + aChar - '0';
216.561 + break;
216.562 + case 'a': case 'b': case 'c':
216.563 + case 'd': case 'e': case 'f':
216.564 + value = (value << 4) + 10 + aChar - 'a';
216.565 + break;
216.566 + case 'A': case 'B': case 'C':
216.567 + case 'D': case 'E': case 'F':
216.568 + value = (value << 4) + 10 + aChar - 'A';
216.569 + break;
216.570 + default:
216.571 + throw new IllegalArgumentException(
216.572 + "Malformed \\uxxxx encoding.");
216.573 + }
216.574 + }
216.575 + out[outLen++] = (char)value;
216.576 + } else {
216.577 + if (aChar == 't') aChar = '\t';
216.578 + else if (aChar == 'r') aChar = '\r';
216.579 + else if (aChar == 'n') aChar = '\n';
216.580 + else if (aChar == 'f') aChar = '\f';
216.581 + out[outLen++] = aChar;
216.582 + }
216.583 + } else {
216.584 + out[outLen++] = aChar;
216.585 + }
216.586 + }
216.587 + return new String (out, 0, outLen);
216.588 + }
216.589 +
216.590 + /*
216.591 + * Converts unicodes to encoded \uxxxx and escapes
216.592 + * special characters with a preceding slash
216.593 + */
216.594 + private String saveConvert(String theString,
216.595 + boolean escapeSpace,
216.596 + boolean escapeUnicode) {
216.597 + int len = theString.length();
216.598 + int bufLen = len * 2;
216.599 + if (bufLen < 0) {
216.600 + bufLen = Integer.MAX_VALUE;
216.601 + }
216.602 + StringBuffer outBuffer = new StringBuffer(bufLen);
216.603 +
216.604 + for(int x=0; x<len; x++) {
216.605 + char aChar = theString.charAt(x);
216.606 + // Handle common case first, selecting largest block that
216.607 + // avoids the specials below
216.608 + if ((aChar > 61) && (aChar < 127)) {
216.609 + if (aChar == '\\') {
216.610 + outBuffer.append('\\'); outBuffer.append('\\');
216.611 + continue;
216.612 + }
216.613 + outBuffer.append(aChar);
216.614 + continue;
216.615 + }
216.616 + switch(aChar) {
216.617 + case ' ':
216.618 + if (x == 0 || escapeSpace)
216.619 + outBuffer.append('\\');
216.620 + outBuffer.append(' ');
216.621 + break;
216.622 + case '\t':outBuffer.append('\\'); outBuffer.append('t');
216.623 + break;
216.624 + case '\n':outBuffer.append('\\'); outBuffer.append('n');
216.625 + break;
216.626 + case '\r':outBuffer.append('\\'); outBuffer.append('r');
216.627 + break;
216.628 + case '\f':outBuffer.append('\\'); outBuffer.append('f');
216.629 + break;
216.630 + case '=': // Fall through
216.631 + case ':': // Fall through
216.632 + case '#': // Fall through
216.633 + case '!':
216.634 + outBuffer.append('\\'); outBuffer.append(aChar);
216.635 + break;
216.636 + default:
216.637 + if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) {
216.638 + outBuffer.append('\\');
216.639 + outBuffer.append('u');
216.640 + outBuffer.append(toHex((aChar >> 12) & 0xF));
216.641 + outBuffer.append(toHex((aChar >> 8) & 0xF));
216.642 + outBuffer.append(toHex((aChar >> 4) & 0xF));
216.643 + outBuffer.append(toHex( aChar & 0xF));
216.644 + } else {
216.645 + outBuffer.append(aChar);
216.646 + }
216.647 + }
216.648 + }
216.649 + return outBuffer.toString();
216.650 + }
216.651 +
216.652 + private static void writeComments(BufferedWriter bw, String comments)
216.653 + throws IOException {
216.654 + bw.write("#");
216.655 + int len = comments.length();
216.656 + int current = 0;
216.657 + int last = 0;
216.658 + char[] uu = new char[6];
216.659 + uu[0] = '\\';
216.660 + uu[1] = 'u';
216.661 + while (current < len) {
216.662 + char c = comments.charAt(current);
216.663 + if (c > '\u00ff' || c == '\n' || c == '\r') {
216.664 + if (last != current)
216.665 + bw.write(comments.substring(last, current));
216.666 + if (c > '\u00ff') {
216.667 + uu[2] = toHex((c >> 12) & 0xf);
216.668 + uu[3] = toHex((c >> 8) & 0xf);
216.669 + uu[4] = toHex((c >> 4) & 0xf);
216.670 + uu[5] = toHex( c & 0xf);
216.671 + bw.write(new String(uu));
216.672 + } else {
216.673 + bw.newLine();
216.674 + if (c == '\r' &&
216.675 + current != len - 1 &&
216.676 + comments.charAt(current + 1) == '\n') {
216.677 + current++;
216.678 + }
216.679 + if (current == len - 1 ||
216.680 + (comments.charAt(current + 1) != '#' &&
216.681 + comments.charAt(current + 1) != '!'))
216.682 + bw.write("#");
216.683 + }
216.684 + last = current + 1;
216.685 + }
216.686 + current++;
216.687 + }
216.688 + if (last != current)
216.689 + bw.write(comments.substring(last, current));
216.690 + bw.newLine();
216.691 + }
216.692 +
216.693 + /**
216.694 + * Calls the <code>store(OutputStream out, String comments)</code> method
216.695 + * and suppresses IOExceptions that were thrown.
216.696 + *
216.697 + * @deprecated This method does not throw an IOException if an I/O error
216.698 + * occurs while saving the property list. The preferred way to save a
216.699 + * properties list is via the <code>store(OutputStream out,
216.700 + * String comments)</code> method or the
216.701 + * <code>storeToXML(OutputStream os, String comment)</code> method.
216.702 + *
216.703 + * @param out an output stream.
216.704 + * @param comments a description of the property list.
216.705 + * @exception ClassCastException if this <code>Properties</code> object
216.706 + * contains any keys or values that are not
216.707 + * <code>Strings</code>.
216.708 + */
216.709 + @Deprecated
216.710 + public void save(OutputStream out, String comments) {
216.711 + try {
216.712 + store(out, comments);
216.713 + } catch (IOException e) {
216.714 + }
216.715 + }
216.716 +
216.717 + /**
216.718 + * Writes this property list (key and element pairs) in this
216.719 + * <code>Properties</code> table to the output character stream in a
216.720 + * format suitable for using the {@link #load(java.io.Reader) load(Reader)}
216.721 + * method.
216.722 + * <p>
216.723 + * Properties from the defaults table of this <code>Properties</code>
216.724 + * table (if any) are <i>not</i> written out by this method.
216.725 + * <p>
216.726 + * If the comments argument is not null, then an ASCII <code>#</code>
216.727 + * character, the comments string, and a line separator are first written
216.728 + * to the output stream. Thus, the <code>comments</code> can serve as an
216.729 + * identifying comment. Any one of a line feed ('\n'), a carriage
216.730 + * return ('\r'), or a carriage return followed immediately by a line feed
216.731 + * in comments is replaced by a line separator generated by the <code>Writer</code>
216.732 + * and if the next character in comments is not character <code>#</code> or
216.733 + * character <code>!</code> then an ASCII <code>#</code> is written out
216.734 + * after that line separator.
216.735 + * <p>
216.736 + * Next, a comment line is always written, consisting of an ASCII
216.737 + * <code>#</code> character, the current date and time (as if produced
216.738 + * by the <code>toString</code> method of <code>Date</code> for the
216.739 + * current time), and a line separator as generated by the <code>Writer</code>.
216.740 + * <p>
216.741 + * Then every entry in this <code>Properties</code> table is
216.742 + * written out, one per line. For each entry the key string is
216.743 + * written, then an ASCII <code>=</code>, then the associated
216.744 + * element string. For the key, all space characters are
216.745 + * written with a preceding <code>\</code> character. For the
216.746 + * element, leading space characters, but not embedded or trailing
216.747 + * space characters, are written with a preceding <code>\</code>
216.748 + * character. The key and element characters <code>#</code>,
216.749 + * <code>!</code>, <code>=</code>, and <code>:</code> are written
216.750 + * with a preceding backslash to ensure that they are properly loaded.
216.751 + * <p>
216.752 + * After the entries have been written, the output stream is flushed.
216.753 + * The output stream remains open after this method returns.
216.754 + * <p>
216.755 + *
216.756 + * @param writer an output character stream writer.
216.757 + * @param comments a description of the property list.
216.758 + * @exception IOException if writing this property list to the specified
216.759 + * output stream throws an <tt>IOException</tt>.
216.760 + * @exception ClassCastException if this <code>Properties</code> object
216.761 + * contains any keys or values that are not <code>Strings</code>.
216.762 + * @exception NullPointerException if <code>writer</code> is null.
216.763 + * @since 1.6
216.764 + */
216.765 + public void store(Writer writer, String comments)
216.766 + throws IOException
216.767 + {
216.768 + store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
216.769 + : new BufferedWriter(writer),
216.770 + comments,
216.771 + false);
216.772 + }
216.773 +
216.774 + /**
216.775 + * Writes this property list (key and element pairs) in this
216.776 + * <code>Properties</code> table to the output stream in a format suitable
216.777 + * for loading into a <code>Properties</code> table using the
216.778 + * {@link #load(InputStream) load(InputStream)} method.
216.779 + * <p>
216.780 + * Properties from the defaults table of this <code>Properties</code>
216.781 + * table (if any) are <i>not</i> written out by this method.
216.782 + * <p>
216.783 + * This method outputs the comments, properties keys and values in
216.784 + * the same format as specified in
216.785 + * {@link #store(java.io.Writer, java.lang.String) store(Writer)},
216.786 + * with the following differences:
216.787 + * <ul>
216.788 + * <li>The stream is written using the ISO 8859-1 character encoding.
216.789 + *
216.790 + * <li>Characters not in Latin-1 in the comments are written as
216.791 + * <code>\u</code><i>xxxx</i> for their appropriate unicode
216.792 + * hexadecimal value <i>xxxx</i>.
216.793 + *
216.794 + * <li>Characters less than <code>\u0020</code> and characters greater
216.795 + * than <code>\u007E</code> in property keys or values are written
216.796 + * as <code>\u</code><i>xxxx</i> for the appropriate hexadecimal
216.797 + * value <i>xxxx</i>.
216.798 + * </ul>
216.799 + * <p>
216.800 + * After the entries have been written, the output stream is flushed.
216.801 + * The output stream remains open after this method returns.
216.802 + * <p>
216.803 + * @param out an output stream.
216.804 + * @param comments a description of the property list.
216.805 + * @exception IOException if writing this property list to the specified
216.806 + * output stream throws an <tt>IOException</tt>.
216.807 + * @exception ClassCastException if this <code>Properties</code> object
216.808 + * contains any keys or values that are not <code>Strings</code>.
216.809 + * @exception NullPointerException if <code>out</code> is null.
216.810 + * @since 1.2
216.811 + */
216.812 + public void store(OutputStream out, String comments)
216.813 + throws IOException
216.814 + {
216.815 + store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
216.816 + comments,
216.817 + true);
216.818 + }
216.819 +
216.820 + private void store0(BufferedWriter bw, String comments, boolean escUnicode)
216.821 + throws IOException
216.822 + {
216.823 + if (comments != null) {
216.824 + writeComments(bw, comments);
216.825 + }
216.826 + bw.write("#" + new Date().toString());
216.827 + bw.newLine();
216.828 + synchronized (this) {
216.829 + for (Enumeration e = keys(); e.hasMoreElements();) {
216.830 + String key = (String)e.nextElement();
216.831 + String val = (String)get(key);
216.832 + key = saveConvert(key, true, escUnicode);
216.833 + /* No need to escape embedded and trailing spaces for value, hence
216.834 + * pass false to flag.
216.835 + */
216.836 + val = saveConvert(val, false, escUnicode);
216.837 + bw.write(key + "=" + val);
216.838 + bw.newLine();
216.839 + }
216.840 + }
216.841 + bw.flush();
216.842 + }
216.843 +
216.844 + /**
216.845 + * Loads all of the properties represented by the XML document on the
216.846 + * specified input stream into this properties table.
216.847 + *
216.848 + * <p>The XML document must have the following DOCTYPE declaration:
216.849 + * <pre>
216.850 + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
216.851 + * </pre>
216.852 + * Furthermore, the document must satisfy the properties DTD described
216.853 + * above.
216.854 + *
216.855 + * <p>The specified stream is closed after this method returns.
216.856 + *
216.857 + * @param in the input stream from which to read the XML document.
216.858 + * @throws IOException if reading from the specified input stream
216.859 + * results in an <tt>IOException</tt>.
216.860 + * @throws InvalidPropertiesFormatException Data on input stream does not
216.861 + * constitute a valid XML document with the mandated document type.
216.862 + * @throws NullPointerException if <code>in</code> is null.
216.863 + * @see #storeToXML(OutputStream, String, String)
216.864 + * @since 1.5
216.865 + */
216.866 + public synchronized void loadFromXML(InputStream in)
216.867 + throws IOException
216.868 + {
216.869 + if (in == null)
216.870 + throw new NullPointerException();
216.871 + throw new IOException();
216.872 + }
216.873 +
216.874 + /**
216.875 + * Emits an XML document representing all of the properties contained
216.876 + * in this table.
216.877 + *
216.878 + * <p> An invocation of this method of the form <tt>props.storeToXML(os,
216.879 + * comment)</tt> behaves in exactly the same way as the invocation
216.880 + * <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
216.881 + *
216.882 + * @param os the output stream on which to emit the XML document.
216.883 + * @param comment a description of the property list, or <code>null</code>
216.884 + * if no comment is desired.
216.885 + * @throws IOException if writing to the specified output stream
216.886 + * results in an <tt>IOException</tt>.
216.887 + * @throws NullPointerException if <code>os</code> is null.
216.888 + * @throws ClassCastException if this <code>Properties</code> object
216.889 + * contains any keys or values that are not
216.890 + * <code>Strings</code>.
216.891 + * @see #loadFromXML(InputStream)
216.892 + * @since 1.5
216.893 + */
216.894 + public void storeToXML(OutputStream os, String comment)
216.895 + throws IOException
216.896 + {
216.897 + if (os == null)
216.898 + throw new NullPointerException();
216.899 + storeToXML(os, comment, "UTF-8");
216.900 + }
216.901 +
216.902 + /**
216.903 + * Emits an XML document representing all of the properties contained
216.904 + * in this table, using the specified encoding.
216.905 + *
216.906 + * <p>The XML document will have the following DOCTYPE declaration:
216.907 + * <pre>
216.908 + * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
216.909 + * </pre>
216.910 + *
216.911 + *<p>If the specified comment is <code>null</code> then no comment
216.912 + * will be stored in the document.
216.913 + *
216.914 + * <p>The specified stream remains open after this method returns.
216.915 + *
216.916 + * @param os the output stream on which to emit the XML document.
216.917 + * @param comment a description of the property list, or <code>null</code>
216.918 + * if no comment is desired.
216.919 + * @param encoding the name of a supported
216.920 + * <a href="../lang/package-summary.html#charenc">
216.921 + * character encoding</a>
216.922 + *
216.923 + * @throws IOException if writing to the specified output stream
216.924 + * results in an <tt>IOException</tt>.
216.925 + * @throws NullPointerException if <code>os</code> is <code>null</code>,
216.926 + * or if <code>encoding</code> is <code>null</code>.
216.927 + * @throws ClassCastException if this <code>Properties</code> object
216.928 + * contains any keys or values that are not
216.929 + * <code>Strings</code>.
216.930 + * @see #loadFromXML(InputStream)
216.931 + * @since 1.5
216.932 + */
216.933 + public void storeToXML(OutputStream os, String comment, String encoding)
216.934 + throws IOException
216.935 + {
216.936 + if (os == null)
216.937 + throw new NullPointerException();
216.938 + throw new IOException();
216.939 + }
216.940 +
216.941 + /**
216.942 + * Searches for the property with the specified key in this property list.
216.943 + * If the key is not found in this property list, the default property list,
216.944 + * and its defaults, recursively, are then checked. The method returns
216.945 + * <code>null</code> if the property is not found.
216.946 + *
216.947 + * @param key the property key.
216.948 + * @return the value in this property list with the specified key value.
216.949 + * @see #setProperty
216.950 + * @see #defaults
216.951 + */
216.952 + public String getProperty(String key) {
216.953 + Object oval = super.get(key);
216.954 + String sval = (oval instanceof String) ? (String)oval : null;
216.955 + return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
216.956 + }
216.957 +
216.958 + /**
216.959 + * Searches for the property with the specified key in this property list.
216.960 + * If the key is not found in this property list, the default property list,
216.961 + * and its defaults, recursively, are then checked. The method returns the
216.962 + * default value argument if the property is not found.
216.963 + *
216.964 + * @param key the hashtable key.
216.965 + * @param defaultValue a default value.
216.966 + *
216.967 + * @return the value in this property list with the specified key value.
216.968 + * @see #setProperty
216.969 + * @see #defaults
216.970 + */
216.971 + public String getProperty(String key, String defaultValue) {
216.972 + String val = getProperty(key);
216.973 + return (val == null) ? defaultValue : val;
216.974 + }
216.975 +
216.976 + /**
216.977 + * Returns an enumeration of all the keys in this property list,
216.978 + * including distinct keys in the default property list if a key
216.979 + * of the same name has not already been found from the main
216.980 + * properties list.
216.981 + *
216.982 + * @return an enumeration of all the keys in this property list, including
216.983 + * the keys in the default property list.
216.984 + * @throws ClassCastException if any key in this property list
216.985 + * is not a string.
216.986 + * @see java.util.Enumeration
216.987 + * @see java.util.Properties#defaults
216.988 + * @see #stringPropertyNames
216.989 + */
216.990 + public Enumeration<?> propertyNames() {
216.991 + Hashtable h = new Hashtable();
216.992 + enumerate(h);
216.993 + return h.keys();
216.994 + }
216.995 +
216.996 + /**
216.997 + * Returns a set of keys in this property list where
216.998 + * the key and its corresponding value are strings,
216.999 + * including distinct keys in the default property list if a key
216.1000 + * of the same name has not already been found from the main
216.1001 + * properties list. Properties whose key or value is not
216.1002 + * of type <tt>String</tt> are omitted.
216.1003 + * <p>
216.1004 + * The returned set is not backed by the <tt>Properties</tt> object.
216.1005 + * Changes to this <tt>Properties</tt> are not reflected in the set,
216.1006 + * or vice versa.
216.1007 + *
216.1008 + * @return a set of keys in this property list where
216.1009 + * the key and its corresponding value are strings,
216.1010 + * including the keys in the default property list.
216.1011 + * @see java.util.Properties#defaults
216.1012 + * @since 1.6
216.1013 + */
216.1014 + public Set<String> stringPropertyNames() {
216.1015 + Hashtable<String, String> h = new Hashtable<>();
216.1016 + enumerateStringProperties(h);
216.1017 + return h.keySet();
216.1018 + }
216.1019 +
216.1020 + /**
216.1021 + * Prints this property list out to the specified output stream.
216.1022 + * This method is useful for debugging.
216.1023 + *
216.1024 + * @param out an output stream.
216.1025 + * @throws ClassCastException if any key in this property list
216.1026 + * is not a string.
216.1027 + */
216.1028 + public void list(PrintStream out) {
216.1029 + out.println("-- listing properties --");
216.1030 + Hashtable h = new Hashtable();
216.1031 + enumerate(h);
216.1032 + for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
216.1033 + String key = (String)e.nextElement();
216.1034 + String val = (String)h.get(key);
216.1035 + if (val.length() > 40) {
216.1036 + val = val.substring(0, 37) + "...";
216.1037 + }
216.1038 + out.println(key + "=" + val);
216.1039 + }
216.1040 + }
216.1041 +
216.1042 + /**
216.1043 + * Prints this property list out to the specified output stream.
216.1044 + * This method is useful for debugging.
216.1045 + *
216.1046 + * @param out an output stream.
216.1047 + * @throws ClassCastException if any key in this property list
216.1048 + * is not a string.
216.1049 + * @since JDK1.1
216.1050 + */
216.1051 + /*
216.1052 + * Rather than use an anonymous inner class to share common code, this
216.1053 + * method is duplicated in order to ensure that a non-1.1 compiler can
216.1054 + * compile this file.
216.1055 + */
216.1056 + public void list(PrintWriter out) {
216.1057 + out.println("-- listing properties --");
216.1058 + Hashtable h = new Hashtable();
216.1059 + enumerate(h);
216.1060 + for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
216.1061 + String key = (String)e.nextElement();
216.1062 + String val = (String)h.get(key);
216.1063 + if (val.length() > 40) {
216.1064 + val = val.substring(0, 37) + "...";
216.1065 + }
216.1066 + out.println(key + "=" + val);
216.1067 + }
216.1068 + }
216.1069 +
216.1070 + /**
216.1071 + * Enumerates all key/value pairs in the specified hashtable.
216.1072 + * @param h the hashtable
216.1073 + * @throws ClassCastException if any of the property keys
216.1074 + * is not of String type.
216.1075 + */
216.1076 + private synchronized void enumerate(Hashtable h) {
216.1077 + if (defaults != null) {
216.1078 + defaults.enumerate(h);
216.1079 + }
216.1080 + for (Enumeration e = keys() ; e.hasMoreElements() ;) {
216.1081 + String key = (String)e.nextElement();
216.1082 + h.put(key, get(key));
216.1083 + }
216.1084 + }
216.1085 +
216.1086 + /**
216.1087 + * Enumerates all key/value pairs in the specified hashtable
216.1088 + * and omits the property if the key or value is not a string.
216.1089 + * @param h the hashtable
216.1090 + */
216.1091 + private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
216.1092 + if (defaults != null) {
216.1093 + defaults.enumerateStringProperties(h);
216.1094 + }
216.1095 + for (Enumeration e = keys() ; e.hasMoreElements() ;) {
216.1096 + Object k = e.nextElement();
216.1097 + Object v = get(k);
216.1098 + if (k instanceof String && v instanceof String) {
216.1099 + h.put((String) k, (String) v);
216.1100 + }
216.1101 + }
216.1102 + }
216.1103 +
216.1104 + /**
216.1105 + * Convert a nibble to a hex character
216.1106 + * @param nibble the nibble to convert.
216.1107 + */
216.1108 + private static char toHex(int nibble) {
216.1109 + return hexDigit[(nibble & 0xF)];
216.1110 + }
216.1111 +
216.1112 + /** A table of hex digits */
216.1113 + private static final char[] hexDigit = {
216.1114 + '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
216.1115 + };
216.1116 +}
217.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
217.2 +++ b/rt/emul/compact/src/main/java/java/util/PropertyResourceBundle.java Wed Apr 30 15:04:10 2014 +0200
217.3 @@ -0,0 +1,242 @@
217.4 +/*
217.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
217.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
217.7 + *
217.8 + * This code is free software; you can redistribute it and/or modify it
217.9 + * under the terms of the GNU General Public License version 2 only, as
217.10 + * published by the Free Software Foundation. Oracle designates this
217.11 + * particular file as subject to the "Classpath" exception as provided
217.12 + * by Oracle in the LICENSE file that accompanied this code.
217.13 + *
217.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
217.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
217.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
217.17 + * version 2 for more details (a copy is included in the LICENSE file that
217.18 + * accompanied this code).
217.19 + *
217.20 + * You should have received a copy of the GNU General Public License version
217.21 + * 2 along with this work; if not, write to the Free Software Foundation,
217.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
217.23 + *
217.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
217.25 + * or visit www.oracle.com if you need additional information or have any
217.26 + * questions.
217.27 + */
217.28 +
217.29 +/*
217.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
217.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
217.32 + *
217.33 + * The original version of this source code and documentation
217.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
217.35 + * subsidiary of IBM. These materials are provided under terms
217.36 + * of a License Agreement between Taligent and Sun. This technology
217.37 + * is protected by multiple US and International patents.
217.38 + *
217.39 + * This notice and attribution to Taligent may not be removed.
217.40 + * Taligent is a registered trademark of Taligent, Inc.
217.41 + */
217.42 +
217.43 +package java.util;
217.44 +
217.45 +import java.io.InputStream;
217.46 +import java.io.Reader;
217.47 +import java.io.IOException;
217.48 +
217.49 +/**
217.50 + * <code>PropertyResourceBundle</code> is a concrete subclass of
217.51 + * <code>ResourceBundle</code> that manages resources for a locale
217.52 + * using a set of static strings from a property file. See
217.53 + * {@link ResourceBundle ResourceBundle} for more information about resource
217.54 + * bundles.
217.55 + *
217.56 + * <p>
217.57 + * Unlike other types of resource bundle, you don't subclass
217.58 + * <code>PropertyResourceBundle</code>. Instead, you supply properties
217.59 + * files containing the resource data. <code>ResourceBundle.getBundle</code>
217.60 + * will automatically look for the appropriate properties file and create a
217.61 + * <code>PropertyResourceBundle</code> that refers to it. See
217.62 + * {@link ResourceBundle#getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader) ResourceBundle.getBundle}
217.63 + * for a complete description of the search and instantiation strategy.
217.64 + *
217.65 + * <p>
217.66 + * The following <a name="sample">example</a> shows a member of a resource
217.67 + * bundle family with the base name "MyResources".
217.68 + * The text defines the bundle "MyResources_de",
217.69 + * the German member of the bundle family.
217.70 + * This member is based on <code>PropertyResourceBundle</code>, and the text
217.71 + * therefore is the content of the file "MyResources_de.properties"
217.72 + * (a related <a href="ListResourceBundle.html#sample">example</a> shows
217.73 + * how you can add bundles to this family that are implemented as subclasses
217.74 + * of <code>ListResourceBundle</code>).
217.75 + * The keys in this example are of the form "s1" etc. The actual
217.76 + * keys are entirely up to your choice, so long as they are the same as
217.77 + * the keys you use in your program to retrieve the objects from the bundle.
217.78 + * Keys are case-sensitive.
217.79 + * <blockquote>
217.80 + * <pre>
217.81 + * # MessageFormat pattern
217.82 + * s1=Die Platte \"{1}\" enthält {0}.
217.83 + *
217.84 + * # location of {0} in pattern
217.85 + * s2=1
217.86 + *
217.87 + * # sample disk name
217.88 + * s3=Meine Platte
217.89 + *
217.90 + * # first ChoiceFormat choice
217.91 + * s4=keine Dateien
217.92 + *
217.93 + * # second ChoiceFormat choice
217.94 + * s5=eine Datei
217.95 + *
217.96 + * # third ChoiceFormat choice
217.97 + * s6={0,number} Dateien
217.98 + *
217.99 + * # sample date
217.100 + * s7=3. März 1996
217.101 + * </pre>
217.102 + * </blockquote>
217.103 + *
217.104 + * <p>
217.105 + * <strong>Note:</strong> PropertyResourceBundle can be constructed either
217.106 + * from an InputStream or a Reader, which represents a property file.
217.107 + * Constructing a PropertyResourceBundle instance from an InputStream requires
217.108 + * that the input stream be encoded in ISO-8859-1. In that case, characters
217.109 + * that cannot be represented in ISO-8859-1 encoding must be represented by Unicode Escapes
217.110 + * as defined in section 3.3 of
217.111 + * <cite>The Java™ Language Specification</cite>
217.112 + * whereas the other constructor which takes a Reader does not have that limitation.
217.113 + *
217.114 + * @see ResourceBundle
217.115 + * @see ListResourceBundle
217.116 + * @see Properties
217.117 + * @since JDK1.1
217.118 + */
217.119 +public class PropertyResourceBundle extends ResourceBundle {
217.120 + /**
217.121 + * Creates a property resource bundle from an {@link java.io.InputStream
217.122 + * InputStream}. The property file read with this constructor
217.123 + * must be encoded in ISO-8859-1.
217.124 + *
217.125 + * @param stream an InputStream that represents a property file
217.126 + * to read from.
217.127 + * @throws IOException if an I/O error occurs
217.128 + * @throws NullPointerException if <code>stream</code> is null
217.129 + */
217.130 + public PropertyResourceBundle (InputStream stream) throws IOException {
217.131 + Properties properties = new Properties();
217.132 + properties.load(stream);
217.133 + lookup = new HashMap(properties);
217.134 + }
217.135 +
217.136 + /**
217.137 + * Creates a property resource bundle from a {@link java.io.Reader
217.138 + * Reader}. Unlike the constructor
217.139 + * {@link #PropertyResourceBundle(java.io.InputStream) PropertyResourceBundle(InputStream)},
217.140 + * there is no limitation as to the encoding of the input property file.
217.141 + *
217.142 + * @param reader a Reader that represents a property file to
217.143 + * read from.
217.144 + * @throws IOException if an I/O error occurs
217.145 + * @throws NullPointerException if <code>reader</code> is null
217.146 + * @since 1.6
217.147 + */
217.148 + public PropertyResourceBundle (Reader reader) throws IOException {
217.149 + Properties properties = new Properties();
217.150 + properties.load(reader);
217.151 + lookup = new HashMap(properties);
217.152 + }
217.153 +
217.154 + // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
217.155 + public Object handleGetObject(String key) {
217.156 + if (key == null) {
217.157 + throw new NullPointerException();
217.158 + }
217.159 + return lookup.get(key);
217.160 + }
217.161 +
217.162 + /**
217.163 + * Returns an <code>Enumeration</code> of the keys contained in
217.164 + * this <code>ResourceBundle</code> and its parent bundles.
217.165 + *
217.166 + * @return an <code>Enumeration</code> of the keys contained in
217.167 + * this <code>ResourceBundle</code> and its parent bundles.
217.168 + * @see #keySet()
217.169 + */
217.170 + public Enumeration<String> getKeys() {
217.171 + ResourceBundle parent = this.parent;
217.172 + return new ResourceBundleEnumeration(lookup.keySet(),
217.173 + (parent != null) ? parent.getKeys() : null);
217.174 + }
217.175 +
217.176 + /**
217.177 + * Returns a <code>Set</code> of the keys contained
217.178 + * <em>only</em> in this <code>ResourceBundle</code>.
217.179 + *
217.180 + * @return a <code>Set</code> of the keys contained only in this
217.181 + * <code>ResourceBundle</code>
217.182 + * @since 1.6
217.183 + * @see #keySet()
217.184 + */
217.185 + protected Set<String> handleKeySet() {
217.186 + return lookup.keySet();
217.187 + }
217.188 +
217.189 + // ==================privates====================
217.190 +
217.191 + private Map<String,Object> lookup;
217.192 +
217.193 +
217.194 + /**
217.195 + * Implements an Enumeration that combines elements from a Set and
217.196 + * an Enumeration. Used by ListResourceBundle and PropertyResourceBundle.
217.197 + */
217.198 + static class ResourceBundleEnumeration implements Enumeration<String> {
217.199 +
217.200 + Set<String> set;
217.201 + Iterator<String> iterator;
217.202 + Enumeration<String> enumeration; // may remain null
217.203 +
217.204 + /**
217.205 + * Constructs a resource bundle enumeration.
217.206 + * @param set an set providing some elements of the enumeration
217.207 + * @param enumeration an enumeration providing more elements of the enumeration.
217.208 + * enumeration may be null.
217.209 + */
217.210 + public ResourceBundleEnumeration(Set<String> set, Enumeration<String> enumeration) {
217.211 + this.set = set;
217.212 + this.iterator = set.iterator();
217.213 + this.enumeration = enumeration;
217.214 + }
217.215 +
217.216 + String next = null;
217.217 +
217.218 + public boolean hasMoreElements() {
217.219 + if (next == null) {
217.220 + if (iterator.hasNext()) {
217.221 + next = iterator.next();
217.222 + } else if (enumeration != null) {
217.223 + while (next == null && enumeration.hasMoreElements()) {
217.224 + next = enumeration.nextElement();
217.225 + if (set.contains(next)) {
217.226 + next = null;
217.227 + }
217.228 + }
217.229 + }
217.230 + }
217.231 + return next != null;
217.232 + }
217.233 +
217.234 + public String nextElement() {
217.235 + if (hasMoreElements()) {
217.236 + String result = next;
217.237 + next = null;
217.238 + return result;
217.239 + } else {
217.240 + throw new NoSuchElementException();
217.241 + }
217.242 + }
217.243 + }
217.244 +
217.245 +}
218.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
218.2 +++ b/rt/emul/compact/src/main/java/java/util/RegularEnumSet.java Wed Apr 30 15:04:10 2014 +0200
218.3 @@ -0,0 +1,303 @@
218.4 +/*
218.5 + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
218.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
218.7 + *
218.8 + * This code is free software; you can redistribute it and/or modify it
218.9 + * under the terms of the GNU General Public License version 2 only, as
218.10 + * published by the Free Software Foundation. Oracle designates this
218.11 + * particular file as subject to the "Classpath" exception as provided
218.12 + * by Oracle in the LICENSE file that accompanied this code.
218.13 + *
218.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
218.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
218.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
218.17 + * version 2 for more details (a copy is included in the LICENSE file that
218.18 + * accompanied this code).
218.19 + *
218.20 + * You should have received a copy of the GNU General Public License version
218.21 + * 2 along with this work; if not, write to the Free Software Foundation,
218.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
218.23 + *
218.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
218.25 + * or visit www.oracle.com if you need additional information or have any
218.26 + * questions.
218.27 + */
218.28 +
218.29 +package java.util;
218.30 +
218.31 +/**
218.32 + * Private implementation class for EnumSet, for "regular sized" enum types
218.33 + * (i.e., those with 64 or fewer enum constants).
218.34 + *
218.35 + * @author Josh Bloch
218.36 + * @since 1.5
218.37 + * @serial exclude
218.38 + */
218.39 +class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
218.40 + private static final long serialVersionUID = 3411599620347842686L;
218.41 + /**
218.42 + * Bit vector representation of this set. The 2^k bit indicates the
218.43 + * presence of universe[k] in this set.
218.44 + */
218.45 + private long elements = 0L;
218.46 +
218.47 + RegularEnumSet(Class<E>elementType, Enum[] universe) {
218.48 + super(elementType, universe);
218.49 + }
218.50 +
218.51 + void addRange(E from, E to) {
218.52 + elements = (-1L >>> (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
218.53 + }
218.54 +
218.55 + void addAll() {
218.56 + if (universe.length != 0)
218.57 + elements = -1L >>> -universe.length;
218.58 + }
218.59 +
218.60 + void complement() {
218.61 + if (universe.length != 0) {
218.62 + elements = ~elements;
218.63 + elements &= -1L >>> -universe.length; // Mask unused bits
218.64 + }
218.65 + }
218.66 +
218.67 + /**
218.68 + * Returns an iterator over the elements contained in this set. The
218.69 + * iterator traverses the elements in their <i>natural order</i> (which is
218.70 + * the order in which the enum constants are declared). The returned
218.71 + * Iterator is a "snapshot" iterator that will never throw {@link
218.72 + * ConcurrentModificationException}; the elements are traversed as they
218.73 + * existed when this call was invoked.
218.74 + *
218.75 + * @return an iterator over the elements contained in this set
218.76 + */
218.77 + public Iterator<E> iterator() {
218.78 + return new EnumSetIterator<>();
218.79 + }
218.80 +
218.81 + private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
218.82 + /**
218.83 + * A bit vector representing the elements in the set not yet
218.84 + * returned by this iterator.
218.85 + */
218.86 + long unseen;
218.87 +
218.88 + /**
218.89 + * The bit representing the last element returned by this iterator
218.90 + * but not removed, or zero if no such element exists.
218.91 + */
218.92 + long lastReturned = 0;
218.93 +
218.94 + EnumSetIterator() {
218.95 + unseen = elements;
218.96 + }
218.97 +
218.98 + public boolean hasNext() {
218.99 + return unseen != 0;
218.100 + }
218.101 +
218.102 + public E next() {
218.103 + if (unseen == 0)
218.104 + throw new NoSuchElementException();
218.105 + lastReturned = unseen & -unseen;
218.106 + unseen -= lastReturned;
218.107 + return (E) universe[Long.numberOfTrailingZeros(lastReturned)];
218.108 + }
218.109 +
218.110 + public void remove() {
218.111 + if (lastReturned == 0)
218.112 + throw new IllegalStateException();
218.113 + elements &= ~lastReturned;
218.114 + lastReturned = 0;
218.115 + }
218.116 + }
218.117 +
218.118 + /**
218.119 + * Returns the number of elements in this set.
218.120 + *
218.121 + * @return the number of elements in this set
218.122 + */
218.123 + public int size() {
218.124 + return Long.bitCount(elements);
218.125 + }
218.126 +
218.127 + /**
218.128 + * Returns <tt>true</tt> if this set contains no elements.
218.129 + *
218.130 + * @return <tt>true</tt> if this set contains no elements
218.131 + */
218.132 + public boolean isEmpty() {
218.133 + return elements == 0;
218.134 + }
218.135 +
218.136 + /**
218.137 + * Returns <tt>true</tt> if this set contains the specified element.
218.138 + *
218.139 + * @param e element to be checked for containment in this collection
218.140 + * @return <tt>true</tt> if this set contains the specified element
218.141 + */
218.142 + public boolean contains(Object e) {
218.143 + if (e == null)
218.144 + return false;
218.145 + Class eClass = e.getClass();
218.146 + if (eClass != elementType && eClass.getSuperclass() != elementType)
218.147 + return false;
218.148 +
218.149 + return (elements & (1L << ((Enum)e).ordinal())) != 0;
218.150 + }
218.151 +
218.152 + // Modification Operations
218.153 +
218.154 + /**
218.155 + * Adds the specified element to this set if it is not already present.
218.156 + *
218.157 + * @param e element to be added to this set
218.158 + * @return <tt>true</tt> if the set changed as a result of the call
218.159 + *
218.160 + * @throws NullPointerException if <tt>e</tt> is null
218.161 + */
218.162 + public boolean add(E e) {
218.163 + typeCheck(e);
218.164 +
218.165 + long oldElements = elements;
218.166 + elements |= (1L << ((Enum)e).ordinal());
218.167 + return elements != oldElements;
218.168 + }
218.169 +
218.170 + /**
218.171 + * Removes the specified element from this set if it is present.
218.172 + *
218.173 + * @param e element to be removed from this set, if present
218.174 + * @return <tt>true</tt> if the set contained the specified element
218.175 + */
218.176 + public boolean remove(Object e) {
218.177 + if (e == null)
218.178 + return false;
218.179 + Class eClass = e.getClass();
218.180 + if (eClass != elementType && eClass.getSuperclass() != elementType)
218.181 + return false;
218.182 +
218.183 + long oldElements = elements;
218.184 + elements &= ~(1L << ((Enum)e).ordinal());
218.185 + return elements != oldElements;
218.186 + }
218.187 +
218.188 + // Bulk Operations
218.189 +
218.190 + /**
218.191 + * Returns <tt>true</tt> if this set contains all of the elements
218.192 + * in the specified collection.
218.193 + *
218.194 + * @param c collection to be checked for containment in this set
218.195 + * @return <tt>true</tt> if this set contains all of the elements
218.196 + * in the specified collection
218.197 + * @throws NullPointerException if the specified collection is null
218.198 + */
218.199 + public boolean containsAll(Collection<?> c) {
218.200 + if (!(c instanceof RegularEnumSet))
218.201 + return super.containsAll(c);
218.202 +
218.203 + RegularEnumSet es = (RegularEnumSet)c;
218.204 + if (es.elementType != elementType)
218.205 + return es.isEmpty();
218.206 +
218.207 + return (es.elements & ~elements) == 0;
218.208 + }
218.209 +
218.210 + /**
218.211 + * Adds all of the elements in the specified collection to this set.
218.212 + *
218.213 + * @param c collection whose elements are to be added to this set
218.214 + * @return <tt>true</tt> if this set changed as a result of the call
218.215 + * @throws NullPointerException if the specified collection or any
218.216 + * of its elements are null
218.217 + */
218.218 + public boolean addAll(Collection<? extends E> c) {
218.219 + if (!(c instanceof RegularEnumSet))
218.220 + return super.addAll(c);
218.221 +
218.222 + RegularEnumSet es = (RegularEnumSet)c;
218.223 + if (es.elementType != elementType) {
218.224 + if (es.isEmpty())
218.225 + return false;
218.226 + else
218.227 + throw new ClassCastException(
218.228 + es.elementType + " != " + elementType);
218.229 + }
218.230 +
218.231 + long oldElements = elements;
218.232 + elements |= es.elements;
218.233 + return elements != oldElements;
218.234 + }
218.235 +
218.236 + /**
218.237 + * Removes from this set all of its elements that are contained in
218.238 + * the specified collection.
218.239 + *
218.240 + * @param c elements to be removed from this set
218.241 + * @return <tt>true</tt> if this set changed as a result of the call
218.242 + * @throws NullPointerException if the specified collection is null
218.243 + */
218.244 + public boolean removeAll(Collection<?> c) {
218.245 + if (!(c instanceof RegularEnumSet))
218.246 + return super.removeAll(c);
218.247 +
218.248 + RegularEnumSet es = (RegularEnumSet)c;
218.249 + if (es.elementType != elementType)
218.250 + return false;
218.251 +
218.252 + long oldElements = elements;
218.253 + elements &= ~es.elements;
218.254 + return elements != oldElements;
218.255 + }
218.256 +
218.257 + /**
218.258 + * Retains only the elements in this set that are contained in the
218.259 + * specified collection.
218.260 + *
218.261 + * @param c elements to be retained in this set
218.262 + * @return <tt>true</tt> if this set changed as a result of the call
218.263 + * @throws NullPointerException if the specified collection is null
218.264 + */
218.265 + public boolean retainAll(Collection<?> c) {
218.266 + if (!(c instanceof RegularEnumSet))
218.267 + return super.retainAll(c);
218.268 +
218.269 + RegularEnumSet<?> es = (RegularEnumSet<?>)c;
218.270 + if (es.elementType != elementType) {
218.271 + boolean changed = (elements != 0);
218.272 + elements = 0;
218.273 + return changed;
218.274 + }
218.275 +
218.276 + long oldElements = elements;
218.277 + elements &= es.elements;
218.278 + return elements != oldElements;
218.279 + }
218.280 +
218.281 + /**
218.282 + * Removes all of the elements from this set.
218.283 + */
218.284 + public void clear() {
218.285 + elements = 0;
218.286 + }
218.287 +
218.288 + /**
218.289 + * Compares the specified object with this set for equality. Returns
218.290 + * <tt>true</tt> if the given object is also a set, the two sets have
218.291 + * the same size, and every member of the given set is contained in
218.292 + * this set.
218.293 + *
218.294 + * @param e object to be compared for equality with this set
218.295 + * @return <tt>true</tt> if the specified object is equal to this set
218.296 + */
218.297 + public boolean equals(Object o) {
218.298 + if (!(o instanceof RegularEnumSet))
218.299 + return super.equals(o);
218.300 +
218.301 + RegularEnumSet es = (RegularEnumSet)o;
218.302 + if (es.elementType != elementType)
218.303 + return elements == 0 && es.elements == 0;
218.304 + return es.elements == elements;
218.305 + }
218.306 +}
219.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
219.2 +++ b/rt/emul/compact/src/main/java/java/util/ResourceBundle.java Wed Apr 30 15:04:10 2014 +0200
219.3 @@ -0,0 +1,2778 @@
219.4 +/*
219.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
219.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
219.7 + *
219.8 + * This code is free software; you can redistribute it and/or modify it
219.9 + * under the terms of the GNU General Public License version 2 only, as
219.10 + * published by the Free Software Foundation. Oracle designates this
219.11 + * particular file as subject to the "Classpath" exception as provided
219.12 + * by Oracle in the LICENSE file that accompanied this code.
219.13 + *
219.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
219.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
219.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
219.17 + * version 2 for more details (a copy is included in the LICENSE file that
219.18 + * accompanied this code).
219.19 + *
219.20 + * You should have received a copy of the GNU General Public License version
219.21 + * 2 along with this work; if not, write to the Free Software Foundation,
219.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
219.23 + *
219.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
219.25 + * or visit www.oracle.com if you need additional information or have any
219.26 + * questions.
219.27 + */
219.28 +
219.29 +/*
219.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
219.31 + * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
219.32 + *
219.33 + * The original version of this source code and documentation
219.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
219.35 + * subsidiary of IBM. These materials are provided under terms
219.36 + * of a License Agreement between Taligent and Sun. This technology
219.37 + * is protected by multiple US and International patents.
219.38 + *
219.39 + * This notice and attribution to Taligent may not be removed.
219.40 + * Taligent is a registered trademark of Taligent, Inc.
219.41 + *
219.42 + */
219.43 +
219.44 +package java.util;
219.45 +
219.46 +import java.io.IOException;
219.47 +import java.io.InputStream;
219.48 +import java.lang.ref.ReferenceQueue;
219.49 +import java.lang.ref.SoftReference;
219.50 +import java.lang.ref.WeakReference;
219.51 +import java.net.URL;
219.52 +
219.53 +
219.54 +/**
219.55 + *
219.56 + * Resource bundles contain locale-specific objects. When your program needs a
219.57 + * locale-specific resource, a <code>String</code> for example, your program can
219.58 + * load it from the resource bundle that is appropriate for the current user's
219.59 + * locale. In this way, you can write program code that is largely independent
219.60 + * of the user's locale isolating most, if not all, of the locale-specific
219.61 + * information in resource bundles.
219.62 + *
219.63 + * <p>
219.64 + * This allows you to write programs that can:
219.65 + * <UL type=SQUARE>
219.66 + * <LI> be easily localized, or translated, into different languages
219.67 + * <LI> handle multiple locales at once
219.68 + * <LI> be easily modified later to support even more locales
219.69 + * </UL>
219.70 + *
219.71 + * <P>
219.72 + * Resource bundles belong to families whose members share a common base
219.73 + * name, but whose names also have additional components that identify
219.74 + * their locales. For example, the base name of a family of resource
219.75 + * bundles might be "MyResources". The family should have a default
219.76 + * resource bundle which simply has the same name as its family -
219.77 + * "MyResources" - and will be used as the bundle of last resort if a
219.78 + * specific locale is not supported. The family can then provide as
219.79 + * many locale-specific members as needed, for example a German one
219.80 + * named "MyResources_de".
219.81 + *
219.82 + * <P>
219.83 + * Each resource bundle in a family contains the same items, but the items have
219.84 + * been translated for the locale represented by that resource bundle.
219.85 + * For example, both "MyResources" and "MyResources_de" may have a
219.86 + * <code>String</code> that's used on a button for canceling operations.
219.87 + * In "MyResources" the <code>String</code> may contain "Cancel" and in
219.88 + * "MyResources_de" it may contain "Abbrechen".
219.89 + *
219.90 + * <P>
219.91 + * If there are different resources for different countries, you
219.92 + * can make specializations: for example, "MyResources_de_CH" contains objects for
219.93 + * the German language (de) in Switzerland (CH). If you want to only
219.94 + * modify some of the resources
219.95 + * in the specialization, you can do so.
219.96 + *
219.97 + * <P>
219.98 + * When your program needs a locale-specific object, it loads
219.99 + * the <code>ResourceBundle</code> class using the
219.100 + * {@link #getBundle(java.lang.String, java.util.Locale) getBundle}
219.101 + * method:
219.102 + * <blockquote>
219.103 + * <pre>
219.104 + * ResourceBundle myResources =
219.105 + * ResourceBundle.getBundle("MyResources", currentLocale);
219.106 + * </pre>
219.107 + * </blockquote>
219.108 + *
219.109 + * <P>
219.110 + * Resource bundles contain key/value pairs. The keys uniquely
219.111 + * identify a locale-specific object in the bundle. Here's an
219.112 + * example of a <code>ListResourceBundle</code> that contains
219.113 + * two key/value pairs:
219.114 + * <blockquote>
219.115 + * <pre>
219.116 + * public class MyResources extends ListResourceBundle {
219.117 + * protected Object[][] getContents() {
219.118 + * return new Object[][] {
219.119 + * // LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
219.120 + * {"OkKey", "OK"},
219.121 + * {"CancelKey", "Cancel"},
219.122 + * // END OF MATERIAL TO LOCALIZE
219.123 + * };
219.124 + * }
219.125 + * }
219.126 + * </pre>
219.127 + * </blockquote>
219.128 + * Keys are always <code>String</code>s.
219.129 + * In this example, the keys are "OkKey" and "CancelKey".
219.130 + * In the above example, the values
219.131 + * are also <code>String</code>s--"OK" and "Cancel"--but
219.132 + * they don't have to be. The values can be any type of object.
219.133 + *
219.134 + * <P>
219.135 + * You retrieve an object from resource bundle using the appropriate
219.136 + * getter method. Because "OkKey" and "CancelKey"
219.137 + * are both strings, you would use <code>getString</code> to retrieve them:
219.138 + * <blockquote>
219.139 + * <pre>
219.140 + * button1 = new Button(myResources.getString("OkKey"));
219.141 + * button2 = new Button(myResources.getString("CancelKey"));
219.142 + * </pre>
219.143 + * </blockquote>
219.144 + * The getter methods all require the key as an argument and return
219.145 + * the object if found. If the object is not found, the getter method
219.146 + * throws a <code>MissingResourceException</code>.
219.147 + *
219.148 + * <P>
219.149 + * Besides <code>getString</code>, <code>ResourceBundle</code> also provides
219.150 + * a method for getting string arrays, <code>getStringArray</code>,
219.151 + * as well as a generic <code>getObject</code> method for any other
219.152 + * type of object. When using <code>getObject</code>, you'll
219.153 + * have to cast the result to the appropriate type. For example:
219.154 + * <blockquote>
219.155 + * <pre>
219.156 + * int[] myIntegers = (int[]) myResources.getObject("intList");
219.157 + * </pre>
219.158 + * </blockquote>
219.159 + *
219.160 + * <P>
219.161 + * The Java Platform provides two subclasses of <code>ResourceBundle</code>,
219.162 + * <code>ListResourceBundle</code> and <code>PropertyResourceBundle</code>,
219.163 + * that provide a fairly simple way to create resources.
219.164 + * As you saw briefly in a previous example, <code>ListResourceBundle</code>
219.165 + * manages its resource as a list of key/value pairs.
219.166 + * <code>PropertyResourceBundle</code> uses a properties file to manage
219.167 + * its resources.
219.168 + *
219.169 + * <p>
219.170 + * If <code>ListResourceBundle</code> or <code>PropertyResourceBundle</code>
219.171 + * do not suit your needs, you can write your own <code>ResourceBundle</code>
219.172 + * subclass. Your subclasses must override two methods: <code>handleGetObject</code>
219.173 + * and <code>getKeys()</code>.
219.174 + *
219.175 + * <h4>ResourceBundle.Control</h4>
219.176 + *
219.177 + * The {@link ResourceBundle.Control} class provides information necessary
219.178 + * to perform the bundle loading process by the <code>getBundle</code>
219.179 + * factory methods that take a <code>ResourceBundle.Control</code>
219.180 + * instance. You can implement your own subclass in order to enable
219.181 + * non-standard resource bundle formats, change the search strategy, or
219.182 + * define caching parameters. Refer to the descriptions of the class and the
219.183 + * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
219.184 + * factory method for details.
219.185 + *
219.186 + * <h4>Cache Management</h4>
219.187 + *
219.188 + * Resource bundle instances created by the <code>getBundle</code> factory
219.189 + * methods are cached by default, and the factory methods return the same
219.190 + * resource bundle instance multiple times if it has been
219.191 + * cached. <code>getBundle</code> clients may clear the cache, manage the
219.192 + * lifetime of cached resource bundle instances using time-to-live values,
219.193 + * or specify not to cache resource bundle instances. Refer to the
219.194 + * descriptions of the {@linkplain #getBundle(String, Locale, ClassLoader,
219.195 + * Control) <code>getBundle</code> factory method}, {@link
219.196 + * #clearCache(ClassLoader) clearCache}, {@link
219.197 + * Control#getTimeToLive(String, Locale)
219.198 + * ResourceBundle.Control.getTimeToLive}, and {@link
219.199 + * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
219.200 + * long) ResourceBundle.Control.needsReload} for details.
219.201 + *
219.202 + * <h4>Example</h4>
219.203 + *
219.204 + * The following is a very simple example of a <code>ResourceBundle</code>
219.205 + * subclass, <code>MyResources</code>, that manages two resources (for a larger number of
219.206 + * resources you would probably use a <code>Map</code>).
219.207 + * Notice that you don't need to supply a value if
219.208 + * a "parent-level" <code>ResourceBundle</code> handles the same
219.209 + * key with the same value (as for the okKey below).
219.210 + * <blockquote>
219.211 + * <pre>
219.212 + * // default (English language, United States)
219.213 + * public class MyResources extends ResourceBundle {
219.214 + * public Object handleGetObject(String key) {
219.215 + * if (key.equals("okKey")) return "Ok";
219.216 + * if (key.equals("cancelKey")) return "Cancel";
219.217 + * return null;
219.218 + * }
219.219 + *
219.220 + * public Enumeration<String> getKeys() {
219.221 + * return Collections.enumeration(keySet());
219.222 + * }
219.223 + *
219.224 + * // Overrides handleKeySet() so that the getKeys() implementation
219.225 + * // can rely on the keySet() value.
219.226 + * protected Set<String> handleKeySet() {
219.227 + * return new HashSet<String>(Arrays.asList("okKey", "cancelKey"));
219.228 + * }
219.229 + * }
219.230 + *
219.231 + * // German language
219.232 + * public class MyResources_de extends MyResources {
219.233 + * public Object handleGetObject(String key) {
219.234 + * // don't need okKey, since parent level handles it.
219.235 + * if (key.equals("cancelKey")) return "Abbrechen";
219.236 + * return null;
219.237 + * }
219.238 + *
219.239 + * protected Set<String> handleKeySet() {
219.240 + * return new HashSet<String>(Arrays.asList("cancelKey"));
219.241 + * }
219.242 + * }
219.243 + * </pre>
219.244 + * </blockquote>
219.245 + * You do not have to restrict yourself to using a single family of
219.246 + * <code>ResourceBundle</code>s. For example, you could have a set of bundles for
219.247 + * exception messages, <code>ExceptionResources</code>
219.248 + * (<code>ExceptionResources_fr</code>, <code>ExceptionResources_de</code>, ...),
219.249 + * and one for widgets, <code>WidgetResource</code> (<code>WidgetResources_fr</code>,
219.250 + * <code>WidgetResources_de</code>, ...); breaking up the resources however you like.
219.251 + *
219.252 + * @see ListResourceBundle
219.253 + * @see PropertyResourceBundle
219.254 + * @see MissingResourceException
219.255 + * @since JDK1.1
219.256 + */
219.257 +public abstract class ResourceBundle {
219.258 +
219.259 + /** initial size of the bundle cache */
219.260 + private static final int INITIAL_CACHE_SIZE = 32;
219.261 +
219.262 + /** constant indicating that no resource bundle exists */
219.263 + private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
219.264 + public Enumeration<String> getKeys() { return null; }
219.265 + protected Object handleGetObject(String key) { return null; }
219.266 + public String toString() { return "NONEXISTENT_BUNDLE"; }
219.267 + };
219.268 +
219.269 +
219.270 + /**
219.271 + * The cache is a map from cache keys (with bundle base name, locale, and
219.272 + * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
219.273 + * BundleReference.
219.274 + *
219.275 + * The cache is a ConcurrentMap, allowing the cache to be searched
219.276 + * concurrently by multiple threads. This will also allow the cache keys
219.277 + * to be reclaimed along with the ClassLoaders they reference.
219.278 + *
219.279 + * This variable would be better named "cache", but we keep the old
219.280 + * name for compatibility with some workarounds for bug 4212439.
219.281 + */
219.282 + private static final Map<CacheKey, BundleReference> cacheList
219.283 + = new HashMap<>(INITIAL_CACHE_SIZE);
219.284 +
219.285 + /**
219.286 + * Queue for reference objects referring to class loaders or bundles.
219.287 + */
219.288 + private static final ReferenceQueue referenceQueue = new ReferenceQueue();
219.289 +
219.290 + /**
219.291 + * The parent bundle of this bundle.
219.292 + * The parent bundle is searched by {@link #getObject getObject}
219.293 + * when this bundle does not contain a particular resource.
219.294 + */
219.295 + protected ResourceBundle parent = null;
219.296 +
219.297 + /**
219.298 + * The locale for this bundle.
219.299 + */
219.300 + private Locale locale = null;
219.301 +
219.302 + /**
219.303 + * The base bundle name for this bundle.
219.304 + */
219.305 + private String name;
219.306 +
219.307 + /**
219.308 + * The flag indicating this bundle has expired in the cache.
219.309 + */
219.310 + private volatile boolean expired;
219.311 +
219.312 + /**
219.313 + * The back link to the cache key. null if this bundle isn't in
219.314 + * the cache (yet) or has expired.
219.315 + */
219.316 + private volatile CacheKey cacheKey;
219.317 +
219.318 + /**
219.319 + * A Set of the keys contained only in this ResourceBundle.
219.320 + */
219.321 + private volatile Set<String> keySet;
219.322 +
219.323 + /**
219.324 + * Sole constructor. (For invocation by subclass constructors, typically
219.325 + * implicit.)
219.326 + */
219.327 + public ResourceBundle() {
219.328 + }
219.329 +
219.330 + /**
219.331 + * Gets a string for the given key from this resource bundle or one of its parents.
219.332 + * Calling this method is equivalent to calling
219.333 + * <blockquote>
219.334 + * <code>(String) {@link #getObject(java.lang.String) getObject}(key)</code>.
219.335 + * </blockquote>
219.336 + *
219.337 + * @param key the key for the desired string
219.338 + * @exception NullPointerException if <code>key</code> is <code>null</code>
219.339 + * @exception MissingResourceException if no object for the given key can be found
219.340 + * @exception ClassCastException if the object found for the given key is not a string
219.341 + * @return the string for the given key
219.342 + */
219.343 + public final String getString(String key) {
219.344 + return (String) getObject(key);
219.345 + }
219.346 +
219.347 + /**
219.348 + * Gets a string array for the given key from this resource bundle or one of its parents.
219.349 + * Calling this method is equivalent to calling
219.350 + * <blockquote>
219.351 + * <code>(String[]) {@link #getObject(java.lang.String) getObject}(key)</code>.
219.352 + * </blockquote>
219.353 + *
219.354 + * @param key the key for the desired string array
219.355 + * @exception NullPointerException if <code>key</code> is <code>null</code>
219.356 + * @exception MissingResourceException if no object for the given key can be found
219.357 + * @exception ClassCastException if the object found for the given key is not a string array
219.358 + * @return the string array for the given key
219.359 + */
219.360 + public final String[] getStringArray(String key) {
219.361 + return (String[]) getObject(key);
219.362 + }
219.363 +
219.364 + /**
219.365 + * Gets an object for the given key from this resource bundle or one of its parents.
219.366 + * This method first tries to obtain the object from this resource bundle using
219.367 + * {@link #handleGetObject(java.lang.String) handleGetObject}.
219.368 + * If not successful, and the parent resource bundle is not null,
219.369 + * it calls the parent's <code>getObject</code> method.
219.370 + * If still not successful, it throws a MissingResourceException.
219.371 + *
219.372 + * @param key the key for the desired object
219.373 + * @exception NullPointerException if <code>key</code> is <code>null</code>
219.374 + * @exception MissingResourceException if no object for the given key can be found
219.375 + * @return the object for the given key
219.376 + */
219.377 + public final Object getObject(String key) {
219.378 + Object obj = handleGetObject(key);
219.379 + if (obj == null) {
219.380 + if (parent != null) {
219.381 + obj = parent.getObject(key);
219.382 + }
219.383 + if (obj == null)
219.384 + throw new MissingResourceException("Can't find resource for bundle "
219.385 + +this.getClass().getName()
219.386 + +", key "+key,
219.387 + this.getClass().getName(),
219.388 + key);
219.389 + }
219.390 + return obj;
219.391 + }
219.392 +
219.393 + /**
219.394 + * Returns the locale of this resource bundle. This method can be used after a
219.395 + * call to getBundle() to determine whether the resource bundle returned really
219.396 + * corresponds to the requested locale or is a fallback.
219.397 + *
219.398 + * @return the locale of this resource bundle
219.399 + */
219.400 + public Locale getLocale() {
219.401 + return locale;
219.402 + }
219.403 +
219.404 + /**
219.405 + * Sets the parent bundle of this bundle.
219.406 + * The parent bundle is searched by {@link #getObject getObject}
219.407 + * when this bundle does not contain a particular resource.
219.408 + *
219.409 + * @param parent this bundle's parent bundle.
219.410 + */
219.411 + protected void setParent(ResourceBundle parent) {
219.412 + assert parent != NONEXISTENT_BUNDLE;
219.413 + this.parent = parent;
219.414 + }
219.415 +
219.416 + /**
219.417 + * Key used for cached resource bundles. The key checks the base
219.418 + * name, the locale, and the class loader to determine if the
219.419 + * resource is a match to the requested one. The loader may be
219.420 + * null, but the base name and the locale must have a non-null
219.421 + * value.
219.422 + */
219.423 + private static final class CacheKey implements Cloneable {
219.424 + // These three are the actual keys for lookup in Map.
219.425 + private String name;
219.426 + private Locale locale;
219.427 +
219.428 + // bundle format which is necessary for calling
219.429 + // Control.needsReload().
219.430 + private String format;
219.431 +
219.432 + // These time values are in CacheKey so that NONEXISTENT_BUNDLE
219.433 + // doesn't need to be cloned for caching.
219.434 +
219.435 + // The time when the bundle has been loaded
219.436 + private volatile long loadTime;
219.437 +
219.438 + // The time when the bundle expires in the cache, or either
219.439 + // Control.TTL_DONT_CACHE or Control.TTL_NO_EXPIRATION_CONTROL.
219.440 + private volatile long expirationTime;
219.441 +
219.442 + // Placeholder for an error report by a Throwable
219.443 + private Throwable cause;
219.444 +
219.445 + // Hash code value cache to avoid recalculating the hash code
219.446 + // of this instance.
219.447 + private int hashCodeCache;
219.448 +
219.449 + CacheKey(String baseName, Locale locale) {
219.450 + this.name = baseName;
219.451 + this.locale = locale;
219.452 + calculateHashCode();
219.453 + }
219.454 +
219.455 + String getName() {
219.456 + return name;
219.457 + }
219.458 +
219.459 + CacheKey setName(String baseName) {
219.460 + if (!this.name.equals(baseName)) {
219.461 + this.name = baseName;
219.462 + calculateHashCode();
219.463 + }
219.464 + return this;
219.465 + }
219.466 +
219.467 + Locale getLocale() {
219.468 + return locale;
219.469 + }
219.470 +
219.471 + CacheKey setLocale(Locale locale) {
219.472 + if (!this.locale.equals(locale)) {
219.473 + this.locale = locale;
219.474 + calculateHashCode();
219.475 + }
219.476 + return this;
219.477 + }
219.478 +
219.479 + public boolean equals(Object other) {
219.480 + if (this == other) {
219.481 + return true;
219.482 + }
219.483 + try {
219.484 + final CacheKey otherEntry = (CacheKey)other;
219.485 + //quick check to see if they are not equal
219.486 + if (hashCodeCache != otherEntry.hashCodeCache) {
219.487 + return false;
219.488 + }
219.489 + //are the names the same?
219.490 + if (!name.equals(otherEntry.name)) {
219.491 + return false;
219.492 + }
219.493 + // are the locales the same?
219.494 + if (!locale.equals(otherEntry.locale)) {
219.495 + return false;
219.496 + }
219.497 + return true;
219.498 + } catch (NullPointerException e) {
219.499 + } catch (ClassCastException e) {
219.500 + }
219.501 + return false;
219.502 + }
219.503 +
219.504 + public int hashCode() {
219.505 + return hashCodeCache;
219.506 + }
219.507 +
219.508 + private void calculateHashCode() {
219.509 + hashCodeCache = name.hashCode() << 3;
219.510 + hashCodeCache ^= locale.hashCode();
219.511 + }
219.512 +
219.513 + public Object clone() {
219.514 + try {
219.515 + CacheKey clone = (CacheKey) super.clone();
219.516 + // Clear the reference to a Throwable
219.517 + clone.cause = null;
219.518 + return clone;
219.519 + } catch (CloneNotSupportedException e) {
219.520 + //this should never happen
219.521 + throw new InternalError();
219.522 + }
219.523 + }
219.524 +
219.525 + String getFormat() {
219.526 + return format;
219.527 + }
219.528 +
219.529 + void setFormat(String format) {
219.530 + this.format = format;
219.531 + }
219.532 +
219.533 + private void setCause(Throwable cause) {
219.534 + if (this.cause == null) {
219.535 + this.cause = cause;
219.536 + } else {
219.537 + // Override the cause if the previous one is
219.538 + // ClassNotFoundException.
219.539 + if (this.cause instanceof ClassNotFoundException) {
219.540 + this.cause = cause;
219.541 + }
219.542 + }
219.543 + }
219.544 +
219.545 + private Throwable getCause() {
219.546 + return cause;
219.547 + }
219.548 +
219.549 + public String toString() {
219.550 + String l = locale.toString();
219.551 + if (l.length() == 0) {
219.552 + if (locale.getVariant().length() != 0) {
219.553 + l = "__" + locale.getVariant();
219.554 + } else {
219.555 + l = "\"\"";
219.556 + }
219.557 + }
219.558 + return "CacheKey[" + name + ", lc=" + l
219.559 + + "(format=" + format + ")]";
219.560 + }
219.561 + }
219.562 +
219.563 + /**
219.564 + * The common interface to get a CacheKey in LoaderReference and
219.565 + * BundleReference.
219.566 + */
219.567 + private static interface CacheKeyReference {
219.568 + public CacheKey getCacheKey();
219.569 + }
219.570 +
219.571 + /**
219.572 + * References to bundles are soft references so that they can be garbage
219.573 + * collected when they have no hard references.
219.574 + */
219.575 + private static final class BundleReference extends SoftReference<ResourceBundle>
219.576 + implements CacheKeyReference {
219.577 + private CacheKey cacheKey;
219.578 +
219.579 + BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) {
219.580 + super(referent, q);
219.581 + cacheKey = key;
219.582 + }
219.583 +
219.584 + public CacheKey getCacheKey() {
219.585 + return cacheKey;
219.586 + }
219.587 + }
219.588 +
219.589 + /**
219.590 + * Gets a resource bundle using the specified base name, the default locale,
219.591 + * and the caller's class loader. Calling this method is equivalent to calling
219.592 + * <blockquote>
219.593 + * <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>,
219.594 + * </blockquote>
219.595 + * except that <code>getClassLoader()</code> is run with the security
219.596 + * privileges of <code>ResourceBundle</code>.
219.597 + * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
219.598 + * for a complete description of the search and instantiation strategy.
219.599 + *
219.600 + * @param baseName the base name of the resource bundle, a fully qualified class name
219.601 + * @exception java.lang.NullPointerException
219.602 + * if <code>baseName</code> is <code>null</code>
219.603 + * @exception MissingResourceException
219.604 + * if no resource bundle for the specified base name can be found
219.605 + * @return a resource bundle for the given base name and the default locale
219.606 + */
219.607 + public static final ResourceBundle getBundle(String baseName)
219.608 + {
219.609 + return getBundleImpl(baseName, Locale.getDefault(),
219.610 + Control.INSTANCE);
219.611 + }
219.612 +
219.613 + /**
219.614 + * Returns a resource bundle using the specified base name, the
219.615 + * default locale and the specified control. Calling this method
219.616 + * is equivalent to calling
219.617 + * <pre>
219.618 + * getBundle(baseName, Locale.getDefault(),
219.619 + * this.getClass().getClassLoader(), control),
219.620 + * </pre>
219.621 + * except that <code>getClassLoader()</code> is run with the security
219.622 + * privileges of <code>ResourceBundle</code>. See {@link
219.623 + * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
219.624 + * complete description of the resource bundle loading process with a
219.625 + * <code>ResourceBundle.Control</code>.
219.626 + *
219.627 + * @param baseName
219.628 + * the base name of the resource bundle, a fully qualified class
219.629 + * name
219.630 + * @param control
219.631 + * the control which gives information for the resource bundle
219.632 + * loading process
219.633 + * @return a resource bundle for the given base name and the default
219.634 + * locale
219.635 + * @exception NullPointerException
219.636 + * if <code>baseName</code> or <code>control</code> is
219.637 + * <code>null</code>
219.638 + * @exception MissingResourceException
219.639 + * if no resource bundle for the specified base name can be found
219.640 + * @exception IllegalArgumentException
219.641 + * if the given <code>control</code> doesn't perform properly
219.642 + * (e.g., <code>control.getCandidateLocales</code> returns null.)
219.643 + * Note that validation of <code>control</code> is performed as
219.644 + * needed.
219.645 + * @since 1.6
219.646 + */
219.647 + public static final ResourceBundle getBundle(String baseName,
219.648 + Control control) {
219.649 + return getBundleImpl(baseName, Locale.getDefault(),
219.650 + /* must determine loader here, else we break stack invariant */
219.651 + control);
219.652 + }
219.653 +
219.654 + /**
219.655 + * Gets a resource bundle using the specified base name and locale,
219.656 + * and the caller's class loader. Calling this method is equivalent to calling
219.657 + * <blockquote>
219.658 + * <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>,
219.659 + * </blockquote>
219.660 + * except that <code>getClassLoader()</code> is run with the security
219.661 + * privileges of <code>ResourceBundle</code>.
219.662 + * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
219.663 + * for a complete description of the search and instantiation strategy.
219.664 + *
219.665 + * @param baseName
219.666 + * the base name of the resource bundle, a fully qualified class name
219.667 + * @param locale
219.668 + * the locale for which a resource bundle is desired
219.669 + * @exception NullPointerException
219.670 + * if <code>baseName</code> or <code>locale</code> is <code>null</code>
219.671 + * @exception MissingResourceException
219.672 + * if no resource bundle for the specified base name can be found
219.673 + * @return a resource bundle for the given base name and locale
219.674 + */
219.675 + public static final ResourceBundle getBundle(String baseName,
219.676 + Locale locale)
219.677 + {
219.678 + return getBundleImpl(baseName, locale,
219.679 + /* must determine loader here, else we break stack invariant */
219.680 + Control.INSTANCE);
219.681 + }
219.682 +
219.683 + /**
219.684 + * Returns a resource bundle using the specified base name, target
219.685 + * locale and control, and the caller's class loader. Calling this
219.686 + * method is equivalent to calling
219.687 + * <pre>
219.688 + * getBundle(baseName, targetLocale, this.getClass().getClassLoader(),
219.689 + * control),
219.690 + * </pre>
219.691 + * except that <code>getClassLoader()</code> is run with the security
219.692 + * privileges of <code>ResourceBundle</code>. See {@link
219.693 + * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
219.694 + * complete description of the resource bundle loading process with a
219.695 + * <code>ResourceBundle.Control</code>.
219.696 + *
219.697 + * @param baseName
219.698 + * the base name of the resource bundle, a fully qualified
219.699 + * class name
219.700 + * @param targetLocale
219.701 + * the locale for which a resource bundle is desired
219.702 + * @param control
219.703 + * the control which gives information for the resource
219.704 + * bundle loading process
219.705 + * @return a resource bundle for the given base name and a
219.706 + * <code>Locale</code> in <code>locales</code>
219.707 + * @exception NullPointerException
219.708 + * if <code>baseName</code>, <code>locales</code> or
219.709 + * <code>control</code> is <code>null</code>
219.710 + * @exception MissingResourceException
219.711 + * if no resource bundle for the specified base name in any
219.712 + * of the <code>locales</code> can be found.
219.713 + * @exception IllegalArgumentException
219.714 + * if the given <code>control</code> doesn't perform properly
219.715 + * (e.g., <code>control.getCandidateLocales</code> returns null.)
219.716 + * Note that validation of <code>control</code> is performed as
219.717 + * needed.
219.718 + * @since 1.6
219.719 + */
219.720 + public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
219.721 + Control control) {
219.722 + return getBundleImpl(baseName, targetLocale,
219.723 + /* must determine loader here, else we break stack invariant */
219.724 + control);
219.725 + }
219.726 +
219.727 + /**
219.728 + * Gets a resource bundle using the specified base name, locale, and class
219.729 + * loader.
219.730 + *
219.731 + * <p><a name="default_behavior"/>This method behaves the same as calling
219.732 + * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
219.733 + * default instance of {@link Control}. The following describes this behavior.
219.734 + *
219.735 + * <p><code>getBundle</code> uses the base name, the specified locale, and
219.736 + * the default locale (obtained from {@link java.util.Locale#getDefault()
219.737 + * Locale.getDefault}) to generate a sequence of <a
219.738 + * name="candidates"><em>candidate bundle names</em></a>. If the specified
219.739 + * locale's language, script, country, and variant are all empty strings,
219.740 + * then the base name is the only candidate bundle name. Otherwise, a list
219.741 + * of candidate locales is generated from the attribute values of the
219.742 + * specified locale (language, script, country and variant) and appended to
219.743 + * the base name. Typically, this will look like the following:
219.744 + *
219.745 + * <pre>
219.746 + * baseName + "_" + language + "_" + script + "_" + country + "_" + variant
219.747 + * baseName + "_" + language + "_" + script + "_" + country
219.748 + * baseName + "_" + language + "_" + script
219.749 + * baseName + "_" + language + "_" + country + "_" + variant
219.750 + * baseName + "_" + language + "_" + country
219.751 + * baseName + "_" + language
219.752 + * </pre>
219.753 + *
219.754 + * <p>Candidate bundle names where the final component is an empty string
219.755 + * are omitted, along with the underscore. For example, if country is an
219.756 + * empty string, the second and the fifth candidate bundle names above
219.757 + * would be omitted. Also, if script is an empty string, the candidate names
219.758 + * including script are omitted. For example, a locale with language "de"
219.759 + * and variant "JAVA" will produce candidate names with base name
219.760 + * "MyResource" below.
219.761 + *
219.762 + * <pre>
219.763 + * MyResource_de__JAVA
219.764 + * MyResource_de
219.765 + * </pre>
219.766 + *
219.767 + * In the case that the variant contains one or more underscores ('_'), a
219.768 + * sequence of bundle names generated by truncating the last underscore and
219.769 + * the part following it is inserted after a candidate bundle name with the
219.770 + * original variant. For example, for a locale with language "en", script
219.771 + * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name
219.772 + * "MyResource", the list of candidate bundle names below is generated:
219.773 + *
219.774 + * <pre>
219.775 + * MyResource_en_Latn_US_WINDOWS_VISTA
219.776 + * MyResource_en_Latn_US_WINDOWS
219.777 + * MyResource_en_Latn_US
219.778 + * MyResource_en_Latn
219.779 + * MyResource_en_US_WINDOWS_VISTA
219.780 + * MyResource_en_US_WINDOWS
219.781 + * MyResource_en_US
219.782 + * MyResource_en
219.783 + * </pre>
219.784 + *
219.785 + * <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of
219.786 + * candidate bundle names contains extra names, or the order of bundle names
219.787 + * is slightly modified. See the description of the default implementation
219.788 + * of {@link Control#getCandidateLocales(String, Locale)
219.789 + * getCandidateLocales} for details.</blockquote>
219.790 + *
219.791 + * <p><code>getBundle</code> then iterates over the candidate bundle names
219.792 + * to find the first one for which it can <em>instantiate</em> an actual
219.793 + * resource bundle. It uses the default controls' {@link Control#getFormats
219.794 + * getFormats} method, which generates two bundle names for each generated
219.795 + * name, the first a class name and the second a properties file name. For
219.796 + * each candidate bundle name, it attempts to create a resource bundle:
219.797 + *
219.798 + * <ul><li>First, it attempts to load a class using the generated class name.
219.799 + * If such a class can be found and loaded using the specified class
219.800 + * loader, is assignment compatible with ResourceBundle, is accessible from
219.801 + * ResourceBundle, and can be instantiated, <code>getBundle</code> creates a
219.802 + * new instance of this class and uses it as the <em>result resource
219.803 + * bundle</em>.
219.804 + *
219.805 + * <li>Otherwise, <code>getBundle</code> attempts to locate a property
219.806 + * resource file using the generated properties file name. It generates a
219.807 + * path name from the candidate bundle name by replacing all "." characters
219.808 + * with "/" and appending the string ".properties". It attempts to find a
219.809 + * "resource" with this name using {@link
219.810 + * java.lang.ClassLoader#getResource(java.lang.String)
219.811 + * ClassLoader.getResource}. (Note that a "resource" in the sense of
219.812 + * <code>getResource</code> has nothing to do with the contents of a
219.813 + * resource bundle, it is just a container of data, such as a file.) If it
219.814 + * finds a "resource", it attempts to create a new {@link
219.815 + * PropertyResourceBundle} instance from its contents. If successful, this
219.816 + * instance becomes the <em>result resource bundle</em>. </ul>
219.817 + *
219.818 + * <p>This continues until a result resource bundle is instantiated or the
219.819 + * list of candidate bundle names is exhausted. If no matching resource
219.820 + * bundle is found, the default control's {@link Control#getFallbackLocale
219.821 + * getFallbackLocale} method is called, which returns the current default
219.822 + * locale. A new sequence of candidate locale names is generated using this
219.823 + * locale and and searched again, as above.
219.824 + *
219.825 + * <p>If still no result bundle is found, the base name alone is looked up. If
219.826 + * this still fails, a <code>MissingResourceException</code> is thrown.
219.827 + *
219.828 + * <p><a name="parent_chain"/> Once a result resource bundle has been found,
219.829 + * its <em>parent chain</em> is instantiated. If the result bundle already
219.830 + * has a parent (perhaps because it was returned from a cache) the chain is
219.831 + * complete.
219.832 + *
219.833 + * <p>Otherwise, <code>getBundle</code> examines the remainder of the
219.834 + * candidate locale list that was used during the pass that generated the
219.835 + * result resource bundle. (As before, candidate bundle names where the
219.836 + * final component is an empty string are omitted.) When it comes to the
219.837 + * end of the candidate list, it tries the plain bundle name. With each of the
219.838 + * candidate bundle names it attempts to instantiate a resource bundle (first
219.839 + * looking for a class and then a properties file, as described above).
219.840 + *
219.841 + * <p>Whenever it succeeds, it calls the previously instantiated resource
219.842 + * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method
219.843 + * with the new resource bundle. This continues until the list of names
219.844 + * is exhausted or the current bundle already has a non-null parent.
219.845 + *
219.846 + * <p>Once the parent chain is complete, the bundle is returned.
219.847 + *
219.848 + * <p><b>Note:</b> <code>getBundle</code> caches instantiated resource
219.849 + * bundles and might return the same resource bundle instance multiple times.
219.850 + *
219.851 + * <p><b>Note:</b>The <code>baseName</code> argument should be a fully
219.852 + * qualified class name. However, for compatibility with earlier versions,
219.853 + * Sun's Java SE Runtime Environments do not verify this, and so it is
219.854 + * possible to access <code>PropertyResourceBundle</code>s by specifying a
219.855 + * path name (using "/") instead of a fully qualified class name (using
219.856 + * ".").
219.857 + *
219.858 + * <p><a name="default_behavior_example"/>
219.859 + * <strong>Example:</strong>
219.860 + * <p>
219.861 + * The following class and property files are provided:
219.862 + * <pre>
219.863 + * MyResources.class
219.864 + * MyResources.properties
219.865 + * MyResources_fr.properties
219.866 + * MyResources_fr_CH.class
219.867 + * MyResources_fr_CH.properties
219.868 + * MyResources_en.properties
219.869 + * MyResources_es_ES.class
219.870 + * </pre>
219.871 + *
219.872 + * The contents of all files are valid (that is, public non-abstract
219.873 + * subclasses of <code>ResourceBundle</code> for the ".class" files,
219.874 + * syntactically correct ".properties" files). The default locale is
219.875 + * <code>Locale("en", "GB")</code>.
219.876 + *
219.877 + * <p>Calling <code>getBundle</code> with the locale arguments below will
219.878 + * instantiate resource bundles as follows:
219.879 + *
219.880 + * <table>
219.881 + * <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
219.882 + * <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
219.883 + * <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
219.884 + * <tr><td>Locale("en", "US")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
219.885 + * <tr><td>Locale("es", "ES")</td><td>MyResources_es_ES.class, parent MyResources.class</td></tr>
219.886 + * </table>
219.887 + *
219.888 + * <p>The file MyResources_fr_CH.properties is never used because it is
219.889 + * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
219.890 + * is also hidden by MyResources.class.
219.891 + *
219.892 + * @param baseName the base name of the resource bundle, a fully qualified class name
219.893 + * @param locale the locale for which a resource bundle is desired
219.894 + * @param loader the class loader from which to load the resource bundle
219.895 + * @return a resource bundle for the given base name and locale
219.896 + * @exception java.lang.NullPointerException
219.897 + * if <code>baseName</code>, <code>locale</code>, or <code>loader</code> is <code>null</code>
219.898 + * @exception MissingResourceException
219.899 + * if no resource bundle for the specified base name can be found
219.900 + * @since 1.2
219.901 + */
219.902 + public static ResourceBundle getBundle(String baseName, Locale locale,
219.903 + ClassLoader loader)
219.904 + {
219.905 + if (loader == null) {
219.906 + throw new NullPointerException();
219.907 + }
219.908 + return getBundleImpl(baseName, locale, Control.INSTANCE);
219.909 + }
219.910 +
219.911 + /**
219.912 + * Returns a resource bundle using the specified base name, target
219.913 + * locale, class loader and control. Unlike the {@linkplain
219.914 + * #getBundle(String, Locale, ClassLoader) <code>getBundle</code>
219.915 + * factory methods with no <code>control</code> argument}, the given
219.916 + * <code>control</code> specifies how to locate and instantiate resource
219.917 + * bundles. Conceptually, the bundle loading process with the given
219.918 + * <code>control</code> is performed in the following steps.
219.919 + *
219.920 + * <p>
219.921 + * <ol>
219.922 + * <li>This factory method looks up the resource bundle in the cache for
219.923 + * the specified <code>baseName</code>, <code>targetLocale</code> and
219.924 + * <code>loader</code>. If the requested resource bundle instance is
219.925 + * found in the cache and the time-to-live periods of the instance and
219.926 + * all of its parent instances have not expired, the instance is returned
219.927 + * to the caller. Otherwise, this factory method proceeds with the
219.928 + * loading process below.</li>
219.929 + *
219.930 + * <li>The {@link ResourceBundle.Control#getFormats(String)
219.931 + * control.getFormats} method is called to get resource bundle formats
219.932 + * to produce bundle or resource names. The strings
219.933 + * <code>"java.class"</code> and <code>"java.properties"</code>
219.934 + * designate class-based and {@linkplain PropertyResourceBundle
219.935 + * property}-based resource bundles, respectively. Other strings
219.936 + * starting with <code>"java."</code> are reserved for future extensions
219.937 + * and must not be used for application-defined formats. Other strings
219.938 + * designate application-defined formats.</li>
219.939 + *
219.940 + * <li>The {@link ResourceBundle.Control#getCandidateLocales(String,
219.941 + * Locale) control.getCandidateLocales} method is called with the target
219.942 + * locale to get a list of <em>candidate <code>Locale</code>s</em> for
219.943 + * which resource bundles are searched.</li>
219.944 + *
219.945 + * <li>The {@link ResourceBundle.Control#newBundle(String, Locale,
219.946 + * String, ClassLoader, boolean) control.newBundle} method is called to
219.947 + * instantiate a <code>ResourceBundle</code> for the base bundle name, a
219.948 + * candidate locale, and a format. (Refer to the note on the cache
219.949 + * lookup below.) This step is iterated over all combinations of the
219.950 + * candidate locales and formats until the <code>newBundle</code> method
219.951 + * returns a <code>ResourceBundle</code> instance or the iteration has
219.952 + * used up all the combinations. For example, if the candidate locales
219.953 + * are <code>Locale("de", "DE")</code>, <code>Locale("de")</code> and
219.954 + * <code>Locale("")</code> and the formats are <code>"java.class"</code>
219.955 + * and <code>"java.properties"</code>, then the following is the
219.956 + * sequence of locale-format combinations to be used to call
219.957 + * <code>control.newBundle</code>.
219.958 + *
219.959 + * <table style="width: 50%; text-align: left; margin-left: 40px;"
219.960 + * border="0" cellpadding="2" cellspacing="2">
219.961 + * <tbody><code>
219.962 + * <tr>
219.963 + * <td
219.964 + * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">Locale<br>
219.965 + * </td>
219.966 + * <td
219.967 + * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">format<br>
219.968 + * </td>
219.969 + * </tr>
219.970 + * <tr>
219.971 + * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")<br>
219.972 + * </td>
219.973 + * <td style="vertical-align: top; width: 50%;">java.class<br>
219.974 + * </td>
219.975 + * </tr>
219.976 + * <tr>
219.977 + * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")</td>
219.978 + * <td style="vertical-align: top; width: 50%;">java.properties<br>
219.979 + * </td>
219.980 + * </tr>
219.981 + * <tr>
219.982 + * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
219.983 + * <td style="vertical-align: top; width: 50%;">java.class</td>
219.984 + * </tr>
219.985 + * <tr>
219.986 + * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
219.987 + * <td style="vertical-align: top; width: 50%;">java.properties</td>
219.988 + * </tr>
219.989 + * <tr>
219.990 + * <td style="vertical-align: top; width: 50%;">Locale("")<br>
219.991 + * </td>
219.992 + * <td style="vertical-align: top; width: 50%;">java.class</td>
219.993 + * </tr>
219.994 + * <tr>
219.995 + * <td style="vertical-align: top; width: 50%;">Locale("")</td>
219.996 + * <td style="vertical-align: top; width: 50%;">java.properties</td>
219.997 + * </tr>
219.998 + * </code></tbody>
219.999 + * </table>
219.1000 + * </li>
219.1001 + *
219.1002 + * <li>If the previous step has found no resource bundle, proceed to
219.1003 + * Step 6. If a bundle has been found that is a base bundle (a bundle
219.1004 + * for <code>Locale("")</code>), and the candidate locale list only contained
219.1005 + * <code>Locale("")</code>, return the bundle to the caller. If a bundle
219.1006 + * has been found that is a base bundle, but the candidate locale list
219.1007 + * contained locales other than Locale(""), put the bundle on hold and
219.1008 + * proceed to Step 6. If a bundle has been found that is not a base
219.1009 + * bundle, proceed to Step 7.</li>
219.1010 + *
219.1011 + * <li>The {@link ResourceBundle.Control#getFallbackLocale(String,
219.1012 + * Locale) control.getFallbackLocale} method is called to get a fallback
219.1013 + * locale (alternative to the current target locale) to try further
219.1014 + * finding a resource bundle. If the method returns a non-null locale,
219.1015 + * it becomes the next target locale and the loading process starts over
219.1016 + * from Step 3. Otherwise, if a base bundle was found and put on hold in
219.1017 + * a previous Step 5, it is returned to the caller now. Otherwise, a
219.1018 + * MissingResourceException is thrown.</li>
219.1019 + *
219.1020 + * <li>At this point, we have found a resource bundle that's not the
219.1021 + * base bundle. If this bundle set its parent during its instantiation,
219.1022 + * it is returned to the caller. Otherwise, its <a
219.1023 + * href="./ResourceBundle.html#parent_chain">parent chain</a> is
219.1024 + * instantiated based on the list of candidate locales from which it was
219.1025 + * found. Finally, the bundle is returned to the caller.</li>
219.1026 + * </ol>
219.1027 + *
219.1028 + * <p>During the resource bundle loading process above, this factory
219.1029 + * method looks up the cache before calling the {@link
219.1030 + * Control#newBundle(String, Locale, String, ClassLoader, boolean)
219.1031 + * control.newBundle} method. If the time-to-live period of the
219.1032 + * resource bundle found in the cache has expired, the factory method
219.1033 + * calls the {@link ResourceBundle.Control#needsReload(String, Locale,
219.1034 + * String, ClassLoader, ResourceBundle, long) control.needsReload}
219.1035 + * method to determine whether the resource bundle needs to be reloaded.
219.1036 + * If reloading is required, the factory method calls
219.1037 + * <code>control.newBundle</code> to reload the resource bundle. If
219.1038 + * <code>control.newBundle</code> returns <code>null</code>, the factory
219.1039 + * method puts a dummy resource bundle in the cache as a mark of
219.1040 + * nonexistent resource bundles in order to avoid lookup overhead for
219.1041 + * subsequent requests. Such dummy resource bundles are under the same
219.1042 + * expiration control as specified by <code>control</code>.
219.1043 + *
219.1044 + * <p>All resource bundles loaded are cached by default. Refer to
219.1045 + * {@link Control#getTimeToLive(String,Locale)
219.1046 + * control.getTimeToLive} for details.
219.1047 + *
219.1048 + * <p>The following is an example of the bundle loading process with the
219.1049 + * default <code>ResourceBundle.Control</code> implementation.
219.1050 + *
219.1051 + * <p>Conditions:
219.1052 + * <ul>
219.1053 + * <li>Base bundle name: <code>foo.bar.Messages</code>
219.1054 + * <li>Requested <code>Locale</code>: {@link Locale#ITALY}</li>
219.1055 + * <li>Default <code>Locale</code>: {@link Locale#FRENCH}</li>
219.1056 + * <li>Available resource bundles:
219.1057 + * <code>foo/bar/Messages_fr.properties</code> and
219.1058 + * <code>foo/bar/Messages.properties</code></li>
219.1059 + * </ul>
219.1060 + *
219.1061 + * <p>First, <code>getBundle</code> tries loading a resource bundle in
219.1062 + * the following sequence.
219.1063 + *
219.1064 + * <ul>
219.1065 + * <li>class <code>foo.bar.Messages_it_IT</code>
219.1066 + * <li>file <code>foo/bar/Messages_it_IT.properties</code>
219.1067 + * <li>class <code>foo.bar.Messages_it</code></li>
219.1068 + * <li>file <code>foo/bar/Messages_it.properties</code></li>
219.1069 + * <li>class <code>foo.bar.Messages</code></li>
219.1070 + * <li>file <code>foo/bar/Messages.properties</code></li>
219.1071 + * </ul>
219.1072 + *
219.1073 + * <p>At this point, <code>getBundle</code> finds
219.1074 + * <code>foo/bar/Messages.properties</code>, which is put on hold
219.1075 + * because it's the base bundle. <code>getBundle</code> calls {@link
219.1076 + * Control#getFallbackLocale(String, Locale)
219.1077 + * control.getFallbackLocale("foo.bar.Messages", Locale.ITALY)} which
219.1078 + * returns <code>Locale.FRENCH</code>. Next, <code>getBundle</code>
219.1079 + * tries loading a bundle in the following sequence.
219.1080 + *
219.1081 + * <ul>
219.1082 + * <li>class <code>foo.bar.Messages_fr</code></li>
219.1083 + * <li>file <code>foo/bar/Messages_fr.properties</code></li>
219.1084 + * <li>class <code>foo.bar.Messages</code></li>
219.1085 + * <li>file <code>foo/bar/Messages.properties</code></li>
219.1086 + * </ul>
219.1087 + *
219.1088 + * <p><code>getBundle</code> finds
219.1089 + * <code>foo/bar/Messages_fr.properties</code> and creates a
219.1090 + * <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
219.1091 + * sets up its parent chain from the list of the candiate locales. Only
219.1092 + * <code>foo/bar/Messages.properties</code> is found in the list and
219.1093 + * <code>getBundle</code> creates a <code>ResourceBundle</code> instance
219.1094 + * that becomes the parent of the instance for
219.1095 + * <code>foo/bar/Messages_fr.properties</code>.
219.1096 + *
219.1097 + * @param baseName
219.1098 + * the base name of the resource bundle, a fully qualified
219.1099 + * class name
219.1100 + * @param targetLocale
219.1101 + * the locale for which a resource bundle is desired
219.1102 + * @param loader
219.1103 + * the class loader from which to load the resource bundle
219.1104 + * @param control
219.1105 + * the control which gives information for the resource
219.1106 + * bundle loading process
219.1107 + * @return a resource bundle for the given base name and locale
219.1108 + * @exception NullPointerException
219.1109 + * if <code>baseName</code>, <code>targetLocale</code>,
219.1110 + * <code>loader</code>, or <code>control</code> is
219.1111 + * <code>null</code>
219.1112 + * @exception MissingResourceException
219.1113 + * if no resource bundle for the specified base name can be found
219.1114 + * @exception IllegalArgumentException
219.1115 + * if the given <code>control</code> doesn't perform properly
219.1116 + * (e.g., <code>control.getCandidateLocales</code> returns null.)
219.1117 + * Note that validation of <code>control</code> is performed as
219.1118 + * needed.
219.1119 + * @since 1.6
219.1120 + */
219.1121 + public static ResourceBundle getBundle(String baseName, Locale targetLocale,
219.1122 + ClassLoader loader, Control control) {
219.1123 + if (loader == null || control == null) {
219.1124 + throw new NullPointerException();
219.1125 + }
219.1126 + return getBundleImpl(baseName, targetLocale, control);
219.1127 + }
219.1128 +
219.1129 + private static ResourceBundle getBundleImpl(String baseName, Locale locale,
219.1130 + Control control) {
219.1131 + if (locale == null || control == null) {
219.1132 + throw new NullPointerException();
219.1133 + }
219.1134 +
219.1135 + // We create a CacheKey here for use by this call. The base
219.1136 + // name and loader will never change during the bundle loading
219.1137 + // process. We have to make sure that the locale is set before
219.1138 + // using it as a cache key.
219.1139 + CacheKey cacheKey = new CacheKey(baseName, locale);
219.1140 + ResourceBundle bundle = null;
219.1141 +
219.1142 + // Quick lookup of the cache.
219.1143 + BundleReference bundleRef = cacheList.get(cacheKey);
219.1144 + if (bundleRef != null) {
219.1145 + bundle = bundleRef.get();
219.1146 + bundleRef = null;
219.1147 + }
219.1148 +
219.1149 + // If this bundle and all of its parents are valid (not expired),
219.1150 + // then return this bundle. If any of the bundles is expired, we
219.1151 + // don't call control.needsReload here but instead drop into the
219.1152 + // complete loading process below.
219.1153 + if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
219.1154 + return bundle;
219.1155 + }
219.1156 +
219.1157 + // No valid bundle was found in the cache, so we need to load the
219.1158 + // resource bundle and its parents.
219.1159 +
219.1160 + boolean isKnownControl = (control == Control.INSTANCE) ||
219.1161 + (control instanceof SingleFormatControl);
219.1162 + List<String> formats = control.getFormats(baseName);
219.1163 + if (!isKnownControl && !checkList(formats)) {
219.1164 + throw new IllegalArgumentException("Invalid Control: getFormats");
219.1165 + }
219.1166 +
219.1167 + ResourceBundle baseBundle = null;
219.1168 + for (Locale targetLocale = locale;
219.1169 + targetLocale != null;
219.1170 + targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
219.1171 + List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
219.1172 + if (!isKnownControl && !checkList(candidateLocales)) {
219.1173 + throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
219.1174 + }
219.1175 +
219.1176 + bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
219.1177 +
219.1178 + // If the loaded bundle is the base bundle and exactly for the
219.1179 + // requested locale or the only candidate locale, then take the
219.1180 + // bundle as the resulting one. If the loaded bundle is the base
219.1181 + // bundle, it's put on hold until we finish processing all
219.1182 + // fallback locales.
219.1183 + if (isValidBundle(bundle)) {
219.1184 + boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
219.1185 + if (!isBaseBundle || bundle.locale.equals(locale)
219.1186 + || (candidateLocales.size() == 1
219.1187 + && bundle.locale.equals(candidateLocales.get(0)))) {
219.1188 + break;
219.1189 + }
219.1190 +
219.1191 + // If the base bundle has been loaded, keep the reference in
219.1192 + // baseBundle so that we can avoid any redundant loading in case
219.1193 + // the control specify not to cache bundles.
219.1194 + if (isBaseBundle && baseBundle == null) {
219.1195 + baseBundle = bundle;
219.1196 + }
219.1197 + }
219.1198 + }
219.1199 +
219.1200 + if (bundle == null) {
219.1201 + if (baseBundle == null) {
219.1202 + throwMissingResourceException(baseName, locale, cacheKey.getCause());
219.1203 + }
219.1204 + bundle = baseBundle;
219.1205 + }
219.1206 +
219.1207 + return bundle;
219.1208 + }
219.1209 +
219.1210 + /**
219.1211 + * Checks if the given <code>List</code> is not null, not empty,
219.1212 + * not having null in its elements.
219.1213 + */
219.1214 + private static final boolean checkList(List a) {
219.1215 + boolean valid = (a != null && a.size() != 0);
219.1216 + if (valid) {
219.1217 + int size = a.size();
219.1218 + for (int i = 0; valid && i < size; i++) {
219.1219 + valid = (a.get(i) != null);
219.1220 + }
219.1221 + }
219.1222 + return valid;
219.1223 + }
219.1224 +
219.1225 + private static final ResourceBundle findBundle(CacheKey cacheKey,
219.1226 + List<Locale> candidateLocales,
219.1227 + List<String> formats,
219.1228 + int index,
219.1229 + Control control,
219.1230 + ResourceBundle baseBundle) {
219.1231 + Locale targetLocale = candidateLocales.get(index);
219.1232 + ResourceBundle parent = null;
219.1233 + if (index != candidateLocales.size() - 1) {
219.1234 + parent = findBundle(cacheKey, candidateLocales, formats, index + 1,
219.1235 + control, baseBundle);
219.1236 + } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
219.1237 + return baseBundle;
219.1238 + }
219.1239 +
219.1240 + // Before we do the real loading work, see whether we need to
219.1241 + // do some housekeeping: If references to class loaders or
219.1242 + // resource bundles have been nulled out, remove all related
219.1243 + // information from the cache.
219.1244 + Object ref;
219.1245 + while ((ref = referenceQueue.poll()) != null) {
219.1246 + cacheList.remove(((CacheKeyReference)ref).getCacheKey());
219.1247 + }
219.1248 +
219.1249 + // flag indicating the resource bundle has expired in the cache
219.1250 + boolean expiredBundle = false;
219.1251 +
219.1252 + // First, look up the cache to see if it's in the cache, without
219.1253 + // attempting to load bundle.
219.1254 + cacheKey.setLocale(targetLocale);
219.1255 + ResourceBundle bundle = findBundleInCache(cacheKey, control);
219.1256 + if (isValidBundle(bundle)) {
219.1257 + expiredBundle = bundle.expired;
219.1258 + if (!expiredBundle) {
219.1259 + // If its parent is the one asked for by the candidate
219.1260 + // locales (the runtime lookup path), we can take the cached
219.1261 + // one. (If it's not identical, then we'd have to check the
219.1262 + // parent's parents to be consistent with what's been
219.1263 + // requested.)
219.1264 + if (bundle.parent == parent) {
219.1265 + return bundle;
219.1266 + }
219.1267 + // Otherwise, remove the cached one since we can't keep
219.1268 + // the same bundles having different parents.
219.1269 + BundleReference bundleRef = cacheList.get(cacheKey);
219.1270 + if (bundleRef != null && bundleRef.get() == bundle) {
219.1271 + cacheList.remove(cacheKey);
219.1272 + }
219.1273 + }
219.1274 + }
219.1275 +
219.1276 + if (bundle != NONEXISTENT_BUNDLE) {
219.1277 + CacheKey constKey = (CacheKey) cacheKey.clone();
219.1278 +
219.1279 + try {
219.1280 + bundle = loadBundle(cacheKey, formats, control, expiredBundle);
219.1281 + if (bundle != null) {
219.1282 + if (bundle.parent == null) {
219.1283 + bundle.setParent(parent);
219.1284 + }
219.1285 + bundle.locale = targetLocale;
219.1286 + bundle = putBundleInCache(cacheKey, bundle, control);
219.1287 + return bundle;
219.1288 + }
219.1289 +
219.1290 + // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
219.1291 + // instance for the locale.
219.1292 + putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
219.1293 + } finally {
219.1294 + if (constKey.getCause() instanceof InterruptedException) {
219.1295 + Thread.currentThread().interrupt();
219.1296 + }
219.1297 + }
219.1298 + }
219.1299 + return parent;
219.1300 + }
219.1301 +
219.1302 + private static final ResourceBundle loadBundle(CacheKey cacheKey,
219.1303 + List<String> formats,
219.1304 + Control control,
219.1305 + boolean reload) {
219.1306 +
219.1307 + // Here we actually load the bundle in the order of formats
219.1308 + // specified by the getFormats() value.
219.1309 + Locale targetLocale = cacheKey.getLocale();
219.1310 +
219.1311 + ResourceBundle bundle = null;
219.1312 + int size = formats.size();
219.1313 + for (int i = 0; i < size; i++) {
219.1314 + String format = formats.get(i);
219.1315 + try {
219.1316 + bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
219.1317 + null, reload);
219.1318 + } catch (LinkageError error) {
219.1319 + // We need to handle the LinkageError case due to
219.1320 + // inconsistent case-sensitivity in ClassLoader.
219.1321 + // See 6572242 for details.
219.1322 + cacheKey.setCause(error);
219.1323 + } catch (Exception cause) {
219.1324 + cacheKey.setCause(cause);
219.1325 + }
219.1326 + if (bundle != null) {
219.1327 + // Set the format in the cache key so that it can be
219.1328 + // used when calling needsReload later.
219.1329 + cacheKey.setFormat(format);
219.1330 + bundle.name = cacheKey.getName();
219.1331 + bundle.locale = targetLocale;
219.1332 + // Bundle provider might reuse instances. So we should make
219.1333 + // sure to clear the expired flag here.
219.1334 + bundle.expired = false;
219.1335 + break;
219.1336 + }
219.1337 + }
219.1338 +
219.1339 + return bundle;
219.1340 + }
219.1341 +
219.1342 + private static final boolean isValidBundle(ResourceBundle bundle) {
219.1343 + return bundle != null && bundle != NONEXISTENT_BUNDLE;
219.1344 + }
219.1345 +
219.1346 + /**
219.1347 + * Determines whether any of resource bundles in the parent chain,
219.1348 + * including the leaf, have expired.
219.1349 + */
219.1350 + private static final boolean hasValidParentChain(ResourceBundle bundle) {
219.1351 + long now = System.currentTimeMillis();
219.1352 + while (bundle != null) {
219.1353 + if (bundle.expired) {
219.1354 + return false;
219.1355 + }
219.1356 + CacheKey key = bundle.cacheKey;
219.1357 + if (key != null) {
219.1358 + long expirationTime = key.expirationTime;
219.1359 + if (expirationTime >= 0 && expirationTime <= now) {
219.1360 + return false;
219.1361 + }
219.1362 + }
219.1363 + bundle = bundle.parent;
219.1364 + }
219.1365 + return true;
219.1366 + }
219.1367 +
219.1368 + /**
219.1369 + * Throw a MissingResourceException with proper message
219.1370 + */
219.1371 + private static final void throwMissingResourceException(String baseName,
219.1372 + Locale locale,
219.1373 + Throwable cause) {
219.1374 + // If the cause is a MissingResourceException, avoid creating
219.1375 + // a long chain. (6355009)
219.1376 + if (cause instanceof MissingResourceException) {
219.1377 + cause = null;
219.1378 + }
219.1379 + throw new MissingResourceException("Can't find bundle for base name "
219.1380 + + baseName + ", locale " + locale,
219.1381 + baseName + "_" + locale, // className
219.1382 + "", // key
219.1383 + cause);
219.1384 + }
219.1385 +
219.1386 + /**
219.1387 + * Finds a bundle in the cache. Any expired bundles are marked as
219.1388 + * `expired' and removed from the cache upon return.
219.1389 + *
219.1390 + * @param cacheKey the key to look up the cache
219.1391 + * @param control the Control to be used for the expiration control
219.1392 + * @return the cached bundle, or null if the bundle is not found in the
219.1393 + * cache or its parent has expired. <code>bundle.expire</code> is true
219.1394 + * upon return if the bundle in the cache has expired.
219.1395 + */
219.1396 + private static final ResourceBundle findBundleInCache(CacheKey cacheKey,
219.1397 + Control control) {
219.1398 + BundleReference bundleRef = cacheList.get(cacheKey);
219.1399 + if (bundleRef == null) {
219.1400 + return null;
219.1401 + }
219.1402 + ResourceBundle bundle = bundleRef.get();
219.1403 + if (bundle == null) {
219.1404 + return null;
219.1405 + }
219.1406 + ResourceBundle p = bundle.parent;
219.1407 + assert p != NONEXISTENT_BUNDLE;
219.1408 + // If the parent has expired, then this one must also expire. We
219.1409 + // check only the immediate parent because the actual loading is
219.1410 + // done from the root (base) to leaf (child) and the purpose of
219.1411 + // checking is to propagate expiration towards the leaf. For
219.1412 + // example, if the requested locale is ja_JP_JP and there are
219.1413 + // bundles for all of the candidates in the cache, we have a list,
219.1414 + //
219.1415 + // base <- ja <- ja_JP <- ja_JP_JP
219.1416 + //
219.1417 + // If ja has expired, then it will reload ja and the list becomes a
219.1418 + // tree.
219.1419 + //
219.1420 + // base <- ja (new)
219.1421 + // " <- ja (expired) <- ja_JP <- ja_JP_JP
219.1422 + //
219.1423 + // When looking up ja_JP in the cache, it finds ja_JP in the cache
219.1424 + // which references to the expired ja. Then, ja_JP is marked as
219.1425 + // expired and removed from the cache. This will be propagated to
219.1426 + // ja_JP_JP.
219.1427 + //
219.1428 + // Now, it's possible, for example, that while loading new ja_JP,
219.1429 + // someone else has started loading the same bundle and finds the
219.1430 + // base bundle has expired. Then, what we get from the first
219.1431 + // getBundle call includes the expired base bundle. However, if
219.1432 + // someone else didn't start its loading, we wouldn't know if the
219.1433 + // base bundle has expired at the end of the loading process. The
219.1434 + // expiration control doesn't guarantee that the returned bundle and
219.1435 + // its parents haven't expired.
219.1436 + //
219.1437 + // We could check the entire parent chain to see if there's any in
219.1438 + // the chain that has expired. But this process may never end. An
219.1439 + // extreme case would be that getTimeToLive returns 0 and
219.1440 + // needsReload always returns true.
219.1441 + if (p != null && p.expired) {
219.1442 + assert bundle != NONEXISTENT_BUNDLE;
219.1443 + bundle.expired = true;
219.1444 + bundle.cacheKey = null;
219.1445 + cacheList.remove(cacheKey);
219.1446 + bundle = null;
219.1447 + } else {
219.1448 + CacheKey key = bundleRef.getCacheKey();
219.1449 + long expirationTime = key.expirationTime;
219.1450 + if (!bundle.expired && expirationTime >= 0 &&
219.1451 + expirationTime <= System.currentTimeMillis()) {
219.1452 + // its TTL period has expired.
219.1453 + if (bundle != NONEXISTENT_BUNDLE) {
219.1454 + // Synchronize here to call needsReload to avoid
219.1455 + // redundant concurrent calls for the same bundle.
219.1456 + synchronized (bundle) {
219.1457 + expirationTime = key.expirationTime;
219.1458 + if (!bundle.expired && expirationTime >= 0 &&
219.1459 + expirationTime <= System.currentTimeMillis()) {
219.1460 + try {
219.1461 + bundle.expired = control.needsReload(key.getName(),
219.1462 + key.getLocale(),
219.1463 + key.getFormat(),
219.1464 + null,
219.1465 + bundle,
219.1466 + key.loadTime);
219.1467 + } catch (Exception e) {
219.1468 + cacheKey.setCause(e);
219.1469 + }
219.1470 + if (bundle.expired) {
219.1471 + // If the bundle needs to be reloaded, then
219.1472 + // remove the bundle from the cache, but
219.1473 + // return the bundle with the expired flag
219.1474 + // on.
219.1475 + bundle.cacheKey = null;
219.1476 + cacheList.remove(cacheKey);
219.1477 + } else {
219.1478 + // Update the expiration control info. and reuse
219.1479 + // the same bundle instance
219.1480 + setExpirationTime(key, control);
219.1481 + }
219.1482 + }
219.1483 + }
219.1484 + } else {
219.1485 + // We just remove NONEXISTENT_BUNDLE from the cache.
219.1486 + cacheList.remove(cacheKey);
219.1487 + bundle = null;
219.1488 + }
219.1489 + }
219.1490 + }
219.1491 + return bundle;
219.1492 + }
219.1493 +
219.1494 + /**
219.1495 + * Put a new bundle in the cache.
219.1496 + *
219.1497 + * @param cacheKey the key for the resource bundle
219.1498 + * @param bundle the resource bundle to be put in the cache
219.1499 + * @return the ResourceBundle for the cacheKey; if someone has put
219.1500 + * the bundle before this call, the one found in the cache is
219.1501 + * returned.
219.1502 + */
219.1503 + private static final ResourceBundle putBundleInCache(CacheKey cacheKey,
219.1504 + ResourceBundle bundle,
219.1505 + Control control) {
219.1506 + setExpirationTime(cacheKey, control);
219.1507 + if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
219.1508 + CacheKey key = (CacheKey) cacheKey.clone();
219.1509 + BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
219.1510 + bundle.cacheKey = key;
219.1511 +
219.1512 + // Put the bundle in the cache if it's not been in the cache.
219.1513 + BundleReference result = cacheList.put(key, bundleRef);
219.1514 +
219.1515 + // If someone else has put the same bundle in the cache before
219.1516 + // us and it has not expired, we should use the one in the cache.
219.1517 + if (result != null) {
219.1518 + ResourceBundle rb = result.get();
219.1519 + if (rb != null && !rb.expired) {
219.1520 + // Clear the back link to the cache key
219.1521 + bundle.cacheKey = null;
219.1522 + bundle = rb;
219.1523 + // Clear the reference in the BundleReference so that
219.1524 + // it won't be enqueued.
219.1525 + bundleRef.clear();
219.1526 + } else {
219.1527 + // Replace the invalid (garbage collected or expired)
219.1528 + // instance with the valid one.
219.1529 + cacheList.put(key, bundleRef);
219.1530 + }
219.1531 + }
219.1532 + }
219.1533 + return bundle;
219.1534 + }
219.1535 +
219.1536 + private static final void setExpirationTime(CacheKey cacheKey, Control control) {
219.1537 + long ttl = control.getTimeToLive(cacheKey.getName(),
219.1538 + cacheKey.getLocale());
219.1539 + if (ttl >= 0) {
219.1540 + // If any expiration time is specified, set the time to be
219.1541 + // expired in the cache.
219.1542 + long now = System.currentTimeMillis();
219.1543 + cacheKey.loadTime = now;
219.1544 + cacheKey.expirationTime = now + ttl;
219.1545 + } else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) {
219.1546 + cacheKey.expirationTime = ttl;
219.1547 + } else {
219.1548 + throw new IllegalArgumentException("Invalid Control: TTL=" + ttl);
219.1549 + }
219.1550 + }
219.1551 +
219.1552 + /**
219.1553 + * Removes all resource bundles from the cache that have been loaded
219.1554 + * using the caller's class loader.
219.1555 + *
219.1556 + * @since 1.6
219.1557 + * @see ResourceBundle.Control#getTimeToLive(String,Locale)
219.1558 + */
219.1559 + public static final void clearCache() {
219.1560 + clearCache(null);
219.1561 + }
219.1562 +
219.1563 + /**
219.1564 + * Removes all resource bundles from the cache that have been loaded
219.1565 + * using the given class loader.
219.1566 + *
219.1567 + * @param loader the class loader
219.1568 + * @exception NullPointerException if <code>loader</code> is null
219.1569 + * @since 1.6
219.1570 + * @see ResourceBundle.Control#getTimeToLive(String,Locale)
219.1571 + */
219.1572 + public static final void clearCache(ClassLoader loader) {
219.1573 + if (loader == null) {
219.1574 + throw new NullPointerException();
219.1575 + }
219.1576 + Set<CacheKey> set = cacheList.keySet();
219.1577 + for (CacheKey key : set) {
219.1578 + set.remove(key);
219.1579 + }
219.1580 + }
219.1581 +
219.1582 + /**
219.1583 + * Gets an object for the given key from this resource bundle.
219.1584 + * Returns null if this resource bundle does not contain an
219.1585 + * object for the given key.
219.1586 + *
219.1587 + * @param key the key for the desired object
219.1588 + * @exception NullPointerException if <code>key</code> is <code>null</code>
219.1589 + * @return the object for the given key, or null
219.1590 + */
219.1591 + protected abstract Object handleGetObject(String key);
219.1592 +
219.1593 + /**
219.1594 + * Returns an enumeration of the keys.
219.1595 + *
219.1596 + * @return an <code>Enumeration</code> of the keys contained in
219.1597 + * this <code>ResourceBundle</code> and its parent bundles.
219.1598 + */
219.1599 + public abstract Enumeration<String> getKeys();
219.1600 +
219.1601 + /**
219.1602 + * Determines whether the given <code>key</code> is contained in
219.1603 + * this <code>ResourceBundle</code> or its parent bundles.
219.1604 + *
219.1605 + * @param key
219.1606 + * the resource <code>key</code>
219.1607 + * @return <code>true</code> if the given <code>key</code> is
219.1608 + * contained in this <code>ResourceBundle</code> or its
219.1609 + * parent bundles; <code>false</code> otherwise.
219.1610 + * @exception NullPointerException
219.1611 + * if <code>key</code> is <code>null</code>
219.1612 + * @since 1.6
219.1613 + */
219.1614 + public boolean containsKey(String key) {
219.1615 + if (key == null) {
219.1616 + throw new NullPointerException();
219.1617 + }
219.1618 + for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
219.1619 + if (rb.handleKeySet().contains(key)) {
219.1620 + return true;
219.1621 + }
219.1622 + }
219.1623 + return false;
219.1624 + }
219.1625 +
219.1626 + /**
219.1627 + * Returns a <code>Set</code> of all keys contained in this
219.1628 + * <code>ResourceBundle</code> and its parent bundles.
219.1629 + *
219.1630 + * @return a <code>Set</code> of all keys contained in this
219.1631 + * <code>ResourceBundle</code> and its parent bundles.
219.1632 + * @since 1.6
219.1633 + */
219.1634 + public Set<String> keySet() {
219.1635 + Set<String> keys = new HashSet<>();
219.1636 + for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
219.1637 + keys.addAll(rb.handleKeySet());
219.1638 + }
219.1639 + return keys;
219.1640 + }
219.1641 +
219.1642 + /**
219.1643 + * Returns a <code>Set</code> of the keys contained <em>only</em>
219.1644 + * in this <code>ResourceBundle</code>.
219.1645 + *
219.1646 + * <p>The default implementation returns a <code>Set</code> of the
219.1647 + * keys returned by the {@link #getKeys() getKeys} method except
219.1648 + * for the ones for which the {@link #handleGetObject(String)
219.1649 + * handleGetObject} method returns <code>null</code>. Once the
219.1650 + * <code>Set</code> has been created, the value is kept in this
219.1651 + * <code>ResourceBundle</code> in order to avoid producing the
219.1652 + * same <code>Set</code> in subsequent calls. Subclasses can
219.1653 + * override this method for faster handling.
219.1654 + *
219.1655 + * @return a <code>Set</code> of the keys contained only in this
219.1656 + * <code>ResourceBundle</code>
219.1657 + * @since 1.6
219.1658 + */
219.1659 + protected Set<String> handleKeySet() {
219.1660 + if (keySet == null) {
219.1661 + synchronized (this) {
219.1662 + if (keySet == null) {
219.1663 + Set<String> keys = new HashSet<>();
219.1664 + Enumeration<String> enumKeys = getKeys();
219.1665 + while (enumKeys.hasMoreElements()) {
219.1666 + String key = enumKeys.nextElement();
219.1667 + if (handleGetObject(key) != null) {
219.1668 + keys.add(key);
219.1669 + }
219.1670 + }
219.1671 + keySet = keys;
219.1672 + }
219.1673 + }
219.1674 + }
219.1675 + return keySet;
219.1676 + }
219.1677 +
219.1678 +
219.1679 +
219.1680 + /**
219.1681 + * <code>ResourceBundle.Control</code> defines a set of callback methods
219.1682 + * that are invoked by the {@link ResourceBundle#getBundle(String,
219.1683 + * Locale, ClassLoader, Control) ResourceBundle.getBundle} factory
219.1684 + * methods during the bundle loading process. In other words, a
219.1685 + * <code>ResourceBundle.Control</code> collaborates with the factory
219.1686 + * methods for loading resource bundles. The default implementation of
219.1687 + * the callback methods provides the information necessary for the
219.1688 + * factory methods to perform the <a
219.1689 + * href="./ResourceBundle.html#default_behavior">default behavior</a>.
219.1690 + *
219.1691 + * <p>In addition to the callback methods, the {@link
219.1692 + * #toBundleName(String, Locale) toBundleName} and {@link
219.1693 + * #toResourceName(String, String) toResourceName} methods are defined
219.1694 + * primarily for convenience in implementing the callback
219.1695 + * methods. However, the <code>toBundleName</code> method could be
219.1696 + * overridden to provide different conventions in the organization and
219.1697 + * packaging of localized resources. The <code>toResourceName</code>
219.1698 + * method is <code>final</code> to avoid use of wrong resource and class
219.1699 + * name separators.
219.1700 + *
219.1701 + * <p>Two factory methods, {@link #getControl(List)} and {@link
219.1702 + * #getNoFallbackControl(List)}, provide
219.1703 + * <code>ResourceBundle.Control</code> instances that implement common
219.1704 + * variations of the default bundle loading process.
219.1705 + *
219.1706 + * <p>The formats returned by the {@link Control#getFormats(String)
219.1707 + * getFormats} method and candidate locales returned by the {@link
219.1708 + * ResourceBundle.Control#getCandidateLocales(String, Locale)
219.1709 + * getCandidateLocales} method must be consistent in all
219.1710 + * <code>ResourceBundle.getBundle</code> invocations for the same base
219.1711 + * bundle. Otherwise, the <code>ResourceBundle.getBundle</code> methods
219.1712 + * may return unintended bundles. For example, if only
219.1713 + * <code>"java.class"</code> is returned by the <code>getFormats</code>
219.1714 + * method for the first call to <code>ResourceBundle.getBundle</code>
219.1715 + * and only <code>"java.properties"</code> for the second call, then the
219.1716 + * second call will return the class-based one that has been cached
219.1717 + * during the first call.
219.1718 + *
219.1719 + * <p>A <code>ResourceBundle.Control</code> instance must be thread-safe
219.1720 + * if it's simultaneously used by multiple threads.
219.1721 + * <code>ResourceBundle.getBundle</code> does not synchronize to call
219.1722 + * the <code>ResourceBundle.Control</code> methods. The default
219.1723 + * implementations of the methods are thread-safe.
219.1724 + *
219.1725 + * <p>Applications can specify <code>ResourceBundle.Control</code>
219.1726 + * instances returned by the <code>getControl</code> factory methods or
219.1727 + * created from a subclass of <code>ResourceBundle.Control</code> to
219.1728 + * customize the bundle loading process. The following are examples of
219.1729 + * changing the default bundle loading process.
219.1730 + *
219.1731 + * <p><b>Example 1</b>
219.1732 + *
219.1733 + * <p>The following code lets <code>ResourceBundle.getBundle</code> look
219.1734 + * up only properties-based resources.
219.1735 + *
219.1736 + * <pre>
219.1737 + * import java.util.*;
219.1738 + * import static java.util.ResourceBundle.Control.*;
219.1739 + * ...
219.1740 + * ResourceBundle bundle =
219.1741 + * ResourceBundle.getBundle("MyResources", new Locale("fr", "CH"),
219.1742 + * ResourceBundle.Control.getControl(FORMAT_PROPERTIES));
219.1743 + * </pre>
219.1744 + *
219.1745 + * Given the resource bundles in the <a
219.1746 + * href="./ResourceBundle.html#default_behavior_example">example</a> in
219.1747 + * the <code>ResourceBundle.getBundle</code> description, this
219.1748 + * <code>ResourceBundle.getBundle</code> call loads
219.1749 + * <code>MyResources_fr_CH.properties</code> whose parent is
219.1750 + * <code>MyResources_fr.properties</code> whose parent is
219.1751 + * <code>MyResources.properties</code>. (<code>MyResources_fr_CH.properties</code>
219.1752 + * is not hidden, but <code>MyResources_fr_CH.class</code> is.)
219.1753 + *
219.1754 + * <p><b>Example 2</b>
219.1755 + *
219.1756 + * <p>The following is an example of loading XML-based bundles
219.1757 + * using {@link Properties#loadFromXML(java.io.InputStream)
219.1758 + * Properties.loadFromXML}.
219.1759 + *
219.1760 + * <pre>
219.1761 + * ResourceBundle rb = ResourceBundle.getBundle("Messages",
219.1762 + * new ResourceBundle.Control() {
219.1763 + * public List<String> getFormats(String baseName) {
219.1764 + * if (baseName == null)
219.1765 + * throw new NullPointerException();
219.1766 + * return Arrays.asList("xml");
219.1767 + * }
219.1768 + * public ResourceBundle newBundle(String baseName,
219.1769 + * Locale locale,
219.1770 + * String format,
219.1771 + * ClassLoader loader,
219.1772 + * boolean reload)
219.1773 + * throws IllegalAccessException,
219.1774 + * InstantiationException,
219.1775 + * IOException {
219.1776 + * if (baseName == null || locale == null
219.1777 + * || format == null || loader == null)
219.1778 + * throw new NullPointerException();
219.1779 + * ResourceBundle bundle = null;
219.1780 + * if (format.equals("xml")) {
219.1781 + * String bundleName = toBundleName(baseName, locale);
219.1782 + * String resourceName = toResourceName(bundleName, format);
219.1783 + * InputStream stream = null;
219.1784 + * if (reload) {
219.1785 + * URL url = loader.getResource(resourceName);
219.1786 + * if (url != null) {
219.1787 + * URLConnection connection = url.openConnection();
219.1788 + * if (connection != null) {
219.1789 + * // Disable caches to get fresh data for
219.1790 + * // reloading.
219.1791 + * connection.setUseCaches(false);
219.1792 + * stream = connection.getInputStream();
219.1793 + * }
219.1794 + * }
219.1795 + * } else {
219.1796 + * stream = loader.getResourceAsStream(resourceName);
219.1797 + * }
219.1798 + * if (stream != null) {
219.1799 + * BufferedInputStream bis = new BufferedInputStream(stream);
219.1800 + * bundle = new XMLResourceBundle(bis);
219.1801 + * bis.close();
219.1802 + * }
219.1803 + * }
219.1804 + * return bundle;
219.1805 + * }
219.1806 + * });
219.1807 + *
219.1808 + * ...
219.1809 + *
219.1810 + * private static class XMLResourceBundle extends ResourceBundle {
219.1811 + * private Properties props;
219.1812 + * XMLResourceBundle(InputStream stream) throws IOException {
219.1813 + * props = new Properties();
219.1814 + * props.loadFromXML(stream);
219.1815 + * }
219.1816 + * protected Object handleGetObject(String key) {
219.1817 + * return props.getProperty(key);
219.1818 + * }
219.1819 + * public Enumeration<String> getKeys() {
219.1820 + * ...
219.1821 + * }
219.1822 + * }
219.1823 + * </pre>
219.1824 + *
219.1825 + * @since 1.6
219.1826 + */
219.1827 + public static class Control {
219.1828 + /**
219.1829 + * The default format <code>List</code>, which contains the strings
219.1830 + * <code>"java.class"</code> and <code>"java.properties"</code>, in
219.1831 + * this order. This <code>List</code> is {@linkplain
219.1832 + * Collections#unmodifiableList(List) unmodifiable}.
219.1833 + *
219.1834 + * @see #getFormats(String)
219.1835 + */
219.1836 + public static final List<String> FORMAT_DEFAULT
219.1837 + = Collections.unmodifiableList(Arrays.asList("java.class",
219.1838 + "java.properties"));
219.1839 +
219.1840 + /**
219.1841 + * The class-only format <code>List</code> containing
219.1842 + * <code>"java.class"</code>. This <code>List</code> is {@linkplain
219.1843 + * Collections#unmodifiableList(List) unmodifiable}.
219.1844 + *
219.1845 + * @see #getFormats(String)
219.1846 + */
219.1847 + public static final List<String> FORMAT_CLASS
219.1848 + = Collections.unmodifiableList(Arrays.asList("java.class"));
219.1849 +
219.1850 + /**
219.1851 + * The properties-only format <code>List</code> containing
219.1852 + * <code>"java.properties"</code>. This <code>List</code> is
219.1853 + * {@linkplain Collections#unmodifiableList(List) unmodifiable}.
219.1854 + *
219.1855 + * @see #getFormats(String)
219.1856 + */
219.1857 + public static final List<String> FORMAT_PROPERTIES
219.1858 + = Collections.unmodifiableList(Arrays.asList("java.properties"));
219.1859 +
219.1860 + /**
219.1861 + * The time-to-live constant for not caching loaded resource bundle
219.1862 + * instances.
219.1863 + *
219.1864 + * @see #getTimeToLive(String, Locale)
219.1865 + */
219.1866 + public static final long TTL_DONT_CACHE = -1;
219.1867 +
219.1868 + /**
219.1869 + * The time-to-live constant for disabling the expiration control
219.1870 + * for loaded resource bundle instances in the cache.
219.1871 + *
219.1872 + * @see #getTimeToLive(String, Locale)
219.1873 + */
219.1874 + public static final long TTL_NO_EXPIRATION_CONTROL = -2;
219.1875 +
219.1876 + private static final Control INSTANCE = new Control();
219.1877 +
219.1878 + /**
219.1879 + * Sole constructor. (For invocation by subclass constructors,
219.1880 + * typically implicit.)
219.1881 + */
219.1882 + protected Control() {
219.1883 + }
219.1884 +
219.1885 + /**
219.1886 + * Returns a <code>ResourceBundle.Control</code> in which the {@link
219.1887 + * #getFormats(String) getFormats} method returns the specified
219.1888 + * <code>formats</code>. The <code>formats</code> must be equal to
219.1889 + * one of {@link Control#FORMAT_PROPERTIES}, {@link
219.1890 + * Control#FORMAT_CLASS} or {@link
219.1891 + * Control#FORMAT_DEFAULT}. <code>ResourceBundle.Control</code>
219.1892 + * instances returned by this method are singletons and thread-safe.
219.1893 + *
219.1894 + * <p>Specifying {@link Control#FORMAT_DEFAULT} is equivalent to
219.1895 + * instantiating the <code>ResourceBundle.Control</code> class,
219.1896 + * except that this method returns a singleton.
219.1897 + *
219.1898 + * @param formats
219.1899 + * the formats to be returned by the
219.1900 + * <code>ResourceBundle.Control.getFormats</code> method
219.1901 + * @return a <code>ResourceBundle.Control</code> supporting the
219.1902 + * specified <code>formats</code>
219.1903 + * @exception NullPointerException
219.1904 + * if <code>formats</code> is <code>null</code>
219.1905 + * @exception IllegalArgumentException
219.1906 + * if <code>formats</code> is unknown
219.1907 + */
219.1908 + public static final Control getControl(List<String> formats) {
219.1909 + if (formats.equals(Control.FORMAT_PROPERTIES)) {
219.1910 + return SingleFormatControl.PROPERTIES_ONLY;
219.1911 + }
219.1912 + if (formats.equals(Control.FORMAT_CLASS)) {
219.1913 + return SingleFormatControl.CLASS_ONLY;
219.1914 + }
219.1915 + if (formats.equals(Control.FORMAT_DEFAULT)) {
219.1916 + return Control.INSTANCE;
219.1917 + }
219.1918 + throw new IllegalArgumentException();
219.1919 + }
219.1920 +
219.1921 + /**
219.1922 + * Returns a <code>ResourceBundle.Control</code> in which the {@link
219.1923 + * #getFormats(String) getFormats} method returns the specified
219.1924 + * <code>formats</code> and the {@link
219.1925 + * Control#getFallbackLocale(String, Locale) getFallbackLocale}
219.1926 + * method returns <code>null</code>. The <code>formats</code> must
219.1927 + * be equal to one of {@link Control#FORMAT_PROPERTIES}, {@link
219.1928 + * Control#FORMAT_CLASS} or {@link Control#FORMAT_DEFAULT}.
219.1929 + * <code>ResourceBundle.Control</code> instances returned by this
219.1930 + * method are singletons and thread-safe.
219.1931 + *
219.1932 + * @param formats
219.1933 + * the formats to be returned by the
219.1934 + * <code>ResourceBundle.Control.getFormats</code> method
219.1935 + * @return a <code>ResourceBundle.Control</code> supporting the
219.1936 + * specified <code>formats</code> with no fallback
219.1937 + * <code>Locale</code> support
219.1938 + * @exception NullPointerException
219.1939 + * if <code>formats</code> is <code>null</code>
219.1940 + * @exception IllegalArgumentException
219.1941 + * if <code>formats</code> is unknown
219.1942 + */
219.1943 + public static final Control getNoFallbackControl(List<String> formats) {
219.1944 + if (formats.equals(Control.FORMAT_DEFAULT)) {
219.1945 + return NoFallbackControl.NO_FALLBACK;
219.1946 + }
219.1947 + if (formats.equals(Control.FORMAT_PROPERTIES)) {
219.1948 + return NoFallbackControl.PROPERTIES_ONLY_NO_FALLBACK;
219.1949 + }
219.1950 + if (formats.equals(Control.FORMAT_CLASS)) {
219.1951 + return NoFallbackControl.CLASS_ONLY_NO_FALLBACK;
219.1952 + }
219.1953 + throw new IllegalArgumentException();
219.1954 + }
219.1955 +
219.1956 + /**
219.1957 + * Returns a <code>List</code> of <code>String</code>s containing
219.1958 + * formats to be used to load resource bundles for the given
219.1959 + * <code>baseName</code>. The <code>ResourceBundle.getBundle</code>
219.1960 + * factory method tries to load resource bundles with formats in the
219.1961 + * order specified by the list. The list returned by this method
219.1962 + * must have at least one <code>String</code>. The predefined
219.1963 + * formats are <code>"java.class"</code> for class-based resource
219.1964 + * bundles and <code>"java.properties"</code> for {@linkplain
219.1965 + * PropertyResourceBundle properties-based} ones. Strings starting
219.1966 + * with <code>"java."</code> are reserved for future extensions and
219.1967 + * must not be used by application-defined formats.
219.1968 + *
219.1969 + * <p>It is not a requirement to return an immutable (unmodifiable)
219.1970 + * <code>List</code>. However, the returned <code>List</code> must
219.1971 + * not be mutated after it has been returned by
219.1972 + * <code>getFormats</code>.
219.1973 + *
219.1974 + * <p>The default implementation returns {@link #FORMAT_DEFAULT} so
219.1975 + * that the <code>ResourceBundle.getBundle</code> factory method
219.1976 + * looks up first class-based resource bundles, then
219.1977 + * properties-based ones.
219.1978 + *
219.1979 + * @param baseName
219.1980 + * the base name of the resource bundle, a fully qualified class
219.1981 + * name
219.1982 + * @return a <code>List</code> of <code>String</code>s containing
219.1983 + * formats for loading resource bundles.
219.1984 + * @exception NullPointerException
219.1985 + * if <code>baseName</code> is null
219.1986 + * @see #FORMAT_DEFAULT
219.1987 + * @see #FORMAT_CLASS
219.1988 + * @see #FORMAT_PROPERTIES
219.1989 + */
219.1990 + public List<String> getFormats(String baseName) {
219.1991 + if (baseName == null) {
219.1992 + throw new NullPointerException();
219.1993 + }
219.1994 + return FORMAT_DEFAULT;
219.1995 + }
219.1996 +
219.1997 + /**
219.1998 + * Returns a <code>List</code> of <code>Locale</code>s as candidate
219.1999 + * locales for <code>baseName</code> and <code>locale</code>. This
219.2000 + * method is called by the <code>ResourceBundle.getBundle</code>
219.2001 + * factory method each time the factory method tries finding a
219.2002 + * resource bundle for a target <code>Locale</code>.
219.2003 + *
219.2004 + * <p>The sequence of the candidate locales also corresponds to the
219.2005 + * runtime resource lookup path (also known as the <I>parent
219.2006 + * chain</I>), if the corresponding resource bundles for the
219.2007 + * candidate locales exist and their parents are not defined by
219.2008 + * loaded resource bundles themselves. The last element of the list
219.2009 + * must be a {@linkplain Locale#ROOT root locale} if it is desired to
219.2010 + * have the base bundle as the terminal of the parent chain.
219.2011 + *
219.2012 + * <p>If the given locale is equal to <code>Locale.ROOT</code> (the
219.2013 + * root locale), a <code>List</code> containing only the root
219.2014 + * <code>Locale</code> must be returned. In this case, the
219.2015 + * <code>ResourceBundle.getBundle</code> factory method loads only
219.2016 + * the base bundle as the resulting resource bundle.
219.2017 + *
219.2018 + * <p>It is not a requirement to return an immutable (unmodifiable)
219.2019 + * <code>List</code>. However, the returned <code>List</code> must not
219.2020 + * be mutated after it has been returned by
219.2021 + * <code>getCandidateLocales</code>.
219.2022 + *
219.2023 + * <p>The default implementation returns a <code>List</code> containing
219.2024 + * <code>Locale</code>s using the rules described below. In the
219.2025 + * description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em>
219.2026 + * respectively represent non-empty language, script, country, and
219.2027 + * variant. For example, [<em>L</em>, <em>C</em>] represents a
219.2028 + * <code>Locale</code> that has non-empty values only for language and
219.2029 + * country. The form <em>L</em>("xx") represents the (non-empty)
219.2030 + * language value is "xx". For all cases, <code>Locale</code>s whose
219.2031 + * final component values are empty strings are omitted.
219.2032 + *
219.2033 + * <ol><li>For an input <code>Locale</code> with an empty script value,
219.2034 + * append candidate <code>Locale</code>s by omitting the final component
219.2035 + * one by one as below:
219.2036 + *
219.2037 + * <ul>
219.2038 + * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
219.2039 + * <li> [<em>L</em>, <em>C</em>]
219.2040 + * <li> [<em>L</em>]
219.2041 + * <li> <code>Locale.ROOT</code>
219.2042 + * </ul>
219.2043 + *
219.2044 + * <li>For an input <code>Locale</code> with a non-empty script value,
219.2045 + * append candidate <code>Locale</code>s by omitting the final component
219.2046 + * up to language, then append candidates generated from the
219.2047 + * <code>Locale</code> with country and variant restored:
219.2048 + *
219.2049 + * <ul>
219.2050 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]
219.2051 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
219.2052 + * <li> [<em>L</em>, <em>S</em>]
219.2053 + * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
219.2054 + * <li> [<em>L</em>, <em>C</em>]
219.2055 + * <li> [<em>L</em>]
219.2056 + * <li> <code>Locale.ROOT</code>
219.2057 + * </ul>
219.2058 + *
219.2059 + * <li>For an input <code>Locale</code> with a variant value consisting
219.2060 + * of multiple subtags separated by underscore, generate candidate
219.2061 + * <code>Locale</code>s by omitting the variant subtags one by one, then
219.2062 + * insert them after every occurence of <code> Locale</code>s with the
219.2063 + * full variant value in the original list. For example, if the
219.2064 + * the variant consists of two subtags <em>V1</em> and <em>V2</em>:
219.2065 + *
219.2066 + * <ul>
219.2067 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
219.2068 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]
219.2069 + * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
219.2070 + * <li> [<em>L</em>, <em>S</em>]
219.2071 + * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
219.2072 + * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]
219.2073 + * <li> [<em>L</em>, <em>C</em>]
219.2074 + * <li> [<em>L</em>]
219.2075 + * <li> <code>Locale.ROOT</code>
219.2076 + * </ul>
219.2077 + *
219.2078 + * <li>Special cases for Chinese. When an input <code>Locale</code> has the
219.2079 + * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
219.2080 + * "Hant" (Traditional) might be supplied, depending on the country.
219.2081 + * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied.
219.2082 + * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China),
219.2083 + * or "TW" (Taiwan), "Hant" is supplied. For all other countries or when the country
219.2084 + * is empty, no script is supplied. For example, for <code>Locale("zh", "CN")
219.2085 + * </code>, the candidate list will be:
219.2086 + * <ul>
219.2087 + * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]
219.2088 + * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]
219.2089 + * <li> [<em>L</em>("zh"), <em>C</em>("CN")]
219.2090 + * <li> [<em>L</em>("zh")]
219.2091 + * <li> <code>Locale.ROOT</code>
219.2092 + * </ul>
219.2093 + *
219.2094 + * For <code>Locale("zh", "TW")</code>, the candidate list will be:
219.2095 + * <ul>
219.2096 + * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]
219.2097 + * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]
219.2098 + * <li> [<em>L</em>("zh"), <em>C</em>("TW")]
219.2099 + * <li> [<em>L</em>("zh")]
219.2100 + * <li> <code>Locale.ROOT</code>
219.2101 + * </ul>
219.2102 + *
219.2103 + * <li>Special cases for Norwegian. Both <code>Locale("no", "NO",
219.2104 + * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
219.2105 + * Nynorsk. When a locale's language is "nn", the standard candidate
219.2106 + * list is generated up to [<em>L</em>("nn")], and then the following
219.2107 + * candidates are added:
219.2108 + *
219.2109 + * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]
219.2110 + * <li> [<em>L</em>("no"), <em>C</em>("NO")]
219.2111 + * <li> [<em>L</em>("no")]
219.2112 + * <li> <code>Locale.ROOT</code>
219.2113 + * </ul>
219.2114 + *
219.2115 + * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
219.2116 + * converted to <code>Locale("nn", "NO")</code> and then the above procedure is
219.2117 + * followed.
219.2118 + *
219.2119 + * <p>Also, Java treats the language "no" as a synonym of Norwegian
219.2120 + * Bokmål "nb". Except for the single case <code>Locale("no",
219.2121 + * "NO", "NY")</code> (handled above), when an input <code>Locale</code>
219.2122 + * has language "no" or "nb", candidate <code>Locale</code>s with
219.2123 + * language code "no" and "nb" are interleaved, first using the
219.2124 + * requested language, then using its synonym. For example,
219.2125 + * <code>Locale("nb", "NO", "POSIX")</code> generates the following
219.2126 + * candidate list:
219.2127 + *
219.2128 + * <ul>
219.2129 + * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]
219.2130 + * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]
219.2131 + * <li> [<em>L</em>("nb"), <em>C</em>("NO")]
219.2132 + * <li> [<em>L</em>("no"), <em>C</em>("NO")]
219.2133 + * <li> [<em>L</em>("nb")]
219.2134 + * <li> [<em>L</em>("no")]
219.2135 + * <li> <code>Locale.ROOT</code>
219.2136 + * </ul>
219.2137 + *
219.2138 + * <code>Locale("no", "NO", "POSIX")</code> would generate the same list
219.2139 + * except that locales with "no" would appear before the corresponding
219.2140 + * locales with "nb".</li>
219.2141 + *
219.2142 + * </li>
219.2143 + * </ol>
219.2144 + *
219.2145 + * <p>The default implementation uses an {@link ArrayList} that
219.2146 + * overriding implementations may modify before returning it to the
219.2147 + * caller. However, a subclass must not modify it after it has
219.2148 + * been returned by <code>getCandidateLocales</code>.
219.2149 + *
219.2150 + * <p>For example, if the given <code>baseName</code> is "Messages"
219.2151 + * and the given <code>locale</code> is
219.2152 + * <code>Locale("ja", "", "XX")</code>, then a
219.2153 + * <code>List</code> of <code>Locale</code>s:
219.2154 + * <pre>
219.2155 + * Locale("ja", "", "XX")
219.2156 + * Locale("ja")
219.2157 + * Locale.ROOT
219.2158 + * </pre>
219.2159 + * is returned. And if the resource bundles for the "ja" and
219.2160 + * "" <code>Locale</code>s are found, then the runtime resource
219.2161 + * lookup path (parent chain) is:
219.2162 + * <pre>
219.2163 + * Messages_ja -> Messages
219.2164 + * </pre>
219.2165 + *
219.2166 + * @param baseName
219.2167 + * the base name of the resource bundle, a fully
219.2168 + * qualified class name
219.2169 + * @param locale
219.2170 + * the locale for which a resource bundle is desired
219.2171 + * @return a <code>List</code> of candidate
219.2172 + * <code>Locale</code>s for the given <code>locale</code>
219.2173 + * @exception NullPointerException
219.2174 + * if <code>baseName</code> or <code>locale</code> is
219.2175 + * <code>null</code>
219.2176 + */
219.2177 + public List<Locale> getCandidateLocales(String baseName, Locale locale) {
219.2178 + if (baseName == null) {
219.2179 + throw new NullPointerException();
219.2180 + }
219.2181 + return new ArrayList<>(CANDIDATES_CACHE.get(locale));
219.2182 + }
219.2183 +
219.2184 + private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
219.2185 +
219.2186 + private static class CandidateListCache {
219.2187 + private Locale prevQuery;
219.2188 + private List<Locale> prevResult;
219.2189 +
219.2190 + public List<Locale> get(Locale l) {
219.2191 + if (prevQuery == l) {
219.2192 + return prevResult;
219.2193 + }
219.2194 + prevResult = createObject(l);
219.2195 + prevQuery = l;
219.2196 + return prevResult;
219.2197 + }
219.2198 +
219.2199 + protected List<Locale> createObject(Locale base) {
219.2200 + String language = base.getLanguage();
219.2201 + String script = base.getScript();
219.2202 + String region = base.getRegion();
219.2203 + String variant = base.getVariant();
219.2204 +
219.2205 + // Special handling for Norwegian
219.2206 + boolean isNorwegianBokmal = false;
219.2207 + boolean isNorwegianNynorsk = false;
219.2208 + if (language.equals("no")) {
219.2209 + if (region.equals("NO") && variant.equals("NY")) {
219.2210 + variant = "";
219.2211 + isNorwegianNynorsk = true;
219.2212 + } else {
219.2213 + isNorwegianBokmal = true;
219.2214 + }
219.2215 + }
219.2216 + if (language.equals("nb") || isNorwegianBokmal) {
219.2217 + List<Locale> tmpList = getDefaultList("nb", script, region, variant);
219.2218 + // Insert a locale replacing "nb" with "no" for every list entry
219.2219 + List<Locale> bokmalList = new LinkedList<>();
219.2220 + for (Locale l : tmpList) {
219.2221 + bokmalList.add(l);
219.2222 + if (l.getLanguage().length() == 0) {
219.2223 + break;
219.2224 + }
219.2225 + bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
219.2226 + l.getVariant(), null));
219.2227 + }
219.2228 + return bokmalList;
219.2229 + } else if (language.equals("nn") || isNorwegianNynorsk) {
219.2230 + // Insert no_NO_NY, no_NO, no after nn
219.2231 + List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
219.2232 + int idx = nynorskList.size() - 1;
219.2233 + nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
219.2234 + nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
219.2235 + nynorskList.add(idx++, Locale.getInstance("no", "", ""));
219.2236 + return nynorskList;
219.2237 + }
219.2238 + // Special handling for Chinese
219.2239 + else if (language.equals("zh")) {
219.2240 + if (script.length() == 0 && region.length() > 0) {
219.2241 + // Supply script for users who want to use zh_Hans/zh_Hant
219.2242 + // as bundle names (recommended for Java7+)
219.2243 + if (region.equals("TW") || region.equals("HK") || region.equals("MO")) {
219.2244 + script = "Hant";
219.2245 + } else if (region.equals("CN") || region.equals("SG")) {
219.2246 + script = "Hans";
219.2247 + }
219.2248 + } else if (script.length() > 0 && region.length() == 0) {
219.2249 + // Supply region(country) for users who still package Chinese
219.2250 + // bundles using old convension.
219.2251 + if (script.equals("Hans")) {
219.2252 + region = "CN";
219.2253 + } else if (script.equals("Hant")) {
219.2254 + region = "TW";
219.2255 + }
219.2256 + }
219.2257 + }
219.2258 +
219.2259 + return getDefaultList(language, script, region, variant);
219.2260 + }
219.2261 +
219.2262 + private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
219.2263 + List<String> variants = null;
219.2264 +
219.2265 + if (variant.length() > 0) {
219.2266 + variants = new LinkedList<>();
219.2267 + int idx = variant.length();
219.2268 + while (idx != -1) {
219.2269 + variants.add(variant.substring(0, idx));
219.2270 + idx = variant.lastIndexOf('_', --idx);
219.2271 + }
219.2272 + }
219.2273 +
219.2274 + List<Locale> list = new LinkedList<>();
219.2275 +
219.2276 + if (variants != null) {
219.2277 + for (String v : variants) {
219.2278 + list.add(Locale.getInstance(language, script, region, v, null));
219.2279 + }
219.2280 + }
219.2281 + if (region.length() > 0) {
219.2282 + list.add(Locale.getInstance(language, script, region, "", null));
219.2283 + }
219.2284 + if (script.length() > 0) {
219.2285 + list.add(Locale.getInstance(language, script, "", "", null));
219.2286 +
219.2287 + // With script, after truncating variant, region and script,
219.2288 + // start over without script.
219.2289 + if (variants != null) {
219.2290 + for (String v : variants) {
219.2291 + list.add(Locale.getInstance(language, "", region, v, null));
219.2292 + }
219.2293 + }
219.2294 + if (region.length() > 0) {
219.2295 + list.add(Locale.getInstance(language, "", region, "", null));
219.2296 + }
219.2297 + }
219.2298 + if (language.length() > 0) {
219.2299 + list.add(Locale.getInstance(language, "", "", "", null));
219.2300 + }
219.2301 + // Add root locale at the end
219.2302 + list.add(Locale.ROOT);
219.2303 +
219.2304 + return list;
219.2305 + }
219.2306 + }
219.2307 +
219.2308 + /**
219.2309 + * Returns a <code>Locale</code> to be used as a fallback locale for
219.2310 + * further resource bundle searches by the
219.2311 + * <code>ResourceBundle.getBundle</code> factory method. This method
219.2312 + * is called from the factory method every time when no resulting
219.2313 + * resource bundle has been found for <code>baseName</code> and
219.2314 + * <code>locale</code>, where locale is either the parameter for
219.2315 + * <code>ResourceBundle.getBundle</code> or the previous fallback
219.2316 + * locale returned by this method.
219.2317 + *
219.2318 + * <p>The method returns <code>null</code> if no further fallback
219.2319 + * search is desired.
219.2320 + *
219.2321 + * <p>The default implementation returns the {@linkplain
219.2322 + * Locale#getDefault() default <code>Locale</code>} if the given
219.2323 + * <code>locale</code> isn't the default one. Otherwise,
219.2324 + * <code>null</code> is returned.
219.2325 + *
219.2326 + * @param baseName
219.2327 + * the base name of the resource bundle, a fully
219.2328 + * qualified class name for which
219.2329 + * <code>ResourceBundle.getBundle</code> has been
219.2330 + * unable to find any resource bundles (except for the
219.2331 + * base bundle)
219.2332 + * @param locale
219.2333 + * the <code>Locale</code> for which
219.2334 + * <code>ResourceBundle.getBundle</code> has been
219.2335 + * unable to find any resource bundles (except for the
219.2336 + * base bundle)
219.2337 + * @return a <code>Locale</code> for the fallback search,
219.2338 + * or <code>null</code> if no further fallback search
219.2339 + * is desired.
219.2340 + * @exception NullPointerException
219.2341 + * if <code>baseName</code> or <code>locale</code>
219.2342 + * is <code>null</code>
219.2343 + */
219.2344 + public Locale getFallbackLocale(String baseName, Locale locale) {
219.2345 + if (baseName == null) {
219.2346 + throw new NullPointerException();
219.2347 + }
219.2348 + Locale defaultLocale = Locale.getDefault();
219.2349 + return locale.equals(defaultLocale) ? null : defaultLocale;
219.2350 + }
219.2351 +
219.2352 + /**
219.2353 + * Instantiates a resource bundle for the given bundle name of the
219.2354 + * given format and locale, using the given class loader if
219.2355 + * necessary. This method returns <code>null</code> if there is no
219.2356 + * resource bundle available for the given parameters. If a resource
219.2357 + * bundle can't be instantiated due to an unexpected error, the
219.2358 + * error must be reported by throwing an <code>Error</code> or
219.2359 + * <code>Exception</code> rather than simply returning
219.2360 + * <code>null</code>.
219.2361 + *
219.2362 + * <p>If the <code>reload</code> flag is <code>true</code>, it
219.2363 + * indicates that this method is being called because the previously
219.2364 + * loaded resource bundle has expired.
219.2365 + *
219.2366 + * <p>The default implementation instantiates a
219.2367 + * <code>ResourceBundle</code> as follows.
219.2368 + *
219.2369 + * <ul>
219.2370 + *
219.2371 + * <li>The bundle name is obtained by calling {@link
219.2372 + * #toBundleName(String, Locale) toBundleName(baseName,
219.2373 + * locale)}.</li>
219.2374 + *
219.2375 + * <li>If <code>format</code> is <code>"java.class"</code>, the
219.2376 + * {@link Class} specified by the bundle name is loaded by calling
219.2377 + * {@link ClassLoader#loadClass(String)}. Then, a
219.2378 + * <code>ResourceBundle</code> is instantiated by calling {@link
219.2379 + * Class#newInstance()}. Note that the <code>reload</code> flag is
219.2380 + * ignored for loading class-based resource bundles in this default
219.2381 + * implementation.</li>
219.2382 + *
219.2383 + * <li>If <code>format</code> is <code>"java.properties"</code>,
219.2384 + * {@link #toResourceName(String, String) toResourceName(bundlename,
219.2385 + * "properties")} is called to get the resource name.
219.2386 + * If <code>reload</code> is <code>true</code>, {@link
219.2387 + * ClassLoader#getResource(String) load.getResource} is called
219.2388 + * to get a {@link URL} for creating a {@link
219.2389 + * URLConnection}. This <code>URLConnection</code> is used to
219.2390 + * {@linkplain URLConnection#setUseCaches(boolean) disable the
219.2391 + * caches} of the underlying resource loading layers,
219.2392 + * and to {@linkplain URLConnection#getInputStream() get an
219.2393 + * <code>InputStream</code>}.
219.2394 + * Otherwise, {@link ClassLoader#getResourceAsStream(String)
219.2395 + * loader.getResourceAsStream} is called to get an {@link
219.2396 + * InputStream}. Then, a {@link
219.2397 + * PropertyResourceBundle} is constructed with the
219.2398 + * <code>InputStream</code>.</li>
219.2399 + *
219.2400 + * <li>If <code>format</code> is neither <code>"java.class"</code>
219.2401 + * nor <code>"java.properties"</code>, an
219.2402 + * <code>IllegalArgumentException</code> is thrown.</li>
219.2403 + *
219.2404 + * </ul>
219.2405 + *
219.2406 + * @param baseName
219.2407 + * the base bundle name of the resource bundle, a fully
219.2408 + * qualified class name
219.2409 + * @param locale
219.2410 + * the locale for which the resource bundle should be
219.2411 + * instantiated
219.2412 + * @param format
219.2413 + * the resource bundle format to be loaded
219.2414 + * @param loader
219.2415 + * the <code>ClassLoader</code> to use to load the bundle
219.2416 + * @param reload
219.2417 + * the flag to indicate bundle reloading; <code>true</code>
219.2418 + * if reloading an expired resource bundle,
219.2419 + * <code>false</code> otherwise
219.2420 + * @return the resource bundle instance,
219.2421 + * or <code>null</code> if none could be found.
219.2422 + * @exception NullPointerException
219.2423 + * if <code>bundleName</code>, <code>locale</code>,
219.2424 + * <code>format</code>, or <code>loader</code> is
219.2425 + * <code>null</code>, or if <code>null</code> is returned by
219.2426 + * {@link #toBundleName(String, Locale) toBundleName}
219.2427 + * @exception IllegalArgumentException
219.2428 + * if <code>format</code> is unknown, or if the resource
219.2429 + * found for the given parameters contains malformed data.
219.2430 + * @exception ClassCastException
219.2431 + * if the loaded class cannot be cast to <code>ResourceBundle</code>
219.2432 + * @exception IllegalAccessException
219.2433 + * if the class or its nullary constructor is not
219.2434 + * accessible.
219.2435 + * @exception InstantiationException
219.2436 + * if the instantiation of a class fails for some other
219.2437 + * reason.
219.2438 + * @exception ExceptionInInitializerError
219.2439 + * if the initialization provoked by this method fails.
219.2440 + * @exception SecurityException
219.2441 + * If a security manager is present and creation of new
219.2442 + * instances is denied. See {@link Class#newInstance()}
219.2443 + * for details.
219.2444 + * @exception IOException
219.2445 + * if an error occurred when reading resources using
219.2446 + * any I/O operations
219.2447 + */
219.2448 + public ResourceBundle newBundle(String baseName, Locale locale, String format,
219.2449 + ClassLoader loader, boolean reload)
219.2450 + throws IllegalAccessException, InstantiationException, IOException {
219.2451 + String bundleName = toBundleName(baseName, locale);
219.2452 + ResourceBundle bundle = null;
219.2453 + if (format.equals("java.class")) {
219.2454 + try {
219.2455 + Class<? extends ResourceBundle> bundleClass
219.2456 + = (Class<? extends ResourceBundle>)(loader != null ?
219.2457 + loader.loadClass(bundleName) :
219.2458 + Class.forName(bundleName));
219.2459 +
219.2460 + // If the class isn't a ResourceBundle subclass, throw a
219.2461 + // ClassCastException.
219.2462 + if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
219.2463 + bundle = bundleClass.newInstance();
219.2464 + } else {
219.2465 + throw new ClassCastException(bundleClass.getName()
219.2466 + + " cannot be cast to ResourceBundle");
219.2467 + }
219.2468 + } catch (ClassNotFoundException e) {
219.2469 + }
219.2470 + } else if (format.equals("java.properties")) {
219.2471 + final String resourceName = toResourceName(bundleName, "properties");
219.2472 + final ClassLoader classLoader = loader;
219.2473 + final boolean reloadFlag = reload;
219.2474 + InputStream stream = classLoader != null ? classLoader.getResourceAsStream(resourceName) :
219.2475 + ResourceBundle.class.getResourceAsStream("/" + resourceName);
219.2476 + if (stream != null) {
219.2477 + try {
219.2478 + bundle = new PropertyResourceBundle(stream);
219.2479 + } finally {
219.2480 + stream.close();
219.2481 + }
219.2482 + }
219.2483 + } else {
219.2484 + throw new IllegalArgumentException("unknown format: " + format);
219.2485 + }
219.2486 + return bundle;
219.2487 + }
219.2488 +
219.2489 + /**
219.2490 + * Returns the time-to-live (TTL) value for resource bundles that
219.2491 + * are loaded under this
219.2492 + * <code>ResourceBundle.Control</code>. Positive time-to-live values
219.2493 + * specify the number of milliseconds a bundle can remain in the
219.2494 + * cache without being validated against the source data from which
219.2495 + * it was constructed. The value 0 indicates that a bundle must be
219.2496 + * validated each time it is retrieved from the cache. {@link
219.2497 + * #TTL_DONT_CACHE} specifies that loaded resource bundles are not
219.2498 + * put in the cache. {@link #TTL_NO_EXPIRATION_CONTROL} specifies
219.2499 + * that loaded resource bundles are put in the cache with no
219.2500 + * expiration control.
219.2501 + *
219.2502 + * <p>The expiration affects only the bundle loading process by the
219.2503 + * <code>ResourceBundle.getBundle</code> factory method. That is,
219.2504 + * if the factory method finds a resource bundle in the cache that
219.2505 + * has expired, the factory method calls the {@link
219.2506 + * #needsReload(String, Locale, String, ClassLoader, ResourceBundle,
219.2507 + * long) needsReload} method to determine whether the resource
219.2508 + * bundle needs to be reloaded. If <code>needsReload</code> returns
219.2509 + * <code>true</code>, the cached resource bundle instance is removed
219.2510 + * from the cache. Otherwise, the instance stays in the cache,
219.2511 + * updated with the new TTL value returned by this method.
219.2512 + *
219.2513 + * <p>All cached resource bundles are subject to removal from the
219.2514 + * cache due to memory constraints of the runtime environment.
219.2515 + * Returning a large positive value doesn't mean to lock loaded
219.2516 + * resource bundles in the cache.
219.2517 + *
219.2518 + * <p>The default implementation returns {@link #TTL_NO_EXPIRATION_CONTROL}.
219.2519 + *
219.2520 + * @param baseName
219.2521 + * the base name of the resource bundle for which the
219.2522 + * expiration value is specified.
219.2523 + * @param locale
219.2524 + * the locale of the resource bundle for which the
219.2525 + * expiration value is specified.
219.2526 + * @return the time (0 or a positive millisecond offset from the
219.2527 + * cached time) to get loaded bundles expired in the cache,
219.2528 + * {@link #TTL_NO_EXPIRATION_CONTROL} to disable the
219.2529 + * expiration control, or {@link #TTL_DONT_CACHE} to disable
219.2530 + * caching.
219.2531 + * @exception NullPointerException
219.2532 + * if <code>baseName</code> or <code>locale</code> is
219.2533 + * <code>null</code>
219.2534 + */
219.2535 + public long getTimeToLive(String baseName, Locale locale) {
219.2536 + if (baseName == null || locale == null) {
219.2537 + throw new NullPointerException();
219.2538 + }
219.2539 + return TTL_NO_EXPIRATION_CONTROL;
219.2540 + }
219.2541 +
219.2542 + /**
219.2543 + * Determines if the expired <code>bundle</code> in the cache needs
219.2544 + * to be reloaded based on the loading time given by
219.2545 + * <code>loadTime</code> or some other criteria. The method returns
219.2546 + * <code>true</code> if reloading is required; <code>false</code>
219.2547 + * otherwise. <code>loadTime</code> is a millisecond offset since
219.2548 + * the <a href="Calendar.html#Epoch"> <code>Calendar</code>
219.2549 + * Epoch</a>.
219.2550 + *
219.2551 + * The calling <code>ResourceBundle.getBundle</code> factory method
219.2552 + * calls this method on the <code>ResourceBundle.Control</code>
219.2553 + * instance used for its current invocation, not on the instance
219.2554 + * used in the invocation that originally loaded the resource
219.2555 + * bundle.
219.2556 + *
219.2557 + * <p>The default implementation compares <code>loadTime</code> and
219.2558 + * the last modified time of the source data of the resource
219.2559 + * bundle. If it's determined that the source data has been modified
219.2560 + * since <code>loadTime</code>, <code>true</code> is
219.2561 + * returned. Otherwise, <code>false</code> is returned. This
219.2562 + * implementation assumes that the given <code>format</code> is the
219.2563 + * same string as its file suffix if it's not one of the default
219.2564 + * formats, <code>"java.class"</code> or
219.2565 + * <code>"java.properties"</code>.
219.2566 + *
219.2567 + * @param baseName
219.2568 + * the base bundle name of the resource bundle, a
219.2569 + * fully qualified class name
219.2570 + * @param locale
219.2571 + * the locale for which the resource bundle
219.2572 + * should be instantiated
219.2573 + * @param format
219.2574 + * the resource bundle format to be loaded
219.2575 + * @param loader
219.2576 + * the <code>ClassLoader</code> to use to load the bundle
219.2577 + * @param bundle
219.2578 + * the resource bundle instance that has been expired
219.2579 + * in the cache
219.2580 + * @param loadTime
219.2581 + * the time when <code>bundle</code> was loaded and put
219.2582 + * in the cache
219.2583 + * @return <code>true</code> if the expired bundle needs to be
219.2584 + * reloaded; <code>false</code> otherwise.
219.2585 + * @exception NullPointerException
219.2586 + * if <code>baseName</code>, <code>locale</code>,
219.2587 + * <code>format</code>, <code>loader</code>, or
219.2588 + * <code>bundle</code> is <code>null</code>
219.2589 + */
219.2590 + public boolean needsReload(String baseName, Locale locale,
219.2591 + String format, ClassLoader loader,
219.2592 + ResourceBundle bundle, long loadTime) {
219.2593 + if (bundle == null) {
219.2594 + throw new NullPointerException();
219.2595 + }
219.2596 + if (format.equals("java.class") || format.equals("java.properties")) {
219.2597 + format = format.substring(5);
219.2598 + }
219.2599 + boolean result = false;
219.2600 + try {
219.2601 +/*
219.2602 + String resourceName = toResourceName(toBundleName(baseName, locale), format);
219.2603 + URL url = loader.getResource(resourceName);
219.2604 + if (url != null) {
219.2605 + long lastModified = 0;
219.2606 + URLConnection connection = url.openConnection();
219.2607 + if (connection != null) {
219.2608 + // disable caches to get the correct data
219.2609 + connection.setUseCaches(false);
219.2610 + if (connection instanceof JarURLConnection) {
219.2611 + JarEntry ent = ((JarURLConnection)connection).getJarEntry();
219.2612 + if (ent != null) {
219.2613 + lastModified = ent.getTime();
219.2614 + if (lastModified == -1) {
219.2615 + lastModified = 0;
219.2616 + }
219.2617 + }
219.2618 + } else {
219.2619 + lastModified = connection.getLastModified();
219.2620 + }
219.2621 + }
219.2622 + result = lastModified >= loadTime;
219.2623 + }
219.2624 + */
219.2625 + } catch (NullPointerException npe) {
219.2626 + throw npe;
219.2627 + } catch (Exception e) {
219.2628 + // ignore other exceptions
219.2629 + }
219.2630 + return result;
219.2631 + }
219.2632 +
219.2633 + /**
219.2634 + * Converts the given <code>baseName</code> and <code>locale</code>
219.2635 + * to the bundle name. This method is called from the default
219.2636 + * implementation of the {@link #newBundle(String, Locale, String,
219.2637 + * ClassLoader, boolean) newBundle} and {@link #needsReload(String,
219.2638 + * Locale, String, ClassLoader, ResourceBundle, long) needsReload}
219.2639 + * methods.
219.2640 + *
219.2641 + * <p>This implementation returns the following value:
219.2642 + * <pre>
219.2643 + * baseName + "_" + language + "_" + script + "_" + country + "_" + variant
219.2644 + * </pre>
219.2645 + * where <code>language</code>, <code>script</code>, <code>country</code>,
219.2646 + * and <code>variant</code> are the language, script, country, and variant
219.2647 + * values of <code>locale</code>, respectively. Final component values that
219.2648 + * are empty Strings are omitted along with the preceding '_'. When the
219.2649 + * script is empty, the script value is ommitted along with the preceding '_'.
219.2650 + * If all of the values are empty strings, then <code>baseName</code>
219.2651 + * is returned.
219.2652 + *
219.2653 + * <p>For example, if <code>baseName</code> is
219.2654 + * <code>"baseName"</code> and <code>locale</code> is
219.2655 + * <code>Locale("ja", "", "XX")</code>, then
219.2656 + * <code>"baseName_ja_ _XX"</code> is returned. If the given
219.2657 + * locale is <code>Locale("en")</code>, then
219.2658 + * <code>"baseName_en"</code> is returned.
219.2659 + *
219.2660 + * <p>Overriding this method allows applications to use different
219.2661 + * conventions in the organization and packaging of localized
219.2662 + * resources.
219.2663 + *
219.2664 + * @param baseName
219.2665 + * the base name of the resource bundle, a fully
219.2666 + * qualified class name
219.2667 + * @param locale
219.2668 + * the locale for which a resource bundle should be
219.2669 + * loaded
219.2670 + * @return the bundle name for the resource bundle
219.2671 + * @exception NullPointerException
219.2672 + * if <code>baseName</code> or <code>locale</code>
219.2673 + * is <code>null</code>
219.2674 + */
219.2675 + public String toBundleName(String baseName, Locale locale) {
219.2676 + if (locale == Locale.ROOT) {
219.2677 + return baseName;
219.2678 + }
219.2679 +
219.2680 + String language = locale.getLanguage();
219.2681 + String script = locale.getScript();
219.2682 + String country = locale.getCountry();
219.2683 + String variant = locale.getVariant();
219.2684 +
219.2685 + if (language == "" && country == "" && variant == "") {
219.2686 + return baseName;
219.2687 + }
219.2688 +
219.2689 + StringBuilder sb = new StringBuilder(baseName);
219.2690 + sb.append('_');
219.2691 + if (script != "") {
219.2692 + if (variant != "") {
219.2693 + sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
219.2694 + } else if (country != "") {
219.2695 + sb.append(language).append('_').append(script).append('_').append(country);
219.2696 + } else {
219.2697 + sb.append(language).append('_').append(script);
219.2698 + }
219.2699 + } else {
219.2700 + if (variant != "") {
219.2701 + sb.append(language).append('_').append(country).append('_').append(variant);
219.2702 + } else if (country != "") {
219.2703 + sb.append(language).append('_').append(country);
219.2704 + } else {
219.2705 + sb.append(language);
219.2706 + }
219.2707 + }
219.2708 + return sb.toString();
219.2709 +
219.2710 + }
219.2711 +
219.2712 + /**
219.2713 + * Converts the given <code>bundleName</code> to the form required
219.2714 + * by the {@link ClassLoader#getResource ClassLoader.getResource}
219.2715 + * method by replacing all occurrences of <code>'.'</code> in
219.2716 + * <code>bundleName</code> with <code>'/'</code> and appending a
219.2717 + * <code>'.'</code> and the given file <code>suffix</code>. For
219.2718 + * example, if <code>bundleName</code> is
219.2719 + * <code>"foo.bar.MyResources_ja_JP"</code> and <code>suffix</code>
219.2720 + * is <code>"properties"</code>, then
219.2721 + * <code>"foo/bar/MyResources_ja_JP.properties"</code> is returned.
219.2722 + *
219.2723 + * @param bundleName
219.2724 + * the bundle name
219.2725 + * @param suffix
219.2726 + * the file type suffix
219.2727 + * @return the converted resource name
219.2728 + * @exception NullPointerException
219.2729 + * if <code>bundleName</code> or <code>suffix</code>
219.2730 + * is <code>null</code>
219.2731 + */
219.2732 + public final String toResourceName(String bundleName, String suffix) {
219.2733 + StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
219.2734 + sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
219.2735 + return sb.toString();
219.2736 + }
219.2737 + }
219.2738 +
219.2739 + private static class SingleFormatControl extends Control {
219.2740 + private static final Control PROPERTIES_ONLY
219.2741 + = new SingleFormatControl(FORMAT_PROPERTIES);
219.2742 +
219.2743 + private static final Control CLASS_ONLY
219.2744 + = new SingleFormatControl(FORMAT_CLASS);
219.2745 +
219.2746 + private final List<String> formats;
219.2747 +
219.2748 + protected SingleFormatControl(List<String> formats) {
219.2749 + this.formats = formats;
219.2750 + }
219.2751 +
219.2752 + public List<String> getFormats(String baseName) {
219.2753 + if (baseName == null) {
219.2754 + throw new NullPointerException();
219.2755 + }
219.2756 + return formats;
219.2757 + }
219.2758 + }
219.2759 +
219.2760 + private static final class NoFallbackControl extends SingleFormatControl {
219.2761 + private static final Control NO_FALLBACK
219.2762 + = new NoFallbackControl(FORMAT_DEFAULT);
219.2763 +
219.2764 + private static final Control PROPERTIES_ONLY_NO_FALLBACK
219.2765 + = new NoFallbackControl(FORMAT_PROPERTIES);
219.2766 +
219.2767 + private static final Control CLASS_ONLY_NO_FALLBACK
219.2768 + = new NoFallbackControl(FORMAT_CLASS);
219.2769 +
219.2770 + protected NoFallbackControl(List<String> formats) {
219.2771 + super(formats);
219.2772 + }
219.2773 +
219.2774 + public Locale getFallbackLocale(String baseName, Locale locale) {
219.2775 + if (baseName == null || locale == null) {
219.2776 + throw new NullPointerException();
219.2777 + }
219.2778 + return null;
219.2779 + }
219.2780 + }
219.2781 +}
220.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
220.2 +++ b/rt/emul/compact/src/main/java/java/util/SimpleTimeZone.java Wed Apr 30 15:04:10 2014 +0200
220.3 @@ -0,0 +1,1737 @@
220.4 +/*
220.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
220.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
220.7 + *
220.8 + * This code is free software; you can redistribute it and/or modify it
220.9 + * under the terms of the GNU General Public License version 2 only, as
220.10 + * published by the Free Software Foundation. Oracle designates this
220.11 + * particular file as subject to the "Classpath" exception as provided
220.12 + * by Oracle in the LICENSE file that accompanied this code.
220.13 + *
220.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
220.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
220.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
220.17 + * version 2 for more details (a copy is included in the LICENSE file that
220.18 + * accompanied this code).
220.19 + *
220.20 + * You should have received a copy of the GNU General Public License version
220.21 + * 2 along with this work; if not, write to the Free Software Foundation,
220.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
220.23 + *
220.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
220.25 + * or visit www.oracle.com if you need additional information or have any
220.26 + * questions.
220.27 + */
220.28 +
220.29 +/*
220.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
220.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
220.32 + *
220.33 + * The original version of this source code and documentation is copyrighted
220.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
220.35 + * materials are provided under terms of a License Agreement between Taligent
220.36 + * and Sun. This technology is protected by multiple US and International
220.37 + * patents. This notice and attribution to Taligent may not be removed.
220.38 + * Taligent is a registered trademark of Taligent, Inc.
220.39 + *
220.40 + */
220.41 +
220.42 +package java.util;
220.43 +
220.44 +import java.io.ObjectInputStream;
220.45 +import java.io.ObjectOutputStream;
220.46 +import java.io.IOException;
220.47 +import java.util.Date.BaseCalendar;
220.48 +
220.49 +/**
220.50 + * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
220.51 + * that represents a time zone for use with a Gregorian calendar.
220.52 + * The class holds an offset from GMT, called <em>raw offset</em>, and start
220.53 + * and end rules for a daylight saving time schedule. Since it only holds
220.54 + * single values for each, it cannot handle historical changes in the offset
220.55 + * from GMT and the daylight saving schedule, except that the {@link
220.56 + * #setStartYear setStartYear} method can specify the year when the daylight
220.57 + * saving time schedule starts in effect.
220.58 + * <p>
220.59 + * To construct a <code>SimpleTimeZone</code> with a daylight saving time
220.60 + * schedule, the schedule can be described with a set of rules,
220.61 + * <em>start-rule</em> and <em>end-rule</em>. A day when daylight saving time
220.62 + * starts or ends is specified by a combination of <em>month</em>,
220.63 + * <em>day-of-month</em>, and <em>day-of-week</em> values. The <em>month</em>
220.64 + * value is represented by a Calendar {@link Calendar#MONTH MONTH} field
220.65 + * value, such as {@link Calendar#MARCH}. The <em>day-of-week</em> value is
220.66 + * represented by a Calendar {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value,
220.67 + * such as {@link Calendar#SUNDAY SUNDAY}. The meanings of value combinations
220.68 + * are as follows.
220.69 + *
220.70 + * <ul>
220.71 + * <li><b>Exact day of month</b><br>
220.72 + * To specify an exact day of month, set the <em>month</em> and
220.73 + * <em>day-of-month</em> to an exact value, and <em>day-of-week</em> to zero. For
220.74 + * example, to specify March 1, set the <em>month</em> to {@link Calendar#MARCH
220.75 + * MARCH}, <em>day-of-month</em> to 1, and <em>day-of-week</em> to 0.</li>
220.76 + *
220.77 + * <li><b>Day of week on or after day of month</b><br>
220.78 + * To specify a day of week on or after an exact day of month, set the
220.79 + * <em>month</em> to an exact month value, <em>day-of-month</em> to the day on
220.80 + * or after which the rule is applied, and <em>day-of-week</em> to a negative {@link
220.81 + * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the
220.82 + * second Sunday of April, set <em>month</em> to {@link Calendar#APRIL APRIL},
220.83 + * <em>day-of-month</em> to 8, and <em>day-of-week</em> to <code>-</code>{@link
220.84 + * Calendar#SUNDAY SUNDAY}.</li>
220.85 + *
220.86 + * <li><b>Day of week on or before day of month</b><br>
220.87 + * To specify a day of the week on or before an exact day of the month, set
220.88 + * <em>day-of-month</em> and <em>day-of-week</em> to a negative value. For
220.89 + * example, to specify the last Wednesday on or before the 21st of March, set
220.90 + * <em>month</em> to {@link Calendar#MARCH MARCH}, <em>day-of-month</em> is -21
220.91 + * and <em>day-of-week</em> is <code>-</code>{@link Calendar#WEDNESDAY WEDNESDAY}. </li>
220.92 + *
220.93 + * <li><b>Last day-of-week of month</b><br>
220.94 + * To specify, the last day-of-week of the month, set <em>day-of-week</em> to a
220.95 + * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value and <em>day-of-month</em> to
220.96 + * -1. For example, to specify the last Sunday of October, set <em>month</em>
220.97 + * to {@link Calendar#OCTOBER OCTOBER}, <em>day-of-week</em> to {@link
220.98 + * Calendar#SUNDAY SUNDAY} and <em>day-of-month</em> to -1. </li>
220.99 + *
220.100 + * </ul>
220.101 + * The time of the day at which daylight saving time starts or ends is
220.102 + * specified by a millisecond value within the day. There are three kinds of
220.103 + * <em>mode</em>s to specify the time: {@link #WALL_TIME}, {@link
220.104 + * #STANDARD_TIME} and {@link #UTC_TIME}. For example, if daylight
220.105 + * saving time ends
220.106 + * at 2:00 am in the wall clock time, it can be specified by 7200000
220.107 + * milliseconds in the {@link #WALL_TIME} mode. In this case, the wall clock time
220.108 + * for an <em>end-rule</em> means the same thing as the daylight time.
220.109 + * <p>
220.110 + * The following are examples of parameters for constructing time zone objects.
220.111 + * <pre><code>
220.112 + * // Base GMT offset: -8:00
220.113 + * // DST starts: at 2:00am in standard time
220.114 + * // on the first Sunday in April
220.115 + * // DST ends: at 2:00am in daylight time
220.116 + * // on the last Sunday in October
220.117 + * // Save: 1 hour
220.118 + * SimpleTimeZone(-28800000,
220.119 + * "America/Los_Angeles",
220.120 + * Calendar.APRIL, 1, -Calendar.SUNDAY,
220.121 + * 7200000,
220.122 + * Calendar.OCTOBER, -1, Calendar.SUNDAY,
220.123 + * 7200000,
220.124 + * 3600000)
220.125 + *
220.126 + * // Base GMT offset: +1:00
220.127 + * // DST starts: at 1:00am in UTC time
220.128 + * // on the last Sunday in March
220.129 + * // DST ends: at 1:00am in UTC time
220.130 + * // on the last Sunday in October
220.131 + * // Save: 1 hour
220.132 + * SimpleTimeZone(3600000,
220.133 + * "Europe/Paris",
220.134 + * Calendar.MARCH, -1, Calendar.SUNDAY,
220.135 + * 3600000, SimpleTimeZone.UTC_TIME,
220.136 + * Calendar.OCTOBER, -1, Calendar.SUNDAY,
220.137 + * 3600000, SimpleTimeZone.UTC_TIME,
220.138 + * 3600000)
220.139 + * </code></pre>
220.140 + * These parameter rules are also applicable to the set rule methods, such as
220.141 + * <code>setStartRule</code>.
220.142 + *
220.143 + * @since 1.1
220.144 + * @see Calendar
220.145 + * @see GregorianCalendar
220.146 + * @see TimeZone
220.147 + * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
220.148 + */
220.149 +
220.150 +public class SimpleTimeZone extends TimeZone {
220.151 + /**
220.152 + * Constructs a SimpleTimeZone with the given base time zone offset from GMT
220.153 + * and time zone ID with no daylight saving time schedule.
220.154 + *
220.155 + * @param rawOffset The base time zone offset in milliseconds to GMT.
220.156 + * @param ID The time zone name that is given to this instance.
220.157 + */
220.158 + public SimpleTimeZone(int rawOffset, String ID)
220.159 + {
220.160 + this.rawOffset = rawOffset;
220.161 + setID (ID);
220.162 + dstSavings = millisPerHour; // In case user sets rules later
220.163 + }
220.164 +
220.165 + /**
220.166 + * Constructs a SimpleTimeZone with the given base time zone offset from
220.167 + * GMT, time zone ID, and rules for starting and ending the daylight
220.168 + * time.
220.169 + * Both <code>startTime</code> and <code>endTime</code> are specified to be
220.170 + * represented in the wall clock time. The amount of daylight saving is
220.171 + * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is
220.172 + * equivalent to:
220.173 + * <pre><code>
220.174 + * SimpleTimeZone(rawOffset,
220.175 + * ID,
220.176 + * startMonth,
220.177 + * startDay,
220.178 + * startDayOfWeek,
220.179 + * startTime,
220.180 + * SimpleTimeZone.{@link #WALL_TIME},
220.181 + * endMonth,
220.182 + * endDay,
220.183 + * endDayOfWeek,
220.184 + * endTime,
220.185 + * SimpleTimeZone.{@link #WALL_TIME},
220.186 + * 3600000)
220.187 + * </code></pre>
220.188 + *
220.189 + * @param rawOffset The given base time zone offset from GMT.
220.190 + * @param ID The time zone ID which is given to this object.
220.191 + * @param startMonth The daylight saving time starting month. Month is
220.192 + * a {@link Calendar#MONTH MONTH} field value (0-based. e.g., 0
220.193 + * for January).
220.194 + * @param startDay The day of the month on which the daylight saving time starts.
220.195 + * See the class description for the special cases of this parameter.
220.196 + * @param startDayOfWeek The daylight saving time starting day-of-week.
220.197 + * See the class description for the special cases of this parameter.
220.198 + * @param startTime The daylight saving time starting time in local wall clock
220.199 + * time (in milliseconds within the day), which is local
220.200 + * standard time in this case.
220.201 + * @param endMonth The daylight saving time ending month. Month is
220.202 + * a {@link Calendar#MONTH MONTH} field
220.203 + * value (0-based. e.g., 9 for October).
220.204 + * @param endDay The day of the month on which the daylight saving time ends.
220.205 + * See the class description for the special cases of this parameter.
220.206 + * @param endDayOfWeek The daylight saving time ending day-of-week.
220.207 + * See the class description for the special cases of this parameter.
220.208 + * @param endTime The daylight saving ending time in local wall clock time,
220.209 + * (in milliseconds within the day) which is local daylight
220.210 + * time in this case.
220.211 + * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
220.212 + * parameters are out of range for the start or end rule
220.213 + */
220.214 + public SimpleTimeZone(int rawOffset, String ID,
220.215 + int startMonth, int startDay, int startDayOfWeek, int startTime,
220.216 + int endMonth, int endDay, int endDayOfWeek, int endTime)
220.217 + {
220.218 + this(rawOffset, ID,
220.219 + startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
220.220 + endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
220.221 + millisPerHour);
220.222 + }
220.223 +
220.224 + /**
220.225 + * Constructs a SimpleTimeZone with the given base time zone offset from
220.226 + * GMT, time zone ID, and rules for starting and ending the daylight
220.227 + * time.
220.228 + * Both <code>startTime</code> and <code>endTime</code> are assumed to be
220.229 + * represented in the wall clock time. This constructor is equivalent to:
220.230 + * <pre><code>
220.231 + * SimpleTimeZone(rawOffset,
220.232 + * ID,
220.233 + * startMonth,
220.234 + * startDay,
220.235 + * startDayOfWeek,
220.236 + * startTime,
220.237 + * SimpleTimeZone.{@link #WALL_TIME},
220.238 + * endMonth,
220.239 + * endDay,
220.240 + * endDayOfWeek,
220.241 + * endTime,
220.242 + * SimpleTimeZone.{@link #WALL_TIME},
220.243 + * dstSavings)
220.244 + * </code></pre>
220.245 + *
220.246 + * @param rawOffset The given base time zone offset from GMT.
220.247 + * @param ID The time zone ID which is given to this object.
220.248 + * @param startMonth The daylight saving time starting month. Month is
220.249 + * a {@link Calendar#MONTH MONTH} field
220.250 + * value (0-based. e.g., 0 for January).
220.251 + * @param startDay The day of the month on which the daylight saving time starts.
220.252 + * See the class description for the special cases of this parameter.
220.253 + * @param startDayOfWeek The daylight saving time starting day-of-week.
220.254 + * See the class description for the special cases of this parameter.
220.255 + * @param startTime The daylight saving time starting time in local wall clock
220.256 + * time, which is local standard time in this case.
220.257 + * @param endMonth The daylight saving time ending month. Month is
220.258 + * a {@link Calendar#MONTH MONTH} field
220.259 + * value (0-based. e.g., 9 for October).
220.260 + * @param endDay The day of the month on which the daylight saving time ends.
220.261 + * See the class description for the special cases of this parameter.
220.262 + * @param endDayOfWeek The daylight saving time ending day-of-week.
220.263 + * See the class description for the special cases of this parameter.
220.264 + * @param endTime The daylight saving ending time in local wall clock time,
220.265 + * which is local daylight time in this case.
220.266 + * @param dstSavings The amount of time in milliseconds saved during
220.267 + * daylight saving time.
220.268 + * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
220.269 + * parameters are out of range for the start or end rule
220.270 + * @since 1.2
220.271 + */
220.272 + public SimpleTimeZone(int rawOffset, String ID,
220.273 + int startMonth, int startDay, int startDayOfWeek, int startTime,
220.274 + int endMonth, int endDay, int endDayOfWeek, int endTime,
220.275 + int dstSavings)
220.276 + {
220.277 + this(rawOffset, ID,
220.278 + startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
220.279 + endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
220.280 + dstSavings);
220.281 + }
220.282 +
220.283 + /**
220.284 + * Constructs a SimpleTimeZone with the given base time zone offset from
220.285 + * GMT, time zone ID, and rules for starting and ending the daylight
220.286 + * time.
220.287 + * This constructor takes the full set of the start and end rules
220.288 + * parameters, including modes of <code>startTime</code> and
220.289 + * <code>endTime</code>. The mode specifies either {@link #WALL_TIME wall
220.290 + * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
220.291 + * time}.
220.292 + *
220.293 + * @param rawOffset The given base time zone offset from GMT.
220.294 + * @param ID The time zone ID which is given to this object.
220.295 + * @param startMonth The daylight saving time starting month. Month is
220.296 + * a {@link Calendar#MONTH MONTH} field
220.297 + * value (0-based. e.g., 0 for January).
220.298 + * @param startDay The day of the month on which the daylight saving time starts.
220.299 + * See the class description for the special cases of this parameter.
220.300 + * @param startDayOfWeek The daylight saving time starting day-of-week.
220.301 + * See the class description for the special cases of this parameter.
220.302 + * @param startTime The daylight saving time starting time in the time mode
220.303 + * specified by <code>startTimeMode</code>.
220.304 + * @param startTimeMode The mode of the start time specified by startTime.
220.305 + * @param endMonth The daylight saving time ending month. Month is
220.306 + * a {@link Calendar#MONTH MONTH} field
220.307 + * value (0-based. e.g., 9 for October).
220.308 + * @param endDay The day of the month on which the daylight saving time ends.
220.309 + * See the class description for the special cases of this parameter.
220.310 + * @param endDayOfWeek The daylight saving time ending day-of-week.
220.311 + * See the class description for the special cases of this parameter.
220.312 + * @param endTime The daylight saving ending time in time time mode
220.313 + * specified by <code>endTimeMode</code>.
220.314 + * @param endTimeMode The mode of the end time specified by endTime
220.315 + * @param dstSavings The amount of time in milliseconds saved during
220.316 + * daylight saving time.
220.317 + *
220.318 + * @exception IllegalArgumentException if the month, day, dayOfWeek, time more, or
220.319 + * time parameters are out of range for the start or end rule, or if a time mode
220.320 + * value is invalid.
220.321 + *
220.322 + * @see #WALL_TIME
220.323 + * @see #STANDARD_TIME
220.324 + * @see #UTC_TIME
220.325 + *
220.326 + * @since 1.4
220.327 + */
220.328 + public SimpleTimeZone(int rawOffset, String ID,
220.329 + int startMonth, int startDay, int startDayOfWeek,
220.330 + int startTime, int startTimeMode,
220.331 + int endMonth, int endDay, int endDayOfWeek,
220.332 + int endTime, int endTimeMode,
220.333 + int dstSavings) {
220.334 +
220.335 + setID(ID);
220.336 + this.rawOffset = rawOffset;
220.337 + this.startMonth = startMonth;
220.338 + this.startDay = startDay;
220.339 + this.startDayOfWeek = startDayOfWeek;
220.340 + this.startTime = startTime;
220.341 + this.startTimeMode = startTimeMode;
220.342 + this.endMonth = endMonth;
220.343 + this.endDay = endDay;
220.344 + this.endDayOfWeek = endDayOfWeek;
220.345 + this.endTime = endTime;
220.346 + this.endTimeMode = endTimeMode;
220.347 + this.dstSavings = dstSavings;
220.348 +
220.349 + // this.useDaylight is set by decodeRules
220.350 + decodeRules();
220.351 + if (dstSavings <= 0) {
220.352 + throw new IllegalArgumentException("Illegal daylight saving value: " + dstSavings);
220.353 + }
220.354 + }
220.355 +
220.356 + /**
220.357 + * Sets the daylight saving time starting year.
220.358 + *
220.359 + * @param year The daylight saving starting year.
220.360 + */
220.361 + public void setStartYear(int year)
220.362 + {
220.363 + startYear = year;
220.364 + invalidateCache();
220.365 + }
220.366 +
220.367 + /**
220.368 + * Sets the daylight saving time start rule. For example, if daylight saving
220.369 + * time starts on the first Sunday in April at 2 am in local wall clock
220.370 + * time, you can set the start rule by calling:
220.371 + * <pre><code>setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);</code></pre>
220.372 + *
220.373 + * @param startMonth The daylight saving time starting month. Month is
220.374 + * a {@link Calendar#MONTH MONTH} field
220.375 + * value (0-based. e.g., 0 for January).
220.376 + * @param startDay The day of the month on which the daylight saving time starts.
220.377 + * See the class description for the special cases of this parameter.
220.378 + * @param startDayOfWeek The daylight saving time starting day-of-week.
220.379 + * See the class description for the special cases of this parameter.
220.380 + * @param startTime The daylight saving time starting time in local wall clock
220.381 + * time, which is local standard time in this case.
220.382 + * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
220.383 + * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
220.384 + */
220.385 + public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime)
220.386 + {
220.387 + this.startMonth = startMonth;
220.388 + this.startDay = startDay;
220.389 + this.startDayOfWeek = startDayOfWeek;
220.390 + this.startTime = startTime;
220.391 + startTimeMode = WALL_TIME;
220.392 + decodeStartRule();
220.393 + invalidateCache();
220.394 + }
220.395 +
220.396 + /**
220.397 + * Sets the daylight saving time start rule to a fixed date within a month.
220.398 + * This method is equivalent to:
220.399 + * <pre><code>setStartRule(startMonth, startDay, 0, startTime)</code></pre>
220.400 + *
220.401 + * @param startMonth The daylight saving time starting month. Month is
220.402 + * a {@link Calendar#MONTH MONTH} field
220.403 + * value (0-based. e.g., 0 for January).
220.404 + * @param startDay The day of the month on which the daylight saving time starts.
220.405 + * @param startTime The daylight saving time starting time in local wall clock
220.406 + * time, which is local standard time in this case.
220.407 + * See the class description for the special cases of this parameter.
220.408 + * @exception IllegalArgumentException if the <code>startMonth</code>,
220.409 + * <code>startDayOfMonth</code>, or <code>startTime</code> parameters are out of range
220.410 + * @since 1.2
220.411 + */
220.412 + public void setStartRule(int startMonth, int startDay, int startTime) {
220.413 + setStartRule(startMonth, startDay, 0, startTime);
220.414 + }
220.415 +
220.416 + /**
220.417 + * Sets the daylight saving time start rule to a weekday before or after the given date within
220.418 + * a month, e.g., the first Monday on or after the 8th.
220.419 + *
220.420 + * @param startMonth The daylight saving time starting month. Month is
220.421 + * a {@link Calendar#MONTH MONTH} field
220.422 + * value (0-based. e.g., 0 for January).
220.423 + * @param startDay The day of the month on which the daylight saving time starts.
220.424 + * @param startDayOfWeek The daylight saving time starting day-of-week.
220.425 + * @param startTime The daylight saving time starting time in local wall clock
220.426 + * time, which is local standard time in this case.
220.427 + * @param after If true, this rule selects the first <code>dayOfWeek</code> on or
220.428 + * <em>after</em> <code>dayOfMonth</code>. If false, this rule
220.429 + * selects the last <code>dayOfWeek</code> on or <em>before</em>
220.430 + * <code>dayOfMonth</code>.
220.431 + * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
220.432 + * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
220.433 + * @since 1.2
220.434 + */
220.435 + public void setStartRule(int startMonth, int startDay, int startDayOfWeek,
220.436 + int startTime, boolean after)
220.437 + {
220.438 + // TODO: this method doesn't check the initial values of dayOfMonth or dayOfWeek.
220.439 + if (after) {
220.440 + setStartRule(startMonth, startDay, -startDayOfWeek, startTime);
220.441 + } else {
220.442 + setStartRule(startMonth, -startDay, -startDayOfWeek, startTime);
220.443 + }
220.444 + }
220.445 +
220.446 + /**
220.447 + * Sets the daylight saving time end rule. For example, if daylight saving time
220.448 + * ends on the last Sunday in October at 2 am in wall clock time,
220.449 + * you can set the end rule by calling:
220.450 + * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>
220.451 + *
220.452 + * @param endMonth The daylight saving time ending month. Month is
220.453 + * a {@link Calendar#MONTH MONTH} field
220.454 + * value (0-based. e.g., 9 for October).
220.455 + * @param endDay The day of the month on which the daylight saving time ends.
220.456 + * See the class description for the special cases of this parameter.
220.457 + * @param endDayOfWeek The daylight saving time ending day-of-week.
220.458 + * See the class description for the special cases of this parameter.
220.459 + * @param endTime The daylight saving ending time in local wall clock time,
220.460 + * (in milliseconds within the day) which is local daylight
220.461 + * time in this case.
220.462 + * @exception IllegalArgumentException if the <code>endMonth</code>, <code>endDay</code>,
220.463 + * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
220.464 + */
220.465 + public void setEndRule(int endMonth, int endDay, int endDayOfWeek,
220.466 + int endTime)
220.467 + {
220.468 + this.endMonth = endMonth;
220.469 + this.endDay = endDay;
220.470 + this.endDayOfWeek = endDayOfWeek;
220.471 + this.endTime = endTime;
220.472 + this.endTimeMode = WALL_TIME;
220.473 + decodeEndRule();
220.474 + invalidateCache();
220.475 + }
220.476 +
220.477 + /**
220.478 + * Sets the daylight saving time end rule to a fixed date within a month.
220.479 + * This method is equivalent to:
220.480 + * <pre><code>setEndRule(endMonth, endDay, 0, endTime)</code></pre>
220.481 + *
220.482 + * @param endMonth The daylight saving time ending month. Month is
220.483 + * a {@link Calendar#MONTH MONTH} field
220.484 + * value (0-based. e.g., 9 for October).
220.485 + * @param endDay The day of the month on which the daylight saving time ends.
220.486 + * @param endTime The daylight saving ending time in local wall clock time,
220.487 + * (in milliseconds within the day) which is local daylight
220.488 + * time in this case.
220.489 + * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
220.490 + * or <code>endTime</code> parameters are out of range
220.491 + * @since 1.2
220.492 + */
220.493 + public void setEndRule(int endMonth, int endDay, int endTime)
220.494 + {
220.495 + setEndRule(endMonth, endDay, 0, endTime);
220.496 + }
220.497 +
220.498 + /**
220.499 + * Sets the daylight saving time end rule to a weekday before or after the given date within
220.500 + * a month, e.g., the first Monday on or after the 8th.
220.501 + *
220.502 + * @param endMonth The daylight saving time ending month. Month is
220.503 + * a {@link Calendar#MONTH MONTH} field
220.504 + * value (0-based. e.g., 9 for October).
220.505 + * @param endDay The day of the month on which the daylight saving time ends.
220.506 + * @param endDayOfWeek The daylight saving time ending day-of-week.
220.507 + * @param endTime The daylight saving ending time in local wall clock time,
220.508 + * (in milliseconds within the day) which is local daylight
220.509 + * time in this case.
220.510 + * @param after If true, this rule selects the first <code>endDayOfWeek</code> on
220.511 + * or <em>after</em> <code>endDay</code>. If false, this rule
220.512 + * selects the last <code>endDayOfWeek</code> on or before
220.513 + * <code>endDay</code> of the month.
220.514 + * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
220.515 + * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
220.516 + * @since 1.2
220.517 + */
220.518 + public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after)
220.519 + {
220.520 + if (after) {
220.521 + setEndRule(endMonth, endDay, -endDayOfWeek, endTime);
220.522 + } else {
220.523 + setEndRule(endMonth, -endDay, -endDayOfWeek, endTime);
220.524 + }
220.525 + }
220.526 +
220.527 + /**
220.528 + * Returns the offset of this time zone from UTC at the given
220.529 + * time. If daylight saving time is in effect at the given time,
220.530 + * the offset value is adjusted with the amount of daylight
220.531 + * saving.
220.532 + *
220.533 + * @param date the time at which the time zone offset is found
220.534 + * @return the amount of time in milliseconds to add to UTC to get
220.535 + * local time.
220.536 + * @since 1.4
220.537 + */
220.538 + public int getOffset(long date) {
220.539 + return getOffsets(date, null);
220.540 + }
220.541 +
220.542 + /**
220.543 + * @see TimeZone#getOffsets
220.544 + */
220.545 + int getOffsets(long date, int[] offsets) {
220.546 + int offset = rawOffset;
220.547 +
220.548 + computeOffset:
220.549 + if (useDaylight) {
220.550 + synchronized (this) {
220.551 + if (cacheStart != 0) {
220.552 + if (date >= cacheStart && date < cacheEnd) {
220.553 + offset += dstSavings;
220.554 + break computeOffset;
220.555 + }
220.556 + }
220.557 + }
220.558 + BaseCalendar cal = gcal;
220.559 +// date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
220.560 +// gcal : (BaseCalendar) CalendarSystem.forName("julian");
220.561 + BaseCalendar.Datum cdate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
220.562 + // Get the year in local time
220.563 + cal.getCalendarDate(date + rawOffset, cdate);
220.564 + int year = cdate.getNormalizedYear();
220.565 + if (year >= startYear) {
220.566 + // Clear time elements for the transition calculations
220.567 + cdate.setTimeOfDay(0, 0, 0, 0);
220.568 + offset = getOffset(cal, cdate, year, date);
220.569 + }
220.570 + }
220.571 +
220.572 + if (offsets != null) {
220.573 + offsets[0] = rawOffset;
220.574 + offsets[1] = offset - rawOffset;
220.575 + }
220.576 + return offset;
220.577 + }
220.578 +
220.579 + /**
220.580 + * Returns the difference in milliseconds between local time and
220.581 + * UTC, taking into account both the raw offset and the effect of
220.582 + * daylight saving, for the specified date and time. This method
220.583 + * assumes that the start and end month are distinct. It also
220.584 + * uses a default {@link GregorianCalendar} object as its
220.585 + * underlying calendar, such as for determining leap years. Do
220.586 + * not use the result of this method with a calendar other than a
220.587 + * default <code>GregorianCalendar</code>.
220.588 + *
220.589 + * <p><em>Note: In general, clients should use
220.590 + * <code>Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)</code>
220.591 + * instead of calling this method.</em>
220.592 + *
220.593 + * @param era The era of the given date.
220.594 + * @param year The year in the given date.
220.595 + * @param month The month in the given date. Month is 0-based. e.g.,
220.596 + * 0 for January.
220.597 + * @param day The day-in-month of the given date.
220.598 + * @param dayOfWeek The day-of-week of the given date.
220.599 + * @param millis The milliseconds in day in <em>standard</em> local time.
220.600 + * @return The milliseconds to add to UTC to get local time.
220.601 + * @exception IllegalArgumentException the <code>era</code>,
220.602 + * <code>month</code>, <code>day</code>, <code>dayOfWeek</code>,
220.603 + * or <code>millis</code> parameters are out of range
220.604 + */
220.605 + public int getOffset(int era, int year, int month, int day, int dayOfWeek,
220.606 + int millis)
220.607 + {
220.608 + if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
220.609 + throw new IllegalArgumentException("Illegal era " + era);
220.610 + }
220.611 +
220.612 + int y = year;
220.613 + if (era == GregorianCalendar.BC) {
220.614 + // adjust y with the GregorianCalendar-style year numbering.
220.615 + y = 1 - y;
220.616 + }
220.617 +
220.618 + // If the year isn't representable with the 64-bit long
220.619 + // integer in milliseconds, convert the year to an
220.620 + // equivalent year. This is required to pass some JCK test cases
220.621 + // which are actually useless though because the specified years
220.622 + // can't be supported by the Java time system.
220.623 + if (y >= 292278994) {
220.624 + y = 2800 + y % 2800;
220.625 + } else if (y <= -292269054) {
220.626 + // y %= 28 also produces an equivalent year, but positive
220.627 + // year numbers would be convenient to use the UNIX cal
220.628 + // command.
220.629 + y = (int) (long) y % 28;
220.630 + }
220.631 +
220.632 + // convert year to its 1-based month value
220.633 + int m = month + 1;
220.634 +
220.635 + // First, calculate time as a Gregorian date.
220.636 + BaseCalendar cal = gcal;
220.637 + BaseCalendar.Datum cdate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
220.638 + cdate.setDate(y, m, day);
220.639 + long time = cal.getTime(cdate); // normalize cdate
220.640 + time += millis - rawOffset; // UTC time
220.641 +
220.642 + // If the time value represents a time before the default
220.643 + // Gregorian cutover, recalculate time using the Julian
220.644 + // calendar system. For the Julian calendar system, the
220.645 + // normalized year numbering is ..., -2 (BCE 2), -1 (BCE 1),
220.646 + // 1, 2 ... which is different from the GregorianCalendar
220.647 + // style year numbering (..., -1, 0 (BCE 1), 1, 2, ...).
220.648 +// if (time < GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER) {
220.649 +// cal = (BaseCalendar) CalendarSystem.forName("julian");
220.650 +// cdate = (BaseCalendar.Datum) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
220.651 +// cdate.setNormalizedDate(y, m, day);
220.652 +// time = cal.getTime(cdate) + millis - rawOffset;
220.653 +// }
220.654 +
220.655 + if ((cdate.getNormalizedYear() != y)
220.656 + || (cdate.getMonth() != m)
220.657 + || (cdate.getDayOfMonth() != day)
220.658 + // The validation should be cdate.getDayOfWeek() ==
220.659 + // dayOfWeek. However, we don't check dayOfWeek for
220.660 + // compatibility.
220.661 + || (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
220.662 + || (millis < 0 || millis >= (24*60*60*1000))) {
220.663 + throw new IllegalArgumentException();
220.664 + }
220.665 +
220.666 + if (!useDaylight || year < startYear || era != GregorianCalendar.CE) {
220.667 + return rawOffset;
220.668 + }
220.669 +
220.670 + return getOffset(cal, cdate, y, time);
220.671 + }
220.672 +
220.673 + private int getOffset(BaseCalendar cal, BaseCalendar.Datum cdate, int year, long time) {
220.674 + synchronized (this) {
220.675 + if (cacheStart != 0) {
220.676 + if (time >= cacheStart && time < cacheEnd) {
220.677 + return rawOffset + dstSavings;
220.678 + }
220.679 + if (year == cacheYear) {
220.680 + return rawOffset;
220.681 + }
220.682 + }
220.683 + }
220.684 +
220.685 + long start = getStart(cal, cdate, year);
220.686 + long end = getEnd(cal, cdate, year);
220.687 + int offset = rawOffset;
220.688 + if (start <= end) {
220.689 + if (time >= start && time < end) {
220.690 + offset += dstSavings;
220.691 + }
220.692 + synchronized (this) {
220.693 + cacheYear = year;
220.694 + cacheStart = start;
220.695 + cacheEnd = end;
220.696 + }
220.697 + } else {
220.698 + if (time < end) {
220.699 + // TODO: support Gregorian cutover. The previous year
220.700 + // may be in the other calendar system.
220.701 + start = getStart(cal, cdate, year - 1);
220.702 + if (time >= start) {
220.703 + offset += dstSavings;
220.704 + }
220.705 + } else if (time >= start) {
220.706 + // TODO: support Gregorian cutover. The next year
220.707 + // may be in the other calendar system.
220.708 + end = getEnd(cal, cdate, year + 1);
220.709 + if (time < end) {
220.710 + offset += dstSavings;
220.711 + }
220.712 + }
220.713 + if (start <= end) {
220.714 + synchronized (this) {
220.715 + // The start and end transitions are in multiple years.
220.716 + cacheYear = (long) startYear - 1;
220.717 + cacheStart = start;
220.718 + cacheEnd = end;
220.719 + }
220.720 + }
220.721 + }
220.722 + return offset;
220.723 + }
220.724 +
220.725 + private long getStart(BaseCalendar cal, BaseCalendar.Datum cdate, int year) {
220.726 + int time = startTime;
220.727 + if (startTimeMode != UTC_TIME) {
220.728 + time -= rawOffset;
220.729 + }
220.730 + return getTransition(cal, cdate, startMode, year, startMonth, startDay,
220.731 + startDayOfWeek, time);
220.732 + }
220.733 +
220.734 + private long getEnd(BaseCalendar cal, BaseCalendar.Datum cdate, int year) {
220.735 + int time = endTime;
220.736 + if (endTimeMode != UTC_TIME) {
220.737 + time -= rawOffset;
220.738 + }
220.739 + if (endTimeMode == WALL_TIME) {
220.740 + time -= dstSavings;
220.741 + }
220.742 + return getTransition(cal, cdate, endMode, year, endMonth, endDay,
220.743 + endDayOfWeek, time);
220.744 + }
220.745 +
220.746 + private long getTransition(BaseCalendar cal, BaseCalendar.Datum cdate,
220.747 + int mode, int year, int month, int dayOfMonth,
220.748 + int dayOfWeek, int timeOfDay) {
220.749 + cdate.setNormalizedYear(year);
220.750 + cdate.setMonth(month + 1);
220.751 + switch (mode) {
220.752 + case DOM_MODE:
220.753 + cdate.setDayOfMonth(dayOfMonth);
220.754 + break;
220.755 +
220.756 + case DOW_IN_MONTH_MODE:
220.757 + cdate.setDayOfMonth(1);
220.758 + if (dayOfMonth < 0) {
220.759 + cdate.setDayOfMonth(cal.getMonthLength(cdate));
220.760 + }
220.761 + cdate = (BaseCalendar.Datum) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
220.762 + break;
220.763 +
220.764 + case DOW_GE_DOM_MODE:
220.765 + cdate.setDayOfMonth(dayOfMonth);
220.766 + cdate = (BaseCalendar.Datum) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
220.767 + break;
220.768 +
220.769 + case DOW_LE_DOM_MODE:
220.770 + cdate.setDayOfMonth(dayOfMonth);
220.771 + cdate = (BaseCalendar.Datum) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
220.772 + break;
220.773 + }
220.774 + return cal.getTime(cdate) + timeOfDay;
220.775 + }
220.776 +
220.777 + /**
220.778 + * Gets the GMT offset for this time zone.
220.779 + * @return the GMT offset value in milliseconds
220.780 + * @see #setRawOffset
220.781 + */
220.782 + public int getRawOffset()
220.783 + {
220.784 + // The given date will be taken into account while
220.785 + // we have the historical time zone data in place.
220.786 + return rawOffset;
220.787 + }
220.788 +
220.789 + /**
220.790 + * Sets the base time zone offset to GMT.
220.791 + * This is the offset to add to UTC to get local time.
220.792 + * @see #getRawOffset
220.793 + */
220.794 + public void setRawOffset(int offsetMillis)
220.795 + {
220.796 + this.rawOffset = offsetMillis;
220.797 + }
220.798 +
220.799 + /**
220.800 + * Sets the amount of time in milliseconds that the clock is advanced
220.801 + * during daylight saving time.
220.802 + * @param millisSavedDuringDST the number of milliseconds the time is
220.803 + * advanced with respect to standard time when the daylight saving time rules
220.804 + * are in effect. A positive number, typically one hour (3600000).
220.805 + * @see #getDSTSavings
220.806 + * @since 1.2
220.807 + */
220.808 + public void setDSTSavings(int millisSavedDuringDST) {
220.809 + if (millisSavedDuringDST <= 0) {
220.810 + throw new IllegalArgumentException("Illegal daylight saving value: "
220.811 + + millisSavedDuringDST);
220.812 + }
220.813 + dstSavings = millisSavedDuringDST;
220.814 + }
220.815 +
220.816 + /**
220.817 + * Returns the amount of time in milliseconds that the clock is
220.818 + * advanced during daylight saving time.
220.819 + *
220.820 + * @return the number of milliseconds the time is advanced with
220.821 + * respect to standard time when the daylight saving rules are in
220.822 + * effect, or 0 (zero) if this time zone doesn't observe daylight
220.823 + * saving time.
220.824 + *
220.825 + * @see #setDSTSavings
220.826 + * @since 1.2
220.827 + */
220.828 + public int getDSTSavings() {
220.829 + return useDaylight ? dstSavings : 0;
220.830 + }
220.831 +
220.832 + /**
220.833 + * Queries if this time zone uses daylight saving time.
220.834 + * @return true if this time zone uses daylight saving time;
220.835 + * false otherwise.
220.836 + */
220.837 + public boolean useDaylightTime()
220.838 + {
220.839 + return useDaylight;
220.840 + }
220.841 +
220.842 + /**
220.843 + * Returns {@code true} if this {@code SimpleTimeZone} observes
220.844 + * Daylight Saving Time. This method is equivalent to {@link
220.845 + * #useDaylightTime()}.
220.846 + *
220.847 + * @return {@code true} if this {@code SimpleTimeZone} observes
220.848 + * Daylight Saving Time; {@code false} otherwise.
220.849 + * @since 1.7
220.850 + */
220.851 + @Override
220.852 + public boolean observesDaylightTime() {
220.853 + return useDaylightTime();
220.854 + }
220.855 +
220.856 + /**
220.857 + * Queries if the given date is in daylight saving time.
220.858 + * @return true if daylight saving time is in effective at the
220.859 + * given date; false otherwise.
220.860 + */
220.861 + public boolean inDaylightTime(Date date)
220.862 + {
220.863 + return (getOffset(date.getTime()) != rawOffset);
220.864 + }
220.865 +
220.866 + /**
220.867 + * Returns a clone of this <code>SimpleTimeZone</code> instance.
220.868 + * @return a clone of this instance.
220.869 + */
220.870 + public Object clone()
220.871 + {
220.872 + return super.clone();
220.873 + }
220.874 +
220.875 + /**
220.876 + * Generates the hash code for the SimpleDateFormat object.
220.877 + * @return the hash code for this object
220.878 + */
220.879 + public synchronized int hashCode()
220.880 + {
220.881 + return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
220.882 + endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
220.883 + }
220.884 +
220.885 + /**
220.886 + * Compares the equality of two <code>SimpleTimeZone</code> objects.
220.887 + *
220.888 + * @param obj The <code>SimpleTimeZone</code> object to be compared with.
220.889 + * @return True if the given <code>obj</code> is the same as this
220.890 + * <code>SimpleTimeZone</code> object; false otherwise.
220.891 + */
220.892 + public boolean equals(Object obj)
220.893 + {
220.894 + if (this == obj) {
220.895 + return true;
220.896 + }
220.897 + if (!(obj instanceof SimpleTimeZone)) {
220.898 + return false;
220.899 + }
220.900 +
220.901 + SimpleTimeZone that = (SimpleTimeZone) obj;
220.902 +
220.903 + return getID().equals(that.getID()) &&
220.904 + hasSameRules(that);
220.905 + }
220.906 +
220.907 + /**
220.908 + * Returns <code>true</code> if this zone has the same rules and offset as another zone.
220.909 + * @param other the TimeZone object to be compared with
220.910 + * @return <code>true</code> if the given zone is a SimpleTimeZone and has the
220.911 + * same rules and offset as this one
220.912 + * @since 1.2
220.913 + */
220.914 + public boolean hasSameRules(TimeZone other) {
220.915 + if (this == other) {
220.916 + return true;
220.917 + }
220.918 + if (!(other instanceof SimpleTimeZone)) {
220.919 + return false;
220.920 + }
220.921 + SimpleTimeZone that = (SimpleTimeZone) other;
220.922 + return rawOffset == that.rawOffset &&
220.923 + useDaylight == that.useDaylight &&
220.924 + (!useDaylight
220.925 + // Only check rules if using DST
220.926 + || (dstSavings == that.dstSavings &&
220.927 + startMode == that.startMode &&
220.928 + startMonth == that.startMonth &&
220.929 + startDay == that.startDay &&
220.930 + startDayOfWeek == that.startDayOfWeek &&
220.931 + startTime == that.startTime &&
220.932 + startTimeMode == that.startTimeMode &&
220.933 + endMode == that.endMode &&
220.934 + endMonth == that.endMonth &&
220.935 + endDay == that.endDay &&
220.936 + endDayOfWeek == that.endDayOfWeek &&
220.937 + endTime == that.endTime &&
220.938 + endTimeMode == that.endTimeMode &&
220.939 + startYear == that.startYear));
220.940 + }
220.941 +
220.942 + /**
220.943 + * Returns a string representation of this time zone.
220.944 + * @return a string representation of this time zone.
220.945 + */
220.946 + public String toString() {
220.947 + return getClass().getName() +
220.948 + "[id=" + getID() +
220.949 + ",offset=" + rawOffset +
220.950 + ",dstSavings=" + dstSavings +
220.951 + ",useDaylight=" + useDaylight +
220.952 + ",startYear=" + startYear +
220.953 + ",startMode=" + startMode +
220.954 + ",startMonth=" + startMonth +
220.955 + ",startDay=" + startDay +
220.956 + ",startDayOfWeek=" + startDayOfWeek +
220.957 + ",startTime=" + startTime +
220.958 + ",startTimeMode=" + startTimeMode +
220.959 + ",endMode=" + endMode +
220.960 + ",endMonth=" + endMonth +
220.961 + ",endDay=" + endDay +
220.962 + ",endDayOfWeek=" + endDayOfWeek +
220.963 + ",endTime=" + endTime +
220.964 + ",endTimeMode=" + endTimeMode + ']';
220.965 + }
220.966 +
220.967 + // =======================privates===============================
220.968 +
220.969 + /**
220.970 + * The month in which daylight saving time starts. This value must be
220.971 + * between <code>Calendar.JANUARY</code> and
220.972 + * <code>Calendar.DECEMBER</code> inclusive. This value must not equal
220.973 + * <code>endMonth</code>.
220.974 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.975 + * @serial
220.976 + */
220.977 + private int startMonth;
220.978 +
220.979 + /**
220.980 + * This field has two possible interpretations:
220.981 + * <dl>
220.982 + * <dt><code>startMode == DOW_IN_MONTH</code></dt>
220.983 + * <dd>
220.984 + * <code>startDay</code> indicates the day of the month of
220.985 + * <code>startMonth</code> on which daylight
220.986 + * saving time starts, from 1 to 28, 30, or 31, depending on the
220.987 + * <code>startMonth</code>.
220.988 + * </dd>
220.989 + * <dt><code>startMode != DOW_IN_MONTH</code></dt>
220.990 + * <dd>
220.991 + * <code>startDay</code> indicates which <code>startDayOfWeek</code> in the
220.992 + * month <code>startMonth</code> daylight
220.993 + * saving time starts on. For example, a value of +1 and a
220.994 + * <code>startDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
220.995 + * first Sunday of <code>startMonth</code>. Likewise, +2 would indicate the
220.996 + * second Sunday, and -1 the last Sunday. A value of 0 is illegal.
220.997 + * </dd>
220.998 + * </dl>
220.999 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.1000 + * @serial
220.1001 + */
220.1002 + private int startDay;
220.1003 +
220.1004 + /**
220.1005 + * The day of the week on which daylight saving time starts. This value
220.1006 + * must be between <code>Calendar.SUNDAY</code> and
220.1007 + * <code>Calendar.SATURDAY</code> inclusive.
220.1008 + * <p>If <code>useDaylight</code> is false or
220.1009 + * <code>startMode == DAY_OF_MONTH</code>, this value is ignored.
220.1010 + * @serial
220.1011 + */
220.1012 + private int startDayOfWeek;
220.1013 +
220.1014 + /**
220.1015 + * The time in milliseconds after midnight at which daylight saving
220.1016 + * time starts. This value is expressed as wall time, standard time,
220.1017 + * or UTC time, depending on the setting of <code>startTimeMode</code>.
220.1018 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.1019 + * @serial
220.1020 + */
220.1021 + private int startTime;
220.1022 +
220.1023 + /**
220.1024 + * The format of startTime, either WALL_TIME, STANDARD_TIME, or UTC_TIME.
220.1025 + * @serial
220.1026 + * @since 1.3
220.1027 + */
220.1028 + private int startTimeMode;
220.1029 +
220.1030 + /**
220.1031 + * The month in which daylight saving time ends. This value must be
220.1032 + * between <code>Calendar.JANUARY</code> and
220.1033 + * <code>Calendar.UNDECIMBER</code>. This value must not equal
220.1034 + * <code>startMonth</code>.
220.1035 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.1036 + * @serial
220.1037 + */
220.1038 + private int endMonth;
220.1039 +
220.1040 + /**
220.1041 + * This field has two possible interpretations:
220.1042 + * <dl>
220.1043 + * <dt><code>endMode == DOW_IN_MONTH</code></dt>
220.1044 + * <dd>
220.1045 + * <code>endDay</code> indicates the day of the month of
220.1046 + * <code>endMonth</code> on which daylight
220.1047 + * saving time ends, from 1 to 28, 30, or 31, depending on the
220.1048 + * <code>endMonth</code>.
220.1049 + * </dd>
220.1050 + * <dt><code>endMode != DOW_IN_MONTH</code></dt>
220.1051 + * <dd>
220.1052 + * <code>endDay</code> indicates which <code>endDayOfWeek</code> in th
220.1053 + * month <code>endMonth</code> daylight
220.1054 + * saving time ends on. For example, a value of +1 and a
220.1055 + * <code>endDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
220.1056 + * first Sunday of <code>endMonth</code>. Likewise, +2 would indicate the
220.1057 + * second Sunday, and -1 the last Sunday. A value of 0 is illegal.
220.1058 + * </dd>
220.1059 + * </dl>
220.1060 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.1061 + * @serial
220.1062 + */
220.1063 + private int endDay;
220.1064 +
220.1065 + /**
220.1066 + * The day of the week on which daylight saving time ends. This value
220.1067 + * must be between <code>Calendar.SUNDAY</code> and
220.1068 + * <code>Calendar.SATURDAY</code> inclusive.
220.1069 + * <p>If <code>useDaylight</code> is false or
220.1070 + * <code>endMode == DAY_OF_MONTH</code>, this value is ignored.
220.1071 + * @serial
220.1072 + */
220.1073 + private int endDayOfWeek;
220.1074 +
220.1075 + /**
220.1076 + * The time in milliseconds after midnight at which daylight saving
220.1077 + * time ends. This value is expressed as wall time, standard time,
220.1078 + * or UTC time, depending on the setting of <code>endTimeMode</code>.
220.1079 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.1080 + * @serial
220.1081 + */
220.1082 + private int endTime;
220.1083 +
220.1084 + /**
220.1085 + * The format of endTime, either <code>WALL_TIME</code>,
220.1086 + * <code>STANDARD_TIME</code>, or <code>UTC_TIME</code>.
220.1087 + * @serial
220.1088 + * @since 1.3
220.1089 + */
220.1090 + private int endTimeMode;
220.1091 +
220.1092 + /**
220.1093 + * The year in which daylight saving time is first observed. This is an {@link GregorianCalendar#AD AD}
220.1094 + * value. If this value is less than 1 then daylight saving time is observed
220.1095 + * for all <code>AD</code> years.
220.1096 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.1097 + * @serial
220.1098 + */
220.1099 + private int startYear;
220.1100 +
220.1101 + /**
220.1102 + * The offset in milliseconds between this zone and GMT. Negative offsets
220.1103 + * are to the west of Greenwich. To obtain local <em>standard</em> time,
220.1104 + * add the offset to GMT time. To obtain local wall time it may also be
220.1105 + * necessary to add <code>dstSavings</code>.
220.1106 + * @serial
220.1107 + */
220.1108 + private int rawOffset;
220.1109 +
220.1110 + /**
220.1111 + * A boolean value which is true if and only if this zone uses daylight
220.1112 + * saving time. If this value is false, several other fields are ignored.
220.1113 + * @serial
220.1114 + */
220.1115 + private boolean useDaylight=false; // indicate if this time zone uses DST
220.1116 +
220.1117 + private static final int millisPerHour = 60*60*1000;
220.1118 + private static final int millisPerDay = 24*millisPerHour;
220.1119 +
220.1120 + /**
220.1121 + * This field was serialized in JDK 1.1, so we have to keep it that way
220.1122 + * to maintain serialization compatibility. However, there's no need to
220.1123 + * recreate the array each time we create a new time zone.
220.1124 + * @serial An array of bytes containing the values {31, 28, 31, 30, 31, 30,
220.1125 + * 31, 31, 30, 31, 30, 31}. This is ignored as of the Java 2 platform v1.2, however, it must
220.1126 + * be streamed out for compatibility with JDK 1.1.
220.1127 + */
220.1128 + private final byte monthLength[] = staticMonthLength;
220.1129 + private final static byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31};
220.1130 + private final static byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
220.1131 +
220.1132 + /**
220.1133 + * Variables specifying the mode of the start rule. Takes the following
220.1134 + * values:
220.1135 + * <dl>
220.1136 + * <dt><code>DOM_MODE</code></dt>
220.1137 + * <dd>
220.1138 + * Exact day of week; e.g., March 1.
220.1139 + * </dd>
220.1140 + * <dt><code>DOW_IN_MONTH_MODE</code></dt>
220.1141 + * <dd>
220.1142 + * Day of week in month; e.g., last Sunday in March.
220.1143 + * </dd>
220.1144 + * <dt><code>DOW_GE_DOM_MODE</code></dt>
220.1145 + * <dd>
220.1146 + * Day of week after day of month; e.g., Sunday on or after March 15.
220.1147 + * </dd>
220.1148 + * <dt><code>DOW_LE_DOM_MODE</code></dt>
220.1149 + * <dd>
220.1150 + * Day of week before day of month; e.g., Sunday on or before March 15.
220.1151 + * </dd>
220.1152 + * </dl>
220.1153 + * The setting of this field affects the interpretation of the
220.1154 + * <code>startDay</code> field.
220.1155 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.1156 + * @serial
220.1157 + * @since 1.1.4
220.1158 + */
220.1159 + private int startMode;
220.1160 +
220.1161 + /**
220.1162 + * Variables specifying the mode of the end rule. Takes the following
220.1163 + * values:
220.1164 + * <dl>
220.1165 + * <dt><code>DOM_MODE</code></dt>
220.1166 + * <dd>
220.1167 + * Exact day of week; e.g., March 1.
220.1168 + * </dd>
220.1169 + * <dt><code>DOW_IN_MONTH_MODE</code></dt>
220.1170 + * <dd>
220.1171 + * Day of week in month; e.g., last Sunday in March.
220.1172 + * </dd>
220.1173 + * <dt><code>DOW_GE_DOM_MODE</code></dt>
220.1174 + * <dd>
220.1175 + * Day of week after day of month; e.g., Sunday on or after March 15.
220.1176 + * </dd>
220.1177 + * <dt><code>DOW_LE_DOM_MODE</code></dt>
220.1178 + * <dd>
220.1179 + * Day of week before day of month; e.g., Sunday on or before March 15.
220.1180 + * </dd>
220.1181 + * </dl>
220.1182 + * The setting of this field affects the interpretation of the
220.1183 + * <code>endDay</code> field.
220.1184 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.1185 + * @serial
220.1186 + * @since 1.1.4
220.1187 + */
220.1188 + private int endMode;
220.1189 +
220.1190 + /**
220.1191 + * A positive value indicating the amount of time saved during DST in
220.1192 + * milliseconds.
220.1193 + * Typically one hour (3600000); sometimes 30 minutes (1800000).
220.1194 + * <p>If <code>useDaylight</code> is false, this value is ignored.
220.1195 + * @serial
220.1196 + * @since 1.1.4
220.1197 + */
220.1198 + private int dstSavings;
220.1199 +
220.1200 + private static final BaseCalendar gcal = new BaseCalendar();//CalendarSystem.getGregorianCalendar();
220.1201 +
220.1202 + /**
220.1203 + * Cache values representing a single period of daylight saving
220.1204 + * time. When the cache values are valid, cacheStart is the start
220.1205 + * time (inclusive) of daylight saving time and cacheEnd is the
220.1206 + * end time (exclusive).
220.1207 + *
220.1208 + * cacheYear has a year value if both cacheStart and cacheEnd are
220.1209 + * in the same year. cacheYear is set to startYear - 1 if
220.1210 + * cacheStart and cacheEnd are in different years. cacheStart is 0
220.1211 + * if the cache values are void. cacheYear is a long to support
220.1212 + * Integer.MIN_VALUE - 1 (JCK requirement).
220.1213 + */
220.1214 + private transient long cacheYear;
220.1215 + private transient long cacheStart;
220.1216 + private transient long cacheEnd;
220.1217 +
220.1218 + /**
220.1219 + * Constants specifying values of startMode and endMode.
220.1220 + */
220.1221 + private static final int DOM_MODE = 1; // Exact day of month, "Mar 1"
220.1222 + private static final int DOW_IN_MONTH_MODE = 2; // Day of week in month, "lastSun"
220.1223 + private static final int DOW_GE_DOM_MODE = 3; // Day of week after day of month, "Sun>=15"
220.1224 + private static final int DOW_LE_DOM_MODE = 4; // Day of week before day of month, "Sun<=21"
220.1225 +
220.1226 + /**
220.1227 + * Constant for a mode of start or end time specified as wall clock
220.1228 + * time. Wall clock time is standard time for the onset rule, and
220.1229 + * daylight time for the end rule.
220.1230 + * @since 1.4
220.1231 + */
220.1232 + public static final int WALL_TIME = 0; // Zero for backward compatibility
220.1233 +
220.1234 + /**
220.1235 + * Constant for a mode of start or end time specified as standard time.
220.1236 + * @since 1.4
220.1237 + */
220.1238 + public static final int STANDARD_TIME = 1;
220.1239 +
220.1240 + /**
220.1241 + * Constant for a mode of start or end time specified as UTC. European
220.1242 + * Union rules are specified as UTC time, for example.
220.1243 + * @since 1.4
220.1244 + */
220.1245 + public static final int UTC_TIME = 2;
220.1246 +
220.1247 + // Proclaim compatibility with 1.1
220.1248 + static final long serialVersionUID = -403250971215465050L;
220.1249 +
220.1250 + // the internal serial version which says which version was written
220.1251 + // - 0 (default) for version up to JDK 1.1.3
220.1252 + // - 1 for version from JDK 1.1.4, which includes 3 new fields
220.1253 + // - 2 for JDK 1.3, which includes 2 new fields
220.1254 + static final int currentSerialVersion = 2;
220.1255 +
220.1256 + /**
220.1257 + * The version of the serialized data on the stream. Possible values:
220.1258 + * <dl>
220.1259 + * <dt><b>0</b> or not present on stream</dt>
220.1260 + * <dd>
220.1261 + * JDK 1.1.3 or earlier.
220.1262 + * </dd>
220.1263 + * <dt><b>1</b></dt>
220.1264 + * <dd>
220.1265 + * JDK 1.1.4 or later. Includes three new fields: <code>startMode</code>,
220.1266 + * <code>endMode</code>, and <code>dstSavings</code>.
220.1267 + * </dd>
220.1268 + * <dt><b>2</b></dt>
220.1269 + * <dd>
220.1270 + * JDK 1.3 or later. Includes two new fields: <code>startTimeMode</code>
220.1271 + * and <code>endTimeMode</code>.
220.1272 + * </dd>
220.1273 + * </dl>
220.1274 + * When streaming out this class, the most recent format
220.1275 + * and the highest allowable <code>serialVersionOnStream</code>
220.1276 + * is written.
220.1277 + * @serial
220.1278 + * @since 1.1.4
220.1279 + */
220.1280 + private int serialVersionOnStream = currentSerialVersion;
220.1281 +
220.1282 + synchronized private void invalidateCache() {
220.1283 + cacheYear = startYear - 1;
220.1284 + cacheStart = cacheEnd = 0;
220.1285 + }
220.1286 +
220.1287 + //----------------------------------------------------------------------
220.1288 + // Rule representation
220.1289 + //
220.1290 + // We represent the following flavors of rules:
220.1291 + // 5 the fifth of the month
220.1292 + // lastSun the last Sunday in the month
220.1293 + // lastMon the last Monday in the month
220.1294 + // Sun>=8 first Sunday on or after the eighth
220.1295 + // Sun<=25 last Sunday on or before the 25th
220.1296 + // This is further complicated by the fact that we need to remain
220.1297 + // backward compatible with the 1.1 FCS. Finally, we need to minimize
220.1298 + // API changes. In order to satisfy these requirements, we support
220.1299 + // three representation systems, and we translate between them.
220.1300 + //
220.1301 + // INTERNAL REPRESENTATION
220.1302 + // This is the format SimpleTimeZone objects take after construction or
220.1303 + // streaming in is complete. Rules are represented directly, using an
220.1304 + // unencoded format. We will discuss the start rule only below; the end
220.1305 + // rule is analogous.
220.1306 + // startMode Takes on enumerated values DAY_OF_MONTH,
220.1307 + // DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
220.1308 + // startDay The day of the month, or for DOW_IN_MONTH mode, a
220.1309 + // value indicating which DOW, such as +1 for first,
220.1310 + // +2 for second, -1 for last, etc.
220.1311 + // startDayOfWeek The day of the week. Ignored for DAY_OF_MONTH.
220.1312 + //
220.1313 + // ENCODED REPRESENTATION
220.1314 + // This is the format accepted by the constructor and by setStartRule()
220.1315 + // and setEndRule(). It uses various combinations of positive, negative,
220.1316 + // and zero values to encode the different rules. This representation
220.1317 + // allows us to specify all the different rule flavors without altering
220.1318 + // the API.
220.1319 + // MODE startMonth startDay startDayOfWeek
220.1320 + // DOW_IN_MONTH_MODE >=0 !=0 >0
220.1321 + // DOM_MODE >=0 >0 ==0
220.1322 + // DOW_GE_DOM_MODE >=0 >0 <0
220.1323 + // DOW_LE_DOM_MODE >=0 <0 <0
220.1324 + // (no DST) don't care ==0 don't care
220.1325 + //
220.1326 + // STREAMED REPRESENTATION
220.1327 + // We must retain binary compatibility with the 1.1 FCS. The 1.1 code only
220.1328 + // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
220.1329 + // flag useDaylight. When we stream an object out, we translate into an
220.1330 + // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
220.1331 + // and used by 1.1 code. Following that, we write out the full
220.1332 + // representation separately so that contemporary code can recognize and
220.1333 + // parse it. The full representation is written in a "packed" format,
220.1334 + // consisting of a version number, a length, and an array of bytes. Future
220.1335 + // versions of this class may specify different versions. If they wish to
220.1336 + // include additional data, they should do so by storing them after the
220.1337 + // packed representation below.
220.1338 + //----------------------------------------------------------------------
220.1339 +
220.1340 + /**
220.1341 + * Given a set of encoded rules in startDay and startDayOfMonth, decode
220.1342 + * them and set the startMode appropriately. Do the same for endDay and
220.1343 + * endDayOfMonth. Upon entry, the day of week variables may be zero or
220.1344 + * negative, in order to indicate special modes. The day of month
220.1345 + * variables may also be negative. Upon exit, the mode variables will be
220.1346 + * set, and the day of week and day of month variables will be positive.
220.1347 + * This method also recognizes a startDay or endDay of zero as indicating
220.1348 + * no DST.
220.1349 + */
220.1350 + private void decodeRules()
220.1351 + {
220.1352 + decodeStartRule();
220.1353 + decodeEndRule();
220.1354 + }
220.1355 +
220.1356 + /**
220.1357 + * Decode the start rule and validate the parameters. The parameters are
220.1358 + * expected to be in encoded form, which represents the various rule modes
220.1359 + * by negating or zeroing certain values. Representation formats are:
220.1360 + * <p>
220.1361 + * <pre>
220.1362 + * DOW_IN_MONTH DOM DOW>=DOM DOW<=DOM no DST
220.1363 + * ------------ ----- -------- -------- ----------
220.1364 + * month 0..11 same same same don't care
220.1365 + * day -5..5 1..31 1..31 -1..-31 0
220.1366 + * dayOfWeek 1..7 0 -1..-7 -1..-7 don't care
220.1367 + * time 0..ONEDAY same same same don't care
220.1368 + * </pre>
220.1369 + * The range for month does not include UNDECIMBER since this class is
220.1370 + * really specific to GregorianCalendar, which does not use that month.
220.1371 + * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
220.1372 + * end rule is an exclusive limit point. That is, the range of times that
220.1373 + * are in DST include those >= the start and < the end. For this reason,
220.1374 + * it should be possible to specify an end of ONEDAY in order to include the
220.1375 + * entire day. Although this is equivalent to time 0 of the following day,
220.1376 + * it's not always possible to specify that, for example, on December 31.
220.1377 + * While arguably the start range should still be 0..ONEDAY-1, we keep
220.1378 + * the start and end ranges the same for consistency.
220.1379 + */
220.1380 + private void decodeStartRule() {
220.1381 + useDaylight = (startDay != 0) && (endDay != 0);
220.1382 + if (startDay != 0) {
220.1383 + if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
220.1384 + throw new IllegalArgumentException(
220.1385 + "Illegal start month " + startMonth);
220.1386 + }
220.1387 + if (startTime < 0 || startTime > millisPerDay) {
220.1388 + throw new IllegalArgumentException(
220.1389 + "Illegal start time " + startTime);
220.1390 + }
220.1391 + if (startDayOfWeek == 0) {
220.1392 + startMode = DOM_MODE;
220.1393 + } else {
220.1394 + if (startDayOfWeek > 0) {
220.1395 + startMode = DOW_IN_MONTH_MODE;
220.1396 + } else {
220.1397 + startDayOfWeek = -startDayOfWeek;
220.1398 + if (startDay > 0) {
220.1399 + startMode = DOW_GE_DOM_MODE;
220.1400 + } else {
220.1401 + startDay = -startDay;
220.1402 + startMode = DOW_LE_DOM_MODE;
220.1403 + }
220.1404 + }
220.1405 + if (startDayOfWeek > Calendar.SATURDAY) {
220.1406 + throw new IllegalArgumentException(
220.1407 + "Illegal start day of week " + startDayOfWeek);
220.1408 + }
220.1409 + }
220.1410 + if (startMode == DOW_IN_MONTH_MODE) {
220.1411 + if (startDay < -5 || startDay > 5) {
220.1412 + throw new IllegalArgumentException(
220.1413 + "Illegal start day of week in month " + startDay);
220.1414 + }
220.1415 + } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
220.1416 + throw new IllegalArgumentException(
220.1417 + "Illegal start day " + startDay);
220.1418 + }
220.1419 + }
220.1420 + }
220.1421 +
220.1422 + /**
220.1423 + * Decode the end rule and validate the parameters. This method is exactly
220.1424 + * analogous to decodeStartRule().
220.1425 + * @see decodeStartRule
220.1426 + */
220.1427 + private void decodeEndRule() {
220.1428 + useDaylight = (startDay != 0) && (endDay != 0);
220.1429 + if (endDay != 0) {
220.1430 + if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
220.1431 + throw new IllegalArgumentException(
220.1432 + "Illegal end month " + endMonth);
220.1433 + }
220.1434 + if (endTime < 0 || endTime > millisPerDay) {
220.1435 + throw new IllegalArgumentException(
220.1436 + "Illegal end time " + endTime);
220.1437 + }
220.1438 + if (endDayOfWeek == 0) {
220.1439 + endMode = DOM_MODE;
220.1440 + } else {
220.1441 + if (endDayOfWeek > 0) {
220.1442 + endMode = DOW_IN_MONTH_MODE;
220.1443 + } else {
220.1444 + endDayOfWeek = -endDayOfWeek;
220.1445 + if (endDay > 0) {
220.1446 + endMode = DOW_GE_DOM_MODE;
220.1447 + } else {
220.1448 + endDay = -endDay;
220.1449 + endMode = DOW_LE_DOM_MODE;
220.1450 + }
220.1451 + }
220.1452 + if (endDayOfWeek > Calendar.SATURDAY) {
220.1453 + throw new IllegalArgumentException(
220.1454 + "Illegal end day of week " + endDayOfWeek);
220.1455 + }
220.1456 + }
220.1457 + if (endMode == DOW_IN_MONTH_MODE) {
220.1458 + if (endDay < -5 || endDay > 5) {
220.1459 + throw new IllegalArgumentException(
220.1460 + "Illegal end day of week in month " + endDay);
220.1461 + }
220.1462 + } else if (endDay < 1 || endDay > staticMonthLength[endMonth]) {
220.1463 + throw new IllegalArgumentException(
220.1464 + "Illegal end day " + endDay);
220.1465 + }
220.1466 + }
220.1467 + }
220.1468 +
220.1469 + /**
220.1470 + * Make rules compatible to 1.1 FCS code. Since 1.1 FCS code only understands
220.1471 + * day-of-week-in-month rules, we must modify other modes of rules to their
220.1472 + * approximate equivalent in 1.1 FCS terms. This method is used when streaming
220.1473 + * out objects of this class. After it is called, the rules will be modified,
220.1474 + * with a possible loss of information. startMode and endMode will NOT be
220.1475 + * altered, even though semantically they should be set to DOW_IN_MONTH_MODE,
220.1476 + * since the rule modification is only intended to be temporary.
220.1477 + */
220.1478 + private void makeRulesCompatible()
220.1479 + {
220.1480 + switch (startMode) {
220.1481 + case DOM_MODE:
220.1482 + startDay = 1 + (startDay / 7);
220.1483 + startDayOfWeek = Calendar.SUNDAY;
220.1484 + break;
220.1485 +
220.1486 + case DOW_GE_DOM_MODE:
220.1487 + // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
220.1488 + // that is, Sun>=1 == firstSun.
220.1489 + if (startDay != 1) {
220.1490 + startDay = 1 + (startDay / 7);
220.1491 + }
220.1492 + break;
220.1493 +
220.1494 + case DOW_LE_DOM_MODE:
220.1495 + if (startDay >= 30) {
220.1496 + startDay = -1;
220.1497 + } else {
220.1498 + startDay = 1 + (startDay / 7);
220.1499 + }
220.1500 + break;
220.1501 + }
220.1502 +
220.1503 + switch (endMode) {
220.1504 + case DOM_MODE:
220.1505 + endDay = 1 + (endDay / 7);
220.1506 + endDayOfWeek = Calendar.SUNDAY;
220.1507 + break;
220.1508 +
220.1509 + case DOW_GE_DOM_MODE:
220.1510 + // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
220.1511 + // that is, Sun>=1 == firstSun.
220.1512 + if (endDay != 1) {
220.1513 + endDay = 1 + (endDay / 7);
220.1514 + }
220.1515 + break;
220.1516 +
220.1517 + case DOW_LE_DOM_MODE:
220.1518 + if (endDay >= 30) {
220.1519 + endDay = -1;
220.1520 + } else {
220.1521 + endDay = 1 + (endDay / 7);
220.1522 + }
220.1523 + break;
220.1524 + }
220.1525 +
220.1526 + /*
220.1527 + * Adjust the start and end times to wall time. This works perfectly
220.1528 + * well unless it pushes into the next or previous day. If that
220.1529 + * happens, we attempt to adjust the day rule somewhat crudely. The day
220.1530 + * rules have been forced into DOW_IN_MONTH mode already, so we change
220.1531 + * the day of week to move forward or back by a day. It's possible to
220.1532 + * make a more refined adjustment of the original rules first, but in
220.1533 + * most cases this extra effort will go to waste once we adjust the day
220.1534 + * rules anyway.
220.1535 + */
220.1536 + switch (startTimeMode) {
220.1537 + case UTC_TIME:
220.1538 + startTime += rawOffset;
220.1539 + break;
220.1540 + }
220.1541 + while (startTime < 0) {
220.1542 + startTime += millisPerDay;
220.1543 + startDayOfWeek = 1 + ((startDayOfWeek+5) % 7); // Back 1 day
220.1544 + }
220.1545 + while (startTime >= millisPerDay) {
220.1546 + startTime -= millisPerDay;
220.1547 + startDayOfWeek = 1 + (startDayOfWeek % 7); // Forward 1 day
220.1548 + }
220.1549 +
220.1550 + switch (endTimeMode) {
220.1551 + case UTC_TIME:
220.1552 + endTime += rawOffset + dstSavings;
220.1553 + break;
220.1554 + case STANDARD_TIME:
220.1555 + endTime += dstSavings;
220.1556 + }
220.1557 + while (endTime < 0) {
220.1558 + endTime += millisPerDay;
220.1559 + endDayOfWeek = 1 + ((endDayOfWeek+5) % 7); // Back 1 day
220.1560 + }
220.1561 + while (endTime >= millisPerDay) {
220.1562 + endTime -= millisPerDay;
220.1563 + endDayOfWeek = 1 + (endDayOfWeek % 7); // Forward 1 day
220.1564 + }
220.1565 + }
220.1566 +
220.1567 + /**
220.1568 + * Pack the start and end rules into an array of bytes. Only pack
220.1569 + * data which is not preserved by makeRulesCompatible.
220.1570 + */
220.1571 + private byte[] packRules()
220.1572 + {
220.1573 + byte[] rules = new byte[6];
220.1574 + rules[0] = (byte)startDay;
220.1575 + rules[1] = (byte)startDayOfWeek;
220.1576 + rules[2] = (byte)endDay;
220.1577 + rules[3] = (byte)endDayOfWeek;
220.1578 +
220.1579 + // As of serial version 2, include time modes
220.1580 + rules[4] = (byte)startTimeMode;
220.1581 + rules[5] = (byte)endTimeMode;
220.1582 +
220.1583 + return rules;
220.1584 + }
220.1585 +
220.1586 + /**
220.1587 + * Given an array of bytes produced by packRules, interpret them
220.1588 + * as the start and end rules.
220.1589 + */
220.1590 + private void unpackRules(byte[] rules)
220.1591 + {
220.1592 + startDay = rules[0];
220.1593 + startDayOfWeek = rules[1];
220.1594 + endDay = rules[2];
220.1595 + endDayOfWeek = rules[3];
220.1596 +
220.1597 + // As of serial version 2, include time modes
220.1598 + if (rules.length >= 6) {
220.1599 + startTimeMode = rules[4];
220.1600 + endTimeMode = rules[5];
220.1601 + }
220.1602 + }
220.1603 +
220.1604 + /**
220.1605 + * Pack the start and end times into an array of bytes. This is required
220.1606 + * as of serial version 2.
220.1607 + */
220.1608 + private int[] packTimes() {
220.1609 + int[] times = new int[2];
220.1610 + times[0] = startTime;
220.1611 + times[1] = endTime;
220.1612 + return times;
220.1613 + }
220.1614 +
220.1615 + /**
220.1616 + * Unpack the start and end times from an array of bytes. This is required
220.1617 + * as of serial version 2.
220.1618 + */
220.1619 + private void unpackTimes(int[] times) {
220.1620 + startTime = times[0];
220.1621 + endTime = times[1];
220.1622 + }
220.1623 +
220.1624 + /**
220.1625 + * Save the state of this object to a stream (i.e., serialize it).
220.1626 + *
220.1627 + * @serialData We write out two formats, a JDK 1.1 compatible format, using
220.1628 + * <code>DOW_IN_MONTH_MODE</code> rules, in the required section, followed
220.1629 + * by the full rules, in packed format, in the optional section. The
220.1630 + * optional section will be ignored by JDK 1.1 code upon stream in.
220.1631 + * <p> Contents of the optional section: The length of a byte array is
220.1632 + * emitted (int); this is 4 as of this release. The byte array of the given
220.1633 + * length is emitted. The contents of the byte array are the true values of
220.1634 + * the fields <code>startDay</code>, <code>startDayOfWeek</code>,
220.1635 + * <code>endDay</code>, and <code>endDayOfWeek</code>. The values of these
220.1636 + * fields in the required section are approximate values suited to the rule
220.1637 + * mode <code>DOW_IN_MONTH_MODE</code>, which is the only mode recognized by
220.1638 + * JDK 1.1.
220.1639 + */
220.1640 + private void writeObject(ObjectOutputStream stream)
220.1641 + throws IOException
220.1642 + {
220.1643 + // Construct a binary rule
220.1644 + byte[] rules = packRules();
220.1645 + int[] times = packTimes();
220.1646 +
220.1647 + // Convert to 1.1 FCS rules. This step may cause us to lose information.
220.1648 + makeRulesCompatible();
220.1649 +
220.1650 + // Write out the 1.1 FCS rules
220.1651 + stream.defaultWriteObject();
220.1652 +
220.1653 + // Write out the binary rules in the optional data area of the stream.
220.1654 + stream.writeInt(rules.length);
220.1655 + stream.write(rules);
220.1656 + stream.writeObject(times);
220.1657 +
220.1658 + // Recover the original rules. This recovers the information lost
220.1659 + // by makeRulesCompatible.
220.1660 + unpackRules(rules);
220.1661 + unpackTimes(times);
220.1662 + }
220.1663 +
220.1664 + /**
220.1665 + * Reconstitute this object from a stream (i.e., deserialize it).
220.1666 + *
220.1667 + * We handle both JDK 1.1
220.1668 + * binary formats and full formats with a packed byte array.
220.1669 + */
220.1670 + private void readObject(ObjectInputStream stream)
220.1671 + throws IOException, ClassNotFoundException
220.1672 + {
220.1673 + stream.defaultReadObject();
220.1674 +
220.1675 + if (serialVersionOnStream < 1) {
220.1676 + // Fix a bug in the 1.1 SimpleTimeZone code -- namely,
220.1677 + // startDayOfWeek and endDayOfWeek were usually uninitialized. We can't do
220.1678 + // too much, so we assume SUNDAY, which actually works most of the time.
220.1679 + if (startDayOfWeek == 0) {
220.1680 + startDayOfWeek = Calendar.SUNDAY;
220.1681 + }
220.1682 + if (endDayOfWeek == 0) {
220.1683 + endDayOfWeek = Calendar.SUNDAY;
220.1684 + }
220.1685 +
220.1686 + // The variables dstSavings, startMode, and endMode are post-1.1, so they
220.1687 + // won't be present if we're reading from a 1.1 stream. Fix them up.
220.1688 + startMode = endMode = DOW_IN_MONTH_MODE;
220.1689 + dstSavings = millisPerHour;
220.1690 + } else {
220.1691 + // For 1.1.4, in addition to the 3 new instance variables, we also
220.1692 + // store the actual rules (which have not be made compatible with 1.1)
220.1693 + // in the optional area. Read them in here and parse them.
220.1694 + int length = stream.readInt();
220.1695 + byte[] rules = new byte[length];
220.1696 + stream.readFully(rules);
220.1697 + unpackRules(rules);
220.1698 + }
220.1699 +
220.1700 + if (serialVersionOnStream >= 2) {
220.1701 + int[] times = (int[]) stream.readObject();
220.1702 + unpackTimes(times);
220.1703 + }
220.1704 +
220.1705 + serialVersionOnStream = currentSerialVersion;
220.1706 + }
220.1707 +
220.1708 + static final class GregorianCalendar {
220.1709 + public static final int BC = 0;
220.1710 +
220.1711 + /**
220.1712 + * Value of the {@link #ERA} field indicating the period before the
220.1713 + * common era, the same value as {@link #BC}.
220.1714 + *
220.1715 + * @see #CE
220.1716 + */
220.1717 + static final int BCE = 0;
220.1718 +
220.1719 + /**
220.1720 + * Value of the <code>ERA</code> field indicating the common era (Anno
220.1721 + * Domini), also known as CE. The sequence of years at the transition
220.1722 + * from <code>BC</code> to <code>AD</code> is ..., 2 BC, 1 BC, 1 AD, 2
220.1723 + * AD,...
220.1724 + *
220.1725 + * @see #ERA
220.1726 + */
220.1727 + public static final int AD = 1;
220.1728 +
220.1729 + // The default value of gregorianCutover.
220.1730 + static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
220.1731 + /**
220.1732 + * Value of the {@link #ERA} field indicating
220.1733 + * the common era, the same value as {@link #AD}.
220.1734 + *
220.1735 + * @see #BCE
220.1736 + */
220.1737 + static final int CE = 1;
220.1738 +
220.1739 + }
220.1740 +}
221.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
221.2 +++ b/rt/emul/compact/src/main/java/java/util/TimeZone.java Wed Apr 30 15:04:10 2014 +0200
221.3 @@ -0,0 +1,715 @@
221.4 +/*
221.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
221.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
221.7 + *
221.8 + * This code is free software; you can redistribute it and/or modify it
221.9 + * under the terms of the GNU General Public License version 2 only, as
221.10 + * published by the Free Software Foundation. Oracle designates this
221.11 + * particular file as subject to the "Classpath" exception as provided
221.12 + * by Oracle in the LICENSE file that accompanied this code.
221.13 + *
221.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
221.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
221.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
221.17 + * version 2 for more details (a copy is included in the LICENSE file that
221.18 + * accompanied this code).
221.19 + *
221.20 + * You should have received a copy of the GNU General Public License version
221.21 + * 2 along with this work; if not, write to the Free Software Foundation,
221.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
221.23 + *
221.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
221.25 + * or visit www.oracle.com if you need additional information or have any
221.26 + * questions.
221.27 + */
221.28 +
221.29 +/*
221.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
221.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
221.32 + *
221.33 + * The original version of this source code and documentation is copyrighted
221.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
221.35 + * materials are provided under terms of a License Agreement between Taligent
221.36 + * and Sun. This technology is protected by multiple US and International
221.37 + * patents. This notice and attribution to Taligent may not be removed.
221.38 + * Taligent is a registered trademark of Taligent, Inc.
221.39 + *
221.40 + */
221.41 +
221.42 +package java.util;
221.43 +
221.44 +import java.io.Serializable;
221.45 +import java.lang.ref.SoftReference;
221.46 +import java.security.AccessController;
221.47 +import java.security.PrivilegedAction;
221.48 +import java.util.concurrent.ConcurrentHashMap;
221.49 +
221.50 +/**
221.51 + * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
221.52 + * savings.
221.53 + *
221.54 + * <p>
221.55 + * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
221.56 + * which creates a <code>TimeZone</code> based on the time zone where the program
221.57 + * is running. For example, for a program running in Japan, <code>getDefault</code>
221.58 + * creates a <code>TimeZone</code> object based on Japanese Standard Time.
221.59 + *
221.60 + * <p>
221.61 + * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
221.62 + * along with a time zone ID. For instance, the time zone ID for the
221.63 + * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
221.64 + * U.S. Pacific Time <code>TimeZone</code> object with:
221.65 + * <blockquote><pre>
221.66 + * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
221.67 + * </pre></blockquote>
221.68 + * You can use the <code>getAvailableIDs</code> method to iterate through
221.69 + * all the supported time zone IDs. You can then choose a
221.70 + * supported ID to get a <code>TimeZone</code>.
221.71 + * If the time zone you want is not represented by one of the
221.72 + * supported IDs, then a custom time zone ID can be specified to
221.73 + * produce a TimeZone. The syntax of a custom time zone ID is:
221.74 + *
221.75 + * <blockquote><pre>
221.76 + * <a name="CustomID"><i>CustomID:</i></a>
221.77 + * <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
221.78 + * <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
221.79 + * <code>GMT</code> <i>Sign</i> <i>Hours</i>
221.80 + * <i>Sign:</i> one of
221.81 + * <code>+ -</code>
221.82 + * <i>Hours:</i>
221.83 + * <i>Digit</i>
221.84 + * <i>Digit</i> <i>Digit</i>
221.85 + * <i>Minutes:</i>
221.86 + * <i>Digit</i> <i>Digit</i>
221.87 + * <i>Digit:</i> one of
221.88 + * <code>0 1 2 3 4 5 6 7 8 9</code>
221.89 + * </pre></blockquote>
221.90 + *
221.91 + * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
221.92 + * between 00 to 59. For example, "GMT+10" and "GMT+0010" mean ten
221.93 + * hours and ten minutes ahead of GMT, respectively.
221.94 + * <p>
221.95 + * The format is locale independent and digits must be taken from the
221.96 + * Basic Latin block of the Unicode standard. No daylight saving time
221.97 + * transition schedule can be specified with a custom time zone ID. If
221.98 + * the specified string doesn't match the syntax, <code>"GMT"</code>
221.99 + * is used.
221.100 + * <p>
221.101 + * When creating a <code>TimeZone</code>, the specified custom time
221.102 + * zone ID is normalized in the following syntax:
221.103 + * <blockquote><pre>
221.104 + * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
221.105 + * <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
221.106 + * <i>Sign:</i> one of
221.107 + * <code>+ -</code>
221.108 + * <i>TwoDigitHours:</i>
221.109 + * <i>Digit</i> <i>Digit</i>
221.110 + * <i>Minutes:</i>
221.111 + * <i>Digit</i> <i>Digit</i>
221.112 + * <i>Digit:</i> one of
221.113 + * <code>0 1 2 3 4 5 6 7 8 9</code>
221.114 + * </pre></blockquote>
221.115 + * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
221.116 + *
221.117 + * <h4>Three-letter time zone IDs</h4>
221.118 + *
221.119 + * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
221.120 + * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
221.121 + * use is deprecated</strong> because the same abbreviation is often used
221.122 + * for multiple time zones (for example, "CST" could be U.S. "Central Standard
221.123 + * Time" and "China Standard Time"), and the Java platform can then only
221.124 + * recognize one of them.
221.125 + *
221.126 + *
221.127 + * @see Calendar
221.128 + * @see GregorianCalendar
221.129 + * @see SimpleTimeZone
221.130 + * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
221.131 + * @since JDK1.1
221.132 + */
221.133 +abstract public class TimeZone implements Serializable, Cloneable {
221.134 + /**
221.135 + * Sole constructor. (For invocation by subclass constructors, typically
221.136 + * implicit.)
221.137 + */
221.138 + public TimeZone() {
221.139 + }
221.140 +
221.141 + /**
221.142 + * A style specifier for <code>getDisplayName()</code> indicating
221.143 + * a short name, such as "PST."
221.144 + * @see #LONG
221.145 + * @since 1.2
221.146 + */
221.147 + public static final int SHORT = 0;
221.148 +
221.149 + /**
221.150 + * A style specifier for <code>getDisplayName()</code> indicating
221.151 + * a long name, such as "Pacific Standard Time."
221.152 + * @see #SHORT
221.153 + * @since 1.2
221.154 + */
221.155 + public static final int LONG = 1;
221.156 +
221.157 + // Constants used internally; unit is milliseconds
221.158 + private static final int ONE_MINUTE = 60*1000;
221.159 + private static final int ONE_HOUR = 60*ONE_MINUTE;
221.160 + private static final int ONE_DAY = 24*ONE_HOUR;
221.161 +
221.162 + // Proclaim serialization compatibility with JDK 1.1
221.163 + static final long serialVersionUID = 3581463369166924961L;
221.164 +
221.165 + /**
221.166 + * Gets the time zone offset, for current date, modified in case of
221.167 + * daylight savings. This is the offset to add to UTC to get local time.
221.168 + * <p>
221.169 + * This method returns a historically correct offset if an
221.170 + * underlying <code>TimeZone</code> implementation subclass
221.171 + * supports historical Daylight Saving Time schedule and GMT
221.172 + * offset changes.
221.173 + *
221.174 + * @param era the era of the given date.
221.175 + * @param year the year in the given date.
221.176 + * @param month the month in the given date.
221.177 + * Month is 0-based. e.g., 0 for January.
221.178 + * @param day the day-in-month of the given date.
221.179 + * @param dayOfWeek the day-of-week of the given date.
221.180 + * @param milliseconds the milliseconds in day in <em>standard</em>
221.181 + * local time.
221.182 + *
221.183 + * @return the offset in milliseconds to add to GMT to get local time.
221.184 + *
221.185 + * @see Calendar#ZONE_OFFSET
221.186 + * @see Calendar#DST_OFFSET
221.187 + */
221.188 + public abstract int getOffset(int era, int year, int month, int day,
221.189 + int dayOfWeek, int milliseconds);
221.190 +
221.191 + /**
221.192 + * Returns the offset of this time zone from UTC at the specified
221.193 + * date. If Daylight Saving Time is in effect at the specified
221.194 + * date, the offset value is adjusted with the amount of daylight
221.195 + * saving.
221.196 + * <p>
221.197 + * This method returns a historically correct offset value if an
221.198 + * underlying TimeZone implementation subclass supports historical
221.199 + * Daylight Saving Time schedule and GMT offset changes.
221.200 + *
221.201 + * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
221.202 + * @return the amount of time in milliseconds to add to UTC to get local time.
221.203 + *
221.204 + * @see Calendar#ZONE_OFFSET
221.205 + * @see Calendar#DST_OFFSET
221.206 + * @since 1.4
221.207 + */
221.208 + public int getOffset(long date) {
221.209 + if (inDaylightTime(new Date(date))) {
221.210 + return getRawOffset() + getDSTSavings();
221.211 + }
221.212 + return getRawOffset();
221.213 + }
221.214 +
221.215 + /**
221.216 + * Gets the raw GMT offset and the amount of daylight saving of this
221.217 + * time zone at the given time.
221.218 + * @param date the milliseconds (since January 1, 1970,
221.219 + * 00:00:00.000 GMT) at which the time zone offset and daylight
221.220 + * saving amount are found
221.221 + * @param offset an array of int where the raw GMT offset
221.222 + * (offset[0]) and daylight saving amount (offset[1]) are stored,
221.223 + * or null if those values are not needed. The method assumes that
221.224 + * the length of the given array is two or larger.
221.225 + * @return the total amount of the raw GMT offset and daylight
221.226 + * saving at the specified date.
221.227 + *
221.228 + * @see Calendar#ZONE_OFFSET
221.229 + * @see Calendar#DST_OFFSET
221.230 + */
221.231 + int getOffsets(long date, int[] offsets) {
221.232 + int rawoffset = getRawOffset();
221.233 + int dstoffset = 0;
221.234 + if (inDaylightTime(new Date(date))) {
221.235 + dstoffset = getDSTSavings();
221.236 + }
221.237 + if (offsets != null) {
221.238 + offsets[0] = rawoffset;
221.239 + offsets[1] = dstoffset;
221.240 + }
221.241 + return rawoffset + dstoffset;
221.242 + }
221.243 +
221.244 + /**
221.245 + * Sets the base time zone offset to GMT.
221.246 + * This is the offset to add to UTC to get local time.
221.247 + * <p>
221.248 + * If an underlying <code>TimeZone</code> implementation subclass
221.249 + * supports historical GMT offset changes, the specified GMT
221.250 + * offset is set as the latest GMT offset and the difference from
221.251 + * the known latest GMT offset value is used to adjust all
221.252 + * historical GMT offset values.
221.253 + *
221.254 + * @param offsetMillis the given base time zone offset to GMT.
221.255 + */
221.256 + abstract public void setRawOffset(int offsetMillis);
221.257 +
221.258 + /**
221.259 + * Returns the amount of time in milliseconds to add to UTC to get
221.260 + * standard time in this time zone. Because this value is not
221.261 + * affected by daylight saving time, it is called <I>raw
221.262 + * offset</I>.
221.263 + * <p>
221.264 + * If an underlying <code>TimeZone</code> implementation subclass
221.265 + * supports historical GMT offset changes, the method returns the
221.266 + * raw offset value of the current date. In Honolulu, for example,
221.267 + * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
221.268 + * this method always returns -36000000 milliseconds (i.e., -10
221.269 + * hours).
221.270 + *
221.271 + * @return the amount of raw offset time in milliseconds to add to UTC.
221.272 + * @see Calendar#ZONE_OFFSET
221.273 + */
221.274 + public abstract int getRawOffset();
221.275 +
221.276 + /**
221.277 + * Gets the ID of this time zone.
221.278 + * @return the ID of this time zone.
221.279 + */
221.280 + public String getID()
221.281 + {
221.282 + return ID;
221.283 + }
221.284 +
221.285 + /**
221.286 + * Sets the time zone ID. This does not change any other data in
221.287 + * the time zone object.
221.288 + * @param ID the new time zone ID.
221.289 + */
221.290 + public void setID(String ID)
221.291 + {
221.292 + if (ID == null) {
221.293 + throw new NullPointerException();
221.294 + }
221.295 + this.ID = ID;
221.296 + }
221.297 +
221.298 + /**
221.299 + * Returns a long standard time name of this {@code TimeZone} suitable for
221.300 + * presentation to the user in the default locale.
221.301 + *
221.302 + * <p>This method is equivalent to:
221.303 + * <pre><blockquote>
221.304 + * getDisplayName(false, {@link #LONG},
221.305 + * Locale.getDefault({@link Locale.Category#DISPLAY}))
221.306 + * </blockquote></pre>
221.307 + *
221.308 + * @return the human-readable name of this time zone in the default locale.
221.309 + * @since 1.2
221.310 + * @see #getDisplayName(boolean, int, Locale)
221.311 + * @see Locale#getDefault(Locale.Category)
221.312 + * @see Locale.Category
221.313 + */
221.314 + public final String getDisplayName() {
221.315 + return getDisplayName(false, LONG,
221.316 + Locale.getDefault(Locale.Category.DISPLAY));
221.317 + }
221.318 +
221.319 + /**
221.320 + * Returns a long standard time name of this {@code TimeZone} suitable for
221.321 + * presentation to the user in the specified {@code locale}.
221.322 + *
221.323 + * <p>This method is equivalent to:
221.324 + * <pre><blockquote>
221.325 + * getDisplayName(false, {@link #LONG}, locale)
221.326 + * </blockquote></pre>
221.327 + *
221.328 + * @param locale the locale in which to supply the display name.
221.329 + * @return the human-readable name of this time zone in the given locale.
221.330 + * @exception NullPointerException if {@code locale} is {@code null}.
221.331 + * @since 1.2
221.332 + * @see #getDisplayName(boolean, int, Locale)
221.333 + */
221.334 + public final String getDisplayName(Locale locale) {
221.335 + return getDisplayName(false, LONG, locale);
221.336 + }
221.337 +
221.338 + /**
221.339 + * Returns a name in the specified {@code style} of this {@code TimeZone}
221.340 + * suitable for presentation to the user in the default locale. If the
221.341 + * specified {@code daylight} is {@code true}, a Daylight Saving Time name
221.342 + * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
221.343 + * Time). Otherwise, a Standard Time name is returned.
221.344 + *
221.345 + * <p>This method is equivalent to:
221.346 + * <pre><blockquote>
221.347 + * getDisplayName(daylight, style,
221.348 + * Locale.getDefault({@link Locale.Category#DISPLAY}))
221.349 + * </blockquote></pre>
221.350 + *
221.351 + * @param daylight {@code true} specifying a Daylight Saving Time name, or
221.352 + * {@code false} specifying a Standard Time name
221.353 + * @param style either {@link #LONG} or {@link #SHORT}
221.354 + * @return the human-readable name of this time zone in the default locale.
221.355 + * @exception IllegalArgumentException if {@code style} is invalid.
221.356 + * @since 1.2
221.357 + * @see #getDisplayName(boolean, int, Locale)
221.358 + * @see Locale#getDefault(Locale.Category)
221.359 + * @see Locale.Category
221.360 + * @see java.text.DateFormatSymbols#getZoneStrings()
221.361 + */
221.362 + public final String getDisplayName(boolean daylight, int style) {
221.363 + return getDisplayName(daylight, style,
221.364 + Locale.getDefault(Locale.Category.DISPLAY));
221.365 + }
221.366 +
221.367 + /**
221.368 + * Returns a name in the specified {@code style} of this {@code TimeZone}
221.369 + * suitable for presentation to the user in the specified {@code
221.370 + * locale}. If the specified {@code daylight} is {@code true}, a Daylight
221.371 + * Saving Time name is returned (even if this {@code TimeZone} doesn't
221.372 + * observe Daylight Saving Time). Otherwise, a Standard Time name is
221.373 + * returned.
221.374 + *
221.375 + * <p>When looking up a time zone name, the {@linkplain
221.376 + * ResourceBundle.Control#getCandidateLocales(String,Locale) default
221.377 + * <code>Locale</code> search path of <code>ResourceBundle</code>} derived
221.378 + * from the specified {@code locale} is used. (No {@linkplain
221.379 + * ResourceBundle.Control#getFallbackLocale(String,Locale) fallback
221.380 + * <code>Locale</code>} search is performed.) If a time zone name in any
221.381 + * {@code Locale} of the search path, including {@link Locale#ROOT}, is
221.382 + * found, the name is returned. Otherwise, a string in the
221.383 + * <a href="#NormalizedCustomID">normalized custom ID format</a> is returned.
221.384 + *
221.385 + * @param daylight {@code true} specifying a Daylight Saving Time name, or
221.386 + * {@code false} specifying a Standard Time name
221.387 + * @param style either {@link #LONG} or {@link #SHORT}
221.388 + * @param locale the locale in which to supply the display name.
221.389 + * @return the human-readable name of this time zone in the given locale.
221.390 + * @exception IllegalArgumentException if {@code style} is invalid.
221.391 + * @exception NullPointerException if {@code locale} is {@code null}.
221.392 + * @since 1.2
221.393 + * @see java.text.DateFormatSymbols#getZoneStrings()
221.394 + */
221.395 + public String getDisplayName(boolean daylight, int style, Locale locale) {
221.396 + if (style != SHORT && style != LONG) {
221.397 + throw new IllegalArgumentException("Illegal style: " + style);
221.398 + }
221.399 +
221.400 + String id = getID();
221.401 + String[] names = getDisplayNames(id, locale);
221.402 + if (names == null) {
221.403 + if (id.startsWith("GMT")) {
221.404 + char sign = id.charAt(3);
221.405 + if (sign == '+' || sign == '-') {
221.406 + return id;
221.407 + }
221.408 + }
221.409 + int offset = getRawOffset();
221.410 + if (daylight) {
221.411 + offset += getDSTSavings();
221.412 + }
221.413 + // return ZoneInfoFile.toCustomID(offset);
221.414 + }
221.415 +
221.416 + int index = daylight ? 3 : 1;
221.417 + if (style == SHORT) {
221.418 + index++;
221.419 + }
221.420 + return names[index];
221.421 + }
221.422 +
221.423 + private static class DisplayNames {
221.424 + // Cache for managing display names per timezone per locale
221.425 + // The structure is:
221.426 + // Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
221.427 + private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
221.428 + new ConcurrentHashMap<String, SoftReference<Map<Locale, String[]>>>();
221.429 + }
221.430 +
221.431 + private static final String[] getDisplayNames(String id, Locale locale) {
221.432 + Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
221.433 +
221.434 + SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
221.435 + if (ref != null) {
221.436 + Map<Locale, String[]> perLocale = ref.get();
221.437 + if (perLocale != null) {
221.438 + String[] names = perLocale.get(locale);
221.439 + if (names != null) {
221.440 + return names;
221.441 + }
221.442 + names = null; // TimeZoneNameUtility.retrieveDisplayNames(id, locale);
221.443 + if (names != null) {
221.444 + perLocale.put(locale, names);
221.445 + }
221.446 + return names;
221.447 + }
221.448 + }
221.449 +
221.450 + String[] names = null; // TimeZoneNameUtility.retrieveDisplayNames(id, locale);
221.451 + if (names != null) {
221.452 + Map<Locale, String[]> perLocale = new ConcurrentHashMap<Locale, String[]>();
221.453 + perLocale.put(locale, names);
221.454 + ref = new SoftReference<Map<Locale, String[]>>(perLocale);
221.455 + displayNames.put(id, ref);
221.456 + }
221.457 + return names;
221.458 + }
221.459 +
221.460 + /**
221.461 + * Returns the amount of time to be added to local standard time
221.462 + * to get local wall clock time.
221.463 + *
221.464 + * <p>The default implementation returns 3600000 milliseconds
221.465 + * (i.e., one hour) if a call to {@link #useDaylightTime()}
221.466 + * returns {@code true}. Otherwise, 0 (zero) is returned.
221.467 + *
221.468 + * <p>If an underlying {@code TimeZone} implementation subclass
221.469 + * supports historical and future Daylight Saving Time schedule
221.470 + * changes, this method returns the amount of saving time of the
221.471 + * last known Daylight Saving Time rule that can be a future
221.472 + * prediction.
221.473 + *
221.474 + * <p>If the amount of saving time at any given time stamp is
221.475 + * required, construct a {@link Calendar} with this {@code
221.476 + * TimeZone} and the time stamp, and call {@link Calendar#get(int)
221.477 + * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
221.478 + *
221.479 + * @return the amount of saving time in milliseconds
221.480 + * @since 1.4
221.481 + * @see #inDaylightTime(Date)
221.482 + * @see #getOffset(long)
221.483 + * @see #getOffset(int,int,int,int,int,int)
221.484 + * @see Calendar#ZONE_OFFSET
221.485 + */
221.486 + public int getDSTSavings() {
221.487 + if (useDaylightTime()) {
221.488 + return 3600000;
221.489 + }
221.490 + return 0;
221.491 + }
221.492 +
221.493 + /**
221.494 + * Queries if this {@code TimeZone} uses Daylight Saving Time.
221.495 + *
221.496 + * <p>If an underlying {@code TimeZone} implementation subclass
221.497 + * supports historical and future Daylight Saving Time schedule
221.498 + * changes, this method refers to the last known Daylight Saving Time
221.499 + * rule that can be a future prediction and may not be the same as
221.500 + * the current rule. Consider calling {@link #observesDaylightTime()}
221.501 + * if the current rule should also be taken into account.
221.502 + *
221.503 + * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
221.504 + * {@code false}, otherwise.
221.505 + * @see #inDaylightTime(Date)
221.506 + * @see Calendar#DST_OFFSET
221.507 + */
221.508 + public abstract boolean useDaylightTime();
221.509 +
221.510 + /**
221.511 + * Returns {@code true} if this {@code TimeZone} is currently in
221.512 + * Daylight Saving Time, or if a transition from Standard Time to
221.513 + * Daylight Saving Time occurs at any future time.
221.514 + *
221.515 + * <p>The default implementation returns {@code true} if
221.516 + * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
221.517 + * returns {@code true}.
221.518 + *
221.519 + * @return {@code true} if this {@code TimeZone} is currently in
221.520 + * Daylight Saving Time, or if a transition from Standard Time to
221.521 + * Daylight Saving Time occurs at any future time; {@code false}
221.522 + * otherwise.
221.523 + * @since 1.7
221.524 + * @see #useDaylightTime()
221.525 + * @see #inDaylightTime(Date)
221.526 + * @see Calendar#DST_OFFSET
221.527 + */
221.528 + public boolean observesDaylightTime() {
221.529 + return useDaylightTime() || inDaylightTime(new Date());
221.530 + }
221.531 +
221.532 + /**
221.533 + * Queries if the given {@code date} is in Daylight Saving Time in
221.534 + * this time zone.
221.535 + *
221.536 + * @param date the given Date.
221.537 + * @return {@code true} if the given date is in Daylight Saving Time,
221.538 + * {@code false}, otherwise.
221.539 + */
221.540 + abstract public boolean inDaylightTime(Date date);
221.541 +
221.542 + /**
221.543 + * Gets the <code>TimeZone</code> for the given ID.
221.544 + *
221.545 + * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
221.546 + * such as "PST", a full name such as "America/Los_Angeles", or a custom
221.547 + * ID such as "GMT-8:00". Note that the support of abbreviations is
221.548 + * for JDK 1.1.x compatibility only and full names should be used.
221.549 + *
221.550 + * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
221.551 + * cannot be understood.
221.552 + */
221.553 + public static synchronized TimeZone getTimeZone(String ID) {
221.554 + return getTimeZone(ID, true);
221.555 + }
221.556 +
221.557 + private static TimeZone getTimeZone(String ID, boolean fallback) {
221.558 +// TimeZone tz = ZoneInfo.getTimeZone(ID);
221.559 +// if (tz == null) {
221.560 +// tz = parseCustomTimeZone(ID);
221.561 +// if (tz == null && fallback) {
221.562 +// tz = new ZoneInfo(GMT_ID, 0);
221.563 +// }
221.564 +// }
221.565 +// return tz;
221.566 + return TimeZone.NO_TIMEZONE;
221.567 + }
221.568 +
221.569 + /**
221.570 + * Gets the available IDs according to the given time zone offset in milliseconds.
221.571 + *
221.572 + * @param rawOffset the given time zone GMT offset in milliseconds.
221.573 + * @return an array of IDs, where the time zone for that ID has
221.574 + * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
221.575 + * both have GMT-07:00, but differ in daylight saving behavior.
221.576 + * @see #getRawOffset()
221.577 + */
221.578 + public static synchronized String[] getAvailableIDs(int rawOffset) {
221.579 + return new String[0];//ZoneInfo.getAvailableIDs(rawOffset);
221.580 + }
221.581 +
221.582 + /**
221.583 + * Gets all the available IDs supported.
221.584 + * @return an array of IDs.
221.585 + */
221.586 + public static synchronized String[] getAvailableIDs() {
221.587 + return new String[0];//return ZoneInfo.getAvailableIDs();
221.588 + }
221.589 +
221.590 + /**
221.591 + * Gets the platform defined TimeZone ID.
221.592 + **/
221.593 + private static native String getSystemTimeZoneID(String javaHome,
221.594 + String country);
221.595 +
221.596 + /**
221.597 + * Gets the custom time zone ID based on the GMT offset of the
221.598 + * platform. (e.g., "GMT+08:00")
221.599 + */
221.600 + private static native String getSystemGMTOffsetID();
221.601 +
221.602 + /**
221.603 + * Gets the default <code>TimeZone</code> for this host.
221.604 + * The source of the default <code>TimeZone</code>
221.605 + * may vary with implementation.
221.606 + * @return a default <code>TimeZone</code>.
221.607 + * @see #setDefault
221.608 + */
221.609 + public static TimeZone getDefault() {
221.610 + return (TimeZone) getDefaultRef().clone();
221.611 + }
221.612 +
221.613 + /**
221.614 + * Returns the reference to the default TimeZone object. This
221.615 + * method doesn't create a clone.
221.616 + */
221.617 + static TimeZone getDefaultRef() {
221.618 + TimeZone defaultZone = null;//defaultZoneTL.get();
221.619 + if (defaultZone == null) {
221.620 + defaultZone = defaultTimeZone;
221.621 + if (defaultZone == null) {
221.622 + // Need to initialize the default time zone.
221.623 + defaultZone = TimeZone.NO_TIMEZONE;
221.624 + assert defaultZone != null;
221.625 + }
221.626 + }
221.627 + // Don't clone here.
221.628 + return defaultZone;
221.629 + }
221.630 +
221.631 + private static boolean hasPermission() {
221.632 + boolean hasPermission = false;
221.633 + return hasPermission;
221.634 + }
221.635 +
221.636 + /**
221.637 + * Sets the <code>TimeZone</code> that is
221.638 + * returned by the <code>getDefault</code> method. If <code>zone</code>
221.639 + * is null, reset the default to the value it had originally when the
221.640 + * VM first started.
221.641 + * @param zone the new default time zone
221.642 + * @see #getDefault
221.643 + */
221.644 + public static void setDefault(TimeZone zone)
221.645 + {
221.646 + if (hasPermission()) {
221.647 + synchronized (TimeZone.class) {
221.648 + defaultTimeZone = zone;
221.649 + // defaultZoneTL.set(null);
221.650 + }
221.651 + } else {
221.652 + //defaultZoneTL.set(zone);
221.653 + }
221.654 + }
221.655 +
221.656 + /**
221.657 + * Returns true if this zone has the same rule and offset as another zone.
221.658 + * That is, if this zone differs only in ID, if at all. Returns false
221.659 + * if the other zone is null.
221.660 + * @param other the <code>TimeZone</code> object to be compared with
221.661 + * @return true if the other zone is not null and is the same as this one,
221.662 + * with the possible exception of the ID
221.663 + * @since 1.2
221.664 + */
221.665 + public boolean hasSameRules(TimeZone other) {
221.666 + return other != null && getRawOffset() == other.getRawOffset() &&
221.667 + useDaylightTime() == other.useDaylightTime();
221.668 + }
221.669 +
221.670 + /**
221.671 + * Creates a copy of this <code>TimeZone</code>.
221.672 + *
221.673 + * @return a clone of this <code>TimeZone</code>
221.674 + */
221.675 + public Object clone()
221.676 + {
221.677 + try {
221.678 + TimeZone other = (TimeZone) super.clone();
221.679 + other.ID = ID;
221.680 + return other;
221.681 + } catch (CloneNotSupportedException e) {
221.682 + throw new InternalError();
221.683 + }
221.684 + }
221.685 +
221.686 + /**
221.687 + * The null constant as a TimeZone.
221.688 + */
221.689 + static final TimeZone NO_TIMEZONE = null;
221.690 +
221.691 + // =======================privates===============================
221.692 +
221.693 + /**
221.694 + * The string identifier of this <code>TimeZone</code>. This is a
221.695 + * programmatic identifier used internally to look up <code>TimeZone</code>
221.696 + * objects from the system table and also to map them to their localized
221.697 + * display names. <code>ID</code> values are unique in the system
221.698 + * table but may not be for dynamically created zones.
221.699 + * @serial
221.700 + */
221.701 + private String ID;
221.702 + private static volatile TimeZone defaultTimeZone;
221.703 +
221.704 + static final String GMT_ID = "GMT";
221.705 + private static final int GMT_ID_LENGTH = 3;
221.706 +
221.707 + /**
221.708 + * Parses a custom time zone identifier and returns a corresponding zone.
221.709 + * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
221.710 + *
221.711 + * @param id a string of the <a href="#CustomID">custom ID form</a>.
221.712 + * @return a newly created TimeZone with the given offset and
221.713 + * no daylight saving time, or null if the id cannot be parsed.
221.714 + */
221.715 + private static final TimeZone parseCustomTimeZone(String id) {
221.716 + return null;
221.717 + }
221.718 +}
222.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
222.2 +++ b/rt/emul/compact/src/main/java/java/util/Timer.java Wed Apr 30 15:04:10 2014 +0200
222.3 @@ -0,0 +1,731 @@
222.4 +/*
222.5 + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
222.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
222.7 + *
222.8 + * This code is free software; you can redistribute it and/or modify it
222.9 + * under the terms of the GNU General Public License version 2 only, as
222.10 + * published by the Free Software Foundation. Oracle designates this
222.11 + * particular file as subject to the "Classpath" exception as provided
222.12 + * by Oracle in the LICENSE file that accompanied this code.
222.13 + *
222.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
222.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
222.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
222.17 + * version 2 for more details (a copy is included in the LICENSE file that
222.18 + * accompanied this code).
222.19 + *
222.20 + * You should have received a copy of the GNU General Public License version
222.21 + * 2 along with this work; if not, write to the Free Software Foundation,
222.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
222.23 + *
222.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
222.25 + * or visit www.oracle.com if you need additional information or have any
222.26 + * questions.
222.27 + */
222.28 +
222.29 +package java.util;
222.30 +import java.util.Date;
222.31 +import java.util.concurrent.atomic.AtomicInteger;
222.32 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
222.33 +
222.34 +/**
222.35 + * A facility for threads to schedule tasks for future execution in a
222.36 + * background thread. Tasks may be scheduled for one-time execution, or for
222.37 + * repeated execution at regular intervals.
222.38 + *
222.39 + * <p>Corresponding to each <tt>Timer</tt> object is a single background
222.40 + * thread that is used to execute all of the timer's tasks, sequentially.
222.41 + * Timer tasks should complete quickly. If a timer task takes excessive time
222.42 + * to complete, it "hogs" the timer's task execution thread. This can, in
222.43 + * turn, delay the execution of subsequent tasks, which may "bunch up" and
222.44 + * execute in rapid succession when (and if) the offending task finally
222.45 + * completes.
222.46 + *
222.47 + * <p>After the last live reference to a <tt>Timer</tt> object goes away
222.48 + * <i>and</i> all outstanding tasks have completed execution, the timer's task
222.49 + * execution thread terminates gracefully (and becomes subject to garbage
222.50 + * collection). However, this can take arbitrarily long to occur. By
222.51 + * default, the task execution thread does not run as a <i>daemon thread</i>,
222.52 + * so it is capable of keeping an application from terminating. If a caller
222.53 + * wants to terminate a timer's task execution thread rapidly, the caller
222.54 + * should invoke the timer's <tt>cancel</tt> method.
222.55 + *
222.56 + * <p>If the timer's task execution thread terminates unexpectedly, for
222.57 + * example, because its <tt>stop</tt> method is invoked, any further
222.58 + * attempt to schedule a task on the timer will result in an
222.59 + * <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
222.60 + * method had been invoked.
222.61 + *
222.62 + * <p>This class is thread-safe: multiple threads can share a single
222.63 + * <tt>Timer</tt> object without the need for external synchronization.
222.64 + *
222.65 + * <p>This class does <i>not</i> offer real-time guarantees: it schedules
222.66 + * tasks using the <tt>Object.wait(long)</tt> method.
222.67 + *
222.68 + * <p>Java 5.0 introduced the {@code java.util.concurrent} package and
222.69 + * one of the concurrency utilities therein is the {@link
222.70 + * java.util.concurrent.ScheduledThreadPoolExecutor
222.71 + * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
222.72 + * executing tasks at a given rate or delay. It is effectively a more
222.73 + * versatile replacement for the {@code Timer}/{@code TimerTask}
222.74 + * combination, as it allows multiple service threads, accepts various
222.75 + * time units, and doesn't require subclassing {@code TimerTask} (just
222.76 + * implement {@code Runnable}). Configuring {@code
222.77 + * ScheduledThreadPoolExecutor} with one thread makes it equivalent to
222.78 + * {@code Timer}.
222.79 + *
222.80 + * <p>Implementation note: This class scales to large numbers of concurrently
222.81 + * scheduled tasks (thousands should present no problem). Internally,
222.82 + * it uses a binary heap to represent its task queue, so the cost to schedule
222.83 + * a task is O(log n), where n is the number of concurrently scheduled tasks.
222.84 + *
222.85 + * <p>Implementation note: All constructors start a timer thread.
222.86 + *
222.87 + * @author Josh Bloch
222.88 + * @see TimerTask
222.89 + * @see Object#wait(long)
222.90 + * @since 1.3
222.91 + */
222.92 +
222.93 +public class Timer {
222.94 + /**
222.95 + * The timer task queue. This data structure is shared with the timer
222.96 + * thread. The timer produces tasks, via its various schedule calls,
222.97 + * and the timer thread consumes, executing timer tasks as appropriate,
222.98 + * and removing them from the queue when they're obsolete.
222.99 + */
222.100 + private final TaskQueue queue = new TaskQueue();
222.101 +
222.102 + /**
222.103 + * The timer thread.
222.104 + */
222.105 + private final TimerThread thread = new TimerThread(queue);
222.106 +
222.107 + /**
222.108 + * This object causes the timer's task execution thread to exit
222.109 + * gracefully when there are no live references to the Timer object and no
222.110 + * tasks in the timer queue. It is used in preference to a finalizer on
222.111 + * Timer as such a finalizer would be susceptible to a subclass's
222.112 + * finalizer forgetting to call it.
222.113 + */
222.114 + private final Object threadReaper = new Object() {
222.115 + protected void finalize() throws Throwable {
222.116 + synchronized(queue) {
222.117 + thread.newTasksMayBeScheduled = false;
222.118 + thread.notifyQueue(1); // In case queue is empty.
222.119 + }
222.120 + }
222.121 + };
222.122 +
222.123 + /**
222.124 + * This ID is used to generate thread names.
222.125 + */
222.126 + private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
222.127 + private static int serialNumber() {
222.128 + return nextSerialNumber.getAndIncrement();
222.129 + }
222.130 +
222.131 + /**
222.132 + * Creates a new timer. The associated thread does <i>not</i>
222.133 + * {@linkplain Thread#setDaemon run as a daemon}.
222.134 + */
222.135 + public Timer() {
222.136 + this("Timer-" + serialNumber());
222.137 + }
222.138 +
222.139 + /**
222.140 + * Creates a new timer whose associated thread may be specified to
222.141 + * {@linkplain Thread#setDaemon run as a daemon}.
222.142 + * A daemon thread is called for if the timer will be used to
222.143 + * schedule repeating "maintenance activities", which must be
222.144 + * performed as long as the application is running, but should not
222.145 + * prolong the lifetime of the application.
222.146 + *
222.147 + * @param isDaemon true if the associated thread should run as a daemon.
222.148 + */
222.149 + public Timer(boolean isDaemon) {
222.150 + this("Timer-" + serialNumber(), isDaemon);
222.151 + }
222.152 +
222.153 + /**
222.154 + * Creates a new timer whose associated thread has the specified name.
222.155 + * The associated thread does <i>not</i>
222.156 + * {@linkplain Thread#setDaemon run as a daemon}.
222.157 + *
222.158 + * @param name the name of the associated thread
222.159 + * @throws NullPointerException if {@code name} is null
222.160 + * @since 1.5
222.161 + */
222.162 + public Timer(String name) {
222.163 + }
222.164 +
222.165 + /**
222.166 + * Creates a new timer whose associated thread has the specified name,
222.167 + * and may be specified to
222.168 + * {@linkplain Thread#setDaemon run as a daemon}.
222.169 + *
222.170 + * @param name the name of the associated thread
222.171 + * @param isDaemon true if the associated thread should run as a daemon
222.172 + * @throws NullPointerException if {@code name} is null
222.173 + * @since 1.5
222.174 + */
222.175 + public Timer(String name, boolean isDaemon) {
222.176 + }
222.177 +
222.178 + /**
222.179 + * Schedules the specified task for execution after the specified delay.
222.180 + *
222.181 + * @param task task to be scheduled.
222.182 + * @param delay delay in milliseconds before task is to be executed.
222.183 + * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
222.184 + * <tt>delay + System.currentTimeMillis()</tt> is negative.
222.185 + * @throws IllegalStateException if task was already scheduled or
222.186 + * cancelled, timer was cancelled, or timer thread terminated.
222.187 + * @throws NullPointerException if {@code task} is null
222.188 + */
222.189 + public void schedule(TimerTask task, long delay) {
222.190 + if (delay < 0)
222.191 + throw new IllegalArgumentException("Negative delay.");
222.192 + sched(task, System.currentTimeMillis()+delay, 0);
222.193 + }
222.194 +
222.195 + /**
222.196 + * Schedules the specified task for execution at the specified time. If
222.197 + * the time is in the past, the task is scheduled for immediate execution.
222.198 + *
222.199 + * @param task task to be scheduled.
222.200 + * @param time time at which task is to be executed.
222.201 + * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
222.202 + * @throws IllegalStateException if task was already scheduled or
222.203 + * cancelled, timer was cancelled, or timer thread terminated.
222.204 + * @throws NullPointerException if {@code task} or {@code time} is null
222.205 + */
222.206 + public void schedule(TimerTask task, Date time) {
222.207 + sched(task, time.getTime(), 0);
222.208 + }
222.209 +
222.210 + /**
222.211 + * Schedules the specified task for repeated <i>fixed-delay execution</i>,
222.212 + * beginning after the specified delay. Subsequent executions take place
222.213 + * at approximately regular intervals separated by the specified period.
222.214 + *
222.215 + * <p>In fixed-delay execution, each execution is scheduled relative to
222.216 + * the actual execution time of the previous execution. If an execution
222.217 + * is delayed for any reason (such as garbage collection or other
222.218 + * background activity), subsequent executions will be delayed as well.
222.219 + * In the long run, the frequency of execution will generally be slightly
222.220 + * lower than the reciprocal of the specified period (assuming the system
222.221 + * clock underlying <tt>Object.wait(long)</tt> is accurate).
222.222 + *
222.223 + * <p>Fixed-delay execution is appropriate for recurring activities
222.224 + * that require "smoothness." In other words, it is appropriate for
222.225 + * activities where it is more important to keep the frequency accurate
222.226 + * in the short run than in the long run. This includes most animation
222.227 + * tasks, such as blinking a cursor at regular intervals. It also includes
222.228 + * tasks wherein regular activity is performed in response to human
222.229 + * input, such as automatically repeating a character as long as a key
222.230 + * is held down.
222.231 + *
222.232 + * @param task task to be scheduled.
222.233 + * @param delay delay in milliseconds before task is to be executed.
222.234 + * @param period time in milliseconds between successive task executions.
222.235 + * @throws IllegalArgumentException if {@code delay < 0}, or
222.236 + * {@code delay + System.currentTimeMillis() < 0}, or
222.237 + * {@code period <= 0}
222.238 + * @throws IllegalStateException if task was already scheduled or
222.239 + * cancelled, timer was cancelled, or timer thread terminated.
222.240 + * @throws NullPointerException if {@code task} is null
222.241 + */
222.242 + public void schedule(TimerTask task, long delay, long period) {
222.243 + if (delay < 0)
222.244 + throw new IllegalArgumentException("Negative delay.");
222.245 + if (period <= 0)
222.246 + throw new IllegalArgumentException("Non-positive period.");
222.247 + sched(task, System.currentTimeMillis()+delay, -period);
222.248 + }
222.249 +
222.250 + /**
222.251 + * Schedules the specified task for repeated <i>fixed-delay execution</i>,
222.252 + * beginning at the specified time. Subsequent executions take place at
222.253 + * approximately regular intervals, separated by the specified period.
222.254 + *
222.255 + * <p>In fixed-delay execution, each execution is scheduled relative to
222.256 + * the actual execution time of the previous execution. If an execution
222.257 + * is delayed for any reason (such as garbage collection or other
222.258 + * background activity), subsequent executions will be delayed as well.
222.259 + * In the long run, the frequency of execution will generally be slightly
222.260 + * lower than the reciprocal of the specified period (assuming the system
222.261 + * clock underlying <tt>Object.wait(long)</tt> is accurate). As a
222.262 + * consequence of the above, if the scheduled first time is in the past,
222.263 + * it is scheduled for immediate execution.
222.264 + *
222.265 + * <p>Fixed-delay execution is appropriate for recurring activities
222.266 + * that require "smoothness." In other words, it is appropriate for
222.267 + * activities where it is more important to keep the frequency accurate
222.268 + * in the short run than in the long run. This includes most animation
222.269 + * tasks, such as blinking a cursor at regular intervals. It also includes
222.270 + * tasks wherein regular activity is performed in response to human
222.271 + * input, such as automatically repeating a character as long as a key
222.272 + * is held down.
222.273 + *
222.274 + * @param task task to be scheduled.
222.275 + * @param firstTime First time at which task is to be executed.
222.276 + * @param period time in milliseconds between successive task executions.
222.277 + * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or
222.278 + * {@code period <= 0}
222.279 + * @throws IllegalStateException if task was already scheduled or
222.280 + * cancelled, timer was cancelled, or timer thread terminated.
222.281 + * @throws NullPointerException if {@code task} or {@code firstTime} is null
222.282 + */
222.283 + public void schedule(TimerTask task, Date firstTime, long period) {
222.284 + if (period <= 0)
222.285 + throw new IllegalArgumentException("Non-positive period.");
222.286 + sched(task, firstTime.getTime(), -period);
222.287 + }
222.288 +
222.289 + /**
222.290 + * Schedules the specified task for repeated <i>fixed-rate execution</i>,
222.291 + * beginning after the specified delay. Subsequent executions take place
222.292 + * at approximately regular intervals, separated by the specified period.
222.293 + *
222.294 + * <p>In fixed-rate execution, each execution is scheduled relative to the
222.295 + * scheduled execution time of the initial execution. If an execution is
222.296 + * delayed for any reason (such as garbage collection or other background
222.297 + * activity), two or more executions will occur in rapid succession to
222.298 + * "catch up." In the long run, the frequency of execution will be
222.299 + * exactly the reciprocal of the specified period (assuming the system
222.300 + * clock underlying <tt>Object.wait(long)</tt> is accurate).
222.301 + *
222.302 + * <p>Fixed-rate execution is appropriate for recurring activities that
222.303 + * are sensitive to <i>absolute</i> time, such as ringing a chime every
222.304 + * hour on the hour, or running scheduled maintenance every day at a
222.305 + * particular time. It is also appropriate for recurring activities
222.306 + * where the total time to perform a fixed number of executions is
222.307 + * important, such as a countdown timer that ticks once every second for
222.308 + * ten seconds. Finally, fixed-rate execution is appropriate for
222.309 + * scheduling multiple repeating timer tasks that must remain synchronized
222.310 + * with respect to one another.
222.311 + *
222.312 + * @param task task to be scheduled.
222.313 + * @param delay delay in milliseconds before task is to be executed.
222.314 + * @param period time in milliseconds between successive task executions.
222.315 + * @throws IllegalArgumentException if {@code delay < 0}, or
222.316 + * {@code delay + System.currentTimeMillis() < 0}, or
222.317 + * {@code period <= 0}
222.318 + * @throws IllegalStateException if task was already scheduled or
222.319 + * cancelled, timer was cancelled, or timer thread terminated.
222.320 + * @throws NullPointerException if {@code task} is null
222.321 + */
222.322 + public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
222.323 + if (delay < 0)
222.324 + throw new IllegalArgumentException("Negative delay.");
222.325 + if (period <= 0)
222.326 + throw new IllegalArgumentException("Non-positive period.");
222.327 + sched(task, System.currentTimeMillis()+delay, period);
222.328 + }
222.329 +
222.330 + /**
222.331 + * Schedules the specified task for repeated <i>fixed-rate execution</i>,
222.332 + * beginning at the specified time. Subsequent executions take place at
222.333 + * approximately regular intervals, separated by the specified period.
222.334 + *
222.335 + * <p>In fixed-rate execution, each execution is scheduled relative to the
222.336 + * scheduled execution time of the initial execution. If an execution is
222.337 + * delayed for any reason (such as garbage collection or other background
222.338 + * activity), two or more executions will occur in rapid succession to
222.339 + * "catch up." In the long run, the frequency of execution will be
222.340 + * exactly the reciprocal of the specified period (assuming the system
222.341 + * clock underlying <tt>Object.wait(long)</tt> is accurate). As a
222.342 + * consequence of the above, if the scheduled first time is in the past,
222.343 + * then any "missed" executions will be scheduled for immediate "catch up"
222.344 + * execution.
222.345 + *
222.346 + * <p>Fixed-rate execution is appropriate for recurring activities that
222.347 + * are sensitive to <i>absolute</i> time, such as ringing a chime every
222.348 + * hour on the hour, or running scheduled maintenance every day at a
222.349 + * particular time. It is also appropriate for recurring activities
222.350 + * where the total time to perform a fixed number of executions is
222.351 + * important, such as a countdown timer that ticks once every second for
222.352 + * ten seconds. Finally, fixed-rate execution is appropriate for
222.353 + * scheduling multiple repeating timer tasks that must remain synchronized
222.354 + * with respect to one another.
222.355 + *
222.356 + * @param task task to be scheduled.
222.357 + * @param firstTime First time at which task is to be executed.
222.358 + * @param period time in milliseconds between successive task executions.
222.359 + * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or
222.360 + * {@code period <= 0}
222.361 + * @throws IllegalStateException if task was already scheduled or
222.362 + * cancelled, timer was cancelled, or timer thread terminated.
222.363 + * @throws NullPointerException if {@code task} or {@code firstTime} is null
222.364 + */
222.365 + public void scheduleAtFixedRate(TimerTask task, Date firstTime,
222.366 + long period) {
222.367 + if (period <= 0)
222.368 + throw new IllegalArgumentException("Non-positive period.");
222.369 + sched(task, firstTime.getTime(), period);
222.370 + }
222.371 +
222.372 + /**
222.373 + * Schedule the specified timer task for execution at the specified
222.374 + * time with the specified period, in milliseconds. If period is
222.375 + * positive, the task is scheduled for repeated execution; if period is
222.376 + * zero, the task is scheduled for one-time execution. Time is specified
222.377 + * in Date.getTime() format. This method checks timer state, task state,
222.378 + * and initial execution time, but not period.
222.379 + *
222.380 + * @throws IllegalArgumentException if <tt>time</tt> is negative.
222.381 + * @throws IllegalStateException if task was already scheduled or
222.382 + * cancelled, timer was cancelled, or timer thread terminated.
222.383 + * @throws NullPointerException if {@code task} is null
222.384 + */
222.385 + private void sched(TimerTask task, long time, long period) {
222.386 + if (time < 0)
222.387 + throw new IllegalArgumentException("Illegal execution time.");
222.388 +
222.389 + // Constrain value of period sufficiently to prevent numeric
222.390 + // overflow while still being effectively infinitely large.
222.391 + if (Math.abs(period) > (Long.MAX_VALUE >> 1))
222.392 + period >>= 1;
222.393 +
222.394 + synchronized(queue) {
222.395 + if (!thread.newTasksMayBeScheduled)
222.396 + throw new IllegalStateException("Timer already cancelled.");
222.397 +
222.398 + synchronized(task.lock) {
222.399 + if (task.state != TimerTask.VIRGIN)
222.400 + throw new IllegalStateException(
222.401 + "Task already scheduled or cancelled");
222.402 + task.nextExecutionTime = time;
222.403 + task.period = period;
222.404 + task.state = TimerTask.SCHEDULED;
222.405 + }
222.406 +
222.407 + queue.add(task);
222.408 + if (queue.getMin() == task)
222.409 + thread.notifyQueue(1);
222.410 + }
222.411 + }
222.412 +
222.413 + /**
222.414 + * Terminates this timer, discarding any currently scheduled tasks.
222.415 + * Does not interfere with a currently executing task (if it exists).
222.416 + * Once a timer has been terminated, its execution thread terminates
222.417 + * gracefully, and no more tasks may be scheduled on it.
222.418 + *
222.419 + * <p>Note that calling this method from within the run method of a
222.420 + * timer task that was invoked by this timer absolutely guarantees that
222.421 + * the ongoing task execution is the last task execution that will ever
222.422 + * be performed by this timer.
222.423 + *
222.424 + * <p>This method may be called repeatedly; the second and subsequent
222.425 + * calls have no effect.
222.426 + */
222.427 + public void cancel() {
222.428 + synchronized(queue) {
222.429 + thread.newTasksMayBeScheduled = false;
222.430 + queue.clear();
222.431 + thread.notifyQueue(1); // In case queue was already empty.
222.432 + }
222.433 + }
222.434 +
222.435 + /**
222.436 + * Removes all cancelled tasks from this timer's task queue. <i>Calling
222.437 + * this method has no effect on the behavior of the timer</i>, but
222.438 + * eliminates the references to the cancelled tasks from the queue.
222.439 + * If there are no external references to these tasks, they become
222.440 + * eligible for garbage collection.
222.441 + *
222.442 + * <p>Most programs will have no need to call this method.
222.443 + * It is designed for use by the rare application that cancels a large
222.444 + * number of tasks. Calling this method trades time for space: the
222.445 + * runtime of the method may be proportional to n + c log n, where n
222.446 + * is the number of tasks in the queue and c is the number of cancelled
222.447 + * tasks.
222.448 + *
222.449 + * <p>Note that it is permissible to call this method from within a
222.450 + * a task scheduled on this timer.
222.451 + *
222.452 + * @return the number of tasks removed from the queue.
222.453 + * @since 1.5
222.454 + */
222.455 + public int purge() {
222.456 + int result = 0;
222.457 +
222.458 + synchronized(queue) {
222.459 + for (int i = queue.size(); i > 0; i--) {
222.460 + if (queue.get(i).state == TimerTask.CANCELLED) {
222.461 + queue.quickRemove(i);
222.462 + result++;
222.463 + }
222.464 + }
222.465 +
222.466 + if (result != 0)
222.467 + queue.heapify();
222.468 + }
222.469 +
222.470 + return result;
222.471 + }
222.472 +}
222.473 +
222.474 +/**
222.475 + * This "helper class" implements the timer's task execution thread, which
222.476 + * waits for tasks on the timer queue, executions them when they fire,
222.477 + * reschedules repeating tasks, and removes cancelled tasks and spent
222.478 + * non-repeating tasks from the queue.
222.479 + */
222.480 +class TimerThread implements Runnable {
222.481 + /**
222.482 + * This flag is set to false by the reaper to inform us that there
222.483 + * are no more live references to our Timer object. Once this flag
222.484 + * is true and there are no more tasks in our queue, there is no
222.485 + * work left for us to do, so we terminate gracefully. Note that
222.486 + * this field is protected by queue's monitor!
222.487 + */
222.488 + boolean newTasksMayBeScheduled = true;
222.489 +
222.490 + /**
222.491 + * Our Timer's queue. We store this reference in preference to
222.492 + * a reference to the Timer so the reference graph remains acyclic.
222.493 + * Otherwise, the Timer would never be garbage-collected and this
222.494 + * thread would never go away.
222.495 + */
222.496 + private TaskQueue queue;
222.497 +
222.498 + TimerThread(TaskQueue queue) {
222.499 + this.queue = queue;
222.500 + }
222.501 +
222.502 + void notifyQueue(int delay) {
222.503 + if (delay < 1) {
222.504 + delay = 1;
222.505 + }
222.506 + setTimeout(delay, this);
222.507 + }
222.508 +
222.509 + @JavaScriptBody(args = { "delay", "r" }, body = "window.setTimeout(function() { r.run__V(); }, delay);")
222.510 + private static native void setTimeout(int delay, Runnable r);
222.511 +
222.512 + public void run() {
222.513 + mainLoop(1);
222.514 +// try {
222.515 +// mainLoop(0);
222.516 +// } finally {
222.517 +// // Someone killed this Thread, behave as if Timer cancelled
222.518 +// synchronized(queue) {
222.519 +// newTasksMayBeScheduled = false;
222.520 +// queue.clear(); // Eliminate obsolete references
222.521 +// }
222.522 +// }
222.523 + }
222.524 +
222.525 + /**
222.526 + * The main timer loop. (See class comment.)
222.527 + */
222.528 + private void mainLoop(int inc) {
222.529 + for (int i = 0; i < 1; i += inc) {
222.530 + try {
222.531 + TimerTask task;
222.532 + boolean taskFired;
222.533 + synchronized(queue) {
222.534 + // Wait for queue to become non-empty
222.535 + while (queue.isEmpty() && newTasksMayBeScheduled)
222.536 + break;
222.537 + if (queue.isEmpty())
222.538 + break; // Queue is empty and will forever remain; die
222.539 +
222.540 + // Queue nonempty; look at first evt and do the right thing
222.541 + long currentTime, executionTime;
222.542 + task = queue.getMin();
222.543 + synchronized(task.lock) {
222.544 + if (task.state == TimerTask.CANCELLED) {
222.545 + queue.removeMin();
222.546 + continue; // No action required, poll queue again
222.547 + }
222.548 + currentTime = System.currentTimeMillis();
222.549 + executionTime = task.nextExecutionTime;
222.550 + if (taskFired = (executionTime<=currentTime)) {
222.551 + if (task.period == 0) { // Non-repeating, remove
222.552 + queue.removeMin();
222.553 + task.state = TimerTask.EXECUTED;
222.554 + } else { // Repeating task, reschedule
222.555 + queue.rescheduleMin(
222.556 + task.period<0 ? currentTime - task.period
222.557 + : executionTime + task.period);
222.558 + }
222.559 + }
222.560 + }
222.561 + if (!taskFired) {
222.562 + // Task hasn't yet fired; wait
222.563 + notifyQueue((int)(executionTime - currentTime));
222.564 + return;
222.565 + }
222.566 + }
222.567 + if (taskFired) // Task fired; run it, holding no locks
222.568 + task.run();
222.569 + } catch(Exception e) {
222.570 + e.printStackTrace();
222.571 + }
222.572 + }
222.573 + }
222.574 +}
222.575 +
222.576 +/**
222.577 + * This class represents a timer task queue: a priority queue of TimerTasks,
222.578 + * ordered on nextExecutionTime. Each Timer object has one of these, which it
222.579 + * shares with its TimerThread. Internally this class uses a heap, which
222.580 + * offers log(n) performance for the add, removeMin and rescheduleMin
222.581 + * operations, and constant time performance for the getMin operation.
222.582 + */
222.583 +class TaskQueue {
222.584 + /**
222.585 + * Priority queue represented as a balanced binary heap: the two children
222.586 + * of queue[n] are queue[2*n] and queue[2*n+1]. The priority queue is
222.587 + * ordered on the nextExecutionTime field: The TimerTask with the lowest
222.588 + * nextExecutionTime is in queue[1] (assuming the queue is nonempty). For
222.589 + * each node n in the heap, and each descendant of n, d,
222.590 + * n.nextExecutionTime <= d.nextExecutionTime.
222.591 + */
222.592 + private TimerTask[] queue = new TimerTask[128];
222.593 +
222.594 + /**
222.595 + * The number of tasks in the priority queue. (The tasks are stored in
222.596 + * queue[1] up to queue[size]).
222.597 + */
222.598 + private int size = 0;
222.599 +
222.600 + /**
222.601 + * Returns the number of tasks currently on the queue.
222.602 + */
222.603 + int size() {
222.604 + return size;
222.605 + }
222.606 +
222.607 + /**
222.608 + * Adds a new task to the priority queue.
222.609 + */
222.610 + void add(TimerTask task) {
222.611 + // Grow backing store if necessary
222.612 + if (size + 1 == queue.length)
222.613 + queue = Arrays.copyOf(queue, 2*queue.length);
222.614 +
222.615 + queue[++size] = task;
222.616 + fixUp(size);
222.617 + }
222.618 +
222.619 + /**
222.620 + * Return the "head task" of the priority queue. (The head task is an
222.621 + * task with the lowest nextExecutionTime.)
222.622 + */
222.623 + TimerTask getMin() {
222.624 + return queue[1];
222.625 + }
222.626 +
222.627 + /**
222.628 + * Return the ith task in the priority queue, where i ranges from 1 (the
222.629 + * head task, which is returned by getMin) to the number of tasks on the
222.630 + * queue, inclusive.
222.631 + */
222.632 + TimerTask get(int i) {
222.633 + return queue[i];
222.634 + }
222.635 +
222.636 + /**
222.637 + * Remove the head task from the priority queue.
222.638 + */
222.639 + void removeMin() {
222.640 + queue[1] = queue[size];
222.641 + queue[size--] = null; // Drop extra reference to prevent memory leak
222.642 + fixDown(1);
222.643 + }
222.644 +
222.645 + /**
222.646 + * Removes the ith element from queue without regard for maintaining
222.647 + * the heap invariant. Recall that queue is one-based, so
222.648 + * 1 <= i <= size.
222.649 + */
222.650 + void quickRemove(int i) {
222.651 + assert i <= size;
222.652 +
222.653 + queue[i] = queue[size];
222.654 + queue[size--] = null; // Drop extra ref to prevent memory leak
222.655 + }
222.656 +
222.657 + /**
222.658 + * Sets the nextExecutionTime associated with the head task to the
222.659 + * specified value, and adjusts priority queue accordingly.
222.660 + */
222.661 + void rescheduleMin(long newTime) {
222.662 + queue[1].nextExecutionTime = newTime;
222.663 + fixDown(1);
222.664 + }
222.665 +
222.666 + /**
222.667 + * Returns true if the priority queue contains no elements.
222.668 + */
222.669 + boolean isEmpty() {
222.670 + return size==0;
222.671 + }
222.672 +
222.673 + /**
222.674 + * Removes all elements from the priority queue.
222.675 + */
222.676 + void clear() {
222.677 + // Null out task references to prevent memory leak
222.678 + for (int i=1; i<=size; i++)
222.679 + queue[i] = null;
222.680 +
222.681 + size = 0;
222.682 + }
222.683 +
222.684 + /**
222.685 + * Establishes the heap invariant (described above) assuming the heap
222.686 + * satisfies the invariant except possibly for the leaf-node indexed by k
222.687 + * (which may have a nextExecutionTime less than its parent's).
222.688 + *
222.689 + * This method functions by "promoting" queue[k] up the hierarchy
222.690 + * (by swapping it with its parent) repeatedly until queue[k]'s
222.691 + * nextExecutionTime is greater than or equal to that of its parent.
222.692 + */
222.693 + private void fixUp(int k) {
222.694 + while (k > 1) {
222.695 + int j = k >> 1;
222.696 + if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
222.697 + break;
222.698 + TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
222.699 + k = j;
222.700 + }
222.701 + }
222.702 +
222.703 + /**
222.704 + * Establishes the heap invariant (described above) in the subtree
222.705 + * rooted at k, which is assumed to satisfy the heap invariant except
222.706 + * possibly for node k itself (which may have a nextExecutionTime greater
222.707 + * than its children's).
222.708 + *
222.709 + * This method functions by "demoting" queue[k] down the hierarchy
222.710 + * (by swapping it with its smaller child) repeatedly until queue[k]'s
222.711 + * nextExecutionTime is less than or equal to those of its children.
222.712 + */
222.713 + private void fixDown(int k) {
222.714 + int j;
222.715 + while ((j = k << 1) <= size && j > 0) {
222.716 + if (j < size &&
222.717 + queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
222.718 + j++; // j indexes smallest kid
222.719 + if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
222.720 + break;
222.721 + TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
222.722 + k = j;
222.723 + }
222.724 + }
222.725 +
222.726 + /**
222.727 + * Establishes the heap invariant (described above) in the entire tree,
222.728 + * assuming nothing about the order of the elements prior to the call.
222.729 + */
222.730 + void heapify() {
222.731 + for (int i = size/2; i >= 1; i--)
222.732 + fixDown(i);
222.733 + }
222.734 +}
223.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
223.2 +++ b/rt/emul/compact/src/main/java/java/util/TimerTask.java Wed Apr 30 15:04:10 2014 +0200
223.3 @@ -0,0 +1,158 @@
223.4 +/*
223.5 + * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
223.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
223.7 + *
223.8 + * This code is free software; you can redistribute it and/or modify it
223.9 + * under the terms of the GNU General Public License version 2 only, as
223.10 + * published by the Free Software Foundation. Oracle designates this
223.11 + * particular file as subject to the "Classpath" exception as provided
223.12 + * by Oracle in the LICENSE file that accompanied this code.
223.13 + *
223.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
223.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
223.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
223.17 + * version 2 for more details (a copy is included in the LICENSE file that
223.18 + * accompanied this code).
223.19 + *
223.20 + * You should have received a copy of the GNU General Public License version
223.21 + * 2 along with this work; if not, write to the Free Software Foundation,
223.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
223.23 + *
223.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
223.25 + * or visit www.oracle.com if you need additional information or have any
223.26 + * questions.
223.27 + */
223.28 +
223.29 +package java.util;
223.30 +
223.31 +/**
223.32 + * A task that can be scheduled for one-time or repeated execution by a Timer.
223.33 + *
223.34 + * @author Josh Bloch
223.35 + * @see Timer
223.36 + * @since 1.3
223.37 + */
223.38 +
223.39 +public abstract class TimerTask implements Runnable {
223.40 + /**
223.41 + * This object is used to control access to the TimerTask internals.
223.42 + */
223.43 + final Object lock = new Object();
223.44 +
223.45 + /**
223.46 + * The state of this task, chosen from the constants below.
223.47 + */
223.48 + int state = VIRGIN;
223.49 +
223.50 + /**
223.51 + * This task has not yet been scheduled.
223.52 + */
223.53 + static final int VIRGIN = 0;
223.54 +
223.55 + /**
223.56 + * This task is scheduled for execution. If it is a non-repeating task,
223.57 + * it has not yet been executed.
223.58 + */
223.59 + static final int SCHEDULED = 1;
223.60 +
223.61 + /**
223.62 + * This non-repeating task has already executed (or is currently
223.63 + * executing) and has not been cancelled.
223.64 + */
223.65 + static final int EXECUTED = 2;
223.66 +
223.67 + /**
223.68 + * This task has been cancelled (with a call to TimerTask.cancel).
223.69 + */
223.70 + static final int CANCELLED = 3;
223.71 +
223.72 + /**
223.73 + * Next execution time for this task in the format returned by
223.74 + * System.currentTimeMillis, assuming this task is scheduled for execution.
223.75 + * For repeating tasks, this field is updated prior to each task execution.
223.76 + */
223.77 + long nextExecutionTime;
223.78 +
223.79 + /**
223.80 + * Period in milliseconds for repeating tasks. A positive value indicates
223.81 + * fixed-rate execution. A negative value indicates fixed-delay execution.
223.82 + * A value of 0 indicates a non-repeating task.
223.83 + */
223.84 + long period = 0;
223.85 +
223.86 + /**
223.87 + * Creates a new timer task.
223.88 + */
223.89 + protected TimerTask() {
223.90 + }
223.91 +
223.92 + /**
223.93 + * The action to be performed by this timer task.
223.94 + */
223.95 + public abstract void run();
223.96 +
223.97 + /**
223.98 + * Cancels this timer task. If the task has been scheduled for one-time
223.99 + * execution and has not yet run, or has not yet been scheduled, it will
223.100 + * never run. If the task has been scheduled for repeated execution, it
223.101 + * will never run again. (If the task is running when this call occurs,
223.102 + * the task will run to completion, but will never run again.)
223.103 + *
223.104 + * <p>Note that calling this method from within the <tt>run</tt> method of
223.105 + * a repeating timer task absolutely guarantees that the timer task will
223.106 + * not run again.
223.107 + *
223.108 + * <p>This method may be called repeatedly; the second and subsequent
223.109 + * calls have no effect.
223.110 + *
223.111 + * @return true if this task is scheduled for one-time execution and has
223.112 + * not yet run, or this task is scheduled for repeated execution.
223.113 + * Returns false if the task was scheduled for one-time execution
223.114 + * and has already run, or if the task was never scheduled, or if
223.115 + * the task was already cancelled. (Loosely speaking, this method
223.116 + * returns <tt>true</tt> if it prevents one or more scheduled
223.117 + * executions from taking place.)
223.118 + */
223.119 + public boolean cancel() {
223.120 + synchronized(lock) {
223.121 + boolean result = (state == SCHEDULED);
223.122 + state = CANCELLED;
223.123 + return result;
223.124 + }
223.125 + }
223.126 +
223.127 + /**
223.128 + * Returns the <i>scheduled</i> execution time of the most recent
223.129 + * <i>actual</i> execution of this task. (If this method is invoked
223.130 + * while task execution is in progress, the return value is the scheduled
223.131 + * execution time of the ongoing task execution.)
223.132 + *
223.133 + * <p>This method is typically invoked from within a task's run method, to
223.134 + * determine whether the current execution of the task is sufficiently
223.135 + * timely to warrant performing the scheduled activity:
223.136 + * <pre>
223.137 + * public void run() {
223.138 + * if (System.currentTimeMillis() - scheduledExecutionTime() >=
223.139 + * MAX_TARDINESS)
223.140 + * return; // Too late; skip this execution.
223.141 + * // Perform the task
223.142 + * }
223.143 + * </pre>
223.144 + * This method is typically <i>not</i> used in conjunction with
223.145 + * <i>fixed-delay execution</i> repeating tasks, as their scheduled
223.146 + * execution times are allowed to drift over time, and so are not terribly
223.147 + * significant.
223.148 + *
223.149 + * @return the time at which the most recent execution of this task was
223.150 + * scheduled to occur, in the format returned by Date.getTime().
223.151 + * The return value is undefined if the task has yet to commence
223.152 + * its first execution.
223.153 + * @see Date#getTime()
223.154 + */
223.155 + public long scheduledExecutionTime() {
223.156 + synchronized(lock) {
223.157 + return (period < 0 ? nextExecutionTime + period
223.158 + : nextExecutionTime - period);
223.159 + }
223.160 + }
223.161 +}
224.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
224.2 +++ b/rt/emul/compact/src/main/java/java/util/TreeMap.java Wed Apr 30 15:04:10 2014 +0200
224.3 @@ -0,0 +1,2442 @@
224.4 +/*
224.5 + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
224.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
224.7 + *
224.8 + * This code is free software; you can redistribute it and/or modify it
224.9 + * under the terms of the GNU General Public License version 2 only, as
224.10 + * published by the Free Software Foundation. Oracle designates this
224.11 + * particular file as subject to the "Classpath" exception as provided
224.12 + * by Oracle in the LICENSE file that accompanied this code.
224.13 + *
224.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
224.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
224.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
224.17 + * version 2 for more details (a copy is included in the LICENSE file that
224.18 + * accompanied this code).
224.19 + *
224.20 + * You should have received a copy of the GNU General Public License version
224.21 + * 2 along with this work; if not, write to the Free Software Foundation,
224.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
224.23 + *
224.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
224.25 + * or visit www.oracle.com if you need additional information or have any
224.26 + * questions.
224.27 + */
224.28 +
224.29 +package java.util;
224.30 +
224.31 +/**
224.32 + * A Red-Black tree based {@link NavigableMap} implementation.
224.33 + * The map is sorted according to the {@linkplain Comparable natural
224.34 + * ordering} of its keys, or by a {@link Comparator} provided at map
224.35 + * creation time, depending on which constructor is used.
224.36 + *
224.37 + * <p>This implementation provides guaranteed log(n) time cost for the
224.38 + * {@code containsKey}, {@code get}, {@code put} and {@code remove}
224.39 + * operations. Algorithms are adaptations of those in Cormen, Leiserson, and
224.40 + * Rivest's <em>Introduction to Algorithms</em>.
224.41 + *
224.42 + * <p>Note that the ordering maintained by a tree map, like any sorted map, and
224.43 + * whether or not an explicit comparator is provided, must be <em>consistent
224.44 + * with {@code equals}</em> if this sorted map is to correctly implement the
224.45 + * {@code Map} interface. (See {@code Comparable} or {@code Comparator} for a
224.46 + * precise definition of <em>consistent with equals</em>.) This is so because
224.47 + * the {@code Map} interface is defined in terms of the {@code equals}
224.48 + * operation, but a sorted map performs all key comparisons using its {@code
224.49 + * compareTo} (or {@code compare}) method, so two keys that are deemed equal by
224.50 + * this method are, from the standpoint of the sorted map, equal. The behavior
224.51 + * of a sorted map <em>is</em> well-defined even if its ordering is
224.52 + * inconsistent with {@code equals}; it just fails to obey the general contract
224.53 + * of the {@code Map} interface.
224.54 + *
224.55 + * <p><strong>Note that this implementation is not synchronized.</strong>
224.56 + * If multiple threads access a map concurrently, and at least one of the
224.57 + * threads modifies the map structurally, it <em>must</em> be synchronized
224.58 + * externally. (A structural modification is any operation that adds or
224.59 + * deletes one or more mappings; merely changing the value associated
224.60 + * with an existing key is not a structural modification.) This is
224.61 + * typically accomplished by synchronizing on some object that naturally
224.62 + * encapsulates the map.
224.63 + * If no such object exists, the map should be "wrapped" using the
224.64 + * {@link Collections#synchronizedSortedMap Collections.synchronizedSortedMap}
224.65 + * method. This is best done at creation time, to prevent accidental
224.66 + * unsynchronized access to the map: <pre>
224.67 + * SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));</pre>
224.68 + *
224.69 + * <p>The iterators returned by the {@code iterator} method of the collections
224.70 + * returned by all of this class's "collection view methods" are
224.71 + * <em>fail-fast</em>: if the map is structurally modified at any time after
224.72 + * the iterator is created, in any way except through the iterator's own
224.73 + * {@code remove} method, the iterator will throw a {@link
224.74 + * ConcurrentModificationException}. Thus, in the face of concurrent
224.75 + * modification, the iterator fails quickly and cleanly, rather than risking
224.76 + * arbitrary, non-deterministic behavior at an undetermined time in the future.
224.77 + *
224.78 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
224.79 + * as it is, generally speaking, impossible to make any hard guarantees in the
224.80 + * presence of unsynchronized concurrent modification. Fail-fast iterators
224.81 + * throw {@code ConcurrentModificationException} on a best-effort basis.
224.82 + * Therefore, it would be wrong to write a program that depended on this
224.83 + * exception for its correctness: <em>the fail-fast behavior of iterators
224.84 + * should be used only to detect bugs.</em>
224.85 + *
224.86 + * <p>All {@code Map.Entry} pairs returned by methods in this class
224.87 + * and its views represent snapshots of mappings at the time they were
224.88 + * produced. They do <strong>not</strong> support the {@code Entry.setValue}
224.89 + * method. (Note however that it is possible to change mappings in the
224.90 + * associated map using {@code put}.)
224.91 + *
224.92 + * <p>This class is a member of the
224.93 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
224.94 + * Java Collections Framework</a>.
224.95 + *
224.96 + * @param <K> the type of keys maintained by this map
224.97 + * @param <V> the type of mapped values
224.98 + *
224.99 + * @author Josh Bloch and Doug Lea
224.100 + * @see Map
224.101 + * @see HashMap
224.102 + * @see Hashtable
224.103 + * @see Comparable
224.104 + * @see Comparator
224.105 + * @see Collection
224.106 + * @since 1.2
224.107 + */
224.108 +
224.109 +public class TreeMap<K,V>
224.110 + extends AbstractMap<K,V>
224.111 + implements NavigableMap<K,V>, Cloneable, java.io.Serializable
224.112 +{
224.113 + /**
224.114 + * The comparator used to maintain order in this tree map, or
224.115 + * null if it uses the natural ordering of its keys.
224.116 + *
224.117 + * @serial
224.118 + */
224.119 + private final Comparator<? super K> comparator;
224.120 +
224.121 + private transient Entry<K,V> root = null;
224.122 +
224.123 + /**
224.124 + * The number of entries in the tree
224.125 + */
224.126 + private transient int size = 0;
224.127 +
224.128 + /**
224.129 + * The number of structural modifications to the tree.
224.130 + */
224.131 + private transient int modCount = 0;
224.132 +
224.133 + /**
224.134 + * Constructs a new, empty tree map, using the natural ordering of its
224.135 + * keys. All keys inserted into the map must implement the {@link
224.136 + * Comparable} interface. Furthermore, all such keys must be
224.137 + * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
224.138 + * a {@code ClassCastException} for any keys {@code k1} and
224.139 + * {@code k2} in the map. If the user attempts to put a key into the
224.140 + * map that violates this constraint (for example, the user attempts to
224.141 + * put a string key into a map whose keys are integers), the
224.142 + * {@code put(Object key, Object value)} call will throw a
224.143 + * {@code ClassCastException}.
224.144 + */
224.145 + public TreeMap() {
224.146 + comparator = null;
224.147 + }
224.148 +
224.149 + /**
224.150 + * Constructs a new, empty tree map, ordered according to the given
224.151 + * comparator. All keys inserted into the map must be <em>mutually
224.152 + * comparable</em> by the given comparator: {@code comparator.compare(k1,
224.153 + * k2)} must not throw a {@code ClassCastException} for any keys
224.154 + * {@code k1} and {@code k2} in the map. If the user attempts to put
224.155 + * a key into the map that violates this constraint, the {@code put(Object
224.156 + * key, Object value)} call will throw a
224.157 + * {@code ClassCastException}.
224.158 + *
224.159 + * @param comparator the comparator that will be used to order this map.
224.160 + * If {@code null}, the {@linkplain Comparable natural
224.161 + * ordering} of the keys will be used.
224.162 + */
224.163 + public TreeMap(Comparator<? super K> comparator) {
224.164 + this.comparator = comparator;
224.165 + }
224.166 +
224.167 + /**
224.168 + * Constructs a new tree map containing the same mappings as the given
224.169 + * map, ordered according to the <em>natural ordering</em> of its keys.
224.170 + * All keys inserted into the new map must implement the {@link
224.171 + * Comparable} interface. Furthermore, all such keys must be
224.172 + * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
224.173 + * a {@code ClassCastException} for any keys {@code k1} and
224.174 + * {@code k2} in the map. This method runs in n*log(n) time.
224.175 + *
224.176 + * @param m the map whose mappings are to be placed in this map
224.177 + * @throws ClassCastException if the keys in m are not {@link Comparable},
224.178 + * or are not mutually comparable
224.179 + * @throws NullPointerException if the specified map is null
224.180 + */
224.181 + public TreeMap(Map<? extends K, ? extends V> m) {
224.182 + comparator = null;
224.183 + putAll(m);
224.184 + }
224.185 +
224.186 + /**
224.187 + * Constructs a new tree map containing the same mappings and
224.188 + * using the same ordering as the specified sorted map. This
224.189 + * method runs in linear time.
224.190 + *
224.191 + * @param m the sorted map whose mappings are to be placed in this map,
224.192 + * and whose comparator is to be used to sort this map
224.193 + * @throws NullPointerException if the specified map is null
224.194 + */
224.195 + public TreeMap(SortedMap<K, ? extends V> m) {
224.196 + comparator = m.comparator();
224.197 + try {
224.198 + buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
224.199 + } catch (java.io.IOException cannotHappen) {
224.200 + } catch (ClassNotFoundException cannotHappen) {
224.201 + }
224.202 + }
224.203 +
224.204 +
224.205 + // Query Operations
224.206 +
224.207 + /**
224.208 + * Returns the number of key-value mappings in this map.
224.209 + *
224.210 + * @return the number of key-value mappings in this map
224.211 + */
224.212 + public int size() {
224.213 + return size;
224.214 + }
224.215 +
224.216 + /**
224.217 + * Returns {@code true} if this map contains a mapping for the specified
224.218 + * key.
224.219 + *
224.220 + * @param key key whose presence in this map is to be tested
224.221 + * @return {@code true} if this map contains a mapping for the
224.222 + * specified key
224.223 + * @throws ClassCastException if the specified key cannot be compared
224.224 + * with the keys currently in the map
224.225 + * @throws NullPointerException if the specified key is null
224.226 + * and this map uses natural ordering, or its comparator
224.227 + * does not permit null keys
224.228 + */
224.229 + public boolean containsKey(Object key) {
224.230 + return getEntry(key) != null;
224.231 + }
224.232 +
224.233 + /**
224.234 + * Returns {@code true} if this map maps one or more keys to the
224.235 + * specified value. More formally, returns {@code true} if and only if
224.236 + * this map contains at least one mapping to a value {@code v} such
224.237 + * that {@code (value==null ? v==null : value.equals(v))}. This
224.238 + * operation will probably require time linear in the map size for
224.239 + * most implementations.
224.240 + *
224.241 + * @param value value whose presence in this map is to be tested
224.242 + * @return {@code true} if a mapping to {@code value} exists;
224.243 + * {@code false} otherwise
224.244 + * @since 1.2
224.245 + */
224.246 + public boolean containsValue(Object value) {
224.247 + for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e))
224.248 + if (valEquals(value, e.value))
224.249 + return true;
224.250 + return false;
224.251 + }
224.252 +
224.253 + /**
224.254 + * Returns the value to which the specified key is mapped,
224.255 + * or {@code null} if this map contains no mapping for the key.
224.256 + *
224.257 + * <p>More formally, if this map contains a mapping from a key
224.258 + * {@code k} to a value {@code v} such that {@code key} compares
224.259 + * equal to {@code k} according to the map's ordering, then this
224.260 + * method returns {@code v}; otherwise it returns {@code null}.
224.261 + * (There can be at most one such mapping.)
224.262 + *
224.263 + * <p>A return value of {@code null} does not <em>necessarily</em>
224.264 + * indicate that the map contains no mapping for the key; it's also
224.265 + * possible that the map explicitly maps the key to {@code null}.
224.266 + * The {@link #containsKey containsKey} operation may be used to
224.267 + * distinguish these two cases.
224.268 + *
224.269 + * @throws ClassCastException if the specified key cannot be compared
224.270 + * with the keys currently in the map
224.271 + * @throws NullPointerException if the specified key is null
224.272 + * and this map uses natural ordering, or its comparator
224.273 + * does not permit null keys
224.274 + */
224.275 + public V get(Object key) {
224.276 + Entry<K,V> p = getEntry(key);
224.277 + return (p==null ? null : p.value);
224.278 + }
224.279 +
224.280 + public Comparator<? super K> comparator() {
224.281 + return comparator;
224.282 + }
224.283 +
224.284 + /**
224.285 + * @throws NoSuchElementException {@inheritDoc}
224.286 + */
224.287 + public K firstKey() {
224.288 + return key(getFirstEntry());
224.289 + }
224.290 +
224.291 + /**
224.292 + * @throws NoSuchElementException {@inheritDoc}
224.293 + */
224.294 + public K lastKey() {
224.295 + return key(getLastEntry());
224.296 + }
224.297 +
224.298 + /**
224.299 + * Copies all of the mappings from the specified map to this map.
224.300 + * These mappings replace any mappings that this map had for any
224.301 + * of the keys currently in the specified map.
224.302 + *
224.303 + * @param map mappings to be stored in this map
224.304 + * @throws ClassCastException if the class of a key or value in
224.305 + * the specified map prevents it from being stored in this map
224.306 + * @throws NullPointerException if the specified map is null or
224.307 + * the specified map contains a null key and this map does not
224.308 + * permit null keys
224.309 + */
224.310 + public void putAll(Map<? extends K, ? extends V> map) {
224.311 + int mapSize = map.size();
224.312 + if (size==0 && mapSize!=0 && map instanceof SortedMap) {
224.313 + Comparator c = ((SortedMap)map).comparator();
224.314 + if (c == comparator || (c != null && c.equals(comparator))) {
224.315 + ++modCount;
224.316 + try {
224.317 + buildFromSorted(mapSize, map.entrySet().iterator(),
224.318 + null, null);
224.319 + } catch (java.io.IOException cannotHappen) {
224.320 + } catch (ClassNotFoundException cannotHappen) {
224.321 + }
224.322 + return;
224.323 + }
224.324 + }
224.325 + super.putAll(map);
224.326 + }
224.327 +
224.328 + /**
224.329 + * Returns this map's entry for the given key, or {@code null} if the map
224.330 + * does not contain an entry for the key.
224.331 + *
224.332 + * @return this map's entry for the given key, or {@code null} if the map
224.333 + * does not contain an entry for the key
224.334 + * @throws ClassCastException if the specified key cannot be compared
224.335 + * with the keys currently in the map
224.336 + * @throws NullPointerException if the specified key is null
224.337 + * and this map uses natural ordering, or its comparator
224.338 + * does not permit null keys
224.339 + */
224.340 + final Entry<K,V> getEntry(Object key) {
224.341 + // Offload comparator-based version for sake of performance
224.342 + if (comparator != null)
224.343 + return getEntryUsingComparator(key);
224.344 + if (key == null)
224.345 + throw new NullPointerException();
224.346 + Comparable<? super K> k = (Comparable<? super K>) key;
224.347 + Entry<K,V> p = root;
224.348 + while (p != null) {
224.349 + int cmp = k.compareTo(p.key);
224.350 + if (cmp < 0)
224.351 + p = p.left;
224.352 + else if (cmp > 0)
224.353 + p = p.right;
224.354 + else
224.355 + return p;
224.356 + }
224.357 + return null;
224.358 + }
224.359 +
224.360 + /**
224.361 + * Version of getEntry using comparator. Split off from getEntry
224.362 + * for performance. (This is not worth doing for most methods,
224.363 + * that are less dependent on comparator performance, but is
224.364 + * worthwhile here.)
224.365 + */
224.366 + final Entry<K,V> getEntryUsingComparator(Object key) {
224.367 + K k = (K) key;
224.368 + Comparator<? super K> cpr = comparator;
224.369 + if (cpr != null) {
224.370 + Entry<K,V> p = root;
224.371 + while (p != null) {
224.372 + int cmp = cpr.compare(k, p.key);
224.373 + if (cmp < 0)
224.374 + p = p.left;
224.375 + else if (cmp > 0)
224.376 + p = p.right;
224.377 + else
224.378 + return p;
224.379 + }
224.380 + }
224.381 + return null;
224.382 + }
224.383 +
224.384 + /**
224.385 + * Gets the entry corresponding to the specified key; if no such entry
224.386 + * exists, returns the entry for the least key greater than the specified
224.387 + * key; if no such entry exists (i.e., the greatest key in the Tree is less
224.388 + * than the specified key), returns {@code null}.
224.389 + */
224.390 + final Entry<K,V> getCeilingEntry(K key) {
224.391 + Entry<K,V> p = root;
224.392 + while (p != null) {
224.393 + int cmp = compare(key, p.key);
224.394 + if (cmp < 0) {
224.395 + if (p.left != null)
224.396 + p = p.left;
224.397 + else
224.398 + return p;
224.399 + } else if (cmp > 0) {
224.400 + if (p.right != null) {
224.401 + p = p.right;
224.402 + } else {
224.403 + Entry<K,V> parent = p.parent;
224.404 + Entry<K,V> ch = p;
224.405 + while (parent != null && ch == parent.right) {
224.406 + ch = parent;
224.407 + parent = parent.parent;
224.408 + }
224.409 + return parent;
224.410 + }
224.411 + } else
224.412 + return p;
224.413 + }
224.414 + return null;
224.415 + }
224.416 +
224.417 + /**
224.418 + * Gets the entry corresponding to the specified key; if no such entry
224.419 + * exists, returns the entry for the greatest key less than the specified
224.420 + * key; if no such entry exists, returns {@code null}.
224.421 + */
224.422 + final Entry<K,V> getFloorEntry(K key) {
224.423 + Entry<K,V> p = root;
224.424 + while (p != null) {
224.425 + int cmp = compare(key, p.key);
224.426 + if (cmp > 0) {
224.427 + if (p.right != null)
224.428 + p = p.right;
224.429 + else
224.430 + return p;
224.431 + } else if (cmp < 0) {
224.432 + if (p.left != null) {
224.433 + p = p.left;
224.434 + } else {
224.435 + Entry<K,V> parent = p.parent;
224.436 + Entry<K,V> ch = p;
224.437 + while (parent != null && ch == parent.left) {
224.438 + ch = parent;
224.439 + parent = parent.parent;
224.440 + }
224.441 + return parent;
224.442 + }
224.443 + } else
224.444 + return p;
224.445 +
224.446 + }
224.447 + return null;
224.448 + }
224.449 +
224.450 + /**
224.451 + * Gets the entry for the least key greater than the specified
224.452 + * key; if no such entry exists, returns the entry for the least
224.453 + * key greater than the specified key; if no such entry exists
224.454 + * returns {@code null}.
224.455 + */
224.456 + final Entry<K,V> getHigherEntry(K key) {
224.457 + Entry<K,V> p = root;
224.458 + while (p != null) {
224.459 + int cmp = compare(key, p.key);
224.460 + if (cmp < 0) {
224.461 + if (p.left != null)
224.462 + p = p.left;
224.463 + else
224.464 + return p;
224.465 + } else {
224.466 + if (p.right != null) {
224.467 + p = p.right;
224.468 + } else {
224.469 + Entry<K,V> parent = p.parent;
224.470 + Entry<K,V> ch = p;
224.471 + while (parent != null && ch == parent.right) {
224.472 + ch = parent;
224.473 + parent = parent.parent;
224.474 + }
224.475 + return parent;
224.476 + }
224.477 + }
224.478 + }
224.479 + return null;
224.480 + }
224.481 +
224.482 + /**
224.483 + * Returns the entry for the greatest key less than the specified key; if
224.484 + * no such entry exists (i.e., the least key in the Tree is greater than
224.485 + * the specified key), returns {@code null}.
224.486 + */
224.487 + final Entry<K,V> getLowerEntry(K key) {
224.488 + Entry<K,V> p = root;
224.489 + while (p != null) {
224.490 + int cmp = compare(key, p.key);
224.491 + if (cmp > 0) {
224.492 + if (p.right != null)
224.493 + p = p.right;
224.494 + else
224.495 + return p;
224.496 + } else {
224.497 + if (p.left != null) {
224.498 + p = p.left;
224.499 + } else {
224.500 + Entry<K,V> parent = p.parent;
224.501 + Entry<K,V> ch = p;
224.502 + while (parent != null && ch == parent.left) {
224.503 + ch = parent;
224.504 + parent = parent.parent;
224.505 + }
224.506 + return parent;
224.507 + }
224.508 + }
224.509 + }
224.510 + return null;
224.511 + }
224.512 +
224.513 + /**
224.514 + * Associates the specified value with the specified key in this map.
224.515 + * If the map previously contained a mapping for the key, the old
224.516 + * value is replaced.
224.517 + *
224.518 + * @param key key with which the specified value is to be associated
224.519 + * @param value value to be associated with the specified key
224.520 + *
224.521 + * @return the previous value associated with {@code key}, or
224.522 + * {@code null} if there was no mapping for {@code key}.
224.523 + * (A {@code null} return can also indicate that the map
224.524 + * previously associated {@code null} with {@code key}.)
224.525 + * @throws ClassCastException if the specified key cannot be compared
224.526 + * with the keys currently in the map
224.527 + * @throws NullPointerException if the specified key is null
224.528 + * and this map uses natural ordering, or its comparator
224.529 + * does not permit null keys
224.530 + */
224.531 + public V put(K key, V value) {
224.532 + Entry<K,V> t = root;
224.533 + if (t == null) {
224.534 + compare(key, key); // type (and possibly null) check
224.535 +
224.536 + root = new Entry<>(key, value, null);
224.537 + size = 1;
224.538 + modCount++;
224.539 + return null;
224.540 + }
224.541 + int cmp;
224.542 + Entry<K,V> parent;
224.543 + // split comparator and comparable paths
224.544 + Comparator<? super K> cpr = comparator;
224.545 + if (cpr != null) {
224.546 + do {
224.547 + parent = t;
224.548 + cmp = cpr.compare(key, t.key);
224.549 + if (cmp < 0)
224.550 + t = t.left;
224.551 + else if (cmp > 0)
224.552 + t = t.right;
224.553 + else
224.554 + return t.setValue(value);
224.555 + } while (t != null);
224.556 + }
224.557 + else {
224.558 + if (key == null)
224.559 + throw new NullPointerException();
224.560 + Comparable<? super K> k = (Comparable<? super K>) key;
224.561 + do {
224.562 + parent = t;
224.563 + cmp = k.compareTo(t.key);
224.564 + if (cmp < 0)
224.565 + t = t.left;
224.566 + else if (cmp > 0)
224.567 + t = t.right;
224.568 + else
224.569 + return t.setValue(value);
224.570 + } while (t != null);
224.571 + }
224.572 + Entry<K,V> e = new Entry<>(key, value, parent);
224.573 + if (cmp < 0)
224.574 + parent.left = e;
224.575 + else
224.576 + parent.right = e;
224.577 + fixAfterInsertion(e);
224.578 + size++;
224.579 + modCount++;
224.580 + return null;
224.581 + }
224.582 +
224.583 + /**
224.584 + * Removes the mapping for this key from this TreeMap if present.
224.585 + *
224.586 + * @param key key for which mapping should be removed
224.587 + * @return the previous value associated with {@code key}, or
224.588 + * {@code null} if there was no mapping for {@code key}.
224.589 + * (A {@code null} return can also indicate that the map
224.590 + * previously associated {@code null} with {@code key}.)
224.591 + * @throws ClassCastException if the specified key cannot be compared
224.592 + * with the keys currently in the map
224.593 + * @throws NullPointerException if the specified key is null
224.594 + * and this map uses natural ordering, or its comparator
224.595 + * does not permit null keys
224.596 + */
224.597 + public V remove(Object key) {
224.598 + Entry<K,V> p = getEntry(key);
224.599 + if (p == null)
224.600 + return null;
224.601 +
224.602 + V oldValue = p.value;
224.603 + deleteEntry(p);
224.604 + return oldValue;
224.605 + }
224.606 +
224.607 + /**
224.608 + * Removes all of the mappings from this map.
224.609 + * The map will be empty after this call returns.
224.610 + */
224.611 + public void clear() {
224.612 + modCount++;
224.613 + size = 0;
224.614 + root = null;
224.615 + }
224.616 +
224.617 + /**
224.618 + * Returns a shallow copy of this {@code TreeMap} instance. (The keys and
224.619 + * values themselves are not cloned.)
224.620 + *
224.621 + * @return a shallow copy of this map
224.622 + */
224.623 + public Object clone() {
224.624 + TreeMap<K,V> clone = null;
224.625 + try {
224.626 + clone = (TreeMap<K,V>) super.clone();
224.627 + } catch (CloneNotSupportedException e) {
224.628 + throw new InternalError();
224.629 + }
224.630 +
224.631 + // Put clone into "virgin" state (except for comparator)
224.632 + clone.root = null;
224.633 + clone.size = 0;
224.634 + clone.modCount = 0;
224.635 + clone.entrySet = null;
224.636 + clone.navigableKeySet = null;
224.637 + clone.descendingMap = null;
224.638 +
224.639 + // Initialize clone with our mappings
224.640 + try {
224.641 + clone.buildFromSorted(size, entrySet().iterator(), null, null);
224.642 + } catch (java.io.IOException cannotHappen) {
224.643 + } catch (ClassNotFoundException cannotHappen) {
224.644 + }
224.645 +
224.646 + return clone;
224.647 + }
224.648 +
224.649 + // NavigableMap API methods
224.650 +
224.651 + /**
224.652 + * @since 1.6
224.653 + */
224.654 + public Map.Entry<K,V> firstEntry() {
224.655 + return exportEntry(getFirstEntry());
224.656 + }
224.657 +
224.658 + /**
224.659 + * @since 1.6
224.660 + */
224.661 + public Map.Entry<K,V> lastEntry() {
224.662 + return exportEntry(getLastEntry());
224.663 + }
224.664 +
224.665 + /**
224.666 + * @since 1.6
224.667 + */
224.668 + public Map.Entry<K,V> pollFirstEntry() {
224.669 + Entry<K,V> p = getFirstEntry();
224.670 + Map.Entry<K,V> result = exportEntry(p);
224.671 + if (p != null)
224.672 + deleteEntry(p);
224.673 + return result;
224.674 + }
224.675 +
224.676 + /**
224.677 + * @since 1.6
224.678 + */
224.679 + public Map.Entry<K,V> pollLastEntry() {
224.680 + Entry<K,V> p = getLastEntry();
224.681 + Map.Entry<K,V> result = exportEntry(p);
224.682 + if (p != null)
224.683 + deleteEntry(p);
224.684 + return result;
224.685 + }
224.686 +
224.687 + /**
224.688 + * @throws ClassCastException {@inheritDoc}
224.689 + * @throws NullPointerException if the specified key is null
224.690 + * and this map uses natural ordering, or its comparator
224.691 + * does not permit null keys
224.692 + * @since 1.6
224.693 + */
224.694 + public Map.Entry<K,V> lowerEntry(K key) {
224.695 + return exportEntry(getLowerEntry(key));
224.696 + }
224.697 +
224.698 + /**
224.699 + * @throws ClassCastException {@inheritDoc}
224.700 + * @throws NullPointerException if the specified key is null
224.701 + * and this map uses natural ordering, or its comparator
224.702 + * does not permit null keys
224.703 + * @since 1.6
224.704 + */
224.705 + public K lowerKey(K key) {
224.706 + return keyOrNull(getLowerEntry(key));
224.707 + }
224.708 +
224.709 + /**
224.710 + * @throws ClassCastException {@inheritDoc}
224.711 + * @throws NullPointerException if the specified key is null
224.712 + * and this map uses natural ordering, or its comparator
224.713 + * does not permit null keys
224.714 + * @since 1.6
224.715 + */
224.716 + public Map.Entry<K,V> floorEntry(K key) {
224.717 + return exportEntry(getFloorEntry(key));
224.718 + }
224.719 +
224.720 + /**
224.721 + * @throws ClassCastException {@inheritDoc}
224.722 + * @throws NullPointerException if the specified key is null
224.723 + * and this map uses natural ordering, or its comparator
224.724 + * does not permit null keys
224.725 + * @since 1.6
224.726 + */
224.727 + public K floorKey(K key) {
224.728 + return keyOrNull(getFloorEntry(key));
224.729 + }
224.730 +
224.731 + /**
224.732 + * @throws ClassCastException {@inheritDoc}
224.733 + * @throws NullPointerException if the specified key is null
224.734 + * and this map uses natural ordering, or its comparator
224.735 + * does not permit null keys
224.736 + * @since 1.6
224.737 + */
224.738 + public Map.Entry<K,V> ceilingEntry(K key) {
224.739 + return exportEntry(getCeilingEntry(key));
224.740 + }
224.741 +
224.742 + /**
224.743 + * @throws ClassCastException {@inheritDoc}
224.744 + * @throws NullPointerException if the specified key is null
224.745 + * and this map uses natural ordering, or its comparator
224.746 + * does not permit null keys
224.747 + * @since 1.6
224.748 + */
224.749 + public K ceilingKey(K key) {
224.750 + return keyOrNull(getCeilingEntry(key));
224.751 + }
224.752 +
224.753 + /**
224.754 + * @throws ClassCastException {@inheritDoc}
224.755 + * @throws NullPointerException if the specified key is null
224.756 + * and this map uses natural ordering, or its comparator
224.757 + * does not permit null keys
224.758 + * @since 1.6
224.759 + */
224.760 + public Map.Entry<K,V> higherEntry(K key) {
224.761 + return exportEntry(getHigherEntry(key));
224.762 + }
224.763 +
224.764 + /**
224.765 + * @throws ClassCastException {@inheritDoc}
224.766 + * @throws NullPointerException if the specified key is null
224.767 + * and this map uses natural ordering, or its comparator
224.768 + * does not permit null keys
224.769 + * @since 1.6
224.770 + */
224.771 + public K higherKey(K key) {
224.772 + return keyOrNull(getHigherEntry(key));
224.773 + }
224.774 +
224.775 + // Views
224.776 +
224.777 + /**
224.778 + * Fields initialized to contain an instance of the entry set view
224.779 + * the first time this view is requested. Views are stateless, so
224.780 + * there's no reason to create more than one.
224.781 + */
224.782 + private transient EntrySet entrySet = null;
224.783 + private transient KeySet<K> navigableKeySet = null;
224.784 + private transient NavigableMap<K,V> descendingMap = null;
224.785 +
224.786 + /**
224.787 + * Returns a {@link Set} view of the keys contained in this map.
224.788 + * The set's iterator returns the keys in ascending order.
224.789 + * The set is backed by the map, so changes to the map are
224.790 + * reflected in the set, and vice-versa. If the map is modified
224.791 + * while an iteration over the set is in progress (except through
224.792 + * the iterator's own {@code remove} operation), the results of
224.793 + * the iteration are undefined. The set supports element removal,
224.794 + * which removes the corresponding mapping from the map, via the
224.795 + * {@code Iterator.remove}, {@code Set.remove},
224.796 + * {@code removeAll}, {@code retainAll}, and {@code clear}
224.797 + * operations. It does not support the {@code add} or {@code addAll}
224.798 + * operations.
224.799 + */
224.800 + public Set<K> keySet() {
224.801 + return navigableKeySet();
224.802 + }
224.803 +
224.804 + /**
224.805 + * @since 1.6
224.806 + */
224.807 + public NavigableSet<K> navigableKeySet() {
224.808 + KeySet<K> nks = navigableKeySet;
224.809 + return (nks != null) ? nks : (navigableKeySet = new KeySet(this));
224.810 + }
224.811 +
224.812 + /**
224.813 + * @since 1.6
224.814 + */
224.815 + public NavigableSet<K> descendingKeySet() {
224.816 + return descendingMap().navigableKeySet();
224.817 + }
224.818 +
224.819 + /**
224.820 + * Returns a {@link Collection} view of the values contained in this map.
224.821 + * The collection's iterator returns the values in ascending order
224.822 + * of the corresponding keys.
224.823 + * The collection is backed by the map, so changes to the map are
224.824 + * reflected in the collection, and vice-versa. If the map is
224.825 + * modified while an iteration over the collection is in progress
224.826 + * (except through the iterator's own {@code remove} operation),
224.827 + * the results of the iteration are undefined. The collection
224.828 + * supports element removal, which removes the corresponding
224.829 + * mapping from the map, via the {@code Iterator.remove},
224.830 + * {@code Collection.remove}, {@code removeAll},
224.831 + * {@code retainAll} and {@code clear} operations. It does not
224.832 + * support the {@code add} or {@code addAll} operations.
224.833 + */
224.834 + public Collection<V> values() {
224.835 + Collection<V> vs = values;
224.836 + return (vs != null) ? vs : (values = new Values());
224.837 + }
224.838 +
224.839 + /**
224.840 + * Returns a {@link Set} view of the mappings contained in this map.
224.841 + * The set's iterator returns the entries in ascending key order.
224.842 + * The set is backed by the map, so changes to the map are
224.843 + * reflected in the set, and vice-versa. If the map is modified
224.844 + * while an iteration over the set is in progress (except through
224.845 + * the iterator's own {@code remove} operation, or through the
224.846 + * {@code setValue} operation on a map entry returned by the
224.847 + * iterator) the results of the iteration are undefined. The set
224.848 + * supports element removal, which removes the corresponding
224.849 + * mapping from the map, via the {@code Iterator.remove},
224.850 + * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
224.851 + * {@code clear} operations. It does not support the
224.852 + * {@code add} or {@code addAll} operations.
224.853 + */
224.854 + public Set<Map.Entry<K,V>> entrySet() {
224.855 + EntrySet es = entrySet;
224.856 + return (es != null) ? es : (entrySet = new EntrySet());
224.857 + }
224.858 +
224.859 + /**
224.860 + * @since 1.6
224.861 + */
224.862 + public NavigableMap<K, V> descendingMap() {
224.863 + NavigableMap<K, V> km = descendingMap;
224.864 + return (km != null) ? km :
224.865 + (descendingMap = new DescendingSubMap(this,
224.866 + true, null, true,
224.867 + true, null, true));
224.868 + }
224.869 +
224.870 + /**
224.871 + * @throws ClassCastException {@inheritDoc}
224.872 + * @throws NullPointerException if {@code fromKey} or {@code toKey} is
224.873 + * null and this map uses natural ordering, or its comparator
224.874 + * does not permit null keys
224.875 + * @throws IllegalArgumentException {@inheritDoc}
224.876 + * @since 1.6
224.877 + */
224.878 + public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
224.879 + K toKey, boolean toInclusive) {
224.880 + return new AscendingSubMap(this,
224.881 + false, fromKey, fromInclusive,
224.882 + false, toKey, toInclusive);
224.883 + }
224.884 +
224.885 + /**
224.886 + * @throws ClassCastException {@inheritDoc}
224.887 + * @throws NullPointerException if {@code toKey} is null
224.888 + * and this map uses natural ordering, or its comparator
224.889 + * does not permit null keys
224.890 + * @throws IllegalArgumentException {@inheritDoc}
224.891 + * @since 1.6
224.892 + */
224.893 + public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
224.894 + return new AscendingSubMap(this,
224.895 + true, null, true,
224.896 + false, toKey, inclusive);
224.897 + }
224.898 +
224.899 + /**
224.900 + * @throws ClassCastException {@inheritDoc}
224.901 + * @throws NullPointerException if {@code fromKey} is null
224.902 + * and this map uses natural ordering, or its comparator
224.903 + * does not permit null keys
224.904 + * @throws IllegalArgumentException {@inheritDoc}
224.905 + * @since 1.6
224.906 + */
224.907 + public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
224.908 + return new AscendingSubMap(this,
224.909 + false, fromKey, inclusive,
224.910 + true, null, true);
224.911 + }
224.912 +
224.913 + /**
224.914 + * @throws ClassCastException {@inheritDoc}
224.915 + * @throws NullPointerException if {@code fromKey} or {@code toKey} is
224.916 + * null and this map uses natural ordering, or its comparator
224.917 + * does not permit null keys
224.918 + * @throws IllegalArgumentException {@inheritDoc}
224.919 + */
224.920 + public SortedMap<K,V> subMap(K fromKey, K toKey) {
224.921 + return subMap(fromKey, true, toKey, false);
224.922 + }
224.923 +
224.924 + /**
224.925 + * @throws ClassCastException {@inheritDoc}
224.926 + * @throws NullPointerException if {@code toKey} is null
224.927 + * and this map uses natural ordering, or its comparator
224.928 + * does not permit null keys
224.929 + * @throws IllegalArgumentException {@inheritDoc}
224.930 + */
224.931 + public SortedMap<K,V> headMap(K toKey) {
224.932 + return headMap(toKey, false);
224.933 + }
224.934 +
224.935 + /**
224.936 + * @throws ClassCastException {@inheritDoc}
224.937 + * @throws NullPointerException if {@code fromKey} is null
224.938 + * and this map uses natural ordering, or its comparator
224.939 + * does not permit null keys
224.940 + * @throws IllegalArgumentException {@inheritDoc}
224.941 + */
224.942 + public SortedMap<K,V> tailMap(K fromKey) {
224.943 + return tailMap(fromKey, true);
224.944 + }
224.945 +
224.946 + // View class support
224.947 +
224.948 + class Values extends AbstractCollection<V> {
224.949 + public Iterator<V> iterator() {
224.950 + return new ValueIterator(getFirstEntry());
224.951 + }
224.952 +
224.953 + public int size() {
224.954 + return TreeMap.this.size();
224.955 + }
224.956 +
224.957 + public boolean contains(Object o) {
224.958 + return TreeMap.this.containsValue(o);
224.959 + }
224.960 +
224.961 + public boolean remove(Object o) {
224.962 + for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e)) {
224.963 + if (valEquals(e.getValue(), o)) {
224.964 + deleteEntry(e);
224.965 + return true;
224.966 + }
224.967 + }
224.968 + return false;
224.969 + }
224.970 +
224.971 + public void clear() {
224.972 + TreeMap.this.clear();
224.973 + }
224.974 + }
224.975 +
224.976 + class EntrySet extends AbstractSet<Map.Entry<K,V>> {
224.977 + public Iterator<Map.Entry<K,V>> iterator() {
224.978 + return new EntryIterator(getFirstEntry());
224.979 + }
224.980 +
224.981 + public boolean contains(Object o) {
224.982 + if (!(o instanceof Map.Entry))
224.983 + return false;
224.984 + Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
224.985 + V value = entry.getValue();
224.986 + Entry<K,V> p = getEntry(entry.getKey());
224.987 + return p != null && valEquals(p.getValue(), value);
224.988 + }
224.989 +
224.990 + public boolean remove(Object o) {
224.991 + if (!(o instanceof Map.Entry))
224.992 + return false;
224.993 + Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
224.994 + V value = entry.getValue();
224.995 + Entry<K,V> p = getEntry(entry.getKey());
224.996 + if (p != null && valEquals(p.getValue(), value)) {
224.997 + deleteEntry(p);
224.998 + return true;
224.999 + }
224.1000 + return false;
224.1001 + }
224.1002 +
224.1003 + public int size() {
224.1004 + return TreeMap.this.size();
224.1005 + }
224.1006 +
224.1007 + public void clear() {
224.1008 + TreeMap.this.clear();
224.1009 + }
224.1010 + }
224.1011 +
224.1012 + /*
224.1013 + * Unlike Values and EntrySet, the KeySet class is static,
224.1014 + * delegating to a NavigableMap to allow use by SubMaps, which
224.1015 + * outweighs the ugliness of needing type-tests for the following
224.1016 + * Iterator methods that are defined appropriately in main versus
224.1017 + * submap classes.
224.1018 + */
224.1019 +
224.1020 + Iterator<K> keyIterator() {
224.1021 + return new KeyIterator(getFirstEntry());
224.1022 + }
224.1023 +
224.1024 + Iterator<K> descendingKeyIterator() {
224.1025 + return new DescendingKeyIterator(getLastEntry());
224.1026 + }
224.1027 +
224.1028 + static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {
224.1029 + private final NavigableMap<E, Object> m;
224.1030 + KeySet(NavigableMap<E,Object> map) { m = map; }
224.1031 +
224.1032 + public Iterator<E> iterator() {
224.1033 + if (m instanceof TreeMap)
224.1034 + return ((TreeMap<E,Object>)m).keyIterator();
224.1035 + else
224.1036 + return (Iterator<E>)(((TreeMap.NavigableSubMap)m).keyIterator());
224.1037 + }
224.1038 +
224.1039 + public Iterator<E> descendingIterator() {
224.1040 + if (m instanceof TreeMap)
224.1041 + return ((TreeMap<E,Object>)m).descendingKeyIterator();
224.1042 + else
224.1043 + return (Iterator<E>)(((TreeMap.NavigableSubMap)m).descendingKeyIterator());
224.1044 + }
224.1045 +
224.1046 + public int size() { return m.size(); }
224.1047 + public boolean isEmpty() { return m.isEmpty(); }
224.1048 + public boolean contains(Object o) { return m.containsKey(o); }
224.1049 + public void clear() { m.clear(); }
224.1050 + public E lower(E e) { return m.lowerKey(e); }
224.1051 + public E floor(E e) { return m.floorKey(e); }
224.1052 + public E ceiling(E e) { return m.ceilingKey(e); }
224.1053 + public E higher(E e) { return m.higherKey(e); }
224.1054 + public E first() { return m.firstKey(); }
224.1055 + public E last() { return m.lastKey(); }
224.1056 + public Comparator<? super E> comparator() { return m.comparator(); }
224.1057 + public E pollFirst() {
224.1058 + Map.Entry<E,Object> e = m.pollFirstEntry();
224.1059 + return (e == null) ? null : e.getKey();
224.1060 + }
224.1061 + public E pollLast() {
224.1062 + Map.Entry<E,Object> e = m.pollLastEntry();
224.1063 + return (e == null) ? null : e.getKey();
224.1064 + }
224.1065 + public boolean remove(Object o) {
224.1066 + int oldSize = size();
224.1067 + m.remove(o);
224.1068 + return size() != oldSize;
224.1069 + }
224.1070 + public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
224.1071 + E toElement, boolean toInclusive) {
224.1072 + return new KeySet<>(m.subMap(fromElement, fromInclusive,
224.1073 + toElement, toInclusive));
224.1074 + }
224.1075 + public NavigableSet<E> headSet(E toElement, boolean inclusive) {
224.1076 + return new KeySet<>(m.headMap(toElement, inclusive));
224.1077 + }
224.1078 + public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
224.1079 + return new KeySet<>(m.tailMap(fromElement, inclusive));
224.1080 + }
224.1081 + public SortedSet<E> subSet(E fromElement, E toElement) {
224.1082 + return subSet(fromElement, true, toElement, false);
224.1083 + }
224.1084 + public SortedSet<E> headSet(E toElement) {
224.1085 + return headSet(toElement, false);
224.1086 + }
224.1087 + public SortedSet<E> tailSet(E fromElement) {
224.1088 + return tailSet(fromElement, true);
224.1089 + }
224.1090 + public NavigableSet<E> descendingSet() {
224.1091 + return new KeySet(m.descendingMap());
224.1092 + }
224.1093 + }
224.1094 +
224.1095 + /**
224.1096 + * Base class for TreeMap Iterators
224.1097 + */
224.1098 + abstract class PrivateEntryIterator<T> implements Iterator<T> {
224.1099 + Entry<K,V> next;
224.1100 + Entry<K,V> lastReturned;
224.1101 + int expectedModCount;
224.1102 +
224.1103 + PrivateEntryIterator(Entry<K,V> first) {
224.1104 + expectedModCount = modCount;
224.1105 + lastReturned = null;
224.1106 + next = first;
224.1107 + }
224.1108 +
224.1109 + public final boolean hasNext() {
224.1110 + return next != null;
224.1111 + }
224.1112 +
224.1113 + final Entry<K,V> nextEntry() {
224.1114 + Entry<K,V> e = next;
224.1115 + if (e == null)
224.1116 + throw new NoSuchElementException();
224.1117 + if (modCount != expectedModCount)
224.1118 + throw new ConcurrentModificationException();
224.1119 + next = successor(e);
224.1120 + lastReturned = e;
224.1121 + return e;
224.1122 + }
224.1123 +
224.1124 + final Entry<K,V> prevEntry() {
224.1125 + Entry<K,V> e = next;
224.1126 + if (e == null)
224.1127 + throw new NoSuchElementException();
224.1128 + if (modCount != expectedModCount)
224.1129 + throw new ConcurrentModificationException();
224.1130 + next = predecessor(e);
224.1131 + lastReturned = e;
224.1132 + return e;
224.1133 + }
224.1134 +
224.1135 + public void remove() {
224.1136 + if (lastReturned == null)
224.1137 + throw new IllegalStateException();
224.1138 + if (modCount != expectedModCount)
224.1139 + throw new ConcurrentModificationException();
224.1140 + // deleted entries are replaced by their successors
224.1141 + if (lastReturned.left != null && lastReturned.right != null)
224.1142 + next = lastReturned;
224.1143 + deleteEntry(lastReturned);
224.1144 + expectedModCount = modCount;
224.1145 + lastReturned = null;
224.1146 + }
224.1147 + }
224.1148 +
224.1149 + final class EntryIterator extends PrivateEntryIterator<Map.Entry<K,V>> {
224.1150 + EntryIterator(Entry<K,V> first) {
224.1151 + super(first);
224.1152 + }
224.1153 + public Map.Entry<K,V> next() {
224.1154 + return nextEntry();
224.1155 + }
224.1156 + }
224.1157 +
224.1158 + final class ValueIterator extends PrivateEntryIterator<V> {
224.1159 + ValueIterator(Entry<K,V> first) {
224.1160 + super(first);
224.1161 + }
224.1162 + public V next() {
224.1163 + return nextEntry().value;
224.1164 + }
224.1165 + }
224.1166 +
224.1167 + final class KeyIterator extends PrivateEntryIterator<K> {
224.1168 + KeyIterator(Entry<K,V> first) {
224.1169 + super(first);
224.1170 + }
224.1171 + public K next() {
224.1172 + return nextEntry().key;
224.1173 + }
224.1174 + }
224.1175 +
224.1176 + final class DescendingKeyIterator extends PrivateEntryIterator<K> {
224.1177 + DescendingKeyIterator(Entry<K,V> first) {
224.1178 + super(first);
224.1179 + }
224.1180 + public K next() {
224.1181 + return prevEntry().key;
224.1182 + }
224.1183 + }
224.1184 +
224.1185 + // Little utilities
224.1186 +
224.1187 + /**
224.1188 + * Compares two keys using the correct comparison method for this TreeMap.
224.1189 + */
224.1190 + final int compare(Object k1, Object k2) {
224.1191 + return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
224.1192 + : comparator.compare((K)k1, (K)k2);
224.1193 + }
224.1194 +
224.1195 + /**
224.1196 + * Test two values for equality. Differs from o1.equals(o2) only in
224.1197 + * that it copes with {@code null} o1 properly.
224.1198 + */
224.1199 + static final boolean valEquals(Object o1, Object o2) {
224.1200 + return (o1==null ? o2==null : o1.equals(o2));
224.1201 + }
224.1202 +
224.1203 + /**
224.1204 + * Return SimpleImmutableEntry for entry, or null if null
224.1205 + */
224.1206 + static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) {
224.1207 + return (e == null) ? null :
224.1208 + new AbstractMap.SimpleImmutableEntry<>(e);
224.1209 + }
224.1210 +
224.1211 + /**
224.1212 + * Return key for entry, or null if null
224.1213 + */
224.1214 + static <K,V> K keyOrNull(TreeMap.Entry<K,V> e) {
224.1215 + return (e == null) ? null : e.key;
224.1216 + }
224.1217 +
224.1218 + /**
224.1219 + * Returns the key corresponding to the specified Entry.
224.1220 + * @throws NoSuchElementException if the Entry is null
224.1221 + */
224.1222 + static <K> K key(Entry<K,?> e) {
224.1223 + if (e==null)
224.1224 + throw new NoSuchElementException();
224.1225 + return e.key;
224.1226 + }
224.1227 +
224.1228 +
224.1229 + // SubMaps
224.1230 +
224.1231 + /**
224.1232 + * Dummy value serving as unmatchable fence key for unbounded
224.1233 + * SubMapIterators
224.1234 + */
224.1235 + private static final Object UNBOUNDED = new Object();
224.1236 +
224.1237 + /**
224.1238 + * @serial include
224.1239 + */
224.1240 + abstract static class NavigableSubMap<K,V> extends AbstractMap<K,V>
224.1241 + implements NavigableMap<K,V>, java.io.Serializable {
224.1242 + /**
224.1243 + * The backing map.
224.1244 + */
224.1245 + final TreeMap<K,V> m;
224.1246 +
224.1247 + /**
224.1248 + * Endpoints are represented as triples (fromStart, lo,
224.1249 + * loInclusive) and (toEnd, hi, hiInclusive). If fromStart is
224.1250 + * true, then the low (absolute) bound is the start of the
224.1251 + * backing map, and the other values are ignored. Otherwise,
224.1252 + * if loInclusive is true, lo is the inclusive bound, else lo
224.1253 + * is the exclusive bound. Similarly for the upper bound.
224.1254 + */
224.1255 + final K lo, hi;
224.1256 + final boolean fromStart, toEnd;
224.1257 + final boolean loInclusive, hiInclusive;
224.1258 +
224.1259 + NavigableSubMap(TreeMap<K,V> m,
224.1260 + boolean fromStart, K lo, boolean loInclusive,
224.1261 + boolean toEnd, K hi, boolean hiInclusive) {
224.1262 + if (!fromStart && !toEnd) {
224.1263 + if (m.compare(lo, hi) > 0)
224.1264 + throw new IllegalArgumentException("fromKey > toKey");
224.1265 + } else {
224.1266 + if (!fromStart) // type check
224.1267 + m.compare(lo, lo);
224.1268 + if (!toEnd)
224.1269 + m.compare(hi, hi);
224.1270 + }
224.1271 +
224.1272 + this.m = m;
224.1273 + this.fromStart = fromStart;
224.1274 + this.lo = lo;
224.1275 + this.loInclusive = loInclusive;
224.1276 + this.toEnd = toEnd;
224.1277 + this.hi = hi;
224.1278 + this.hiInclusive = hiInclusive;
224.1279 + }
224.1280 +
224.1281 + // internal utilities
224.1282 +
224.1283 + final boolean tooLow(Object key) {
224.1284 + if (!fromStart) {
224.1285 + int c = m.compare(key, lo);
224.1286 + if (c < 0 || (c == 0 && !loInclusive))
224.1287 + return true;
224.1288 + }
224.1289 + return false;
224.1290 + }
224.1291 +
224.1292 + final boolean tooHigh(Object key) {
224.1293 + if (!toEnd) {
224.1294 + int c = m.compare(key, hi);
224.1295 + if (c > 0 || (c == 0 && !hiInclusive))
224.1296 + return true;
224.1297 + }
224.1298 + return false;
224.1299 + }
224.1300 +
224.1301 + final boolean inRange(Object key) {
224.1302 + return !tooLow(key) && !tooHigh(key);
224.1303 + }
224.1304 +
224.1305 + final boolean inClosedRange(Object key) {
224.1306 + return (fromStart || m.compare(key, lo) >= 0)
224.1307 + && (toEnd || m.compare(hi, key) >= 0);
224.1308 + }
224.1309 +
224.1310 + final boolean inRange(Object key, boolean inclusive) {
224.1311 + return inclusive ? inRange(key) : inClosedRange(key);
224.1312 + }
224.1313 +
224.1314 + /*
224.1315 + * Absolute versions of relation operations.
224.1316 + * Subclasses map to these using like-named "sub"
224.1317 + * versions that invert senses for descending maps
224.1318 + */
224.1319 +
224.1320 + final TreeMap.Entry<K,V> absLowest() {
224.1321 + TreeMap.Entry<K,V> e =
224.1322 + (fromStart ? m.getFirstEntry() :
224.1323 + (loInclusive ? m.getCeilingEntry(lo) :
224.1324 + m.getHigherEntry(lo)));
224.1325 + return (e == null || tooHigh(e.key)) ? null : e;
224.1326 + }
224.1327 +
224.1328 + final TreeMap.Entry<K,V> absHighest() {
224.1329 + TreeMap.Entry<K,V> e =
224.1330 + (toEnd ? m.getLastEntry() :
224.1331 + (hiInclusive ? m.getFloorEntry(hi) :
224.1332 + m.getLowerEntry(hi)));
224.1333 + return (e == null || tooLow(e.key)) ? null : e;
224.1334 + }
224.1335 +
224.1336 + final TreeMap.Entry<K,V> absCeiling(K key) {
224.1337 + if (tooLow(key))
224.1338 + return absLowest();
224.1339 + TreeMap.Entry<K,V> e = m.getCeilingEntry(key);
224.1340 + return (e == null || tooHigh(e.key)) ? null : e;
224.1341 + }
224.1342 +
224.1343 + final TreeMap.Entry<K,V> absHigher(K key) {
224.1344 + if (tooLow(key))
224.1345 + return absLowest();
224.1346 + TreeMap.Entry<K,V> e = m.getHigherEntry(key);
224.1347 + return (e == null || tooHigh(e.key)) ? null : e;
224.1348 + }
224.1349 +
224.1350 + final TreeMap.Entry<K,V> absFloor(K key) {
224.1351 + if (tooHigh(key))
224.1352 + return absHighest();
224.1353 + TreeMap.Entry<K,V> e = m.getFloorEntry(key);
224.1354 + return (e == null || tooLow(e.key)) ? null : e;
224.1355 + }
224.1356 +
224.1357 + final TreeMap.Entry<K,V> absLower(K key) {
224.1358 + if (tooHigh(key))
224.1359 + return absHighest();
224.1360 + TreeMap.Entry<K,V> e = m.getLowerEntry(key);
224.1361 + return (e == null || tooLow(e.key)) ? null : e;
224.1362 + }
224.1363 +
224.1364 + /** Returns the absolute high fence for ascending traversal */
224.1365 + final TreeMap.Entry<K,V> absHighFence() {
224.1366 + return (toEnd ? null : (hiInclusive ?
224.1367 + m.getHigherEntry(hi) :
224.1368 + m.getCeilingEntry(hi)));
224.1369 + }
224.1370 +
224.1371 + /** Return the absolute low fence for descending traversal */
224.1372 + final TreeMap.Entry<K,V> absLowFence() {
224.1373 + return (fromStart ? null : (loInclusive ?
224.1374 + m.getLowerEntry(lo) :
224.1375 + m.getFloorEntry(lo)));
224.1376 + }
224.1377 +
224.1378 + // Abstract methods defined in ascending vs descending classes
224.1379 + // These relay to the appropriate absolute versions
224.1380 +
224.1381 + abstract TreeMap.Entry<K,V> subLowest();
224.1382 + abstract TreeMap.Entry<K,V> subHighest();
224.1383 + abstract TreeMap.Entry<K,V> subCeiling(K key);
224.1384 + abstract TreeMap.Entry<K,V> subHigher(K key);
224.1385 + abstract TreeMap.Entry<K,V> subFloor(K key);
224.1386 + abstract TreeMap.Entry<K,V> subLower(K key);
224.1387 +
224.1388 + /** Returns ascending iterator from the perspective of this submap */
224.1389 + abstract Iterator<K> keyIterator();
224.1390 +
224.1391 + /** Returns descending iterator from the perspective of this submap */
224.1392 + abstract Iterator<K> descendingKeyIterator();
224.1393 +
224.1394 + // public methods
224.1395 +
224.1396 + public boolean isEmpty() {
224.1397 + return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty();
224.1398 + }
224.1399 +
224.1400 + public int size() {
224.1401 + return (fromStart && toEnd) ? m.size() : entrySet().size();
224.1402 + }
224.1403 +
224.1404 + public final boolean containsKey(Object key) {
224.1405 + return inRange(key) && m.containsKey(key);
224.1406 + }
224.1407 +
224.1408 + public final V put(K key, V value) {
224.1409 + if (!inRange(key))
224.1410 + throw new IllegalArgumentException("key out of range");
224.1411 + return m.put(key, value);
224.1412 + }
224.1413 +
224.1414 + public final V get(Object key) {
224.1415 + return !inRange(key) ? null : m.get(key);
224.1416 + }
224.1417 +
224.1418 + public final V remove(Object key) {
224.1419 + return !inRange(key) ? null : m.remove(key);
224.1420 + }
224.1421 +
224.1422 + public final Map.Entry<K,V> ceilingEntry(K key) {
224.1423 + return exportEntry(subCeiling(key));
224.1424 + }
224.1425 +
224.1426 + public final K ceilingKey(K key) {
224.1427 + return keyOrNull(subCeiling(key));
224.1428 + }
224.1429 +
224.1430 + public final Map.Entry<K,V> higherEntry(K key) {
224.1431 + return exportEntry(subHigher(key));
224.1432 + }
224.1433 +
224.1434 + public final K higherKey(K key) {
224.1435 + return keyOrNull(subHigher(key));
224.1436 + }
224.1437 +
224.1438 + public final Map.Entry<K,V> floorEntry(K key) {
224.1439 + return exportEntry(subFloor(key));
224.1440 + }
224.1441 +
224.1442 + public final K floorKey(K key) {
224.1443 + return keyOrNull(subFloor(key));
224.1444 + }
224.1445 +
224.1446 + public final Map.Entry<K,V> lowerEntry(K key) {
224.1447 + return exportEntry(subLower(key));
224.1448 + }
224.1449 +
224.1450 + public final K lowerKey(K key) {
224.1451 + return keyOrNull(subLower(key));
224.1452 + }
224.1453 +
224.1454 + public final K firstKey() {
224.1455 + return key(subLowest());
224.1456 + }
224.1457 +
224.1458 + public final K lastKey() {
224.1459 + return key(subHighest());
224.1460 + }
224.1461 +
224.1462 + public final Map.Entry<K,V> firstEntry() {
224.1463 + return exportEntry(subLowest());
224.1464 + }
224.1465 +
224.1466 + public final Map.Entry<K,V> lastEntry() {
224.1467 + return exportEntry(subHighest());
224.1468 + }
224.1469 +
224.1470 + public final Map.Entry<K,V> pollFirstEntry() {
224.1471 + TreeMap.Entry<K,V> e = subLowest();
224.1472 + Map.Entry<K,V> result = exportEntry(e);
224.1473 + if (e != null)
224.1474 + m.deleteEntry(e);
224.1475 + return result;
224.1476 + }
224.1477 +
224.1478 + public final Map.Entry<K,V> pollLastEntry() {
224.1479 + TreeMap.Entry<K,V> e = subHighest();
224.1480 + Map.Entry<K,V> result = exportEntry(e);
224.1481 + if (e != null)
224.1482 + m.deleteEntry(e);
224.1483 + return result;
224.1484 + }
224.1485 +
224.1486 + // Views
224.1487 + transient NavigableMap<K,V> descendingMapView = null;
224.1488 + transient EntrySetView entrySetView = null;
224.1489 + transient KeySet<K> navigableKeySetView = null;
224.1490 +
224.1491 + public final NavigableSet<K> navigableKeySet() {
224.1492 + KeySet<K> nksv = navigableKeySetView;
224.1493 + return (nksv != null) ? nksv :
224.1494 + (navigableKeySetView = new TreeMap.KeySet(this));
224.1495 + }
224.1496 +
224.1497 + public final Set<K> keySet() {
224.1498 + return navigableKeySet();
224.1499 + }
224.1500 +
224.1501 + public NavigableSet<K> descendingKeySet() {
224.1502 + return descendingMap().navigableKeySet();
224.1503 + }
224.1504 +
224.1505 + public final SortedMap<K,V> subMap(K fromKey, K toKey) {
224.1506 + return subMap(fromKey, true, toKey, false);
224.1507 + }
224.1508 +
224.1509 + public final SortedMap<K,V> headMap(K toKey) {
224.1510 + return headMap(toKey, false);
224.1511 + }
224.1512 +
224.1513 + public final SortedMap<K,V> tailMap(K fromKey) {
224.1514 + return tailMap(fromKey, true);
224.1515 + }
224.1516 +
224.1517 + // View classes
224.1518 +
224.1519 + abstract class EntrySetView extends AbstractSet<Map.Entry<K,V>> {
224.1520 + private transient int size = -1, sizeModCount;
224.1521 +
224.1522 + public int size() {
224.1523 + if (fromStart && toEnd)
224.1524 + return m.size();
224.1525 + if (size == -1 || sizeModCount != m.modCount) {
224.1526 + sizeModCount = m.modCount;
224.1527 + size = 0;
224.1528 + Iterator i = iterator();
224.1529 + while (i.hasNext()) {
224.1530 + size++;
224.1531 + i.next();
224.1532 + }
224.1533 + }
224.1534 + return size;
224.1535 + }
224.1536 +
224.1537 + public boolean isEmpty() {
224.1538 + TreeMap.Entry<K,V> n = absLowest();
224.1539 + return n == null || tooHigh(n.key);
224.1540 + }
224.1541 +
224.1542 + public boolean contains(Object o) {
224.1543 + if (!(o instanceof Map.Entry))
224.1544 + return false;
224.1545 + Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
224.1546 + K key = entry.getKey();
224.1547 + if (!inRange(key))
224.1548 + return false;
224.1549 + TreeMap.Entry node = m.getEntry(key);
224.1550 + return node != null &&
224.1551 + valEquals(node.getValue(), entry.getValue());
224.1552 + }
224.1553 +
224.1554 + public boolean remove(Object o) {
224.1555 + if (!(o instanceof Map.Entry))
224.1556 + return false;
224.1557 + Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
224.1558 + K key = entry.getKey();
224.1559 + if (!inRange(key))
224.1560 + return false;
224.1561 + TreeMap.Entry<K,V> node = m.getEntry(key);
224.1562 + if (node!=null && valEquals(node.getValue(),
224.1563 + entry.getValue())) {
224.1564 + m.deleteEntry(node);
224.1565 + return true;
224.1566 + }
224.1567 + return false;
224.1568 + }
224.1569 + }
224.1570 +
224.1571 + /**
224.1572 + * Iterators for SubMaps
224.1573 + */
224.1574 + abstract class SubMapIterator<T> implements Iterator<T> {
224.1575 + TreeMap.Entry<K,V> lastReturned;
224.1576 + TreeMap.Entry<K,V> next;
224.1577 + final Object fenceKey;
224.1578 + int expectedModCount;
224.1579 +
224.1580 + SubMapIterator(TreeMap.Entry<K,V> first,
224.1581 + TreeMap.Entry<K,V> fence) {
224.1582 + expectedModCount = m.modCount;
224.1583 + lastReturned = null;
224.1584 + next = first;
224.1585 + fenceKey = fence == null ? UNBOUNDED : fence.key;
224.1586 + }
224.1587 +
224.1588 + public final boolean hasNext() {
224.1589 + return next != null && next.key != fenceKey;
224.1590 + }
224.1591 +
224.1592 + final TreeMap.Entry<K,V> nextEntry() {
224.1593 + TreeMap.Entry<K,V> e = next;
224.1594 + if (e == null || e.key == fenceKey)
224.1595 + throw new NoSuchElementException();
224.1596 + if (m.modCount != expectedModCount)
224.1597 + throw new ConcurrentModificationException();
224.1598 + next = successor(e);
224.1599 + lastReturned = e;
224.1600 + return e;
224.1601 + }
224.1602 +
224.1603 + final TreeMap.Entry<K,V> prevEntry() {
224.1604 + TreeMap.Entry<K,V> e = next;
224.1605 + if (e == null || e.key == fenceKey)
224.1606 + throw new NoSuchElementException();
224.1607 + if (m.modCount != expectedModCount)
224.1608 + throw new ConcurrentModificationException();
224.1609 + next = predecessor(e);
224.1610 + lastReturned = e;
224.1611 + return e;
224.1612 + }
224.1613 +
224.1614 + final void removeAscending() {
224.1615 + if (lastReturned == null)
224.1616 + throw new IllegalStateException();
224.1617 + if (m.modCount != expectedModCount)
224.1618 + throw new ConcurrentModificationException();
224.1619 + // deleted entries are replaced by their successors
224.1620 + if (lastReturned.left != null && lastReturned.right != null)
224.1621 + next = lastReturned;
224.1622 + m.deleteEntry(lastReturned);
224.1623 + lastReturned = null;
224.1624 + expectedModCount = m.modCount;
224.1625 + }
224.1626 +
224.1627 + final void removeDescending() {
224.1628 + if (lastReturned == null)
224.1629 + throw new IllegalStateException();
224.1630 + if (m.modCount != expectedModCount)
224.1631 + throw new ConcurrentModificationException();
224.1632 + m.deleteEntry(lastReturned);
224.1633 + lastReturned = null;
224.1634 + expectedModCount = m.modCount;
224.1635 + }
224.1636 +
224.1637 + }
224.1638 +
224.1639 + final class SubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
224.1640 + SubMapEntryIterator(TreeMap.Entry<K,V> first,
224.1641 + TreeMap.Entry<K,V> fence) {
224.1642 + super(first, fence);
224.1643 + }
224.1644 + public Map.Entry<K,V> next() {
224.1645 + return nextEntry();
224.1646 + }
224.1647 + public void remove() {
224.1648 + removeAscending();
224.1649 + }
224.1650 + }
224.1651 +
224.1652 + final class SubMapKeyIterator extends SubMapIterator<K> {
224.1653 + SubMapKeyIterator(TreeMap.Entry<K,V> first,
224.1654 + TreeMap.Entry<K,V> fence) {
224.1655 + super(first, fence);
224.1656 + }
224.1657 + public K next() {
224.1658 + return nextEntry().key;
224.1659 + }
224.1660 + public void remove() {
224.1661 + removeAscending();
224.1662 + }
224.1663 + }
224.1664 +
224.1665 + final class DescendingSubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
224.1666 + DescendingSubMapEntryIterator(TreeMap.Entry<K,V> last,
224.1667 + TreeMap.Entry<K,V> fence) {
224.1668 + super(last, fence);
224.1669 + }
224.1670 +
224.1671 + public Map.Entry<K,V> next() {
224.1672 + return prevEntry();
224.1673 + }
224.1674 + public void remove() {
224.1675 + removeDescending();
224.1676 + }
224.1677 + }
224.1678 +
224.1679 + final class DescendingSubMapKeyIterator extends SubMapIterator<K> {
224.1680 + DescendingSubMapKeyIterator(TreeMap.Entry<K,V> last,
224.1681 + TreeMap.Entry<K,V> fence) {
224.1682 + super(last, fence);
224.1683 + }
224.1684 + public K next() {
224.1685 + return prevEntry().key;
224.1686 + }
224.1687 + public void remove() {
224.1688 + removeDescending();
224.1689 + }
224.1690 + }
224.1691 + }
224.1692 +
224.1693 + /**
224.1694 + * @serial include
224.1695 + */
224.1696 + static final class AscendingSubMap<K,V> extends NavigableSubMap<K,V> {
224.1697 + private static final long serialVersionUID = 912986545866124060L;
224.1698 +
224.1699 + AscendingSubMap(TreeMap<K,V> m,
224.1700 + boolean fromStart, K lo, boolean loInclusive,
224.1701 + boolean toEnd, K hi, boolean hiInclusive) {
224.1702 + super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
224.1703 + }
224.1704 +
224.1705 + public Comparator<? super K> comparator() {
224.1706 + return m.comparator();
224.1707 + }
224.1708 +
224.1709 + public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
224.1710 + K toKey, boolean toInclusive) {
224.1711 + if (!inRange(fromKey, fromInclusive))
224.1712 + throw new IllegalArgumentException("fromKey out of range");
224.1713 + if (!inRange(toKey, toInclusive))
224.1714 + throw new IllegalArgumentException("toKey out of range");
224.1715 + return new AscendingSubMap(m,
224.1716 + false, fromKey, fromInclusive,
224.1717 + false, toKey, toInclusive);
224.1718 + }
224.1719 +
224.1720 + public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
224.1721 + if (!inRange(toKey, inclusive))
224.1722 + throw new IllegalArgumentException("toKey out of range");
224.1723 + return new AscendingSubMap(m,
224.1724 + fromStart, lo, loInclusive,
224.1725 + false, toKey, inclusive);
224.1726 + }
224.1727 +
224.1728 + public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
224.1729 + if (!inRange(fromKey, inclusive))
224.1730 + throw new IllegalArgumentException("fromKey out of range");
224.1731 + return new AscendingSubMap(m,
224.1732 + false, fromKey, inclusive,
224.1733 + toEnd, hi, hiInclusive);
224.1734 + }
224.1735 +
224.1736 + public NavigableMap<K,V> descendingMap() {
224.1737 + NavigableMap<K,V> mv = descendingMapView;
224.1738 + return (mv != null) ? mv :
224.1739 + (descendingMapView =
224.1740 + new DescendingSubMap(m,
224.1741 + fromStart, lo, loInclusive,
224.1742 + toEnd, hi, hiInclusive));
224.1743 + }
224.1744 +
224.1745 + Iterator<K> keyIterator() {
224.1746 + return new SubMapKeyIterator(absLowest(), absHighFence());
224.1747 + }
224.1748 +
224.1749 + Iterator<K> descendingKeyIterator() {
224.1750 + return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
224.1751 + }
224.1752 +
224.1753 + final class AscendingEntrySetView extends EntrySetView {
224.1754 + public Iterator<Map.Entry<K,V>> iterator() {
224.1755 + return new SubMapEntryIterator(absLowest(), absHighFence());
224.1756 + }
224.1757 + }
224.1758 +
224.1759 + public Set<Map.Entry<K,V>> entrySet() {
224.1760 + EntrySetView es = entrySetView;
224.1761 + return (es != null) ? es : new AscendingEntrySetView();
224.1762 + }
224.1763 +
224.1764 + TreeMap.Entry<K,V> subLowest() { return absLowest(); }
224.1765 + TreeMap.Entry<K,V> subHighest() { return absHighest(); }
224.1766 + TreeMap.Entry<K,V> subCeiling(K key) { return absCeiling(key); }
224.1767 + TreeMap.Entry<K,V> subHigher(K key) { return absHigher(key); }
224.1768 + TreeMap.Entry<K,V> subFloor(K key) { return absFloor(key); }
224.1769 + TreeMap.Entry<K,V> subLower(K key) { return absLower(key); }
224.1770 + }
224.1771 +
224.1772 + /**
224.1773 + * @serial include
224.1774 + */
224.1775 + static final class DescendingSubMap<K,V> extends NavigableSubMap<K,V> {
224.1776 + private static final long serialVersionUID = 912986545866120460L;
224.1777 + DescendingSubMap(TreeMap<K,V> m,
224.1778 + boolean fromStart, K lo, boolean loInclusive,
224.1779 + boolean toEnd, K hi, boolean hiInclusive) {
224.1780 + super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
224.1781 + }
224.1782 +
224.1783 + private final Comparator<? super K> reverseComparator =
224.1784 + Collections.reverseOrder(m.comparator);
224.1785 +
224.1786 + public Comparator<? super K> comparator() {
224.1787 + return reverseComparator;
224.1788 + }
224.1789 +
224.1790 + public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
224.1791 + K toKey, boolean toInclusive) {
224.1792 + if (!inRange(fromKey, fromInclusive))
224.1793 + throw new IllegalArgumentException("fromKey out of range");
224.1794 + if (!inRange(toKey, toInclusive))
224.1795 + throw new IllegalArgumentException("toKey out of range");
224.1796 + return new DescendingSubMap(m,
224.1797 + false, toKey, toInclusive,
224.1798 + false, fromKey, fromInclusive);
224.1799 + }
224.1800 +
224.1801 + public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
224.1802 + if (!inRange(toKey, inclusive))
224.1803 + throw new IllegalArgumentException("toKey out of range");
224.1804 + return new DescendingSubMap(m,
224.1805 + false, toKey, inclusive,
224.1806 + toEnd, hi, hiInclusive);
224.1807 + }
224.1808 +
224.1809 + public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
224.1810 + if (!inRange(fromKey, inclusive))
224.1811 + throw new IllegalArgumentException("fromKey out of range");
224.1812 + return new DescendingSubMap(m,
224.1813 + fromStart, lo, loInclusive,
224.1814 + false, fromKey, inclusive);
224.1815 + }
224.1816 +
224.1817 + public NavigableMap<K,V> descendingMap() {
224.1818 + NavigableMap<K,V> mv = descendingMapView;
224.1819 + return (mv != null) ? mv :
224.1820 + (descendingMapView =
224.1821 + new AscendingSubMap(m,
224.1822 + fromStart, lo, loInclusive,
224.1823 + toEnd, hi, hiInclusive));
224.1824 + }
224.1825 +
224.1826 + Iterator<K> keyIterator() {
224.1827 + return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
224.1828 + }
224.1829 +
224.1830 + Iterator<K> descendingKeyIterator() {
224.1831 + return new SubMapKeyIterator(absLowest(), absHighFence());
224.1832 + }
224.1833 +
224.1834 + final class DescendingEntrySetView extends EntrySetView {
224.1835 + public Iterator<Map.Entry<K,V>> iterator() {
224.1836 + return new DescendingSubMapEntryIterator(absHighest(), absLowFence());
224.1837 + }
224.1838 + }
224.1839 +
224.1840 + public Set<Map.Entry<K,V>> entrySet() {
224.1841 + EntrySetView es = entrySetView;
224.1842 + return (es != null) ? es : new DescendingEntrySetView();
224.1843 + }
224.1844 +
224.1845 + TreeMap.Entry<K,V> subLowest() { return absHighest(); }
224.1846 + TreeMap.Entry<K,V> subHighest() { return absLowest(); }
224.1847 + TreeMap.Entry<K,V> subCeiling(K key) { return absFloor(key); }
224.1848 + TreeMap.Entry<K,V> subHigher(K key) { return absLower(key); }
224.1849 + TreeMap.Entry<K,V> subFloor(K key) { return absCeiling(key); }
224.1850 + TreeMap.Entry<K,V> subLower(K key) { return absHigher(key); }
224.1851 + }
224.1852 +
224.1853 + /**
224.1854 + * This class exists solely for the sake of serialization
224.1855 + * compatibility with previous releases of TreeMap that did not
224.1856 + * support NavigableMap. It translates an old-version SubMap into
224.1857 + * a new-version AscendingSubMap. This class is never otherwise
224.1858 + * used.
224.1859 + *
224.1860 + * @serial include
224.1861 + */
224.1862 + private class SubMap extends AbstractMap<K,V>
224.1863 + implements SortedMap<K,V>, java.io.Serializable {
224.1864 + private static final long serialVersionUID = -6520786458950516097L;
224.1865 + private boolean fromStart = false, toEnd = false;
224.1866 + private K fromKey, toKey;
224.1867 + private Object readResolve() {
224.1868 + return new AscendingSubMap(TreeMap.this,
224.1869 + fromStart, fromKey, true,
224.1870 + toEnd, toKey, false);
224.1871 + }
224.1872 + public Set<Map.Entry<K,V>> entrySet() { throw new InternalError(); }
224.1873 + public K lastKey() { throw new InternalError(); }
224.1874 + public K firstKey() { throw new InternalError(); }
224.1875 + public SortedMap<K,V> subMap(K fromKey, K toKey) { throw new InternalError(); }
224.1876 + public SortedMap<K,V> headMap(K toKey) { throw new InternalError(); }
224.1877 + public SortedMap<K,V> tailMap(K fromKey) { throw new InternalError(); }
224.1878 + public Comparator<? super K> comparator() { throw new InternalError(); }
224.1879 + }
224.1880 +
224.1881 +
224.1882 + // Red-black mechanics
224.1883 +
224.1884 + private static final boolean RED = false;
224.1885 + private static final boolean BLACK = true;
224.1886 +
224.1887 + /**
224.1888 + * Node in the Tree. Doubles as a means to pass key-value pairs back to
224.1889 + * user (see Map.Entry).
224.1890 + */
224.1891 +
224.1892 + static final class Entry<K,V> implements Map.Entry<K,V> {
224.1893 + K key;
224.1894 + V value;
224.1895 + Entry<K,V> left = null;
224.1896 + Entry<K,V> right = null;
224.1897 + Entry<K,V> parent;
224.1898 + boolean color = BLACK;
224.1899 +
224.1900 + /**
224.1901 + * Make a new cell with given key, value, and parent, and with
224.1902 + * {@code null} child links, and BLACK color.
224.1903 + */
224.1904 + Entry(K key, V value, Entry<K,V> parent) {
224.1905 + this.key = key;
224.1906 + this.value = value;
224.1907 + this.parent = parent;
224.1908 + }
224.1909 +
224.1910 + /**
224.1911 + * Returns the key.
224.1912 + *
224.1913 + * @return the key
224.1914 + */
224.1915 + public K getKey() {
224.1916 + return key;
224.1917 + }
224.1918 +
224.1919 + /**
224.1920 + * Returns the value associated with the key.
224.1921 + *
224.1922 + * @return the value associated with the key
224.1923 + */
224.1924 + public V getValue() {
224.1925 + return value;
224.1926 + }
224.1927 +
224.1928 + /**
224.1929 + * Replaces the value currently associated with the key with the given
224.1930 + * value.
224.1931 + *
224.1932 + * @return the value associated with the key before this method was
224.1933 + * called
224.1934 + */
224.1935 + public V setValue(V value) {
224.1936 + V oldValue = this.value;
224.1937 + this.value = value;
224.1938 + return oldValue;
224.1939 + }
224.1940 +
224.1941 + public boolean equals(Object o) {
224.1942 + if (!(o instanceof Map.Entry))
224.1943 + return false;
224.1944 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
224.1945 +
224.1946 + return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
224.1947 + }
224.1948 +
224.1949 + public int hashCode() {
224.1950 + int keyHash = (key==null ? 0 : key.hashCode());
224.1951 + int valueHash = (value==null ? 0 : value.hashCode());
224.1952 + return keyHash ^ valueHash;
224.1953 + }
224.1954 +
224.1955 + public String toString() {
224.1956 + return key + "=" + value;
224.1957 + }
224.1958 + }
224.1959 +
224.1960 + /**
224.1961 + * Returns the first Entry in the TreeMap (according to the TreeMap's
224.1962 + * key-sort function). Returns null if the TreeMap is empty.
224.1963 + */
224.1964 + final Entry<K,V> getFirstEntry() {
224.1965 + Entry<K,V> p = root;
224.1966 + if (p != null)
224.1967 + while (p.left != null)
224.1968 + p = p.left;
224.1969 + return p;
224.1970 + }
224.1971 +
224.1972 + /**
224.1973 + * Returns the last Entry in the TreeMap (according to the TreeMap's
224.1974 + * key-sort function). Returns null if the TreeMap is empty.
224.1975 + */
224.1976 + final Entry<K,V> getLastEntry() {
224.1977 + Entry<K,V> p = root;
224.1978 + if (p != null)
224.1979 + while (p.right != null)
224.1980 + p = p.right;
224.1981 + return p;
224.1982 + }
224.1983 +
224.1984 + /**
224.1985 + * Returns the successor of the specified Entry, or null if no such.
224.1986 + */
224.1987 + static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
224.1988 + if (t == null)
224.1989 + return null;
224.1990 + else if (t.right != null) {
224.1991 + Entry<K,V> p = t.right;
224.1992 + while (p.left != null)
224.1993 + p = p.left;
224.1994 + return p;
224.1995 + } else {
224.1996 + Entry<K,V> p = t.parent;
224.1997 + Entry<K,V> ch = t;
224.1998 + while (p != null && ch == p.right) {
224.1999 + ch = p;
224.2000 + p = p.parent;
224.2001 + }
224.2002 + return p;
224.2003 + }
224.2004 + }
224.2005 +
224.2006 + /**
224.2007 + * Returns the predecessor of the specified Entry, or null if no such.
224.2008 + */
224.2009 + static <K,V> Entry<K,V> predecessor(Entry<K,V> t) {
224.2010 + if (t == null)
224.2011 + return null;
224.2012 + else if (t.left != null) {
224.2013 + Entry<K,V> p = t.left;
224.2014 + while (p.right != null)
224.2015 + p = p.right;
224.2016 + return p;
224.2017 + } else {
224.2018 + Entry<K,V> p = t.parent;
224.2019 + Entry<K,V> ch = t;
224.2020 + while (p != null && ch == p.left) {
224.2021 + ch = p;
224.2022 + p = p.parent;
224.2023 + }
224.2024 + return p;
224.2025 + }
224.2026 + }
224.2027 +
224.2028 + /**
224.2029 + * Balancing operations.
224.2030 + *
224.2031 + * Implementations of rebalancings during insertion and deletion are
224.2032 + * slightly different than the CLR version. Rather than using dummy
224.2033 + * nilnodes, we use a set of accessors that deal properly with null. They
224.2034 + * are used to avoid messiness surrounding nullness checks in the main
224.2035 + * algorithms.
224.2036 + */
224.2037 +
224.2038 + private static <K,V> boolean colorOf(Entry<K,V> p) {
224.2039 + return (p == null ? BLACK : p.color);
224.2040 + }
224.2041 +
224.2042 + private static <K,V> Entry<K,V> parentOf(Entry<K,V> p) {
224.2043 + return (p == null ? null: p.parent);
224.2044 + }
224.2045 +
224.2046 + private static <K,V> void setColor(Entry<K,V> p, boolean c) {
224.2047 + if (p != null)
224.2048 + p.color = c;
224.2049 + }
224.2050 +
224.2051 + private static <K,V> Entry<K,V> leftOf(Entry<K,V> p) {
224.2052 + return (p == null) ? null: p.left;
224.2053 + }
224.2054 +
224.2055 + private static <K,V> Entry<K,V> rightOf(Entry<K,V> p) {
224.2056 + return (p == null) ? null: p.right;
224.2057 + }
224.2058 +
224.2059 + /** From CLR */
224.2060 + private void rotateLeft(Entry<K,V> p) {
224.2061 + if (p != null) {
224.2062 + Entry<K,V> r = p.right;
224.2063 + p.right = r.left;
224.2064 + if (r.left != null)
224.2065 + r.left.parent = p;
224.2066 + r.parent = p.parent;
224.2067 + if (p.parent == null)
224.2068 + root = r;
224.2069 + else if (p.parent.left == p)
224.2070 + p.parent.left = r;
224.2071 + else
224.2072 + p.parent.right = r;
224.2073 + r.left = p;
224.2074 + p.parent = r;
224.2075 + }
224.2076 + }
224.2077 +
224.2078 + /** From CLR */
224.2079 + private void rotateRight(Entry<K,V> p) {
224.2080 + if (p != null) {
224.2081 + Entry<K,V> l = p.left;
224.2082 + p.left = l.right;
224.2083 + if (l.right != null) l.right.parent = p;
224.2084 + l.parent = p.parent;
224.2085 + if (p.parent == null)
224.2086 + root = l;
224.2087 + else if (p.parent.right == p)
224.2088 + p.parent.right = l;
224.2089 + else p.parent.left = l;
224.2090 + l.right = p;
224.2091 + p.parent = l;
224.2092 + }
224.2093 + }
224.2094 +
224.2095 + /** From CLR */
224.2096 + private void fixAfterInsertion(Entry<K,V> x) {
224.2097 + x.color = RED;
224.2098 +
224.2099 + while (x != null && x != root && x.parent.color == RED) {
224.2100 + if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
224.2101 + Entry<K,V> y = rightOf(parentOf(parentOf(x)));
224.2102 + if (colorOf(y) == RED) {
224.2103 + setColor(parentOf(x), BLACK);
224.2104 + setColor(y, BLACK);
224.2105 + setColor(parentOf(parentOf(x)), RED);
224.2106 + x = parentOf(parentOf(x));
224.2107 + } else {
224.2108 + if (x == rightOf(parentOf(x))) {
224.2109 + x = parentOf(x);
224.2110 + rotateLeft(x);
224.2111 + }
224.2112 + setColor(parentOf(x), BLACK);
224.2113 + setColor(parentOf(parentOf(x)), RED);
224.2114 + rotateRight(parentOf(parentOf(x)));
224.2115 + }
224.2116 + } else {
224.2117 + Entry<K,V> y = leftOf(parentOf(parentOf(x)));
224.2118 + if (colorOf(y) == RED) {
224.2119 + setColor(parentOf(x), BLACK);
224.2120 + setColor(y, BLACK);
224.2121 + setColor(parentOf(parentOf(x)), RED);
224.2122 + x = parentOf(parentOf(x));
224.2123 + } else {
224.2124 + if (x == leftOf(parentOf(x))) {
224.2125 + x = parentOf(x);
224.2126 + rotateRight(x);
224.2127 + }
224.2128 + setColor(parentOf(x), BLACK);
224.2129 + setColor(parentOf(parentOf(x)), RED);
224.2130 + rotateLeft(parentOf(parentOf(x)));
224.2131 + }
224.2132 + }
224.2133 + }
224.2134 + root.color = BLACK;
224.2135 + }
224.2136 +
224.2137 + /**
224.2138 + * Delete node p, and then rebalance the tree.
224.2139 + */
224.2140 + private void deleteEntry(Entry<K,V> p) {
224.2141 + modCount++;
224.2142 + size--;
224.2143 +
224.2144 + // If strictly internal, copy successor's element to p and then make p
224.2145 + // point to successor.
224.2146 + if (p.left != null && p.right != null) {
224.2147 + Entry<K,V> s = successor(p);
224.2148 + p.key = s.key;
224.2149 + p.value = s.value;
224.2150 + p = s;
224.2151 + } // p has 2 children
224.2152 +
224.2153 + // Start fixup at replacement node, if it exists.
224.2154 + Entry<K,V> replacement = (p.left != null ? p.left : p.right);
224.2155 +
224.2156 + if (replacement != null) {
224.2157 + // Link replacement to parent
224.2158 + replacement.parent = p.parent;
224.2159 + if (p.parent == null)
224.2160 + root = replacement;
224.2161 + else if (p == p.parent.left)
224.2162 + p.parent.left = replacement;
224.2163 + else
224.2164 + p.parent.right = replacement;
224.2165 +
224.2166 + // Null out links so they are OK to use by fixAfterDeletion.
224.2167 + p.left = p.right = p.parent = null;
224.2168 +
224.2169 + // Fix replacement
224.2170 + if (p.color == BLACK)
224.2171 + fixAfterDeletion(replacement);
224.2172 + } else if (p.parent == null) { // return if we are the only node.
224.2173 + root = null;
224.2174 + } else { // No children. Use self as phantom replacement and unlink.
224.2175 + if (p.color == BLACK)
224.2176 + fixAfterDeletion(p);
224.2177 +
224.2178 + if (p.parent != null) {
224.2179 + if (p == p.parent.left)
224.2180 + p.parent.left = null;
224.2181 + else if (p == p.parent.right)
224.2182 + p.parent.right = null;
224.2183 + p.parent = null;
224.2184 + }
224.2185 + }
224.2186 + }
224.2187 +
224.2188 + /** From CLR */
224.2189 + private void fixAfterDeletion(Entry<K,V> x) {
224.2190 + while (x != root && colorOf(x) == BLACK) {
224.2191 + if (x == leftOf(parentOf(x))) {
224.2192 + Entry<K,V> sib = rightOf(parentOf(x));
224.2193 +
224.2194 + if (colorOf(sib) == RED) {
224.2195 + setColor(sib, BLACK);
224.2196 + setColor(parentOf(x), RED);
224.2197 + rotateLeft(parentOf(x));
224.2198 + sib = rightOf(parentOf(x));
224.2199 + }
224.2200 +
224.2201 + if (colorOf(leftOf(sib)) == BLACK &&
224.2202 + colorOf(rightOf(sib)) == BLACK) {
224.2203 + setColor(sib, RED);
224.2204 + x = parentOf(x);
224.2205 + } else {
224.2206 + if (colorOf(rightOf(sib)) == BLACK) {
224.2207 + setColor(leftOf(sib), BLACK);
224.2208 + setColor(sib, RED);
224.2209 + rotateRight(sib);
224.2210 + sib = rightOf(parentOf(x));
224.2211 + }
224.2212 + setColor(sib, colorOf(parentOf(x)));
224.2213 + setColor(parentOf(x), BLACK);
224.2214 + setColor(rightOf(sib), BLACK);
224.2215 + rotateLeft(parentOf(x));
224.2216 + x = root;
224.2217 + }
224.2218 + } else { // symmetric
224.2219 + Entry<K,V> sib = leftOf(parentOf(x));
224.2220 +
224.2221 + if (colorOf(sib) == RED) {
224.2222 + setColor(sib, BLACK);
224.2223 + setColor(parentOf(x), RED);
224.2224 + rotateRight(parentOf(x));
224.2225 + sib = leftOf(parentOf(x));
224.2226 + }
224.2227 +
224.2228 + if (colorOf(rightOf(sib)) == BLACK &&
224.2229 + colorOf(leftOf(sib)) == BLACK) {
224.2230 + setColor(sib, RED);
224.2231 + x = parentOf(x);
224.2232 + } else {
224.2233 + if (colorOf(leftOf(sib)) == BLACK) {
224.2234 + setColor(rightOf(sib), BLACK);
224.2235 + setColor(sib, RED);
224.2236 + rotateLeft(sib);
224.2237 + sib = leftOf(parentOf(x));
224.2238 + }
224.2239 + setColor(sib, colorOf(parentOf(x)));
224.2240 + setColor(parentOf(x), BLACK);
224.2241 + setColor(leftOf(sib), BLACK);
224.2242 + rotateRight(parentOf(x));
224.2243 + x = root;
224.2244 + }
224.2245 + }
224.2246 + }
224.2247 +
224.2248 + setColor(x, BLACK);
224.2249 + }
224.2250 +
224.2251 + private static final long serialVersionUID = 919286545866124006L;
224.2252 +
224.2253 + /**
224.2254 + * Save the state of the {@code TreeMap} instance to a stream (i.e.,
224.2255 + * serialize it).
224.2256 + *
224.2257 + * @serialData The <em>size</em> of the TreeMap (the number of key-value
224.2258 + * mappings) is emitted (int), followed by the key (Object)
224.2259 + * and value (Object) for each key-value mapping represented
224.2260 + * by the TreeMap. The key-value mappings are emitted in
224.2261 + * key-order (as determined by the TreeMap's Comparator,
224.2262 + * or by the keys' natural ordering if the TreeMap has no
224.2263 + * Comparator).
224.2264 + */
224.2265 + private void writeObject(java.io.ObjectOutputStream s)
224.2266 + throws java.io.IOException {
224.2267 + // Write out the Comparator and any hidden stuff
224.2268 + s.defaultWriteObject();
224.2269 +
224.2270 + // Write out size (number of Mappings)
224.2271 + s.writeInt(size);
224.2272 +
224.2273 + // Write out keys and values (alternating)
224.2274 + for (Iterator<Map.Entry<K,V>> i = entrySet().iterator(); i.hasNext(); ) {
224.2275 + Map.Entry<K,V> e = i.next();
224.2276 + s.writeObject(e.getKey());
224.2277 + s.writeObject(e.getValue());
224.2278 + }
224.2279 + }
224.2280 +
224.2281 + /**
224.2282 + * Reconstitute the {@code TreeMap} instance from a stream (i.e.,
224.2283 + * deserialize it).
224.2284 + */
224.2285 + private void readObject(final java.io.ObjectInputStream s)
224.2286 + throws java.io.IOException, ClassNotFoundException {
224.2287 + // Read in the Comparator and any hidden stuff
224.2288 + s.defaultReadObject();
224.2289 +
224.2290 + // Read in size
224.2291 + int size = s.readInt();
224.2292 +
224.2293 + buildFromSorted(size, null, s, null);
224.2294 + }
224.2295 +
224.2296 + /** Intended to be called only from TreeSet.readObject */
224.2297 + void readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal)
224.2298 + throws java.io.IOException, ClassNotFoundException {
224.2299 + buildFromSorted(size, null, s, defaultVal);
224.2300 + }
224.2301 +
224.2302 + /** Intended to be called only from TreeSet.addAll */
224.2303 + void addAllForTreeSet(SortedSet<? extends K> set, V defaultVal) {
224.2304 + try {
224.2305 + buildFromSorted(set.size(), set.iterator(), null, defaultVal);
224.2306 + } catch (java.io.IOException cannotHappen) {
224.2307 + } catch (ClassNotFoundException cannotHappen) {
224.2308 + }
224.2309 + }
224.2310 +
224.2311 +
224.2312 + /**
224.2313 + * Linear time tree building algorithm from sorted data. Can accept keys
224.2314 + * and/or values from iterator or stream. This leads to too many
224.2315 + * parameters, but seems better than alternatives. The four formats
224.2316 + * that this method accepts are:
224.2317 + *
224.2318 + * 1) An iterator of Map.Entries. (it != null, defaultVal == null).
224.2319 + * 2) An iterator of keys. (it != null, defaultVal != null).
224.2320 + * 3) A stream of alternating serialized keys and values.
224.2321 + * (it == null, defaultVal == null).
224.2322 + * 4) A stream of serialized keys. (it == null, defaultVal != null).
224.2323 + *
224.2324 + * It is assumed that the comparator of the TreeMap is already set prior
224.2325 + * to calling this method.
224.2326 + *
224.2327 + * @param size the number of keys (or key-value pairs) to be read from
224.2328 + * the iterator or stream
224.2329 + * @param it If non-null, new entries are created from entries
224.2330 + * or keys read from this iterator.
224.2331 + * @param str If non-null, new entries are created from keys and
224.2332 + * possibly values read from this stream in serialized form.
224.2333 + * Exactly one of it and str should be non-null.
224.2334 + * @param defaultVal if non-null, this default value is used for
224.2335 + * each value in the map. If null, each value is read from
224.2336 + * iterator or stream, as described above.
224.2337 + * @throws IOException propagated from stream reads. This cannot
224.2338 + * occur if str is null.
224.2339 + * @throws ClassNotFoundException propagated from readObject.
224.2340 + * This cannot occur if str is null.
224.2341 + */
224.2342 + private void buildFromSorted(int size, Iterator it,
224.2343 + java.io.ObjectInputStream str,
224.2344 + V defaultVal)
224.2345 + throws java.io.IOException, ClassNotFoundException {
224.2346 + this.size = size;
224.2347 + root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
224.2348 + it, str, defaultVal);
224.2349 + }
224.2350 +
224.2351 + /**
224.2352 + * Recursive "helper method" that does the real work of the
224.2353 + * previous method. Identically named parameters have
224.2354 + * identical definitions. Additional parameters are documented below.
224.2355 + * It is assumed that the comparator and size fields of the TreeMap are
224.2356 + * already set prior to calling this method. (It ignores both fields.)
224.2357 + *
224.2358 + * @param level the current level of tree. Initial call should be 0.
224.2359 + * @param lo the first element index of this subtree. Initial should be 0.
224.2360 + * @param hi the last element index of this subtree. Initial should be
224.2361 + * size-1.
224.2362 + * @param redLevel the level at which nodes should be red.
224.2363 + * Must be equal to computeRedLevel for tree of this size.
224.2364 + */
224.2365 + private final Entry<K,V> buildFromSorted(int level, int lo, int hi,
224.2366 + int redLevel,
224.2367 + Iterator it,
224.2368 + java.io.ObjectInputStream str,
224.2369 + V defaultVal)
224.2370 + throws java.io.IOException, ClassNotFoundException {
224.2371 + /*
224.2372 + * Strategy: The root is the middlemost element. To get to it, we
224.2373 + * have to first recursively construct the entire left subtree,
224.2374 + * so as to grab all of its elements. We can then proceed with right
224.2375 + * subtree.
224.2376 + *
224.2377 + * The lo and hi arguments are the minimum and maximum
224.2378 + * indices to pull out of the iterator or stream for current subtree.
224.2379 + * They are not actually indexed, we just proceed sequentially,
224.2380 + * ensuring that items are extracted in corresponding order.
224.2381 + */
224.2382 +
224.2383 + if (hi < lo) return null;
224.2384 +
224.2385 + int mid = (lo + hi) >>> 1;
224.2386 +
224.2387 + Entry<K,V> left = null;
224.2388 + if (lo < mid)
224.2389 + left = buildFromSorted(level+1, lo, mid - 1, redLevel,
224.2390 + it, str, defaultVal);
224.2391 +
224.2392 + // extract key and/or value from iterator or stream
224.2393 + K key;
224.2394 + V value;
224.2395 + if (it != null) {
224.2396 + if (defaultVal==null) {
224.2397 + Map.Entry<K,V> entry = (Map.Entry<K,V>)it.next();
224.2398 + key = entry.getKey();
224.2399 + value = entry.getValue();
224.2400 + } else {
224.2401 + key = (K)it.next();
224.2402 + value = defaultVal;
224.2403 + }
224.2404 + } else { // use stream
224.2405 + key = (K) str.readObject();
224.2406 + value = (defaultVal != null ? defaultVal : (V) str.readObject());
224.2407 + }
224.2408 +
224.2409 + Entry<K,V> middle = new Entry<>(key, value, null);
224.2410 +
224.2411 + // color nodes in non-full bottommost level red
224.2412 + if (level == redLevel)
224.2413 + middle.color = RED;
224.2414 +
224.2415 + if (left != null) {
224.2416 + middle.left = left;
224.2417 + left.parent = middle;
224.2418 + }
224.2419 +
224.2420 + if (mid < hi) {
224.2421 + Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
224.2422 + it, str, defaultVal);
224.2423 + middle.right = right;
224.2424 + right.parent = middle;
224.2425 + }
224.2426 +
224.2427 + return middle;
224.2428 + }
224.2429 +
224.2430 + /**
224.2431 + * Find the level down to which to assign all nodes BLACK. This is the
224.2432 + * last `full' level of the complete binary tree produced by
224.2433 + * buildTree. The remaining nodes are colored RED. (This makes a `nice'
224.2434 + * set of color assignments wrt future insertions.) This level number is
224.2435 + * computed by finding the number of splits needed to reach the zeroeth
224.2436 + * node. (The answer is ~lg(N), but in any case must be computed by same
224.2437 + * quick O(lg(N)) loop.)
224.2438 + */
224.2439 + private static int computeRedLevel(int sz) {
224.2440 + int level = 0;
224.2441 + for (int m = sz - 1; m >= 0; m = m / 2 - 1)
224.2442 + level++;
224.2443 + return level;
224.2444 + }
224.2445 +}
225.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
225.2 +++ b/rt/emul/compact/src/main/java/java/util/TreeSet.java Wed Apr 30 15:04:10 2014 +0200
225.3 @@ -0,0 +1,539 @@
225.4 +/*
225.5 + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
225.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
225.7 + *
225.8 + * This code is free software; you can redistribute it and/or modify it
225.9 + * under the terms of the GNU General Public License version 2 only, as
225.10 + * published by the Free Software Foundation. Oracle designates this
225.11 + * particular file as subject to the "Classpath" exception as provided
225.12 + * by Oracle in the LICENSE file that accompanied this code.
225.13 + *
225.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
225.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
225.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
225.17 + * version 2 for more details (a copy is included in the LICENSE file that
225.18 + * accompanied this code).
225.19 + *
225.20 + * You should have received a copy of the GNU General Public License version
225.21 + * 2 along with this work; if not, write to the Free Software Foundation,
225.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
225.23 + *
225.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
225.25 + * or visit www.oracle.com if you need additional information or have any
225.26 + * questions.
225.27 + */
225.28 +
225.29 +package java.util;
225.30 +
225.31 +/**
225.32 + * A {@link NavigableSet} implementation based on a {@link TreeMap}.
225.33 + * The elements are ordered using their {@linkplain Comparable natural
225.34 + * ordering}, or by a {@link Comparator} provided at set creation
225.35 + * time, depending on which constructor is used.
225.36 + *
225.37 + * <p>This implementation provides guaranteed log(n) time cost for the basic
225.38 + * operations ({@code add}, {@code remove} and {@code contains}).
225.39 + *
225.40 + * <p>Note that the ordering maintained by a set (whether or not an explicit
225.41 + * comparator is provided) must be <i>consistent with equals</i> if it is to
225.42 + * correctly implement the {@code Set} interface. (See {@code Comparable}
225.43 + * or {@code Comparator} for a precise definition of <i>consistent with
225.44 + * equals</i>.) This is so because the {@code Set} interface is defined in
225.45 + * terms of the {@code equals} operation, but a {@code TreeSet} instance
225.46 + * performs all element comparisons using its {@code compareTo} (or
225.47 + * {@code compare}) method, so two elements that are deemed equal by this method
225.48 + * are, from the standpoint of the set, equal. The behavior of a set
225.49 + * <i>is</i> well-defined even if its ordering is inconsistent with equals; it
225.50 + * just fails to obey the general contract of the {@code Set} interface.
225.51 + *
225.52 + * <p><strong>Note that this implementation is not synchronized.</strong>
225.53 + * If multiple threads access a tree set concurrently, and at least one
225.54 + * of the threads modifies the set, it <i>must</i> be synchronized
225.55 + * externally. This is typically accomplished by synchronizing on some
225.56 + * object that naturally encapsulates the set.
225.57 + * If no such object exists, the set should be "wrapped" using the
225.58 + * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet}
225.59 + * method. This is best done at creation time, to prevent accidental
225.60 + * unsynchronized access to the set: <pre>
225.61 + * SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));</pre>
225.62 + *
225.63 + * <p>The iterators returned by this class's {@code iterator} method are
225.64 + * <i>fail-fast</i>: if the set is modified at any time after the iterator is
225.65 + * created, in any way except through the iterator's own {@code remove}
225.66 + * method, the iterator will throw a {@link ConcurrentModificationException}.
225.67 + * Thus, in the face of concurrent modification, the iterator fails quickly
225.68 + * and cleanly, rather than risking arbitrary, non-deterministic behavior at
225.69 + * an undetermined time in the future.
225.70 + *
225.71 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
225.72 + * as it is, generally speaking, impossible to make any hard guarantees in the
225.73 + * presence of unsynchronized concurrent modification. Fail-fast iterators
225.74 + * throw {@code ConcurrentModificationException} on a best-effort basis.
225.75 + * Therefore, it would be wrong to write a program that depended on this
225.76 + * exception for its correctness: <i>the fail-fast behavior of iterators
225.77 + * should be used only to detect bugs.</i>
225.78 + *
225.79 + * <p>This class is a member of the
225.80 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
225.81 + * Java Collections Framework</a>.
225.82 + *
225.83 + * @param <E> the type of elements maintained by this set
225.84 + *
225.85 + * @author Josh Bloch
225.86 + * @see Collection
225.87 + * @see Set
225.88 + * @see HashSet
225.89 + * @see Comparable
225.90 + * @see Comparator
225.91 + * @see TreeMap
225.92 + * @since 1.2
225.93 + */
225.94 +
225.95 +public class TreeSet<E> extends AbstractSet<E>
225.96 + implements NavigableSet<E>, Cloneable, java.io.Serializable
225.97 +{
225.98 + /**
225.99 + * The backing map.
225.100 + */
225.101 + private transient NavigableMap<E,Object> m;
225.102 +
225.103 + // Dummy value to associate with an Object in the backing Map
225.104 + private static final Object PRESENT = new Object();
225.105 +
225.106 + /**
225.107 + * Constructs a set backed by the specified navigable map.
225.108 + */
225.109 + TreeSet(NavigableMap<E,Object> m) {
225.110 + this.m = m;
225.111 + }
225.112 +
225.113 + /**
225.114 + * Constructs a new, empty tree set, sorted according to the
225.115 + * natural ordering of its elements. All elements inserted into
225.116 + * the set must implement the {@link Comparable} interface.
225.117 + * Furthermore, all such elements must be <i>mutually
225.118 + * comparable</i>: {@code e1.compareTo(e2)} must not throw a
225.119 + * {@code ClassCastException} for any elements {@code e1} and
225.120 + * {@code e2} in the set. If the user attempts to add an element
225.121 + * to the set that violates this constraint (for example, the user
225.122 + * attempts to add a string element to a set whose elements are
225.123 + * integers), the {@code add} call will throw a
225.124 + * {@code ClassCastException}.
225.125 + */
225.126 + public TreeSet() {
225.127 + this(new TreeMap<E,Object>());
225.128 + }
225.129 +
225.130 + /**
225.131 + * Constructs a new, empty tree set, sorted according to the specified
225.132 + * comparator. All elements inserted into the set must be <i>mutually
225.133 + * comparable</i> by the specified comparator: {@code comparator.compare(e1,
225.134 + * e2)} must not throw a {@code ClassCastException} for any elements
225.135 + * {@code e1} and {@code e2} in the set. If the user attempts to add
225.136 + * an element to the set that violates this constraint, the
225.137 + * {@code add} call will throw a {@code ClassCastException}.
225.138 + *
225.139 + * @param comparator the comparator that will be used to order this set.
225.140 + * If {@code null}, the {@linkplain Comparable natural
225.141 + * ordering} of the elements will be used.
225.142 + */
225.143 + public TreeSet(Comparator<? super E> comparator) {
225.144 + this(new TreeMap<>(comparator));
225.145 + }
225.146 +
225.147 + /**
225.148 + * Constructs a new tree set containing the elements in the specified
225.149 + * collection, sorted according to the <i>natural ordering</i> of its
225.150 + * elements. All elements inserted into the set must implement the
225.151 + * {@link Comparable} interface. Furthermore, all such elements must be
225.152 + * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
225.153 + * {@code ClassCastException} for any elements {@code e1} and
225.154 + * {@code e2} in the set.
225.155 + *
225.156 + * @param c collection whose elements will comprise the new set
225.157 + * @throws ClassCastException if the elements in {@code c} are
225.158 + * not {@link Comparable}, or are not mutually comparable
225.159 + * @throws NullPointerException if the specified collection is null
225.160 + */
225.161 + public TreeSet(Collection<? extends E> c) {
225.162 + this();
225.163 + addAll(c);
225.164 + }
225.165 +
225.166 + /**
225.167 + * Constructs a new tree set containing the same elements and
225.168 + * using the same ordering as the specified sorted set.
225.169 + *
225.170 + * @param s sorted set whose elements will comprise the new set
225.171 + * @throws NullPointerException if the specified sorted set is null
225.172 + */
225.173 + public TreeSet(SortedSet<E> s) {
225.174 + this(s.comparator());
225.175 + addAll(s);
225.176 + }
225.177 +
225.178 + /**
225.179 + * Returns an iterator over the elements in this set in ascending order.
225.180 + *
225.181 + * @return an iterator over the elements in this set in ascending order
225.182 + */
225.183 + public Iterator<E> iterator() {
225.184 + return m.navigableKeySet().iterator();
225.185 + }
225.186 +
225.187 + /**
225.188 + * Returns an iterator over the elements in this set in descending order.
225.189 + *
225.190 + * @return an iterator over the elements in this set in descending order
225.191 + * @since 1.6
225.192 + */
225.193 + public Iterator<E> descendingIterator() {
225.194 + return m.descendingKeySet().iterator();
225.195 + }
225.196 +
225.197 + /**
225.198 + * @since 1.6
225.199 + */
225.200 + public NavigableSet<E> descendingSet() {
225.201 + return new TreeSet<>(m.descendingMap());
225.202 + }
225.203 +
225.204 + /**
225.205 + * Returns the number of elements in this set (its cardinality).
225.206 + *
225.207 + * @return the number of elements in this set (its cardinality)
225.208 + */
225.209 + public int size() {
225.210 + return m.size();
225.211 + }
225.212 +
225.213 + /**
225.214 + * Returns {@code true} if this set contains no elements.
225.215 + *
225.216 + * @return {@code true} if this set contains no elements
225.217 + */
225.218 + public boolean isEmpty() {
225.219 + return m.isEmpty();
225.220 + }
225.221 +
225.222 + /**
225.223 + * Returns {@code true} if this set contains the specified element.
225.224 + * More formally, returns {@code true} if and only if this set
225.225 + * contains an element {@code e} such that
225.226 + * <tt>(o==null ? e==null : o.equals(e))</tt>.
225.227 + *
225.228 + * @param o object to be checked for containment in this set
225.229 + * @return {@code true} if this set contains the specified element
225.230 + * @throws ClassCastException if the specified object cannot be compared
225.231 + * with the elements currently in the set
225.232 + * @throws NullPointerException if the specified element is null
225.233 + * and this set uses natural ordering, or its comparator
225.234 + * does not permit null elements
225.235 + */
225.236 + public boolean contains(Object o) {
225.237 + return m.containsKey(o);
225.238 + }
225.239 +
225.240 + /**
225.241 + * Adds the specified element to this set if it is not already present.
225.242 + * More formally, adds the specified element {@code e} to this set if
225.243 + * the set contains no element {@code e2} such that
225.244 + * <tt>(e==null ? e2==null : e.equals(e2))</tt>.
225.245 + * If this set already contains the element, the call leaves the set
225.246 + * unchanged and returns {@code false}.
225.247 + *
225.248 + * @param e element to be added to this set
225.249 + * @return {@code true} if this set did not already contain the specified
225.250 + * element
225.251 + * @throws ClassCastException if the specified object cannot be compared
225.252 + * with the elements currently in this set
225.253 + * @throws NullPointerException if the specified element is null
225.254 + * and this set uses natural ordering, or its comparator
225.255 + * does not permit null elements
225.256 + */
225.257 + public boolean add(E e) {
225.258 + return m.put(e, PRESENT)==null;
225.259 + }
225.260 +
225.261 + /**
225.262 + * Removes the specified element from this set if it is present.
225.263 + * More formally, removes an element {@code e} such that
225.264 + * <tt>(o==null ? e==null : o.equals(e))</tt>,
225.265 + * if this set contains such an element. Returns {@code true} if
225.266 + * this set contained the element (or equivalently, if this set
225.267 + * changed as a result of the call). (This set will not contain the
225.268 + * element once the call returns.)
225.269 + *
225.270 + * @param o object to be removed from this set, if present
225.271 + * @return {@code true} if this set contained the specified element
225.272 + * @throws ClassCastException if the specified object cannot be compared
225.273 + * with the elements currently in this set
225.274 + * @throws NullPointerException if the specified element is null
225.275 + * and this set uses natural ordering, or its comparator
225.276 + * does not permit null elements
225.277 + */
225.278 + public boolean remove(Object o) {
225.279 + return m.remove(o)==PRESENT;
225.280 + }
225.281 +
225.282 + /**
225.283 + * Removes all of the elements from this set.
225.284 + * The set will be empty after this call returns.
225.285 + */
225.286 + public void clear() {
225.287 + m.clear();
225.288 + }
225.289 +
225.290 + /**
225.291 + * Adds all of the elements in the specified collection to this set.
225.292 + *
225.293 + * @param c collection containing elements to be added to this set
225.294 + * @return {@code true} if this set changed as a result of the call
225.295 + * @throws ClassCastException if the elements provided cannot be compared
225.296 + * with the elements currently in the set
225.297 + * @throws NullPointerException if the specified collection is null or
225.298 + * if any element is null and this set uses natural ordering, or
225.299 + * its comparator does not permit null elements
225.300 + */
225.301 + public boolean addAll(Collection<? extends E> c) {
225.302 + // Use linear-time version if applicable
225.303 + if (m.size()==0 && c.size() > 0 &&
225.304 + c instanceof SortedSet &&
225.305 + m instanceof TreeMap) {
225.306 + SortedSet<? extends E> set = (SortedSet<? extends E>) c;
225.307 + TreeMap<E,Object> map = (TreeMap<E, Object>) m;
225.308 + Comparator<? super E> cc = (Comparator<? super E>) set.comparator();
225.309 + Comparator<? super E> mc = map.comparator();
225.310 + if (cc==mc || (cc != null && cc.equals(mc))) {
225.311 + map.addAllForTreeSet(set, PRESENT);
225.312 + return true;
225.313 + }
225.314 + }
225.315 + return super.addAll(c);
225.316 + }
225.317 +
225.318 + /**
225.319 + * @throws ClassCastException {@inheritDoc}
225.320 + * @throws NullPointerException if {@code fromElement} or {@code toElement}
225.321 + * is null and this set uses natural ordering, or its comparator
225.322 + * does not permit null elements
225.323 + * @throws IllegalArgumentException {@inheritDoc}
225.324 + * @since 1.6
225.325 + */
225.326 + public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
225.327 + E toElement, boolean toInclusive) {
225.328 + return new TreeSet<>(m.subMap(fromElement, fromInclusive,
225.329 + toElement, toInclusive));
225.330 + }
225.331 +
225.332 + /**
225.333 + * @throws ClassCastException {@inheritDoc}
225.334 + * @throws NullPointerException if {@code toElement} is null and
225.335 + * this set uses natural ordering, or its comparator does
225.336 + * not permit null elements
225.337 + * @throws IllegalArgumentException {@inheritDoc}
225.338 + * @since 1.6
225.339 + */
225.340 + public NavigableSet<E> headSet(E toElement, boolean inclusive) {
225.341 + return new TreeSet<>(m.headMap(toElement, inclusive));
225.342 + }
225.343 +
225.344 + /**
225.345 + * @throws ClassCastException {@inheritDoc}
225.346 + * @throws NullPointerException if {@code fromElement} is null and
225.347 + * this set uses natural ordering, or its comparator does
225.348 + * not permit null elements
225.349 + * @throws IllegalArgumentException {@inheritDoc}
225.350 + * @since 1.6
225.351 + */
225.352 + public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
225.353 + return new TreeSet<>(m.tailMap(fromElement, inclusive));
225.354 + }
225.355 +
225.356 + /**
225.357 + * @throws ClassCastException {@inheritDoc}
225.358 + * @throws NullPointerException if {@code fromElement} or
225.359 + * {@code toElement} is null and this set uses natural ordering,
225.360 + * or its comparator does not permit null elements
225.361 + * @throws IllegalArgumentException {@inheritDoc}
225.362 + */
225.363 + public SortedSet<E> subSet(E fromElement, E toElement) {
225.364 + return subSet(fromElement, true, toElement, false);
225.365 + }
225.366 +
225.367 + /**
225.368 + * @throws ClassCastException {@inheritDoc}
225.369 + * @throws NullPointerException if {@code toElement} is null
225.370 + * and this set uses natural ordering, or its comparator does
225.371 + * not permit null elements
225.372 + * @throws IllegalArgumentException {@inheritDoc}
225.373 + */
225.374 + public SortedSet<E> headSet(E toElement) {
225.375 + return headSet(toElement, false);
225.376 + }
225.377 +
225.378 + /**
225.379 + * @throws ClassCastException {@inheritDoc}
225.380 + * @throws NullPointerException if {@code fromElement} is null
225.381 + * and this set uses natural ordering, or its comparator does
225.382 + * not permit null elements
225.383 + * @throws IllegalArgumentException {@inheritDoc}
225.384 + */
225.385 + public SortedSet<E> tailSet(E fromElement) {
225.386 + return tailSet(fromElement, true);
225.387 + }
225.388 +
225.389 + public Comparator<? super E> comparator() {
225.390 + return m.comparator();
225.391 + }
225.392 +
225.393 + /**
225.394 + * @throws NoSuchElementException {@inheritDoc}
225.395 + */
225.396 + public E first() {
225.397 + return m.firstKey();
225.398 + }
225.399 +
225.400 + /**
225.401 + * @throws NoSuchElementException {@inheritDoc}
225.402 + */
225.403 + public E last() {
225.404 + return m.lastKey();
225.405 + }
225.406 +
225.407 + // NavigableSet API methods
225.408 +
225.409 + /**
225.410 + * @throws ClassCastException {@inheritDoc}
225.411 + * @throws NullPointerException if the specified element is null
225.412 + * and this set uses natural ordering, or its comparator
225.413 + * does not permit null elements
225.414 + * @since 1.6
225.415 + */
225.416 + public E lower(E e) {
225.417 + return m.lowerKey(e);
225.418 + }
225.419 +
225.420 + /**
225.421 + * @throws ClassCastException {@inheritDoc}
225.422 + * @throws NullPointerException if the specified element is null
225.423 + * and this set uses natural ordering, or its comparator
225.424 + * does not permit null elements
225.425 + * @since 1.6
225.426 + */
225.427 + public E floor(E e) {
225.428 + return m.floorKey(e);
225.429 + }
225.430 +
225.431 + /**
225.432 + * @throws ClassCastException {@inheritDoc}
225.433 + * @throws NullPointerException if the specified element is null
225.434 + * and this set uses natural ordering, or its comparator
225.435 + * does not permit null elements
225.436 + * @since 1.6
225.437 + */
225.438 + public E ceiling(E e) {
225.439 + return m.ceilingKey(e);
225.440 + }
225.441 +
225.442 + /**
225.443 + * @throws ClassCastException {@inheritDoc}
225.444 + * @throws NullPointerException if the specified element is null
225.445 + * and this set uses natural ordering, or its comparator
225.446 + * does not permit null elements
225.447 + * @since 1.6
225.448 + */
225.449 + public E higher(E e) {
225.450 + return m.higherKey(e);
225.451 + }
225.452 +
225.453 + /**
225.454 + * @since 1.6
225.455 + */
225.456 + public E pollFirst() {
225.457 + Map.Entry<E,?> e = m.pollFirstEntry();
225.458 + return (e == null) ? null : e.getKey();
225.459 + }
225.460 +
225.461 + /**
225.462 + * @since 1.6
225.463 + */
225.464 + public E pollLast() {
225.465 + Map.Entry<E,?> e = m.pollLastEntry();
225.466 + return (e == null) ? null : e.getKey();
225.467 + }
225.468 +
225.469 + /**
225.470 + * Returns a shallow copy of this {@code TreeSet} instance. (The elements
225.471 + * themselves are not cloned.)
225.472 + *
225.473 + * @return a shallow copy of this set
225.474 + */
225.475 + public Object clone() {
225.476 + TreeSet<E> clone = null;
225.477 + try {
225.478 + clone = (TreeSet<E>) super.clone();
225.479 + } catch (CloneNotSupportedException e) {
225.480 + throw new InternalError();
225.481 + }
225.482 +
225.483 + clone.m = new TreeMap<>(m);
225.484 + return clone;
225.485 + }
225.486 +
225.487 + /**
225.488 + * Save the state of the {@code TreeSet} instance to a stream (that is,
225.489 + * serialize it).
225.490 + *
225.491 + * @serialData Emits the comparator used to order this set, or
225.492 + * {@code null} if it obeys its elements' natural ordering
225.493 + * (Object), followed by the size of the set (the number of
225.494 + * elements it contains) (int), followed by all of its
225.495 + * elements (each an Object) in order (as determined by the
225.496 + * set's Comparator, or by the elements' natural ordering if
225.497 + * the set has no Comparator).
225.498 + */
225.499 + private void writeObject(java.io.ObjectOutputStream s)
225.500 + throws java.io.IOException {
225.501 + // Write out any hidden stuff
225.502 + s.defaultWriteObject();
225.503 +
225.504 + // Write out Comparator
225.505 + s.writeObject(m.comparator());
225.506 +
225.507 + // Write out size
225.508 + s.writeInt(m.size());
225.509 +
225.510 + // Write out all elements in the proper order.
225.511 + for (E e : m.keySet())
225.512 + s.writeObject(e);
225.513 + }
225.514 +
225.515 + /**
225.516 + * Reconstitute the {@code TreeSet} instance from a stream (that is,
225.517 + * deserialize it).
225.518 + */
225.519 + private void readObject(java.io.ObjectInputStream s)
225.520 + throws java.io.IOException, ClassNotFoundException {
225.521 + // Read in any hidden stuff
225.522 + s.defaultReadObject();
225.523 +
225.524 + // Read in Comparator
225.525 + Comparator<? super E> c = (Comparator<? super E>) s.readObject();
225.526 +
225.527 + // Create backing TreeMap
225.528 + TreeMap<E,Object> tm;
225.529 + if (c==null)
225.530 + tm = new TreeMap<>();
225.531 + else
225.532 + tm = new TreeMap<>(c);
225.533 + m = tm;
225.534 +
225.535 + // Read in size
225.536 + int size = s.readInt();
225.537 +
225.538 + tm.readTreeSet(size, s, PRESENT);
225.539 + }
225.540 +
225.541 + private static final long serialVersionUID = -2479143000061671589L;
225.542 +}
226.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
226.2 +++ b/rt/emul/compact/src/main/java/java/util/WeakHashMap.java Wed Apr 30 15:04:10 2014 +0200
226.3 @@ -0,0 +1,972 @@
226.4 +/*
226.5 + * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
226.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
226.7 + *
226.8 + * This code is free software; you can redistribute it and/or modify it
226.9 + * under the terms of the GNU General Public License version 2 only, as
226.10 + * published by the Free Software Foundation. Oracle designates this
226.11 + * particular file as subject to the "Classpath" exception as provided
226.12 + * by Oracle in the LICENSE file that accompanied this code.
226.13 + *
226.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
226.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
226.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
226.17 + * version 2 for more details (a copy is included in the LICENSE file that
226.18 + * accompanied this code).
226.19 + *
226.20 + * You should have received a copy of the GNU General Public License version
226.21 + * 2 along with this work; if not, write to the Free Software Foundation,
226.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
226.23 + *
226.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
226.25 + * or visit www.oracle.com if you need additional information or have any
226.26 + * questions.
226.27 + */
226.28 +
226.29 +package java.util;
226.30 +import java.lang.ref.WeakReference;
226.31 +import java.lang.ref.ReferenceQueue;
226.32 +
226.33 +
226.34 +/**
226.35 + * Hash table based implementation of the <tt>Map</tt> interface, with
226.36 + * <em>weak keys</em>.
226.37 + * An entry in a <tt>WeakHashMap</tt> will automatically be removed when
226.38 + * its key is no longer in ordinary use. More precisely, the presence of a
226.39 + * mapping for a given key will not prevent the key from being discarded by the
226.40 + * garbage collector, that is, made finalizable, finalized, and then reclaimed.
226.41 + * When a key has been discarded its entry is effectively removed from the map,
226.42 + * so this class behaves somewhat differently from other <tt>Map</tt>
226.43 + * implementations.
226.44 + *
226.45 + * <p> Both null values and the null key are supported. This class has
226.46 + * performance characteristics similar to those of the <tt>HashMap</tt>
226.47 + * class, and has the same efficiency parameters of <em>initial capacity</em>
226.48 + * and <em>load factor</em>.
226.49 + *
226.50 + * <p> Like most collection classes, this class is not synchronized.
226.51 + * A synchronized <tt>WeakHashMap</tt> may be constructed using the
226.52 + * {@link Collections#synchronizedMap Collections.synchronizedMap}
226.53 + * method.
226.54 + *
226.55 + * <p> This class is intended primarily for use with key objects whose
226.56 + * <tt>equals</tt> methods test for object identity using the
226.57 + * <tt>==</tt> operator. Once such a key is discarded it can never be
226.58 + * recreated, so it is impossible to do a lookup of that key in a
226.59 + * <tt>WeakHashMap</tt> at some later time and be surprised that its entry
226.60 + * has been removed. This class will work perfectly well with key objects
226.61 + * whose <tt>equals</tt> methods are not based upon object identity, such
226.62 + * as <tt>String</tt> instances. With such recreatable key objects,
226.63 + * however, the automatic removal of <tt>WeakHashMap</tt> entries whose
226.64 + * keys have been discarded may prove to be confusing.
226.65 + *
226.66 + * <p> The behavior of the <tt>WeakHashMap</tt> class depends in part upon
226.67 + * the actions of the garbage collector, so several familiar (though not
226.68 + * required) <tt>Map</tt> invariants do not hold for this class. Because
226.69 + * the garbage collector may discard keys at any time, a
226.70 + * <tt>WeakHashMap</tt> may behave as though an unknown thread is silently
226.71 + * removing entries. In particular, even if you synchronize on a
226.72 + * <tt>WeakHashMap</tt> instance and invoke none of its mutator methods, it
226.73 + * is possible for the <tt>size</tt> method to return smaller values over
226.74 + * time, for the <tt>isEmpty</tt> method to return <tt>false</tt> and
226.75 + * then <tt>true</tt>, for the <tt>containsKey</tt> method to return
226.76 + * <tt>true</tt> and later <tt>false</tt> for a given key, for the
226.77 + * <tt>get</tt> method to return a value for a given key but later return
226.78 + * <tt>null</tt>, for the <tt>put</tt> method to return
226.79 + * <tt>null</tt> and the <tt>remove</tt> method to return
226.80 + * <tt>false</tt> for a key that previously appeared to be in the map, and
226.81 + * for successive examinations of the key set, the value collection, and
226.82 + * the entry set to yield successively smaller numbers of elements.
226.83 + *
226.84 + * <p> Each key object in a <tt>WeakHashMap</tt> is stored indirectly as
226.85 + * the referent of a weak reference. Therefore a key will automatically be
226.86 + * removed only after the weak references to it, both inside and outside of the
226.87 + * map, have been cleared by the garbage collector.
226.88 + *
226.89 + * <p> <strong>Implementation note:</strong> The value objects in a
226.90 + * <tt>WeakHashMap</tt> are held by ordinary strong references. Thus care
226.91 + * should be taken to ensure that value objects do not strongly refer to their
226.92 + * own keys, either directly or indirectly, since that will prevent the keys
226.93 + * from being discarded. Note that a value object may refer indirectly to its
226.94 + * key via the <tt>WeakHashMap</tt> itself; that is, a value object may
226.95 + * strongly refer to some other key object whose associated value object, in
226.96 + * turn, strongly refers to the key of the first value object. One way
226.97 + * to deal with this is to wrap values themselves within
226.98 + * <tt>WeakReferences</tt> before
226.99 + * inserting, as in: <tt>m.put(key, new WeakReference(value))</tt>,
226.100 + * and then unwrapping upon each <tt>get</tt>.
226.101 + *
226.102 + * <p>The iterators returned by the <tt>iterator</tt> method of the collections
226.103 + * returned by all of this class's "collection view methods" are
226.104 + * <i>fail-fast</i>: if the map is structurally modified at any time after the
226.105 + * iterator is created, in any way except through the iterator's own
226.106 + * <tt>remove</tt> method, the iterator will throw a {@link
226.107 + * ConcurrentModificationException}. Thus, in the face of concurrent
226.108 + * modification, the iterator fails quickly and cleanly, rather than risking
226.109 + * arbitrary, non-deterministic behavior at an undetermined time in the future.
226.110 + *
226.111 + * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
226.112 + * as it is, generally speaking, impossible to make any hard guarantees in the
226.113 + * presence of unsynchronized concurrent modification. Fail-fast iterators
226.114 + * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
226.115 + * Therefore, it would be wrong to write a program that depended on this
226.116 + * exception for its correctness: <i>the fail-fast behavior of iterators
226.117 + * should be used only to detect bugs.</i>
226.118 + *
226.119 + * <p>This class is a member of the
226.120 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
226.121 + * Java Collections Framework</a>.
226.122 + *
226.123 + * @param <K> the type of keys maintained by this map
226.124 + * @param <V> the type of mapped values
226.125 + *
226.126 + * @author Doug Lea
226.127 + * @author Josh Bloch
226.128 + * @author Mark Reinhold
226.129 + * @since 1.2
226.130 + * @see java.util.HashMap
226.131 + * @see java.lang.ref.WeakReference
226.132 + */
226.133 +public class WeakHashMap<K,V>
226.134 + extends AbstractMap<K,V>
226.135 + implements Map<K,V> {
226.136 +
226.137 + /**
226.138 + * The default initial capacity -- MUST be a power of two.
226.139 + */
226.140 + private static final int DEFAULT_INITIAL_CAPACITY = 16;
226.141 +
226.142 + /**
226.143 + * The maximum capacity, used if a higher value is implicitly specified
226.144 + * by either of the constructors with arguments.
226.145 + * MUST be a power of two <= 1<<30.
226.146 + */
226.147 + private static final int MAXIMUM_CAPACITY = 1 << 30;
226.148 +
226.149 + /**
226.150 + * The load factor used when none specified in constructor.
226.151 + */
226.152 + private static final float DEFAULT_LOAD_FACTOR = 0.75f;
226.153 +
226.154 + /**
226.155 + * The table, resized as necessary. Length MUST Always be a power of two.
226.156 + */
226.157 + Entry<K,V>[] table;
226.158 +
226.159 + /**
226.160 + * The number of key-value mappings contained in this weak hash map.
226.161 + */
226.162 + private int size;
226.163 +
226.164 + /**
226.165 + * The next size value at which to resize (capacity * load factor).
226.166 + */
226.167 + private int threshold;
226.168 +
226.169 + /**
226.170 + * The load factor for the hash table.
226.171 + */
226.172 + private final float loadFactor;
226.173 +
226.174 + /**
226.175 + * Reference queue for cleared WeakEntries
226.176 + */
226.177 + private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
226.178 +
226.179 + /**
226.180 + * The number of times this WeakHashMap has been structurally modified.
226.181 + * Structural modifications are those that change the number of
226.182 + * mappings in the map or otherwise modify its internal structure
226.183 + * (e.g., rehash). This field is used to make iterators on
226.184 + * Collection-views of the map fail-fast.
226.185 + *
226.186 + * @see ConcurrentModificationException
226.187 + */
226.188 + int modCount;
226.189 +
226.190 + @SuppressWarnings("unchecked")
226.191 + private Entry<K,V>[] newTable(int n) {
226.192 + return (Entry<K,V>[]) new Entry[n];
226.193 + }
226.194 +
226.195 + /**
226.196 + * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
226.197 + * capacity and the given load factor.
226.198 + *
226.199 + * @param initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
226.200 + * @param loadFactor The load factor of the <tt>WeakHashMap</tt>
226.201 + * @throws IllegalArgumentException if the initial capacity is negative,
226.202 + * or if the load factor is nonpositive.
226.203 + */
226.204 + public WeakHashMap(int initialCapacity, float loadFactor) {
226.205 + if (initialCapacity < 0)
226.206 + throw new IllegalArgumentException("Illegal Initial Capacity: "+
226.207 + initialCapacity);
226.208 + if (initialCapacity > MAXIMUM_CAPACITY)
226.209 + initialCapacity = MAXIMUM_CAPACITY;
226.210 +
226.211 + if (loadFactor <= 0 || Float.isNaN(loadFactor))
226.212 + throw new IllegalArgumentException("Illegal Load factor: "+
226.213 + loadFactor);
226.214 + int capacity = 1;
226.215 + while (capacity < initialCapacity)
226.216 + capacity <<= 1;
226.217 + table = newTable(capacity);
226.218 + this.loadFactor = loadFactor;
226.219 + threshold = (int)(capacity * loadFactor);
226.220 + }
226.221 +
226.222 + /**
226.223 + * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
226.224 + * capacity and the default load factor (0.75).
226.225 + *
226.226 + * @param initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
226.227 + * @throws IllegalArgumentException if the initial capacity is negative
226.228 + */
226.229 + public WeakHashMap(int initialCapacity) {
226.230 + this(initialCapacity, DEFAULT_LOAD_FACTOR);
226.231 + }
226.232 +
226.233 + /**
226.234 + * Constructs a new, empty <tt>WeakHashMap</tt> with the default initial
226.235 + * capacity (16) and load factor (0.75).
226.236 + */
226.237 + public WeakHashMap() {
226.238 + this.loadFactor = DEFAULT_LOAD_FACTOR;
226.239 + threshold = DEFAULT_INITIAL_CAPACITY;
226.240 + table = newTable(DEFAULT_INITIAL_CAPACITY);
226.241 + }
226.242 +
226.243 + /**
226.244 + * Constructs a new <tt>WeakHashMap</tt> with the same mappings as the
226.245 + * specified map. The <tt>WeakHashMap</tt> is created with the default
226.246 + * load factor (0.75) and an initial capacity sufficient to hold the
226.247 + * mappings in the specified map.
226.248 + *
226.249 + * @param m the map whose mappings are to be placed in this map
226.250 + * @throws NullPointerException if the specified map is null
226.251 + * @since 1.3
226.252 + */
226.253 + public WeakHashMap(Map<? extends K, ? extends V> m) {
226.254 + this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, 16),
226.255 + DEFAULT_LOAD_FACTOR);
226.256 + putAll(m);
226.257 + }
226.258 +
226.259 + // internal utilities
226.260 +
226.261 + /**
226.262 + * Value representing null keys inside tables.
226.263 + */
226.264 + private static final Object NULL_KEY = new Object();
226.265 +
226.266 + /**
226.267 + * Use NULL_KEY for key if it is null.
226.268 + */
226.269 + private static Object maskNull(Object key) {
226.270 + return (key == null) ? NULL_KEY : key;
226.271 + }
226.272 +
226.273 + /**
226.274 + * Returns internal representation of null key back to caller as null.
226.275 + */
226.276 + static Object unmaskNull(Object key) {
226.277 + return (key == NULL_KEY) ? null : key;
226.278 + }
226.279 +
226.280 + /**
226.281 + * Checks for equality of non-null reference x and possibly-null y. By
226.282 + * default uses Object.equals.
226.283 + */
226.284 + private static boolean eq(Object x, Object y) {
226.285 + return x == y || x.equals(y);
226.286 + }
226.287 +
226.288 + /**
226.289 + * Returns index for hash code h.
226.290 + */
226.291 + private static int indexFor(int h, int length) {
226.292 + return h & (length-1);
226.293 + }
226.294 +
226.295 + /**
226.296 + * Expunges stale entries from the table.
226.297 + */
226.298 + private void expungeStaleEntries() {
226.299 + for (Object x; (x = queue.poll()) != null; ) {
226.300 + synchronized (queue) {
226.301 + @SuppressWarnings("unchecked")
226.302 + Entry<K,V> e = (Entry<K,V>) x;
226.303 + int i = indexFor(e.hash, table.length);
226.304 +
226.305 + Entry<K,V> prev = table[i];
226.306 + Entry<K,V> p = prev;
226.307 + while (p != null) {
226.308 + Entry<K,V> next = p.next;
226.309 + if (p == e) {
226.310 + if (prev == e)
226.311 + table[i] = next;
226.312 + else
226.313 + prev.next = next;
226.314 + // Must not null out e.next;
226.315 + // stale entries may be in use by a HashIterator
226.316 + e.value = null; // Help GC
226.317 + size--;
226.318 + break;
226.319 + }
226.320 + prev = p;
226.321 + p = next;
226.322 + }
226.323 + }
226.324 + }
226.325 + }
226.326 +
226.327 + /**
226.328 + * Returns the table after first expunging stale entries.
226.329 + */
226.330 + private Entry<K,V>[] getTable() {
226.331 + expungeStaleEntries();
226.332 + return table;
226.333 + }
226.334 +
226.335 + /**
226.336 + * Returns the number of key-value mappings in this map.
226.337 + * This result is a snapshot, and may not reflect unprocessed
226.338 + * entries that will be removed before next attempted access
226.339 + * because they are no longer referenced.
226.340 + */
226.341 + public int size() {
226.342 + if (size == 0)
226.343 + return 0;
226.344 + expungeStaleEntries();
226.345 + return size;
226.346 + }
226.347 +
226.348 + /**
226.349 + * Returns <tt>true</tt> if this map contains no key-value mappings.
226.350 + * This result is a snapshot, and may not reflect unprocessed
226.351 + * entries that will be removed before next attempted access
226.352 + * because they are no longer referenced.
226.353 + */
226.354 + public boolean isEmpty() {
226.355 + return size() == 0;
226.356 + }
226.357 +
226.358 + /**
226.359 + * Returns the value to which the specified key is mapped,
226.360 + * or {@code null} if this map contains no mapping for the key.
226.361 + *
226.362 + * <p>More formally, if this map contains a mapping from a key
226.363 + * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
226.364 + * key.equals(k))}, then this method returns {@code v}; otherwise
226.365 + * it returns {@code null}. (There can be at most one such mapping.)
226.366 + *
226.367 + * <p>A return value of {@code null} does not <i>necessarily</i>
226.368 + * indicate that the map contains no mapping for the key; it's also
226.369 + * possible that the map explicitly maps the key to {@code null}.
226.370 + * The {@link #containsKey containsKey} operation may be used to
226.371 + * distinguish these two cases.
226.372 + *
226.373 + * @see #put(Object, Object)
226.374 + */
226.375 + public V get(Object key) {
226.376 + Object k = maskNull(key);
226.377 + int h = HashMap.hash(k.hashCode());
226.378 + Entry<K,V>[] tab = getTable();
226.379 + int index = indexFor(h, tab.length);
226.380 + Entry<K,V> e = tab[index];
226.381 + while (e != null) {
226.382 + if (e.hash == h && eq(k, e.get()))
226.383 + return e.value;
226.384 + e = e.next;
226.385 + }
226.386 + return null;
226.387 + }
226.388 +
226.389 + /**
226.390 + * Returns <tt>true</tt> if this map contains a mapping for the
226.391 + * specified key.
226.392 + *
226.393 + * @param key The key whose presence in this map is to be tested
226.394 + * @return <tt>true</tt> if there is a mapping for <tt>key</tt>;
226.395 + * <tt>false</tt> otherwise
226.396 + */
226.397 + public boolean containsKey(Object key) {
226.398 + return getEntry(key) != null;
226.399 + }
226.400 +
226.401 + /**
226.402 + * Returns the entry associated with the specified key in this map.
226.403 + * Returns null if the map contains no mapping for this key.
226.404 + */
226.405 + Entry<K,V> getEntry(Object key) {
226.406 + Object k = maskNull(key);
226.407 + int h = HashMap.hash(k.hashCode());
226.408 + Entry<K,V>[] tab = getTable();
226.409 + int index = indexFor(h, tab.length);
226.410 + Entry<K,V> e = tab[index];
226.411 + while (e != null && !(e.hash == h && eq(k, e.get())))
226.412 + e = e.next;
226.413 + return e;
226.414 + }
226.415 +
226.416 + /**
226.417 + * Associates the specified value with the specified key in this map.
226.418 + * If the map previously contained a mapping for this key, the old
226.419 + * value is replaced.
226.420 + *
226.421 + * @param key key with which the specified value is to be associated.
226.422 + * @param value value to be associated with the specified key.
226.423 + * @return the previous value associated with <tt>key</tt>, or
226.424 + * <tt>null</tt> if there was no mapping for <tt>key</tt>.
226.425 + * (A <tt>null</tt> return can also indicate that the map
226.426 + * previously associated <tt>null</tt> with <tt>key</tt>.)
226.427 + */
226.428 + public V put(K key, V value) {
226.429 + Object k = maskNull(key);
226.430 + int h = HashMap.hash(k.hashCode());
226.431 + Entry<K,V>[] tab = getTable();
226.432 + int i = indexFor(h, tab.length);
226.433 +
226.434 + for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
226.435 + if (h == e.hash && eq(k, e.get())) {
226.436 + V oldValue = e.value;
226.437 + if (value != oldValue)
226.438 + e.value = value;
226.439 + return oldValue;
226.440 + }
226.441 + }
226.442 +
226.443 + modCount++;
226.444 + Entry<K,V> e = tab[i];
226.445 + tab[i] = new Entry<>(k, value, queue, h, e);
226.446 + if (++size >= threshold)
226.447 + resize(tab.length * 2);
226.448 + return null;
226.449 + }
226.450 +
226.451 + /**
226.452 + * Rehashes the contents of this map into a new array with a
226.453 + * larger capacity. This method is called automatically when the
226.454 + * number of keys in this map reaches its threshold.
226.455 + *
226.456 + * If current capacity is MAXIMUM_CAPACITY, this method does not
226.457 + * resize the map, but sets threshold to Integer.MAX_VALUE.
226.458 + * This has the effect of preventing future calls.
226.459 + *
226.460 + * @param newCapacity the new capacity, MUST be a power of two;
226.461 + * must be greater than current capacity unless current
226.462 + * capacity is MAXIMUM_CAPACITY (in which case value
226.463 + * is irrelevant).
226.464 + */
226.465 + void resize(int newCapacity) {
226.466 + Entry<K,V>[] oldTable = getTable();
226.467 + int oldCapacity = oldTable.length;
226.468 + if (oldCapacity == MAXIMUM_CAPACITY) {
226.469 + threshold = Integer.MAX_VALUE;
226.470 + return;
226.471 + }
226.472 +
226.473 + Entry<K,V>[] newTable = newTable(newCapacity);
226.474 + transfer(oldTable, newTable);
226.475 + table = newTable;
226.476 +
226.477 + /*
226.478 + * If ignoring null elements and processing ref queue caused massive
226.479 + * shrinkage, then restore old table. This should be rare, but avoids
226.480 + * unbounded expansion of garbage-filled tables.
226.481 + */
226.482 + if (size >= threshold / 2) {
226.483 + threshold = (int)(newCapacity * loadFactor);
226.484 + } else {
226.485 + expungeStaleEntries();
226.486 + transfer(newTable, oldTable);
226.487 + table = oldTable;
226.488 + }
226.489 + }
226.490 +
226.491 + /** Transfers all entries from src to dest tables */
226.492 + private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest) {
226.493 + for (int j = 0; j < src.length; ++j) {
226.494 + Entry<K,V> e = src[j];
226.495 + src[j] = null;
226.496 + while (e != null) {
226.497 + Entry<K,V> next = e.next;
226.498 + Object key = e.get();
226.499 + if (key == null) {
226.500 + e.next = null; // Help GC
226.501 + e.value = null; // " "
226.502 + size--;
226.503 + } else {
226.504 + int i = indexFor(e.hash, dest.length);
226.505 + e.next = dest[i];
226.506 + dest[i] = e;
226.507 + }
226.508 + e = next;
226.509 + }
226.510 + }
226.511 + }
226.512 +
226.513 + /**
226.514 + * Copies all of the mappings from the specified map to this map.
226.515 + * These mappings will replace any mappings that this map had for any
226.516 + * of the keys currently in the specified map.
226.517 + *
226.518 + * @param m mappings to be stored in this map.
226.519 + * @throws NullPointerException if the specified map is null.
226.520 + */
226.521 + public void putAll(Map<? extends K, ? extends V> m) {
226.522 + int numKeysToBeAdded = m.size();
226.523 + if (numKeysToBeAdded == 0)
226.524 + return;
226.525 +
226.526 + /*
226.527 + * Expand the map if the map if the number of mappings to be added
226.528 + * is greater than or equal to threshold. This is conservative; the
226.529 + * obvious condition is (m.size() + size) >= threshold, but this
226.530 + * condition could result in a map with twice the appropriate capacity,
226.531 + * if the keys to be added overlap with the keys already in this map.
226.532 + * By using the conservative calculation, we subject ourself
226.533 + * to at most one extra resize.
226.534 + */
226.535 + if (numKeysToBeAdded > threshold) {
226.536 + int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
226.537 + if (targetCapacity > MAXIMUM_CAPACITY)
226.538 + targetCapacity = MAXIMUM_CAPACITY;
226.539 + int newCapacity = table.length;
226.540 + while (newCapacity < targetCapacity)
226.541 + newCapacity <<= 1;
226.542 + if (newCapacity > table.length)
226.543 + resize(newCapacity);
226.544 + }
226.545 +
226.546 + for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
226.547 + put(e.getKey(), e.getValue());
226.548 + }
226.549 +
226.550 + /**
226.551 + * Removes the mapping for a key from this weak hash map if it is present.
226.552 + * More formally, if this map contains a mapping from key <tt>k</tt> to
226.553 + * value <tt>v</tt> such that <code>(key==null ? k==null :
226.554 + * key.equals(k))</code>, that mapping is removed. (The map can contain
226.555 + * at most one such mapping.)
226.556 + *
226.557 + * <p>Returns the value to which this map previously associated the key,
226.558 + * or <tt>null</tt> if the map contained no mapping for the key. A
226.559 + * return value of <tt>null</tt> does not <i>necessarily</i> indicate
226.560 + * that the map contained no mapping for the key; it's also possible
226.561 + * that the map explicitly mapped the key to <tt>null</tt>.
226.562 + *
226.563 + * <p>The map will not contain a mapping for the specified key once the
226.564 + * call returns.
226.565 + *
226.566 + * @param key key whose mapping is to be removed from the map
226.567 + * @return the previous value associated with <tt>key</tt>, or
226.568 + * <tt>null</tt> if there was no mapping for <tt>key</tt>
226.569 + */
226.570 + public V remove(Object key) {
226.571 + Object k = maskNull(key);
226.572 + int h = HashMap.hash(k.hashCode());
226.573 + Entry<K,V>[] tab = getTable();
226.574 + int i = indexFor(h, tab.length);
226.575 + Entry<K,V> prev = tab[i];
226.576 + Entry<K,V> e = prev;
226.577 +
226.578 + while (e != null) {
226.579 + Entry<K,V> next = e.next;
226.580 + if (h == e.hash && eq(k, e.get())) {
226.581 + modCount++;
226.582 + size--;
226.583 + if (prev == e)
226.584 + tab[i] = next;
226.585 + else
226.586 + prev.next = next;
226.587 + return e.value;
226.588 + }
226.589 + prev = e;
226.590 + e = next;
226.591 + }
226.592 +
226.593 + return null;
226.594 + }
226.595 +
226.596 + /** Special version of remove needed by Entry set */
226.597 + boolean removeMapping(Object o) {
226.598 + if (!(o instanceof Map.Entry))
226.599 + return false;
226.600 + Entry<K,V>[] tab = getTable();
226.601 + Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
226.602 + Object k = maskNull(entry.getKey());
226.603 + int h = HashMap.hash(k.hashCode());
226.604 + int i = indexFor(h, tab.length);
226.605 + Entry<K,V> prev = tab[i];
226.606 + Entry<K,V> e = prev;
226.607 +
226.608 + while (e != null) {
226.609 + Entry<K,V> next = e.next;
226.610 + if (h == e.hash && e.equals(entry)) {
226.611 + modCount++;
226.612 + size--;
226.613 + if (prev == e)
226.614 + tab[i] = next;
226.615 + else
226.616 + prev.next = next;
226.617 + return true;
226.618 + }
226.619 + prev = e;
226.620 + e = next;
226.621 + }
226.622 +
226.623 + return false;
226.624 + }
226.625 +
226.626 + /**
226.627 + * Removes all of the mappings from this map.
226.628 + * The map will be empty after this call returns.
226.629 + */
226.630 + public void clear() {
226.631 + // clear out ref queue. We don't need to expunge entries
226.632 + // since table is getting cleared.
226.633 + while (queue.poll() != null)
226.634 + ;
226.635 +
226.636 + modCount++;
226.637 + Arrays.fill(table, null);
226.638 + size = 0;
226.639 +
226.640 + // Allocation of array may have caused GC, which may have caused
226.641 + // additional entries to go stale. Removing these entries from the
226.642 + // reference queue will make them eligible for reclamation.
226.643 + while (queue.poll() != null)
226.644 + ;
226.645 + }
226.646 +
226.647 + /**
226.648 + * Returns <tt>true</tt> if this map maps one or more keys to the
226.649 + * specified value.
226.650 + *
226.651 + * @param value value whose presence in this map is to be tested
226.652 + * @return <tt>true</tt> if this map maps one or more keys to the
226.653 + * specified value
226.654 + */
226.655 + public boolean containsValue(Object value) {
226.656 + if (value==null)
226.657 + return containsNullValue();
226.658 +
226.659 + Entry<K,V>[] tab = getTable();
226.660 + for (int i = tab.length; i-- > 0;)
226.661 + for (Entry<K,V> e = tab[i]; e != null; e = e.next)
226.662 + if (value.equals(e.value))
226.663 + return true;
226.664 + return false;
226.665 + }
226.666 +
226.667 + /**
226.668 + * Special-case code for containsValue with null argument
226.669 + */
226.670 + private boolean containsNullValue() {
226.671 + Entry<K,V>[] tab = getTable();
226.672 + for (int i = tab.length; i-- > 0;)
226.673 + for (Entry<K,V> e = tab[i]; e != null; e = e.next)
226.674 + if (e.value==null)
226.675 + return true;
226.676 + return false;
226.677 + }
226.678 +
226.679 + /**
226.680 + * The entries in this hash table extend WeakReference, using its main ref
226.681 + * field as the key.
226.682 + */
226.683 + private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
226.684 + V value;
226.685 + final int hash;
226.686 + Entry<K,V> next;
226.687 +
226.688 + /**
226.689 + * Creates new entry.
226.690 + */
226.691 + Entry(Object key, V value,
226.692 + ReferenceQueue<Object> queue,
226.693 + int hash, Entry<K,V> next) {
226.694 + super(key, queue);
226.695 + this.value = value;
226.696 + this.hash = hash;
226.697 + this.next = next;
226.698 + }
226.699 +
226.700 + @SuppressWarnings("unchecked")
226.701 + public K getKey() {
226.702 + return (K) WeakHashMap.unmaskNull(get());
226.703 + }
226.704 +
226.705 + public V getValue() {
226.706 + return value;
226.707 + }
226.708 +
226.709 + public V setValue(V newValue) {
226.710 + V oldValue = value;
226.711 + value = newValue;
226.712 + return oldValue;
226.713 + }
226.714 +
226.715 + public boolean equals(Object o) {
226.716 + if (!(o instanceof Map.Entry))
226.717 + return false;
226.718 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
226.719 + K k1 = getKey();
226.720 + Object k2 = e.getKey();
226.721 + if (k1 == k2 || (k1 != null && k1.equals(k2))) {
226.722 + V v1 = getValue();
226.723 + Object v2 = e.getValue();
226.724 + if (v1 == v2 || (v1 != null && v1.equals(v2)))
226.725 + return true;
226.726 + }
226.727 + return false;
226.728 + }
226.729 +
226.730 + public int hashCode() {
226.731 + K k = getKey();
226.732 + V v = getValue();
226.733 + return ((k==null ? 0 : k.hashCode()) ^
226.734 + (v==null ? 0 : v.hashCode()));
226.735 + }
226.736 +
226.737 + public String toString() {
226.738 + return getKey() + "=" + getValue();
226.739 + }
226.740 + }
226.741 +
226.742 + private abstract class HashIterator<T> implements Iterator<T> {
226.743 + private int index;
226.744 + private Entry<K,V> entry = null;
226.745 + private Entry<K,V> lastReturned = null;
226.746 + private int expectedModCount = modCount;
226.747 +
226.748 + /**
226.749 + * Strong reference needed to avoid disappearance of key
226.750 + * between hasNext and next
226.751 + */
226.752 + private Object nextKey = null;
226.753 +
226.754 + /**
226.755 + * Strong reference needed to avoid disappearance of key
226.756 + * between nextEntry() and any use of the entry
226.757 + */
226.758 + private Object currentKey = null;
226.759 +
226.760 + HashIterator() {
226.761 + index = isEmpty() ? 0 : table.length;
226.762 + }
226.763 +
226.764 + public boolean hasNext() {
226.765 + Entry<K,V>[] t = table;
226.766 +
226.767 + while (nextKey == null) {
226.768 + Entry<K,V> e = entry;
226.769 + int i = index;
226.770 + while (e == null && i > 0)
226.771 + e = t[--i];
226.772 + entry = e;
226.773 + index = i;
226.774 + if (e == null) {
226.775 + currentKey = null;
226.776 + return false;
226.777 + }
226.778 + nextKey = e.get(); // hold on to key in strong ref
226.779 + if (nextKey == null)
226.780 + entry = entry.next;
226.781 + }
226.782 + return true;
226.783 + }
226.784 +
226.785 + /** The common parts of next() across different types of iterators */
226.786 + protected Entry<K,V> nextEntry() {
226.787 + if (modCount != expectedModCount)
226.788 + throw new ConcurrentModificationException();
226.789 + if (nextKey == null && !hasNext())
226.790 + throw new NoSuchElementException();
226.791 +
226.792 + lastReturned = entry;
226.793 + entry = entry.next;
226.794 + currentKey = nextKey;
226.795 + nextKey = null;
226.796 + return lastReturned;
226.797 + }
226.798 +
226.799 + public void remove() {
226.800 + if (lastReturned == null)
226.801 + throw new IllegalStateException();
226.802 + if (modCount != expectedModCount)
226.803 + throw new ConcurrentModificationException();
226.804 +
226.805 + WeakHashMap.this.remove(currentKey);
226.806 + expectedModCount = modCount;
226.807 + lastReturned = null;
226.808 + currentKey = null;
226.809 + }
226.810 +
226.811 + }
226.812 +
226.813 + private class ValueIterator extends HashIterator<V> {
226.814 + public V next() {
226.815 + return nextEntry().value;
226.816 + }
226.817 + }
226.818 +
226.819 + private class KeyIterator extends HashIterator<K> {
226.820 + public K next() {
226.821 + return nextEntry().getKey();
226.822 + }
226.823 + }
226.824 +
226.825 + private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
226.826 + public Map.Entry<K,V> next() {
226.827 + return nextEntry();
226.828 + }
226.829 + }
226.830 +
226.831 + // Views
226.832 +
226.833 + private transient Set<Map.Entry<K,V>> entrySet = null;
226.834 +
226.835 + /**
226.836 + * Returns a {@link Set} view of the keys contained in this map.
226.837 + * The set is backed by the map, so changes to the map are
226.838 + * reflected in the set, and vice-versa. If the map is modified
226.839 + * while an iteration over the set is in progress (except through
226.840 + * the iterator's own <tt>remove</tt> operation), the results of
226.841 + * the iteration are undefined. The set supports element removal,
226.842 + * which removes the corresponding mapping from the map, via the
226.843 + * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
226.844 + * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
226.845 + * operations. It does not support the <tt>add</tt> or <tt>addAll</tt>
226.846 + * operations.
226.847 + */
226.848 + public Set<K> keySet() {
226.849 + Set<K> ks = keySet;
226.850 + return (ks != null ? ks : (keySet = new KeySet()));
226.851 + }
226.852 +
226.853 + private class KeySet extends AbstractSet<K> {
226.854 + public Iterator<K> iterator() {
226.855 + return new KeyIterator();
226.856 + }
226.857 +
226.858 + public int size() {
226.859 + return WeakHashMap.this.size();
226.860 + }
226.861 +
226.862 + public boolean contains(Object o) {
226.863 + return containsKey(o);
226.864 + }
226.865 +
226.866 + public boolean remove(Object o) {
226.867 + if (containsKey(o)) {
226.868 + WeakHashMap.this.remove(o);
226.869 + return true;
226.870 + }
226.871 + else
226.872 + return false;
226.873 + }
226.874 +
226.875 + public void clear() {
226.876 + WeakHashMap.this.clear();
226.877 + }
226.878 + }
226.879 +
226.880 + /**
226.881 + * Returns a {@link Collection} view of the values contained in this map.
226.882 + * The collection is backed by the map, so changes to the map are
226.883 + * reflected in the collection, and vice-versa. If the map is
226.884 + * modified while an iteration over the collection is in progress
226.885 + * (except through the iterator's own <tt>remove</tt> operation),
226.886 + * the results of the iteration are undefined. The collection
226.887 + * supports element removal, which removes the corresponding
226.888 + * mapping from the map, via the <tt>Iterator.remove</tt>,
226.889 + * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
226.890 + * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not
226.891 + * support the <tt>add</tt> or <tt>addAll</tt> operations.
226.892 + */
226.893 + public Collection<V> values() {
226.894 + Collection<V> vs = values;
226.895 + return (vs != null) ? vs : (values = new Values());
226.896 + }
226.897 +
226.898 + private class Values extends AbstractCollection<V> {
226.899 + public Iterator<V> iterator() {
226.900 + return new ValueIterator();
226.901 + }
226.902 +
226.903 + public int size() {
226.904 + return WeakHashMap.this.size();
226.905 + }
226.906 +
226.907 + public boolean contains(Object o) {
226.908 + return containsValue(o);
226.909 + }
226.910 +
226.911 + public void clear() {
226.912 + WeakHashMap.this.clear();
226.913 + }
226.914 + }
226.915 +
226.916 + /**
226.917 + * Returns a {@link Set} view of the mappings contained in this map.
226.918 + * The set is backed by the map, so changes to the map are
226.919 + * reflected in the set, and vice-versa. If the map is modified
226.920 + * while an iteration over the set is in progress (except through
226.921 + * the iterator's own <tt>remove</tt> operation, or through the
226.922 + * <tt>setValue</tt> operation on a map entry returned by the
226.923 + * iterator) the results of the iteration are undefined. The set
226.924 + * supports element removal, which removes the corresponding
226.925 + * mapping from the map, via the <tt>Iterator.remove</tt>,
226.926 + * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
226.927 + * <tt>clear</tt> operations. It does not support the
226.928 + * <tt>add</tt> or <tt>addAll</tt> operations.
226.929 + */
226.930 + public Set<Map.Entry<K,V>> entrySet() {
226.931 + Set<Map.Entry<K,V>> es = entrySet;
226.932 + return es != null ? es : (entrySet = new EntrySet());
226.933 + }
226.934 +
226.935 + private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
226.936 + public Iterator<Map.Entry<K,V>> iterator() {
226.937 + return new EntryIterator();
226.938 + }
226.939 +
226.940 + public boolean contains(Object o) {
226.941 + if (!(o instanceof Map.Entry))
226.942 + return false;
226.943 + Map.Entry<?,?> e = (Map.Entry<?,?>)o;
226.944 + Entry<K,V> candidate = getEntry(e.getKey());
226.945 + return candidate != null && candidate.equals(e);
226.946 + }
226.947 +
226.948 + public boolean remove(Object o) {
226.949 + return removeMapping(o);
226.950 + }
226.951 +
226.952 + public int size() {
226.953 + return WeakHashMap.this.size();
226.954 + }
226.955 +
226.956 + public void clear() {
226.957 + WeakHashMap.this.clear();
226.958 + }
226.959 +
226.960 + private List<Map.Entry<K,V>> deepCopy() {
226.961 + List<Map.Entry<K,V>> list = new ArrayList<>(size());
226.962 + for (Map.Entry<K,V> e : this)
226.963 + list.add(new AbstractMap.SimpleEntry<>(e));
226.964 + return list;
226.965 + }
226.966 +
226.967 + public Object[] toArray() {
226.968 + return deepCopy().toArray();
226.969 + }
226.970 +
226.971 + public <T> T[] toArray(T[] a) {
226.972 + return deepCopy().toArray(a);
226.973 + }
226.974 + }
226.975 +}
227.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
227.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentHashMap.java Wed Apr 30 15:04:10 2014 +0200
227.3 @@ -0,0 +1,327 @@
227.4 +/*
227.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
227.6 + *
227.7 + * This code is free software; you can redistribute it and/or modify it
227.8 + * under the terms of the GNU General Public License version 2 only, as
227.9 + * published by the Free Software Foundation. Oracle designates this
227.10 + * particular file as subject to the "Classpath" exception as provided
227.11 + * by Oracle in the LICENSE file that accompanied this code.
227.12 + *
227.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
227.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
227.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
227.16 + * version 2 for more details (a copy is included in the LICENSE file that
227.17 + * accompanied this code).
227.18 + *
227.19 + * You should have received a copy of the GNU General Public License version
227.20 + * 2 along with this work; if not, write to the Free Software Foundation,
227.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
227.22 + *
227.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
227.24 + * or visit www.oracle.com if you need additional information or have any
227.25 + * questions.
227.26 + */
227.27 +
227.28 +/*
227.29 + * This file is available under and governed by the GNU General Public
227.30 + * License version 2 only, as published by the Free Software Foundation.
227.31 + * However, the following notice accompanied the original version of this
227.32 + * file:
227.33 + *
227.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
227.35 + * Expert Group and released to the public domain, as explained at
227.36 + * http://creativecommons.org/publicdomain/zero/1.0/
227.37 + */
227.38 +package java.util.concurrent;
227.39 +
227.40 +import java.util.*;
227.41 +import java.io.Serializable;
227.42 +import java.io.IOException;
227.43 +import java.io.ObjectInputStream;
227.44 +import java.io.ObjectOutputStream;
227.45 +
227.46 +/**
227.47 + * A hash table supporting full concurrency of retrievals and adjustable
227.48 + * expected concurrency for updates. This class obeys the same functional
227.49 + * specification as {@link java.util.Hashtable}, and includes versions of
227.50 + * methods corresponding to each method of
227.51 + * <tt>Hashtable</tt>. However, even though all operations are thread-safe,
227.52 + * retrieval operations do <em>not</em> entail locking, and there is
227.53 + * <em>not</em> any support for locking the entire table in a way that prevents
227.54 + * all access. This class is fully interoperable with <tt>Hashtable</tt> in
227.55 + * programs that rely on its thread safety but not on its synchronization
227.56 + * details.
227.57 + *
227.58 + * <p>
227.59 + * Retrieval operations (including <tt>get</tt>) generally do not block, so may
227.60 + * overlap with update operations (including
227.61 + * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results of the most
227.62 + * recently <em>completed</em> update operations holding upon their onset. For
227.63 + * aggregate operations such as <tt>putAll</tt>
227.64 + * and <tt>clear</tt>, concurrent retrievals may reflect insertion or removal of
227.65 + * only some entries. Similarly, Iterators and Enumerations return elements
227.66 + * reflecting the state of the hash table at some point at or since the creation
227.67 + * of the iterator/enumeration. They do <em>not</em> throw
227.68 + * {@link ConcurrentModificationException}. However, iterators are designed to
227.69 + * be used by only one thread at a time.
227.70 + *
227.71 + * <p>
227.72 + * The allowed concurrency among update operations is guided by the optional
227.73 + * <tt>concurrencyLevel</tt> constructor argument (default <tt>16</tt>), which
227.74 + * is used as a hint for internal sizing. The table is internally partitioned to
227.75 + * try to permit the indicated number of concurrent updates without contention.
227.76 + * Because placement in hash tables is essentially random, the actual
227.77 + * concurrency will vary. Ideally, you should choose a value to accommodate as
227.78 + * many threads as will ever concurrently modify the table. Using a
227.79 + * significantly higher value than you need can waste space and time, and a
227.80 + * significantly lower value can lead to thread contention. But overestimates
227.81 + * and underestimates within an order of magnitude do not usually have much
227.82 + * noticeable impact. A value of one is appropriate when it is known that only
227.83 + * one thread will modify and all others will only read. Also, resizing this or
227.84 + * any other kind of hash table is a relatively slow operation, so, when
227.85 + * possible, it is a good idea to provide estimates of expected table sizes in
227.86 + * constructors.
227.87 + *
227.88 + * <p>
227.89 + * This class and its views and iterators implement all of the
227.90 + * <em>optional</em> methods of the {@link Map} and {@link Iterator} interfaces.
227.91 + *
227.92 + * <p>
227.93 + * Like {@link Hashtable} but unlike {@link HashMap}, this class does
227.94 + * <em>not</em> allow <tt>null</tt> to be used as a key or value.
227.95 + *
227.96 + * <p>
227.97 + * This class is a member of the
227.98 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
227.99 + * Java Collections Framework</a>.
227.100 + *
227.101 + * @since 1.5
227.102 + * @author Doug Lea
227.103 + * @param <K> the type of keys maintained by this map
227.104 + * @param <V> the type of mapped values
227.105 + */
227.106 +public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
227.107 + implements ConcurrentMap<K, V>, Serializable {
227.108 +
227.109 + private static final long serialVersionUID = 7249069246763182397L;
227.110 + /**
227.111 + * The default initial capacity for this table,
227.112 + * used when not otherwise specified in a constructor.
227.113 + */
227.114 + static final int DEFAULT_INITIAL_CAPACITY = 16;
227.115 +
227.116 + /**
227.117 + * The default load factor for this table, used when not
227.118 + * otherwise specified in a constructor.
227.119 + */
227.120 + static final float DEFAULT_LOAD_FACTOR = 0.75f;
227.121 +
227.122 + /**
227.123 + * The default concurrency level for this table, used when not
227.124 + * otherwise specified in a constructor.
227.125 + */
227.126 + static final int DEFAULT_CONCURRENCY_LEVEL = 16;
227.127 +
227.128 + private final Map<K, V> delegate;
227.129 +
227.130 +
227.131 + /**
227.132 + * Creates a new, empty map with the specified initial
227.133 + * capacity, load factor and concurrency level.
227.134 + *
227.135 + * @param initialCapacity the initial capacity. The implementation
227.136 + * performs internal sizing to accommodate this many elements.
227.137 + * @param loadFactor the load factor threshold, used to control resizing.
227.138 + * Resizing may be performed when the average number of elements per
227.139 + * bin exceeds this threshold.
227.140 + * @param concurrencyLevel the estimated number of concurrently
227.141 + * updating threads. The implementation performs internal sizing
227.142 + * to try to accommodate this many threads.
227.143 + * @throws IllegalArgumentException if the initial capacity is
227.144 + * negative or the load factor or concurrencyLevel are
227.145 + * nonpositive.
227.146 + */
227.147 + @SuppressWarnings("unchecked")
227.148 + public ConcurrentHashMap(int initialCapacity,
227.149 + float loadFactor, int concurrencyLevel) {
227.150 + if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
227.151 + throw new IllegalArgumentException();
227.152 + delegate = new HashMap<>(initialCapacity, loadFactor);
227.153 + }
227.154 +
227.155 + /**
227.156 + * Creates a new, empty map with the specified initial capacity
227.157 + * and load factor and with the default concurrencyLevel (16).
227.158 + *
227.159 + * @param initialCapacity The implementation performs internal
227.160 + * sizing to accommodate this many elements.
227.161 + * @param loadFactor the load factor threshold, used to control resizing.
227.162 + * Resizing may be performed when the average number of elements per
227.163 + * bin exceeds this threshold.
227.164 + * @throws IllegalArgumentException if the initial capacity of
227.165 + * elements is negative or the load factor is nonpositive
227.166 + *
227.167 + * @since 1.6
227.168 + */
227.169 + public ConcurrentHashMap(int initialCapacity, float loadFactor) {
227.170 + this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
227.171 + }
227.172 +
227.173 + /**
227.174 + * Creates a new, empty map with the specified initial capacity,
227.175 + * and with default load factor (0.75) and concurrencyLevel (16).
227.176 + *
227.177 + * @param initialCapacity the initial capacity. The implementation
227.178 + * performs internal sizing to accommodate this many elements.
227.179 + * @throws IllegalArgumentException if the initial capacity of
227.180 + * elements is negative.
227.181 + */
227.182 + public ConcurrentHashMap(int initialCapacity) {
227.183 + this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
227.184 + }
227.185 +
227.186 + /**
227.187 + * Creates a new, empty map with a default initial capacity (16),
227.188 + * load factor (0.75) and concurrencyLevel (16).
227.189 + */
227.190 + public ConcurrentHashMap() {
227.191 + this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
227.192 + }
227.193 +
227.194 + /**
227.195 + * Creates a new map with the same mappings as the given map.
227.196 + * The map is created with a capacity of 1.5 times the number
227.197 + * of mappings in the given map or 16 (whichever is greater),
227.198 + * and a default load factor (0.75) and concurrencyLevel (16).
227.199 + *
227.200 + * @param m the map
227.201 + */
227.202 + public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
227.203 + this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
227.204 + DEFAULT_INITIAL_CAPACITY),
227.205 + DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
227.206 + putAll(m);
227.207 + }
227.208 +
227.209 +
227.210 + @Override
227.211 + public int size() {
227.212 + return delegate.size();
227.213 + }
227.214 +
227.215 + @Override
227.216 + public boolean isEmpty() {
227.217 + return delegate.isEmpty();
227.218 + }
227.219 +
227.220 + @Override
227.221 + public boolean containsKey(Object key) {
227.222 + return delegate.containsKey(key);
227.223 + }
227.224 +
227.225 + @Override
227.226 + public boolean containsValue(Object value) {
227.227 + return delegate.containsValue(value);
227.228 + }
227.229 +
227.230 + @Override
227.231 + public V get(Object key) {
227.232 + return delegate.get(key);
227.233 + }
227.234 +
227.235 + @Override
227.236 + public V put(K key, V value) {
227.237 + return delegate.put(key, value);
227.238 + }
227.239 +
227.240 + @Override
227.241 + public V remove(Object key) {
227.242 + return delegate.remove(key);
227.243 + }
227.244 +
227.245 + @Override
227.246 + public void putAll(Map<? extends K, ? extends V> m) {
227.247 + delegate.putAll(m);
227.248 + }
227.249 +
227.250 + @Override
227.251 + public void clear() {
227.252 + delegate.clear();
227.253 + }
227.254 +
227.255 + @Override
227.256 + public Set<K> keySet() {
227.257 + return delegate.keySet();
227.258 + }
227.259 +
227.260 + @Override
227.261 + public Collection<V> values() {
227.262 + return delegate.values();
227.263 + }
227.264 +
227.265 + @Override
227.266 + public Set<Entry<K, V>> entrySet() {
227.267 + return delegate.entrySet();
227.268 + }
227.269 +
227.270 + @Override
227.271 + public boolean equals(Object o) {
227.272 + return delegate.equals(o);
227.273 + }
227.274 +
227.275 + @Override
227.276 + public int hashCode() {
227.277 + return delegate.hashCode();
227.278 + }
227.279 +
227.280 + @Override
227.281 + public String toString() {
227.282 + return delegate.toString();
227.283 + }
227.284 +
227.285 + @Override
227.286 + public V putIfAbsent(K key, V value) {
227.287 + V old = delegate.get(key);
227.288 + if (old == null) {
227.289 + return delegate.put(key, value);
227.290 + }
227.291 + return old;
227.292 + }
227.293 +
227.294 + @Override
227.295 + public boolean remove(Object key, Object value) {
227.296 + if (equals(value, delegate.get(key))) {
227.297 + delegate.remove(key);
227.298 + return true;
227.299 + } else {
227.300 + return false;
227.301 + }
227.302 + }
227.303 +
227.304 + @Override
227.305 + public boolean replace(K key, V oldValue, V newValue) {
227.306 + if (equals(oldValue, delegate.get(key))) {
227.307 + delegate.put(key, newValue);
227.308 + return true;
227.309 + } else {
227.310 + return false;
227.311 + }
227.312 + }
227.313 +
227.314 + @Override
227.315 + public V replace(K key, V value) {
227.316 + if (delegate.containsKey(key)) {
227.317 + return delegate.put(key, value);
227.318 + } else {
227.319 + return null;
227.320 + }
227.321 + }
227.322 +
227.323 + private static boolean equals(Object a, Object b) {
227.324 + if (a == null) {
227.325 + return b == null;
227.326 + } else {
227.327 + return a.equals(b);
227.328 + }
227.329 + }
227.330 +}
228.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
228.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentMap.java Wed Apr 30 15:04:10 2014 +0200
228.3 @@ -0,0 +1,165 @@
228.4 +/*
228.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
228.6 + *
228.7 + * This code is free software; you can redistribute it and/or modify it
228.8 + * under the terms of the GNU General Public License version 2 only, as
228.9 + * published by the Free Software Foundation. Oracle designates this
228.10 + * particular file as subject to the "Classpath" exception as provided
228.11 + * by Oracle in the LICENSE file that accompanied this code.
228.12 + *
228.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
228.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
228.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
228.16 + * version 2 for more details (a copy is included in the LICENSE file that
228.17 + * accompanied this code).
228.18 + *
228.19 + * You should have received a copy of the GNU General Public License version
228.20 + * 2 along with this work; if not, write to the Free Software Foundation,
228.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
228.22 + *
228.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
228.24 + * or visit www.oracle.com if you need additional information or have any
228.25 + * questions.
228.26 + */
228.27 +
228.28 +/*
228.29 + * This file is available under and governed by the GNU General Public
228.30 + * License version 2 only, as published by the Free Software Foundation.
228.31 + * However, the following notice accompanied the original version of this
228.32 + * file:
228.33 + *
228.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
228.35 + * Expert Group and released to the public domain, as explained at
228.36 + * http://creativecommons.org/publicdomain/zero/1.0/
228.37 + */
228.38 +
228.39 +package java.util.concurrent;
228.40 +import java.util.Map;
228.41 +
228.42 +/**
228.43 + * A {@link java.util.Map} providing additional atomic
228.44 + * <tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt> methods.
228.45 + *
228.46 + * <p>Memory consistency effects: As with other concurrent
228.47 + * collections, actions in a thread prior to placing an object into a
228.48 + * {@code ConcurrentMap} as a key or value
228.49 + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
228.50 + * actions subsequent to the access or removal of that object from
228.51 + * the {@code ConcurrentMap} in another thread.
228.52 + *
228.53 + * <p>This interface is a member of the
228.54 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
228.55 + * Java Collections Framework</a>.
228.56 + *
228.57 + * @since 1.5
228.58 + * @author Doug Lea
228.59 + * @param <K> the type of keys maintained by this map
228.60 + * @param <V> the type of mapped values
228.61 + */
228.62 +public interface ConcurrentMap<K, V> extends Map<K, V> {
228.63 + /**
228.64 + * If the specified key is not already associated
228.65 + * with a value, associate it with the given value.
228.66 + * This is equivalent to
228.67 + * <pre>
228.68 + * if (!map.containsKey(key))
228.69 + * return map.put(key, value);
228.70 + * else
228.71 + * return map.get(key);</pre>
228.72 + * except that the action is performed atomically.
228.73 + *
228.74 + * @param key key with which the specified value is to be associated
228.75 + * @param value value to be associated with the specified key
228.76 + * @return the previous value associated with the specified key, or
228.77 + * <tt>null</tt> if there was no mapping for the key.
228.78 + * (A <tt>null</tt> return can also indicate that the map
228.79 + * previously associated <tt>null</tt> with the key,
228.80 + * if the implementation supports null values.)
228.81 + * @throws UnsupportedOperationException if the <tt>put</tt> operation
228.82 + * is not supported by this map
228.83 + * @throws ClassCastException if the class of the specified key or value
228.84 + * prevents it from being stored in this map
228.85 + * @throws NullPointerException if the specified key or value is null,
228.86 + * and this map does not permit null keys or values
228.87 + * @throws IllegalArgumentException if some property of the specified key
228.88 + * or value prevents it from being stored in this map
228.89 + *
228.90 + */
228.91 + V putIfAbsent(K key, V value);
228.92 +
228.93 + /**
228.94 + * Removes the entry for a key only if currently mapped to a given value.
228.95 + * This is equivalent to
228.96 + * <pre>
228.97 + * if (map.containsKey(key) && map.get(key).equals(value)) {
228.98 + * map.remove(key);
228.99 + * return true;
228.100 + * } else return false;</pre>
228.101 + * except that the action is performed atomically.
228.102 + *
228.103 + * @param key key with which the specified value is associated
228.104 + * @param value value expected to be associated with the specified key
228.105 + * @return <tt>true</tt> if the value was removed
228.106 + * @throws UnsupportedOperationException if the <tt>remove</tt> operation
228.107 + * is not supported by this map
228.108 + * @throws ClassCastException if the key or value is of an inappropriate
228.109 + * type for this map
228.110 + * (<a href="../Collection.html#optional-restrictions">optional</a>)
228.111 + * @throws NullPointerException if the specified key or value is null,
228.112 + * and this map does not permit null keys or values
228.113 + * (<a href="../Collection.html#optional-restrictions">optional</a>)
228.114 + */
228.115 + boolean remove(Object key, Object value);
228.116 +
228.117 + /**
228.118 + * Replaces the entry for a key only if currently mapped to a given value.
228.119 + * This is equivalent to
228.120 + * <pre>
228.121 + * if (map.containsKey(key) && map.get(key).equals(oldValue)) {
228.122 + * map.put(key, newValue);
228.123 + * return true;
228.124 + * } else return false;</pre>
228.125 + * except that the action is performed atomically.
228.126 + *
228.127 + * @param key key with which the specified value is associated
228.128 + * @param oldValue value expected to be associated with the specified key
228.129 + * @param newValue value to be associated with the specified key
228.130 + * @return <tt>true</tt> if the value was replaced
228.131 + * @throws UnsupportedOperationException if the <tt>put</tt> operation
228.132 + * is not supported by this map
228.133 + * @throws ClassCastException if the class of a specified key or value
228.134 + * prevents it from being stored in this map
228.135 + * @throws NullPointerException if a specified key or value is null,
228.136 + * and this map does not permit null keys or values
228.137 + * @throws IllegalArgumentException if some property of a specified key
228.138 + * or value prevents it from being stored in this map
228.139 + */
228.140 + boolean replace(K key, V oldValue, V newValue);
228.141 +
228.142 + /**
228.143 + * Replaces the entry for a key only if currently mapped to some value.
228.144 + * This is equivalent to
228.145 + * <pre>
228.146 + * if (map.containsKey(key)) {
228.147 + * return map.put(key, value);
228.148 + * } else return null;</pre>
228.149 + * except that the action is performed atomically.
228.150 + *
228.151 + * @param key key with which the specified value is associated
228.152 + * @param value value to be associated with the specified key
228.153 + * @return the previous value associated with the specified key, or
228.154 + * <tt>null</tt> if there was no mapping for the key.
228.155 + * (A <tt>null</tt> return can also indicate that the map
228.156 + * previously associated <tt>null</tt> with the key,
228.157 + * if the implementation supports null values.)
228.158 + * @throws UnsupportedOperationException if the <tt>put</tt> operation
228.159 + * is not supported by this map
228.160 + * @throws ClassCastException if the class of the specified key or value
228.161 + * prevents it from being stored in this map
228.162 + * @throws NullPointerException if the specified key or value is null,
228.163 + * and this map does not permit null keys or values
228.164 + * @throws IllegalArgumentException if some property of the specified key
228.165 + * or value prevents it from being stored in this map
228.166 + */
228.167 + V replace(K key, V value);
228.168 +}
229.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
229.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/Executor.java Wed Apr 30 15:04:10 2014 +0200
229.3 @@ -0,0 +1,141 @@
229.4 +/*
229.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
229.6 + *
229.7 + * This code is free software; you can redistribute it and/or modify it
229.8 + * under the terms of the GNU General Public License version 2 only, as
229.9 + * published by the Free Software Foundation. Oracle designates this
229.10 + * particular file as subject to the "Classpath" exception as provided
229.11 + * by Oracle in the LICENSE file that accompanied this code.
229.12 + *
229.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
229.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
229.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
229.16 + * version 2 for more details (a copy is included in the LICENSE file that
229.17 + * accompanied this code).
229.18 + *
229.19 + * You should have received a copy of the GNU General Public License version
229.20 + * 2 along with this work; if not, write to the Free Software Foundation,
229.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
229.22 + *
229.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
229.24 + * or visit www.oracle.com if you need additional information or have any
229.25 + * questions.
229.26 + */
229.27 +
229.28 +/*
229.29 + * This file is available under and governed by the GNU General Public
229.30 + * License version 2 only, as published by the Free Software Foundation.
229.31 + * However, the following notice accompanied the original version of this
229.32 + * file:
229.33 + *
229.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
229.35 + * Expert Group and released to the public domain, as explained at
229.36 + * http://creativecommons.org/publicdomain/zero/1.0/
229.37 + */
229.38 +
229.39 +package java.util.concurrent;
229.40 +
229.41 +/**
229.42 + * An object that executes submitted {@link Runnable} tasks. This
229.43 + * interface provides a way of decoupling task submission from the
229.44 + * mechanics of how each task will be run, including details of thread
229.45 + * use, scheduling, etc. An <tt>Executor</tt> is normally used
229.46 + * instead of explicitly creating threads. For example, rather than
229.47 + * invoking <tt>new Thread(new(RunnableTask())).start()</tt> for each
229.48 + * of a set of tasks, you might use:
229.49 + *
229.50 + * <pre>
229.51 + * Executor executor = <em>anExecutor</em>;
229.52 + * executor.execute(new RunnableTask1());
229.53 + * executor.execute(new RunnableTask2());
229.54 + * ...
229.55 + * </pre>
229.56 + *
229.57 + * However, the <tt>Executor</tt> interface does not strictly
229.58 + * require that execution be asynchronous. In the simplest case, an
229.59 + * executor can run the submitted task immediately in the caller's
229.60 + * thread:
229.61 + *
229.62 + * <pre>
229.63 + * class DirectExecutor implements Executor {
229.64 + * public void execute(Runnable r) {
229.65 + * r.run();
229.66 + * }
229.67 + * }</pre>
229.68 + *
229.69 + * More typically, tasks are executed in some thread other
229.70 + * than the caller's thread. The executor below spawns a new thread
229.71 + * for each task.
229.72 + *
229.73 + * <pre>
229.74 + * class ThreadPerTaskExecutor implements Executor {
229.75 + * public void execute(Runnable r) {
229.76 + * new Thread(r).start();
229.77 + * }
229.78 + * }</pre>
229.79 + *
229.80 + * Many <tt>Executor</tt> implementations impose some sort of
229.81 + * limitation on how and when tasks are scheduled. The executor below
229.82 + * serializes the submission of tasks to a second executor,
229.83 + * illustrating a composite executor.
229.84 + *
229.85 + * <pre> {@code
229.86 + * class SerialExecutor implements Executor {
229.87 + * final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
229.88 + * final Executor executor;
229.89 + * Runnable active;
229.90 + *
229.91 + * SerialExecutor(Executor executor) {
229.92 + * this.executor = executor;
229.93 + * }
229.94 + *
229.95 + * public synchronized void execute(final Runnable r) {
229.96 + * tasks.offer(new Runnable() {
229.97 + * public void run() {
229.98 + * try {
229.99 + * r.run();
229.100 + * } finally {
229.101 + * scheduleNext();
229.102 + * }
229.103 + * }
229.104 + * });
229.105 + * if (active == null) {
229.106 + * scheduleNext();
229.107 + * }
229.108 + * }
229.109 + *
229.110 + * protected synchronized void scheduleNext() {
229.111 + * if ((active = tasks.poll()) != null) {
229.112 + * executor.execute(active);
229.113 + * }
229.114 + * }
229.115 + * }}</pre>
229.116 + *
229.117 + * The <tt>Executor</tt> implementations provided in this package
229.118 + * implement {@link ExecutorService}, which is a more extensive
229.119 + * interface. The {@link ThreadPoolExecutor} class provides an
229.120 + * extensible thread pool implementation. The {@link Executors} class
229.121 + * provides convenient factory methods for these Executors.
229.122 + *
229.123 + * <p>Memory consistency effects: Actions in a thread prior to
229.124 + * submitting a {@code Runnable} object to an {@code Executor}
229.125 + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
229.126 + * its execution begins, perhaps in another thread.
229.127 + *
229.128 + * @since 1.5
229.129 + * @author Doug Lea
229.130 + */
229.131 +public interface Executor {
229.132 +
229.133 + /**
229.134 + * Executes the given command at some time in the future. The command
229.135 + * may execute in a new thread, in a pooled thread, or in the calling
229.136 + * thread, at the discretion of the <tt>Executor</tt> implementation.
229.137 + *
229.138 + * @param command the runnable task
229.139 + * @throws RejectedExecutionException if this task cannot be
229.140 + * accepted for execution.
229.141 + * @throws NullPointerException if command is null
229.142 + */
229.143 + void execute(Runnable command);
229.144 +}
230.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
230.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java Wed Apr 30 15:04:10 2014 +0200
230.3 @@ -0,0 +1,155 @@
230.4 +/*
230.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
230.6 + *
230.7 + * This code is free software; you can redistribute it and/or modify it
230.8 + * under the terms of the GNU General Public License version 2 only, as
230.9 + * published by the Free Software Foundation. Oracle designates this
230.10 + * particular file as subject to the "Classpath" exception as provided
230.11 + * by Oracle in the LICENSE file that accompanied this code.
230.12 + *
230.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
230.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
230.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
230.16 + * version 2 for more details (a copy is included in the LICENSE file that
230.17 + * accompanied this code).
230.18 + *
230.19 + * You should have received a copy of the GNU General Public License version
230.20 + * 2 along with this work; if not, write to the Free Software Foundation,
230.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
230.22 + *
230.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
230.24 + * or visit www.oracle.com if you need additional information or have any
230.25 + * questions.
230.26 + */
230.27 +
230.28 +/*
230.29 + * This file is available under and governed by the GNU General Public
230.30 + * License version 2 only, as published by the Free Software Foundation.
230.31 + * However, the following notice accompanied the original version of this
230.32 + * file:
230.33 + *
230.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
230.35 + * Expert Group and released to the public domain, as explained at
230.36 + * http://creativecommons.org/publicdomain/zero/1.0/
230.37 + */
230.38 +
230.39 +package java.util.concurrent.atomic;
230.40 +
230.41 +/**
230.42 + * A {@code boolean} value that may be updated atomically. See the
230.43 + * {@link java.util.concurrent.atomic} package specification for
230.44 + * description of the properties of atomic variables. An
230.45 + * {@code AtomicBoolean} is used in applications such as atomically
230.46 + * updated flags, and cannot be used as a replacement for a
230.47 + * {@link java.lang.Boolean}.
230.48 + *
230.49 + * @since 1.5
230.50 + * @author Doug Lea
230.51 + */
230.52 +public class AtomicBoolean implements java.io.Serializable {
230.53 + private static final long serialVersionUID = 4654671469794556979L;
230.54 +
230.55 + private volatile int value;
230.56 +
230.57 + /**
230.58 + * Creates a new {@code AtomicBoolean} with the given initial value.
230.59 + *
230.60 + * @param initialValue the initial value
230.61 + */
230.62 + public AtomicBoolean(boolean initialValue) {
230.63 + value = initialValue ? 1 : 0;
230.64 + }
230.65 +
230.66 + /**
230.67 + * Creates a new {@code AtomicBoolean} with initial value {@code false}.
230.68 + */
230.69 + public AtomicBoolean() {
230.70 + }
230.71 +
230.72 + /**
230.73 + * Returns the current value.
230.74 + *
230.75 + * @return the current value
230.76 + */
230.77 + public final boolean get() {
230.78 + return value != 0;
230.79 + }
230.80 +
230.81 + /**
230.82 + * Atomically sets the value to the given updated value
230.83 + * if the current value {@code ==} the expected value.
230.84 + *
230.85 + * @param expect the expected value
230.86 + * @param update the new value
230.87 + * @return true if successful. False return indicates that
230.88 + * the actual value was not equal to the expected value.
230.89 + */
230.90 + public final boolean compareAndSet(boolean expect, boolean update) {
230.91 + int e = expect ? 1 : 0;
230.92 + int u = update ? 1 : 0;
230.93 + if (this.value == e) {
230.94 + this.value = u;
230.95 + return true;
230.96 + } else {
230.97 + return false;
230.98 + }
230.99 + }
230.100 +
230.101 + /**
230.102 + * Atomically sets the value to the given updated value
230.103 + * if the current value {@code ==} the expected value.
230.104 + *
230.105 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
230.106 + * and does not provide ordering guarantees, so is only rarely an
230.107 + * appropriate alternative to {@code compareAndSet}.
230.108 + *
230.109 + * @param expect the expected value
230.110 + * @param update the new value
230.111 + * @return true if successful.
230.112 + */
230.113 + public boolean weakCompareAndSet(boolean expect, boolean update) {
230.114 + return compareAndSet(expect, update);
230.115 + }
230.116 +
230.117 + /**
230.118 + * Unconditionally sets to the given value.
230.119 + *
230.120 + * @param newValue the new value
230.121 + */
230.122 + public final void set(boolean newValue) {
230.123 + value = newValue ? 1 : 0;
230.124 + }
230.125 +
230.126 + /**
230.127 + * Eventually sets to the given value.
230.128 + *
230.129 + * @param newValue the new value
230.130 + * @since 1.6
230.131 + */
230.132 + public final void lazySet(boolean newValue) {
230.133 + set(newValue);
230.134 + }
230.135 +
230.136 + /**
230.137 + * Atomically sets to the given value and returns the previous value.
230.138 + *
230.139 + * @param newValue the new value
230.140 + * @return the previous value
230.141 + */
230.142 + public final boolean getAndSet(boolean newValue) {
230.143 + for (;;) {
230.144 + boolean current = get();
230.145 + if (compareAndSet(current, newValue))
230.146 + return current;
230.147 + }
230.148 + }
230.149 +
230.150 + /**
230.151 + * Returns the String representation of the current value.
230.152 + * @return the String representation of the current value.
230.153 + */
230.154 + public String toString() {
230.155 + return Boolean.toString(get());
230.156 + }
230.157 +
230.158 +}
231.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
231.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicInteger.java Wed Apr 30 15:04:10 2014 +0200
231.3 @@ -0,0 +1,258 @@
231.4 +/*
231.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
231.6 + *
231.7 + * This code is free software; you can redistribute it and/or modify it
231.8 + * under the terms of the GNU General Public License version 2 only, as
231.9 + * published by the Free Software Foundation. Oracle designates this
231.10 + * particular file as subject to the "Classpath" exception as provided
231.11 + * by Oracle in the LICENSE file that accompanied this code.
231.12 + *
231.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
231.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
231.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
231.16 + * version 2 for more details (a copy is included in the LICENSE file that
231.17 + * accompanied this code).
231.18 + *
231.19 + * You should have received a copy of the GNU General Public License version
231.20 + * 2 along with this work; if not, write to the Free Software Foundation,
231.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
231.22 + *
231.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
231.24 + * or visit www.oracle.com if you need additional information or have any
231.25 + * questions.
231.26 + */
231.27 +
231.28 +/*
231.29 + * This file is available under and governed by the GNU General Public
231.30 + * License version 2 only, as published by the Free Software Foundation.
231.31 + * However, the following notice accompanied the original version of this
231.32 + * file:
231.33 + *
231.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
231.35 + * Expert Group and released to the public domain, as explained at
231.36 + * http://creativecommons.org/publicdomain/zero/1.0/
231.37 + */
231.38 +
231.39 +package java.util.concurrent.atomic;
231.40 +
231.41 +/**
231.42 + * An {@code int} value that may be updated atomically. See the
231.43 + * {@link java.util.concurrent.atomic} package specification for
231.44 + * description of the properties of atomic variables. An
231.45 + * {@code AtomicInteger} is used in applications such as atomically
231.46 + * incremented counters, and cannot be used as a replacement for an
231.47 + * {@link java.lang.Integer}. However, this class does extend
231.48 + * {@code Number} to allow uniform access by tools and utilities that
231.49 + * deal with numerically-based classes.
231.50 + *
231.51 + * @since 1.5
231.52 + * @author Doug Lea
231.53 +*/
231.54 +public class AtomicInteger extends Number implements java.io.Serializable {
231.55 + private static final long serialVersionUID = 6214790243416807050L;
231.56 +
231.57 + private volatile int value;
231.58 +
231.59 + /**
231.60 + * Creates a new AtomicInteger with the given initial value.
231.61 + *
231.62 + * @param initialValue the initial value
231.63 + */
231.64 + public AtomicInteger(int initialValue) {
231.65 + value = initialValue;
231.66 + }
231.67 +
231.68 + /**
231.69 + * Creates a new AtomicInteger with initial value {@code 0}.
231.70 + */
231.71 + public AtomicInteger() {
231.72 + }
231.73 +
231.74 + /**
231.75 + * Gets the current value.
231.76 + *
231.77 + * @return the current value
231.78 + */
231.79 + public final int get() {
231.80 + return value;
231.81 + }
231.82 +
231.83 + /**
231.84 + * Sets to the given value.
231.85 + *
231.86 + * @param newValue the new value
231.87 + */
231.88 + public final void set(int newValue) {
231.89 + value = newValue;
231.90 + }
231.91 +
231.92 + /**
231.93 + * Eventually sets to the given value.
231.94 + *
231.95 + * @param newValue the new value
231.96 + * @since 1.6
231.97 + */
231.98 + public final void lazySet(int newValue) {
231.99 + value = newValue;
231.100 + }
231.101 +
231.102 + /**
231.103 + * Atomically sets to the given value and returns the old value.
231.104 + *
231.105 + * @param newValue the new value
231.106 + * @return the previous value
231.107 + */
231.108 + public final int getAndSet(int newValue) {
231.109 + for (;;) {
231.110 + int current = get();
231.111 + if (compareAndSet(current, newValue))
231.112 + return current;
231.113 + }
231.114 + }
231.115 +
231.116 + /**
231.117 + * Atomically sets the value to the given updated value
231.118 + * if the current value {@code ==} the expected value.
231.119 + *
231.120 + * @param expect the expected value
231.121 + * @param update the new value
231.122 + * @return true if successful. False return indicates that
231.123 + * the actual value was not equal to the expected value.
231.124 + */
231.125 + public final boolean compareAndSet(int expect, int update) {
231.126 + if (value == expect) {
231.127 + value = update;
231.128 + return true;
231.129 + } else {
231.130 + return false;
231.131 + }
231.132 + }
231.133 +
231.134 + /**
231.135 + * Atomically sets the value to the given updated value
231.136 + * if the current value {@code ==} the expected value.
231.137 + *
231.138 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
231.139 + * and does not provide ordering guarantees, so is only rarely an
231.140 + * appropriate alternative to {@code compareAndSet}.
231.141 + *
231.142 + * @param expect the expected value
231.143 + * @param update the new value
231.144 + * @return true if successful.
231.145 + */
231.146 + public final boolean weakCompareAndSet(int expect, int update) {
231.147 + return compareAndSet(expect, update);
231.148 + }
231.149 +
231.150 + /**
231.151 + * Atomically increments by one the current value.
231.152 + *
231.153 + * @return the previous value
231.154 + */
231.155 + public final int getAndIncrement() {
231.156 + for (;;) {
231.157 + int current = get();
231.158 + int next = current + 1;
231.159 + if (compareAndSet(current, next))
231.160 + return current;
231.161 + }
231.162 + }
231.163 +
231.164 + /**
231.165 + * Atomically decrements by one the current value.
231.166 + *
231.167 + * @return the previous value
231.168 + */
231.169 + public final int getAndDecrement() {
231.170 + for (;;) {
231.171 + int current = get();
231.172 + int next = current - 1;
231.173 + if (compareAndSet(current, next))
231.174 + return current;
231.175 + }
231.176 + }
231.177 +
231.178 + /**
231.179 + * Atomically adds the given value to the current value.
231.180 + *
231.181 + * @param delta the value to add
231.182 + * @return the previous value
231.183 + */
231.184 + public final int getAndAdd(int delta) {
231.185 + for (;;) {
231.186 + int current = get();
231.187 + int next = current + delta;
231.188 + if (compareAndSet(current, next))
231.189 + return current;
231.190 + }
231.191 + }
231.192 +
231.193 + /**
231.194 + * Atomically increments by one the current value.
231.195 + *
231.196 + * @return the updated value
231.197 + */
231.198 + public final int incrementAndGet() {
231.199 + for (;;) {
231.200 + int current = get();
231.201 + int next = current + 1;
231.202 + if (compareAndSet(current, next))
231.203 + return next;
231.204 + }
231.205 + }
231.206 +
231.207 + /**
231.208 + * Atomically decrements by one the current value.
231.209 + *
231.210 + * @return the updated value
231.211 + */
231.212 + public final int decrementAndGet() {
231.213 + for (;;) {
231.214 + int current = get();
231.215 + int next = current - 1;
231.216 + if (compareAndSet(current, next))
231.217 + return next;
231.218 + }
231.219 + }
231.220 +
231.221 + /**
231.222 + * Atomically adds the given value to the current value.
231.223 + *
231.224 + * @param delta the value to add
231.225 + * @return the updated value
231.226 + */
231.227 + public final int addAndGet(int delta) {
231.228 + for (;;) {
231.229 + int current = get();
231.230 + int next = current + delta;
231.231 + if (compareAndSet(current, next))
231.232 + return next;
231.233 + }
231.234 + }
231.235 +
231.236 + /**
231.237 + * Returns the String representation of the current value.
231.238 + * @return the String representation of the current value.
231.239 + */
231.240 + public String toString() {
231.241 + return Integer.toString(get());
231.242 + }
231.243 +
231.244 +
231.245 + public int intValue() {
231.246 + return get();
231.247 + }
231.248 +
231.249 + public long longValue() {
231.250 + return (long)get();
231.251 + }
231.252 +
231.253 + public float floatValue() {
231.254 + return (float)get();
231.255 + }
231.256 +
231.257 + public double doubleValue() {
231.258 + return (double)get();
231.259 + }
231.260 +
231.261 +}
232.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
232.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java Wed Apr 30 15:04:10 2014 +0200
232.3 @@ -0,0 +1,247 @@
232.4 +/*
232.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
232.6 + *
232.7 + * This code is free software; you can redistribute it and/or modify it
232.8 + * under the terms of the GNU General Public License version 2 only, as
232.9 + * published by the Free Software Foundation. Oracle designates this
232.10 + * particular file as subject to the "Classpath" exception as provided
232.11 + * by Oracle in the LICENSE file that accompanied this code.
232.12 + *
232.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
232.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
232.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
232.16 + * version 2 for more details (a copy is included in the LICENSE file that
232.17 + * accompanied this code).
232.18 + *
232.19 + * You should have received a copy of the GNU General Public License version
232.20 + * 2 along with this work; if not, write to the Free Software Foundation,
232.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
232.22 + *
232.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
232.24 + * or visit www.oracle.com if you need additional information or have any
232.25 + * questions.
232.26 + */
232.27 +
232.28 +/*
232.29 + * This file is available under and governed by the GNU General Public
232.30 + * License version 2 only, as published by the Free Software Foundation.
232.31 + * However, the following notice accompanied the original version of this
232.32 + * file:
232.33 + *
232.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
232.35 + * Expert Group and released to the public domain, as explained at
232.36 + * http://creativecommons.org/publicdomain/zero/1.0/
232.37 + */
232.38 +
232.39 +package java.util.concurrent.atomic;
232.40 +
232.41 +/**
232.42 + * An {@code int} array in which elements may be updated atomically.
232.43 + * See the {@link java.util.concurrent.atomic} package
232.44 + * specification for description of the properties of atomic
232.45 + * variables.
232.46 + * @since 1.5
232.47 + * @author Doug Lea
232.48 + */
232.49 +public class AtomicIntegerArray implements java.io.Serializable {
232.50 + private static final long serialVersionUID = 2862133569453604235L;
232.51 +
232.52 + private final int[] array;
232.53 +
232.54 + /**
232.55 + * Creates a new AtomicIntegerArray of the given length, with all
232.56 + * elements initially zero.
232.57 + *
232.58 + * @param length the length of the array
232.59 + */
232.60 + public AtomicIntegerArray(int length) {
232.61 + array = new int[length];
232.62 + }
232.63 +
232.64 + /**
232.65 + * Creates a new AtomicIntegerArray with the same length as, and
232.66 + * all elements copied from, the given array.
232.67 + *
232.68 + * @param array the array to copy elements from
232.69 + * @throws NullPointerException if array is null
232.70 + */
232.71 + public AtomicIntegerArray(int[] array) {
232.72 + // Visibility guaranteed by final field guarantees
232.73 + this.array = array.clone();
232.74 + }
232.75 +
232.76 + /**
232.77 + * Returns the length of the array.
232.78 + *
232.79 + * @return the length of the array
232.80 + */
232.81 + public final int length() {
232.82 + return array.length;
232.83 + }
232.84 +
232.85 + /**
232.86 + * Gets the current value at position {@code i}.
232.87 + *
232.88 + * @param i the index
232.89 + * @return the current value
232.90 + */
232.91 + public final int get(int i) {
232.92 + return array[i];
232.93 + }
232.94 +
232.95 + /**
232.96 + * Sets the element at position {@code i} to the given value.
232.97 + *
232.98 + * @param i the index
232.99 + * @param newValue the new value
232.100 + */
232.101 + public final void set(int i, int newValue) {
232.102 + array[i] = newValue;
232.103 + }
232.104 +
232.105 + /**
232.106 + * Eventually sets the element at position {@code i} to the given value.
232.107 + *
232.108 + * @param i the index
232.109 + * @param newValue the new value
232.110 + * @since 1.6
232.111 + */
232.112 + public final void lazySet(int i, int newValue) {
232.113 + array[i] = newValue;
232.114 + }
232.115 +
232.116 + /**
232.117 + * Atomically sets the element at position {@code i} to the given
232.118 + * value and returns the old value.
232.119 + *
232.120 + * @param i the index
232.121 + * @param newValue the new value
232.122 + * @return the previous value
232.123 + */
232.124 + public final int getAndSet(int i, int newValue) {
232.125 + int current = array[i];
232.126 + array[i] = newValue;
232.127 + return current;
232.128 + }
232.129 +
232.130 + /**
232.131 + * Atomically sets the element at position {@code i} to the given
232.132 + * updated value if the current value {@code ==} the expected value.
232.133 + *
232.134 + * @param i the index
232.135 + * @param expect the expected value
232.136 + * @param update the new value
232.137 + * @return true if successful. False return indicates that
232.138 + * the actual value was not equal to the expected value.
232.139 + */
232.140 + public final boolean compareAndSet(int i, int expect, int update) {
232.141 + if (array[i] == expect) {
232.142 + array[i] = update;
232.143 + return true;
232.144 + } else {
232.145 + return false;
232.146 + }
232.147 + }
232.148 +
232.149 + /**
232.150 + * Atomically sets the element at position {@code i} to the given
232.151 + * updated value if the current value {@code ==} the expected value.
232.152 + *
232.153 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
232.154 + * and does not provide ordering guarantees, so is only rarely an
232.155 + * appropriate alternative to {@code compareAndSet}.
232.156 + *
232.157 + * @param i the index
232.158 + * @param expect the expected value
232.159 + * @param update the new value
232.160 + * @return true if successful.
232.161 + */
232.162 + public final boolean weakCompareAndSet(int i, int expect, int update) {
232.163 + return compareAndSet(i, expect, update);
232.164 + }
232.165 +
232.166 + /**
232.167 + * Atomically increments by one the element at index {@code i}.
232.168 + *
232.169 + * @param i the index
232.170 + * @return the previous value
232.171 + */
232.172 + public final int getAndIncrement(int i) {
232.173 + return getAndAdd(i, 1);
232.174 + }
232.175 +
232.176 + /**
232.177 + * Atomically decrements by one the element at index {@code i}.
232.178 + *
232.179 + * @param i the index
232.180 + * @return the previous value
232.181 + */
232.182 + public final int getAndDecrement(int i) {
232.183 + return getAndAdd(i, -1);
232.184 + }
232.185 +
232.186 + /**
232.187 + * Atomically adds the given value to the element at index {@code i}.
232.188 + *
232.189 + * @param i the index
232.190 + * @param delta the value to add
232.191 + * @return the previous value
232.192 + */
232.193 + public final int getAndAdd(int i, int delta) {
232.194 + int v = array[i];
232.195 + array[i] += delta;
232.196 + return v;
232.197 + }
232.198 +
232.199 + /**
232.200 + * Atomically increments by one the element at index {@code i}.
232.201 + *
232.202 + * @param i the index
232.203 + * @return the updated value
232.204 + */
232.205 + public final int incrementAndGet(int i) {
232.206 + return addAndGet(i, 1);
232.207 + }
232.208 +
232.209 + /**
232.210 + * Atomically decrements by one the element at index {@code i}.
232.211 + *
232.212 + * @param i the index
232.213 + * @return the updated value
232.214 + */
232.215 + public final int decrementAndGet(int i) {
232.216 + return addAndGet(i, -1);
232.217 + }
232.218 +
232.219 + /**
232.220 + * Atomically adds the given value to the element at index {@code i}.
232.221 + *
232.222 + * @param i the index
232.223 + * @param delta the value to add
232.224 + * @return the updated value
232.225 + */
232.226 + public final int addAndGet(int i, int delta) {
232.227 + array[i] += delta;
232.228 + return array[i];
232.229 + }
232.230 +
232.231 + /**
232.232 + * Returns the String representation of the current values of array.
232.233 + * @return the String representation of the current values of array
232.234 + */
232.235 + public String toString() {
232.236 + int iMax = array.length - 1;
232.237 + if (iMax == -1)
232.238 + return "[]";
232.239 +
232.240 + StringBuilder b = new StringBuilder();
232.241 + b.append('[');
232.242 + for (int i = 0; ; i++) {
232.243 + b.append(get(i));
232.244 + if (i == iMax)
232.245 + return b.append(']').toString();
232.246 + b.append(',').append(' ');
232.247 + }
232.248 + }
232.249 +
232.250 +}
233.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
233.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLong.java Wed Apr 30 15:04:10 2014 +0200
233.3 @@ -0,0 +1,265 @@
233.4 +/*
233.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
233.6 + *
233.7 + * This code is free software; you can redistribute it and/or modify it
233.8 + * under the terms of the GNU General Public License version 2 only, as
233.9 + * published by the Free Software Foundation. Oracle designates this
233.10 + * particular file as subject to the "Classpath" exception as provided
233.11 + * by Oracle in the LICENSE file that accompanied this code.
233.12 + *
233.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
233.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
233.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
233.16 + * version 2 for more details (a copy is included in the LICENSE file that
233.17 + * accompanied this code).
233.18 + *
233.19 + * You should have received a copy of the GNU General Public License version
233.20 + * 2 along with this work; if not, write to the Free Software Foundation,
233.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
233.22 + *
233.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
233.24 + * or visit www.oracle.com if you need additional information or have any
233.25 + * questions.
233.26 + */
233.27 +
233.28 +/*
233.29 + * This file is available under and governed by the GNU General Public
233.30 + * License version 2 only, as published by the Free Software Foundation.
233.31 + * However, the following notice accompanied the original version of this
233.32 + * file:
233.33 + *
233.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
233.35 + * Expert Group and released to the public domain, as explained at
233.36 + * http://creativecommons.org/publicdomain/zero/1.0/
233.37 + */
233.38 +
233.39 +package java.util.concurrent.atomic;
233.40 +
233.41 +/**
233.42 + * A {@code long} value that may be updated atomically. See the
233.43 + * {@link java.util.concurrent.atomic} package specification for
233.44 + * description of the properties of atomic variables. An
233.45 + * {@code AtomicLong} is used in applications such as atomically
233.46 + * incremented sequence numbers, and cannot be used as a replacement
233.47 + * for a {@link java.lang.Long}. However, this class does extend
233.48 + * {@code Number} to allow uniform access by tools and utilities that
233.49 + * deal with numerically-based classes.
233.50 + *
233.51 + * @since 1.5
233.52 + * @author Doug Lea
233.53 + */
233.54 +public class AtomicLong extends Number implements java.io.Serializable {
233.55 + private static final long serialVersionUID = 1927816293512124184L;
233.56 +
233.57 +
233.58 + /**
233.59 + * Returns whether underlying JVM supports lockless CompareAndSet
233.60 + * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
233.61 + */
233.62 + private static native boolean VMSupportsCS8();
233.63 +
233.64 + private volatile long value;
233.65 +
233.66 + /**
233.67 + * Creates a new AtomicLong with the given initial value.
233.68 + *
233.69 + * @param initialValue the initial value
233.70 + */
233.71 + public AtomicLong(long initialValue) {
233.72 + value = initialValue;
233.73 + }
233.74 +
233.75 + /**
233.76 + * Creates a new AtomicLong with initial value {@code 0}.
233.77 + */
233.78 + public AtomicLong() {
233.79 + }
233.80 +
233.81 + /**
233.82 + * Gets the current value.
233.83 + *
233.84 + * @return the current value
233.85 + */
233.86 + public final long get() {
233.87 + return value;
233.88 + }
233.89 +
233.90 + /**
233.91 + * Sets to the given value.
233.92 + *
233.93 + * @param newValue the new value
233.94 + */
233.95 + public final void set(long newValue) {
233.96 + value = newValue;
233.97 + }
233.98 +
233.99 + /**
233.100 + * Eventually sets to the given value.
233.101 + *
233.102 + * @param newValue the new value
233.103 + * @since 1.6
233.104 + */
233.105 + public final void lazySet(long newValue) {
233.106 + value = newValue;
233.107 + }
233.108 +
233.109 + /**
233.110 + * Atomically sets to the given value and returns the old value.
233.111 + *
233.112 + * @param newValue the new value
233.113 + * @return the previous value
233.114 + */
233.115 + public final long getAndSet(long newValue) {
233.116 + while (true) {
233.117 + long current = get();
233.118 + if (compareAndSet(current, newValue))
233.119 + return current;
233.120 + }
233.121 + }
233.122 +
233.123 + /**
233.124 + * Atomically sets the value to the given updated value
233.125 + * if the current value {@code ==} the expected value.
233.126 + *
233.127 + * @param expect the expected value
233.128 + * @param update the new value
233.129 + * @return true if successful. False return indicates that
233.130 + * the actual value was not equal to the expected value.
233.131 + */
233.132 + public final boolean compareAndSet(long expect, long update) {
233.133 + if (value == expect) {
233.134 + value = update;
233.135 + return true;
233.136 + } else {
233.137 + return false;
233.138 + }
233.139 + }
233.140 +
233.141 + /**
233.142 + * Atomically sets the value to the given updated value
233.143 + * if the current value {@code ==} the expected value.
233.144 + *
233.145 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
233.146 + * and does not provide ordering guarantees, so is only rarely an
233.147 + * appropriate alternative to {@code compareAndSet}.
233.148 + *
233.149 + * @param expect the expected value
233.150 + * @param update the new value
233.151 + * @return true if successful.
233.152 + */
233.153 + public final boolean weakCompareAndSet(long expect, long update) {
233.154 + return compareAndSet(expect, update);
233.155 + }
233.156 +
233.157 + /**
233.158 + * Atomically increments by one the current value.
233.159 + *
233.160 + * @return the previous value
233.161 + */
233.162 + public final long getAndIncrement() {
233.163 + while (true) {
233.164 + long current = get();
233.165 + long next = current + 1;
233.166 + if (compareAndSet(current, next))
233.167 + return current;
233.168 + }
233.169 + }
233.170 +
233.171 + /**
233.172 + * Atomically decrements by one the current value.
233.173 + *
233.174 + * @return the previous value
233.175 + */
233.176 + public final long getAndDecrement() {
233.177 + while (true) {
233.178 + long current = get();
233.179 + long next = current - 1;
233.180 + if (compareAndSet(current, next))
233.181 + return current;
233.182 + }
233.183 + }
233.184 +
233.185 + /**
233.186 + * Atomically adds the given value to the current value.
233.187 + *
233.188 + * @param delta the value to add
233.189 + * @return the previous value
233.190 + */
233.191 + public final long getAndAdd(long delta) {
233.192 + while (true) {
233.193 + long current = get();
233.194 + long next = current + delta;
233.195 + if (compareAndSet(current, next))
233.196 + return current;
233.197 + }
233.198 + }
233.199 +
233.200 + /**
233.201 + * Atomically increments by one the current value.
233.202 + *
233.203 + * @return the updated value
233.204 + */
233.205 + public final long incrementAndGet() {
233.206 + for (;;) {
233.207 + long current = get();
233.208 + long next = current + 1;
233.209 + if (compareAndSet(current, next))
233.210 + return next;
233.211 + }
233.212 + }
233.213 +
233.214 + /**
233.215 + * Atomically decrements by one the current value.
233.216 + *
233.217 + * @return the updated value
233.218 + */
233.219 + public final long decrementAndGet() {
233.220 + for (;;) {
233.221 + long current = get();
233.222 + long next = current - 1;
233.223 + if (compareAndSet(current, next))
233.224 + return next;
233.225 + }
233.226 + }
233.227 +
233.228 + /**
233.229 + * Atomically adds the given value to the current value.
233.230 + *
233.231 + * @param delta the value to add
233.232 + * @return the updated value
233.233 + */
233.234 + public final long addAndGet(long delta) {
233.235 + for (;;) {
233.236 + long current = get();
233.237 + long next = current + delta;
233.238 + if (compareAndSet(current, next))
233.239 + return next;
233.240 + }
233.241 + }
233.242 +
233.243 + /**
233.244 + * Returns the String representation of the current value.
233.245 + * @return the String representation of the current value.
233.246 + */
233.247 + public String toString() {
233.248 + return Long.toString(get());
233.249 + }
233.250 +
233.251 +
233.252 + public int intValue() {
233.253 + return (int)get();
233.254 + }
233.255 +
233.256 + public long longValue() {
233.257 + return get();
233.258 + }
233.259 +
233.260 + public float floatValue() {
233.261 + return (float)get();
233.262 + }
233.263 +
233.264 + public double doubleValue() {
233.265 + return (double)get();
233.266 + }
233.267 +
233.268 +}
234.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
234.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java Wed Apr 30 15:04:10 2014 +0200
234.3 @@ -0,0 +1,247 @@
234.4 +/*
234.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
234.6 + *
234.7 + * This code is free software; you can redistribute it and/or modify it
234.8 + * under the terms of the GNU General Public License version 2 only, as
234.9 + * published by the Free Software Foundation. Oracle designates this
234.10 + * particular file as subject to the "Classpath" exception as provided
234.11 + * by Oracle in the LICENSE file that accompanied this code.
234.12 + *
234.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
234.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
234.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
234.16 + * version 2 for more details (a copy is included in the LICENSE file that
234.17 + * accompanied this code).
234.18 + *
234.19 + * You should have received a copy of the GNU General Public License version
234.20 + * 2 along with this work; if not, write to the Free Software Foundation,
234.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
234.22 + *
234.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
234.24 + * or visit www.oracle.com if you need additional information or have any
234.25 + * questions.
234.26 + */
234.27 +
234.28 +/*
234.29 + * This file is available under and governed by the GNU General Public
234.30 + * License version 2 only, as published by the Free Software Foundation.
234.31 + * However, the following notice accompanied the original version of this
234.32 + * file:
234.33 + *
234.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
234.35 + * Expert Group and released to the public domain, as explained at
234.36 + * http://creativecommons.org/publicdomain/zero/1.0/
234.37 + */
234.38 +
234.39 +package java.util.concurrent.atomic;
234.40 +
234.41 +/**
234.42 + * A {@code long} array in which elements may be updated atomically.
234.43 + * See the {@link java.util.concurrent.atomic} package specification
234.44 + * for description of the properties of atomic variables.
234.45 + * @since 1.5
234.46 + * @author Doug Lea
234.47 + */
234.48 +public class AtomicLongArray implements java.io.Serializable {
234.49 + private static final long serialVersionUID = -2308431214976778248L;
234.50 +
234.51 + private final long[] array;
234.52 +
234.53 + /**
234.54 + * Creates a new AtomicLongArray of the given length, with all
234.55 + * elements initially zero.
234.56 + *
234.57 + * @param length the length of the array
234.58 + */
234.59 + public AtomicLongArray(int length) {
234.60 + array = new long[length];
234.61 + }
234.62 +
234.63 + /**
234.64 + * Creates a new AtomicLongArray with the same length as, and
234.65 + * all elements copied from, the given array.
234.66 + *
234.67 + * @param array the array to copy elements from
234.68 + * @throws NullPointerException if array is null
234.69 + */
234.70 + public AtomicLongArray(long[] array) {
234.71 + // Visibility guaranteed by final field guarantees
234.72 + this.array = array.clone();
234.73 + }
234.74 +
234.75 + /**
234.76 + * Returns the length of the array.
234.77 + *
234.78 + * @return the length of the array
234.79 + */
234.80 + public final int length() {
234.81 + return array.length;
234.82 + }
234.83 +
234.84 + /**
234.85 + * Gets the current value at position {@code i}.
234.86 + *
234.87 + * @param i the index
234.88 + * @return the current value
234.89 + */
234.90 + public final long get(int i) {
234.91 + return array[i];
234.92 + }
234.93 +
234.94 + /**
234.95 + * Sets the element at position {@code i} to the given value.
234.96 + *
234.97 + * @param i the index
234.98 + * @param newValue the new value
234.99 + */
234.100 + public final void set(int i, long newValue) {
234.101 + array[i] = newValue;
234.102 + }
234.103 +
234.104 + /**
234.105 + * Eventually sets the element at position {@code i} to the given value.
234.106 + *
234.107 + * @param i the index
234.108 + * @param newValue the new value
234.109 + * @since 1.6
234.110 + */
234.111 + public final void lazySet(int i, long newValue) {
234.112 + array[i] = newValue;
234.113 + }
234.114 +
234.115 +
234.116 + /**
234.117 + * Atomically sets the element at position {@code i} to the given value
234.118 + * and returns the old value.
234.119 + *
234.120 + * @param i the index
234.121 + * @param newValue the new value
234.122 + * @return the previous value
234.123 + */
234.124 + public final long getAndSet(int i, long newValue) {
234.125 + long v = array[i];
234.126 + array[i] = newValue;
234.127 + return v;
234.128 + }
234.129 +
234.130 + /**
234.131 + * Atomically sets the element at position {@code i} to the given
234.132 + * updated value if the current value {@code ==} the expected value.
234.133 + *
234.134 + * @param i the index
234.135 + * @param expect the expected value
234.136 + * @param update the new value
234.137 + * @return true if successful. False return indicates that
234.138 + * the actual value was not equal to the expected value.
234.139 + */
234.140 + public final boolean compareAndSet(int i, long expect, long update) {
234.141 + if (array[i] == expect) {
234.142 + array[i] = update;
234.143 + return true;
234.144 + } else {
234.145 + return false;
234.146 + }
234.147 + }
234.148 +
234.149 + /**
234.150 + * Atomically sets the element at position {@code i} to the given
234.151 + * updated value if the current value {@code ==} the expected value.
234.152 + *
234.153 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
234.154 + * and does not provide ordering guarantees, so is only rarely an
234.155 + * appropriate alternative to {@code compareAndSet}.
234.156 + *
234.157 + * @param i the index
234.158 + * @param expect the expected value
234.159 + * @param update the new value
234.160 + * @return true if successful.
234.161 + */
234.162 + public final boolean weakCompareAndSet(int i, long expect, long update) {
234.163 + return compareAndSet(i, expect, update);
234.164 + }
234.165 +
234.166 + /**
234.167 + * Atomically increments by one the element at index {@code i}.
234.168 + *
234.169 + * @param i the index
234.170 + * @return the previous value
234.171 + */
234.172 + public final long getAndIncrement(int i) {
234.173 + return getAndAdd(i, 1);
234.174 + }
234.175 +
234.176 + /**
234.177 + * Atomically decrements by one the element at index {@code i}.
234.178 + *
234.179 + * @param i the index
234.180 + * @return the previous value
234.181 + */
234.182 + public final long getAndDecrement(int i) {
234.183 + return getAndAdd(i, -1);
234.184 + }
234.185 +
234.186 + /**
234.187 + * Atomically adds the given value to the element at index {@code i}.
234.188 + *
234.189 + * @param i the index
234.190 + * @param delta the value to add
234.191 + * @return the previous value
234.192 + */
234.193 + public final long getAndAdd(int i, long delta) {
234.194 + long v = array[i];
234.195 + array[i] += delta;
234.196 + return v;
234.197 + }
234.198 +
234.199 + /**
234.200 + * Atomically increments by one the element at index {@code i}.
234.201 + *
234.202 + * @param i the index
234.203 + * @return the updated value
234.204 + */
234.205 + public final long incrementAndGet(int i) {
234.206 + return addAndGet(i, 1);
234.207 + }
234.208 +
234.209 + /**
234.210 + * Atomically decrements by one the element at index {@code i}.
234.211 + *
234.212 + * @param i the index
234.213 + * @return the updated value
234.214 + */
234.215 + public final long decrementAndGet(int i) {
234.216 + return addAndGet(i, -1);
234.217 + }
234.218 +
234.219 + /**
234.220 + * Atomically adds the given value to the element at index {@code i}.
234.221 + *
234.222 + * @param i the index
234.223 + * @param delta the value to add
234.224 + * @return the updated value
234.225 + */
234.226 + public long addAndGet(int i, long delta) {
234.227 + array[i] += delta;
234.228 + return array[i];
234.229 + }
234.230 +
234.231 + /**
234.232 + * Returns the String representation of the current values of array.
234.233 + * @return the String representation of the current values of array
234.234 + */
234.235 + public String toString() {
234.236 + int iMax = array.length - 1;
234.237 + if (iMax == -1)
234.238 + return "[]";
234.239 +
234.240 + StringBuilder b = new StringBuilder();
234.241 + b.append('[');
234.242 + for (int i = 0; ; i++) {
234.243 + b.append(get(i));
234.244 + if (i == iMax)
234.245 + return b.append(']').toString();
234.246 + b.append(',').append(' ');
234.247 + }
234.248 + }
234.249 +
234.250 +}
235.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
235.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReference.java Wed Apr 30 15:04:10 2014 +0200
235.3 @@ -0,0 +1,149 @@
235.4 +/*
235.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
235.6 + *
235.7 + * This code is free software; you can redistribute it and/or modify it
235.8 + * under the terms of the GNU General Public License version 2 only, as
235.9 + * published by the Free Software Foundation. Oracle designates this
235.10 + * particular file as subject to the "Classpath" exception as provided
235.11 + * by Oracle in the LICENSE file that accompanied this code.
235.12 + *
235.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
235.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
235.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
235.16 + * version 2 for more details (a copy is included in the LICENSE file that
235.17 + * accompanied this code).
235.18 + *
235.19 + * You should have received a copy of the GNU General Public License version
235.20 + * 2 along with this work; if not, write to the Free Software Foundation,
235.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
235.22 + *
235.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
235.24 + * or visit www.oracle.com if you need additional information or have any
235.25 + * questions.
235.26 + */
235.27 +
235.28 +/*
235.29 + * This file is available under and governed by the GNU General Public
235.30 + * License version 2 only, as published by the Free Software Foundation.
235.31 + * However, the following notice accompanied the original version of this
235.32 + * file:
235.33 + *
235.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
235.35 + * Expert Group and released to the public domain, as explained at
235.36 + * http://creativecommons.org/publicdomain/zero/1.0/
235.37 + */
235.38 +
235.39 +package java.util.concurrent.atomic;
235.40 +
235.41 +/**
235.42 + * An object reference that may be updated atomically. See the {@link
235.43 + * java.util.concurrent.atomic} package specification for description
235.44 + * of the properties of atomic variables.
235.45 + * @since 1.5
235.46 + * @author Doug Lea
235.47 + * @param <V> The type of object referred to by this reference
235.48 + */
235.49 +public class AtomicReference<V> implements java.io.Serializable {
235.50 + private static final long serialVersionUID = -1848883965231344442L;
235.51 +
235.52 + private volatile V value;
235.53 +
235.54 + /**
235.55 + * Creates a new AtomicReference with the given initial value.
235.56 + *
235.57 + * @param initialValue the initial value
235.58 + */
235.59 + public AtomicReference(V initialValue) {
235.60 + value = initialValue;
235.61 + }
235.62 +
235.63 + /**
235.64 + * Creates a new AtomicReference with null initial value.
235.65 + */
235.66 + public AtomicReference() {
235.67 + }
235.68 +
235.69 + /**
235.70 + * Gets the current value.
235.71 + *
235.72 + * @return the current value
235.73 + */
235.74 + public final V get() {
235.75 + return value;
235.76 + }
235.77 +
235.78 + /**
235.79 + * Sets to the given value.
235.80 + *
235.81 + * @param newValue the new value
235.82 + */
235.83 + public final void set(V newValue) {
235.84 + value = newValue;
235.85 + }
235.86 +
235.87 + /**
235.88 + * Eventually sets to the given value.
235.89 + *
235.90 + * @param newValue the new value
235.91 + * @since 1.6
235.92 + */
235.93 + public final void lazySet(V newValue) {
235.94 + value = newValue;
235.95 + }
235.96 +
235.97 + /**
235.98 + * Atomically sets the value to the given updated value
235.99 + * if the current value {@code ==} the expected value.
235.100 + * @param expect the expected value
235.101 + * @param update the new value
235.102 + * @return true if successful. False return indicates that
235.103 + * the actual value was not equal to the expected value.
235.104 + */
235.105 + public final boolean compareAndSet(V expect, V update) {
235.106 + if (value == expect) {
235.107 + value = update;
235.108 + return true;
235.109 + } else {
235.110 + return false;
235.111 + }
235.112 + }
235.113 +
235.114 + /**
235.115 + * Atomically sets the value to the given updated value
235.116 + * if the current value {@code ==} the expected value.
235.117 + *
235.118 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
235.119 + * and does not provide ordering guarantees, so is only rarely an
235.120 + * appropriate alternative to {@code compareAndSet}.
235.121 + *
235.122 + * @param expect the expected value
235.123 + * @param update the new value
235.124 + * @return true if successful.
235.125 + */
235.126 + public final boolean weakCompareAndSet(V expect, V update) {
235.127 + return compareAndSet(expect, update);
235.128 + }
235.129 +
235.130 + /**
235.131 + * Atomically sets to the given value and returns the old value.
235.132 + *
235.133 + * @param newValue the new value
235.134 + * @return the previous value
235.135 + */
235.136 + public final V getAndSet(V newValue) {
235.137 + while (true) {
235.138 + V x = get();
235.139 + if (compareAndSet(x, newValue))
235.140 + return x;
235.141 + }
235.142 + }
235.143 +
235.144 + /**
235.145 + * Returns the String representation of the current value.
235.146 + * @return the String representation of the current value.
235.147 + */
235.148 + public String toString() {
235.149 + return String.valueOf(get());
235.150 + }
235.151 +
235.152 +}
236.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
236.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java Wed Apr 30 15:04:10 2014 +0200
236.3 @@ -0,0 +1,184 @@
236.4 +/*
236.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
236.6 + *
236.7 + * This code is free software; you can redistribute it and/or modify it
236.8 + * under the terms of the GNU General Public License version 2 only, as
236.9 + * published by the Free Software Foundation. Oracle designates this
236.10 + * particular file as subject to the "Classpath" exception as provided
236.11 + * by Oracle in the LICENSE file that accompanied this code.
236.12 + *
236.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
236.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
236.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
236.16 + * version 2 for more details (a copy is included in the LICENSE file that
236.17 + * accompanied this code).
236.18 + *
236.19 + * You should have received a copy of the GNU General Public License version
236.20 + * 2 along with this work; if not, write to the Free Software Foundation,
236.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
236.22 + *
236.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
236.24 + * or visit www.oracle.com if you need additional information or have any
236.25 + * questions.
236.26 + */
236.27 +
236.28 +/*
236.29 + * This file is available under and governed by the GNU General Public
236.30 + * License version 2 only, as published by the Free Software Foundation.
236.31 + * However, the following notice accompanied the original version of this
236.32 + * file:
236.33 + *
236.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
236.35 + * Expert Group and released to the public domain, as explained at
236.36 + * http://creativecommons.org/publicdomain/zero/1.0/
236.37 + */
236.38 +
236.39 +package java.util.concurrent.atomic;
236.40 +
236.41 +/**
236.42 + * An array of object references in which elements may be updated
236.43 + * atomically. See the {@link java.util.concurrent.atomic} package
236.44 + * specification for description of the properties of atomic
236.45 + * variables.
236.46 + * @since 1.5
236.47 + * @author Doug Lea
236.48 + * @param <E> The base class of elements held in this array
236.49 + */
236.50 +public class AtomicReferenceArray<E> implements java.io.Serializable {
236.51 + private static final long serialVersionUID = -6209656149925076980L;
236.52 +
236.53 + private final Object[] array;
236.54 +
236.55 + /**
236.56 + * Creates a new AtomicReferenceArray of the given length, with all
236.57 + * elements initially null.
236.58 + *
236.59 + * @param length the length of the array
236.60 + */
236.61 + public AtomicReferenceArray(int length) {
236.62 + array = new Object[length];
236.63 + }
236.64 +
236.65 + /**
236.66 + * Creates a new AtomicReferenceArray with the same length as, and
236.67 + * all elements copied from, the given array.
236.68 + *
236.69 + * @param array the array to copy elements from
236.70 + * @throws NullPointerException if array is null
236.71 + */
236.72 + public AtomicReferenceArray(E[] array) {
236.73 + // Visibility guaranteed by final field guarantees
236.74 + this.array = array.clone();
236.75 + }
236.76 +
236.77 + /**
236.78 + * Returns the length of the array.
236.79 + *
236.80 + * @return the length of the array
236.81 + */
236.82 + public final int length() {
236.83 + return array.length;
236.84 + }
236.85 +
236.86 + /**
236.87 + * Gets the current value at position {@code i}.
236.88 + *
236.89 + * @param i the index
236.90 + * @return the current value
236.91 + */
236.92 + public final E get(int i) {
236.93 + return (E)array[i];
236.94 + }
236.95 +
236.96 + /**
236.97 + * Sets the element at position {@code i} to the given value.
236.98 + *
236.99 + * @param i the index
236.100 + * @param newValue the new value
236.101 + */
236.102 + public final void set(int i, E newValue) {
236.103 + array[i] = newValue;
236.104 + }
236.105 +
236.106 + /**
236.107 + * Eventually sets the element at position {@code i} to the given value.
236.108 + *
236.109 + * @param i the index
236.110 + * @param newValue the new value
236.111 + * @since 1.6
236.112 + */
236.113 + public final void lazySet(int i, E newValue) {
236.114 + array[i] = newValue;
236.115 + }
236.116 +
236.117 +
236.118 + /**
236.119 + * Atomically sets the element at position {@code i} to the given
236.120 + * value and returns the old value.
236.121 + *
236.122 + * @param i the index
236.123 + * @param newValue the new value
236.124 + * @return the previous value
236.125 + */
236.126 + public final E getAndSet(int i, E newValue) {
236.127 + E v = (E)array[i];
236.128 + array[i] = newValue;
236.129 + return v;
236.130 + }
236.131 +
236.132 + /**
236.133 + * Atomically sets the element at position {@code i} to the given
236.134 + * updated value if the current value {@code ==} the expected value.
236.135 + *
236.136 + * @param i the index
236.137 + * @param expect the expected value
236.138 + * @param update the new value
236.139 + * @return true if successful. False return indicates that
236.140 + * the actual value was not equal to the expected value.
236.141 + */
236.142 + public final boolean compareAndSet(int i, E expect, E update) {
236.143 + if (array[i] == expect) {
236.144 + array[i] = update;
236.145 + return true;
236.146 + } else {
236.147 + return false;
236.148 + }
236.149 + }
236.150 +
236.151 + /**
236.152 + * Atomically sets the element at position {@code i} to the given
236.153 + * updated value if the current value {@code ==} the expected value.
236.154 + *
236.155 + * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
236.156 + * and does not provide ordering guarantees, so is only rarely an
236.157 + * appropriate alternative to {@code compareAndSet}.
236.158 + *
236.159 + * @param i the index
236.160 + * @param expect the expected value
236.161 + * @param update the new value
236.162 + * @return true if successful.
236.163 + */
236.164 + public final boolean weakCompareAndSet(int i, E expect, E update) {
236.165 + return compareAndSet(i, expect, update);
236.166 + }
236.167 +
236.168 + /**
236.169 + * Returns the String representation of the current values of array.
236.170 + * @return the String representation of the current values of array
236.171 + */
236.172 + public String toString() {
236.173 + int iMax = array.length - 1;
236.174 + if (iMax == -1)
236.175 + return "[]";
236.176 +
236.177 + StringBuilder b = new StringBuilder();
236.178 + b.append('[');
236.179 + for (int i = 0; ; i++) {
236.180 + b.append(get(i));
236.181 + if (i == iMax)
236.182 + return b.append(']').toString();
236.183 + b.append(',').append(' ');
236.184 + }
236.185 + }
236.186 +
236.187 +}
237.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
237.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/package-info.java Wed Apr 30 15:04:10 2014 +0200
237.3 @@ -0,0 +1,199 @@
237.4 +/*
237.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
237.6 + *
237.7 + * This code is free software; you can redistribute it and/or modify it
237.8 + * under the terms of the GNU General Public License version 2 only, as
237.9 + * published by the Free Software Foundation. Oracle designates this
237.10 + * particular file as subject to the "Classpath" exception as provided
237.11 + * by Oracle in the LICENSE file that accompanied this code.
237.12 + *
237.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
237.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
237.15 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
237.16 + * version 2 for more details (a copy is included in the LICENSE file that
237.17 + * accompanied this code).
237.18 + *
237.19 + * You should have received a copy of the GNU General Public License version
237.20 + * 2 along with this work; if not, write to the Free Software Foundation,
237.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
237.22 + *
237.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
237.24 + * or visit www.oracle.com if you need additional information or have any
237.25 + * questions.
237.26 + */
237.27 +
237.28 +/*
237.29 + * This file is available under and governed by the GNU General Public
237.30 + * License version 2 only, as published by the Free Software Foundation.
237.31 + * However, the following notice accompanied the original version of this
237.32 + * file:
237.33 + *
237.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
237.35 + * Expert Group and released to the public domain, as explained at
237.36 + * http://creativecommons.org/publicdomain/zero/1.0/
237.37 + */
237.38 +
237.39 +/**
237.40 + * A small toolkit of classes that support lock-free thread-safe
237.41 + * programming on single variables. In essence, the classes in this
237.42 + * package extend the notion of {@code volatile} values, fields, and
237.43 + * array elements to those that also provide an atomic conditional update
237.44 + * operation of the form:
237.45 + *
237.46 + * <pre>
237.47 + * boolean compareAndSet(expectedValue, updateValue);
237.48 + * </pre>
237.49 + *
237.50 + * <p>This method (which varies in argument types across different
237.51 + * classes) atomically sets a variable to the {@code updateValue} if it
237.52 + * currently holds the {@code expectedValue}, reporting {@code true} on
237.53 + * success. The classes in this package also contain methods to get and
237.54 + * unconditionally set values, as well as a weaker conditional atomic
237.55 + * update operation {@code weakCompareAndSet} described below.
237.56 + *
237.57 + * <p>The specifications of these methods enable implementations to
237.58 + * employ efficient machine-level atomic instructions that are available
237.59 + * on contemporary processors. However on some platforms, support may
237.60 + * entail some form of internal locking. Thus the methods are not
237.61 + * strictly guaranteed to be non-blocking --
237.62 + * a thread may block transiently before performing the operation.
237.63 + *
237.64 + * <p>Instances of classes
237.65 + * {@link java.util.concurrent.atomic.AtomicBoolean},
237.66 + * {@link java.util.concurrent.atomic.AtomicInteger},
237.67 + * {@link java.util.concurrent.atomic.AtomicLong}, and
237.68 + * {@link java.util.concurrent.atomic.AtomicReference}
237.69 + * each provide access and updates to a single variable of the
237.70 + * corresponding type. Each class also provides appropriate utility
237.71 + * methods for that type. For example, classes {@code AtomicLong} and
237.72 + * {@code AtomicInteger} provide atomic increment methods. One
237.73 + * application is to generate sequence numbers, as in:
237.74 + *
237.75 + * <pre>
237.76 + * class Sequencer {
237.77 + * private final AtomicLong sequenceNumber
237.78 + * = new AtomicLong(0);
237.79 + * public long next() {
237.80 + * return sequenceNumber.getAndIncrement();
237.81 + * }
237.82 + * }
237.83 + * </pre>
237.84 + *
237.85 + * <p>The memory effects for accesses and updates of atomics generally
237.86 + * follow the rules for volatiles, as stated in section 17.4 of
237.87 + * <cite>The Java™ Language Specification</cite>.
237.88 + *
237.89 + * <ul>
237.90 + *
237.91 + * <li> {@code get} has the memory effects of reading a
237.92 + * {@code volatile} variable.
237.93 + *
237.94 + * <li> {@code set} has the memory effects of writing (assigning) a
237.95 + * {@code volatile} variable.
237.96 + *
237.97 + * <li> {@code lazySet} has the memory effects of writing (assigning)
237.98 + * a {@code volatile} variable except that it permits reorderings with
237.99 + * subsequent (but not previous) memory actions that do not themselves
237.100 + * impose reordering constraints with ordinary non-{@code volatile}
237.101 + * writes. Among other usage contexts, {@code lazySet} may apply when
237.102 + * nulling out, for the sake of garbage collection, a reference that is
237.103 + * never accessed again.
237.104 + *
237.105 + * <li>{@code weakCompareAndSet} atomically reads and conditionally
237.106 + * writes a variable but does <em>not</em>
237.107 + * create any happens-before orderings, so provides no guarantees
237.108 + * with respect to previous or subsequent reads and writes of any
237.109 + * variables other than the target of the {@code weakCompareAndSet}.
237.110 + *
237.111 + * <li> {@code compareAndSet}
237.112 + * and all other read-and-update operations such as {@code getAndIncrement}
237.113 + * have the memory effects of both reading and
237.114 + * writing {@code volatile} variables.
237.115 + * </ul>
237.116 + *
237.117 + * <p>In addition to classes representing single values, this package
237.118 + * contains <em>Updater</em> classes that can be used to obtain
237.119 + * {@code compareAndSet} operations on any selected {@code volatile}
237.120 + * field of any selected class.
237.121 + *
237.122 + * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
237.123 + * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
237.124 + * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
237.125 + * reflection-based utilities that provide access to the associated
237.126 + * field types. These are mainly of use in atomic data structures in
237.127 + * which several {@code volatile} fields of the same node (for
237.128 + * example, the links of a tree node) are independently subject to
237.129 + * atomic updates. These classes enable greater flexibility in how
237.130 + * and when to use atomic updates, at the expense of more awkward
237.131 + * reflection-based setup, less convenient usage, and weaker
237.132 + * guarantees.
237.133 + *
237.134 + * <p>The
237.135 + * {@link java.util.concurrent.atomic.AtomicIntegerArray},
237.136 + * {@link java.util.concurrent.atomic.AtomicLongArray}, and
237.137 + * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
237.138 + * further extend atomic operation support to arrays of these types.
237.139 + * These classes are also notable in providing {@code volatile} access
237.140 + * semantics for their array elements, which is not supported for
237.141 + * ordinary arrays.
237.142 + *
237.143 + * <a name="Spurious">
237.144 + * <p>The atomic classes also support method {@code weakCompareAndSet},
237.145 + * which has limited applicability. On some platforms, the weak version
237.146 + * may be more efficient than {@code compareAndSet} in the normal case,
237.147 + * but differs in that any given invocation of the
237.148 + * {@code weakCompareAndSet} method may return {@code false}
237.149 + * <em>spuriously</em> (that is, for no apparent reason)</a>. A
237.150 + * {@code false} return means only that the operation may be retried if
237.151 + * desired, relying on the guarantee that repeated invocation when the
237.152 + * variable holds {@code expectedValue} and no other thread is also
237.153 + * attempting to set the variable will eventually succeed. (Such
237.154 + * spurious failures may for example be due to memory contention effects
237.155 + * that are unrelated to whether the expected and current values are
237.156 + * equal.) Additionally {@code weakCompareAndSet} does not provide
237.157 + * ordering guarantees that are usually needed for synchronization
237.158 + * control. However, the method may be useful for updating counters and
237.159 + * statistics when such updates are unrelated to the other
237.160 + * happens-before orderings of a program. When a thread sees an update
237.161 + * to an atomic variable caused by a {@code weakCompareAndSet}, it does
237.162 + * not necessarily see updates to any <em>other</em> variables that
237.163 + * occurred before the {@code weakCompareAndSet}. This may be
237.164 + * acceptable when, for example, updating performance statistics, but
237.165 + * rarely otherwise.
237.166 + *
237.167 + * <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
237.168 + * class associates a single boolean with a reference. For example, this
237.169 + * bit might be used inside a data structure to mean that the object
237.170 + * being referenced has logically been deleted.
237.171 + *
237.172 + * The {@link java.util.concurrent.atomic.AtomicStampedReference}
237.173 + * class associates an integer value with a reference. This may be
237.174 + * used for example, to represent version numbers corresponding to
237.175 + * series of updates.
237.176 + *
237.177 + * <p>Atomic classes are designed primarily as building blocks for
237.178 + * implementing non-blocking data structures and related infrastructure
237.179 + * classes. The {@code compareAndSet} method is not a general
237.180 + * replacement for locking. It applies only when critical updates for an
237.181 + * object are confined to a <em>single</em> variable.
237.182 + *
237.183 + * <p>Atomic classes are not general purpose replacements for
237.184 + * {@code java.lang.Integer} and related classes. They do <em>not</em>
237.185 + * define methods such as {@code hashCode} and
237.186 + * {@code compareTo}. (Because atomic variables are expected to be
237.187 + * mutated, they are poor choices for hash table keys.) Additionally,
237.188 + * classes are provided only for those types that are commonly useful in
237.189 + * intended applications. For example, there is no atomic class for
237.190 + * representing {@code byte}. In those infrequent cases where you would
237.191 + * like to do so, you can use an {@code AtomicInteger} to hold
237.192 + * {@code byte} values, and cast appropriately.
237.193 + *
237.194 + * You can also hold floats using
237.195 + * {@link java.lang.Float#floatToIntBits} and
237.196 + * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
237.197 + * {@link java.lang.Double#doubleToLongBits} and
237.198 + * {@link java.lang.Double#longBitsToDouble} conversions.
237.199 + *
237.200 + * @since 1.5
237.201 + */
237.202 +package java.util.concurrent.atomic;
238.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
238.2 +++ b/rt/emul/compact/src/main/java/java/util/logging/Level.java Wed Apr 30 15:04:10 2014 +0200
238.3 @@ -0,0 +1,372 @@
238.4 +/*
238.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
238.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
238.7 + *
238.8 + * This code is free software; you can redistribute it and/or modify it
238.9 + * under the terms of the GNU General Public License version 2 only, as
238.10 + * published by the Free Software Foundation. Oracle designates this
238.11 + * particular file as subject to the "Classpath" exception as provided
238.12 + * by Oracle in the LICENSE file that accompanied this code.
238.13 + *
238.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
238.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
238.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
238.17 + * version 2 for more details (a copy is included in the LICENSE file that
238.18 + * accompanied this code).
238.19 + *
238.20 + * You should have received a copy of the GNU General Public License version
238.21 + * 2 along with this work; if not, write to the Free Software Foundation,
238.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
238.23 + *
238.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
238.25 + * or visit www.oracle.com if you need additional information or have any
238.26 + * questions.
238.27 + */
238.28 +
238.29 +package java.util.logging;
238.30 +
238.31 +/**
238.32 + * The Level class defines a set of standard logging levels that
238.33 + * can be used to control logging output. The logging Level objects
238.34 + * are ordered and are specified by ordered integers. Enabling logging
238.35 + * at a given level also enables logging at all higher levels.
238.36 + * <p>
238.37 + * Clients should normally use the predefined Level constants such
238.38 + * as Level.SEVERE.
238.39 + * <p>
238.40 + * The levels in descending order are:
238.41 + * <ul>
238.42 + * <li>SEVERE (highest value)
238.43 + * <li>WARNING
238.44 + * <li>INFO
238.45 + * <li>CONFIG
238.46 + * <li>FINE
238.47 + * <li>FINER
238.48 + * <li>FINEST (lowest value)
238.49 + * </ul>
238.50 + * In addition there is a level OFF that can be used to turn
238.51 + * off logging, and a level ALL that can be used to enable
238.52 + * logging of all messages.
238.53 + * <p>
238.54 + * It is possible for third parties to define additional logging
238.55 + * levels by subclassing Level. In such cases subclasses should
238.56 + * take care to chose unique integer level values and to ensure that
238.57 + * they maintain the Object uniqueness property across serialization
238.58 + * by defining a suitable readResolve method.
238.59 + *
238.60 + * @since 1.4
238.61 + */
238.62 +
238.63 +public class Level implements java.io.Serializable {
238.64 + private static java.util.ArrayList<Level> known = new java.util.ArrayList<>();
238.65 + private static String defaultBundle = "sun.util.logging.resources.logging";
238.66 +
238.67 + /**
238.68 + * @serial The non-localized name of the level.
238.69 + */
238.70 + private final String name;
238.71 +
238.72 + /**
238.73 + * @serial The integer value of the level.
238.74 + */
238.75 + private final int value;
238.76 +
238.77 + /**
238.78 + * @serial The resource bundle name to be used in localizing the level name.
238.79 + */
238.80 + private final String resourceBundleName;
238.81 +
238.82 + /**
238.83 + * OFF is a special level that can be used to turn off logging.
238.84 + * This level is initialized to <CODE>Integer.MAX_VALUE</CODE>.
238.85 + */
238.86 + public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
238.87 +
238.88 + /**
238.89 + * SEVERE is a message level indicating a serious failure.
238.90 + * <p>
238.91 + * In general SEVERE messages should describe events that are
238.92 + * of considerable importance and which will prevent normal
238.93 + * program execution. They should be reasonably intelligible
238.94 + * to end users and to system administrators.
238.95 + * This level is initialized to <CODE>1000</CODE>.
238.96 + */
238.97 + public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
238.98 +
238.99 + /**
238.100 + * WARNING is a message level indicating a potential problem.
238.101 + * <p>
238.102 + * In general WARNING messages should describe events that will
238.103 + * be of interest to end users or system managers, or which
238.104 + * indicate potential problems.
238.105 + * This level is initialized to <CODE>900</CODE>.
238.106 + */
238.107 + public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
238.108 +
238.109 + /**
238.110 + * INFO is a message level for informational messages.
238.111 + * <p>
238.112 + * Typically INFO messages will be written to the console
238.113 + * or its equivalent. So the INFO level should only be
238.114 + * used for reasonably significant messages that will
238.115 + * make sense to end users and system administrators.
238.116 + * This level is initialized to <CODE>800</CODE>.
238.117 + */
238.118 + public static final Level INFO = new Level("INFO", 800, defaultBundle);
238.119 +
238.120 + /**
238.121 + * CONFIG is a message level for static configuration messages.
238.122 + * <p>
238.123 + * CONFIG messages are intended to provide a variety of static
238.124 + * configuration information, to assist in debugging problems
238.125 + * that may be associated with particular configurations.
238.126 + * For example, CONFIG message might include the CPU type,
238.127 + * the graphics depth, the GUI look-and-feel, etc.
238.128 + * This level is initialized to <CODE>700</CODE>.
238.129 + */
238.130 + public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
238.131 +
238.132 + /**
238.133 + * FINE is a message level providing tracing information.
238.134 + * <p>
238.135 + * All of FINE, FINER, and FINEST are intended for relatively
238.136 + * detailed tracing. The exact meaning of the three levels will
238.137 + * vary between subsystems, but in general, FINEST should be used
238.138 + * for the most voluminous detailed output, FINER for somewhat
238.139 + * less detailed output, and FINE for the lowest volume (and
238.140 + * most important) messages.
238.141 + * <p>
238.142 + * In general the FINE level should be used for information
238.143 + * that will be broadly interesting to developers who do not have
238.144 + * a specialized interest in the specific subsystem.
238.145 + * <p>
238.146 + * FINE messages might include things like minor (recoverable)
238.147 + * failures. Issues indicating potential performance problems
238.148 + * are also worth logging as FINE.
238.149 + * This level is initialized to <CODE>500</CODE>.
238.150 + */
238.151 + public static final Level FINE = new Level("FINE", 500, defaultBundle);
238.152 +
238.153 + /**
238.154 + * FINER indicates a fairly detailed tracing message.
238.155 + * By default logging calls for entering, returning, or throwing
238.156 + * an exception are traced at this level.
238.157 + * This level is initialized to <CODE>400</CODE>.
238.158 + */
238.159 + public static final Level FINER = new Level("FINER", 400, defaultBundle);
238.160 +
238.161 + /**
238.162 + * FINEST indicates a highly detailed tracing message.
238.163 + * This level is initialized to <CODE>300</CODE>.
238.164 + */
238.165 + public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
238.166 +
238.167 + /**
238.168 + * ALL indicates that all messages should be logged.
238.169 + * This level is initialized to <CODE>Integer.MIN_VALUE</CODE>.
238.170 + */
238.171 + public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
238.172 +
238.173 + /**
238.174 + * Create a named Level with a given integer value.
238.175 + * <p>
238.176 + * Note that this constructor is "protected" to allow subclassing.
238.177 + * In general clients of logging should use one of the constant Level
238.178 + * objects such as SEVERE or FINEST. However, if clients need to
238.179 + * add new logging levels, they may subclass Level and define new
238.180 + * constants.
238.181 + * @param name the name of the Level, for example "SEVERE".
238.182 + * @param value an integer value for the level.
238.183 + * @throws NullPointerException if the name is null
238.184 + */
238.185 + protected Level(String name, int value) {
238.186 + this(name, value, null);
238.187 + }
238.188 +
238.189 + /**
238.190 + * Create a named Level with a given integer value and a
238.191 + * given localization resource name.
238.192 + * <p>
238.193 + * @param name the name of the Level, for example "SEVERE".
238.194 + * @param value an integer value for the level.
238.195 + * @param resourceBundleName name of a resource bundle to use in
238.196 + * localizing the given name. If the resourceBundleName is null
238.197 + * or an empty string, it is ignored.
238.198 + * @throws NullPointerException if the name is null
238.199 + */
238.200 + protected Level(String name, int value, String resourceBundleName) {
238.201 + if (name == null) {
238.202 + throw new NullPointerException();
238.203 + }
238.204 + this.name = name;
238.205 + this.value = value;
238.206 + this.resourceBundleName = resourceBundleName;
238.207 + synchronized (Level.class) {
238.208 + known.add(this);
238.209 + }
238.210 + }
238.211 +
238.212 + /**
238.213 + * Return the level's localization resource bundle name, or
238.214 + * null if no localization bundle is defined.
238.215 + *
238.216 + * @return localization resource bundle name
238.217 + */
238.218 + public String getResourceBundleName() {
238.219 + return resourceBundleName;
238.220 + }
238.221 +
238.222 + /**
238.223 + * Return the non-localized string name of the Level.
238.224 + *
238.225 + * @return non-localized name
238.226 + */
238.227 + public String getName() {
238.228 + return name;
238.229 + }
238.230 +
238.231 + /**
238.232 + * Return the localized string name of the Level, for
238.233 + * the current default locale.
238.234 + * <p>
238.235 + * If no localization information is available, the
238.236 + * non-localized name is returned.
238.237 + *
238.238 + * @return localized name
238.239 + */
238.240 + public String getLocalizedName() {
238.241 + return getName();
238.242 + }
238.243 +
238.244 + /**
238.245 + * Returns a string representation of this Level.
238.246 + *
238.247 + * @return the non-localized name of the Level, for example "INFO".
238.248 + */
238.249 + public final String toString() {
238.250 + return name;
238.251 + }
238.252 +
238.253 + /**
238.254 + * Get the integer value for this level. This integer value
238.255 + * can be used for efficient ordering comparisons between
238.256 + * Level objects.
238.257 + * @return the integer value for this level.
238.258 + */
238.259 + public final int intValue() {
238.260 + return value;
238.261 + }
238.262 +
238.263 + private static final long serialVersionUID = -8176160795706313070L;
238.264 +
238.265 + // Serialization magic to prevent "doppelgangers".
238.266 + // This is a performance optimization.
238.267 + private Object readResolve() {
238.268 + synchronized (Level.class) {
238.269 + for (int i = 0; i < known.size(); i++) {
238.270 + Level other = known.get(i);
238.271 + if (this.name.equals(other.name) && this.value == other.value
238.272 + && (this.resourceBundleName == other.resourceBundleName ||
238.273 + (this.resourceBundleName != null &&
238.274 + this.resourceBundleName.equals(other.resourceBundleName)))) {
238.275 + return other;
238.276 + }
238.277 + }
238.278 + // Woops. Whoever sent us this object knows
238.279 + // about a new log level. Add it to our list.
238.280 + known.add(this);
238.281 + return this;
238.282 + }
238.283 + }
238.284 +
238.285 + /**
238.286 + * Parse a level name string into a Level.
238.287 + * <p>
238.288 + * The argument string may consist of either a level name
238.289 + * or an integer value.
238.290 + * <p>
238.291 + * For example:
238.292 + * <ul>
238.293 + * <li> "SEVERE"
238.294 + * <li> "1000"
238.295 + * </ul>
238.296 + * @param name string to be parsed
238.297 + * @throws NullPointerException if the name is null
238.298 + * @throws IllegalArgumentException if the value is not valid.
238.299 + * Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
238.300 + * and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
238.301 + * Known names are the levels defined by this class (e.g., <CODE>FINE</CODE>,
238.302 + * <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
238.303 + * appropriate package access, or new levels defined or created
238.304 + * by subclasses.
238.305 + *
238.306 + * @return The parsed value. Passing an integer that corresponds to a known name
238.307 + * (e.g., 700) will return the associated name (e.g., <CODE>CONFIG</CODE>).
238.308 + * Passing an integer that does not (e.g., 1) will return a new level name
238.309 + * initialized to that value.
238.310 + */
238.311 + public static synchronized Level parse(String name) throws IllegalArgumentException {
238.312 + // Check that name is not null.
238.313 + name.length();
238.314 +
238.315 + // Look for a known Level with the given non-localized name.
238.316 + for (int i = 0; i < known.size(); i++) {
238.317 + Level l = known.get(i);
238.318 + if (name.equals(l.name)) {
238.319 + return l;
238.320 + }
238.321 + }
238.322 +
238.323 + // Now, check if the given name is an integer. If so,
238.324 + // first look for a Level with the given value and then
238.325 + // if necessary create one.
238.326 + try {
238.327 + int x = Integer.parseInt(name);
238.328 + for (int i = 0; i < known.size(); i++) {
238.329 + Level l = known.get(i);
238.330 + if (l.value == x) {
238.331 + return l;
238.332 + }
238.333 + }
238.334 + // Create a new Level.
238.335 + return new Level(name, x);
238.336 + } catch (NumberFormatException ex) {
238.337 + // Not an integer.
238.338 + // Drop through.
238.339 + }
238.340 +
238.341 + // Finally, look for a known level with the given localized name,
238.342 + // in the current default locale.
238.343 + // This is relatively expensive, but not excessively so.
238.344 + for (int i = 0; i < known.size(); i++) {
238.345 + Level l = known.get(i);
238.346 + if (name.equals(l.getLocalizedName())) {
238.347 + return l;
238.348 + }
238.349 + }
238.350 +
238.351 + // OK, we've tried everything and failed
238.352 + throw new IllegalArgumentException("Bad level \"" + name + "\"");
238.353 + }
238.354 +
238.355 + /**
238.356 + * Compare two objects for value equality.
238.357 + * @return true if and only if the two objects have the same level value.
238.358 + */
238.359 + public boolean equals(Object ox) {
238.360 + try {
238.361 + Level lx = (Level)ox;
238.362 + return (lx.value == this.value);
238.363 + } catch (Exception ex) {
238.364 + return false;
238.365 + }
238.366 + }
238.367 +
238.368 + /**
238.369 + * Generate a hashcode.
238.370 + * @return a hashcode based on the level value
238.371 + */
238.372 + public int hashCode() {
238.373 + return this.value;
238.374 + }
238.375 +}
239.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
239.2 +++ b/rt/emul/compact/src/main/java/java/util/logging/LogRecord.java Wed Apr 30 15:04:10 2014 +0200
239.3 @@ -0,0 +1,468 @@
239.4 +/*
239.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
239.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
239.7 + *
239.8 + * This code is free software; you can redistribute it and/or modify it
239.9 + * under the terms of the GNU General Public License version 2 only, as
239.10 + * published by the Free Software Foundation. Oracle designates this
239.11 + * particular file as subject to the "Classpath" exception as provided
239.12 + * by Oracle in the LICENSE file that accompanied this code.
239.13 + *
239.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
239.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
239.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
239.17 + * version 2 for more details (a copy is included in the LICENSE file that
239.18 + * accompanied this code).
239.19 + *
239.20 + * You should have received a copy of the GNU General Public License version
239.21 + * 2 along with this work; if not, write to the Free Software Foundation,
239.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
239.23 + *
239.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
239.25 + * or visit www.oracle.com if you need additional information or have any
239.26 + * questions.
239.27 + */
239.28 +
239.29 +package java.util.logging;
239.30 +import java.io.*;
239.31 +
239.32 +/**
239.33 + * LogRecord objects are used to pass logging requests between
239.34 + * the logging framework and individual log Handlers.
239.35 + * <p>
239.36 + * When a LogRecord is passed into the logging framework it
239.37 + * logically belongs to the framework and should no longer be
239.38 + * used or updated by the client application.
239.39 + * <p>
239.40 + * Note that if the client application has not specified an
239.41 + * explicit source method name and source class name, then the
239.42 + * LogRecord class will infer them automatically when they are
239.43 + * first accessed (due to a call on getSourceMethodName or
239.44 + * getSourceClassName) by analyzing the call stack. Therefore,
239.45 + * if a logging Handler wants to pass off a LogRecord to another
239.46 + * thread, or to transmit it over RMI, and if it wishes to subsequently
239.47 + * obtain method name or class name information it should call
239.48 + * one of getSourceClassName or getSourceMethodName to force
239.49 + * the values to be filled in.
239.50 + * <p>
239.51 + * <b> Serialization notes:</b>
239.52 + * <ul>
239.53 + * <li>The LogRecord class is serializable.
239.54 + *
239.55 + * <li> Because objects in the parameters array may not be serializable,
239.56 + * during serialization all objects in the parameters array are
239.57 + * written as the corresponding Strings (using Object.toString).
239.58 + *
239.59 + * <li> The ResourceBundle is not transmitted as part of the serialized
239.60 + * form, but the resource bundle name is, and the recipient object's
239.61 + * readObject method will attempt to locate a suitable resource bundle.
239.62 + *
239.63 + * </ul>
239.64 + *
239.65 + * @since 1.4
239.66 + */
239.67 +
239.68 +public class LogRecord implements java.io.Serializable {
239.69 + private static long globalSequenceNumber = 0;
239.70 +
239.71 + /**
239.72 + * The default value of threadID will be the current thread's
239.73 + * thread id, for ease of correlation, unless it is greater than
239.74 + * MIN_SEQUENTIAL_THREAD_ID, in which case we try harder to keep
239.75 + * our promise to keep threadIDs unique by avoiding collisions due
239.76 + * to 32-bit wraparound. Unfortunately, LogRecord.getThreadID()
239.77 + * returns int, while Thread.getId() returns long.
239.78 + */
239.79 + private static final int MIN_SEQUENTIAL_THREAD_ID = Integer.MAX_VALUE / 2;
239.80 +
239.81 + /**
239.82 + * @serial Logging message level
239.83 + */
239.84 + private Level level;
239.85 +
239.86 + /**
239.87 + * @serial Sequence number
239.88 + */
239.89 + private long sequenceNumber;
239.90 +
239.91 + /**
239.92 + * @serial Class that issued logging call
239.93 + */
239.94 + private String sourceClassName;
239.95 +
239.96 + /**
239.97 + * @serial Method that issued logging call
239.98 + */
239.99 + private String sourceMethodName;
239.100 +
239.101 + /**
239.102 + * @serial Non-localized raw message text
239.103 + */
239.104 + private String message;
239.105 +
239.106 + /**
239.107 + * @serial Thread ID for thread that issued logging call.
239.108 + */
239.109 + private int threadID;
239.110 +
239.111 + /**
239.112 + * @serial Event time in milliseconds since 1970
239.113 + */
239.114 + private long millis;
239.115 +
239.116 + /**
239.117 + * @serial The Throwable (if any) associated with log message
239.118 + */
239.119 + private Throwable thrown;
239.120 +
239.121 + /**
239.122 + * @serial Name of the source Logger.
239.123 + */
239.124 + private String loggerName;
239.125 +
239.126 + /**
239.127 + * @serial Resource bundle name to localized log message.
239.128 + */
239.129 + private String resourceBundleName;
239.130 +
239.131 + private transient boolean needToInferCaller;
239.132 + private transient Object parameters[];
239.133 +
239.134 + /**
239.135 + * Returns the default value for a new LogRecord's threadID.
239.136 + */
239.137 + private int defaultThreadID() {
239.138 + return 0;
239.139 + }
239.140 +
239.141 + /**
239.142 + * Construct a LogRecord with the given level and message values.
239.143 + * <p>
239.144 + * The sequence property will be initialized with a new unique value.
239.145 + * These sequence values are allocated in increasing order within a VM.
239.146 + * <p>
239.147 + * The millis property will be initialized to the current time.
239.148 + * <p>
239.149 + * The thread ID property will be initialized with a unique ID for
239.150 + * the current thread.
239.151 + * <p>
239.152 + * All other properties will be initialized to "null".
239.153 + *
239.154 + * @param level a logging level value
239.155 + * @param msg the raw non-localized logging message (may be null)
239.156 + */
239.157 + public LogRecord(Level level, String msg) {
239.158 + // Make sure level isn't null, by calling random method.
239.159 + level.getClass();
239.160 + this.level = level;
239.161 + message = msg;
239.162 + // Assign a thread ID and a unique sequence number.
239.163 + sequenceNumber = globalSequenceNumber++;
239.164 + threadID = defaultThreadID();
239.165 + millis = System.currentTimeMillis();
239.166 + needToInferCaller = true;
239.167 + }
239.168 +
239.169 + /**
239.170 + * Get the source Logger's name.
239.171 + *
239.172 + * @return source logger name (may be null)
239.173 + */
239.174 + public String getLoggerName() {
239.175 + return loggerName;
239.176 + }
239.177 +
239.178 + /**
239.179 + * Set the source Logger's name.
239.180 + *
239.181 + * @param name the source logger name (may be null)
239.182 + */
239.183 + public void setLoggerName(String name) {
239.184 + loggerName = name;
239.185 + }
239.186 +
239.187 + /**
239.188 + * Get the localization resource bundle
239.189 + * <p>
239.190 + * This is the ResourceBundle that should be used to localize
239.191 + * the message string before formatting it. The result may
239.192 + * be null if the message is not localizable, or if no suitable
239.193 + * ResourceBundle is available.
239.194 + */
239.195 +// public ResourceBundle getResourceBundle() {
239.196 +// return resourceBundle;
239.197 +// }
239.198 +
239.199 + /**
239.200 + * Set the localization resource bundle.
239.201 + *
239.202 + * @param bundle localization bundle (may be null)
239.203 + */
239.204 +// public void setResourceBundle(ResourceBundle bundle) {
239.205 +// resourceBundle = bundle;
239.206 +// }
239.207 +
239.208 + /**
239.209 + * Get the localization resource bundle name
239.210 + * <p>
239.211 + * This is the name for the ResourceBundle that should be
239.212 + * used to localize the message string before formatting it.
239.213 + * The result may be null if the message is not localizable.
239.214 + */
239.215 + public String getResourceBundleName() {
239.216 + return resourceBundleName;
239.217 + }
239.218 +
239.219 + /**
239.220 + * Set the localization resource bundle name.
239.221 + *
239.222 + * @param name localization bundle name (may be null)
239.223 + */
239.224 + public void setResourceBundleName(String name) {
239.225 + resourceBundleName = name;
239.226 + }
239.227 +
239.228 + /**
239.229 + * Get the logging message level, for example Level.SEVERE.
239.230 + * @return the logging message level
239.231 + */
239.232 + public Level getLevel() {
239.233 + return level;
239.234 + }
239.235 +
239.236 + /**
239.237 + * Set the logging message level, for example Level.SEVERE.
239.238 + * @param level the logging message level
239.239 + */
239.240 + public void setLevel(Level level) {
239.241 + if (level == null) {
239.242 + throw new NullPointerException();
239.243 + }
239.244 + this.level = level;
239.245 + }
239.246 +
239.247 + /**
239.248 + * Get the sequence number.
239.249 + * <p>
239.250 + * Sequence numbers are normally assigned in the LogRecord
239.251 + * constructor, which assigns unique sequence numbers to
239.252 + * each new LogRecord in increasing order.
239.253 + * @return the sequence number
239.254 + */
239.255 + public long getSequenceNumber() {
239.256 + return sequenceNumber;
239.257 + }
239.258 +
239.259 + /**
239.260 + * Set the sequence number.
239.261 + * <p>
239.262 + * Sequence numbers are normally assigned in the LogRecord constructor,
239.263 + * so it should not normally be necessary to use this method.
239.264 + */
239.265 + public void setSequenceNumber(long seq) {
239.266 + sequenceNumber = seq;
239.267 + }
239.268 +
239.269 + /**
239.270 + * Get the name of the class that (allegedly) issued the logging request.
239.271 + * <p>
239.272 + * Note that this sourceClassName is not verified and may be spoofed.
239.273 + * This information may either have been provided as part of the
239.274 + * logging call, or it may have been inferred automatically by the
239.275 + * logging framework. In the latter case, the information may only
239.276 + * be approximate and may in fact describe an earlier call on the
239.277 + * stack frame.
239.278 + * <p>
239.279 + * May be null if no information could be obtained.
239.280 + *
239.281 + * @return the source class name
239.282 + */
239.283 + public String getSourceClassName() {
239.284 + return sourceClassName;
239.285 + }
239.286 +
239.287 + /**
239.288 + * Set the name of the class that (allegedly) issued the logging request.
239.289 + *
239.290 + * @param sourceClassName the source class name (may be null)
239.291 + */
239.292 + public void setSourceClassName(String sourceClassName) {
239.293 + this.sourceClassName = sourceClassName;
239.294 + needToInferCaller = false;
239.295 + }
239.296 +
239.297 + /**
239.298 + * Get the name of the method that (allegedly) issued the logging request.
239.299 + * <p>
239.300 + * Note that this sourceMethodName is not verified and may be spoofed.
239.301 + * This information may either have been provided as part of the
239.302 + * logging call, or it may have been inferred automatically by the
239.303 + * logging framework. In the latter case, the information may only
239.304 + * be approximate and may in fact describe an earlier call on the
239.305 + * stack frame.
239.306 + * <p>
239.307 + * May be null if no information could be obtained.
239.308 + *
239.309 + * @return the source method name
239.310 + */
239.311 + public String getSourceMethodName() {
239.312 + return sourceMethodName;
239.313 + }
239.314 +
239.315 + /**
239.316 + * Set the name of the method that (allegedly) issued the logging request.
239.317 + *
239.318 + * @param sourceMethodName the source method name (may be null)
239.319 + */
239.320 + public void setSourceMethodName(String sourceMethodName) {
239.321 + this.sourceMethodName = sourceMethodName;
239.322 + needToInferCaller = false;
239.323 + }
239.324 +
239.325 + /**
239.326 + * Get the "raw" log message, before localization or formatting.
239.327 + * <p>
239.328 + * May be null, which is equivalent to the empty string "".
239.329 + * <p>
239.330 + * This message may be either the final text or a localization key.
239.331 + * <p>
239.332 + * During formatting, if the source logger has a localization
239.333 + * ResourceBundle and if that ResourceBundle has an entry for
239.334 + * this message string, then the message string is replaced
239.335 + * with the localized value.
239.336 + *
239.337 + * @return the raw message string
239.338 + */
239.339 + public String getMessage() {
239.340 + return message;
239.341 + }
239.342 +
239.343 + /**
239.344 + * Set the "raw" log message, before localization or formatting.
239.345 + *
239.346 + * @param message the raw message string (may be null)
239.347 + */
239.348 + public void setMessage(String message) {
239.349 + this.message = message;
239.350 + }
239.351 +
239.352 + /**
239.353 + * Get the parameters to the log message.
239.354 + *
239.355 + * @return the log message parameters. May be null if
239.356 + * there are no parameters.
239.357 + */
239.358 + public Object[] getParameters() {
239.359 + return parameters;
239.360 + }
239.361 +
239.362 + /**
239.363 + * Set the parameters to the log message.
239.364 + *
239.365 + * @param parameters the log message parameters. (may be null)
239.366 + */
239.367 + public void setParameters(Object parameters[]) {
239.368 + this.parameters = parameters;
239.369 + }
239.370 +
239.371 + /**
239.372 + * Get an identifier for the thread where the message originated.
239.373 + * <p>
239.374 + * This is a thread identifier within the Java VM and may or
239.375 + * may not map to any operating system ID.
239.376 + *
239.377 + * @return thread ID
239.378 + */
239.379 + public int getThreadID() {
239.380 + return threadID;
239.381 + }
239.382 +
239.383 + /**
239.384 + * Set an identifier for the thread where the message originated.
239.385 + * @param threadID the thread ID
239.386 + */
239.387 + public void setThreadID(int threadID) {
239.388 + this.threadID = threadID;
239.389 + }
239.390 +
239.391 + /**
239.392 + * Get event time in milliseconds since 1970.
239.393 + *
239.394 + * @return event time in millis since 1970
239.395 + */
239.396 + public long getMillis() {
239.397 + return millis;
239.398 + }
239.399 +
239.400 + /**
239.401 + * Set event time.
239.402 + *
239.403 + * @param millis event time in millis since 1970
239.404 + */
239.405 + public void setMillis(long millis) {
239.406 + this.millis = millis;
239.407 + }
239.408 +
239.409 + /**
239.410 + * Get any throwable associated with the log record.
239.411 + * <p>
239.412 + * If the event involved an exception, this will be the
239.413 + * exception object. Otherwise null.
239.414 + *
239.415 + * @return a throwable
239.416 + */
239.417 + public Throwable getThrown() {
239.418 + return thrown;
239.419 + }
239.420 +
239.421 + /**
239.422 + * Set a throwable associated with the log event.
239.423 + *
239.424 + * @param thrown a throwable (may be null)
239.425 + */
239.426 + public void setThrown(Throwable thrown) {
239.427 + this.thrown = thrown;
239.428 + }
239.429 +
239.430 + private static final long serialVersionUID = 5372048053134512534L;
239.431 +
239.432 + /**
239.433 + * @serialData Default fields, followed by a two byte version number
239.434 + * (major byte, followed by minor byte), followed by information on
239.435 + * the log record parameter array. If there is no parameter array,
239.436 + * then -1 is written. If there is a parameter array (possible of zero
239.437 + * length) then the array length is written as an integer, followed
239.438 + * by String values for each parameter. If a parameter is null, then
239.439 + * a null String is written. Otherwise the output of Object.toString()
239.440 + * is written.
239.441 + */
239.442 + private void writeObject(ObjectOutputStream out) throws IOException {
239.443 + // We have to call defaultWriteObject first.
239.444 + out.defaultWriteObject();
239.445 +
239.446 + // Write our version number.
239.447 + out.writeByte(1);
239.448 + out.writeByte(0);
239.449 + if (parameters == null) {
239.450 + out.writeInt(-1);
239.451 + return;
239.452 + }
239.453 + out.writeInt(parameters.length);
239.454 + // Write string values for the parameters.
239.455 + for (int i = 0; i < parameters.length; i++) {
239.456 + if (parameters[i] == null) {
239.457 + out.writeObject(null);
239.458 + } else {
239.459 + out.writeObject(parameters[i].toString());
239.460 + }
239.461 + }
239.462 + }
239.463 +
239.464 +
239.465 + private boolean isLoggerImplFrame(String cname) {
239.466 + // the log record could be created for a platform logger
239.467 + return (cname.equals("java.util.logging.Logger") ||
239.468 + cname.startsWith("java.util.logging.LoggingProxyImpl") ||
239.469 + cname.startsWith("sun.util.logging."));
239.470 + }
239.471 +}
240.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
240.2 +++ b/rt/emul/compact/src/main/java/java/util/logging/Logger.java Wed Apr 30 15:04:10 2014 +0200
240.3 @@ -0,0 +1,1264 @@
240.4 +/*
240.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
240.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
240.7 + *
240.8 + * This code is free software; you can redistribute it and/or modify it
240.9 + * under the terms of the GNU General Public License version 2 only, as
240.10 + * published by the Free Software Foundation. Oracle designates this
240.11 + * particular file as subject to the "Classpath" exception as provided
240.12 + * by Oracle in the LICENSE file that accompanied this code.
240.13 + *
240.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
240.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
240.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
240.17 + * version 2 for more details (a copy is included in the LICENSE file that
240.18 + * accompanied this code).
240.19 + *
240.20 + * You should have received a copy of the GNU General Public License version
240.21 + * 2 along with this work; if not, write to the Free Software Foundation,
240.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
240.23 + *
240.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
240.25 + * or visit www.oracle.com if you need additional information or have any
240.26 + * questions.
240.27 + */
240.28 +
240.29 +
240.30 +package java.util.logging;
240.31 +
240.32 +import java.util.HashMap;
240.33 +import java.util.Map;
240.34 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
240.35 +
240.36 +/**
240.37 + * A Logger object is used to log messages for a specific
240.38 + * system or application component. Loggers are normally named,
240.39 + * using a hierarchical dot-separated namespace. Logger names
240.40 + * can be arbitrary strings, but they should normally be based on
240.41 + * the package name or class name of the logged component, such
240.42 + * as java.net or javax.swing. In addition it is possible to create
240.43 + * "anonymous" Loggers that are not stored in the Logger namespace.
240.44 + * <p>
240.45 + * Logger objects may be obtained by calls on one of the getLogger
240.46 + * factory methods. These will either create a new Logger or
240.47 + * return a suitable existing Logger. It is important to note that
240.48 + * the Logger returned by one of the {@code getLogger} factory methods
240.49 + * may be garbage collected at any time if a strong reference to the
240.50 + * Logger is not kept.
240.51 + * <p>
240.52 + * Logging messages will be forwarded to registered Handler
240.53 + * objects, which can forward the messages to a variety of
240.54 + * destinations, including consoles, files, OS logs, etc.
240.55 + * <p>
240.56 + * Each Logger keeps track of a "parent" Logger, which is its
240.57 + * nearest existing ancestor in the Logger namespace.
240.58 + * <p>
240.59 + * Each Logger has a "Level" associated with it. This reflects
240.60 + * a minimum Level that this logger cares about. If a Logger's
240.61 + * level is set to <tt>null</tt>, then its effective level is inherited
240.62 + * from its parent, which may in turn obtain it recursively from its
240.63 + * parent, and so on up the tree.
240.64 + * <p>
240.65 + * The log level can be configured based on the properties from the
240.66 + * logging configuration file, as described in the description
240.67 + * of the LogManager class. However it may also be dynamically changed
240.68 + * by calls on the Logger.setLevel method. If a logger's level is
240.69 + * changed the change may also affect child loggers, since any child
240.70 + * logger that has <tt>null</tt> as its level will inherit its
240.71 + * effective level from its parent.
240.72 + * <p>
240.73 + * On each logging call the Logger initially performs a cheap
240.74 + * check of the request level (e.g., SEVERE or FINE) against the
240.75 + * effective log level of the logger. If the request level is
240.76 + * lower than the log level, the logging call returns immediately.
240.77 + * <p>
240.78 + * After passing this initial (cheap) test, the Logger will allocate
240.79 + * a LogRecord to describe the logging message. It will then call a
240.80 + * Filter (if present) to do a more detailed check on whether the
240.81 + * record should be published. If that passes it will then publish
240.82 + * the LogRecord to its output Handlers. By default, loggers also
240.83 + * publish to their parent's Handlers, recursively up the tree.
240.84 + * <p>
240.85 + * Each Logger may have a ResourceBundle name associated with it.
240.86 + * The named bundle will be used for localizing logging messages.
240.87 + * If a Logger does not have its own ResourceBundle name, then
240.88 + * it will inherit the ResourceBundle name from its parent,
240.89 + * recursively up the tree.
240.90 + * <p>
240.91 + * Most of the logger output methods take a "msg" argument. This
240.92 + * msg argument may be either a raw value or a localization key.
240.93 + * During formatting, if the logger has (or inherits) a localization
240.94 + * ResourceBundle and if the ResourceBundle has a mapping for the msg
240.95 + * string, then the msg string is replaced by the localized value.
240.96 + * Otherwise the original msg string is used. Typically, formatters use
240.97 + * java.text.MessageFormat style formatting to format parameters, so
240.98 + * for example a format string "{0} {1}" would format two parameters
240.99 + * as strings.
240.100 + * <p>
240.101 + * When mapping ResourceBundle names to ResourceBundles, the Logger
240.102 + * will first try to use the Thread's ContextClassLoader. If that
240.103 + * is null it will try the SystemClassLoader instead. As a temporary
240.104 + * transition feature in the initial implementation, if the Logger is
240.105 + * unable to locate a ResourceBundle from the ContextClassLoader or
240.106 + * SystemClassLoader the Logger will also search up the class stack
240.107 + * and use successive calling ClassLoaders to try to locate a ResourceBundle.
240.108 + * (This call stack search is to allow containers to transition to
240.109 + * using ContextClassLoaders and is likely to be removed in future
240.110 + * versions.)
240.111 + * <p>
240.112 + * Formatting (including localization) is the responsibility of
240.113 + * the output Handler, which will typically call a Formatter.
240.114 + * <p>
240.115 + * Note that formatting need not occur synchronously. It may be delayed
240.116 + * until a LogRecord is actually written to an external sink.
240.117 + * <p>
240.118 + * The logging methods are grouped in five main categories:
240.119 + * <ul>
240.120 + * <li><p>
240.121 + * There are a set of "log" methods that take a log level, a message
240.122 + * string, and optionally some parameters to the message string.
240.123 + * <li><p>
240.124 + * There are a set of "logp" methods (for "log precise") that are
240.125 + * like the "log" methods, but also take an explicit source class name
240.126 + * and method name.
240.127 + * <li><p>
240.128 + * There are a set of "logrb" method (for "log with resource bundle")
240.129 + * that are like the "logp" method, but also take an explicit resource
240.130 + * bundle name for use in localizing the log message.
240.131 + * <li><p>
240.132 + * There are convenience methods for tracing method entries (the
240.133 + * "entering" methods), method returns (the "exiting" methods) and
240.134 + * throwing exceptions (the "throwing" methods).
240.135 + * <li><p>
240.136 + * Finally, there are a set of convenience methods for use in the
240.137 + * very simplest cases, when a developer simply wants to log a
240.138 + * simple string at a given log level. These methods are named
240.139 + * after the standard Level names ("severe", "warning", "info", etc.)
240.140 + * and take a single argument, a message string.
240.141 + * </ul>
240.142 + * <p>
240.143 + * For the methods that do not take an explicit source name and
240.144 + * method name, the Logging framework will make a "best effort"
240.145 + * to determine which class and method called into the logging method.
240.146 + * However, it is important to realize that this automatically inferred
240.147 + * information may only be approximate (or may even be quite wrong!).
240.148 + * Virtual machines are allowed to do extensive optimizations when
240.149 + * JITing and may entirely remove stack frames, making it impossible
240.150 + * to reliably locate the calling class and method.
240.151 + * <P>
240.152 + * All methods on Logger are multi-thread safe.
240.153 + * <p>
240.154 + * <b>Subclassing Information:</b> Note that a LogManager class may
240.155 + * provide its own implementation of named Loggers for any point in
240.156 + * the namespace. Therefore, any subclasses of Logger (unless they
240.157 + * are implemented in conjunction with a new LogManager class) should
240.158 + * take care to obtain a Logger instance from the LogManager class and
240.159 + * should delegate operations such as "isLoggable" and "log(LogRecord)"
240.160 + * to that instance. Note that in order to intercept all logging
240.161 + * output, subclasses need only override the log(LogRecord) method.
240.162 + * All the other logging methods are implemented as calls on this
240.163 + * log(LogRecord) method.
240.164 + *
240.165 + * @since 1.4
240.166 + */
240.167 +
240.168 +
240.169 +public class Logger {
240.170 + private static int offValue = Level.OFF.intValue();
240.171 + private static final Map<String,Logger> ALL = new HashMap<>();
240.172 + private String name;
240.173 +
240.174 + private volatile int levelValue; // current effective level value
240.175 + private Level levelObject;
240.176 +
240.177 + /**
240.178 + * GLOBAL_LOGGER_NAME is a name for the global logger.
240.179 + *
240.180 + * @since 1.6
240.181 + */
240.182 + public static final String GLOBAL_LOGGER_NAME = "global";
240.183 +
240.184 + /**
240.185 + * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME.
240.186 + *
240.187 + * @return global logger object
240.188 + * @since 1.7
240.189 + */
240.190 + public static final Logger getGlobal() {
240.191 + return global;
240.192 + }
240.193 +
240.194 + /**
240.195 + * The "global" Logger object is provided as a convenience to developers
240.196 + * who are making casual use of the Logging package. Developers
240.197 + * who are making serious use of the logging package (for example
240.198 + * in products) should create and use their own Logger objects,
240.199 + * with appropriate names, so that logging can be controlled on a
240.200 + * suitable per-Logger granularity. Developers also need to keep a
240.201 + * strong reference to their Logger objects to prevent them from
240.202 + * being garbage collected.
240.203 + * <p>
240.204 + * @deprecated Initialization of this field is prone to deadlocks.
240.205 + * The field must be initialized by the Logger class initialization
240.206 + * which may cause deadlocks with the LogManager class initialization.
240.207 + * In such cases two class initialization wait for each other to complete.
240.208 + * The preferred way to get the global logger object is via the call
240.209 + * <code>Logger.getGlobal()</code>.
240.210 + * For compatibility with old JDK versions where the
240.211 + * <code>Logger.getGlobal()</code> is not available use the call
240.212 + * <code>Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)</code>
240.213 + * or <code>Logger.getLogger("global")</code>.
240.214 + */
240.215 + @Deprecated
240.216 + public static final Logger global = new Logger(GLOBAL_LOGGER_NAME);
240.217 +
240.218 + /**
240.219 + * Protected method to construct a logger for a named subsystem.
240.220 + * <p>
240.221 + * The logger will be initially configured with a null Level
240.222 + * and with useParentHandlers set to true.
240.223 + *
240.224 + * @param name A name for the logger. This should
240.225 + * be a dot-separated name and should normally
240.226 + * be based on the package name or class name
240.227 + * of the subsystem, such as java.net
240.228 + * or javax.swing. It may be null for anonymous Loggers.
240.229 + * @param resourceBundleName name of ResourceBundle to be used for localizing
240.230 + * messages for this logger. May be null if none
240.231 + * of the messages require localization.
240.232 + * @throws MissingResourceException if the resourceBundleName is non-null and
240.233 + * no corresponding resource can be found.
240.234 + */
240.235 + protected Logger(String name, String resourceBundleName) {
240.236 + this.name = name;
240.237 + levelValue = Level.INFO.intValue();
240.238 + }
240.239 +
240.240 + // This constructor is used only to create the global Logger.
240.241 + // It is needed to break a cyclic dependence between the LogManager
240.242 + // and Logger static initializers causing deadlocks.
240.243 + private Logger(String name) {
240.244 + // The manager field is not initialized here.
240.245 + this.name = name;
240.246 + levelValue = Level.INFO.intValue();
240.247 + }
240.248 +
240.249 + private void checkAccess() throws SecurityException {
240.250 + throw new SecurityException();
240.251 + }
240.252 +
240.253 + /**
240.254 + * Find or create a logger for a named subsystem. If a logger has
240.255 + * already been created with the given name it is returned. Otherwise
240.256 + * a new logger is created.
240.257 + * <p>
240.258 + * If a new logger is created its log level will be configured
240.259 + * based on the LogManager configuration and it will configured
240.260 + * to also send logging output to its parent's Handlers. It will
240.261 + * be registered in the LogManager global namespace.
240.262 + * <p>
240.263 + * Note: The LogManager may only retain a weak reference to the newly
240.264 + * created Logger. It is important to understand that a previously
240.265 + * created Logger with the given name may be garbage collected at any
240.266 + * time if there is no strong reference to the Logger. In particular,
240.267 + * this means that two back-to-back calls like
240.268 + * {@code getLogger("MyLogger").log(...)} may use different Logger
240.269 + * objects named "MyLogger" if there is no strong reference to the
240.270 + * Logger named "MyLogger" elsewhere in the program.
240.271 + *
240.272 + * @param name A name for the logger. This should
240.273 + * be a dot-separated name and should normally
240.274 + * be based on the package name or class name
240.275 + * of the subsystem, such as java.net
240.276 + * or javax.swing
240.277 + * @return a suitable Logger
240.278 + * @throws NullPointerException if the name is null.
240.279 + */
240.280 +
240.281 + // Synchronization is not required here. All synchronization for
240.282 + // adding a new Logger object is handled by LogManager.addLogger().
240.283 + public static Logger getLogger(String name) {
240.284 + return getLogger(name, null);
240.285 + }
240.286 +
240.287 + /**
240.288 + * Find or create a logger for a named subsystem. If a logger has
240.289 + * already been created with the given name it is returned. Otherwise
240.290 + * a new logger is created.
240.291 + * <p>
240.292 + * If a new logger is created its log level will be configured
240.293 + * based on the LogManager and it will configured to also send logging
240.294 + * output to its parent's Handlers. It will be registered in
240.295 + * the LogManager global namespace.
240.296 + * <p>
240.297 + * Note: The LogManager may only retain a weak reference to the newly
240.298 + * created Logger. It is important to understand that a previously
240.299 + * created Logger with the given name may be garbage collected at any
240.300 + * time if there is no strong reference to the Logger. In particular,
240.301 + * this means that two back-to-back calls like
240.302 + * {@code getLogger("MyLogger", ...).log(...)} may use different Logger
240.303 + * objects named "MyLogger" if there is no strong reference to the
240.304 + * Logger named "MyLogger" elsewhere in the program.
240.305 + * <p>
240.306 + * If the named Logger already exists and does not yet have a
240.307 + * localization resource bundle then the given resource bundle
240.308 + * name is used. If the named Logger already exists and has
240.309 + * a different resource bundle name then an IllegalArgumentException
240.310 + * is thrown.
240.311 + * <p>
240.312 + * @param name A name for the logger. This should
240.313 + * be a dot-separated name and should normally
240.314 + * be based on the package name or class name
240.315 + * of the subsystem, such as java.net
240.316 + * or javax.swing
240.317 + * @param resourceBundleName name of ResourceBundle to be used for localizing
240.318 + * messages for this logger. May be <CODE>null</CODE> if none of
240.319 + * the messages require localization.
240.320 + * @return a suitable Logger
240.321 + * @throws MissingResourceException if the resourceBundleName is non-null and
240.322 + * no corresponding resource can be found.
240.323 + * @throws IllegalArgumentException if the Logger already exists and uses
240.324 + * a different resource bundle name.
240.325 + * @throws NullPointerException if the name is null.
240.326 + */
240.327 +
240.328 + // Synchronization is not required here. All synchronization for
240.329 + // adding a new Logger object is handled by LogManager.addLogger().
240.330 + public static Logger getLogger(String name, String resourceBundleName) {
240.331 + Logger l = ALL.get(name);
240.332 + if (l == null) {
240.333 + l = new Logger(name, resourceBundleName);
240.334 + ALL.put(name, l);
240.335 + }
240.336 + return l;
240.337 + }
240.338 +
240.339 +
240.340 + /**
240.341 + * Create an anonymous Logger. The newly created Logger is not
240.342 + * registered in the LogManager namespace. There will be no
240.343 + * access checks on updates to the logger.
240.344 + * <p>
240.345 + * This factory method is primarily intended for use from applets.
240.346 + * Because the resulting Logger is anonymous it can be kept private
240.347 + * by the creating class. This removes the need for normal security
240.348 + * checks, which in turn allows untrusted applet code to update
240.349 + * the control state of the Logger. For example an applet can do
240.350 + * a setLevel or an addHandler on an anonymous Logger.
240.351 + * <p>
240.352 + * Even although the new logger is anonymous, it is configured
240.353 + * to have the root logger ("") as its parent. This means that
240.354 + * by default it inherits its effective level and handlers
240.355 + * from the root logger.
240.356 + * <p>
240.357 + *
240.358 + * @return a newly created private Logger
240.359 + */
240.360 + public static Logger getAnonymousLogger() {
240.361 + return getAnonymousLogger(null);
240.362 + }
240.363 +
240.364 + /**
240.365 + * Create an anonymous Logger. The newly created Logger is not
240.366 + * registered in the LogManager namespace. There will be no
240.367 + * access checks on updates to the logger.
240.368 + * <p>
240.369 + * This factory method is primarily intended for use from applets.
240.370 + * Because the resulting Logger is anonymous it can be kept private
240.371 + * by the creating class. This removes the need for normal security
240.372 + * checks, which in turn allows untrusted applet code to update
240.373 + * the control state of the Logger. For example an applet can do
240.374 + * a setLevel or an addHandler on an anonymous Logger.
240.375 + * <p>
240.376 + * Even although the new logger is anonymous, it is configured
240.377 + * to have the root logger ("") as its parent. This means that
240.378 + * by default it inherits its effective level and handlers
240.379 + * from the root logger.
240.380 + * <p>
240.381 + * @param resourceBundleName name of ResourceBundle to be used for localizing
240.382 + * messages for this logger.
240.383 + * May be null if none of the messages require localization.
240.384 + * @return a newly created private Logger
240.385 + * @throws MissingResourceException if the resourceBundleName is non-null and
240.386 + * no corresponding resource can be found.
240.387 + */
240.388 +
240.389 + // Synchronization is not required here. All synchronization for
240.390 + // adding a new anonymous Logger object is handled by doSetParent().
240.391 + public static Logger getAnonymousLogger(String resourceBundleName) {
240.392 + return new Logger(null, resourceBundleName);
240.393 + }
240.394 +
240.395 + /**
240.396 + * Retrieve the localization resource bundle for this
240.397 + * logger for the current default locale. Note that if
240.398 + * the result is null, then the Logger will use a resource
240.399 + * bundle inherited from its parent.
240.400 + *
240.401 + * @return localization bundle (may be null)
240.402 + */
240.403 +// public ResourceBundle getResourceBundle() {
240.404 +// return findResourceBundle(getResourceBundleName());
240.405 +// }
240.406 +
240.407 + /**
240.408 + * Retrieve the localization resource bundle name for this
240.409 + * logger. Note that if the result is null, then the Logger
240.410 + * will use a resource bundle name inherited from its parent.
240.411 + *
240.412 + * @return localization bundle name (may be null)
240.413 + */
240.414 + public String getResourceBundleName() {
240.415 + return null;
240.416 + }
240.417 +
240.418 + /**
240.419 + * Set a filter to control output on this Logger.
240.420 + * <P>
240.421 + * After passing the initial "level" check, the Logger will
240.422 + * call this Filter to check if a log record should really
240.423 + * be published.
240.424 + *
240.425 + * @param newFilter a filter object (may be null)
240.426 + * @exception SecurityException if a security manager exists and if
240.427 + * the caller does not have LoggingPermission("control").
240.428 + */
240.429 +// public void setFilter(Filter newFilter) throws SecurityException {
240.430 +// checkAccess();
240.431 +// }
240.432 +
240.433 + /**
240.434 + * Get the current filter for this Logger.
240.435 + *
240.436 + * @return a filter object (may be null)
240.437 + */
240.438 +// public Filter getFilter() {
240.439 +// return filter;
240.440 +// }
240.441 +
240.442 + /**
240.443 + * Log a LogRecord.
240.444 + * <p>
240.445 + * All the other logging methods in this class call through
240.446 + * this method to actually perform any logging. Subclasses can
240.447 + * override this single method to capture all log activity.
240.448 + *
240.449 + * @param record the LogRecord to be published
240.450 + */
240.451 + public void log(LogRecord record) {
240.452 + if (record.getLevel().intValue() < levelValue) {
240.453 + return;
240.454 + }
240.455 +
240.456 + String method;
240.457 + switch (record.getLevel().toString()) {
240.458 + case "INFO": method = "info"; break;
240.459 + case "SEVERE": method = "error"; break;
240.460 + case "WARNING": method = "warn"; break;
240.461 + default: method = "log"; break;
240.462 + }
240.463 +
240.464 + String msg = record.getMessage();
240.465 + final Object[] params = record.getParameters();
240.466 + if (params != null && params.length != 0) {
240.467 + for (int i = 0; i < params.length; i++) {
240.468 + msg = msg.replace("{" + i + "}", params[i] == null ? "null" : params[i].toString());
240.469 + }
240.470 + }
240.471 +
240.472 + consoleLog(
240.473 + method,
240.474 + record.getLoggerName(), msg);
240.475 + }
240.476 +
240.477 + @JavaScriptBody(args = { "method", "logger", "msg" }, body =
240.478 + "if (typeof console !== 'undefined') console[method]('[' + logger + ']: ' + msg);"
240.479 + )
240.480 + private static native void consoleLog(
240.481 + String method, String logger, String msg
240.482 + );
240.483 +
240.484 + // private support method for logging.
240.485 + // We fill in the logger name, resource bundle name, and
240.486 + // resource bundle and then call "void log(LogRecord)".
240.487 + private void doLog(LogRecord lr) {
240.488 + doLog(lr, lr.getResourceBundleName());
240.489 + }
240.490 + private void doLog(LogRecord lr, String bundleName) {
240.491 + lr.setLoggerName(name);
240.492 + log(lr);
240.493 + }
240.494 +
240.495 +
240.496 + //================================================================
240.497 + // Start of convenience methods WITHOUT className and methodName
240.498 + //================================================================
240.499 +
240.500 + /**
240.501 + * Log a message, with no arguments.
240.502 + * <p>
240.503 + * If the logger is currently enabled for the given message
240.504 + * level then the given message is forwarded to all the
240.505 + * registered output Handler objects.
240.506 + * <p>
240.507 + * @param level One of the message level identifiers, e.g., SEVERE
240.508 + * @param msg The string message (or a key in the message catalog)
240.509 + */
240.510 + public void log(Level level, String msg) {
240.511 + if (level.intValue() < levelValue || levelValue == offValue) {
240.512 + return;
240.513 + }
240.514 + LogRecord lr = new LogRecord(level, msg);
240.515 + doLog(lr);
240.516 + }
240.517 +
240.518 + /**
240.519 + * Log a message, with one object parameter.
240.520 + * <p>
240.521 + * If the logger is currently enabled for the given message
240.522 + * level then a corresponding LogRecord is created and forwarded
240.523 + * to all the registered output Handler objects.
240.524 + * <p>
240.525 + * @param level One of the message level identifiers, e.g., SEVERE
240.526 + * @param msg The string message (or a key in the message catalog)
240.527 + * @param param1 parameter to the message
240.528 + */
240.529 + public void log(Level level, String msg, Object param1) {
240.530 + if (level.intValue() < levelValue || levelValue == offValue) {
240.531 + return;
240.532 + }
240.533 + LogRecord lr = new LogRecord(level, msg);
240.534 + Object params[] = { param1 };
240.535 + lr.setParameters(params);
240.536 + doLog(lr);
240.537 + }
240.538 +
240.539 + /**
240.540 + * Log a message, with an array of object arguments.
240.541 + * <p>
240.542 + * If the logger is currently enabled for the given message
240.543 + * level then a corresponding LogRecord is created and forwarded
240.544 + * to all the registered output Handler objects.
240.545 + * <p>
240.546 + * @param level One of the message level identifiers, e.g., SEVERE
240.547 + * @param msg The string message (or a key in the message catalog)
240.548 + * @param params array of parameters to the message
240.549 + */
240.550 + public void log(Level level, String msg, Object params[]) {
240.551 + if (level.intValue() < levelValue || levelValue == offValue) {
240.552 + return;
240.553 + }
240.554 + LogRecord lr = new LogRecord(level, msg);
240.555 + lr.setParameters(params);
240.556 + doLog(lr);
240.557 + }
240.558 +
240.559 + /**
240.560 + * Log a message, with associated Throwable information.
240.561 + * <p>
240.562 + * If the logger is currently enabled for the given message
240.563 + * level then the given arguments are stored in a LogRecord
240.564 + * which is forwarded to all registered output handlers.
240.565 + * <p>
240.566 + * Note that the thrown argument is stored in the LogRecord thrown
240.567 + * property, rather than the LogRecord parameters property. Thus is it
240.568 + * processed specially by output Formatters and is not treated
240.569 + * as a formatting parameter to the LogRecord message property.
240.570 + * <p>
240.571 + * @param level One of the message level identifiers, e.g., SEVERE
240.572 + * @param msg The string message (or a key in the message catalog)
240.573 + * @param thrown Throwable associated with log message.
240.574 + */
240.575 + public void log(Level level, String msg, Throwable thrown) {
240.576 + if (level.intValue() < levelValue || levelValue == offValue) {
240.577 + return;
240.578 + }
240.579 + LogRecord lr = new LogRecord(level, msg);
240.580 + lr.setThrown(thrown);
240.581 + doLog(lr);
240.582 + }
240.583 +
240.584 + //================================================================
240.585 + // Start of convenience methods WITH className and methodName
240.586 + //================================================================
240.587 +
240.588 + /**
240.589 + * Log a message, specifying source class and method,
240.590 + * with no arguments.
240.591 + * <p>
240.592 + * If the logger is currently enabled for the given message
240.593 + * level then the given message is forwarded to all the
240.594 + * registered output Handler objects.
240.595 + * <p>
240.596 + * @param level One of the message level identifiers, e.g., SEVERE
240.597 + * @param sourceClass name of class that issued the logging request
240.598 + * @param sourceMethod name of method that issued the logging request
240.599 + * @param msg The string message (or a key in the message catalog)
240.600 + */
240.601 + public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
240.602 + if (level.intValue() < levelValue || levelValue == offValue) {
240.603 + return;
240.604 + }
240.605 + LogRecord lr = new LogRecord(level, msg);
240.606 + lr.setSourceClassName(sourceClass);
240.607 + lr.setSourceMethodName(sourceMethod);
240.608 + doLog(lr);
240.609 + }
240.610 +
240.611 + /**
240.612 + * Log a message, specifying source class and method,
240.613 + * with a single object parameter to the log message.
240.614 + * <p>
240.615 + * If the logger is currently enabled for the given message
240.616 + * level then a corresponding LogRecord is created and forwarded
240.617 + * to all the registered output Handler objects.
240.618 + * <p>
240.619 + * @param level One of the message level identifiers, e.g., SEVERE
240.620 + * @param sourceClass name of class that issued the logging request
240.621 + * @param sourceMethod name of method that issued the logging request
240.622 + * @param msg The string message (or a key in the message catalog)
240.623 + * @param param1 Parameter to the log message.
240.624 + */
240.625 + public void logp(Level level, String sourceClass, String sourceMethod,
240.626 + String msg, Object param1) {
240.627 + if (level.intValue() < levelValue || levelValue == offValue) {
240.628 + return;
240.629 + }
240.630 + LogRecord lr = new LogRecord(level, msg);
240.631 + lr.setSourceClassName(sourceClass);
240.632 + lr.setSourceMethodName(sourceMethod);
240.633 + Object params[] = { param1 };
240.634 + lr.setParameters(params);
240.635 + doLog(lr);
240.636 + }
240.637 +
240.638 + /**
240.639 + * Log a message, specifying source class and method,
240.640 + * with an array of object arguments.
240.641 + * <p>
240.642 + * If the logger is currently enabled for the given message
240.643 + * level then a corresponding LogRecord is created and forwarded
240.644 + * to all the registered output Handler objects.
240.645 + * <p>
240.646 + * @param level One of the message level identifiers, e.g., SEVERE
240.647 + * @param sourceClass name of class that issued the logging request
240.648 + * @param sourceMethod name of method that issued the logging request
240.649 + * @param msg The string message (or a key in the message catalog)
240.650 + * @param params Array of parameters to the message
240.651 + */
240.652 + public void logp(Level level, String sourceClass, String sourceMethod,
240.653 + String msg, Object params[]) {
240.654 + if (level.intValue() < levelValue || levelValue == offValue) {
240.655 + return;
240.656 + }
240.657 + LogRecord lr = new LogRecord(level, msg);
240.658 + lr.setSourceClassName(sourceClass);
240.659 + lr.setSourceMethodName(sourceMethod);
240.660 + lr.setParameters(params);
240.661 + doLog(lr);
240.662 + }
240.663 +
240.664 + /**
240.665 + * Log a message, specifying source class and method,
240.666 + * with associated Throwable information.
240.667 + * <p>
240.668 + * If the logger is currently enabled for the given message
240.669 + * level then the given arguments are stored in a LogRecord
240.670 + * which is forwarded to all registered output handlers.
240.671 + * <p>
240.672 + * Note that the thrown argument is stored in the LogRecord thrown
240.673 + * property, rather than the LogRecord parameters property. Thus is it
240.674 + * processed specially by output Formatters and is not treated
240.675 + * as a formatting parameter to the LogRecord message property.
240.676 + * <p>
240.677 + * @param level One of the message level identifiers, e.g., SEVERE
240.678 + * @param sourceClass name of class that issued the logging request
240.679 + * @param sourceMethod name of method that issued the logging request
240.680 + * @param msg The string message (or a key in the message catalog)
240.681 + * @param thrown Throwable associated with log message.
240.682 + */
240.683 + public void logp(Level level, String sourceClass, String sourceMethod,
240.684 + String msg, Throwable thrown) {
240.685 + if (level.intValue() < levelValue || levelValue == offValue) {
240.686 + return;
240.687 + }
240.688 + LogRecord lr = new LogRecord(level, msg);
240.689 + lr.setSourceClassName(sourceClass);
240.690 + lr.setSourceMethodName(sourceMethod);
240.691 + lr.setThrown(thrown);
240.692 + doLog(lr);
240.693 + }
240.694 +
240.695 +
240.696 + //=========================================================================
240.697 + // Start of convenience methods WITH className, methodName and bundle name.
240.698 + //=========================================================================
240.699 +
240.700 +
240.701 + /**
240.702 + * Log a message, specifying source class, method, and resource bundle name
240.703 + * with no arguments.
240.704 + * <p>
240.705 + * If the logger is currently enabled for the given message
240.706 + * level then the given message is forwarded to all the
240.707 + * registered output Handler objects.
240.708 + * <p>
240.709 + * The msg string is localized using the named resource bundle. If the
240.710 + * resource bundle name is null, or an empty String or invalid
240.711 + * then the msg string is not localized.
240.712 + * <p>
240.713 + * @param level One of the message level identifiers, e.g., SEVERE
240.714 + * @param sourceClass name of class that issued the logging request
240.715 + * @param sourceMethod name of method that issued the logging request
240.716 + * @param bundleName name of resource bundle to localize msg,
240.717 + * can be null
240.718 + * @param msg The string message (or a key in the message catalog)
240.719 + */
240.720 +
240.721 + public void logrb(Level level, String sourceClass, String sourceMethod,
240.722 + String bundleName, String msg) {
240.723 + if (level.intValue() < levelValue || levelValue == offValue) {
240.724 + return;
240.725 + }
240.726 + LogRecord lr = new LogRecord(level, msg);
240.727 + lr.setSourceClassName(sourceClass);
240.728 + lr.setSourceMethodName(sourceMethod);
240.729 + doLog(lr, bundleName);
240.730 + }
240.731 +
240.732 + /**
240.733 + * Log a message, specifying source class, method, and resource bundle name,
240.734 + * with a single object parameter to the log message.
240.735 + * <p>
240.736 + * If the logger is currently enabled for the given message
240.737 + * level then a corresponding LogRecord is created and forwarded
240.738 + * to all the registered output Handler objects.
240.739 + * <p>
240.740 + * The msg string is localized using the named resource bundle. If the
240.741 + * resource bundle name is null, or an empty String or invalid
240.742 + * then the msg string is not localized.
240.743 + * <p>
240.744 + * @param level One of the message level identifiers, e.g., SEVERE
240.745 + * @param sourceClass name of class that issued the logging request
240.746 + * @param sourceMethod name of method that issued the logging request
240.747 + * @param bundleName name of resource bundle to localize msg,
240.748 + * can be null
240.749 + * @param msg The string message (or a key in the message catalog)
240.750 + * @param param1 Parameter to the log message.
240.751 + */
240.752 + public void logrb(Level level, String sourceClass, String sourceMethod,
240.753 + String bundleName, String msg, Object param1) {
240.754 + if (level.intValue() < levelValue || levelValue == offValue) {
240.755 + return;
240.756 + }
240.757 + LogRecord lr = new LogRecord(level, msg);
240.758 + lr.setSourceClassName(sourceClass);
240.759 + lr.setSourceMethodName(sourceMethod);
240.760 + Object params[] = { param1 };
240.761 + lr.setParameters(params);
240.762 + doLog(lr, bundleName);
240.763 + }
240.764 +
240.765 + /**
240.766 + * Log a message, specifying source class, method, and resource bundle name,
240.767 + * with an array of object arguments.
240.768 + * <p>
240.769 + * If the logger is currently enabled for the given message
240.770 + * level then a corresponding LogRecord is created and forwarded
240.771 + * to all the registered output Handler objects.
240.772 + * <p>
240.773 + * The msg string is localized using the named resource bundle. If the
240.774 + * resource bundle name is null, or an empty String or invalid
240.775 + * then the msg string is not localized.
240.776 + * <p>
240.777 + * @param level One of the message level identifiers, e.g., SEVERE
240.778 + * @param sourceClass name of class that issued the logging request
240.779 + * @param sourceMethod name of method that issued the logging request
240.780 + * @param bundleName name of resource bundle to localize msg,
240.781 + * can be null.
240.782 + * @param msg The string message (or a key in the message catalog)
240.783 + * @param params Array of parameters to the message
240.784 + */
240.785 + public void logrb(Level level, String sourceClass, String sourceMethod,
240.786 + String bundleName, String msg, Object params[]) {
240.787 + if (level.intValue() < levelValue || levelValue == offValue) {
240.788 + return;
240.789 + }
240.790 + LogRecord lr = new LogRecord(level, msg);
240.791 + lr.setSourceClassName(sourceClass);
240.792 + lr.setSourceMethodName(sourceMethod);
240.793 + lr.setParameters(params);
240.794 + doLog(lr, bundleName);
240.795 + }
240.796 +
240.797 + /**
240.798 + * Log a message, specifying source class, method, and resource bundle name,
240.799 + * with associated Throwable information.
240.800 + * <p>
240.801 + * If the logger is currently enabled for the given message
240.802 + * level then the given arguments are stored in a LogRecord
240.803 + * which is forwarded to all registered output handlers.
240.804 + * <p>
240.805 + * The msg string is localized using the named resource bundle. If the
240.806 + * resource bundle name is null, or an empty String or invalid
240.807 + * then the msg string is not localized.
240.808 + * <p>
240.809 + * Note that the thrown argument is stored in the LogRecord thrown
240.810 + * property, rather than the LogRecord parameters property. Thus is it
240.811 + * processed specially by output Formatters and is not treated
240.812 + * as a formatting parameter to the LogRecord message property.
240.813 + * <p>
240.814 + * @param level One of the message level identifiers, e.g., SEVERE
240.815 + * @param sourceClass name of class that issued the logging request
240.816 + * @param sourceMethod name of method that issued the logging request
240.817 + * @param bundleName name of resource bundle to localize msg,
240.818 + * can be null
240.819 + * @param msg The string message (or a key in the message catalog)
240.820 + * @param thrown Throwable associated with log message.
240.821 + */
240.822 + public void logrb(Level level, String sourceClass, String sourceMethod,
240.823 + String bundleName, String msg, Throwable thrown) {
240.824 + if (level.intValue() < levelValue || levelValue == offValue) {
240.825 + return;
240.826 + }
240.827 + LogRecord lr = new LogRecord(level, msg);
240.828 + lr.setSourceClassName(sourceClass);
240.829 + lr.setSourceMethodName(sourceMethod);
240.830 + lr.setThrown(thrown);
240.831 + doLog(lr, bundleName);
240.832 + }
240.833 +
240.834 +
240.835 + //======================================================================
240.836 + // Start of convenience methods for logging method entries and returns.
240.837 + //======================================================================
240.838 +
240.839 + /**
240.840 + * Log a method entry.
240.841 + * <p>
240.842 + * This is a convenience method that can be used to log entry
240.843 + * to a method. A LogRecord with message "ENTRY", log level
240.844 + * FINER, and the given sourceMethod and sourceClass is logged.
240.845 + * <p>
240.846 + * @param sourceClass name of class that issued the logging request
240.847 + * @param sourceMethod name of method that is being entered
240.848 + */
240.849 + public void entering(String sourceClass, String sourceMethod) {
240.850 + if (Level.FINER.intValue() < levelValue) {
240.851 + return;
240.852 + }
240.853 + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
240.854 + }
240.855 +
240.856 + /**
240.857 + * Log a method entry, with one parameter.
240.858 + * <p>
240.859 + * This is a convenience method that can be used to log entry
240.860 + * to a method. A LogRecord with message "ENTRY {0}", log level
240.861 + * FINER, and the given sourceMethod, sourceClass, and parameter
240.862 + * is logged.
240.863 + * <p>
240.864 + * @param sourceClass name of class that issued the logging request
240.865 + * @param sourceMethod name of method that is being entered
240.866 + * @param param1 parameter to the method being entered
240.867 + */
240.868 + public void entering(String sourceClass, String sourceMethod, Object param1) {
240.869 + if (Level.FINER.intValue() < levelValue) {
240.870 + return;
240.871 + }
240.872 + Object params[] = { param1 };
240.873 + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params);
240.874 + }
240.875 +
240.876 + /**
240.877 + * Log a method entry, with an array of parameters.
240.878 + * <p>
240.879 + * This is a convenience method that can be used to log entry
240.880 + * to a method. A LogRecord with message "ENTRY" (followed by a
240.881 + * format {N} indicator for each entry in the parameter array),
240.882 + * log level FINER, and the given sourceMethod, sourceClass, and
240.883 + * parameters is logged.
240.884 + * <p>
240.885 + * @param sourceClass name of class that issued the logging request
240.886 + * @param sourceMethod name of method that is being entered
240.887 + * @param params array of parameters to the method being entered
240.888 + */
240.889 + public void entering(String sourceClass, String sourceMethod, Object params[]) {
240.890 + if (Level.FINER.intValue() < levelValue) {
240.891 + return;
240.892 + }
240.893 + String msg = "ENTRY";
240.894 + if (params == null ) {
240.895 + logp(Level.FINER, sourceClass, sourceMethod, msg);
240.896 + return;
240.897 + }
240.898 + for (int i = 0; i < params.length; i++) {
240.899 + msg = msg + " {" + i + "}";
240.900 + }
240.901 + logp(Level.FINER, sourceClass, sourceMethod, msg, params);
240.902 + }
240.903 +
240.904 + /**
240.905 + * Log a method return.
240.906 + * <p>
240.907 + * This is a convenience method that can be used to log returning
240.908 + * from a method. A LogRecord with message "RETURN", log level
240.909 + * FINER, and the given sourceMethod and sourceClass is logged.
240.910 + * <p>
240.911 + * @param sourceClass name of class that issued the logging request
240.912 + * @param sourceMethod name of the method
240.913 + */
240.914 + public void exiting(String sourceClass, String sourceMethod) {
240.915 + if (Level.FINER.intValue() < levelValue) {
240.916 + return;
240.917 + }
240.918 + logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
240.919 + }
240.920 +
240.921 +
240.922 + /**
240.923 + * Log a method return, with result object.
240.924 + * <p>
240.925 + * This is a convenience method that can be used to log returning
240.926 + * from a method. A LogRecord with message "RETURN {0}", log level
240.927 + * FINER, and the gives sourceMethod, sourceClass, and result
240.928 + * object is logged.
240.929 + * <p>
240.930 + * @param sourceClass name of class that issued the logging request
240.931 + * @param sourceMethod name of the method
240.932 + * @param result Object that is being returned
240.933 + */
240.934 + public void exiting(String sourceClass, String sourceMethod, Object result) {
240.935 + if (Level.FINER.intValue() < levelValue) {
240.936 + return;
240.937 + }
240.938 + Object params[] = { result };
240.939 + logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
240.940 + }
240.941 +
240.942 + /**
240.943 + * Log throwing an exception.
240.944 + * <p>
240.945 + * This is a convenience method to log that a method is
240.946 + * terminating by throwing an exception. The logging is done
240.947 + * using the FINER level.
240.948 + * <p>
240.949 + * If the logger is currently enabled for the given message
240.950 + * level then the given arguments are stored in a LogRecord
240.951 + * which is forwarded to all registered output handlers. The
240.952 + * LogRecord's message is set to "THROW".
240.953 + * <p>
240.954 + * Note that the thrown argument is stored in the LogRecord thrown
240.955 + * property, rather than the LogRecord parameters property. Thus is it
240.956 + * processed specially by output Formatters and is not treated
240.957 + * as a formatting parameter to the LogRecord message property.
240.958 + * <p>
240.959 + * @param sourceClass name of class that issued the logging request
240.960 + * @param sourceMethod name of the method.
240.961 + * @param thrown The Throwable that is being thrown.
240.962 + */
240.963 + public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
240.964 + if (Level.FINER.intValue() < levelValue || levelValue == offValue ) {
240.965 + return;
240.966 + }
240.967 + LogRecord lr = new LogRecord(Level.FINER, "THROW");
240.968 + lr.setSourceClassName(sourceClass);
240.969 + lr.setSourceMethodName(sourceMethod);
240.970 + lr.setThrown(thrown);
240.971 + doLog(lr);
240.972 + }
240.973 +
240.974 + //=======================================================================
240.975 + // Start of simple convenience methods using level names as method names
240.976 + //=======================================================================
240.977 +
240.978 + /**
240.979 + * Log a SEVERE message.
240.980 + * <p>
240.981 + * If the logger is currently enabled for the SEVERE message
240.982 + * level then the given message is forwarded to all the
240.983 + * registered output Handler objects.
240.984 + * <p>
240.985 + * @param msg The string message (or a key in the message catalog)
240.986 + */
240.987 + public void severe(String msg) {
240.988 + if (Level.SEVERE.intValue() < levelValue) {
240.989 + return;
240.990 + }
240.991 + log(Level.SEVERE, msg);
240.992 + }
240.993 +
240.994 + /**
240.995 + * Log a WARNING message.
240.996 + * <p>
240.997 + * If the logger is currently enabled for the WARNING message
240.998 + * level then the given message is forwarded to all the
240.999 + * registered output Handler objects.
240.1000 + * <p>
240.1001 + * @param msg The string message (or a key in the message catalog)
240.1002 + */
240.1003 + public void warning(String msg) {
240.1004 + if (Level.WARNING.intValue() < levelValue) {
240.1005 + return;
240.1006 + }
240.1007 + log(Level.WARNING, msg);
240.1008 + }
240.1009 +
240.1010 + /**
240.1011 + * Log an INFO message.
240.1012 + * <p>
240.1013 + * If the logger is currently enabled for the INFO message
240.1014 + * level then the given message is forwarded to all the
240.1015 + * registered output Handler objects.
240.1016 + * <p>
240.1017 + * @param msg The string message (or a key in the message catalog)
240.1018 + */
240.1019 + public void info(String msg) {
240.1020 + if (Level.INFO.intValue() < levelValue) {
240.1021 + return;
240.1022 + }
240.1023 + log(Level.INFO, msg);
240.1024 + }
240.1025 +
240.1026 + /**
240.1027 + * Log a CONFIG message.
240.1028 + * <p>
240.1029 + * If the logger is currently enabled for the CONFIG message
240.1030 + * level then the given message is forwarded to all the
240.1031 + * registered output Handler objects.
240.1032 + * <p>
240.1033 + * @param msg The string message (or a key in the message catalog)
240.1034 + */
240.1035 + public void config(String msg) {
240.1036 + if (Level.CONFIG.intValue() < levelValue) {
240.1037 + return;
240.1038 + }
240.1039 + log(Level.CONFIG, msg);
240.1040 + }
240.1041 +
240.1042 + /**
240.1043 + * Log a FINE message.
240.1044 + * <p>
240.1045 + * If the logger is currently enabled for the FINE message
240.1046 + * level then the given message is forwarded to all the
240.1047 + * registered output Handler objects.
240.1048 + * <p>
240.1049 + * @param msg The string message (or a key in the message catalog)
240.1050 + */
240.1051 + public void fine(String msg) {
240.1052 + if (Level.FINE.intValue() < levelValue) {
240.1053 + return;
240.1054 + }
240.1055 + log(Level.FINE, msg);
240.1056 + }
240.1057 +
240.1058 + /**
240.1059 + * Log a FINER message.
240.1060 + * <p>
240.1061 + * If the logger is currently enabled for the FINER message
240.1062 + * level then the given message is forwarded to all the
240.1063 + * registered output Handler objects.
240.1064 + * <p>
240.1065 + * @param msg The string message (or a key in the message catalog)
240.1066 + */
240.1067 + public void finer(String msg) {
240.1068 + if (Level.FINER.intValue() < levelValue) {
240.1069 + return;
240.1070 + }
240.1071 + log(Level.FINER, msg);
240.1072 + }
240.1073 +
240.1074 + /**
240.1075 + * Log a FINEST message.
240.1076 + * <p>
240.1077 + * If the logger is currently enabled for the FINEST message
240.1078 + * level then the given message is forwarded to all the
240.1079 + * registered output Handler objects.
240.1080 + * <p>
240.1081 + * @param msg The string message (or a key in the message catalog)
240.1082 + */
240.1083 + public void finest(String msg) {
240.1084 + if (Level.FINEST.intValue() < levelValue) {
240.1085 + return;
240.1086 + }
240.1087 + log(Level.FINEST, msg);
240.1088 + }
240.1089 +
240.1090 + //================================================================
240.1091 + // End of convenience methods
240.1092 + //================================================================
240.1093 +
240.1094 + /**
240.1095 + * Set the log level specifying which message levels will be
240.1096 + * logged by this logger. Message levels lower than this
240.1097 + * value will be discarded. The level value Level.OFF
240.1098 + * can be used to turn off logging.
240.1099 + * <p>
240.1100 + * If the new level is null, it means that this node should
240.1101 + * inherit its level from its nearest ancestor with a specific
240.1102 + * (non-null) level value.
240.1103 + *
240.1104 + * @param newLevel the new value for the log level (may be null)
240.1105 + * @exception SecurityException if a security manager exists and if
240.1106 + * the caller does not have LoggingPermission("control").
240.1107 + */
240.1108 + public void setLevel(Level newLevel) throws SecurityException {
240.1109 + levelValue = newLevel.intValue();
240.1110 + levelObject = newLevel;
240.1111 + }
240.1112 +
240.1113 + /**
240.1114 + * Get the log Level that has been specified for this Logger.
240.1115 + * The result may be null, which means that this logger's
240.1116 + * effective level will be inherited from its parent.
240.1117 + *
240.1118 + * @return this Logger's level
240.1119 + */
240.1120 + public Level getLevel() {
240.1121 + return levelObject;
240.1122 + }
240.1123 +
240.1124 + /**
240.1125 + * Check if a message of the given level would actually be logged
240.1126 + * by this logger. This check is based on the Loggers effective level,
240.1127 + * which may be inherited from its parent.
240.1128 + *
240.1129 + * @param level a message logging level
240.1130 + * @return true if the given message level is currently being logged.
240.1131 + */
240.1132 + public boolean isLoggable(Level level) {
240.1133 + if (level.intValue() < levelValue || levelValue == offValue) {
240.1134 + return false;
240.1135 + }
240.1136 + return true;
240.1137 + }
240.1138 +
240.1139 + /**
240.1140 + * Get the name for this logger.
240.1141 + * @return logger name. Will be null for anonymous Loggers.
240.1142 + */
240.1143 + public String getName() {
240.1144 + return name;
240.1145 + }
240.1146 +
240.1147 + /**
240.1148 + * Add a log Handler to receive logging messages.
240.1149 + * <p>
240.1150 + * By default, Loggers also send their output to their parent logger.
240.1151 + * Typically the root Logger is configured with a set of Handlers
240.1152 + * that essentially act as default handlers for all loggers.
240.1153 + *
240.1154 + * @param handler a logging Handler
240.1155 + * @exception SecurityException if a security manager exists and if
240.1156 + * the caller does not have LoggingPermission("control").
240.1157 + */
240.1158 +// public void addHandler(Handler handler) throws SecurityException {
240.1159 +// // Check for null handler
240.1160 +// handler.getClass();
240.1161 +// checkAccess();
240.1162 +// handlers.add(handler);
240.1163 +// }
240.1164 +
240.1165 + /**
240.1166 + * Remove a log Handler.
240.1167 + * <P>
240.1168 + * Returns silently if the given Handler is not found or is null
240.1169 + *
240.1170 + * @param handler a logging Handler
240.1171 + * @exception SecurityException if a security manager exists and if
240.1172 + * the caller does not have LoggingPermission("control").
240.1173 + */
240.1174 +// public void removeHandler(Handler handler) throws SecurityException {
240.1175 +// checkAccess();
240.1176 +// if (handler == null) {
240.1177 +// return;
240.1178 +// }
240.1179 +// handlers.remove(handler);
240.1180 +// }
240.1181 +
240.1182 + /**
240.1183 + * Get the Handlers associated with this logger.
240.1184 + * <p>
240.1185 + * @return an array of all registered Handlers
240.1186 + */
240.1187 +// public Handler[] getHandlers() {
240.1188 +// return handlers.toArray(emptyHandlers);
240.1189 +// }
240.1190 +
240.1191 + /**
240.1192 + * Specify whether or not this logger should send its output
240.1193 + * to its parent Logger. This means that any LogRecords will
240.1194 + * also be written to the parent's Handlers, and potentially
240.1195 + * to its parent, recursively up the namespace.
240.1196 + *
240.1197 + * @param useParentHandlers true if output is to be sent to the
240.1198 + * logger's parent.
240.1199 + * @exception SecurityException if a security manager exists and if
240.1200 + * the caller does not have LoggingPermission("control").
240.1201 + */
240.1202 + public void setUseParentHandlers(boolean useParentHandlers) {
240.1203 + checkAccess();
240.1204 + }
240.1205 +
240.1206 + /**
240.1207 + * Discover whether or not this logger is sending its output
240.1208 + * to its parent logger.
240.1209 + *
240.1210 + * @return true if output is to be sent to the logger's parent
240.1211 + */
240.1212 + public boolean getUseParentHandlers() {
240.1213 + return true;
240.1214 + }
240.1215 +
240.1216 + /**
240.1217 + * Return the parent for this Logger.
240.1218 + * <p>
240.1219 + * This method returns the nearest extant parent in the namespace.
240.1220 + * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
240.1221 + * has been created but no logger "a.b.c" exists, then a call of
240.1222 + * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
240.1223 + * <p>
240.1224 + * The result will be null if it is called on the root Logger
240.1225 + * in the namespace.
240.1226 + *
240.1227 + * @return nearest existing parent Logger
240.1228 + */
240.1229 + public Logger getParent() {
240.1230 + // Note: this used to be synchronized on treeLock. However, this only
240.1231 + // provided memory semantics, as there was no guarantee that the caller
240.1232 + // would synchronize on treeLock (in fact, there is no way for external
240.1233 + // callers to so synchronize). Therefore, we have made parent volatile
240.1234 + // instead.
240.1235 + String n = getName();
240.1236 + int at = n.length();
240.1237 + for (;;) {
240.1238 + int last = n.lastIndexOf('.', at - 1);
240.1239 + if (last == -1) {
240.1240 + return getGlobal();
240.1241 + }
240.1242 + Logger p = ALL.get(n.substring(0, last));
240.1243 + if (p != null) {
240.1244 + return p;
240.1245 + }
240.1246 + at = last;
240.1247 + }
240.1248 + }
240.1249 +
240.1250 + /**
240.1251 + * Set the parent for this Logger. This method is used by
240.1252 + * the LogManager to update a Logger when the namespace changes.
240.1253 + * <p>
240.1254 + * It should not be called from application code.
240.1255 + * <p>
240.1256 + * @param parent the new parent logger
240.1257 + * @exception SecurityException if a security manager exists and if
240.1258 + * the caller does not have LoggingPermission("control").
240.1259 + */
240.1260 + public void setParent(Logger parent) {
240.1261 + if (parent == null) {
240.1262 + throw new NullPointerException();
240.1263 + }
240.1264 + checkAccess();
240.1265 + }
240.1266 +
240.1267 +}
241.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
241.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/ASCII.java Wed Apr 30 15:04:10 2014 +0200
241.3 @@ -0,0 +1,274 @@
241.4 +/*
241.5 + * Copyright (c) 1999, 2000, Oracle and/or its affiliates. All rights reserved.
241.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
241.7 + *
241.8 + * This code is free software; you can redistribute it and/or modify it
241.9 + * under the terms of the GNU General Public License version 2 only, as
241.10 + * published by the Free Software Foundation. Oracle designates this
241.11 + * particular file as subject to the "Classpath" exception as provided
241.12 + * by Oracle in the LICENSE file that accompanied this code.
241.13 + *
241.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
241.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
241.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
241.17 + * version 2 for more details (a copy is included in the LICENSE file that
241.18 + * accompanied this code).
241.19 + *
241.20 + * You should have received a copy of the GNU General Public License version
241.21 + * 2 along with this work; if not, write to the Free Software Foundation,
241.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
241.23 + *
241.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
241.25 + * or visit www.oracle.com if you need additional information or have any
241.26 + * questions.
241.27 + */
241.28 +
241.29 +package java.util.regex;
241.30 +
241.31 +
241.32 +/**
241.33 + * Utility class that implements the standard C ctype functionality.
241.34 + *
241.35 + * @author Hong Zhang
241.36 + */
241.37 +
241.38 +final class ASCII {
241.39 +
241.40 + static final int UPPER = 0x00000100;
241.41 +
241.42 + static final int LOWER = 0x00000200;
241.43 +
241.44 + static final int DIGIT = 0x00000400;
241.45 +
241.46 + static final int SPACE = 0x00000800;
241.47 +
241.48 + static final int PUNCT = 0x00001000;
241.49 +
241.50 + static final int CNTRL = 0x00002000;
241.51 +
241.52 + static final int BLANK = 0x00004000;
241.53 +
241.54 + static final int HEX = 0x00008000;
241.55 +
241.56 + static final int UNDER = 0x00010000;
241.57 +
241.58 + static final int ASCII = 0x0000FF00;
241.59 +
241.60 + static final int ALPHA = (UPPER|LOWER);
241.61 +
241.62 + static final int ALNUM = (UPPER|LOWER|DIGIT);
241.63 +
241.64 + static final int GRAPH = (PUNCT|UPPER|LOWER|DIGIT);
241.65 +
241.66 + static final int WORD = (UPPER|LOWER|UNDER|DIGIT);
241.67 +
241.68 + static final int XDIGIT = (HEX);
241.69 +
241.70 + private static final int[] ctype = new int[] {
241.71 + CNTRL, /* 00 (NUL) */
241.72 + CNTRL, /* 01 (SOH) */
241.73 + CNTRL, /* 02 (STX) */
241.74 + CNTRL, /* 03 (ETX) */
241.75 + CNTRL, /* 04 (EOT) */
241.76 + CNTRL, /* 05 (ENQ) */
241.77 + CNTRL, /* 06 (ACK) */
241.78 + CNTRL, /* 07 (BEL) */
241.79 + CNTRL, /* 08 (BS) */
241.80 + SPACE+CNTRL+BLANK, /* 09 (HT) */
241.81 + SPACE+CNTRL, /* 0A (LF) */
241.82 + SPACE+CNTRL, /* 0B (VT) */
241.83 + SPACE+CNTRL, /* 0C (FF) */
241.84 + SPACE+CNTRL, /* 0D (CR) */
241.85 + CNTRL, /* 0E (SI) */
241.86 + CNTRL, /* 0F (SO) */
241.87 + CNTRL, /* 10 (DLE) */
241.88 + CNTRL, /* 11 (DC1) */
241.89 + CNTRL, /* 12 (DC2) */
241.90 + CNTRL, /* 13 (DC3) */
241.91 + CNTRL, /* 14 (DC4) */
241.92 + CNTRL, /* 15 (NAK) */
241.93 + CNTRL, /* 16 (SYN) */
241.94 + CNTRL, /* 17 (ETB) */
241.95 + CNTRL, /* 18 (CAN) */
241.96 + CNTRL, /* 19 (EM) */
241.97 + CNTRL, /* 1A (SUB) */
241.98 + CNTRL, /* 1B (ESC) */
241.99 + CNTRL, /* 1C (FS) */
241.100 + CNTRL, /* 1D (GS) */
241.101 + CNTRL, /* 1E (RS) */
241.102 + CNTRL, /* 1F (US) */
241.103 + SPACE+BLANK, /* 20 SPACE */
241.104 + PUNCT, /* 21 ! */
241.105 + PUNCT, /* 22 " */
241.106 + PUNCT, /* 23 # */
241.107 + PUNCT, /* 24 $ */
241.108 + PUNCT, /* 25 % */
241.109 + PUNCT, /* 26 & */
241.110 + PUNCT, /* 27 ' */
241.111 + PUNCT, /* 28 ( */
241.112 + PUNCT, /* 29 ) */
241.113 + PUNCT, /* 2A * */
241.114 + PUNCT, /* 2B + */
241.115 + PUNCT, /* 2C , */
241.116 + PUNCT, /* 2D - */
241.117 + PUNCT, /* 2E . */
241.118 + PUNCT, /* 2F / */
241.119 + DIGIT+HEX+0, /* 30 0 */
241.120 + DIGIT+HEX+1, /* 31 1 */
241.121 + DIGIT+HEX+2, /* 32 2 */
241.122 + DIGIT+HEX+3, /* 33 3 */
241.123 + DIGIT+HEX+4, /* 34 4 */
241.124 + DIGIT+HEX+5, /* 35 5 */
241.125 + DIGIT+HEX+6, /* 36 6 */
241.126 + DIGIT+HEX+7, /* 37 7 */
241.127 + DIGIT+HEX+8, /* 38 8 */
241.128 + DIGIT+HEX+9, /* 39 9 */
241.129 + PUNCT, /* 3A : */
241.130 + PUNCT, /* 3B ; */
241.131 + PUNCT, /* 3C < */
241.132 + PUNCT, /* 3D = */
241.133 + PUNCT, /* 3E > */
241.134 + PUNCT, /* 3F ? */
241.135 + PUNCT, /* 40 @ */
241.136 + UPPER+HEX+10, /* 41 A */
241.137 + UPPER+HEX+11, /* 42 B */
241.138 + UPPER+HEX+12, /* 43 C */
241.139 + UPPER+HEX+13, /* 44 D */
241.140 + UPPER+HEX+14, /* 45 E */
241.141 + UPPER+HEX+15, /* 46 F */
241.142 + UPPER+16, /* 47 G */
241.143 + UPPER+17, /* 48 H */
241.144 + UPPER+18, /* 49 I */
241.145 + UPPER+19, /* 4A J */
241.146 + UPPER+20, /* 4B K */
241.147 + UPPER+21, /* 4C L */
241.148 + UPPER+22, /* 4D M */
241.149 + UPPER+23, /* 4E N */
241.150 + UPPER+24, /* 4F O */
241.151 + UPPER+25, /* 50 P */
241.152 + UPPER+26, /* 51 Q */
241.153 + UPPER+27, /* 52 R */
241.154 + UPPER+28, /* 53 S */
241.155 + UPPER+29, /* 54 T */
241.156 + UPPER+30, /* 55 U */
241.157 + UPPER+31, /* 56 V */
241.158 + UPPER+32, /* 57 W */
241.159 + UPPER+33, /* 58 X */
241.160 + UPPER+34, /* 59 Y */
241.161 + UPPER+35, /* 5A Z */
241.162 + PUNCT, /* 5B [ */
241.163 + PUNCT, /* 5C \ */
241.164 + PUNCT, /* 5D ] */
241.165 + PUNCT, /* 5E ^ */
241.166 + PUNCT|UNDER, /* 5F _ */
241.167 + PUNCT, /* 60 ` */
241.168 + LOWER+HEX+10, /* 61 a */
241.169 + LOWER+HEX+11, /* 62 b */
241.170 + LOWER+HEX+12, /* 63 c */
241.171 + LOWER+HEX+13, /* 64 d */
241.172 + LOWER+HEX+14, /* 65 e */
241.173 + LOWER+HEX+15, /* 66 f */
241.174 + LOWER+16, /* 67 g */
241.175 + LOWER+17, /* 68 h */
241.176 + LOWER+18, /* 69 i */
241.177 + LOWER+19, /* 6A j */
241.178 + LOWER+20, /* 6B k */
241.179 + LOWER+21, /* 6C l */
241.180 + LOWER+22, /* 6D m */
241.181 + LOWER+23, /* 6E n */
241.182 + LOWER+24, /* 6F o */
241.183 + LOWER+25, /* 70 p */
241.184 + LOWER+26, /* 71 q */
241.185 + LOWER+27, /* 72 r */
241.186 + LOWER+28, /* 73 s */
241.187 + LOWER+29, /* 74 t */
241.188 + LOWER+30, /* 75 u */
241.189 + LOWER+31, /* 76 v */
241.190 + LOWER+32, /* 77 w */
241.191 + LOWER+33, /* 78 x */
241.192 + LOWER+34, /* 79 y */
241.193 + LOWER+35, /* 7A z */
241.194 + PUNCT, /* 7B { */
241.195 + PUNCT, /* 7C | */
241.196 + PUNCT, /* 7D } */
241.197 + PUNCT, /* 7E ~ */
241.198 + CNTRL, /* 7F (DEL) */
241.199 + };
241.200 +
241.201 + static int getType(int ch) {
241.202 + return ((ch & 0xFFFFFF80) == 0 ? ctype[ch] : 0);
241.203 + }
241.204 +
241.205 + static boolean isType(int ch, int type) {
241.206 + return (getType(ch) & type) != 0;
241.207 + }
241.208 +
241.209 + static boolean isAscii(int ch) {
241.210 + return ((ch & 0xFFFFFF80) == 0);
241.211 + }
241.212 +
241.213 + static boolean isAlpha(int ch) {
241.214 + return isType(ch, ALPHA);
241.215 + }
241.216 +
241.217 + static boolean isDigit(int ch) {
241.218 + return ((ch-'0')|('9'-ch)) >= 0;
241.219 + }
241.220 +
241.221 + static boolean isAlnum(int ch) {
241.222 + return isType(ch, ALNUM);
241.223 + }
241.224 +
241.225 + static boolean isGraph(int ch) {
241.226 + return isType(ch, GRAPH);
241.227 + }
241.228 +
241.229 + static boolean isPrint(int ch) {
241.230 + return ((ch-0x20)|(0x7E-ch)) >= 0;
241.231 + }
241.232 +
241.233 + static boolean isPunct(int ch) {
241.234 + return isType(ch, PUNCT);
241.235 + }
241.236 +
241.237 + static boolean isSpace(int ch) {
241.238 + return isType(ch, SPACE);
241.239 + }
241.240 +
241.241 + static boolean isHexDigit(int ch) {
241.242 + return isType(ch, HEX);
241.243 + }
241.244 +
241.245 + static boolean isOctDigit(int ch) {
241.246 + return ((ch-'0')|('7'-ch)) >= 0;
241.247 + }
241.248 +
241.249 + static boolean isCntrl(int ch) {
241.250 + return isType(ch, CNTRL);
241.251 + }
241.252 +
241.253 + static boolean isLower(int ch) {
241.254 + return ((ch-'a')|('z'-ch)) >= 0;
241.255 + }
241.256 +
241.257 + static boolean isUpper(int ch) {
241.258 + return ((ch-'A')|('Z'-ch)) >= 0;
241.259 + }
241.260 +
241.261 + static boolean isWord(int ch) {
241.262 + return isType(ch, WORD);
241.263 + }
241.264 +
241.265 + static int toDigit(int ch) {
241.266 + return (ctype[ch & 0x7F] & 0x3F);
241.267 + }
241.268 +
241.269 + static int toLower(int ch) {
241.270 + return isUpper(ch) ? (ch + 0x20) : ch;
241.271 + }
241.272 +
241.273 + static int toUpper(int ch) {
241.274 + return isLower(ch) ? (ch - 0x20) : ch;
241.275 + }
241.276 +
241.277 +}
242.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
242.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/MatchResult.java Wed Apr 30 15:04:10 2014 +0200
242.3 @@ -0,0 +1,188 @@
242.4 +/*
242.5 + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
242.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
242.7 + *
242.8 + * This code is free software; you can redistribute it and/or modify it
242.9 + * under the terms of the GNU General Public License version 2 only, as
242.10 + * published by the Free Software Foundation. Oracle designates this
242.11 + * particular file as subject to the "Classpath" exception as provided
242.12 + * by Oracle in the LICENSE file that accompanied this code.
242.13 + *
242.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
242.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
242.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
242.17 + * version 2 for more details (a copy is included in the LICENSE file that
242.18 + * accompanied this code).
242.19 + *
242.20 + * You should have received a copy of the GNU General Public License version
242.21 + * 2 along with this work; if not, write to the Free Software Foundation,
242.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
242.23 + *
242.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
242.25 + * or visit www.oracle.com if you need additional information or have any
242.26 + * questions.
242.27 + */
242.28 +
242.29 +package java.util.regex;
242.30 +
242.31 +/**
242.32 + * The result of a match operation.
242.33 + *
242.34 + * <p>This interface contains query methods used to determine the
242.35 + * results of a match against a regular expression. The match boundaries,
242.36 + * groups and group boundaries can be seen but not modified through
242.37 + * a <code>MatchResult</code>.
242.38 + *
242.39 + * @author Michael McCloskey
242.40 + * @see Matcher
242.41 + * @since 1.5
242.42 + */
242.43 +public interface MatchResult {
242.44 +
242.45 + /**
242.46 + * Returns the start index of the match.
242.47 + *
242.48 + * @return The index of the first character matched
242.49 + *
242.50 + * @throws IllegalStateException
242.51 + * If no match has yet been attempted,
242.52 + * or if the previous match operation failed
242.53 + */
242.54 + public int start();
242.55 +
242.56 + /**
242.57 + * Returns the start index of the subsequence captured by the given group
242.58 + * during this match.
242.59 + *
242.60 + * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
242.61 + * to right, starting at one. Group zero denotes the entire pattern, so
242.62 + * the expression <i>m.</i><tt>start(0)</tt> is equivalent to
242.63 + * <i>m.</i><tt>start()</tt>. </p>
242.64 + *
242.65 + * @param group
242.66 + * The index of a capturing group in this matcher's pattern
242.67 + *
242.68 + * @return The index of the first character captured by the group,
242.69 + * or <tt>-1</tt> if the match was successful but the group
242.70 + * itself did not match anything
242.71 + *
242.72 + * @throws IllegalStateException
242.73 + * If no match has yet been attempted,
242.74 + * or if the previous match operation failed
242.75 + *
242.76 + * @throws IndexOutOfBoundsException
242.77 + * If there is no capturing group in the pattern
242.78 + * with the given index
242.79 + */
242.80 + public int start(int group);
242.81 +
242.82 + /**
242.83 + * Returns the offset after the last character matched. </p>
242.84 + *
242.85 + * @return @return The offset after the last character matched
242.86 + *
242.87 + * @throws IllegalStateException
242.88 + * If no match has yet been attempted,
242.89 + * or if the previous match operation failed
242.90 + */
242.91 + public int end();
242.92 +
242.93 + /**
242.94 + * Returns the offset after the last character of the subsequence
242.95 + * captured by the given group during this match.
242.96 + *
242.97 + * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
242.98 + * to right, starting at one. Group zero denotes the entire pattern, so
242.99 + * the expression <i>m.</i><tt>end(0)</tt> is equivalent to
242.100 + * <i>m.</i><tt>end()</tt>. </p>
242.101 + *
242.102 + * @param group
242.103 + * The index of a capturing group in this matcher's pattern
242.104 + *
242.105 + * @return The offset after the last character captured by the group,
242.106 + * or <tt>-1</tt> if the match was successful
242.107 + * but the group itself did not match anything
242.108 + *
242.109 + * @throws IllegalStateException
242.110 + * If no match has yet been attempted,
242.111 + * or if the previous match operation failed
242.112 + *
242.113 + * @throws IndexOutOfBoundsException
242.114 + * If there is no capturing group in the pattern
242.115 + * with the given index
242.116 + */
242.117 + public int end(int group);
242.118 +
242.119 + /**
242.120 + * Returns the input subsequence matched by the previous match.
242.121 + *
242.122 + * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
242.123 + * the expressions <i>m.</i><tt>group()</tt> and
242.124 + * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(),</tt> <i>m.</i><tt>end())</tt>
242.125 + * are equivalent. </p>
242.126 + *
242.127 + * <p> Note that some patterns, for example <tt>a*</tt>, match the empty
242.128 + * string. This method will return the empty string when the pattern
242.129 + * successfully matches the empty string in the input. </p>
242.130 + *
242.131 + * @return The (possibly empty) subsequence matched by the previous match,
242.132 + * in string form
242.133 + *
242.134 + * @throws IllegalStateException
242.135 + * If no match has yet been attempted,
242.136 + * or if the previous match operation failed
242.137 + */
242.138 + public String group();
242.139 +
242.140 + /**
242.141 + * Returns the input subsequence captured by the given group during the
242.142 + * previous match operation.
242.143 + *
242.144 + * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
242.145 + * <i>g</i>, the expressions <i>m.</i><tt>group(</tt><i>g</i><tt>)</tt> and
242.146 + * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(</tt><i>g</i><tt>),</tt> <i>m.</i><tt>end(</tt><i>g</i><tt>))</tt>
242.147 + * are equivalent. </p>
242.148 + *
242.149 + * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
242.150 + * to right, starting at one. Group zero denotes the entire pattern, so
242.151 + * the expression <tt>m.group(0)</tt> is equivalent to <tt>m.group()</tt>.
242.152 + * </p>
242.153 + *
242.154 + * <p> If the match was successful but the group specified failed to match
242.155 + * any part of the input sequence, then <tt>null</tt> is returned. Note
242.156 + * that some groups, for example <tt>(a*)</tt>, match the empty string.
242.157 + * This method will return the empty string when such a group successfully
242.158 + * matches the empty string in the input. </p>
242.159 + *
242.160 + * @param group
242.161 + * The index of a capturing group in this matcher's pattern
242.162 + *
242.163 + * @return The (possibly empty) subsequence captured by the group
242.164 + * during the previous match, or <tt>null</tt> if the group
242.165 + * failed to match part of the input
242.166 + *
242.167 + * @throws IllegalStateException
242.168 + * If no match has yet been attempted,
242.169 + * or if the previous match operation failed
242.170 + *
242.171 + * @throws IndexOutOfBoundsException
242.172 + * If there is no capturing group in the pattern
242.173 + * with the given index
242.174 + */
242.175 + public String group(int group);
242.176 +
242.177 + /**
242.178 + * Returns the number of capturing groups in this match result's pattern.
242.179 + *
242.180 + * <p> Group zero denotes the entire pattern by convention. It is not
242.181 + * included in this count.
242.182 + *
242.183 + * <p> Any non-negative integer smaller than or equal to the value
242.184 + * returned by this method is guaranteed to be a valid group index for
242.185 + * this matcher. </p>
242.186 + *
242.187 + * @return The number of capturing groups in this matcher's pattern
242.188 + */
242.189 + public int groupCount();
242.190 +
242.191 +}
243.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
243.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/Matcher.java Wed Apr 30 15:04:10 2014 +0200
243.3 @@ -0,0 +1,1256 @@
243.4 +/*
243.5 + * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
243.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
243.7 + *
243.8 + * This code is free software; you can redistribute it and/or modify it
243.9 + * under the terms of the GNU General Public License version 2 only, as
243.10 + * published by the Free Software Foundation. Oracle designates this
243.11 + * particular file as subject to the "Classpath" exception as provided
243.12 + * by Oracle in the LICENSE file that accompanied this code.
243.13 + *
243.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
243.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
243.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
243.17 + * version 2 for more details (a copy is included in the LICENSE file that
243.18 + * accompanied this code).
243.19 + *
243.20 + * You should have received a copy of the GNU General Public License version
243.21 + * 2 along with this work; if not, write to the Free Software Foundation,
243.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
243.23 + *
243.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
243.25 + * or visit www.oracle.com if you need additional information or have any
243.26 + * questions.
243.27 + */
243.28 +
243.29 +package java.util.regex;
243.30 +
243.31 +
243.32 +/**
243.33 + * An engine that performs match operations on a {@link java.lang.CharSequence
243.34 + * </code>character sequence<code>} by interpreting a {@link Pattern}.
243.35 + *
243.36 + * <p> A matcher is created from a pattern by invoking the pattern's {@link
243.37 + * Pattern#matcher matcher} method. Once created, a matcher can be used to
243.38 + * perform three different kinds of match operations:
243.39 + *
243.40 + * <ul>
243.41 + *
243.42 + * <li><p> The {@link #matches matches} method attempts to match the entire
243.43 + * input sequence against the pattern. </p></li>
243.44 + *
243.45 + * <li><p> The {@link #lookingAt lookingAt} method attempts to match the
243.46 + * input sequence, starting at the beginning, against the pattern. </p></li>
243.47 + *
243.48 + * <li><p> The {@link #find find} method scans the input sequence looking for
243.49 + * the next subsequence that matches the pattern. </p></li>
243.50 + *
243.51 + * </ul>
243.52 + *
243.53 + * <p> Each of these methods returns a boolean indicating success or failure.
243.54 + * More information about a successful match can be obtained by querying the
243.55 + * state of the matcher.
243.56 + *
243.57 + * <p> A matcher finds matches in a subset of its input called the
243.58 + * <i>region</i>. By default, the region contains all of the matcher's input.
243.59 + * The region can be modified via the{@link #region region} method and queried
243.60 + * via the {@link #regionStart regionStart} and {@link #regionEnd regionEnd}
243.61 + * methods. The way that the region boundaries interact with some pattern
243.62 + * constructs can be changed. See {@link #useAnchoringBounds
243.63 + * useAnchoringBounds} and {@link #useTransparentBounds useTransparentBounds}
243.64 + * for more details.
243.65 + *
243.66 + * <p> This class also defines methods for replacing matched subsequences with
243.67 + * new strings whose contents can, if desired, be computed from the match
243.68 + * result. The {@link #appendReplacement appendReplacement} and {@link
243.69 + * #appendTail appendTail} methods can be used in tandem in order to collect
243.70 + * the result into an existing string buffer, or the more convenient {@link
243.71 + * #replaceAll replaceAll} method can be used to create a string in which every
243.72 + * matching subsequence in the input sequence is replaced.
243.73 + *
243.74 + * <p> The explicit state of a matcher includes the start and end indices of
243.75 + * the most recent successful match. It also includes the start and end
243.76 + * indices of the input subsequence captured by each <a
243.77 + * href="Pattern.html#cg">capturing group</a> in the pattern as well as a total
243.78 + * count of such subsequences. As a convenience, methods are also provided for
243.79 + * returning these captured subsequences in string form.
243.80 + *
243.81 + * <p> The explicit state of a matcher is initially undefined; attempting to
243.82 + * query any part of it before a successful match will cause an {@link
243.83 + * IllegalStateException} to be thrown. The explicit state of a matcher is
243.84 + * recomputed by every match operation.
243.85 + *
243.86 + * <p> The implicit state of a matcher includes the input character sequence as
243.87 + * well as the <i>append position</i>, which is initially zero and is updated
243.88 + * by the {@link #appendReplacement appendReplacement} method.
243.89 + *
243.90 + * <p> A matcher may be reset explicitly by invoking its {@link #reset()}
243.91 + * method or, if a new input sequence is desired, its {@link
243.92 + * #reset(java.lang.CharSequence) reset(CharSequence)} method. Resetting a
243.93 + * matcher discards its explicit state information and sets the append position
243.94 + * to zero.
243.95 + *
243.96 + * <p> Instances of this class are not safe for use by multiple concurrent
243.97 + * threads. </p>
243.98 + *
243.99 + *
243.100 + * @author Mike McCloskey
243.101 + * @author Mark Reinhold
243.102 + * @author JSR-51 Expert Group
243.103 + * @since 1.4
243.104 + * @spec JSR-51
243.105 + */
243.106 +
243.107 +public final class Matcher implements MatchResult {
243.108 +
243.109 + /**
243.110 + * The Pattern object that created this Matcher.
243.111 + */
243.112 + Pattern parentPattern;
243.113 +
243.114 + /**
243.115 + * The storage used by groups. They may contain invalid values if
243.116 + * a group was skipped during the matching.
243.117 + */
243.118 + int[] groups;
243.119 +
243.120 + /**
243.121 + * The range within the sequence that is to be matched. Anchors
243.122 + * will match at these "hard" boundaries. Changing the region
243.123 + * changes these values.
243.124 + */
243.125 + int from, to;
243.126 +
243.127 + /**
243.128 + * Lookbehind uses this value to ensure that the subexpression
243.129 + * match ends at the point where the lookbehind was encountered.
243.130 + */
243.131 + int lookbehindTo;
243.132 +
243.133 + /**
243.134 + * The original string being matched.
243.135 + */
243.136 + CharSequence text;
243.137 +
243.138 + /**
243.139 + * Matcher state used by the last node. NOANCHOR is used when a
243.140 + * match does not have to consume all of the input. ENDANCHOR is
243.141 + * the mode used for matching all the input.
243.142 + */
243.143 + static final int ENDANCHOR = 1;
243.144 + static final int NOANCHOR = 0;
243.145 + int acceptMode = NOANCHOR;
243.146 +
243.147 + /**
243.148 + * The range of string that last matched the pattern. If the last
243.149 + * match failed then first is -1; last initially holds 0 then it
243.150 + * holds the index of the end of the last match (which is where the
243.151 + * next search starts).
243.152 + */
243.153 + int first = -1, last = 0;
243.154 +
243.155 + /**
243.156 + * The end index of what matched in the last match operation.
243.157 + */
243.158 + int oldLast = -1;
243.159 +
243.160 + /**
243.161 + * The index of the last position appended in a substitution.
243.162 + */
243.163 + int lastAppendPosition = 0;
243.164 +
243.165 + /**
243.166 + * Storage used by nodes to tell what repetition they are on in
243.167 + * a pattern, and where groups begin. The nodes themselves are stateless,
243.168 + * so they rely on this field to hold state during a match.
243.169 + */
243.170 + int[] locals;
243.171 +
243.172 + /**
243.173 + * Boolean indicating whether or not more input could change
243.174 + * the results of the last match.
243.175 + *
243.176 + * If hitEnd is true, and a match was found, then more input
243.177 + * might cause a different match to be found.
243.178 + * If hitEnd is true and a match was not found, then more
243.179 + * input could cause a match to be found.
243.180 + * If hitEnd is false and a match was found, then more input
243.181 + * will not change the match.
243.182 + * If hitEnd is false and a match was not found, then more
243.183 + * input will not cause a match to be found.
243.184 + */
243.185 + boolean hitEnd;
243.186 +
243.187 + /**
243.188 + * Boolean indicating whether or not more input could change
243.189 + * a positive match into a negative one.
243.190 + *
243.191 + * If requireEnd is true, and a match was found, then more
243.192 + * input could cause the match to be lost.
243.193 + * If requireEnd is false and a match was found, then more
243.194 + * input might change the match but the match won't be lost.
243.195 + * If a match was not found, then requireEnd has no meaning.
243.196 + */
243.197 + boolean requireEnd;
243.198 +
243.199 + /**
243.200 + * If transparentBounds is true then the boundaries of this
243.201 + * matcher's region are transparent to lookahead, lookbehind,
243.202 + * and boundary matching constructs that try to see beyond them.
243.203 + */
243.204 + boolean transparentBounds = false;
243.205 +
243.206 + /**
243.207 + * If anchoringBounds is true then the boundaries of this
243.208 + * matcher's region match anchors such as ^ and $.
243.209 + */
243.210 + boolean anchoringBounds = true;
243.211 +
243.212 + /**
243.213 + * No default constructor.
243.214 + */
243.215 + Matcher() {
243.216 + }
243.217 +
243.218 + /**
243.219 + * All matchers have the state used by Pattern during a match.
243.220 + */
243.221 + Matcher(Pattern parent, CharSequence text) {
243.222 + this.parentPattern = parent;
243.223 + this.text = text;
243.224 +
243.225 + // Allocate state storage
243.226 + int parentGroupCount = Math.max(parent.capturingGroupCount, 10);
243.227 + groups = new int[parentGroupCount * 2];
243.228 + locals = new int[parent.localCount];
243.229 +
243.230 + // Put fields into initial states
243.231 + reset();
243.232 + }
243.233 +
243.234 + /**
243.235 + * Returns the pattern that is interpreted by this matcher.
243.236 + *
243.237 + * @return The pattern for which this matcher was created
243.238 + */
243.239 + public Pattern pattern() {
243.240 + return parentPattern;
243.241 + }
243.242 +
243.243 + /**
243.244 + * Returns the match state of this matcher as a {@link MatchResult}.
243.245 + * The result is unaffected by subsequent operations performed upon this
243.246 + * matcher.
243.247 + *
243.248 + * @return a <code>MatchResult</code> with the state of this matcher
243.249 + * @since 1.5
243.250 + */
243.251 + public MatchResult toMatchResult() {
243.252 + Matcher result = new Matcher(this.parentPattern, text.toString());
243.253 + result.first = this.first;
243.254 + result.last = this.last;
243.255 + result.groups = this.groups.clone();
243.256 + return result;
243.257 + }
243.258 +
243.259 + /**
243.260 + * Changes the <tt>Pattern</tt> that this <tt>Matcher</tt> uses to
243.261 + * find matches with.
243.262 + *
243.263 + * <p> This method causes this matcher to lose information
243.264 + * about the groups of the last match that occurred. The
243.265 + * matcher's position in the input is maintained and its
243.266 + * last append position is unaffected.</p>
243.267 + *
243.268 + * @param newPattern
243.269 + * The new pattern used by this matcher
243.270 + * @return This matcher
243.271 + * @throws IllegalArgumentException
243.272 + * If newPattern is <tt>null</tt>
243.273 + * @since 1.5
243.274 + */
243.275 + public Matcher usePattern(Pattern newPattern) {
243.276 + if (newPattern == null)
243.277 + throw new IllegalArgumentException("Pattern cannot be null");
243.278 + parentPattern = newPattern;
243.279 +
243.280 + // Reallocate state storage
243.281 + int parentGroupCount = Math.max(newPattern.capturingGroupCount, 10);
243.282 + groups = new int[parentGroupCount * 2];
243.283 + locals = new int[newPattern.localCount];
243.284 + for (int i = 0; i < groups.length; i++)
243.285 + groups[i] = -1;
243.286 + for (int i = 0; i < locals.length; i++)
243.287 + locals[i] = -1;
243.288 + return this;
243.289 + }
243.290 +
243.291 + /**
243.292 + * Resets this matcher.
243.293 + *
243.294 + * <p> Resetting a matcher discards all of its explicit state information
243.295 + * and sets its append position to zero. The matcher's region is set to the
243.296 + * default region, which is its entire character sequence. The anchoring
243.297 + * and transparency of this matcher's region boundaries are unaffected.
243.298 + *
243.299 + * @return This matcher
243.300 + */
243.301 + public Matcher reset() {
243.302 + first = -1;
243.303 + last = 0;
243.304 + oldLast = -1;
243.305 + for(int i=0; i<groups.length; i++)
243.306 + groups[i] = -1;
243.307 + for(int i=0; i<locals.length; i++)
243.308 + locals[i] = -1;
243.309 + lastAppendPosition = 0;
243.310 + from = 0;
243.311 + to = getTextLength();
243.312 + return this;
243.313 + }
243.314 +
243.315 + /**
243.316 + * Resets this matcher with a new input sequence.
243.317 + *
243.318 + * <p> Resetting a matcher discards all of its explicit state information
243.319 + * and sets its append position to zero. The matcher's region is set to
243.320 + * the default region, which is its entire character sequence. The
243.321 + * anchoring and transparency of this matcher's region boundaries are
243.322 + * unaffected.
243.323 + *
243.324 + * @param input
243.325 + * The new input character sequence
243.326 + *
243.327 + * @return This matcher
243.328 + */
243.329 + public Matcher reset(CharSequence input) {
243.330 + text = input;
243.331 + return reset();
243.332 + }
243.333 +
243.334 + /**
243.335 + * Returns the start index of the previous match. </p>
243.336 + *
243.337 + * @return The index of the first character matched
243.338 + *
243.339 + * @throws IllegalStateException
243.340 + * If no match has yet been attempted,
243.341 + * or if the previous match operation failed
243.342 + */
243.343 + public int start() {
243.344 + if (first < 0)
243.345 + throw new IllegalStateException("No match available");
243.346 + return first;
243.347 + }
243.348 +
243.349 + /**
243.350 + * Returns the start index of the subsequence captured by the given group
243.351 + * during the previous match operation.
243.352 + *
243.353 + * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
243.354 + * to right, starting at one. Group zero denotes the entire pattern, so
243.355 + * the expression <i>m.</i><tt>start(0)</tt> is equivalent to
243.356 + * <i>m.</i><tt>start()</tt>. </p>
243.357 + *
243.358 + * @param group
243.359 + * The index of a capturing group in this matcher's pattern
243.360 + *
243.361 + * @return The index of the first character captured by the group,
243.362 + * or <tt>-1</tt> if the match was successful but the group
243.363 + * itself did not match anything
243.364 + *
243.365 + * @throws IllegalStateException
243.366 + * If no match has yet been attempted,
243.367 + * or if the previous match operation failed
243.368 + *
243.369 + * @throws IndexOutOfBoundsException
243.370 + * If there is no capturing group in the pattern
243.371 + * with the given index
243.372 + */
243.373 + public int start(int group) {
243.374 + if (first < 0)
243.375 + throw new IllegalStateException("No match available");
243.376 + if (group > groupCount())
243.377 + throw new IndexOutOfBoundsException("No group " + group);
243.378 + return groups[group * 2];
243.379 + }
243.380 +
243.381 + /**
243.382 + * Returns the offset after the last character matched. </p>
243.383 + *
243.384 + * @return The offset after the last character matched
243.385 + *
243.386 + * @throws IllegalStateException
243.387 + * If no match has yet been attempted,
243.388 + * or if the previous match operation failed
243.389 + */
243.390 + public int end() {
243.391 + if (first < 0)
243.392 + throw new IllegalStateException("No match available");
243.393 + return last;
243.394 + }
243.395 +
243.396 + /**
243.397 + * Returns the offset after the last character of the subsequence
243.398 + * captured by the given group during the previous match operation.
243.399 + *
243.400 + * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
243.401 + * to right, starting at one. Group zero denotes the entire pattern, so
243.402 + * the expression <i>m.</i><tt>end(0)</tt> is equivalent to
243.403 + * <i>m.</i><tt>end()</tt>. </p>
243.404 + *
243.405 + * @param group
243.406 + * The index of a capturing group in this matcher's pattern
243.407 + *
243.408 + * @return The offset after the last character captured by the group,
243.409 + * or <tt>-1</tt> if the match was successful
243.410 + * but the group itself did not match anything
243.411 + *
243.412 + * @throws IllegalStateException
243.413 + * If no match has yet been attempted,
243.414 + * or if the previous match operation failed
243.415 + *
243.416 + * @throws IndexOutOfBoundsException
243.417 + * If there is no capturing group in the pattern
243.418 + * with the given index
243.419 + */
243.420 + public int end(int group) {
243.421 + if (first < 0)
243.422 + throw new IllegalStateException("No match available");
243.423 + if (group > groupCount())
243.424 + throw new IndexOutOfBoundsException("No group " + group);
243.425 + return groups[group * 2 + 1];
243.426 + }
243.427 +
243.428 + /**
243.429 + * Returns the input subsequence matched by the previous match.
243.430 + *
243.431 + * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
243.432 + * the expressions <i>m.</i><tt>group()</tt> and
243.433 + * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(),</tt> <i>m.</i><tt>end())</tt>
243.434 + * are equivalent. </p>
243.435 + *
243.436 + * <p> Note that some patterns, for example <tt>a*</tt>, match the empty
243.437 + * string. This method will return the empty string when the pattern
243.438 + * successfully matches the empty string in the input. </p>
243.439 + *
243.440 + * @return The (possibly empty) subsequence matched by the previous match,
243.441 + * in string form
243.442 + *
243.443 + * @throws IllegalStateException
243.444 + * If no match has yet been attempted,
243.445 + * or if the previous match operation failed
243.446 + */
243.447 + public String group() {
243.448 + return group(0);
243.449 + }
243.450 +
243.451 + /**
243.452 + * Returns the input subsequence captured by the given group during the
243.453 + * previous match operation.
243.454 + *
243.455 + * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
243.456 + * <i>g</i>, the expressions <i>m.</i><tt>group(</tt><i>g</i><tt>)</tt> and
243.457 + * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(</tt><i>g</i><tt>),</tt> <i>m.</i><tt>end(</tt><i>g</i><tt>))</tt>
243.458 + * are equivalent. </p>
243.459 + *
243.460 + * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
243.461 + * to right, starting at one. Group zero denotes the entire pattern, so
243.462 + * the expression <tt>m.group(0)</tt> is equivalent to <tt>m.group()</tt>.
243.463 + * </p>
243.464 + *
243.465 + * <p> If the match was successful but the group specified failed to match
243.466 + * any part of the input sequence, then <tt>null</tt> is returned. Note
243.467 + * that some groups, for example <tt>(a*)</tt>, match the empty string.
243.468 + * This method will return the empty string when such a group successfully
243.469 + * matches the empty string in the input. </p>
243.470 + *
243.471 + * @param group
243.472 + * The index of a capturing group in this matcher's pattern
243.473 + *
243.474 + * @return The (possibly empty) subsequence captured by the group
243.475 + * during the previous match, or <tt>null</tt> if the group
243.476 + * failed to match part of the input
243.477 + *
243.478 + * @throws IllegalStateException
243.479 + * If no match has yet been attempted,
243.480 + * or if the previous match operation failed
243.481 + *
243.482 + * @throws IndexOutOfBoundsException
243.483 + * If there is no capturing group in the pattern
243.484 + * with the given index
243.485 + */
243.486 + public String group(int group) {
243.487 + if (first < 0)
243.488 + throw new IllegalStateException("No match found");
243.489 + if (group < 0 || group > groupCount())
243.490 + throw new IndexOutOfBoundsException("No group " + group);
243.491 + if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
243.492 + return null;
243.493 + return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
243.494 + }
243.495 +
243.496 + /**
243.497 + * Returns the input subsequence captured by the given
243.498 + * <a href="Pattern.html#groupname">named-capturing group</a> during the previous
243.499 + * match operation.
243.500 + *
243.501 + * <p> If the match was successful but the group specified failed to match
243.502 + * any part of the input sequence, then <tt>null</tt> is returned. Note
243.503 + * that some groups, for example <tt>(a*)</tt>, match the empty string.
243.504 + * This method will return the empty string when such a group successfully
243.505 + * matches the empty string in the input. </p>
243.506 + *
243.507 + * @param name
243.508 + * The name of a named-capturing group in this matcher's pattern
243.509 + *
243.510 + * @return The (possibly empty) subsequence captured by the named group
243.511 + * during the previous match, or <tt>null</tt> if the group
243.512 + * failed to match part of the input
243.513 + *
243.514 + * @throws IllegalStateException
243.515 + * If no match has yet been attempted,
243.516 + * or if the previous match operation failed
243.517 + *
243.518 + * @throws IllegalArgumentException
243.519 + * If there is no capturing group in the pattern
243.520 + * with the given name
243.521 + */
243.522 + public String group(String name) {
243.523 + if (name == null)
243.524 + throw new NullPointerException("Null group name");
243.525 + if (first < 0)
243.526 + throw new IllegalStateException("No match found");
243.527 + if (!parentPattern.namedGroups().containsKey(name))
243.528 + throw new IllegalArgumentException("No group with name <" + name + ">");
243.529 + int group = parentPattern.namedGroups().get(name);
243.530 + if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
243.531 + return null;
243.532 + return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
243.533 + }
243.534 +
243.535 + /**
243.536 + * Returns the number of capturing groups in this matcher's pattern.
243.537 + *
243.538 + * <p> Group zero denotes the entire pattern by convention. It is not
243.539 + * included in this count.
243.540 + *
243.541 + * <p> Any non-negative integer smaller than or equal to the value
243.542 + * returned by this method is guaranteed to be a valid group index for
243.543 + * this matcher. </p>
243.544 + *
243.545 + * @return The number of capturing groups in this matcher's pattern
243.546 + */
243.547 + public int groupCount() {
243.548 + return parentPattern.capturingGroupCount - 1;
243.549 + }
243.550 +
243.551 + /**
243.552 + * Attempts to match the entire region against the pattern.
243.553 + *
243.554 + * <p> If the match succeeds then more information can be obtained via the
243.555 + * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods. </p>
243.556 + *
243.557 + * @return <tt>true</tt> if, and only if, the entire region sequence
243.558 + * matches this matcher's pattern
243.559 + */
243.560 + public boolean matches() {
243.561 + return match(from, ENDANCHOR);
243.562 + }
243.563 +
243.564 + /**
243.565 + * Attempts to find the next subsequence of the input sequence that matches
243.566 + * the pattern.
243.567 + *
243.568 + * <p> This method starts at the beginning of this matcher's region, or, if
243.569 + * a previous invocation of the method was successful and the matcher has
243.570 + * not since been reset, at the first character not matched by the previous
243.571 + * match.
243.572 + *
243.573 + * <p> If the match succeeds then more information can be obtained via the
243.574 + * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods. </p>
243.575 + *
243.576 + * @return <tt>true</tt> if, and only if, a subsequence of the input
243.577 + * sequence matches this matcher's pattern
243.578 + */
243.579 + public boolean find() {
243.580 + int nextSearchIndex = last;
243.581 + if (nextSearchIndex == first)
243.582 + nextSearchIndex++;
243.583 +
243.584 + // If next search starts before region, start it at region
243.585 + if (nextSearchIndex < from)
243.586 + nextSearchIndex = from;
243.587 +
243.588 + // If next search starts beyond region then it fails
243.589 + if (nextSearchIndex > to) {
243.590 + for (int i = 0; i < groups.length; i++)
243.591 + groups[i] = -1;
243.592 + return false;
243.593 + }
243.594 + return search(nextSearchIndex);
243.595 + }
243.596 +
243.597 + /**
243.598 + * Resets this matcher and then attempts to find the next subsequence of
243.599 + * the input sequence that matches the pattern, starting at the specified
243.600 + * index.
243.601 + *
243.602 + * <p> If the match succeeds then more information can be obtained via the
243.603 + * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods, and subsequent
243.604 + * invocations of the {@link #find()} method will start at the first
243.605 + * character not matched by this match. </p>
243.606 + *
243.607 + * @throws IndexOutOfBoundsException
243.608 + * If start is less than zero or if start is greater than the
243.609 + * length of the input sequence.
243.610 + *
243.611 + * @return <tt>true</tt> if, and only if, a subsequence of the input
243.612 + * sequence starting at the given index matches this matcher's
243.613 + * pattern
243.614 + */
243.615 + public boolean find(int start) {
243.616 + int limit = getTextLength();
243.617 + if ((start < 0) || (start > limit))
243.618 + throw new IndexOutOfBoundsException("Illegal start index");
243.619 + reset();
243.620 + return search(start);
243.621 + }
243.622 +
243.623 + /**
243.624 + * Attempts to match the input sequence, starting at the beginning of the
243.625 + * region, against the pattern.
243.626 + *
243.627 + * <p> Like the {@link #matches matches} method, this method always starts
243.628 + * at the beginning of the region; unlike that method, it does not
243.629 + * require that the entire region be matched.
243.630 + *
243.631 + * <p> If the match succeeds then more information can be obtained via the
243.632 + * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods. </p>
243.633 + *
243.634 + * @return <tt>true</tt> if, and only if, a prefix of the input
243.635 + * sequence matches this matcher's pattern
243.636 + */
243.637 + public boolean lookingAt() {
243.638 + return match(from, NOANCHOR);
243.639 + }
243.640 +
243.641 + /**
243.642 + * Returns a literal replacement <code>String</code> for the specified
243.643 + * <code>String</code>.
243.644 + *
243.645 + * This method produces a <code>String</code> that will work
243.646 + * as a literal replacement <code>s</code> in the
243.647 + * <code>appendReplacement</code> method of the {@link Matcher} class.
243.648 + * The <code>String</code> produced will match the sequence of characters
243.649 + * in <code>s</code> treated as a literal sequence. Slashes ('\') and
243.650 + * dollar signs ('$') will be given no special meaning.
243.651 + *
243.652 + * @param s The string to be literalized
243.653 + * @return A literal string replacement
243.654 + * @since 1.5
243.655 + */
243.656 + public static String quoteReplacement(String s) {
243.657 + if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1))
243.658 + return s;
243.659 + StringBuilder sb = new StringBuilder();
243.660 + for (int i=0; i<s.length(); i++) {
243.661 + char c = s.charAt(i);
243.662 + if (c == '\\' || c == '$') {
243.663 + sb.append('\\');
243.664 + }
243.665 + sb.append(c);
243.666 + }
243.667 + return sb.toString();
243.668 + }
243.669 +
243.670 + /**
243.671 + * Implements a non-terminal append-and-replace step.
243.672 + *
243.673 + * <p> This method performs the following actions: </p>
243.674 + *
243.675 + * <ol>
243.676 + *
243.677 + * <li><p> It reads characters from the input sequence, starting at the
243.678 + * append position, and appends them to the given string buffer. It
243.679 + * stops after reading the last character preceding the previous match,
243.680 + * that is, the character at index {@link
243.681 + * #start()} <tt>-</tt> <tt>1</tt>. </p></li>
243.682 + *
243.683 + * <li><p> It appends the given replacement string to the string buffer.
243.684 + * </p></li>
243.685 + *
243.686 + * <li><p> It sets the append position of this matcher to the index of
243.687 + * the last character matched, plus one, that is, to {@link #end()}.
243.688 + * </p></li>
243.689 + *
243.690 + * </ol>
243.691 + *
243.692 + * <p> The replacement string may contain references to subsequences
243.693 + * captured during the previous match: Each occurrence of
243.694 + * <tt>${</tt><i>name</i><tt>}</tt> or <tt>$</tt><i>g</i>
243.695 + * will be replaced by the result of evaluating the corresponding
243.696 + * {@link #group(String) group(name)} or {@link #group(int) group(g)</tt>}
243.697 + * respectively. For <tt>$</tt><i>g</i><tt></tt>,
243.698 + * the first number after the <tt>$</tt> is always treated as part of
243.699 + * the group reference. Subsequent numbers are incorporated into g if
243.700 + * they would form a legal group reference. Only the numerals '0'
243.701 + * through '9' are considered as potential components of the group
243.702 + * reference. If the second group matched the string <tt>"foo"</tt>, for
243.703 + * example, then passing the replacement string <tt>"$2bar"</tt> would
243.704 + * cause <tt>"foobar"</tt> to be appended to the string buffer. A dollar
243.705 + * sign (<tt>$</tt>) may be included as a literal in the replacement
243.706 + * string by preceding it with a backslash (<tt>\$</tt>).
243.707 + *
243.708 + * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
243.709 + * the replacement string may cause the results to be different than if it
243.710 + * were being treated as a literal replacement string. Dollar signs may be
243.711 + * treated as references to captured subsequences as described above, and
243.712 + * backslashes are used to escape literal characters in the replacement
243.713 + * string.
243.714 + *
243.715 + * <p> This method is intended to be used in a loop together with the
243.716 + * {@link #appendTail appendTail} and {@link #find find} methods. The
243.717 + * following code, for example, writes <tt>one dog two dogs in the
243.718 + * yard</tt> to the standard-output stream: </p>
243.719 + *
243.720 + * <blockquote><pre>
243.721 + * Pattern p = Pattern.compile("cat");
243.722 + * Matcher m = p.matcher("one cat two cats in the yard");
243.723 + * StringBuffer sb = new StringBuffer();
243.724 + * while (m.find()) {
243.725 + * m.appendReplacement(sb, "dog");
243.726 + * }
243.727 + * m.appendTail(sb);
243.728 + * System.out.println(sb.toString());</pre></blockquote>
243.729 + *
243.730 + * @param sb
243.731 + * The target string buffer
243.732 + *
243.733 + * @param replacement
243.734 + * The replacement string
243.735 + *
243.736 + * @return This matcher
243.737 + *
243.738 + * @throws IllegalStateException
243.739 + * If no match has yet been attempted,
243.740 + * or if the previous match operation failed
243.741 + *
243.742 + * @throws IllegalArgumentException
243.743 + * If the replacement string refers to a named-capturing
243.744 + * group that does not exist in the pattern
243.745 + *
243.746 + * @throws IndexOutOfBoundsException
243.747 + * If the replacement string refers to a capturing group
243.748 + * that does not exist in the pattern
243.749 + */
243.750 + public Matcher appendReplacement(StringBuffer sb, String replacement) {
243.751 +
243.752 + // If no match, return error
243.753 + if (first < 0)
243.754 + throw new IllegalStateException("No match available");
243.755 +
243.756 + // Process substitution string to replace group references with groups
243.757 + int cursor = 0;
243.758 + StringBuilder result = new StringBuilder();
243.759 +
243.760 + while (cursor < replacement.length()) {
243.761 + char nextChar = replacement.charAt(cursor);
243.762 + if (nextChar == '\\') {
243.763 + cursor++;
243.764 + nextChar = replacement.charAt(cursor);
243.765 + result.append(nextChar);
243.766 + cursor++;
243.767 + } else if (nextChar == '$') {
243.768 + // Skip past $
243.769 + cursor++;
243.770 + // A StringIndexOutOfBoundsException is thrown if
243.771 + // this "$" is the last character in replacement
243.772 + // string in current implementation, a IAE might be
243.773 + // more appropriate.
243.774 + nextChar = replacement.charAt(cursor);
243.775 + int refNum = -1;
243.776 + if (nextChar == '{') {
243.777 + cursor++;
243.778 + StringBuilder gsb = new StringBuilder();
243.779 + while (cursor < replacement.length()) {
243.780 + nextChar = replacement.charAt(cursor);
243.781 + if (ASCII.isLower(nextChar) ||
243.782 + ASCII.isUpper(nextChar) ||
243.783 + ASCII.isDigit(nextChar)) {
243.784 + gsb.append(nextChar);
243.785 + cursor++;
243.786 + } else {
243.787 + break;
243.788 + }
243.789 + }
243.790 + if (gsb.length() == 0)
243.791 + throw new IllegalArgumentException(
243.792 + "named capturing group has 0 length name");
243.793 + if (nextChar != '}')
243.794 + throw new IllegalArgumentException(
243.795 + "named capturing group is missing trailing '}'");
243.796 + String gname = gsb.toString();
243.797 + if (ASCII.isDigit(gname.charAt(0)))
243.798 + throw new IllegalArgumentException(
243.799 + "capturing group name {" + gname +
243.800 + "} starts with digit character");
243.801 + if (!parentPattern.namedGroups().containsKey(gname))
243.802 + throw new IllegalArgumentException(
243.803 + "No group with name {" + gname + "}");
243.804 + refNum = parentPattern.namedGroups().get(gname);
243.805 + cursor++;
243.806 + } else {
243.807 + // The first number is always a group
243.808 + refNum = (int)nextChar - '0';
243.809 + if ((refNum < 0)||(refNum > 9))
243.810 + throw new IllegalArgumentException(
243.811 + "Illegal group reference");
243.812 + cursor++;
243.813 + // Capture the largest legal group string
243.814 + boolean done = false;
243.815 + while (!done) {
243.816 + if (cursor >= replacement.length()) {
243.817 + break;
243.818 + }
243.819 + int nextDigit = replacement.charAt(cursor) - '0';
243.820 + if ((nextDigit < 0)||(nextDigit > 9)) { // not a number
243.821 + break;
243.822 + }
243.823 + int newRefNum = (refNum * 10) + nextDigit;
243.824 + if (groupCount() < newRefNum) {
243.825 + done = true;
243.826 + } else {
243.827 + refNum = newRefNum;
243.828 + cursor++;
243.829 + }
243.830 + }
243.831 + }
243.832 + // Append group
243.833 + if (start(refNum) != -1 && end(refNum) != -1)
243.834 + result.append(text, start(refNum), end(refNum));
243.835 + } else {
243.836 + result.append(nextChar);
243.837 + cursor++;
243.838 + }
243.839 + }
243.840 + // Append the intervening text
243.841 + sb.append(text, lastAppendPosition, first);
243.842 + // Append the match substitution
243.843 + sb.append(result);
243.844 +
243.845 + lastAppendPosition = last;
243.846 + return this;
243.847 + }
243.848 +
243.849 + /**
243.850 + * Implements a terminal append-and-replace step.
243.851 + *
243.852 + * <p> This method reads characters from the input sequence, starting at
243.853 + * the append position, and appends them to the given string buffer. It is
243.854 + * intended to be invoked after one or more invocations of the {@link
243.855 + * #appendReplacement appendReplacement} method in order to copy the
243.856 + * remainder of the input sequence. </p>
243.857 + *
243.858 + * @param sb
243.859 + * The target string buffer
243.860 + *
243.861 + * @return The target string buffer
243.862 + */
243.863 + public StringBuffer appendTail(StringBuffer sb) {
243.864 + sb.append(text, lastAppendPosition, getTextLength());
243.865 + return sb;
243.866 + }
243.867 +
243.868 + /**
243.869 + * Replaces every subsequence of the input sequence that matches the
243.870 + * pattern with the given replacement string.
243.871 + *
243.872 + * <p> This method first resets this matcher. It then scans the input
243.873 + * sequence looking for matches of the pattern. Characters that are not
243.874 + * part of any match are appended directly to the result string; each match
243.875 + * is replaced in the result by the replacement string. The replacement
243.876 + * string may contain references to captured subsequences as in the {@link
243.877 + * #appendReplacement appendReplacement} method.
243.878 + *
243.879 + * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
243.880 + * the replacement string may cause the results to be different than if it
243.881 + * were being treated as a literal replacement string. Dollar signs may be
243.882 + * treated as references to captured subsequences as described above, and
243.883 + * backslashes are used to escape literal characters in the replacement
243.884 + * string.
243.885 + *
243.886 + * <p> Given the regular expression <tt>a*b</tt>, the input
243.887 + * <tt>"aabfooaabfooabfoob"</tt>, and the replacement string
243.888 + * <tt>"-"</tt>, an invocation of this method on a matcher for that
243.889 + * expression would yield the string <tt>"-foo-foo-foo-"</tt>.
243.890 + *
243.891 + * <p> Invoking this method changes this matcher's state. If the matcher
243.892 + * is to be used in further matching operations then it should first be
243.893 + * reset. </p>
243.894 + *
243.895 + * @param replacement
243.896 + * The replacement string
243.897 + *
243.898 + * @return The string constructed by replacing each matching subsequence
243.899 + * by the replacement string, substituting captured subsequences
243.900 + * as needed
243.901 + */
243.902 + public String replaceAll(String replacement) {
243.903 + reset();
243.904 + boolean result = find();
243.905 + if (result) {
243.906 + StringBuffer sb = new StringBuffer();
243.907 + do {
243.908 + appendReplacement(sb, replacement);
243.909 + result = find();
243.910 + } while (result);
243.911 + appendTail(sb);
243.912 + return sb.toString();
243.913 + }
243.914 + return text.toString();
243.915 + }
243.916 +
243.917 + /**
243.918 + * Replaces the first subsequence of the input sequence that matches the
243.919 + * pattern with the given replacement string.
243.920 + *
243.921 + * <p> This method first resets this matcher. It then scans the input
243.922 + * sequence looking for a match of the pattern. Characters that are not
243.923 + * part of the match are appended directly to the result string; the match
243.924 + * is replaced in the result by the replacement string. The replacement
243.925 + * string may contain references to captured subsequences as in the {@link
243.926 + * #appendReplacement appendReplacement} method.
243.927 + *
243.928 + * <p>Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
243.929 + * the replacement string may cause the results to be different than if it
243.930 + * were being treated as a literal replacement string. Dollar signs may be
243.931 + * treated as references to captured subsequences as described above, and
243.932 + * backslashes are used to escape literal characters in the replacement
243.933 + * string.
243.934 + *
243.935 + * <p> Given the regular expression <tt>dog</tt>, the input
243.936 + * <tt>"zzzdogzzzdogzzz"</tt>, and the replacement string
243.937 + * <tt>"cat"</tt>, an invocation of this method on a matcher for that
243.938 + * expression would yield the string <tt>"zzzcatzzzdogzzz"</tt>. </p>
243.939 + *
243.940 + * <p> Invoking this method changes this matcher's state. If the matcher
243.941 + * is to be used in further matching operations then it should first be
243.942 + * reset. </p>
243.943 + *
243.944 + * @param replacement
243.945 + * The replacement string
243.946 + * @return The string constructed by replacing the first matching
243.947 + * subsequence by the replacement string, substituting captured
243.948 + * subsequences as needed
243.949 + */
243.950 + public String replaceFirst(String replacement) {
243.951 + if (replacement == null)
243.952 + throw new NullPointerException("replacement");
243.953 + reset();
243.954 + if (!find())
243.955 + return text.toString();
243.956 + StringBuffer sb = new StringBuffer();
243.957 + appendReplacement(sb, replacement);
243.958 + appendTail(sb);
243.959 + return sb.toString();
243.960 + }
243.961 +
243.962 + /**
243.963 + * Sets the limits of this matcher's region. The region is the part of the
243.964 + * input sequence that will be searched to find a match. Invoking this
243.965 + * method resets the matcher, and then sets the region to start at the
243.966 + * index specified by the <code>start</code> parameter and end at the
243.967 + * index specified by the <code>end</code> parameter.
243.968 + *
243.969 + * <p>Depending on the transparency and anchoring being used (see
243.970 + * {@link #useTransparentBounds useTransparentBounds} and
243.971 + * {@link #useAnchoringBounds useAnchoringBounds}), certain constructs such
243.972 + * as anchors may behave differently at or around the boundaries of the
243.973 + * region.
243.974 + *
243.975 + * @param start
243.976 + * The index to start searching at (inclusive)
243.977 + * @param end
243.978 + * The index to end searching at (exclusive)
243.979 + * @throws IndexOutOfBoundsException
243.980 + * If start or end is less than zero, if
243.981 + * start is greater than the length of the input sequence, if
243.982 + * end is greater than the length of the input sequence, or if
243.983 + * start is greater than end.
243.984 + * @return this matcher
243.985 + * @since 1.5
243.986 + */
243.987 + public Matcher region(int start, int end) {
243.988 + if ((start < 0) || (start > getTextLength()))
243.989 + throw new IndexOutOfBoundsException("start");
243.990 + if ((end < 0) || (end > getTextLength()))
243.991 + throw new IndexOutOfBoundsException("end");
243.992 + if (start > end)
243.993 + throw new IndexOutOfBoundsException("start > end");
243.994 + reset();
243.995 + from = start;
243.996 + to = end;
243.997 + return this;
243.998 + }
243.999 +
243.1000 + /**
243.1001 + * Reports the start index of this matcher's region. The
243.1002 + * searches this matcher conducts are limited to finding matches
243.1003 + * within {@link #regionStart regionStart} (inclusive) and
243.1004 + * {@link #regionEnd regionEnd} (exclusive).
243.1005 + *
243.1006 + * @return The starting point of this matcher's region
243.1007 + * @since 1.5
243.1008 + */
243.1009 + public int regionStart() {
243.1010 + return from;
243.1011 + }
243.1012 +
243.1013 + /**
243.1014 + * Reports the end index (exclusive) of this matcher's region.
243.1015 + * The searches this matcher conducts are limited to finding matches
243.1016 + * within {@link #regionStart regionStart} (inclusive) and
243.1017 + * {@link #regionEnd regionEnd} (exclusive).
243.1018 + *
243.1019 + * @return the ending point of this matcher's region
243.1020 + * @since 1.5
243.1021 + */
243.1022 + public int regionEnd() {
243.1023 + return to;
243.1024 + }
243.1025 +
243.1026 + /**
243.1027 + * Queries the transparency of region bounds for this matcher.
243.1028 + *
243.1029 + * <p> This method returns <tt>true</tt> if this matcher uses
243.1030 + * <i>transparent</i> bounds, <tt>false</tt> if it uses <i>opaque</i>
243.1031 + * bounds.
243.1032 + *
243.1033 + * <p> See {@link #useTransparentBounds useTransparentBounds} for a
243.1034 + * description of transparent and opaque bounds.
243.1035 + *
243.1036 + * <p> By default, a matcher uses opaque region boundaries.
243.1037 + *
243.1038 + * @return <tt>true</tt> iff this matcher is using transparent bounds,
243.1039 + * <tt>false</tt> otherwise.
243.1040 + * @see java.util.regex.Matcher#useTransparentBounds(boolean)
243.1041 + * @since 1.5
243.1042 + */
243.1043 + public boolean hasTransparentBounds() {
243.1044 + return transparentBounds;
243.1045 + }
243.1046 +
243.1047 + /**
243.1048 + * Sets the transparency of region bounds for this matcher.
243.1049 + *
243.1050 + * <p> Invoking this method with an argument of <tt>true</tt> will set this
243.1051 + * matcher to use <i>transparent</i> bounds. If the boolean
243.1052 + * argument is <tt>false</tt>, then <i>opaque</i> bounds will be used.
243.1053 + *
243.1054 + * <p> Using transparent bounds, the boundaries of this
243.1055 + * matcher's region are transparent to lookahead, lookbehind,
243.1056 + * and boundary matching constructs. Those constructs can see beyond the
243.1057 + * boundaries of the region to see if a match is appropriate.
243.1058 + *
243.1059 + * <p> Using opaque bounds, the boundaries of this matcher's
243.1060 + * region are opaque to lookahead, lookbehind, and boundary matching
243.1061 + * constructs that may try to see beyond them. Those constructs cannot
243.1062 + * look past the boundaries so they will fail to match anything outside
243.1063 + * of the region.
243.1064 + *
243.1065 + * <p> By default, a matcher uses opaque bounds.
243.1066 + *
243.1067 + * @param b a boolean indicating whether to use opaque or transparent
243.1068 + * regions
243.1069 + * @return this matcher
243.1070 + * @see java.util.regex.Matcher#hasTransparentBounds
243.1071 + * @since 1.5
243.1072 + */
243.1073 + public Matcher useTransparentBounds(boolean b) {
243.1074 + transparentBounds = b;
243.1075 + return this;
243.1076 + }
243.1077 +
243.1078 + /**
243.1079 + * Queries the anchoring of region bounds for this matcher.
243.1080 + *
243.1081 + * <p> This method returns <tt>true</tt> if this matcher uses
243.1082 + * <i>anchoring</i> bounds, <tt>false</tt> otherwise.
243.1083 + *
243.1084 + * <p> See {@link #useAnchoringBounds useAnchoringBounds} for a
243.1085 + * description of anchoring bounds.
243.1086 + *
243.1087 + * <p> By default, a matcher uses anchoring region boundaries.
243.1088 + *
243.1089 + * @return <tt>true</tt> iff this matcher is using anchoring bounds,
243.1090 + * <tt>false</tt> otherwise.
243.1091 + * @see java.util.regex.Matcher#useAnchoringBounds(boolean)
243.1092 + * @since 1.5
243.1093 + */
243.1094 + public boolean hasAnchoringBounds() {
243.1095 + return anchoringBounds;
243.1096 + }
243.1097 +
243.1098 + /**
243.1099 + * Sets the anchoring of region bounds for this matcher.
243.1100 + *
243.1101 + * <p> Invoking this method with an argument of <tt>true</tt> will set this
243.1102 + * matcher to use <i>anchoring</i> bounds. If the boolean
243.1103 + * argument is <tt>false</tt>, then <i>non-anchoring</i> bounds will be
243.1104 + * used.
243.1105 + *
243.1106 + * <p> Using anchoring bounds, the boundaries of this
243.1107 + * matcher's region match anchors such as ^ and $.
243.1108 + *
243.1109 + * <p> Without anchoring bounds, the boundaries of this
243.1110 + * matcher's region will not match anchors such as ^ and $.
243.1111 + *
243.1112 + * <p> By default, a matcher uses anchoring region boundaries.
243.1113 + *
243.1114 + * @param b a boolean indicating whether or not to use anchoring bounds.
243.1115 + * @return this matcher
243.1116 + * @see java.util.regex.Matcher#hasAnchoringBounds
243.1117 + * @since 1.5
243.1118 + */
243.1119 + public Matcher useAnchoringBounds(boolean b) {
243.1120 + anchoringBounds = b;
243.1121 + return this;
243.1122 + }
243.1123 +
243.1124 + /**
243.1125 + * <p>Returns the string representation of this matcher. The
243.1126 + * string representation of a <code>Matcher</code> contains information
243.1127 + * that may be useful for debugging. The exact format is unspecified.
243.1128 + *
243.1129 + * @return The string representation of this matcher
243.1130 + * @since 1.5
243.1131 + */
243.1132 + public String toString() {
243.1133 + StringBuilder sb = new StringBuilder();
243.1134 + sb.append("java.util.regex.Matcher");
243.1135 + sb.append("[pattern=" + pattern());
243.1136 + sb.append(" region=");
243.1137 + sb.append(regionStart() + "," + regionEnd());
243.1138 + sb.append(" lastmatch=");
243.1139 + if ((first >= 0) && (group() != null)) {
243.1140 + sb.append(group());
243.1141 + }
243.1142 + sb.append("]");
243.1143 + return sb.toString();
243.1144 + }
243.1145 +
243.1146 + /**
243.1147 + * <p>Returns true if the end of input was hit by the search engine in
243.1148 + * the last match operation performed by this matcher.
243.1149 + *
243.1150 + * <p>When this method returns true, then it is possible that more input
243.1151 + * would have changed the result of the last search.
243.1152 + *
243.1153 + * @return true iff the end of input was hit in the last match; false
243.1154 + * otherwise
243.1155 + * @since 1.5
243.1156 + */
243.1157 + public boolean hitEnd() {
243.1158 + return hitEnd;
243.1159 + }
243.1160 +
243.1161 + /**
243.1162 + * <p>Returns true if more input could change a positive match into a
243.1163 + * negative one.
243.1164 + *
243.1165 + * <p>If this method returns true, and a match was found, then more
243.1166 + * input could cause the match to be lost. If this method returns false
243.1167 + * and a match was found, then more input might change the match but the
243.1168 + * match won't be lost. If a match was not found, then requireEnd has no
243.1169 + * meaning.
243.1170 + *
243.1171 + * @return true iff more input could change a positive match into a
243.1172 + * negative one.
243.1173 + * @since 1.5
243.1174 + */
243.1175 + public boolean requireEnd() {
243.1176 + return requireEnd;
243.1177 + }
243.1178 +
243.1179 + /**
243.1180 + * Initiates a search to find a Pattern within the given bounds.
243.1181 + * The groups are filled with default values and the match of the root
243.1182 + * of the state machine is called. The state machine will hold the state
243.1183 + * of the match as it proceeds in this matcher.
243.1184 + *
243.1185 + * Matcher.from is not set here, because it is the "hard" boundary
243.1186 + * of the start of the search which anchors will set to. The from param
243.1187 + * is the "soft" boundary of the start of the search, meaning that the
243.1188 + * regex tries to match at that index but ^ won't match there. Subsequent
243.1189 + * calls to the search methods start at a new "soft" boundary which is
243.1190 + * the end of the previous match.
243.1191 + */
243.1192 + boolean search(int from) {
243.1193 + this.hitEnd = false;
243.1194 + this.requireEnd = false;
243.1195 + from = from < 0 ? 0 : from;
243.1196 + this.first = from;
243.1197 + this.oldLast = oldLast < 0 ? from : oldLast;
243.1198 + for (int i = 0; i < groups.length; i++)
243.1199 + groups[i] = -1;
243.1200 + acceptMode = NOANCHOR;
243.1201 + boolean result = parentPattern.root.match(this, from, text);
243.1202 + if (!result)
243.1203 + this.first = -1;
243.1204 + this.oldLast = this.last;
243.1205 + return result;
243.1206 + }
243.1207 +
243.1208 + /**
243.1209 + * Initiates a search for an anchored match to a Pattern within the given
243.1210 + * bounds. The groups are filled with default values and the match of the
243.1211 + * root of the state machine is called. The state machine will hold the
243.1212 + * state of the match as it proceeds in this matcher.
243.1213 + */
243.1214 + boolean match(int from, int anchor) {
243.1215 + this.hitEnd = false;
243.1216 + this.requireEnd = false;
243.1217 + from = from < 0 ? 0 : from;
243.1218 + this.first = from;
243.1219 + this.oldLast = oldLast < 0 ? from : oldLast;
243.1220 + for (int i = 0; i < groups.length; i++)
243.1221 + groups[i] = -1;
243.1222 + acceptMode = anchor;
243.1223 + boolean result = parentPattern.matchRoot.match(this, from, text);
243.1224 + if (!result)
243.1225 + this.first = -1;
243.1226 + this.oldLast = this.last;
243.1227 + return result;
243.1228 + }
243.1229 +
243.1230 + /**
243.1231 + * Returns the end index of the text.
243.1232 + *
243.1233 + * @return the index after the last character in the text
243.1234 + */
243.1235 + int getTextLength() {
243.1236 + return text.length();
243.1237 + }
243.1238 +
243.1239 + /**
243.1240 + * Generates a String from this Matcher's input in the specified range.
243.1241 + *
243.1242 + * @param beginIndex the beginning index, inclusive
243.1243 + * @param endIndex the ending index, exclusive
243.1244 + * @return A String generated from this Matcher's input
243.1245 + */
243.1246 + CharSequence getSubSequence(int beginIndex, int endIndex) {
243.1247 + return text.subSequence(beginIndex, endIndex);
243.1248 + }
243.1249 +
243.1250 + /**
243.1251 + * Returns this Matcher's input character at index i.
243.1252 + *
243.1253 + * @return A char from the specified index
243.1254 + */
243.1255 + char charAt(int i) {
243.1256 + return text.charAt(i);
243.1257 + }
243.1258 +
243.1259 +}
244.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
244.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/Pattern.java Wed Apr 30 15:04:10 2014 +0200
244.3 @@ -0,0 +1,5657 @@
244.4 +/*
244.5 + * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
244.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
244.7 + *
244.8 + * This code is free software; you can redistribute it and/or modify it
244.9 + * under the terms of the GNU General Public License version 2 only, as
244.10 + * published by the Free Software Foundation. Oracle designates this
244.11 + * particular file as subject to the "Classpath" exception as provided
244.12 + * by Oracle in the LICENSE file that accompanied this code.
244.13 + *
244.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
244.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
244.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
244.17 + * version 2 for more details (a copy is included in the LICENSE file that
244.18 + * accompanied this code).
244.19 + *
244.20 + * You should have received a copy of the GNU General Public License version
244.21 + * 2 along with this work; if not, write to the Free Software Foundation,
244.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
244.23 + *
244.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
244.25 + * or visit www.oracle.com if you need additional information or have any
244.26 + * questions.
244.27 + */
244.28 +
244.29 +package java.util.regex;
244.30 +
244.31 +import java.util.Locale;
244.32 +import java.util.Map;
244.33 +import java.util.ArrayList;
244.34 +import java.util.HashMap;
244.35 +import java.util.Arrays;
244.36 +
244.37 +
244.38 +/**
244.39 + * A compiled representation of a regular expression.
244.40 + *
244.41 + * <p> A regular expression, specified as a string, must first be compiled into
244.42 + * an instance of this class. The resulting pattern can then be used to create
244.43 + * a {@link Matcher} object that can match arbitrary {@link
244.44 + * java.lang.CharSequence </code>character sequences<code>} against the regular
244.45 + * expression. All of the state involved in performing a match resides in the
244.46 + * matcher, so many matchers can share the same pattern.
244.47 + *
244.48 + * <p> A typical invocation sequence is thus
244.49 + *
244.50 + * <blockquote><pre>
244.51 + * Pattern p = Pattern.{@link #compile compile}("a*b");
244.52 + * Matcher m = p.{@link #matcher matcher}("aaaaab");
244.53 + * boolean b = m.{@link Matcher#matches matches}();</pre></blockquote>
244.54 + *
244.55 + * <p> A {@link #matches matches} method is defined by this class as a
244.56 + * convenience for when a regular expression is used just once. This method
244.57 + * compiles an expression and matches an input sequence against it in a single
244.58 + * invocation. The statement
244.59 + *
244.60 + * <blockquote><pre>
244.61 + * boolean b = Pattern.matches("a*b", "aaaaab");</pre></blockquote>
244.62 + *
244.63 + * is equivalent to the three statements above, though for repeated matches it
244.64 + * is less efficient since it does not allow the compiled pattern to be reused.
244.65 + *
244.66 + * <p> Instances of this class are immutable and are safe for use by multiple
244.67 + * concurrent threads. Instances of the {@link Matcher} class are not safe for
244.68 + * such use.
244.69 + *
244.70 + *
244.71 + * <a name="sum">
244.72 + * <h4> Summary of regular-expression constructs </h4>
244.73 + *
244.74 + * <table border="0" cellpadding="1" cellspacing="0"
244.75 + * summary="Regular expression constructs, and what they match">
244.76 + *
244.77 + * <tr align="left">
244.78 + * <th bgcolor="#CCCCFF" align="left" id="construct">Construct</th>
244.79 + * <th bgcolor="#CCCCFF" align="left" id="matches">Matches</th>
244.80 + * </tr>
244.81 + *
244.82 + * <tr><th> </th></tr>
244.83 + * <tr align="left"><th colspan="2" id="characters">Characters</th></tr>
244.84 + *
244.85 + * <tr><td valign="top" headers="construct characters"><i>x</i></td>
244.86 + * <td headers="matches">The character <i>x</i></td></tr>
244.87 + * <tr><td valign="top" headers="construct characters"><tt>\\</tt></td>
244.88 + * <td headers="matches">The backslash character</td></tr>
244.89 + * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>n</i></td>
244.90 + * <td headers="matches">The character with octal value <tt>0</tt><i>n</i>
244.91 + * (0 <tt><=</tt> <i>n</i> <tt><=</tt> 7)</td></tr>
244.92 + * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>nn</i></td>
244.93 + * <td headers="matches">The character with octal value <tt>0</tt><i>nn</i>
244.94 + * (0 <tt><=</tt> <i>n</i> <tt><=</tt> 7)</td></tr>
244.95 + * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>mnn</i></td>
244.96 + * <td headers="matches">The character with octal value <tt>0</tt><i>mnn</i>
244.97 + * (0 <tt><=</tt> <i>m</i> <tt><=</tt> 3,
244.98 + * 0 <tt><=</tt> <i>n</i> <tt><=</tt> 7)</td></tr>
244.99 + * <tr><td valign="top" headers="construct characters"><tt>\x</tt><i>hh</i></td>
244.100 + * <td headers="matches">The character with hexadecimal value <tt>0x</tt><i>hh</i></td></tr>
244.101 + * <tr><td valign="top" headers="construct characters"><tt>\u</tt><i>hhhh</i></td>
244.102 + * <td headers="matches">The character with hexadecimal value <tt>0x</tt><i>hhhh</i></td></tr>
244.103 + * <tr><td valign="top" headers="construct characters"><tt>\x</tt><i>{h...h}</i></td>
244.104 + * <td headers="matches">The character with hexadecimal value <tt>0x</tt><i>h...h</i>
244.105 + * ({@link java.lang.Character#MIN_CODE_POINT Character.MIN_CODE_POINT}
244.106 + * <= <tt>0x</tt><i>h...h</i> <= 
244.107 + * {@link java.lang.Character#MAX_CODE_POINT Character.MAX_CODE_POINT})</td></tr>
244.108 + * <tr><td valign="top" headers="matches"><tt>\t</tt></td>
244.109 + * <td headers="matches">The tab character (<tt>'\u0009'</tt>)</td></tr>
244.110 + * <tr><td valign="top" headers="construct characters"><tt>\n</tt></td>
244.111 + * <td headers="matches">The newline (line feed) character (<tt>'\u000A'</tt>)</td></tr>
244.112 + * <tr><td valign="top" headers="construct characters"><tt>\r</tt></td>
244.113 + * <td headers="matches">The carriage-return character (<tt>'\u000D'</tt>)</td></tr>
244.114 + * <tr><td valign="top" headers="construct characters"><tt>\f</tt></td>
244.115 + * <td headers="matches">The form-feed character (<tt>'\u000C'</tt>)</td></tr>
244.116 + * <tr><td valign="top" headers="construct characters"><tt>\a</tt></td>
244.117 + * <td headers="matches">The alert (bell) character (<tt>'\u0007'</tt>)</td></tr>
244.118 + * <tr><td valign="top" headers="construct characters"><tt>\e</tt></td>
244.119 + * <td headers="matches">The escape character (<tt>'\u001B'</tt>)</td></tr>
244.120 + * <tr><td valign="top" headers="construct characters"><tt>\c</tt><i>x</i></td>
244.121 + * <td headers="matches">The control character corresponding to <i>x</i></td></tr>
244.122 + *
244.123 + * <tr><th> </th></tr>
244.124 + * <tr align="left"><th colspan="2" id="classes">Character classes</th></tr>
244.125 + *
244.126 + * <tr><td valign="top" headers="construct classes"><tt>[abc]</tt></td>
244.127 + * <td headers="matches"><tt>a</tt>, <tt>b</tt>, or <tt>c</tt> (simple class)</td></tr>
244.128 + * <tr><td valign="top" headers="construct classes"><tt>[^abc]</tt></td>
244.129 + * <td headers="matches">Any character except <tt>a</tt>, <tt>b</tt>, or <tt>c</tt> (negation)</td></tr>
244.130 + * <tr><td valign="top" headers="construct classes"><tt>[a-zA-Z]</tt></td>
244.131 + * <td headers="matches"><tt>a</tt> through <tt>z</tt>
244.132 + * or <tt>A</tt> through <tt>Z</tt>, inclusive (range)</td></tr>
244.133 + * <tr><td valign="top" headers="construct classes"><tt>[a-d[m-p]]</tt></td>
244.134 + * <td headers="matches"><tt>a</tt> through <tt>d</tt>,
244.135 + * or <tt>m</tt> through <tt>p</tt>: <tt>[a-dm-p]</tt> (union)</td></tr>
244.136 + * <tr><td valign="top" headers="construct classes"><tt>[a-z&&[def]]</tt></td>
244.137 + * <td headers="matches"><tt>d</tt>, <tt>e</tt>, or <tt>f</tt> (intersection)</tr>
244.138 + * <tr><td valign="top" headers="construct classes"><tt>[a-z&&[^bc]]</tt></td>
244.139 + * <td headers="matches"><tt>a</tt> through <tt>z</tt>,
244.140 + * except for <tt>b</tt> and <tt>c</tt>: <tt>[ad-z]</tt> (subtraction)</td></tr>
244.141 + * <tr><td valign="top" headers="construct classes"><tt>[a-z&&[^m-p]]</tt></td>
244.142 + * <td headers="matches"><tt>a</tt> through <tt>z</tt>,
244.143 + * and not <tt>m</tt> through <tt>p</tt>: <tt>[a-lq-z]</tt>(subtraction)</td></tr>
244.144 + * <tr><th> </th></tr>
244.145 + *
244.146 + * <tr align="left"><th colspan="2" id="predef">Predefined character classes</th></tr>
244.147 + *
244.148 + * <tr><td valign="top" headers="construct predef"><tt>.</tt></td>
244.149 + * <td headers="matches">Any character (may or may not match <a href="#lt">line terminators</a>)</td></tr>
244.150 + * <tr><td valign="top" headers="construct predef"><tt>\d</tt></td>
244.151 + * <td headers="matches">A digit: <tt>[0-9]</tt></td></tr>
244.152 + * <tr><td valign="top" headers="construct predef"><tt>\D</tt></td>
244.153 + * <td headers="matches">A non-digit: <tt>[^0-9]</tt></td></tr>
244.154 + * <tr><td valign="top" headers="construct predef"><tt>\s</tt></td>
244.155 + * <td headers="matches">A whitespace character: <tt>[ \t\n\x0B\f\r]</tt></td></tr>
244.156 + * <tr><td valign="top" headers="construct predef"><tt>\S</tt></td>
244.157 + * <td headers="matches">A non-whitespace character: <tt>[^\s]</tt></td></tr>
244.158 + * <tr><td valign="top" headers="construct predef"><tt>\w</tt></td>
244.159 + * <td headers="matches">A word character: <tt>[a-zA-Z_0-9]</tt></td></tr>
244.160 + * <tr><td valign="top" headers="construct predef"><tt>\W</tt></td>
244.161 + * <td headers="matches">A non-word character: <tt>[^\w]</tt></td></tr>
244.162 + *
244.163 + * <tr><th> </th></tr>
244.164 + * <tr align="left"><th colspan="2" id="posix">POSIX character classes</b> (US-ASCII only)<b></th></tr>
244.165 + *
244.166 + * <tr><td valign="top" headers="construct posix"><tt>\p{Lower}</tt></td>
244.167 + * <td headers="matches">A lower-case alphabetic character: <tt>[a-z]</tt></td></tr>
244.168 + * <tr><td valign="top" headers="construct posix"><tt>\p{Upper}</tt></td>
244.169 + * <td headers="matches">An upper-case alphabetic character:<tt>[A-Z]</tt></td></tr>
244.170 + * <tr><td valign="top" headers="construct posix"><tt>\p{ASCII}</tt></td>
244.171 + * <td headers="matches">All ASCII:<tt>[\x00-\x7F]</tt></td></tr>
244.172 + * <tr><td valign="top" headers="construct posix"><tt>\p{Alpha}</tt></td>
244.173 + * <td headers="matches">An alphabetic character:<tt>[\p{Lower}\p{Upper}]</tt></td></tr>
244.174 + * <tr><td valign="top" headers="construct posix"><tt>\p{Digit}</tt></td>
244.175 + * <td headers="matches">A decimal digit: <tt>[0-9]</tt></td></tr>
244.176 + * <tr><td valign="top" headers="construct posix"><tt>\p{Alnum}</tt></td>
244.177 + * <td headers="matches">An alphanumeric character:<tt>[\p{Alpha}\p{Digit}]</tt></td></tr>
244.178 + * <tr><td valign="top" headers="construct posix"><tt>\p{Punct}</tt></td>
244.179 + * <td headers="matches">Punctuation: One of <tt>!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~</tt></td></tr>
244.180 + * <!-- <tt>[\!"#\$%&'\(\)\*\+,\-\./:;\<=\>\?@\[\\\]\^_`\{\|\}~]</tt>
244.181 + * <tt>[\X21-\X2F\X31-\X40\X5B-\X60\X7B-\X7E]</tt> -->
244.182 + * <tr><td valign="top" headers="construct posix"><tt>\p{Graph}</tt></td>
244.183 + * <td headers="matches">A visible character: <tt>[\p{Alnum}\p{Punct}]</tt></td></tr>
244.184 + * <tr><td valign="top" headers="construct posix"><tt>\p{Print}</tt></td>
244.185 + * <td headers="matches">A printable character: <tt>[\p{Graph}\x20]</tt></td></tr>
244.186 + * <tr><td valign="top" headers="construct posix"><tt>\p{Blank}</tt></td>
244.187 + * <td headers="matches">A space or a tab: <tt>[ \t]</tt></td></tr>
244.188 + * <tr><td valign="top" headers="construct posix"><tt>\p{Cntrl}</tt></td>
244.189 + * <td headers="matches">A control character: <tt>[\x00-\x1F\x7F]</tt></td></tr>
244.190 + * <tr><td valign="top" headers="construct posix"><tt>\p{XDigit}</tt></td>
244.191 + * <td headers="matches">A hexadecimal digit: <tt>[0-9a-fA-F]</tt></td></tr>
244.192 + * <tr><td valign="top" headers="construct posix"><tt>\p{Space}</tt></td>
244.193 + * <td headers="matches">A whitespace character: <tt>[ \t\n\x0B\f\r]</tt></td></tr>
244.194 + *
244.195 + * <tr><th> </th></tr>
244.196 + * <tr align="left"><th colspan="2">java.lang.Character classes (simple <a href="#jcc">java character type</a>)</th></tr>
244.197 + *
244.198 + * <tr><td valign="top"><tt>\p{javaLowerCase}</tt></td>
244.199 + * <td>Equivalent to java.lang.Character.isLowerCase()</td></tr>
244.200 + * <tr><td valign="top"><tt>\p{javaUpperCase}</tt></td>
244.201 + * <td>Equivalent to java.lang.Character.isUpperCase()</td></tr>
244.202 + * <tr><td valign="top"><tt>\p{javaWhitespace}</tt></td>
244.203 + * <td>Equivalent to java.lang.Character.isWhitespace()</td></tr>
244.204 + * <tr><td valign="top"><tt>\p{javaMirrored}</tt></td>
244.205 + * <td>Equivalent to java.lang.Character.isMirrored()</td></tr>
244.206 + *
244.207 + * <tr><th> </th></tr>
244.208 + * <tr align="left"><th colspan="2" id="unicode">Classes for Unicode scripts, blocks, categories and binary properties</th></tr>
244.209 + * * <tr><td valign="top" headers="construct unicode"><tt>\p{IsLatin}</tt></td>
244.210 + * <td headers="matches">A Latin script character (<a href="#usc">script</a>)</td></tr>
244.211 + * <tr><td valign="top" headers="construct unicode"><tt>\p{InGreek}</tt></td>
244.212 + * <td headers="matches">A character in the Greek block (<a href="#ubc">block</a>)</td></tr>
244.213 + * <tr><td valign="top" headers="construct unicode"><tt>\p{Lu}</tt></td>
244.214 + * <td headers="matches">An uppercase letter (<a href="#ucc">category</a>)</td></tr>
244.215 + * <tr><td valign="top" headers="construct unicode"><tt>\p{IsAlphabetic}</tt></td>
244.216 + * <td headers="matches">An alphabetic character (<a href="#ubpc">binary property</a>)</td></tr>
244.217 + * <tr><td valign="top" headers="construct unicode"><tt>\p{Sc}</tt></td>
244.218 + * <td headers="matches">A currency symbol</td></tr>
244.219 + * <tr><td valign="top" headers="construct unicode"><tt>\P{InGreek}</tt></td>
244.220 + * <td headers="matches">Any character except one in the Greek block (negation)</td></tr>
244.221 + * <tr><td valign="top" headers="construct unicode"><tt>[\p{L}&&[^\p{Lu}]] </tt></td>
244.222 + * <td headers="matches">Any letter except an uppercase letter (subtraction)</td></tr>
244.223 + *
244.224 + * <tr><th> </th></tr>
244.225 + * <tr align="left"><th colspan="2" id="bounds">Boundary matchers</th></tr>
244.226 + *
244.227 + * <tr><td valign="top" headers="construct bounds"><tt>^</tt></td>
244.228 + * <td headers="matches">The beginning of a line</td></tr>
244.229 + * <tr><td valign="top" headers="construct bounds"><tt>$</tt></td>
244.230 + * <td headers="matches">The end of a line</td></tr>
244.231 + * <tr><td valign="top" headers="construct bounds"><tt>\b</tt></td>
244.232 + * <td headers="matches">A word boundary</td></tr>
244.233 + * <tr><td valign="top" headers="construct bounds"><tt>\B</tt></td>
244.234 + * <td headers="matches">A non-word boundary</td></tr>
244.235 + * <tr><td valign="top" headers="construct bounds"><tt>\A</tt></td>
244.236 + * <td headers="matches">The beginning of the input</td></tr>
244.237 + * <tr><td valign="top" headers="construct bounds"><tt>\G</tt></td>
244.238 + * <td headers="matches">The end of the previous match</td></tr>
244.239 + * <tr><td valign="top" headers="construct bounds"><tt>\Z</tt></td>
244.240 + * <td headers="matches">The end of the input but for the final
244.241 + * <a href="#lt">terminator</a>, if any</td></tr>
244.242 + * <tr><td valign="top" headers="construct bounds"><tt>\z</tt></td>
244.243 + * <td headers="matches">The end of the input</td></tr>
244.244 + *
244.245 + * <tr><th> </th></tr>
244.246 + * <tr align="left"><th colspan="2" id="greedy">Greedy quantifiers</th></tr>
244.247 + *
244.248 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>?</tt></td>
244.249 + * <td headers="matches"><i>X</i>, once or not at all</td></tr>
244.250 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>*</tt></td>
244.251 + * <td headers="matches"><i>X</i>, zero or more times</td></tr>
244.252 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>+</tt></td>
244.253 + * <td headers="matches"><i>X</i>, one or more times</td></tr>
244.254 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>}</tt></td>
244.255 + * <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
244.256 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>,}</tt></td>
244.257 + * <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
244.258 + * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}</tt></td>
244.259 + * <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
244.260 + *
244.261 + * <tr><th> </th></tr>
244.262 + * <tr align="left"><th colspan="2" id="reluc">Reluctant quantifiers</th></tr>
244.263 + *
244.264 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>??</tt></td>
244.265 + * <td headers="matches"><i>X</i>, once or not at all</td></tr>
244.266 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>*?</tt></td>
244.267 + * <td headers="matches"><i>X</i>, zero or more times</td></tr>
244.268 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>+?</tt></td>
244.269 + * <td headers="matches"><i>X</i>, one or more times</td></tr>
244.270 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>}?</tt></td>
244.271 + * <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
244.272 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>,}?</tt></td>
244.273 + * <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
244.274 + * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}?</tt></td>
244.275 + * <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
244.276 + *
244.277 + * <tr><th> </th></tr>
244.278 + * <tr align="left"><th colspan="2" id="poss">Possessive quantifiers</th></tr>
244.279 + *
244.280 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>?+</tt></td>
244.281 + * <td headers="matches"><i>X</i>, once or not at all</td></tr>
244.282 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>*+</tt></td>
244.283 + * <td headers="matches"><i>X</i>, zero or more times</td></tr>
244.284 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>++</tt></td>
244.285 + * <td headers="matches"><i>X</i>, one or more times</td></tr>
244.286 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>}+</tt></td>
244.287 + * <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
244.288 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>,}+</tt></td>
244.289 + * <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
244.290 + * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}+</tt></td>
244.291 + * <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
244.292 + *
244.293 + * <tr><th> </th></tr>
244.294 + * <tr align="left"><th colspan="2" id="logical">Logical operators</th></tr>
244.295 + *
244.296 + * <tr><td valign="top" headers="construct logical"><i>XY</i></td>
244.297 + * <td headers="matches"><i>X</i> followed by <i>Y</i></td></tr>
244.298 + * <tr><td valign="top" headers="construct logical"><i>X</i><tt>|</tt><i>Y</i></td>
244.299 + * <td headers="matches">Either <i>X</i> or <i>Y</i></td></tr>
244.300 + * <tr><td valign="top" headers="construct logical"><tt>(</tt><i>X</i><tt>)</tt></td>
244.301 + * <td headers="matches">X, as a <a href="#cg">capturing group</a></td></tr>
244.302 + *
244.303 + * <tr><th> </th></tr>
244.304 + * <tr align="left"><th colspan="2" id="backref">Back references</th></tr>
244.305 + *
244.306 + * <tr><td valign="bottom" headers="construct backref"><tt>\</tt><i>n</i></td>
244.307 + * <td valign="bottom" headers="matches">Whatever the <i>n</i><sup>th</sup>
244.308 + * <a href="#cg">capturing group</a> matched</td></tr>
244.309 + *
244.310 + * <tr><td valign="bottom" headers="construct backref"><tt>\</tt><i>k</i><<i>name</i>></td>
244.311 + * <td valign="bottom" headers="matches">Whatever the
244.312 + * <a href="#groupname">named-capturing group</a> "name" matched</td></tr>
244.313 + *
244.314 + * <tr><th> </th></tr>
244.315 + * <tr align="left"><th colspan="2" id="quot">Quotation</th></tr>
244.316 + *
244.317 + * <tr><td valign="top" headers="construct quot"><tt>\</tt></td>
244.318 + * <td headers="matches">Nothing, but quotes the following character</td></tr>
244.319 + * <tr><td valign="top" headers="construct quot"><tt>\Q</tt></td>
244.320 + * <td headers="matches">Nothing, but quotes all characters until <tt>\E</tt></td></tr>
244.321 + * <tr><td valign="top" headers="construct quot"><tt>\E</tt></td>
244.322 + * <td headers="matches">Nothing, but ends quoting started by <tt>\Q</tt></td></tr>
244.323 + * <!-- Metachars: !$()*+.<>?[\]^{|} -->
244.324 + *
244.325 + * <tr><th> </th></tr>
244.326 + * <tr align="left"><th colspan="2" id="special">Special constructs (named-capturing and non-capturing)</th></tr>
244.327 + *
244.328 + * <tr><td valign="top" headers="construct special"><tt>(?<<a href="#groupname">name</a>></tt><i>X</i><tt>)</tt></td>
244.329 + * <td headers="matches"><i>X</i>, as a named-capturing group</td></tr>
244.330 + * <tr><td valign="top" headers="construct special"><tt>(?:</tt><i>X</i><tt>)</tt></td>
244.331 + * <td headers="matches"><i>X</i>, as a non-capturing group</td></tr>
244.332 + * <tr><td valign="top" headers="construct special"><tt>(?idmsuxU-idmsuxU) </tt></td>
244.333 + * <td headers="matches">Nothing, but turns match flags <a href="#CASE_INSENSITIVE">i</a>
244.334 + * <a href="#UNIX_LINES">d</a> <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a>
244.335 + * <a href="#UNICODE_CASE">u</a> <a href="#COMMENTS">x</a> <a href="#UNICODE_CHARACTER_CLASS">U</a>
244.336 + * on - off</td></tr>
244.337 + * <tr><td valign="top" headers="construct special"><tt>(?idmsux-idmsux:</tt><i>X</i><tt>)</tt> </td>
244.338 + * <td headers="matches"><i>X</i>, as a <a href="#cg">non-capturing group</a> with the
244.339 + * given flags <a href="#CASE_INSENSITIVE">i</a> <a href="#UNIX_LINES">d</a>
244.340 + * <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a> <a href="#UNICODE_CASE">u</a >
244.341 + * <a href="#COMMENTS">x</a> on - off</td></tr>
244.342 + * <tr><td valign="top" headers="construct special"><tt>(?=</tt><i>X</i><tt>)</tt></td>
244.343 + * <td headers="matches"><i>X</i>, via zero-width positive lookahead</td></tr>
244.344 + * <tr><td valign="top" headers="construct special"><tt>(?!</tt><i>X</i><tt>)</tt></td>
244.345 + * <td headers="matches"><i>X</i>, via zero-width negative lookahead</td></tr>
244.346 + * <tr><td valign="top" headers="construct special"><tt>(?<=</tt><i>X</i><tt>)</tt></td>
244.347 + * <td headers="matches"><i>X</i>, via zero-width positive lookbehind</td></tr>
244.348 + * <tr><td valign="top" headers="construct special"><tt>(?<!</tt><i>X</i><tt>)</tt></td>
244.349 + * <td headers="matches"><i>X</i>, via zero-width negative lookbehind</td></tr>
244.350 + * <tr><td valign="top" headers="construct special"><tt>(?></tt><i>X</i><tt>)</tt></td>
244.351 + * <td headers="matches"><i>X</i>, as an independent, non-capturing group</td></tr>
244.352 + *
244.353 + * </table>
244.354 + *
244.355 + * <hr>
244.356 + *
244.357 + *
244.358 + * <a name="bs">
244.359 + * <h4> Backslashes, escapes, and quoting </h4>
244.360 + *
244.361 + * <p> The backslash character (<tt>'\'</tt>) serves to introduce escaped
244.362 + * constructs, as defined in the table above, as well as to quote characters
244.363 + * that otherwise would be interpreted as unescaped constructs. Thus the
244.364 + * expression <tt>\\</tt> matches a single backslash and <tt>\{</tt> matches a
244.365 + * left brace.
244.366 + *
244.367 + * <p> It is an error to use a backslash prior to any alphabetic character that
244.368 + * does not denote an escaped construct; these are reserved for future
244.369 + * extensions to the regular-expression language. A backslash may be used
244.370 + * prior to a non-alphabetic character regardless of whether that character is
244.371 + * part of an unescaped construct.
244.372 + *
244.373 + * <p> Backslashes within string literals in Java source code are interpreted
244.374 + * as required by
244.375 + * <cite>The Java™ Language Specification</cite>
244.376 + * as either Unicode escapes (section 3.3) or other character escapes (section 3.10.6)
244.377 + * It is therefore necessary to double backslashes in string
244.378 + * literals that represent regular expressions to protect them from
244.379 + * interpretation by the Java bytecode compiler. The string literal
244.380 + * <tt>"\b"</tt>, for example, matches a single backspace character when
244.381 + * interpreted as a regular expression, while <tt>"\\b"</tt> matches a
244.382 + * word boundary. The string literal <tt>"\(hello\)"</tt> is illegal
244.383 + * and leads to a compile-time error; in order to match the string
244.384 + * <tt>(hello)</tt> the string literal <tt>"\\(hello\\)"</tt>
244.385 + * must be used.
244.386 + *
244.387 + * <a name="cc">
244.388 + * <h4> Character Classes </h4>
244.389 + *
244.390 + * <p> Character classes may appear within other character classes, and
244.391 + * may be composed by the union operator (implicit) and the intersection
244.392 + * operator (<tt>&&</tt>).
244.393 + * The union operator denotes a class that contains every character that is
244.394 + * in at least one of its operand classes. The intersection operator
244.395 + * denotes a class that contains every character that is in both of its
244.396 + * operand classes.
244.397 + *
244.398 + * <p> The precedence of character-class operators is as follows, from
244.399 + * highest to lowest:
244.400 + *
244.401 + * <blockquote><table border="0" cellpadding="1" cellspacing="0"
244.402 + * summary="Precedence of character class operators.">
244.403 + * <tr><th>1 </th>
244.404 + * <td>Literal escape </td>
244.405 + * <td><tt>\x</tt></td></tr>
244.406 + * <tr><th>2 </th>
244.407 + * <td>Grouping</td>
244.408 + * <td><tt>[...]</tt></td></tr>
244.409 + * <tr><th>3 </th>
244.410 + * <td>Range</td>
244.411 + * <td><tt>a-z</tt></td></tr>
244.412 + * <tr><th>4 </th>
244.413 + * <td>Union</td>
244.414 + * <td><tt>[a-e][i-u]</tt></td></tr>
244.415 + * <tr><th>5 </th>
244.416 + * <td>Intersection</td>
244.417 + * <td><tt>[a-z&&[aeiou]]</tt></td></tr>
244.418 + * </table></blockquote>
244.419 + *
244.420 + * <p> Note that a different set of metacharacters are in effect inside
244.421 + * a character class than outside a character class. For instance, the
244.422 + * regular expression <tt>.</tt> loses its special meaning inside a
244.423 + * character class, while the expression <tt>-</tt> becomes a range
244.424 + * forming metacharacter.
244.425 + *
244.426 + * <a name="lt">
244.427 + * <h4> Line terminators </h4>
244.428 + *
244.429 + * <p> A <i>line terminator</i> is a one- or two-character sequence that marks
244.430 + * the end of a line of the input character sequence. The following are
244.431 + * recognized as line terminators:
244.432 + *
244.433 + * <ul>
244.434 + *
244.435 + * <li> A newline (line feed) character (<tt>'\n'</tt>),
244.436 + *
244.437 + * <li> A carriage-return character followed immediately by a newline
244.438 + * character (<tt>"\r\n"</tt>),
244.439 + *
244.440 + * <li> A standalone carriage-return character (<tt>'\r'</tt>),
244.441 + *
244.442 + * <li> A next-line character (<tt>'\u0085'</tt>),
244.443 + *
244.444 + * <li> A line-separator character (<tt>'\u2028'</tt>), or
244.445 + *
244.446 + * <li> A paragraph-separator character (<tt>'\u2029</tt>).
244.447 + *
244.448 + * </ul>
244.449 + * <p>If {@link #UNIX_LINES} mode is activated, then the only line terminators
244.450 + * recognized are newline characters.
244.451 + *
244.452 + * <p> The regular expression <tt>.</tt> matches any character except a line
244.453 + * terminator unless the {@link #DOTALL} flag is specified.
244.454 + *
244.455 + * <p> By default, the regular expressions <tt>^</tt> and <tt>$</tt> ignore
244.456 + * line terminators and only match at the beginning and the end, respectively,
244.457 + * of the entire input sequence. If {@link #MULTILINE} mode is activated then
244.458 + * <tt>^</tt> matches at the beginning of input and after any line terminator
244.459 + * except at the end of input. When in {@link #MULTILINE} mode <tt>$</tt>
244.460 + * matches just before a line terminator or the end of the input sequence.
244.461 + *
244.462 + * <a name="cg">
244.463 + * <h4> Groups and capturing </h4>
244.464 + *
244.465 + * <a name="gnumber">
244.466 + * <h5> Group number </h5>
244.467 + * <p> Capturing groups are numbered by counting their opening parentheses from
244.468 + * left to right. In the expression <tt>((A)(B(C)))</tt>, for example, there
244.469 + * are four such groups: </p>
244.470 + *
244.471 + * <blockquote><table cellpadding=1 cellspacing=0 summary="Capturing group numberings">
244.472 + * <tr><th>1 </th>
244.473 + * <td><tt>((A)(B(C)))</tt></td></tr>
244.474 + * <tr><th>2 </th>
244.475 + * <td><tt>(A)</tt></td></tr>
244.476 + * <tr><th>3 </th>
244.477 + * <td><tt>(B(C))</tt></td></tr>
244.478 + * <tr><th>4 </th>
244.479 + * <td><tt>(C)</tt></td></tr>
244.480 + * </table></blockquote>
244.481 + *
244.482 + * <p> Group zero always stands for the entire expression.
244.483 + *
244.484 + * <p> Capturing groups are so named because, during a match, each subsequence
244.485 + * of the input sequence that matches such a group is saved. The captured
244.486 + * subsequence may be used later in the expression, via a back reference, and
244.487 + * may also be retrieved from the matcher once the match operation is complete.
244.488 + *
244.489 + * <a name="groupname">
244.490 + * <h5> Group name </h5>
244.491 + * <p>A capturing group can also be assigned a "name", a <tt>named-capturing group</tt>,
244.492 + * and then be back-referenced later by the "name". Group names are composed of
244.493 + * the following characters. The first character must be a <tt>letter</tt>.
244.494 + *
244.495 + * <ul>
244.496 + * <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
244.497 + * (<tt>'\u0041'</tt> through <tt>'\u005a'</tt>),
244.498 + * <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
244.499 + * (<tt>'\u0061'</tt> through <tt>'\u007a'</tt>),
244.500 + * <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
244.501 + * (<tt>'\u0030'</tt> through <tt>'\u0039'</tt>),
244.502 + * </ul>
244.503 + *
244.504 + * <p> A <tt>named-capturing group</tt> is still numbered as described in
244.505 + * <a href="#gnumber">Group number</a>.
244.506 + *
244.507 + * <p> The captured input associated with a group is always the subsequence
244.508 + * that the group most recently matched. If a group is evaluated a second time
244.509 + * because of quantification then its previously-captured value, if any, will
244.510 + * be retained if the second evaluation fails. Matching the string
244.511 + * <tt>"aba"</tt> against the expression <tt>(a(b)?)+</tt>, for example, leaves
244.512 + * group two set to <tt>"b"</tt>. All captured input is discarded at the
244.513 + * beginning of each match.
244.514 + *
244.515 + * <p> Groups beginning with <tt>(?</tt> are either pure, <i>non-capturing</i> groups
244.516 + * that do not capture text and do not count towards the group total, or
244.517 + * <i>named-capturing</i> group.
244.518 + *
244.519 + * <h4> Unicode support </h4>
244.520 + *
244.521 + * <p> This class is in conformance with Level 1 of <a
244.522 + * href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
244.523 + * Standard #18: Unicode Regular Expression</i></a>, plus RL2.1
244.524 + * Canonical Equivalents.
244.525 + * <p>
244.526 + * <b>Unicode escape sequences</b> such as <tt>\u2014</tt> in Java source code
244.527 + * are processed as described in section 3.3 of
244.528 + * <cite>The Java™ Language Specification</cite>.
244.529 + * Such escape sequences are also implemented directly by the regular-expression
244.530 + * parser so that Unicode escapes can be used in expressions that are read from
244.531 + * files or from the keyboard. Thus the strings <tt>"\u2014"</tt> and
244.532 + * <tt>"\\u2014"</tt>, while not equal, compile into the same pattern, which
244.533 + * matches the character with hexadecimal value <tt>0x2014</tt>.
244.534 + * <p>
244.535 + * A Unicode character can also be represented in a regular-expression by
244.536 + * using its <b>Hex notation</b>(hexadecimal code point value) directly as described in construct
244.537 + * <tt>\x{...}</tt>, for example a supplementary character U+2011F
244.538 + * can be specified as <tt>\x{2011F}</tt>, instead of two consecutive
244.539 + * Unicode escape sequences of the surrogate pair
244.540 + * <tt>\uD840</tt><tt>\uDD1F</tt>.
244.541 + * <p>
244.542 + * Unicode scripts, blocks, categories and binary properties are written with
244.543 + * the <tt>\p</tt> and <tt>\P</tt> constructs as in Perl.
244.544 + * <tt>\p{</tt><i>prop</i><tt>}</tt> matches if
244.545 + * the input has the property <i>prop</i>, while <tt>\P{</tt><i>prop</i><tt>}</tt>
244.546 + * does not match if the input has that property.
244.547 + * <p>
244.548 + * Scripts, blocks, categories and binary properties can be used both inside
244.549 + * and outside of a character class.
244.550 + * <a name="usc">
244.551 + * <p>
244.552 + * <b>Scripts</b> are specified either with the prefix {@code Is}, as in
244.553 + * {@code IsHiragana}, or by using the {@code script} keyword (or its short
244.554 + * form {@code sc})as in {@code script=Hiragana} or {@code sc=Hiragana}.
244.555 + * <p>
244.556 + * The script names supported by <code>Pattern</code> are the valid script names
244.557 + * accepted and defined by
244.558 + * {@link java.lang.Character.UnicodeScript#forName(String) UnicodeScript.forName}.
244.559 + * <a name="ubc">
244.560 + * <p>
244.561 + * <b>Blocks</b> are specified with the prefix {@code In}, as in
244.562 + * {@code InMongolian}, or by using the keyword {@code block} (or its short
244.563 + * form {@code blk}) as in {@code block=Mongolian} or {@code blk=Mongolian}.
244.564 + * <p>
244.565 + * The block names supported by <code>Pattern</code> are the valid block names
244.566 + * accepted and defined by
244.567 + * {@link java.lang.Character.UnicodeBlock#forName(String) UnicodeBlock.forName}.
244.568 + * <p>
244.569 + * <a name="ucc">
244.570 + * <b>Categories</b> may be specified with the optional prefix {@code Is}:
244.571 + * Both {@code \p{L}} and {@code \p{IsL}} denote the category of Unicode
244.572 + * letters. Same as scripts and blocks, categories can also be specified
244.573 + * by using the keyword {@code general_category} (or its short form
244.574 + * {@code gc}) as in {@code general_category=Lu} or {@code gc=Lu}.
244.575 + * <p>
244.576 + * The supported categories are those of
244.577 + * <a href="http://www.unicode.org/unicode/standard/standard.html">
244.578 + * <i>The Unicode Standard</i></a> in the version specified by the
244.579 + * {@link java.lang.Character Character} class. The category names are those
244.580 + * defined in the Standard, both normative and informative.
244.581 + * <p>
244.582 + * <a name="ubpc">
244.583 + * <b>Binary properties</b> are specified with the prefix {@code Is}, as in
244.584 + * {@code IsAlphabetic}. The supported binary properties by <code>Pattern</code>
244.585 + * are
244.586 + * <ul>
244.587 + * <li> Alphabetic
244.588 + * <li> Ideographic
244.589 + * <li> Letter
244.590 + * <li> Lowercase
244.591 + * <li> Uppercase
244.592 + * <li> Titlecase
244.593 + * <li> Punctuation
244.594 + * <Li> Control
244.595 + * <li> White_Space
244.596 + * <li> Digit
244.597 + * <li> Hex_Digit
244.598 + * <li> Noncharacter_Code_Point
244.599 + * <li> Assigned
244.600 + * </ul>
244.601 +
244.602 +
244.603 + * <p>
244.604 + * <b>Predefined Character classes</b> and <b>POSIX character classes</b> are in
244.605 + * conformance with the recommendation of <i>Annex C: Compatibility Properties</i>
244.606 + * of <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Regular Expression
244.607 + * </i></a>, when {@link #UNICODE_CHARACTER_CLASS} flag is specified.
244.608 + * <p>
244.609 + * <table border="0" cellpadding="1" cellspacing="0"
244.610 + * summary="predefined and posix character classes in Unicode mode">
244.611 + * <tr align="left">
244.612 + * <th bgcolor="#CCCCFF" align="left" id="classes">Classes</th>
244.613 + * <th bgcolor="#CCCCFF" align="left" id="matches">Matches</th>
244.614 + *</tr>
244.615 + * <tr><td><tt>\p{Lower}</tt></td>
244.616 + * <td>A lowercase character:<tt>\p{IsLowercase}</tt></td></tr>
244.617 + * <tr><td><tt>\p{Upper}</tt></td>
244.618 + * <td>An uppercase character:<tt>\p{IsUppercase}</tt></td></tr>
244.619 + * <tr><td><tt>\p{ASCII}</tt></td>
244.620 + * <td>All ASCII:<tt>[\x00-\x7F]</tt></td></tr>
244.621 + * <tr><td><tt>\p{Alpha}</tt></td>
244.622 + * <td>An alphabetic character:<tt>\p{IsAlphabetic}</tt></td></tr>
244.623 + * <tr><td><tt>\p{Digit}</tt></td>
244.624 + * <td>A decimal digit character:<tt>p{IsDigit}</tt></td></tr>
244.625 + * <tr><td><tt>\p{Alnum}</tt></td>
244.626 + * <td>An alphanumeric character:<tt>[\p{IsAlphabetic}\p{IsDigit}]</tt></td></tr>
244.627 + * <tr><td><tt>\p{Punct}</tt></td>
244.628 + * <td>A punctuation character:<tt>p{IsPunctuation}</tt></td></tr>
244.629 + * <tr><td><tt>\p{Graph}</tt></td>
244.630 + * <td>A visible character: <tt>[^\p{IsWhite_Space}\p{gc=Cc}\p{gc=Cs}\p{gc=Cn}]</tt></td></tr>
244.631 + * <tr><td><tt>\p{Print}</tt></td>
244.632 + * <td>A printable character: <tt>[\p{Graph}\p{Blank}&&[^\p{Cntrl}]]</tt></td></tr>
244.633 + * <tr><td><tt>\p{Blank}</tt></td>
244.634 + * <td>A space or a tab: <tt>[\p{IsWhite_Space}&&[^\p{gc=Zl}\p{gc=Zp}\x0a\x0b\x0c\x0d\x85]]</tt></td></tr>
244.635 + * <tr><td><tt>\p{Cntrl}</tt></td>
244.636 + * <td>A control character: <tt>\p{gc=Cc}</tt></td></tr>
244.637 + * <tr><td><tt>\p{XDigit}</tt></td>
244.638 + * <td>A hexadecimal digit: <tt>[\p{gc=Nd}\p{IsHex_Digit}]</tt></td></tr>
244.639 + * <tr><td><tt>\p{Space}</tt></td>
244.640 + * <td>A whitespace character:<tt>\p{IsWhite_Space}</tt></td></tr>
244.641 + * <tr><td><tt>\d</tt></td>
244.642 + * <td>A digit: <tt>\p{IsDigit}</tt></td></tr>
244.643 + * <tr><td><tt>\D</tt></td>
244.644 + * <td>A non-digit: <tt>[^\d]</tt></td></tr>
244.645 + * <tr><td><tt>\s</tt></td>
244.646 + * <td>A whitespace character: <tt>\p{IsWhite_Space}</tt></td></tr>
244.647 + * <tr><td><tt>\S</tt></td>
244.648 + * <td>A non-whitespace character: <tt>[^\s]</tt></td></tr>
244.649 + * <tr><td><tt>\w</tt></td>
244.650 + * <td>A word character: <tt>[\p{Alpha}\p{gc=Mn}\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}]</tt></td></tr>
244.651 + * <tr><td><tt>\W</tt></td>
244.652 + * <td>A non-word character: <tt>[^\w]</tt></td></tr>
244.653 + * </table>
244.654 + * <p>
244.655 + * <a name="jcc">
244.656 + * Categories that behave like the java.lang.Character
244.657 + * boolean is<i>methodname</i> methods (except for the deprecated ones) are
244.658 + * available through the same <tt>\p{</tt><i>prop</i><tt>}</tt> syntax where
244.659 + * the specified property has the name <tt>java<i>methodname</i></tt>.
244.660 + *
244.661 + * <h4> Comparison to Perl 5 </h4>
244.662 + *
244.663 + * <p>The <code>Pattern</code> engine performs traditional NFA-based matching
244.664 + * with ordered alternation as occurs in Perl 5.
244.665 + *
244.666 + * <p> Perl constructs not supported by this class: </p>
244.667 + *
244.668 + * <ul>
244.669 + * <li><p> Predefined character classes (Unicode character)
244.670 + * <p><tt>\h </tt>A horizontal whitespace
244.671 + * <p><tt>\H </tt>A non horizontal whitespace
244.672 + * <p><tt>\v </tt>A vertical whitespace
244.673 + * <p><tt>\V </tt>A non vertical whitespace
244.674 + * <p><tt>\R </tt>Any Unicode linebreak sequence
244.675 + * <tt>\u005cu000D\u005cu000A|[\u005cu000A\u005cu000B\u005cu000C\u005cu000D\u005cu0085\u005cu2028\u005cu2029]</tt>
244.676 + * <p><tt>\X </tt>Match Unicode
244.677 + * <a href="http://www.unicode.org/reports/tr18/#Default_Grapheme_Clusters">
244.678 + * <i>extended grapheme cluster</i></a>
244.679 + * </p></li>
244.680 + *
244.681 + * <li><p> The backreference constructs, <tt>\g{</tt><i>n</i><tt>}</tt> for
244.682 + * the <i>n</i><sup>th</sup><a href="#cg">capturing group</a> and
244.683 + * <tt>\g{</tt><i>name</i><tt>}</tt> for
244.684 + * <a href="#groupname">named-capturing group</a>.
244.685 + * </p></li>
244.686 + *
244.687 + * <li><p> The named character construct, <tt>\N{</tt><i>name</i><tt>}</tt>
244.688 + * for a Unicode character by its name.
244.689 + * </p></li>
244.690 + *
244.691 + * <li><p> The conditional constructs
244.692 + * <tt>(?(</tt><i>condition</i><tt>)</tt><i>X</i><tt>)</tt> and
244.693 + * <tt>(?(</tt><i>condition</i><tt>)</tt><i>X</i><tt>|</tt><i>Y</i><tt>)</tt>,
244.694 + * </p></li>
244.695 + *
244.696 + * <li><p> The embedded code constructs <tt>(?{</tt><i>code</i><tt>})</tt>
244.697 + * and <tt>(??{</tt><i>code</i><tt>})</tt>,</p></li>
244.698 + *
244.699 + * <li><p> The embedded comment syntax <tt>(?#comment)</tt>, and </p></li>
244.700 + *
244.701 + * <li><p> The preprocessing operations <tt>\l</tt> <tt>\u</tt>,
244.702 + * <tt>\L</tt>, and <tt>\U</tt>. </p></li>
244.703 + *
244.704 + * </ul>
244.705 + *
244.706 + * <p> Constructs supported by this class but not by Perl: </p>
244.707 + *
244.708 + * <ul>
244.709 + *
244.710 + * <li><p> Character-class union and intersection as described
244.711 + * <a href="#cc">above</a>.</p></li>
244.712 + *
244.713 + * </ul>
244.714 + *
244.715 + * <p> Notable differences from Perl: </p>
244.716 + *
244.717 + * <ul>
244.718 + *
244.719 + * <li><p> In Perl, <tt>\1</tt> through <tt>\9</tt> are always interpreted
244.720 + * as back references; a backslash-escaped number greater than <tt>9</tt> is
244.721 + * treated as a back reference if at least that many subexpressions exist,
244.722 + * otherwise it is interpreted, if possible, as an octal escape. In this
244.723 + * class octal escapes must always begin with a zero. In this class,
244.724 + * <tt>\1</tt> through <tt>\9</tt> are always interpreted as back
244.725 + * references, and a larger number is accepted as a back reference if at
244.726 + * least that many subexpressions exist at that point in the regular
244.727 + * expression, otherwise the parser will drop digits until the number is
244.728 + * smaller or equal to the existing number of groups or it is one digit.
244.729 + * </p></li>
244.730 + *
244.731 + * <li><p> Perl uses the <tt>g</tt> flag to request a match that resumes
244.732 + * where the last match left off. This functionality is provided implicitly
244.733 + * by the {@link Matcher} class: Repeated invocations of the {@link
244.734 + * Matcher#find find} method will resume where the last match left off,
244.735 + * unless the matcher is reset. </p></li>
244.736 + *
244.737 + * <li><p> In Perl, embedded flags at the top level of an expression affect
244.738 + * the whole expression. In this class, embedded flags always take effect
244.739 + * at the point at which they appear, whether they are at the top level or
244.740 + * within a group; in the latter case, flags are restored at the end of the
244.741 + * group just as in Perl. </p></li>
244.742 + *
244.743 + * </ul>
244.744 + *
244.745 + *
244.746 + * <p> For a more precise description of the behavior of regular expression
244.747 + * constructs, please see <a href="http://www.oreilly.com/catalog/regex3/">
244.748 + * <i>Mastering Regular Expressions, 3nd Edition</i>, Jeffrey E. F. Friedl,
244.749 + * O'Reilly and Associates, 2006.</a>
244.750 + * </p>
244.751 + *
244.752 + * @see java.lang.String#split(String, int)
244.753 + * @see java.lang.String#split(String)
244.754 + *
244.755 + * @author Mike McCloskey
244.756 + * @author Mark Reinhold
244.757 + * @author JSR-51 Expert Group
244.758 + * @since 1.4
244.759 + * @spec JSR-51
244.760 + */
244.761 +
244.762 +public final class Pattern
244.763 + implements java.io.Serializable
244.764 +{
244.765 +
244.766 + /**
244.767 + * Regular expression modifier values. Instead of being passed as
244.768 + * arguments, they can also be passed as inline modifiers.
244.769 + * For example, the following statements have the same effect.
244.770 + * <pre>
244.771 + * RegExp r1 = RegExp.compile("abc", Pattern.I|Pattern.M);
244.772 + * RegExp r2 = RegExp.compile("(?im)abc", 0);
244.773 + * </pre>
244.774 + *
244.775 + * The flags are duplicated so that the familiar Perl match flag
244.776 + * names are available.
244.777 + */
244.778 +
244.779 + /**
244.780 + * Enables Unix lines mode.
244.781 + *
244.782 + * <p> In this mode, only the <tt>'\n'</tt> line terminator is recognized
244.783 + * in the behavior of <tt>.</tt>, <tt>^</tt>, and <tt>$</tt>.
244.784 + *
244.785 + * <p> Unix lines mode can also be enabled via the embedded flag
244.786 + * expression <tt>(?d)</tt>.
244.787 + */
244.788 + public static final int UNIX_LINES = 0x01;
244.789 +
244.790 + /**
244.791 + * Enables case-insensitive matching.
244.792 + *
244.793 + * <p> By default, case-insensitive matching assumes that only characters
244.794 + * in the US-ASCII charset are being matched. Unicode-aware
244.795 + * case-insensitive matching can be enabled by specifying the {@link
244.796 + * #UNICODE_CASE} flag in conjunction with this flag.
244.797 + *
244.798 + * <p> Case-insensitive matching can also be enabled via the embedded flag
244.799 + * expression <tt>(?i)</tt>.
244.800 + *
244.801 + * <p> Specifying this flag may impose a slight performance penalty. </p>
244.802 + */
244.803 + public static final int CASE_INSENSITIVE = 0x02;
244.804 +
244.805 + /**
244.806 + * Permits whitespace and comments in pattern.
244.807 + *
244.808 + * <p> In this mode, whitespace is ignored, and embedded comments starting
244.809 + * with <tt>#</tt> are ignored until the end of a line.
244.810 + *
244.811 + * <p> Comments mode can also be enabled via the embedded flag
244.812 + * expression <tt>(?x)</tt>.
244.813 + */
244.814 + public static final int COMMENTS = 0x04;
244.815 +
244.816 + /**
244.817 + * Enables multiline mode.
244.818 + *
244.819 + * <p> In multiline mode the expressions <tt>^</tt> and <tt>$</tt> match
244.820 + * just after or just before, respectively, a line terminator or the end of
244.821 + * the input sequence. By default these expressions only match at the
244.822 + * beginning and the end of the entire input sequence.
244.823 + *
244.824 + * <p> Multiline mode can also be enabled via the embedded flag
244.825 + * expression <tt>(?m)</tt>. </p>
244.826 + */
244.827 + public static final int MULTILINE = 0x08;
244.828 +
244.829 + /**
244.830 + * Enables literal parsing of the pattern.
244.831 + *
244.832 + * <p> When this flag is specified then the input string that specifies
244.833 + * the pattern is treated as a sequence of literal characters.
244.834 + * Metacharacters or escape sequences in the input sequence will be
244.835 + * given no special meaning.
244.836 + *
244.837 + * <p>The flags CASE_INSENSITIVE and UNICODE_CASE retain their impact on
244.838 + * matching when used in conjunction with this flag. The other flags
244.839 + * become superfluous.
244.840 + *
244.841 + * <p> There is no embedded flag character for enabling literal parsing.
244.842 + * @since 1.5
244.843 + */
244.844 + public static final int LITERAL = 0x10;
244.845 +
244.846 + /**
244.847 + * Enables dotall mode.
244.848 + *
244.849 + * <p> In dotall mode, the expression <tt>.</tt> matches any character,
244.850 + * including a line terminator. By default this expression does not match
244.851 + * line terminators.
244.852 + *
244.853 + * <p> Dotall mode can also be enabled via the embedded flag
244.854 + * expression <tt>(?s)</tt>. (The <tt>s</tt> is a mnemonic for
244.855 + * "single-line" mode, which is what this is called in Perl.) </p>
244.856 + */
244.857 + public static final int DOTALL = 0x20;
244.858 +
244.859 + /**
244.860 + * Enables Unicode-aware case folding.
244.861 + *
244.862 + * <p> When this flag is specified then case-insensitive matching, when
244.863 + * enabled by the {@link #CASE_INSENSITIVE} flag, is done in a manner
244.864 + * consistent with the Unicode Standard. By default, case-insensitive
244.865 + * matching assumes that only characters in the US-ASCII charset are being
244.866 + * matched.
244.867 + *
244.868 + * <p> Unicode-aware case folding can also be enabled via the embedded flag
244.869 + * expression <tt>(?u)</tt>.
244.870 + *
244.871 + * <p> Specifying this flag may impose a performance penalty. </p>
244.872 + */
244.873 + public static final int UNICODE_CASE = 0x40;
244.874 +
244.875 + /**
244.876 + * Enables canonical equivalence.
244.877 + *
244.878 + * <p> When this flag is specified then two characters will be considered
244.879 + * to match if, and only if, their full canonical decompositions match.
244.880 + * The expression <tt>"a\u030A"</tt>, for example, will match the
244.881 + * string <tt>"\u00E5"</tt> when this flag is specified. By default,
244.882 + * matching does not take canonical equivalence into account.
244.883 + *
244.884 + * <p> There is no embedded flag character for enabling canonical
244.885 + * equivalence.
244.886 + *
244.887 + * <p> Specifying this flag may impose a performance penalty. </p>
244.888 + */
244.889 + public static final int CANON_EQ = 0x80;
244.890 +
244.891 + /**
244.892 + * Enables the Unicode version of <i>Predefined character classes</i> and
244.893 + * <i>POSIX character classes</i>.
244.894 + *
244.895 + * <p> When this flag is specified then the (US-ASCII only)
244.896 + * <i>Predefined character classes</i> and <i>POSIX character classes</i>
244.897 + * are in conformance with
244.898 + * <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
244.899 + * Standard #18: Unicode Regular Expression</i></a>
244.900 + * <i>Annex C: Compatibility Properties</i>.
244.901 + * <p>
244.902 + * The UNICODE_CHARACTER_CLASS mode can also be enabled via the embedded
244.903 + * flag expression <tt>(?U)</tt>.
244.904 + * <p>
244.905 + * The flag implies UNICODE_CASE, that is, it enables Unicode-aware case
244.906 + * folding.
244.907 + * <p>
244.908 + * Specifying this flag may impose a performance penalty. </p>
244.909 + * @since 1.7
244.910 + */
244.911 + public static final int UNICODE_CHARACTER_CLASS = 0x100;
244.912 +
244.913 + /* Pattern has only two serialized components: The pattern string
244.914 + * and the flags, which are all that is needed to recompile the pattern
244.915 + * when it is deserialized.
244.916 + */
244.917 +
244.918 + /** use serialVersionUID from Merlin b59 for interoperability */
244.919 + private static final long serialVersionUID = 5073258162644648461L;
244.920 +
244.921 + /**
244.922 + * The original regular-expression pattern string.
244.923 + *
244.924 + * @serial
244.925 + */
244.926 + private String pattern;
244.927 +
244.928 + /**
244.929 + * The original pattern flags.
244.930 + *
244.931 + * @serial
244.932 + */
244.933 + private int flags;
244.934 +
244.935 + /**
244.936 + * Boolean indicating this Pattern is compiled; this is necessary in order
244.937 + * to lazily compile deserialized Patterns.
244.938 + */
244.939 + private transient volatile boolean compiled = false;
244.940 +
244.941 + /**
244.942 + * The normalized pattern string.
244.943 + */
244.944 + private transient String normalizedPattern;
244.945 +
244.946 + /**
244.947 + * The starting point of state machine for the find operation. This allows
244.948 + * a match to start anywhere in the input.
244.949 + */
244.950 + transient Node root;
244.951 +
244.952 + /**
244.953 + * The root of object tree for a match operation. The pattern is matched
244.954 + * at the beginning. This may include a find that uses BnM or a First
244.955 + * node.
244.956 + */
244.957 + transient Node matchRoot;
244.958 +
244.959 + /**
244.960 + * Temporary storage used by parsing pattern slice.
244.961 + */
244.962 + transient int[] buffer;
244.963 +
244.964 + /**
244.965 + * Map the "name" of the "named capturing group" to its group id
244.966 + * node.
244.967 + */
244.968 + transient volatile Map<String, Integer> namedGroups;
244.969 +
244.970 + /**
244.971 + * Temporary storage used while parsing group references.
244.972 + */
244.973 + transient GroupHead[] groupNodes;
244.974 +
244.975 + /**
244.976 + * Temporary null terminated code point array used by pattern compiling.
244.977 + */
244.978 + private transient int[] temp;
244.979 +
244.980 + /**
244.981 + * The number of capturing groups in this Pattern. Used by matchers to
244.982 + * allocate storage needed to perform a match.
244.983 + */
244.984 + transient int capturingGroupCount;
244.985 +
244.986 + /**
244.987 + * The local variable count used by parsing tree. Used by matchers to
244.988 + * allocate storage needed to perform a match.
244.989 + */
244.990 + transient int localCount;
244.991 +
244.992 + /**
244.993 + * Index into the pattern string that keeps track of how much has been
244.994 + * parsed.
244.995 + */
244.996 + private transient int cursor;
244.997 +
244.998 + /**
244.999 + * Holds the length of the pattern string.
244.1000 + */
244.1001 + private transient int patternLength;
244.1002 +
244.1003 + /**
244.1004 + * If the Start node might possibly match supplementary characters.
244.1005 + * It is set to true during compiling if
244.1006 + * (1) There is supplementary char in pattern, or
244.1007 + * (2) There is complement node of Category or Block
244.1008 + */
244.1009 + private transient boolean hasSupplementary;
244.1010 +
244.1011 + /**
244.1012 + * Compiles the given regular expression into a pattern. </p>
244.1013 + *
244.1014 + * @param regex
244.1015 + * The expression to be compiled
244.1016 + *
244.1017 + * @throws PatternSyntaxException
244.1018 + * If the expression's syntax is invalid
244.1019 + */
244.1020 + public static Pattern compile(String regex) {
244.1021 + return new Pattern(regex, 0);
244.1022 + }
244.1023 +
244.1024 + /**
244.1025 + * Compiles the given regular expression into a pattern with the given
244.1026 + * flags. </p>
244.1027 + *
244.1028 + * @param regex
244.1029 + * The expression to be compiled
244.1030 + *
244.1031 + * @param flags
244.1032 + * Match flags, a bit mask that may include
244.1033 + * {@link #CASE_INSENSITIVE}, {@link #MULTILINE}, {@link #DOTALL},
244.1034 + * {@link #UNICODE_CASE}, {@link #CANON_EQ}, {@link #UNIX_LINES},
244.1035 + * {@link #LITERAL}, {@link #UNICODE_CHARACTER_CLASS}
244.1036 + * and {@link #COMMENTS}
244.1037 + *
244.1038 + * @throws IllegalArgumentException
244.1039 + * If bit values other than those corresponding to the defined
244.1040 + * match flags are set in <tt>flags</tt>
244.1041 + *
244.1042 + * @throws PatternSyntaxException
244.1043 + * If the expression's syntax is invalid
244.1044 + */
244.1045 + public static Pattern compile(String regex, int flags) {
244.1046 + return new Pattern(regex, flags);
244.1047 + }
244.1048 +
244.1049 + /**
244.1050 + * Returns the regular expression from which this pattern was compiled.
244.1051 + * </p>
244.1052 + *
244.1053 + * @return The source of this pattern
244.1054 + */
244.1055 + public String pattern() {
244.1056 + return pattern;
244.1057 + }
244.1058 +
244.1059 + /**
244.1060 + * <p>Returns the string representation of this pattern. This
244.1061 + * is the regular expression from which this pattern was
244.1062 + * compiled.</p>
244.1063 + *
244.1064 + * @return The string representation of this pattern
244.1065 + * @since 1.5
244.1066 + */
244.1067 + public String toString() {
244.1068 + return pattern;
244.1069 + }
244.1070 +
244.1071 + /**
244.1072 + * Creates a matcher that will match the given input against this pattern.
244.1073 + * </p>
244.1074 + *
244.1075 + * @param input
244.1076 + * The character sequence to be matched
244.1077 + *
244.1078 + * @return A new matcher for this pattern
244.1079 + */
244.1080 + public Matcher matcher(CharSequence input) {
244.1081 + if (!compiled) {
244.1082 + synchronized(this) {
244.1083 + if (!compiled)
244.1084 + compile();
244.1085 + }
244.1086 + }
244.1087 + Matcher m = new Matcher(this, input);
244.1088 + return m;
244.1089 + }
244.1090 +
244.1091 + /**
244.1092 + * Returns this pattern's match flags. </p>
244.1093 + *
244.1094 + * @return The match flags specified when this pattern was compiled
244.1095 + */
244.1096 + public int flags() {
244.1097 + return flags;
244.1098 + }
244.1099 +
244.1100 + /**
244.1101 + * Compiles the given regular expression and attempts to match the given
244.1102 + * input against it.
244.1103 + *
244.1104 + * <p> An invocation of this convenience method of the form
244.1105 + *
244.1106 + * <blockquote><pre>
244.1107 + * Pattern.matches(regex, input);</pre></blockquote>
244.1108 + *
244.1109 + * behaves in exactly the same way as the expression
244.1110 + *
244.1111 + * <blockquote><pre>
244.1112 + * Pattern.compile(regex).matcher(input).matches()</pre></blockquote>
244.1113 + *
244.1114 + * <p> If a pattern is to be used multiple times, compiling it once and reusing
244.1115 + * it will be more efficient than invoking this method each time. </p>
244.1116 + *
244.1117 + * @param regex
244.1118 + * The expression to be compiled
244.1119 + *
244.1120 + * @param input
244.1121 + * The character sequence to be matched
244.1122 + *
244.1123 + * @throws PatternSyntaxException
244.1124 + * If the expression's syntax is invalid
244.1125 + */
244.1126 + public static boolean matches(String regex, CharSequence input) {
244.1127 + Pattern p = Pattern.compile(regex);
244.1128 + Matcher m = p.matcher(input);
244.1129 + return m.matches();
244.1130 + }
244.1131 +
244.1132 + /**
244.1133 + * Splits the given input sequence around matches of this pattern.
244.1134 + *
244.1135 + * <p> The array returned by this method contains each substring of the
244.1136 + * input sequence that is terminated by another subsequence that matches
244.1137 + * this pattern or is terminated by the end of the input sequence. The
244.1138 + * substrings in the array are in the order in which they occur in the
244.1139 + * input. If this pattern does not match any subsequence of the input then
244.1140 + * the resulting array has just one element, namely the input sequence in
244.1141 + * string form.
244.1142 + *
244.1143 + * <p> The <tt>limit</tt> parameter controls the number of times the
244.1144 + * pattern is applied and therefore affects the length of the resulting
244.1145 + * array. If the limit <i>n</i> is greater than zero then the pattern
244.1146 + * will be applied at most <i>n</i> - 1 times, the array's
244.1147 + * length will be no greater than <i>n</i>, and the array's last entry
244.1148 + * will contain all input beyond the last matched delimiter. If <i>n</i>
244.1149 + * is non-positive then the pattern will be applied as many times as
244.1150 + * possible and the array can have any length. If <i>n</i> is zero then
244.1151 + * the pattern will be applied as many times as possible, the array can
244.1152 + * have any length, and trailing empty strings will be discarded.
244.1153 + *
244.1154 + * <p> The input <tt>"boo:and:foo"</tt>, for example, yields the following
244.1155 + * results with these parameters:
244.1156 + *
244.1157 + * <blockquote><table cellpadding=1 cellspacing=0
244.1158 + * summary="Split examples showing regex, limit, and result">
244.1159 + * <tr><th><P align="left"><i>Regex </i></th>
244.1160 + * <th><P align="left"><i>Limit </i></th>
244.1161 + * <th><P align="left"><i>Result </i></th></tr>
244.1162 + * <tr><td align=center>:</td>
244.1163 + * <td align=center>2</td>
244.1164 + * <td><tt>{ "boo", "and:foo" }</tt></td></tr>
244.1165 + * <tr><td align=center>:</td>
244.1166 + * <td align=center>5</td>
244.1167 + * <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
244.1168 + * <tr><td align=center>:</td>
244.1169 + * <td align=center>-2</td>
244.1170 + * <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
244.1171 + * <tr><td align=center>o</td>
244.1172 + * <td align=center>5</td>
244.1173 + * <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
244.1174 + * <tr><td align=center>o</td>
244.1175 + * <td align=center>-2</td>
244.1176 + * <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
244.1177 + * <tr><td align=center>o</td>
244.1178 + * <td align=center>0</td>
244.1179 + * <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
244.1180 + * </table></blockquote>
244.1181 + *
244.1182 + *
244.1183 + * @param input
244.1184 + * The character sequence to be split
244.1185 + *
244.1186 + * @param limit
244.1187 + * The result threshold, as described above
244.1188 + *
244.1189 + * @return The array of strings computed by splitting the input
244.1190 + * around matches of this pattern
244.1191 + */
244.1192 + public String[] split(CharSequence input, int limit) {
244.1193 + int index = 0;
244.1194 + boolean matchLimited = limit > 0;
244.1195 + ArrayList<String> matchList = new ArrayList<>();
244.1196 + Matcher m = matcher(input);
244.1197 +
244.1198 + // Add segments before each match found
244.1199 + while(m.find()) {
244.1200 + if (!matchLimited || matchList.size() < limit - 1) {
244.1201 + String match = input.subSequence(index, m.start()).toString();
244.1202 + matchList.add(match);
244.1203 + index = m.end();
244.1204 + } else if (matchList.size() == limit - 1) { // last one
244.1205 + String match = input.subSequence(index,
244.1206 + input.length()).toString();
244.1207 + matchList.add(match);
244.1208 + index = m.end();
244.1209 + }
244.1210 + }
244.1211 +
244.1212 + // If no match was found, return this
244.1213 + if (index == 0)
244.1214 + return new String[] {input.toString()};
244.1215 +
244.1216 + // Add remaining segment
244.1217 + if (!matchLimited || matchList.size() < limit)
244.1218 + matchList.add(input.subSequence(index, input.length()).toString());
244.1219 +
244.1220 + // Construct result
244.1221 + int resultSize = matchList.size();
244.1222 + if (limit == 0)
244.1223 + while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
244.1224 + resultSize--;
244.1225 + String[] result = new String[resultSize];
244.1226 + return matchList.subList(0, resultSize).toArray(result);
244.1227 + }
244.1228 +
244.1229 + /**
244.1230 + * Splits the given input sequence around matches of this pattern.
244.1231 + *
244.1232 + * <p> This method works as if by invoking the two-argument {@link
244.1233 + * #split(java.lang.CharSequence, int) split} method with the given input
244.1234 + * sequence and a limit argument of zero. Trailing empty strings are
244.1235 + * therefore not included in the resulting array. </p>
244.1236 + *
244.1237 + * <p> The input <tt>"boo:and:foo"</tt>, for example, yields the following
244.1238 + * results with these expressions:
244.1239 + *
244.1240 + * <blockquote><table cellpadding=1 cellspacing=0
244.1241 + * summary="Split examples showing regex and result">
244.1242 + * <tr><th><P align="left"><i>Regex </i></th>
244.1243 + * <th><P align="left"><i>Result</i></th></tr>
244.1244 + * <tr><td align=center>:</td>
244.1245 + * <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
244.1246 + * <tr><td align=center>o</td>
244.1247 + * <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
244.1248 + * </table></blockquote>
244.1249 + *
244.1250 + *
244.1251 + * @param input
244.1252 + * The character sequence to be split
244.1253 + *
244.1254 + * @return The array of strings computed by splitting the input
244.1255 + * around matches of this pattern
244.1256 + */
244.1257 + public String[] split(CharSequence input) {
244.1258 + return split(input, 0);
244.1259 + }
244.1260 +
244.1261 + /**
244.1262 + * Returns a literal pattern <code>String</code> for the specified
244.1263 + * <code>String</code>.
244.1264 + *
244.1265 + * <p>This method produces a <code>String</code> that can be used to
244.1266 + * create a <code>Pattern</code> that would match the string
244.1267 + * <code>s</code> as if it were a literal pattern.</p> Metacharacters
244.1268 + * or escape sequences in the input sequence will be given no special
244.1269 + * meaning.
244.1270 + *
244.1271 + * @param s The string to be literalized
244.1272 + * @return A literal string replacement
244.1273 + * @since 1.5
244.1274 + */
244.1275 + public static String quote(String s) {
244.1276 + int slashEIndex = s.indexOf("\\E");
244.1277 + if (slashEIndex == -1)
244.1278 + return "\\Q" + s + "\\E";
244.1279 +
244.1280 + StringBuilder sb = new StringBuilder(s.length() * 2);
244.1281 + sb.append("\\Q");
244.1282 + slashEIndex = 0;
244.1283 + int current = 0;
244.1284 + while ((slashEIndex = s.indexOf("\\E", current)) != -1) {
244.1285 + sb.append(s.substring(current, slashEIndex));
244.1286 + current = slashEIndex + 2;
244.1287 + sb.append("\\E\\\\E\\Q");
244.1288 + }
244.1289 + sb.append(s.substring(current, s.length()));
244.1290 + sb.append("\\E");
244.1291 + return sb.toString();
244.1292 + }
244.1293 +
244.1294 + /**
244.1295 + * Recompile the Pattern instance from a stream. The original pattern
244.1296 + * string is read in and the object tree is recompiled from it.
244.1297 + */
244.1298 + private void readObject(java.io.ObjectInputStream s)
244.1299 + throws java.io.IOException, ClassNotFoundException {
244.1300 +
244.1301 + // Read in all fields
244.1302 + s.defaultReadObject();
244.1303 +
244.1304 + // Initialize counts
244.1305 + capturingGroupCount = 1;
244.1306 + localCount = 0;
244.1307 +
244.1308 + // if length > 0, the Pattern is lazily compiled
244.1309 + compiled = false;
244.1310 + if (pattern.length() == 0) {
244.1311 + root = new Start(lastAccept);
244.1312 + matchRoot = lastAccept;
244.1313 + compiled = true;
244.1314 + }
244.1315 + }
244.1316 +
244.1317 + /**
244.1318 + * This private constructor is used to create all Patterns. The pattern
244.1319 + * string and match flags are all that is needed to completely describe
244.1320 + * a Pattern. An empty pattern string results in an object tree with
244.1321 + * only a Start node and a LastNode node.
244.1322 + */
244.1323 + private Pattern(String p, int f) {
244.1324 + pattern = p;
244.1325 + flags = f;
244.1326 +
244.1327 + // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
244.1328 + if ((flags & UNICODE_CHARACTER_CLASS) != 0)
244.1329 + flags |= UNICODE_CASE;
244.1330 +
244.1331 + // Reset group index count
244.1332 + capturingGroupCount = 1;
244.1333 + localCount = 0;
244.1334 +
244.1335 + if (pattern.length() > 0) {
244.1336 + compile();
244.1337 + } else {
244.1338 + root = new Start(lastAccept);
244.1339 + matchRoot = lastAccept;
244.1340 + }
244.1341 + }
244.1342 +
244.1343 + /**
244.1344 + * The pattern is converted to normalizedD form and then a pure group
244.1345 + * is constructed to match canonical equivalences of the characters.
244.1346 + */
244.1347 + private void normalize() {
244.1348 + boolean inCharClass = false;
244.1349 + int lastCodePoint = -1;
244.1350 +
244.1351 + // Convert pattern into normalizedD form
244.1352 + normalizedPattern = Normalizer.normalize(pattern, Normalizer.NFD);
244.1353 + patternLength = normalizedPattern.length();
244.1354 +
244.1355 + // Modify pattern to match canonical equivalences
244.1356 + StringBuilder newPattern = new StringBuilder(patternLength);
244.1357 + for(int i=0; i<patternLength; ) {
244.1358 + int c = normalizedPattern.codePointAt(i);
244.1359 + StringBuilder sequenceBuffer;
244.1360 + if ((Character.getType(c) == Character.NON_SPACING_MARK)
244.1361 + && (lastCodePoint != -1)) {
244.1362 + sequenceBuffer = new StringBuilder();
244.1363 + sequenceBuffer.appendCodePoint(lastCodePoint);
244.1364 + sequenceBuffer.appendCodePoint(c);
244.1365 + while(Character.getType(c) == Character.NON_SPACING_MARK) {
244.1366 + i += Character.charCount(c);
244.1367 + if (i >= patternLength)
244.1368 + break;
244.1369 + c = normalizedPattern.codePointAt(i);
244.1370 + sequenceBuffer.appendCodePoint(c);
244.1371 + }
244.1372 + String ea = produceEquivalentAlternation(
244.1373 + sequenceBuffer.toString());
244.1374 + newPattern.setLength(newPattern.length()-Character.charCount(lastCodePoint));
244.1375 + newPattern.append("(?:").append(ea).append(")");
244.1376 + } else if (c == '[' && lastCodePoint != '\\') {
244.1377 + i = normalizeCharClass(newPattern, i);
244.1378 + } else {
244.1379 + newPattern.appendCodePoint(c);
244.1380 + }
244.1381 + lastCodePoint = c;
244.1382 + i += Character.charCount(c);
244.1383 + }
244.1384 + normalizedPattern = newPattern.toString();
244.1385 + }
244.1386 +
244.1387 + /**
244.1388 + * Complete the character class being parsed and add a set
244.1389 + * of alternations to it that will match the canonical equivalences
244.1390 + * of the characters within the class.
244.1391 + */
244.1392 + private int normalizeCharClass(StringBuilder newPattern, int i) {
244.1393 + StringBuilder charClass = new StringBuilder();
244.1394 + StringBuilder eq = null;
244.1395 + int lastCodePoint = -1;
244.1396 + String result;
244.1397 +
244.1398 + i++;
244.1399 + charClass.append("[");
244.1400 + while(true) {
244.1401 + int c = normalizedPattern.codePointAt(i);
244.1402 + StringBuilder sequenceBuffer;
244.1403 +
244.1404 + if (c == ']' && lastCodePoint != '\\') {
244.1405 + charClass.append((char)c);
244.1406 + break;
244.1407 + } else if (Character.getType(c) == Character.NON_SPACING_MARK) {
244.1408 + sequenceBuffer = new StringBuilder();
244.1409 + sequenceBuffer.appendCodePoint(lastCodePoint);
244.1410 + while(Character.getType(c) == Character.NON_SPACING_MARK) {
244.1411 + sequenceBuffer.appendCodePoint(c);
244.1412 + i += Character.charCount(c);
244.1413 + if (i >= normalizedPattern.length())
244.1414 + break;
244.1415 + c = normalizedPattern.codePointAt(i);
244.1416 + }
244.1417 + String ea = produceEquivalentAlternation(
244.1418 + sequenceBuffer.toString());
244.1419 +
244.1420 + charClass.setLength(charClass.length()-Character.charCount(lastCodePoint));
244.1421 + if (eq == null)
244.1422 + eq = new StringBuilder();
244.1423 + eq.append('|');
244.1424 + eq.append(ea);
244.1425 + } else {
244.1426 + charClass.appendCodePoint(c);
244.1427 + i++;
244.1428 + }
244.1429 + if (i == normalizedPattern.length())
244.1430 + throw error("Unclosed character class");
244.1431 + lastCodePoint = c;
244.1432 + }
244.1433 +
244.1434 + if (eq != null) {
244.1435 + result = "(?:"+charClass.toString()+eq.toString()+")";
244.1436 + } else {
244.1437 + result = charClass.toString();
244.1438 + }
244.1439 +
244.1440 + newPattern.append(result);
244.1441 + return i;
244.1442 + }
244.1443 +
244.1444 + /**
244.1445 + * Given a specific sequence composed of a regular character and
244.1446 + * combining marks that follow it, produce the alternation that will
244.1447 + * match all canonical equivalences of that sequence.
244.1448 + */
244.1449 + private String produceEquivalentAlternation(String source) {
244.1450 + int len = countChars(source, 0, 1);
244.1451 + if (source.length() == len)
244.1452 + // source has one character.
244.1453 + return source;
244.1454 +
244.1455 + String base = source.substring(0,len);
244.1456 + String combiningMarks = source.substring(len);
244.1457 +
244.1458 + String[] perms = producePermutations(combiningMarks);
244.1459 + StringBuilder result = new StringBuilder(source);
244.1460 +
244.1461 + // Add combined permutations
244.1462 + for(int x=0; x<perms.length; x++) {
244.1463 + String next = base + perms[x];
244.1464 + if (x>0)
244.1465 + result.append("|"+next);
244.1466 + next = composeOneStep(next);
244.1467 + if (next != null)
244.1468 + result.append("|"+produceEquivalentAlternation(next));
244.1469 + }
244.1470 + return result.toString();
244.1471 + }
244.1472 +
244.1473 + /**
244.1474 + * Returns an array of strings that have all the possible
244.1475 + * permutations of the characters in the input string.
244.1476 + * This is used to get a list of all possible orderings
244.1477 + * of a set of combining marks. Note that some of the permutations
244.1478 + * are invalid because of combining class collisions, and these
244.1479 + * possibilities must be removed because they are not canonically
244.1480 + * equivalent.
244.1481 + */
244.1482 + private String[] producePermutations(String input) {
244.1483 + if (input.length() == countChars(input, 0, 1))
244.1484 + return new String[] {input};
244.1485 +
244.1486 + if (input.length() == countChars(input, 0, 2)) {
244.1487 + int c0 = Character.codePointAt(input, 0);
244.1488 + int c1 = Character.codePointAt(input, Character.charCount(c0));
244.1489 + if (getClass(c1) == getClass(c0)) {
244.1490 + return new String[] {input};
244.1491 + }
244.1492 + String[] result = new String[2];
244.1493 + result[0] = input;
244.1494 + StringBuilder sb = new StringBuilder(2);
244.1495 + sb.appendCodePoint(c1);
244.1496 + sb.appendCodePoint(c0);
244.1497 + result[1] = sb.toString();
244.1498 + return result;
244.1499 + }
244.1500 +
244.1501 + int length = 1;
244.1502 + int nCodePoints = countCodePoints(input);
244.1503 + for(int x=1; x<nCodePoints; x++)
244.1504 + length = length * (x+1);
244.1505 +
244.1506 + String[] temp = new String[length];
244.1507 +
244.1508 + int combClass[] = new int[nCodePoints];
244.1509 + for(int x=0, i=0; x<nCodePoints; x++) {
244.1510 + int c = Character.codePointAt(input, i);
244.1511 + combClass[x] = getClass(c);
244.1512 + i += Character.charCount(c);
244.1513 + }
244.1514 +
244.1515 + // For each char, take it out and add the permutations
244.1516 + // of the remaining chars
244.1517 + int index = 0;
244.1518 + int len;
244.1519 + // offset maintains the index in code units.
244.1520 +loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
244.1521 + len = countChars(input, offset, 1);
244.1522 + boolean skip = false;
244.1523 + for(int y=x-1; y>=0; y--) {
244.1524 + if (combClass[y] == combClass[x]) {
244.1525 + continue loop;
244.1526 + }
244.1527 + }
244.1528 + StringBuilder sb = new StringBuilder(input);
244.1529 + String otherChars = sb.delete(offset, offset+len).toString();
244.1530 + String[] subResult = producePermutations(otherChars);
244.1531 +
244.1532 + String prefix = input.substring(offset, offset+len);
244.1533 + for(int y=0; y<subResult.length; y++)
244.1534 + temp[index++] = prefix + subResult[y];
244.1535 + }
244.1536 + String[] result = new String[index];
244.1537 + for (int x=0; x<index; x++)
244.1538 + result[x] = temp[x];
244.1539 + return result;
244.1540 + }
244.1541 +
244.1542 + private int getClass(int c) {
244.1543 + return Normalizer.getCombiningClass(c);
244.1544 + }
244.1545 +
244.1546 + /**
244.1547 + * Attempts to compose input by combining the first character
244.1548 + * with the first combining mark following it. Returns a String
244.1549 + * that is the composition of the leading character with its first
244.1550 + * combining mark followed by the remaining combining marks. Returns
244.1551 + * null if the first two characters cannot be further composed.
244.1552 + */
244.1553 + private String composeOneStep(String input) {
244.1554 + int len = countChars(input, 0, 2);
244.1555 + String firstTwoCharacters = input.substring(0, len);
244.1556 + String result = Normalizer.normalize(firstTwoCharacters, Normalizer.NFC);
244.1557 +
244.1558 + if (result.equals(firstTwoCharacters))
244.1559 + return null;
244.1560 + else {
244.1561 + String remainder = input.substring(len);
244.1562 + return result + remainder;
244.1563 + }
244.1564 + }
244.1565 +
244.1566 + /**
244.1567 + * Preprocess any \Q...\E sequences in `temp', meta-quoting them.
244.1568 + * See the description of `quotemeta' in perlfunc(1).
244.1569 + */
244.1570 + private void RemoveQEQuoting() {
244.1571 + final int pLen = patternLength;
244.1572 + int i = 0;
244.1573 + while (i < pLen-1) {
244.1574 + if (temp[i] != '\\')
244.1575 + i += 1;
244.1576 + else if (temp[i + 1] != 'Q')
244.1577 + i += 2;
244.1578 + else
244.1579 + break;
244.1580 + }
244.1581 + if (i >= pLen - 1) // No \Q sequence found
244.1582 + return;
244.1583 + int j = i;
244.1584 + i += 2;
244.1585 + int[] newtemp = new int[j + 2*(pLen-i) + 2];
244.1586 + System.arraycopy(temp, 0, newtemp, 0, j);
244.1587 +
244.1588 + boolean inQuote = true;
244.1589 + while (i < pLen) {
244.1590 + int c = temp[i++];
244.1591 + if (! ASCII.isAscii(c) || ASCII.isAlnum(c)) {
244.1592 + newtemp[j++] = c;
244.1593 + } else if (c != '\\') {
244.1594 + if (inQuote) newtemp[j++] = '\\';
244.1595 + newtemp[j++] = c;
244.1596 + } else if (inQuote) {
244.1597 + if (temp[i] == 'E') {
244.1598 + i++;
244.1599 + inQuote = false;
244.1600 + } else {
244.1601 + newtemp[j++] = '\\';
244.1602 + newtemp[j++] = '\\';
244.1603 + }
244.1604 + } else {
244.1605 + if (temp[i] == 'Q') {
244.1606 + i++;
244.1607 + inQuote = true;
244.1608 + } else {
244.1609 + newtemp[j++] = c;
244.1610 + if (i != pLen)
244.1611 + newtemp[j++] = temp[i++];
244.1612 + }
244.1613 + }
244.1614 + }
244.1615 +
244.1616 + patternLength = j;
244.1617 + temp = Arrays.copyOf(newtemp, j + 2); // double zero termination
244.1618 + }
244.1619 +
244.1620 + /**
244.1621 + * Copies regular expression to an int array and invokes the parsing
244.1622 + * of the expression which will create the object tree.
244.1623 + */
244.1624 + private void compile() {
244.1625 + // Handle canonical equivalences
244.1626 + if (has(CANON_EQ) && !has(LITERAL)) {
244.1627 + normalize();
244.1628 + } else {
244.1629 + normalizedPattern = pattern;
244.1630 + }
244.1631 + patternLength = normalizedPattern.length();
244.1632 +
244.1633 + // Copy pattern to int array for convenience
244.1634 + // Use double zero to terminate pattern
244.1635 + temp = new int[patternLength + 2];
244.1636 +
244.1637 + hasSupplementary = false;
244.1638 + int c, count = 0;
244.1639 + // Convert all chars into code points
244.1640 + for (int x = 0; x < patternLength; x += Character.charCount(c)) {
244.1641 + c = normalizedPattern.codePointAt(x);
244.1642 + if (isSupplementary(c)) {
244.1643 + hasSupplementary = true;
244.1644 + }
244.1645 + temp[count++] = c;
244.1646 + }
244.1647 +
244.1648 + patternLength = count; // patternLength now in code points
244.1649 +
244.1650 + if (! has(LITERAL))
244.1651 + RemoveQEQuoting();
244.1652 +
244.1653 + // Allocate all temporary objects here.
244.1654 + buffer = new int[32];
244.1655 + groupNodes = new GroupHead[10];
244.1656 + namedGroups = null;
244.1657 +
244.1658 + if (has(LITERAL)) {
244.1659 + // Literal pattern handling
244.1660 + matchRoot = newSlice(temp, patternLength, hasSupplementary);
244.1661 + matchRoot.next = lastAccept;
244.1662 + } else {
244.1663 + // Start recursive descent parsing
244.1664 + matchRoot = expr(lastAccept);
244.1665 + // Check extra pattern characters
244.1666 + if (patternLength != cursor) {
244.1667 + if (peek() == ')') {
244.1668 + throw error("Unmatched closing ')'");
244.1669 + } else {
244.1670 + throw error("Unexpected internal error");
244.1671 + }
244.1672 + }
244.1673 + }
244.1674 +
244.1675 + // Peephole optimization
244.1676 + if (matchRoot instanceof Slice) {
244.1677 + root = BnM.optimize(matchRoot);
244.1678 + if (root == matchRoot) {
244.1679 + root = hasSupplementary ? new StartS(matchRoot) : new Start(matchRoot);
244.1680 + }
244.1681 + } else if (matchRoot instanceof Begin || matchRoot instanceof First) {
244.1682 + root = matchRoot;
244.1683 + } else {
244.1684 + root = hasSupplementary ? new StartS(matchRoot) : new Start(matchRoot);
244.1685 + }
244.1686 +
244.1687 + // Release temporary storage
244.1688 + temp = null;
244.1689 + buffer = null;
244.1690 + groupNodes = null;
244.1691 + patternLength = 0;
244.1692 + compiled = true;
244.1693 + }
244.1694 +
244.1695 + Map<String, Integer> namedGroups() {
244.1696 + if (namedGroups == null)
244.1697 + namedGroups = new HashMap<>(2);
244.1698 + return namedGroups;
244.1699 + }
244.1700 +
244.1701 + /**
244.1702 + * Used to print out a subtree of the Pattern to help with debugging.
244.1703 + */
244.1704 + private static void printObjectTree(Node node) {
244.1705 + while(node != null) {
244.1706 + if (node instanceof Prolog) {
244.1707 + System.out.println(node);
244.1708 + printObjectTree(((Prolog)node).loop);
244.1709 + System.out.println("**** end contents prolog loop");
244.1710 + } else if (node instanceof Loop) {
244.1711 + System.out.println(node);
244.1712 + printObjectTree(((Loop)node).body);
244.1713 + System.out.println("**** end contents Loop body");
244.1714 + } else if (node instanceof Curly) {
244.1715 + System.out.println(node);
244.1716 + printObjectTree(((Curly)node).atom);
244.1717 + System.out.println("**** end contents Curly body");
244.1718 + } else if (node instanceof GroupCurly) {
244.1719 + System.out.println(node);
244.1720 + printObjectTree(((GroupCurly)node).atom);
244.1721 + System.out.println("**** end contents GroupCurly body");
244.1722 + } else if (node instanceof GroupTail) {
244.1723 + System.out.println(node);
244.1724 + System.out.println("Tail next is "+node.next);
244.1725 + return;
244.1726 + } else {
244.1727 + System.out.println(node);
244.1728 + }
244.1729 + node = node.next;
244.1730 + if (node != null)
244.1731 + System.out.println("->next:");
244.1732 + if (node == Pattern.accept) {
244.1733 + System.out.println("Accept Node");
244.1734 + node = null;
244.1735 + }
244.1736 + }
244.1737 + }
244.1738 +
244.1739 + /**
244.1740 + * Used to accumulate information about a subtree of the object graph
244.1741 + * so that optimizations can be applied to the subtree.
244.1742 + */
244.1743 + static final class TreeInfo {
244.1744 + int minLength;
244.1745 + int maxLength;
244.1746 + boolean maxValid;
244.1747 + boolean deterministic;
244.1748 +
244.1749 + TreeInfo() {
244.1750 + reset();
244.1751 + }
244.1752 + void reset() {
244.1753 + minLength = 0;
244.1754 + maxLength = 0;
244.1755 + maxValid = true;
244.1756 + deterministic = true;
244.1757 + }
244.1758 + }
244.1759 +
244.1760 + /*
244.1761 + * The following private methods are mainly used to improve the
244.1762 + * readability of the code. In order to let the Java compiler easily
244.1763 + * inline them, we should not put many assertions or error checks in them.
244.1764 + */
244.1765 +
244.1766 + /**
244.1767 + * Indicates whether a particular flag is set or not.
244.1768 + */
244.1769 + private boolean has(int f) {
244.1770 + return (flags & f) != 0;
244.1771 + }
244.1772 +
244.1773 + /**
244.1774 + * Match next character, signal error if failed.
244.1775 + */
244.1776 + private void accept(int ch, String s) {
244.1777 + int testChar = temp[cursor++];
244.1778 + if (has(COMMENTS))
244.1779 + testChar = parsePastWhitespace(testChar);
244.1780 + if (ch != testChar) {
244.1781 + throw error(s);
244.1782 + }
244.1783 + }
244.1784 +
244.1785 + /**
244.1786 + * Mark the end of pattern with a specific character.
244.1787 + */
244.1788 + private void mark(int c) {
244.1789 + temp[patternLength] = c;
244.1790 + }
244.1791 +
244.1792 + /**
244.1793 + * Peek the next character, and do not advance the cursor.
244.1794 + */
244.1795 + private int peek() {
244.1796 + int ch = temp[cursor];
244.1797 + if (has(COMMENTS))
244.1798 + ch = peekPastWhitespace(ch);
244.1799 + return ch;
244.1800 + }
244.1801 +
244.1802 + /**
244.1803 + * Read the next character, and advance the cursor by one.
244.1804 + */
244.1805 + private int read() {
244.1806 + int ch = temp[cursor++];
244.1807 + if (has(COMMENTS))
244.1808 + ch = parsePastWhitespace(ch);
244.1809 + return ch;
244.1810 + }
244.1811 +
244.1812 + /**
244.1813 + * Read the next character, and advance the cursor by one,
244.1814 + * ignoring the COMMENTS setting
244.1815 + */
244.1816 + private int readEscaped() {
244.1817 + int ch = temp[cursor++];
244.1818 + return ch;
244.1819 + }
244.1820 +
244.1821 + /**
244.1822 + * Advance the cursor by one, and peek the next character.
244.1823 + */
244.1824 + private int next() {
244.1825 + int ch = temp[++cursor];
244.1826 + if (has(COMMENTS))
244.1827 + ch = peekPastWhitespace(ch);
244.1828 + return ch;
244.1829 + }
244.1830 +
244.1831 + /**
244.1832 + * Advance the cursor by one, and peek the next character,
244.1833 + * ignoring the COMMENTS setting
244.1834 + */
244.1835 + private int nextEscaped() {
244.1836 + int ch = temp[++cursor];
244.1837 + return ch;
244.1838 + }
244.1839 +
244.1840 + /**
244.1841 + * If in xmode peek past whitespace and comments.
244.1842 + */
244.1843 + private int peekPastWhitespace(int ch) {
244.1844 + while (ASCII.isSpace(ch) || ch == '#') {
244.1845 + while (ASCII.isSpace(ch))
244.1846 + ch = temp[++cursor];
244.1847 + if (ch == '#') {
244.1848 + ch = peekPastLine();
244.1849 + }
244.1850 + }
244.1851 + return ch;
244.1852 + }
244.1853 +
244.1854 + /**
244.1855 + * If in xmode parse past whitespace and comments.
244.1856 + */
244.1857 + private int parsePastWhitespace(int ch) {
244.1858 + while (ASCII.isSpace(ch) || ch == '#') {
244.1859 + while (ASCII.isSpace(ch))
244.1860 + ch = temp[cursor++];
244.1861 + if (ch == '#')
244.1862 + ch = parsePastLine();
244.1863 + }
244.1864 + return ch;
244.1865 + }
244.1866 +
244.1867 + /**
244.1868 + * xmode parse past comment to end of line.
244.1869 + */
244.1870 + private int parsePastLine() {
244.1871 + int ch = temp[cursor++];
244.1872 + while (ch != 0 && !isLineSeparator(ch))
244.1873 + ch = temp[cursor++];
244.1874 + return ch;
244.1875 + }
244.1876 +
244.1877 + /**
244.1878 + * xmode peek past comment to end of line.
244.1879 + */
244.1880 + private int peekPastLine() {
244.1881 + int ch = temp[++cursor];
244.1882 + while (ch != 0 && !isLineSeparator(ch))
244.1883 + ch = temp[++cursor];
244.1884 + return ch;
244.1885 + }
244.1886 +
244.1887 + /**
244.1888 + * Determines if character is a line separator in the current mode
244.1889 + */
244.1890 + private boolean isLineSeparator(int ch) {
244.1891 + if (has(UNIX_LINES)) {
244.1892 + return ch == '\n';
244.1893 + } else {
244.1894 + return (ch == '\n' ||
244.1895 + ch == '\r' ||
244.1896 + (ch|1) == '\u2029' ||
244.1897 + ch == '\u0085');
244.1898 + }
244.1899 + }
244.1900 +
244.1901 + /**
244.1902 + * Read the character after the next one, and advance the cursor by two.
244.1903 + */
244.1904 + private int skip() {
244.1905 + int i = cursor;
244.1906 + int ch = temp[i+1];
244.1907 + cursor = i + 2;
244.1908 + return ch;
244.1909 + }
244.1910 +
244.1911 + /**
244.1912 + * Unread one next character, and retreat cursor by one.
244.1913 + */
244.1914 + private void unread() {
244.1915 + cursor--;
244.1916 + }
244.1917 +
244.1918 + /**
244.1919 + * Internal method used for handling all syntax errors. The pattern is
244.1920 + * displayed with a pointer to aid in locating the syntax error.
244.1921 + */
244.1922 + private PatternSyntaxException error(String s) {
244.1923 + return new PatternSyntaxException(s, normalizedPattern, cursor - 1);
244.1924 + }
244.1925 +
244.1926 + /**
244.1927 + * Determines if there is any supplementary character or unpaired
244.1928 + * surrogate in the specified range.
244.1929 + */
244.1930 + private boolean findSupplementary(int start, int end) {
244.1931 + for (int i = start; i < end; i++) {
244.1932 + if (isSupplementary(temp[i]))
244.1933 + return true;
244.1934 + }
244.1935 + return false;
244.1936 + }
244.1937 +
244.1938 + /**
244.1939 + * Determines if the specified code point is a supplementary
244.1940 + * character or unpaired surrogate.
244.1941 + */
244.1942 + private static final boolean isSupplementary(int ch) {
244.1943 + return ch >= Character.MIN_SUPPLEMENTARY_CODE_POINT ||
244.1944 + Character.isSurrogate((char)ch);
244.1945 + }
244.1946 +
244.1947 + /**
244.1948 + * The following methods handle the main parsing. They are sorted
244.1949 + * according to their precedence order, the lowest one first.
244.1950 + */
244.1951 +
244.1952 + /**
244.1953 + * The expression is parsed with branch nodes added for alternations.
244.1954 + * This may be called recursively to parse sub expressions that may
244.1955 + * contain alternations.
244.1956 + */
244.1957 + private Node expr(Node end) {
244.1958 + Node prev = null;
244.1959 + Node firstTail = null;
244.1960 + Node branchConn = null;
244.1961 +
244.1962 + for (;;) {
244.1963 + Node node = sequence(end);
244.1964 + Node nodeTail = root; //double return
244.1965 + if (prev == null) {
244.1966 + prev = node;
244.1967 + firstTail = nodeTail;
244.1968 + } else {
244.1969 + // Branch
244.1970 + if (branchConn == null) {
244.1971 + branchConn = new BranchConn();
244.1972 + branchConn.next = end;
244.1973 + }
244.1974 + if (node == end) {
244.1975 + // if the node returned from sequence() is "end"
244.1976 + // we have an empty expr, set a null atom into
244.1977 + // the branch to indicate to go "next" directly.
244.1978 + node = null;
244.1979 + } else {
244.1980 + // the "tail.next" of each atom goes to branchConn
244.1981 + nodeTail.next = branchConn;
244.1982 + }
244.1983 + if (prev instanceof Branch) {
244.1984 + ((Branch)prev).add(node);
244.1985 + } else {
244.1986 + if (prev == end) {
244.1987 + prev = null;
244.1988 + } else {
244.1989 + // replace the "end" with "branchConn" at its tail.next
244.1990 + // when put the "prev" into the branch as the first atom.
244.1991 + firstTail.next = branchConn;
244.1992 + }
244.1993 + prev = new Branch(prev, node, branchConn);
244.1994 + }
244.1995 + }
244.1996 + if (peek() != '|') {
244.1997 + return prev;
244.1998 + }
244.1999 + next();
244.2000 + }
244.2001 + }
244.2002 +
244.2003 + /**
244.2004 + * Parsing of sequences between alternations.
244.2005 + */
244.2006 + private Node sequence(Node end) {
244.2007 + Node head = null;
244.2008 + Node tail = null;
244.2009 + Node node = null;
244.2010 + LOOP:
244.2011 + for (;;) {
244.2012 + int ch = peek();
244.2013 + switch (ch) {
244.2014 + case '(':
244.2015 + // Because group handles its own closure,
244.2016 + // we need to treat it differently
244.2017 + node = group0();
244.2018 + // Check for comment or flag group
244.2019 + if (node == null)
244.2020 + continue;
244.2021 + if (head == null)
244.2022 + head = node;
244.2023 + else
244.2024 + tail.next = node;
244.2025 + // Double return: Tail was returned in root
244.2026 + tail = root;
244.2027 + continue;
244.2028 + case '[':
244.2029 + node = clazz(true);
244.2030 + break;
244.2031 + case '\\':
244.2032 + ch = nextEscaped();
244.2033 + if (ch == 'p' || ch == 'P') {
244.2034 + boolean oneLetter = true;
244.2035 + boolean comp = (ch == 'P');
244.2036 + ch = next(); // Consume { if present
244.2037 + if (ch != '{') {
244.2038 + unread();
244.2039 + } else {
244.2040 + oneLetter = false;
244.2041 + }
244.2042 + node = family(oneLetter, comp);
244.2043 + } else {
244.2044 + unread();
244.2045 + node = atom();
244.2046 + }
244.2047 + break;
244.2048 + case '^':
244.2049 + next();
244.2050 + if (has(MULTILINE)) {
244.2051 + if (has(UNIX_LINES))
244.2052 + node = new UnixCaret();
244.2053 + else
244.2054 + node = new Caret();
244.2055 + } else {
244.2056 + node = new Begin();
244.2057 + }
244.2058 + break;
244.2059 + case '$':
244.2060 + next();
244.2061 + if (has(UNIX_LINES))
244.2062 + node = new UnixDollar(has(MULTILINE));
244.2063 + else
244.2064 + node = new Dollar(has(MULTILINE));
244.2065 + break;
244.2066 + case '.':
244.2067 + next();
244.2068 + if (has(DOTALL)) {
244.2069 + node = new All();
244.2070 + } else {
244.2071 + if (has(UNIX_LINES))
244.2072 + node = new UnixDot();
244.2073 + else {
244.2074 + node = new Dot();
244.2075 + }
244.2076 + }
244.2077 + break;
244.2078 + case '|':
244.2079 + case ')':
244.2080 + break LOOP;
244.2081 + case ']': // Now interpreting dangling ] and } as literals
244.2082 + case '}':
244.2083 + node = atom();
244.2084 + break;
244.2085 + case '?':
244.2086 + case '*':
244.2087 + case '+':
244.2088 + next();
244.2089 + throw error("Dangling meta character '" + ((char)ch) + "'");
244.2090 + case 0:
244.2091 + if (cursor >= patternLength) {
244.2092 + break LOOP;
244.2093 + }
244.2094 + // Fall through
244.2095 + default:
244.2096 + node = atom();
244.2097 + break;
244.2098 + }
244.2099 +
244.2100 + node = closure(node);
244.2101 +
244.2102 + if (head == null) {
244.2103 + head = tail = node;
244.2104 + } else {
244.2105 + tail.next = node;
244.2106 + tail = node;
244.2107 + }
244.2108 + }
244.2109 + if (head == null) {
244.2110 + return end;
244.2111 + }
244.2112 + tail.next = end;
244.2113 + root = tail; //double return
244.2114 + return head;
244.2115 + }
244.2116 +
244.2117 + /**
244.2118 + * Parse and add a new Single or Slice.
244.2119 + */
244.2120 + private Node atom() {
244.2121 + int first = 0;
244.2122 + int prev = -1;
244.2123 + boolean hasSupplementary = false;
244.2124 + int ch = peek();
244.2125 + for (;;) {
244.2126 + switch (ch) {
244.2127 + case '*':
244.2128 + case '+':
244.2129 + case '?':
244.2130 + case '{':
244.2131 + if (first > 1) {
244.2132 + cursor = prev; // Unwind one character
244.2133 + first--;
244.2134 + }
244.2135 + break;
244.2136 + case '$':
244.2137 + case '.':
244.2138 + case '^':
244.2139 + case '(':
244.2140 + case '[':
244.2141 + case '|':
244.2142 + case ')':
244.2143 + break;
244.2144 + case '\\':
244.2145 + ch = nextEscaped();
244.2146 + if (ch == 'p' || ch == 'P') { // Property
244.2147 + if (first > 0) { // Slice is waiting; handle it first
244.2148 + unread();
244.2149 + break;
244.2150 + } else { // No slice; just return the family node
244.2151 + boolean comp = (ch == 'P');
244.2152 + boolean oneLetter = true;
244.2153 + ch = next(); // Consume { if present
244.2154 + if (ch != '{')
244.2155 + unread();
244.2156 + else
244.2157 + oneLetter = false;
244.2158 + return family(oneLetter, comp);
244.2159 + }
244.2160 + }
244.2161 + unread();
244.2162 + prev = cursor;
244.2163 + ch = escape(false, first == 0);
244.2164 + if (ch >= 0) {
244.2165 + append(ch, first);
244.2166 + first++;
244.2167 + if (isSupplementary(ch)) {
244.2168 + hasSupplementary = true;
244.2169 + }
244.2170 + ch = peek();
244.2171 + continue;
244.2172 + } else if (first == 0) {
244.2173 + return root;
244.2174 + }
244.2175 + // Unwind meta escape sequence
244.2176 + cursor = prev;
244.2177 + break;
244.2178 + case 0:
244.2179 + if (cursor >= patternLength) {
244.2180 + break;
244.2181 + }
244.2182 + // Fall through
244.2183 + default:
244.2184 + prev = cursor;
244.2185 + append(ch, first);
244.2186 + first++;
244.2187 + if (isSupplementary(ch)) {
244.2188 + hasSupplementary = true;
244.2189 + }
244.2190 + ch = next();
244.2191 + continue;
244.2192 + }
244.2193 + break;
244.2194 + }
244.2195 + if (first == 1) {
244.2196 + return newSingle(buffer[0]);
244.2197 + } else {
244.2198 + return newSlice(buffer, first, hasSupplementary);
244.2199 + }
244.2200 + }
244.2201 +
244.2202 + private void append(int ch, int len) {
244.2203 + if (len >= buffer.length) {
244.2204 + int[] tmp = new int[len+len];
244.2205 + System.arraycopy(buffer, 0, tmp, 0, len);
244.2206 + buffer = tmp;
244.2207 + }
244.2208 + buffer[len] = ch;
244.2209 + }
244.2210 +
244.2211 + /**
244.2212 + * Parses a backref greedily, taking as many numbers as it
244.2213 + * can. The first digit is always treated as a backref, but
244.2214 + * multi digit numbers are only treated as a backref if at
244.2215 + * least that many backrefs exist at this point in the regex.
244.2216 + */
244.2217 + private Node ref(int refNum) {
244.2218 + boolean done = false;
244.2219 + while(!done) {
244.2220 + int ch = peek();
244.2221 + switch(ch) {
244.2222 + case '0':
244.2223 + case '1':
244.2224 + case '2':
244.2225 + case '3':
244.2226 + case '4':
244.2227 + case '5':
244.2228 + case '6':
244.2229 + case '7':
244.2230 + case '8':
244.2231 + case '9':
244.2232 + int newRefNum = (refNum * 10) + (ch - '0');
244.2233 + // Add another number if it doesn't make a group
244.2234 + // that doesn't exist
244.2235 + if (capturingGroupCount - 1 < newRefNum) {
244.2236 + done = true;
244.2237 + break;
244.2238 + }
244.2239 + refNum = newRefNum;
244.2240 + read();
244.2241 + break;
244.2242 + default:
244.2243 + done = true;
244.2244 + break;
244.2245 + }
244.2246 + }
244.2247 + if (has(CASE_INSENSITIVE))
244.2248 + return new CIBackRef(refNum, has(UNICODE_CASE));
244.2249 + else
244.2250 + return new BackRef(refNum);
244.2251 + }
244.2252 +
244.2253 + /**
244.2254 + * Parses an escape sequence to determine the actual value that needs
244.2255 + * to be matched.
244.2256 + * If -1 is returned and create was true a new object was added to the tree
244.2257 + * to handle the escape sequence.
244.2258 + * If the returned value is greater than zero, it is the value that
244.2259 + * matches the escape sequence.
244.2260 + */
244.2261 + private int escape(boolean inclass, boolean create) {
244.2262 + int ch = skip();
244.2263 + switch (ch) {
244.2264 + case '0':
244.2265 + return o();
244.2266 + case '1':
244.2267 + case '2':
244.2268 + case '3':
244.2269 + case '4':
244.2270 + case '5':
244.2271 + case '6':
244.2272 + case '7':
244.2273 + case '8':
244.2274 + case '9':
244.2275 + if (inclass) break;
244.2276 + if (create) {
244.2277 + root = ref((ch - '0'));
244.2278 + }
244.2279 + return -1;
244.2280 + case 'A':
244.2281 + if (inclass) break;
244.2282 + if (create) root = new Begin();
244.2283 + return -1;
244.2284 + case 'B':
244.2285 + if (inclass) break;
244.2286 + if (create) root = new Bound(Bound.NONE, has(UNICODE_CHARACTER_CLASS));
244.2287 + return -1;
244.2288 + case 'C':
244.2289 + break;
244.2290 + case 'D':
244.2291 + if (create) root = has(UNICODE_CHARACTER_CLASS)
244.2292 + ? new Utype(UnicodeProp.DIGIT).complement()
244.2293 + : new Ctype(ASCII.DIGIT).complement();
244.2294 + return -1;
244.2295 + case 'E':
244.2296 + case 'F':
244.2297 + break;
244.2298 + case 'G':
244.2299 + if (inclass) break;
244.2300 + if (create) root = new LastMatch();
244.2301 + return -1;
244.2302 + case 'H':
244.2303 + case 'I':
244.2304 + case 'J':
244.2305 + case 'K':
244.2306 + case 'L':
244.2307 + case 'M':
244.2308 + case 'N':
244.2309 + case 'O':
244.2310 + case 'P':
244.2311 + case 'Q':
244.2312 + case 'R':
244.2313 + break;
244.2314 + case 'S':
244.2315 + if (create) root = has(UNICODE_CHARACTER_CLASS)
244.2316 + ? new Utype(UnicodeProp.WHITE_SPACE).complement()
244.2317 + : new Ctype(ASCII.SPACE).complement();
244.2318 + return -1;
244.2319 + case 'T':
244.2320 + case 'U':
244.2321 + case 'V':
244.2322 + break;
244.2323 + case 'W':
244.2324 + if (create) root = has(UNICODE_CHARACTER_CLASS)
244.2325 + ? new Utype(UnicodeProp.WORD).complement()
244.2326 + : new Ctype(ASCII.WORD).complement();
244.2327 + return -1;
244.2328 + case 'X':
244.2329 + case 'Y':
244.2330 + break;
244.2331 + case 'Z':
244.2332 + if (inclass) break;
244.2333 + if (create) {
244.2334 + if (has(UNIX_LINES))
244.2335 + root = new UnixDollar(false);
244.2336 + else
244.2337 + root = new Dollar(false);
244.2338 + }
244.2339 + return -1;
244.2340 + case 'a':
244.2341 + return '\007';
244.2342 + case 'b':
244.2343 + if (inclass) break;
244.2344 + if (create) root = new Bound(Bound.BOTH, has(UNICODE_CHARACTER_CLASS));
244.2345 + return -1;
244.2346 + case 'c':
244.2347 + return c();
244.2348 + case 'd':
244.2349 + if (create) root = has(UNICODE_CHARACTER_CLASS)
244.2350 + ? new Utype(UnicodeProp.DIGIT)
244.2351 + : new Ctype(ASCII.DIGIT);
244.2352 + return -1;
244.2353 + case 'e':
244.2354 + return '\033';
244.2355 + case 'f':
244.2356 + return '\f';
244.2357 + case 'g':
244.2358 + case 'h':
244.2359 + case 'i':
244.2360 + case 'j':
244.2361 + break;
244.2362 + case 'k':
244.2363 + if (inclass)
244.2364 + break;
244.2365 + if (read() != '<')
244.2366 + throw error("\\k is not followed by '<' for named capturing group");
244.2367 + String name = groupname(read());
244.2368 + if (!namedGroups().containsKey(name))
244.2369 + throw error("(named capturing group <"+ name+"> does not exit");
244.2370 + if (create) {
244.2371 + if (has(CASE_INSENSITIVE))
244.2372 + root = new CIBackRef(namedGroups().get(name), has(UNICODE_CASE));
244.2373 + else
244.2374 + root = new BackRef(namedGroups().get(name));
244.2375 + }
244.2376 + return -1;
244.2377 + case 'l':
244.2378 + case 'm':
244.2379 + break;
244.2380 + case 'n':
244.2381 + return '\n';
244.2382 + case 'o':
244.2383 + case 'p':
244.2384 + case 'q':
244.2385 + break;
244.2386 + case 'r':
244.2387 + return '\r';
244.2388 + case 's':
244.2389 + if (create) root = has(UNICODE_CHARACTER_CLASS)
244.2390 + ? new Utype(UnicodeProp.WHITE_SPACE)
244.2391 + : new Ctype(ASCII.SPACE);
244.2392 + return -1;
244.2393 + case 't':
244.2394 + return '\t';
244.2395 + case 'u':
244.2396 + return u();
244.2397 + case 'v':
244.2398 + return '\013';
244.2399 + case 'w':
244.2400 + if (create) root = has(UNICODE_CHARACTER_CLASS)
244.2401 + ? new Utype(UnicodeProp.WORD)
244.2402 + : new Ctype(ASCII.WORD);
244.2403 + return -1;
244.2404 + case 'x':
244.2405 + return x();
244.2406 + case 'y':
244.2407 + break;
244.2408 + case 'z':
244.2409 + if (inclass) break;
244.2410 + if (create) root = new End();
244.2411 + return -1;
244.2412 + default:
244.2413 + return ch;
244.2414 + }
244.2415 + throw error("Illegal/unsupported escape sequence");
244.2416 + }
244.2417 +
244.2418 + /**
244.2419 + * Parse a character class, and return the node that matches it.
244.2420 + *
244.2421 + * Consumes a ] on the way out if consume is true. Usually consume
244.2422 + * is true except for the case of [abc&&def] where def is a separate
244.2423 + * right hand node with "understood" brackets.
244.2424 + */
244.2425 + private CharProperty clazz(boolean consume) {
244.2426 + CharProperty prev = null;
244.2427 + CharProperty node = null;
244.2428 + BitClass bits = new BitClass();
244.2429 + boolean include = true;
244.2430 + boolean firstInClass = true;
244.2431 + int ch = next();
244.2432 + for (;;) {
244.2433 + switch (ch) {
244.2434 + case '^':
244.2435 + // Negates if first char in a class, otherwise literal
244.2436 + if (firstInClass) {
244.2437 + if (temp[cursor-1] != '[')
244.2438 + break;
244.2439 + ch = next();
244.2440 + include = !include;
244.2441 + continue;
244.2442 + } else {
244.2443 + // ^ not first in class, treat as literal
244.2444 + break;
244.2445 + }
244.2446 + case '[':
244.2447 + firstInClass = false;
244.2448 + node = clazz(true);
244.2449 + if (prev == null)
244.2450 + prev = node;
244.2451 + else
244.2452 + prev = union(prev, node);
244.2453 + ch = peek();
244.2454 + continue;
244.2455 + case '&':
244.2456 + firstInClass = false;
244.2457 + ch = next();
244.2458 + if (ch == '&') {
244.2459 + ch = next();
244.2460 + CharProperty rightNode = null;
244.2461 + while (ch != ']' && ch != '&') {
244.2462 + if (ch == '[') {
244.2463 + if (rightNode == null)
244.2464 + rightNode = clazz(true);
244.2465 + else
244.2466 + rightNode = union(rightNode, clazz(true));
244.2467 + } else { // abc&&def
244.2468 + unread();
244.2469 + rightNode = clazz(false);
244.2470 + }
244.2471 + ch = peek();
244.2472 + }
244.2473 + if (rightNode != null)
244.2474 + node = rightNode;
244.2475 + if (prev == null) {
244.2476 + if (rightNode == null)
244.2477 + throw error("Bad class syntax");
244.2478 + else
244.2479 + prev = rightNode;
244.2480 + } else {
244.2481 + prev = intersection(prev, node);
244.2482 + }
244.2483 + } else {
244.2484 + // treat as a literal &
244.2485 + unread();
244.2486 + break;
244.2487 + }
244.2488 + continue;
244.2489 + case 0:
244.2490 + firstInClass = false;
244.2491 + if (cursor >= patternLength)
244.2492 + throw error("Unclosed character class");
244.2493 + break;
244.2494 + case ']':
244.2495 + firstInClass = false;
244.2496 + if (prev != null) {
244.2497 + if (consume)
244.2498 + next();
244.2499 + return prev;
244.2500 + }
244.2501 + break;
244.2502 + default:
244.2503 + firstInClass = false;
244.2504 + break;
244.2505 + }
244.2506 + node = range(bits);
244.2507 + if (include) {
244.2508 + if (prev == null) {
244.2509 + prev = node;
244.2510 + } else {
244.2511 + if (prev != node)
244.2512 + prev = union(prev, node);
244.2513 + }
244.2514 + } else {
244.2515 + if (prev == null) {
244.2516 + prev = node.complement();
244.2517 + } else {
244.2518 + if (prev != node)
244.2519 + prev = setDifference(prev, node);
244.2520 + }
244.2521 + }
244.2522 + ch = peek();
244.2523 + }
244.2524 + }
244.2525 +
244.2526 + private CharProperty bitsOrSingle(BitClass bits, int ch) {
244.2527 + /* Bits can only handle codepoints in [u+0000-u+00ff] range.
244.2528 + Use "single" node instead of bits when dealing with unicode
244.2529 + case folding for codepoints listed below.
244.2530 + (1)Uppercase out of range: u+00ff, u+00b5
244.2531 + toUpperCase(u+00ff) -> u+0178
244.2532 + toUpperCase(u+00b5) -> u+039c
244.2533 + (2)LatinSmallLetterLongS u+17f
244.2534 + toUpperCase(u+017f) -> u+0053
244.2535 + (3)LatinSmallLetterDotlessI u+131
244.2536 + toUpperCase(u+0131) -> u+0049
244.2537 + (4)LatinCapitalLetterIWithDotAbove u+0130
244.2538 + toLowerCase(u+0130) -> u+0069
244.2539 + (5)KelvinSign u+212a
244.2540 + toLowerCase(u+212a) ==> u+006B
244.2541 + (6)AngstromSign u+212b
244.2542 + toLowerCase(u+212b) ==> u+00e5
244.2543 + */
244.2544 + int d;
244.2545 + if (ch < 256 &&
244.2546 + !(has(CASE_INSENSITIVE) && has(UNICODE_CASE) &&
244.2547 + (ch == 0xff || ch == 0xb5 ||
244.2548 + ch == 0x49 || ch == 0x69 || //I and i
244.2549 + ch == 0x53 || ch == 0x73 || //S and s
244.2550 + ch == 0x4b || ch == 0x6b || //K and k
244.2551 + ch == 0xc5 || ch == 0xe5))) //A+ring
244.2552 + return bits.add(ch, flags());
244.2553 + return newSingle(ch);
244.2554 + }
244.2555 +
244.2556 + /**
244.2557 + * Parse a single character or a character range in a character class
244.2558 + * and return its representative node.
244.2559 + */
244.2560 + private CharProperty range(BitClass bits) {
244.2561 + int ch = peek();
244.2562 + if (ch == '\\') {
244.2563 + ch = nextEscaped();
244.2564 + if (ch == 'p' || ch == 'P') { // A property
244.2565 + boolean comp = (ch == 'P');
244.2566 + boolean oneLetter = true;
244.2567 + // Consume { if present
244.2568 + ch = next();
244.2569 + if (ch != '{')
244.2570 + unread();
244.2571 + else
244.2572 + oneLetter = false;
244.2573 + return family(oneLetter, comp);
244.2574 + } else { // ordinary escape
244.2575 + unread();
244.2576 + ch = escape(true, true);
244.2577 + if (ch == -1)
244.2578 + return (CharProperty) root;
244.2579 + }
244.2580 + } else {
244.2581 + ch = single();
244.2582 + }
244.2583 + if (ch >= 0) {
244.2584 + if (peek() == '-') {
244.2585 + int endRange = temp[cursor+1];
244.2586 + if (endRange == '[') {
244.2587 + return bitsOrSingle(bits, ch);
244.2588 + }
244.2589 + if (endRange != ']') {
244.2590 + next();
244.2591 + int m = single();
244.2592 + if (m < ch)
244.2593 + throw error("Illegal character range");
244.2594 + if (has(CASE_INSENSITIVE))
244.2595 + return caseInsensitiveRangeFor(ch, m);
244.2596 + else
244.2597 + return rangeFor(ch, m);
244.2598 + }
244.2599 + }
244.2600 + return bitsOrSingle(bits, ch);
244.2601 + }
244.2602 + throw error("Unexpected character '"+((char)ch)+"'");
244.2603 + }
244.2604 +
244.2605 + private int single() {
244.2606 + int ch = peek();
244.2607 + switch (ch) {
244.2608 + case '\\':
244.2609 + return escape(true, false);
244.2610 + default:
244.2611 + next();
244.2612 + return ch;
244.2613 + }
244.2614 + }
244.2615 +
244.2616 + /**
244.2617 + * Parses a Unicode character family and returns its representative node.
244.2618 + */
244.2619 + private CharProperty family(boolean singleLetter,
244.2620 + boolean maybeComplement)
244.2621 + {
244.2622 + next();
244.2623 + String name;
244.2624 + CharProperty node = null;
244.2625 +
244.2626 + if (singleLetter) {
244.2627 + int c = temp[cursor];
244.2628 + if (!Character.isSupplementaryCodePoint(c)) {
244.2629 + name = String.valueOf((char)c);
244.2630 + } else {
244.2631 + name = new String(temp, cursor, 1);
244.2632 + }
244.2633 + read();
244.2634 + } else {
244.2635 + int i = cursor;
244.2636 + mark('}');
244.2637 + while(read() != '}') {
244.2638 + }
244.2639 + mark('\000');
244.2640 + int j = cursor;
244.2641 + if (j > patternLength)
244.2642 + throw error("Unclosed character family");
244.2643 + if (i + 1 >= j)
244.2644 + throw error("Empty character family");
244.2645 + name = new String(temp, i, j-i-1);
244.2646 + }
244.2647 +
244.2648 + int i = name.indexOf('=');
244.2649 + if (i != -1) {
244.2650 + // property construct \p{name=value}
244.2651 + String value = name.substring(i + 1);
244.2652 + name = name.substring(0, i).toLowerCase(Locale.ENGLISH);
244.2653 + /* if ("sc".equals(name) || "script".equals(name)) {
244.2654 + node = unicodeScriptPropertyFor(value);
244.2655 + } else if ("blk".equals(name) || "block".equals(name)) {
244.2656 + node = unicodeBlockPropertyFor(value);
244.2657 + } else*/ if ("gc".equals(name) || "general_category".equals(name)) {
244.2658 + node = charPropertyNodeFor(value);
244.2659 + } else {
244.2660 + throw error("Unknown Unicode property {name=<" + name + ">, "
244.2661 + + "value=<" + value + ">}");
244.2662 + }
244.2663 + } else {
244.2664 + /*if (name.startsWith("In")) {
244.2665 + // \p{inBlockName}
244.2666 + node = unicodeBlockPropertyFor(name.substring(2));
244.2667 + } else if (name.startsWith("Is")) {
244.2668 + // \p{isGeneralCategory} and \p{isScriptName}
244.2669 + name = name.substring(2);
244.2670 + UnicodeProp uprop = UnicodeProp.forName(name);
244.2671 + if (uprop != null)
244.2672 + node = new Utype(uprop);
244.2673 + if (node == null)
244.2674 + node = CharPropertyNames.charPropertyFor(name);
244.2675 + if (node == null)
244.2676 + node = unicodeScriptPropertyFor(name);
244.2677 + } else*/ {
244.2678 + if (has(UNICODE_CHARACTER_CLASS)) {
244.2679 + UnicodeProp uprop = UnicodeProp.forPOSIXName(name);
244.2680 + if (uprop != null)
244.2681 + node = new Utype(uprop);
244.2682 + }
244.2683 + if (node == null)
244.2684 + node = charPropertyNodeFor(name);
244.2685 + }
244.2686 + }
244.2687 + if (maybeComplement) {
244.2688 + if (node instanceof Category /*|| node instanceof Block*/)
244.2689 + hasSupplementary = true;
244.2690 + node = node.complement();
244.2691 + }
244.2692 + return node;
244.2693 + }
244.2694 +
244.2695 +
244.2696 + /**
244.2697 + * Returns a CharProperty matching all characters belong to
244.2698 + * a UnicodeScript.
244.2699 + *
244.2700 + private CharProperty unicodeScriptPropertyFor(String name) {
244.2701 + final Character.UnicodeScript script;
244.2702 + try {
244.2703 + script = Character.UnicodeScript.forName(name);
244.2704 + } catch (IllegalArgumentException iae) {
244.2705 + throw error("Unknown character script name {" + name + "}");
244.2706 + }
244.2707 + return new Script(script);
244.2708 + }
244.2709 +
244.2710 + /**
244.2711 + * Returns a CharProperty matching all characters in a UnicodeBlock.
244.2712 + *
244.2713 + private CharProperty unicodeBlockPropertyFor(String name) {
244.2714 + final Character.UnicodeBlock block;
244.2715 + try {
244.2716 + block = Character.UnicodeBlock.forName(name);
244.2717 + } catch (IllegalArgumentException iae) {
244.2718 + throw error("Unknown character block name {" + name + "}");
244.2719 + }
244.2720 + return new Block(block);
244.2721 + }
244.2722 +
244.2723 + /**
244.2724 + * Returns a CharProperty matching all characters in a named property.
244.2725 + */
244.2726 + private CharProperty charPropertyNodeFor(String name) {
244.2727 + CharProperty p = CharPropertyNames.charPropertyFor(name);
244.2728 + if (p == null)
244.2729 + throw error("Unknown character property name {" + name + "}");
244.2730 + return p;
244.2731 + }
244.2732 +
244.2733 + /**
244.2734 + * Parses and returns the name of a "named capturing group", the trailing
244.2735 + * ">" is consumed after parsing.
244.2736 + */
244.2737 + private String groupname(int ch) {
244.2738 + StringBuilder sb = new StringBuilder();
244.2739 + sb.append(Character.toChars(ch));
244.2740 + while (ASCII.isLower(ch=read()) || ASCII.isUpper(ch) ||
244.2741 + ASCII.isDigit(ch)) {
244.2742 + sb.append(Character.toChars(ch));
244.2743 + }
244.2744 + if (sb.length() == 0)
244.2745 + throw error("named capturing group has 0 length name");
244.2746 + if (ch != '>')
244.2747 + throw error("named capturing group is missing trailing '>'");
244.2748 + return sb.toString();
244.2749 + }
244.2750 +
244.2751 + /**
244.2752 + * Parses a group and returns the head node of a set of nodes that process
244.2753 + * the group. Sometimes a double return system is used where the tail is
244.2754 + * returned in root.
244.2755 + */
244.2756 + private Node group0() {
244.2757 + boolean capturingGroup = false;
244.2758 + Node head = null;
244.2759 + Node tail = null;
244.2760 + int save = flags;
244.2761 + root = null;
244.2762 + int ch = next();
244.2763 + if (ch == '?') {
244.2764 + ch = skip();
244.2765 + switch (ch) {
244.2766 + case ':': // (?:xxx) pure group
244.2767 + head = createGroup(true);
244.2768 + tail = root;
244.2769 + head.next = expr(tail);
244.2770 + break;
244.2771 + case '=': // (?=xxx) and (?!xxx) lookahead
244.2772 + case '!':
244.2773 + head = createGroup(true);
244.2774 + tail = root;
244.2775 + head.next = expr(tail);
244.2776 + if (ch == '=') {
244.2777 + head = tail = new Pos(head);
244.2778 + } else {
244.2779 + head = tail = new Neg(head);
244.2780 + }
244.2781 + break;
244.2782 + case '>': // (?>xxx) independent group
244.2783 + head = createGroup(true);
244.2784 + tail = root;
244.2785 + head.next = expr(tail);
244.2786 + head = tail = new Ques(head, INDEPENDENT);
244.2787 + break;
244.2788 + case '<': // (?<xxx) look behind
244.2789 + ch = read();
244.2790 + if (ASCII.isLower(ch) || ASCII.isUpper(ch)) {
244.2791 + // named captured group
244.2792 + String name = groupname(ch);
244.2793 + if (namedGroups().containsKey(name))
244.2794 + throw error("Named capturing group <" + name
244.2795 + + "> is already defined");
244.2796 + capturingGroup = true;
244.2797 + head = createGroup(false);
244.2798 + tail = root;
244.2799 + namedGroups().put(name, capturingGroupCount-1);
244.2800 + head.next = expr(tail);
244.2801 + break;
244.2802 + }
244.2803 + int start = cursor;
244.2804 + head = createGroup(true);
244.2805 + tail = root;
244.2806 + head.next = expr(tail);
244.2807 + tail.next = lookbehindEnd;
244.2808 + TreeInfo info = new TreeInfo();
244.2809 + head.study(info);
244.2810 + if (info.maxValid == false) {
244.2811 + throw error("Look-behind group does not have "
244.2812 + + "an obvious maximum length");
244.2813 + }
244.2814 + boolean hasSupplementary = findSupplementary(start, patternLength);
244.2815 + if (ch == '=') {
244.2816 + head = tail = (hasSupplementary ?
244.2817 + new BehindS(head, info.maxLength,
244.2818 + info.minLength) :
244.2819 + new Behind(head, info.maxLength,
244.2820 + info.minLength));
244.2821 + } else if (ch == '!') {
244.2822 + head = tail = (hasSupplementary ?
244.2823 + new NotBehindS(head, info.maxLength,
244.2824 + info.minLength) :
244.2825 + new NotBehind(head, info.maxLength,
244.2826 + info.minLength));
244.2827 + } else {
244.2828 + throw error("Unknown look-behind group");
244.2829 + }
244.2830 + break;
244.2831 + case '$':
244.2832 + case '@':
244.2833 + throw error("Unknown group type");
244.2834 + default: // (?xxx:) inlined match flags
244.2835 + unread();
244.2836 + addFlag();
244.2837 + ch = read();
244.2838 + if (ch == ')') {
244.2839 + return null; // Inline modifier only
244.2840 + }
244.2841 + if (ch != ':') {
244.2842 + throw error("Unknown inline modifier");
244.2843 + }
244.2844 + head = createGroup(true);
244.2845 + tail = root;
244.2846 + head.next = expr(tail);
244.2847 + break;
244.2848 + }
244.2849 + } else { // (xxx) a regular group
244.2850 + capturingGroup = true;
244.2851 + head = createGroup(false);
244.2852 + tail = root;
244.2853 + head.next = expr(tail);
244.2854 + }
244.2855 +
244.2856 + accept(')', "Unclosed group");
244.2857 + flags = save;
244.2858 +
244.2859 + // Check for quantifiers
244.2860 + Node node = closure(head);
244.2861 + if (node == head) { // No closure
244.2862 + root = tail;
244.2863 + return node; // Dual return
244.2864 + }
244.2865 + if (head == tail) { // Zero length assertion
244.2866 + root = node;
244.2867 + return node; // Dual return
244.2868 + }
244.2869 +
244.2870 + if (node instanceof Ques) {
244.2871 + Ques ques = (Ques) node;
244.2872 + if (ques.type == POSSESSIVE) {
244.2873 + root = node;
244.2874 + return node;
244.2875 + }
244.2876 + tail.next = new BranchConn();
244.2877 + tail = tail.next;
244.2878 + if (ques.type == GREEDY) {
244.2879 + head = new Branch(head, null, tail);
244.2880 + } else { // Reluctant quantifier
244.2881 + head = new Branch(null, head, tail);
244.2882 + }
244.2883 + root = tail;
244.2884 + return head;
244.2885 + } else if (node instanceof Curly) {
244.2886 + Curly curly = (Curly) node;
244.2887 + if (curly.type == POSSESSIVE) {
244.2888 + root = node;
244.2889 + return node;
244.2890 + }
244.2891 + // Discover if the group is deterministic
244.2892 + TreeInfo info = new TreeInfo();
244.2893 + if (head.study(info)) { // Deterministic
244.2894 + GroupTail temp = (GroupTail) tail;
244.2895 + head = root = new GroupCurly(head.next, curly.cmin,
244.2896 + curly.cmax, curly.type,
244.2897 + ((GroupTail)tail).localIndex,
244.2898 + ((GroupTail)tail).groupIndex,
244.2899 + capturingGroup);
244.2900 + return head;
244.2901 + } else { // Non-deterministic
244.2902 + int temp = ((GroupHead) head).localIndex;
244.2903 + Loop loop;
244.2904 + if (curly.type == GREEDY)
244.2905 + loop = new Loop(this.localCount, temp);
244.2906 + else // Reluctant Curly
244.2907 + loop = new LazyLoop(this.localCount, temp);
244.2908 + Prolog prolog = new Prolog(loop);
244.2909 + this.localCount += 1;
244.2910 + loop.cmin = curly.cmin;
244.2911 + loop.cmax = curly.cmax;
244.2912 + loop.body = head;
244.2913 + tail.next = loop;
244.2914 + root = loop;
244.2915 + return prolog; // Dual return
244.2916 + }
244.2917 + }
244.2918 + throw error("Internal logic error");
244.2919 + }
244.2920 +
244.2921 + /**
244.2922 + * Create group head and tail nodes using double return. If the group is
244.2923 + * created with anonymous true then it is a pure group and should not
244.2924 + * affect group counting.
244.2925 + */
244.2926 + private Node createGroup(boolean anonymous) {
244.2927 + int localIndex = localCount++;
244.2928 + int groupIndex = 0;
244.2929 + if (!anonymous)
244.2930 + groupIndex = capturingGroupCount++;
244.2931 + GroupHead head = new GroupHead(localIndex);
244.2932 + root = new GroupTail(localIndex, groupIndex);
244.2933 + if (!anonymous && groupIndex < 10)
244.2934 + groupNodes[groupIndex] = head;
244.2935 + return head;
244.2936 + }
244.2937 +
244.2938 + /**
244.2939 + * Parses inlined match flags and set them appropriately.
244.2940 + */
244.2941 + private void addFlag() {
244.2942 + int ch = peek();
244.2943 + for (;;) {
244.2944 + switch (ch) {
244.2945 + case 'i':
244.2946 + flags |= CASE_INSENSITIVE;
244.2947 + break;
244.2948 + case 'm':
244.2949 + flags |= MULTILINE;
244.2950 + break;
244.2951 + case 's':
244.2952 + flags |= DOTALL;
244.2953 + break;
244.2954 + case 'd':
244.2955 + flags |= UNIX_LINES;
244.2956 + break;
244.2957 + case 'u':
244.2958 + flags |= UNICODE_CASE;
244.2959 + break;
244.2960 + case 'c':
244.2961 + flags |= CANON_EQ;
244.2962 + break;
244.2963 + case 'x':
244.2964 + flags |= COMMENTS;
244.2965 + break;
244.2966 + case 'U':
244.2967 + flags |= (UNICODE_CHARACTER_CLASS | UNICODE_CASE);
244.2968 + break;
244.2969 + case '-': // subFlag then fall through
244.2970 + ch = next();
244.2971 + subFlag();
244.2972 + default:
244.2973 + return;
244.2974 + }
244.2975 + ch = next();
244.2976 + }
244.2977 + }
244.2978 +
244.2979 + /**
244.2980 + * Parses the second part of inlined match flags and turns off
244.2981 + * flags appropriately.
244.2982 + */
244.2983 + private void subFlag() {
244.2984 + int ch = peek();
244.2985 + for (;;) {
244.2986 + switch (ch) {
244.2987 + case 'i':
244.2988 + flags &= ~CASE_INSENSITIVE;
244.2989 + break;
244.2990 + case 'm':
244.2991 + flags &= ~MULTILINE;
244.2992 + break;
244.2993 + case 's':
244.2994 + flags &= ~DOTALL;
244.2995 + break;
244.2996 + case 'd':
244.2997 + flags &= ~UNIX_LINES;
244.2998 + break;
244.2999 + case 'u':
244.3000 + flags &= ~UNICODE_CASE;
244.3001 + break;
244.3002 + case 'c':
244.3003 + flags &= ~CANON_EQ;
244.3004 + break;
244.3005 + case 'x':
244.3006 + flags &= ~COMMENTS;
244.3007 + break;
244.3008 + case 'U':
244.3009 + flags &= ~(UNICODE_CHARACTER_CLASS | UNICODE_CASE);
244.3010 + default:
244.3011 + return;
244.3012 + }
244.3013 + ch = next();
244.3014 + }
244.3015 + }
244.3016 +
244.3017 + static final int MAX_REPS = 0x7FFFFFFF;
244.3018 +
244.3019 + static final int GREEDY = 0;
244.3020 +
244.3021 + static final int LAZY = 1;
244.3022 +
244.3023 + static final int POSSESSIVE = 2;
244.3024 +
244.3025 + static final int INDEPENDENT = 3;
244.3026 +
244.3027 + /**
244.3028 + * Processes repetition. If the next character peeked is a quantifier
244.3029 + * then new nodes must be appended to handle the repetition.
244.3030 + * Prev could be a single or a group, so it could be a chain of nodes.
244.3031 + */
244.3032 + private Node closure(Node prev) {
244.3033 + Node atom;
244.3034 + int ch = peek();
244.3035 + switch (ch) {
244.3036 + case '?':
244.3037 + ch = next();
244.3038 + if (ch == '?') {
244.3039 + next();
244.3040 + return new Ques(prev, LAZY);
244.3041 + } else if (ch == '+') {
244.3042 + next();
244.3043 + return new Ques(prev, POSSESSIVE);
244.3044 + }
244.3045 + return new Ques(prev, GREEDY);
244.3046 + case '*':
244.3047 + ch = next();
244.3048 + if (ch == '?') {
244.3049 + next();
244.3050 + return new Curly(prev, 0, MAX_REPS, LAZY);
244.3051 + } else if (ch == '+') {
244.3052 + next();
244.3053 + return new Curly(prev, 0, MAX_REPS, POSSESSIVE);
244.3054 + }
244.3055 + return new Curly(prev, 0, MAX_REPS, GREEDY);
244.3056 + case '+':
244.3057 + ch = next();
244.3058 + if (ch == '?') {
244.3059 + next();
244.3060 + return new Curly(prev, 1, MAX_REPS, LAZY);
244.3061 + } else if (ch == '+') {
244.3062 + next();
244.3063 + return new Curly(prev, 1, MAX_REPS, POSSESSIVE);
244.3064 + }
244.3065 + return new Curly(prev, 1, MAX_REPS, GREEDY);
244.3066 + case '{':
244.3067 + ch = temp[cursor+1];
244.3068 + if (ASCII.isDigit(ch)) {
244.3069 + skip();
244.3070 + int cmin = 0;
244.3071 + do {
244.3072 + cmin = cmin * 10 + (ch - '0');
244.3073 + } while (ASCII.isDigit(ch = read()));
244.3074 + int cmax = cmin;
244.3075 + if (ch == ',') {
244.3076 + ch = read();
244.3077 + cmax = MAX_REPS;
244.3078 + if (ch != '}') {
244.3079 + cmax = 0;
244.3080 + while (ASCII.isDigit(ch)) {
244.3081 + cmax = cmax * 10 + (ch - '0');
244.3082 + ch = read();
244.3083 + }
244.3084 + }
244.3085 + }
244.3086 + if (ch != '}')
244.3087 + throw error("Unclosed counted closure");
244.3088 + if (((cmin) | (cmax) | (cmax - cmin)) < 0)
244.3089 + throw error("Illegal repetition range");
244.3090 + Curly curly;
244.3091 + ch = peek();
244.3092 + if (ch == '?') {
244.3093 + next();
244.3094 + curly = new Curly(prev, cmin, cmax, LAZY);
244.3095 + } else if (ch == '+') {
244.3096 + next();
244.3097 + curly = new Curly(prev, cmin, cmax, POSSESSIVE);
244.3098 + } else {
244.3099 + curly = new Curly(prev, cmin, cmax, GREEDY);
244.3100 + }
244.3101 + return curly;
244.3102 + } else {
244.3103 + throw error("Illegal repetition");
244.3104 + }
244.3105 + default:
244.3106 + return prev;
244.3107 + }
244.3108 + }
244.3109 +
244.3110 + /**
244.3111 + * Utility method for parsing control escape sequences.
244.3112 + */
244.3113 + private int c() {
244.3114 + if (cursor < patternLength) {
244.3115 + return read() ^ 64;
244.3116 + }
244.3117 + throw error("Illegal control escape sequence");
244.3118 + }
244.3119 +
244.3120 + /**
244.3121 + * Utility method for parsing octal escape sequences.
244.3122 + */
244.3123 + private int o() {
244.3124 + int n = read();
244.3125 + if (((n-'0')|('7'-n)) >= 0) {
244.3126 + int m = read();
244.3127 + if (((m-'0')|('7'-m)) >= 0) {
244.3128 + int o = read();
244.3129 + if ((((o-'0')|('7'-o)) >= 0) && (((n-'0')|('3'-n)) >= 0)) {
244.3130 + return (n - '0') * 64 + (m - '0') * 8 + (o - '0');
244.3131 + }
244.3132 + unread();
244.3133 + return (n - '0') * 8 + (m - '0');
244.3134 + }
244.3135 + unread();
244.3136 + return (n - '0');
244.3137 + }
244.3138 + throw error("Illegal octal escape sequence");
244.3139 + }
244.3140 +
244.3141 + /**
244.3142 + * Utility method for parsing hexadecimal escape sequences.
244.3143 + */
244.3144 + private int x() {
244.3145 + int n = read();
244.3146 + if (ASCII.isHexDigit(n)) {
244.3147 + int m = read();
244.3148 + if (ASCII.isHexDigit(m)) {
244.3149 + return ASCII.toDigit(n) * 16 + ASCII.toDigit(m);
244.3150 + }
244.3151 + } else if (n == '{' && ASCII.isHexDigit(peek())) {
244.3152 + int ch = 0;
244.3153 + while (ASCII.isHexDigit(n = read())) {
244.3154 + ch = (ch << 4) + ASCII.toDigit(n);
244.3155 + if (ch > Character.MAX_CODE_POINT)
244.3156 + throw error("Hexadecimal codepoint is too big");
244.3157 + }
244.3158 + if (n != '}')
244.3159 + throw error("Unclosed hexadecimal escape sequence");
244.3160 + return ch;
244.3161 + }
244.3162 + throw error("Illegal hexadecimal escape sequence");
244.3163 + }
244.3164 +
244.3165 + /**
244.3166 + * Utility method for parsing unicode escape sequences.
244.3167 + */
244.3168 + private int cursor() {
244.3169 + return cursor;
244.3170 + }
244.3171 +
244.3172 + private void setcursor(int pos) {
244.3173 + cursor = pos;
244.3174 + }
244.3175 +
244.3176 + private int uxxxx() {
244.3177 + int n = 0;
244.3178 + for (int i = 0; i < 4; i++) {
244.3179 + int ch = read();
244.3180 + if (!ASCII.isHexDigit(ch)) {
244.3181 + throw error("Illegal Unicode escape sequence");
244.3182 + }
244.3183 + n = n * 16 + ASCII.toDigit(ch);
244.3184 + }
244.3185 + return n;
244.3186 + }
244.3187 +
244.3188 + private int u() {
244.3189 + int n = uxxxx();
244.3190 + if (Character.isHighSurrogate((char)n)) {
244.3191 + int cur = cursor();
244.3192 + if (read() == '\\' && read() == 'u') {
244.3193 + int n2 = uxxxx();
244.3194 + if (Character.isLowSurrogate((char)n2))
244.3195 + return Character.toCodePoint((char)n, (char)n2);
244.3196 + }
244.3197 + setcursor(cur);
244.3198 + }
244.3199 + return n;
244.3200 + }
244.3201 +
244.3202 + //
244.3203 + // Utility methods for code point support
244.3204 + //
244.3205 +
244.3206 + private static final int countChars(CharSequence seq, int index,
244.3207 + int lengthInCodePoints) {
244.3208 + // optimization
244.3209 + if (lengthInCodePoints == 1 && !Character.isHighSurrogate(seq.charAt(index))) {
244.3210 + assert (index >= 0 && index < seq.length());
244.3211 + return 1;
244.3212 + }
244.3213 + int length = seq.length();
244.3214 + int x = index;
244.3215 + if (lengthInCodePoints >= 0) {
244.3216 + assert (index >= 0 && index < length);
244.3217 + for (int i = 0; x < length && i < lengthInCodePoints; i++) {
244.3218 + if (Character.isHighSurrogate(seq.charAt(x++))) {
244.3219 + if (x < length && Character.isLowSurrogate(seq.charAt(x))) {
244.3220 + x++;
244.3221 + }
244.3222 + }
244.3223 + }
244.3224 + return x - index;
244.3225 + }
244.3226 +
244.3227 + assert (index >= 0 && index <= length);
244.3228 + if (index == 0) {
244.3229 + return 0;
244.3230 + }
244.3231 + int len = -lengthInCodePoints;
244.3232 + for (int i = 0; x > 0 && i < len; i++) {
244.3233 + if (Character.isLowSurrogate(seq.charAt(--x))) {
244.3234 + if (x > 0 && Character.isHighSurrogate(seq.charAt(x-1))) {
244.3235 + x--;
244.3236 + }
244.3237 + }
244.3238 + }
244.3239 + return index - x;
244.3240 + }
244.3241 +
244.3242 + private static final int countCodePoints(CharSequence seq) {
244.3243 + int length = seq.length();
244.3244 + int n = 0;
244.3245 + for (int i = 0; i < length; ) {
244.3246 + n++;
244.3247 + if (Character.isHighSurrogate(seq.charAt(i++))) {
244.3248 + if (i < length && Character.isLowSurrogate(seq.charAt(i))) {
244.3249 + i++;
244.3250 + }
244.3251 + }
244.3252 + }
244.3253 + return n;
244.3254 + }
244.3255 +
244.3256 + /**
244.3257 + * Creates a bit vector for matching Latin-1 values. A normal BitClass
244.3258 + * never matches values above Latin-1, and a complemented BitClass always
244.3259 + * matches values above Latin-1.
244.3260 + */
244.3261 + private static final class BitClass extends BmpCharProperty {
244.3262 + final boolean[] bits;
244.3263 + BitClass() { bits = new boolean[256]; }
244.3264 + private BitClass(boolean[] bits) { this.bits = bits; }
244.3265 + BitClass add(int c, int flags) {
244.3266 + assert c >= 0 && c <= 255;
244.3267 + if ((flags & CASE_INSENSITIVE) != 0) {
244.3268 + if (ASCII.isAscii(c)) {
244.3269 + bits[ASCII.toUpper(c)] = true;
244.3270 + bits[ASCII.toLower(c)] = true;
244.3271 + } else if ((flags & UNICODE_CASE) != 0) {
244.3272 + bits[Character.toLowerCase(c)] = true;
244.3273 + bits[Character.toUpperCase(c)] = true;
244.3274 + }
244.3275 + }
244.3276 + bits[c] = true;
244.3277 + return this;
244.3278 + }
244.3279 + boolean isSatisfiedBy(int ch) {
244.3280 + return ch < 256 && bits[ch];
244.3281 + }
244.3282 + }
244.3283 +
244.3284 + /**
244.3285 + * Returns a suitably optimized, single character matcher.
244.3286 + */
244.3287 + private CharProperty newSingle(final int ch) {
244.3288 + if (has(CASE_INSENSITIVE)) {
244.3289 + int lower, upper;
244.3290 + if (has(UNICODE_CASE)) {
244.3291 + upper = Character.toUpperCase(ch);
244.3292 + lower = Character.toLowerCase(upper);
244.3293 + if (upper != lower)
244.3294 + return new SingleU(lower);
244.3295 + } else if (ASCII.isAscii(ch)) {
244.3296 + lower = ASCII.toLower(ch);
244.3297 + upper = ASCII.toUpper(ch);
244.3298 + if (lower != upper)
244.3299 + return new SingleI(lower, upper);
244.3300 + }
244.3301 + }
244.3302 + if (isSupplementary(ch))
244.3303 + return new SingleS(ch); // Match a given Unicode character
244.3304 + return new Single(ch); // Match a given BMP character
244.3305 + }
244.3306 +
244.3307 + /**
244.3308 + * Utility method for creating a string slice matcher.
244.3309 + */
244.3310 + private Node newSlice(int[] buf, int count, boolean hasSupplementary) {
244.3311 + int[] tmp = new int[count];
244.3312 + if (has(CASE_INSENSITIVE)) {
244.3313 + if (has(UNICODE_CASE)) {
244.3314 + for (int i = 0; i < count; i++) {
244.3315 + tmp[i] = Character.toLowerCase(
244.3316 + Character.toUpperCase(buf[i]));
244.3317 + }
244.3318 + return hasSupplementary? new SliceUS(tmp) : new SliceU(tmp);
244.3319 + }
244.3320 + for (int i = 0; i < count; i++) {
244.3321 + tmp[i] = ASCII.toLower(buf[i]);
244.3322 + }
244.3323 + return hasSupplementary? new SliceIS(tmp) : new SliceI(tmp);
244.3324 + }
244.3325 + for (int i = 0; i < count; i++) {
244.3326 + tmp[i] = buf[i];
244.3327 + }
244.3328 + return hasSupplementary ? new SliceS(tmp) : new Slice(tmp);
244.3329 + }
244.3330 +
244.3331 + /**
244.3332 + * The following classes are the building components of the object
244.3333 + * tree that represents a compiled regular expression. The object tree
244.3334 + * is made of individual elements that handle constructs in the Pattern.
244.3335 + * Each type of object knows how to match its equivalent construct with
244.3336 + * the match() method.
244.3337 + */
244.3338 +
244.3339 + /**
244.3340 + * Base class for all node classes. Subclasses should override the match()
244.3341 + * method as appropriate. This class is an accepting node, so its match()
244.3342 + * always returns true.
244.3343 + */
244.3344 + static class Node extends Object {
244.3345 + Node next;
244.3346 + Node() {
244.3347 + next = Pattern.accept;
244.3348 + }
244.3349 + /**
244.3350 + * This method implements the classic accept node.
244.3351 + */
244.3352 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3353 + matcher.last = i;
244.3354 + matcher.groups[0] = matcher.first;
244.3355 + matcher.groups[1] = matcher.last;
244.3356 + return true;
244.3357 + }
244.3358 + /**
244.3359 + * This method is good for all zero length assertions.
244.3360 + */
244.3361 + boolean study(TreeInfo info) {
244.3362 + if (next != null) {
244.3363 + return next.study(info);
244.3364 + } else {
244.3365 + return info.deterministic;
244.3366 + }
244.3367 + }
244.3368 + }
244.3369 +
244.3370 + static class LastNode extends Node {
244.3371 + /**
244.3372 + * This method implements the classic accept node with
244.3373 + * the addition of a check to see if the match occurred
244.3374 + * using all of the input.
244.3375 + */
244.3376 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3377 + if (matcher.acceptMode == Matcher.ENDANCHOR && i != matcher.to)
244.3378 + return false;
244.3379 + matcher.last = i;
244.3380 + matcher.groups[0] = matcher.first;
244.3381 + matcher.groups[1] = matcher.last;
244.3382 + return true;
244.3383 + }
244.3384 + }
244.3385 +
244.3386 + /**
244.3387 + * Used for REs that can start anywhere within the input string.
244.3388 + * This basically tries to match repeatedly at each spot in the
244.3389 + * input string, moving forward after each try. An anchored search
244.3390 + * or a BnM will bypass this node completely.
244.3391 + */
244.3392 + static class Start extends Node {
244.3393 + int minLength;
244.3394 + Start(Node node) {
244.3395 + this.next = node;
244.3396 + TreeInfo info = new TreeInfo();
244.3397 + next.study(info);
244.3398 + minLength = info.minLength;
244.3399 + }
244.3400 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3401 + if (i > matcher.to - minLength) {
244.3402 + matcher.hitEnd = true;
244.3403 + return false;
244.3404 + }
244.3405 + int guard = matcher.to - minLength;
244.3406 + for (; i <= guard; i++) {
244.3407 + if (next.match(matcher, i, seq)) {
244.3408 + matcher.first = i;
244.3409 + matcher.groups[0] = matcher.first;
244.3410 + matcher.groups[1] = matcher.last;
244.3411 + return true;
244.3412 + }
244.3413 + }
244.3414 + matcher.hitEnd = true;
244.3415 + return false;
244.3416 + }
244.3417 + boolean study(TreeInfo info) {
244.3418 + next.study(info);
244.3419 + info.maxValid = false;
244.3420 + info.deterministic = false;
244.3421 + return false;
244.3422 + }
244.3423 + }
244.3424 +
244.3425 + /*
244.3426 + * StartS supports supplementary characters, including unpaired surrogates.
244.3427 + */
244.3428 + static final class StartS extends Start {
244.3429 + StartS(Node node) {
244.3430 + super(node);
244.3431 + }
244.3432 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3433 + if (i > matcher.to - minLength) {
244.3434 + matcher.hitEnd = true;
244.3435 + return false;
244.3436 + }
244.3437 + int guard = matcher.to - minLength;
244.3438 + while (i <= guard) {
244.3439 + //if ((ret = next.match(matcher, i, seq)) || i == guard)
244.3440 + if (next.match(matcher, i, seq)) {
244.3441 + matcher.first = i;
244.3442 + matcher.groups[0] = matcher.first;
244.3443 + matcher.groups[1] = matcher.last;
244.3444 + return true;
244.3445 + }
244.3446 + if (i == guard)
244.3447 + break;
244.3448 + // Optimization to move to the next character. This is
244.3449 + // faster than countChars(seq, i, 1).
244.3450 + if (Character.isHighSurrogate(seq.charAt(i++))) {
244.3451 + if (i < seq.length() &&
244.3452 + Character.isLowSurrogate(seq.charAt(i))) {
244.3453 + i++;
244.3454 + }
244.3455 + }
244.3456 + }
244.3457 + matcher.hitEnd = true;
244.3458 + return false;
244.3459 + }
244.3460 + }
244.3461 +
244.3462 + /**
244.3463 + * Node to anchor at the beginning of input. This object implements the
244.3464 + * match for a \A sequence, and the caret anchor will use this if not in
244.3465 + * multiline mode.
244.3466 + */
244.3467 + static final class Begin extends Node {
244.3468 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3469 + int fromIndex = (matcher.anchoringBounds) ?
244.3470 + matcher.from : 0;
244.3471 + if (i == fromIndex && next.match(matcher, i, seq)) {
244.3472 + matcher.first = i;
244.3473 + matcher.groups[0] = i;
244.3474 + matcher.groups[1] = matcher.last;
244.3475 + return true;
244.3476 + } else {
244.3477 + return false;
244.3478 + }
244.3479 + }
244.3480 + }
244.3481 +
244.3482 + /**
244.3483 + * Node to anchor at the end of input. This is the absolute end, so this
244.3484 + * should not match at the last newline before the end as $ will.
244.3485 + */
244.3486 + static final class End extends Node {
244.3487 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3488 + int endIndex = (matcher.anchoringBounds) ?
244.3489 + matcher.to : matcher.getTextLength();
244.3490 + if (i == endIndex) {
244.3491 + matcher.hitEnd = true;
244.3492 + return next.match(matcher, i, seq);
244.3493 + }
244.3494 + return false;
244.3495 + }
244.3496 + }
244.3497 +
244.3498 + /**
244.3499 + * Node to anchor at the beginning of a line. This is essentially the
244.3500 + * object to match for the multiline ^.
244.3501 + */
244.3502 + static final class Caret extends Node {
244.3503 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3504 + int startIndex = matcher.from;
244.3505 + int endIndex = matcher.to;
244.3506 + if (!matcher.anchoringBounds) {
244.3507 + startIndex = 0;
244.3508 + endIndex = matcher.getTextLength();
244.3509 + }
244.3510 + // Perl does not match ^ at end of input even after newline
244.3511 + if (i == endIndex) {
244.3512 + matcher.hitEnd = true;
244.3513 + return false;
244.3514 + }
244.3515 + if (i > startIndex) {
244.3516 + char ch = seq.charAt(i-1);
244.3517 + if (ch != '\n' && ch != '\r'
244.3518 + && (ch|1) != '\u2029'
244.3519 + && ch != '\u0085' ) {
244.3520 + return false;
244.3521 + }
244.3522 + // Should treat /r/n as one newline
244.3523 + if (ch == '\r' && seq.charAt(i) == '\n')
244.3524 + return false;
244.3525 + }
244.3526 + return next.match(matcher, i, seq);
244.3527 + }
244.3528 + }
244.3529 +
244.3530 + /**
244.3531 + * Node to anchor at the beginning of a line when in unixdot mode.
244.3532 + */
244.3533 + static final class UnixCaret extends Node {
244.3534 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3535 + int startIndex = matcher.from;
244.3536 + int endIndex = matcher.to;
244.3537 + if (!matcher.anchoringBounds) {
244.3538 + startIndex = 0;
244.3539 + endIndex = matcher.getTextLength();
244.3540 + }
244.3541 + // Perl does not match ^ at end of input even after newline
244.3542 + if (i == endIndex) {
244.3543 + matcher.hitEnd = true;
244.3544 + return false;
244.3545 + }
244.3546 + if (i > startIndex) {
244.3547 + char ch = seq.charAt(i-1);
244.3548 + if (ch != '\n') {
244.3549 + return false;
244.3550 + }
244.3551 + }
244.3552 + return next.match(matcher, i, seq);
244.3553 + }
244.3554 + }
244.3555 +
244.3556 + /**
244.3557 + * Node to match the location where the last match ended.
244.3558 + * This is used for the \G construct.
244.3559 + */
244.3560 + static final class LastMatch extends Node {
244.3561 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3562 + if (i != matcher.oldLast)
244.3563 + return false;
244.3564 + return next.match(matcher, i, seq);
244.3565 + }
244.3566 + }
244.3567 +
244.3568 + /**
244.3569 + * Node to anchor at the end of a line or the end of input based on the
244.3570 + * multiline mode.
244.3571 + *
244.3572 + * When not in multiline mode, the $ can only match at the very end
244.3573 + * of the input, unless the input ends in a line terminator in which
244.3574 + * it matches right before the last line terminator.
244.3575 + *
244.3576 + * Note that \r\n is considered an atomic line terminator.
244.3577 + *
244.3578 + * Like ^ the $ operator matches at a position, it does not match the
244.3579 + * line terminators themselves.
244.3580 + */
244.3581 + static final class Dollar extends Node {
244.3582 + boolean multiline;
244.3583 + Dollar(boolean mul) {
244.3584 + multiline = mul;
244.3585 + }
244.3586 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3587 + int endIndex = (matcher.anchoringBounds) ?
244.3588 + matcher.to : matcher.getTextLength();
244.3589 + if (!multiline) {
244.3590 + if (i < endIndex - 2)
244.3591 + return false;
244.3592 + if (i == endIndex - 2) {
244.3593 + char ch = seq.charAt(i);
244.3594 + if (ch != '\r')
244.3595 + return false;
244.3596 + ch = seq.charAt(i + 1);
244.3597 + if (ch != '\n')
244.3598 + return false;
244.3599 + }
244.3600 + }
244.3601 + // Matches before any line terminator; also matches at the
244.3602 + // end of input
244.3603 + // Before line terminator:
244.3604 + // If multiline, we match here no matter what
244.3605 + // If not multiline, fall through so that the end
244.3606 + // is marked as hit; this must be a /r/n or a /n
244.3607 + // at the very end so the end was hit; more input
244.3608 + // could make this not match here
244.3609 + if (i < endIndex) {
244.3610 + char ch = seq.charAt(i);
244.3611 + if (ch == '\n') {
244.3612 + // No match between \r\n
244.3613 + if (i > 0 && seq.charAt(i-1) == '\r')
244.3614 + return false;
244.3615 + if (multiline)
244.3616 + return next.match(matcher, i, seq);
244.3617 + } else if (ch == '\r' || ch == '\u0085' ||
244.3618 + (ch|1) == '\u2029') {
244.3619 + if (multiline)
244.3620 + return next.match(matcher, i, seq);
244.3621 + } else { // No line terminator, no match
244.3622 + return false;
244.3623 + }
244.3624 + }
244.3625 + // Matched at current end so hit end
244.3626 + matcher.hitEnd = true;
244.3627 + // If a $ matches because of end of input, then more input
244.3628 + // could cause it to fail!
244.3629 + matcher.requireEnd = true;
244.3630 + return next.match(matcher, i, seq);
244.3631 + }
244.3632 + boolean study(TreeInfo info) {
244.3633 + next.study(info);
244.3634 + return info.deterministic;
244.3635 + }
244.3636 + }
244.3637 +
244.3638 + /**
244.3639 + * Node to anchor at the end of a line or the end of input based on the
244.3640 + * multiline mode when in unix lines mode.
244.3641 + */
244.3642 + static final class UnixDollar extends Node {
244.3643 + boolean multiline;
244.3644 + UnixDollar(boolean mul) {
244.3645 + multiline = mul;
244.3646 + }
244.3647 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3648 + int endIndex = (matcher.anchoringBounds) ?
244.3649 + matcher.to : matcher.getTextLength();
244.3650 + if (i < endIndex) {
244.3651 + char ch = seq.charAt(i);
244.3652 + if (ch == '\n') {
244.3653 + // If not multiline, then only possible to
244.3654 + // match at very end or one before end
244.3655 + if (multiline == false && i != endIndex - 1)
244.3656 + return false;
244.3657 + // If multiline return next.match without setting
244.3658 + // matcher.hitEnd
244.3659 + if (multiline)
244.3660 + return next.match(matcher, i, seq);
244.3661 + } else {
244.3662 + return false;
244.3663 + }
244.3664 + }
244.3665 + // Matching because at the end or 1 before the end;
244.3666 + // more input could change this so set hitEnd
244.3667 + matcher.hitEnd = true;
244.3668 + // If a $ matches because of end of input, then more input
244.3669 + // could cause it to fail!
244.3670 + matcher.requireEnd = true;
244.3671 + return next.match(matcher, i, seq);
244.3672 + }
244.3673 + boolean study(TreeInfo info) {
244.3674 + next.study(info);
244.3675 + return info.deterministic;
244.3676 + }
244.3677 + }
244.3678 +
244.3679 + /**
244.3680 + * Abstract node class to match one character satisfying some
244.3681 + * boolean property.
244.3682 + */
244.3683 + private static abstract class CharProperty extends Node {
244.3684 + abstract boolean isSatisfiedBy(int ch);
244.3685 + CharProperty complement() {
244.3686 + return new CharProperty() {
244.3687 + boolean isSatisfiedBy(int ch) {
244.3688 + return ! CharProperty.this.isSatisfiedBy(ch);}};
244.3689 + }
244.3690 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3691 + if (i < matcher.to) {
244.3692 + int ch = Character.codePointAt(seq, i);
244.3693 + return isSatisfiedBy(ch)
244.3694 + && next.match(matcher, i+Character.charCount(ch), seq);
244.3695 + } else {
244.3696 + matcher.hitEnd = true;
244.3697 + return false;
244.3698 + }
244.3699 + }
244.3700 + boolean study(TreeInfo info) {
244.3701 + info.minLength++;
244.3702 + info.maxLength++;
244.3703 + return next.study(info);
244.3704 + }
244.3705 + }
244.3706 +
244.3707 + /**
244.3708 + * Optimized version of CharProperty that works only for
244.3709 + * properties never satisfied by Supplementary characters.
244.3710 + */
244.3711 + private static abstract class BmpCharProperty extends CharProperty {
244.3712 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3713 + if (i < matcher.to) {
244.3714 + return isSatisfiedBy(seq.charAt(i))
244.3715 + && next.match(matcher, i+1, seq);
244.3716 + } else {
244.3717 + matcher.hitEnd = true;
244.3718 + return false;
244.3719 + }
244.3720 + }
244.3721 + }
244.3722 +
244.3723 + /**
244.3724 + * Node class that matches a Supplementary Unicode character
244.3725 + */
244.3726 + static final class SingleS extends CharProperty {
244.3727 + final int c;
244.3728 + SingleS(int c) { this.c = c; }
244.3729 + boolean isSatisfiedBy(int ch) {
244.3730 + return ch == c;
244.3731 + }
244.3732 + }
244.3733 +
244.3734 + /**
244.3735 + * Optimization -- matches a given BMP character
244.3736 + */
244.3737 + static final class Single extends BmpCharProperty {
244.3738 + final int c;
244.3739 + Single(int c) { this.c = c; }
244.3740 + boolean isSatisfiedBy(int ch) {
244.3741 + return ch == c;
244.3742 + }
244.3743 + }
244.3744 +
244.3745 + /**
244.3746 + * Case insensitive matches a given BMP character
244.3747 + */
244.3748 + static final class SingleI extends BmpCharProperty {
244.3749 + final int lower;
244.3750 + final int upper;
244.3751 + SingleI(int lower, int upper) {
244.3752 + this.lower = lower;
244.3753 + this.upper = upper;
244.3754 + }
244.3755 + boolean isSatisfiedBy(int ch) {
244.3756 + return ch == lower || ch == upper;
244.3757 + }
244.3758 + }
244.3759 +
244.3760 + /**
244.3761 + * Unicode case insensitive matches a given Unicode character
244.3762 + */
244.3763 + static final class SingleU extends CharProperty {
244.3764 + final int lower;
244.3765 + SingleU(int lower) {
244.3766 + this.lower = lower;
244.3767 + }
244.3768 + boolean isSatisfiedBy(int ch) {
244.3769 + return lower == ch ||
244.3770 + lower == Character.toLowerCase(Character.toUpperCase(ch));
244.3771 + }
244.3772 + }
244.3773 +
244.3774 +
244.3775 + /**
244.3776 + * Node class that matches a Unicode block.
244.3777 + *
244.3778 + static final class Block extends CharProperty {
244.3779 + final Character.UnicodeBlock block;
244.3780 + Block(Character.UnicodeBlock block) {
244.3781 + this.block = block;
244.3782 + }
244.3783 + boolean isSatisfiedBy(int ch) {
244.3784 + return block == Character.UnicodeBlock.of(ch);
244.3785 + }
244.3786 + }
244.3787 +
244.3788 + /**
244.3789 + * Node class that matches a Unicode script
244.3790 + *
244.3791 + static final class Script extends CharProperty {
244.3792 + final Character.UnicodeScript script;
244.3793 + Script(Character.UnicodeScript script) {
244.3794 + this.script = script;
244.3795 + }
244.3796 + boolean isSatisfiedBy(int ch) {
244.3797 + return script == Character.UnicodeScript.of(ch);
244.3798 + }
244.3799 + }
244.3800 +
244.3801 + /**
244.3802 + * Node class that matches a Unicode category.
244.3803 + */
244.3804 + static final class Category extends CharProperty {
244.3805 + final int typeMask;
244.3806 + Category(int typeMask) { this.typeMask = typeMask; }
244.3807 + boolean isSatisfiedBy(int ch) {
244.3808 + return (typeMask & (1 << Character.getType(ch))) != 0;
244.3809 + }
244.3810 + }
244.3811 +
244.3812 + /**
244.3813 + * Node class that matches a Unicode "type"
244.3814 + */
244.3815 + static final class Utype extends CharProperty {
244.3816 + final UnicodeProp uprop;
244.3817 + Utype(UnicodeProp uprop) { this.uprop = uprop; }
244.3818 + boolean isSatisfiedBy(int ch) {
244.3819 + return uprop.is(ch);
244.3820 + }
244.3821 + }
244.3822 +
244.3823 +
244.3824 + /**
244.3825 + * Node class that matches a POSIX type.
244.3826 + */
244.3827 + static final class Ctype extends BmpCharProperty {
244.3828 + final int ctype;
244.3829 + Ctype(int ctype) { this.ctype = ctype; }
244.3830 + boolean isSatisfiedBy(int ch) {
244.3831 + return ch < 128 && ASCII.isType(ch, ctype);
244.3832 + }
244.3833 + }
244.3834 +
244.3835 + /**
244.3836 + * Base class for all Slice nodes
244.3837 + */
244.3838 + static class SliceNode extends Node {
244.3839 + int[] buffer;
244.3840 + SliceNode(int[] buf) {
244.3841 + buffer = buf;
244.3842 + }
244.3843 + boolean study(TreeInfo info) {
244.3844 + info.minLength += buffer.length;
244.3845 + info.maxLength += buffer.length;
244.3846 + return next.study(info);
244.3847 + }
244.3848 + }
244.3849 +
244.3850 + /**
244.3851 + * Node class for a case sensitive/BMP-only sequence of literal
244.3852 + * characters.
244.3853 + */
244.3854 + static final class Slice extends SliceNode {
244.3855 + Slice(int[] buf) {
244.3856 + super(buf);
244.3857 + }
244.3858 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3859 + int[] buf = buffer;
244.3860 + int len = buf.length;
244.3861 + for (int j=0; j<len; j++) {
244.3862 + if ((i+j) >= matcher.to) {
244.3863 + matcher.hitEnd = true;
244.3864 + return false;
244.3865 + }
244.3866 + if (buf[j] != seq.charAt(i+j))
244.3867 + return false;
244.3868 + }
244.3869 + return next.match(matcher, i+len, seq);
244.3870 + }
244.3871 + }
244.3872 +
244.3873 + /**
244.3874 + * Node class for a case_insensitive/BMP-only sequence of literal
244.3875 + * characters.
244.3876 + */
244.3877 + static class SliceI extends SliceNode {
244.3878 + SliceI(int[] buf) {
244.3879 + super(buf);
244.3880 + }
244.3881 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3882 + int[] buf = buffer;
244.3883 + int len = buf.length;
244.3884 + for (int j=0; j<len; j++) {
244.3885 + if ((i+j) >= matcher.to) {
244.3886 + matcher.hitEnd = true;
244.3887 + return false;
244.3888 + }
244.3889 + int c = seq.charAt(i+j);
244.3890 + if (buf[j] != c &&
244.3891 + buf[j] != ASCII.toLower(c))
244.3892 + return false;
244.3893 + }
244.3894 + return next.match(matcher, i+len, seq);
244.3895 + }
244.3896 + }
244.3897 +
244.3898 + /**
244.3899 + * Node class for a unicode_case_insensitive/BMP-only sequence of
244.3900 + * literal characters. Uses unicode case folding.
244.3901 + */
244.3902 + static final class SliceU extends SliceNode {
244.3903 + SliceU(int[] buf) {
244.3904 + super(buf);
244.3905 + }
244.3906 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3907 + int[] buf = buffer;
244.3908 + int len = buf.length;
244.3909 + for (int j=0; j<len; j++) {
244.3910 + if ((i+j) >= matcher.to) {
244.3911 + matcher.hitEnd = true;
244.3912 + return false;
244.3913 + }
244.3914 + int c = seq.charAt(i+j);
244.3915 + if (buf[j] != c &&
244.3916 + buf[j] != Character.toLowerCase(Character.toUpperCase(c)))
244.3917 + return false;
244.3918 + }
244.3919 + return next.match(matcher, i+len, seq);
244.3920 + }
244.3921 + }
244.3922 +
244.3923 + /**
244.3924 + * Node class for a case sensitive sequence of literal characters
244.3925 + * including supplementary characters.
244.3926 + */
244.3927 + static final class SliceS extends SliceNode {
244.3928 + SliceS(int[] buf) {
244.3929 + super(buf);
244.3930 + }
244.3931 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3932 + int[] buf = buffer;
244.3933 + int x = i;
244.3934 + for (int j = 0; j < buf.length; j++) {
244.3935 + if (x >= matcher.to) {
244.3936 + matcher.hitEnd = true;
244.3937 + return false;
244.3938 + }
244.3939 + int c = Character.codePointAt(seq, x);
244.3940 + if (buf[j] != c)
244.3941 + return false;
244.3942 + x += Character.charCount(c);
244.3943 + if (x > matcher.to) {
244.3944 + matcher.hitEnd = true;
244.3945 + return false;
244.3946 + }
244.3947 + }
244.3948 + return next.match(matcher, x, seq);
244.3949 + }
244.3950 + }
244.3951 +
244.3952 + /**
244.3953 + * Node class for a case insensitive sequence of literal characters
244.3954 + * including supplementary characters.
244.3955 + */
244.3956 + static class SliceIS extends SliceNode {
244.3957 + SliceIS(int[] buf) {
244.3958 + super(buf);
244.3959 + }
244.3960 + int toLower(int c) {
244.3961 + return ASCII.toLower(c);
244.3962 + }
244.3963 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.3964 + int[] buf = buffer;
244.3965 + int x = i;
244.3966 + for (int j = 0; j < buf.length; j++) {
244.3967 + if (x >= matcher.to) {
244.3968 + matcher.hitEnd = true;
244.3969 + return false;
244.3970 + }
244.3971 + int c = Character.codePointAt(seq, x);
244.3972 + if (buf[j] != c && buf[j] != toLower(c))
244.3973 + return false;
244.3974 + x += Character.charCount(c);
244.3975 + if (x > matcher.to) {
244.3976 + matcher.hitEnd = true;
244.3977 + return false;
244.3978 + }
244.3979 + }
244.3980 + return next.match(matcher, x, seq);
244.3981 + }
244.3982 + }
244.3983 +
244.3984 + /**
244.3985 + * Node class for a case insensitive sequence of literal characters.
244.3986 + * Uses unicode case folding.
244.3987 + */
244.3988 + static final class SliceUS extends SliceIS {
244.3989 + SliceUS(int[] buf) {
244.3990 + super(buf);
244.3991 + }
244.3992 + int toLower(int c) {
244.3993 + return Character.toLowerCase(Character.toUpperCase(c));
244.3994 + }
244.3995 + }
244.3996 +
244.3997 + private static boolean inRange(int lower, int ch, int upper) {
244.3998 + return lower <= ch && ch <= upper;
244.3999 + }
244.4000 +
244.4001 + /**
244.4002 + * Returns node for matching characters within an explicit value range.
244.4003 + */
244.4004 + private static CharProperty rangeFor(final int lower,
244.4005 + final int upper) {
244.4006 + return new CharProperty() {
244.4007 + boolean isSatisfiedBy(int ch) {
244.4008 + return inRange(lower, ch, upper);}};
244.4009 + }
244.4010 +
244.4011 + /**
244.4012 + * Returns node for matching characters within an explicit value
244.4013 + * range in a case insensitive manner.
244.4014 + */
244.4015 + private CharProperty caseInsensitiveRangeFor(final int lower,
244.4016 + final int upper) {
244.4017 + if (has(UNICODE_CASE))
244.4018 + return new CharProperty() {
244.4019 + boolean isSatisfiedBy(int ch) {
244.4020 + if (inRange(lower, ch, upper))
244.4021 + return true;
244.4022 + int up = Character.toUpperCase(ch);
244.4023 + return inRange(lower, up, upper) ||
244.4024 + inRange(lower, Character.toLowerCase(up), upper);}};
244.4025 + return new CharProperty() {
244.4026 + boolean isSatisfiedBy(int ch) {
244.4027 + return inRange(lower, ch, upper) ||
244.4028 + ASCII.isAscii(ch) &&
244.4029 + (inRange(lower, ASCII.toUpper(ch), upper) ||
244.4030 + inRange(lower, ASCII.toLower(ch), upper));
244.4031 + }};
244.4032 + }
244.4033 +
244.4034 + /**
244.4035 + * Implements the Unicode category ALL and the dot metacharacter when
244.4036 + * in dotall mode.
244.4037 + */
244.4038 + static final class All extends CharProperty {
244.4039 + boolean isSatisfiedBy(int ch) {
244.4040 + return true;
244.4041 + }
244.4042 + }
244.4043 +
244.4044 + /**
244.4045 + * Node class for the dot metacharacter when dotall is not enabled.
244.4046 + */
244.4047 + static final class Dot extends CharProperty {
244.4048 + boolean isSatisfiedBy(int ch) {
244.4049 + return (ch != '\n' && ch != '\r'
244.4050 + && (ch|1) != '\u2029'
244.4051 + && ch != '\u0085');
244.4052 + }
244.4053 + }
244.4054 +
244.4055 + /**
244.4056 + * Node class for the dot metacharacter when dotall is not enabled
244.4057 + * but UNIX_LINES is enabled.
244.4058 + */
244.4059 + static final class UnixDot extends CharProperty {
244.4060 + boolean isSatisfiedBy(int ch) {
244.4061 + return ch != '\n';
244.4062 + }
244.4063 + }
244.4064 +
244.4065 + /**
244.4066 + * The 0 or 1 quantifier. This one class implements all three types.
244.4067 + */
244.4068 + static final class Ques extends Node {
244.4069 + Node atom;
244.4070 + int type;
244.4071 + Ques(Node node, int type) {
244.4072 + this.atom = node;
244.4073 + this.type = type;
244.4074 + }
244.4075 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4076 + switch (type) {
244.4077 + case GREEDY:
244.4078 + return (atom.match(matcher, i, seq) && next.match(matcher, matcher.last, seq))
244.4079 + || next.match(matcher, i, seq);
244.4080 + case LAZY:
244.4081 + return next.match(matcher, i, seq)
244.4082 + || (atom.match(matcher, i, seq) && next.match(matcher, matcher.last, seq));
244.4083 + case POSSESSIVE:
244.4084 + if (atom.match(matcher, i, seq)) i = matcher.last;
244.4085 + return next.match(matcher, i, seq);
244.4086 + default:
244.4087 + return atom.match(matcher, i, seq) && next.match(matcher, matcher.last, seq);
244.4088 + }
244.4089 + }
244.4090 + boolean study(TreeInfo info) {
244.4091 + if (type != INDEPENDENT) {
244.4092 + int minL = info.minLength;
244.4093 + atom.study(info);
244.4094 + info.minLength = minL;
244.4095 + info.deterministic = false;
244.4096 + return next.study(info);
244.4097 + } else {
244.4098 + atom.study(info);
244.4099 + return next.study(info);
244.4100 + }
244.4101 + }
244.4102 + }
244.4103 +
244.4104 + /**
244.4105 + * Handles the curly-brace style repetition with a specified minimum and
244.4106 + * maximum occurrences. The * quantifier is handled as a special case.
244.4107 + * This class handles the three types.
244.4108 + */
244.4109 + static final class Curly extends Node {
244.4110 + Node atom;
244.4111 + int type;
244.4112 + int cmin;
244.4113 + int cmax;
244.4114 +
244.4115 + Curly(Node node, int cmin, int cmax, int type) {
244.4116 + this.atom = node;
244.4117 + this.type = type;
244.4118 + this.cmin = cmin;
244.4119 + this.cmax = cmax;
244.4120 + }
244.4121 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4122 + int j;
244.4123 + for (j = 0; j < cmin; j++) {
244.4124 + if (atom.match(matcher, i, seq)) {
244.4125 + i = matcher.last;
244.4126 + continue;
244.4127 + }
244.4128 + return false;
244.4129 + }
244.4130 + if (type == GREEDY)
244.4131 + return match0(matcher, i, j, seq);
244.4132 + else if (type == LAZY)
244.4133 + return match1(matcher, i, j, seq);
244.4134 + else
244.4135 + return match2(matcher, i, j, seq);
244.4136 + }
244.4137 + // Greedy match.
244.4138 + // i is the index to start matching at
244.4139 + // j is the number of atoms that have matched
244.4140 + boolean match0(Matcher matcher, int i, int j, CharSequence seq) {
244.4141 + if (j >= cmax) {
244.4142 + // We have matched the maximum... continue with the rest of
244.4143 + // the regular expression
244.4144 + return next.match(matcher, i, seq);
244.4145 + }
244.4146 + int backLimit = j;
244.4147 + while (atom.match(matcher, i, seq)) {
244.4148 + // k is the length of this match
244.4149 + int k = matcher.last - i;
244.4150 + if (k == 0) // Zero length match
244.4151 + break;
244.4152 + // Move up index and number matched
244.4153 + i = matcher.last;
244.4154 + j++;
244.4155 + // We are greedy so match as many as we can
244.4156 + while (j < cmax) {
244.4157 + if (!atom.match(matcher, i, seq))
244.4158 + break;
244.4159 + if (i + k != matcher.last) {
244.4160 + if (match0(matcher, matcher.last, j+1, seq))
244.4161 + return true;
244.4162 + break;
244.4163 + }
244.4164 + i += k;
244.4165 + j++;
244.4166 + }
244.4167 + // Handle backing off if match fails
244.4168 + while (j >= backLimit) {
244.4169 + if (next.match(matcher, i, seq))
244.4170 + return true;
244.4171 + i -= k;
244.4172 + j--;
244.4173 + }
244.4174 + return false;
244.4175 + }
244.4176 + return next.match(matcher, i, seq);
244.4177 + }
244.4178 + // Reluctant match. At this point, the minimum has been satisfied.
244.4179 + // i is the index to start matching at
244.4180 + // j is the number of atoms that have matched
244.4181 + boolean match1(Matcher matcher, int i, int j, CharSequence seq) {
244.4182 + for (;;) {
244.4183 + // Try finishing match without consuming any more
244.4184 + if (next.match(matcher, i, seq))
244.4185 + return true;
244.4186 + // At the maximum, no match found
244.4187 + if (j >= cmax)
244.4188 + return false;
244.4189 + // Okay, must try one more atom
244.4190 + if (!atom.match(matcher, i, seq))
244.4191 + return false;
244.4192 + // If we haven't moved forward then must break out
244.4193 + if (i == matcher.last)
244.4194 + return false;
244.4195 + // Move up index and number matched
244.4196 + i = matcher.last;
244.4197 + j++;
244.4198 + }
244.4199 + }
244.4200 + boolean match2(Matcher matcher, int i, int j, CharSequence seq) {
244.4201 + for (; j < cmax; j++) {
244.4202 + if (!atom.match(matcher, i, seq))
244.4203 + break;
244.4204 + if (i == matcher.last)
244.4205 + break;
244.4206 + i = matcher.last;
244.4207 + }
244.4208 + return next.match(matcher, i, seq);
244.4209 + }
244.4210 + boolean study(TreeInfo info) {
244.4211 + // Save original info
244.4212 + int minL = info.minLength;
244.4213 + int maxL = info.maxLength;
244.4214 + boolean maxV = info.maxValid;
244.4215 + boolean detm = info.deterministic;
244.4216 + info.reset();
244.4217 +
244.4218 + atom.study(info);
244.4219 +
244.4220 + int temp = info.minLength * cmin + minL;
244.4221 + if (temp < minL) {
244.4222 + temp = 0xFFFFFFF; // arbitrary large number
244.4223 + }
244.4224 + info.minLength = temp;
244.4225 +
244.4226 + if (maxV & info.maxValid) {
244.4227 + temp = info.maxLength * cmax + maxL;
244.4228 + info.maxLength = temp;
244.4229 + if (temp < maxL) {
244.4230 + info.maxValid = false;
244.4231 + }
244.4232 + } else {
244.4233 + info.maxValid = false;
244.4234 + }
244.4235 +
244.4236 + if (info.deterministic && cmin == cmax)
244.4237 + info.deterministic = detm;
244.4238 + else
244.4239 + info.deterministic = false;
244.4240 +
244.4241 + return next.study(info);
244.4242 + }
244.4243 + }
244.4244 +
244.4245 + /**
244.4246 + * Handles the curly-brace style repetition with a specified minimum and
244.4247 + * maximum occurrences in deterministic cases. This is an iterative
244.4248 + * optimization over the Prolog and Loop system which would handle this
244.4249 + * in a recursive way. The * quantifier is handled as a special case.
244.4250 + * If capture is true then this class saves group settings and ensures
244.4251 + * that groups are unset when backing off of a group match.
244.4252 + */
244.4253 + static final class GroupCurly extends Node {
244.4254 + Node atom;
244.4255 + int type;
244.4256 + int cmin;
244.4257 + int cmax;
244.4258 + int localIndex;
244.4259 + int groupIndex;
244.4260 + boolean capture;
244.4261 +
244.4262 + GroupCurly(Node node, int cmin, int cmax, int type, int local,
244.4263 + int group, boolean capture) {
244.4264 + this.atom = node;
244.4265 + this.type = type;
244.4266 + this.cmin = cmin;
244.4267 + this.cmax = cmax;
244.4268 + this.localIndex = local;
244.4269 + this.groupIndex = group;
244.4270 + this.capture = capture;
244.4271 + }
244.4272 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4273 + int[] groups = matcher.groups;
244.4274 + int[] locals = matcher.locals;
244.4275 + int save0 = locals[localIndex];
244.4276 + int save1 = 0;
244.4277 + int save2 = 0;
244.4278 +
244.4279 + if (capture) {
244.4280 + save1 = groups[groupIndex];
244.4281 + save2 = groups[groupIndex+1];
244.4282 + }
244.4283 +
244.4284 + // Notify GroupTail there is no need to setup group info
244.4285 + // because it will be set here
244.4286 + locals[localIndex] = -1;
244.4287 +
244.4288 + boolean ret = true;
244.4289 + for (int j = 0; j < cmin; j++) {
244.4290 + if (atom.match(matcher, i, seq)) {
244.4291 + if (capture) {
244.4292 + groups[groupIndex] = i;
244.4293 + groups[groupIndex+1] = matcher.last;
244.4294 + }
244.4295 + i = matcher.last;
244.4296 + } else {
244.4297 + ret = false;
244.4298 + break;
244.4299 + }
244.4300 + }
244.4301 + if (ret) {
244.4302 + if (type == GREEDY) {
244.4303 + ret = match0(matcher, i, cmin, seq);
244.4304 + } else if (type == LAZY) {
244.4305 + ret = match1(matcher, i, cmin, seq);
244.4306 + } else {
244.4307 + ret = match2(matcher, i, cmin, seq);
244.4308 + }
244.4309 + }
244.4310 + if (!ret) {
244.4311 + locals[localIndex] = save0;
244.4312 + if (capture) {
244.4313 + groups[groupIndex] = save1;
244.4314 + groups[groupIndex+1] = save2;
244.4315 + }
244.4316 + }
244.4317 + return ret;
244.4318 + }
244.4319 + // Aggressive group match
244.4320 + boolean match0(Matcher matcher, int i, int j, CharSequence seq) {
244.4321 + int[] groups = matcher.groups;
244.4322 + int save0 = 0;
244.4323 + int save1 = 0;
244.4324 + if (capture) {
244.4325 + save0 = groups[groupIndex];
244.4326 + save1 = groups[groupIndex+1];
244.4327 + }
244.4328 + for (;;) {
244.4329 + if (j >= cmax)
244.4330 + break;
244.4331 + if (!atom.match(matcher, i, seq))
244.4332 + break;
244.4333 + int k = matcher.last - i;
244.4334 + if (k <= 0) {
244.4335 + if (capture) {
244.4336 + groups[groupIndex] = i;
244.4337 + groups[groupIndex+1] = i + k;
244.4338 + }
244.4339 + i = i + k;
244.4340 + break;
244.4341 + }
244.4342 + for (;;) {
244.4343 + if (capture) {
244.4344 + groups[groupIndex] = i;
244.4345 + groups[groupIndex+1] = i + k;
244.4346 + }
244.4347 + i = i + k;
244.4348 + if (++j >= cmax)
244.4349 + break;
244.4350 + if (!atom.match(matcher, i, seq))
244.4351 + break;
244.4352 + if (i + k != matcher.last) {
244.4353 + if (match0(matcher, i, j, seq))
244.4354 + return true;
244.4355 + break;
244.4356 + }
244.4357 + }
244.4358 + while (j > cmin) {
244.4359 + if (next.match(matcher, i, seq)) {
244.4360 + if (capture) {
244.4361 + groups[groupIndex+1] = i;
244.4362 + groups[groupIndex] = i - k;
244.4363 + }
244.4364 + i = i - k;
244.4365 + return true;
244.4366 + }
244.4367 + // backing off
244.4368 + if (capture) {
244.4369 + groups[groupIndex+1] = i;
244.4370 + groups[groupIndex] = i - k;
244.4371 + }
244.4372 + i = i - k;
244.4373 + j--;
244.4374 + }
244.4375 + break;
244.4376 + }
244.4377 + if (capture) {
244.4378 + groups[groupIndex] = save0;
244.4379 + groups[groupIndex+1] = save1;
244.4380 + }
244.4381 + return next.match(matcher, i, seq);
244.4382 + }
244.4383 + // Reluctant matching
244.4384 + boolean match1(Matcher matcher, int i, int j, CharSequence seq) {
244.4385 + for (;;) {
244.4386 + if (next.match(matcher, i, seq))
244.4387 + return true;
244.4388 + if (j >= cmax)
244.4389 + return false;
244.4390 + if (!atom.match(matcher, i, seq))
244.4391 + return false;
244.4392 + if (i == matcher.last)
244.4393 + return false;
244.4394 + if (capture) {
244.4395 + matcher.groups[groupIndex] = i;
244.4396 + matcher.groups[groupIndex+1] = matcher.last;
244.4397 + }
244.4398 + i = matcher.last;
244.4399 + j++;
244.4400 + }
244.4401 + }
244.4402 + // Possessive matching
244.4403 + boolean match2(Matcher matcher, int i, int j, CharSequence seq) {
244.4404 + for (; j < cmax; j++) {
244.4405 + if (!atom.match(matcher, i, seq)) {
244.4406 + break;
244.4407 + }
244.4408 + if (capture) {
244.4409 + matcher.groups[groupIndex] = i;
244.4410 + matcher.groups[groupIndex+1] = matcher.last;
244.4411 + }
244.4412 + if (i == matcher.last) {
244.4413 + break;
244.4414 + }
244.4415 + i = matcher.last;
244.4416 + }
244.4417 + return next.match(matcher, i, seq);
244.4418 + }
244.4419 + boolean study(TreeInfo info) {
244.4420 + // Save original info
244.4421 + int minL = info.minLength;
244.4422 + int maxL = info.maxLength;
244.4423 + boolean maxV = info.maxValid;
244.4424 + boolean detm = info.deterministic;
244.4425 + info.reset();
244.4426 +
244.4427 + atom.study(info);
244.4428 +
244.4429 + int temp = info.minLength * cmin + minL;
244.4430 + if (temp < minL) {
244.4431 + temp = 0xFFFFFFF; // Arbitrary large number
244.4432 + }
244.4433 + info.minLength = temp;
244.4434 +
244.4435 + if (maxV & info.maxValid) {
244.4436 + temp = info.maxLength * cmax + maxL;
244.4437 + info.maxLength = temp;
244.4438 + if (temp < maxL) {
244.4439 + info.maxValid = false;
244.4440 + }
244.4441 + } else {
244.4442 + info.maxValid = false;
244.4443 + }
244.4444 +
244.4445 + if (info.deterministic && cmin == cmax) {
244.4446 + info.deterministic = detm;
244.4447 + } else {
244.4448 + info.deterministic = false;
244.4449 + }
244.4450 +
244.4451 + return next.study(info);
244.4452 + }
244.4453 + }
244.4454 +
244.4455 + /**
244.4456 + * A Guard node at the end of each atom node in a Branch. It
244.4457 + * serves the purpose of chaining the "match" operation to
244.4458 + * "next" but not the "study", so we can collect the TreeInfo
244.4459 + * of each atom node without including the TreeInfo of the
244.4460 + * "next".
244.4461 + */
244.4462 + static final class BranchConn extends Node {
244.4463 + BranchConn() {};
244.4464 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4465 + return next.match(matcher, i, seq);
244.4466 + }
244.4467 + boolean study(TreeInfo info) {
244.4468 + return info.deterministic;
244.4469 + }
244.4470 + }
244.4471 +
244.4472 + /**
244.4473 + * Handles the branching of alternations. Note this is also used for
244.4474 + * the ? quantifier to branch between the case where it matches once
244.4475 + * and where it does not occur.
244.4476 + */
244.4477 + static final class Branch extends Node {
244.4478 + Node[] atoms = new Node[2];
244.4479 + int size = 2;
244.4480 + Node conn;
244.4481 + Branch(Node first, Node second, Node branchConn) {
244.4482 + conn = branchConn;
244.4483 + atoms[0] = first;
244.4484 + atoms[1] = second;
244.4485 + }
244.4486 +
244.4487 + void add(Node node) {
244.4488 + if (size >= atoms.length) {
244.4489 + Node[] tmp = new Node[atoms.length*2];
244.4490 + System.arraycopy(atoms, 0, tmp, 0, atoms.length);
244.4491 + atoms = tmp;
244.4492 + }
244.4493 + atoms[size++] = node;
244.4494 + }
244.4495 +
244.4496 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4497 + for (int n = 0; n < size; n++) {
244.4498 + if (atoms[n] == null) {
244.4499 + if (conn.next.match(matcher, i, seq))
244.4500 + return true;
244.4501 + } else if (atoms[n].match(matcher, i, seq)) {
244.4502 + return true;
244.4503 + }
244.4504 + }
244.4505 + return false;
244.4506 + }
244.4507 +
244.4508 + boolean study(TreeInfo info) {
244.4509 + int minL = info.minLength;
244.4510 + int maxL = info.maxLength;
244.4511 + boolean maxV = info.maxValid;
244.4512 +
244.4513 + int minL2 = Integer.MAX_VALUE; //arbitrary large enough num
244.4514 + int maxL2 = -1;
244.4515 + for (int n = 0; n < size; n++) {
244.4516 + info.reset();
244.4517 + if (atoms[n] != null)
244.4518 + atoms[n].study(info);
244.4519 + minL2 = Math.min(minL2, info.minLength);
244.4520 + maxL2 = Math.max(maxL2, info.maxLength);
244.4521 + maxV = (maxV & info.maxValid);
244.4522 + }
244.4523 +
244.4524 + minL += minL2;
244.4525 + maxL += maxL2;
244.4526 +
244.4527 + info.reset();
244.4528 + conn.next.study(info);
244.4529 +
244.4530 + info.minLength += minL;
244.4531 + info.maxLength += maxL;
244.4532 + info.maxValid &= maxV;
244.4533 + info.deterministic = false;
244.4534 + return false;
244.4535 + }
244.4536 + }
244.4537 +
244.4538 + /**
244.4539 + * The GroupHead saves the location where the group begins in the locals
244.4540 + * and restores them when the match is done.
244.4541 + *
244.4542 + * The matchRef is used when a reference to this group is accessed later
244.4543 + * in the expression. The locals will have a negative value in them to
244.4544 + * indicate that we do not want to unset the group if the reference
244.4545 + * doesn't match.
244.4546 + */
244.4547 + static final class GroupHead extends Node {
244.4548 + int localIndex;
244.4549 + GroupHead(int localCount) {
244.4550 + localIndex = localCount;
244.4551 + }
244.4552 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4553 + int save = matcher.locals[localIndex];
244.4554 + matcher.locals[localIndex] = i;
244.4555 + boolean ret = next.match(matcher, i, seq);
244.4556 + matcher.locals[localIndex] = save;
244.4557 + return ret;
244.4558 + }
244.4559 + boolean matchRef(Matcher matcher, int i, CharSequence seq) {
244.4560 + int save = matcher.locals[localIndex];
244.4561 + matcher.locals[localIndex] = ~i; // HACK
244.4562 + boolean ret = next.match(matcher, i, seq);
244.4563 + matcher.locals[localIndex] = save;
244.4564 + return ret;
244.4565 + }
244.4566 + }
244.4567 +
244.4568 + /**
244.4569 + * Recursive reference to a group in the regular expression. It calls
244.4570 + * matchRef because if the reference fails to match we would not unset
244.4571 + * the group.
244.4572 + */
244.4573 + static final class GroupRef extends Node {
244.4574 + GroupHead head;
244.4575 + GroupRef(GroupHead head) {
244.4576 + this.head = head;
244.4577 + }
244.4578 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4579 + return head.matchRef(matcher, i, seq)
244.4580 + && next.match(matcher, matcher.last, seq);
244.4581 + }
244.4582 + boolean study(TreeInfo info) {
244.4583 + info.maxValid = false;
244.4584 + info.deterministic = false;
244.4585 + return next.study(info);
244.4586 + }
244.4587 + }
244.4588 +
244.4589 + /**
244.4590 + * The GroupTail handles the setting of group beginning and ending
244.4591 + * locations when groups are successfully matched. It must also be able to
244.4592 + * unset groups that have to be backed off of.
244.4593 + *
244.4594 + * The GroupTail node is also used when a previous group is referenced,
244.4595 + * and in that case no group information needs to be set.
244.4596 + */
244.4597 + static final class GroupTail extends Node {
244.4598 + int localIndex;
244.4599 + int groupIndex;
244.4600 + GroupTail(int localCount, int groupCount) {
244.4601 + localIndex = localCount;
244.4602 + groupIndex = groupCount + groupCount;
244.4603 + }
244.4604 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4605 + int tmp = matcher.locals[localIndex];
244.4606 + if (tmp >= 0) { // This is the normal group case.
244.4607 + // Save the group so we can unset it if it
244.4608 + // backs off of a match.
244.4609 + int groupStart = matcher.groups[groupIndex];
244.4610 + int groupEnd = matcher.groups[groupIndex+1];
244.4611 +
244.4612 + matcher.groups[groupIndex] = tmp;
244.4613 + matcher.groups[groupIndex+1] = i;
244.4614 + if (next.match(matcher, i, seq)) {
244.4615 + return true;
244.4616 + }
244.4617 + matcher.groups[groupIndex] = groupStart;
244.4618 + matcher.groups[groupIndex+1] = groupEnd;
244.4619 + return false;
244.4620 + } else {
244.4621 + // This is a group reference case. We don't need to save any
244.4622 + // group info because it isn't really a group.
244.4623 + matcher.last = i;
244.4624 + return true;
244.4625 + }
244.4626 + }
244.4627 + }
244.4628 +
244.4629 + /**
244.4630 + * This sets up a loop to handle a recursive quantifier structure.
244.4631 + */
244.4632 + static final class Prolog extends Node {
244.4633 + Loop loop;
244.4634 + Prolog(Loop loop) {
244.4635 + this.loop = loop;
244.4636 + }
244.4637 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4638 + return loop.matchInit(matcher, i, seq);
244.4639 + }
244.4640 + boolean study(TreeInfo info) {
244.4641 + return loop.study(info);
244.4642 + }
244.4643 + }
244.4644 +
244.4645 + /**
244.4646 + * Handles the repetition count for a greedy Curly. The matchInit
244.4647 + * is called from the Prolog to save the index of where the group
244.4648 + * beginning is stored. A zero length group check occurs in the
244.4649 + * normal match but is skipped in the matchInit.
244.4650 + */
244.4651 + static class Loop extends Node {
244.4652 + Node body;
244.4653 + int countIndex; // local count index in matcher locals
244.4654 + int beginIndex; // group beginning index
244.4655 + int cmin, cmax;
244.4656 + Loop(int countIndex, int beginIndex) {
244.4657 + this.countIndex = countIndex;
244.4658 + this.beginIndex = beginIndex;
244.4659 + }
244.4660 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4661 + // Avoid infinite loop in zero-length case.
244.4662 + if (i > matcher.locals[beginIndex]) {
244.4663 + int count = matcher.locals[countIndex];
244.4664 +
244.4665 + // This block is for before we reach the minimum
244.4666 + // iterations required for the loop to match
244.4667 + if (count < cmin) {
244.4668 + matcher.locals[countIndex] = count + 1;
244.4669 + boolean b = body.match(matcher, i, seq);
244.4670 + // If match failed we must backtrack, so
244.4671 + // the loop count should NOT be incremented
244.4672 + if (!b)
244.4673 + matcher.locals[countIndex] = count;
244.4674 + // Return success or failure since we are under
244.4675 + // minimum
244.4676 + return b;
244.4677 + }
244.4678 + // This block is for after we have the minimum
244.4679 + // iterations required for the loop to match
244.4680 + if (count < cmax) {
244.4681 + matcher.locals[countIndex] = count + 1;
244.4682 + boolean b = body.match(matcher, i, seq);
244.4683 + // If match failed we must backtrack, so
244.4684 + // the loop count should NOT be incremented
244.4685 + if (!b)
244.4686 + matcher.locals[countIndex] = count;
244.4687 + else
244.4688 + return true;
244.4689 + }
244.4690 + }
244.4691 + return next.match(matcher, i, seq);
244.4692 + }
244.4693 + boolean matchInit(Matcher matcher, int i, CharSequence seq) {
244.4694 + int save = matcher.locals[countIndex];
244.4695 + boolean ret = false;
244.4696 + if (0 < cmin) {
244.4697 + matcher.locals[countIndex] = 1;
244.4698 + ret = body.match(matcher, i, seq);
244.4699 + } else if (0 < cmax) {
244.4700 + matcher.locals[countIndex] = 1;
244.4701 + ret = body.match(matcher, i, seq);
244.4702 + if (ret == false)
244.4703 + ret = next.match(matcher, i, seq);
244.4704 + } else {
244.4705 + ret = next.match(matcher, i, seq);
244.4706 + }
244.4707 + matcher.locals[countIndex] = save;
244.4708 + return ret;
244.4709 + }
244.4710 + boolean study(TreeInfo info) {
244.4711 + info.maxValid = false;
244.4712 + info.deterministic = false;
244.4713 + return false;
244.4714 + }
244.4715 + }
244.4716 +
244.4717 + /**
244.4718 + * Handles the repetition count for a reluctant Curly. The matchInit
244.4719 + * is called from the Prolog to save the index of where the group
244.4720 + * beginning is stored. A zero length group check occurs in the
244.4721 + * normal match but is skipped in the matchInit.
244.4722 + */
244.4723 + static final class LazyLoop extends Loop {
244.4724 + LazyLoop(int countIndex, int beginIndex) {
244.4725 + super(countIndex, beginIndex);
244.4726 + }
244.4727 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4728 + // Check for zero length group
244.4729 + if (i > matcher.locals[beginIndex]) {
244.4730 + int count = matcher.locals[countIndex];
244.4731 + if (count < cmin) {
244.4732 + matcher.locals[countIndex] = count + 1;
244.4733 + boolean result = body.match(matcher, i, seq);
244.4734 + // If match failed we must backtrack, so
244.4735 + // the loop count should NOT be incremented
244.4736 + if (!result)
244.4737 + matcher.locals[countIndex] = count;
244.4738 + return result;
244.4739 + }
244.4740 + if (next.match(matcher, i, seq))
244.4741 + return true;
244.4742 + if (count < cmax) {
244.4743 + matcher.locals[countIndex] = count + 1;
244.4744 + boolean result = body.match(matcher, i, seq);
244.4745 + // If match failed we must backtrack, so
244.4746 + // the loop count should NOT be incremented
244.4747 + if (!result)
244.4748 + matcher.locals[countIndex] = count;
244.4749 + return result;
244.4750 + }
244.4751 + return false;
244.4752 + }
244.4753 + return next.match(matcher, i, seq);
244.4754 + }
244.4755 + boolean matchInit(Matcher matcher, int i, CharSequence seq) {
244.4756 + int save = matcher.locals[countIndex];
244.4757 + boolean ret = false;
244.4758 + if (0 < cmin) {
244.4759 + matcher.locals[countIndex] = 1;
244.4760 + ret = body.match(matcher, i, seq);
244.4761 + } else if (next.match(matcher, i, seq)) {
244.4762 + ret = true;
244.4763 + } else if (0 < cmax) {
244.4764 + matcher.locals[countIndex] = 1;
244.4765 + ret = body.match(matcher, i, seq);
244.4766 + }
244.4767 + matcher.locals[countIndex] = save;
244.4768 + return ret;
244.4769 + }
244.4770 + boolean study(TreeInfo info) {
244.4771 + info.maxValid = false;
244.4772 + info.deterministic = false;
244.4773 + return false;
244.4774 + }
244.4775 + }
244.4776 +
244.4777 + /**
244.4778 + * Refers to a group in the regular expression. Attempts to match
244.4779 + * whatever the group referred to last matched.
244.4780 + */
244.4781 + static class BackRef extends Node {
244.4782 + int groupIndex;
244.4783 + BackRef(int groupCount) {
244.4784 + super();
244.4785 + groupIndex = groupCount + groupCount;
244.4786 + }
244.4787 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4788 + int j = matcher.groups[groupIndex];
244.4789 + int k = matcher.groups[groupIndex+1];
244.4790 +
244.4791 + int groupSize = k - j;
244.4792 +
244.4793 + // If the referenced group didn't match, neither can this
244.4794 + if (j < 0)
244.4795 + return false;
244.4796 +
244.4797 + // If there isn't enough input left no match
244.4798 + if (i + groupSize > matcher.to) {
244.4799 + matcher.hitEnd = true;
244.4800 + return false;
244.4801 + }
244.4802 +
244.4803 + // Check each new char to make sure it matches what the group
244.4804 + // referenced matched last time around
244.4805 + for (int index=0; index<groupSize; index++)
244.4806 + if (seq.charAt(i+index) != seq.charAt(j+index))
244.4807 + return false;
244.4808 +
244.4809 + return next.match(matcher, i+groupSize, seq);
244.4810 + }
244.4811 + boolean study(TreeInfo info) {
244.4812 + info.maxValid = false;
244.4813 + return next.study(info);
244.4814 + }
244.4815 + }
244.4816 +
244.4817 + static class CIBackRef extends Node {
244.4818 + int groupIndex;
244.4819 + boolean doUnicodeCase;
244.4820 + CIBackRef(int groupCount, boolean doUnicodeCase) {
244.4821 + super();
244.4822 + groupIndex = groupCount + groupCount;
244.4823 + this.doUnicodeCase = doUnicodeCase;
244.4824 + }
244.4825 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4826 + int j = matcher.groups[groupIndex];
244.4827 + int k = matcher.groups[groupIndex+1];
244.4828 +
244.4829 + int groupSize = k - j;
244.4830 +
244.4831 + // If the referenced group didn't match, neither can this
244.4832 + if (j < 0)
244.4833 + return false;
244.4834 +
244.4835 + // If there isn't enough input left no match
244.4836 + if (i + groupSize > matcher.to) {
244.4837 + matcher.hitEnd = true;
244.4838 + return false;
244.4839 + }
244.4840 +
244.4841 + // Check each new char to make sure it matches what the group
244.4842 + // referenced matched last time around
244.4843 + int x = i;
244.4844 + for (int index=0; index<groupSize; index++) {
244.4845 + int c1 = Character.codePointAt(seq, x);
244.4846 + int c2 = Character.codePointAt(seq, j);
244.4847 + if (c1 != c2) {
244.4848 + if (doUnicodeCase) {
244.4849 + int cc1 = Character.toUpperCase(c1);
244.4850 + int cc2 = Character.toUpperCase(c2);
244.4851 + if (cc1 != cc2 &&
244.4852 + Character.toLowerCase(cc1) !=
244.4853 + Character.toLowerCase(cc2))
244.4854 + return false;
244.4855 + } else {
244.4856 + if (ASCII.toLower(c1) != ASCII.toLower(c2))
244.4857 + return false;
244.4858 + }
244.4859 + }
244.4860 + x += Character.charCount(c1);
244.4861 + j += Character.charCount(c2);
244.4862 + }
244.4863 +
244.4864 + return next.match(matcher, i+groupSize, seq);
244.4865 + }
244.4866 + boolean study(TreeInfo info) {
244.4867 + info.maxValid = false;
244.4868 + return next.study(info);
244.4869 + }
244.4870 + }
244.4871 +
244.4872 + /**
244.4873 + * Searches until the next instance of its atom. This is useful for
244.4874 + * finding the atom efficiently without passing an instance of it
244.4875 + * (greedy problem) and without a lot of wasted search time (reluctant
244.4876 + * problem).
244.4877 + */
244.4878 + static final class First extends Node {
244.4879 + Node atom;
244.4880 + First(Node node) {
244.4881 + this.atom = BnM.optimize(node);
244.4882 + }
244.4883 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4884 + if (atom instanceof BnM) {
244.4885 + return atom.match(matcher, i, seq)
244.4886 + && next.match(matcher, matcher.last, seq);
244.4887 + }
244.4888 + for (;;) {
244.4889 + if (i > matcher.to) {
244.4890 + matcher.hitEnd = true;
244.4891 + return false;
244.4892 + }
244.4893 + if (atom.match(matcher, i, seq)) {
244.4894 + return next.match(matcher, matcher.last, seq);
244.4895 + }
244.4896 + i += countChars(seq, i, 1);
244.4897 + matcher.first++;
244.4898 + }
244.4899 + }
244.4900 + boolean study(TreeInfo info) {
244.4901 + atom.study(info);
244.4902 + info.maxValid = false;
244.4903 + info.deterministic = false;
244.4904 + return next.study(info);
244.4905 + }
244.4906 + }
244.4907 +
244.4908 + static final class Conditional extends Node {
244.4909 + Node cond, yes, not;
244.4910 + Conditional(Node cond, Node yes, Node not) {
244.4911 + this.cond = cond;
244.4912 + this.yes = yes;
244.4913 + this.not = not;
244.4914 + }
244.4915 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4916 + if (cond.match(matcher, i, seq)) {
244.4917 + return yes.match(matcher, i, seq);
244.4918 + } else {
244.4919 + return not.match(matcher, i, seq);
244.4920 + }
244.4921 + }
244.4922 + boolean study(TreeInfo info) {
244.4923 + int minL = info.minLength;
244.4924 + int maxL = info.maxLength;
244.4925 + boolean maxV = info.maxValid;
244.4926 + info.reset();
244.4927 + yes.study(info);
244.4928 +
244.4929 + int minL2 = info.minLength;
244.4930 + int maxL2 = info.maxLength;
244.4931 + boolean maxV2 = info.maxValid;
244.4932 + info.reset();
244.4933 + not.study(info);
244.4934 +
244.4935 + info.minLength = minL + Math.min(minL2, info.minLength);
244.4936 + info.maxLength = maxL + Math.max(maxL2, info.maxLength);
244.4937 + info.maxValid = (maxV & maxV2 & info.maxValid);
244.4938 + info.deterministic = false;
244.4939 + return next.study(info);
244.4940 + }
244.4941 + }
244.4942 +
244.4943 + /**
244.4944 + * Zero width positive lookahead.
244.4945 + */
244.4946 + static final class Pos extends Node {
244.4947 + Node cond;
244.4948 + Pos(Node cond) {
244.4949 + this.cond = cond;
244.4950 + }
244.4951 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4952 + int savedTo = matcher.to;
244.4953 + boolean conditionMatched = false;
244.4954 +
244.4955 + // Relax transparent region boundaries for lookahead
244.4956 + if (matcher.transparentBounds)
244.4957 + matcher.to = matcher.getTextLength();
244.4958 + try {
244.4959 + conditionMatched = cond.match(matcher, i, seq);
244.4960 + } finally {
244.4961 + // Reinstate region boundaries
244.4962 + matcher.to = savedTo;
244.4963 + }
244.4964 + return conditionMatched && next.match(matcher, i, seq);
244.4965 + }
244.4966 + }
244.4967 +
244.4968 + /**
244.4969 + * Zero width negative lookahead.
244.4970 + */
244.4971 + static final class Neg extends Node {
244.4972 + Node cond;
244.4973 + Neg(Node cond) {
244.4974 + this.cond = cond;
244.4975 + }
244.4976 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.4977 + int savedTo = matcher.to;
244.4978 + boolean conditionMatched = false;
244.4979 +
244.4980 + // Relax transparent region boundaries for lookahead
244.4981 + if (matcher.transparentBounds)
244.4982 + matcher.to = matcher.getTextLength();
244.4983 + try {
244.4984 + if (i < matcher.to) {
244.4985 + conditionMatched = !cond.match(matcher, i, seq);
244.4986 + } else {
244.4987 + // If a negative lookahead succeeds then more input
244.4988 + // could cause it to fail!
244.4989 + matcher.requireEnd = true;
244.4990 + conditionMatched = !cond.match(matcher, i, seq);
244.4991 + }
244.4992 + } finally {
244.4993 + // Reinstate region boundaries
244.4994 + matcher.to = savedTo;
244.4995 + }
244.4996 + return conditionMatched && next.match(matcher, i, seq);
244.4997 + }
244.4998 + }
244.4999 +
244.5000 + /**
244.5001 + * For use with lookbehinds; matches the position where the lookbehind
244.5002 + * was encountered.
244.5003 + */
244.5004 + static Node lookbehindEnd = new Node() {
244.5005 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.5006 + return i == matcher.lookbehindTo;
244.5007 + }
244.5008 + };
244.5009 +
244.5010 + /**
244.5011 + * Zero width positive lookbehind.
244.5012 + */
244.5013 + static class Behind extends Node {
244.5014 + Node cond;
244.5015 + int rmax, rmin;
244.5016 + Behind(Node cond, int rmax, int rmin) {
244.5017 + this.cond = cond;
244.5018 + this.rmax = rmax;
244.5019 + this.rmin = rmin;
244.5020 + }
244.5021 +
244.5022 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.5023 + int savedFrom = matcher.from;
244.5024 + boolean conditionMatched = false;
244.5025 + int startIndex = (!matcher.transparentBounds) ?
244.5026 + matcher.from : 0;
244.5027 + int from = Math.max(i - rmax, startIndex);
244.5028 + // Set end boundary
244.5029 + int savedLBT = matcher.lookbehindTo;
244.5030 + matcher.lookbehindTo = i;
244.5031 + // Relax transparent region boundaries for lookbehind
244.5032 + if (matcher.transparentBounds)
244.5033 + matcher.from = 0;
244.5034 + for (int j = i - rmin; !conditionMatched && j >= from; j--) {
244.5035 + conditionMatched = cond.match(matcher, j, seq);
244.5036 + }
244.5037 + matcher.from = savedFrom;
244.5038 + matcher.lookbehindTo = savedLBT;
244.5039 + return conditionMatched && next.match(matcher, i, seq);
244.5040 + }
244.5041 + }
244.5042 +
244.5043 + /**
244.5044 + * Zero width positive lookbehind, including supplementary
244.5045 + * characters or unpaired surrogates.
244.5046 + */
244.5047 + static final class BehindS extends Behind {
244.5048 + BehindS(Node cond, int rmax, int rmin) {
244.5049 + super(cond, rmax, rmin);
244.5050 + }
244.5051 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.5052 + int rmaxChars = countChars(seq, i, -rmax);
244.5053 + int rminChars = countChars(seq, i, -rmin);
244.5054 + int savedFrom = matcher.from;
244.5055 + int startIndex = (!matcher.transparentBounds) ?
244.5056 + matcher.from : 0;
244.5057 + boolean conditionMatched = false;
244.5058 + int from = Math.max(i - rmaxChars, startIndex);
244.5059 + // Set end boundary
244.5060 + int savedLBT = matcher.lookbehindTo;
244.5061 + matcher.lookbehindTo = i;
244.5062 + // Relax transparent region boundaries for lookbehind
244.5063 + if (matcher.transparentBounds)
244.5064 + matcher.from = 0;
244.5065 +
244.5066 + for (int j = i - rminChars;
244.5067 + !conditionMatched && j >= from;
244.5068 + j -= j>from ? countChars(seq, j, -1) : 1) {
244.5069 + conditionMatched = cond.match(matcher, j, seq);
244.5070 + }
244.5071 + matcher.from = savedFrom;
244.5072 + matcher.lookbehindTo = savedLBT;
244.5073 + return conditionMatched && next.match(matcher, i, seq);
244.5074 + }
244.5075 + }
244.5076 +
244.5077 + /**
244.5078 + * Zero width negative lookbehind.
244.5079 + */
244.5080 + static class NotBehind extends Node {
244.5081 + Node cond;
244.5082 + int rmax, rmin;
244.5083 + NotBehind(Node cond, int rmax, int rmin) {
244.5084 + this.cond = cond;
244.5085 + this.rmax = rmax;
244.5086 + this.rmin = rmin;
244.5087 + }
244.5088 +
244.5089 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.5090 + int savedLBT = matcher.lookbehindTo;
244.5091 + int savedFrom = matcher.from;
244.5092 + boolean conditionMatched = false;
244.5093 + int startIndex = (!matcher.transparentBounds) ?
244.5094 + matcher.from : 0;
244.5095 + int from = Math.max(i - rmax, startIndex);
244.5096 + matcher.lookbehindTo = i;
244.5097 + // Relax transparent region boundaries for lookbehind
244.5098 + if (matcher.transparentBounds)
244.5099 + matcher.from = 0;
244.5100 + for (int j = i - rmin; !conditionMatched && j >= from; j--) {
244.5101 + conditionMatched = cond.match(matcher, j, seq);
244.5102 + }
244.5103 + // Reinstate region boundaries
244.5104 + matcher.from = savedFrom;
244.5105 + matcher.lookbehindTo = savedLBT;
244.5106 + return !conditionMatched && next.match(matcher, i, seq);
244.5107 + }
244.5108 + }
244.5109 +
244.5110 + /**
244.5111 + * Zero width negative lookbehind, including supplementary
244.5112 + * characters or unpaired surrogates.
244.5113 + */
244.5114 + static final class NotBehindS extends NotBehind {
244.5115 + NotBehindS(Node cond, int rmax, int rmin) {
244.5116 + super(cond, rmax, rmin);
244.5117 + }
244.5118 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.5119 + int rmaxChars = countChars(seq, i, -rmax);
244.5120 + int rminChars = countChars(seq, i, -rmin);
244.5121 + int savedFrom = matcher.from;
244.5122 + int savedLBT = matcher.lookbehindTo;
244.5123 + boolean conditionMatched = false;
244.5124 + int startIndex = (!matcher.transparentBounds) ?
244.5125 + matcher.from : 0;
244.5126 + int from = Math.max(i - rmaxChars, startIndex);
244.5127 + matcher.lookbehindTo = i;
244.5128 + // Relax transparent region boundaries for lookbehind
244.5129 + if (matcher.transparentBounds)
244.5130 + matcher.from = 0;
244.5131 + for (int j = i - rminChars;
244.5132 + !conditionMatched && j >= from;
244.5133 + j -= j>from ? countChars(seq, j, -1) : 1) {
244.5134 + conditionMatched = cond.match(matcher, j, seq);
244.5135 + }
244.5136 + //Reinstate region boundaries
244.5137 + matcher.from = savedFrom;
244.5138 + matcher.lookbehindTo = savedLBT;
244.5139 + return !conditionMatched && next.match(matcher, i, seq);
244.5140 + }
244.5141 + }
244.5142 +
244.5143 + /**
244.5144 + * Returns the set union of two CharProperty nodes.
244.5145 + */
244.5146 + private static CharProperty union(final CharProperty lhs,
244.5147 + final CharProperty rhs) {
244.5148 + return new CharProperty() {
244.5149 + boolean isSatisfiedBy(int ch) {
244.5150 + return lhs.isSatisfiedBy(ch) || rhs.isSatisfiedBy(ch);}};
244.5151 + }
244.5152 +
244.5153 + /**
244.5154 + * Returns the set intersection of two CharProperty nodes.
244.5155 + */
244.5156 + private static CharProperty intersection(final CharProperty lhs,
244.5157 + final CharProperty rhs) {
244.5158 + return new CharProperty() {
244.5159 + boolean isSatisfiedBy(int ch) {
244.5160 + return lhs.isSatisfiedBy(ch) && rhs.isSatisfiedBy(ch);}};
244.5161 + }
244.5162 +
244.5163 + /**
244.5164 + * Returns the set difference of two CharProperty nodes.
244.5165 + */
244.5166 + private static CharProperty setDifference(final CharProperty lhs,
244.5167 + final CharProperty rhs) {
244.5168 + return new CharProperty() {
244.5169 + boolean isSatisfiedBy(int ch) {
244.5170 + return ! rhs.isSatisfiedBy(ch) && lhs.isSatisfiedBy(ch);}};
244.5171 + }
244.5172 +
244.5173 + /**
244.5174 + * Handles word boundaries. Includes a field to allow this one class to
244.5175 + * deal with the different types of word boundaries we can match. The word
244.5176 + * characters include underscores, letters, and digits. Non spacing marks
244.5177 + * can are also part of a word if they have a base character, otherwise
244.5178 + * they are ignored for purposes of finding word boundaries.
244.5179 + */
244.5180 + static final class Bound extends Node {
244.5181 + static int LEFT = 0x1;
244.5182 + static int RIGHT= 0x2;
244.5183 + static int BOTH = 0x3;
244.5184 + static int NONE = 0x4;
244.5185 + int type;
244.5186 + boolean useUWORD;
244.5187 + Bound(int n, boolean useUWORD) {
244.5188 + type = n;
244.5189 + this.useUWORD = useUWORD;
244.5190 + }
244.5191 +
244.5192 + boolean isWord(int ch) {
244.5193 + return useUWORD ? UnicodeProp.WORD.is(ch)
244.5194 + : (ch == '_' || Character.isLetterOrDigit(ch));
244.5195 + }
244.5196 +
244.5197 + int check(Matcher matcher, int i, CharSequence seq) {
244.5198 + int ch;
244.5199 + boolean left = false;
244.5200 + int startIndex = matcher.from;
244.5201 + int endIndex = matcher.to;
244.5202 + if (matcher.transparentBounds) {
244.5203 + startIndex = 0;
244.5204 + endIndex = matcher.getTextLength();
244.5205 + }
244.5206 + if (i > startIndex) {
244.5207 + ch = Character.codePointBefore(seq, i);
244.5208 + left = (isWord(ch) ||
244.5209 + ((Character.getType(ch) == Character.NON_SPACING_MARK)
244.5210 + && hasBaseCharacter(matcher, i-1, seq)));
244.5211 + }
244.5212 + boolean right = false;
244.5213 + if (i < endIndex) {
244.5214 + ch = Character.codePointAt(seq, i);
244.5215 + right = (isWord(ch) ||
244.5216 + ((Character.getType(ch) == Character.NON_SPACING_MARK)
244.5217 + && hasBaseCharacter(matcher, i, seq)));
244.5218 + } else {
244.5219 + // Tried to access char past the end
244.5220 + matcher.hitEnd = true;
244.5221 + // The addition of another char could wreck a boundary
244.5222 + matcher.requireEnd = true;
244.5223 + }
244.5224 + return ((left ^ right) ? (right ? LEFT : RIGHT) : NONE);
244.5225 + }
244.5226 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.5227 + return (check(matcher, i, seq) & type) > 0
244.5228 + && next.match(matcher, i, seq);
244.5229 + }
244.5230 + }
244.5231 +
244.5232 + /**
244.5233 + * Non spacing marks only count as word characters in bounds calculations
244.5234 + * if they have a base character.
244.5235 + */
244.5236 + private static boolean hasBaseCharacter(Matcher matcher, int i,
244.5237 + CharSequence seq)
244.5238 + {
244.5239 + int start = (!matcher.transparentBounds) ?
244.5240 + matcher.from : 0;
244.5241 + for (int x=i; x >= start; x--) {
244.5242 + int ch = Character.codePointAt(seq, x);
244.5243 + if (Character.isLetterOrDigit(ch))
244.5244 + return true;
244.5245 + if (Character.getType(ch) == Character.NON_SPACING_MARK)
244.5246 + continue;
244.5247 + return false;
244.5248 + }
244.5249 + return false;
244.5250 + }
244.5251 +
244.5252 + /**
244.5253 + * Attempts to match a slice in the input using the Boyer-Moore string
244.5254 + * matching algorithm. The algorithm is based on the idea that the
244.5255 + * pattern can be shifted farther ahead in the search text if it is
244.5256 + * matched right to left.
244.5257 + * <p>
244.5258 + * The pattern is compared to the input one character at a time, from
244.5259 + * the rightmost character in the pattern to the left. If the characters
244.5260 + * all match the pattern has been found. If a character does not match,
244.5261 + * the pattern is shifted right a distance that is the maximum of two
244.5262 + * functions, the bad character shift and the good suffix shift. This
244.5263 + * shift moves the attempted match position through the input more
244.5264 + * quickly than a naive one position at a time check.
244.5265 + * <p>
244.5266 + * The bad character shift is based on the character from the text that
244.5267 + * did not match. If the character does not appear in the pattern, the
244.5268 + * pattern can be shifted completely beyond the bad character. If the
244.5269 + * character does occur in the pattern, the pattern can be shifted to
244.5270 + * line the pattern up with the next occurrence of that character.
244.5271 + * <p>
244.5272 + * The good suffix shift is based on the idea that some subset on the right
244.5273 + * side of the pattern has matched. When a bad character is found, the
244.5274 + * pattern can be shifted right by the pattern length if the subset does
244.5275 + * not occur again in pattern, or by the amount of distance to the
244.5276 + * next occurrence of the subset in the pattern.
244.5277 + *
244.5278 + * Boyer-Moore search methods adapted from code by Amy Yu.
244.5279 + */
244.5280 + static class BnM extends Node {
244.5281 + int[] buffer;
244.5282 + int[] lastOcc;
244.5283 + int[] optoSft;
244.5284 +
244.5285 + /**
244.5286 + * Pre calculates arrays needed to generate the bad character
244.5287 + * shift and the good suffix shift. Only the last seven bits
244.5288 + * are used to see if chars match; This keeps the tables small
244.5289 + * and covers the heavily used ASCII range, but occasionally
244.5290 + * results in an aliased match for the bad character shift.
244.5291 + */
244.5292 + static Node optimize(Node node) {
244.5293 + if (!(node instanceof Slice)) {
244.5294 + return node;
244.5295 + }
244.5296 +
244.5297 + int[] src = ((Slice) node).buffer;
244.5298 + int patternLength = src.length;
244.5299 + // The BM algorithm requires a bit of overhead;
244.5300 + // If the pattern is short don't use it, since
244.5301 + // a shift larger than the pattern length cannot
244.5302 + // be used anyway.
244.5303 + if (patternLength < 4) {
244.5304 + return node;
244.5305 + }
244.5306 + int i, j, k;
244.5307 + int[] lastOcc = new int[128];
244.5308 + int[] optoSft = new int[patternLength];
244.5309 + // Precalculate part of the bad character shift
244.5310 + // It is a table for where in the pattern each
244.5311 + // lower 7-bit value occurs
244.5312 + for (i = 0; i < patternLength; i++) {
244.5313 + lastOcc[src[i]&0x7F] = i + 1;
244.5314 + }
244.5315 + // Precalculate the good suffix shift
244.5316 + // i is the shift amount being considered
244.5317 +NEXT: for (i = patternLength; i > 0; i--) {
244.5318 + // j is the beginning index of suffix being considered
244.5319 + for (j = patternLength - 1; j >= i; j--) {
244.5320 + // Testing for good suffix
244.5321 + if (src[j] == src[j-i]) {
244.5322 + // src[j..len] is a good suffix
244.5323 + optoSft[j-1] = i;
244.5324 + } else {
244.5325 + // No match. The array has already been
244.5326 + // filled up with correct values before.
244.5327 + continue NEXT;
244.5328 + }
244.5329 + }
244.5330 + // This fills up the remaining of optoSft
244.5331 + // any suffix can not have larger shift amount
244.5332 + // then its sub-suffix. Why???
244.5333 + while (j > 0) {
244.5334 + optoSft[--j] = i;
244.5335 + }
244.5336 + }
244.5337 + // Set the guard value because of unicode compression
244.5338 + optoSft[patternLength-1] = 1;
244.5339 + if (node instanceof SliceS)
244.5340 + return new BnMS(src, lastOcc, optoSft, node.next);
244.5341 + return new BnM(src, lastOcc, optoSft, node.next);
244.5342 + }
244.5343 + BnM(int[] src, int[] lastOcc, int[] optoSft, Node next) {
244.5344 + this.buffer = src;
244.5345 + this.lastOcc = lastOcc;
244.5346 + this.optoSft = optoSft;
244.5347 + this.next = next;
244.5348 + }
244.5349 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.5350 + int[] src = buffer;
244.5351 + int patternLength = src.length;
244.5352 + int last = matcher.to - patternLength;
244.5353 +
244.5354 + // Loop over all possible match positions in text
244.5355 +NEXT: while (i <= last) {
244.5356 + // Loop over pattern from right to left
244.5357 + for (int j = patternLength - 1; j >= 0; j--) {
244.5358 + int ch = seq.charAt(i+j);
244.5359 + if (ch != src[j]) {
244.5360 + // Shift search to the right by the maximum of the
244.5361 + // bad character shift and the good suffix shift
244.5362 + i += Math.max(j + 1 - lastOcc[ch&0x7F], optoSft[j]);
244.5363 + continue NEXT;
244.5364 + }
244.5365 + }
244.5366 + // Entire pattern matched starting at i
244.5367 + matcher.first = i;
244.5368 + boolean ret = next.match(matcher, i + patternLength, seq);
244.5369 + if (ret) {
244.5370 + matcher.first = i;
244.5371 + matcher.groups[0] = matcher.first;
244.5372 + matcher.groups[1] = matcher.last;
244.5373 + return true;
244.5374 + }
244.5375 + i++;
244.5376 + }
244.5377 + // BnM is only used as the leading node in the unanchored case,
244.5378 + // and it replaced its Start() which always searches to the end
244.5379 + // if it doesn't find what it's looking for, so hitEnd is true.
244.5380 + matcher.hitEnd = true;
244.5381 + return false;
244.5382 + }
244.5383 + boolean study(TreeInfo info) {
244.5384 + info.minLength += buffer.length;
244.5385 + info.maxValid = false;
244.5386 + return next.study(info);
244.5387 + }
244.5388 + }
244.5389 +
244.5390 + /**
244.5391 + * Supplementary support version of BnM(). Unpaired surrogates are
244.5392 + * also handled by this class.
244.5393 + */
244.5394 + static final class BnMS extends BnM {
244.5395 + int lengthInChars;
244.5396 +
244.5397 + BnMS(int[] src, int[] lastOcc, int[] optoSft, Node next) {
244.5398 + super(src, lastOcc, optoSft, next);
244.5399 + for (int x = 0; x < buffer.length; x++) {
244.5400 + lengthInChars += Character.charCount(buffer[x]);
244.5401 + }
244.5402 + }
244.5403 + boolean match(Matcher matcher, int i, CharSequence seq) {
244.5404 + int[] src = buffer;
244.5405 + int patternLength = src.length;
244.5406 + int last = matcher.to - lengthInChars;
244.5407 +
244.5408 + // Loop over all possible match positions in text
244.5409 +NEXT: while (i <= last) {
244.5410 + // Loop over pattern from right to left
244.5411 + int ch;
244.5412 + for (int j = countChars(seq, i, patternLength), x = patternLength - 1;
244.5413 + j > 0; j -= Character.charCount(ch), x--) {
244.5414 + ch = Character.codePointBefore(seq, i+j);
244.5415 + if (ch != src[x]) {
244.5416 + // Shift search to the right by the maximum of the
244.5417 + // bad character shift and the good suffix shift
244.5418 + int n = Math.max(x + 1 - lastOcc[ch&0x7F], optoSft[x]);
244.5419 + i += countChars(seq, i, n);
244.5420 + continue NEXT;
244.5421 + }
244.5422 + }
244.5423 + // Entire pattern matched starting at i
244.5424 + matcher.first = i;
244.5425 + boolean ret = next.match(matcher, i + lengthInChars, seq);
244.5426 + if (ret) {
244.5427 + matcher.first = i;
244.5428 + matcher.groups[0] = matcher.first;
244.5429 + matcher.groups[1] = matcher.last;
244.5430 + return true;
244.5431 + }
244.5432 + i += countChars(seq, i, 1);
244.5433 + }
244.5434 + matcher.hitEnd = true;
244.5435 + return false;
244.5436 + }
244.5437 + }
244.5438 +
244.5439 +///////////////////////////////////////////////////////////////////////////////
244.5440 +///////////////////////////////////////////////////////////////////////////////
244.5441 +
244.5442 + /**
244.5443 + * This must be the very first initializer.
244.5444 + */
244.5445 + static Node accept = new Node();
244.5446 +
244.5447 + static Node lastAccept = new LastNode();
244.5448 +
244.5449 + private static class CharPropertyNames {
244.5450 +
244.5451 + static CharProperty charPropertyFor(String name) {
244.5452 + CharPropertyFactory m = map.get(name);
244.5453 + return m == null ? null : m.make();
244.5454 + }
244.5455 +
244.5456 + private static abstract class CharPropertyFactory {
244.5457 + abstract CharProperty make();
244.5458 + }
244.5459 +
244.5460 + private static void defCategory(String name,
244.5461 + final int typeMask) {
244.5462 + map.put(name, new CharPropertyFactory() {
244.5463 + CharProperty make() { return new Category(typeMask);}});
244.5464 + }
244.5465 +
244.5466 + private static void defRange(String name,
244.5467 + final int lower, final int upper) {
244.5468 + map.put(name, new CharPropertyFactory() {
244.5469 + CharProperty make() { return rangeFor(lower, upper);}});
244.5470 + }
244.5471 +
244.5472 + private static void defCtype(String name,
244.5473 + final int ctype) {
244.5474 + map.put(name, new CharPropertyFactory() {
244.5475 + CharProperty make() { return new Ctype(ctype);}});
244.5476 + }
244.5477 +
244.5478 + private static abstract class CloneableProperty
244.5479 + extends CharProperty implements Cloneable
244.5480 + {
244.5481 + public CloneableProperty clone() {
244.5482 + try {
244.5483 + return (CloneableProperty) super.clone();
244.5484 + } catch (CloneNotSupportedException e) {
244.5485 + throw new AssertionError(e);
244.5486 + }
244.5487 + }
244.5488 + }
244.5489 +
244.5490 + private static void defClone(String name,
244.5491 + final CloneableProperty p) {
244.5492 + map.put(name, new CharPropertyFactory() {
244.5493 + CharProperty make() { return p.clone();}});
244.5494 + }
244.5495 +
244.5496 + private static final HashMap<String, CharPropertyFactory> map
244.5497 + = new HashMap<>();
244.5498 +
244.5499 + static {
244.5500 + // Unicode character property aliases, defined in
244.5501 + // http://www.unicode.org/Public/UNIDATA/PropertyValueAliases.txt
244.5502 + defCategory("Cn", 1<<Character.UNASSIGNED);
244.5503 + defCategory("Lu", 1<<Character.UPPERCASE_LETTER);
244.5504 + defCategory("Ll", 1<<Character.LOWERCASE_LETTER);
244.5505 + defCategory("Lt", 1<<Character.TITLECASE_LETTER);
244.5506 + defCategory("Lm", 1<<Character.MODIFIER_LETTER);
244.5507 + defCategory("Lo", 1<<Character.OTHER_LETTER);
244.5508 + defCategory("Mn", 1<<Character.NON_SPACING_MARK);
244.5509 + defCategory("Me", 1<<Character.ENCLOSING_MARK);
244.5510 + defCategory("Mc", 1<<Character.COMBINING_SPACING_MARK);
244.5511 + defCategory("Nd", 1<<Character.DECIMAL_DIGIT_NUMBER);
244.5512 + defCategory("Nl", 1<<Character.LETTER_NUMBER);
244.5513 + defCategory("No", 1<<Character.OTHER_NUMBER);
244.5514 + defCategory("Zs", 1<<Character.SPACE_SEPARATOR);
244.5515 + defCategory("Zl", 1<<Character.LINE_SEPARATOR);
244.5516 + defCategory("Zp", 1<<Character.PARAGRAPH_SEPARATOR);
244.5517 + defCategory("Cc", 1<<Character.CONTROL);
244.5518 + defCategory("Cf", 1<<Character.FORMAT);
244.5519 + defCategory("Co", 1<<Character.PRIVATE_USE);
244.5520 + defCategory("Cs", 1<<Character.SURROGATE);
244.5521 + defCategory("Pd", 1<<Character.DASH_PUNCTUATION);
244.5522 + defCategory("Ps", 1<<Character.START_PUNCTUATION);
244.5523 + defCategory("Pe", 1<<Character.END_PUNCTUATION);
244.5524 + defCategory("Pc", 1<<Character.CONNECTOR_PUNCTUATION);
244.5525 + defCategory("Po", 1<<Character.OTHER_PUNCTUATION);
244.5526 + defCategory("Sm", 1<<Character.MATH_SYMBOL);
244.5527 + defCategory("Sc", 1<<Character.CURRENCY_SYMBOL);
244.5528 + defCategory("Sk", 1<<Character.MODIFIER_SYMBOL);
244.5529 + defCategory("So", 1<<Character.OTHER_SYMBOL);
244.5530 + defCategory("Pi", 1<<Character.INITIAL_QUOTE_PUNCTUATION);
244.5531 + defCategory("Pf", 1<<Character.FINAL_QUOTE_PUNCTUATION);
244.5532 + defCategory("L", ((1<<Character.UPPERCASE_LETTER) |
244.5533 + (1<<Character.LOWERCASE_LETTER) |
244.5534 + (1<<Character.TITLECASE_LETTER) |
244.5535 + (1<<Character.MODIFIER_LETTER) |
244.5536 + (1<<Character.OTHER_LETTER)));
244.5537 + defCategory("M", ((1<<Character.NON_SPACING_MARK) |
244.5538 + (1<<Character.ENCLOSING_MARK) |
244.5539 + (1<<Character.COMBINING_SPACING_MARK)));
244.5540 + defCategory("N", ((1<<Character.DECIMAL_DIGIT_NUMBER) |
244.5541 + (1<<Character.LETTER_NUMBER) |
244.5542 + (1<<Character.OTHER_NUMBER)));
244.5543 + defCategory("Z", ((1<<Character.SPACE_SEPARATOR) |
244.5544 + (1<<Character.LINE_SEPARATOR) |
244.5545 + (1<<Character.PARAGRAPH_SEPARATOR)));
244.5546 + defCategory("C", ((1<<Character.CONTROL) |
244.5547 + (1<<Character.FORMAT) |
244.5548 + (1<<Character.PRIVATE_USE) |
244.5549 + (1<<Character.SURROGATE))); // Other
244.5550 + defCategory("P", ((1<<Character.DASH_PUNCTUATION) |
244.5551 + (1<<Character.START_PUNCTUATION) |
244.5552 + (1<<Character.END_PUNCTUATION) |
244.5553 + (1<<Character.CONNECTOR_PUNCTUATION) |
244.5554 + (1<<Character.OTHER_PUNCTUATION) |
244.5555 + (1<<Character.INITIAL_QUOTE_PUNCTUATION) |
244.5556 + (1<<Character.FINAL_QUOTE_PUNCTUATION)));
244.5557 + defCategory("S", ((1<<Character.MATH_SYMBOL) |
244.5558 + (1<<Character.CURRENCY_SYMBOL) |
244.5559 + (1<<Character.MODIFIER_SYMBOL) |
244.5560 + (1<<Character.OTHER_SYMBOL)));
244.5561 + defCategory("LC", ((1<<Character.UPPERCASE_LETTER) |
244.5562 + (1<<Character.LOWERCASE_LETTER) |
244.5563 + (1<<Character.TITLECASE_LETTER)));
244.5564 + defCategory("LD", ((1<<Character.UPPERCASE_LETTER) |
244.5565 + (1<<Character.LOWERCASE_LETTER) |
244.5566 + (1<<Character.TITLECASE_LETTER) |
244.5567 + (1<<Character.MODIFIER_LETTER) |
244.5568 + (1<<Character.OTHER_LETTER) |
244.5569 + (1<<Character.DECIMAL_DIGIT_NUMBER)));
244.5570 + defRange("L1", 0x00, 0xFF); // Latin-1
244.5571 + map.put("all", new CharPropertyFactory() {
244.5572 + CharProperty make() { return new All(); }});
244.5573 +
244.5574 + // Posix regular expression character classes, defined in
244.5575 + // http://www.unix.org/onlinepubs/009695399/basedefs/xbd_chap09.html
244.5576 + defRange("ASCII", 0x00, 0x7F); // ASCII
244.5577 + defCtype("Alnum", ASCII.ALNUM); // Alphanumeric characters
244.5578 + defCtype("Alpha", ASCII.ALPHA); // Alphabetic characters
244.5579 + defCtype("Blank", ASCII.BLANK); // Space and tab characters
244.5580 + defCtype("Cntrl", ASCII.CNTRL); // Control characters
244.5581 + defRange("Digit", '0', '9'); // Numeric characters
244.5582 + defCtype("Graph", ASCII.GRAPH); // printable and visible
244.5583 + defRange("Lower", 'a', 'z'); // Lower-case alphabetic
244.5584 + defRange("Print", 0x20, 0x7E); // Printable characters
244.5585 + defCtype("Punct", ASCII.PUNCT); // Punctuation characters
244.5586 + defCtype("Space", ASCII.SPACE); // Space characters
244.5587 + defRange("Upper", 'A', 'Z'); // Upper-case alphabetic
244.5588 + defCtype("XDigit",ASCII.XDIGIT); // hexadecimal digits
244.5589 +
244.5590 + // Java character properties, defined by methods in Character.java
244.5591 + defClone("javaLowerCase", new CloneableProperty() {
244.5592 + boolean isSatisfiedBy(int ch) {
244.5593 + return Character.isLowerCase(ch);}});
244.5594 + defClone("javaUpperCase", new CloneableProperty() {
244.5595 + boolean isSatisfiedBy(int ch) {
244.5596 + return Character.isUpperCase(ch);}});
244.5597 + defClone("javaAlphabetic", new CloneableProperty() {
244.5598 + boolean isSatisfiedBy(int ch) {
244.5599 + return Character.isAlphabetic(ch);}});
244.5600 + defClone("javaIdeographic", new CloneableProperty() {
244.5601 + boolean isSatisfiedBy(int ch) {
244.5602 + return Character.isIdeographic(ch);}});
244.5603 + defClone("javaTitleCase", new CloneableProperty() {
244.5604 + boolean isSatisfiedBy(int ch) {
244.5605 + return Character.isTitleCase(ch);}});
244.5606 + defClone("javaDigit", new CloneableProperty() {
244.5607 + boolean isSatisfiedBy(int ch) {
244.5608 + return Character.isDigit(ch);}});
244.5609 + defClone("javaDefined", new CloneableProperty() {
244.5610 + boolean isSatisfiedBy(int ch) {
244.5611 + return Character.isDefined(ch);}});
244.5612 + defClone("javaLetter", new CloneableProperty() {
244.5613 + boolean isSatisfiedBy(int ch) {
244.5614 + return Character.isLetter(ch);}});
244.5615 + defClone("javaLetterOrDigit", new CloneableProperty() {
244.5616 + boolean isSatisfiedBy(int ch) {
244.5617 + return Character.isLetterOrDigit(ch);}});
244.5618 + defClone("javaJavaIdentifierStart", new CloneableProperty() {
244.5619 + boolean isSatisfiedBy(int ch) {
244.5620 + return Character.isJavaIdentifierStart(ch);}});
244.5621 + defClone("javaJavaIdentifierPart", new CloneableProperty() {
244.5622 + boolean isSatisfiedBy(int ch) {
244.5623 + return Character.isJavaIdentifierPart(ch);}});
244.5624 + defClone("javaUnicodeIdentifierStart", new CloneableProperty() {
244.5625 + boolean isSatisfiedBy(int ch) {
244.5626 + return Character.isUnicodeIdentifierStart(ch);}});
244.5627 + defClone("javaUnicodeIdentifierPart", new CloneableProperty() {
244.5628 + boolean isSatisfiedBy(int ch) {
244.5629 + return Character.isUnicodeIdentifierPart(ch);}});
244.5630 + defClone("javaIdentifierIgnorable", new CloneableProperty() {
244.5631 + boolean isSatisfiedBy(int ch) {
244.5632 + return Character.isIdentifierIgnorable(ch);}});
244.5633 + defClone("javaSpaceChar", new CloneableProperty() {
244.5634 + boolean isSatisfiedBy(int ch) {
244.5635 + return Character.isSpaceChar(ch);}});
244.5636 + defClone("javaWhitespace", new CloneableProperty() {
244.5637 + boolean isSatisfiedBy(int ch) {
244.5638 + return Character.isWhitespace(ch);}});
244.5639 + defClone("javaISOControl", new CloneableProperty() {
244.5640 + boolean isSatisfiedBy(int ch) {
244.5641 + return Character.isISOControl(ch);}});
244.5642 + defClone("javaMirrored", new CloneableProperty() {
244.5643 + boolean isSatisfiedBy(int ch) {
244.5644 + return Character.isMirrored(ch);}});
244.5645 + }
244.5646 + }
244.5647 +
244.5648 + private static final class Normalizer {
244.5649 + public static final int NFD = 1;
244.5650 + public static final int NFC = 2;
244.5651 +
244.5652 + static String normalize(String pattern, int NFD) {
244.5653 + return pattern;
244.5654 + }
244.5655 +
244.5656 + private static int getCombiningClass(int c) {
244.5657 + return 1;
244.5658 + }
244.5659 + }
244.5660 +}
245.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
245.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/PatternSyntaxException.java Wed Apr 30 15:04:10 2014 +0200
245.3 @@ -0,0 +1,119 @@
245.4 +/*
245.5 + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
245.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
245.7 + *
245.8 + * This code is free software; you can redistribute it and/or modify it
245.9 + * under the terms of the GNU General Public License version 2 only, as
245.10 + * published by the Free Software Foundation. Oracle designates this
245.11 + * particular file as subject to the "Classpath" exception as provided
245.12 + * by Oracle in the LICENSE file that accompanied this code.
245.13 + *
245.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
245.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
245.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
245.17 + * version 2 for more details (a copy is included in the LICENSE file that
245.18 + * accompanied this code).
245.19 + *
245.20 + * You should have received a copy of the GNU General Public License version
245.21 + * 2 along with this work; if not, write to the Free Software Foundation,
245.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
245.23 + *
245.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
245.25 + * or visit www.oracle.com if you need additional information or have any
245.26 + * questions.
245.27 + */
245.28 +
245.29 +package java.util.regex;
245.30 +
245.31 +/**
245.32 + * Unchecked exception thrown to indicate a syntax error in a
245.33 + * regular-expression pattern.
245.34 + *
245.35 + * @author unascribed
245.36 + * @since 1.4
245.37 + * @spec JSR-51
245.38 + */
245.39 +
245.40 +public class PatternSyntaxException
245.41 + extends IllegalArgumentException
245.42 +{
245.43 + private static final long serialVersionUID = -3864639126226059218L;
245.44 +
245.45 + private final String desc;
245.46 + private final String pattern;
245.47 + private final int index;
245.48 +
245.49 + /**
245.50 + * Constructs a new instance of this class.
245.51 + *
245.52 + * @param desc
245.53 + * A description of the error
245.54 + *
245.55 + * @param regex
245.56 + * The erroneous pattern
245.57 + *
245.58 + * @param index
245.59 + * The approximate index in the pattern of the error,
245.60 + * or <tt>-1</tt> if the index is not known
245.61 + */
245.62 + public PatternSyntaxException(String desc, String regex, int index) {
245.63 + this.desc = desc;
245.64 + this.pattern = regex;
245.65 + this.index = index;
245.66 + }
245.67 +
245.68 + /**
245.69 + * Retrieves the error index.
245.70 + *
245.71 + * @return The approximate index in the pattern of the error,
245.72 + * or <tt>-1</tt> if the index is not known
245.73 + */
245.74 + public int getIndex() {
245.75 + return index;
245.76 + }
245.77 +
245.78 + /**
245.79 + * Retrieves the description of the error.
245.80 + *
245.81 + * @return The description of the error
245.82 + */
245.83 + public String getDescription() {
245.84 + return desc;
245.85 + }
245.86 +
245.87 + /**
245.88 + * Retrieves the erroneous regular-expression pattern.
245.89 + *
245.90 + * @return The erroneous pattern
245.91 + */
245.92 + public String getPattern() {
245.93 + return pattern;
245.94 + }
245.95 +
245.96 + private static final String nl = System.lineSeparator();
245.97 +
245.98 + /**
245.99 + * Returns a multi-line string containing the description of the syntax
245.100 + * error and its index, the erroneous regular-expression pattern, and a
245.101 + * visual indication of the error index within the pattern.
245.102 + *
245.103 + * @return The full detail message
245.104 + */
245.105 + public String getMessage() {
245.106 + StringBuffer sb = new StringBuffer();
245.107 + sb.append(desc);
245.108 + if (index >= 0) {
245.109 + sb.append(" near index ");
245.110 + sb.append(index);
245.111 + }
245.112 + sb.append(nl);
245.113 + sb.append(pattern);
245.114 + if (index >= 0) {
245.115 + sb.append(nl);
245.116 + for (int i = 0; i < index; i++) sb.append(' ');
245.117 + sb.append('^');
245.118 + }
245.119 + return sb.toString();
245.120 + }
245.121 +
245.122 +}
246.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
246.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/UnicodeProp.java Wed Apr 30 15:04:10 2014 +0200
246.3 @@ -0,0 +1,236 @@
246.4 +/*
246.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
246.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
246.7 + *
246.8 + * This code is free software; you can redistribute it and/or modify it
246.9 + * under the terms of the GNU General Public License version 2 only, as
246.10 + * published by the Free Software Foundation. Oracle designates this
246.11 + * particular file as subject to the "Classpath" exception as provided
246.12 + * by Oracle in the LICENSE file that accompanied this code.
246.13 + *
246.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
246.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
246.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
246.17 + * version 2 for more details (a copy is included in the LICENSE file that
246.18 + * accompanied this code).
246.19 + *
246.20 + * You should have received a copy of the GNU General Public License version
246.21 + * 2 along with this work; if not, write to the Free Software Foundation,
246.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
246.23 + *
246.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
246.25 + * or visit www.oracle.com if you need additional information or have any
246.26 + * questions.
246.27 + */
246.28 +
246.29 +package java.util.regex;
246.30 +
246.31 +import java.util.HashMap;
246.32 +import java.util.Locale;
246.33 +
246.34 +enum UnicodeProp {
246.35 +
246.36 + ALPHABETIC {
246.37 + public boolean is(int ch) {
246.38 + return Character.isAlphabetic(ch);
246.39 + }
246.40 + },
246.41 +
246.42 + LETTER {
246.43 + public boolean is(int ch) {
246.44 + return Character.isLetter(ch);
246.45 + }
246.46 + },
246.47 +
246.48 + IDEOGRAPHIC {
246.49 + public boolean is(int ch) {
246.50 + return Character.isIdeographic(ch);
246.51 + }
246.52 + },
246.53 +
246.54 + LOWERCASE {
246.55 + public boolean is(int ch) {
246.56 + return Character.isLowerCase(ch);
246.57 + }
246.58 + },
246.59 +
246.60 + UPPERCASE {
246.61 + public boolean is(int ch) {
246.62 + return Character.isUpperCase(ch);
246.63 + }
246.64 + },
246.65 +
246.66 + TITLECASE {
246.67 + public boolean is(int ch) {
246.68 + return Character.isTitleCase(ch);
246.69 + }
246.70 + },
246.71 +
246.72 + WHITE_SPACE {
246.73 + // \p{Whitespace}
246.74 + public boolean is(int ch) {
246.75 + return ((((1 << Character.SPACE_SEPARATOR) |
246.76 + (1 << Character.LINE_SEPARATOR) |
246.77 + (1 << Character.PARAGRAPH_SEPARATOR)) >> Character.getType(ch)) & 1)
246.78 + != 0 || (ch >= 0x9 && ch <= 0xd) || (ch == 0x85);
246.79 + }
246.80 + },
246.81 +
246.82 + CONTROL {
246.83 + // \p{gc=Control}
246.84 + public boolean is(int ch) {
246.85 + return Character.getType(ch) == Character.CONTROL;
246.86 + }
246.87 + },
246.88 +
246.89 + PUNCTUATION {
246.90 + // \p{gc=Punctuation}
246.91 + public boolean is(int ch) {
246.92 + return ((((1 << Character.CONNECTOR_PUNCTUATION) |
246.93 + (1 << Character.DASH_PUNCTUATION) |
246.94 + (1 << Character.START_PUNCTUATION) |
246.95 + (1 << Character.END_PUNCTUATION) |
246.96 + (1 << Character.OTHER_PUNCTUATION) |
246.97 + (1 << Character.INITIAL_QUOTE_PUNCTUATION) |
246.98 + (1 << Character.FINAL_QUOTE_PUNCTUATION)) >> Character.getType(ch)) & 1)
246.99 + != 0;
246.100 + }
246.101 + },
246.102 +
246.103 + HEX_DIGIT {
246.104 + // \p{gc=Decimal_Number}
246.105 + // \p{Hex_Digit} -> PropList.txt: Hex_Digit
246.106 + public boolean is(int ch) {
246.107 + return DIGIT.is(ch) ||
246.108 + (ch >= 0x0030 && ch <= 0x0039) ||
246.109 + (ch >= 0x0041 && ch <= 0x0046) ||
246.110 + (ch >= 0x0061 && ch <= 0x0066) ||
246.111 + (ch >= 0xFF10 && ch <= 0xFF19) ||
246.112 + (ch >= 0xFF21 && ch <= 0xFF26) ||
246.113 + (ch >= 0xFF41 && ch <= 0xFF46);
246.114 + }
246.115 + },
246.116 +
246.117 + ASSIGNED {
246.118 + public boolean is(int ch) {
246.119 + return Character.getType(ch) != Character.UNASSIGNED;
246.120 + }
246.121 + },
246.122 +
246.123 + NONCHARACTER_CODE_POINT {
246.124 + // PropList.txt:Noncharacter_Code_Point
246.125 + public boolean is(int ch) {
246.126 + return (ch & 0xfffe) == 0xfffe || (ch >= 0xfdd0 && ch <= 0xfdef);
246.127 + }
246.128 + },
246.129 +
246.130 + DIGIT {
246.131 + // \p{gc=Decimal_Number}
246.132 + public boolean is(int ch) {
246.133 + return Character.isDigit(ch);
246.134 + }
246.135 + },
246.136 +
246.137 + ALNUM {
246.138 + // \p{alpha}
246.139 + // \p{digit}
246.140 + public boolean is(int ch) {
246.141 + return ALPHABETIC.is(ch) || DIGIT.is(ch);
246.142 + }
246.143 + },
246.144 +
246.145 + BLANK {
246.146 + // \p{Whitespace} --
246.147 + // [\N{LF} \N{VT} \N{FF} \N{CR} \N{NEL} -> 0xa, 0xb, 0xc, 0xd, 0x85
246.148 + // \p{gc=Line_Separator}
246.149 + // \p{gc=Paragraph_Separator}]
246.150 + public boolean is(int ch) {
246.151 + return Character.getType(ch) == Character.SPACE_SEPARATOR ||
246.152 + ch == 0x9; // \N{HT}
246.153 + }
246.154 + },
246.155 +
246.156 + GRAPH {
246.157 + // [^
246.158 + // \p{space}
246.159 + // \p{gc=Control}
246.160 + // \p{gc=Surrogate}
246.161 + // \p{gc=Unassigned}]
246.162 + public boolean is(int ch) {
246.163 + return ((((1 << Character.SPACE_SEPARATOR) |
246.164 + (1 << Character.LINE_SEPARATOR) |
246.165 + (1 << Character.PARAGRAPH_SEPARATOR) |
246.166 + (1 << Character.CONTROL) |
246.167 + (1 << Character.SURROGATE) |
246.168 + (1 << Character.UNASSIGNED)) >> Character.getType(ch)) & 1)
246.169 + == 0;
246.170 + }
246.171 + },
246.172 +
246.173 + PRINT {
246.174 + // \p{graph}
246.175 + // \p{blank}
246.176 + // -- \p{cntrl}
246.177 + public boolean is(int ch) {
246.178 + return (GRAPH.is(ch) || BLANK.is(ch)) && !CONTROL.is(ch);
246.179 + }
246.180 + },
246.181 +
246.182 + WORD {
246.183 + // \p{alpha}
246.184 + // \p{gc=Mark}
246.185 + // \p{digit}
246.186 + // \p{gc=Connector_Punctuation}
246.187 +
246.188 + public boolean is(int ch) {
246.189 + return ALPHABETIC.is(ch) ||
246.190 + ((((1 << Character.NON_SPACING_MARK) |
246.191 + (1 << Character.ENCLOSING_MARK) |
246.192 + (1 << Character.COMBINING_SPACING_MARK) |
246.193 + (1 << Character.DECIMAL_DIGIT_NUMBER) |
246.194 + (1 << Character.CONNECTOR_PUNCTUATION)) >> Character.getType(ch)) & 1)
246.195 + != 0;
246.196 + }
246.197 + };
246.198 +
246.199 + private final static HashMap<String, String> posix = new HashMap<>();
246.200 + private final static HashMap<String, String> aliases = new HashMap<>();
246.201 + static {
246.202 + posix.put("ALPHA", "ALPHABETIC");
246.203 + posix.put("LOWER", "LOWERCASE");
246.204 + posix.put("UPPER", "UPPERCASE");
246.205 + posix.put("SPACE", "WHITE_SPACE");
246.206 + posix.put("PUNCT", "PUNCTUATION");
246.207 + posix.put("XDIGIT","HEX_DIGIT");
246.208 + posix.put("ALNUM", "ALNUM");
246.209 + posix.put("CNTRL", "CONTROL");
246.210 + posix.put("DIGIT", "DIGIT");
246.211 + posix.put("BLANK", "BLANK");
246.212 + posix.put("GRAPH", "GRAPH");
246.213 + posix.put("PRINT", "PRINT");
246.214 +
246.215 + aliases.put("WHITESPACE", "WHITE_SPACE");
246.216 + aliases.put("HEXDIGIT","HEX_DIGIT");
246.217 + aliases.put("NONCHARACTERCODEPOINT", "NONCHARACTER_CODE_POINT");
246.218 + }
246.219 +
246.220 + public static UnicodeProp forName(String propName) {
246.221 + propName = propName.toUpperCase(Locale.ENGLISH);
246.222 + String alias = aliases.get(propName);
246.223 + if (alias != null)
246.224 + propName = alias;
246.225 + try {
246.226 + return valueOf (propName);
246.227 + } catch (IllegalArgumentException x) {}
246.228 + return null;
246.229 + }
246.230 +
246.231 + public static UnicodeProp forPOSIXName(String propName) {
246.232 + propName = posix.get(propName.toUpperCase(Locale.ENGLISH));
246.233 + if (propName == null)
246.234 + return null;
246.235 + return valueOf (propName);
246.236 + }
246.237 +
246.238 + public abstract boolean is(int ch);
246.239 +}
247.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
247.2 +++ b/rt/emul/compact/src/main/java/java/util/regex/package.html Wed Apr 30 15:04:10 2014 +0200
247.3 @@ -0,0 +1,66 @@
247.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
247.5 +<html>
247.6 +<head>
247.7 +<!--
247.8 +Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
247.9 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
247.10 +
247.11 +This code is free software; you can redistribute it and/or modify it
247.12 +under the terms of the GNU General Public License version 2 only, as
247.13 +published by the Free Software Foundation. Oracle designates this
247.14 +particular file as subject to the "Classpath" exception as provided
247.15 +by Oracle in the LICENSE file that accompanied this code.
247.16 +
247.17 +This code is distributed in the hope that it will be useful, but WITHOUT
247.18 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
247.19 +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
247.20 +version 2 for more details (a copy is included in the LICENSE file that
247.21 +accompanied this code).
247.22 +
247.23 +You should have received a copy of the GNU General Public License version
247.24 +2 along with this work; if not, write to the Free Software Foundation,
247.25 +Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
247.26 +
247.27 +Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
247.28 +or visit www.oracle.com if you need additional information or have any
247.29 +questions.
247.30 +-->
247.31 +
247.32 +</head>
247.33 +<body bgcolor="white">
247.34 +
247.35 +Classes for matching character sequences against patterns specified by regular
247.36 +expressions.
247.37 +
247.38 +<p> An instance of the {@link java.util.regex.Pattern} class represents a
247.39 +regular expression that is specified in string form in a syntax similar to
247.40 +that used by Perl.
247.41 +
247.42 +<p> Instances of the {@link java.util.regex.Matcher} class are used to match
247.43 +character sequences against a given pattern. Input is provided to matchers via
247.44 +the {@link java.lang.CharSequence} interface in order to support matching
247.45 +against characters from a wide variety of input sources. </p>
247.46 +
247.47 +<p> Unless otherwise noted, passing a <tt>null</tt> argument to a method
247.48 +in any class or interface in this package will cause a
247.49 +{@link java.lang.NullPointerException NullPointerException} to be thrown.
247.50 +
247.51 +<h2>Related Documentation</h2>
247.52 +
247.53 +<p> An excellent tutorial and overview of regular expressions is <a
247.54 +href="http://www.oreilly.com/catalog/regex/"><i>Mastering Regular
247.55 +Expressions</i>, Jeffrey E. F. Friedl, O'Reilly and Associates, 1997.</a> </p>
247.56 +
247.57 +<!--
247.58 +For overviews, tutorials, examples, guides, and tool documentation, please see:
247.59 +<ul>
247.60 + <li><a href="">##### REFER TO NON-SPEC DOCUMENTATION HERE #####</a>
247.61 +</ul>
247.62 +-->
247.63 +
247.64 +@since 1.4
247.65 +@author Mike McCloskey
247.66 +@author Mark Reinhold
247.67 +
247.68 +</body>
247.69 +</html>
248.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
248.2 +++ b/rt/emul/compact/src/main/java/org/apidesign/bck2brwsr/emul/reflect/ProxyImpl.java Wed Apr 30 15:04:10 2014 +0200
248.3 @@ -0,0 +1,1620 @@
248.4 +/*
248.5 + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
248.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
248.7 + *
248.8 + * This code is free software; you can redistribute it and/or modify it
248.9 + * under the terms of the GNU General Public License version 2 only, as
248.10 + * published by the Free Software Foundation. Oracle designates this
248.11 + * particular file as subject to the "Classpath" exception as provided
248.12 + * by Oracle in the LICENSE file that accompanied this code.
248.13 + *
248.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
248.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
248.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
248.17 + * version 2 for more details (a copy is included in the LICENSE file that
248.18 + * accompanied this code).
248.19 + *
248.20 + * You should have received a copy of the GNU General Public License version
248.21 + * 2 along with this work; if not, write to the Free Software Foundation,
248.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
248.23 + *
248.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
248.25 + * or visit www.oracle.com if you need additional information or have any
248.26 + * questions.
248.27 + */
248.28 +
248.29 +package org.apidesign.bck2brwsr.emul.reflect;
248.30 +
248.31 +import java.io.ByteArrayOutputStream;
248.32 +import java.io.DataOutputStream;
248.33 +import java.io.IOException;
248.34 +import java.io.OutputStream;
248.35 +import java.lang.ref.Reference;
248.36 +import java.lang.ref.WeakReference;
248.37 +import java.lang.reflect.Array;
248.38 +import java.lang.reflect.Constructor;
248.39 +import java.lang.reflect.InvocationHandler;
248.40 +import java.lang.reflect.InvocationTargetException;
248.41 +import java.lang.reflect.Method;
248.42 +import java.lang.reflect.Modifier;
248.43 +import java.util.ArrayList;
248.44 +import java.util.Arrays;
248.45 +import java.util.Collections;
248.46 +import java.util.HashMap;
248.47 +import java.util.HashSet;
248.48 +import java.util.LinkedList;
248.49 +import java.util.Map;
248.50 +import java.util.Set;
248.51 +import java.util.List;
248.52 +import java.util.ListIterator;
248.53 +import java.util.WeakHashMap;
248.54 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
248.55 +import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
248.56 +
248.57 +/**
248.58 + * {@code Proxy} provides static methods for creating dynamic proxy
248.59 + * classes and instances, and it is also the superclass of all
248.60 + * dynamic proxy classes created by those methods.
248.61 + *
248.62 + * <p>To create a proxy for some interface {@code Foo}:
248.63 + * <pre>
248.64 + * InvocationHandler handler = new MyInvocationHandler(...);
248.65 + * Class proxyClass = Proxy.getProxyClass(
248.66 + * Foo.class.getClassLoader(), new Class[] { Foo.class });
248.67 + * Foo f = (Foo) proxyClass.
248.68 + * getConstructor(new Class[] { InvocationHandler.class }).
248.69 + * newInstance(new Object[] { handler });
248.70 + * </pre>
248.71 + * or more simply:
248.72 + * <pre>
248.73 + * Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
248.74 + * new Class[] { Foo.class },
248.75 + * handler);
248.76 + * </pre>
248.77 + *
248.78 + * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
248.79 + * class</i> below) is a class that implements a list of interfaces
248.80 + * specified at runtime when the class is created, with behavior as
248.81 + * described below.
248.82 + *
248.83 + * A <i>proxy interface</i> is such an interface that is implemented
248.84 + * by a proxy class.
248.85 + *
248.86 + * A <i>proxy instance</i> is an instance of a proxy class.
248.87 + *
248.88 + * Each proxy instance has an associated <i>invocation handler</i>
248.89 + * object, which implements the interface {@link InvocationHandler}.
248.90 + * A method invocation on a proxy instance through one of its proxy
248.91 + * interfaces will be dispatched to the {@link InvocationHandler#invoke
248.92 + * invoke} method of the instance's invocation handler, passing the proxy
248.93 + * instance, a {@code java.lang.reflect.Method} object identifying
248.94 + * the method that was invoked, and an array of type {@code Object}
248.95 + * containing the arguments. The invocation handler processes the
248.96 + * encoded method invocation as appropriate and the result that it
248.97 + * returns will be returned as the result of the method invocation on
248.98 + * the proxy instance.
248.99 + *
248.100 + * <p>A proxy class has the following properties:
248.101 + *
248.102 + * <ul>
248.103 + * <li>Proxy classes are public, final, and not abstract.
248.104 + *
248.105 + * <li>The unqualified name of a proxy class is unspecified. The space
248.106 + * of class names that begin with the string {@code "$Proxy"}
248.107 + * should be, however, reserved for proxy classes.
248.108 + *
248.109 + * <li>A proxy class extends {@code java.lang.reflect.Proxy}.
248.110 + *
248.111 + * <li>A proxy class implements exactly the interfaces specified at its
248.112 + * creation, in the same order.
248.113 + *
248.114 + * <li>If a proxy class implements a non-public interface, then it will
248.115 + * be defined in the same package as that interface. Otherwise, the
248.116 + * package of a proxy class is also unspecified. Note that package
248.117 + * sealing will not prevent a proxy class from being successfully defined
248.118 + * in a particular package at runtime, and neither will classes already
248.119 + * defined by the same class loader and the same package with particular
248.120 + * signers.
248.121 + *
248.122 + * <li>Since a proxy class implements all of the interfaces specified at
248.123 + * its creation, invoking {@code getInterfaces} on its
248.124 + * {@code Class} object will return an array containing the same
248.125 + * list of interfaces (in the order specified at its creation), invoking
248.126 + * {@code getMethods} on its {@code Class} object will return
248.127 + * an array of {@code Method} objects that include all of the
248.128 + * methods in those interfaces, and invoking {@code getMethod} will
248.129 + * find methods in the proxy interfaces as would be expected.
248.130 + *
248.131 + * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will
248.132 + * return true if it is passed a proxy class-- a class returned by
248.133 + * {@code Proxy.getProxyClass} or the class of an object returned by
248.134 + * {@code Proxy.newProxyInstance}-- and false otherwise.
248.135 + *
248.136 + * <li>The {@code java.security.ProtectionDomain} of a proxy class
248.137 + * is the same as that of system classes loaded by the bootstrap class
248.138 + * loader, such as {@code java.lang.Object}, because the code for a
248.139 + * proxy class is generated by trusted system code. This protection
248.140 + * domain will typically be granted
248.141 + * {@code java.security.AllPermission}.
248.142 + *
248.143 + * <li>Each proxy class has one public constructor that takes one argument,
248.144 + * an implementation of the interface {@link InvocationHandler}, to set
248.145 + * the invocation handler for a proxy instance. Rather than having to use
248.146 + * the reflection API to access the public constructor, a proxy instance
248.147 + * can be also be created by calling the {@link Proxy#newProxyInstance
248.148 + * Proxy.newProxyInstance} method, which combines the actions of calling
248.149 + * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the
248.150 + * constructor with an invocation handler.
248.151 + * </ul>
248.152 + *
248.153 + * <p>A proxy instance has the following properties:
248.154 + *
248.155 + * <ul>
248.156 + * <li>Given a proxy instance {@code proxy} and one of the
248.157 + * interfaces implemented by its proxy class {@code Foo}, the
248.158 + * following expression will return true:
248.159 + * <pre>
248.160 + * {@code proxy instanceof Foo}
248.161 + * </pre>
248.162 + * and the following cast operation will succeed (rather than throwing
248.163 + * a {@code ClassCastException}):
248.164 + * <pre>
248.165 + * {@code (Foo) proxy}
248.166 + * </pre>
248.167 + *
248.168 + * <li>Each proxy instance has an associated invocation handler, the one
248.169 + * that was passed to its constructor. The static
248.170 + * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method
248.171 + * will return the invocation handler associated with the proxy instance
248.172 + * passed as its argument.
248.173 + *
248.174 + * <li>An interface method invocation on a proxy instance will be
248.175 + * encoded and dispatched to the invocation handler's {@link
248.176 + * InvocationHandler#invoke invoke} method as described in the
248.177 + * documentation for that method.
248.178 + *
248.179 + * <li>An invocation of the {@code hashCode},
248.180 + * {@code equals}, or {@code toString} methods declared in
248.181 + * {@code java.lang.Object} on a proxy instance will be encoded and
248.182 + * dispatched to the invocation handler's {@code invoke} method in
248.183 + * the same manner as interface method invocations are encoded and
248.184 + * dispatched, as described above. The declaring class of the
248.185 + * {@code Method} object passed to {@code invoke} will be
248.186 + * {@code java.lang.Object}. Other public methods of a proxy
248.187 + * instance inherited from {@code java.lang.Object} are not
248.188 + * overridden by a proxy class, so invocations of those methods behave
248.189 + * like they do for instances of {@code java.lang.Object}.
248.190 + * </ul>
248.191 + *
248.192 + * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3>
248.193 + *
248.194 + * <p>When two or more interfaces of a proxy class contain a method with
248.195 + * the same name and parameter signature, the order of the proxy class's
248.196 + * interfaces becomes significant. When such a <i>duplicate method</i>
248.197 + * is invoked on a proxy instance, the {@code Method} object passed
248.198 + * to the invocation handler will not necessarily be the one whose
248.199 + * declaring class is assignable from the reference type of the interface
248.200 + * that the proxy's method was invoked through. This limitation exists
248.201 + * because the corresponding method implementation in the generated proxy
248.202 + * class cannot determine which interface it was invoked through.
248.203 + * Therefore, when a duplicate method is invoked on a proxy instance,
248.204 + * the {@code Method} object for the method in the foremost interface
248.205 + * that contains the method (either directly or inherited through a
248.206 + * superinterface) in the proxy class's list of interfaces is passed to
248.207 + * the invocation handler's {@code invoke} method, regardless of the
248.208 + * reference type through which the method invocation occurred.
248.209 + *
248.210 + * <p>If a proxy interface contains a method with the same name and
248.211 + * parameter signature as the {@code hashCode}, {@code equals},
248.212 + * or {@code toString} methods of {@code java.lang.Object},
248.213 + * when such a method is invoked on a proxy instance, the
248.214 + * {@code Method} object passed to the invocation handler will have
248.215 + * {@code java.lang.Object} as its declaring class. In other words,
248.216 + * the public, non-final methods of {@code java.lang.Object}
248.217 + * logically precede all of the proxy interfaces for the determination of
248.218 + * which {@code Method} object to pass to the invocation handler.
248.219 + *
248.220 + * <p>Note also that when a duplicate method is dispatched to an
248.221 + * invocation handler, the {@code invoke} method may only throw
248.222 + * checked exception types that are assignable to one of the exception
248.223 + * types in the {@code throws} clause of the method in <i>all</i> of
248.224 + * the proxy interfaces that it can be invoked through. If the
248.225 + * {@code invoke} method throws a checked exception that is not
248.226 + * assignable to any of the exception types declared by the method in one
248.227 + * of the proxy interfaces that it can be invoked through, then an
248.228 + * unchecked {@code UndeclaredThrowableException} will be thrown by
248.229 + * the invocation on the proxy instance. This restriction means that not
248.230 + * all of the exception types returned by invoking
248.231 + * {@code getExceptionTypes} on the {@code Method} object
248.232 + * passed to the {@code invoke} method can necessarily be thrown
248.233 + * successfully by the {@code invoke} method.
248.234 + *
248.235 + * @author Peter Jones
248.236 + * @see InvocationHandler
248.237 + * @since 1.3
248.238 + */
248.239 +public final class ProxyImpl implements java.io.Serializable {
248.240 +
248.241 + private static final long serialVersionUID = -2222568056686623797L;
248.242 +
248.243 + /** prefix for all proxy class names */
248.244 + private final static String proxyClassNamePrefix = "$Proxy";
248.245 +
248.246 + /** parameter types of a proxy class constructor */
248.247 + private final static Class[] constructorParams =
248.248 + { InvocationHandler.class };
248.249 +
248.250 + /** maps a class loader to the proxy class cache for that loader */
248.251 + private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
248.252 + = new WeakHashMap<>();
248.253 +
248.254 + /** marks that a particular proxy class is currently being generated */
248.255 + private static Object pendingGenerationMarker = new Object();
248.256 +
248.257 + /** next number to use for generation of unique proxy class names */
248.258 + private static long nextUniqueNumber = 0;
248.259 + private static Object nextUniqueNumberLock = new Object();
248.260 +
248.261 + /** set of all generated proxy classes, for isProxyClass implementation */
248.262 + private static Map<Class<?>, Void> proxyClasses =
248.263 + Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>());
248.264 +
248.265 + /**
248.266 + * the invocation handler for this proxy instance.
248.267 + * @serial
248.268 + */
248.269 + protected InvocationHandler h;
248.270 +
248.271 + /**
248.272 + * Prohibits instantiation.
248.273 + */
248.274 + private ProxyImpl() {
248.275 + }
248.276 +
248.277 + /**
248.278 + * Constructs a new {@code Proxy} instance from a subclass
248.279 + * (typically, a dynamic proxy class) with the specified value
248.280 + * for its invocation handler.
248.281 + *
248.282 + * @param h the invocation handler for this proxy instance
248.283 + */
248.284 + protected ProxyImpl(InvocationHandler h) {
248.285 + this.h = h;
248.286 + }
248.287 +
248.288 + /**
248.289 + * Returns the {@code java.lang.Class} object for a proxy class
248.290 + * given a class loader and an array of interfaces. The proxy class
248.291 + * will be defined by the specified class loader and will implement
248.292 + * all of the supplied interfaces. If a proxy class for the same
248.293 + * permutation of interfaces has already been defined by the class
248.294 + * loader, then the existing proxy class will be returned; otherwise,
248.295 + * a proxy class for those interfaces will be generated dynamically
248.296 + * and defined by the class loader.
248.297 + *
248.298 + * <p>There are several restrictions on the parameters that may be
248.299 + * passed to {@code Proxy.getProxyClass}:
248.300 + *
248.301 + * <ul>
248.302 + * <li>All of the {@code Class} objects in the
248.303 + * {@code interfaces} array must represent interfaces, not
248.304 + * classes or primitive types.
248.305 + *
248.306 + * <li>No two elements in the {@code interfaces} array may
248.307 + * refer to identical {@code Class} objects.
248.308 + *
248.309 + * <li>All of the interface types must be visible by name through the
248.310 + * specified class loader. In other words, for class loader
248.311 + * {@code cl} and every interface {@code i}, the following
248.312 + * expression must be true:
248.313 + * <pre>
248.314 + * Class.forName(i.getName(), false, cl) == i
248.315 + * </pre>
248.316 + *
248.317 + * <li>All non-public interfaces must be in the same package;
248.318 + * otherwise, it would not be possible for the proxy class to
248.319 + * implement all of the interfaces, regardless of what package it is
248.320 + * defined in.
248.321 + *
248.322 + * <li>For any set of member methods of the specified interfaces
248.323 + * that have the same signature:
248.324 + * <ul>
248.325 + * <li>If the return type of any of the methods is a primitive
248.326 + * type or void, then all of the methods must have that same
248.327 + * return type.
248.328 + * <li>Otherwise, one of the methods must have a return type that
248.329 + * is assignable to all of the return types of the rest of the
248.330 + * methods.
248.331 + * </ul>
248.332 + *
248.333 + * <li>The resulting proxy class must not exceed any limits imposed
248.334 + * on classes by the virtual machine. For example, the VM may limit
248.335 + * the number of interfaces that a class may implement to 65535; in
248.336 + * that case, the size of the {@code interfaces} array must not
248.337 + * exceed 65535.
248.338 + * </ul>
248.339 + *
248.340 + * <p>If any of these restrictions are violated,
248.341 + * {@code Proxy.getProxyClass} will throw an
248.342 + * {@code IllegalArgumentException}. If the {@code interfaces}
248.343 + * array argument or any of its elements are {@code null}, a
248.344 + * {@code NullPointerException} will be thrown.
248.345 + *
248.346 + * <p>Note that the order of the specified proxy interfaces is
248.347 + * significant: two requests for a proxy class with the same combination
248.348 + * of interfaces but in a different order will result in two distinct
248.349 + * proxy classes.
248.350 + *
248.351 + * @param loader the class loader to define the proxy class
248.352 + * @param interfaces the list of interfaces for the proxy class
248.353 + * to implement
248.354 + * @return a proxy class that is defined in the specified class loader
248.355 + * and that implements the specified interfaces
248.356 + * @throws IllegalArgumentException if any of the restrictions on the
248.357 + * parameters that may be passed to {@code getProxyClass}
248.358 + * are violated
248.359 + * @throws NullPointerException if the {@code interfaces} array
248.360 + * argument or any of its elements are {@code null}
248.361 + */
248.362 + public static Class<?> getProxyClass(ClassLoader loader,
248.363 + Class<?>... interfaces)
248.364 + throws IllegalArgumentException
248.365 + {
248.366 + if (interfaces.length > 65535) {
248.367 + throw new IllegalArgumentException("interface limit exceeded");
248.368 + }
248.369 +
248.370 + Class<?> proxyClass = null;
248.371 +
248.372 + /* collect interface names to use as key for proxy class cache */
248.373 + String[] interfaceNames = new String[interfaces.length];
248.374 +
248.375 + // for detecting duplicates
248.376 + Set<Class<?>> interfaceSet = new HashSet<>();
248.377 +
248.378 + for (int i = 0; i < interfaces.length; i++) {
248.379 + /*
248.380 + * Verify that the class loader resolves the name of this
248.381 + * interface to the same Class object.
248.382 + */
248.383 + String interfaceName = interfaces[i].getName();
248.384 + Class<?> interfaceClass = null;
248.385 + try {
248.386 + interfaceClass = Class.forName(interfaceName, false, loader);
248.387 + } catch (ClassNotFoundException e) {
248.388 + }
248.389 + if (interfaceClass != interfaces[i]) {
248.390 + throw new IllegalArgumentException(
248.391 + interfaces[i] + " is not visible from class loader");
248.392 + }
248.393 +
248.394 + /*
248.395 + * Verify that the Class object actually represents an
248.396 + * interface.
248.397 + */
248.398 + if (!interfaceClass.isInterface()) {
248.399 + throw new IllegalArgumentException(
248.400 + interfaceClass.getName() + " is not an interface");
248.401 + }
248.402 +
248.403 + /*
248.404 + * Verify that this interface is not a duplicate.
248.405 + */
248.406 + if (interfaceSet.contains(interfaceClass)) {
248.407 + throw new IllegalArgumentException(
248.408 + "repeated interface: " + interfaceClass.getName());
248.409 + }
248.410 + interfaceSet.add(interfaceClass);
248.411 +
248.412 + interfaceNames[i] = interfaceName;
248.413 + }
248.414 +
248.415 + /*
248.416 + * Using string representations of the proxy interfaces as
248.417 + * keys in the proxy class cache (instead of their Class
248.418 + * objects) is sufficient because we require the proxy
248.419 + * interfaces to be resolvable by name through the supplied
248.420 + * class loader, and it has the advantage that using a string
248.421 + * representation of a class makes for an implicit weak
248.422 + * reference to the class.
248.423 + */
248.424 + List<String> key = Arrays.asList(interfaceNames);
248.425 +
248.426 + /*
248.427 + * Find or create the proxy class cache for the class loader.
248.428 + */
248.429 + Map<List<String>, Object> cache;
248.430 + synchronized (loaderToCache) {
248.431 + cache = loaderToCache.get(loader);
248.432 + if (cache == null) {
248.433 + cache = new HashMap<>();
248.434 + loaderToCache.put(loader, cache);
248.435 + }
248.436 + /*
248.437 + * This mapping will remain valid for the duration of this
248.438 + * method, without further synchronization, because the mapping
248.439 + * will only be removed if the class loader becomes unreachable.
248.440 + */
248.441 + }
248.442 +
248.443 + /*
248.444 + * Look up the list of interfaces in the proxy class cache using
248.445 + * the key. This lookup will result in one of three possible
248.446 + * kinds of values:
248.447 + * null, if there is currently no proxy class for the list of
248.448 + * interfaces in the class loader,
248.449 + * the pendingGenerationMarker object, if a proxy class for the
248.450 + * list of interfaces is currently being generated,
248.451 + * or a weak reference to a Class object, if a proxy class for
248.452 + * the list of interfaces has already been generated.
248.453 + */
248.454 + synchronized (cache) {
248.455 + /*
248.456 + * Note that we need not worry about reaping the cache for
248.457 + * entries with cleared weak references because if a proxy class
248.458 + * has been garbage collected, its class loader will have been
248.459 + * garbage collected as well, so the entire cache will be reaped
248.460 + * from the loaderToCache map.
248.461 + */
248.462 + do {
248.463 + Object value = cache.get(key);
248.464 + if (value instanceof Reference) {
248.465 + proxyClass = (Class<?>) ((Reference) value).get();
248.466 + }
248.467 + if (proxyClass != null) {
248.468 + // proxy class already generated: return it
248.469 + return proxyClass;
248.470 + } else if (value == pendingGenerationMarker) {
248.471 + // proxy class being generated: wait for it
248.472 + try {
248.473 + cache.wait();
248.474 + } catch (InterruptedException e) {
248.475 + /*
248.476 + * The class generation that we are waiting for should
248.477 + * take a small, bounded time, so we can safely ignore
248.478 + * thread interrupts here.
248.479 + */
248.480 + }
248.481 + continue;
248.482 + } else {
248.483 + /*
248.484 + * No proxy class for this list of interfaces has been
248.485 + * generated or is being generated, so we will go and
248.486 + * generate it now. Mark it as pending generation.
248.487 + */
248.488 + cache.put(key, pendingGenerationMarker);
248.489 + break;
248.490 + }
248.491 + } while (true);
248.492 + }
248.493 +
248.494 + try {
248.495 + String proxyPkg = null; // package to define proxy class in
248.496 +
248.497 + /*
248.498 + * Record the package of a non-public proxy interface so that the
248.499 + * proxy class will be defined in the same package. Verify that
248.500 + * all non-public proxy interfaces are in the same package.
248.501 + */
248.502 + for (int i = 0; i < interfaces.length; i++) {
248.503 + int flags = interfaces[i].getModifiers();
248.504 + if (!Modifier.isPublic(flags)) {
248.505 + String name = interfaces[i].getName();
248.506 + int n = name.lastIndexOf('.');
248.507 + String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
248.508 + if (proxyPkg == null) {
248.509 + proxyPkg = pkg;
248.510 + } else if (!pkg.equals(proxyPkg)) {
248.511 + throw new IllegalArgumentException(
248.512 + "non-public interfaces from different packages");
248.513 + }
248.514 + }
248.515 + }
248.516 +
248.517 + if (proxyPkg == null) { // if no non-public proxy interfaces,
248.518 + proxyPkg = ""; // use the unnamed package
248.519 + }
248.520 +
248.521 + {
248.522 + /*
248.523 + * Choose a name for the proxy class to generate.
248.524 + */
248.525 + long num;
248.526 + synchronized (nextUniqueNumberLock) {
248.527 + num = nextUniqueNumber++;
248.528 + }
248.529 + String proxyName = proxyPkg + proxyClassNamePrefix + num;
248.530 + /*
248.531 + * Verify that the class loader hasn't already
248.532 + * defined a class with the chosen name.
248.533 + */
248.534 +
248.535 + /*
248.536 + * Generate the specified proxy class.
248.537 + */
248.538 + Generator gen = new Generator(proxyName, interfaces);
248.539 + final byte[] proxyClassFile = gen.generateClassFile();
248.540 + try {
248.541 + proxyClass = defineClass0(loader, proxyName,
248.542 + proxyClassFile);
248.543 + } catch (ClassFormatError e) {
248.544 + /*
248.545 + * A ClassFormatError here means that (barring bugs in the
248.546 + * proxy class generation code) there was some other
248.547 + * invalid aspect of the arguments supplied to the proxy
248.548 + * class creation (such as virtual machine limitations
248.549 + * exceeded).
248.550 + */
248.551 + throw new IllegalArgumentException(e.toString());
248.552 + }
248.553 + gen.fillInMethods(proxyClass);
248.554 + }
248.555 + // add to set of all generated proxy classes, for isProxyClass
248.556 + proxyClasses.put(proxyClass, null);
248.557 +
248.558 + } finally {
248.559 + /*
248.560 + * We must clean up the "pending generation" state of the proxy
248.561 + * class cache entry somehow. If a proxy class was successfully
248.562 + * generated, store it in the cache (with a weak reference);
248.563 + * otherwise, remove the reserved entry. In all cases, notify
248.564 + * all waiters on reserved entries in this cache.
248.565 + */
248.566 + synchronized (cache) {
248.567 + if (proxyClass != null) {
248.568 + cache.put(key, new WeakReference<Class<?>>(proxyClass));
248.569 + } else {
248.570 + cache.remove(key);
248.571 + }
248.572 + cache.notifyAll();
248.573 + }
248.574 + }
248.575 + return proxyClass;
248.576 + }
248.577 +
248.578 + /**
248.579 + * Returns an instance of a proxy class for the specified interfaces
248.580 + * that dispatches method invocations to the specified invocation
248.581 + * handler. This method is equivalent to:
248.582 + * <pre>
248.583 + * Proxy.getProxyClass(loader, interfaces).
248.584 + * getConstructor(new Class[] { InvocationHandler.class }).
248.585 + * newInstance(new Object[] { handler });
248.586 + * </pre>
248.587 + *
248.588 + * <p>{@code Proxy.newProxyInstance} throws
248.589 + * {@code IllegalArgumentException} for the same reasons that
248.590 + * {@code Proxy.getProxyClass} does.
248.591 + *
248.592 + * @param loader the class loader to define the proxy class
248.593 + * @param interfaces the list of interfaces for the proxy class
248.594 + * to implement
248.595 + * @param h the invocation handler to dispatch method invocations to
248.596 + * @return a proxy instance with the specified invocation handler of a
248.597 + * proxy class that is defined by the specified class loader
248.598 + * and that implements the specified interfaces
248.599 + * @throws IllegalArgumentException if any of the restrictions on the
248.600 + * parameters that may be passed to {@code getProxyClass}
248.601 + * are violated
248.602 + * @throws NullPointerException if the {@code interfaces} array
248.603 + * argument or any of its elements are {@code null}, or
248.604 + * if the invocation handler, {@code h}, is
248.605 + * {@code null}
248.606 + */
248.607 + public static Object newProxyInstance(ClassLoader loader,
248.608 + Class<?>[] interfaces,
248.609 + InvocationHandler h)
248.610 + throws IllegalArgumentException
248.611 + {
248.612 + if (h == null) {
248.613 + throw new NullPointerException();
248.614 + }
248.615 +
248.616 + /*
248.617 + * Look up or generate the designated proxy class.
248.618 + */
248.619 + Class<?> cl = getProxyClass(loader, interfaces);
248.620 +
248.621 + /*
248.622 + * Invoke its constructor with the designated invocation handler.
248.623 + */
248.624 + try {
248.625 + Constructor cons = cl.getConstructor(constructorParams);
248.626 + return cons.newInstance(new Object[] { h });
248.627 + } catch (NoSuchMethodException e) {
248.628 + throw new InternalError(e.toString());
248.629 + } catch (IllegalAccessException e) {
248.630 + throw new InternalError(e.toString());
248.631 + } catch (InstantiationException e) {
248.632 + throw new InternalError(e.toString());
248.633 + } catch (InvocationTargetException e) {
248.634 + throw new InternalError(e.toString());
248.635 + }
248.636 + }
248.637 +
248.638 + /**
248.639 + * Returns true if and only if the specified class was dynamically
248.640 + * generated to be a proxy class using the {@code getProxyClass}
248.641 + * method or the {@code newProxyInstance} method.
248.642 + *
248.643 + * <p>The reliability of this method is important for the ability
248.644 + * to use it to make security decisions, so its implementation should
248.645 + * not just test if the class in question extends {@code Proxy}.
248.646 + *
248.647 + * @param cl the class to test
248.648 + * @return {@code true} if the class is a proxy class and
248.649 + * {@code false} otherwise
248.650 + * @throws NullPointerException if {@code cl} is {@code null}
248.651 + */
248.652 + public static boolean isProxyClass(Class<?> cl) {
248.653 + if (cl == null) {
248.654 + throw new NullPointerException();
248.655 + }
248.656 +
248.657 + return proxyClasses.containsKey(cl);
248.658 + }
248.659 +
248.660 + /**
248.661 + * Returns the invocation handler for the specified proxy instance.
248.662 + *
248.663 + * @param proxy the proxy instance to return the invocation handler for
248.664 + * @return the invocation handler for the proxy instance
248.665 + * @throws IllegalArgumentException if the argument is not a
248.666 + * proxy instance
248.667 + */
248.668 + public static InvocationHandler getInvocationHandler(Object proxy)
248.669 + throws IllegalArgumentException
248.670 + {
248.671 + /*
248.672 + * Verify that the object is actually a proxy instance.
248.673 + */
248.674 + if (!isProxyClass(proxy.getClass())) {
248.675 + throw new IllegalArgumentException("not a proxy instance");
248.676 + }
248.677 +
248.678 + ProxyImpl p = (ProxyImpl) proxy;
248.679 + return p.h;
248.680 + }
248.681 +
248.682 + @JavaScriptBody(args = { "ignore", "name", "byteCode" },
248.683 + body = "return vm._reload(name, byteCode).constructor.$class;"
248.684 + )
248.685 + private static native Class defineClass0(
248.686 + ClassLoader loader, String name, byte[] b
248.687 + );
248.688 +
248.689 + private static class Generator {
248.690 + /*
248.691 + * In the comments below, "JVMS" refers to The Java Virtual Machine
248.692 + * Specification Second Edition and "JLS" refers to the original
248.693 + * version of The Java Language Specification, unless otherwise
248.694 + * specified.
248.695 + */
248.696 +
248.697 + /* need 1.6 bytecode */
248.698 + private static final int CLASSFILE_MAJOR_VERSION = 50;
248.699 + private static final int CLASSFILE_MINOR_VERSION = 0;
248.700 +
248.701 + /*
248.702 + * beginning of constants copied from
248.703 + * sun.tools.java.RuntimeConstants (which no longer exists):
248.704 + */
248.705 +
248.706 + /* constant pool tags */
248.707 + private static final int CONSTANT_UTF8 = 1;
248.708 + private static final int CONSTANT_UNICODE = 2;
248.709 + private static final int CONSTANT_INTEGER = 3;
248.710 + private static final int CONSTANT_FLOAT = 4;
248.711 + private static final int CONSTANT_LONG = 5;
248.712 + private static final int CONSTANT_DOUBLE = 6;
248.713 + private static final int CONSTANT_CLASS = 7;
248.714 + private static final int CONSTANT_STRING = 8;
248.715 + private static final int CONSTANT_FIELD = 9;
248.716 + private static final int CONSTANT_METHOD = 10;
248.717 + private static final int CONSTANT_INTERFACEMETHOD = 11;
248.718 + private static final int CONSTANT_NAMEANDTYPE = 12;
248.719 +
248.720 + /* access and modifier flags */
248.721 + private static final int ACC_PUBLIC = 0x00000001;
248.722 + private static final int ACC_FINAL = 0x00000010;
248.723 + private static final int ACC_SUPER = 0x00000020;
248.724 +
248.725 + // end of constants copied from sun.tools.java.RuntimeConstants
248.726 + /**
248.727 + * name of the superclass of proxy classes
248.728 + */
248.729 + private final static String superclassName = "java/lang/reflect/Proxy";
248.730 +
248.731 + /**
248.732 + * name of field for storing a proxy instance's invocation handler
248.733 + */
248.734 + private final static String handlerFieldName = "h";
248.735 +
248.736 + /* preloaded Method objects for methods in java.lang.Object */
248.737 + private static Method hashCodeMethod;
248.738 + private static Method equalsMethod;
248.739 + private static Method toStringMethod;
248.740 +
248.741 + static {
248.742 + try {
248.743 + hashCodeMethod = Object.class.getMethod("hashCode");
248.744 + equalsMethod
248.745 + = Object.class.getMethod("equals", new Class[]{Object.class});
248.746 + toStringMethod = Object.class.getMethod("toString");
248.747 + } catch (NoSuchMethodException e) {
248.748 + throw new IllegalStateException(e.getMessage());
248.749 + }
248.750 + }
248.751 +
248.752 + /**
248.753 + * name of proxy class
248.754 + */
248.755 + private String className;
248.756 +
248.757 + /**
248.758 + * proxy interfaces
248.759 + */
248.760 + private Class[] interfaces;
248.761 +
248.762 + /**
248.763 + * constant pool of class being generated
248.764 + */
248.765 + private ConstantPool cp = new ConstantPool();
248.766 +
248.767 + /**
248.768 + * maps method signature string to list of ProxyMethod objects for proxy
248.769 + * methods with that signature
248.770 + */
248.771 + private Map<String, List<ProxyMethod>> proxyMethods
248.772 + = new HashMap<String, List<ProxyMethod>>();
248.773 +
248.774 + /**
248.775 + * count of ProxyMethod objects added to proxyMethods
248.776 + */
248.777 + private int proxyMethodCount = 0;
248.778 +
248.779 + /**
248.780 + * Construct a ProxyGenerator to generate a proxy class with the
248.781 + * specified name and for the given interfaces.
248.782 + *
248.783 + * A ProxyGenerator object contains the state for the ongoing generation
248.784 + * of a particular proxy class.
248.785 + */
248.786 + private Generator(String className, Class[] interfaces) {
248.787 + this.className = className;
248.788 + this.interfaces = interfaces;
248.789 + }
248.790 +
248.791 + /**
248.792 + * Generate a class file for the proxy class. This method drives the
248.793 + * class file generation process.
248.794 + */
248.795 + private byte[] generateClassFile() {
248.796 +
248.797 + /* ============================================================
248.798 + * Step 1: Assemble ProxyMethod objects for all methods to
248.799 + * generate proxy dispatching code for.
248.800 + */
248.801 +
248.802 + /*
248.803 + * Record that proxy methods are needed for the hashCode, equals,
248.804 + * and toString methods of java.lang.Object. This is done before
248.805 + * the methods from the proxy interfaces so that the methods from
248.806 + * java.lang.Object take precedence over duplicate methods in the
248.807 + * proxy interfaces.
248.808 + */
248.809 + addProxyMethod(hashCodeMethod, Object.class);
248.810 + addProxyMethod(equalsMethod, Object.class);
248.811 + addProxyMethod(toStringMethod, Object.class);
248.812 +
248.813 + /*
248.814 + * Now record all of the methods from the proxy interfaces, giving
248.815 + * earlier interfaces precedence over later ones with duplicate
248.816 + * methods.
248.817 + */
248.818 + for (int i = 0; i < interfaces.length; i++) {
248.819 + Method[] methods = interfaces[i].getMethods();
248.820 + for (int j = 0; j < methods.length; j++) {
248.821 + addProxyMethod(methods[j], interfaces[i]);
248.822 + }
248.823 + }
248.824 +
248.825 + /*
248.826 + * For each set of proxy methods with the same signature,
248.827 + * verify that the methods' return types are compatible.
248.828 + */
248.829 + for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
248.830 + checkReturnTypes(sigmethods);
248.831 + }
248.832 +
248.833 + /* ============================================================
248.834 + * Step 2: Assemble FieldInfo and MethodInfo structs for all of
248.835 + * fields and methods in the class we are generating.
248.836 + */
248.837 +
248.838 + // will be done in fillInMethods
248.839 +
248.840 + /* ============================================================
248.841 + * Step 3: Write the final class file.
248.842 + */
248.843 +
248.844 + /*
248.845 + * Make sure that constant pool indexes are reserved for the
248.846 + * following items before starting to write the final class file.
248.847 + */
248.848 + cp.getClass(dotToSlash(className));
248.849 + cp.getClass(superclassName);
248.850 + for (int i = 0; i < interfaces.length; i++) {
248.851 + cp.getClass(dotToSlash(interfaces[i].getName()));
248.852 + }
248.853 +
248.854 + /*
248.855 + * Disallow new constant pool additions beyond this point, since
248.856 + * we are about to write the final constant pool table.
248.857 + */
248.858 + cp.setReadOnly();
248.859 +
248.860 + ByteArrayOutputStream bout = new ByteArrayOutputStream();
248.861 + DataOutputStream dout = new DataOutputStream(bout);
248.862 +
248.863 + try {
248.864 + /*
248.865 + * Write all the items of the "ClassFile" structure.
248.866 + * See JVMS section 4.1.
248.867 + */
248.868 + // u4 magic;
248.869 + dout.writeInt(0xCAFEBABE);
248.870 + // u2 minor_version;
248.871 + dout.writeShort(CLASSFILE_MINOR_VERSION);
248.872 + // u2 major_version;
248.873 + dout.writeShort(CLASSFILE_MAJOR_VERSION);
248.874 +
248.875 + cp.write(dout); // (write constant pool)
248.876 +
248.877 + // u2 access_flags;
248.878 + dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);
248.879 + // u2 this_class;
248.880 + dout.writeShort(cp.getClass(dotToSlash(className)));
248.881 + // u2 super_class;
248.882 + dout.writeShort(cp.getClass(superclassName));
248.883 +
248.884 + // u2 interfaces_count;
248.885 + dout.writeShort(interfaces.length);
248.886 + // u2 interfaces[interfaces_count];
248.887 + for (int i = 0; i < interfaces.length; i++) {
248.888 + dout.writeShort(cp.getClass(
248.889 + dotToSlash(interfaces[i].getName())));
248.890 + }
248.891 +
248.892 + // u2 fields_count;
248.893 + dout.writeShort(0);
248.894 +
248.895 + // u2 methods_count;
248.896 + dout.writeShort(0);
248.897 +
248.898 + // u2 attributes_count;
248.899 + dout.writeShort(0); // (no ClassFile attributes for proxy classes)
248.900 +
248.901 + } catch (IOException e) {
248.902 + throw new InternalError("unexpected I/O Exception");
248.903 + }
248.904 +
248.905 + return bout.toByteArray();
248.906 + }
248.907 +
248.908 + @JavaScriptBody(args = { "c", "sig", "method", "primitive" }, body =
248.909 + "var p = c.cnstr.prototype;\n" +
248.910 + "p[sig] = function() {\n" +
248.911 + " var h = this._h();\n" +
248.912 + " var res = h.invoke__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_reflect_Method_2_3Ljava_lang_Object_2(this, method, arguments);\n" +
248.913 + " \n" +
248.914 + " \n" +
248.915 + " return res;\n" +
248.916 + "};"
248.917 + )
248.918 + private static native void defineMethod(Class<?> proxyClass, String sig, Method method, boolean primitive);
248.919 +
248.920 + @JavaScriptBody(args = "c", body =
248.921 + "var h = c.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2 = function(h) {\n"
248.922 + + " c.superclass.cnstr.cons__VLjava_lang_reflect_InvocationHandler_2.call(this, h);\n"
248.923 + + "}\n"
248.924 + + "h.cls = c.cnstr;\n"
248.925 + )
248.926 + private static native void defineConstructor(Class<?> proxyClass);
248.927 +
248.928 + final void fillInMethods(Class<?> proxyClass) {
248.929 + for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
248.930 + for (ProxyMethod pm : sigmethods) {
248.931 + String sig = MethodImpl.toSignature(pm.method);
248.932 + defineMethod(proxyClass, sig, pm.method, pm.method.getReturnType().isPrimitive());
248.933 + }
248.934 + }
248.935 + defineConstructor(proxyClass);
248.936 + }
248.937 +
248.938 + /**
248.939 + * Add another method to be proxied, either by creating a new
248.940 + * ProxyMethod object or augmenting an old one for a duplicate method.
248.941 + *
248.942 + * "fromClass" indicates the proxy interface that the method was found
248.943 + * through, which may be different from (a subinterface of) the method's
248.944 + * "declaring class". Note that the first Method object passed for a
248.945 + * given name and descriptor identifies the Method object (and thus the
248.946 + * declaring class) that will be passed to the invocation handler's
248.947 + * "invoke" method for a given set of duplicate methods.
248.948 + */
248.949 + private void addProxyMethod(Method m, Class fromClass) {
248.950 + String name = m.getName();
248.951 + Class[] parameterTypes = m.getParameterTypes();
248.952 + Class returnType = m.getReturnType();
248.953 + Class[] exceptionTypes = m.getExceptionTypes();
248.954 +
248.955 + String sig = MethodImpl.toSignature(m);
248.956 + List<ProxyMethod> sigmethods = proxyMethods.get(sig);
248.957 + if (sigmethods != null) {
248.958 + for (ProxyMethod pm : sigmethods) {
248.959 + if (returnType == pm.returnType) {
248.960 + /*
248.961 + * Found a match: reduce exception types to the
248.962 + * greatest set of exceptions that can thrown
248.963 + * compatibly with the throws clauses of both
248.964 + * overridden methods.
248.965 + */
248.966 + List<Class<?>> legalExceptions = new ArrayList<Class<?>>();
248.967 + collectCompatibleTypes(
248.968 + exceptionTypes, pm.exceptionTypes, legalExceptions);
248.969 + collectCompatibleTypes(
248.970 + pm.exceptionTypes, exceptionTypes, legalExceptions);
248.971 + pm.exceptionTypes = new Class[legalExceptions.size()];
248.972 + pm.exceptionTypes
248.973 + = legalExceptions.toArray(pm.exceptionTypes);
248.974 + return;
248.975 + }
248.976 + }
248.977 + } else {
248.978 + sigmethods = new ArrayList<ProxyMethod>(3);
248.979 + proxyMethods.put(sig, sigmethods);
248.980 + }
248.981 + sigmethods.add(new ProxyMethod(m, name, parameterTypes, returnType,
248.982 + exceptionTypes, fromClass));
248.983 + }
248.984 +
248.985 + /**
248.986 + * For a given set of proxy methods with the same signature, check that
248.987 + * their return types are compatible according to the Proxy
248.988 + * specification.
248.989 + *
248.990 + * Specifically, if there is more than one such method, then all of the
248.991 + * return types must be reference types, and there must be one return
248.992 + * type that is assignable to each of the rest of them.
248.993 + */
248.994 + private static void checkReturnTypes(List<ProxyMethod> methods) {
248.995 + /*
248.996 + * If there is only one method with a given signature, there
248.997 + * cannot be a conflict. This is the only case in which a
248.998 + * primitive (or void) return type is allowed.
248.999 + */
248.1000 + if (methods.size() < 2) {
248.1001 + return;
248.1002 + }
248.1003 +
248.1004 + /*
248.1005 + * List of return types that are not yet known to be
248.1006 + * assignable from ("covered" by) any of the others.
248.1007 + */
248.1008 + LinkedList<Class<?>> uncoveredReturnTypes = new LinkedList<Class<?>>();
248.1009 +
248.1010 + nextNewReturnType:
248.1011 + for (ProxyMethod pm : methods) {
248.1012 + Class<?> newReturnType = pm.returnType;
248.1013 + if (newReturnType.isPrimitive()) {
248.1014 + throw new IllegalArgumentException(
248.1015 + "methods with same signature "
248.1016 + + getFriendlyMethodSignature(pm.methodName,
248.1017 + pm.parameterTypes)
248.1018 + + " but incompatible return types: "
248.1019 + + newReturnType.getName() + " and others");
248.1020 + }
248.1021 + boolean added = false;
248.1022 +
248.1023 + /*
248.1024 + * Compare the new return type to the existing uncovered
248.1025 + * return types.
248.1026 + */
248.1027 + ListIterator<Class<?>> liter = uncoveredReturnTypes.listIterator();
248.1028 + while (liter.hasNext()) {
248.1029 + Class<?> uncoveredReturnType = liter.next();
248.1030 +
248.1031 + /*
248.1032 + * If an existing uncovered return type is assignable
248.1033 + * to this new one, then we can forget the new one.
248.1034 + */
248.1035 + if (newReturnType.isAssignableFrom(uncoveredReturnType)) {
248.1036 + assert !added;
248.1037 + continue nextNewReturnType;
248.1038 + }
248.1039 +
248.1040 + /*
248.1041 + * If the new return type is assignable to an existing
248.1042 + * uncovered one, then should replace the existing one
248.1043 + * with the new one (or just forget the existing one,
248.1044 + * if the new one has already be put in the list).
248.1045 + */
248.1046 + if (uncoveredReturnType.isAssignableFrom(newReturnType)) {
248.1047 + // (we can assume that each return type is unique)
248.1048 + if (!added) {
248.1049 + liter.set(newReturnType);
248.1050 + added = true;
248.1051 + } else {
248.1052 + liter.remove();
248.1053 + }
248.1054 + }
248.1055 + }
248.1056 +
248.1057 + /*
248.1058 + * If we got through the list of existing uncovered return
248.1059 + * types without an assignability relationship, then add
248.1060 + * the new return type to the list of uncovered ones.
248.1061 + */
248.1062 + if (!added) {
248.1063 + uncoveredReturnTypes.add(newReturnType);
248.1064 + }
248.1065 + }
248.1066 +
248.1067 + /*
248.1068 + * We shouldn't end up with more than one return type that is
248.1069 + * not assignable from any of the others.
248.1070 + */
248.1071 + if (uncoveredReturnTypes.size() > 1) {
248.1072 + ProxyMethod pm = methods.get(0);
248.1073 + throw new IllegalArgumentException(
248.1074 + "methods with same signature "
248.1075 + + getFriendlyMethodSignature(pm.methodName, pm.parameterTypes)
248.1076 + + " but incompatible return types: " + uncoveredReturnTypes);
248.1077 + }
248.1078 + }
248.1079 +
248.1080 +
248.1081 + /**
248.1082 + * A ProxyMethod object represents a proxy method in the proxy class
248.1083 + * being generated: a method whose implementation will encode and
248.1084 + * dispatch invocations to the proxy instance's invocation handler.
248.1085 + */
248.1086 + private class ProxyMethod {
248.1087 +
248.1088 + private final Method method;
248.1089 + public String methodName;
248.1090 + public Class[] parameterTypes;
248.1091 + public Class returnType;
248.1092 + public Class[] exceptionTypes;
248.1093 + public Class fromClass;
248.1094 + public String methodFieldName;
248.1095 +
248.1096 + private ProxyMethod(Method m,
248.1097 + String methodName, Class[] parameterTypes,
248.1098 + Class returnType, Class[] exceptionTypes,
248.1099 + Class fromClass
248.1100 + ) {
248.1101 + this.method = m;
248.1102 + this.methodName = methodName;
248.1103 + this.parameterTypes = parameterTypes;
248.1104 + this.returnType = returnType;
248.1105 + this.exceptionTypes = exceptionTypes;
248.1106 + this.fromClass = fromClass;
248.1107 + this.methodFieldName = "m" + proxyMethodCount++;
248.1108 + }
248.1109 +
248.1110 + }
248.1111 +
248.1112 + /*
248.1113 + * ==================== General Utility Methods ====================
248.1114 + */
248.1115 + /**
248.1116 + * Convert a fully qualified class name that uses '.' as the package
248.1117 + * separator, the external representation used by the Java language and
248.1118 + * APIs, to a fully qualified class name that uses '/' as the package
248.1119 + * separator, the representation used in the class file format (see JVMS
248.1120 + * section 4.2).
248.1121 + */
248.1122 + private static String dotToSlash(String name) {
248.1123 + return name.replace('.', '/');
248.1124 + }
248.1125 +
248.1126 + /**
248.1127 + * Return the list of "parameter descriptor" strings enclosed in
248.1128 + * parentheses corresponding to the given parameter types (in other
248.1129 + * words, a method descriptor without a return descriptor). This string
248.1130 + * is useful for constructing string keys for methods without regard to
248.1131 + * their return type.
248.1132 + */
248.1133 + private static String getParameterDescriptors(Class[] parameterTypes) {
248.1134 + StringBuilder desc = new StringBuilder("(");
248.1135 + for (int i = 0; i < parameterTypes.length; i++) {
248.1136 + desc.append(getFieldType(parameterTypes[i]));
248.1137 + }
248.1138 + desc.append(')');
248.1139 + return desc.toString();
248.1140 + }
248.1141 +
248.1142 + /**
248.1143 + * Return the "field type" string for the given type, appropriate for a
248.1144 + * field descriptor, a parameter descriptor, or a return descriptor
248.1145 + * other than "void". See JVMS section 4.3.2.
248.1146 + */
248.1147 + private static String getFieldType(Class type) {
248.1148 + if (type.isPrimitive()) {
248.1149 + return PrimitiveTypeInfo.get(type).baseTypeString;
248.1150 + } else if (type.isArray()) {
248.1151 + /*
248.1152 + * According to JLS 20.3.2, the getName() method on Class does
248.1153 + * return the VM type descriptor format for array classes (only);
248.1154 + * using that should be quicker than the otherwise obvious code:
248.1155 + *
248.1156 + * return "[" + getTypeDescriptor(type.getComponentType());
248.1157 + */
248.1158 + return type.getName().replace('.', '/');
248.1159 + } else {
248.1160 + return "L" + dotToSlash(type.getName()) + ";";
248.1161 + }
248.1162 + }
248.1163 +
248.1164 + /**
248.1165 + * Returns a human-readable string representing the signature of a
248.1166 + * method with the given name and parameter types.
248.1167 + */
248.1168 + private static String getFriendlyMethodSignature(String name,
248.1169 + Class[] parameterTypes) {
248.1170 + StringBuilder sig = new StringBuilder(name);
248.1171 + sig.append('(');
248.1172 + for (int i = 0; i < parameterTypes.length; i++) {
248.1173 + if (i > 0) {
248.1174 + sig.append(',');
248.1175 + }
248.1176 + Class parameterType = parameterTypes[i];
248.1177 + int dimensions = 0;
248.1178 + while (parameterType.isArray()) {
248.1179 + parameterType = parameterType.getComponentType();
248.1180 + dimensions++;
248.1181 + }
248.1182 + sig.append(parameterType.getName());
248.1183 + while (dimensions-- > 0) {
248.1184 + sig.append("[]");
248.1185 + }
248.1186 + }
248.1187 + sig.append(')');
248.1188 + return sig.toString();
248.1189 + }
248.1190 +
248.1191 + /**
248.1192 + * Add to the given list all of the types in the "from" array that are
248.1193 + * not already contained in the list and are assignable to at least one
248.1194 + * of the types in the "with" array.
248.1195 + *
248.1196 + * This method is useful for computing the greatest common set of
248.1197 + * declared exceptions from duplicate methods inherited from different
248.1198 + * interfaces.
248.1199 + */
248.1200 + private static void collectCompatibleTypes(Class<?>[] from,
248.1201 + Class<?>[] with,
248.1202 + List<Class<?>> list) {
248.1203 + for (int i = 0; i < from.length; i++) {
248.1204 + if (!list.contains(from[i])) {
248.1205 + for (int j = 0; j < with.length; j++) {
248.1206 + if (with[j].isAssignableFrom(from[i])) {
248.1207 + list.add(from[i]);
248.1208 + break;
248.1209 + }
248.1210 + }
248.1211 + }
248.1212 + }
248.1213 + }
248.1214 +
248.1215 +
248.1216 + /**
248.1217 + * A PrimitiveTypeInfo object contains assorted information about a
248.1218 + * primitive type in its public fields. The struct for a particular
248.1219 + * primitive type can be obtained using the static "get" method.
248.1220 + */
248.1221 + private static class PrimitiveTypeInfo {
248.1222 +
248.1223 + /**
248.1224 + * "base type" used in various descriptors (see JVMS section 4.3.2)
248.1225 + */
248.1226 + public String baseTypeString;
248.1227 +
248.1228 + /**
248.1229 + * name of corresponding wrapper class
248.1230 + */
248.1231 + public String wrapperClassName;
248.1232 +
248.1233 + /**
248.1234 + * method descriptor for wrapper class "valueOf" factory method
248.1235 + */
248.1236 + public String wrapperValueOfDesc;
248.1237 +
248.1238 + /**
248.1239 + * name of wrapper class method for retrieving primitive value
248.1240 + */
248.1241 + public String unwrapMethodName;
248.1242 +
248.1243 + /**
248.1244 + * descriptor of same method
248.1245 + */
248.1246 + public String unwrapMethodDesc;
248.1247 +
248.1248 + private static Map<Class, PrimitiveTypeInfo> table
248.1249 + = new HashMap<Class, PrimitiveTypeInfo>();
248.1250 +
248.1251 + static {
248.1252 + add(byte.class, Byte.class);
248.1253 + add(char.class, Character.class);
248.1254 + add(double.class, Double.class);
248.1255 + add(float.class, Float.class);
248.1256 + add(int.class, Integer.class);
248.1257 + add(long.class, Long.class);
248.1258 + add(short.class, Short.class);
248.1259 + add(boolean.class, Boolean.class);
248.1260 + }
248.1261 +
248.1262 + private static void add(Class primitiveClass, Class wrapperClass) {
248.1263 + table.put(primitiveClass,
248.1264 + new PrimitiveTypeInfo(primitiveClass, wrapperClass));
248.1265 + }
248.1266 +
248.1267 + private PrimitiveTypeInfo(Class primitiveClass, Class wrapperClass) {
248.1268 + assert primitiveClass.isPrimitive();
248.1269 +
248.1270 + baseTypeString
248.1271 + = Array.newInstance(primitiveClass, 0)
248.1272 + .getClass().getName().substring(1);
248.1273 + wrapperClassName = dotToSlash(wrapperClass.getName());
248.1274 + wrapperValueOfDesc
248.1275 + = "(" + baseTypeString + ")L" + wrapperClassName + ";";
248.1276 + unwrapMethodName = primitiveClass.getName() + "Value";
248.1277 + unwrapMethodDesc = "()" + baseTypeString;
248.1278 + }
248.1279 +
248.1280 + public static PrimitiveTypeInfo get(Class cl) {
248.1281 + return table.get(cl);
248.1282 + }
248.1283 + }
248.1284 +
248.1285 + /**
248.1286 + * A ConstantPool object represents the constant pool of a class file
248.1287 + * being generated. This representation of a constant pool is designed
248.1288 + * specifically for use by ProxyGenerator; in particular, it assumes
248.1289 + * that constant pool entries will not need to be resorted (for example,
248.1290 + * by their type, as the Java compiler does), so that the final index
248.1291 + * value can be assigned and used when an entry is first created.
248.1292 + *
248.1293 + * Note that new entries cannot be created after the constant pool has
248.1294 + * been written to a class file. To prevent such logic errors, a
248.1295 + * ConstantPool instance can be marked "read only", so that further
248.1296 + * attempts to add new entries will fail with a runtime exception.
248.1297 + *
248.1298 + * See JVMS section 4.4 for more information about the constant pool of
248.1299 + * a class file.
248.1300 + */
248.1301 + private static class ConstantPool {
248.1302 +
248.1303 + /**
248.1304 + * list of constant pool entries, in constant pool index order.
248.1305 + *
248.1306 + * This list is used when writing the constant pool to a stream and
248.1307 + * for assigning the next index value. Note that element 0 of this
248.1308 + * list corresponds to constant pool index 1.
248.1309 + */
248.1310 + private List<Entry> pool = new ArrayList<Entry>(32);
248.1311 +
248.1312 + /**
248.1313 + * maps constant pool data of all types to constant pool indexes.
248.1314 + *
248.1315 + * This map is used to look up the index of an existing entry for
248.1316 + * values of all types.
248.1317 + */
248.1318 + private Map<Object, Short> map = new HashMap<Object, Short>(16);
248.1319 +
248.1320 + /**
248.1321 + * true if no new constant pool entries may be added
248.1322 + */
248.1323 + private boolean readOnly = false;
248.1324 +
248.1325 + /**
248.1326 + * Get or assign the index for a CONSTANT_Utf8 entry.
248.1327 + */
248.1328 + public short getUtf8(String s) {
248.1329 + if (s == null) {
248.1330 + throw new NullPointerException();
248.1331 + }
248.1332 + return getValue(s);
248.1333 + }
248.1334 +
248.1335 + /**
248.1336 + * Get or assign the index for a CONSTANT_Integer entry.
248.1337 + */
248.1338 + public short getInteger(int i) {
248.1339 + return getValue(new Integer(i));
248.1340 + }
248.1341 +
248.1342 + /**
248.1343 + * Get or assign the index for a CONSTANT_Float entry.
248.1344 + */
248.1345 + public short getFloat(float f) {
248.1346 + return getValue(new Float(f));
248.1347 + }
248.1348 +
248.1349 + /**
248.1350 + * Get or assign the index for a CONSTANT_Class entry.
248.1351 + */
248.1352 + public short getClass(String name) {
248.1353 + short utf8Index = getUtf8(name);
248.1354 + return getIndirect(new IndirectEntry(
248.1355 + CONSTANT_CLASS, utf8Index));
248.1356 + }
248.1357 +
248.1358 + /**
248.1359 + * Get or assign the index for a CONSTANT_String entry.
248.1360 + */
248.1361 + public short getString(String s) {
248.1362 + short utf8Index = getUtf8(s);
248.1363 + return getIndirect(new IndirectEntry(
248.1364 + CONSTANT_STRING, utf8Index));
248.1365 + }
248.1366 +
248.1367 + /**
248.1368 + * Get or assign the index for a CONSTANT_FieldRef entry.
248.1369 + */
248.1370 + public short getFieldRef(String className,
248.1371 + String name, String descriptor) {
248.1372 + short classIndex = getClass(className);
248.1373 + short nameAndTypeIndex = getNameAndType(name, descriptor);
248.1374 + return getIndirect(new IndirectEntry(
248.1375 + CONSTANT_FIELD, classIndex, nameAndTypeIndex));
248.1376 + }
248.1377 +
248.1378 + /**
248.1379 + * Get or assign the index for a CONSTANT_MethodRef entry.
248.1380 + */
248.1381 + public short getMethodRef(String className,
248.1382 + String name, String descriptor) {
248.1383 + short classIndex = getClass(className);
248.1384 + short nameAndTypeIndex = getNameAndType(name, descriptor);
248.1385 + return getIndirect(new IndirectEntry(
248.1386 + CONSTANT_METHOD, classIndex, nameAndTypeIndex));
248.1387 + }
248.1388 +
248.1389 + /**
248.1390 + * Get or assign the index for a CONSTANT_InterfaceMethodRef entry.
248.1391 + */
248.1392 + public short getInterfaceMethodRef(String className, String name,
248.1393 + String descriptor) {
248.1394 + short classIndex = getClass(className);
248.1395 + short nameAndTypeIndex = getNameAndType(name, descriptor);
248.1396 + return getIndirect(new IndirectEntry(
248.1397 + CONSTANT_INTERFACEMETHOD, classIndex, nameAndTypeIndex));
248.1398 + }
248.1399 +
248.1400 + /**
248.1401 + * Get or assign the index for a CONSTANT_NameAndType entry.
248.1402 + */
248.1403 + public short getNameAndType(String name, String descriptor) {
248.1404 + short nameIndex = getUtf8(name);
248.1405 + short descriptorIndex = getUtf8(descriptor);
248.1406 + return getIndirect(new IndirectEntry(
248.1407 + CONSTANT_NAMEANDTYPE, nameIndex, descriptorIndex));
248.1408 + }
248.1409 +
248.1410 + /**
248.1411 + * Set this ConstantPool instance to be "read only".
248.1412 + *
248.1413 + * After this method has been called, further requests to get an
248.1414 + * index for a non-existent entry will cause an InternalError to be
248.1415 + * thrown instead of creating of the entry.
248.1416 + */
248.1417 + public void setReadOnly() {
248.1418 + readOnly = true;
248.1419 + }
248.1420 +
248.1421 + /**
248.1422 + * Write this constant pool to a stream as part of the class file
248.1423 + * format.
248.1424 + *
248.1425 + * This consists of writing the "constant_pool_count" and
248.1426 + * "constant_pool[]" items of the "ClassFile" structure, as
248.1427 + * described in JVMS section 4.1.
248.1428 + */
248.1429 + public void write(OutputStream out) throws IOException {
248.1430 + DataOutputStream dataOut = new DataOutputStream(out);
248.1431 +
248.1432 + // constant_pool_count: number of entries plus one
248.1433 + dataOut.writeShort(pool.size() + 1);
248.1434 +
248.1435 + for (Entry e : pool) {
248.1436 + e.write(dataOut);
248.1437 + }
248.1438 + }
248.1439 +
248.1440 + /**
248.1441 + * Add a new constant pool entry and return its index.
248.1442 + */
248.1443 + private short addEntry(Entry entry) {
248.1444 + pool.add(entry);
248.1445 + /*
248.1446 + * Note that this way of determining the index of the
248.1447 + * added entry is wrong if this pool supports
248.1448 + * CONSTANT_Long or CONSTANT_Double entries.
248.1449 + */
248.1450 + if (pool.size() >= 65535) {
248.1451 + throw new IllegalArgumentException(
248.1452 + "constant pool size limit exceeded");
248.1453 + }
248.1454 + return (short) pool.size();
248.1455 + }
248.1456 +
248.1457 + /**
248.1458 + * Get or assign the index for an entry of a type that contains a
248.1459 + * direct value. The type of the given object determines the type of
248.1460 + * the desired entry as follows:
248.1461 + *
248.1462 + * java.lang.String CONSTANT_Utf8 java.lang.Integer CONSTANT_Integer
248.1463 + * java.lang.Float CONSTANT_Float java.lang.Long CONSTANT_Long
248.1464 + * java.lang.Double CONSTANT_DOUBLE
248.1465 + */
248.1466 + private short getValue(Object key) {
248.1467 + Short index = map.get(key);
248.1468 + if (index != null) {
248.1469 + return index.shortValue();
248.1470 + } else {
248.1471 + if (readOnly) {
248.1472 + throw new InternalError(
248.1473 + "late constant pool addition: " + key);
248.1474 + }
248.1475 + short i = addEntry(new ValueEntry(key));
248.1476 + map.put(key, new Short(i));
248.1477 + return i;
248.1478 + }
248.1479 + }
248.1480 +
248.1481 + /**
248.1482 + * Get or assign the index for an entry of a type that contains
248.1483 + * references to other constant pool entries.
248.1484 + */
248.1485 + private short getIndirect(IndirectEntry e) {
248.1486 + Short index = map.get(e);
248.1487 + if (index != null) {
248.1488 + return index.shortValue();
248.1489 + } else {
248.1490 + if (readOnly) {
248.1491 + throw new InternalError("late constant pool addition");
248.1492 + }
248.1493 + short i = addEntry(e);
248.1494 + map.put(e, new Short(i));
248.1495 + return i;
248.1496 + }
248.1497 + }
248.1498 +
248.1499 + /**
248.1500 + * Entry is the abstact superclass of all constant pool entry types
248.1501 + * that can be stored in the "pool" list; its purpose is to define a
248.1502 + * common method for writing constant pool entries to a class file.
248.1503 + */
248.1504 + private static abstract class Entry {
248.1505 +
248.1506 + public abstract void write(DataOutputStream out)
248.1507 + throws IOException;
248.1508 + }
248.1509 +
248.1510 + /**
248.1511 + * ValueEntry represents a constant pool entry of a type that
248.1512 + * contains a direct value (see the comments for the "getValue"
248.1513 + * method for a list of such types).
248.1514 + *
248.1515 + * ValueEntry objects are not used as keys for their entries in the
248.1516 + * Map "map", so no useful hashCode or equals methods are defined.
248.1517 + */
248.1518 + private static class ValueEntry extends Entry {
248.1519 +
248.1520 + private Object value;
248.1521 +
248.1522 + public ValueEntry(Object value) {
248.1523 + this.value = value;
248.1524 + }
248.1525 +
248.1526 + public void write(DataOutputStream out) throws IOException {
248.1527 + if (value instanceof String) {
248.1528 + out.writeByte(CONSTANT_UTF8);
248.1529 + out.writeUTF((String) value);
248.1530 + } else if (value instanceof Integer) {
248.1531 + out.writeByte(CONSTANT_INTEGER);
248.1532 + out.writeInt(((Integer) value).intValue());
248.1533 + } else if (value instanceof Float) {
248.1534 + out.writeByte(CONSTANT_FLOAT);
248.1535 + out.writeFloat(((Float) value).floatValue());
248.1536 + } else if (value instanceof Long) {
248.1537 + out.writeByte(CONSTANT_LONG);
248.1538 + out.writeLong(((Long) value).longValue());
248.1539 + } else if (value instanceof Double) {
248.1540 + out.writeDouble(CONSTANT_DOUBLE);
248.1541 + out.writeDouble(((Double) value).doubleValue());
248.1542 + } else {
248.1543 + throw new InternalError("bogus value entry: " + value);
248.1544 + }
248.1545 + }
248.1546 + }
248.1547 +
248.1548 + /**
248.1549 + * IndirectEntry represents a constant pool entry of a type that
248.1550 + * references other constant pool entries, i.e., the following
248.1551 + * types:
248.1552 + *
248.1553 + * CONSTANT_Class, CONSTANT_String, CONSTANT_Fieldref,
248.1554 + * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, and
248.1555 + * CONSTANT_NameAndType.
248.1556 + *
248.1557 + * Each of these entry types contains either one or two indexes of
248.1558 + * other constant pool entries.
248.1559 + *
248.1560 + * IndirectEntry objects are used as the keys for their entries in
248.1561 + * the Map "map", so the hashCode and equals methods are overridden
248.1562 + * to allow matching.
248.1563 + */
248.1564 + private static class IndirectEntry extends Entry {
248.1565 +
248.1566 + private int tag;
248.1567 + private short index0;
248.1568 + private short index1;
248.1569 +
248.1570 + /**
248.1571 + * Construct an IndirectEntry for a constant pool entry type
248.1572 + * that contains one index of another entry.
248.1573 + */
248.1574 + public IndirectEntry(int tag, short index) {
248.1575 + this.tag = tag;
248.1576 + this.index0 = index;
248.1577 + this.index1 = 0;
248.1578 + }
248.1579 +
248.1580 + /**
248.1581 + * Construct an IndirectEntry for a constant pool entry type
248.1582 + * that contains two indexes for other entries.
248.1583 + */
248.1584 + public IndirectEntry(int tag, short index0, short index1) {
248.1585 + this.tag = tag;
248.1586 + this.index0 = index0;
248.1587 + this.index1 = index1;
248.1588 + }
248.1589 +
248.1590 + public void write(DataOutputStream out) throws IOException {
248.1591 + out.writeByte(tag);
248.1592 + out.writeShort(index0);
248.1593 + /*
248.1594 + * If this entry type contains two indexes, write
248.1595 + * out the second, too.
248.1596 + */
248.1597 + if (tag == CONSTANT_FIELD
248.1598 + || tag == CONSTANT_METHOD
248.1599 + || tag == CONSTANT_INTERFACEMETHOD
248.1600 + || tag == CONSTANT_NAMEANDTYPE) {
248.1601 + out.writeShort(index1);
248.1602 + }
248.1603 + }
248.1604 +
248.1605 + public int hashCode() {
248.1606 + return tag + index0 + index1;
248.1607 + }
248.1608 +
248.1609 + public boolean equals(Object obj) {
248.1610 + if (obj instanceof IndirectEntry) {
248.1611 + IndirectEntry other = (IndirectEntry) obj;
248.1612 + if (tag == other.tag
248.1613 + && index0 == other.index0 && index1 == other.index1) {
248.1614 + return true;
248.1615 + }
248.1616 + }
248.1617 + return false;
248.1618 + }
248.1619 + }
248.1620 + }
248.1621 + }
248.1622 +
248.1623 +}
249.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ReaderTest.java Tue Apr 29 15:25:58 2014 +0200
249.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/compact/tck/ReaderTest.java Wed Apr 30 15:04:10 2014 +0200
249.3 @@ -18,8 +18,10 @@
249.4 package org.apidesign.bck2brwsr.compact.tck;
249.5
249.6 import java.io.ByteArrayInputStream;
249.7 +import java.io.ByteArrayOutputStream;
249.8 import java.io.IOException;
249.9 import java.io.InputStreamReader;
249.10 +import java.io.OutputStreamWriter;
249.11 import java.io.UnsupportedEncodingException;
249.12 import java.util.Arrays;
249.13 import org.apidesign.bck2brwsr.vmtest.Compare;
249.14 @@ -40,7 +42,10 @@
249.15 };
249.16 ByteArrayInputStream is = new ByteArrayInputStream(arr);
249.17 InputStreamReader r = new InputStreamReader(is, "UTF-8");
249.18 -
249.19 + return readReader(r);
249.20 + }
249.21 +
249.22 + private String readReader(InputStreamReader r) throws IOException {
249.23 StringBuilder sb = new StringBuilder();
249.24 for (;;) {
249.25 int ch = r.read();
249.26 @@ -52,7 +57,19 @@
249.27 return sb.toString().toString();
249.28 }
249.29 @Compare public String stringToBytes() throws UnsupportedEncodingException {
249.30 - return Arrays.toString("\u017dlu\u0165ou\u010dk\u00fd k\u016f\u0148".getBytes("UTF-8"));
249.31 + return Arrays.toString(YellowHorse.getBytes("UTF-8"));
249.32 + }
249.33 + private final String YellowHorse = "\u017dlu\u0165ou\u010dk\u00fd k\u016f\u0148";
249.34 +
249.35 + @Compare public String readAndWrite() throws Exception {
249.36 + ByteArrayOutputStream arr = new ByteArrayOutputStream();
249.37 + OutputStreamWriter w = new OutputStreamWriter(arr);
249.38 + w.write(YellowHorse);
249.39 + w.close();
249.40 +
249.41 + ByteArrayInputStream is = new ByteArrayInputStream(arr.toByteArray());
249.42 + InputStreamReader r = new InputStreamReader(is, "UTF-8");
249.43 + return readReader(r);
249.44 }
249.45
249.46 @Factory public static Object[] create() {
250.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
250.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/AtomicTest.java Wed Apr 30 15:04:10 2014 +0200
250.3 @@ -0,0 +1,54 @@
250.4 +/**
250.5 + * Back 2 Browser Bytecode Translator
250.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
250.7 + *
250.8 + * This program is free software: you can redistribute it and/or modify
250.9 + * it under the terms of the GNU General Public License as published by
250.10 + * the Free Software Foundation, version 2 of the License.
250.11 + *
250.12 + * This program is distributed in the hope that it will be useful,
250.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
250.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
250.15 + * GNU General Public License for more details.
250.16 + *
250.17 + * You should have received a copy of the GNU General Public License
250.18 + * along with this program. Look for COPYING file in the top folder.
250.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
250.20 + */
250.21 +package org.apidesign.bck2brwsr.tck;
250.22 +
250.23 +import java.util.concurrent.atomic.AtomicBoolean;
250.24 +import java.util.concurrent.atomic.AtomicInteger;
250.25 +import java.util.concurrent.atomic.AtomicReference;
250.26 +import org.apidesign.bck2brwsr.vmtest.Compare;
250.27 +import org.apidesign.bck2brwsr.vmtest.VMTest;
250.28 +import org.testng.annotations.Factory;
250.29 +
250.30 +/**
250.31 + *
250.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
250.33 + */
250.34 +public class AtomicTest {
250.35 + @Compare public boolean atomicBoolean() {
250.36 + AtomicBoolean ab = new AtomicBoolean();
250.37 + ab.set(true);
250.38 + return ab.compareAndSet(true, false);
250.39 + }
250.40 +
250.41 + @Compare public int atomicInt() {
250.42 + AtomicInteger ab = new AtomicInteger();
250.43 + ab.set(30);
250.44 + assert ab.compareAndSet(30, 10);
250.45 + return ab.get();
250.46 + }
250.47 +
250.48 + @Compare public String atomicRef() {
250.49 + AtomicReference<String> ar = new AtomicReference<String>("Ahoj");
250.50 + assert ar.compareAndSet("Ahoj", "Hello");
250.51 + return ar.getAndSet("Other");
250.52 + }
250.53 +
250.54 + @Factory public static Object[] create() {
250.55 + return VMTest.create(AtomicTest.class);
250.56 + }
250.57 +}
251.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
251.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CharacterTest.java Wed Apr 30 15:04:10 2014 +0200
251.3 @@ -0,0 +1,61 @@
251.4 +/**
251.5 + * Back 2 Browser Bytecode Translator
251.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
251.7 + *
251.8 + * This program is free software: you can redistribute it and/or modify
251.9 + * it under the terms of the GNU General Public License as published by
251.10 + * the Free Software Foundation, version 2 of the License.
251.11 + *
251.12 + * This program is distributed in the hope that it will be useful,
251.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
251.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
251.15 + * GNU General Public License for more details.
251.16 + *
251.17 + * You should have received a copy of the GNU General Public License
251.18 + * along with this program. Look for COPYING file in the top folder.
251.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
251.20 + */
251.21 +package org.apidesign.bck2brwsr.tck;
251.22 +
251.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
251.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
251.25 +import org.testng.annotations.Factory;
251.26 +
251.27 +/**
251.28 + *
251.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
251.30 + */
251.31 +public class CharacterTest {
251.32 + @Compare public boolean dolarJavaStart() {
251.33 + return Character.isJavaIdentifierStart('$');
251.34 + }
251.35 +
251.36 + @Compare public boolean dolarJavaPart() {
251.37 + return Character.isJavaIdentifierPart('$');
251.38 + }
251.39 +
251.40 + @Compare public boolean numberJavaStart() {
251.41 + return Character.isJavaIdentifierStart('3');
251.42 + }
251.43 +
251.44 + @Compare public boolean numberJavaPart() {
251.45 + return Character.isJavaIdentifierPart('3');
251.46 + }
251.47 +
251.48 + @Compare public String testWhiteSpaces() {
251.49 + StringBuilder sb = new StringBuilder();
251.50 + for (int i = 1; i < 128; i++) {
251.51 + char ch = (char)i;
251.52 + if (Character.isWhitespace(ch)) {
251.53 + sb.append(i).append(",");
251.54 + }
251.55 + }
251.56 + return sb.toString();
251.57 + }
251.58 +
251.59 + @Factory
251.60 + public static Object[] create() {
251.61 + return VMTest.create(CharacterTest.class);
251.62 + }
251.63 +
251.64 +}
252.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
252.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ClassLoaderTest.java Wed Apr 30 15:04:10 2014 +0200
252.3 @@ -0,0 +1,41 @@
252.4 +/**
252.5 + * Back 2 Browser Bytecode Translator
252.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
252.7 + *
252.8 + * This program is free software: you can redistribute it and/or modify
252.9 + * it under the terms of the GNU General Public License as published by
252.10 + * the Free Software Foundation, version 2 of the License.
252.11 + *
252.12 + * This program is distributed in the hope that it will be useful,
252.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
252.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
252.15 + * GNU General Public License for more details.
252.16 + *
252.17 + * You should have received a copy of the GNU General Public License
252.18 + * along with this program. Look for COPYING file in the top folder.
252.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
252.20 + */
252.21 +package org.apidesign.bck2brwsr.tck;
252.22 +
252.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
252.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
252.25 +import org.testng.annotations.Factory;
252.26 +
252.27 +/**
252.28 + *
252.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
252.30 + */
252.31 +public class ClassLoaderTest {
252.32 + @Compare public Object unknownResource() {
252.33 + return ClassLoader.getSystemResource("really/unknown/resource.txt");
252.34 + }
252.35 +
252.36 + @Compare public boolean indenpotentSetOfClassloaderIsOK() {
252.37 + Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
252.38 + return Thread.currentThread().getContextClassLoader() == ClassLoader.getSystemClassLoader();
252.39 + }
252.40 +
252.41 + @Factory public static Object[] create() {
252.42 + return VMTest.create(ClassLoaderTest.class);
252.43 + }
252.44 +}
253.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java Tue Apr 29 15:25:58 2014 +0200
253.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareHashTest.java Wed Apr 30 15:04:10 2014 +0200
253.3 @@ -30,6 +30,16 @@
253.4 return "Ahoj".hashCode();
253.5 }
253.6
253.7 + @Compare public boolean hashOfIntegerDifferentToOwnHash() {
253.8 + Integer i = 120;
253.9 + return System.identityHashCode(i) != i.hashCode();
253.10 + }
253.11 +
253.12 + @Compare public int hashOfObjectSameAsOwnHash() {
253.13 + Object o = new Object();
253.14 + return System.identityHashCode(o) - o.hashCode();
253.15 + }
253.16 +
253.17 @Compare public int hashRemainsYieldsZero() {
253.18 Object o = new Object();
253.19 return o.hashCode() - o.hashCode();
254.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Tue Apr 29 15:25:58 2014 +0200
254.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/CompareStringsTest.java Wed Apr 30 15:04:10 2014 +0200
254.3 @@ -19,7 +19,9 @@
254.4
254.5 import java.io.UnsupportedEncodingException;
254.6 import java.net.MalformedURLException;
254.7 +import java.net.URISyntaxException;
254.8 import java.net.URL;
254.9 +import java.util.Locale;
254.10 import org.apidesign.bck2brwsr.vmtest.Compare;
254.11 import org.apidesign.bck2brwsr.vmtest.VMTest;
254.12 import org.testng.annotations.Factory;
254.13 @@ -47,6 +49,14 @@
254.14 return "Ahoj".equals(null);
254.15 }
254.16
254.17 + @Compare public boolean internIsSame() {
254.18 + return new String("Ahoj").intern() == another();
254.19 + }
254.20 +
254.21 + private static String another() {
254.22 + return new String("Ahoj").intern();
254.23 + }
254.24 +
254.25 @Compare public int highByteLenght() {
254.26 byte[] arr= { 77,97,110,105,102,101,115,116,45,86,101,114,115,105,111,110 };
254.27 return new String(arr, 0).length();
254.28 @@ -63,6 +73,10 @@
254.29 @Compare public static Object compareURLs() throws MalformedURLException {
254.30 return new URL("http://apidesign.org:8080/wiki/").toExternalForm().toString();
254.31 }
254.32 +
254.33 + @Compare public static Object compareURLsViaURIs() throws Exception {
254.34 + return new URL("http://apidesign.org:8080/wiki/").toURI().toString();
254.35 + }
254.36
254.37 @Compare public String deleteLastTwoCharacters() {
254.38 StringBuilder sb = new StringBuilder();
254.39 @@ -161,7 +175,28 @@
254.40 assert res.equals("ba") : "Expecting ba: " + res;
254.41 return res;
254.42 }
254.43 +
254.44 + @Compare public String localeUS() {
254.45 + return Locale.US.toString();
254.46 + }
254.47 +
254.48 + @Compare public String localeFrench() {
254.49 + return Locale.FRENCH.toString();
254.50 + }
254.51 +
254.52 +
254.53 + @Compare public String formatSimple() {
254.54 + return String.format((Locale)null, "Hello %s!", "World");
254.55 + }
254.56
254.57 + @Compare public String replaceWithItself() {
254.58 + return "org.apidesign.bck2brwsr.core.JavaScriptBody".replace(".", "\\.");
254.59 + }
254.60 +
254.61 + @Compare public boolean matchWithComplicatedRegExp() {
254.62 + return "Activates this model instance.".matches("(?sm).*^\\s*@deprecated( |$).*");
254.63 + }
254.64 +
254.65 @Factory
254.66 public static Object[] create() {
254.67 return VMTest.create(CompareStringsTest.class);
255.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
255.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ConcurrentTest.java Wed Apr 30 15:04:10 2014 +0200
255.3 @@ -0,0 +1,40 @@
255.4 +/**
255.5 + * Back 2 Browser Bytecode Translator
255.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
255.7 + *
255.8 + * This program is free software: you can redistribute it and/or modify
255.9 + * it under the terms of the GNU General Public License as published by
255.10 + * the Free Software Foundation, version 2 of the License.
255.11 + *
255.12 + * This program is distributed in the hope that it will be useful,
255.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
255.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
255.15 + * GNU General Public License for more details.
255.16 + *
255.17 + * You should have received a copy of the GNU General Public License
255.18 + * along with this program. Look for COPYING file in the top folder.
255.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
255.20 + */
255.21 +package org.apidesign.bck2brwsr.tck;
255.22 +
255.23 +import java.util.concurrent.ConcurrentHashMap;
255.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
255.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
255.26 +import org.testng.annotations.Factory;
255.27 +
255.28 +/**
255.29 + *
255.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
255.31 + */
255.32 +public class ConcurrentTest {
255.33 + @Compare public String mapIfAbsent() {
255.34 + ConcurrentHashMap<String,String> m = new ConcurrentHashMap<>();
255.35 + m.putIfAbsent("Ahoj", "Jardo");
255.36 + m.putIfAbsent("Ahoj", "Dardo");
255.37 + return m.get("Ahoj");
255.38 + }
255.39 +
255.40 + @Factory public static Object[] create() {
255.41 + return VMTest.create(ConcurrentTest.class);
255.42 + }
255.43 +}
256.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/DoubleTest.java Tue Apr 29 15:25:58 2014 +0200
256.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/DoubleTest.java Wed Apr 30 15:04:10 2014 +0200
256.3 @@ -26,6 +26,14 @@
256.4 * @author Jaroslav Tulach <jtulach@netbeans.org>
256.5 */
256.6 public class DoubleTest {
256.7 + @Compare public boolean parsedDoubleIsDouble() {
256.8 + return Double.valueOf("1.1") instanceof Double;
256.9 + }
256.10 +
256.11 + @Compare public boolean parsedFloatIsFloat() {
256.12 + return Float.valueOf("1.1") instanceof Float;
256.13 + }
256.14 +
256.15 @Compare public String integerToString() {
256.16 return toStr(1);
256.17 }
257.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
257.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/EnumsTest.java Wed Apr 30 15:04:10 2014 +0200
257.3 @@ -0,0 +1,76 @@
257.4 +/**
257.5 + * Back 2 Browser Bytecode Translator
257.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
257.7 + *
257.8 + * This program is free software: you can redistribute it and/or modify
257.9 + * it under the terms of the GNU General Public License as published by
257.10 + * the Free Software Foundation, version 2 of the License.
257.11 + *
257.12 + * This program is distributed in the hope that it will be useful,
257.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
257.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
257.15 + * GNU General Public License for more details.
257.16 + *
257.17 + * You should have received a copy of the GNU General Public License
257.18 + * along with this program. Look for COPYING file in the top folder.
257.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
257.20 + */
257.21 +package org.apidesign.bck2brwsr.tck;
257.22 +
257.23 +import java.util.EnumMap;
257.24 +import java.util.EnumSet;
257.25 +import org.apidesign.bck2brwsr.vmtest.Compare;
257.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
257.27 +import org.testng.annotations.Factory;
257.28 +
257.29 +/**
257.30 + *
257.31 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
257.32 + */
257.33 +public class EnumsTest {
257.34 + enum Color {
257.35 + B, W;
257.36 + }
257.37 +
257.38 + @Compare public String enumSet() {
257.39 + try { throw new Exception(); } catch (Exception ex) {}
257.40 + EnumSet<Color> c = EnumSet.allOf(Color.class);
257.41 + return c.toString();
257.42 + }
257.43 +
257.44 + @Compare public String enumSetOneByOne() {
257.45 + EnumSet<Color> c = EnumSet.of(Color.B, Color.W);
257.46 + return c.toString();
257.47 + }
257.48 +
257.49 + @Compare public boolean enumFirstContains() {
257.50 + EnumSet<Color> c = EnumSet.of(Color.B);
257.51 + return c.contains(Color.B);
257.52 + }
257.53 +
257.54 + @Compare public boolean enumFirstDoesNotContains() {
257.55 + EnumSet<Color> c = EnumSet.of(Color.B);
257.56 + return c.contains(Color.W);
257.57 + }
257.58 +
257.59 + @Compare public boolean enumSndContains() {
257.60 + EnumSet<Color> c = EnumSet.of(Color.W);
257.61 + return c.contains(Color.W);
257.62 + }
257.63 +
257.64 + @Compare public boolean enumSecondDoesNotContains() {
257.65 + EnumSet<Color> c = EnumSet.of(Color.W);
257.66 + return c.contains(Color.B);
257.67 + }
257.68 +
257.69 + @Compare public String enumMap() {
257.70 + EnumMap<Color,String> c = new EnumMap(Color.class);
257.71 + c.put(Color.B, "Black");
257.72 + c.put(Color.W, "White");
257.73 + return c.toString();
257.74 + }
257.75 +
257.76 + @Factory public static Object[] create() {
257.77 + return VMTest.create(EnumsTest.class);
257.78 + }
257.79 +}
258.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
258.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ExceptionsTest.java Wed Apr 30 15:04:10 2014 +0200
258.3 @@ -0,0 +1,68 @@
258.4 +/**
258.5 + * Back 2 Browser Bytecode Translator
258.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
258.7 + *
258.8 + * This program is free software: you can redistribute it and/or modify
258.9 + * it under the terms of the GNU General Public License as published by
258.10 + * the Free Software Foundation, version 2 of the License.
258.11 + *
258.12 + * This program is distributed in the hope that it will be useful,
258.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
258.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
258.15 + * GNU General Public License for more details.
258.16 + *
258.17 + * You should have received a copy of the GNU General Public License
258.18 + * along with this program. Look for COPYING file in the top folder.
258.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
258.20 + */
258.21 +package org.apidesign.bck2brwsr.tck;
258.22 +
258.23 +import java.io.ByteArrayOutputStream;
258.24 +import java.io.PrintStream;
258.25 +import java.io.PrintWriter;
258.26 +import java.io.StringWriter;
258.27 +import java.io.UnsupportedEncodingException;
258.28 +import org.apidesign.bck2brwsr.vmtest.Compare;
258.29 +import org.apidesign.bck2brwsr.vmtest.VMTest;
258.30 +import org.testng.annotations.Factory;
258.31 +
258.32 +/**
258.33 + *
258.34 + * @author Jaroslav Tulach <jtulach@netbeans.org>
258.35 + */
258.36 +public class ExceptionsTest {
258.37 + @Compare public String firstLineIsTheSame() throws UnsupportedEncodingException {
258.38 + MyException ex = new MyException("Hello");
258.39 + ByteArrayOutputStream out = new ByteArrayOutputStream();
258.40 + PrintStream ps = new PrintStream(out);
258.41 + ex.printStackTrace(ps);
258.42 + ps.flush();
258.43 +
258.44 + String s = new String(out.toByteArray(), "UTF-8");
258.45 + int newLine = s.indexOf('\n');
258.46 + return s.substring(0, newLine);
258.47 + }
258.48 +
258.49 + @Compare public String firstLineIsTheSameWithWriter() throws UnsupportedEncodingException {
258.50 + MyException ex = new MyException("Hello");
258.51 + StringWriter sw = new StringWriter();
258.52 + PrintWriter pw = new PrintWriter(sw);
258.53 + ex.printStackTrace(pw);
258.54 + pw.flush();
258.55 +
258.56 + String s = sw.toString();
258.57 + int newLine = s.indexOf('\n');
258.58 + return s.substring(0, newLine);
258.59 + }
258.60 +
258.61 + static class MyException extends Exception {
258.62 + public MyException(String message) {
258.63 + super(message);
258.64 + }
258.65 + }
258.66 +
258.67 +
258.68 + @Factory public static Object[] create() {
258.69 + return VMTest.create(ExceptionsTest.class);
258.70 + }
258.71 +}
259.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
259.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/LoggerTest.java Wed Apr 30 15:04:10 2014 +0200
259.3 @@ -0,0 +1,43 @@
259.4 +/**
259.5 + * Back 2 Browser Bytecode Translator
259.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
259.7 + *
259.8 + * This program is free software: you can redistribute it and/or modify
259.9 + * it under the terms of the GNU General Public License as published by
259.10 + * the Free Software Foundation, version 2 of the License.
259.11 + *
259.12 + * This program is distributed in the hope that it will be useful,
259.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
259.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
259.15 + * GNU General Public License for more details.
259.16 + *
259.17 + * You should have received a copy of the GNU General Public License
259.18 + * along with this program. Look for COPYING file in the top folder.
259.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
259.20 + */
259.21 +package org.apidesign.bck2brwsr.tck;
259.22 +
259.23 +import java.util.logging.Logger;
259.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
259.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
259.26 +import org.testng.annotations.Factory;
259.27 +
259.28 +/**
259.29 + *
259.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
259.31 + */
259.32 +public class LoggerTest {
259.33 + @Compare public String parentLogger() {
259.34 + Logger lx = Logger.getLogger("x");
259.35 + assert lx != null;
259.36 + assert lx.getName().equals("x") : "Right name: " + lx.getName();
259.37 + Logger lxyz = Logger.getLogger("x.y.z");
259.38 + assert lxyz != null;
259.39 + assert lxyz.getName().equals("x.y.z") : "xyz name: " + lxyz.getName();
259.40 + return lxyz.getParent().getName();
259.41 + }
259.42 +
259.43 + @Factory public static Object[] create() {
259.44 + return VMTest.create(LoggerTest.class);
259.45 + }
259.46 +}
260.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Tue Apr 29 15:25:58 2014 +0200
260.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Wed Apr 30 15:04:10 2014 +0200
260.3 @@ -304,6 +304,14 @@
260.4 @Compare public long shiftL3() {
260.5 return shl(0x00fa37d7763e0ca1l, 45);
260.6 }
260.7 +
260.8 + @Compare public long shiftL4() {
260.9 + return shl(0x00fa37d7763e0ca1l, 0);
260.10 + }
260.11 +
260.12 + @Compare public long shiftL5() {
260.13 + return shl(0x00fa37d7763e0ca1l, 70);
260.14 + }
260.15
260.16 @Compare public long shiftR1() {
260.17 return shr(0x00fa37d7763e0ca1l, 5);
260.18 @@ -316,6 +324,14 @@
260.19 @Compare public long shiftR3() {
260.20 return shr(0x00fa37d7763e0ca1l, 45);
260.21 }
260.22 +
260.23 + @Compare public long shiftR4() {
260.24 + return shr(0x00fa37d7763e0ca1l, 0);
260.25 + }
260.26 +
260.27 + @Compare public long shiftR5() {
260.28 + return shr(0x00fa37d7763e0ca1l, 70);
260.29 + }
260.30
260.31 @Compare public long uShiftR1() {
260.32 return ushr(0x00fa37d7763e0ca1l, 5);
260.33 @@ -324,14 +340,30 @@
260.34 @Compare public long uShiftR2() {
260.35 return ushr(0x00fa37d7763e0ca1l, 45);
260.36 }
260.37 +
260.38 + @Compare public long uShiftR3() {
260.39 + return ushr(0x00fa37d7763e0ca1l, 0);
260.40 + }
260.41 +
260.42 + @Compare public long uShiftR4() {
260.43 + return ushr(0x00fa37d7763e0ca1l, 70);
260.44 + }
260.45
260.46 - @Compare public long uShiftR3() {
260.47 + @Compare public long uShiftR5() {
260.48 return ushr(0xf0fa37d7763e0ca1l, 5);
260.49 }
260.50
260.51 - @Compare public long uShiftR4() {
260.52 + @Compare public long uShiftR6() {
260.53 return ushr(0xf0fa37d7763e0ca1l, 45);
260.54 }
260.55 +
260.56 + @Compare public long uShiftR7() {
260.57 + return ushr(0xf0fa37d7763e0ca1l, 0);
260.58 + }
260.59 +
260.60 + @Compare public long uShiftR8() {
260.61 + return ushr(0xf0fa37d7763e0ca1l, 70);
260.62 + }
260.63
260.64 @Compare public long and1() {
260.65 return and(0x00fa37d7763e0ca1l, 0xa7b3432fff00123el);
261.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
261.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/NotifyWaitTest.java Wed Apr 30 15:04:10 2014 +0200
261.3 @@ -0,0 +1,63 @@
261.4 +/**
261.5 + * Back 2 Browser Bytecode Translator
261.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
261.7 + *
261.8 + * This program is free software: you can redistribute it and/or modify
261.9 + * it under the terms of the GNU General Public License as published by
261.10 + * the Free Software Foundation, version 2 of the License.
261.11 + *
261.12 + * This program is distributed in the hope that it will be useful,
261.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
261.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
261.15 + * GNU General Public License for more details.
261.16 + *
261.17 + * You should have received a copy of the GNU General Public License
261.18 + * along with this program. Look for COPYING file in the top folder.
261.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
261.20 + */
261.21 +package org.apidesign.bck2brwsr.tck;
261.22 +
261.23 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
261.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
261.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
261.26 +import org.testng.annotations.Factory;
261.27 +
261.28 +/**
261.29 + *
261.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
261.31 + */
261.32 +public class NotifyWaitTest {
261.33 +
261.34 +
261.35 + @Compare public synchronized String canCallNotify() throws Exception {
261.36 + notify();
261.37 + return "OK";
261.38 + }
261.39 +
261.40 + @Compare public synchronized String canCallNotifyAll() throws Exception {
261.41 + notifyAll();
261.42 + return "OK";
261.43 + }
261.44 +
261.45 + @BrwsrTest public synchronized String throwsInterruptedException() {
261.46 + try {
261.47 + wait();
261.48 + throw new IllegalStateException();
261.49 + } catch (InterruptedException ex) {
261.50 + return "OK";
261.51 + }
261.52 + }
261.53 +
261.54 + @BrwsrTest public synchronized String waitMsThrowsInterruptedException() {
261.55 + try {
261.56 + wait(32);
261.57 + throw new IllegalStateException();
261.58 + } catch (InterruptedException ex) {
261.59 + return "OK";
261.60 + }
261.61 + }
261.62 +
261.63 + @Factory public static Object[] create() {
261.64 + return VMTest.create(NotifyWaitTest.class);
261.65 + }
261.66 +}
262.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
262.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ProxyTest.java Wed Apr 30 15:04:10 2014 +0200
262.3 @@ -0,0 +1,71 @@
262.4 +/**
262.5 + * Back 2 Browser Bytecode Translator
262.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
262.7 + *
262.8 + * This program is free software: you can redistribute it and/or modify
262.9 + * it under the terms of the GNU General Public License as published by
262.10 + * the Free Software Foundation, version 2 of the License.
262.11 + *
262.12 + * This program is distributed in the hope that it will be useful,
262.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
262.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
262.15 + * GNU General Public License for more details.
262.16 + *
262.17 + * You should have received a copy of the GNU General Public License
262.18 + * along with this program. Look for COPYING file in the top folder.
262.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
262.20 + */
262.21 +package org.apidesign.bck2brwsr.tck;
262.22 +
262.23 +import java.lang.reflect.InvocationHandler;
262.24 +import java.lang.reflect.Method;
262.25 +import java.lang.reflect.Proxy;
262.26 +import org.apidesign.bck2brwsr.vmtest.Compare;
262.27 +import org.apidesign.bck2brwsr.vmtest.VMTest;
262.28 +import org.testng.annotations.Factory;
262.29 +
262.30 +/**
262.31 + *
262.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
262.33 + */
262.34 +public class ProxyTest {
262.35 + @Compare public String generateAnnotation() throws Exception {
262.36 + class InvHandler implements InvocationHandler {
262.37 + @Override
262.38 + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
262.39 + return "Joe Hacker";
262.40 + }
262.41 + }
262.42 + Anno anno = (Anno) Proxy.newProxyInstance(
262.43 + Anno.class.getClassLoader(),
262.44 + new Class[] { Anno.class },
262.45 + new InvHandler()
262.46 + );
262.47 + return anno.name();
262.48 + }
262.49 +
262.50 + @Compare public int getPrimitiveType() throws Exception {
262.51 + class InvHandler implements InvocationHandler {
262.52 + @Override
262.53 + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
262.54 + return 40;
262.55 + }
262.56 + }
262.57 + Anno anno = (Anno) Proxy.newProxyInstance(
262.58 + Anno.class.getClassLoader(),
262.59 + new Class[] { Anno.class },
262.60 + new InvHandler()
262.61 + );
262.62 + return 2 + anno.age();
262.63 + }
262.64 +
262.65 + public static @interface Anno {
262.66 + public String name();
262.67 + public int age();
262.68 + }
262.69 +
262.70 + @Factory
262.71 + public static Object[] create() {
262.72 + return VMTest.create(ProxyTest.class);
262.73 + }
262.74 +}
263.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java Tue Apr 29 15:25:58 2014 +0200
263.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionArrayTest.java Wed Apr 30 15:04:10 2014 +0200
263.3 @@ -34,6 +34,11 @@
263.4 return arr.length;
263.5 }
263.6
263.7 + @Compare public String indexOutOfBounds() {
263.8 + String[] arr = { null, null };
263.9 + return arr[2];
263.10 + }
263.11 +
263.12 @Compare public int reflectiveLengthOfStringArray() {
263.13 Object arr = Array.newInstance(String.class, 10);
263.14 return Array.getLength(arr);
264.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Tue Apr 29 15:25:58 2014 +0200
264.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ReflectionTest.java Wed Apr 30 15:04:10 2014 +0200
264.3 @@ -19,7 +19,9 @@
264.4
264.5 import java.lang.annotation.Retention;
264.6 import java.lang.annotation.RetentionPolicy;
264.7 +import java.lang.reflect.Constructor;
264.8 import java.lang.reflect.Method;
264.9 +import java.lang.reflect.Proxy;
264.10 import java.util.Arrays;
264.11 import java.util.Collections;
264.12 import java.util.List;
264.13 @@ -72,6 +74,18 @@
264.14 @Compare public String isRunnableHasRunMethod() throws NoSuchMethodException {
264.15 return Runnable.class.getMethod("run").getName();
264.16 }
264.17 +
264.18 + @Compare public String isRunnableDeclaresRunMethod() throws NoSuchMethodException {
264.19 + return Runnable.class.getDeclaredMethod("run").getName();
264.20 + }
264.21 +
264.22 + @Compare public String intValue() throws Exception {
264.23 + return Integer.class.getConstructor(int.class).newInstance(10).toString();
264.24 + }
264.25 +
264.26 + @Compare public String getMethodWithArray() throws Exception {
264.27 + return Proxy.class.getMethod("getProxyClass", ClassLoader.class, Class[].class).getName();
264.28 + }
264.29
264.30 @Compare public String namesOfMethods() {
264.31 StringBuilder sb = new StringBuilder();
264.32 @@ -86,6 +100,19 @@
264.33 return sb.toString();
264.34 }
264.35
264.36 + @Compare public String paramsOfConstructors() {
264.37 + StringBuilder sb = new StringBuilder();
264.38 + String[] arr = new String[20];
264.39 + int i = 0;
264.40 + for (Constructor<?> m : StaticUse.class.getConstructors()) {
264.41 + arr[i++] = m.getName();
264.42 + }
264.43 + for (String s : sort(arr, i)) {
264.44 + sb.append(s).append("\n");
264.45 + }
264.46 + return sb.toString();
264.47 + }
264.48 +
264.49 @Compare public String namesOfDeclaringClassesOfMethods() {
264.50 StringBuilder sb = new StringBuilder();
264.51 String[] arr = new String[20];
264.52 @@ -223,6 +250,17 @@
264.53 }
264.54 }
264.55
264.56 + @Compare public int callAbst() throws Exception {
264.57 + class Impl extends Abst {
264.58 + @Override
264.59 + public int abst() {
264.60 + return 10;
264.61 + }
264.62 + }
264.63 + Abst impl = new Impl();
264.64 + return (int) Abst.class.getMethod("abst").invoke(impl);
264.65 + }
264.66 +
264.67 @Compare public String componentGetNameForObjectArray() {
264.68 return (new Object[3]).getClass().getComponentType().getName();
264.69 }
264.70 @@ -269,4 +307,7 @@
264.71 return VMTest.create(ReflectionTest.class);
264.72 }
264.73
264.74 + public static abstract class Abst {
264.75 + public abstract int abst();
264.76 + }
264.77 }
265.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
265.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/RegExpReplaceAllTest.java Wed Apr 30 15:04:10 2014 +0200
265.3 @@ -0,0 +1,54 @@
265.4 +/**
265.5 + * Back 2 Browser Bytecode Translator
265.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
265.7 + *
265.8 + * This program is free software: you can redistribute it and/or modify
265.9 + * it under the terms of the GNU General Public License as published by
265.10 + * the Free Software Foundation, version 2 of the License.
265.11 + *
265.12 + * This program is distributed in the hope that it will be useful,
265.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
265.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
265.15 + * GNU General Public License for more details.
265.16 + *
265.17 + * You should have received a copy of the GNU General Public License
265.18 + * along with this program. Look for COPYING file in the top folder.
265.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
265.20 + */
265.21 +package org.apidesign.bck2brwsr.tck;
265.22 +
265.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
265.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
265.25 +import org.testng.annotations.Factory;
265.26 +
265.27 +/**
265.28 + *
265.29 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
265.30 + */
265.31 +public class RegExpReplaceAllTest {
265.32 +
265.33 + @Compare public String replaceAll() {
265.34 + return "JavaScript".replaceAll("Script", "One");
265.35 + }
265.36 +
265.37 + @Compare public String replaceAllTwice() {
265.38 + return "Script JavaScript!".replaceAll("Script", "One");
265.39 + }
265.40 +
265.41 +
265.42 + @Compare public String replaceAllRegexp() {
265.43 + return "JavaScript".replaceAll("S....t", "One");
265.44 + }
265.45 +
265.46 + @Compare public String replaceAllRegexpTwice() {
265.47 + return "Script JavaScript!".replaceAll("S....t", "One");
265.48 + }
265.49 +
265.50 + @Compare public String replaceFirstRegexpOnly() {
265.51 + return "Script JavaScript!".replaceFirst("S....t", "One");
265.52 + }
265.53 +
265.54 + @Factory public static Object[] create() {
265.55 + return VMTest.create(RegExpReplaceAllTest.class);
265.56 + }
265.57 +}
266.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
266.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/RegExpSplitTest.java Wed Apr 30 15:04:10 2014 +0200
266.3 @@ -0,0 +1,54 @@
266.4 +/**
266.5 + * Back 2 Browser Bytecode Translator
266.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
266.7 + *
266.8 + * This program is free software: you can redistribute it and/or modify
266.9 + * it under the terms of the GNU General Public License as published by
266.10 + * the Free Software Foundation, version 2 of the License.
266.11 + *
266.12 + * This program is distributed in the hope that it will be useful,
266.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
266.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
266.15 + * GNU General Public License for more details.
266.16 + *
266.17 + * You should have received a copy of the GNU General Public License
266.18 + * along with this program. Look for COPYING file in the top folder.
266.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
266.20 + */
266.21 +package org.apidesign.bck2brwsr.tck;
266.22 +
266.23 +import java.util.Arrays;
266.24 +import org.apidesign.bck2brwsr.vmtest.Compare;
266.25 +import org.apidesign.bck2brwsr.vmtest.VMTest;
266.26 +import org.testng.annotations.Factory;
266.27 +
266.28 +/**
266.29 + *
266.30 + * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
266.31 + */
266.32 +public class RegExpSplitTest {
266.33 +
266.34 + public @Compare Object splitSpace() {
266.35 + return Arrays.asList("How are you today?".split(" "));
266.36 + }
266.37 +
266.38 + public @Compare String splitNewline() {
266.39 + return Arrays.toString("initializer must be able to complete normally".split("\n"));
266.40 + }
266.41 +
266.42 + public @Compare Object splitSpaceTrimMinusOne() {
266.43 + return Arrays.asList(" How are you today? ".split(" ", -1));
266.44 + }
266.45 +
266.46 + public @Compare Object splitSpaceTrimZero() {
266.47 + return Arrays.asList(" How are you today? ".split(" ", 0));
266.48 + }
266.49 +
266.50 + public @Compare Object splitSpaceLimit2() {
266.51 + return Arrays.asList("How are you today?".split(" ", 2));
266.52 + }
266.53 +
266.54 + @Factory public static Object[] create() {
266.55 + return VMTest.create(RegExpSplitTest.class);
266.56 + }
266.57 +}
267.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
267.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourceBundleTest.java Wed Apr 30 15:04:10 2014 +0200
267.3 @@ -0,0 +1,45 @@
267.4 +/**
267.5 + * Back 2 Browser Bytecode Translator
267.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
267.7 + *
267.8 + * This program is free software: you can redistribute it and/or modify
267.9 + * it under the terms of the GNU General Public License as published by
267.10 + * the Free Software Foundation, version 2 of the License.
267.11 + *
267.12 + * This program is distributed in the hope that it will be useful,
267.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
267.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
267.15 + * GNU General Public License for more details.
267.16 + *
267.17 + * You should have received a copy of the GNU General Public License
267.18 + * along with this program. Look for COPYING file in the top folder.
267.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
267.20 + */
267.21 +package org.apidesign.bck2brwsr.tck;
267.22 +
267.23 +import java.net.URL;
267.24 +import java.util.ResourceBundle;
267.25 +import org.apidesign.bck2brwsr.vmtest.Compare;
267.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
267.27 +import org.testng.annotations.Factory;
267.28 +
267.29 +/**
267.30 + *
267.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
267.32 + */
267.33 +public class ResourceBundleTest {
267.34 +
267.35 + @Compare public String readFromBundle() throws Exception {
267.36 + ResourceBundle b = ResourceBundle.getBundle("org/apidesign/bck2brwsr/tck/Bundle");
267.37 + return b.getString("KEY");
267.38 + }
267.39 +
267.40 + @Compare public String toURIFromURL() throws Exception {
267.41 + URL u = new URL("http://apidesign.org");
267.42 + return u.toURI().toString();
267.43 + }
267.44 +
267.45 + @Factory public static Object[] create() {
267.46 + return VMTest.create(ResourceBundleTest.class);
267.47 + }
267.48 +}
268.1 --- a/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Tue Apr 29 15:25:58 2014 +0200
268.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/ResourcesTest.java Wed Apr 30 15:04:10 2014 +0200
268.3 @@ -17,7 +17,10 @@
268.4 */
268.5 package org.apidesign.bck2brwsr.tck;
268.6
268.7 +import java.io.IOException;
268.8 import java.io.InputStream;
268.9 +import java.net.URL;
268.10 +import java.util.Enumeration;
268.11 import org.apidesign.bck2brwsr.vmtest.Compare;
268.12 import org.apidesign.bck2brwsr.vmtest.VMTest;
268.13 import org.testng.annotations.Factory;
268.14 @@ -27,17 +30,62 @@
268.15 * @author Jaroslav Tulach <jtulach@netbeans.org>
268.16 */
268.17 public class ResourcesTest {
268.18 + @Compare public String allManifests() throws Exception {
268.19 + Enumeration<URL> en = ClassLoader.getSystemResources("META-INF/MANIFEST.MF");
268.20 + assert en.hasMoreElements() : "Should have at least one manifest";
268.21 + String first = readString(en.nextElement().openStream());
268.22 + boolean different = false;
268.23 + int cnt = 1;
268.24 + while (en.hasMoreElements()) {
268.25 + URL url = en.nextElement();
268.26 + String now = readString(url.openStream());
268.27 + if (!first.equals(now)) {
268.28 + different = true;
268.29 + }
268.30 + cnt++;
268.31 + if (cnt > 500) {
268.32 + throw new IllegalStateException(
268.33 + "Giving up. First manifest:\n" + first +
268.34 + "\nLast manifest:\n" + now
268.35 + );
268.36 + }
268.37 + }
268.38 + assert different : "Not all manifests should look like first one:\n" + first;
268.39 + return "" + cnt;
268.40 + }
268.41
268.42 @Compare public String readResourceAsStream() throws Exception {
268.43 InputStream is = getClass().getResourceAsStream("Resources.txt");
268.44 - assert is != null : "The stream for Resources.txt should be found";
268.45 - byte[] b = new byte[30];
268.46 - int len = is.read(b);
268.47 + return readString(is);
268.48 + }
268.49 +
268.50 + @Compare public String readResourceViaConnection() throws Exception {
268.51 + InputStream is = getClass().getResource("Resources.txt").openConnection().getInputStream();
268.52 + return readString(is);
268.53 + }
268.54 +
268.55 + private String readString(InputStream is) throws IOException {
268.56 StringBuilder sb = new StringBuilder();
268.57 - for (int i = 0; i < len; i++) {
268.58 - sb.append((char)b[i]);
268.59 + byte[] b = new byte[512];
268.60 + for (;;) {
268.61 + int len = is.read(b);
268.62 + if (len == -1) {
268.63 + return sb.toString();
268.64 + }
268.65 + for (int i = 0; i < len; i++) {
268.66 + sb.append((char)b[i]);
268.67 + }
268.68 }
268.69 - return sb.toString();
268.70 + }
268.71 +
268.72 + @Compare public String readResourceAsStreamFromClassLoader() throws Exception {
268.73 + InputStream is = getClass().getClassLoader().getResourceAsStream("org/apidesign/bck2brwsr/tck/Resources.txt");
268.74 + return readString(is);
268.75 + }
268.76 +
268.77 + @Compare public String toURIFromURL() throws Exception {
268.78 + URL u = new URL("http://apidesign.org");
268.79 + return u.toURI().toString();
268.80 }
268.81
268.82 @Factory public static Object[] create() {
269.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
269.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/SystemTest.java Wed Apr 30 15:04:10 2014 +0200
269.3 @@ -0,0 +1,65 @@
269.4 +/**
269.5 + * Back 2 Browser Bytecode Translator
269.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
269.7 + *
269.8 + * This program is free software: you can redistribute it and/or modify
269.9 + * it under the terms of the GNU General Public License as published by
269.10 + * the Free Software Foundation, version 2 of the License.
269.11 + *
269.12 + * This program is distributed in the hope that it will be useful,
269.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
269.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
269.15 + * GNU General Public License for more details.
269.16 + *
269.17 + * You should have received a copy of the GNU General Public License
269.18 + * along with this program. Look for COPYING file in the top folder.
269.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
269.20 + */
269.21 +package org.apidesign.bck2brwsr.tck;
269.22 +
269.23 +import java.io.ByteArrayOutputStream;
269.24 +import java.io.PrintStream;
269.25 +import org.apidesign.bck2brwsr.core.ExtraJavaScript;
269.26 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
269.27 +import org.apidesign.bck2brwsr.vmtest.Compare;
269.28 +import org.apidesign.bck2brwsr.vmtest.VMTest;
269.29 +import org.testng.annotations.Factory;
269.30 +
269.31 +/**
269.32 + *
269.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
269.34 + */
269.35 +@ExtraJavaScript(resource = "/org/apidesign/bck2brwsr/tck/console.js")
269.36 +public class SystemTest {
269.37 + @Compare public boolean nonNullOSName() {
269.38 + return System.getProperty("os.name") != null;
269.39 + }
269.40 +
269.41 + @Compare public String captureStdOut() throws Exception {
269.42 + Object capture = initCapture();
269.43 + System.out.println("Ahoj");
269.44 + return textCapture(capture);
269.45 + }
269.46 +
269.47 + @JavaScriptBody(args = {}, body = ""
269.48 + + "var lines = [];"
269.49 + + "console.log = function(l) { lines.push(l); };"
269.50 + + "return lines;")
269.51 + Object initCapture() {
269.52 + ByteArrayOutputStream os = new ByteArrayOutputStream();
269.53 + PrintStream ps = new PrintStream(os);
269.54 +
269.55 + System.setOut(ps);
269.56 + return os;
269.57 + }
269.58 +
269.59 + @JavaScriptBody(args = { "o" }, body = "return o.join('');")
269.60 + String textCapture(Object o) throws java.io.IOException {
269.61 + ByteArrayOutputStream b = (ByteArrayOutputStream) o;
269.62 + return new String(b.toByteArray(), "UTF-8");
269.63 + }
269.64 +
269.65 + @Factory public static Object[] create() {
269.66 + return VMTest.create(SystemTest.class);
269.67 + }
269.68 +}
270.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
270.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/tck/TimerTest.java Wed Apr 30 15:04:10 2014 +0200
270.3 @@ -0,0 +1,81 @@
270.4 +/**
270.5 + * Back 2 Browser Bytecode Translator
270.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
270.7 + *
270.8 + * This program is free software: you can redistribute it and/or modify
270.9 + * it under the terms of the GNU General Public License as published by
270.10 + * the Free Software Foundation, version 2 of the License.
270.11 + *
270.12 + * This program is distributed in the hope that it will be useful,
270.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
270.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
270.15 + * GNU General Public License for more details.
270.16 + *
270.17 + * You should have received a copy of the GNU General Public License
270.18 + * along with this program. Look for COPYING file in the top folder.
270.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
270.20 + */
270.21 +package org.apidesign.bck2brwsr.tck;
270.22 +
270.23 +import java.util.Timer;
270.24 +import java.util.TimerTask;
270.25 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
270.26 +import org.apidesign.bck2brwsr.vmtest.VMTest;
270.27 +import org.testng.annotations.Factory;
270.28 +
270.29 +/**
270.30 + *
270.31 + * @author Jaroslav Tulach <jtulach@netbeans.org>
270.32 + */
270.33 +public class TimerTest {
270.34 + int miss;
270.35 + int exec;
270.36 +
270.37 + public TimerTest() {
270.38 + }
270.39 +
270.40 + @BrwsrTest public void scheduleTick() throws Exception {
270.41 + Timer t = new Timer("MyTest");
270.42 + class TT extends TimerTask {
270.43 + @Override
270.44 + public void run() {
270.45 + exec++;
270.46 + }
270.47 + }
270.48 + TT task = new TT();
270.49 + t.schedule(task, 15);
270.50 +
270.51 + if (exec == 0) {
270.52 + miss++;
270.53 + throw new InterruptedException();
270.54 + }
270.55 +
270.56 + assert exec == 1 : "One exec: " + exec;
270.57 + assert miss == 1 : "One miss: " + miss;
270.58 + }
270.59 +
270.60 + @BrwsrTest public void repeatedTicks() throws Exception {
270.61 + Timer t = new Timer("MyTest");
270.62 + class TT extends TimerTask {
270.63 + @Override
270.64 + public void run() {
270.65 + exec++;
270.66 + }
270.67 + }
270.68 + TT task = new TT();
270.69 + t.scheduleAtFixedRate(task, 15, 10);
270.70 +
270.71 + if (exec != 2) {
270.72 + miss++;
270.73 + throw new InterruptedException();
270.74 + }
270.75 +
270.76 + assert exec == 2 : "Two execs: " + exec;
270.77 + assert miss == 2 : "Two misses: " + miss;
270.78 + }
270.79 +
270.80 + @Factory public static Object[] create() {
270.81 + return VMTest.create(TimerTest.class);
270.82 + }
270.83 +
270.84 +}
271.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
271.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/HtmlAnnotations.java Wed Apr 30 15:04:10 2014 +0200
271.3 @@ -0,0 +1,86 @@
271.4 +/**
271.5 + * Back 2 Browser Bytecode Translator
271.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
271.7 + *
271.8 + * This program is free software: you can redistribute it and/or modify
271.9 + * it under the terms of the GNU General Public License as published by
271.10 + * the Free Software Foundation, version 2 of the License.
271.11 + *
271.12 + * This program is distributed in the hope that it will be useful,
271.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
271.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
271.15 + * GNU General Public License for more details.
271.16 + *
271.17 + * You should have received a copy of the GNU General Public License
271.18 + * along with this program. Look for COPYING file in the top folder.
271.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
271.20 + */
271.21 +package org.apidesign.bck2brwsr.vmtest.impl;
271.22 +
271.23 +import net.java.html.js.JavaScriptBody;
271.24 +import net.java.html.js.JavaScriptResource;
271.25 +
271.26 +/**
271.27 + *
271.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
271.29 + */
271.30 +@JavaScriptResource("htmlannotations.js")
271.31 +public class HtmlAnnotations {
271.32 + private Object callback;
271.33 +
271.34 +
271.35 + @JavaScriptBody(args = {}, body = "return 42;")
271.36 + public static int fourtyTwo() {
271.37 + return -1;
271.38 + }
271.39 +
271.40 + @JavaScriptBody(args = { "x", "y" }, body = "return mul(x, y);")
271.41 + public static native int useExternalMul(int x, int y);
271.42 +
271.43 + public static int callback() {
271.44 + final int[] arr = { 0 };
271.45 + callback(new Runnable() {
271.46 + @Override
271.47 + public void run() {
271.48 + arr[0]++;
271.49 + }
271.50 + });
271.51 + return arr[0];
271.52 + }
271.53 +
271.54 + @JavaScriptBody(args = { "r" }, javacall=true, body = "r.@java.lang.Runnable::run()()")
271.55 + private static native void callback(Runnable r);
271.56 +
271.57 + @JavaScriptBody(args = { }, javacall = true, body = "return @org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations::callback()();")
271.58 + public static native int staticCallback();
271.59 +
271.60 +
271.61 + protected long chooseLong(boolean takeFirst, boolean takeSecond, long first, long second) {
271.62 + long l = 0;
271.63 + if (takeFirst) l += first;
271.64 + if (takeSecond) l += second;
271.65 + return l;
271.66 + }
271.67 +
271.68 + protected void onError(Object obj) throws Exception {
271.69 + callback = obj;
271.70 + }
271.71 +
271.72 + Object getError() {
271.73 + return callback;
271.74 + }
271.75 +
271.76 + public static Object create() {
271.77 + return new HtmlAnnotations();
271.78 + }
271.79 + @JavaScriptBody(args = { "impl", "a", "b" }, javacall = true, body =
271.80 + "return impl.@org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations::chooseLong(ZZJJ)(true, false, a, b);"
271.81 + )
271.82 + public static native long first(Object impl, long a, long b);
271.83 +
271.84 + @JavaScriptBody(args = { "impl", "d" }, javacall = true, body =
271.85 + "impl.@org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations::onError(Ljava/lang/Object;)(d);" +
271.86 + "return impl.@org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations::getError()();"
271.87 + )
271.88 + public static native Double onError(Object impl, Double d);
271.89 +}
272.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
272.2 +++ b/rt/emul/compact/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/HtmlAnnotationsTest.java Wed Apr 30 15:04:10 2014 +0200
272.3 @@ -0,0 +1,71 @@
272.4 +/**
272.5 + * Back 2 Browser Bytecode Translator
272.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
272.7 + *
272.8 + * This program is free software: you can redistribute it and/or modify
272.9 + * it under the terms of the GNU General Public License as published by
272.10 + * the Free Software Foundation, version 2 of the License.
272.11 + *
272.12 + * This program is distributed in the hope that it will be useful,
272.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
272.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
272.15 + * GNU General Public License for more details.
272.16 + *
272.17 + * You should have received a copy of the GNU General Public License
272.18 + * along with this program. Look for COPYING file in the top folder.
272.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
272.20 + */
272.21 +package org.apidesign.bck2brwsr.vmtest.impl;
272.22 +
272.23 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
272.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
272.25 +import org.testng.annotations.Factory;
272.26 +
272.27 +/** Verify cooperation with net.java.html.js annotations.
272.28 + *
272.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
272.30 + */
272.31 +public class HtmlAnnotationsTest {
272.32 + @BrwsrTest public void fourtyTwo() throws Exception {
272.33 + assertEquals(HtmlAnnotations.fourtyTwo(), 42);
272.34 + }
272.35 +
272.36 + @BrwsrTest public void externalMul() throws Exception {
272.37 + assertEquals(HtmlAnnotations.useExternalMul(7, 6), 42);
272.38 + }
272.39 +
272.40 + @BrwsrTest public void callRunnableFromJS() throws Exception {
272.41 + assertEquals(HtmlAnnotations.callback(), 1);
272.42 + }
272.43 +
272.44 + @BrwsrTest public void callStaticMethodFromJS() throws Exception {
272.45 + assertEquals(HtmlAnnotations.staticCallback(), 1);
272.46 + }
272.47 +
272.48 + @BrwsrTest public void callbackWithFourParamsAndReturnType() throws Exception {
272.49 + Object instance = HtmlAnnotations.create();
272.50 + assertNotNull(instance, "Instance created");
272.51 + assertEquals(HtmlAnnotations.first(instance, 42, 31), 42);
272.52 + }
272.53 +
272.54 + @BrwsrTest public void callbackWithObjectParamsAndReturnType() throws Exception {
272.55 + Object instance = HtmlAnnotations.create();
272.56 + assertNotNull(instance, "Instance created");
272.57 + assertEquals(HtmlAnnotations.onError(instance, 42.0), 42.0);
272.58 + }
272.59 +
272.60 + private static void assertEquals(double real, double exp) {
272.61 + if (real - exp < 0.01) {
272.62 + return;
272.63 + }
272.64 + assert false : "Expecting " + exp + " but was " + real;
272.65 + }
272.66 +
272.67 + private static void assertNotNull(Object obj, String msg) {
272.68 + assert obj != null : msg;
272.69 + }
272.70 +
272.71 + @Factory public static Object[] create() {
272.72 + return VMTest.create(HtmlAnnotationsTest.class);
272.73 + }
272.74 +}
273.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
273.2 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/Bundle.properties Wed Apr 30 15:04:10 2014 +0200
273.3 @@ -0,0 +1,2 @@
273.4 +KEY=Value
273.5 +
274.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
274.2 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/tck/console.js Wed Apr 30 15:04:10 2014 +0200
274.3 @@ -0,0 +1,22 @@
274.4 +/**
274.5 + * Back 2 Browser Bytecode Translator
274.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
274.7 + *
274.8 + * This program is free software: you can redistribute it and/or modify
274.9 + * it under the terms of the GNU General Public License as published by
274.10 + * the Free Software Foundation, version 2 of the License.
274.11 + *
274.12 + * This program is distributed in the hope that it will be useful,
274.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
274.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
274.15 + * GNU General Public License for more details.
274.16 + *
274.17 + * You should have received a copy of the GNU General Public License
274.18 + * along with this program. Look for COPYING file in the top folder.
274.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
274.20 + */
274.21 +
274.22 +if (typeof console === 'undefined') {
274.23 + console = {};
274.24 +}
274.25 +
275.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
275.2 +++ b/rt/emul/compact/src/test/resources/org/apidesign/bck2brwsr/vmtest/impl/htmlannotations.js Wed Apr 30 15:04:10 2014 +0200
275.3 @@ -0,0 +1,20 @@
275.4 +/*
275.5 + * Back 2 Browser Bytecode Translator
275.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
275.7 + *
275.8 + * This program is free software: you can redistribute it and/or modify
275.9 + * it under the terms of the GNU General Public License as published by
275.10 + * the Free Software Foundation, version 2 of the License.
275.11 + *
275.12 + * This program is distributed in the hope that it will be useful,
275.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
275.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
275.15 + * GNU General Public License for more details.
275.16 + *
275.17 + * You should have received a copy of the GNU General Public License
275.18 + * along with this program. Look for COPYING file in the top folder.
275.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
275.20 + */
275.21 +
275.22 +function mul(x, y) { return x * y; }
275.23 +window.mul = mul;
276.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
276.2 +++ b/rt/emul/fake/pom.xml Wed Apr 30 15:04:10 2014 +0200
276.3 @@ -0,0 +1,28 @@
276.4 +<?xml version="1.0" encoding="UTF-8"?>
276.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
276.6 + <modelVersion>4.0.0</modelVersion>
276.7 + <parent>
276.8 + <groupId>org.apidesign.bck2brwsr</groupId>
276.9 + <artifactId>emul.pom</artifactId>
276.10 + <version>0.9-SNAPSHOT</version>
276.11 + </parent>
276.12 + <artifactId>fake</artifactId>
276.13 + <packaging>jar</packaging>
276.14 + <name>Fake Stubs of Java APIs</name>
276.15 + <description>
276.16 + The minimal emulation classes have certain references
276.17 + to less essential classes in the JDK. This module provides
276.18 + their stubs for purpose of compilation.
276.19 + </description>
276.20 + <build>
276.21 + <plugins>
276.22 + <plugin>
276.23 + <artifactId>maven-deploy-plugin</artifactId>
276.24 + <version>2.7</version>
276.25 + <configuration>
276.26 + <skip>true</skip>
276.27 + </configuration>
276.28 + </plugin>
276.29 + </plugins>
276.30 + </build>
276.31 +</project>
277.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
277.2 +++ b/rt/emul/fake/src/main/java/java/io/PrintStream.java Wed Apr 30 15:04:10 2014 +0200
277.3 @@ -0,0 +1,26 @@
277.4 +/**
277.5 + * Back 2 Browser Bytecode Translator
277.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
277.7 + *
277.8 + * This program is free software: you can redistribute it and/or modify
277.9 + * it under the terms of the GNU General Public License as published by
277.10 + * the Free Software Foundation, version 2 of the License.
277.11 + *
277.12 + * This program is distributed in the hope that it will be useful,
277.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
277.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
277.15 + * GNU General Public License for more details.
277.16 + *
277.17 + * You should have received a copy of the GNU General Public License
277.18 + * along with this program. Look for COPYING file in the top folder.
277.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
277.20 + */
277.21 +package java.io;
277.22 +
277.23 +/** Fake signature of an existing Java class.
277.24 + * @author Jaroslav Tulach
277.25 + */
277.26 +public abstract class PrintStream {
277.27 + public abstract void print(String s);
277.28 + public abstract void println(String s);
277.29 +}
278.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
278.2 +++ b/rt/emul/fake/src/main/java/java/io/PrintWriter.java Wed Apr 30 15:04:10 2014 +0200
278.3 @@ -0,0 +1,26 @@
278.4 +/**
278.5 + * Back 2 Browser Bytecode Translator
278.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
278.7 + *
278.8 + * This program is free software: you can redistribute it and/or modify
278.9 + * it under the terms of the GNU General Public License as published by
278.10 + * the Free Software Foundation, version 2 of the License.
278.11 + *
278.12 + * This program is distributed in the hope that it will be useful,
278.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
278.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
278.15 + * GNU General Public License for more details.
278.16 + *
278.17 + * You should have received a copy of the GNU General Public License
278.18 + * along with this program. Look for COPYING file in the top folder.
278.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
278.20 + */
278.21 +package java.io;
278.22 +
278.23 +/** Fake signature of an existing Java class.
278.24 + * @author Jaroslav Tulach
278.25 + */
278.26 +public abstract class PrintWriter {
278.27 + public abstract PrintWriter append(String s);
278.28 + public abstract void println(String s);
278.29 +}
279.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
279.2 +++ b/rt/emul/fake/src/main/java/java/net/URI.java Wed Apr 30 15:04:10 2014 +0200
279.3 @@ -0,0 +1,26 @@
279.4 +/**
279.5 + * Back 2 Browser Bytecode Translator
279.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
279.7 + *
279.8 + * This program is free software: you can redistribute it and/or modify
279.9 + * it under the terms of the GNU General Public License as published by
279.10 + * the Free Software Foundation, version 2 of the License.
279.11 + *
279.12 + * This program is distributed in the hope that it will be useful,
279.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
279.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
279.15 + * GNU General Public License for more details.
279.16 + *
279.17 + * You should have received a copy of the GNU General Public License
279.18 + * along with this program. Look for COPYING file in the top folder.
279.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
279.20 + */
279.21 +package java.net;
279.22 +
279.23 +/** Fake signature of an existing Java class.
279.24 + * @author Jaroslav Tulach
279.25 + */
279.26 +public class URI {
279.27 + public URI(String url) {
279.28 + }
279.29 +}
280.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
280.2 +++ b/rt/emul/fake/src/main/java/java/net/URISyntaxException.java Wed Apr 30 15:04:10 2014 +0200
280.3 @@ -0,0 +1,25 @@
280.4 +/**
280.5 + * Back 2 Browser Bytecode Translator
280.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
280.7 + *
280.8 + * This program is free software: you can redistribute it and/or modify
280.9 + * it under the terms of the GNU General Public License as published by
280.10 + * the Free Software Foundation, version 2 of the License.
280.11 + *
280.12 + * This program is distributed in the hope that it will be useful,
280.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
280.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
280.15 + * GNU General Public License for more details.
280.16 + *
280.17 + * You should have received a copy of the GNU General Public License
280.18 + * along with this program. Look for COPYING file in the top folder.
280.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
280.20 + */
280.21 +package java.net;
280.22 +
280.23 +/** Fake signature of an existing Java class.
280.24 + * @author Jaroslav Tulach
280.25 + */
280.26 +public class URISyntaxException extends Exception {
280.27 +
280.28 +}
281.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
281.2 +++ b/rt/emul/fake/src/main/java/java/net/URLConnection.java Wed Apr 30 15:04:10 2014 +0200
281.3 @@ -0,0 +1,33 @@
281.4 +/**
281.5 + * Back 2 Browser Bytecode Translator
281.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
281.7 + *
281.8 + * This program is free software: you can redistribute it and/or modify
281.9 + * it under the terms of the GNU General Public License as published by
281.10 + * the Free Software Foundation, version 2 of the License.
281.11 + *
281.12 + * This program is distributed in the hope that it will be useful,
281.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
281.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
281.15 + * GNU General Public License for more details.
281.16 + *
281.17 + * You should have received a copy of the GNU General Public License
281.18 + * along with this program. Look for COPYING file in the top folder.
281.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
281.20 + */
281.21 +package java.net;
281.22 +
281.23 +import java.io.IOException;
281.24 +import java.io.InputStream;
281.25 +
281.26 +/** Fake signature of an existing Java class.
281.27 + * @author Jaroslav Tulach
281.28 + */
281.29 +public abstract class URLConnection {
281.30 + protected URL url;
281.31 + public URLConnection(URL u) {
281.32 + }
281.33 + public abstract void connect() throws IOException;
281.34 + public abstract InputStream getInputStream() throws IOException;
281.35 +
281.36 +}
282.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
282.2 +++ b/rt/emul/fake/src/main/java/java/util/Locale.java Wed Apr 30 15:04:10 2014 +0200
282.3 @@ -0,0 +1,24 @@
282.4 +/**
282.5 + * Back 2 Browser Bytecode Translator
282.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
282.7 + *
282.8 + * This program is free software: you can redistribute it and/or modify
282.9 + * it under the terms of the GNU General Public License as published by
282.10 + * the Free Software Foundation, version 2 of the License.
282.11 + *
282.12 + * This program is distributed in the hope that it will be useful,
282.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
282.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
282.15 + * GNU General Public License for more details.
282.16 + *
282.17 + * You should have received a copy of the GNU General Public License
282.18 + * along with this program. Look for COPYING file in the top folder.
282.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
282.20 + */
282.21 +package java.util;
282.22 +
282.23 +/** Fake signature of an existing Java class.
282.24 + * @author Jaroslav Tulach
282.25 + */
282.26 +public abstract class Locale {
282.27 +}
283.1 --- a/rt/emul/mini/pom.xml Tue Apr 29 15:25:58 2014 +0200
283.2 +++ b/rt/emul/mini/pom.xml Wed Apr 30 15:04:10 2014 +0200
283.3 @@ -4,11 +4,11 @@
283.4 <parent>
283.5 <groupId>org.apidesign.bck2brwsr</groupId>
283.6 <artifactId>emul.pom</artifactId>
283.7 - <version>0.8-SNAPSHOT</version>
283.8 + <version>0.9-SNAPSHOT</version>
283.9 </parent>
283.10 <groupId>org.apidesign.bck2brwsr</groupId>
283.11 <artifactId>emul.mini</artifactId>
283.12 - <version>0.8-SNAPSHOT</version>
283.13 + <version>0.9-SNAPSHOT</version>
283.14 <name>Minimal API Profile</name>
283.15 <url>http://maven.apache.org</url>
283.16 <properties>
283.17 @@ -18,13 +18,19 @@
283.18 <dependency>
283.19 <groupId>org.apidesign.bck2brwsr</groupId>
283.20 <artifactId>core</artifactId>
283.21 - <version>0.8-SNAPSHOT</version>
283.22 + <version>0.9-SNAPSHOT</version>
283.23 + <type>jar</type>
283.24 + </dependency>
283.25 + <dependency>
283.26 + <groupId>org.apidesign.bck2brwsr</groupId>
283.27 + <artifactId>fake</artifactId>
283.28 + <version>0.9-SNAPSHOT</version>
283.29 + <scope>provided</scope>
283.30 <type>jar</type>
283.31 </dependency>
283.32 <dependency>
283.33 <groupId>org.testng</groupId>
283.34 <artifactId>testng</artifactId>
283.35 - <version>6.5.2</version>
283.36 <scope>test</scope>
283.37 </dependency>
283.38 </dependencies>
284.1 --- a/rt/emul/mini/src/main/java/java/lang/Character.java Tue Apr 29 15:25:58 2014 +0200
284.2 +++ b/rt/emul/mini/src/main/java/java/lang/Character.java Wed Apr 30 15:04:10 2014 +0200
284.3 @@ -572,6 +572,46 @@
284.4 */
284.5 public static final int MAX_CODE_POINT = 0X10FFFF;
284.6
284.7 + public static boolean isAlphabetic(int ch) {
284.8 + throw new UnsupportedOperationException("isAlphabetic: " + (char)ch);
284.9 + }
284.10 +
284.11 + public static boolean isIdeographic(int ch) {
284.12 + throw new UnsupportedOperationException("isIdeographic: " + (char)ch);
284.13 + }
284.14 +
284.15 + public static boolean isLowerCase(int ch) {
284.16 + throw new UnsupportedOperationException("isLowerCase: " + (char)ch);
284.17 + }
284.18 +
284.19 + public static boolean isUpperCase(int ch) {
284.20 + throw new UnsupportedOperationException("isUpperCase: " + (char)ch);
284.21 + }
284.22 +
284.23 + public static boolean isMirrored(int ch) {
284.24 + throw new UnsupportedOperationException("isMirrored: " + (char)ch);
284.25 + }
284.26 +
284.27 + public static boolean isIdentifierIgnorable(int ch) {
284.28 + throw new UnsupportedOperationException("isIdentifierIgnorable: " + (char)ch);
284.29 + }
284.30 +
284.31 + public static boolean isUnicodeIdentifierPart(int ch) {
284.32 + throw new UnsupportedOperationException("isUnicodeIdentifierPart: " + (char)ch);
284.33 + }
284.34 +
284.35 + public static boolean isUnicodeIdentifierStart(int ch) {
284.36 + throw new UnsupportedOperationException("isUnicodeIdentifierStart: " + (char)ch);
284.37 + }
284.38 +
284.39 + public static char toUpperCase(int ch) {
284.40 + throw new UnsupportedOperationException("toUpperCase: " + (char)ch);
284.41 + }
284.42 +
284.43 + public static int toLowerCase(int ch) {
284.44 + throw new UnsupportedOperationException("toLowerCase: " + (char)ch);
284.45 + }
284.46 +
284.47
284.48 /**
284.49 * Instances of this class represent particular subsets of the Unicode
284.50 @@ -1892,8 +1932,8 @@
284.51 return fromCodeChars(codePoint).matches("\\w");
284.52 }
284.53
284.54 - static int getType(int x) {
284.55 - throw new UnsupportedOperationException();
284.56 + public static int getType(int x) {
284.57 + throw new UnsupportedOperationException("getType: " + (char)x);
284.58 }
284.59
284.60 /**
284.61 @@ -1955,7 +1995,8 @@
284.62 public static boolean isJavaIdentifierStart(int codePoint) {
284.63 return
284.64 ('A' <= codePoint && codePoint <= 'Z') ||
284.65 - ('a' <= codePoint && codePoint <= 'z');
284.66 + ('a' <= codePoint && codePoint <= 'z') ||
284.67 + codePoint == '$';
284.68 }
284.69
284.70 /**
284.71 @@ -2298,6 +2339,10 @@
284.72 */
284.73 @Deprecated
284.74 public static boolean isSpace(char ch) {
284.75 + return isSpaceChar(ch);
284.76 + }
284.77 +
284.78 + public static boolean isSpaceChar(int ch) {
284.79 return (ch <= 0x0020) &&
284.80 (((((1L << 0x0009) |
284.81 (1L << 0x000A) |
284.82 @@ -2307,7 +2352,6 @@
284.83 }
284.84
284.85
284.86 -
284.87 /**
284.88 * Determines if the specified character is white space according to Java.
284.89 * A character is a Java whitespace character if and only if it satisfies
284.90 @@ -2372,7 +2416,14 @@
284.91 * @since 1.5
284.92 */
284.93 public static boolean isWhitespace(int codePoint) {
284.94 - throw new UnsupportedOperationException();
284.95 + // values up to 128: [9,10,11,12,13,28,29,30,31,32]
284.96 + if (9 <= codePoint && 13 >= codePoint) {
284.97 + return true;
284.98 + }
284.99 + if (28 <= codePoint && 32 >= codePoint) {
284.100 + return true;
284.101 + }
284.102 + return false;
284.103 }
284.104
284.105 /**
285.1 --- a/rt/emul/mini/src/main/java/java/lang/Class.java Tue Apr 29 15:25:58 2014 +0200
285.2 +++ b/rt/emul/mini/src/main/java/java/lang/Class.java Wed Apr 30 15:04:10 2014 +0200
285.3 @@ -26,14 +26,16 @@
285.4 package java.lang;
285.5
285.6 import java.io.ByteArrayInputStream;
285.7 -import org.apidesign.bck2brwsr.emul.reflect.AnnotationImpl;
285.8 import java.io.InputStream;
285.9 import java.lang.annotation.Annotation;
285.10 +import java.lang.reflect.Array;
285.11 +import java.lang.reflect.Constructor;
285.12 import java.lang.reflect.Field;
285.13 import java.lang.reflect.Method;
285.14 import java.lang.reflect.TypeVariable;
285.15 import java.net.URL;
285.16 import org.apidesign.bck2brwsr.core.JavaScriptBody;
285.17 +import org.apidesign.bck2brwsr.emul.reflect.AnnotationImpl;
285.18 import org.apidesign.bck2brwsr.emul.reflect.MethodImpl;
285.19
285.20 /**
285.21 @@ -155,11 +157,15 @@
285.22 }
285.23 return arrType;
285.24 }
285.25 - Class<?> c = loadCls(className, className.replace('.', '_'));
285.26 - if (c == null) {
285.27 - throw new ClassNotFoundException(className);
285.28 + try {
285.29 + Class<?> c = loadCls(className, className.replace('.', '_'));
285.30 + if (c == null) {
285.31 + throw new ClassNotFoundException(className);
285.32 + }
285.33 + return c;
285.34 + } catch (Throwable ex) {
285.35 + throw new ClassNotFoundException(className, ex);
285.36 }
285.37 - return c;
285.38 }
285.39
285.40
285.41 @@ -627,6 +633,20 @@
285.42 return getAccess();
285.43 }
285.44
285.45 + /**
285.46 + * If the class or interface represented by this {@code Class} object
285.47 + * is a member of another class, returns the {@code Class} object
285.48 + * representing the class in which it was declared. This method returns
285.49 + * null if this class or interface is not a member of any other class. If
285.50 + * this {@code Class} object represents an array class, a primitive
285.51 + * type, or void,then this method returns null.
285.52 + *
285.53 + * @return the declaring class for this class
285.54 + * @since JDK1.1
285.55 + */
285.56 + public Class<?> getDeclaringClass() {
285.57 + throw new SecurityException();
285.58 + }
285.59
285.60 /**
285.61 * Returns the simple name of the underlying class as given in the
285.62 @@ -971,6 +991,319 @@
285.63 }
285.64
285.65 /**
285.66 + * Returns an array of {@code Field} objects reflecting all the fields
285.67 + * declared by the class or interface represented by this
285.68 + * {@code Class} object. This includes public, protected, default
285.69 + * (package) access, and private fields, but excludes inherited fields.
285.70 + * The elements in the array returned are not sorted and are not in any
285.71 + * particular order. This method returns an array of length 0 if the class
285.72 + * or interface declares no fields, or if this {@code Class} object
285.73 + * represents a primitive type, an array class, or void.
285.74 + *
285.75 + * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
285.76 + *
285.77 + * @return the array of {@code Field} objects representing all the
285.78 + * declared fields of this class
285.79 + * @exception SecurityException
285.80 + * If a security manager, <i>s</i>, is present and any of the
285.81 + * following conditions is met:
285.82 + *
285.83 + * <ul>
285.84 + *
285.85 + * <li> invocation of
285.86 + * {@link SecurityManager#checkMemberAccess
285.87 + * s.checkMemberAccess(this, Member.DECLARED)} denies
285.88 + * access to the declared fields within this class
285.89 + *
285.90 + * <li> the caller's class loader is not the same as or an
285.91 + * ancestor of the class loader for the current class and
285.92 + * invocation of {@link SecurityManager#checkPackageAccess
285.93 + * s.checkPackageAccess()} denies access to the package
285.94 + * of this class
285.95 + *
285.96 + * </ul>
285.97 + *
285.98 + * @since JDK1.1
285.99 + */
285.100 + public Field[] getDeclaredFields() throws SecurityException {
285.101 + throw new SecurityException();
285.102 + }
285.103 +
285.104 + /**
285.105 + * <b>Bck2Brwsr</b> emulation can only seek public methods, otherwise it
285.106 + * throws a {@code SecurityException}.
285.107 + * <p>
285.108 + * Returns a {@code Method} object that reflects the specified
285.109 + * declared method of the class or interface represented by this
285.110 + * {@code Class} object. The {@code name} parameter is a
285.111 + * {@code String} that specifies the simple name of the desired
285.112 + * method, and the {@code parameterTypes} parameter is an array of
285.113 + * {@code Class} objects that identify the method's formal parameter
285.114 + * types, in declared order. If more than one method with the same
285.115 + * parameter types is declared in a class, and one of these methods has a
285.116 + * return type that is more specific than any of the others, that method is
285.117 + * returned; otherwise one of the methods is chosen arbitrarily. If the
285.118 + * name is "<init>"or "<clinit>" a {@code NoSuchMethodException}
285.119 + * is raised.
285.120 + *
285.121 + * @param name the name of the method
285.122 + * @param parameterTypes the parameter array
285.123 + * @return the {@code Method} object for the method of this class
285.124 + * matching the specified name and parameters
285.125 + * @exception NoSuchMethodException if a matching method is not found.
285.126 + * @exception NullPointerException if {@code name} is {@code null}
285.127 + * @exception SecurityException
285.128 + * If a security manager, <i>s</i>, is present and any of the
285.129 + * following conditions is met:
285.130 + *
285.131 + * <ul>
285.132 + *
285.133 + * <li> invocation of
285.134 + * {@link SecurityManager#checkMemberAccess
285.135 + * s.checkMemberAccess(this, Member.DECLARED)} denies
285.136 + * access to the declared method
285.137 + *
285.138 + * <li> the caller's class loader is not the same as or an
285.139 + * ancestor of the class loader for the current class and
285.140 + * invocation of {@link SecurityManager#checkPackageAccess
285.141 + * s.checkPackageAccess()} denies access to the package
285.142 + * of this class
285.143 + *
285.144 + * </ul>
285.145 + *
285.146 + * @since JDK1.1
285.147 + */
285.148 + public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
285.149 + throws NoSuchMethodException, SecurityException {
285.150 + try {
285.151 + return getMethod(name, parameterTypes);
285.152 + } catch (NoSuchMethodException ex) {
285.153 + throw new SecurityException();
285.154 + }
285.155 + }
285.156 +
285.157 + /**
285.158 + * Returns a {@code Field} object that reflects the specified declared
285.159 + * field of the class or interface represented by this {@code Class}
285.160 + * object. The {@code name} parameter is a {@code String} that
285.161 + * specifies the simple name of the desired field. Note that this method
285.162 + * will not reflect the {@code length} field of an array class.
285.163 + *
285.164 + * @param name the name of the field
285.165 + * @return the {@code Field} object for the specified field in this
285.166 + * class
285.167 + * @exception NoSuchFieldException if a field with the specified name is
285.168 + * not found.
285.169 + * @exception NullPointerException if {@code name} is {@code null}
285.170 + * @exception SecurityException
285.171 + * If a security manager, <i>s</i>, is present and any of the
285.172 + * following conditions is met:
285.173 + *
285.174 + * <ul>
285.175 + *
285.176 + * <li> invocation of
285.177 + * {@link SecurityManager#checkMemberAccess
285.178 + * s.checkMemberAccess(this, Member.DECLARED)} denies
285.179 + * access to the declared field
285.180 + *
285.181 + * <li> the caller's class loader is not the same as or an
285.182 + * ancestor of the class loader for the current class and
285.183 + * invocation of {@link SecurityManager#checkPackageAccess
285.184 + * s.checkPackageAccess()} denies access to the package
285.185 + * of this class
285.186 + *
285.187 + * </ul>
285.188 + *
285.189 + * @since JDK1.1
285.190 + */
285.191 + public Field getDeclaredField(String name)
285.192 + throws SecurityException {
285.193 + throw new SecurityException();
285.194 + }
285.195 +
285.196 + /**
285.197 + * Returns an array containing {@code Constructor} objects reflecting
285.198 + * all the public constructors of the class represented by this
285.199 + * {@code Class} object. An array of length 0 is returned if the
285.200 + * class has no public constructors, or if the class is an array class, or
285.201 + * if the class reflects a primitive type or void.
285.202 + *
285.203 + * Note that while this method returns an array of {@code
285.204 + * Constructor<T>} objects (that is an array of constructors from
285.205 + * this class), the return type of this method is {@code
285.206 + * Constructor<?>[]} and <em>not</em> {@code Constructor<T>[]} as
285.207 + * might be expected. This less informative return type is
285.208 + * necessary since after being returned from this method, the
285.209 + * array could be modified to hold {@code Constructor} objects for
285.210 + * different classes, which would violate the type guarantees of
285.211 + * {@code Constructor<T>[]}.
285.212 + *
285.213 + * @return the array of {@code Constructor} objects representing the
285.214 + * public constructors of this class
285.215 + * @exception SecurityException
285.216 + * If a security manager, <i>s</i>, is present and any of the
285.217 + * following conditions is met:
285.218 + *
285.219 + * <ul>
285.220 + *
285.221 + * <li> invocation of
285.222 + * {@link SecurityManager#checkMemberAccess
285.223 + * s.checkMemberAccess(this, Member.PUBLIC)} denies
285.224 + * access to the constructors within this class
285.225 + *
285.226 + * <li> the caller's class loader is not the same as or an
285.227 + * ancestor of the class loader for the current class and
285.228 + * invocation of {@link SecurityManager#checkPackageAccess
285.229 + * s.checkPackageAccess()} denies access to the package
285.230 + * of this class
285.231 + *
285.232 + * </ul>
285.233 + *
285.234 + * @since JDK1.1
285.235 + */
285.236 + public Constructor<?>[] getConstructors() throws SecurityException {
285.237 + return MethodImpl.findConstructors(this, 0x01);
285.238 + }
285.239 +
285.240 + /**
285.241 + * Returns a {@code Constructor} object that reflects the specified
285.242 + * public constructor of the class represented by this {@code Class}
285.243 + * object. The {@code parameterTypes} parameter is an array of
285.244 + * {@code Class} objects that identify the constructor's formal
285.245 + * parameter types, in declared order.
285.246 + *
285.247 + * If this {@code Class} object represents an inner class
285.248 + * declared in a non-static context, the formal parameter types
285.249 + * include the explicit enclosing instance as the first parameter.
285.250 + *
285.251 + * <p> The constructor to reflect is the public constructor of the class
285.252 + * represented by this {@code Class} object whose formal parameter
285.253 + * types match those specified by {@code parameterTypes}.
285.254 + *
285.255 + * @param parameterTypes the parameter array
285.256 + * @return the {@code Constructor} object of the public constructor that
285.257 + * matches the specified {@code parameterTypes}
285.258 + * @exception NoSuchMethodException if a matching method is not found.
285.259 + * @exception SecurityException
285.260 + * If a security manager, <i>s</i>, is present and any of the
285.261 + * following conditions is met:
285.262 + *
285.263 + * <ul>
285.264 + *
285.265 + * <li> invocation of
285.266 + * {@link SecurityManager#checkMemberAccess
285.267 + * s.checkMemberAccess(this, Member.PUBLIC)} denies
285.268 + * access to the constructor
285.269 + *
285.270 + * <li> the caller's class loader is not the same as or an
285.271 + * ancestor of the class loader for the current class and
285.272 + * invocation of {@link SecurityManager#checkPackageAccess
285.273 + * s.checkPackageAccess()} denies access to the package
285.274 + * of this class
285.275 + *
285.276 + * </ul>
285.277 + *
285.278 + * @since JDK1.1
285.279 + */
285.280 + public Constructor<T> getConstructor(Class<?>... parameterTypes)
285.281 + throws NoSuchMethodException, SecurityException {
285.282 + Constructor c = MethodImpl.findConstructor(this, parameterTypes);
285.283 + if (c == null) {
285.284 + StringBuilder sb = new StringBuilder();
285.285 + sb.append(getName()).append('(');
285.286 + String sep = "";
285.287 + for (int i = 0; i < parameterTypes.length; i++) {
285.288 + sb.append(sep).append(parameterTypes[i].getName());
285.289 + sep = ", ";
285.290 + }
285.291 + sb.append(')');
285.292 + throw new NoSuchMethodException(sb.toString());
285.293 + }
285.294 + return c;
285.295 + }
285.296 +
285.297 + /**
285.298 + * Returns an array of {@code Constructor} objects reflecting all the
285.299 + * constructors declared by the class represented by this
285.300 + * {@code Class} object. These are public, protected, default
285.301 + * (package) access, and private constructors. The elements in the array
285.302 + * returned are not sorted and are not in any particular order. If the
285.303 + * class has a default constructor, it is included in the returned array.
285.304 + * This method returns an array of length 0 if this {@code Class}
285.305 + * object represents an interface, a primitive type, an array class, or
285.306 + * void.
285.307 + *
285.308 + * <p> See <em>The Java Language Specification</em>, section 8.2.
285.309 + *
285.310 + * @return the array of {@code Constructor} objects representing all the
285.311 + * declared constructors of this class
285.312 + * @exception SecurityException
285.313 + * If a security manager, <i>s</i>, is present and any of the
285.314 + * following conditions is met:
285.315 + *
285.316 + * <ul>
285.317 + *
285.318 + * <li> invocation of
285.319 + * {@link SecurityManager#checkMemberAccess
285.320 + * s.checkMemberAccess(this, Member.DECLARED)} denies
285.321 + * access to the declared constructors within this class
285.322 + *
285.323 + * <li> the caller's class loader is not the same as or an
285.324 + * ancestor of the class loader for the current class and
285.325 + * invocation of {@link SecurityManager#checkPackageAccess
285.326 + * s.checkPackageAccess()} denies access to the package
285.327 + * of this class
285.328 + *
285.329 + * </ul>
285.330 + *
285.331 + * @since JDK1.1
285.332 + */
285.333 + public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
285.334 + throw new SecurityException();
285.335 + }
285.336 + /**
285.337 + * Returns a {@code Constructor} object that reflects the specified
285.338 + * constructor of the class or interface represented by this
285.339 + * {@code Class} object. The {@code parameterTypes} parameter is
285.340 + * an array of {@code Class} objects that identify the constructor's
285.341 + * formal parameter types, in declared order.
285.342 + *
285.343 + * If this {@code Class} object represents an inner class
285.344 + * declared in a non-static context, the formal parameter types
285.345 + * include the explicit enclosing instance as the first parameter.
285.346 + *
285.347 + * @param parameterTypes the parameter array
285.348 + * @return The {@code Constructor} object for the constructor with the
285.349 + * specified parameter list
285.350 + * @exception NoSuchMethodException if a matching method is not found.
285.351 + * @exception SecurityException
285.352 + * If a security manager, <i>s</i>, is present and any of the
285.353 + * following conditions is met:
285.354 + *
285.355 + * <ul>
285.356 + *
285.357 + * <li> invocation of
285.358 + * {@link SecurityManager#checkMemberAccess
285.359 + * s.checkMemberAccess(this, Member.DECLARED)} denies
285.360 + * access to the declared constructor
285.361 + *
285.362 + * <li> the caller's class loader is not the same as or an
285.363 + * ancestor of the class loader for the current class and
285.364 + * invocation of {@link SecurityManager#checkPackageAccess
285.365 + * s.checkPackageAccess()} denies access to the package
285.366 + * of this class
285.367 + *
285.368 + * </ul>
285.369 + *
285.370 + * @since JDK1.1
285.371 + */
285.372 + public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
285.373 + throws NoSuchMethodException, SecurityException {
285.374 + return getConstructor(parameterTypes);
285.375 + }
285.376 +
285.377 +
285.378 + /**
285.379 * Character.isDigit answers {@code true} to some non-ascii
285.380 * digits. This one does not.
285.381 */
285.382 @@ -1047,15 +1380,10 @@
285.383 */
285.384 public InputStream getResourceAsStream(String name) {
285.385 name = resolveName(name);
285.386 - byte[] arr = getResourceAsStream0(name);
285.387 + byte[] arr = ClassLoader.getResourceAsStream0(name, 0);
285.388 return arr == null ? null : new ByteArrayInputStream(arr);
285.389 }
285.390 -
285.391 - @JavaScriptBody(args = "name", body =
285.392 - "return (vm.loadBytes) ? vm.loadBytes(name) : null;"
285.393 - )
285.394 - private static native byte[] getResourceAsStream0(String name);
285.395 -
285.396 +
285.397 /**
285.398 * Finds a resource with a given name. The rules for searching resources
285.399 * associated with a given class are implemented by the defining
285.400 @@ -1091,8 +1419,11 @@
285.401 * @since JDK1.1
285.402 */
285.403 public java.net.URL getResource(String name) {
285.404 - InputStream is = getResourceAsStream(name);
285.405 - return is == null ? null : newResourceURL(URL.class, "res:/" + name, is);
285.406 + return newResourceURL(name, getResourceAsStream(name));
285.407 + }
285.408 +
285.409 + static URL newResourceURL(String name, InputStream is) {
285.410 + return is == null ? null : newResourceURL0(URL.class, "res:/" + name, is);
285.411 }
285.412
285.413 @JavaScriptBody(args = { "url", "spec", "is" }, body =
285.414 @@ -1100,7 +1431,7 @@
285.415 + "u.constructor.cons__VLjava_lang_String_2Ljava_io_InputStream_2.call(u, spec, is);\n"
285.416 + "return u;"
285.417 )
285.418 - private static native URL newResourceURL(Class<URL> url, String spec, InputStream is);
285.419 + private static native URL newResourceURL0(Class<URL> url, String spec, InputStream is);
285.420
285.421 /**
285.422 * Add a package name prefix if the name is not absolute Remove leading "/"
285.423 @@ -1154,7 +1485,7 @@
285.424 * @see java.lang.RuntimePermission
285.425 */
285.426 public ClassLoader getClassLoader() {
285.427 - throw new SecurityException();
285.428 + return ClassLoader.getSystemClassLoader();
285.429 }
285.430
285.431 /**
285.432 @@ -1331,9 +1662,11 @@
285.433
285.434 @JavaScriptBody(args = { "ac" },
285.435 body =
285.436 - "if (this.anno) {"
285.437 - + " return this.anno['L' + ac.jvmName + ';'];"
285.438 - + "} else return null;"
285.439 + "if (this.anno) {\n"
285.440 + + " var r = this.anno['L' + ac.jvmName + ';'];\n"
285.441 + + " if (typeof r === 'undefined') r = null;\n"
285.442 + + " return r;\n"
285.443 + + "} else return null;\n"
285.444 )
285.445 private Object getAnnotationData(Class<?> annotationClass) {
285.446 throw new UnsupportedOperationException();
285.447 @@ -1395,4 +1728,50 @@
285.448 "return vm.desiredAssertionStatus ? vm.desiredAssertionStatus : false;"
285.449 )
285.450 public native boolean desiredAssertionStatus();
285.451 +
285.452 + static void registerNatives() {
285.453 + boolean assertsOn = false;
285.454 + // assert assertsOn = true;
285.455 + if (assertsOn) {
285.456 + try {
285.457 + Array.get(null, 0);
285.458 + } catch (Throwable ex) {
285.459 + // ignore
285.460 + }
285.461 + }
285.462 + }
285.463 +
285.464 + @JavaScriptBody(args = {}, body = "var p = vm.java_lang_Object(false);"
285.465 + + "p.toString = function() { return this.toString__Ljava_lang_String_2(); };"
285.466 + )
285.467 + static native void registerToString();
285.468 +
285.469 + @JavaScriptBody(args = {"self"}, body
285.470 + = "var c = self.constructor.$class;\n"
285.471 + + "return c ? c : null;\n"
285.472 + )
285.473 + static native Class<?> classFor(Object self);
285.474 +
285.475 + @JavaScriptBody(args = { "self" }, body
285.476 + = "if (self.$hashCode) return self.$hashCode;\n"
285.477 + + "var h = self.computeHashCode__I ? self.computeHashCode__I() : Math.random() * Math.pow(2, 31);\n"
285.478 + + "return self.$hashCode = h & h;"
285.479 + )
285.480 + static native int defaultHashCode(Object self);
285.481 +
285.482 + @JavaScriptBody(args = "self", body
285.483 + = "\nif (!self['$instOf_java_lang_Cloneable']) {"
285.484 + + "\n return null;"
285.485 + + "\n} else {"
285.486 + + "\n var clone = self.constructor(true);"
285.487 + + "\n var props = Object.getOwnPropertyNames(self);"
285.488 + + "\n for (var i = 0; i < props.length; i++) {"
285.489 + + "\n var p = props[i];"
285.490 + + "\n clone[p] = self[p];"
285.491 + + "\n };"
285.492 + + "\n return clone;"
285.493 + + "\n}"
285.494 + )
285.495 + static native Object clone(Object self) throws CloneNotSupportedException;
285.496 +
285.497 }
286.1 --- a/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Tue Apr 29 15:25:58 2014 +0200
286.2 +++ b/rt/emul/mini/src/main/java/java/lang/ClassLoader.java Wed Apr 30 15:04:10 2014 +0200
286.3 @@ -24,6 +24,7 @@
286.4 */
286.5 package java.lang;
286.6
286.7 +import java.io.ByteArrayInputStream;
286.8 import java.io.InputStream;
286.9 import java.io.IOException;
286.10 import java.net.URL;
286.11 @@ -180,7 +181,7 @@
286.12 * @since 1.2
286.13 */
286.14 protected ClassLoader(ClassLoader parent) {
286.15 - throw new SecurityException();
286.16 + this.parent = parent;
286.17 }
286.18
286.19 /**
286.20 @@ -199,7 +200,7 @@
286.21 * of a new class loader.
286.22 */
286.23 protected ClassLoader() {
286.24 - throw new SecurityException();
286.25 + this.parent = null;
286.26 }
286.27
286.28 // -- Class --
286.29 @@ -845,8 +846,27 @@
286.30 * @revised 1.4
286.31 */
286.32 public static ClassLoader getSystemClassLoader() {
286.33 - throw new SecurityException();
286.34 + if (SYSTEM == null) {
286.35 + SYSTEM = new ClassLoader() {
286.36 + @Override
286.37 + protected Enumeration<URL> findResources(String name) throws IOException {
286.38 + return getBootstrapResources(name);
286.39 + }
286.40 +
286.41 + @Override
286.42 + protected URL findResource(String name) {
286.43 + return getBootstrapResource(name);
286.44 + }
286.45 +
286.46 + @Override
286.47 + protected Class<?> findClass(String name) throws ClassNotFoundException {
286.48 + return Class.forName(name);
286.49 + }
286.50 + };
286.51 + }
286.52 + return SYSTEM;
286.53 }
286.54 + private static ClassLoader SYSTEM;
286.55
286.56 // Returns true if the specified class loader can be found in this class
286.57 // loader's delegation chain.
286.58 @@ -870,12 +890,48 @@
286.59 }
286.60
286.61 private static URL getBootstrapResource(String name) {
286.62 - throw new UnsupportedOperationException();
286.63 + return Object.class.getResource("/" + name);
286.64 }
286.65
286.66 + @JavaScriptBody(args = { "name", "skip" }, body
286.67 + = "return (vm.loadBytes) ? vm.loadBytes(name, skip) : null;"
286.68 + )
286.69 + static native byte[] getResourceAsStream0(String name, int skip);
286.70 +
286.71 private static Enumeration<URL> getBootstrapResources(String name) {
286.72 - URL u = Object.class.getResource("/" + name);
286.73 - return new OneOrZeroEnum(u);
286.74 + return new ResEnum(name);
286.75 + }
286.76 +
286.77 + private static class ResEnum implements Enumeration<URL> {
286.78 + private final String name;
286.79 + private URL next;
286.80 + private int skip;
286.81 +
286.82 + public ResEnum(String name) {
286.83 + this.name = name;
286.84 + }
286.85 +
286.86 +
286.87 + public boolean hasMoreElements() {
286.88 + if (next == null && skip >= 0) {
286.89 + byte[] arr = getResourceAsStream0(name, skip++);
286.90 + if (arr != null) {
286.91 + next = Class.newResourceURL(name, new ByteArrayInputStream(arr));
286.92 + } else {
286.93 + skip = -1;
286.94 + }
286.95 + }
286.96 + return next != null;
286.97 + }
286.98 +
286.99 + public URL nextElement() {
286.100 + URL r = next;
286.101 + if (r == null) {
286.102 + throw new NoSuchElementException();
286.103 + }
286.104 + next = null;
286.105 + return r;
286.106 + }
286.107 }
286.108
286.109 private static class OneOrZeroEnum implements Enumeration<URL> {
286.110 @@ -910,7 +966,7 @@
286.111 }
286.112
286.113 public boolean hasMoreElements() {
286.114 - if (next == null) {
286.115 + if (next == null && index < arr.length) {
286.116 if (arr[index].hasMoreElements()) {
286.117 next = (URL) arr[index].nextElement();
286.118 } else {
287.1 --- a/rt/emul/mini/src/main/java/java/lang/Double.java Tue Apr 29 15:25:58 2014 +0200
287.2 +++ b/rt/emul/mini/src/main/java/java/lang/Double.java Wed Apr 30 15:04:10 2014 +0200
287.3 @@ -502,10 +502,8 @@
287.4 * @throws NumberFormatException if the string does not contain a
287.5 * parsable number.
287.6 */
287.7 - @JavaScriptBody(args="s", body="return parseFloat(s);")
287.8 public static Double valueOf(String s) throws NumberFormatException {
287.9 - throw new UnsupportedOperationException();
287.10 -// return new Double(FloatingDecimal.readJavaFormatString(s).doubleValue());
287.11 + return new Double(parseDouble(s));
287.12 }
287.13
287.14 /**
287.15 @@ -542,8 +540,7 @@
287.16 */
287.17 @JavaScriptBody(args="s", body="return parseFloat(s);")
287.18 public static double parseDouble(String s) throws NumberFormatException {
287.19 - throw new UnsupportedOperationException();
287.20 -// return FloatingDecimal.readJavaFormatString(s).doubleValue();
287.21 + return 0;
287.22 }
287.23
287.24 /**
288.1 --- a/rt/emul/mini/src/main/java/java/lang/Enum.java Tue Apr 29 15:25:58 2014 +0200
288.2 +++ b/rt/emul/mini/src/main/java/java/lang/Enum.java Wed Apr 30 15:04:10 2014 +0200
288.3 @@ -235,7 +235,7 @@
288.4 throw new IllegalArgumentException();
288.5 }
288.6
288.7 - @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.$VALUES;")
288.8 + @JavaScriptBody(args = { "enumType" }, body = "return enumType.cnstr.fld_$VALUES;")
288.9 private static native Object[] values(Class<?> enumType);
288.10
288.11 /**
289.1 --- a/rt/emul/mini/src/main/java/java/lang/Float.java Tue Apr 29 15:25:58 2014 +0200
289.2 +++ b/rt/emul/mini/src/main/java/java/lang/Float.java Wed Apr 30 15:04:10 2014 +0200
289.3 @@ -412,8 +412,7 @@
289.4 * parsable number.
289.5 */
289.6 public static Float valueOf(String s) throws NumberFormatException {
289.7 - throw new UnsupportedOperationException();
289.8 -// return new Float(FloatingDecimal.readJavaFormatString(s).floatValue());
289.9 + return new Float(parseFloat(s));
289.10 }
289.11
289.12 /**
289.13 @@ -447,9 +446,9 @@
289.14 * @see java.lang.Float#valueOf(String)
289.15 * @since 1.2
289.16 */
289.17 + @JavaScriptBody(args="s", body="return parseFloat(s);")
289.18 public static float parseFloat(String s) throws NumberFormatException {
289.19 - throw new UnsupportedOperationException();
289.20 -// return FloatingDecimal.readJavaFormatString(s).floatValue();
289.21 + return 0;
289.22 }
289.23
289.24 /**
290.1 --- a/rt/emul/mini/src/main/java/java/lang/Object.java Tue Apr 29 15:25:58 2014 +0200
290.2 +++ b/rt/emul/mini/src/main/java/java/lang/Object.java Wed Apr 30 15:04:10 2014 +0200
290.3 @@ -25,7 +25,6 @@
290.4
290.5 package java.lang;
290.6
290.7 -import java.lang.reflect.Array;
290.8 import org.apidesign.bck2brwsr.core.JavaScriptBody;
290.9 import org.apidesign.bck2brwsr.core.JavaScriptPrototype;
290.10
290.11 @@ -40,23 +39,9 @@
290.12 */
290.13 @JavaScriptPrototype(container = "Object.prototype", prototype = "new Object")
290.14 public class Object {
290.15 -
290.16 - private static void registerNatives() {
290.17 - boolean assertsOn = false;
290.18 - assert assertsOn = false;
290.19 - if (assertsOn) try {
290.20 - Array.get(null, 0);
290.21 - } catch (Throwable ex) {
290.22 - // ignore
290.23 - }
290.24 - }
290.25 - @JavaScriptBody(args = {}, body = "var p = vm.java_lang_Object(false);" +
290.26 - "p.toString = function() { return this.toString__Ljava_lang_String_2(); };"
290.27 - )
290.28 - private static native void registerToString();
290.29 static {
290.30 - registerNatives();
290.31 - registerToString();
290.32 + Class.registerNatives();
290.33 + Class.registerToString();
290.34 }
290.35
290.36 /**
290.37 @@ -79,8 +64,10 @@
290.38 * @see Class Literals, section 15.8.2 of
290.39 * <cite>The Java™ Language Specification</cite>.
290.40 */
290.41 - @JavaScriptBody(args={}, body="return this.constructor.$class;")
290.42 - public final native Class<?> getClass();
290.43 + public final Class<?> getClass() {
290.44 + Class<?> c = Class.classFor(this);
290.45 + return c == null ? Object.class : c;
290.46 + }
290.47
290.48 /**
290.49 * Returns a hash code value for the object. This method is
290.50 @@ -117,16 +104,10 @@
290.51 * @see java.lang.Object#equals(java.lang.Object)
290.52 * @see java.lang.System#identityHashCode
290.53 */
290.54 - @JavaScriptBody(args = {}, body =
290.55 - "if (this.$hashCode) return this.$hashCode;\n"
290.56 - + "var h = this.computeHashCode__I();\n"
290.57 - + "return this.$hashCode = h & h;"
290.58 - )
290.59 - public native int hashCode();
290.60 + public int hashCode() {
290.61 + return Class.defaultHashCode(this);
290.62 + }
290.63
290.64 - @JavaScriptBody(args = {}, body = "return Math.random() * Math.pow(2, 32);")
290.65 - native int computeHashCode();
290.66 -
290.67 /**
290.68 * Indicates whether some other object is "equal to" this one.
290.69 * <p>
290.70 @@ -238,28 +219,13 @@
290.71 * @see java.lang.Cloneable
290.72 */
290.73 protected Object clone() throws CloneNotSupportedException {
290.74 - Object ret = clone(this);
290.75 + Object ret = Class.clone(this);
290.76 if (ret == null) {
290.77 throw new CloneNotSupportedException(getClass().getName());
290.78 }
290.79 return ret;
290.80 }
290.81
290.82 - @JavaScriptBody(args = "self", body =
290.83 - "\nif (!self['$instOf_java_lang_Cloneable']) {"
290.84 - + "\n return null;"
290.85 - + "\n} else {"
290.86 - + "\n var clone = self.constructor(true);"
290.87 - + "\n var props = Object.getOwnPropertyNames(self);"
290.88 - + "\n for (var i = 0; i < props.length; i++) {"
290.89 - + "\n var p = props[i];"
290.90 - + "\n clone[p] = self[p];"
290.91 - + "\n };"
290.92 - + "\n return clone;"
290.93 - + "\n}"
290.94 - )
290.95 - private static native Object clone(Object self) throws CloneNotSupportedException;
290.96 -
290.97 /**
290.98 * Returns a string representation of the object. In general, the
290.99 * {@code toString} method returns a string that
290.100 @@ -317,7 +283,8 @@
290.101 * @see java.lang.Object#notifyAll()
290.102 * @see java.lang.Object#wait()
290.103 */
290.104 - public final native void notify();
290.105 + public final void notify() {
290.106 + }
290.107
290.108 /**
290.109 * Wakes up all threads that are waiting on this object's monitor. A
290.110 @@ -341,7 +308,8 @@
290.111 * @see java.lang.Object#notify()
290.112 * @see java.lang.Object#wait()
290.113 */
290.114 - public final native void notifyAll();
290.115 + public final void notifyAll() {
290.116 + }
290.117
290.118 /**
290.119 * Causes the current thread to wait until either another thread invokes the
290.120 @@ -428,7 +396,9 @@
290.121 * @see java.lang.Object#notify()
290.122 * @see java.lang.Object#notifyAll()
290.123 */
290.124 - public final native void wait(long timeout) throws InterruptedException;
290.125 + public final void wait(long timeout) throws InterruptedException {
290.126 + throw new InterruptedException();
290.127 + }
290.128
290.129 /**
290.130 * Causes the current thread to wait until another thread invokes the
290.131 @@ -493,20 +463,7 @@
290.132 * this exception is thrown.
290.133 */
290.134 public final void wait(long timeout, int nanos) throws InterruptedException {
290.135 - if (timeout < 0) {
290.136 - throw new IllegalArgumentException("timeout value is negative");
290.137 - }
290.138 -
290.139 - if (nanos < 0 || nanos > 999999) {
290.140 - throw new IllegalArgumentException(
290.141 - "nanosecond timeout value out of range");
290.142 - }
290.143 -
290.144 - if (nanos >= 500000 || (nanos != 0 && timeout == 0)) {
290.145 - timeout++;
290.146 - }
290.147 -
290.148 - wait(timeout);
290.149 + throw new InterruptedException();
290.150 }
290.151
290.152 /**
290.153 @@ -548,7 +505,7 @@
290.154 * @see java.lang.Object#notifyAll()
290.155 */
290.156 public final void wait() throws InterruptedException {
290.157 - wait(0);
290.158 + throw new InterruptedException();
290.159 }
290.160
290.161 /**
291.1 --- a/rt/emul/mini/src/main/java/java/lang/String.java Tue Apr 29 15:25:58 2014 +0200
291.2 +++ b/rt/emul/mini/src/main/java/java/lang/String.java Wed Apr 30 15:04:10 2014 +0200
291.3 @@ -26,7 +26,10 @@
291.4 package java.lang;
291.5
291.6 import java.io.UnsupportedEncodingException;
291.7 +import java.lang.reflect.InvocationTargetException;
291.8 +import java.lang.reflect.Method;
291.9 import java.util.Comparator;
291.10 +import java.util.Locale;
291.11 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
291.12 import org.apidesign.bck2brwsr.core.JavaScriptBody;
291.13 import org.apidesign.bck2brwsr.core.JavaScriptOnly;
291.14 @@ -2097,13 +2100,31 @@
291.15 * @since 1.4
291.16 * @spec JSR-51
291.17 */
291.18 + public boolean matches(String regex) {
291.19 + try {
291.20 + return matchesViaJS(regex);
291.21 + } catch (Throwable t) {
291.22 + // fallback to classical behavior
291.23 + try {
291.24 + Method m = Class.forName("java.util.regex.Pattern").getMethod("matches", String.class, CharSequence.class);
291.25 + return (Boolean)m.invoke(null, regex, this);
291.26 + } catch (InvocationTargetException ex) {
291.27 + if (ex.getTargetException() instanceof RuntimeException) {
291.28 + throw (RuntimeException)ex.getTargetException();
291.29 + }
291.30 + } catch (Throwable another) {
291.31 + // will report the old one
291.32 + }
291.33 + throw new RuntimeException(t);
291.34 + }
291.35 + }
291.36 @JavaScriptBody(args = { "regex" }, body =
291.37 "var self = this.toString();\n"
291.38 + "var re = new RegExp(regex.toString());\n"
291.39 + "var r = re.exec(self);\n"
291.40 + "return r != null && r.length > 0 && self.length == r[0].length;"
291.41 )
291.42 - public boolean matches(String regex) {
291.43 + private boolean matchesViaJS(String regex) {
291.44 throw new UnsupportedOperationException();
291.45 }
291.46
291.47 @@ -2159,6 +2180,14 @@
291.48 * @since 1.4
291.49 * @spec JSR-51
291.50 */
291.51 + @JavaScriptBody(args = { "regex", "newText" }, body =
291.52 + "var self = this.toString();\n"
291.53 + + "var re = new RegExp(regex.toString());\n"
291.54 + + "var r = re.exec(self);\n"
291.55 + + "if (r === null || r.length === 0) return this;\n"
291.56 + + "var from = self.indexOf(r[0]);\n"
291.57 + + "return this.substring(0, from) + newText + this.substring(from + r[0].length);\n"
291.58 + )
291.59 public String replaceFirst(String regex, String replacement) {
291.60 throw new UnsupportedOperationException();
291.61 }
291.62 @@ -2203,7 +2232,14 @@
291.63 * @spec JSR-51
291.64 */
291.65 public String replaceAll(String regex, String replacement) {
291.66 - throw new UnsupportedOperationException();
291.67 + String p = this;
291.68 + for (;;) {
291.69 + String n = p.replaceFirst(regex, replacement);
291.70 + if (n == p) {
291.71 + return n;
291.72 + }
291.73 + p = n;
291.74 + }
291.75 }
291.76
291.77 /**
291.78 @@ -2224,12 +2260,14 @@
291.79 "var s = this.toString();\n"
291.80 + "target = target.toString();\n"
291.81 + "replacement = replacement.toString();\n"
291.82 + + "var pos = 0;\n"
291.83 + "for (;;) {\n"
291.84 - + " var ret = s.replace(target, replacement);\n"
291.85 - + " if (ret === s) {\n"
291.86 - + " return ret;\n"
291.87 + + " var indx = s.indexOf(target, pos);\n"
291.88 + + " if (indx === -1) {\n"
291.89 + + " return s;\n"
291.90 + " }\n"
291.91 - + " s = ret;\n"
291.92 + + " pos = indx + replacement.length;\n"
291.93 + + " s = s.substring(0, indx) + replacement + s.substring(indx + target.length);\n"
291.94 + "}"
291.95 )
291.96 public native String replace(CharSequence target, CharSequence replacement);
291.97 @@ -2315,8 +2353,35 @@
291.98 * @spec JSR-51
291.99 */
291.100 public String[] split(String regex, int limit) {
291.101 - throw new UnsupportedOperationException("Needs regexp");
291.102 + if (limit <= 0) {
291.103 + Object[] arr = splitImpl(this, regex, Integer.MAX_VALUE);
291.104 + int to = arr.length;
291.105 + if (limit == 0 && to > 0) {
291.106 + while (to > 0 && ((String)arr[--to]).isEmpty()) {
291.107 + }
291.108 + to++;
291.109 + }
291.110 + String[] ret = new String[to];
291.111 + System.arraycopy(arr, 0, ret, 0, to);
291.112 + return ret;
291.113 + } else {
291.114 + Object[] arr = splitImpl(this, regex, limit);
291.115 + String[] ret = new String[arr.length];
291.116 + int pos = 0;
291.117 + for (int i = 0; i < arr.length; i++) {
291.118 + final String s = (String)arr[i];
291.119 + ret[i] = s;
291.120 + pos = indexOf(s, pos) + s.length();
291.121 + }
291.122 + ret[arr.length - 1] += substring(pos);
291.123 + return ret;
291.124 + }
291.125 }
291.126 +
291.127 + @JavaScriptBody(args = { "str", "regex", "limit"}, body =
291.128 + "return str.split(new RegExp(regex), limit);"
291.129 + )
291.130 + private static native Object[] splitImpl(String str, String regex, int limit);
291.131
291.132 /**
291.133 * Splits this string around matches of the given <a
291.134 @@ -2412,7 +2477,9 @@
291.135 * @see java.lang.String#toUpperCase(Locale)
291.136 * @since 1.1
291.137 */
291.138 -// public String toLowerCase(Locale locale) {
291.139 + public String toLowerCase(java.util.Locale locale) {
291.140 + return toLowerCase();
291.141 + }
291.142 // if (locale == null) {
291.143 // throw new NullPointerException();
291.144 // }
291.145 @@ -2527,7 +2594,7 @@
291.146 */
291.147 @JavaScriptBody(args = {}, body = "return this.toLowerCase();")
291.148 public String toLowerCase() {
291.149 - throw new UnsupportedOperationException("Should be supported but without connection to locale");
291.150 + return null;
291.151 }
291.152
291.153 /**
291.154 @@ -2578,8 +2645,10 @@
291.155 * @see java.lang.String#toLowerCase(Locale)
291.156 * @since 1.1
291.157 */
291.158 + public String toUpperCase(Locale locale) {
291.159 + return toUpperCase();
291.160 + }
291.161 /* not for javascript
291.162 - public String toUpperCase(Locale locale) {
291.163 if (locale == null) {
291.164 throw new NullPointerException();
291.165 }
291.166 @@ -2693,7 +2762,7 @@
291.167 */
291.168 @JavaScriptBody(args = {}, body = "return this.toUpperCase();")
291.169 public String toUpperCase() {
291.170 - throw new UnsupportedOperationException();
291.171 + return null;
291.172 }
291.173
291.174 /**
291.175 @@ -2804,7 +2873,7 @@
291.176 * @since 1.5
291.177 */
291.178 public static String format(String format, Object ... args) {
291.179 - throw new UnsupportedOperationException();
291.180 + return format((Locale)null, format, args);
291.181 }
291.182
291.183 /**
291.184 @@ -2847,9 +2916,15 @@
291.185 * @see java.util.Formatter
291.186 * @since 1.5
291.187 */
291.188 -// public static String format(Locale l, String format, Object ... args) {
291.189 -// return new Formatter(l).format(format, args).toString();
291.190 -// }
291.191 + public static String format(Locale l, String format, Object ... args) {
291.192 + String p = format;
291.193 + for (int i = 0; i < args.length; i++) {
291.194 + String v = args[i] == null ? "null" : args[i].toString();
291.195 + p = p.replaceFirst("%s", v);
291.196 + }
291.197 + return p;
291.198 + // return new Formatter(l).format(format, args).toString();
291.199 + }
291.200
291.201 /**
291.202 * Returns the string representation of the <code>Object</code> argument.
291.203 @@ -3034,6 +3109,14 @@
291.204 * @return a string that has the same contents as this string, but is
291.205 * guaranteed to be from a pool of unique strings.
291.206 */
291.207 + @JavaScriptBody(args = {}, body =
291.208 + "var s = this.toString().toString();\n" +
291.209 + "var i = String.intern || (String.intern = {})\n" +
291.210 + "if (!i[s]) {\n" +
291.211 + " i[s] = s;\n" +
291.212 + "}\n" +
291.213 + "return i[s];"
291.214 + )
291.215 public native String intern();
291.216
291.217
292.1 --- a/rt/emul/mini/src/main/java/java/lang/Throwable.java Tue Apr 29 15:25:58 2014 +0200
292.2 +++ b/rt/emul/mini/src/main/java/java/lang/Throwable.java Wed Apr 30 15:04:10 2014 +0200
292.3 @@ -638,94 +638,34 @@
292.4 * ... 2 more
292.5 * </pre>
292.6 */
292.7 -// public void printStackTrace() {
292.8 -// printStackTrace(System.err);
292.9 -// }
292.10 -//
292.11 -// /**
292.12 -// * Prints this throwable and its backtrace to the specified print stream.
292.13 -// *
292.14 -// * @param s {@code PrintStream} to use for output
292.15 -// */
292.16 -// public void printStackTrace(PrintStream s) {
292.17 -// printStackTrace(new WrappedPrintStream(s));
292.18 -// }
292.19 -//
292.20 -// private void printStackTrace(PrintStreamOrWriter s) {
292.21 -// // Guard against malicious overrides of Throwable.equals by
292.22 -// // using a Set with identity equality semantics.
292.23 -//// Set<Throwable> dejaVu =
292.24 -//// Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
292.25 -//// dejaVu.add(this);
292.26 -//
292.27 -// synchronized (s.lock()) {
292.28 -// // Print our stack trace
292.29 -// s.println(this);
292.30 -// StackTraceElement[] trace = getOurStackTrace();
292.31 -// for (StackTraceElement traceElement : trace)
292.32 -// s.println("\tat " + traceElement);
292.33 -//
292.34 -// // Print suppressed exceptions, if any
292.35 -//// for (Throwable se : getSuppressed())
292.36 -//// se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
292.37 -//
292.38 -// // Print cause, if any
292.39 -// Throwable ourCause = getCause();
292.40 -//// if (ourCause != null)
292.41 -//// ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
292.42 -// }
292.43 -// }
292.44 -//
292.45 -// /**
292.46 -// * Print our stack trace as an enclosed exception for the specified
292.47 -// * stack trace.
292.48 -// */
292.49 -// private void printEnclosedStackTrace(PrintStreamOrWriter s,
292.50 -// StackTraceElement[] enclosingTrace,
292.51 -// String caption,
292.52 -// String prefix,
292.53 -// Object dejaVu) {
292.54 -// assert Thread.holdsLock(s.lock());
292.55 -// {
292.56 -// // Compute number of frames in common between this and enclosing trace
292.57 -// StackTraceElement[] trace = getOurStackTrace();
292.58 -// int m = trace.length - 1;
292.59 -// int n = enclosingTrace.length - 1;
292.60 -// while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
292.61 -// m--; n--;
292.62 -// }
292.63 -// int framesInCommon = trace.length - 1 - m;
292.64 -//
292.65 -// // Print our stack trace
292.66 -// s.println(prefix + caption + this);
292.67 -// for (int i = 0; i <= m; i++)
292.68 -// s.println(prefix + "\tat " + trace[i]);
292.69 -// if (framesInCommon != 0)
292.70 -// s.println(prefix + "\t... " + framesInCommon + " more");
292.71 -//
292.72 -// // Print suppressed exceptions, if any
292.73 -// for (Throwable se : getSuppressed())
292.74 -// se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
292.75 -// prefix +"\t", dejaVu);
292.76 -//
292.77 -// // Print cause, if any
292.78 -// Throwable ourCause = getCause();
292.79 -// if (ourCause != null)
292.80 -// ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
292.81 -// }
292.82 -// }
292.83 -//
292.84 -// /**
292.85 -// * Prints this throwable and its backtrace to the specified
292.86 -// * print writer.
292.87 -// *
292.88 -// * @param s {@code PrintWriter} to use for output
292.89 -// * @since JDK1.1
292.90 -// */
292.91 -// public void printStackTrace(PrintWriter s) {
292.92 -// printStackTrace(new WrappedPrintWriter(s));
292.93 -// }
292.94 -//
292.95 + public void printStackTrace() {
292.96 + warn(getClass().getName() + ": " + getMessage());
292.97 + }
292.98 + @JavaScriptBody(args = { "msg" }, body = "if (console) console.warn(msg.toString());")
292.99 + private native void warn(String msg);
292.100 +
292.101 + /**
292.102 + * Prints this throwable and its backtrace to the specified print stream.
292.103 + *
292.104 + * @param s {@code PrintStream} to use for output
292.105 + */
292.106 + public void printStackTrace(PrintStream s) {
292.107 + s.print(getClass().getName());
292.108 + s.print(": ");
292.109 + s.println(getMessage());
292.110 + }
292.111 +
292.112 + /**
292.113 + * Prints this throwable and its backtrace to the specified
292.114 + * print writer.
292.115 + *
292.116 + * @param s {@code PrintWriter} to use for output
292.117 + * @since JDK1.1
292.118 + */
292.119 + public void printStackTrace(PrintWriter s) {
292.120 + s.append(getClass().getName()).append(": ").println(getMessage());
292.121 + }
292.122 +
292.123 // /**
292.124 // * Wrapper class for PrintStream and PrintWriter to enable a single
292.125 // * implementation of printStackTrace.
293.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Tue Apr 29 15:25:58 2014 +0200
293.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Array.java Wed Apr 30 15:04:10 2014 +0200
293.3 @@ -107,7 +107,7 @@
293.4 if (type.getName().equals("void")) {
293.5 throw new IllegalStateException("Can't create array for " + type);
293.6 }
293.7 - return "[L" + type.getName() + ";";
293.8 + return "[L" + type.getName().replace('.', '/') + ";";
293.9 }
293.10 /**
293.11 * Creates a new array
294.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Constructor.java Tue Apr 29 15:25:58 2014 +0200
294.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Constructor.java Wed Apr 30 15:04:10 2014 +0200
294.3 @@ -26,6 +26,10 @@
294.4 package java.lang.reflect;
294.5
294.6 import java.lang.annotation.Annotation;
294.7 +import static java.lang.reflect.Method.fromPrimitive;
294.8 +import static java.lang.reflect.Method.getAccess;
294.9 +import static java.lang.reflect.Method.getParameterTypes;
294.10 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
294.11 import org.apidesign.bck2brwsr.emul.reflect.TypeProvider;
294.12
294.13 /**
294.14 @@ -53,44 +57,20 @@
294.15 GenericDeclaration,
294.16 Member {
294.17
294.18 - private Class<T> clazz;
294.19 - private int slot;
294.20 - private Class<?>[] parameterTypes;
294.21 - private Class<?>[] exceptionTypes;
294.22 - private int modifiers;
294.23 - // Generics and annotations support
294.24 - private transient String signature;
294.25 - private byte[] annotations;
294.26 - private byte[] parameterAnnotations;
294.27 -
294.28 -
294.29 - // For sharing of ConstructorAccessors. This branching structure
294.30 - // is currently only two levels deep (i.e., one root Constructor
294.31 - // and potentially many Constructor objects pointing to it.)
294.32 - private Constructor<T> root;
294.33 + private final Class<T> clazz;
294.34 + private final Object data;
294.35 + private final String sig;
294.36
294.37 /**
294.38 * Package-private constructor used by ReflectAccess to enable
294.39 * instantiation of these objects in Java code from the java.lang
294.40 * package via sun.reflect.LangReflectAccess.
294.41 */
294.42 - Constructor(Class<T> declaringClass,
294.43 - Class<?>[] parameterTypes,
294.44 - Class<?>[] checkedExceptions,
294.45 - int modifiers,
294.46 - int slot,
294.47 - String signature,
294.48 - byte[] annotations,
294.49 - byte[] parameterAnnotations)
294.50 + Constructor(Class<T> declaringClass, Object data, String sig)
294.51 {
294.52 this.clazz = declaringClass;
294.53 - this.parameterTypes = parameterTypes;
294.54 - this.exceptionTypes = checkedExceptions;
294.55 - this.modifiers = modifiers;
294.56 - this.slot = slot;
294.57 - this.signature = signature;
294.58 - this.annotations = annotations;
294.59 - this.parameterAnnotations = parameterAnnotations;
294.60 + this.data = data;
294.61 + this.sig = sig;
294.62 }
294.63
294.64 /**
294.65 @@ -126,7 +106,7 @@
294.66 * @see Modifier
294.67 */
294.68 public int getModifiers() {
294.69 - return modifiers;
294.70 + return getAccess(data);
294.71 }
294.72
294.73 /**
294.74 @@ -159,7 +139,7 @@
294.75 * represents
294.76 */
294.77 public Class<?>[] getParameterTypes() {
294.78 - return (Class<?>[]) parameterTypes.clone();
294.79 + return Method.getParameterTypes(sig);
294.80 }
294.81
294.82
294.83 @@ -205,7 +185,7 @@
294.84 * constructor this object represents
294.85 */
294.86 public Class<?>[] getExceptionTypes() {
294.87 - return (Class<?>[])exceptionTypes.clone();
294.88 + return new Class[0];
294.89 }
294.90
294.91
294.92 @@ -242,20 +222,9 @@
294.93 * same formal parameter types.
294.94 */
294.95 public boolean equals(Object obj) {
294.96 - if (obj != null && obj instanceof Constructor) {
294.97 - Constructor<?> other = (Constructor<?>)obj;
294.98 - if (getDeclaringClass() == other.getDeclaringClass()) {
294.99 - /* Avoid unnecessary cloning */
294.100 - Class<?>[] params1 = parameterTypes;
294.101 - Class<?>[] params2 = other.parameterTypes;
294.102 - if (params1.length == params2.length) {
294.103 - for (int i = 0; i < params1.length; i++) {
294.104 - if (params1[i] != params2[i])
294.105 - return false;
294.106 - }
294.107 - return true;
294.108 - }
294.109 - }
294.110 + if (obj instanceof Constructor) {
294.111 + Constructor other = (Constructor)obj;
294.112 + return data == other.data;
294.113 }
294.114 return false;
294.115 }
294.116 @@ -293,13 +262,14 @@
294.117 }
294.118 sb.append(Field.getTypeName(getDeclaringClass()));
294.119 sb.append("(");
294.120 - Class<?>[] params = parameterTypes; // avoid clone
294.121 + Class<?>[] params = getParameterTypes(); // avoid clone
294.122 for (int j = 0; j < params.length; j++) {
294.123 sb.append(Field.getTypeName(params[j]));
294.124 if (j < (params.length - 1))
294.125 sb.append(",");
294.126 }
294.127 sb.append(")");
294.128 + /*
294.129 Class<?>[] exceptions = exceptionTypes; // avoid clone
294.130 if (exceptions.length > 0) {
294.131 sb.append(" throws ");
294.132 @@ -309,6 +279,7 @@
294.133 sb.append(",");
294.134 }
294.135 }
294.136 + */
294.137 return sb.toString();
294.138 } catch (Exception e) {
294.139 return "<" + e + ">";
294.140 @@ -452,9 +423,29 @@
294.141 throws InstantiationException, IllegalAccessException,
294.142 IllegalArgumentException, InvocationTargetException
294.143 {
294.144 - throw new SecurityException();
294.145 + Class[] types = getParameterTypes();
294.146 + if (types.length != initargs.length) {
294.147 + throw new IllegalArgumentException("Types len " + types.length + " args: " + initargs.length);
294.148 + } else {
294.149 + initargs = initargs.clone();
294.150 + for (int i = 0; i < types.length; i++) {
294.151 + Class c = types[i];
294.152 + if (c.isPrimitive() && initargs[i] != null) {
294.153 + initargs[i] = Method.toPrimitive(initargs[i]);
294.154 + }
294.155 + }
294.156 + }
294.157 + return (T) newInstance0(this.getDeclaringClass(), "cons__" + sig, initargs);
294.158 }
294.159
294.160 + @JavaScriptBody(args = { "self", "sig", "args" }, body =
294.161 + "\nvar c = self.cnstr;"
294.162 + + "\nvar inst = c();"
294.163 + + "\nc[sig].apply(inst, args);"
294.164 + + "\nreturn inst;"
294.165 + )
294.166 + private static native Object newInstance0(Class<?> self, String sig, Object[] args);
294.167 +
294.168 /**
294.169 * Returns {@code true} if this constructor was declared to take
294.170 * a variable number of arguments; returns {@code false}
294.171 @@ -481,22 +472,6 @@
294.172 return Modifier.isSynthetic(getModifiers());
294.173 }
294.174
294.175 - int getSlot() {
294.176 - return slot;
294.177 - }
294.178 -
294.179 - String getSignature() {
294.180 - return signature;
294.181 - }
294.182 -
294.183 - byte[] getRawAnnotations() {
294.184 - return annotations;
294.185 - }
294.186 -
294.187 - byte[] getRawParameterAnnotations() {
294.188 - return parameterAnnotations;
294.189 - }
294.190 -
294.191 /**
294.192 * @throws NullPointerException {@inheritDoc}
294.193 * @since 1.5
294.194 @@ -532,11 +507,11 @@
294.195 * @since 1.5
294.196 */
294.197 public Annotation[][] getParameterAnnotations() {
294.198 - int numParameters = parameterTypes.length;
294.199 - if (parameterAnnotations == null)
294.200 - return new Annotation[numParameters][0];
294.201 +// int numParameters = parameterTypes.length;
294.202 +// if (parameterAnnotations == null)
294.203 +// return new Annotation[numParameters][0];
294.204
294.205 - return new Annotation[numParameters][0]; // XXX
294.206 + return new Annotation[0][0]; // XXX
294.207 /*
294.208 Annotation[][] result = AnnotationParser.parseParameterAnnotations(
294.209 parameterAnnotations,
295.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Tue Apr 29 15:25:58 2014 +0200
295.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Method.java Wed Apr 30 15:04:10 2014 +0200
295.3 @@ -113,7 +113,7 @@
295.4 }
295.5
295.6 @JavaScriptBody(args = "self", body = "return self.access;")
295.7 - private static native int getAccess(Object self);
295.8 + static native int getAccess(Object self);
295.9
295.10 /**
295.11 * Returns an array of {@code TypeVariable} objects that represent the
295.12 @@ -183,6 +183,10 @@
295.13 * represents
295.14 */
295.15 public Class<?>[] getParameterTypes() {
295.16 + return getParameterTypes(sig);
295.17 + }
295.18 +
295.19 + static Class<?>[] getParameterTypes(String sig) {
295.20 Class[] arr = new Class[MethodImpl.signatureElements(sig) - 1];
295.21 Enumeration<Class> en = MethodImpl.signatureParser(sig);
295.22 en.nextElement(); // return type
295.23 @@ -235,8 +239,7 @@
295.24 * method this object represents
295.25 */
295.26 public Class<?>[] getExceptionTypes() {
295.27 - throw new UnsupportedOperationException();
295.28 - //return (Class<?>[]) exceptionTypes.clone();
295.29 + return new Class[0];
295.30 }
295.31
295.32 /**
295.33 @@ -525,15 +528,17 @@
295.34 }
295.35
295.36 @JavaScriptBody(args = { "st", "method", "self", "args" }, body =
295.37 - "var p;\n"
295.38 + "var p; var cll;\n"
295.39 + "if (st) {\n"
295.40 + + " cll = self[method._name() + '__' + method._sig()];\n"
295.41 + " p = new Array(1);\n"
295.42 + " p[0] = self;\n"
295.43 + " p = p.concat(args);\n"
295.44 + "} else {\n"
295.45 + " p = args;\n"
295.46 + + " cll = method._data();"
295.47 + "}\n"
295.48 - + "return method._data().apply(self, p);\n"
295.49 + + "return cll.apply(self, p);\n"
295.50 )
295.51 private static native Object invoke0(boolean isStatic, Method m, Object self, Object[] args);
295.52
295.53 @@ -583,7 +588,7 @@
295.54 private static native Integer fromRaw(Class<?> cls, String m, Object o);
295.55
295.56 @JavaScriptBody(args = { "o" }, body = "return o.valueOf();")
295.57 - private static native Object toPrimitive(Object o);
295.58 + static native Object toPrimitive(Object o);
295.59
295.60 /**
295.61 * Returns {@code true} if this method is a bridge
295.62 @@ -692,6 +697,11 @@
295.63 protected Method create(Class<?> declaringClass, String name, Object data, String sig) {
295.64 return new Method(declaringClass, name, data, sig);
295.65 }
295.66 +
295.67 + @Override
295.68 + protected Constructor create(Class<?> declaringClass, Object data, String sig) {
295.69 + return new Constructor(declaringClass, data, sig);
295.70 + }
295.71 };
295.72 }
295.73 }
296.1 --- a/rt/emul/mini/src/main/java/java/lang/reflect/Proxy.java Tue Apr 29 15:25:58 2014 +0200
296.2 +++ b/rt/emul/mini/src/main/java/java/lang/reflect/Proxy.java Wed Apr 30 15:04:10 2014 +0200
296.3 @@ -212,7 +212,16 @@
296.4
296.5 private static final long serialVersionUID = -2222568056686623797L;
296.6
296.7 -
296.8 + private final static Method getProxyClass;
296.9 + static {
296.10 + Class<?> pg;
296.11 + try {
296.12 + pg = Class.forName("org.apidesign.bck2brwsr.emul.reflect.ProxyImpl");
296.13 + getProxyClass = pg.getMethod("getProxyClass", ClassLoader.class, Class[].class);
296.14 + } catch (Exception ex) {
296.15 + throw new IllegalStateException(ex);
296.16 + }
296.17 + }
296.18
296.19 /**
296.20 * the invocation handler for this proxy instance.
296.21 @@ -315,7 +324,13 @@
296.22 Class<?>... interfaces)
296.23 throws IllegalArgumentException
296.24 {
296.25 - throw new IllegalArgumentException();
296.26 + try {
296.27 + return (Class<?>) getProxyClass.invoke(null, loader, interfaces);
296.28 + } catch (IllegalAccessException ex) {
296.29 + throw new IllegalStateException(ex);
296.30 + } catch (InvocationTargetException ex) {
296.31 + throw (RuntimeException)ex.getTargetException();
296.32 + }
296.33 }
296.34
296.35 /**
296.36 @@ -355,7 +370,27 @@
296.37 if (h == null) {
296.38 throw new NullPointerException();
296.39 }
296.40 - throw new IllegalArgumentException();
296.41 +
296.42 + /*
296.43 + * Look up or generate the designated proxy class.
296.44 + */
296.45 + Class<?> cl = getProxyClass(loader, interfaces);
296.46 +
296.47 + /*
296.48 + * Invoke its constructor with the designated invocation handler.
296.49 + */
296.50 + try {
296.51 + Constructor cons = cl.getConstructor(InvocationHandler.class);
296.52 + return cons.newInstance(new Object[] { h });
296.53 + } catch (NoSuchMethodException e) {
296.54 + throw new IllegalStateException(e.toString());
296.55 + } catch (IllegalAccessException e) {
296.56 + throw new IllegalStateException(e.toString());
296.57 + } catch (InstantiationException e) {
296.58 + throw new IllegalStateException(e.toString());
296.59 + } catch (InvocationTargetException e) {
296.60 + throw new IllegalStateException(e.toString());
296.61 + }
296.62 }
296.63
296.64 /**
296.65 @@ -376,8 +411,7 @@
296.66 if (cl == null) {
296.67 throw new NullPointerException();
296.68 }
296.69 -
296.70 - return false;
296.71 + return Proxy.class.isAssignableFrom(cl);
296.72 }
296.73
296.74 /**
296.75 @@ -401,7 +435,4 @@
296.76 Proxy p = (Proxy) proxy;
296.77 return p.h;
296.78 }
296.79 -
296.80 - private static native Class defineClass0(ClassLoader loader, String name,
296.81 - byte[] b, int off, int len);
296.82 }
297.1 --- a/rt/emul/mini/src/main/java/java/net/URL.java Tue Apr 29 15:25:58 2014 +0200
297.2 +++ b/rt/emul/mini/src/main/java/java/net/URL.java Wed Apr 30 15:04:10 2014 +0200
297.3 @@ -920,6 +920,23 @@
297.4 }
297.5
297.6 /**
297.7 + * Returns a {@link java.net.URI} equivalent to this URL.
297.8 + * This method functions in the same way as <code>new URI (this.toString())</code>.
297.9 + * <p>Note, any URL instance that complies with RFC 2396 can be converted
297.10 + * to a URI. However, some URLs that are not strictly in compliance
297.11 + * can not be converted to a URI.
297.12 + *
297.13 + * @exception URISyntaxException if this URL is not formatted strictly according to
297.14 + * to RFC2396 and cannot be converted to a URI.
297.15 + *
297.16 + * @return a URI instance equivalent to this URL.
297.17 + * @since 1.5
297.18 + */
297.19 + public URI toURI() throws URISyntaxException {
297.20 + return new URI (toString());
297.21 + }
297.22 +
297.23 + /**
297.24 * Returns a {@link java.net.URLConnection URLConnection} instance that
297.25 * represents a connection to the remote object referred to by the
297.26 * {@code URL}.
297.27 @@ -948,9 +965,9 @@
297.28 * @see java.net.URL#URL(java.lang.String, java.lang.String,
297.29 * int, java.lang.String)
297.30 */
297.31 -// public URLConnection openConnection() throws java.io.IOException {
297.32 -// return handler.openConnection(this);
297.33 -// }
297.34 + public URLConnection openConnection() throws java.io.IOException {
297.35 + return handler.openConnection(this);
297.36 + }
297.37
297.38
297.39 /**
297.40 @@ -1027,18 +1044,53 @@
297.41 public final Object getContent(Class[] classes)
297.42 throws java.io.IOException {
297.43 for (Class<?> c : classes) {
297.44 - if (c == String.class) {
297.45 - return loadText(toExternalForm());
297.46 - }
297.47 - if (c == byte[].class) {
297.48 - return loadBytes(toExternalForm(), new byte[0]);
297.49 + try {
297.50 + if (c == String.class) {
297.51 + return loadText(toExternalForm());
297.52 + }
297.53 + if (c == byte[].class) {
297.54 + return loadBytes(toExternalForm(), new byte[0]);
297.55 + }
297.56 + } catch (Throwable t) {
297.57 + throw new IOException(t);
297.58 }
297.59 }
297.60 return null;
297.61 }
297.62
297.63 - static URLStreamHandler getURLStreamHandler(String protocol) {
297.64 - URLStreamHandler universal = new URLStreamHandler() {};
297.65 + static URLStreamHandler getURLStreamHandler(final String protocol) {
297.66 + URLStreamHandler universal = new URLStreamHandler() {
297.67 + @Override
297.68 + protected URLConnection openConnection(URL u) throws IOException {
297.69 + return new URLConnection(u) {
297.70 + Object stream = url.is;
297.71 +
297.72 + @Override
297.73 + public void connect() throws IOException {
297.74 + if (stream == null) {
297.75 + try {
297.76 + byte[] arr = (byte[]) url.getContent(new Class[]{byte[].class});
297.77 + stream = new ByteArrayInputStream(arr);
297.78 + } catch (IOException ex) {
297.79 + stream = ex;
297.80 + throw ex;
297.81 + }
297.82 + }
297.83 + }
297.84 +
297.85 + @Override
297.86 + public InputStream getInputStream() throws IOException {
297.87 + connect();
297.88 + if (stream instanceof IOException) {
297.89 + throw (IOException)stream;
297.90 + }
297.91 + return (InputStream)stream;
297.92 + }
297.93 +
297.94 +
297.95 + };
297.96 + }
297.97 + };
297.98 return universal;
297.99 }
297.100
297.101 @@ -1053,10 +1105,16 @@
297.102 }
297.103
297.104 @JavaScriptBody(args = {}, body =
297.105 - "if (typeof window !== 'object') return null;\n"
297.106 - + "if (!window.location) return null;\n"
297.107 - + "if (!window.location.href) return null;\n"
297.108 - + "return window.location.href;\n"
297.109 + "var l;\n"
297.110 + + "if (typeof location !== 'object') {"
297.111 + + " if (typeof window !== 'object') return null;\n"
297.112 + + " if (!window.location) return null;\n"
297.113 + + " l = window.location;\n"
297.114 + + "} else {\n"
297.115 + + " l = location;\n"
297.116 + + "}\n"
297.117 + + "if (!l.href) return null;\n"
297.118 + + "return l.href;\n"
297.119 )
297.120 private static native String findBaseURL();
297.121 }
298.1 --- a/rt/emul/mini/src/main/java/java/net/URLStreamHandler.java Tue Apr 29 15:25:58 2014 +0200
298.2 +++ b/rt/emul/mini/src/main/java/java/net/URLStreamHandler.java Wed Apr 30 15:04:10 2014 +0200
298.3 @@ -25,6 +25,8 @@
298.4
298.5 package java.net;
298.6
298.7 +import java.io.IOException;
298.8 +
298.9
298.10 /**
298.11 * The abstract class <code>URLStreamHandler</code> is the common
298.12 @@ -62,7 +64,7 @@
298.13 * @exception IOException if an I/O error occurs while opening the
298.14 * connection.
298.15 */
298.16 -// abstract protected URLConnection openConnection(URL u) throws IOException;
298.17 + abstract protected URLConnection openConnection(URL u) throws IOException;
298.18
298.19 /**
298.20 * Same as openConnection(URL), except that the connection will be
299.1 --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Tue Apr 29 15:25:58 2014 +0200
299.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Wed Apr 30 15:04:10 2014 +0200
299.3 @@ -19,6 +19,7 @@
299.4
299.5 import java.lang.reflect.Method;
299.6 import org.apidesign.bck2brwsr.core.JavaScriptBody;
299.7 +import org.apidesign.bck2brwsr.core.JavaScriptOnly;
299.8
299.9 /**
299.10 *
299.11 @@ -71,4 +72,27 @@
299.12 }
299.13 @JavaScriptBody(args = { "obj" }, body="return vm.java_lang_Object(false).hashCode__I.call(obj);")
299.14 public static native int identityHashCode(Object obj);
299.15 +
299.16 + @JavaScriptOnly(name = "toJS", value = "function(v) {\n" +
299.17 + " if (v === null) return null;\n" +
299.18 + " if (Object.prototype.toString.call(v) === '[object Array]') {\n" +
299.19 + " return vm.org_apidesign_bck2brwsr_emul_lang_System(false).convArray__Ljava_lang_Object_2Ljava_lang_Object_2(v);\n" +
299.20 + " }\n" +
299.21 + " return v.valueOf();\n" +
299.22 + "}\n"
299.23 + )
299.24 + public static native int toJS();
299.25 +
299.26 + private static Object convArray(Object o) {
299.27 + if (o instanceof Object[]) {
299.28 + Object[] arr = (Object[]) o;
299.29 + final int l = arr.length;
299.30 + Object[] ret = new Object[l];
299.31 + for (int i = 0; i < l; i++) {
299.32 + ret[i] = convArray(arr[i]);
299.33 + }
299.34 + return ret;
299.35 + }
299.36 + return o;
299.37 + }
299.38 }
300.1 --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Tue Apr 29 15:25:58 2014 +0200
300.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/reflect/MethodImpl.java Wed Apr 30 15:04:10 2014 +0200
300.3 @@ -18,6 +18,7 @@
300.4 package org.apidesign.bck2brwsr.emul.reflect;
300.5
300.6 import java.lang.reflect.Array;
300.7 +import java.lang.reflect.Constructor;
300.8 import java.lang.reflect.Method;
300.9 import java.util.Enumeration;
300.10 import org.apidesign.bck2brwsr.core.JavaScriptBody;
300.11 @@ -37,15 +38,17 @@
300.12 }
300.13
300.14 protected abstract Method create(Class<?> declaringClass, String name, Object data, String sig);
300.15 + protected abstract Constructor create(Class<?> declaringClass, Object data, String sig);
300.16
300.17
300.18 //
300.19 // bck2brwsr implementation
300.20 //
300.21
300.22 - @JavaScriptBody(args = {"clazz", "prefix"},
300.23 + @JavaScriptBody(args = {"clazz", "prefix", "cnstr"},
300.24 body = ""
300.25 - + "var c = clazz.cnstr.prototype;"
300.26 + + "var c = clazz.cnstr;\n"
300.27 + + "if (!cnstr) c = c.prototype;"
300.28 + "var arr = new Array();\n"
300.29 + "for (m in c) {\n"
300.30 + " if (m.indexOf(prefix) === 0) {\n"
300.31 @@ -57,11 +60,55 @@
300.32 + "}\n"
300.33 + "return arr;")
300.34 private static native Object[] findMethodData(
300.35 - Class<?> clazz, String prefix);
300.36 + Class<?> clazz, String prefix, boolean cnstr);
300.37
300.38 + public static Constructor findConstructor(
300.39 + Class<?> clazz, Class<?>... parameterTypes) {
300.40 + Object[] data = findMethodData(clazz, "cons__", true);
300.41 + BIG: for (int i = 0; i < data.length; i += 3) {
300.42 + String sig = ((String) data[i]).substring(6);
300.43 + Class<?> cls = (Class<?>) data[i + 2];
300.44 + Constructor tmp = INSTANCE.create(cls, data[i + 1], sig);
300.45 + Class<?>[] tmpParms = tmp.getParameterTypes();
300.46 + if (parameterTypes.length != tmpParms.length) {
300.47 + continue;
300.48 + }
300.49 + for (int j = 0; j < tmpParms.length; j++) {
300.50 + if (!parameterTypes[j].equals(tmpParms[j])) {
300.51 + continue BIG;
300.52 + }
300.53 + }
300.54 + return tmp;
300.55 + }
300.56 + return null;
300.57 + }
300.58 +
300.59 + public static Constructor[] findConstructors(Class<?> clazz, int mask) {
300.60 + Object[] namesAndData = findMethodData(clazz, "", true);
300.61 + int cnt = 0;
300.62 + for (int i = 0; i < namesAndData.length; i += 3) {
300.63 + String sig = (String) namesAndData[i];
300.64 + Object data = namesAndData[i + 1];
300.65 + if (!sig.startsWith("cons__")) {
300.66 + continue;
300.67 + }
300.68 + sig = sig.substring(6);
300.69 + Class<?> cls = (Class<?>) namesAndData[i + 2];
300.70 + final Constructor m = INSTANCE.create(cls, data, sig);
300.71 + if ((m.getModifiers() & mask) == 0) {
300.72 + continue;
300.73 + }
300.74 + namesAndData[cnt++] = m;
300.75 + }
300.76 + Constructor[] arr = new Constructor[cnt];
300.77 + for (int i = 0; i < cnt; i++) {
300.78 + arr[i] = (Constructor) namesAndData[i];
300.79 + }
300.80 + return arr;
300.81 + }
300.82 public static Method findMethod(
300.83 Class<?> clazz, String name, Class<?>... parameterTypes) {
300.84 - Object[] data = findMethodData(clazz, name + "__");
300.85 + Object[] data = findMethodData(clazz, name + "__", false);
300.86 BIG: for (int i = 0; i < data.length; i += 3) {
300.87 String sig = ((String) data[i]).substring(name.length() + 2);
300.88 Class<?> cls = (Class<?>) data[i + 2];
300.89 @@ -81,7 +128,7 @@
300.90 }
300.91
300.92 public static Method[] findMethods(Class<?> clazz, int mask) {
300.93 - Object[] namesAndData = findMethodData(clazz, "");
300.94 + Object[] namesAndData = findMethodData(clazz, "", false);
300.95 int cnt = 0;
300.96 for (int i = 0; i < namesAndData.length; i += 3) {
300.97 String sig = (String) namesAndData[i];
301.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
301.2 +++ b/rt/emul/mini/src/main/java/org/apidesign/vm4brwsr/api/VM.java Wed Apr 30 15:04:10 2014 +0200
301.3 @@ -0,0 +1,47 @@
301.4 +/**
301.5 + * Back 2 Browser Bytecode Translator
301.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
301.7 + *
301.8 + * This program is free software: you can redistribute it and/or modify
301.9 + * it under the terms of the GNU General Public License as published by
301.10 + * the Free Software Foundation, version 2 of the License.
301.11 + *
301.12 + * This program is distributed in the hope that it will be useful,
301.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
301.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
301.15 + * GNU General Public License for more details.
301.16 + *
301.17 + * You should have received a copy of the GNU General Public License
301.18 + * along with this program. Look for COPYING file in the top folder.
301.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
301.20 + */
301.21 +package org.apidesign.vm4brwsr.api;
301.22 +
301.23 +import java.io.IOException;
301.24 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
301.25 +
301.26 +/** Utility methods to talk to the Bck2Brwsr virtual machine.
301.27 + *
301.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
301.29 + * @since 0.9
301.30 + */
301.31 +public final class VM {
301.32 + private VM() {
301.33 + }
301.34 +
301.35 + /** Takes an existing class and replaces its existing byte code
301.36 + * with new one.
301.37 + *
301.38 + * @param clazz existing class to reload
301.39 + * @param byteCode new bytecode
301.40 + * @throws IOException an exception is something goes wrong
301.41 + */
301.42 + public static void reload(Class<?> clazz, byte[] byteCode) throws IOException {
301.43 + reloadImpl(clazz.getName(), byteCode);
301.44 + }
301.45 +
301.46 + @JavaScriptBody(args = { "name", "byteCode" }, body = "vm._reload(name, byteCode);")
301.47 + private static void reloadImpl(String name, byte[] byteCode) throws IOException {
301.48 + throw new IOException();
301.49 + }
301.50 +}
302.1 --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Tue Apr 29 15:25:58 2014 +0200
302.2 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Wed Apr 30 15:04:10 2014 +0200
302.3 @@ -176,6 +176,8 @@
302.4 };
302.5
302.6 numberPrototype.shl64 = function(x) {
302.7 + x &= 0x3f;
302.8 + if (x == 0) return this;
302.9 if (x >= 32) {
302.10 var hi = this << (x - 32);
302.11 return hi.next32(0);
302.12 @@ -190,6 +192,8 @@
302.13 };
302.14
302.15 numberPrototype.shr64 = function(x) {
302.16 + x &= 0x3f;
302.17 + if (x == 0) return this;
302.18 if (x >= 32) {
302.19 var low = this.high32() >> (x - 32);
302.20 low += (low < 0) ? (__m32 + 1) : 0;
302.21 @@ -205,6 +209,8 @@
302.22 };
302.23
302.24 numberPrototype.ushr64 = function(x) {
302.25 + x &= 0x3f;
302.26 + if (x == 0) return this;
302.27 if (x >= 32) {
302.28 var low = this.high32() >>> (x - 32);
302.29 low += (low < 0) ? (__m32 + 1) : 0;
302.30 @@ -218,6 +224,14 @@
302.31 return hi.next32(low);
302.32 }
302.33 };
302.34 +
302.35 + numberPrototype.compare = function(x) {
302.36 + if (this == x) {
302.37 + return 0;
302.38 + } else {
302.39 + return (this < x) ? -1 : 1;
302.40 + }
302.41 + };
302.42
302.43 numberPrototype.compare64 = function(x) {
302.44 if (this.high32() === x.high32()) {
303.1 --- a/rt/emul/pom.xml Tue Apr 29 15:25:58 2014 +0200
303.2 +++ b/rt/emul/pom.xml Wed Apr 30 15:04:10 2014 +0200
303.3 @@ -4,16 +4,17 @@
303.4 <parent>
303.5 <groupId>org.apidesign.bck2brwsr</groupId>
303.6 <artifactId>rt</artifactId>
303.7 - <version>0.8-SNAPSHOT</version>
303.8 + <version>0.9-SNAPSHOT</version>
303.9 </parent>
303.10 <groupId>org.apidesign.bck2brwsr</groupId>
303.11 <artifactId>emul.pom</artifactId>
303.12 - <version>0.8-SNAPSHOT</version>
303.13 + <version>0.9-SNAPSHOT</version>
303.14 <packaging>pom</packaging>
303.15 <name>Emulation of Core Libraries</name>
303.16 <modules>
303.17 <module>mini</module>
303.18 <module>compact</module>
303.19 <module>brwsrtest</module>
303.20 + <module>fake</module>
303.21 </modules>
303.22 </project>
304.1 --- a/rt/mojo/pom.xml Tue Apr 29 15:25:58 2014 +0200
304.2 +++ b/rt/mojo/pom.xml Wed Apr 30 15:04:10 2014 +0200
304.3 @@ -4,11 +4,11 @@
304.4 <parent>
304.5 <groupId>org.apidesign.bck2brwsr</groupId>
304.6 <artifactId>rt</artifactId>
304.7 - <version>0.8-SNAPSHOT</version>
304.8 + <version>0.9-SNAPSHOT</version>
304.9 </parent>
304.10 <groupId>org.apidesign.bck2brwsr</groupId>
304.11 <artifactId>bck2brwsr-maven-plugin</artifactId>
304.12 - <version>0.8-SNAPSHOT</version>
304.13 + <version>0.9-SNAPSHOT</version>
304.14 <packaging>maven-plugin</packaging>
304.15 <name>Bck2Brwsr Maven Plugin</name>
304.16 <url>http://bck2brwsr.apidesign.org/</url>
305.1 --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrwsrMojo.java Tue Apr 29 15:25:58 2014 +0200
305.2 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/BrwsrMojo.java Wed Apr 30 15:04:10 2014 +0200
305.3 @@ -29,15 +29,21 @@
305.4 import java.util.Collection;
305.5 import java.util.List;
305.6 import org.apache.maven.artifact.Artifact;
305.7 +import org.apache.maven.model.Resource;
305.8 import org.apache.maven.plugin.MojoExecutionException;
305.9 import org.apache.maven.plugins.annotations.LifecyclePhase;
305.10 import org.apache.maven.plugins.annotations.Mojo;
305.11 import org.apache.maven.plugins.annotations.Parameter;
305.12 +import org.apache.maven.plugins.annotations.ResolutionScope;
305.13 import org.apache.maven.project.MavenProject;
305.14 import org.apidesign.bck2brwsr.launcher.Launcher;
305.15
305.16 /** Executes given HTML page in a browser. */
305.17 -@Mojo(name="brwsr", defaultPhase=LifecyclePhase.NONE)
305.18 +@Mojo(
305.19 + name="brwsr",
305.20 + requiresDependencyResolution = ResolutionScope.RUNTIME,
305.21 + defaultPhase=LifecyclePhase.NONE
305.22 +)
305.23 public class BrwsrMojo extends AbstractMojo {
305.24 public BrwsrMojo() {
305.25 }
305.26 @@ -64,20 +70,33 @@
305.27 /** Root of all pages, and files, etc. */
305.28 @Parameter
305.29 private File directory;
305.30 +
305.31 + @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js")
305.32 + private File javascript;
305.33
305.34 @Override
305.35 public void execute() throws MojoExecutionException {
305.36 if (startpage == null) {
305.37 throw new MojoExecutionException("You have to provide a start page");
305.38 }
305.39 -
305.40 + if (javascript != null && javascript.isFile()) {
305.41 + System.setProperty("bck2brwsr.js", javascript.toURI().toString());
305.42 + }
305.43 try {
305.44 Closeable httpServer;
305.45 if (directory != null) {
305.46 - httpServer = Launcher.showDir(directory, startpage);
305.47 + URLClassLoader url = buildClassLoader(classes, prj.getArtifacts());
305.48 + httpServer = Launcher.showDir(launcher, directory, url, startpage);
305.49 } else {
305.50 - URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts());
305.51 + URLClassLoader url = buildClassLoader(classes, prj.getArtifacts());
305.52 try {
305.53 + for (Resource r : prj.getResources()) {
305.54 + File f = new File(r.getDirectory(), startpage().replace('/', File.separatorChar));
305.55 + if (f.exists()) {
305.56 + System.setProperty("startpage.file", f.getPath());
305.57 + }
305.58 + }
305.59 +
305.60 httpServer = Launcher.showURL(launcher, url, startpage());
305.61 } catch (Exception ex) {
305.62 throw new MojoExecutionException("Can't open " + startpage(), ex);
306.1 --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Tue Apr 29 15:25:58 2014 +0200
306.2 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Wed Apr 30 15:04:10 2014 +0200
306.3 @@ -33,12 +33,16 @@
306.4 import org.apache.maven.plugins.annotations.LifecyclePhase;
306.5 import org.apache.maven.plugins.annotations.Mojo;
306.6 import org.apache.maven.plugins.annotations.Parameter;
306.7 +import org.apache.maven.plugins.annotations.ResolutionScope;
306.8 import org.apache.maven.project.MavenProject;
306.9 import org.apidesign.vm4brwsr.Bck2Brwsr;
306.10 import org.apidesign.vm4brwsr.ObfuscationLevel;
306.11
306.12 /** Compiles classes into JavaScript. */
306.13 -@Mojo(name="j2js", defaultPhase=LifecyclePhase.PROCESS_CLASSES)
306.14 +@Mojo(name="j2js",
306.15 + requiresDependencyResolution = ResolutionScope.COMPILE,
306.16 + defaultPhase=LifecyclePhase.PROCESS_CLASSES
306.17 +)
306.18 public class Java2JavaScript extends AbstractMojo {
306.19 public Java2JavaScript() {
306.20 }
306.21 @@ -46,7 +50,7 @@
306.22 @Parameter(defaultValue="${project.build.directory}/classes")
306.23 private File classes;
306.24 /** JavaScript file to generate */
306.25 - @Parameter
306.26 + @Parameter(defaultValue="${project.build.directory}/bck2brwsr.js")
306.27 private File javascript;
306.28
306.29 /** Additional classes that should be pre-compiled into the javascript
306.30 @@ -66,6 +70,10 @@
306.31 */
306.32 @Parameter(defaultValue="NONE")
306.33 private ObfuscationLevel obfuscation;
306.34 +
306.35 + /** Should classes from rt.jar be included? */
306.36 + @Parameter(defaultValue = "false")
306.37 + private boolean ignoreBootClassPath;
306.38
306.39 /**
306.40 * Indicates whether to create an extension library
306.41 @@ -81,6 +89,9 @@
306.42 if (!classes.isDirectory()) {
306.43 throw new MojoExecutionException("Can't find " + classes);
306.44 }
306.45 + if (javascript == null) {
306.46 + throw new MojoExecutionException("Need to define 'javascript' attribute with a path to file to generate");
306.47 + }
306.48
306.49 List<String> arr = new ArrayList<String>();
306.50 long newest = collectAllClasses("", classes, arr);
306.51 @@ -95,12 +106,12 @@
306.52 }
306.53
306.54 try {
306.55 - URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts());
306.56 + URLClassLoader url = buildClassLoader(classes, prj.getArtifacts());
306.57 FileWriter w = new FileWriter(javascript);
306.58 Bck2Brwsr.newCompiler().
306.59 obfuscation(obfuscation).
306.60 library(library).
306.61 - resources(url).
306.62 + resources(url, ignoreBootClassPath).
306.63 addRootClasses(arr.toArray(new String[0])).
306.64 generate(w);
306.65 w.close();
307.1 --- a/rt/pom.xml Tue Apr 29 15:25:58 2014 +0200
307.2 +++ b/rt/pom.xml Wed Apr 30 15:04:10 2014 +0200
307.3 @@ -3,18 +3,17 @@
307.4 <modelVersion>4.0.0</modelVersion>
307.5 <groupId>org.apidesign.bck2brwsr</groupId>
307.6 <artifactId>rt</artifactId>
307.7 - <version>0.8-SNAPSHOT</version>
307.8 + <version>0.9-SNAPSHOT</version>
307.9 <packaging>pom</packaging>
307.10 <name>Bck2Brwsr Runtime</name>
307.11 <parent>
307.12 <groupId>org.apidesign</groupId>
307.13 <artifactId>bck2brwsr</artifactId>
307.14 - <version>0.8-SNAPSHOT</version>
307.15 + <version>0.9-SNAPSHOT</version>
307.16 </parent>
307.17 <modules>
307.18 <module>core</module>
307.19 <module>emul</module>
307.20 - <module>archetype</module>
307.21 <module>mojo</module>
307.22 <module>vm</module>
307.23 <module>vmtest</module>
308.1 --- a/rt/vm/pom.xml Tue Apr 29 15:25:58 2014 +0200
308.2 +++ b/rt/vm/pom.xml Wed Apr 30 15:04:10 2014 +0200
308.3 @@ -3,12 +3,12 @@
308.4 <parent>
308.5 <groupId>org.apidesign.bck2brwsr</groupId>
308.6 <artifactId>rt</artifactId>
308.7 - <version>0.8-SNAPSHOT</version>
308.8 + <version>0.9-SNAPSHOT</version>
308.9 </parent>
308.10
308.11 <groupId>org.apidesign.bck2brwsr</groupId>
308.12 <artifactId>vm4brwsr</artifactId>
308.13 - <version>0.8-SNAPSHOT</version>
308.14 + <version>0.9-SNAPSHOT</version>
308.15 <packaging>jar</packaging>
308.16
308.17 <name>Virtual Machine for Browser</name>
308.18 @@ -18,6 +18,7 @@
308.19 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
308.20 <author.name>Jaroslav Tulach</author.name>
308.21 <author.email>jaroslav.tulach@apidesign.org</author.email>
308.22 + <bck2brwsr.obfuscationlevel>MINIMAL</bck2brwsr.obfuscationlevel>
308.23 </properties>
308.24
308.25 <repositories>
308.26 @@ -91,7 +92,7 @@
308.27 <classpath />
308.28 <argument>org.apidesign.vm4brwsr.Main</argument>
308.29 <argument>--obfuscatelevel</argument>
308.30 - <argument>MINIMAL</argument>
308.31 + <argument>${bck2brwsr.obfuscationlevel}</argument>
308.32 <argument>${project.build.directory}/bck2brwsr.js</argument>
308.33 <argument>org/apidesign/vm4brwsr/Bck2Brwsr</argument>
308.34 </arguments>
308.35 @@ -151,6 +152,18 @@
308.36 <artifactId>closure-compiler</artifactId>
308.37 <version>r2388</version>
308.38 <scope>compile</scope>
308.39 - </dependency>
308.40 + </dependency>
308.41 + <dependency>
308.42 + <groupId>org.netbeans.html</groupId>
308.43 + <artifactId>net.java.html.boot</artifactId>
308.44 + <scope>test</scope>
308.45 + <version>${net.java.html.version}</version>
308.46 + </dependency>
308.47 + <dependency>
308.48 + <groupId>${project.groupId}</groupId>
308.49 + <artifactId>fake</artifactId>
308.50 + <version>${project.version}</version>
308.51 + <scope>test</scope>
308.52 + </dependency>
308.53 </dependencies>
308.54 </project>
309.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Tue Apr 29 15:25:58 2014 +0200
309.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Wed Apr 30 15:04:10 2014 +0200
309.3 @@ -217,7 +217,21 @@
309.4 * @since 0.5
309.5 */
309.6 public Bck2Brwsr resources(final ClassLoader loader) {
309.7 - return resources(new LdrRsrcs(loader));
309.8 + return resources(loader, false);
309.9 + }
309.10 +
309.11 + /** A way to change the provider of additional resources (classes) for the
309.12 + * compiler by specifying classloader to use for loading them.
309.13 + *
309.14 + * @param loader class loader to load the resources from
309.15 + * @param ignoreBootClassPath <code>true</code> if classes loaded
309.16 + * from <code>rt.jar</code>
309.17 + * @return new instance of the compiler with all values being the same, just
309.18 + * different resources provider
309.19 + * @since 0.9
309.20 + */
309.21 + public Bck2Brwsr resources(final ClassLoader loader, boolean ignoreBootClassPath) {
309.22 + return resources(new LdrRsrcs(loader, ignoreBootClassPath));
309.23 }
309.24
309.25 /** Generates virtual machine based on previous configuration of the
309.26 @@ -247,7 +261,7 @@
309.27 //
309.28
309.29 Resources getResources() {
309.30 - return res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader());
309.31 + return res != null ? res : new LdrRsrcs(Bck2Brwsr.class.getClassLoader(), false);
309.32 }
309.33
309.34 String[] allClasses() {
310.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Tue Apr 29 15:25:58 2014 +0200
310.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeParser.java Wed Apr 30 15:04:10 2014 +0200
310.3 @@ -39,37 +39,6 @@
310.4 final class ByteCodeParser {
310.5 private ByteCodeParser() {
310.6 }
310.7 - /* Signature Characters */
310.8 - public static final char SIGC_VOID = 'V';
310.9 - public static final String SIG_VOID = "V";
310.10 - public static final char SIGC_BOOLEAN = 'Z';
310.11 - public static final String SIG_BOOLEAN = "Z";
310.12 - public static final char SIGC_BYTE = 'B';
310.13 - public static final String SIG_BYTE = "B";
310.14 - public static final char SIGC_CHAR = 'C';
310.15 - public static final String SIG_CHAR = "C";
310.16 - public static final char SIGC_SHORT = 'S';
310.17 - public static final String SIG_SHORT = "S";
310.18 - public static final char SIGC_INT = 'I';
310.19 - public static final String SIG_INT = "I";
310.20 - public static final char SIGC_LONG = 'J';
310.21 - public static final String SIG_LONG = "J";
310.22 - public static final char SIGC_FLOAT = 'F';
310.23 - public static final String SIG_FLOAT = "F";
310.24 - public static final char SIGC_DOUBLE = 'D';
310.25 - public static final String SIG_DOUBLE = "D";
310.26 - public static final char SIGC_ARRAY = '[';
310.27 - public static final String SIG_ARRAY = "[";
310.28 - public static final char SIGC_CLASS = 'L';
310.29 - public static final String SIG_CLASS = "L";
310.30 - public static final char SIGC_METHOD = '(';
310.31 - public static final String SIG_METHOD = "(";
310.32 - public static final char SIGC_ENDCLASS = ';';
310.33 - public static final String SIG_ENDCLASS = ";";
310.34 - public static final char SIGC_ENDMETHOD = ')';
310.35 - public static final String SIG_ENDMETHOD = ")";
310.36 - public static final char SIGC_PACKAGE = '/';
310.37 - public static final String SIG_PACKAGE = "/";
310.38
310.39 /* Class File Constants */
310.40 public static final int JAVA_MAGIC = 0xcafebabe;
310.41 @@ -107,17 +76,6 @@
310.42 public static final int ACC_EXPLICIT = 0x00001000;
310.43 public static final int ACC_SYNTHETIC = 0x00010000; // actually, this is an attribute
310.44
310.45 - /* Type codes */
310.46 - public static final int T_CLASS = 0x00000002;
310.47 - public static final int T_BOOLEAN = 0x00000004;
310.48 - public static final int T_CHAR = 0x00000005;
310.49 - public static final int T_FLOAT = 0x00000006;
310.50 - public static final int T_DOUBLE = 0x00000007;
310.51 - public static final int T_BYTE = 0x00000008;
310.52 - public static final int T_SHORT = 0x00000009;
310.53 - public static final int T_INT = 0x0000000a;
310.54 - public static final int T_LONG = 0x0000000b;
310.55 -
310.56 /* Type codes for StackMap attribute */
310.57 public static final int ITEM_Bogus =0; // an unknown or uninitialized value
310.58 public static final int ITEM_Integer =1; // a 32-bit integer
310.59 @@ -358,7 +316,7 @@
310.60 public static final int opc_nonpriv = 254;
310.61 public static final int opc_priv = 255;
310.62
310.63 - /* Wide instructions */
310.64 + /* Wide instructions *
310.65 public static final int opc_iload_w = (opc_wide<<8)|opc_iload;
310.66 public static final int opc_lload_w = (opc_wide<<8)|opc_lload;
310.67 public static final int opc_fload_w = (opc_wide<<8)|opc_fload;
310.68 @@ -371,762 +329,7 @@
310.69 public static final int opc_astore_w = (opc_wide<<8)|opc_astore;
310.70 public static final int opc_ret_w = (opc_wide<<8)|opc_ret;
310.71 public static final int opc_iinc_w = (opc_wide<<8)|opc_iinc;
310.72 -
310.73 - /* Opcode Names */
310.74 - public static final String opcNamesTab[] = {
310.75 - "nop",
310.76 - "aconst_null",
310.77 - "iconst_m1",
310.78 - "iconst_0",
310.79 - "iconst_1",
310.80 - "iconst_2",
310.81 - "iconst_3",
310.82 - "iconst_4",
310.83 - "iconst_5",
310.84 - "lconst_0",
310.85 - "lconst_1",
310.86 - "fconst_0",
310.87 - "fconst_1",
310.88 - "fconst_2",
310.89 - "dconst_0",
310.90 - "dconst_1",
310.91 - "bipush",
310.92 - "sipush",
310.93 - "ldc",
310.94 - "ldc_w",
310.95 - "ldc2_w",
310.96 - "iload",
310.97 - "lload",
310.98 - "fload",
310.99 - "dload",
310.100 - "aload",
310.101 - "iload_0",
310.102 - "iload_1",
310.103 - "iload_2",
310.104 - "iload_3",
310.105 - "lload_0",
310.106 - "lload_1",
310.107 - "lload_2",
310.108 - "lload_3",
310.109 - "fload_0",
310.110 - "fload_1",
310.111 - "fload_2",
310.112 - "fload_3",
310.113 - "dload_0",
310.114 - "dload_1",
310.115 - "dload_2",
310.116 - "dload_3",
310.117 - "aload_0",
310.118 - "aload_1",
310.119 - "aload_2",
310.120 - "aload_3",
310.121 - "iaload",
310.122 - "laload",
310.123 - "faload",
310.124 - "daload",
310.125 - "aaload",
310.126 - "baload",
310.127 - "caload",
310.128 - "saload",
310.129 - "istore",
310.130 - "lstore",
310.131 - "fstore",
310.132 - "dstore",
310.133 - "astore",
310.134 - "istore_0",
310.135 - "istore_1",
310.136 - "istore_2",
310.137 - "istore_3",
310.138 - "lstore_0",
310.139 - "lstore_1",
310.140 - "lstore_2",
310.141 - "lstore_3",
310.142 - "fstore_0",
310.143 - "fstore_1",
310.144 - "fstore_2",
310.145 - "fstore_3",
310.146 - "dstore_0",
310.147 - "dstore_1",
310.148 - "dstore_2",
310.149 - "dstore_3",
310.150 - "astore_0",
310.151 - "astore_1",
310.152 - "astore_2",
310.153 - "astore_3",
310.154 - "iastore",
310.155 - "lastore",
310.156 - "fastore",
310.157 - "dastore",
310.158 - "aastore",
310.159 - "bastore",
310.160 - "castore",
310.161 - "sastore",
310.162 - "pop",
310.163 - "pop2",
310.164 - "dup",
310.165 - "dup_x1",
310.166 - "dup_x2",
310.167 - "dup2",
310.168 - "dup2_x1",
310.169 - "dup2_x2",
310.170 - "swap",
310.171 - "iadd",
310.172 - "ladd",
310.173 - "fadd",
310.174 - "dadd",
310.175 - "isub",
310.176 - "lsub",
310.177 - "fsub",
310.178 - "dsub",
310.179 - "imul",
310.180 - "lmul",
310.181 - "fmul",
310.182 - "dmul",
310.183 - "idiv",
310.184 - "ldiv",
310.185 - "fdiv",
310.186 - "ddiv",
310.187 - "irem",
310.188 - "lrem",
310.189 - "frem",
310.190 - "drem",
310.191 - "ineg",
310.192 - "lneg",
310.193 - "fneg",
310.194 - "dneg",
310.195 - "ishl",
310.196 - "lshl",
310.197 - "ishr",
310.198 - "lshr",
310.199 - "iushr",
310.200 - "lushr",
310.201 - "iand",
310.202 - "land",
310.203 - "ior",
310.204 - "lor",
310.205 - "ixor",
310.206 - "lxor",
310.207 - "iinc",
310.208 - "i2l",
310.209 - "i2f",
310.210 - "i2d",
310.211 - "l2i",
310.212 - "l2f",
310.213 - "l2d",
310.214 - "f2i",
310.215 - "f2l",
310.216 - "f2d",
310.217 - "d2i",
310.218 - "d2l",
310.219 - "d2f",
310.220 - "i2b",
310.221 - "i2c",
310.222 - "i2s",
310.223 - "lcmp",
310.224 - "fcmpl",
310.225 - "fcmpg",
310.226 - "dcmpl",
310.227 - "dcmpg",
310.228 - "ifeq",
310.229 - "ifne",
310.230 - "iflt",
310.231 - "ifge",
310.232 - "ifgt",
310.233 - "ifle",
310.234 - "if_icmpeq",
310.235 - "if_icmpne",
310.236 - "if_icmplt",
310.237 - "if_icmpge",
310.238 - "if_icmpgt",
310.239 - "if_icmple",
310.240 - "if_acmpeq",
310.241 - "if_acmpne",
310.242 - "goto",
310.243 - "jsr",
310.244 - "ret",
310.245 - "tableswitch",
310.246 - "lookupswitch",
310.247 - "ireturn",
310.248 - "lreturn",
310.249 - "freturn",
310.250 - "dreturn",
310.251 - "areturn",
310.252 - "return",
310.253 - "getstatic",
310.254 - "putstatic",
310.255 - "getfield",
310.256 - "putfield",
310.257 - "invokevirtual",
310.258 - "invokespecial", // was "invokenonvirtual",
310.259 - "invokestatic",
310.260 - "invokeinterface",
310.261 - "bytecode 186", //"xxxunusedxxx",
310.262 - "new",
310.263 - "newarray",
310.264 - "anewarray",
310.265 - "arraylength",
310.266 - "athrow",
310.267 - "checkcast",
310.268 - "instanceof",
310.269 - "monitorenter",
310.270 - "monitorexit",
310.271 - null, // "wide",
310.272 - "multianewarray",
310.273 - "ifnull",
310.274 - "ifnonnull",
310.275 - "goto_w",
310.276 - "jsr_w",
310.277 - "bytecode 202", // "breakpoint",
310.278 - "bytecode",
310.279 - "try",
310.280 - "endtry",
310.281 - "catch",
310.282 - "var",
310.283 - "endvar",
310.284 - "locals_map",
310.285 - "stack_map"
310.286 - };
310.287 -
310.288 - /* Opcode Lengths */
310.289 - public static final int opcLengthsTab[] = {
310.290 - 1,
310.291 - 1,
310.292 - 1,
310.293 - 1,
310.294 - 1,
310.295 - 1,
310.296 - 1,
310.297 - 1,
310.298 - 1,
310.299 - 1,
310.300 - 1,
310.301 - 1,
310.302 - 1,
310.303 - 1,
310.304 - 1,
310.305 - 1,
310.306 - 2,
310.307 - 3,
310.308 - 2,
310.309 - 3,
310.310 - 3,
310.311 - 2,
310.312 - 2,
310.313 - 2,
310.314 - 2,
310.315 - 2,
310.316 - 1,
310.317 - 1,
310.318 - 1,
310.319 - 1,
310.320 - 1,
310.321 - 1,
310.322 - 1,
310.323 - 1,
310.324 - 1,
310.325 - 1,
310.326 - 1,
310.327 - 1,
310.328 - 1,
310.329 - 1,
310.330 - 1,
310.331 - 1,
310.332 - 1,
310.333 - 1,
310.334 - 1,
310.335 - 1,
310.336 - 1,
310.337 - 1,
310.338 - 1,
310.339 - 1,
310.340 - 1,
310.341 - 1,
310.342 - 1,
310.343 - 1,
310.344 - 2,
310.345 - 2,
310.346 - 2,
310.347 - 2,
310.348 - 2,
310.349 - 1,
310.350 - 1,
310.351 - 1,
310.352 - 1,
310.353 - 1,
310.354 - 1,
310.355 - 1,
310.356 - 1,
310.357 - 1,
310.358 - 1,
310.359 - 1,
310.360 - 1,
310.361 - 1,
310.362 - 1,
310.363 - 1,
310.364 - 1,
310.365 - 1,
310.366 - 1,
310.367 - 1,
310.368 - 1,
310.369 - 1,
310.370 - 1,
310.371 - 1,
310.372 - 1,
310.373 - 1,
310.374 - 1,
310.375 - 1,
310.376 - 1,
310.377 - 1,
310.378 - 1,
310.379 - 1,
310.380 - 1,
310.381 - 1,
310.382 - 1,
310.383 - 1,
310.384 - 1,
310.385 - 1,
310.386 - 1,
310.387 - 1,
310.388 - 1,
310.389 - 1,
310.390 - 1,
310.391 - 1,
310.392 - 1,
310.393 - 1,
310.394 - 1,
310.395 - 1,
310.396 - 1,
310.397 - 1,
310.398 - 1,
310.399 - 1,
310.400 - 1,
310.401 - 1,
310.402 - 1,
310.403 - 1,
310.404 - 1,
310.405 - 1,
310.406 - 1,
310.407 - 1,
310.408 - 1,
310.409 - 1,
310.410 - 1,
310.411 - 1,
310.412 - 1,
310.413 - 1,
310.414 - 1,
310.415 - 1,
310.416 - 1,
310.417 - 1,
310.418 - 1,
310.419 - 1,
310.420 - 1,
310.421 - 1,
310.422 - 3,
310.423 - 1,
310.424 - 1,
310.425 - 1,
310.426 - 1,
310.427 - 1,
310.428 - 1,
310.429 - 1,
310.430 - 1,
310.431 - 1,
310.432 - 1,
310.433 - 1,
310.434 - 1,
310.435 - 1,
310.436 - 1,
310.437 - 1,
310.438 - 1,
310.439 - 1,
310.440 - 1,
310.441 - 1,
310.442 - 1,
310.443 - 3,
310.444 - 3,
310.445 - 3,
310.446 - 3,
310.447 - 3,
310.448 - 3,
310.449 - 3,
310.450 - 3,
310.451 - 3,
310.452 - 3,
310.453 - 3,
310.454 - 3,
310.455 - 3,
310.456 - 3,
310.457 - 3,
310.458 - 3,
310.459 - 2,
310.460 - 99,
310.461 - 99,
310.462 - 1,
310.463 - 1,
310.464 - 1,
310.465 - 1,
310.466 - 1,
310.467 - 1,
310.468 - 3,
310.469 - 3,
310.470 - 3,
310.471 - 3,
310.472 - 3,
310.473 - 3,
310.474 - 3,
310.475 - 5,
310.476 - 0,
310.477 - 3,
310.478 - 2,
310.479 - 3,
310.480 - 1,
310.481 - 1,
310.482 - 3,
310.483 - 3,
310.484 - 1,
310.485 - 1,
310.486 - 0, // wide
310.487 - 4,
310.488 - 3,
310.489 - 3,
310.490 - 5,
310.491 - 5,
310.492 - 1,
310.493 - 1, 0, 0, 0, 0, 0 // pseudo
310.494 - };
310.495 -
310.496 - /**
310.497 - * End of input
310.498 - */
310.499 - public static final int EOF = -1;
310.500 -
310.501 - /*
310.502 - * Flags
310.503 - */
310.504 - public static final int F_VERBOSE = 1 << 0;
310.505 - public static final int F_DUMP = 1 << 1;
310.506 - public static final int F_WARNINGS = 1 << 2;
310.507 - public static final int F_DEBUG = 1 << 3;
310.508 - public static final int F_OPTIMIZE = 1 << 4;
310.509 - public static final int F_DEPENDENCIES = 1 << 5;
310.510 -
310.511 - /*
310.512 - * Type codes
310.513 - */
310.514 - public static final int TC_BOOLEAN = 0;
310.515 - public static final int TC_BYTE = 1;
310.516 - public static final int TC_CHAR = 2;
310.517 - public static final int TC_SHORT = 3;
310.518 - public static final int TC_INT = 4;
310.519 - public static final int TC_LONG = 5;
310.520 - public static final int TC_FLOAT = 6;
310.521 - public static final int TC_DOUBLE = 7;
310.522 - public static final int TC_NULL = 8;
310.523 - public static final int TC_ARRAY = 9;
310.524 - public static final int TC_CLASS = 10;
310.525 - public static final int TC_VOID = 11;
310.526 - public static final int TC_METHOD = 12;
310.527 - public static final int TC_ERROR = 13;
310.528 -
310.529 - /*
310.530 - * Type Masks
310.531 - */
310.532 - public static final int TM_NULL = 1 << TC_NULL;
310.533 - public static final int TM_VOID = 1 << TC_VOID;
310.534 - public static final int TM_BOOLEAN = 1 << TC_BOOLEAN;
310.535 - public static final int TM_BYTE = 1 << TC_BYTE;
310.536 - public static final int TM_CHAR = 1 << TC_CHAR;
310.537 - public static final int TM_SHORT = 1 << TC_SHORT;
310.538 - public static final int TM_INT = 1 << TC_INT;
310.539 - public static final int TM_LONG = 1 << TC_LONG;
310.540 - public static final int TM_FLOAT = 1 << TC_FLOAT;
310.541 - public static final int TM_DOUBLE = 1 << TC_DOUBLE;
310.542 - public static final int TM_ARRAY = 1 << TC_ARRAY;
310.543 - public static final int TM_CLASS = 1 << TC_CLASS;
310.544 - public static final int TM_METHOD = 1 << TC_METHOD;
310.545 - public static final int TM_ERROR = 1 << TC_ERROR;
310.546 -
310.547 - public static final int TM_INT32 = TM_BYTE | TM_SHORT | TM_CHAR | TM_INT;
310.548 - public static final int TM_NUM32 = TM_INT32 | TM_FLOAT;
310.549 - public static final int TM_NUM64 = TM_LONG | TM_DOUBLE;
310.550 - public static final int TM_INTEGER = TM_INT32 | TM_LONG;
310.551 - public static final int TM_REAL = TM_FLOAT | TM_DOUBLE;
310.552 - public static final int TM_NUMBER = TM_INTEGER | TM_REAL;
310.553 - public static final int TM_REFERENCE = TM_ARRAY | TM_CLASS | TM_NULL;
310.554 -
310.555 - /*
310.556 - * Class status
310.557 - */
310.558 - public static final int CS_UNDEFINED = 0;
310.559 - public static final int CS_UNDECIDED = 1;
310.560 - public static final int CS_BINARY = 2;
310.561 - public static final int CS_SOURCE = 3;
310.562 - public static final int CS_PARSED = 4;
310.563 - public static final int CS_COMPILED = 5;
310.564 - public static final int CS_NOTFOUND = 6;
310.565 -
310.566 - /*
310.567 - * Attributes
310.568 - */
310.569 - public static final int ATT_ALL = -1;
310.570 - public static final int ATT_CODE = 1;
310.571 -
310.572 - /*
310.573 - * Number of bits used in file offsets
310.574 - */
310.575 - public static final int OFFSETBITS = 19;
310.576 - public static final int MAXFILESIZE = (1 << OFFSETBITS) - 1;
310.577 - public static final int MAXLINENUMBER = (1 << (32 - OFFSETBITS)) - 1;
310.578 -
310.579 - /*
310.580 - * Operators
310.581 - */
310.582 - public final int COMMA = 0;
310.583 - public final int ASSIGN = 1;
310.584 -
310.585 - public final int ASGMUL = 2;
310.586 - public final int ASGDIV = 3;
310.587 - public final int ASGREM = 4;
310.588 - public final int ASGADD = 5;
310.589 - public final int ASGSUB = 6;
310.590 - public final int ASGLSHIFT = 7;
310.591 - public final int ASGRSHIFT = 8;
310.592 - public final int ASGURSHIFT = 9;
310.593 - public final int ASGBITAND = 10;
310.594 - public final int ASGBITOR = 11;
310.595 - public final int ASGBITXOR = 12;
310.596 -
310.597 - public final int COND = 13;
310.598 - public final int OR = 14;
310.599 - public final int AND = 15;
310.600 - public final int BITOR = 16;
310.601 - public final int BITXOR = 17;
310.602 - public final int BITAND = 18;
310.603 - public final int NE = 19;
310.604 - public final int EQ = 20;
310.605 - public final int GE = 21;
310.606 - public final int GT = 22;
310.607 - public final int LE = 23;
310.608 - public final int LT = 24;
310.609 - public final int INSTANCEOF = 25;
310.610 - public final int LSHIFT = 26;
310.611 - public final int RSHIFT = 27;
310.612 - public final int URSHIFT = 28;
310.613 - public final int ADD = 29;
310.614 - public final int SUB = 30;
310.615 - public final int DIV = 31;
310.616 - public final int REM = 32;
310.617 - public final int MUL = 33;
310.618 - public final int CAST = 34; // (x)y
310.619 - public final int POS = 35; // +x
310.620 - public final int NEG = 36; // -x
310.621 - public final int NOT = 37;
310.622 - public final int BITNOT = 38;
310.623 - public final int PREINC = 39; // ++x
310.624 - public final int PREDEC = 40; // --x
310.625 - public final int NEWARRAY = 41;
310.626 - public final int NEWINSTANCE = 42;
310.627 - public final int NEWFROMNAME = 43;
310.628 - public final int POSTINC = 44; // x++
310.629 - public final int POSTDEC = 45; // x--
310.630 - public final int FIELD = 46;
310.631 - public final int METHOD = 47; // x(y)
310.632 - public final int ARRAYACCESS = 48; // x[y]
310.633 - public final int NEW = 49;
310.634 - public final int INC = 50;
310.635 - public final int DEC = 51;
310.636 -
310.637 - public final int CONVERT = 55; // implicit conversion
310.638 - public final int EXPR = 56; // (x)
310.639 - public final int ARRAY = 57; // {x, y, ...}
310.640 - public final int GOTO = 58;
310.641 -
310.642 - /*
310.643 - * Value tokens
310.644 - */
310.645 - public final int IDENT = 60;
310.646 - public final int BOOLEANVAL = 61;
310.647 - public final int BYTEVAL = 62;
310.648 - public final int CHARVAL = 63;
310.649 - public final int SHORTVAL = 64;
310.650 - public final int INTVAL = 65;
310.651 - public final int LONGVAL = 66;
310.652 - public final int FLOATVAL = 67;
310.653 - public final int DOUBLEVAL = 68;
310.654 - public final int STRINGVAL = 69;
310.655 -
310.656 - /*
310.657 - * Type keywords
310.658 - */
310.659 - public final int BYTE = 70;
310.660 - public final int CHAR = 71;
310.661 - public final int SHORT = 72;
310.662 - public final int INT = 73;
310.663 - public final int LONG = 74;
310.664 - public final int FLOAT = 75;
310.665 - public final int DOUBLE = 76;
310.666 - public final int VOID = 77;
310.667 - public final int BOOLEAN = 78;
310.668 -
310.669 - /*
310.670 - * Expression keywords
310.671 - */
310.672 - public final int TRUE = 80;
310.673 - public final int FALSE = 81;
310.674 - public final int THIS = 82;
310.675 - public final int SUPER = 83;
310.676 - public final int NULL = 84;
310.677 -
310.678 - /*
310.679 - * Statement keywords
310.680 - */
310.681 - public final int IF = 90;
310.682 - public final int ELSE = 91;
310.683 - public final int FOR = 92;
310.684 - public final int WHILE = 93;
310.685 - public final int DO = 94;
310.686 - public final int SWITCH = 95;
310.687 - public final int CASE = 96;
310.688 - public final int DEFAULT = 97;
310.689 - public final int BREAK = 98;
310.690 - public final int CONTINUE = 99;
310.691 - public final int RETURN = 100;
310.692 - public final int TRY = 101;
310.693 - public final int CATCH = 102;
310.694 - public final int FINALLY = 103;
310.695 - public final int THROW = 104;
310.696 - public final int STAT = 105;
310.697 - public final int EXPRESSION = 106;
310.698 - public final int DECLARATION = 107;
310.699 - public final int VARDECLARATION = 108;
310.700 -
310.701 - /*
310.702 - * Declaration keywords
310.703 - */
310.704 - public final int IMPORT = 110;
310.705 - public final int CLASS = 111;
310.706 - public final int EXTENDS = 112;
310.707 - public final int IMPLEMENTS = 113;
310.708 - public final int INTERFACE = 114;
310.709 - public final int PACKAGE = 115;
310.710 -
310.711 - /*
310.712 - * Modifier keywords
310.713 - */
310.714 - public final int PRIVATE = 120;
310.715 - public final int PUBLIC = 121;
310.716 - public final int PROTECTED = 122;
310.717 - public final int CONST = 123;
310.718 - public final int STATIC = 124;
310.719 - public final int TRANSIENT = 125;
310.720 - public final int SYNCHRONIZED = 126;
310.721 - public final int NATIVE = 127;
310.722 - public final int FINAL = 128;
310.723 - public final int VOLATILE = 129;
310.724 - public final int ABSTRACT = 130;
310.725 - public final int STRICT = 165;
310.726 -
310.727 - /*
310.728 - * Punctuation
310.729 - */
310.730 - public final int SEMICOLON = 135;
310.731 - public final int COLON = 136;
310.732 - public final int QUESTIONMARK = 137;
310.733 - public final int LBRACE = 138;
310.734 - public final int RBRACE = 139;
310.735 - public final int LPAREN = 140;
310.736 - public final int RPAREN = 141;
310.737 - public final int LSQBRACKET = 142;
310.738 - public final int RSQBRACKET = 143;
310.739 - public final int THROWS = 144;
310.740 -
310.741 - /*
310.742 - * Special tokens
310.743 - */
310.744 - public final int ERROR = 145; // an error
310.745 - public final int COMMENT = 146; // not used anymore.
310.746 - public final int TYPE = 147;
310.747 - public final int LENGTH = 148;
310.748 - public final int INLINERETURN = 149;
310.749 - public final int INLINEMETHOD = 150;
310.750 - public final int INLINENEWINSTANCE = 151;
310.751 -
310.752 - /*
310.753 - * Added for jasm
310.754 - */
310.755 - public final int METHODREF = 152;
310.756 - public final int FIELDREF = 153;
310.757 - public final int STACK = 154;
310.758 - public final int LOCAL = 155;
310.759 - public final int CPINDEX = 156;
310.760 - public final int CPNAME = 157;
310.761 - public final int SIGN = 158;
310.762 - public final int BITS = 159;
310.763 - public final int INF = 160;
310.764 - public final int NAN = 161;
310.765 - public final int INNERCLASS = 162;
310.766 - public final int OF = 163;
310.767 - public final int SYNTHETIC = 164;
310.768 -// last used=165;
310.769 -
310.770 - /*
310.771 - * Operator precedence
310.772 - */
310.773 - public static final int opPrecedence[] = {
310.774 - 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
310.775 - 11, 11, 11, 12, 13, 14, 15, 16, 17, 18,
310.776 - 18, 19, 19, 19, 19, 19, 20, 20, 20, 21,
310.777 - 21, 22, 22, 22, 23, 24, 24, 24, 24, 24,
310.778 - 24, 25, 25, 26, 26, 26, 26, 26, 26
310.779 - };
310.780 -
310.781 - /*
310.782 - * Operator names
310.783 - */
310.784 - public static final String opNames[] = {
310.785 - ",", "=", "*=", "/=", "%=",
310.786 - "+=", "-=", "<<=", ">>=", "<<<=",
310.787 - "&=", "|=", "^=", "?:", "||",
310.788 - "&&", "|", "^", "&", "!=",
310.789 - "==", ">=", ">", "<=", "<",
310.790 - "instanceof", "<<", ">>", "<<<", "+",
310.791 - "-", "/", "%", "*", "cast",
310.792 - "+", "-", "!", "~", "++",
310.793 - "--", "new", "new", "new", "++",
310.794 - "--", "field", "method", "[]", "new",
310.795 - "++", "--", null, null, null,
310.796 -
310.797 - "convert", "expr", "array", "goto", null,
310.798 -
310.799 - "Identifier", "Boolean", "Byte", "Char", "Short",
310.800 - "Integer", "Long", "Float", "Double", "String",
310.801 -
310.802 - "byte", "char", "short", "int", "long",
310.803 - "float", "double", "void", "boolean", null,
310.804 -
310.805 - "true", "false", "this", "super", "null",
310.806 - null, null, null, null, null,
310.807 -
310.808 - "if", "else", "for", "while", "do",
310.809 - "switch", "case", "default", "break", "continue",
310.810 - "return", "try", "catch", "finally", "throw",
310.811 - "stat", "expression", "declaration", "declaration", null,
310.812 -
310.813 - "import", "class", "extends", "implements", "interface",
310.814 - "package", null, null, null, null,
310.815 -
310.816 - "private", "public", "protected", "const", "static",
310.817 - "transient", "synchronized", "native", "final", "volatile",
310.818 - "abstract", null, null, null, null,
310.819 -
310.820 - ";", ":", "?", "{", "}",
310.821 - "(", ")", "[", "]", "throws",
310.822 - "error", "comment", "type", "length", "inline-return",
310.823 - "inline-method", "inline-new",
310.824 - "method", "field", "stack", "locals", "CPINDEX", "CPName", "SIGN",
310.825 - "bits", "INF", "NaN", "InnerClass", "of", "synthetic"
310.826 - };
310.827 -
310.828 +*/
310.829 static class AnnotationParser {
310.830
310.831 private final boolean textual;
310.832 @@ -1332,15 +535,11 @@
310.833 private int super_class;
310.834 private int interfaces_count;
310.835 private int[] interfaces = new int[0];
310.836 - private int fields_count;
310.837 private FieldData[] fields;
310.838 - private int methods_count;
310.839 private MethodData[] methods;
310.840 private InnerClassData[] innerClasses;
310.841 private int attributes_count;
310.842 private AttrData[] attrs;
310.843 - private String classname;
310.844 - private String superclassname;
310.845 private int source_cpx = 0;
310.846 private byte tags[];
310.847 private Hashtable indexHashAscii = new Hashtable();
310.848 @@ -1845,6 +1044,12 @@
310.849 case '\"':
310.850 sb.append('\\').append('\"');
310.851 break;
310.852 + case '\u2028':
310.853 + sb.append("\\u2028");
310.854 + break;
310.855 + case '\u2029':
310.856 + sb.append("\\u2029");
310.857 + break;
310.858 default:
310.859 sb.append(c);
310.860 }
310.861 @@ -2080,7 +1285,7 @@
310.862 int name_index;
310.863 int descriptor_index;
310.864 int attributes_count;
310.865 - int value_cpx = 0;
310.866 + int value_cpx = -1;
310.867 boolean isSynthetic = false;
310.868 boolean isDeprecated = false;
310.869 Vector attrs;
310.870 @@ -2201,11 +1406,8 @@
310.871 return isDeprecated;
310.872 }
310.873
310.874 - /**
310.875 - * Returns index of constant value in cpool.
310.876 - */
310.877 - public int getConstantValueIndex() {
310.878 - return (value_cpx);
310.879 + public boolean hasConstantValue() {
310.880 + return value_cpx != -1;
310.881 }
310.882
310.883 /**
310.884 @@ -2824,6 +2026,10 @@
310.885 lastFrameByteCodeOffset = -1;
310.886 advanceBy(0);
310.887 }
310.888 +
310.889 + public boolean isEmpty() {
310.890 + return stackMapTable.length == 0;
310.891 + }
310.892
310.893 public String getFrameAsString() {
310.894 return (nextFrameIndex == 0)
311.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Apr 29 15:25:58 2014 +0200
311.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Apr 30 15:04:10 2014 +0200
311.3 @@ -25,14 +25,36 @@
311.4 *
311.5 * @author Jaroslav Tulach <jtulach@netbeans.org>
311.6 */
311.7 -abstract class ByteCodeToJavaScript {
311.8 +abstract class ByteCodeToJavaScript implements Appendable {
311.9 private ClassData jc;
311.10 - final Appendable out;
311.11 + private final Appendable out;
311.12 + private boolean outChanged;
311.13
311.14 protected ByteCodeToJavaScript(Appendable out) {
311.15 this.out = out;
311.16 }
311.17
311.18 + @Override
311.19 + public final Appendable append(CharSequence csq) throws IOException {
311.20 + out.append(csq);
311.21 + outChanged = true;
311.22 + return this;
311.23 + }
311.24 +
311.25 + @Override
311.26 + public final Appendable append(CharSequence csq, int start, int end) throws IOException {
311.27 + out.append(csq, start, end);
311.28 + outChanged = true;
311.29 + return this;
311.30 + }
311.31 +
311.32 + @Override
311.33 + public final Appendable append(char c) throws IOException {
311.34 + out.append(c);
311.35 + outChanged = true;
311.36 + return this;
311.37 + }
311.38 +
311.39 /* Collects additional required resources.
311.40 *
311.41 * @param internalClassName classes that were referenced and should be loaded in order the
311.42 @@ -99,7 +121,7 @@
311.43 * @throws IOException
311.44 */
311.45 boolean debug(String msg) throws IOException {
311.46 - out.append(msg);
311.47 + append(msg);
311.48 return true;
311.49 }
311.50
311.51 @@ -124,16 +146,34 @@
311.52 );
311.53 }
311.54 byte[] arrData = jc.findAnnotationData(true);
311.55 - String[] arr = findAnnotation(arrData, jc,
311.56 - "org.apidesign.bck2brwsr.core.ExtraJavaScript",
311.57 - "resource", "processByteCode"
311.58 - );
311.59 - if (arr != null) {
311.60 - if (!arr[0].isEmpty()) {
311.61 - requireScript(arr[0]);
311.62 + {
311.63 + String[] arr = findAnnotation(arrData, jc,
311.64 + "org.apidesign.bck2brwsr.core.ExtraJavaScript",
311.65 + "resource", "processByteCode"
311.66 + );
311.67 + if (arr != null) {
311.68 + if (!arr[0].isEmpty()) {
311.69 + requireScript(arr[0]);
311.70 + }
311.71 + if ("0".equals(arr[1])) {
311.72 + return null;
311.73 + }
311.74 }
311.75 - if ("0".equals(arr[1])) {
311.76 - return null;
311.77 + }
311.78 + {
311.79 + String[] arr = findAnnotation(arrData, jc,
311.80 + "net.java.html.js.JavaScriptResource",
311.81 + "value"
311.82 + );
311.83 + if (arr != null) {
311.84 + if (arr[0].startsWith("/")) {
311.85 + requireScript(arr[0]);
311.86 + } else {
311.87 + int last = jc.getClassName().lastIndexOf('/');
311.88 + requireScript(
311.89 + jc.getClassName().substring(0, last + 1).replace('.', '/') + arr[0]
311.90 + );
311.91 + }
311.92 }
311.93 }
311.94 String[] proto = findAnnotation(arrData, jc,
311.95 @@ -142,34 +182,39 @@
311.96 );
311.97 StringArray toInitilize = new StringArray();
311.98 final String className = className(jc);
311.99 - out.append("\n\n").append(assignClass(className));
311.100 - out.append("function ").append(className).append("() {");
311.101 - out.append("\n var CLS = ").append(className).append(';');
311.102 - out.append("\n if (!CLS.$class) {");
311.103 + append("\n\n").append(assignClass(className));
311.104 + append("function ").append(className).append("() {");
311.105 + append("\n var CLS = ").append(className).append(';');
311.106 + append("\n if (!CLS.$class) {");
311.107 if (proto == null) {
311.108 String sc = jc.getSuperClassName(); // with _
311.109 - out.append("\n var pp = ").
311.110 - append(accessClass(sc.replace('/', '_'))).append("(true);");
311.111 - out.append("\n var p = CLS.prototype = pp;");
311.112 - out.append("\n var c = p;");
311.113 - out.append("\n var sprcls = pp.constructor.$class;");
311.114 + append("\n var pp = ").
311.115 + append(accessClass(mangleClassName(sc))).append("(true);");
311.116 + append("\n var p = CLS.prototype = pp;");
311.117 + append("\n var c = p;");
311.118 + append("\n var sprcls = pp.constructor.$class;");
311.119 } else {
311.120 - out.append("\n var p = CLS.prototype = ").append(proto[1]).append(";");
311.121 + append("\n var p = CLS.prototype = ").append(proto[1]).append(";");
311.122 if (proto[0] == null) {
311.123 proto[0] = "p";
311.124 }
311.125 - out.append("\n var c = ").append(proto[0]).append(";");
311.126 - out.append("\n var sprcls = null;");
311.127 + append("\n var c = ").append(proto[0]).append(";");
311.128 + append("\n var sprcls = null;");
311.129 }
311.130 for (FieldData v : jc.getFields()) {
311.131 if (v.isStatic()) {
311.132 - out.append("\n CLS.").append(v.getName()).append(initField(v));
311.133 - out.append("\n c._").append(v.getName()).append(" = function (v) {")
311.134 - .append(" if (arguments.length == 1) CLS.").append(v.getName())
311.135 - .append(" = v; return CLS.").
311.136 + if ((v.access & ACC_FINAL) != 0 && v.hasConstantValue()) {
311.137 + if (v.getInternalSig().length() == 1 || v.getInternalSig().equals("Ljava/lang/String;")) {
311.138 + continue;
311.139 + }
311.140 + }
311.141 + append("\n CLS.fld_").append(v.getName()).append(initField(v));
311.142 + append("\n c._").append(v.getName()).append(" = function (v) {")
311.143 + .append(" if (arguments.length == 1) CLS.fld_").append(v.getName())
311.144 + .append(" = v; return CLS.fld_").
311.145 append(v.getName()).append("; };");
311.146 } else {
311.147 - out.append("\n c._").append(v.getName()).append(" = function (v) {")
311.148 + append("\n c._").append(v.getName()).append(" = function (v) {")
311.149 .append(" if (arguments.length == 1) this.fld_").
311.150 append(className).append('_').append(v.getName())
311.151 .append(" = v; return this.fld_").
311.152 @@ -187,14 +232,14 @@
311.153 );
311.154 if (only != null) {
311.155 if (only[0] != null && only[1] != null) {
311.156 - out.append("\n p.").append(only[0]).append(" = ")
311.157 + append("\n p.").append(only[0]).append(" = ")
311.158 .append(only[1]).append(";");
311.159 }
311.160 continue;
311.161 }
311.162 String destObject;
311.163 String mn;
311.164 - out.append("\n ");
311.165 + append("\n ");
311.166 if (m.isStatic()) {
311.167 destObject = "c";
311.168 mn = generateStaticMethod(destObject, m, toInitilize);
311.169 @@ -210,39 +255,47 @@
311.170 declaredMethod(m, destObject, mn);
311.171 byte[] runAnno = m.findAnnotationData(false);
311.172 if (runAnno != null) {
311.173 - out.append("\n ").append(destObject).append(".").append(mn).append(".anno = {");
311.174 - generateAnno(jc, out, runAnno);
311.175 - out.append("\n };");
311.176 + append("\n ").append(destObject).append(".").append(mn).append(".anno = {");
311.177 + generateAnno(jc, runAnno);
311.178 + append("\n };");
311.179 }
311.180 - out.append("\n ").append(destObject).append(".").append(mn).append(".access = " + m.getAccess()).append(";");
311.181 - out.append("\n ").append(destObject).append(".").append(mn).append(".cls = CLS;");
311.182 + append("\n ").append(destObject).append(".").append(mn).append(".access = " + m.getAccess()).append(";");
311.183 + append("\n ").append(destObject).append(".").append(mn).append(".cls = CLS;");
311.184 }
311.185 - out.append("\n c.constructor = CLS;");
311.186 - out.append("\n c['$instOf_").append(className).append("'] = true;");
311.187 + append("\n c.constructor = CLS;");
311.188 + append("\n function fillInstOf(x) {");
311.189 + String instOfName = "$instOf_" + className;
311.190 + append("\n x['").append(instOfName).append("'] = true;");
311.191 for (String superInterface : jc.getSuperInterfaces()) {
311.192 - out.append("\n c['$instOf_").append(superInterface.replace('/', '_')).append("'] = true;");
311.193 + String intrfc = superInterface.replace('/', '_');
311.194 + append("\n vm.").append(intrfc).append("(false)['fillInstOf'](x);");
311.195 + requireReference(superInterface);
311.196 }
311.197 - out.append("\n CLS.$class = 'temp';");
311.198 - out.append("\n CLS.$class = ");
311.199 - out.append(accessClass("java_lang_Class(true);"));
311.200 - out.append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
311.201 - out.append("\n CLS.$class.superclass = sprcls;");
311.202 - out.append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";");
311.203 - out.append("\n CLS.$class.cnstr = CLS;");
311.204 + append("\n }");
311.205 + append("\n c['fillInstOf'] = fillInstOf;");
311.206 + append("\n fillInstOf(c);");
311.207 +// obfuscationDelegate.exportJSProperty(this, "c", instOfName);
311.208 + append("\n CLS.$class = 'temp';");
311.209 + append("\n CLS.$class = ");
311.210 + append(accessClass("java_lang_Class(true);"));
311.211 + append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
311.212 + append("\n CLS.$class.superclass = sprcls;");
311.213 + append("\n CLS.$class.access = ").append(jc.getAccessFlags()+";");
311.214 + append("\n CLS.$class.cnstr = CLS;");
311.215 byte[] classAnno = jc.findAnnotationData(false);
311.216 if (classAnno != null) {
311.217 - out.append("\n CLS.$class.anno = {");
311.218 - generateAnno(jc, out, classAnno);
311.219 - out.append("\n };");
311.220 + append("\n CLS.$class.anno = {");
311.221 + generateAnno(jc, classAnno);
311.222 + append("\n };");
311.223 }
311.224 for (String init : toInitilize.toArray()) {
311.225 - out.append("\n ").append(init).append("();");
311.226 + append("\n ").append(init).append("();");
311.227 }
311.228 - out.append("\n }");
311.229 - out.append("\n if (arguments.length === 0) {");
311.230 - out.append("\n if (!(this instanceof CLS)) {");
311.231 - out.append("\n return new CLS();");
311.232 - out.append("\n }");
311.233 + append("\n }");
311.234 + append("\n if (arguments.length === 0) {");
311.235 + append("\n if (!(this instanceof CLS)) {");
311.236 + append("\n return new CLS();");
311.237 + append("\n }");
311.238 for (FieldData v : jc.getFields()) {
311.239 byte[] onlyArr = v.findAnnotationData(true);
311.240 String[] only = findAnnotation(onlyArr, jc,
311.241 @@ -251,21 +304,21 @@
311.242 );
311.243 if (only != null) {
311.244 if (only[0] != null && only[1] != null) {
311.245 - out.append("\n p.").append(only[0]).append(" = ")
311.246 + append("\n p.").append(only[0]).append(" = ")
311.247 .append(only[1]).append(";");
311.248 }
311.249 continue;
311.250 }
311.251 if (!v.isStatic()) {
311.252 - out.append("\n this.fld_").
311.253 + append("\n this.fld_").
311.254 append(className).append('_').
311.255 append(v.getName()).append(initField(v));
311.256 }
311.257 }
311.258 - out.append("\n return this;");
311.259 - out.append("\n }");
311.260 - out.append("\n return arguments[0] ? new CLS() : CLS.prototype;");
311.261 - out.append("\n};");
311.262 + append("\n return this;");
311.263 + append("\n }");
311.264 + append("\n return arguments[0] ? new CLS() : CLS.prototype;");
311.265 + append("\n};");
311.266
311.267 declaredClass(jc, className);
311.268
311.269 @@ -305,34 +358,43 @@
311.270 final LocalsMapper lmapper =
311.271 new LocalsMapper(stackMapIterator.getArguments());
311.272
311.273 - out.append(destObject).append(".").append(name).append(" = function(");
311.274 - lmapper.outputArguments(out, m.isStatic());
311.275 - out.append(") {").append("\n");
311.276 + append(destObject).append(".").append(name).append(" = function(");
311.277 + lmapper.outputArguments(this, m.isStatic());
311.278 + append(") {").append("\n");
311.279
311.280 final byte[] byteCodes = m.getCode();
311.281 if (byteCodes == null) {
311.282 - out.append(" throw 'no code found for ")
311.283 + append(" throw 'no code found for ")
311.284 .append(jc.getClassName()).append('.')
311.285 .append(m.getName()).append("';\n");
311.286 - out.append("};");
311.287 + append("};");
311.288 return;
311.289 }
311.290
311.291 final StackMapper smapper = new StackMapper();
311.292
311.293 if (!m.isStatic()) {
311.294 - out.append(" var ").append(" lcA0 = this;\n");
311.295 + append(" var ").append(" lcA0 = this;\n");
311.296 }
311.297
311.298 - int lastStackFrame = -1;
311.299 + int lastStackFrame;
311.300 TrapData[] previousTrap = null;
311.301 boolean wide = false;
311.302 + boolean didBranches;
311.303 + if (stackMapIterator.isEmpty()) {
311.304 + didBranches = false;
311.305 + lastStackFrame = 0;
311.306 + } else {
311.307 + didBranches = true;
311.308 + lastStackFrame = -1;
311.309 + append("\n var gt = 0;\n");
311.310 + }
311.311
311.312 - out.append("\n var gt = 0;\n");
311.313 int openBraces = 0;
311.314 int topMostLabel = 0;
311.315 for (int i = 0; i < byteCodes.length; i++) {
311.316 int prev = i;
311.317 + outChanged = false;
311.318 stackMapIterator.advanceTo(i);
311.319 boolean changeInCatch = trap.advanceTo(i);
311.320 if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) {
311.321 @@ -342,12 +404,13 @@
311.322 }
311.323 }
311.324 if (lastStackFrame != stackMapIterator.getFrameIndex()) {
311.325 + smapper.flush(this);
311.326 if (i != 0) {
311.327 - out.append(" }\n");
311.328 + append(" }\n");
311.329 }
311.330 if (openBraces > 64) {
311.331 for (int c = 0; c < 64; c++) {
311.332 - out.append("break;}\n");
311.333 + append("break;}\n");
311.334 }
311.335 openBraces = 1;
311.336 topMostLabel = i;
311.337 @@ -356,85 +419,84 @@
311.338 lastStackFrame = stackMapIterator.getFrameIndex();
311.339 lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals());
311.340 smapper.syncWithFrameStack(stackMapIterator.getFrameStack());
311.341 - out.append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
311.342 + append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
311.343 openBraces++;
311.344 changeInCatch = true;
311.345 } else {
311.346 debug(" /* " + i + " */ ");
311.347 }
311.348 if (changeInCatch && trap.useTry()) {
311.349 - out.append("try {");
311.350 + append("try {");
311.351 previousTrap = trap.current();
311.352 }
311.353 final int c = readUByte(byteCodes, i);
311.354 switch (c) {
311.355 case opc_aload_0:
311.356 - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(0));
311.357 + smapper.assign(this, VarType.REFERENCE, lmapper.getA(0));
311.358 break;
311.359 case opc_iload_0:
311.360 - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(0));
311.361 + smapper.assign(this, VarType.INTEGER, lmapper.getI(0));
311.362 break;
311.363 case opc_lload_0:
311.364 - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(0));
311.365 + smapper.assign(this, VarType.LONG, lmapper.getL(0));
311.366 break;
311.367 case opc_fload_0:
311.368 - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(0));
311.369 + smapper.assign(this, VarType.FLOAT, lmapper.getF(0));
311.370 break;
311.371 case opc_dload_0:
311.372 - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(0));
311.373 + smapper.assign(this, VarType.DOUBLE, lmapper.getD(0));
311.374 break;
311.375 case opc_aload_1:
311.376 - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(1));
311.377 + smapper.assign(this, VarType.REFERENCE, lmapper.getA(1));
311.378 break;
311.379 case opc_iload_1:
311.380 - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(1));
311.381 + smapper.assign(this, VarType.INTEGER, lmapper.getI(1));
311.382 break;
311.383 case opc_lload_1:
311.384 - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(1));
311.385 + smapper.assign(this, VarType.LONG, lmapper.getL(1));
311.386 break;
311.387 case opc_fload_1:
311.388 - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(1));
311.389 + smapper.assign(this, VarType.FLOAT, lmapper.getF(1));
311.390 break;
311.391 case opc_dload_1:
311.392 - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(1));
311.393 + smapper.assign(this, VarType.DOUBLE, lmapper.getD(1));
311.394 break;
311.395 case opc_aload_2:
311.396 - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(2));
311.397 + smapper.assign(this, VarType.REFERENCE, lmapper.getA(2));
311.398 break;
311.399 case opc_iload_2:
311.400 - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(2));
311.401 + smapper.assign(this, VarType.INTEGER, lmapper.getI(2));
311.402 break;
311.403 case opc_lload_2:
311.404 - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(2));
311.405 + smapper.assign(this, VarType.LONG, lmapper.getL(2));
311.406 break;
311.407 case opc_fload_2:
311.408 - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(2));
311.409 + smapper.assign(this, VarType.FLOAT, lmapper.getF(2));
311.410 break;
311.411 case opc_dload_2:
311.412 - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(2));
311.413 + smapper.assign(this, VarType.DOUBLE, lmapper.getD(2));
311.414 break;
311.415 case opc_aload_3:
311.416 - emit(out, "var @1 = @2;", smapper.pushA(), lmapper.getA(3));
311.417 + smapper.assign(this, VarType.REFERENCE, lmapper.getA(3));
311.418 break;
311.419 case opc_iload_3:
311.420 - emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(3));
311.421 + smapper.assign(this, VarType.INTEGER, lmapper.getI(3));
311.422 break;
311.423 case opc_lload_3:
311.424 - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(3));
311.425 + smapper.assign(this, VarType.LONG, lmapper.getL(3));
311.426 break;
311.427 case opc_fload_3:
311.428 - emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(3));
311.429 + smapper.assign(this, VarType.FLOAT, lmapper.getF(3));
311.430 break;
311.431 case opc_dload_3:
311.432 - emit(out, "var @1 = @2;", smapper.pushD(), lmapper.getD(3));
311.433 + smapper.assign(this, VarType.DOUBLE, lmapper.getD(3));
311.434 break;
311.435 case opc_iload: {
311.436 ++i;
311.437 final int indx = wide ? readUShort(byteCodes, i++)
311.438 : readUByte(byteCodes, i);
311.439 wide = false;
311.440 - emit(out, "var @1 = @2;",
311.441 - smapper.pushI(), lmapper.getI(indx));
311.442 + smapper.assign(this, VarType.INTEGER, lmapper.getI(indx));
311.443 break;
311.444 }
311.445 case opc_lload: {
311.446 @@ -442,8 +504,7 @@
311.447 final int indx = wide ? readUShort(byteCodes, i++)
311.448 : readUByte(byteCodes, i);
311.449 wide = false;
311.450 - emit(out, "var @1 = @2;",
311.451 - smapper.pushL(), lmapper.getL(indx));
311.452 + smapper.assign(this, VarType.LONG, lmapper.getL(indx));
311.453 break;
311.454 }
311.455 case opc_fload: {
311.456 @@ -451,8 +512,7 @@
311.457 final int indx = wide ? readUShort(byteCodes, i++)
311.458 : readUByte(byteCodes, i);
311.459 wide = false;
311.460 - emit(out, "var @1 = @2;",
311.461 - smapper.pushF(), lmapper.getF(indx));
311.462 + smapper.assign(this, VarType.FLOAT, lmapper.getF(indx));
311.463 break;
311.464 }
311.465 case opc_dload: {
311.466 @@ -460,8 +520,7 @@
311.467 final int indx = wide ? readUShort(byteCodes, i++)
311.468 : readUByte(byteCodes, i);
311.469 wide = false;
311.470 - emit(out, "var @1 = @2;",
311.471 - smapper.pushD(), lmapper.getD(indx));
311.472 + smapper.assign(this, VarType.DOUBLE, lmapper.getD(indx));
311.473 break;
311.474 }
311.475 case opc_aload: {
311.476 @@ -469,8 +528,7 @@
311.477 final int indx = wide ? readUShort(byteCodes, i++)
311.478 : readUByte(byteCodes, i);
311.479 wide = false;
311.480 - emit(out, "var @1 = @2;",
311.481 - smapper.pushA(), lmapper.getA(indx));
311.482 + smapper.assign(this, VarType.REFERENCE, lmapper.getA(indx));
311.483 break;
311.484 }
311.485 case opc_istore: {
311.486 @@ -478,7 +536,7 @@
311.487 final int indx = wide ? readUShort(byteCodes, i++)
311.488 : readUByte(byteCodes, i);
311.489 wide = false;
311.490 - emit(out, "var @1 = @2;",
311.491 + emit(smapper, this, "var @1 = @2;",
311.492 lmapper.setI(indx), smapper.popI());
311.493 break;
311.494 }
311.495 @@ -487,7 +545,7 @@
311.496 final int indx = wide ? readUShort(byteCodes, i++)
311.497 : readUByte(byteCodes, i);
311.498 wide = false;
311.499 - emit(out, "var @1 = @2;",
311.500 + emit(smapper, this, "var @1 = @2;",
311.501 lmapper.setL(indx), smapper.popL());
311.502 break;
311.503 }
311.504 @@ -496,7 +554,7 @@
311.505 final int indx = wide ? readUShort(byteCodes, i++)
311.506 : readUByte(byteCodes, i);
311.507 wide = false;
311.508 - emit(out, "var @1 = @2;",
311.509 + emit(smapper, this, "var @1 = @2;",
311.510 lmapper.setF(indx), smapper.popF());
311.511 break;
311.512 }
311.513 @@ -505,7 +563,7 @@
311.514 final int indx = wide ? readUShort(byteCodes, i++)
311.515 : readUByte(byteCodes, i);
311.516 wide = false;
311.517 - emit(out, "var @1 = @2;",
311.518 + emit(smapper, this, "var @1 = @2;",
311.519 lmapper.setD(indx), smapper.popD());
311.520 break;
311.521 }
311.522 @@ -514,181 +572,181 @@
311.523 final int indx = wide ? readUShort(byteCodes, i++)
311.524 : readUByte(byteCodes, i);
311.525 wide = false;
311.526 - emit(out, "var @1 = @2;",
311.527 + emit(smapper, this, "var @1 = @2;",
311.528 lmapper.setA(indx), smapper.popA());
311.529 break;
311.530 }
311.531 case opc_astore_0:
311.532 - emit(out, "var @1 = @2;", lmapper.setA(0), smapper.popA());
311.533 + emit(smapper, this, "var @1 = @2;", lmapper.setA(0), smapper.popA());
311.534 break;
311.535 case opc_istore_0:
311.536 - emit(out, "var @1 = @2;", lmapper.setI(0), smapper.popI());
311.537 + emit(smapper, this, "var @1 = @2;", lmapper.setI(0), smapper.popI());
311.538 break;
311.539 case opc_lstore_0:
311.540 - emit(out, "var @1 = @2;", lmapper.setL(0), smapper.popL());
311.541 + emit(smapper, this, "var @1 = @2;", lmapper.setL(0), smapper.popL());
311.542 break;
311.543 case opc_fstore_0:
311.544 - emit(out, "var @1 = @2;", lmapper.setF(0), smapper.popF());
311.545 + emit(smapper, this, "var @1 = @2;", lmapper.setF(0), smapper.popF());
311.546 break;
311.547 case opc_dstore_0:
311.548 - emit(out, "var @1 = @2;", lmapper.setD(0), smapper.popD());
311.549 + emit(smapper, this, "var @1 = @2;", lmapper.setD(0), smapper.popD());
311.550 break;
311.551 case opc_astore_1:
311.552 - emit(out, "var @1 = @2;", lmapper.setA(1), smapper.popA());
311.553 + emit(smapper, this, "var @1 = @2;", lmapper.setA(1), smapper.popA());
311.554 break;
311.555 case opc_istore_1:
311.556 - emit(out, "var @1 = @2;", lmapper.setI(1), smapper.popI());
311.557 + emit(smapper, this, "var @1 = @2;", lmapper.setI(1), smapper.popI());
311.558 break;
311.559 case opc_lstore_1:
311.560 - emit(out, "var @1 = @2;", lmapper.setL(1), smapper.popL());
311.561 + emit(smapper, this, "var @1 = @2;", lmapper.setL(1), smapper.popL());
311.562 break;
311.563 case opc_fstore_1:
311.564 - emit(out, "var @1 = @2;", lmapper.setF(1), smapper.popF());
311.565 + emit(smapper, this, "var @1 = @2;", lmapper.setF(1), smapper.popF());
311.566 break;
311.567 case opc_dstore_1:
311.568 - emit(out, "var @1 = @2;", lmapper.setD(1), smapper.popD());
311.569 + emit(smapper, this, "var @1 = @2;", lmapper.setD(1), smapper.popD());
311.570 break;
311.571 case opc_astore_2:
311.572 - emit(out, "var @1 = @2;", lmapper.setA(2), smapper.popA());
311.573 + emit(smapper, this, "var @1 = @2;", lmapper.setA(2), smapper.popA());
311.574 break;
311.575 case opc_istore_2:
311.576 - emit(out, "var @1 = @2;", lmapper.setI(2), smapper.popI());
311.577 + emit(smapper, this, "var @1 = @2;", lmapper.setI(2), smapper.popI());
311.578 break;
311.579 case opc_lstore_2:
311.580 - emit(out, "var @1 = @2;", lmapper.setL(2), smapper.popL());
311.581 + emit(smapper, this, "var @1 = @2;", lmapper.setL(2), smapper.popL());
311.582 break;
311.583 case opc_fstore_2:
311.584 - emit(out, "var @1 = @2;", lmapper.setF(2), smapper.popF());
311.585 + emit(smapper, this, "var @1 = @2;", lmapper.setF(2), smapper.popF());
311.586 break;
311.587 case opc_dstore_2:
311.588 - emit(out, "var @1 = @2;", lmapper.setD(2), smapper.popD());
311.589 + emit(smapper, this, "var @1 = @2;", lmapper.setD(2), smapper.popD());
311.590 break;
311.591 case opc_astore_3:
311.592 - emit(out, "var @1 = @2;", lmapper.setA(3), smapper.popA());
311.593 + emit(smapper, this, "var @1 = @2;", lmapper.setA(3), smapper.popA());
311.594 break;
311.595 case opc_istore_3:
311.596 - emit(out, "var @1 = @2;", lmapper.setI(3), smapper.popI());
311.597 + emit(smapper, this, "var @1 = @2;", lmapper.setI(3), smapper.popI());
311.598 break;
311.599 case opc_lstore_3:
311.600 - emit(out, "var @1 = @2;", lmapper.setL(3), smapper.popL());
311.601 + emit(smapper, this, "var @1 = @2;", lmapper.setL(3), smapper.popL());
311.602 break;
311.603 case opc_fstore_3:
311.604 - emit(out, "var @1 = @2;", lmapper.setF(3), smapper.popF());
311.605 + emit(smapper, this, "var @1 = @2;", lmapper.setF(3), smapper.popF());
311.606 break;
311.607 case opc_dstore_3:
311.608 - emit(out, "var @1 = @2;", lmapper.setD(3), smapper.popD());
311.609 + emit(smapper, this, "var @1 = @2;", lmapper.setD(3), smapper.popD());
311.610 break;
311.611 case opc_iadd:
311.612 - emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI());
311.613 + smapper.replace(this, VarType.INTEGER, "(@1).add32(@2)", smapper.getI(1), smapper.popI());
311.614 break;
311.615 case opc_ladd:
311.616 - emit(out, "@1 = @1.add64(@2);", smapper.getL(1), smapper.popL());
311.617 + smapper.replace(this, VarType.LONG, "(@1).add64(@2)", smapper.getL(1), smapper.popL());
311.618 break;
311.619 case opc_fadd:
311.620 - emit(out, "@1 += @2;", smapper.getF(1), smapper.popF());
311.621 + smapper.replace(this, VarType.FLOAT, "(@1 + @2)", smapper.getF(1), smapper.popF());
311.622 break;
311.623 case opc_dadd:
311.624 - emit(out, "@1 += @2;", smapper.getD(1), smapper.popD());
311.625 + smapper.replace(this, VarType.DOUBLE, "(@1 + @2)", smapper.getD(1), smapper.popD());
311.626 break;
311.627 case opc_isub:
311.628 - emit(out, "@1 = @1.sub32(@2);", smapper.getI(1), smapper.popI());
311.629 + smapper.replace(this, VarType.INTEGER, "(@1).sub32(@2)", smapper.getI(1), smapper.popI());
311.630 break;
311.631 case opc_lsub:
311.632 - emit(out, "@1 = @1.sub64(@2);", smapper.getL(1), smapper.popL());
311.633 + smapper.replace(this, VarType.LONG, "(@1).sub64(@2)", smapper.getL(1), smapper.popL());
311.634 break;
311.635 case opc_fsub:
311.636 - emit(out, "@1 -= @2;", smapper.getF(1), smapper.popF());
311.637 + smapper.replace(this, VarType.FLOAT, "(@1 - @2)", smapper.getF(1), smapper.popF());
311.638 break;
311.639 case opc_dsub:
311.640 - emit(out, "@1 -= @2;", smapper.getD(1), smapper.popD());
311.641 + smapper.replace(this, VarType.DOUBLE, "(@1 - @2)", smapper.getD(1), smapper.popD());
311.642 break;
311.643 case opc_imul:
311.644 - emit(out, "@1 = @1.mul32(@2);", smapper.getI(1), smapper.popI());
311.645 + smapper.replace(this, VarType.INTEGER, "(@1).mul32(@2)", smapper.getI(1), smapper.popI());
311.646 break;
311.647 case opc_lmul:
311.648 - emit(out, "@1 = @1.mul64(@2);", smapper.getL(1), smapper.popL());
311.649 + smapper.replace(this, VarType.LONG, "(@1).mul64(@2)", smapper.getL(1), smapper.popL());
311.650 break;
311.651 case opc_fmul:
311.652 - emit(out, "@1 *= @2;", smapper.getF(1), smapper.popF());
311.653 + smapper.replace(this, VarType.FLOAT, "(@1 * @2)", smapper.getF(1), smapper.popF());
311.654 break;
311.655 case opc_dmul:
311.656 - emit(out, "@1 *= @2;", smapper.getD(1), smapper.popD());
311.657 + smapper.replace(this, VarType.DOUBLE, "(@1 * @2)", smapper.getD(1), smapper.popD());
311.658 break;
311.659 case opc_idiv:
311.660 - emit(out, "@1 = @1.div32(@2);",
311.661 + smapper.replace(this, VarType.INTEGER, "(@1).div32(@2)",
311.662 smapper.getI(1), smapper.popI());
311.663 break;
311.664 case opc_ldiv:
311.665 - emit(out, "@1 = @1.div64(@2);",
311.666 + smapper.replace(this, VarType.LONG, "(@1).div64(@2)",
311.667 smapper.getL(1), smapper.popL());
311.668 break;
311.669 case opc_fdiv:
311.670 - emit(out, "@1 /= @2;", smapper.getF(1), smapper.popF());
311.671 + smapper.replace(this, VarType.FLOAT, "(@1 / @2)", smapper.getF(1), smapper.popF());
311.672 break;
311.673 case opc_ddiv:
311.674 - emit(out, "@1 /= @2;", smapper.getD(1), smapper.popD());
311.675 + smapper.replace(this, VarType.DOUBLE, "(@1 / @2)", smapper.getD(1), smapper.popD());
311.676 break;
311.677 case opc_irem:
311.678 - emit(out, "@1 = @1.mod32(@2);",
311.679 + smapper.replace(this, VarType.INTEGER, "(@1).mod32(@2)",
311.680 smapper.getI(1), smapper.popI());
311.681 break;
311.682 case opc_lrem:
311.683 - emit(out, "@1 = @1.mod64(@2);",
311.684 + smapper.replace(this, VarType.LONG, "(@1).mod64(@2)",
311.685 smapper.getL(1), smapper.popL());
311.686 break;
311.687 case opc_frem:
311.688 - emit(out, "@1 %= @2;", smapper.getF(1), smapper.popF());
311.689 + smapper.replace(this, VarType.FLOAT, "(@1 % @2)", smapper.getF(1), smapper.popF());
311.690 break;
311.691 case opc_drem:
311.692 - emit(out, "@1 %= @2;", smapper.getD(1), smapper.popD());
311.693 + smapper.replace(this, VarType.DOUBLE, "(@1 % @2)", smapper.getD(1), smapper.popD());
311.694 break;
311.695 case opc_iand:
311.696 - emit(out, "@1 &= @2;", smapper.getI(1), smapper.popI());
311.697 + smapper.replace(this, VarType.INTEGER, "(@1 & @2)", smapper.getI(1), smapper.popI());
311.698 break;
311.699 case opc_land:
311.700 - emit(out, "@1 = @1.and64(@2);", smapper.getL(1), smapper.popL());
311.701 + smapper.replace(this, VarType.LONG, "(@1).and64(@2)", smapper.getL(1), smapper.popL());
311.702 break;
311.703 case opc_ior:
311.704 - emit(out, "@1 |= @2;", smapper.getI(1), smapper.popI());
311.705 + smapper.replace(this, VarType.INTEGER, "(@1 | @2)", smapper.getI(1), smapper.popI());
311.706 break;
311.707 case opc_lor:
311.708 - emit(out, "@1 = @1.or64(@2);", smapper.getL(1), smapper.popL());
311.709 + smapper.replace(this, VarType.LONG, "(@1).or64(@2)", smapper.getL(1), smapper.popL());
311.710 break;
311.711 case opc_ixor:
311.712 - emit(out, "@1 ^= @2;", smapper.getI(1), smapper.popI());
311.713 + smapper.replace(this, VarType.INTEGER, "(@1 ^ @2)", smapper.getI(1), smapper.popI());
311.714 break;
311.715 case opc_lxor:
311.716 - emit(out, "@1 = @1.xor64(@2);", smapper.getL(1), smapper.popL());
311.717 + smapper.replace(this, VarType.LONG, "(@1).xor64(@2)", smapper.getL(1), smapper.popL());
311.718 break;
311.719 case opc_ineg:
311.720 - emit(out, "@1 = @1.neg32();", smapper.getI(0));
311.721 + smapper.replace(this, VarType.INTEGER, "(@1).neg32()", smapper.getI(0));
311.722 break;
311.723 case opc_lneg:
311.724 - emit(out, "@1 = @1.neg64();", smapper.getL(0));
311.725 + smapper.replace(this, VarType.LONG, "(@1).neg64()", smapper.getL(0));
311.726 break;
311.727 case opc_fneg:
311.728 - emit(out, "@1 = -@1;", smapper.getF(0));
311.729 + smapper.replace(this, VarType.FLOAT, "(-@1)", smapper.getF(0));
311.730 break;
311.731 case opc_dneg:
311.732 - emit(out, "@1 = -@1;", smapper.getD(0));
311.733 + smapper.replace(this, VarType.DOUBLE, "(-@1)", smapper.getD(0));
311.734 break;
311.735 case opc_ishl:
311.736 - emit(out, "@1 <<= @2;", smapper.getI(1), smapper.popI());
311.737 + smapper.replace(this, VarType.INTEGER, "(@1 << @2)", smapper.getI(1), smapper.popI());
311.738 break;
311.739 case opc_lshl:
311.740 - emit(out, "@1 = @1.shl64(@2);", smapper.getL(1), smapper.popI());
311.741 + smapper.replace(this, VarType.LONG, "(@1).shl64(@2)", smapper.getL(1), smapper.popI());
311.742 break;
311.743 case opc_ishr:
311.744 - emit(out, "@1 >>= @2;", smapper.getI(1), smapper.popI());
311.745 + smapper.replace(this, VarType.INTEGER, "(@1 >> @2)", smapper.getI(1), smapper.popI());
311.746 break;
311.747 case opc_lshr:
311.748 - emit(out, "@1 = @1.shr64(@2);", smapper.getL(1), smapper.popI());
311.749 + smapper.replace(this, VarType.LONG, "(@1).shr64(@2)", smapper.getL(1), smapper.popI());
311.750 break;
311.751 case opc_iushr:
311.752 - emit(out, "@1 >>>= @2;", smapper.getI(1), smapper.popI());
311.753 + smapper.replace(this, VarType.INTEGER, "(@1 >>> @2)", smapper.getI(1), smapper.popI());
311.754 break;
311.755 case opc_lushr:
311.756 - emit(out, "@1 = @1.ushr64(@2);", smapper.getL(1), smapper.popI());
311.757 + smapper.replace(this, VarType.LONG, "(@1).ushr64(@2)", smapper.getL(1), smapper.popI());
311.758 break;
311.759 case opc_iinc: {
311.760 ++i;
311.761 @@ -699,132 +757,132 @@
311.762 : byteCodes[i];
311.763 wide = false;
311.764 if (incrBy == 1) {
311.765 - emit(out, "@1++;", lmapper.getI(varIndx));
311.766 + emit(smapper, this, "@1++;", lmapper.getI(varIndx));
311.767 } else {
311.768 - emit(out, "@1 += @2;",
311.769 + emit(smapper, this, "@1 += @2;",
311.770 lmapper.getI(varIndx),
311.771 Integer.toString(incrBy));
311.772 }
311.773 break;
311.774 }
311.775 case opc_return:
311.776 - emit(out, "return;");
311.777 + emit(smapper, this, "return;");
311.778 break;
311.779 case opc_ireturn:
311.780 - emit(out, "return @1;", smapper.popI());
311.781 + emit(smapper, this, "return @1;", smapper.popI());
311.782 break;
311.783 case opc_lreturn:
311.784 - emit(out, "return @1;", smapper.popL());
311.785 + emit(smapper, this, "return @1;", smapper.popL());
311.786 break;
311.787 case opc_freturn:
311.788 - emit(out, "return @1;", smapper.popF());
311.789 + emit(smapper, this, "return @1;", smapper.popF());
311.790 break;
311.791 case opc_dreturn:
311.792 - emit(out, "return @1;", smapper.popD());
311.793 + emit(smapper, this, "return @1;", smapper.popD());
311.794 break;
311.795 case opc_areturn:
311.796 - emit(out, "return @1;", smapper.popA());
311.797 + emit(smapper, this, "return @1;", smapper.popA());
311.798 break;
311.799 case opc_i2l:
311.800 - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushL());
311.801 + smapper.replace(this, VarType.LONG, "@1", smapper.getI(0));
311.802 break;
311.803 case opc_i2f:
311.804 - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushF());
311.805 + smapper.replace(this, VarType.FLOAT, "@1", smapper.getI(0));
311.806 break;
311.807 case opc_i2d:
311.808 - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD());
311.809 + smapper.replace(this, VarType.DOUBLE, "@1", smapper.getI(0));
311.810 break;
311.811 case opc_l2i:
311.812 - emit(out, "var @2 = @1.toInt32();", smapper.popL(), smapper.pushI());
311.813 + smapper.replace(this, VarType.INTEGER, "(@1).toInt32()", smapper.getL(0));
311.814 break;
311.815 // max int check?
311.816 case opc_l2f:
311.817 - emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushF());
311.818 + smapper.replace(this, VarType.FLOAT, "(@1).toFP()", smapper.getL(0));
311.819 break;
311.820 case opc_l2d:
311.821 - emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushD());
311.822 + smapper.replace(this, VarType.DOUBLE, "(@1).toFP()", smapper.getL(0));
311.823 break;
311.824 case opc_f2d:
311.825 - emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD());
311.826 + smapper.replace(this, VarType.DOUBLE, "@1",
311.827 + smapper.getF(0));
311.828 break;
311.829 case opc_d2f:
311.830 - emit(out, "var @2 = @1;", smapper.popD(), smapper.pushF());
311.831 + smapper.replace(this, VarType.FLOAT, "@1",
311.832 + smapper.getD(0));
311.833 break;
311.834 case opc_f2i:
311.835 - emit(out, "var @2 = @1.toInt32();",
311.836 - smapper.popF(), smapper.pushI());
311.837 + smapper.replace(this, VarType.INTEGER, "(@1).toInt32()",
311.838 + smapper.getF(0));
311.839 break;
311.840 case opc_f2l:
311.841 - emit(out, "var @2 = @1.toLong();",
311.842 - smapper.popF(), smapper.pushL());
311.843 + smapper.replace(this, VarType.LONG, "(@1).toLong()",
311.844 + smapper.getF(0));
311.845 break;
311.846 case opc_d2i:
311.847 - emit(out, "var @2 = @1.toInt32();",
311.848 - smapper.popD(), smapper.pushI());
311.849 + smapper.replace(this, VarType.INTEGER, "(@1).toInt32()",
311.850 + smapper.getD(0));
311.851 break;
311.852 case opc_d2l:
311.853 - emit(out, "var @2 = @1.toLong();",
311.854 - smapper.popD(), smapper.pushL());
311.855 + smapper.replace(this, VarType.LONG, "(@1).toLong()", smapper.getD(0));
311.856 break;
311.857 case opc_i2b:
311.858 - emit(out, "var @1 = @1.toInt8();", smapper.getI(0));
311.859 + smapper.replace(this, VarType.INTEGER, "(@1).toInt8()", smapper.getI(0));
311.860 break;
311.861 case opc_i2c:
311.862 - out.append("{ /* number conversion */ }");
311.863 break;
311.864 case opc_i2s:
311.865 - emit(out, "var @1 = @1.toInt16();", smapper.getI(0));
311.866 + smapper.replace(this, VarType.INTEGER, "(@1).toInt16()", smapper.getI(0));
311.867 break;
311.868 case opc_aconst_null:
311.869 - emit(out, "var @1 = null;", smapper.pushA());
311.870 + smapper.assign(this, VarType.REFERENCE, "null");
311.871 break;
311.872 case opc_iconst_m1:
311.873 - emit(out, "var @1 = -1;", smapper.pushI());
311.874 + smapper.assign(this, VarType.INTEGER, "-1");
311.875 break;
311.876 case opc_iconst_0:
311.877 - emit(out, "var @1 = 0;", smapper.pushI());
311.878 + smapper.assign(this, VarType.INTEGER, "0");
311.879 break;
311.880 case opc_dconst_0:
311.881 - emit(out, "var @1 = 0;", smapper.pushD());
311.882 + smapper.assign(this, VarType.DOUBLE, "0");
311.883 break;
311.884 case opc_lconst_0:
311.885 - emit(out, "var @1 = 0;", smapper.pushL());
311.886 + smapper.assign(this, VarType.LONG, "0");
311.887 break;
311.888 case opc_fconst_0:
311.889 - emit(out, "var @1 = 0;", smapper.pushF());
311.890 + smapper.assign(this, VarType.FLOAT, "0");
311.891 break;
311.892 case opc_iconst_1:
311.893 - emit(out, "var @1 = 1;", smapper.pushI());
311.894 + smapper.assign(this, VarType.INTEGER, "1");
311.895 break;
311.896 case opc_lconst_1:
311.897 - emit(out, "var @1 = 1;", smapper.pushL());
311.898 + smapper.assign(this, VarType.LONG, "1");
311.899 break;
311.900 case opc_fconst_1:
311.901 - emit(out, "var @1 = 1;", smapper.pushF());
311.902 + smapper.assign(this, VarType.FLOAT, "1");
311.903 break;
311.904 case opc_dconst_1:
311.905 - emit(out, "var @1 = 1;", smapper.pushD());
311.906 + smapper.assign(this, VarType.DOUBLE, "1");
311.907 break;
311.908 case opc_iconst_2:
311.909 - emit(out, "var @1 = 2;", smapper.pushI());
311.910 + smapper.assign(this, VarType.INTEGER, "2");
311.911 break;
311.912 case opc_fconst_2:
311.913 - emit(out, "var @1 = 2;", smapper.pushF());
311.914 + smapper.assign(this, VarType.FLOAT, "2");
311.915 break;
311.916 case opc_iconst_3:
311.917 - emit(out, "var @1 = 3;", smapper.pushI());
311.918 + smapper.assign(this, VarType.INTEGER, "3");
311.919 break;
311.920 case opc_iconst_4:
311.921 - emit(out, "var @1 = 4;", smapper.pushI());
311.922 + smapper.assign(this, VarType.INTEGER, "4");
311.923 break;
311.924 case opc_iconst_5:
311.925 - emit(out, "var @1 = 5;", smapper.pushI());
311.926 + smapper.assign(this, VarType.INTEGER, "5");
311.927 break;
311.928 case opc_ldc: {
311.929 int indx = readUByte(byteCodes, ++i);
311.930 String v = encodeConstant(indx);
311.931 int type = VarType.fromConstantType(jc.getTag(indx));
311.932 - emit(out, "var @1 = @2;", smapper.pushT(type), v);
311.933 + smapper.assign(this, type, v);
311.934 break;
311.935 }
311.936 case opc_ldc_w:
311.937 @@ -837,118 +895,122 @@
311.938 final Long lv = new Long(v);
311.939 final int low = (int)(lv.longValue() & 0xFFFFFFFF);
311.940 final int hi = (int)(lv.longValue() >> 32);
311.941 - emit(out, "var @1 = 0x@3.next32(0x@2);", smapper.pushL(),
311.942 - Integer.toHexString(low), Integer.toHexString(hi));
311.943 + if (hi == 0) {
311.944 + smapper.assign(this, VarType.LONG, "0x" + Integer.toHexString(low));
311.945 + } else {
311.946 + smapper.assign(this, VarType.LONG,
311.947 + "0x" + Integer.toHexString(hi) + ".next32(0x" +
311.948 + Integer.toHexString(low) + ")"
311.949 + );
311.950 + }
311.951 } else {
311.952 - emit(out, "var @1 = @2;", smapper.pushT(type), v);
311.953 + smapper.assign(this, type, v);
311.954 }
311.955 break;
311.956 }
311.957 case opc_lcmp:
311.958 - emit(out, "var @3 = @2.compare64(@1);",
311.959 - smapper.popL(), smapper.popL(), smapper.pushI());
311.960 + smapper.replace(this, VarType.INTEGER, "(@2).compare64(@1)", smapper.popL(), smapper.getL(0));
311.961 break;
311.962 case opc_fcmpl:
311.963 case opc_fcmpg:
311.964 - emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
311.965 - smapper.popF(), smapper.popF(), smapper.pushI());
311.966 + smapper.replace(this, VarType.INTEGER, "(@2).compare(@1)", smapper.popF(), smapper.getF(0));
311.967 break;
311.968 case opc_dcmpl:
311.969 case opc_dcmpg:
311.970 - emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
311.971 - smapper.popD(), smapper.popD(), smapper.pushI());
311.972 + smapper.replace(this, VarType.INTEGER, "(@2).compare(@1)", smapper.popD(), smapper.getD(0));
311.973 break;
311.974 case opc_if_acmpeq:
311.975 - i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
311.976 + i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(),
311.977 "===", topMostLabel);
311.978 break;
311.979 case opc_if_acmpne:
311.980 - i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
311.981 + i = generateIf(smapper, byteCodes, i, smapper.popA(), smapper.popA(),
311.982 "!==", topMostLabel);
311.983 break;
311.984 case opc_if_icmpeq:
311.985 - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
311.986 + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
311.987 "==", topMostLabel);
311.988 break;
311.989 case opc_ifeq: {
311.990 int indx = i + readShortArg(byteCodes, i);
311.991 - emitIf(out, "if (@1 == 0) ",
311.992 + emitIf(smapper, this, "if ((@1) == 0) ",
311.993 smapper.popI(), i, indx, topMostLabel);
311.994 i += 2;
311.995 break;
311.996 }
311.997 case opc_ifne: {
311.998 int indx = i + readShortArg(byteCodes, i);
311.999 - emitIf(out, "if (@1 != 0) ",
311.1000 + emitIf(smapper, this, "if ((@1) != 0) ",
311.1001 smapper.popI(), i, indx, topMostLabel);
311.1002 i += 2;
311.1003 break;
311.1004 }
311.1005 case opc_iflt: {
311.1006 int indx = i + readShortArg(byteCodes, i);
311.1007 - emitIf(out, "if (@1 < 0) ",
311.1008 + emitIf(smapper, this, "if ((@1) < 0) ",
311.1009 smapper.popI(), i, indx, topMostLabel);
311.1010 i += 2;
311.1011 break;
311.1012 }
311.1013 case opc_ifle: {
311.1014 int indx = i + readShortArg(byteCodes, i);
311.1015 - emitIf(out, "if (@1 <= 0) ",
311.1016 + emitIf(smapper, this, "if ((@1) <= 0) ",
311.1017 smapper.popI(), i, indx, topMostLabel);
311.1018 i += 2;
311.1019 break;
311.1020 }
311.1021 case opc_ifgt: {
311.1022 int indx = i + readShortArg(byteCodes, i);
311.1023 - emitIf(out, "if (@1 > 0) ",
311.1024 + emitIf(smapper, this, "if ((@1) > 0) ",
311.1025 smapper.popI(), i, indx, topMostLabel);
311.1026 i += 2;
311.1027 break;
311.1028 }
311.1029 case opc_ifge: {
311.1030 int indx = i + readShortArg(byteCodes, i);
311.1031 - emitIf(out, "if (@1 >= 0) ",
311.1032 + emitIf(smapper, this, "if ((@1) >= 0) ",
311.1033 smapper.popI(), i, indx, topMostLabel);
311.1034 i += 2;
311.1035 break;
311.1036 }
311.1037 case opc_ifnonnull: {
311.1038 int indx = i + readShortArg(byteCodes, i);
311.1039 - emitIf(out, "if (@1 !== null) ",
311.1040 + emitIf(smapper, this, "if ((@1) !== null) ",
311.1041 smapper.popA(), i, indx, topMostLabel);
311.1042 i += 2;
311.1043 break;
311.1044 }
311.1045 case opc_ifnull: {
311.1046 int indx = i + readShortArg(byteCodes, i);
311.1047 - emitIf(out, "if (@1 === null) ",
311.1048 + emitIf(smapper, this, "if ((@1) === null) ",
311.1049 smapper.popA(), i, indx, topMostLabel);
311.1050 i += 2;
311.1051 break;
311.1052 }
311.1053 case opc_if_icmpne:
311.1054 - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
311.1055 + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
311.1056 "!=", topMostLabel);
311.1057 break;
311.1058 case opc_if_icmplt:
311.1059 - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
311.1060 + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
311.1061 "<", topMostLabel);
311.1062 break;
311.1063 case opc_if_icmple:
311.1064 - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
311.1065 + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
311.1066 "<=", topMostLabel);
311.1067 break;
311.1068 case opc_if_icmpgt:
311.1069 - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
311.1070 + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
311.1071 ">", topMostLabel);
311.1072 break;
311.1073 case opc_if_icmpge:
311.1074 - i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
311.1075 + i = generateIf(smapper, byteCodes, i, smapper.popI(), smapper.popI(),
311.1076 ">=", topMostLabel);
311.1077 break;
311.1078 case opc_goto: {
311.1079 + smapper.flush(this);
311.1080 int indx = i + readShortArg(byteCodes, i);
311.1081 - goTo(out, i, indx, topMostLabel);
311.1082 + goTo(this, i, indx, topMostLabel);
311.1083 i += 2;
311.1084 break;
311.1085 }
311.1086 @@ -976,8 +1038,8 @@
311.1087 case opc_new: {
311.1088 int indx = readUShortArg(byteCodes, i);
311.1089 String ci = jc.getClassName(indx);
311.1090 - emit(out, "var @1 = new @2;",
311.1091 - smapper.pushA(), accessClass(ci.replace('/', '_')));
311.1092 + emit(smapper, this, "var @1 = new @2;",
311.1093 + smapper.pushA(), accessClass(mangleClassName(ci)));
311.1094 addReference(ci);
311.1095 i += 2;
311.1096 break;
311.1097 @@ -999,54 +1061,53 @@
311.1098 break;
311.1099 }
311.1100 case opc_arraylength:
311.1101 - emit(out, "var @2 = @1.length;",
311.1102 - smapper.popA(), smapper.pushI());
311.1103 + smapper.replace(this, VarType.INTEGER, "(@1).length", smapper.getA(0));
311.1104 break;
311.1105 case opc_lastore:
311.1106 - emit(out, "Array.at(@3, @2, @1);",
311.1107 + emit(smapper, this, "Array.at(@3, @2, @1);",
311.1108 smapper.popL(), smapper.popI(), smapper.popA());
311.1109 break;
311.1110 case opc_fastore:
311.1111 - emit(out, "Array.at(@3, @2, @1);",
311.1112 + emit(smapper, this, "Array.at(@3, @2, @1);",
311.1113 smapper.popF(), smapper.popI(), smapper.popA());
311.1114 break;
311.1115 case opc_dastore:
311.1116 - emit(out, "Array.at(@3, @2, @1);",
311.1117 + emit(smapper, this, "Array.at(@3, @2, @1);",
311.1118 smapper.popD(), smapper.popI(), smapper.popA());
311.1119 break;
311.1120 case opc_aastore:
311.1121 - emit(out, "Array.at(@3, @2, @1);",
311.1122 + emit(smapper, this, "Array.at(@3, @2, @1);",
311.1123 smapper.popA(), smapper.popI(), smapper.popA());
311.1124 break;
311.1125 case opc_iastore:
311.1126 case opc_bastore:
311.1127 case opc_castore:
311.1128 case opc_sastore:
311.1129 - emit(out, "Array.at(@3, @2, @1);",
311.1130 + emit(smapper, this, "Array.at(@3, @2, @1);",
311.1131 smapper.popI(), smapper.popI(), smapper.popA());
311.1132 break;
311.1133 case opc_laload:
311.1134 - emit(out, "var @3 = Array.at(@2, @1);",
311.1135 - smapper.popI(), smapper.popA(), smapper.pushL());
311.1136 + smapper.replace(this, VarType.LONG, "Array.at(@2, @1)",
311.1137 + smapper.popI(), smapper.getA(0));
311.1138 break;
311.1139 case opc_faload:
311.1140 - emit(out, "var @3 = Array.at(@2, @1);",
311.1141 - smapper.popI(), smapper.popA(), smapper.pushF());
311.1142 + smapper.replace(this, VarType.FLOAT, "Array.at(@2, @1)",
311.1143 + smapper.popI(), smapper.getA(0));
311.1144 break;
311.1145 case opc_daload:
311.1146 - emit(out, "var @3 = Array.at(@2, @1);",
311.1147 - smapper.popI(), smapper.popA(), smapper.pushD());
311.1148 + smapper.replace(this, VarType.DOUBLE, "Array.at(@2, @1)",
311.1149 + smapper.popI(), smapper.getA(0));
311.1150 break;
311.1151 case opc_aaload:
311.1152 - emit(out, "var @3 = Array.at(@2, @1);",
311.1153 - smapper.popI(), smapper.popA(), smapper.pushA());
311.1154 + smapper.replace(this, VarType.REFERENCE, "Array.at(@2, @1)",
311.1155 + smapper.popI(), smapper.getA(0));
311.1156 break;
311.1157 case opc_iaload:
311.1158 case opc_baload:
311.1159 case opc_caload:
311.1160 case opc_saload:
311.1161 - emit(out, "var @3 = Array.at(@2, @1);",
311.1162 - smapper.popI(), smapper.popA(), smapper.pushI());
311.1163 + smapper.replace(this, VarType.INTEGER, "Array.at(@2, @1)",
311.1164 + smapper.popI(), smapper.getA(0));
311.1165 break;
311.1166 case opc_pop:
311.1167 case opc_pop2:
311.1168 @@ -1055,86 +1116,86 @@
311.1169 break;
311.1170 case opc_dup: {
311.1171 final Variable v = smapper.get(0);
311.1172 - emit(out, "var @1 = @2;", smapper.pushT(v.getType()), v);
311.1173 + emit(smapper, this, "var @1 = @2;", smapper.pushT(v.getType()), v);
311.1174 break;
311.1175 }
311.1176 case opc_dup2: {
311.1177 final Variable vi1 = smapper.get(0);
311.1178
311.1179 if (vi1.isCategory2()) {
311.1180 - emit(out, "var @1 = @2;",
311.1181 + emit(smapper, this, "var @1 = @2;",
311.1182 smapper.pushT(vi1.getType()), vi1);
311.1183 } else {
311.1184 final Variable vi2 = smapper.get(1);
311.1185 - emit(out, "var @1 = @2, @3 = @4;",
311.1186 + emit(smapper, this, "var @1 = @2, @3 = @4;",
311.1187 smapper.pushT(vi2.getType()), vi2,
311.1188 smapper.pushT(vi1.getType()), vi1);
311.1189 }
311.1190 break;
311.1191 }
311.1192 case opc_dup_x1: {
311.1193 - final Variable vi1 = smapper.pop();
311.1194 - final Variable vi2 = smapper.pop();
311.1195 + final Variable vi1 = smapper.pop(this);
311.1196 + final Variable vi2 = smapper.pop(this);
311.1197 final Variable vo3 = smapper.pushT(vi1.getType());
311.1198 final Variable vo2 = smapper.pushT(vi2.getType());
311.1199 final Variable vo1 = smapper.pushT(vi1.getType());
311.1200
311.1201 - emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
311.1202 + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;",
311.1203 vo1, vi1, vo2, vi2, vo3, vo1);
311.1204 break;
311.1205 }
311.1206 case opc_dup2_x1: {
311.1207 - final Variable vi1 = smapper.pop();
311.1208 - final Variable vi2 = smapper.pop();
311.1209 + final Variable vi1 = smapper.pop(this);
311.1210 + final Variable vi2 = smapper.pop(this);
311.1211
311.1212 if (vi1.isCategory2()) {
311.1213 final Variable vo3 = smapper.pushT(vi1.getType());
311.1214 final Variable vo2 = smapper.pushT(vi2.getType());
311.1215 final Variable vo1 = smapper.pushT(vi1.getType());
311.1216
311.1217 - emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
311.1218 + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;",
311.1219 vo1, vi1, vo2, vi2, vo3, vo1);
311.1220 } else {
311.1221 - final Variable vi3 = smapper.pop();
311.1222 + final Variable vi3 = smapper.pop(this);
311.1223 final Variable vo5 = smapper.pushT(vi2.getType());
311.1224 final Variable vo4 = smapper.pushT(vi1.getType());
311.1225 final Variable vo3 = smapper.pushT(vi3.getType());
311.1226 final Variable vo2 = smapper.pushT(vi2.getType());
311.1227 final Variable vo1 = smapper.pushT(vi1.getType());
311.1228
311.1229 - emit(out, "var @1 = @2, @3 = @4, @5 = @6,",
311.1230 + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6,",
311.1231 vo1, vi1, vo2, vi2, vo3, vi3);
311.1232 - emit(out, " @1 = @2, @3 = @4;",
311.1233 + emit(smapper, this, " @1 = @2, @3 = @4;",
311.1234 vo4, vo1, vo5, vo2);
311.1235 }
311.1236 break;
311.1237 }
311.1238 case opc_dup_x2: {
311.1239 - final Variable vi1 = smapper.pop();
311.1240 - final Variable vi2 = smapper.pop();
311.1241 + final Variable vi1 = smapper.pop(this);
311.1242 + final Variable vi2 = smapper.pop(this);
311.1243
311.1244 if (vi2.isCategory2()) {
311.1245 final Variable vo3 = smapper.pushT(vi1.getType());
311.1246 final Variable vo2 = smapper.pushT(vi2.getType());
311.1247 final Variable vo1 = smapper.pushT(vi1.getType());
311.1248
311.1249 - emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
311.1250 + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;",
311.1251 vo1, vi1, vo2, vi2, vo3, vo1);
311.1252 } else {
311.1253 - final Variable vi3 = smapper.pop();
311.1254 + final Variable vi3 = smapper.pop(this);
311.1255 final Variable vo4 = smapper.pushT(vi1.getType());
311.1256 final Variable vo3 = smapper.pushT(vi3.getType());
311.1257 final Variable vo2 = smapper.pushT(vi2.getType());
311.1258 final Variable vo1 = smapper.pushT(vi1.getType());
311.1259
311.1260 - emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
311.1261 + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
311.1262 vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
311.1263 }
311.1264 break;
311.1265 }
311.1266 case opc_dup2_x2: {
311.1267 - final Variable vi1 = smapper.pop();
311.1268 - final Variable vi2 = smapper.pop();
311.1269 + final Variable vi1 = smapper.pop(this);
311.1270 + final Variable vi2 = smapper.pop(this);
311.1271
311.1272 if (vi1.isCategory2()) {
311.1273 if (vi2.isCategory2()) {
311.1274 @@ -1142,20 +1203,20 @@
311.1275 final Variable vo2 = smapper.pushT(vi2.getType());
311.1276 final Variable vo1 = smapper.pushT(vi1.getType());
311.1277
311.1278 - emit(out, "var @1 = @2, @3 = @4, @5 = @6;",
311.1279 + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6;",
311.1280 vo1, vi1, vo2, vi2, vo3, vo1);
311.1281 } else {
311.1282 - final Variable vi3 = smapper.pop();
311.1283 + final Variable vi3 = smapper.pop(this);
311.1284 final Variable vo4 = smapper.pushT(vi1.getType());
311.1285 final Variable vo3 = smapper.pushT(vi3.getType());
311.1286 final Variable vo2 = smapper.pushT(vi2.getType());
311.1287 final Variable vo1 = smapper.pushT(vi1.getType());
311.1288
311.1289 - emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
311.1290 + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8;",
311.1291 vo1, vi1, vo2, vi2, vo3, vi3, vo4, vo1);
311.1292 }
311.1293 } else {
311.1294 - final Variable vi3 = smapper.pop();
311.1295 + final Variable vi3 = smapper.pop(this);
311.1296
311.1297 if (vi3.isCategory2()) {
311.1298 final Variable vo5 = smapper.pushT(vi2.getType());
311.1299 @@ -1164,12 +1225,12 @@
311.1300 final Variable vo2 = smapper.pushT(vi2.getType());
311.1301 final Variable vo1 = smapper.pushT(vi1.getType());
311.1302
311.1303 - emit(out, "var @1 = @2, @3 = @4, @5 = @6,",
311.1304 + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6,",
311.1305 vo1, vi1, vo2, vi2, vo3, vi3);
311.1306 - emit(out, " @1 = @2, @3 = @4;",
311.1307 + emit(smapper, this, " @1 = @2, @3 = @4;",
311.1308 vo4, vo1, vo5, vo2);
311.1309 } else {
311.1310 - final Variable vi4 = smapper.pop();
311.1311 + final Variable vi4 = smapper.pop(this);
311.1312 final Variable vo6 = smapper.pushT(vi2.getType());
311.1313 final Variable vo5 = smapper.pushT(vi1.getType());
311.1314 final Variable vo4 = smapper.pushT(vi4.getType());
311.1315 @@ -1177,9 +1238,9 @@
311.1316 final Variable vo2 = smapper.pushT(vi2.getType());
311.1317 final Variable vo1 = smapper.pushT(vi1.getType());
311.1318
311.1319 - emit(out, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,",
311.1320 + emit(smapper, this, "var @1 = @2, @3 = @4, @5 = @6, @7 = @8,",
311.1321 vo1, vi1, vo2, vi2, vo3, vi3, vo4, vi4);
311.1322 - emit(out, " @1 = @2, @3 = @4;",
311.1323 + emit(smapper, this, " @1 = @2, @3 = @4;",
311.1324 vo5, vo1, vo6, vo2);
311.1325 }
311.1326 }
311.1327 @@ -1192,7 +1253,7 @@
311.1328 if (vi1.getType() == vi2.getType()) {
311.1329 final Variable tmp = smapper.pushT(vi1.getType());
311.1330
311.1331 - emit(out, "var @1 = @2, @2 = @3, @3 = @1;",
311.1332 + emit(smapper, this, "var @1 = @2, @2 = @3, @3 = @1;",
311.1333 tmp, vi1, vi2);
311.1334 smapper.pop(1);
311.1335 } else {
311.1336 @@ -1203,26 +1264,26 @@
311.1337 break;
311.1338 }
311.1339 case opc_bipush:
311.1340 - emit(out, "var @1 = @2;",
311.1341 - smapper.pushI(), Integer.toString(byteCodes[++i]));
311.1342 + smapper.assign(this, VarType.INTEGER,
311.1343 + "(" + Integer.toString(byteCodes[++i]) + ")");
311.1344 break;
311.1345 case opc_sipush:
311.1346 - emit(out, "var @1 = @2;",
311.1347 - smapper.pushI(),
311.1348 - Integer.toString(readShortArg(byteCodes, i)));
311.1349 + smapper.assign(this, VarType.INTEGER,
311.1350 + "(" + Integer.toString(readShortArg(byteCodes, i)) + ")"
311.1351 + );
311.1352 i += 2;
311.1353 break;
311.1354 case opc_getfield: {
311.1355 int indx = readUShortArg(byteCodes, i);
311.1356 String[] fi = jc.getFieldInfoName(indx);
311.1357 final int type = VarType.fromFieldType(fi[2].charAt(0));
311.1358 - final String mangleClass = mangleSig(fi[0]);
311.1359 + final String mangleClass = mangleClassName(fi[0]);
311.1360 final String mangleClassAccess = accessClass(mangleClass);
311.1361 - emit(out, "var @2 = @3.call(@1);",
311.1362 - smapper.popA(),
311.1363 - smapper.pushT(type),
311.1364 + smapper.replace(this, type, "@2.call(@1)",
311.1365 + smapper.getA(0),
311.1366 accessField(mangleClassAccess + "(false)",
311.1367 - "_" + fi[1], fi));
311.1368 + "_" + fi[1], fi)
311.1369 + );
311.1370 i += 2;
311.1371 break;
311.1372 }
311.1373 @@ -1230,9 +1291,9 @@
311.1374 int indx = readUShortArg(byteCodes, i);
311.1375 String[] fi = jc.getFieldInfoName(indx);
311.1376 final int type = VarType.fromFieldType(fi[2].charAt(0));
311.1377 - final String mangleClass = mangleSig(fi[0]);
311.1378 + final String mangleClass = mangleClassName(fi[0]);
311.1379 final String mangleClassAccess = accessClass(mangleClass);
311.1380 - emit(out, "@3.call(@2, @1);",
311.1381 + emit(smapper, this, "@3.call(@2, @1);",
311.1382 smapper.popT(type),
311.1383 smapper.popA(),
311.1384 accessField(mangleClassAccess + "(false)",
311.1385 @@ -1244,11 +1305,8 @@
311.1386 int indx = readUShortArg(byteCodes, i);
311.1387 String[] fi = jc.getFieldInfoName(indx);
311.1388 final int type = VarType.fromFieldType(fi[2].charAt(0));
311.1389 - emit(out, "var @1 = @2();",
311.1390 - smapper.pushT(type),
311.1391 - accessField(accessClass(fi[0].replace('/', '_'))
311.1392 - + "(false)",
311.1393 - "_" + fi[1], fi));
311.1394 + String ac = accessClass(mangleClassName(fi[0]));
311.1395 + smapper.assign(this, type, ac + "(false)._" + fi[1] + "()");
311.1396 i += 2;
311.1397 addReference(fi[0]);
311.1398 break;
311.1399 @@ -1257,10 +1315,8 @@
311.1400 int indx = readUShortArg(byteCodes, i);
311.1401 String[] fi = jc.getFieldInfoName(indx);
311.1402 final int type = VarType.fromFieldType(fi[2].charAt(0));
311.1403 - emit(out, "@1(@2);",
311.1404 - accessField(accessClass(fi[0].replace('/', '_'))
311.1405 - + "(false)",
311.1406 - "_" + fi[1], fi),
311.1407 + emit(smapper, this, "@1(false)._@2(@3);",
311.1408 + accessClass(mangleClassName(fi[0])), fi[1],
311.1409 smapper.popT(type));
311.1410 i += 2;
311.1411 addReference(fi[0]);
311.1412 @@ -1279,22 +1335,22 @@
311.1413 break;
311.1414 }
311.1415 case opc_athrow: {
311.1416 - final Variable v = smapper.popA();
311.1417 + final CharSequence v = smapper.popA();
311.1418 smapper.clear();
311.1419
311.1420 - emit(out, "{ var @1 = @2; throw @2; }",
311.1421 + emit(smapper, this, "{ var @1 = @2; throw @2; }",
311.1422 smapper.pushA(), v);
311.1423 break;
311.1424 }
311.1425
311.1426 case opc_monitorenter: {
311.1427 - out.append("/* monitor enter */");
311.1428 + debug("/* monitor enter */");
311.1429 smapper.popA();
311.1430 break;
311.1431 }
311.1432
311.1433 case opc_monitorexit: {
311.1434 - out.append("/* monitor exit */");
311.1435 + debug("/* monitor exit */");
311.1436 smapper.popA();
311.1437 break;
311.1438 }
311.1439 @@ -1305,31 +1361,39 @@
311.1440
311.1441 default: {
311.1442 wide = false;
311.1443 - emit(out, "throw 'unknown bytecode @1';",
311.1444 + emit(smapper, this, "throw 'unknown bytecode @1';",
311.1445 Integer.toString(c));
311.1446 }
311.1447 }
311.1448 if (debug(" //")) {
311.1449 generateByteCodeComment(prev, i, byteCodes);
311.1450 }
311.1451 - out.append("\n");
311.1452 + if (outChanged) {
311.1453 + append("\n");
311.1454 + }
311.1455 }
311.1456 if (previousTrap != null) {
311.1457 generateCatch(previousTrap, byteCodes.length, topMostLabel);
311.1458 }
311.1459 - out.append("\n }\n");
311.1460 + if (didBranches) {
311.1461 + append("\n }\n");
311.1462 + }
311.1463 while (openBraces-- > 0) {
311.1464 - out.append('}');
311.1465 + append('}');
311.1466 }
311.1467 - out.append("\n};");
311.1468 + append("\n};");
311.1469 }
311.1470
311.1471 - private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException {
311.1472 + private int generateIf(StackMapper mapper, byte[] byteCodes,
311.1473 + int i, final CharSequence v2, final CharSequence v1,
311.1474 + final String test, int topMostLabel
311.1475 + ) throws IOException {
311.1476 + mapper.flush(this);
311.1477 int indx = i + readShortArg(byteCodes, i);
311.1478 - out.append("if (").append(v1)
311.1479 - .append(' ').append(test).append(' ')
311.1480 - .append(v2).append(") ");
311.1481 - goTo(out, i, indx, topMostLabel);
311.1482 + append("if ((").append(v1)
311.1483 + .append(") ").append(test).append(" (")
311.1484 + .append(v2).append(")) ");
311.1485 + goTo(this, i, indx, topMostLabel);
311.1486 return i + 2;
311.1487 }
311.1488
311.1489 @@ -1442,8 +1506,20 @@
311.1490 return mangleSig(sig, 0, sig.length());
311.1491 }
311.1492
311.1493 + private static String mangleMethodName(String name) {
311.1494 + StringBuilder sb = new StringBuilder(name.length() * 2);
311.1495 + int last = name.length();
311.1496 + for (int i = 0; i < last; i++) {
311.1497 + final char ch = name.charAt(i);
311.1498 + switch (ch) {
311.1499 + case '_': sb.append("_1"); break;
311.1500 + default: sb.append(ch); break;
311.1501 + }
311.1502 + }
311.1503 + return sb.toString();
311.1504 + }
311.1505 private static String mangleSig(String txt, int first, int last) {
311.1506 - StringBuilder sb = new StringBuilder();
311.1507 + StringBuilder sb = new StringBuilder((last - first) * 2);
311.1508 for (int i = first; i < last; i++) {
311.1509 final char ch = txt.charAt(i);
311.1510 switch (ch) {
311.1511 @@ -1456,6 +1532,10 @@
311.1512 }
311.1513 return sb.toString();
311.1514 }
311.1515 +
311.1516 + private static String mangleClassName(String name) {
311.1517 + return mangleSig(name);
311.1518 + }
311.1519
311.1520 private static String findMethodName(MethodData m, StringBuilder cnt) {
311.1521 StringBuilder name = new StringBuilder();
311.1522 @@ -1464,7 +1544,7 @@
311.1523 } else if ("<clinit>".equals(m.getName())) { // NOI18N
311.1524 name.append("class"); // NOI18N
311.1525 } else {
311.1526 - name.append(m.getName());
311.1527 + name.append(mangleMethodName(m.getName()));
311.1528 }
311.1529
311.1530 countArgs(m.getInternalSig(), new char[1], name, cnt);
311.1531 @@ -1478,7 +1558,7 @@
311.1532 if ("<init>".equals(nm)) { // NOI18N
311.1533 name.append("cons"); // NOI18N
311.1534 } else {
311.1535 - name.append(nm);
311.1536 + name.append(mangleMethodName(nm));
311.1537 }
311.1538 countArgs(descr, returnType, name, cnt);
311.1539 return name.toString();
311.1540 @@ -1493,14 +1573,14 @@
311.1541 String mn = findMethodName(mi, cnt, returnType);
311.1542
311.1543 final int numArguments = isStatic ? cnt.length() : cnt.length() + 1;
311.1544 - final Variable[] vars = new Variable[numArguments];
311.1545 + final CharSequence[] vars = new CharSequence[numArguments];
311.1546
311.1547 for (int j = numArguments - 1; j >= 0; --j) {
311.1548 - vars[j] = mapper.pop();
311.1549 + vars[j] = mapper.popValue();
311.1550 }
311.1551
311.1552 if (returnType[0] != 'V') {
311.1553 - out.append("var ")
311.1554 + append("var ")
311.1555 .append(mapper.pushT(VarType.fromFieldType(returnType[0])))
311.1556 .append(" = ");
311.1557 }
311.1558 @@ -1510,20 +1590,20 @@
311.1559 if (mn.startsWith("cons_")) {
311.1560 object += ".constructor";
311.1561 }
311.1562 - out.append(accessStaticMethod(object, mn, mi));
311.1563 + append(accessStaticMethod(object, mn, mi));
311.1564 if (isStatic) {
311.1565 - out.append('(');
311.1566 + append('(');
311.1567 } else {
311.1568 - out.append(".call(");
311.1569 + append(".call(");
311.1570 }
311.1571 if (numArguments > 0) {
311.1572 - out.append(vars[0]);
311.1573 + append(vars[0]);
311.1574 for (int j = 1; j < numArguments; ++j) {
311.1575 - out.append(", ");
311.1576 - out.append(vars[j]);
311.1577 + append(", ");
311.1578 + append(vars[j]);
311.1579 }
311.1580 }
311.1581 - out.append(");");
311.1582 + append(");");
311.1583 i += 2;
311.1584 addReference(in);
311.1585 return i;
311.1586 @@ -1537,27 +1617,27 @@
311.1587 String mn = findMethodName(mi, cnt, returnType);
311.1588
311.1589 final int numArguments = cnt.length() + 1;
311.1590 - final Variable[] vars = new Variable[numArguments];
311.1591 + final CharSequence[] vars = new CharSequence[numArguments];
311.1592
311.1593 for (int j = numArguments - 1; j >= 0; --j) {
311.1594 - vars[j] = mapper.pop();
311.1595 + vars[j] = mapper.popValue();
311.1596 }
311.1597
311.1598 if (returnType[0] != 'V') {
311.1599 - out.append("var ")
311.1600 + append("var ")
311.1601 .append(mapper.pushT(VarType.fromFieldType(returnType[0])))
311.1602 .append(" = ");
311.1603 }
311.1604
311.1605 - out.append(accessVirtualMethod(vars[0].toString(), mn, mi));
311.1606 - out.append('(');
311.1607 + append(accessVirtualMethod(vars[0].toString(), mn, mi));
311.1608 + append('(');
311.1609 String sep = "";
311.1610 for (int j = 1; j < numArguments; ++j) {
311.1611 - out.append(sep);
311.1612 - out.append(vars[j]);
311.1613 + append(sep);
311.1614 + append(vars[j]);
311.1615 sep = ", ";
311.1616 }
311.1617 - out.append(");");
311.1618 + append(");");
311.1619 i += 2;
311.1620 return i;
311.1621 }
311.1622 @@ -1587,10 +1667,10 @@
311.1623 String s = jc.stringValue(entryIndex, classRef);
311.1624 if (classRef[0] != null) {
311.1625 if (classRef[0].startsWith("[")) {
311.1626 - s = accessClass("java_lang_Class") + "(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('" + classRef[0] + "');";
311.1627 + s = accessClass("java_lang_Class") + "(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('" + classRef[0] + "')";
311.1628 } else {
311.1629 addReference(classRef[0]);
311.1630 - s = accessClass(s.replace('/', '_')) + "(false).constructor.$class";
311.1631 + s = accessClass(mangleClassName(s)) + "(false).constructor.$class";
311.1632 }
311.1633 }
311.1634 return s;
311.1635 @@ -1602,6 +1682,7 @@
311.1636 return null;
311.1637 }
311.1638 final String jvmType = "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;";
311.1639 + final String htmlType = "Lnet/java/html/js/JavaScriptBody;";
311.1640 class P extends AnnotationParser {
311.1641 public P() {
311.1642 super(false, true);
311.1643 @@ -1610,6 +1691,8 @@
311.1644 int cnt;
311.1645 String[] args = new String[30];
311.1646 String body;
311.1647 + boolean javacall;
311.1648 + boolean html4j;
311.1649
311.1650 @Override
311.1651 protected void visitAttr(String type, String attr, String at, String value) {
311.1652 @@ -1622,6 +1705,18 @@
311.1653 throw new IllegalArgumentException(attr);
311.1654 }
311.1655 }
311.1656 + if (type.equals(htmlType)) {
311.1657 + html4j = true;
311.1658 + if ("body".equals(attr)) {
311.1659 + body = value;
311.1660 + } else if ("args".equals(attr)) {
311.1661 + args[cnt++] = value;
311.1662 + } else if ("javacall".equals(attr)) {
311.1663 + javacall = "1".equals(value);
311.1664 + } else {
311.1665 + throw new IllegalArgumentException(attr);
311.1666 + }
311.1667 + }
311.1668 }
311.1669 }
311.1670 P p = new P();
311.1671 @@ -1631,23 +1726,153 @@
311.1672 }
311.1673 StringBuilder cnt = new StringBuilder();
311.1674 final String mn = findMethodName(m, cnt);
311.1675 - out.append(destObject).append(".").append(mn);
311.1676 - out.append(" = function(");
311.1677 + append(destObject).append(".").append(mn);
311.1678 + append(" = function(");
311.1679 String space = "";
311.1680 int index = 0;
311.1681 + StringBuilder toValue = new StringBuilder();
311.1682 for (int i = 0; i < cnt.length(); i++) {
311.1683 - out.append(space);
311.1684 - space = outputArg(out, p.args, index);
311.1685 + append(space);
311.1686 + space = outputArg(this, p.args, index);
311.1687 + if (p.html4j && space.length() > 0) {
311.1688 + toValue.append("\n ").append(p.args[index]).append(" = vm.org_apidesign_bck2brwsr_emul_lang_System(false).toJS(").
311.1689 + append(p.args[index]).append(");");
311.1690 + }
311.1691 index++;
311.1692 }
311.1693 - out.append(") {").append("\n");
311.1694 - out.append(p.body);
311.1695 - out.append("\n}\n");
311.1696 + append(") {").append("\n");
311.1697 + append(toValue.toString());
311.1698 + if (p.javacall) {
311.1699 + int lastSlash = jc.getClassName().lastIndexOf('/');
311.1700 + final String pkg = jc.getClassName().substring(0, lastSlash);
311.1701 + append(mangleCallbacks(pkg, p.body));
311.1702 + requireReference(pkg + "/$JsCallbacks$");
311.1703 + } else {
311.1704 + append(p.body);
311.1705 + }
311.1706 + append("\n}\n");
311.1707 return mn;
311.1708 }
311.1709 +
311.1710 + private static CharSequence mangleCallbacks(String pkgName, String body) {
311.1711 + StringBuilder sb = new StringBuilder();
311.1712 + int pos = 0;
311.1713 + for (;;) {
311.1714 + int next = body.indexOf(".@", pos);
311.1715 + if (next == -1) {
311.1716 + sb.append(body.substring(pos));
311.1717 + body = sb.toString();
311.1718 + break;
311.1719 + }
311.1720 + int ident = next;
311.1721 + while (ident > 0) {
311.1722 + if (!Character.isJavaIdentifierPart(body.charAt(--ident))) {
311.1723 + ident++;
311.1724 + break;
311.1725 + }
311.1726 + }
311.1727 + String refId = body.substring(ident, next);
311.1728 +
311.1729 + sb.append(body.substring(pos, ident));
311.1730 +
311.1731 + int sigBeg = body.indexOf('(', next);
311.1732 + int sigEnd = body.indexOf(')', sigBeg);
311.1733 + int colon4 = body.indexOf("::", next);
311.1734 + if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
311.1735 + throw new IllegalStateException("Malformed body " + body);
311.1736 + }
311.1737 + String fqn = body.substring(next + 2, colon4);
311.1738 + String method = body.substring(colon4 + 2, sigBeg);
311.1739 + String params = body.substring(sigBeg, sigEnd + 1);
311.1740 +
311.1741 + int paramBeg = body.indexOf('(', sigEnd + 1);
311.1742 +
311.1743 + sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM().");
311.1744 + sb.append(mangleJsCallbacks(fqn, method, params, false));
311.1745 + sb.append("(").append(refId);
311.1746 + if (body.charAt(paramBeg + 1) != ')') {
311.1747 + sb.append(",");
311.1748 + }
311.1749 + pos = paramBeg + 1;
311.1750 + }
311.1751 + sb = null;
311.1752 + pos = 0;
311.1753 + for (;;) {
311.1754 + int next = body.indexOf("@", pos);
311.1755 + if (next == -1) {
311.1756 + if (sb == null) {
311.1757 + return body;
311.1758 + }
311.1759 + sb.append(body.substring(pos));
311.1760 + return sb;
311.1761 + }
311.1762 + if (sb == null) {
311.1763 + sb = new StringBuilder();
311.1764 + }
311.1765 +
311.1766 + sb.append(body.substring(pos, next));
311.1767 +
311.1768 + int sigBeg = body.indexOf('(', next);
311.1769 + int sigEnd = body.indexOf(')', sigBeg);
311.1770 + int colon4 = body.indexOf("::", next);
311.1771 + if (sigBeg == -1 || sigEnd == -1 || colon4 == -1) {
311.1772 + throw new IllegalStateException("Malformed body " + body);
311.1773 + }
311.1774 + String fqn = body.substring(next + 1, colon4);
311.1775 + String method = body.substring(colon4 + 2, sigBeg);
311.1776 + String params = body.substring(sigBeg, sigEnd + 1);
311.1777 +
311.1778 + int paramBeg = body.indexOf('(', sigEnd + 1);
311.1779 +
311.1780 + sb.append("vm.").append(pkgName.replace('/', '_')).append("_$JsCallbacks$(false)._VM().");
311.1781 + sb.append(mangleJsCallbacks(fqn, method, params, true));
311.1782 + sb.append("(");
311.1783 + pos = paramBeg + 1;
311.1784 + }
311.1785 + }
311.1786 +
311.1787 + static String mangleJsCallbacks(String fqn, String method, String params, boolean isStatic) {
311.1788 + if (params.startsWith("(")) {
311.1789 + params = params.substring(1);
311.1790 + }
311.1791 + if (params.endsWith(")")) {
311.1792 + params = params.substring(0, params.length() - 1);
311.1793 + }
311.1794 + StringBuilder sb = new StringBuilder();
311.1795 + final String fqnu = fqn.replace('.', '_');
311.1796 + final String rfqn = mangleClassName(fqnu);
311.1797 + final String rm = mangleMethodName(method);
311.1798 + final String srp;
311.1799 + {
311.1800 + StringBuilder pb = new StringBuilder();
311.1801 + int len = params.length();
311.1802 + int indx = 0;
311.1803 + while (indx < len) {
311.1804 + char ch = params.charAt(indx);
311.1805 + if (ch == '[' || ch == 'L') {
311.1806 + pb.append("Ljava/lang/Object;");
311.1807 + indx = params.indexOf(';', indx) + 1;
311.1808 + } else {
311.1809 + pb.append(ch);
311.1810 + indx++;
311.1811 + }
311.1812 + }
311.1813 + srp = mangleSig(pb.toString());
311.1814 + }
311.1815 + final String rp = mangleSig(params);
311.1816 + final String mrp = mangleMethodName(rp);
311.1817 + sb.append(rfqn).append("$").append(rm).
311.1818 + append('$').append(mrp).append("__Ljava_lang_Object_2");
311.1819 + if (!isStatic) {
311.1820 + sb.append('L').append(fqnu).append("_2");
311.1821 + }
311.1822 + sb.append(srp);
311.1823 + return sb.toString();
311.1824 + }
311.1825 +
311.1826 private static String className(ClassData jc) {
311.1827 //return jc.getName().getInternalName().replace('/', '_');
311.1828 - return jc.getClassName().replace('/', '_');
311.1829 + return mangleClassName(jc.getClassName());
311.1830 }
311.1831
311.1832 private static String[] findAnnotation(
311.1833 @@ -1697,7 +1922,7 @@
311.1834 return " = null;";
311.1835 }
311.1836
311.1837 - private void generateAnno(ClassData cd, final Appendable out, byte[] data) throws IOException {
311.1838 + private void generateAnno(ClassData cd, byte[] data) throws IOException {
311.1839 AnnotationParser ap = new AnnotationParser(true, false) {
311.1840 int[] cnt = new int[32];
311.1841 int depth;
311.1842 @@ -1708,39 +1933,39 @@
311.1843 requireReference(slashType);
311.1844
311.1845 if (cnt[depth]++ > 0) {
311.1846 - out.append(",");
311.1847 + append(",");
311.1848 }
311.1849 if (top) {
311.1850 - out.append('"').append(attrType).append("\" : ");
311.1851 + append('"').append(attrType).append("\" : ");
311.1852 }
311.1853 - out.append("{\n");
311.1854 + append("{\n");
311.1855 cnt[++depth] = 0;
311.1856 }
311.1857
311.1858 @Override
311.1859 protected void visitAnnotationEnd(String type, boolean top) throws IOException {
311.1860 - out.append("\n}\n");
311.1861 + append("\n}\n");
311.1862 depth--;
311.1863 }
311.1864
311.1865 @Override
311.1866 protected void visitValueStart(String attrName, char type) throws IOException {
311.1867 if (cnt[depth]++ > 0) {
311.1868 - out.append(",\n");
311.1869 + append(",\n");
311.1870 }
311.1871 cnt[++depth] = 0;
311.1872 if (attrName != null) {
311.1873 - out.append(attrName).append(" : ");
311.1874 + append(attrName).append(" : ");
311.1875 }
311.1876 if (type == '[') {
311.1877 - out.append("[");
311.1878 + append("[");
311.1879 }
311.1880 }
311.1881
311.1882 @Override
311.1883 protected void visitValueEnd(String attrName, char type) throws IOException {
311.1884 if (type == '[') {
311.1885 - out.append("]");
311.1886 + append("]");
311.1887 }
311.1888 depth--;
311.1889 }
311.1890 @@ -1751,7 +1976,7 @@
311.1891 if (attr == null && value == null) {
311.1892 return;
311.1893 }
311.1894 - out.append(value);
311.1895 + append(value);
311.1896 }
311.1897
311.1898 @Override
311.1899 @@ -1760,8 +1985,8 @@
311.1900 final String slashType = attrType.substring(1, attrType.length() - 1);
311.1901 requireReference(slashType);
311.1902
311.1903 - out.append(accessClass(slashType.replace('/', '_')))
311.1904 - .append("(false).constructor.").append(value);
311.1905 + append(accessClass(mangleClassName(slashType)))
311.1906 + .append("(false).constructor.fld_").append(value);
311.1907 }
311.1908 };
311.1909 ap.parse(data, cd);
311.1910 @@ -1779,7 +2004,21 @@
311.1911 return ",";
311.1912 }
311.1913
311.1914 - private static void emit(final Appendable out,
311.1915 + final void emitNoFlush(
311.1916 + StackMapper sm,
311.1917 + final String format, final CharSequence... params
311.1918 + ) throws IOException {
311.1919 + emitImpl(this, format, params);
311.1920 + }
311.1921 + static final void emit(
311.1922 + StackMapper sm,
311.1923 + final Appendable out,
311.1924 + final String format, final CharSequence... params
311.1925 + ) throws IOException {
311.1926 + sm.flush(out);
311.1927 + emitImpl(out, format, params);
311.1928 + }
311.1929 + static void emitImpl(final Appendable out,
311.1930 final String format,
311.1931 final CharSequence... params) throws IOException {
311.1932 final int length = format.length();
311.1933 @@ -1805,7 +2044,7 @@
311.1934 }
311.1935
311.1936 private void generateCatch(TrapData[] traps, int current, int topMostLabel) throws IOException {
311.1937 - out.append("} catch (e) {\n");
311.1938 + append("} catch (e) {\n");
311.1939 int finallyPC = -1;
311.1940 for (TrapData e : traps) {
311.1941 if (e == null) {
311.1942 @@ -1814,22 +2053,22 @@
311.1943 if (e.catch_cpx != 0) { //not finally
311.1944 final String classInternalName = jc.getClassName(e.catch_cpx);
311.1945 addReference(classInternalName);
311.1946 - out.append("e = vm.java_lang_Throwable(false).bck2BrwsrCnvrt(e);");
311.1947 - out.append("if (e['$instOf_" + classInternalName.replace('/', '_') + "']) {");
311.1948 - out.append("var stA0 = e;");
311.1949 - goTo(out, current, e.handler_pc, topMostLabel);
311.1950 - out.append("}\n");
311.1951 + append("e = vm.java_lang_Throwable(false).bck2BrwsrCnvrt(e);");
311.1952 + append("if (e['$instOf_" + classInternalName.replace('/', '_') + "']) {");
311.1953 + append("var stA0 = e;");
311.1954 + goTo(this, current, e.handler_pc, topMostLabel);
311.1955 + append("}\n");
311.1956 } else {
311.1957 finallyPC = e.handler_pc;
311.1958 }
311.1959 }
311.1960 if (finallyPC == -1) {
311.1961 - out.append("throw e;");
311.1962 + append("throw e;");
311.1963 } else {
311.1964 - out.append("var stA0 = e;");
311.1965 - goTo(out, current, finallyPC, topMostLabel);
311.1966 + append("var stA0 = e;");
311.1967 + goTo(this, current, finallyPC, topMostLabel);
311.1968 }
311.1969 - out.append("\n}");
311.1970 + append("\n}");
311.1971 }
311.1972
311.1973 private static void goTo(Appendable out, int current, int to, int canBack) throws IOException {
311.1974 @@ -1845,10 +2084,13 @@
311.1975 }
311.1976
311.1977 private static void emitIf(
311.1978 - Appendable out, String pattern, Variable param,
311.1979 + StackMapper sm,
311.1980 + Appendable out, String pattern,
311.1981 + CharSequence param,
311.1982 int current, int to, int canBack
311.1983 ) throws IOException {
311.1984 - emit(out, pattern, param);
311.1985 + sm.flush(out);
311.1986 + emitImpl(out, pattern, param);
311.1987 goTo(out, current, to, canBack);
311.1988 }
311.1989
311.1990 @@ -1865,7 +2107,8 @@
311.1991 case 11: jvmType = "[J"; break;
311.1992 default: throw new IllegalStateException("Array type: " + atype);
311.1993 }
311.1994 - emit(out, "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](true, '@3', @1);",
311.1995 + emit(smapper, this,
311.1996 + "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](true, '@3', @1);",
311.1997 smapper.popI(), smapper.pushA(), jvmType);
311.1998 }
311.1999
311.2000 @@ -1876,7 +2119,8 @@
311.2001 } else {
311.2002 typeName = "[L" + typeName + ";";
311.2003 }
311.2004 - emit(out, "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](false, '@3', @1);",
311.2005 + emit(smapper, this,
311.2006 + "var @2 = Array.prototype['newArray__Ljava_lang_Object_2ZLjava_lang_String_2I'](false, '@3', @1);",
311.2007 smapper.popI(), smapper.pushA(), typeName);
311.2008 }
311.2009
311.2010 @@ -1892,7 +2136,8 @@
311.2011 dims.insert(1, smapper.popI());
311.2012 }
311.2013 dims.append(']');
311.2014 - emit(out, "var @2 = Array.prototype['multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II']('@3', @1, 0);",
311.2015 + emit(smapper, this,
311.2016 + "var @2 = Array.prototype['multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II']('@3', @1, 0);",
311.2017 dims.toString(), smapper.pushA(), typeName);
311.2018 return i;
311.2019 }
311.2020 @@ -1905,16 +2150,18 @@
311.2021 table += 4;
311.2022 int high = readInt4(byteCodes, table);
311.2023 table += 4;
311.2024 - out.append("switch (").append(smapper.popI()).append(") {\n");
311.2025 + final CharSequence swVar = smapper.popValue();
311.2026 + smapper.flush(this);
311.2027 + append("switch (").append(swVar).append(") {\n");
311.2028 while (low <= high) {
311.2029 int offset = i + readInt4(byteCodes, table);
311.2030 table += 4;
311.2031 - out.append(" case " + low).append(":"); goTo(out, i, offset, topMostLabel); out.append('\n');
311.2032 + append(" case " + low).append(":"); goTo(this, i, offset, topMostLabel); append('\n');
311.2033 low++;
311.2034 }
311.2035 - out.append(" default: ");
311.2036 - goTo(out, i, dflt, topMostLabel);
311.2037 - out.append("\n}");
311.2038 + append(" default: ");
311.2039 + goTo(this, i, dflt, topMostLabel);
311.2040 + append("\n}");
311.2041 i = table - 1;
311.2042 return i;
311.2043 }
311.2044 @@ -1925,17 +2172,19 @@
311.2045 table += 4;
311.2046 int n = readInt4(byteCodes, table);
311.2047 table += 4;
311.2048 - out.append("switch (").append(smapper.popI()).append(") {\n");
311.2049 + final CharSequence swVar = smapper.popValue();
311.2050 + smapper.flush(this);
311.2051 + append("switch (").append(swVar).append(") {\n");
311.2052 while (n-- > 0) {
311.2053 int cnstnt = readInt4(byteCodes, table);
311.2054 table += 4;
311.2055 int offset = i + readInt4(byteCodes, table);
311.2056 table += 4;
311.2057 - out.append(" case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel); out.append('\n');
311.2058 + append(" case " + cnstnt).append(": "); goTo(this, i, offset, topMostLabel); append('\n');
311.2059 }
311.2060 - out.append(" default: ");
311.2061 - goTo(out, i, dflt, topMostLabel);
311.2062 - out.append("\n}");
311.2063 + append(" default: ");
311.2064 + goTo(this, i, dflt, topMostLabel);
311.2065 + append("\n}");
311.2066 i = table - 1;
311.2067 return i;
311.2068 }
311.2069 @@ -1943,11 +2192,13 @@
311.2070 private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException {
311.2071 final String type = jc.getClassName(indx);
311.2072 if (!type.startsWith("[")) {
311.2073 - emit(out, "var @2 = @1 != null && @1['$instOf_@3'] ? 1 : 0;",
311.2074 + emit(smapper, this,
311.2075 + "var @2 = @1 != null && @1['$instOf_@3'] ? 1 : 0;",
311.2076 smapper.popA(), smapper.pushI(),
311.2077 type.replace('/', '_'));
311.2078 } else {
311.2079 - emit(out, "var @2 = vm.java_lang_Class(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('@3')['isInstance__ZLjava_lang_Object_2'](@1);",
311.2080 + emit(smapper, this,
311.2081 + "var @2 = vm.java_lang_Class(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('@3')['isInstance__ZLjava_lang_Object_2'](@1);",
311.2082 smapper.popA(), smapper.pushI(),
311.2083 type
311.2084 );
311.2085 @@ -1957,21 +2208,22 @@
311.2086 private void generateCheckcast(int indx, final StackMapper smapper) throws IOException {
311.2087 final String type = jc.getClassName(indx);
311.2088 if (!type.startsWith("[")) {
311.2089 - emit(out,
311.2090 + emitNoFlush(smapper,
311.2091 "if (@1 !== null && !@1['$instOf_@2']) throw vm.java_lang_ClassCastException(true);",
311.2092 - smapper.getA(0), type.replace('/', '_'));
311.2093 + smapper.getT(0, VarType.REFERENCE, false), type.replace('/', '_'));
311.2094 } else {
311.2095 - emit(out, "vm.java_lang_Class(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('@2')['cast__Ljava_lang_Object_2Ljava_lang_Object_2'](@1);",
311.2096 - smapper.getA(0), type
311.2097 + emitNoFlush(smapper,
311.2098 + "vm.java_lang_Class(false)['forName__Ljava_lang_Class_2Ljava_lang_String_2']('@2')['cast__Ljava_lang_Object_2Ljava_lang_Object_2'](@1);",
311.2099 + smapper.getT(0, VarType.REFERENCE, false), type
311.2100 );
311.2101 }
311.2102 }
311.2103
311.2104 private void generateByteCodeComment(int prev, int i, final byte[] byteCodes) throws IOException {
311.2105 for (int j = prev; j <= i; j++) {
311.2106 - out.append(" ");
311.2107 + append(" ");
311.2108 final int cc = readUByte(byteCodes, j);
311.2109 - out.append(Integer.toString(cc));
311.2110 + append(Integer.toString(cc));
311.2111 }
311.2112 }
311.2113 }
312.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java Tue Apr 29 15:25:58 2014 +0200
312.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/LdrRsrcs.java Wed Apr 30 15:04:10 2014 +0200
312.3 @@ -28,9 +28,11 @@
312.4 */
312.5 final class LdrRsrcs implements Bck2Brwsr.Resources {
312.6 private final ClassLoader loader;
312.7 + private final boolean skipRtJar;
312.8
312.9 - LdrRsrcs(ClassLoader loader) {
312.10 + LdrRsrcs(ClassLoader loader, boolean skipRtJar) {
312.11 this.loader = loader;
312.12 + this.skipRtJar = skipRtJar;
312.13 }
312.14
312.15 @Override
312.16 @@ -40,6 +42,12 @@
312.17 while (en.hasMoreElements()) {
312.18 u = en.nextElement();
312.19 }
312.20 - return (u != null) ? u.openStream() : null;
312.21 + if (u == null) {
312.22 + throw new IOException("Can't find " + name);
312.23 + }
312.24 + if (skipRtJar && u.toExternalForm().contains("lib/rt.jar!")) {
312.25 + return null;
312.26 + }
312.27 + return u.openStream();
312.28 }
312.29 }
313.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Tue Apr 29 15:25:58 2014 +0200
313.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Wed Apr 30 15:04:10 2014 +0200
313.3 @@ -108,7 +108,7 @@
313.4 Bck2Brwsr.newCompiler().library(createExtension).
313.5 obfuscation(obfLevel).
313.6 addRootClasses(classes.toArray()).
313.7 - resources(new LdrRsrcs(mainClassLoader)).
313.8 + resources(new LdrRsrcs(Main.class.getClassLoader(), true)).
313.9 generate(w);
313.10 }
313.11 }
314.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java Tue Apr 29 15:25:58 2014 +0200
314.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StackMapper.java Wed Apr 30 15:04:10 2014 +0200
314.3 @@ -17,24 +17,21 @@
314.4 */
314.5 package org.apidesign.vm4brwsr;
314.6
314.7 +import java.io.IOException;
314.8 import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray;
314.9
314.10 final class StackMapper {
314.11 private final TypeArray stackTypeIndexPairs;
314.12 - private int[] typeCounters;
314.13 - private int[] typeMaxCounters;
314.14 + private final StringArray stackValues;
314.15
314.16 public StackMapper() {
314.17 stackTypeIndexPairs = new TypeArray();
314.18 - typeCounters = new int[VarType.LAST + 1];
314.19 - typeMaxCounters = new int[VarType.LAST + 1];
314.20 + stackValues = new StringArray();
314.21 }
314.22
314.23 public void clear() {
314.24 - for (int type = 0; type <= VarType.LAST; ++type) {
314.25 - typeCounters[type] = 0;
314.26 - }
314.27 stackTypeIndexPairs.clear();
314.28 + stackValues.clear();
314.29 }
314.30
314.31 public void syncWithFrameStack(final TypeArray frameStack) {
314.32 @@ -70,33 +67,66 @@
314.33 return getVariable(pushTypeImpl(type));
314.34 }
314.35
314.36 - public Variable popI() {
314.37 + void assign(Appendable out, int varType, CharSequence s) throws IOException {
314.38 + pushTypeAndValue(varType, s);
314.39 + }
314.40 +
314.41 + void replace(Appendable out, int varType, String format, CharSequence... arr)
314.42 + throws IOException {
314.43 + StringBuilder sb = new StringBuilder();
314.44 + ByteCodeToJavaScript.emitImpl(sb, format, arr);
314.45 + String[] values = stackValues.toArray();
314.46 + final int last = stackTypeIndexPairs.getSize() - 1;
314.47 + values[last] = sb.toString();
314.48 + final int value = (last << 8) | (varType & 0xff);
314.49 + stackTypeIndexPairs.set(last, value);
314.50 + }
314.51 +
314.52 + void flush(Appendable out) throws IOException {
314.53 + int count = stackTypeIndexPairs.getSize();
314.54 + for (int i = 0; i < count; i++) {
314.55 + String val = stackValues.getAndClear(i, true);
314.56 + if (val == null) {
314.57 + continue;
314.58 + }
314.59 + CharSequence var = getVariable(stackTypeIndexPairs.get(i));
314.60 + ByteCodeToJavaScript.emitImpl(out, "var @1 = @2;", var, val);
314.61 + }
314.62 + }
314.63 +
314.64 + public CharSequence popI() {
314.65 return popT(VarType.INTEGER);
314.66 }
314.67
314.68 - public Variable popL() {
314.69 + public CharSequence popL() {
314.70 return popT(VarType.LONG);
314.71 }
314.72
314.73 - public Variable popF() {
314.74 + public CharSequence popF() {
314.75 return popT(VarType.FLOAT);
314.76 }
314.77
314.78 - public Variable popD() {
314.79 + public CharSequence popD() {
314.80 return popT(VarType.DOUBLE);
314.81 }
314.82
314.83 - public Variable popA() {
314.84 + public CharSequence popA() {
314.85 return popT(VarType.REFERENCE);
314.86 }
314.87
314.88 - public Variable popT(final int type) {
314.89 - final Variable variable = getT(0, type);
314.90 + public CharSequence popT(final int type) {
314.91 + final CharSequence variable = getT(0, type);
314.92 popImpl(1);
314.93 return variable;
314.94 }
314.95
314.96 - public Variable pop() {
314.97 + public CharSequence popValue() {
314.98 + final CharSequence variable = getT(0, -1);
314.99 + popImpl(1);
314.100 + return variable;
314.101 + }
314.102 + public Variable pop(Appendable out) throws IOException {
314.103 + flush(out);
314.104 final Variable variable = get(0);
314.105 popImpl(1);
314.106 return variable;
314.107 @@ -110,37 +140,44 @@
314.108 popImpl(count);
314.109 }
314.110
314.111 - public Variable getI(final int indexFromTop) {
314.112 + public CharSequence getI(final int indexFromTop) {
314.113 return getT(indexFromTop, VarType.INTEGER);
314.114 }
314.115
314.116 - public Variable getL(final int indexFromTop) {
314.117 + public CharSequence getL(final int indexFromTop) {
314.118 return getT(indexFromTop, VarType.LONG);
314.119 }
314.120
314.121 - public Variable getF(final int indexFromTop) {
314.122 + public CharSequence getF(final int indexFromTop) {
314.123 return getT(indexFromTop, VarType.FLOAT);
314.124 }
314.125
314.126 - public Variable getD(final int indexFromTop) {
314.127 + public CharSequence getD(final int indexFromTop) {
314.128 return getT(indexFromTop, VarType.DOUBLE);
314.129 }
314.130
314.131 - public Variable getA(final int indexFromTop) {
314.132 + public CharSequence getA(final int indexFromTop) {
314.133 return getT(indexFromTop, VarType.REFERENCE);
314.134 }
314.135
314.136 - public Variable getT(final int indexFromTop, final int type) {
314.137 + public CharSequence getT(final int indexFromTop, final int type) {
314.138 + return getT(indexFromTop, type, true);
314.139 + }
314.140 + public CharSequence getT(final int indexFromTop, final int type, boolean clear) {
314.141 final int stackSize = stackTypeIndexPairs.getSize();
314.142 if (indexFromTop >= stackSize) {
314.143 throw new IllegalStateException("Stack underflow");
314.144 }
314.145 final int stackValue =
314.146 stackTypeIndexPairs.get(stackSize - indexFromTop - 1);
314.147 - if ((stackValue & 0xff) != type) {
314.148 + if (type != -1 && (stackValue & 0xff) != type) {
314.149 throw new IllegalStateException("Type mismatch");
314.150 }
314.151 -
314.152 + String value =
314.153 + stackValues.getAndClear(stackSize - indexFromTop - 1, clear);
314.154 + if (value != null) {
314.155 + return value;
314.156 + }
314.157 return getVariable(stackValue);
314.158 }
314.159
314.160 @@ -156,35 +193,36 @@
314.161 }
314.162
314.163 private int pushTypeImpl(final int type) {
314.164 - final int count = typeCounters[type];
314.165 + final int count = stackTypeIndexPairs.getSize();
314.166 final int value = (count << 8) | (type & 0xff);
314.167 - incCounter(type);
314.168 stackTypeIndexPairs.add(value);
314.169 +
314.170 + addStackValue(count, null);
314.171 + return value;
314.172 + }
314.173
314.174 - return value;
314.175 + private void pushTypeAndValue(final int type, CharSequence v) {
314.176 + final int count = stackTypeIndexPairs.getSize();
314.177 + final int value = (count << 8) | (type & 0xff);
314.178 + stackTypeIndexPairs.add(value);
314.179 + final String val = v.toString();
314.180 + addStackValue(count, val);
314.181 + }
314.182 +
314.183 + private void addStackValue(int at, final String val) {
314.184 + final String[] arr = stackValues.toArray();
314.185 + if (arr.length > at) {
314.186 + arr[at] = val;
314.187 + } else {
314.188 + stackValues.add(val);
314.189 + }
314.190 }
314.191
314.192 private void popImpl(final int count) {
314.193 final int stackSize = stackTypeIndexPairs.getSize();
314.194 - for (int i = stackSize - count; i < stackSize; ++i) {
314.195 - final int value = stackTypeIndexPairs.get(i);
314.196 - decCounter(value & 0xff);
314.197 - }
314.198 -
314.199 stackTypeIndexPairs.setSize(stackSize - count);
314.200 }
314.201
314.202 - private void incCounter(final int type) {
314.203 - final int newValue = ++typeCounters[type];
314.204 - if (typeMaxCounters[type] < newValue) {
314.205 - typeMaxCounters[type] = newValue;
314.206 - }
314.207 - }
314.208 -
314.209 - private void decCounter(final int type) {
314.210 - --typeCounters[type];
314.211 - }
314.212 -
314.213 public Variable getVariable(final int typeAndIndex) {
314.214 final int type = typeAndIndex & 0xff;
314.215 final int index = typeAndIndex >> 8;
315.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Tue Apr 29 15:25:58 2014 +0200
315.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/StringArray.java Wed Apr 30 15:04:10 2014 +0200
315.3 @@ -105,11 +105,23 @@
315.4 }
315.5
315.6 int indexOf(String ic) {
315.7 - for (int i = 0; i < arr.length; i++) {
315.8 + if (arr != null) for (int i = 0; i < arr.length; i++) {
315.9 if (ic.equals(arr[i])) {
315.10 return i;
315.11 }
315.12 }
315.13 return -1;
315.14 }
315.15 +
315.16 + String getAndClear(int count, boolean clear) {
315.17 + String s = arr[count];
315.18 + if (clear) {
315.19 + arr[count] = null;
315.20 + }
315.21 + return s;
315.22 + }
315.23 +
315.24 + void clear() {
315.25 + arr = null;
315.26 + }
315.27 }
316.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Tue Apr 29 15:25:58 2014 +0200
316.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Wed Apr 30 15:04:10 2014 +0200
316.3 @@ -85,11 +85,11 @@
316.4
316.5 private void doCompile(StringArray names, StringArray asBinary) throws IOException {
316.6 generatePrologue();
316.7 - out.append(
316.8 + append(
316.9 "\n var invoker = {};");
316.10 generateBody(names);
316.11 for (String invokerMethod: invokerMethods.toArray()) {
316.12 - out.append("\n invoker." + invokerMethod + " = function(target) {"
316.13 + append("\n invoker." + invokerMethod + " = function(target) {"
316.14 + "\n return function() {"
316.15 + "\n return target['" + invokerMethod + "'].apply(target, arguments);"
316.16 + "\n };"
316.17 @@ -98,19 +98,19 @@
316.18 }
316.19
316.20 for (String r : asBinary.toArray()) {
316.21 - out.append("\n ").append(getExportsObject()).append(".registerResource('");
316.22 - out.append(r).append("', '");
316.23 + append("\n ").append(getExportsObject()).append(".registerResource('");
316.24 + append(r).append("', '");
316.25 InputStream is = this.resources.get(r);
316.26 byte[] arr = new byte[is.available()];
316.27 int len = is.read(arr);
316.28 if (len != arr.length) {
316.29 throw new IOException("Not read as much as expected for " + r + " expected: " + arr.length + " was: " + len);
316.30 }
316.31 - out.append(btoa(arr));
316.32 - out.append("');");
316.33 + append(btoa(arr));
316.34 + append("');");
316.35 }
316.36
316.37 - out.append("\n");
316.38 + append("\n");
316.39 generateEpilogue();
316.40 }
316.41
316.42 @@ -131,7 +131,7 @@
316.43 protected final void declaredClass(ClassData classData, String mangledName)
316.44 throws IOException {
316.45 if (exportedSymbols.isExported(classData)) {
316.46 - out.append("\n").append(getExportsObject()).append("['")
316.47 + append("\n").append(getExportsObject()).append("['")
316.48 .append(mangledName)
316.49 .append("'] = ")
316.50 .append(accessClass(mangledName))
316.51 @@ -167,7 +167,7 @@
316.52
316.53 private void exportMember(String destObject, String memberName)
316.54 throws IOException {
316.55 - out.append("\n").append(destObject).append("['")
316.56 + append("\n").append(destObject).append("['")
316.57 .append(memberName)
316.58 .append("'] = ")
316.59 .append(destObject).append(".").append(memberName)
316.60 @@ -177,11 +177,15 @@
316.61 private void generateBody(StringArray names) throws IOException {
316.62 StringArray processed = new StringArray();
316.63 StringArray initCode = new StringArray();
316.64 + StringArray skipClass = new StringArray();
316.65 for (String baseClass : names.toArray()) {
316.66 references.add(baseClass);
316.67 for (;;) {
316.68 String name = null;
316.69 for (String n : references.toArray()) {
316.70 + if (skipClass.contains(n)) {
316.71 + continue;
316.72 + }
316.73 if (processed.contains(n)) {
316.74 continue;
316.75 }
316.76 @@ -190,28 +194,18 @@
316.77 if (name == null) {
316.78 break;
316.79 }
316.80 -
316.81 + InputStream is = resources.get(name + ".class");
316.82 + if (is == null) {
316.83 + lazyReference(this, name);
316.84 + skipClass.add(name);
316.85 + continue;
316.86 + }
316.87 try {
316.88 String ic = generateClass(name);
316.89 processed.add(name);
316.90 initCode.add(ic == null ? "" : ic);
316.91 } catch (RuntimeException ex) {
316.92 - if (out instanceof CharSequence) {
316.93 - CharSequence seq = (CharSequence)out;
316.94 - int lastBlock = seq.length();
316.95 - while (lastBlock-- > 0) {
316.96 - if (seq.charAt(lastBlock) == '{') {
316.97 - break;
316.98 - }
316.99 - }
316.100 - throw new IOException("Error while compiling " + name + "\n"
316.101 - + seq.subSequence(lastBlock + 1, seq.length()), ex
316.102 - );
316.103 - } else {
316.104 - throw new IOException("Error while compiling " + name + "\n"
316.105 - + out, ex
316.106 - );
316.107 - }
316.108 + throw new IOException("Error while compiling " + name + "\n", ex);
316.109 }
316.110 }
316.111
316.112 @@ -223,7 +217,7 @@
316.113 if (emul == null) {
316.114 throw new IOException("Can't find " + resource);
316.115 }
316.116 - readResource(emul, out);
316.117 + readResource(emul, this);
316.118 }
316.119 scripts = new StringArray();
316.120
316.121 @@ -235,12 +229,53 @@
316.122 if (indx >= 0) {
316.123 final String theCode = initCode.toArray()[indx];
316.124 if (!theCode.isEmpty()) {
316.125 - out.append(theCode).append("\n");
316.126 + append(theCode).append("\n");
316.127 }
316.128 initCode.toArray()[indx] = "";
316.129 }
316.130 }
316.131 }
316.132 +/*
316.133 + append(
316.134 + " return vm;\n"
316.135 + + " };\n"
316.136 + + " function mangleClass(name) {\n"
316.137 + + " return name.replace__Ljava_lang_String_2Ljava_lang_CharSequence_2Ljava_lang_CharSequence_2(\n"
316.138 + + " '_', '_1').replace__Ljava_lang_String_2CC('.','_');\n"
316.139 + + " };\n"
316.140 + + " global.bck2brwsr = function() {\n"
316.141 + + " var args = Array.prototype.slice.apply(arguments);\n"
316.142 + + " var vm = fillInVMSkeleton({});\n"
316.143 + + " var loader = {};\n"
316.144 + + " loader.vm = vm;\n"
316.145 + + " loader.loadClass = function(name) {\n"
316.146 + + " var attr = mangleClass(name);\n"
316.147 + + " var fn = vm[attr];\n"
316.148 + + " if (fn) return fn(false);\n"
316.149 + + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
316.150 + + " load__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
316.151 + + " }\n"
316.152 + + " if (vm.loadClass) {\n"
316.153 + + " throw 'Cannot initialize the bck2brwsr VM twice!';\n"
316.154 + + " }\n"
316.155 + + " vm.loadClass = loader.loadClass;\n"
316.156 + + " vm._reload = function(name, byteCode) {;\n"
316.157 + + " var attr = mangleClass(name);\n"
316.158 + + " delete vm[attr];\n"
316.159 + + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
316.160 + + " reload__Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2_3B(loader, name, args, byteCode);\n"
316.161 + + " };\n"
316.162 + + " vm.loadBytes = function(name, skip) {\n"
316.163 + + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
316.164 + + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, name, args, typeof skip == 'number' ? skip : 0);\n"
316.165 + + " }\n"
316.166 + + " vm.java_lang_reflect_Array(false);\n"
316.167 + + " vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
316.168 + + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, null, args, 0);\n"
316.169 + + " return loader;\n"
316.170 + + " };\n");
316.171 + append("}(this));");
316.172 +*/
316.173 }
316.174
316.175 private static void readResource(InputStream emul, Appendable out) throws IOException {
316.176 @@ -442,12 +477,12 @@
316.177
316.178 @Override
316.179 protected void generatePrologue() throws IOException {
316.180 - out.append("(function VM(global) {var fillInVMSkeleton = function(vm) {");
316.181 + append("(function VM(global) {var fillInVMSkeleton = function(vm) {");
316.182 }
316.183
316.184 @Override
316.185 protected void generateEpilogue() throws IOException {
316.186 - out.append(
316.187 + append(
316.188 " return vm;\n"
316.189 + " };\n"
316.190 + " var extensions = [];\n"
316.191 @@ -495,22 +530,22 @@
316.192 + " throw 'Cannot initialize the bck2brwsr VM twice!';\n"
316.193 + " }\n"
316.194 + " vm.loadClass = loader.loadClass;\n"
316.195 - + " vm.loadBytes = function(name) {\n"
316.196 + + " vm.loadBytes = function(name, skip) {\n"
316.197 + " if (resources[name]) return resources[name][0];\n"
316.198 + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
316.199 - + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
316.200 + + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, name, args, typeof skip == 'number' ? skip : 0);\n"
316.201 + " }\n"
316.202 + " vm.java_lang_reflect_Array(false);\n"
316.203 + " vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
316.204 - + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, null, args);\n"
316.205 + + " loadBytes___3BLjava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2I(loader, null, args, 0);\n"
316.206 + " return loader;\n"
316.207 + " };\n");
316.208 - out.append(
316.209 + append(
316.210 " global.bck2brwsr.registerExtension = function(extension) {\n"
316.211 + " extensions.push(extension);\n"
316.212 + " return null;\n"
316.213 + " };\n");
316.214 - out.append("}(this));");
316.215 + append("}(this));");
316.216 }
316.217
316.218 @Override
316.219 @@ -535,9 +570,9 @@
316.220
316.221 @Override
316.222 protected void generatePrologue() throws IOException {
316.223 - out.append("bck2brwsr.registerExtension(function(exports) {\n"
316.224 + append("bck2brwsr.registerExtension(function(exports) {\n"
316.225 + " var vm = {};\n");
316.226 - out.append(" function link(n, inst) {\n"
316.227 + append(" function link(n, inst) {\n"
316.228 + " var cls = n['replace__Ljava_lang_String_2CC']"
316.229 + "('/', '_').toString();\n"
316.230 + " var dot = n['replace__Ljava_lang_String_2CC']"
316.231 @@ -550,13 +585,13 @@
316.232
316.233 @Override
316.234 protected void generateEpilogue() throws IOException {
316.235 - out.append("});");
316.236 + append("});");
316.237 }
316.238
316.239 @Override
316.240 protected String generateClass(String className) throws IOException {
316.241 if (isExternalClass(className)) {
316.242 - out.append("\n").append(assignClass(
316.243 + append("\n").append(assignClass(
316.244 className.replace('/', '_')))
316.245 .append("function() {\n return link('")
316.246 .append(className)
316.247 @@ -579,4 +614,16 @@
316.248 return !extensionClasses.contains(className);
316.249 }
316.250 }
316.251 +
316.252 + private static void lazyReference(Appendable out, String n) throws IOException {
316.253 + String cls = n.replace('/', '_');
316.254 + String dot = n.replace('/', '.');
316.255 +
316.256 + out.append("\nvm.").append(cls).append(" = function() {");
316.257 + out.append("\n var instance = arguments.length == 0 || arguments[0] === true;");
316.258 + out.append("\n delete vm.").append(cls).append(";");
316.259 + out.append("\n var c = vm.loadClass('").append(dot).append("');");
316.260 + out.append("\n return vm.").append(cls).append("(instance);");
316.261 + out.append("\n}");
316.262 + }
316.263 }
317.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Tue Apr 29 15:25:58 2014 +0200
317.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Wed Apr 30 15:04:10 2014 +0200
317.3 @@ -20,7 +20,6 @@
317.4 import java.io.ByteArrayInputStream;
317.5 import java.io.IOException;
317.6 import java.io.InputStream;
317.7 -import java.lang.reflect.Array;
317.8 import org.apidesign.bck2brwsr.core.JavaScriptBody;
317.9
317.10 /**
317.11 @@ -43,27 +42,34 @@
317.12 throws IOException, ClassNotFoundException {
317.13 return new VMLazy(loader, arguments).load(name, false);
317.14 }
317.15 +
317.16 + static Object reload(Object loader, String name, Object[] arguments, byte[] arr)
317.17 + throws IOException, ClassNotFoundException {
317.18 + return new VMLazy(loader, arguments).defineClass(arr, name, false);
317.19 + }
317.20
317.21 - static byte[] loadBytes(Object loader, String name, Object[] arguments) throws Exception {
317.22 - return Zips.loadFromCp(arguments, name);
317.23 + static byte[] loadBytes(Object loader, String name, Object[] arguments, int skip) throws Exception {
317.24 + return Zips.loadFromCp(arguments, name, skip);
317.25 }
317.26
317.27 private Object load(String name, boolean instance)
317.28 throws IOException, ClassNotFoundException {
317.29 String res = name.replace('.', '/') + ".class";
317.30 - byte[] arr = Zips.loadFromCp(args, res);
317.31 + byte[] arr = Zips.loadFromCp(args, res, 0);
317.32 if (arr == null) {
317.33 throw new ClassNotFoundException(name);
317.34 }
317.35 -// beingDefined(loader, name);
317.36 +
317.37 + return defineClass(arr, name, instance);
317.38 + }
317.39 +
317.40 + private Object defineClass(byte[] arr, String name, boolean instance) throws IOException {
317.41 StringBuilder out = new StringBuilder(65535);
317.42 out.append("var loader = arguments[0];\n");
317.43 out.append("var vm = loader.vm;\n");
317.44 int prelude = out.length();
317.45 String initCode = new Gen(this, out).compile(new ByteArrayInputStream(arr));
317.46 String code = out.toString().toString();
317.47 -// dump("Loading " + name);
317.48 - dump(code);
317.49 String under = name.replace('.', '_');
317.50 Object fn = applyCode(loader, under, code, instance);
317.51
317.52 @@ -71,26 +77,12 @@
317.53 out.setLength(prelude);
317.54 out.append(initCode);
317.55 code = out.toString().toString();
317.56 - dump(code);
317.57 applyCode(loader, null, code, false);
317.58 }
317.59
317.60 return fn;
317.61 }
317.62
317.63 -// @JavaScriptBody(args = "s", body = "java.lang.System.out.println(s.toString());")
317.64 - static void dump(String s) {
317.65 - }
317.66 -
317.67 -/* possibly not needed:
317.68 - @JavaScriptBody(args = {"loader", "n" }, body =
317.69 - "var cls = n.replace__Ljava_lang_String_2CC(n, '.','_').toString();" +
317.70 - "loader.vm[cls] = true;\n"
317.71 - )
317.72 - private static native void beingDefined(Object loader, String name);
317.73 -*/
317.74 -
317.75 -
317.76 @JavaScriptBody(args = {"loader", "name", "script", "instance" }, body =
317.77 "try {\n" +
317.78 " new Function(script)(loader, name);\n" +
317.79 @@ -130,6 +122,14 @@
317.80
317.81 @Override
317.82 protected void requireScript(String resourcePath) throws IOException {
317.83 + if (!resourcePath.startsWith("/")) {
317.84 + resourcePath = "/" + resourcePath;
317.85 + }
317.86 + String code = readCode(resourcePath);
317.87 + applyCode(lazy.loader, null, code, false);
317.88 + }
317.89 +
317.90 + private String readCode(String resourcePath) throws IOException {
317.91 InputStream is = getClass().getResourceAsStream(resourcePath);
317.92 StringBuilder sb = new StringBuilder();
317.93 for (;;) {
317.94 @@ -139,7 +139,7 @@
317.95 }
317.96 sb.append((char)ch);
317.97 }
317.98 - applyCode(lazy.loader, null, sb.toString(), false);
317.99 + return sb.toString();
317.100 }
317.101
317.102 @Override
318.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Zips.java Tue Apr 29 15:25:58 2014 +0200
318.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Zips.java Wed Apr 30 15:04:10 2014 +0200
318.3 @@ -49,7 +49,7 @@
318.4 @JavaScriptBody(args = { "arr", "index", "value" }, body = "arr[index] = value; return value;")
318.5 private static native Object set(Object arr, int index, Object value);
318.6
318.7 - public static byte[] loadFromCp(Object classpath, String res)
318.8 + public static byte[] loadFromCp(Object classpath, String res, int skip)
318.9 throws IOException, ClassNotFoundException {
318.10 for (int i = 0; i < length(classpath); i++) {
318.11 Object c = at(classpath, i);
318.12 @@ -74,24 +74,27 @@
318.13 byte[] checkRes;
318.14 if (c instanceof Zips) {
318.15 checkRes = ((Zips)c).findRes(res);
318.16 + if (checkRes != null && --skip < 0) {
318.17 + return checkRes;
318.18 + }
318.19 } else {
318.20 - checkRes = callFunction(c, res);
318.21 - }
318.22 - if (checkRes != null) {
318.23 - return checkRes;
318.24 + checkRes = callFunction(c, res, skip);
318.25 + if (checkRes != null) {
318.26 + return checkRes;
318.27 + }
318.28 }
318.29 }
318.30 }
318.31 return null;
318.32 }
318.33
318.34 - @JavaScriptBody(args = { "fn", "res" }, body =
318.35 - "if (typeof fn === 'function') return fn(res);\n"
318.36 + @JavaScriptBody(args = { "fn", "res", "skip" }, body =
318.37 + "if (typeof fn === 'function') return fn(res, skip);\n"
318.38 + "return null;"
318.39 )
318.40 - private static native byte[] callFunction(Object fn, String res);
318.41 + private static native byte[] callFunction(Object fn, String res, int skip);
318.42
318.43 - @JavaScriptBody(args = { "msg" }, body = "console.log(msg.toString());")
318.44 + @JavaScriptBody(args = { "msg" }, body = "if (typeof console !== 'undefined') console.log(msg.toString());")
318.45 private static native void log(String msg);
318.46
318.47 private byte[] findRes(String res) throws IOException {
319.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ByteCodeToJavaScriptTest.java Tue Apr 29 15:25:58 2014 +0200
319.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ByteCodeToJavaScriptTest.java Wed Apr 30 15:04:10 2014 +0200
319.3 @@ -52,4 +52,15 @@
319.4 assertTrue(returnType[0] != 'V', "Returns string");
319.5 assertEquals(ret, "toJavaScript__Ljava_lang_String_2_3B");
319.6 }
319.7 +
319.8 + @Test public void mangleJsCallbackToAType() throws Exception {
319.9 + String res = ByteCodeToJavaScript.mangleJsCallbacks(
319.10 + "org.apidesign.bck2brwsr.vmtest.impl.HtmlAnnotations",
319.11 + "onError", "Ljava/lang/Object;", false
319.12 + );
319.13 + assertEquals(res,
319.14 + "org_1apidesign_1bck2brwsr_1vmtest_1impl_1HtmlAnnotations$onError$Ljava_1lang_1Object_12__Ljava_lang_Object_2Lorg_apidesign_bck2brwsr_vmtest_impl_HtmlAnnotations_2Ljava_lang_Object_2",
319.15 + "Pretty long method name"
319.16 + );
319.17 + }
319.18 }
320.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java Tue Apr 29 15:25:58 2014 +0200
320.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java Wed Apr 30 15:04:10 2014 +0200
320.3 @@ -21,20 +21,19 @@
320.4 import java.io.InputStream;
320.5 import java.net.URL;
320.6 import java.util.Enumeration;
320.7 -import java.util.Set;
320.8 -import java.util.TreeSet;
320.9
320.10 /**
320.11 *
320.12 * @author Jaroslav Tulach <jtulach@netbeans.org>
320.13 */
320.14 public final class BytesLoader {
320.15 - private static Set<String> requested = new TreeSet<String>();
320.16 + private static final StringArray requested = new StringArray();
320.17
320.18 public byte[] get(String name) throws IOException {
320.19 - if (!requested.add(name)) {
320.20 + if (requested.contains(name)) {
320.21 throw new IllegalStateException("Requested for second time: " + name);
320.22 }
320.23 + requested.add(name);
320.24 byte[] arr = readClass(name);
320.25 /*
320.26 System.err.print("loader['" + name + "'] = [");
321.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Tue Apr 29 15:25:58 2014 +0200
321.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Wed Apr 30 15:04:10 2014 +0200
321.3 @@ -215,4 +215,17 @@
321.4 );
321.5 }
321.6
321.7 + @Test public void typeOfFn() throws Exception {
321.8 + assertExec("Type of function is Object", Classes.class,
321.9 + "typeOfFn__Ljava_lang_String_2",
321.10 + "java.lang.Object"
321.11 + );
321.12 + }
321.13 +
321.14 + @Test public void instanceOfSuperInterface() throws Exception {
321.15 + assertExec("Is iof super interface", Classes.class,
321.16 + "instanceOfSuperInterface__Z",
321.17 + 1.0
321.18 + );
321.19 + }
321.20 }
322.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Tue Apr 29 15:25:58 2014 +0200
322.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Wed Apr 30 15:04:10 2014 +0200
322.3 @@ -18,6 +18,7 @@
322.4 package org.apidesign.vm4brwsr;
322.5
322.6 import java.io.IOException;
322.7 +import java.io.Serializable;
322.8 import java.lang.annotation.Annotation;
322.9 import java.lang.annotation.Retention;
322.10 import java.lang.annotation.RetentionPolicy;
322.11 @@ -233,4 +234,20 @@
322.12 public static String valueEnum(String v) {
322.13 return ClassesMarker.E.valueOf(v).toString();
322.14 }
322.15 +
322.16 + public static String typeOfFn() {
322.17 + return fn().getClass().getName();
322.18 + }
322.19 +
322.20 + @JavaScriptBody(args = { }, body = "return function() { alert('x'); };")
322.21 + private native static Object fn();
322.22 +
322.23 + public static boolean instanceOfSuperInterface() {
322.24 + Object obj = new SuperSerial() {
322.25 + };
322.26 + return obj instanceof Serializable;
322.27 + }
322.28 +
322.29 + private static interface SuperSerial extends Serializable {
322.30 + }
322.31 }
323.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
323.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/DelayedLoading.java Wed Apr 30 15:04:10 2014 +0200
323.3 @@ -0,0 +1,31 @@
323.4 +/**
323.5 + * Back 2 Browser Bytecode Translator
323.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
323.7 + *
323.8 + * This program is free software: you can redistribute it and/or modify
323.9 + * it under the terms of the GNU General Public License as published by
323.10 + * the Free Software Foundation, version 2 of the License.
323.11 + *
323.12 + * This program is distributed in the hope that it will be useful,
323.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
323.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
323.15 + * GNU General Public License for more details.
323.16 + *
323.17 + * You should have received a copy of the GNU General Public License
323.18 + * along with this program. Look for COPYING file in the top folder.
323.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
323.20 + */
323.21 +package org.apidesign.vm4brwsr;
323.22 +
323.23 +import java.net.URL;
323.24 +
323.25 +/**
323.26 + *
323.27 + * @author Jaroslav Tulach <jtulach@netbeans.org>
323.28 + */
323.29 +public class DelayedLoading {
323.30 + public static String toStrViaURI(String url) throws Exception {
323.31 + URL u = new URL(url);
323.32 + return u.toURI().toString();
323.33 + }
323.34 +}
324.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
324.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/DelayedLoadingTest.java Wed Apr 30 15:04:10 2014 +0200
324.3 @@ -0,0 +1,55 @@
324.4 +/**
324.5 + * Back 2 Browser Bytecode Translator
324.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
324.7 + *
324.8 + * This program is free software: you can redistribute it and/or modify
324.9 + * it under the terms of the GNU General Public License as published by
324.10 + * the Free Software Foundation, version 2 of the License.
324.11 + *
324.12 + * This program is distributed in the hope that it will be useful,
324.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
324.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
324.15 + * GNU General Public License for more details.
324.16 + *
324.17 + * You should have received a copy of the GNU General Public License
324.18 + * along with this program. Look for COPYING file in the top folder.
324.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
324.20 + */
324.21 +package org.apidesign.vm4brwsr;
324.22 +
324.23 +import java.net.URL;
324.24 +import org.testng.annotations.BeforeClass;
324.25 +import org.testng.annotations.AfterClass;
324.26 +import org.testng.annotations.Test;
324.27 +
324.28 +/**
324.29 + *
324.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
324.31 + */
324.32 +public class DelayedLoadingTest {
324.33 + private static TestVM code;
324.34 +
324.35 + @Test public void verifyUsageOf() throws Exception {
324.36 + code.register(new BytesLoader());
324.37 +
324.38 + URL u = new URL("http://apidesign.org");
324.39 +
324.40 + Object str = code.execCode("Access URI",
324.41 + DelayedLoading.class, "toStrViaURI__Ljava_lang_String_2Ljava_lang_String_2",
324.42 + u.toExternalForm(), u.toExternalForm()
324.43 + );
324.44 + }
324.45 +
324.46 +
324.47 + @BeforeClass
324.48 + public static void compileTheCode() throws Exception {
324.49 + code = TestVM.compileClass(
324.50 + "org/apidesign/vm4brwsr/DelayedLoading");
324.51 + }
324.52 + @AfterClass
324.53 + public static void releaseTheCode() {
324.54 + code = null;
324.55 + }
324.56 +
324.57 +}
324.58 +
325.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
325.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Hello.java Wed Apr 30 15:04:10 2014 +0200
325.3 @@ -0,0 +1,35 @@
325.4 +/**
325.5 + * Back 2 Browser Bytecode Translator
325.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
325.7 + *
325.8 + * This program is free software: you can redistribute it and/or modify
325.9 + * it under the terms of the GNU General Public License as published by
325.10 + * the Free Software Foundation, version 2 of the License.
325.11 + *
325.12 + * This program is distributed in the hope that it will be useful,
325.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
325.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
325.15 + * GNU General Public License for more details.
325.16 + *
325.17 + * You should have received a copy of the GNU General Public License
325.18 + * along with this program. Look for COPYING file in the top folder.
325.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
325.20 + */
325.21 +package org.apidesign.vm4brwsr;
325.22 +
325.23 +import java.io.IOException;
325.24 +
325.25 +/**
325.26 + *
325.27 + * @author Jaroslav Tulach <jtulach@netbeans.org>
325.28 + */
325.29 +public class Hello {
325.30 + public static String hello() {
325.31 + return "Hello World!";
325.32 + }
325.33 +
325.34 + public static Object reloadYourSelf(byte[] arr) throws IOException {
325.35 + org.apidesign.vm4brwsr.api.VM.reload(Hello.class, arr);
325.36 + return null;
325.37 + }
325.38 +}
326.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Instance.java Tue Apr 29 15:25:58 2014 +0200
326.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Instance.java Wed Apr 30 15:04:10 2014 +0200
326.3 @@ -137,4 +137,8 @@
326.4
326.5 @JavaScriptBody(args = { "instance" }, body = "return instance.getByte__B();")
326.6 private static native int jsgetbytes(Instance instance);
326.7 +
326.8 + int sum(int i, int i0) {
326.9 + return i + i0;
326.10 + }
326.11 }
327.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/InstanceSub.java Tue Apr 29 15:25:58 2014 +0200
327.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/InstanceSub.java Wed Apr 30 15:04:10 2014 +0200
327.3 @@ -31,7 +31,7 @@
327.4
327.5 @Override
327.6 public void setByte(byte b) {
327.7 - super.setByte((byte) (b + 1));
327.8 + super.setByte((byte) (b + StaticMethod.MISSING_CONSTANT));
327.9 }
327.10
327.11 public static double recallDbl() {
328.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
328.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/NoStringCnstntsTest.java Wed Apr 30 15:04:10 2014 +0200
328.3 @@ -0,0 +1,62 @@
328.4 +/**
328.5 + * Back 2 Browser Bytecode Translator
328.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
328.7 + *
328.8 + * This program is free software: you can redistribute it and/or modify
328.9 + * it under the terms of the GNU General Public License as published by
328.10 + * the Free Software Foundation, version 2 of the License.
328.11 + *
328.12 + * This program is distributed in the hope that it will be useful,
328.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
328.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
328.15 + * GNU General Public License for more details.
328.16 + *
328.17 + * You should have received a copy of the GNU General Public License
328.18 + * along with this program. Look for COPYING file in the top folder.
328.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
328.20 + */
328.21 +
328.22 +package org.apidesign.vm4brwsr;
328.23 +
328.24 +import java.io.IOException;
328.25 +import java.io.InputStream;
328.26 +import static org.testng.Assert.assertEquals;
328.27 +import org.testng.annotations.AfterClass;
328.28 +import org.testng.annotations.BeforeClass;
328.29 +import org.testng.annotations.Test;
328.30 +
328.31 +/**
328.32 + *
328.33 + * @author Jaroslav Tulach <jtulach@netbeans.org>
328.34 + */
328.35 +public class NoStringCnstntsTest {
328.36 + private static String code;
328.37 +
328.38 +
328.39 + @Test public void dontGeneratePrimitiveFinalConstants() {
328.40 + assertEquals(code.indexOf("HELLO"), -1, "MISSING_CONSTANT field should not be generated");
328.41 + }
328.42 +
328.43 + @BeforeClass
328.44 + public static void compileTheCode() throws Exception {
328.45 + final String res = "org/apidesign/vm4brwsr/StringSample";
328.46 + StringBuilder sb = new StringBuilder();
328.47 + class JustStaticMethod implements Bck2Brwsr.Resources {
328.48 + @Override
328.49 + public InputStream get(String resource) throws IOException {
328.50 + final String cn = res + ".class";
328.51 + if (resource.equals(cn)) {
328.52 + return getClass().getClassLoader().getResourceAsStream(cn);
328.53 + }
328.54 + return null;
328.55 + }
328.56 + }
328.57 + Bck2Brwsr.generate(sb, new JustStaticMethod(), res);
328.58 + code = sb.toString();
328.59 + }
328.60 + @AfterClass
328.61 + public static void releaseTheCode() {
328.62 + code = null;
328.63 + }
328.64 +
328.65 +}
329.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Tue Apr 29 15:25:58 2014 +0200
329.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Wed Apr 30 15:04:10 2014 +0200
329.3 @@ -77,16 +77,22 @@
329.4 new byte[] { (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)13, (byte)126 }
329.5 );
329.6 }
329.7 - /* XXX: JavaScript cannot represent as big longs as Java.
329.8 + @Test public void deserializeMiddleLong() throws Exception {
329.9 + final byte[] arr = new byte[] {
329.10 + (byte)0, (byte)0, (byte)64, (byte)32, (byte)23, (byte)0, (byte)0, (byte)0
329.11 + };
329.12 + long exp = Numbers.deserLong(arr, 16);
329.13 + assertExec("Should be " + exp, Numbers.class, "deserLong__J_3BI",
329.14 + Double.valueOf(exp), arr, 16);
329.15 + }
329.16 @Test public void deserializeLargeLong() throws Exception {
329.17 final byte[] arr = new byte[] {
329.18 (byte)64, (byte)8, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0
329.19 };
329.20 - long exp = Numbers.deserLong(arr);
329.21 - assertExec("Should be " + exp, "org_apidesign_vm4brwsr_Numbers_deserLong__JAB",
329.22 - Double.valueOf(exp), arr);
329.23 + long exp = Numbers.deserLong(arr, 32);
329.24 + assertExec("Should be " + exp, Numbers.class, "deserLong__J_3BI",
329.25 + Double.valueOf(exp), arr, 32);
329.26 }
329.27 - */
329.28
329.29 @Test public void deserializeFloatInJava() throws Exception {
329.30 float f = 54324.32423f;
329.31 @@ -111,6 +117,12 @@
329.32 double f = 3.0;
329.33 assertExec("Should be the same", Numbers.class, "deserDouble__D", f);
329.34 }
329.35 +
329.36 + @Test public void bytesToLong() throws Exception {
329.37 + long exp = Numbers.bytesToLong((byte)30, (byte)20, 32);
329.38 + assertExec("Should be the same", Numbers.class, "bytesToLong__JBBI",
329.39 + Double.valueOf(exp), 30, 20, 32);
329.40 + }
329.41 /*
329.42 @Test public void serDouble() throws IOException {
329.43 double f = 3.0;
330.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Tue Apr 29 15:25:58 2014 +0200
330.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Wed Apr 30 15:04:10 2014 +0200
330.3 @@ -55,12 +55,19 @@
330.4 DataInputStream dis = new DataInputStream(is);
330.5 return dis.readLong();
330.6 }
330.7 + static long deserLong(byte[] arr, int shift) throws IOException {
330.8 + return deserLong(arr) >> shift;
330.9 + }
330.10 static int deserInt() throws IOException {
330.11 byte[] arr = {(byte) 71, (byte) 84, (byte) 52, (byte) 83};
330.12 ByteArrayInputStream is = new ByteArrayInputStream(arr);
330.13 DataInputStream dis = new DataInputStream(is);
330.14 return dis.readInt();
330.15 }
330.16 + static long bytesToLong(byte b1, byte b2, int shift) {
330.17 + return (((long)b1 << 56) +
330.18 + ((long)b2 & 255) << 48) >> shift;
330.19 + }
330.20
330.21 static String intToString() {
330.22 return new Integer(5).toString().toString();
331.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
331.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ReloadingTest.java Wed Apr 30 15:04:10 2014 +0200
331.3 @@ -0,0 +1,72 @@
331.4 +/**
331.5 + * Back 2 Browser Bytecode Translator
331.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
331.7 + *
331.8 + * This program is free software: you can redistribute it and/or modify
331.9 + * it under the terms of the GNU General Public License as published by
331.10 + * the Free Software Foundation, version 2 of the License.
331.11 + *
331.12 + * This program is distributed in the hope that it will be useful,
331.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
331.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
331.15 + * GNU General Public License for more details.
331.16 + *
331.17 + * You should have received a copy of the GNU General Public License
331.18 + * along with this program. Look for COPYING file in the top folder.
331.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
331.20 + */
331.21 +package org.apidesign.vm4brwsr;
331.22 +
331.23 +import org.testng.annotations.BeforeClass;
331.24 +import org.testng.annotations.AfterClass;
331.25 +import org.testng.annotations.Test;
331.26 +
331.27 +/**
331.28 + *
331.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
331.30 + */
331.31 +public class ReloadingTest {
331.32 + private static TestVM code;
331.33 +
331.34 + @Test public void verifyUsageOf() throws Exception {
331.35 + code.execCode("First hello",
331.36 + Hello.class, "hello__Ljava_lang_String_2",
331.37 + "Hello World!"
331.38 + );
331.39 +
331.40 + byte[] arr = BytesLoader.readClass("org/apidesign/vm4brwsr/Hello.class");
331.41 + for (int i = 0; i < arr.length; i++) {
331.42 + if (arr[i] == 'H' && arr[i + 1] == 'e' && arr[i + 2] == 'l') {
331.43 + arr[i] = 'A';
331.44 + arr[i + 1] = 'h';
331.45 + arr[i + 2] = 'o';
331.46 + arr[i + 3] = 'y';
331.47 + arr[i + 4] = ' ';
331.48 + break;
331.49 + }
331.50 + }
331.51 +
331.52 + code.execCode("Redefine class",
331.53 + Hello.class, "reloadYourSelf__Ljava_lang_Object_2_3B",
331.54 + null, arr
331.55 + );
331.56 +
331.57 + code.execCode("Second hello",
331.58 + Hello.class, "hello__Ljava_lang_String_2",
331.59 + "Ahoy World!"
331.60 + );
331.61 + }
331.62 +
331.63 +
331.64 + @BeforeClass
331.65 + public static void compileTheCode() throws Exception {
331.66 + code = TestVM.compileClass(
331.67 + "org/apidesign/vm4brwsr/Hello");
331.68 + }
331.69 + @AfterClass
331.70 + public static void releaseTheCode() {
331.71 + code = null;
331.72 + }
331.73 +
331.74 +}
331.75 +
332.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/Resources.java Tue Apr 29 15:25:58 2014 +0200
332.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Resources.java Wed Apr 30 15:04:10 2014 +0200
332.3 @@ -59,6 +59,10 @@
332.4
332.5 return sb.toString().toString();
332.6 }
332.7 + static long bytesToLong(byte b1, byte b2, int shift) {
332.8 + return (((long)b1 << 56) +
332.9 + ((long)b2 & 255) << 48) >> shift;
332.10 + }
332.11
332.12 static String loadHello() throws IOException {
332.13 Enumeration<URL> en;
333.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/ResourcesWithExtensionsTest.java Tue Apr 29 15:25:58 2014 +0200
333.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/ResourcesWithExtensionsTest.java Wed Apr 30 15:04:10 2014 +0200
333.3 @@ -46,7 +46,7 @@
333.4 );
333.5 }
333.6 */
333.7 -
333.8 +
333.9 private static TestVM code;
333.10
333.11 @BeforeClass
334.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
334.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/SizeOfAMethodTest.java Wed Apr 30 15:04:10 2014 +0200
334.3 @@ -0,0 +1,96 @@
334.4 +/**
334.5 + * Back 2 Browser Bytecode Translator
334.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
334.7 + *
334.8 + * This program is free software: you can redistribute it and/or modify
334.9 + * it under the terms of the GNU General Public License as published by
334.10 + * the Free Software Foundation, version 2 of the License.
334.11 + *
334.12 + * This program is distributed in the hope that it will be useful,
334.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
334.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
334.15 + * GNU General Public License for more details.
334.16 + *
334.17 + * You should have received a copy of the GNU General Public License
334.18 + * along with this program. Look for COPYING file in the top folder.
334.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
334.20 + */
334.21 +/*
334.22 + * To change this license header, choose License Headers in Project Properties.
334.23 + * To change this template file, choose Tools | Templates
334.24 + * and open the template in the editor.
334.25 + */
334.26 +
334.27 +package org.apidesign.vm4brwsr;
334.28 +
334.29 +import java.io.IOException;
334.30 +import java.io.InputStream;
334.31 +import static org.testng.Assert.assertEquals;
334.32 +import static org.testng.Assert.assertTrue;
334.33 +import org.testng.annotations.AfterClass;
334.34 +import org.testng.annotations.BeforeClass;
334.35 +import org.testng.annotations.Test;
334.36 +
334.37 +/**
334.38 + *
334.39 + * @author Jaroslav Tulach <jtulach@netbeans.org>
334.40 + */
334.41 +public class SizeOfAMethodTest {
334.42 + private static String code;
334.43 +
334.44 + @Test public void sumXYShouldBeSmall() {
334.45 + String s = code;
334.46 + int beg = s.indexOf("c.sum__III");
334.47 + int end = s.indexOf("c.sum__III.access");
334.48 +
334.49 + assertTrue(beg > 0, "Found sum method in " + code);
334.50 + assertTrue(beg < end, "Found end of sum method in " + code);
334.51 +
334.52 + String method = s.substring(beg, end);
334.53 +
334.54 +
334.55 + assertEquals(method.indexOf("st"), -1, "There should be no stack operations:\n" + method);
334.56 + }
334.57 +
334.58 + @Test public void emptyConstructorRequiresNoStack() {
334.59 + String s = code;
334.60 + int beg = s.indexOf("CLS.cons__V");
334.61 + int end = s.indexOf("CLS.cons__V.access");
334.62 +
334.63 + assertTrue(beg > 0, "Found constructor in " + code);
334.64 + assertTrue(beg < end, "Found end of constructor in " + code);
334.65 +
334.66 + String method = s.substring(beg, end);
334.67 + method = method.replace("constructor", "CNSTR");
334.68 +
334.69 + assertEquals(method.indexOf("st"), -1, "There should be no stack operations:\n" + method);
334.70 + assertEquals(method.indexOf("for"), -1, "There should be no for blocks:\n" + method);
334.71 + }
334.72 +
334.73 + @Test public void dontGeneratePrimitiveFinalConstants() {
334.74 + assertEquals(code.indexOf("MISSING_CONSTANT"), -1, "MISSING_CONSTANT field should not be generated");
334.75 + }
334.76 +
334.77 + @BeforeClass
334.78 + public static void compileTheCode() throws Exception {
334.79 + final String res = "org/apidesign/vm4brwsr/StaticMethod";
334.80 + StringBuilder sb = new StringBuilder();
334.81 + class JustStaticMethod implements Bck2Brwsr.Resources {
334.82 + @Override
334.83 + public InputStream get(String resource) throws IOException {
334.84 + final String cn = res + ".class";
334.85 + if (resource.equals(cn)) {
334.86 + return getClass().getClassLoader().getResourceAsStream(cn);
334.87 + }
334.88 + return null;
334.89 + }
334.90 + }
334.91 + Bck2Brwsr.generate(sb, new JustStaticMethod(), res);
334.92 + code = sb.toString();
334.93 + }
334.94 + @AfterClass
334.95 + public static void releaseTheCode() {
334.96 + code = null;
334.97 + }
334.98 +
334.99 +}
335.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java Tue Apr 29 15:25:58 2014 +0200
335.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethod.java Wed Apr 30 15:04:10 2014 +0200
335.3 @@ -24,6 +24,7 @@
335.4 * @author Jaroslav Tulach <jtulach@netbeans.org>
335.5 */
335.6 public class StaticMethod {
335.7 + public static final int MISSING_CONSTANT = 1;
335.8 private static int cnt;
335.9 private static Object NULL;
335.10
335.11 @@ -82,7 +83,7 @@
335.12 if (n <= 1) {
335.13 return 1;
335.14 } else {
335.15 - return n * factRec(n - 1);
335.16 + return n * factRec(n - MISSING_CONSTANT);
335.17 }
335.18 }
335.19 public static long factIter(int n) {
335.20 @@ -99,6 +100,10 @@
335.21 return cnt;
335.22 }
335.23
335.24 + public static int helloWorldLength(String x) {
335.25 + return (StringSample.HELLO + x).length();
335.26 + }
335.27 +
335.28 @JavaScriptBody(
335.29 args={"i","j"}, body="\n\r\treturn (i + j).toString();"
335.30 )
335.31 @@ -128,6 +133,62 @@
335.32 }
335.33 }
335.34
335.35 + public static int castString(Object o) {
335.36 + return ((String)o).length();
335.37 + }
335.38 +
335.39 + public static int initInflater(int w, boolean nowrap) {
335.40 + Instance i = new Instance(w, 0.0);
335.41 + return i.sum(nowrap?-w:w, 1);
335.42 + }
335.43 +
335.44 + public static String toStringArr() {
335.45 + class N implements Next {
335.46 + int idx = 0;
335.47 +
335.48 + @Override
335.49 + public boolean hasNext() {
335.50 + return idx < 5;
335.51 + }
335.52 +
335.53 + @Override
335.54 + public String next() {
335.55 + switch (idx++) {
335.56 + case 0: return "Zero";
335.57 + case 1: return "One";
335.58 + case 2: return "Two";
335.59 + case 3: return "Three";
335.60 + case 4: return "Four";
335.61 + }
335.62 + throw new IllegalStateException();
335.63 + }
335.64 + }
335.65 + return toString(null, new N()).toString();
335.66 + }
335.67 +
335.68 + static String toString(Object thiz, Next it) {
335.69 + if (!it.hasNext()) {
335.70 + return "[]";
335.71 + }
335.72 +
335.73 + StringBuilder sb = new StringBuilder();
335.74 + sb.append('[');
335.75 + for (;;) {
335.76 + String e = it.next();
335.77 + sb.append(e == thiz ? "(this Collection)" : e);
335.78 + if (!it.hasNext()) {
335.79 + return sb.append(']').toString();
335.80 + }
335.81 + sb.append(',').append(' ');
335.82 + }
335.83 + }
335.84 +
335.85 + static interface Next {
335.86 + boolean hasNext();
335.87 + String next();
335.88 + }
335.89 +
335.90 +
335.91 static {
335.92 // check order of initializers
335.93 StaticUse.NON_NULL.equals(new Object());
336.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Tue Apr 29 15:25:58 2014 +0200
336.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Wed Apr 30 15:04:10 2014 +0200
336.3 @@ -36,6 +36,15 @@
336.4 );
336.5 }
336.6
336.7 + @Test public void cast() throws Exception {
336.8 + assertExec(
336.9 + "Length is four",
336.10 + StaticMethod.class, "castString__ILjava_lang_Object_2",
336.11 + Double.valueOf(4),
336.12 + "Ahoj"
336.13 + );
336.14 + }
336.15 +
336.16 @Test public void checkReallyInitializedValues() throws Exception {
336.17 assertExec(
336.18 "Return true",
336.19 @@ -161,6 +170,25 @@
336.20 3, 3.75
336.21 );
336.22 }
336.23 +
336.24 + @Test public void inflaterInit() throws Exception {
336.25 + assertExec(
336.26 + "Down and minus",
336.27 + StaticMethod.class, "initInflater__IIZ",
336.28 + Double.valueOf(-9),
336.29 + 10, true
336.30 + );
336.31 + }
336.32 +
336.33 + @Test public void inflaterInitNoNeg() throws Exception {
336.34 + assertExec(
336.35 + "One up",
336.36 + StaticMethod.class, "initInflater__IIZ",
336.37 + Double.valueOf(11),
336.38 + 10, false
336.39 + );
336.40 + }
336.41 +
336.42 @Test public void mixedMethodFourParams() throws Exception {
336.43 assertExec(
336.44 "Should be two",
336.45 @@ -196,6 +224,15 @@
336.46 );
336.47 }
336.48
336.49 + @Test public void collectionToString() throws Exception {
336.50 + String exp = StaticMethod.toStringArr();
336.51 + assertExec(
336.52 + "0 to 4",
336.53 + StaticMethod.class, "toStringArr__Ljava_lang_String_2",
336.54 + exp
336.55 + );
336.56 + }
336.57 +
336.58 @Test public void or() throws Exception {
336.59 assertExec(
336.60 "Or will be 7",
336.61 @@ -322,6 +359,13 @@
336.62 );
336.63 }
336.64
336.65 + @Test public void stringConstantIsCopied() throws Exception {
336.66 + assertExec("String constants are copied between class pools",
336.67 + StaticMethod.class, "helloWorldLength__ILjava_lang_String_2",
336.68 + 17, "Jardo"
336.69 + );
336.70 + }
336.71 +
336.72 private static TestVM code;
336.73
336.74 @BeforeClass
337.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Tue Apr 29 15:25:58 2014 +0200
337.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringSample.java Wed Apr 30 15:04:10 2014 +0200
337.3 @@ -80,6 +80,10 @@
337.4 return sb.toString().toString();
337.5 }
337.6
337.7 + public static String unicode() {
337.8 + return "\r\n\u2028\u2029]";
337.9 + }
337.10 +
337.11 public static String insertBuffer() {
337.12 StringBuilder sb = new StringBuilder();
337.13 sb.append("Jardo!");
338.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Tue Apr 29 15:25:58 2014 +0200
338.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/StringTest.java Wed Apr 30 15:04:10 2014 +0200
338.3 @@ -213,6 +213,16 @@
338.4 exp, false, true
338.5 );
338.6 }
338.7 +
338.8 + @Test public void weirdUnicodeCharacters() throws Exception {
338.9 + String exp = StringSample.unicode();
338.10 +
338.11 + assertExec(
338.12 + "Unicode is OK",
338.13 + StringSample.class, "unicode__Ljava_lang_String_2",
338.14 + exp
338.15 + );
338.16 + }
338.17
338.18 @Test public void valueOfOnJSArray() throws Exception {
338.19 assertExec(
339.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Tue Apr 29 15:25:58 2014 +0200
339.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Wed Apr 30 15:04:10 2014 +0200
339.3 @@ -25,23 +25,33 @@
339.4 import java.net.URL;
339.5 import java.util.Enumeration;
339.6 import javax.script.Invocable;
339.7 +import javax.script.ScriptContext;
339.8 import javax.script.ScriptEngine;
339.9 import javax.script.ScriptEngineManager;
339.10 import javax.script.ScriptException;
339.11 import static org.testng.Assert.*;
339.12
339.13 -final class TestVM {
339.14 +public final class TestVM {
339.15 private final Invocable code;
339.16 private final CharSequence codeSeq;
339.17 private final Object bck2brwsr;
339.18 + private BytesLoader resources;
339.19
339.20
339.21 private TestVM(Invocable code, CharSequence codeSeq) throws ScriptException, NoSuchMethodException {
339.22 this.code = code;
339.23 this.codeSeq = codeSeq;
339.24 - this.bck2brwsr = code.invokeFunction("bck2brwsr");
339.25 + this.bck2brwsr = ((ScriptEngine)code).eval("bck2brwsr(function(n) { return loader.get(n); })");
339.26 + ((ScriptEngine)code).getContext().setAttribute("loader", this, ScriptContext.ENGINE_SCOPE);
339.27 }
339.28
339.29 + public void register(BytesLoader res) {
339.30 + this.resources = res;
339.31 + }
339.32 +
339.33 + public byte[] get(String res) throws IOException {
339.34 + return resources != null ? resources.get(res) : null;
339.35 + }
339.36
339.37 public Object execCode(
339.38 String msg, Class<?> clazz, String method,
339.39 @@ -234,11 +244,26 @@
339.40 return ex.toString();
339.41 }
339.42 }
339.43 -
339.44 +
339.45 + final CharSequence codeSeq() {
339.46 + return codeSeq;
339.47 + }
339.48
339.49 private static class EmulationResources implements Bck2Brwsr.Resources {
339.50 @Override
339.51 public InputStream get(String name) throws IOException {
339.52 + if ("java/net/URI.class".equals(name)) {
339.53 + // skip
339.54 + return null;
339.55 + }
339.56 + if ("java/net/URLConnection.class".equals(name)) {
339.57 + // skip
339.58 + return null;
339.59 + }
339.60 + if ("java/lang/System.class".equals(name)) {
339.61 + // skip
339.62 + return null;
339.63 + }
339.64 Enumeration<URL> en = StaticMethodTest.class.getClassLoader().getResources(name);
339.65 URL u = null;
339.66 while (en.hasMoreElements()) {
340.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
340.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/UnderTest.java Wed Apr 30 15:04:10 2014 +0200
340.3 @@ -0,0 +1,88 @@
340.4 +/**
340.5 + * Back 2 Browser Bytecode Translator
340.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
340.7 + *
340.8 + * This program is free software: you can redistribute it and/or modify
340.9 + * it under the terms of the GNU General Public License as published by
340.10 + * the Free Software Foundation, version 2 of the License.
340.11 + *
340.12 + * This program is distributed in the hope that it will be useful,
340.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
340.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
340.15 + * GNU General Public License for more details.
340.16 + *
340.17 + * You should have received a copy of the GNU General Public License
340.18 + * along with this program. Look for COPYING file in the top folder.
340.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
340.20 + */
340.21 +package org.apidesign.vm4brwsr;
340.22 +
340.23 +import org.testng.annotations.AfterClass;
340.24 +import org.testng.annotations.BeforeClass;
340.25 +import org.testng.annotations.Test;
340.26 +
340.27 +/** Checks behavior of classes and methods with underscore.
340.28 + *
340.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
340.30 + */
340.31 +public class UnderTest {
340.32 + @Test public void one() throws Exception {
340.33 + assertExec(
340.34 + "Should be one",
340.35 + Under_Score.class, "one__I",
340.36 + Double.valueOf(1)
340.37 + );
340.38 + }
340.39 +
340.40 + @Test public void onePlusOne() throws Exception {
340.41 + assertExec(
340.42 + "Should be two",
340.43 + Under_Score.class, "one_1plus_1one__I",
340.44 + Double.valueOf(2)
340.45 + );
340.46 + }
340.47 +
340.48 + @Test public void two() throws Exception {
340.49 + assertExec(
340.50 + "Should be two",
340.51 + Under_Score.class, "two__I",
340.52 + Double.valueOf(2)
340.53 + );
340.54 + }
340.55 +
340.56 + @Test public void staticField() throws Exception {
340.57 + assertExec(
340.58 + "Should be ten",
340.59 + Under_Score.class, "staticField__I",
340.60 + Double.valueOf(10)
340.61 + );
340.62 + }
340.63 +
340.64 + @Test public void instance() throws Exception {
340.65 + assertExec(
340.66 + "Should be five",
340.67 + Under_Score.class, "instance__I",
340.68 + Double.valueOf(5)
340.69 + );
340.70 + }
340.71 +
340.72 +
340.73 + private static TestVM code;
340.74 +
340.75 + @BeforeClass
340.76 + public static void compileTheCode() throws Exception {
340.77 + StringBuilder sb = new StringBuilder();
340.78 + code = TestVM.compileClass(sb, "org/apidesign/vm4brwsr/Under_Score");
340.79 + }
340.80 + @AfterClass
340.81 + public static void releaseTheCode() {
340.82 + code = null;
340.83 + }
340.84 +
340.85 + private void assertExec(
340.86 + String msg, Class<?> clazz, String method,
340.87 + Object ret, Object... args
340.88 + ) throws Exception {
340.89 + code.assertExec(msg, clazz, method, ret, args);
340.90 + }
340.91 +}
341.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
341.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/Under_Score.java Wed Apr 30 15:04:10 2014 +0200
341.3 @@ -0,0 +1,51 @@
341.4 +/**
341.5 + * Back 2 Browser Bytecode Translator
341.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
341.7 + *
341.8 + * This program is free software: you can redistribute it and/or modify
341.9 + * it under the terms of the GNU General Public License as published by
341.10 + * the Free Software Foundation, version 2 of the License.
341.11 + *
341.12 + * This program is distributed in the hope that it will be useful,
341.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
341.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
341.15 + * GNU General Public License for more details.
341.16 + *
341.17 + * You should have received a copy of the GNU General Public License
341.18 + * along with this program. Look for COPYING file in the top folder.
341.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
341.20 + */
341.21 +package org.apidesign.vm4brwsr;
341.22 +
341.23 +/**
341.24 + *
341.25 + * @author Jaroslav Tulach <jtulach@netbeans.org>
341.26 + */
341.27 +public class Under_Score {
341.28 + public static int under_field = 10;
341.29 + public int instance_field = 5;
341.30 +
341.31 + public static int one() {
341.32 + return 1;
341.33 + }
341.34 +
341.35 + public static int one_plus_one() {
341.36 + return 1 + 1;
341.37 + }
341.38 +
341.39 + public static int two() {
341.40 + return one_plus_one();
341.41 + }
341.42 +
341.43 + public static int staticField() {
341.44 + return under_field;
341.45 + }
341.46 +
341.47 + public static int instance() {
341.48 + return new Under_Score().get_fld();
341.49 + }
341.50 +
341.51 + private int get_fld() {
341.52 + return instance_field;
341.53 + }
341.54 +}
342.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Tue Apr 29 15:25:58 2014 +0200
342.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Wed Apr 30 15:04:10 2014 +0200
342.3 @@ -79,7 +79,7 @@
342.4 }
342.5 }
342.6 w.append("\n];\n");
342.7 - w.append(code.toString());
342.8 + w.append(code.codeSeq());
342.9 w.close();
342.10 throw new Exception(ex.getMessage() + " file: " + f, ex);
342.11 }
343.1 --- a/rt/vmtest/pom.xml Tue Apr 29 15:25:58 2014 +0200
343.2 +++ b/rt/vmtest/pom.xml Wed Apr 30 15:04:10 2014 +0200
343.3 @@ -4,11 +4,11 @@
343.4 <parent>
343.5 <groupId>org.apidesign.bck2brwsr</groupId>
343.6 <artifactId>rt</artifactId>
343.7 - <version>0.8-SNAPSHOT</version>
343.8 + <version>0.9-SNAPSHOT</version>
343.9 </parent>
343.10 <groupId>org.apidesign.bck2brwsr</groupId>
343.11 <artifactId>vmtest</artifactId>
343.12 - <version>0.8-SNAPSHOT</version>
343.13 + <version>0.9-SNAPSHOT</version>
343.14
343.15 <name>VM Testing APIs</name>
343.16 <url>http://bck2brwsr.apidesign.org</url>
344.1 --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/VMTest.java Tue Apr 29 15:25:58 2014 +0200
344.2 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/VMTest.java Wed Apr 30 15:04:10 2014 +0200
344.3 @@ -17,6 +17,7 @@
344.4 */
344.5 package org.apidesign.bck2brwsr.vmtest;
344.6
344.7 +import java.lang.annotation.Annotation;
344.8 import java.util.ArrayList;
344.9 import java.util.Arrays;
344.10 import java.util.List;
344.11 @@ -39,6 +40,7 @@
344.12 public final class VMTest {
344.13 private final List<Class> classes = new ArrayList<>();
344.14 private final List<String> launcher = new ArrayList<>();
344.15 + private Class<? extends Annotation> annotation = BrwsrTest.class;
344.16
344.17 private VMTest() {
344.18 }
344.19 @@ -104,6 +106,24 @@
344.20 this.launcher.addAll(Arrays.asList(launcher));
344.21 return this;
344.22 }
344.23 +
344.24 + /** Specifies which annotation annotates the test methods
344.25 + * to be executed. By
344.26 + * default it is the {@link BrwsrTest} annotation. Methods in
344.27 + * {@link #withClasses(java.lang.Class[]) test classes} annotated by
344.28 + * this annotation will be executed.
344.29 + *
344.30 + * @param aClass an annotation class
344.31 + * @return this
344.32 + * @since 0.8
344.33 + */
344.34 + public final VMTest withTestAnnotation(Class<? extends Annotation> aClass) {
344.35 + if (!aClass.isAnnotation()) {
344.36 + throw new IllegalStateException();
344.37 + }
344.38 + this.annotation = aClass;
344.39 + return this;
344.40 + }
344.41
344.42 /** Assembles the provided information into the final array of tests.
344.43 * @return array of TestNG tests
344.44 @@ -112,7 +132,8 @@
344.45 public final Object[] build() {
344.46 return CompareCase.create(
344.47 launcher.toArray(new String[0]),
344.48 - classes.toArray(new Class[0])
344.49 + classes.toArray(new Class[0]),
344.50 + annotation
344.51 );
344.52 }
344.53 }
345.1 --- a/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Tue Apr 29 15:25:58 2014 +0200
345.2 +++ b/rt/vmtest/src/main/java/org/apidesign/bck2brwsr/vmtest/impl/CompareCase.java Wed Apr 30 15:04:10 2014 +0200
345.3 @@ -17,6 +17,7 @@
345.4 */
345.5 package org.apidesign.bck2brwsr.vmtest.impl;
345.6
345.7 +import java.lang.annotation.Annotation;
345.8 import org.apidesign.bck2brwsr.vmtest.*;
345.9 import java.lang.reflect.Method;
345.10 import java.util.ArrayList;
345.11 @@ -53,7 +54,7 @@
345.12 * @param clazz the class to inspect
345.13 * @return the set of created tests
345.14 */
345.15 - public static Object[] create(String[] brwsr, Class[] classes) {
345.16 + public static Object[] create(String[] brwsr, Class[] classes, Class<? extends Annotation> brwsrTest) {
345.17 List<Object> ret = new ArrayList<>();
345.18
345.19 final LaunchSetup l = LaunchSetup.INSTANCE;
345.20 @@ -70,7 +71,7 @@
345.21 Method[] arr = clazz.getMethods();
345.22 for (Method m : arr) {
345.23 registerCompareCases(m, l, ret, brwsr);
345.24 - registerBrwsrCases(m, l, ret, brwsr);
345.25 + registerBrwsrCases(brwsrTest, m, l, ret, brwsr);
345.26 }
345.27 }
345.28 return ret.toArray();
345.29 @@ -149,8 +150,8 @@
345.30 ret.add(new CompareCase(m, real, cse));
345.31 }
345.32 }
345.33 - private static void registerBrwsrCases(Method m, final LaunchSetup l, List<Object> ret, String[] brwsr) {
345.34 - BrwsrTest c = m.getAnnotation(BrwsrTest.class);
345.35 + private static void registerBrwsrCases(Class<? extends Annotation> brwsrTest, Method m, final LaunchSetup l, List<Object> ret, String[] brwsr) {
345.36 + Object c = m.getAnnotation(brwsrTest);
345.37 if (c == null) {
345.38 return;
345.39 }