diff --git a/gwt/.classpath b/gwt/.classpath new file mode 100644 index 0000000..1d11b4c --- /dev/null +++ b/gwt/.classpath @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/gwt/.gitignore b/gwt/.gitignore new file mode 100644 index 0000000..d06b883 --- /dev/null +++ b/gwt/.gitignore @@ -0,0 +1,8 @@ +.gwt +gwt-unitCache +war/WEB-INF +war/mailiverse_gwt +war/*.html +war/*.js +war/*.css +war/rev/ diff --git a/gwt/.project b/gwt/.project new file mode 100644 index 0000000..32a42a8 --- /dev/null +++ b/gwt/.project @@ -0,0 +1,34 @@ + + + Mailiverse-GWT + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.google.gdt.eclipse.core.webAppProjectValidator + + + + + com.google.gwt.eclipse.core.gwtProjectValidator + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.wst.common.project.facet.core.nature + com.google.gwt.eclipse.core.gwtNature + + diff --git a/gwt/.settings/com.google.appengine.eclipse.core.prefs b/gwt/.settings/com.google.appengine.eclipse.core.prefs new file mode 100644 index 0000000..5260f5f --- /dev/null +++ b/gwt/.settings/com.google.appengine.eclipse.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +filesCopiedToWebInfLib= +googleCloudSqlEnabled=false +localDevMySqlEnabled=true diff --git a/gwt/.settings/com.google.gdt.eclipse.core.prefs b/gwt/.settings/com.google.gdt.eclipse.core.prefs new file mode 100644 index 0000000..7d1e0c7 --- /dev/null +++ b/gwt/.settings/com.google.gdt.eclipse.core.prefs @@ -0,0 +1,5 @@ +eclipse.preferences.version=1 +jarsExcludedFromWebInfLib= +launchConfigExternalUrlPrefix= +warSrcDir=war +warSrcDirIsOutput=true diff --git a/gwt/.settings/com.google.gwt.eclipse.core.prefs b/gwt/.settings/com.google.gwt.eclipse.core.prefs new file mode 100644 index 0000000..fb8b63a --- /dev/null +++ b/gwt/.settings/com.google.gwt.eclipse.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +entryPointModules= +filesCopiedToWebInfLib=gwt-servlet.jar +gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBW11dPjwvZXh0cmEtYXJncz48dm0tYXJncz48IVtDREFUQVstWG14NTEybSAtRGd3dC51c2VhcmNoaXZlcz1mYWxzZV1dPjwvdm0tYXJncz48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5tYWlsaXZlcnNlLmd3dC5NYWlsaXZlcnNlX0dXVDwvZW50cnktcG9pbnQtbW9kdWxlPjwvZ3d0LWNvbXBpbGUtc2V0dGluZ3M+ diff --git a/gwt/.settings/org.eclipse.jdt.core.prefs b/gwt/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..7341ab1 --- /dev/null +++ b/gwt/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/gwt/.settings/org.eclipse.wst.common.project.facet.core.xml b/gwt/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..bc0009a --- /dev/null +++ b/gwt/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,4 @@ + + + + diff --git a/gwt/Notes.txt b/gwt/Notes.txt new file mode 100644 index 0000000..741055f --- /dev/null +++ b/gwt/Notes.txt @@ -0,0 +1,4 @@ +Todo: + +Make random come from javascript secure random. +Make login pages not be black. \ No newline at end of file diff --git a/gwt/clean b/gwt/clean new file mode 100755 index 0000000..90c80b4 --- /dev/null +++ b/gwt/clean @@ -0,0 +1,5 @@ +rm -rf gwt-unitCache +rm -rf war/WEB-INF/classes/ +rm -rf war/WEB-INF/deploy/ + +rm war/mailiverse_gwt/*.cache.html diff --git a/gwt/jre-gwt/JRE.gwt.xml b/gwt/jre-gwt/JRE.gwt.xml new file mode 100644 index 0000000..726dfa0 --- /dev/null +++ b/gwt/jre-gwt/JRE.gwt.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/gwt/jre-gwt/jre b/gwt/jre-gwt/jre new file mode 120000 index 0000000..2665712 --- /dev/null +++ b/gwt/jre-gwt/jre @@ -0,0 +1 @@ +../jre \ No newline at end of file diff --git a/gwt/jre/java/io/BufferedInputStream.java b/gwt/jre/java/io/BufferedInputStream.java new file mode 100644 index 0000000..47f588f --- /dev/null +++ b/gwt/jre/java/io/BufferedInputStream.java @@ -0,0 +1,375 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * BufferedInputStream is a class which takes an input stream and + * buffers the input. In this way, costly interaction with the + * original input stream can be minimized by reading buffered amounts of data + * infrequently. The drawback is that extra space is required to hold the buffer + * and that copying takes place when reading that buffer. + * + * @see BufferedOutputStream + */ +public class BufferedInputStream extends FilterInputStream { + /** + * The buffer containing the current bytes read from the target InputStream. + */ + protected byte[] buf; + + /** + * The total number of bytes inside the byte array buf. + */ + protected int count; + + /** + * The current limit, which when passed, invalidates the current mark. + */ + protected int marklimit; + + /** + * The currently marked position. -1 indicates no mark has been set or the + * mark has been invalidated. + */ + protected int markpos = -1; + + /** + * The current position within the byte array buf. + */ + protected int pos; + + private boolean closed = false; + + /** + * Constructs a new BufferedInputStream on the InputStream + * in. The default buffer size (8Kb) is allocated and all + * reads can now be filtered through this stream. + * + * @param in + * the InputStream to buffer reads on. + */ + public BufferedInputStream(InputStream in) { + super(in); + buf = new byte[8192]; + } + + /** + * Constructs a new BufferedInputStream on the InputStream in. + * The buffer size is specified by the parameter size and all + * reads can now be filtered through this BufferedInputStream. + * + * @param in + * the InputStream to buffer reads on. + * @param size + * the size of buffer to allocate. + */ + public BufferedInputStream(InputStream in, int size) { + super(in); + if (size <= 0) { + // K0058=size must be > 0 + throw new IllegalArgumentException(Msg.getString("K0058")); //$NON-NLS-1$ + } + buf = new byte[size]; + } + + /** + * Answers an int representing the number of bytes that are available before + * this BufferedInputStream will block. This method returns the number of + * bytes available in the buffer plus those available in the target stream. + * + * @return the number of bytes available before blocking. + * + * @throws IOException + * If an error occurs in this stream. + */ + @Override + public synchronized int available() throws IOException { + if (buf == null) { + // K0059=Stream is closed + throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$ + } + return count - pos + in.available(); + } + + /** + * Close this BufferedInputStream. This implementation closes the target + * stream and releases any resources associated with it. + * + * @throws IOException + * If an error occurs attempting to close this stream. + */ + @Override + public synchronized void close() throws IOException { + if (null != in) { + super.close(); + in = null; + } + buf = null; + closed = true; + } + + private int fillbuf() throws IOException { + if (markpos == -1 || (pos - markpos >= marklimit)) { + /* Mark position not set or exceeded readlimit */ + int result = in.read(buf); + if (result > 0) { + markpos = -1; + pos = 0; + count = result == -1 ? 0 : result; + } + return result; + } + if (markpos == 0 && marklimit > buf.length) { + /* Increase buffer size to accomodate the readlimit */ + int newLength = buf.length * 2; + if (newLength > marklimit) { + newLength = marklimit; + } + byte[] newbuf = new byte[newLength]; + System.arraycopy(buf, 0, newbuf, 0, buf.length); + buf = newbuf; + } else if (markpos > 0) { + System.arraycopy(buf, markpos, buf, 0, buf.length - markpos); + } + /* Set the new position and mark position */ + pos -= markpos; + count = markpos = 0; + int bytesread = in.read(buf, pos, buf.length - pos); + count = bytesread <= 0 ? pos : pos + bytesread; + return bytesread; + } + + /** + * Set a Mark position in this BufferedInputStream. The parameter + * readLimit indicates how many bytes can be read before a + * mark is invalidated. Sending reset() will reposition the Stream back to + * the marked position provided readLimit has not been + * surpassed. The underlying buffer may be increased in size to allow + * readlimit number of bytes to be supported. + * + * @param readlimit + * the number of bytes to be able to read before invalidating the + * mark. + */ + @Override + public synchronized void mark(int readlimit) { + marklimit = readlimit; + markpos = pos; + } + + /** + * Answers a boolean indicating whether or not this BufferedInputStream + * supports mark() and reset(). This implementation answers + * true. + * + * @return true for BufferedInputStreams. + */ + @Override + public boolean markSupported() { + return true; + } + + /** + * Reads a single byte from this BufferedInputStream and returns the result + * as an int. The low-order byte is returned or -1 of the end of stream was + * encountered. If the underlying buffer does not contain any available + * bytes then it is filled and the first byte is returned. + * + * @return the byte read or -1 if end of stream. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + @Override + public synchronized int read() throws IOException { + if (in == null) { + // K0059=Stream is closed + throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$ + } + + /* Are there buffered bytes available? */ + if (pos >= count && fillbuf() == -1) { + return -1; /* no, fill buffer */ + } + + /* Did filling the buffer fail with -1 (EOF)? */ + if (count - pos > 0) { + return buf[pos++] & 0xFF; + } + return -1; + } + + /** + * Reads at most length bytes from this BufferedInputStream + * and stores them in byte array buffer starting at offset + * offset. Answer the number of bytes actually read or -1 if + * no bytes were read and end of stream was encountered. If all the buffered + * bytes have been used, a mark has not been set, and the requested number + * of bytes is larger than the receiver's buffer size, this implementation + * bypasses the buffer and simply places the results directly into + * buffer. + * + * @param buffer + * the byte array in which to store the read bytes. + * @param offset + * the offset in buffer to store the read bytes. + * @param length + * the maximum number of bytes to store in buffer. + * @return the number of bytes actually read or -1 if end of stream. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + @Override + public synchronized int read(byte[] buffer, int offset, int length) + throws IOException { + if (closed) { + // K0059=Stream is closed + throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$ + } + // avoid int overflow + if (offset > buffer.length - length || offset < 0 || length < 0) { + throw new IndexOutOfBoundsException(); + } + if (length == 0) { + return 0; + } + if (null == buf) { + throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$ + } + + int required; + if (pos < count) { + /* There are bytes available in the buffer. */ + int copylength = count - pos >= length ? length : count - pos; + System.arraycopy(buf, pos, buffer, offset, copylength); + pos += copylength; + if (copylength == length || in.available() == 0) { + return copylength; + } + offset += copylength; + required = length - copylength; + } else { + required = length; + } + + while (true) { + int read; + /* + * If we're not marked and the required size is greater than the + * buffer, simply read the bytes directly bypassing the buffer. + */ + if (markpos == -1 && required >= buf.length) { + read = in.read(buffer, offset, required); + if (read == -1) { + return required == length ? -1 : length - required; + } + } else { + if (fillbuf() == -1) { + return required == length ? -1 : length - required; + } + read = count - pos >= required ? required : count - pos; + System.arraycopy(buf, pos, buffer, offset, read); + pos += read; + } + required -= read; + if (required == 0) { + return length; + } + if (in.available() == 0) { + return length - required; + } + offset += read; + } + } + + /** + * Reset this BufferedInputStream to the last marked location. If the + * readlimit has been passed or no mark has + * been set, throw IOException. This implementation resets the target + * stream. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + + @Override + public synchronized void reset() throws IOException { + if (closed) { + // K0059=Stream is closed + throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$ + } + if (-1 == markpos) { + // K005a=Mark has been invalidated. + throw new IOException(Msg.getString("K005a")); //$NON-NLS-1$ + } + pos = markpos; + } + + /** + * Skips amount number of bytes in this BufferedInputStream. + * Subsequent read()'s will not return these bytes unless + * reset() is used. + * + * @param amount + * the number of bytes to skip. + * @return the number of bytes actually skipped. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + @Override + public synchronized long skip(long amount) throws IOException { + if (null == in) { + // K0059=Stream is closed + throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$ + } + if (amount < 1) { + return 0; + } + + if (count - pos >= amount) { + pos += amount; + return amount; + } + long read = count - pos; + pos = count; + + if (markpos != -1) { + if (amount <= marklimit) { + if (fillbuf() == -1) { + return read; + } + if (count - pos >= amount - read) { + pos += amount - read; + return amount; + } + // Couldn't get all the bytes, skip what we read + read += (count - pos); + pos = count; + return read; + } + markpos = -1; + } + return read + in.skip(amount - read); + } +} \ No newline at end of file diff --git a/gwt/jre/java/io/BufferedReader.java b/gwt/jre/java/io/BufferedReader.java new file mode 100644 index 0000000..7fb1152 --- /dev/null +++ b/gwt/jre/java/io/BufferedReader.java @@ -0,0 +1,485 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * BufferedReader is a buffered character input reader. Buffering allows reading + * from character streams more efficiently. If the default size of the buffer is + * not practical, another size may be specified. Reading a character from a + * Reader class usually involves reading a character from its Stream or + * subsequent Reader. It is advisable to wrap a BufferedReader around those + * Readers whose read operations may have high latency. For example, the + * following code + * + *
+ * BufferedReader inReader = new BufferedReader(new FileReader("file.java"));
+ * 
+ * + * will buffer input for the file file.java. + * + * @see BufferedWriter + * @since 1.1 + */ +public class BufferedReader extends Reader { + + private Reader in; + + private char[] buf; + + private int marklimit = -1; + + private int count; + + private int markpos = -1; + + private int pos; + + /** + * Constructs a new BufferedReader on the Reader in. The + * default buffer size (8K) is allocated and all reads can now be filtered + * through this BufferedReader. + * + * @param in + * the Reader to buffer reads on. + */ + public BufferedReader(Reader in) { + super(in); + this.in = in; + buf = new char[8192]; + } + + /** + * Constructs a new BufferedReader on the Reader in. The + * buffer size is specified by the parameter size and all + * reads can now be filtered through this BufferedReader. + * + * @param in + * the Reader to buffer reads on. + * @param size + * the size of buffer to allocate. + * @throws IllegalArgumentException + * if the size is <= 0 + */ + public BufferedReader(Reader in, int size) { + super(in); + if (size <= 0) { + throw new IllegalArgumentException(Msg.getString("K0058")); //$NON-NLS-1$ + } + this.in = in; + buf = new char[size]; + } + + /** + * Close the Reader. This implementation closes the Reader being filtered + * and releases the buffer used by this reader. If this BufferedReader has + * already been closed, nothing is done. + * + * @throws IOException + * If an error occurs attempting to close this BufferedReader. + */ + @Override + public void close() throws IOException { + synchronized (lock) { + if (!isClosed()) { + in.close(); + buf = null; + } + } + } + + private int fillbuf() throws IOException { + if (markpos == -1 || (pos - markpos >= marklimit)) { + /* Mark position not set or exceeded readlimit */ + int result = in.read(buf, 0, buf.length); + if (result > 0) { + markpos = -1; + pos = 0; + count = result == -1 ? 0 : result; + } + return result; + } + if (markpos == 0 && marklimit > buf.length) { + /* Increase buffer size to accommodate the readlimit */ + int newLength = buf.length * 2; + if (newLength > marklimit) { + newLength = marklimit; + } + char[] newbuf = new char[newLength]; + System.arraycopy(buf, 0, newbuf, 0, buf.length); + buf = newbuf; + } else if (markpos > 0) { + System.arraycopy(buf, markpos, buf, 0, buf.length - markpos); + } + + /* Set the new position and mark position */ + pos -= markpos; + count = markpos = 0; + int charsread = in.read(buf, pos, buf.length - pos); + count = charsread == -1 ? pos : pos + charsread; + return charsread; + } + + /** + * Answer a boolean indicating whether or not this BufferedReader is closed. + * + * @return true if this reader is closed, false + * otherwise + */ + private boolean isClosed() { + return buf == null; + } + + /** + * Set a Mark position in this BufferedReader. The parameter + * readLimit indicates how many characters can be read before + * a mark is invalidated. Sending reset() will reposition the reader back to + * the marked position provided readLimit has not been + * surpassed. + * + * @param readlimit + * an int representing how many characters must be read before + * invalidating the mark. + * + * @throws IOException + * If an error occurs attempting mark this BufferedReader. + * @throws IllegalArgumentException + * If readlimit is < 0 + */ + @Override + public void mark(int readlimit) throws IOException { + if (readlimit < 0) { + throw new IllegalArgumentException(); + } + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$ + } + marklimit = readlimit; + markpos = pos; + } + } + + /** + * Answers a boolean indicating whether or not this Reader supports mark() + * and reset(). This implementation answers true. + * + * @return true if mark() and reset() are supported, + * false otherwise + */ + @Override + public boolean markSupported() { + return true; + } + + /** + * Reads a single character from this reader and returns the result as an + * int. The 2 higher-order characters are set to 0. If the end of reader was + * encountered then return -1. This implementation either returns a + * character from the buffer or if there are no characters available, fill + * the buffer then return a character or -1. + * + * @return the character read or -1 if end of reader. + * + * @throws IOException + * If the BufferedReader is already closed or some other IO + * error occurs. + */ + @Override + public int read() throws IOException { + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$ + } + /* Are there buffered characters available? */ + if (pos < count || fillbuf() != -1) { + return buf[pos++]; + } + return -1; + } + } + + /** + * Reads at most length characters from this BufferedReader + * and stores them at offset in the character array + * buffer. Returns the number of characters actually read or + * -1 if the end of reader was encountered. If all the buffered characters + * have been used, a mark has not been set, and the requested number of + * characters is larger than this Readers buffer size, this implementation + * bypasses the buffer and simply places the results directly into + * buffer. + * + * @param buffer + * character array to store the read characters + * @param offset + * offset in buf to store the read characters + * @param length + * maximum number of characters to read + * @return number of characters read or -1 if end of reader. + * + * @throws IOException + * If the BufferedReader is already closed or some other IO + * error occurs. + */ + @Override + public int read(char[] buffer, int offset, int length) throws IOException { + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$ + } + if (offset < 0 || offset > buffer.length - length || length < 0) { + throw new IndexOutOfBoundsException(); + } + if (length == 0) { + return 0; + } + int required; + if (pos < count) { + /* There are bytes available in the buffer. */ + int copylength = count - pos >= length ? length : count - pos; + System.arraycopy(buf, pos, buffer, offset, copylength); + pos += copylength; + if (copylength == length || !in.ready()) { + return copylength; + } + offset += copylength; + required = length - copylength; + } else { + required = length; + } + + while (true) { + int read; + /* + * If we're not marked and the required size is greater than the + * buffer, simply read the bytes directly bypassing the buffer. + */ + if (markpos == -1 && required >= buf.length) { + read = in.read(buffer, offset, required); + if (read == -1) { + return required == length ? -1 : length - required; + } + } else { + if (fillbuf() == -1) { + return required == length ? -1 : length - required; + } + read = count - pos >= required ? required : count - pos; + System.arraycopy(buf, pos, buffer, offset, read); + pos += read; + } + required -= read; + if (required == 0) { + return length; + } + if (!in.ready()) { + return length - required; + } + offset += read; + } + } + } + + /** + * Answers a String representing the next line of text + * available in this BufferedReader. A line is represented by 0 or more + * characters followed by '\n', '\r', + * '\r\n' or end of stream. The String does + * not include the newline sequence. + * + * @return the contents of the line or null if no characters were read + * before end of stream. + * + * @throws IOException + * If the BufferedReader is already closed or some other IO + * error occurs. + */ + public String readLine() throws IOException { + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$ + } + /* Are there buffered characters available? */ + if ((pos >= count) && (fillbuf() == -1)) { + return null; + } + for (int charPos = pos; charPos < count; charPos++) { + char ch = buf[charPos]; + if (ch > '\r') { + continue; + } + if (ch == '\n') { + String res = new String(buf, pos, charPos - pos); + pos = charPos + 1; + return res; + } else if (ch == '\r') { + String res = new String(buf, pos, charPos - pos); + pos = charPos + 1; + if (((pos < count) || (fillbuf() != -1)) + && (buf[pos] == '\n')) { + pos++; + } + return res; + } + } + + char eol = '\0'; + StringBuilder result = new StringBuilder(80); + /* Typical Line Length */ + + result.append(buf, pos, count - pos); + pos = count; + while (true) { + /* Are there buffered characters available? */ + if (pos >= count) { + if (eol == '\n') { + return result.toString(); + } + // attempt to fill buffer + if (fillbuf() == -1) { + // characters or null. + return result.length() > 0 || eol != '\0' ? result + .toString() : null; + } + } + for (int charPos = pos; charPos < count; charPos++) { + if (eol == '\0') { + if ((buf[charPos] == '\n' || buf[charPos] == '\r')) { + eol = buf[charPos]; + } + } else if (eol == '\r' && (buf[charPos] == '\n')) { + if (charPos > pos) { + result.append(buf, pos, charPos - pos - 1); + } + pos = charPos + 1; + return result.toString(); + } else if (eol != '\0') { + if (charPos > pos) { + result.append(buf, pos, charPos - pos - 1); + } + pos = charPos; + return result.toString(); + } + } + if (eol == '\0') { + result.append(buf, pos, count - pos); + } else { + result.append(buf, pos, count - pos - 1); + } + pos = count; + } + } + + } + + /** + * Answers a boolean indicating whether or not this Reader is + * ready to be read without blocking. If the result is true, + * the next read() will not block. If the result is + * false this Reader may or may not block when + * read() is sent. + * + * @return true if the receiver will not block when + * read() is called, false if unknown + * or blocking will occur. + * + * @throws IOException + * If the BufferedReader is already closed or some other IO + * error occurs. + */ + @Override + public boolean ready() throws IOException { + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$ + } + return ((count - pos) > 0) || in.ready(); + } + } + + /** + * Reset this BufferedReader's position to the last mark() + * location. Invocations of read()/skip() will occur from + * this new location. If this Reader was not marked, throw IOException. + * + * @throws IOException + * If a problem occurred, the receiver does not support + * mark()/reset(), or no mark has been set. + */ + @Override + public void reset() throws IOException { + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$ + } + if (markpos == -1) { + throw new IOException(Msg.getString("K005c")); //$NON-NLS-1$ + } + pos = markpos; + } + } + + /** + * Skips amount number of characters in this Reader. + * Subsequent read()'s will not return these characters + * unless reset() is used. Skipping characters may invalidate + * a mark if marklimit is surpassed. + * + * @param amount + * the maximum number of characters to skip. + * @return the number of characters actually skipped. + * + * @throws IOException + * If the BufferedReader is already closed or some other IO + * error occurs. + * @throws IllegalArgumentException + * If amount is negative + */ + @Override + public long skip(long amount) throws IOException { + if (amount < 0) { + throw new IllegalArgumentException(); + } + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K005b")); //$NON-NLS-1$ + } + if (amount < 1) { + return 0; + } + if (count - pos >= amount) { + pos += amount; + return amount; + } + + long read = count - pos; + pos = count; + while (read < amount) { + if (fillbuf() == -1) { + return read; + } + if (count - pos >= amount - read) { + pos += amount - read; + return amount; + } + // Couldn't get all the characters, skip what we read + read += (count - pos); + pos = count; + } + return amount; + } + } +} \ No newline at end of file diff --git a/gwt/jre/java/io/ByteArrayInputStream.java b/gwt/jre/java/io/ByteArrayInputStream.java new file mode 100644 index 0000000..2b749b4 --- /dev/null +++ b/gwt/jre/java/io/ByteArrayInputStream.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package java.io; + +public class ByteArrayInputStream extends InputStream { + + protected byte[] buf; + protected int pos = 0; + protected int start = 0; + protected int mark = 0; + protected int count; + + public ByteArrayInputStream(byte[] data) { + this.buf = data; + this.count = data.length; + } + + public ByteArrayInputStream(byte[] data, int offset, int len) { + this.buf = data; + count = offset + len; + this.mark = this.start = this.pos = offset; + } + + @Override + public int read() { + return pos < count ? (buf[pos++] & 0xFF) : -1; + } + + @Override + public int available() { + return count - pos; + } + + @Override + public long skip(long n) throws IOException, IllegalArgumentException { + // TODO Auto-generated method stub + pos += n; + return pos; + } + + @Override + public void reset() throws IOException { + pos = mark; + } + + @Override + public void mark(int readAheadLimit) { + mark = pos; + } + + @Override + public boolean markSupported() { + return true; + } + +} diff --git a/gwt/jre/java/io/ByteArrayOutputStream.java b/gwt/jre/java/io/ByteArrayOutputStream.java new file mode 100644 index 0000000..9a668a4 --- /dev/null +++ b/gwt/jre/java/io/ByteArrayOutputStream.java @@ -0,0 +1,67 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package java.io; + +import core.util.Arrays; + +public class ByteArrayOutputStream extends OutputStream { + + protected int count = 0; + protected byte[] buf; + + public ByteArrayOutputStream() { + this(16); + } + + public ByteArrayOutputStream(int initialSize) { + buf = new byte[initialSize]; + } + + public void write(int b) { + if (buf.length == count) { + byte[] newBuf = new byte[buf.length * 3 / 2]; + Arrays.copyFromTo(buf, 0, newBuf, 0, count); + buf = newBuf; + } + + buf[count++] = (byte)b; + } + + public void write(byte[] ba, int start, int len) { + int end = start + len; + for (int i = start; i < end; i++) { + write(ba[i]); + } + } + + public void write(byte[] ba) + { + write(ba,0, ba.length); + } + + public byte[] toByteArray() { + return Arrays.copyOf(buf,count); + } + + + public int size() { + return count; + } + + public void reset () { + count = 0; + } +} diff --git a/gwt/jre/java/io/DataInputStream.java b/gwt/jre/java/io/DataInputStream.java new file mode 100644 index 0000000..5f1acb7 --- /dev/null +++ b/gwt/jre/java/io/DataInputStream.java @@ -0,0 +1,79 @@ +package java.io; + +public class DataInputStream extends FilterInputStream +{ + public DataInputStream(InputStream in) + { + super(in); + } + + + /** + * Reads bytes from the source stream into the byte array + * buffer. The number of bytes actually read is returned. + * + * @param buffer + * the buffer to read bytes into + * @return the number of bytes actually read or -1 if end of stream. + * + * @throws IOException + * If a problem occurs reading from this DataInputStream. + * + * @see DataOutput#write(byte[]) + * @see DataOutput#write(byte[], int, int) + */ + @Override + public final int read(byte[] buffer) throws IOException { + return in.read(buffer, 0, buffer.length); + } + + /** + * Reads a 32-bit integer value from this stream. + * + * @return the next int value from the source stream. + * + * @throws IOException + * If a problem occurs reading from this DataInputStream. + * + * @see DataOutput#writeInt(int) + */ + public final int readInt() throws IOException { + int b1 = in.read(); + int b2 = in.read(); + int b3 = in.read(); + int b4 = in.read(); + + if ((b1 | b2 | b3 | b4) < 0) { + throw new EOFException(); + } + + return ((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); + } + + /** + * Read at most length bytes from this DataInputStream and + * stores them in byte array buffer starting at + * offset. Answer the number of bytes actually read or -1 if + * no bytes were read and end of stream was encountered. + * + * @param buffer + * the byte array in which to store the read bytes. + * @param offset + * the offset in buffer to store the read bytes. + * @param length + * the maximum number of bytes to store in buffer. + * @return the number of bytes actually read or -1 if end of stream. + * + * @throws IOException + * If a problem occurs reading from this DataInputStream. + * + * @see DataOutput#write(byte[]) + * @see DataOutput#write(byte[], int, int) + */ + @Override + public final int read(byte[] buffer, int offset, int length) + throws IOException { + return in.read(buffer, offset, length); + } + +} diff --git a/gwt/jre/java/io/DataOutputStream.java b/gwt/jre/java/io/DataOutputStream.java new file mode 100644 index 0000000..97c54e3 --- /dev/null +++ b/gwt/jre/java/io/DataOutputStream.java @@ -0,0 +1,49 @@ +package java.io; + +public class DataOutputStream extends FilterOutputStream { + + protected int written; + + public DataOutputStream(OutputStream out) { + super(out); + } + + public void close() throws IOException + { + super.close(); + } + + public void write(byte buffer[], int offset, int count) throws IOException { + if (buffer == null) { + throw new NullPointerException(); //$NON-NLS-1$ + } + out.write(buffer, offset, count); + written += count; + } + + public void write(byte buffer[]) throws IOException + { + write(buffer, 0, buffer.length); + } + + /** + * Writes a 32-bit int to this output stream. The resulting output is the 4 + * bytes, highest order first, of val. + * + * @param val + * the int to be written. + * + * @throws IOException + * If an error occurs attempting to write to this + * DataOutputStream. + * + * @see DataInput#readInt() + */ + public final void writeInt(int val) throws IOException { + out.write((byte)(val >> 24)); + out.write((byte)(val >> 16)); + out.write((byte)(val >> 8)); + out.write((byte)(val)); + written += 4; + } +} diff --git a/gwt/jre/java/io/EOFException.java b/gwt/jre/java/io/EOFException.java new file mode 100644 index 0000000..ccd3004 --- /dev/null +++ b/gwt/jre/java/io/EOFException.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * This End Of File (EOF) exception is thrown when a program encounters the end + * of a file or stream during an operation. + */ +public class EOFException extends IOException { + + private static final long serialVersionUID = 6433858223774886977L; + + /** + * Constructs a new instance of this class with its walkback filled in. + * + */ + public EOFException() { + super(); + } + + /** + * Constructs a new instance of this class with its walkback and message + * filled in. + * + * @param detailMessage + * The detail message for the exception. + */ + public EOFException(String detailMessage) { + super(detailMessage); + } +} \ No newline at end of file diff --git a/gwt/jre/java/io/FilterInputStream.java b/gwt/jre/java/io/FilterInputStream.java new file mode 100644 index 0000000..30dfd25 --- /dev/null +++ b/gwt/jre/java/io/FilterInputStream.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * FilteredInputStream is a class which takes an input stream and + * filters the input in some way. The filtered view may be a buffered + * view or one which uncompresses data before returning bytes read. + * FilterInputStreams are meant for byte streams. + * + * @see FilterOutputStream + */ +public class FilterInputStream extends InputStream { + + /** + * The target InputStream which is being filtered. + */ + protected InputStream in; + + /** + * Constructs a new FilterInputStream on the InputStream in. + * All reads are now filtered through this stream. + * + * @param in + * The non-null InputStream to filter reads on. + */ + protected FilterInputStream(InputStream in) { + super(); + this.in = in; + } + + /** + * Answers a int representing the number of bytes that are available before + * this FilterInputStream will block. This method returns the number of + * bytes available in the target stream. + * + * @return the number of bytes available before blocking. + * + * @throws IOException + * If an error occurs in this stream. + */ + @Override + public int available() throws IOException { + return in.available(); + } + + /** + * Close this FilterInputStream. This implementation closes the target + * stream. + * + * @throws IOException + * If an error occurs attempting to close this stream. + */ + @Override + public void close() throws IOException { + in.close(); + } + + /** + * Set a Mark position in this FilterInputStream. The parameter + * readLimit indicates how many bytes can be read before a + * mark is invalidated. Sending reset() will reposition the Stream back to + * the marked position provided readLimit has not been + * surpassed. + *

+ * This implementation sets a mark in the target stream. + * + * @param readlimit + * the number of bytes to be able to read before invalidating the + * mark. + */ + @Override + public synchronized void mark(int readlimit) { + in.mark(readlimit); + } + + /** + * Answers a boolean indicating whether or not this FilterInputStream + * supports mark() and reset(). This implementation answers whether or not + * the target stream supports marking. + * + * @return true if mark() and reset() are supported, + * false otherwise. + */ + @Override + public boolean markSupported() { + return in.markSupported(); + } + + /** + * Reads a single byte from this FilterInputStream and returns the result as + * an int. The low-order byte is returned or -1 of the end of stream was + * encountered. This implementation returns a byte from the target stream. + * + * @return the byte read or -1 if end of stream. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + @Override + public int read() throws IOException { + return in.read(); + } + + /** + * Reads bytes from this FilterInputStream and stores them in byte array + * buffer. Answer the number of bytes actually read or -1 if + * no bytes were read and end of stream was encountered. This implementation + * reads bytes from the target stream. + * + * @param buffer + * the byte array in which to store the read bytes. + * @return the number of bytes actually read or -1 if end of stream. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + @Override + public int read(byte[] buffer) throws IOException { + return read(buffer, 0, buffer.length); + } + + /** + * Reads at most count bytes from this FilterInputStream and + * stores them in byte array buffer starting at + * offset. Answer the number of bytes actually read or -1 if + * no bytes were read and end of stream was encountered. This implementation + * reads bytes from the target stream. + * + * @param buffer + * the byte array in which to store the read bytes. + * @param offset + * the offset in buffer to store the read bytes. + * @param count + * the maximum number of bytes to store in buffer. + * @return the number of bytes actually read or -1 if end of stream. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + @Override + public int read(byte[] buffer, int offset, int count) throws IOException { + return in.read(buffer, offset, count); + } + + /** + * Reset this FilterInputStream to the last marked location. If the + * readlimit has been passed or no mark has + * been set, throw IOException. This implementation resets the target + * stream. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + @Override + public synchronized void reset() throws IOException { + in.reset(); + } + + /** + * Skips count number of bytes in this InputStream. + * Subsequent read()'s will not return these bytes unless + * reset() is used. This implementation skips + * count number of bytes in the target stream. + * + * @param count + * the number of bytes to skip. + * @return the number of bytes actually skipped. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + @Override + public long skip(long count) throws IOException { + return in.skip(count); + } +} \ No newline at end of file diff --git a/gwt/jre/java/io/FilterOutputStream.java b/gwt/jre/java/io/FilterOutputStream.java new file mode 100644 index 0000000..4cf9a1d --- /dev/null +++ b/gwt/jre/java/io/FilterOutputStream.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * FilteredOutputStream is a class which takes an output stream and + * filters the output in some way. The filtered view may be a + * buffered output or one which compresses data before actually writing the + * bytes. FilterOutputStreams are meant for byte streams. + * + * @see FilterInputStream + */ +public class FilterOutputStream extends OutputStream { + + /** + * The target OutputStream for this filter. + */ + protected OutputStream out; + + /** + * Constructs a new FilterOutputStream on the OutputStream out. + * All writes are now filtered through this stream. + * + * @param out + * the target OutputStream to filter writes on. + */ + public FilterOutputStream(OutputStream out) { + this.out = out; + } + + /** + * Close this FilterOutputStream. This implementation closes the target + * stream. + * + * @throws IOException + * If an error occurs attempting to close this stream. + */ + @Override + public void close() throws IOException { + try { + flush(); + } catch (IOException e) { + // Ignored + } + /* Make sure we clean up this stream if exception fires */ + out.close(); + } + + /** + * Flush this FilterOutputStream to ensure all pending data is sent out to + * the target OutputStream. This implementation flushes the target + * OutputStream. + * + * @throws IOException + * If an error occurs attempting to flush this + * FilterOutputStream. + */ + @Override + public void flush() throws IOException { + out.flush(); + } + + /** + * Writes the entire contents of the byte array buffer to + * this FilterOutputStream. This implementation writes the + * buffer to the target stream. + * + * @param buffer + * the buffer to be written + * + * @throws IOException + * If an error occurs attempting to write to this + * FilterOutputStream. + */ + @Override + public void write(byte buffer[]) throws IOException { + write(buffer, 0, buffer.length); + } + + /** + * Writes count bytes from the byte array + * buffer starting at offset to this + * FilterOutputStream. This implementation writes the buffer + * to the target OutputStream. + * + * @param buffer + * the buffer to be written + * @param offset + * offset in buffer to get bytes + * @param count + * number of bytes in buffer to write + * + * @throws IOException + * If an error occurs attempting to write to this + * FilterOutputStream. + * @throws IndexOutOfBoundsException + * If offset or count are outside of bounds. + */ + @Override + public void write(byte buffer[], int offset, int count) throws IOException { + // avoid int overflow, force null buffer check first + if (offset > buffer.length || offset < 0 || count < 0 + || count > buffer.length - offset) { + throw new ArrayIndexOutOfBoundsException(); //$NON-NLS-1$ + } + for (int i = 0; i < count; i++) { + // Call write() instead of out.write() since subclasses could + // override the write() method. + write(buffer[offset + i]); + } + } + + /** + * Writes the specified byte oneByte to this + * FilterOutputStream. Only the low order byte of oneByte is + * written. This implementation writes the byte to the target OutputStream. + * + * @param oneByte + * the byte to be written + * + * @throws IOException + * If an error occurs attempting to write to this + * FilterOutputStream. + */ + @Override + public void write(int oneByte) throws IOException { + out.write(oneByte); + } +} \ No newline at end of file diff --git a/gwt/jre/java/io/IOException.java b/gwt/jre/java/io/IOException.java new file mode 100644 index 0000000..46a66ee --- /dev/null +++ b/gwt/jre/java/io/IOException.java @@ -0,0 +1,31 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package java.io; + +public class IOException extends Exception { + + public IOException() { + super(); + } + + public IOException(String s) { + super(s); + } + + public IOException(Exception e) { + super(e); + } +} diff --git a/gwt/jre/java/io/InputStream.java b/gwt/jre/java/io/InputStream.java new file mode 100644 index 0000000..446a013 --- /dev/null +++ b/gwt/jre/java/io/InputStream.java @@ -0,0 +1,57 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package java.io; + +public abstract class InputStream { + public abstract int read() throws IOException; + + public int read(byte[]buf, int start, int len) throws IOException { + + int end = start + len; + for (int i = start; i < end; i++) { + int r = read(); + if (r == -1) { + return i == start ? -1 : i - start; + } + buf[i] = (byte) r; + } + return len; + } + + public int read(byte[] buf) throws IOException { + return read(buf, 0, buf.length); + } + + public void close() throws IOException { + + } + + public int available() throws IOException + { + return 0; + } + + public void mark(int readAheadLimit){ + } + + public boolean markSupported() { + return false; + } + + public long skip(long n) throws IOException, IllegalArgumentException { return 0; } + + public void reset() throws IOException {} +} diff --git a/gwt/jre/java/io/InputStreamReader.java b/gwt/jre/java/io/InputStreamReader.java new file mode 100644 index 0000000..99f406c --- /dev/null +++ b/gwt/jre/java/io/InputStreamReader.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +import core.util.Streams; + +/** + * InputStreamReader is class for turning a byte Stream into a character Stream. + * Data read from the source input stream is converted into characters by either + * a default or provided character converter. By default, the encoding is + * assumed to ISO8859_1. The InputStreamReader contains a buffer of bytes read + * from the source input stream and converts these into characters as needed. + * The buffer size is 8K. + * + * @see OutputStreamWriter + */ +public class InputStreamReader extends StringReader { + + /** + * Constructs a new InputStreamReader on the InputStream in. + * Now character reading can be filtered through this InputStreamReader. + * This constructor assumes the default conversion of ISO8859_1 + * (ISO-Latin-1). + * + * @param in + * the InputStream to convert to characters. + * @throws IOException + */ + public InputStreamReader(InputStream in) throws IOException { + super(Streams.readFullyString(in, "UTF-8")); + } + + public InputStreamReader(InputStream in, String enc) throws IOException + { + super(Streams.readFullyString(in, enc)); + } + +} \ No newline at end of file diff --git a/gwt/jre/java/io/Msg.java b/gwt/jre/java/io/Msg.java new file mode 100644 index 0000000..b706d5c --- /dev/null +++ b/gwt/jre/java/io/Msg.java @@ -0,0 +1,15 @@ +package java.io; + +public class Msg { + + public static String getString(String string) { + // TODO Auto-generated method stub + return null; + } + + public static String getString(String string, int offset) { + // TODO Auto-generated method stub + return null; + } + +}; diff --git a/gwt/jre/java/io/OutputStream.java b/gwt/jre/java/io/OutputStream.java new file mode 100644 index 0000000..d8d3aa9 --- /dev/null +++ b/gwt/jre/java/io/OutputStream.java @@ -0,0 +1,41 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package java.io; + +public abstract class OutputStream { + + // not abstact because of some gwt strangeness + public abstract void write(int b) throws IOException; + + public void write(byte[] ba) throws IOException { + write(ba, 0, ba.length); + } + + public void write(byte[] ba, int start, int len) throws IOException { + int end = start + len; + for (int i = start; i < end; i++) { + write(ba[i]); + } + } + + public void close() throws IOException { + } + + public void flush() throws IOException { + } + +} diff --git a/gwt/jre/java/io/OutputStreamWriter.java b/gwt/jre/java/io/OutputStreamWriter.java new file mode 100644 index 0000000..bb02ae0 --- /dev/null +++ b/gwt/jre/java/io/OutputStreamWriter.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +import core.util.Strings; + +/** + * OutputStreamWriter is a class for turning a character output stream into a + * byte output stream. The conversion of Unicode characters to their byte + * equivalents is determined by the converter used. By default, the encoding is + * ISO8859_1 (ISO-Latin-1) but can be changed by calling the constructor which + * takes an encoding. + * + * @see InputStreamReader + */ + +public class OutputStreamWriter extends Writer { + + private OutputStream out; + String enc; + + /** + * Constructs a new OutputStreamWriter using out as the + * OutputStream to write converted characters to. The default character + * encoding is used (see class description). + * + * @param out + * the non-null OutputStream to write converted bytes to. + */ + public OutputStreamWriter(OutputStream out) { + super(out); + this.out = out; + } + + /** + * Constructs a new OutputStreamWriter using out as the + * OutputStream to write converted characters to and enc as + * the character encoding. If the encoding cannot be found, an + * UnsupportedEncodingException error is thrown. + * + * @param out + * the non-null OutputStream to write converted bytes to. + * @param enc + * the non-null String describing the desired character encoding. + * + * @throws UnsupportedEncodingException + * if the encoding cannot be found. + */ + public OutputStreamWriter(OutputStream out, final String enc) + throws UnsupportedEncodingException { + super(out); + if (enc == null) { + throw new NullPointerException(); + } + this.out = out; + this.enc = enc; + } + + /** + * Close this OutputStreamWriter. This implementation first flushes the + * buffer and the target OutputStream. The OutputStream is then closed and + * the resources for the buffer and converter are freed. + *

+ * Only the first invocation of this method has any effect. Subsequent calls + * do no work. + * + * @throws IOException + * If an error occurs attempting to close this + * OutputStreamWriter. + */ + @Override + public void close() throws IOException { + synchronized (lock) { + out.flush(); + out.close(); + } + } + + /** + * Flush this OutputStreamWriter. This implementation ensures all buffered + * bytes are written to the target OutputStream. After writing the bytes, + * the target OutputStream is then flushed. + * + * @throws IOException + * If an error occurs attempting to flush this + * OutputStreamWriter. + */ + @Override + public void flush() throws IOException { + synchronized (lock) { + out.flush(); + } + } + + private void checkStatus() throws IOException { + } + + /** + * Answer the String which identifies the encoding used to convert + * characters to bytes. The value null is returned if this + * Writer has been closed. + * + * @return the String describing the converter or null if this Writer is + * closed. + */ + + public String getEncoding() { + return enc; + } + + /** + * Writes count characters starting at offset + * in buf to this Writer. The characters are immediately + * converted to bytes by the character converter and stored in a local + * buffer. If the buffer becomes full as a result of this write, this Writer + * is flushed. + * + * @param buf + * the non-null array containing characters to write. + * @param offset + * offset in buf to retrieve characters + * @param count + * maximum number of characters to write + * + * @throws IOException + * If this OutputStreamWriter has already been closed or some + * other IOException occurs. + * @throws IndexOutOfBoundsException + * If offset or count is outside of bounds. + */ + @Override + public void write(char[] buf, int offset, int count) throws IOException { + char[] sb = new char[count]; + for (int i=0; ioneChar to this Writer. The + * low-order 2 bytes are immediately converted to bytes by the character + * converter and stored in a local buffer. If the buffer becomes full as a + * result of this write, this Writer is flushed. + * + * @param oneChar + * the character to write + * + * @throws IOException + * If this OutputStreamWriter has already been closed or some + * other IOException occurs. + */ + @Override + public void write(int oneChar) throws IOException { + char[] cs = new char[] { (char)oneChar }; + write(cs, 0, 1); + } + + /** + * Writes count characters starting at offset + * in str to this Writer. The characters are immediately + * converted to bytes by the character converter and stored in a local + * buffer. If the buffer becomes full as a result of this write, this Writer + * is flushed. + * + * @param str + * the non-null String containing characters to write. + * @param offset + * offset in str to retrieve characters + * @param count + * maximum number of characters to write + * + * @throws IOException + * If this OutputStreamWriter has already been closed or some + * other IOException occurs. + * @throws IndexOutOfBoundsException + * If count is negative + * @throws StringIndexOutOfBoundsException + * If offset is negative or offset + count is outside of bounds + */ + @Override + public void write(String str, int offset, int count) throws IOException { + synchronized (lock) { + char[] chars = new char[count]; + str.getChars(0, count, chars, 0); + + write(chars); + } + } +} \ No newline at end of file diff --git a/gwt/jre/java/io/PushbackInputStream.java b/gwt/jre/java/io/PushbackInputStream.java new file mode 100644 index 0000000..c4c2041 --- /dev/null +++ b/gwt/jre/java/io/PushbackInputStream.java @@ -0,0 +1,335 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * PushbackInputStream is a filter class which allows bytes read to be pushed + * back into the stream so that they can be reread. Parsers may find this + * useful. There is a progammable limit to the number of bytes which may be + * pushed back. If the buffer of pushed back bytes is empty, bytes are read from + * the source input stream. + */ +public class PushbackInputStream extends FilterInputStream { + /** + * The byte array containing the bytes to read. + */ + protected byte[] buf; + + /** + * The current position within the byte array buf. A value + * equal to buf.length indicates no bytes available. A value of 0 indicates + * the buffer is full. + */ + protected int pos; + + /** + * Constructs a new PushbackInputStream on the InputStream in. + * The size of the pushback buffer is set to the default, or 1 byte. + * + * @param in + * the InputStream to allow pushback operations on. + */ + public PushbackInputStream(InputStream in) { + super(in); + buf = (in == null) ? null : new byte[1]; + pos = 1; + } + + /** + * Constructs a new PushbackInputStream on the InputStream in. + * The size of the pushback buffer is set to size. + * + * @param in + * the InputStream to allow pushback operations on. + * @param size + * the size of the pushback buffer (size>=0). + */ + public PushbackInputStream(InputStream in, int size) { + super(in); + if (size <= 0) { + throw new IllegalArgumentException(Msg.getString("K0058")); //$NON-NLS-1$ + } + buf = (in == null) ? null : new byte[size]; + pos = size; + } + + /** + * Answers a int representing then number of bytes that are available before + * this PushbackInputStream will block. This method returns the number of + * bytes available in the pushback buffer plus those available in the target + * stream. + * + * @return int the number of bytes available before blocking. + * + * @throws java.io.IOException + * If an error occurs in this stream. + */ + @Override + public int available() throws IOException { + if (buf == null) { + throw new IOException(); + } + return buf.length - pos + in.available(); + } + + /** + * Close this PushbackInputStream. This implementation closes the target + * stream. + * + * @throws IOException + * If an error occurs attempting to close this stream. + */ + @Override + public void close() throws IOException { + if (in != null) { + in.close(); + in = null; + buf = null; + } + } + + /** + * Answers a boolean indicating whether or not this PushbackInputStream + * supports mark() and reset(). This implementation always answers false + * since PushbackInputStreams do not support mark/reset. + * + * @return boolean indicates whether or not mark() and reset() are + * supported. + */ + @Override + public boolean markSupported() { + return false; + } + + /** + * Reads a single byte from this PushbackInputStream and returns the result + * as an int. The low-order byte is returned or -1 of the end of stream was + * encountered. If the pushback buffer does not contain any available bytes + * then a byte from the target input stream is returned. + * + * @return int The byte read or -1 if end of stream. + * + * @throws IOException + * If an IOException occurs. + */ + @Override + public int read() throws IOException { + if (buf == null) { + throw new IOException(); + } + // Is there a pushback byte available? + if (pos < buf.length) { + return (buf[pos++] & 0xFF); + } + // Assume read() in the InputStream will return low-order byte or -1 + // if end of stream. + return in.read(); + } + + /** + * Reads at most length bytes from this PushbackInputStream + * and stores them in byte array buffer starting at + * offset. Answer the number of bytes actually read or -1 if + * no bytes were read and end of stream was encountered. This implementation + * reads bytes from the pushback buffer first, then the target stream if + * more bytes are required to satisfy count. + * + * @param buffer + * the byte array in which to store the read bytes. + * @param offset + * the offset in buffer to store the read bytes. + * @param length + * the maximum number of bytes to store in buffer. + * @return the number of bytes actually read or -1 if end of stream. + * + * @throws IOException + * If an IOException occurs. + */ + @Override + public int read(byte[] buffer, int offset, int length) throws IOException { + if (buf == null) { + throw new IOException(); + } + if (buffer == null) { + throw new NullPointerException(); + } + // avoid int overflow + if (offset < 0 || offset > buffer.length || length < 0 + || length > buffer.length - offset) { + throw new ArrayIndexOutOfBoundsException(); + } + + int copiedBytes = 0, copyLength = 0, newOffset = offset; + // Are there pushback bytes available? + if (pos < buf.length) { + copyLength = (buf.length - pos >= length) ? length : buf.length + - pos; + System.arraycopy(buf, pos, buffer, newOffset, copyLength); + newOffset += copyLength; + copiedBytes += copyLength; + // Use up the bytes in the local buffer + pos += copyLength; + } + // Have we copied enough? + if (copyLength == length) { + return length; + } + int inCopied = in.read(buffer, newOffset, length - copiedBytes); + if (inCopied > 0) { + return inCopied + copiedBytes; + } + if (copiedBytes == 0) { + return inCopied; + } + return copiedBytes; + } + + /** + * Skips count number of bytes in this PushbackInputStream. + * Subsequent read()'s will not return these bytes unless + * reset() is used. This implementation skips + * count number of bytes in the buffer and/or the target + * stream. + * + * @param count + * the number of bytes to skip. + * @return the number of bytes actually skipped. + * + * @throws IOException + * If the stream is already closed or another IOException + * occurs. + */ + @Override + public long skip(long count) throws IOException { + if (in == null) { + throw new IOException(Msg.getString("K0059")); //$NON-NLS-1$ + } + if (count <= 0) { + return 0; + } + int numSkipped = 0; + if (pos < buf.length) { + numSkipped += (count < buf.length - pos) ? count : buf.length - pos; + pos += numSkipped; + } + if (numSkipped < count) { + numSkipped += in.skip(count - numSkipped); + } + return numSkipped; + } + + /** + * Push back all the bytes in buffer. The bytes are pushed + * so that they would be read back buffer[0], buffer[1], etc. If the push + * back buffer cannot handle the entire contents of buffer, + * an IOException will be thrown. Some of the buffer may already be in the + * buffer after the exception is thrown. + * + * @param buffer + * the byte array containing bytes to push back into the stream. + * + * @throws IOException + * If the pushback buffer becomes, or is, full. + */ + public void unread(byte[] buffer) throws IOException { + unread(buffer, 0, buffer.length); + } + + /** + * Push back length number of bytes in buffer + * starting at offset. The bytes are pushed so that they + * would be read back buffer[offset], buffer[offset+1], etc. If the push + * back buffer cannot handle the bytes copied from buffer, + * an IOException will be thrown. Some of the bytes may already be in the + * buffer after the exception is thrown. + * + * @param buffer + * the byte array containing bytes to push back into the stream. + * @param offset + * the location to start taking bytes to push back. + * @param length + * the number of bytes to push back. + * + * @throws IOException + * If the pushback buffer becomes, or is, full. + */ + public void unread(byte[] buffer, int offset, int length) + throws IOException { + if (length > pos) { + // Pushback buffer full + throw new IOException(Msg.getString("K007e")); //$NON-NLS-1$ + } + // avoid int overflow + if (offset < 0 || offset > buffer.length || length < 0 + || length > buffer.length - offset) { + throw new ArrayIndexOutOfBoundsException(); + } + + for (int i = offset + length - 1; i >= offset; i--) { + unread(buffer[i]); + } + } + + /** + * Push back one byte. Takes the byte oneByte + * and puts in in the local buffer of bytes to read back before accessing + * the target input stream. + * + * @param oneByte + * the byte to push back into the stream. + * + * @throws IOException + * If the pushback buffer is already full. + */ + public void unread(int oneByte) throws IOException { + if (buf == null) { + throw new IOException(); + } + if (pos == 0) { + throw new IOException(Msg.getString("K007e")); //$NON-NLS-1$ + } + buf[--pos] = (byte) oneByte; + } + + /** + * Make a mark of the current position in the stream but the mark method + * does nothing. + * + * @param readlimit + * the maximum number of bytes that are able to be read before + * the mark becomes invalid + * @override the method mark in FilterInputStream + */ + @Override + public void mark(int readlimit) { + return; + } + + /** + * Reset current position to the mark made previously int the stream, but + * the reset method will throw IOException and do nothing else if called. + * + * @override the method reset in FilterInputStream + * @throws IOException + * If the method is called + */ + @Override + public void reset() throws IOException { + throw new IOException(); + } +} \ No newline at end of file diff --git a/gwt/jre/java/io/Reader.java b/gwt/jre/java/io/Reader.java new file mode 100644 index 0000000..bba92c0 --- /dev/null +++ b/gwt/jre/java/io/Reader.java @@ -0,0 +1,234 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * Reader is an Abstract class for reading Character Streams. Subclasses of + * Reader must implement the methods read(char[], int, int) and + * close(). + * + * @see Writer + */ +public abstract class Reader { + /** + * The object used to synchronize access to the reader. + */ + protected Object lock; + + /** + * Constructs a new character stream Reader using this as the + * Object to synchronize critical regions around. + */ + protected Reader() { + super(); + lock = this; + } + + /** + * Constructs a new character stream Reader using lock as the + * Object to synchronize critical regions around. + * + * @param lock + * the Object to synchronize critical regions + * around. + */ + protected Reader(Object lock) { + if (lock == null) { + throw new NullPointerException(); + } + this.lock = lock; + } + + /** + * Close this Reader. This must be implemented by any concrete subclasses. + * The implementation should free any resources associated with the Reader. + * + * @throws IOException + * If an error occurs attempting to close this Reader. + */ + public abstract void close() throws IOException; + + /** + * Set a Mark position in this Reader. The parameter readLimit + * indicates how many characters can be read before a mark is invalidated. + * Sending reset() will reposition the reader back to the marked position + * provided readLimit has not been surpassed. + *

+ * This default implementation simply throws IOException and concrete + * subclasses must provide their own implementations. + * + * @param readLimit + * an int representing how many characters must be read before + * invalidating the mark. + * + * @throws IOException + * If an error occurs attempting mark this Reader. + */ + public void mark(int readLimit) throws IOException { + throw new IOException(); + } + + /** + * Answers a boolean indicating whether or not this Reader supports mark() + * and reset(). This class a default implementation which answers false. + * + * @return true if mark() and reset() are supported, + * false otherwise. This implementation returns + * false. + */ + public boolean markSupported() { + return false; + } + + /** + * Reads a single character from this reader and returns the result as an + * int. The 2 higher-order characters are set to 0. If the end of reader was + * encountered then return -1. + * + * @return the character read or -1 if end of reader. + * + * @throws IOException + * If the Reader is already closed or some other IO error + * occurs. + */ + public int read() throws IOException { + synchronized (lock) { + char charArray[] = new char[1]; + if (read(charArray, 0, 1) != -1) { + return charArray[0]; + } + return -1; + } + } + + /** + * Reads characters from this Reader and stores them in the character array + * buf starting at offset 0. Returns the number of characters + * actually read or -1 if the end of reader was encountered. + * + * @param buf + * character array to store the read characters + * @return how many characters were successfully read in or else -1 if the + * end of the reader was detected. + * + * @throws IOException + * If the Reader is already closed or some other IO error + * occurs. + */ + public int read(char buf[]) throws IOException { + return read(buf, 0, buf.length); + } + + /** + * Reads at most count characters from this Reader and stores + * them at offset in the character array buf. + * Returns the number of characters actually read or -1 if the end of reader + * was encountered. + * + * @param buf + * character array to store the read characters + * @param offset + * offset in buf to store the read characters + * @param count + * how many characters should be read in + * @return how many characters were successfully read in or else -1 if the + * end of the reader was detected. + * + * @throws IOException + * If the Reader is already closed or some other IO error + * occurs. + */ + public abstract int read(char buf[], int offset, int count) + throws IOException; + + /** + * Answers a boolean indicating whether or not this Reader is + * ready to be read without blocking. If the result is true, + * the next read() will not block. If the result is + * false this Reader may or may not block when + * read() is sent. + * + * @return true if the receiver will not block when + * read() is called, false if unknown + * or blocking will occur. + * + * @throws IOException + * If the Reader is already closed or some other IO error + * occurs. + */ + public boolean ready() throws IOException { + return false; + } + + /** + * Reset this Readers position to the last mark() location. + * Invocations of read()/skip() will occur from this new + * location. If this Reader was not marked, the implementation of + * reset() is implementation specific. See the comment for + * the specific Reader subclass for implementation details. The default + * action is to throw IOException. + * + * @throws IOException + * If a problem occured or the receiver does not support + * mark()/reset(). + */ + public void reset() throws IOException { + throw new IOException(); + } + + /** + * Skips count number of characters in this Reader. + * Subsequent read()'s will not return these characters + * unless reset() is used. This method may perform multiple + * reads to read count characters. + * + * @param count + * how many characters should be passed over + * @return how many characters were successfully passed over + * + * @throws IOException + * If the Reader is closed when the call is made or if an IO + * error occurs during the operation. + */ + public long skip(long count) throws IOException { + if (count < 0) { + throw new IllegalArgumentException(); + } + synchronized (lock) { + long skipped = 0; + int toRead = count < 512 ? (int) count : 512; + char charsSkipped[] = new char[toRead]; + while (skipped < count) { + int read = read(charsSkipped, 0, toRead); + if (read == -1) { + return skipped; + } + skipped += read; + if (read < toRead) { + return skipped; + } + if (count - skipped < toRead) { + toRead = (int) (count - skipped); + } + } + return skipped; + } + } + + +} \ No newline at end of file diff --git a/gwt/jre/java/io/StringReader.java b/gwt/jre/java/io/StringReader.java new file mode 100644 index 0000000..3b81233 --- /dev/null +++ b/gwt/jre/java/io/StringReader.java @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * A specialized {@link Reader} that reads characters from a {@code String} in + * a sequential manner. + * + * @see StringWriter + */ +public class StringReader extends Reader { + private String str; + + private int markpos = -1; + + private int pos; + + private int count; + + /** + * Construct a new {@code StringReader} with {@code str} as source. The size + * of the reader is set to the {@code length()} of the string and the Object + * to synchronize access through is set to {@code str}. + * + * @param str + * the source string for this reader. + */ + public StringReader(String str) { + super(); + this.str = str; + this.count = str.length(); + } + + /** + * Closes this reader. Once it is closed, read operations on this reader + * will throw an {@code IOException}. Only the first invocation of this + * method has any effect. + */ + @Override + public void close() { + str = null; + } + + /** + * Returns a boolean indicating whether this reader is closed. + * + * @return {@code true} if closed, otherwise {@code false}. + */ + private boolean isClosed() { + return str == null; + } + + /** + * Sets a mark position in this reader. The parameter {@code readLimit} is + * ignored for this class. Calling {@code reset()} will reposition the + * reader back to the marked position. + * + * @param readLimit + * ignored for {@code StringReader} instances. + * @throws IllegalArgumentException + * if {@code readLimit < 0}. + * @throws IOException + * if this reader is closed. + * @see #markSupported() + * @see #reset() + */ + @Override + public void mark(int readLimit) throws IOException { + if (readLimit < 0) { + throw new IllegalArgumentException(); + } + + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$ + } + markpos = pos; + } + } + + /** + * Indicates whether this reader supports the {@code mark()} and {@code + * reset()} methods. This implementation returns {@code true}. + * + * @return always {@code true}. + */ + @Override + public boolean markSupported() { + return true; + } + + /** + * Reads a single character from the source string and returns it as an + * integer with the two higher-order bytes set to 0. Returns -1 if the end + * of the source string has been reached. + * + * @return the character read or -1 if the end of the source string has been + * reached. + * @throws IOException + * if this reader is closed. + */ + @Override + public int read() throws IOException { + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$ + } + if (pos != count) { + return str.charAt(pos++); + } + return -1; + } + } + + /** + * Reads at most {@code len} characters from the source string and stores + * them at {@code offset} in the character array {@code buf}. Returns the + * number of characters actually read or -1 if the end of the source string + * has been reached. + * + * @param buf + * the character array to store the characters read. + * @param offset + * the initial position in {@code buffer} to store the characters + * read from this reader. + * @param len + * the maximum number of characters to read. + * @return the number of characters read or -1 if the end of the reader has + * been reached. + * @throws IndexOutOfBoundsException + * if {@code offset < 0} or {@code len < 0}, or if + * {@code offset + len} is greater than the size of {@code buf}. + * @throws IOException + * if this reader is closed. + */ + @Override + public int read(char buf[], int offset, int len) throws IOException { + synchronized (lock) { + if (isClosed()) { + // K0083=StringReader is closed. + throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$ + } + if (offset < 0 || offset > buf.length) { + // K002e=Offset out of bounds \: {0} + throw new ArrayIndexOutOfBoundsException(Msg.getString("K002e", offset)); //$NON-NLS-1$ + } + if (len < 0 || len > buf.length - offset) { + // K0031=Length out of bounds \: {0} + throw new ArrayIndexOutOfBoundsException(Msg.getString("K0031", len)); //$NON-NLS-1$ + } + if (len == 0) { + return 0; + } + if (pos == this.count) { + return -1; + } + int end = pos + len > this.count ? this.count : pos + len; + str.getChars(pos, end, buf, offset); + int read = end - pos; + pos = end; + return read; + } + } + + /** + * Indicates whether this reader is ready to be read without blocking. This + * implementation always returns {@code true}. + * + * @return always {@code true}. + * @throws IOException + * if this reader is closed. + * @see #read() + * @see #read(char[], int, int) + */ + @Override + public boolean ready() throws IOException { + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$ + } + return true; + } + } + + /** + * Resets this reader's position to the last {@code mark()} location. + * Invocations of {@code read()} and {@code skip()} will occur from this new + * location. If this reader has not been marked, it is reset to the + * beginning of the source string. + * + * @throws IOException + * if this reader is closed. + * @see #mark(int) + * @see #markSupported() + */ + @Override + public void reset() throws IOException { + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$ + } + pos = markpos != -1 ? markpos : 0; + } + } + + /** + * Moves {@code ns} characters in the source string. Unlike the {@link + * Reader#skip(long) overridden method}, this method may skip negative skip + * distances: this rewinds the input so that characters may be read again. + * When the end of the source string has been reached, the input cannot be + * rewound. + * + * @param ns + * the maximum number of characters to skip. Positive values skip + * forward; negative values skip backward. + * @return the number of characters actually skipped. This is bounded below + * by the number of characters already read and above by the + * number of characters remaining:
{@code -(num chars already + * read) <= distance skipped <= num chars remaining}. + * @throws IOException + * if this reader is closed. + * @see #mark(int) + * @see #markSupported() + * @see #reset() + */ + @Override + public long skip(long ns) throws IOException { + synchronized (lock) { + if (isClosed()) { + throw new IOException(Msg.getString("K0083")); //$NON-NLS-1$ + } + + int minSkip = -pos; + int maxSkip = count - pos; + + if (maxSkip == 0 || ns > maxSkip) { + ns = maxSkip; // no rewinding if we're at the end + } else if (ns < minSkip) { + ns = minSkip; + } + + pos += ns; + return ns; + } + } +} \ No newline at end of file diff --git a/gwt/jre/java/io/StringWriter.java b/gwt/jre/java/io/StringWriter.java new file mode 100644 index 0000000..f399552 --- /dev/null +++ b/gwt/jre/java/io/StringWriter.java @@ -0,0 +1,250 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * StringWriter is an class for writing Character Streams to a StringBuffer. The + * characters written can then be returned as a String. This is used for + * capturing output sent to a Writer by substituting a StringWriter. + * + * @see StringReader + */ +public class StringWriter extends Writer { + + private StringBuffer buf; + + /** + * Constructs a new StringWriter which has a StringBuffer allocated with the + * default size of 16 characters. The StringBuffer is also the + * lock used to synchronize access to this Writer. + */ + public StringWriter() { + super(); + buf = new StringBuffer(16); + lock = buf; + } + + /** + * Constructs a new StringWriter which has a StringBuffer allocated with the + * size of initialSize characters. The StringBuffer is also + * the lock used to synchronize access to this Writer. + * + * @param initialSize + * the intial number of characters + */ + public StringWriter(int initialSize) { + if (initialSize < 0) { + throw new IllegalArgumentException(); + } + buf = new StringBuffer(initialSize); + lock = buf; + } + + /** + * Close this Writer. This is the concrete implementation required. This + * particular implementation does nothing. + * + * @throws IOException + * If an IO error occurs closing this StringWriter. + */ + @Override + public void close() throws IOException { + /* empty */ + } + + /** + * Flush this Writer. This is the concrete implementation required. This + * particular implementation does nothing. + */ + @Override + public void flush() { + /* empty */ + } + + /** + * Answer the contents of this StringWriter as a StringBuffer. Any changes + * made to the StringBuffer by the receiver or the caller are reflected in + * this StringWriter. + * + * @return this StringWriters local StringBuffer. + */ + public StringBuffer getBuffer() { + synchronized (lock) { + return buf; + } + } + + /** + * Answer the contents of this StringWriter as a String. Any changes made to + * the StringBuffer by the receiver after returning will not be reflected in + * the String returned to the caller. + * + * @return this StringWriters current contents as a String. + */ + @Override + public String toString() { + synchronized (lock) { + return buf.toString(); + } + } + + /** + * Writes count characters starting at offset + * in cbuf to this StringWriter. + * + * @param cbuf + * the non-null array containing characters to write. + * @param offset + * offset in buf to retrieve characters + * @param count + * maximum number of characters to write + * + * @throws ArrayIndexOutOfBoundsException + * If offset or count are outside of bounds. + */ + @Override + public void write(char[] cbuf, int offset, int count) { + // avoid int overflow + if (offset < 0 || offset > cbuf.length || count < 0 + || count > cbuf.length - offset) { + throw new IndexOutOfBoundsException(); + } + synchronized (lock) { + this.buf.append(cbuf, offset, count); + } + } + + /** + * Writes the specified character oneChar to this + * StringWriter. This implementation writes the low order two bytes to the + * Stream. + * + * @param oneChar + * The character to write + */ + @Override + public void write(int oneChar) { + synchronized (lock) { + buf.append((char) oneChar); + } + } + + /** + * Writes the characters from the String str to this + * StringWriter. + * + * @param str + * the non-null String containing the characters to write. + */ + @Override + public void write(String str) { + synchronized (lock) { + buf.append(str); + } + } + + /** + * Writes count number of characters starting at + * offset from the String str to this + * StringWriter. + * + * @param str + * the non-null String containing the characters to write. + * @param offset + * the starting point to retrieve characters. + * @param count + * the number of characters to retrieve and write. + * + * @throws ArrayIndexOutOfBoundsException + * If offset or count are outside of bounds. + */ + @Override + public void write(String str, int offset, int count) { + String sub = str.substring(offset, offset + count); + synchronized (lock) { + buf.append(sub); + } + } + + /** + * Append a char cto the StringWriter. The + * StringWriter.append(c) works the same way as + * StringWriter.write(c). + * + * @param c + * The character appended to the StringWriter. + * @return The StringWriter. + */ + @Override + public StringWriter append(char c) { + write(c); + return this; + } + + /** + * Append a CharSequence csq to the StringWriter. The + * StringWriter.append(csq) works the same way as + * StringWriter.write(csq.toString()). If csq + * is null, then "null" will be substituted for csq. + * + * @param csq + * The CharSequence appended to the StringWriter. + * @return The StringWriter + */ + @Override + public StringWriter append(CharSequence csq) { + if (null == csq) { + append(TOKEN_NULL, 0, TOKEN_NULL.length()); + } else { + append(csq, 0, csq.length()); + } + return this; + } + + /** + * Append a subsequence of a CharSequence csq to the + * StringWriter. The first char and the last char of the subsequnce is + * specified by the parameter start and end. + * The StringWriter.append(csq) works the same way as + * StringWriter.write(csq.subSequence(start,end).toString).If + * csq is null, then "null" will be substituted for + * csq. s + * + * @param csq + * The CharSequence appended to the StringWriter. + * @param start + * The index of the first char in the CharSequence appended to + * the StringWriter. + * @param end + * The index of the char after the last one in the CharSequence + * appended to the StringWriter. + * @return The StringWriter. + * @throws IndexOutOfBoundsException + * If start is less than end, end is greater than the length of + * the CharSequence, or start or end is negative. + */ + @Override + public StringWriter append(CharSequence csq, int start, int end) { + if (null == csq) { + csq = TOKEN_NULL; + } + String output = csq.subSequence(start, end).toString(); + write(output, 0, output.length()); + return this; + } +} \ No newline at end of file diff --git a/gwt/jre/java/io/Writer.java b/gwt/jre/java/io/Writer.java new file mode 100644 index 0000000..3b7dce5 --- /dev/null +++ b/gwt/jre/java/io/Writer.java @@ -0,0 +1,241 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.io; + +/** + * Writer is an Abstract class for writing Character Streams. Subclasses of + * writer must implement the methods write(char[], int, int), + * close() and flush(). + * + * @see Reader + */ +public abstract class Writer { + + static final String TOKEN_NULL = "null"; //$NON-NLS-1$ + + /** + * The object used to synchronize access to the writer. + */ + protected Object lock; + + /** + * Constructs a new character stream Writer using this as the + * Object to synchronize critical regions around. + */ + protected Writer() { + super(); + lock = this; + } + + /** + * Constructs a new character stream Writer using lock as the + * Object to synchronize critical regions around. + * + * @param lock + * the Object to synchronize critical regions around. + */ + protected Writer(Object lock) { + if (lock == null) { + throw new NullPointerException(); + } + this.lock = lock; + } + + /** + * Close this Writer. This must be implemented by any concrete subclasses. + * The implementation should free any resources associated with the Writer. + * + * @throws IOException + * If an error occurs attempting to close this Writer. + */ + public abstract void close() throws IOException; + + /** + * Flush this Writer. This must be implemented by any concrete subclasses. + * The implementation should ensure all buffered characters are written out. + * + * @throws IOException + * If an error occurs attempting to flush this Writer. + */ + public abstract void flush() throws IOException; + + /** + * Writes the entire character buffer buf to this Writer. + * + * @param buf + * the non-null array containing characters to write. + * + * @throws IOException + * If this Writer has already been closed or some other + * IOException occurs. + */ + public void write(char buf[]) throws IOException { + write(buf, 0, buf.length); + } + + /** + * Writes count characters starting at offset in + * buf to this Writer. This abstract method must be implemented + * by concrete subclasses. + * + * @param buf the non-null array containing characters to write. + * @param offset offset in buf to retrieve characters + * @param count maximum number of characters to write + * + * @throws IOException If this Writer has already been closed or some other IOException occurs. + * @throws ArrayIndexOutOfBoundsException If offset or count are outside of bounds. + */ + public abstract void write(char buf[], int offset, int count) + throws IOException; + + /** + * Writes the specified character oneChar to this Writer. + * This implementation writes the low order two bytes of + * oneChar to the Stream. + * + * @param oneChar + * The character to write + * + * @throws IOException + * If this Writer has already been closed or some other + * IOException occurs. + */ + public void write(int oneChar) throws IOException { + synchronized (lock) { + char oneCharArray[] = new char[1]; + oneCharArray[0] = (char) oneChar; + write(oneCharArray); + } + } + + /** + * Writes the characters from the String str to this Writer. + * + * @param str + * the non-null String containing the characters to write. + * + * @throws IOException + * If this Writer has already been closed or some other + * IOException occurs. + */ + public void write(String str) throws IOException { + char buf[] = new char[str.length()]; + str.getChars(0, buf.length, buf, 0); + synchronized (lock) { + write(buf); + } + } + + /** + * Writes count number of characters starting at + * offset from the String str to this Writer. + * + * @param str + * the non-null String containing the characters to write. + * @param offset + * the starting point to retrieve characters. + * @param count + * the number of characters to retrieve and write. + * + * @throws IOException + * If this Writer has already been closed or some other + * IOException occurs. + * @throws ArrayIndexOutOfBoundsException + * If offset or count are outside of bounds. + */ + public void write(String str, int offset, int count) throws IOException { + if (count < 0) { // other cases tested by getChars() + throw new StringIndexOutOfBoundsException(); + } + char buf[] = new char[count]; + str.getChars(offset, offset + count, buf, 0); + + synchronized (lock) { + write(buf); + } + } + + /** + * Append a char cto the Writer. The Writer.append(c) + * works the same as Writer.write(c). + * + * @param c + * The character appended to the Writer. + * @return The Writer. + * @throws IOException + * If any IOException raises during the procedure. + */ + public Writer append(char c) throws IOException { + write(c); + return this; + } + + /** + * Append a CharSequence csq to the Writer. The + * Writer.append(csq) works the same way as Writer.write(csq.toString()). + * If csq is null, then "null" will be substituted for + * csq. + * + * @param csq + * The CharSequence appended to the Writer. + * @return The Writer. + * @throws IOException + * If any IOException raises during the procedure. + */ + public Writer append(CharSequence csq) throws IOException { + if (null == csq) { + write(TOKEN_NULL); + } else { + write(csq.toString()); + } + return this; + } + + /** + * Append a subsequence of a CharSequence csq to the Writer. + * The first char and the last char of the subsequnce is specified by the + * parameter start and end. The + * Writer.append(csq) works the same way as Writer.write (csqcsq.subSequence(start,end).toString). + * If csq is null, then "null" will be substituted for + * csq. + * + * @param csq + * The CharSequence appended to the Writaer. + * @param start + * The index of the first char in the CharSequence appended to + * the Writer. + * @param end + * The index of the char after the last one in the CharSequence + * appended to the Writer. + * @return The Writer. + * @throws IndexOutOfBoundsException + * If start is less than end, end is greater than the length of + * the CharSequence, or start or end is negative. + * @throws IOException + * If any IOException raises during the procedure. + */ + public Writer append(CharSequence csq, int start, int end) + throws IOException { + if (null == csq) { + write(TOKEN_NULL.substring(start, end)); + } else { + write(csq.subSequence(start, end).toString()); + } + return this; + } +} \ No newline at end of file diff --git a/gwt/jre/java/lang/ClassNotFoundException.java b/gwt/jre/java/lang/ClassNotFoundException.java new file mode 100644 index 0000000..aa86717 --- /dev/null +++ b/gwt/jre/java/lang/ClassNotFoundException.java @@ -0,0 +1,18 @@ +package java.lang; + +public class ClassNotFoundException extends Exception { + + public ClassNotFoundException() + { + } + + public ClassNotFoundException(String s) + { + super(s); + } + + public ClassNotFoundException(String s, Throwable ex) + { + super(s,ex); + } +} diff --git a/gwt/jre/java/lang/CloneNotSupportedException.java b/gwt/jre/java/lang/CloneNotSupportedException.java new file mode 100644 index 0000000..abd3feb --- /dev/null +++ b/gwt/jre/java/lang/CloneNotSupportedException.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang; + + +/** + * This exception is thrown when a program attempts to clone an object which + * does not support the Cloneable interface. + * + * @see Cloneable + */ +public class CloneNotSupportedException extends Exception { + + private static final long serialVersionUID = 5195511250079656443L; + + /** + * Constructs a new instance of this class with its walkback filled in. + */ + public CloneNotSupportedException() { + super(); + } + + /** + * Constructs a new instance of this class with its walkback and message + * filled in. + * + * @param detailMessage + * String The detail message for the exception. + */ + public CloneNotSupportedException(String detailMessage) { + super(detailMessage); + } +} \ No newline at end of file diff --git a/gwt/jre/java/lang/InternalError.java b/gwt/jre/java/lang/InternalError.java new file mode 100644 index 0000000..dc7a1aa --- /dev/null +++ b/gwt/jre/java/lang/InternalError.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.lang; + + +/** + * This error is thrown when the VM notices that it has gotten into a state + * which it does not understand. + */ +public class InternalError extends RuntimeException { + + private static final long serialVersionUID = -9062593416125562365L; + + /** + * Constructs a new instance of this class with its walkback filled in. + */ + public InternalError() { + super(); + } + + /** + * Constructs a new instance of this class with its walkback and message + * filled in. + * + * @param detailMessage + * String The detail message for the exception. + */ + public InternalError(String detailMessage) { + super(detailMessage); + } +} \ No newline at end of file diff --git a/gwt/jre/java/math/BigDecimal.java b/gwt/jre/java/math/BigDecimal.java new file mode 100644 index 0000000..7cc988b --- /dev/null +++ b/gwt/jre/java/math/BigDecimal.java @@ -0,0 +1,2845 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +import com.google.gwt.core.client.JavaScriptObject; + +import java.io.Serializable; + +/** + * This class represents immutable arbitrary precision decimal numbers. Each + * {@code BigDecimal} instance is represented with a unscaled arbitrary + * precision mantissa (the unscaled value) and a scale. The value of the {@code + * BigDecimal} is {@code unscaledValue} 10^(-{@code scale}). + */ +public class BigDecimal extends Number implements Comparable, + Serializable { + + /** + * One more than the number of bits which can be stored in {@link #smallValue}. + */ + private static final int SMALL_VALUE_BITS = 54; + + /** + * The constant one as a {@code BigDecimal}. + */ + public static final BigDecimal ONE = new BigDecimal(1, 0); + + /** + * Rounding mode to round towards positive infinity. For positive values this + * rounding mode behaves as {@link #ROUND_UP}, for negative values as + * {@link #ROUND_DOWN}. + * + * @see RoundingMode#CEILING + */ + public static final int ROUND_CEILING = 2; + + /** + * Rounding mode where the values are rounded towards zero. + * + * @see RoundingMode#DOWN + */ + public static final int ROUND_DOWN = 1; + + /** + * Rounding mode to round towards negative infinity. For positive values this + * rounding mode behaves as {@link #ROUND_DOWN}, for negative values as + * {@link #ROUND_UP}. + * + * @see RoundingMode#FLOOR + */ + public static final int ROUND_FLOOR = 3; + + /** + * Rounding mode where values are rounded towards the nearest neighbor. Ties + * are broken by rounding down. + * + * @see RoundingMode#HALF_DOWN + */ + public static final int ROUND_HALF_DOWN = 5; + + /** + * Rounding mode where values are rounded towards the nearest neighbor. Ties + * are broken by rounding to the even neighbor. + * + * @see RoundingMode#HALF_EVEN + */ + public static final int ROUND_HALF_EVEN = 6; + + /** + * Rounding mode where values are rounded towards the nearest neighbor. Ties + * are broken by rounding up. + * + * @see RoundingMode#HALF_UP + */ + public static final int ROUND_HALF_UP = 4; + + /** + * Rounding mode where the rounding operations throws an {@code + * ArithmeticException} for the case that rounding is necessary, i.e. for the + * case that the value cannot be represented exactly. + * + * @see RoundingMode#UNNECESSARY + */ + public static final int ROUND_UNNECESSARY = 7; + + /** + * Rounding mode where positive values are rounded towards positive infinity + * and negative values towards negative infinity. + * + * @see RoundingMode#UP + */ + public static final int ROUND_UP = 0; + + /** + * The constant ten as a {@code BigDecimal}. + */ + public static final BigDecimal TEN = new BigDecimal(10, 0); + + /** + * The constant zero as a {@code BigDecimal}. + */ + public static final BigDecimal ZERO = new BigDecimal(0, 0); + + protected static JavaScriptObject unscaledRegex; + + private static final int BI_SCALED_BY_ZERO_LENGTH = 11; + + /** + * An array with the first BigInteger scaled by zero. ( + * [0,0],[1,0],...,[10,0]). + */ + private static final BigDecimal BI_SCALED_BY_ZERO[] = new BigDecimal[BI_SCALED_BY_ZERO_LENGTH]; + + /** + * An array filled with characters '0'. + */ + private static final char[] CH_ZEROS = new char[100]; + + private static final double[] DOUBLE_FIVE_POW = new double[] { + 1D, 5D, 25D, 125D, 625D, 3125D, 15625D, 78125D, 390625D, 1953125D, + 9765625D, 48828125D, 244140625D, 1220703125D, 6103515625D, 30517578125D, + 152587890625D, 762939453125D, 3814697265625D, 19073486328125D, + 95367431640625D, 476837158203125D, 2384185791015625D,}; + + private static final int[] DOUBLE_FIVE_POW_BIT_LENGTH = new int[DOUBLE_FIVE_POW.length]; + + /** + * An array with powers of ten that fit in the type double ( + * 10^0,10^1,...,10^18). + */ + private static final double[] DOUBLE_TEN_POW = new double[] { + 1D, 10D, 100D, 1000D, 10000D, 100000D, 1000000D, 10000000D, 100000000D, + 1000000000D, 10000000000D, 100000000000D, 1000000000000D, + 10000000000000D, 100000000000000D, 1000000000000000D, + 10000000000000000D,}; + + private static final int[] DOUBLE_TEN_POW_BIT_LENGTH = new int[DOUBLE_TEN_POW.length]; + + /** + * An array with powers of five that fit in the type double ( + * 5^0,5^1,...,5^27). + */ + private static final BigInteger FIVE_POW[]; + + /** + * The double closest to Math.log(2.0d). + */ + private static final double LOG2 = 0.6931471805599453d; + + /** + * The double closest to Log10(2). + */ + private static final double LOG10_2 = 0.3010299956639812; + + /** + * The double closer to Math.pow(2, 47). + */ + private static final double POW47 = 140737488355328d; + + /** + * This is the serialVersionUID used by the sun implementation. + */ + private static final long serialVersionUID = 6108874887143696463L; + + /** + * An array with powers of ten that fit in the type double ( + * 10^0,10^1,...,10^18). + */ + private static final BigInteger TEN_POW[]; + + /** + * An array with the zero number scaled by the first positive scales. ( + * 0*10^0, 0*10^1, ..., 0*10^10). + */ + private static final BigDecimal ZERO_SCALED_BY[] = new BigDecimal[11]; + + static { + // To fill all static arrays. + int i = 0; + + for (; i < ZERO_SCALED_BY.length; i++) { + BI_SCALED_BY_ZERO[i] = new BigDecimal(i, 0); + ZERO_SCALED_BY[i] = new BigDecimal(0, i); + CH_ZEROS[i] = '0'; + } + + for (; i < CH_ZEROS.length; i++) { + CH_ZEROS[i] = '0'; + } + for (int j = 0; j < DOUBLE_FIVE_POW_BIT_LENGTH.length; j++) { + DOUBLE_FIVE_POW_BIT_LENGTH[j] = bitLength(DOUBLE_FIVE_POW[j]); + } + for (int j = 0; j < DOUBLE_TEN_POW_BIT_LENGTH.length; j++) { + DOUBLE_TEN_POW_BIT_LENGTH[j] = bitLength(DOUBLE_TEN_POW[j]); + } + + // Taking the references of useful powers. + TEN_POW = Multiplication.bigTenPows; + FIVE_POW = Multiplication.bigFivePows; + } + + /** + * Returns a new {@code BigDecimal} instance whose value is equal to {@code + * val}. The new decimal is constructed as if the {@code BigDecimal(String)} + * constructor is called with an argument which is equal to {@code + * Double.toString(val)}. For example, {@code valueOf("0.1")} is converted to + * (unscaled=1, scale=1), although the double {@code 0.1} cannot be + * represented exactly as a double value. In contrast to that, a new {@code + * BigDecimal(0.1)} instance has the value {@code + * 0.1000000000000000055511151231257827021181583404541015625} with an unscaled + * value {@code 1000000000000000055511151231257827021181583404541015625} and + * the scale {@code 55}. + * + * @param val double value to be converted to a {@code BigDecimal}. + * @return {@code BigDecimal} instance with the value {@code val}. + * @throws NumberFormatException if {@code val} is infinite or {@code val} is + * not a number + */ + public static BigDecimal valueOf(double val) { + if (Double.isInfinite(val) || Double.isNaN(val)) { + // math.03=Infinity or NaN + throw new NumberFormatException("Infinite or NaN"); //$NON-NLS-1$ + } + return new BigDecimal(Double.toString(val)); + } + + /** + * Returns a new {@code BigDecimal} instance whose value is equal to {@code + * unscaledVal}. The scale of the result is {@code 0}, and its unscaled value + * is {@code unscaledVal}. + * + * @param unscaledVal value to be converted to a {@code BigDecimal}. + * @return {@code BigDecimal} instance with the value {@code unscaledVal}. + */ + public static BigDecimal valueOf(long unscaledVal) { + if ((unscaledVal >= 0) && (unscaledVal < BI_SCALED_BY_ZERO_LENGTH)) { + return BI_SCALED_BY_ZERO[(int) unscaledVal]; + } + return new BigDecimal(unscaledVal, 0); + } + + /** + * Returns a new {@code BigDecimal} instance whose value is equal to {@code + * unscaledVal} 10^(-{@code scale}). The scale of the result is {@code scale}, + * and its unscaled value is {@code unscaledVal}. + * + * @param unscaledVal unscaled value to be used to construct the new {@code + * BigDecimal}. + * @param scale scale to be used to construct the new {@code BigDecimal}. + * @return {@code BigDecimal} instance with the value {@code unscaledVal}* + * 10^(-{@code unscaledVal}). + */ + public static BigDecimal valueOf(long unscaledVal, int scale) { + if (scale == 0) { + return valueOf(unscaledVal); + } + if ((unscaledVal == 0) && (scale >= 0) && (scale < ZERO_SCALED_BY.length)) { + return ZERO_SCALED_BY[scale]; + } + return new BigDecimal(unscaledVal, scale); + } + + private static BigDecimal addAndMult10(BigDecimal thisValue, + BigDecimal augend, double diffScale) { + if (diffScale < DOUBLE_TEN_POW.length + && Math.max(thisValue.bitLength, augend.bitLength + + DOUBLE_TEN_POW_BIT_LENGTH[(int) diffScale]) + 1 + < SMALL_VALUE_BITS) { + return valueOf(thisValue.smallValue + augend.smallValue + * DOUBLE_TEN_POW[(int) diffScale], thisValue.scale); + } + return new BigDecimal(thisValue.getUnscaledValue().add( + Multiplication.multiplyByTenPow(augend.getUnscaledValue(), + (int) diffScale)), thisValue.scale); + } + + private static int bitLength(double value) { + // if |value| is less than 2^47, use log + if (value > -POW47 && value < POW47) { + if (value == 0.0) { + // special-case zero, otherwise we get -INFINITY below + return 0; + } + boolean negative = (value < 0.0); + if (negative) { + value = -value; + } + int result = (int) Math.floor(Math.log(value) / LOG2); + if (!negative || value != Math.pow(2, result)) { + result++; + } + return result; + } + return bitLength((long) value); + } + + private static int bitLength(long value) { + if (value < 0) { + value = ~value; + } + return 64 - Long.numberOfLeadingZeros(value); + } + + private static BigDecimal divideBigIntegers(BigInteger scaledDividend, + BigInteger scaledDivisor, int scale, RoundingMode roundingMode) { + + BigInteger[] quotAndRem = scaledDividend.divideAndRemainder(scaledDivisor); // quotient + // and + // remainder + // If after division there is a remainder... + BigInteger quotient = quotAndRem[0]; + BigInteger remainder = quotAndRem[1]; + if (remainder.signum() == 0) { + return new BigDecimal(quotient, scale); + } + int sign = scaledDividend.signum() * scaledDivisor.signum(); + int compRem; // 'compare to remainder' + if (scaledDivisor.bitLength() < SMALL_VALUE_BITS) { + long rem = remainder.longValue(); + long divisor = scaledDivisor.longValue(); + compRem = longCompareTo(Math.abs(rem) << 1, Math.abs(divisor)); + // To look if there is a carry + compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0, sign + * (5 + compRem), roundingMode); + + } else { + // Checking if: remainder * 2 >= scaledDivisor + compRem = remainder.abs().shiftLeftOneBit().compareTo(scaledDivisor.abs()); + compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0, sign + * (5 + compRem), roundingMode); + } + if (compRem != 0) { + if (quotient.bitLength() < SMALL_VALUE_BITS) { + return valueOf(quotient.longValue() + compRem, scale); + } + quotient = quotient.add(BigInteger.valueOf(compRem)); + return new BigDecimal(quotient, scale); + } + // Constructing the result with the appropriate unscaled value + return new BigDecimal(quotient, scale); + } + + private static BigDecimal dividePrimitiveDoubles(double scaledDividend, + double scaledDivisor, int scale, RoundingMode roundingMode) { + double quotient = intDivide(scaledDividend, scaledDivisor); + double remainder = scaledDividend % scaledDivisor; + int sign = Double.compare(scaledDividend * scaledDivisor, 0.0); + if (remainder != 0) { + // Checking if: remainder * 2 >= scaledDivisor + int compRem; // 'compare to remainder' + compRem = Double.compare(Math.abs(remainder) * 2, + Math.abs(scaledDivisor)); + // To look if there is a carry + quotient += roundingBehavior(((int) quotient) & 1, sign * (5 + compRem), + roundingMode); + } + // Constructing the result with the appropriate unscaled value + return valueOf(quotient, scale); + } + + private static double intDivide(double dividend, double divisor) { + double quotient = dividend / divisor; + return quotient > 0 ? Math.floor(quotient) : Math.ceil(quotient); + } + + private static int longCompareTo(long a, long b) { + return Long.signum(a - b); + } + + private static native double parseUnscaled(String str) /*-{ + var unscaledRegex = @java.math.BigDecimal::unscaledRegex; + if (!unscaledRegex) { + unscaledRegex = @java.math.BigDecimal::unscaledRegex = /^[+-]?\d*$/i; + } + if (unscaledRegex.test(str)) { + return parseInt(str, 10); + } else { + return Number.NaN; + } + }-*/; + + /** + * Return an increment that can be -1,0 or 1, depending of {@code + * roundingMode}. + * + * @param parityBit can be 0 or 1, it's only used in the case {@code + * HALF_EVEN} + * @param fraction the mantisa to be analyzed + * @param roundingMode the type of rounding + * @return the carry propagated after rounding + */ + private static int roundingBehavior(int parityBit, int fraction, + RoundingMode roundingMode) { + int increment = 0; // the carry after rounding + + switch (roundingMode) { + case UNNECESSARY: + if (fraction != 0) { + // math.08=Rounding necessary + throw new ArithmeticException("Rounding necessary"); //$NON-NLS-1$ + } + break; + case UP: + increment = Integer.signum(fraction); + break; + case DOWN: + break; + case CEILING: + increment = Math.max(Integer.signum(fraction), 0); + break; + case FLOOR: + increment = Math.min(Integer.signum(fraction), 0); + break; + case HALF_UP: + if (Math.abs(fraction) >= 5) { + increment = Integer.signum(fraction); + } + break; + case HALF_DOWN: + if (Math.abs(fraction) > 5) { + increment = Integer.signum(fraction); + } + break; + case HALF_EVEN: + if (Math.abs(fraction) + parityBit > 5) { + increment = Integer.signum(fraction); + } + break; + } + return increment; + } + + /** + * It tests if a scale of type {@code long} fits in 32 bits. It returns the + * same scale being casted to {@code int} type when is possible, otherwise + * throws an exception. + * + * @param doubleScale a double bit scale + * @return a 32 bit scale when is possible + * @throws ArithmeticException when {@code scale} doesn't fit in {@code int} + * type + * @see #scale + */ + private static int toIntScale(double doubleScale) { + if (doubleScale < Integer.MIN_VALUE) { + // math.09=Overflow + throw new ArithmeticException("Overflow"); //$NON-NLS-1$ + } else if (doubleScale > Integer.MAX_VALUE) { + // math.0A=Underflow + throw new ArithmeticException("Underflow"); //$NON-NLS-1$ + } else { + return (int) doubleScale; + } + } + + /** + * Convert a double to a string with {@code digits} precision. The resulting + * string may still be in exponential notation. + * + * @param d double value + * @param digits number of digits of precision to include + * @return non-localized string representation of {@code d} + */ + private static native String toPrecision(double d, int digits) /*-{ + return d.toPrecision(digits); + }-*/; + + private static BigDecimal valueOf(double smallValue, double scale) { + return new BigDecimal(smallValue, scale); + } + + /** + * It returns the value 0 with the most approximated scale of type {@code int} + * . if {@code longScale > Integer.MAX_VALUE} the scale will be {@code + * Integer.MAX_VALUE}; if {@code longScale < Integer.MIN_VALUE} the scale will + * be {@code Integer.MIN_VALUE}; otherwise {@code longScale} is casted to the + * type {@code int}. + * + * @param doubleScale the scale to which the value 0 will be scaled. + * @return the value 0 scaled by the closer scale of type {@code int}. + * @see #scale + */ + private static BigDecimal zeroScaledBy(double doubleScale) { + if (doubleScale == (int) doubleScale) { + return valueOf(0, (int) doubleScale); + } + if (doubleScale >= 0) { + return new BigDecimal(0, Integer.MAX_VALUE); + } + return new BigDecimal(0, Integer.MIN_VALUE); + } + + private transient int bitLength; + + /** + * Cache for the hash code. + */ + private transient int hashCode; + + /** + * The arbitrary precision integer (unscaled value) in the internal + * representation of {@code BigDecimal}. + */ + private BigInteger intVal; + + /** + * Represent the number of decimal digits in the unscaled value. This + * precision is calculated the first time, and used in the following calls of + * method precision(). Note that some call to the private method + * inplaceRound() could update this field. + * + * @see #precision() + * @see #inplaceRound(MathContext) + */ + private transient int precision; + + private double scale; + + /** + * The unscaled integer value (stored in a double) if the number of bits is + * less than {@link #SMALL_VALUE_BITS}. + */ + private transient double smallValue; + + /** + * The String representation is cached. + */ + private transient String toStringImage; + + /** + * Constructs a new {@code BigDecimal} instance from the given big integer + * {@code val}. The scale of the result is {@code 0}. + * + * @param val {@code BigInteger} value to be converted to a {@code BigDecimal} + * instance. + */ + public BigDecimal(BigInteger val) { + this(val, 0); + } + + /** + * Constructs a new {@code BigDecimal} instance from a given unscaled value + * {@code unscaledVal} and a given scale. The value of this instance is + * {@code unscaledVal} 10^(-{@code scale}). + * + * @param unscaledVal {@code BigInteger} representing the unscaled value of + * this {@code BigDecimal} instance. + * @param scale scale of this {@code BigDecimal} instance. + * @throws NullPointerException if {@code unscaledVal == null}. + */ + public BigDecimal(BigInteger unscaledVal, int scale) { + if (unscaledVal == null) { + throw new NullPointerException(); + } + this.scale = scale; + setUnscaledValue(unscaledVal); + } + + /** + * Constructs a new {@code BigDecimal} instance from a given unscaled value + * {@code unscaledVal} and a given scale. The value of this instance is + * {@code unscaledVal} 10^(-{@code scale}). The result is rounded according to + * the specified math context. + * + * @param unscaledVal {@code BigInteger} representing the unscaled value of + * this {@code BigDecimal} instance. + * @param scale scale of this {@code BigDecimal} instance. + * @param mc rounding mode and precision for the result of this operation. + * @throws ArithmeticException if {@code mc.precision > 0} and {@code + * mc.roundingMode == UNNECESSARY} and the new big decimal cannot be + * represented within the given precision without rounding. + * @throws NullPointerException if {@code unscaledVal == null}. + */ + public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) { + this(unscaledVal, scale); + inplaceRound(mc); + } + + /** + * Constructs a new {@code BigDecimal} instance from the given big integer + * {@code val}. The scale of the result is {@code 0}. + * + * @param val {@code BigInteger} value to be converted to a {@code BigDecimal} + * instance. + * @param mc rounding mode and precision for the result of this operation. + * @throws ArithmeticException if {@code mc.precision > 0} and {@code + * mc.roundingMode == UNNECESSARY} and the new big decimal cannot be + * represented within the given precision without rounding. + */ + public BigDecimal(BigInteger val, MathContext mc) { + this(val); + inplaceRound(mc); + } + + /** + * Constructs a new {@code BigDecimal} instance from a string representation + * given as a character array. + * + * @param in array of characters containing the string representation of this + * {@code BigDecimal}. + * @throws NullPointerException if {@code in == null}. + * @throws NumberFormatException if {@code in} does not contain a valid string + * representation of a big decimal. + */ + public BigDecimal(char[] in) { + this(in, 0, in.length); + } + + /** + * Constructs a new {@code BigDecimal} instance from a string representation + * given as a character array. + * + * @param in array of characters containing the string representation of this + * {@code BigDecimal}. + * @param offset first index to be copied. + * @param len number of characters to be used. + * @throws NullPointerException if {@code in == null}. + * @throws NumberFormatException if {@code offset < 0} or {@code len <= 0} or + * {@code offset+len-1 < 0} or {@code offset+len-1 >= in.length}. + * @throws NumberFormatException if in does not contain a valid string + * representation of a big decimal. + */ + public BigDecimal(char[] in, int offset, int len) { + try { + initFrom(new String(in, offset, len)); + } catch (StringIndexOutOfBoundsException e) { + throw new NumberFormatException(e.getMessage()); + } + } + + /** + * Constructs a new {@code BigDecimal} instance from a string representation + * given as a character array. + * + * @param in array of characters containing the string representation of this + * {@code BigDecimal}. + * @param offset first index to be copied. + * @param len number of characters to be used. + * @param mc rounding mode and precision for the result of this operation. + * @throws NullPointerException if {@code in == null}. + * @throws NumberFormatException if {@code offset < 0} or {@code len <= 0} or + * {@code offset+len-1 < 0} or {@code offset+len-1 >= in.length}. + * @throws NumberFormatException if {@code in} does not contain a valid string + * representation of a big decimal. + * @throws ArithmeticException if {@code mc.precision > 0} and {@code + * mc.roundingMode == UNNECESSARY} and the new big decimal cannot be + * represented within the given precision without rounding. + */ + public BigDecimal(char[] in, int offset, int len, MathContext mc) { + this(in, offset, len); + inplaceRound(mc); + } + + /** + * Constructs a new {@code BigDecimal} instance from a string representation + * given as a character array. The result is rounded according to the + * specified math context. + * + * @param in array of characters containing the string representation of this + * {@code BigDecimal}. + * @param mc rounding mode and precision for the result of this operation. + * @throws NullPointerException if {@code in == null}. + * @throws NumberFormatException if {@code in} does not contain a valid string + * representation of a big decimal. + * @throws ArithmeticException if {@code mc.precision > 0} and {@code + * mc.roundingMode == UNNECESSARY} and the new big decimal cannot be + * represented within the given precision without rounding. + */ + public BigDecimal(char[] in, MathContext mc) { + this(in, 0, in.length); + inplaceRound(mc); + } + + /** + * Constructs a new {@code BigDecimal} instance from the given double {@code + * val}. The scale of the result is 0. + * + * @param val double value to be converted to a {@code BigDecimal} instance. + * @throws NumberFormatException if {@code val} is infinite or a NaN + */ + public BigDecimal(double val) { + if (Double.isInfinite(val) || Double.isNaN(val)) { + // math.03=Infinity or NaN + throw new NumberFormatException("Infinite or NaN"); //$NON-NLS-1$ + } + initFrom(toPrecision(val, 20)); + } + + /** + * Constructs a new {@code BigDecimal} instance from the given double {@code + * val}. The scale of the result is 0. The result is rounded according to the + * specified math context. + * + * @param val double value to be converted to a {@code BigDecimal} instance. + * @param mc rounding mode and precision for the result of this operation. + * @throws NumberFormatException if {@code val} is infinite or a NaN + * @throws ArithmeticException if {@code mc.precision > 0} and {@code + * mc.roundingMode == UNNECESSARY} and the new big decimal cannot be + * represented within the given precision without rounding. + */ + public BigDecimal(double val, MathContext mc) { + if (Double.isInfinite(val) || Double.isNaN(val)) { + // math.03=Infinity or NaN + throw new NumberFormatException("Infinite or NaN"); //$NON-NLS-1$ + } + initFrom(toPrecision(val, 20)); + inplaceRound(mc); + } + + /** + * Constructs a new {@code BigDecimal} instance from the given int {@code val} + * . The scale of the result is 0. + * + * @param val int value to be converted to a {@code BigDecimal} instance. + */ + public BigDecimal(int val) { + this(val, 0); + } + + /** + * Constructs a new {@code BigDecimal} instance from the given int {@code val} + * . The scale of the result is {@code 0}. The result is rounded according to + * the specified math context. + * + * @param val int value to be converted to a {@code BigDecimal} instance. + * @param mc rounding mode and precision for the result of this operation. + * @throws ArithmeticException if {@code mc.precision > 0} and {@code + * c.roundingMode == UNNECESSARY} and the new big decimal cannot be + * represented within the given precision without rounding. + */ + public BigDecimal(int val, MathContext mc) { + this(val, 0); + inplaceRound(mc); + } + + /** + * Constructs a new {@code BigDecimal} instance from the given long {@code + * val}. The scale of the result is {@code 0}. + * + * @param val long value to be converted to a {@code BigDecimal} instance. + */ + public BigDecimal(long val) { + this(val, 0); + } + + /** + * Constructs a new {@code BigDecimal} instance from the given long {@code + * val}. The scale of the result is {@code 0}. The result is rounded according + * to the specified math context. + * + * @param val long value to be converted to a {@code BigDecimal} instance. + * @param mc rounding mode and precision for the result of this operation. + * @throws ArithmeticException if {@code mc.precision > 0} and {@code + * mc.roundingMode == UNNECESSARY} and the new big decimal cannot be + * represented within the given precision without rounding. + */ + public BigDecimal(long val, MathContext mc) { + this(val); + inplaceRound(mc); + } + + /** + * Constructs a new {@code BigDecimal} instance from a string representation. + * + * @param val string containing the string representation of this {@code + * BigDecimal}. + * @throws NumberFormatException if {@code val} does not contain a valid + * string representation of a big decimal. + */ + public BigDecimal(String val) { + initFrom(val); + } + + /** + * Constructs a new {@code BigDecimal} instance from a string representation. + * The result is rounded according to the specified math context. + * + * @param val string containing the string representation of this {@code + * BigDecimal}. + * @param mc rounding mode and precision for the result of this operation. + * @throws NumberFormatException if {@code val} does not contain a valid + * string representation of a big decimal. + * @throws ArithmeticException if {@code mc.precision > 0} and {@code + * mc.roundingMode == UNNECESSARY} and the new big decimal cannot be + * represented within the given precision without rounding. + */ + public BigDecimal(String val, MathContext mc) { + this(val.toCharArray(), 0, val.length()); + inplaceRound(mc); + } + + private BigDecimal(BigInteger unscaledVal, double scale) { + if (unscaledVal == null) { + throw new NullPointerException(); + } + this.scale = scale; + setUnscaledValue(unscaledVal); + } + + private BigDecimal(double smallValue, double scale) { + this.smallValue = smallValue; + this.scale = scale; + this.bitLength = bitLength(smallValue); + } + + private BigDecimal(long smallValue, int scale) { + this.scale = scale; + this.bitLength = bitLength(smallValue); + if (bitLength < SMALL_VALUE_BITS) { + this.smallValue = smallValue; + } else { + this.intVal = BigInteger.valueOf(smallValue); + } + } + + /** + * Returns a new {@code BigDecimal} whose value is the absolute value of + * {@code this}. The scale of the result is the same as the scale of this. + * + * @return {@code abs(this)} + */ + public BigDecimal abs() { + return ((signum() < 0) ? negate() : this); + } + + /** + * Returns a new {@code BigDecimal} whose value is the absolute value of + * {@code this}. The result is rounded according to the passed context {@code + * mc}. + * + * @param mc rounding mode and precision for the result of this operation. + * @return {@code abs(this)} + */ + public BigDecimal abs(MathContext mc) { + return round(mc).abs(); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this + augend}. The + * scale of the result is the maximum of the scales of the two arguments. + * + * @param augend value to be added to {@code this}. + * @return {@code this + augend}. + * @throws NullPointerException if {@code augend == null}. + */ + public BigDecimal add(BigDecimal augend) { + double diffScale = this.scale - augend.scale; + // Fast return when some operand is zero + if (this.isZero()) { + if (diffScale <= 0) { + return augend; + } + if (augend.isZero()) { + return this; + } + } else if (augend.isZero()) { + if (diffScale >= 0) { + return this; + } + } + // Let be: this = [u1,s1] and augend = [u2,s2] + if (diffScale == 0) { + // case s1 == s2: [u1 + u2 , s1] + if (Math.max(this.bitLength, augend.bitLength) + 1 < SMALL_VALUE_BITS) { + return valueOf(this.smallValue + augend.smallValue, this.scale); + } + return new BigDecimal(this.getUnscaledValue().add( + augend.getUnscaledValue()), this.scale); + } else if (diffScale > 0) { + // case s1 > s2 : [(u1 + u2) * 10 ^ (s1 - s2) , s1] + return addAndMult10(this, augend, diffScale); + } else { + // case s2 > s1 : [(u2 + u1) * 10 ^ (s2 - s1) , s2] + return addAndMult10(augend, this, -diffScale); + } + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this + augend}. The + * result is rounded according to the passed context {@code mc}. + * + * @param augend value to be added to {@code this}. + * @param mc rounding mode and precision for the result of this operation. + * @return {@code this + augend}. + * @throws NullPointerException if {@code augend == null} or {@code mc == + * null}. + */ + public BigDecimal add(BigDecimal augend, MathContext mc) { + BigDecimal larger; // operand with the largest unscaled value + BigDecimal smaller; // operand with the smallest unscaled value + BigInteger tempBI; + double diffScale = this.scale - augend.scale; + int largerSignum; + // Some operand is zero or the precision is infinity + if ((augend.isZero()) || (this.isZero()) || (mc.getPrecision() == 0)) { + return add(augend).round(mc); + } + // Cases where there is room for optimizations + if (this.approxPrecision() < diffScale - 1) { + larger = augend; + smaller = this; + } else if (augend.approxPrecision() < -diffScale - 1) { + larger = this; + smaller = augend; + } else { + // No optimization is done + return add(augend).round(mc); + } + if (mc.getPrecision() >= larger.approxPrecision()) { + // No optimization is done + return add(augend).round(mc); + } + // Cases where it's unnecessary to add two numbers with very different + // scales + largerSignum = larger.signum(); + if (largerSignum == smaller.signum()) { + tempBI = Multiplication.multiplyByPositiveInt(larger.getUnscaledValue(), + 10).add(BigInteger.valueOf(largerSignum)); + } else { + tempBI = larger.getUnscaledValue().subtract( + BigInteger.valueOf(largerSignum)); + tempBI = Multiplication.multiplyByPositiveInt(tempBI, 10).add( + BigInteger.valueOf(largerSignum * 9)); + } + // Rounding the improved adding + larger = new BigDecimal(tempBI, larger.scale + 1); + return larger.round(mc); + } + + /** + * Returns this {@code BigDecimal} as a byte value if it has no fractional + * part and if its value fits to the byte range ([-128..127]). If these + * conditions are not met, an {@code ArithmeticException} is thrown. + * + * @return this {@code BigDecimal} as a byte value. + * @throws ArithmeticException if rounding is necessary or the number doesn't + * fit in a byte. + */ + public byte byteValueExact() { + return (byte) valueExact(8); + } + + /** + * Compares this {@code BigDecimal} with {@code val}. Returns one of the three + * values {@code 1}, {@code 0}, or {@code -1}. The method behaves as if + * {@code this.subtract(val)} is computed. If this difference is > 0 then 1 is + * returned, if the difference is < 0 then -1 is returned, and if the + * difference is 0 then 0 is returned. This means, that if two decimal + * instances are compared which are equal in value but differ in scale, then + * these two instances are considered as equal. + * + * @param val value to be compared with {@code this}. + * @return {@code 1} if {@code this > val}, {@code -1} if {@code this < val}, + * {@code 0} if {@code this == val}. + * @throws NullPointerException if {@code val == null}. + */ + public int compareTo(BigDecimal val) { + int thisSign = signum(); + int valueSign = val.signum(); + + if (thisSign == valueSign) { + if (this.scale == val.scale && this.bitLength < SMALL_VALUE_BITS + && val.bitLength < SMALL_VALUE_BITS) { + return (smallValue < val.smallValue) ? -1 + : (smallValue > val.smallValue) ? 1 : 0; + } + double diffScale = this.scale - val.scale; + double diffPrecision = this.approxPrecision() - val.approxPrecision(); + if (diffPrecision > diffScale + 1) { + return thisSign; + } else if (diffPrecision < diffScale - 1) { + return -thisSign; + } else { + // thisSign == val.signum() and diffPrecision is aprox. diffScale + BigInteger thisUnscaled = this.getUnscaledValue(); + BigInteger valUnscaled = val.getUnscaledValue(); + // If any of both precision is bigger, append zeros to the shorter one + if (diffScale < 0) { + thisUnscaled = thisUnscaled.multiply(Multiplication.powerOf10(-diffScale)); + } else if (diffScale > 0) { + valUnscaled = valUnscaled.multiply(Multiplication.powerOf10(diffScale)); + } + return thisUnscaled.compareTo(valUnscaled); + } + } else if (thisSign < valueSign) { + return -1; + } else { + return 1; + } + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. The + * scale of the result is the difference of the scales of {@code this} and + * {@code divisor}. If the exact result requires more digits, then the scale + * is adjusted accordingly. For example, {@code 1/128 = 0.0078125} which has a + * scale of {@code 7} and precision {@code 5}. + * + * @param divisor value by which {@code this} is divided. + * @return {@code this / divisor}. + * @throws NullPointerException if {@code divisor == null}. + * @throws ArithmeticException if {@code divisor == 0}. + * @throws ArithmeticException if the result cannot be represented exactly. + */ + public BigDecimal divide(BigDecimal divisor) { + BigInteger p = this.getUnscaledValue(); + BigInteger q = divisor.getUnscaledValue(); + BigInteger gcd; // greatest common divisor between 'p' and 'q' + BigInteger quotAndRem[]; + double diffScale = scale - divisor.scale; + int newScale; // the new scale for final quotient + int k; // number of factors "2" in 'q' + int l = 0; // number of factors "5" in 'q' + int i = 1; + int lastPow = FIVE_POW.length - 1; + + if (divisor.isZero()) { + // math.04=Division by zero + throw new ArithmeticException("Division by zero"); //$NON-NLS-1$ + } + if (p.signum() == 0) { + return zeroScaledBy(diffScale); + } + // To divide both by the GCD + gcd = p.gcd(q); + p = p.divide(gcd); + q = q.divide(gcd); + // To simplify all "2" factors of q, dividing by 2^k + k = q.getLowestSetBit(); + q = q.shiftRight(k); + // To simplify all "5" factors of q, dividing by 5^l + do { + quotAndRem = q.divideAndRemainder(FIVE_POW[i]); + if (quotAndRem[1].signum() == 0) { + l += i; + if (i < lastPow) { + i++; + } + q = quotAndRem[0]; + } else { + if (i == 1) { + break; + } + i = 1; + } + } while (true); + // If abs(q) != 1 then the quotient is periodic + if (!q.abs().equals(BigInteger.ONE)) { + // math.05=Non-terminating decimal expansion; no exact representable + // decimal result. + throw new ArithmeticException( + "Non-terminating decimal expansion; no exact representable decimal result"); //$NON-NLS-1$ + } + // The sign of the is fixed and the quotient will be saved in 'p' + if (q.signum() < 0) { + p = p.negate(); + } + // Checking if the new scale is out of range + newScale = toIntScale(diffScale + Math.max(k, l)); + // k >= 0 and l >= 0 implies that k - l is in the 32-bit range + i = k - l; + + p = (i > 0) ? Multiplication.multiplyByFivePow(p, i) : p.shiftLeft(-i); + return new BigDecimal(p, newScale); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. The + * scale of the result is the scale of {@code this}. If rounding is required + * to meet the specified scale, then the specified rounding mode {@code + * roundingMode} is applied. + * + * @param divisor value by which {@code this} is divided. + * @param roundingMode rounding mode to be used to round the result. + * @return {@code this / divisor} rounded according to the given rounding + * mode. + * @throws NullPointerException if {@code divisor == null}. + * @throws IllegalArgumentException if {@code roundingMode} is not a valid + * rounding mode. + * @throws ArithmeticException if {@code divisor == 0}. + * @throws ArithmeticException if {@code roundingMode == ROUND_UNNECESSARY} + * and rounding is necessary according to the scale of this. + */ + public BigDecimal divide(BigDecimal divisor, int roundingMode) { + return divide(divisor, (int) scale, RoundingMode.valueOf(roundingMode)); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. As + * scale of the result the parameter {@code scale} is used. If rounding is + * required to meet the specified scale, then the specified rounding mode + * {@code roundingMode} is applied. + * + * @param divisor value by which {@code this} is divided. + * @param scale the scale of the result returned. + * @param roundingMode rounding mode to be used to round the result. + * @return {@code this / divisor} rounded according to the given rounding + * mode. + * @throws NullPointerException if {@code divisor == null}. + * @throws IllegalArgumentException if {@code roundingMode} is not a valid + * rounding mode. + * @throws ArithmeticException if {@code divisor == 0}. + * @throws ArithmeticException if {@code roundingMode == ROUND_UNNECESSARY} + * and rounding is necessary according to the given scale. + */ + public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) { + return divide(divisor, scale, RoundingMode.valueOf(roundingMode)); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. As + * scale of the result the parameter {@code scale} is used. If rounding is + * required to meet the specified scale, then the specified rounding mode + * {@code roundingMode} is applied. + * + * @param divisor value by which {@code this} is divided. + * @param scale the scale of the result returned. + * @param roundingMode rounding mode to be used to round the result. + * @return {@code this / divisor} rounded according to the given rounding + * mode. + * @throws NullPointerException if {@code divisor == null} or {@code + * roundingMode == null}. + * @throws ArithmeticException if {@code divisor == 0}. + * @throws ArithmeticException if {@code roundingMode == + * RoundingMode.UNNECESSAR}Y and rounding is necessary according to + * the given scale and given precision. + */ + public BigDecimal divide(BigDecimal divisor, int scale, + RoundingMode roundingMode) { + // Let be: this = [u1,s1] and divisor = [u2,s2] + if (roundingMode == null) { + throw new NullPointerException(); + } + if (divisor.isZero()) { + // math.04=Division by zero + throw new ArithmeticException("Division by zero"); //$NON-NLS-1$ + } + + double diffScale = this.scale - divisor.scale - scale; + if (this.bitLength < SMALL_VALUE_BITS + && divisor.bitLength < SMALL_VALUE_BITS) { + if (diffScale == 0) { + return dividePrimitiveDoubles(this.smallValue, divisor.smallValue, + scale, roundingMode); + } else if (diffScale > 0) { + if (diffScale < DOUBLE_TEN_POW.length + && divisor.bitLength + DOUBLE_TEN_POW_BIT_LENGTH[ + (int) diffScale] < SMALL_VALUE_BITS) { + return dividePrimitiveDoubles(this.smallValue, divisor.smallValue + * DOUBLE_TEN_POW[(int) diffScale], scale, roundingMode); + } + } else { // diffScale < 0 + if (-diffScale < DOUBLE_TEN_POW.length + && this.bitLength + DOUBLE_TEN_POW_BIT_LENGTH[(int) -diffScale] + < SMALL_VALUE_BITS) { + return dividePrimitiveDoubles(this.smallValue + * DOUBLE_TEN_POW[(int) -diffScale], divisor.smallValue, scale, + roundingMode); + } + } + } + + BigInteger scaledDividend = this.getUnscaledValue(); + BigInteger scaledDivisor = divisor.getUnscaledValue(); // for scaling of + // 'u2' + + if (diffScale > 0) { + // Multiply 'u2' by: 10^((s1 - s2) - scale) + scaledDivisor = Multiplication.multiplyByTenPow(scaledDivisor, + (int) diffScale); + } else if (diffScale < 0) { + // Multiply 'u1' by: 10^(scale - (s1 - s2)) + scaledDividend = Multiplication.multiplyByTenPow(scaledDividend, + (int) -diffScale); + } + return divideBigIntegers(scaledDividend, scaledDivisor, scale, roundingMode); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. The + * result is rounded according to the passed context {@code mc}. If the passed + * math context specifies precision {@code 0}, then this call is equivalent to + * {@code this.divide(divisor)}. + * + * @param divisor value by which {@code this} is divided. + * @param mc rounding mode and precision for the result of this operation. + * @return {@code this / divisor}. + * @throws NullPointerException if {@code divisor == null} or {@code mc == + * null}. + * @throws ArithmeticException if {@code divisor == 0}. + * @throws ArithmeticException if {@code mc.getRoundingMode() == UNNECESSARY} + * and rounding is necessary according {@code mc.getPrecision()}. + */ + public BigDecimal divide(BigDecimal divisor, MathContext mc) { + /* + * Calculating how many zeros must be append to 'dividend' to obtain a + * quotient with at least 'mc.precision()' digits + */ + double traillingZeros = mc.getPrecision() + 2L + divisor.approxPrecision() + - approxPrecision(); + double diffScale = scale - divisor.scale; + double newScale = diffScale; // scale of the final quotient + int compRem; // to compare the remainder + int i = 1; // index + int lastPow = TEN_POW.length - 1; // last power of ten + BigInteger integerQuot; // for temporal results + BigInteger quotAndRem[] = {getUnscaledValue()}; + // In special cases it reduces the problem to call the dual method + if ((mc.getPrecision() == 0) || (this.isZero()) || (divisor.isZero())) { + return this.divide(divisor); + } + if (traillingZeros > 0) { + // To append trailing zeros at end of dividend + quotAndRem[0] = getUnscaledValue().multiply( + Multiplication.powerOf10(traillingZeros)); + newScale += traillingZeros; + } + quotAndRem = quotAndRem[0].divideAndRemainder(divisor.getUnscaledValue()); + integerQuot = quotAndRem[0]; + // Calculating the exact quotient with at least 'mc.precision()' digits + if (quotAndRem[1].signum() != 0) { + // Checking if: 2 * remainder >= divisor ? + compRem = quotAndRem[1].shiftLeftOneBit().compareTo( + divisor.getUnscaledValue()); + // quot := quot * 10 + r; with 'r' in {-6,-5,-4, 0,+4,+5,+6} + integerQuot = integerQuot.multiply(BigInteger.TEN).add( + BigInteger.valueOf(quotAndRem[0].signum() * (5 + compRem))); + newScale++; + } else { + // To strip trailing zeros until the preferred scale is reached + while (!integerQuot.testBit(0)) { + quotAndRem = integerQuot.divideAndRemainder(TEN_POW[i]); + if ((quotAndRem[1].signum() == 0) && (newScale - i >= diffScale)) { + newScale -= i; + if (i < lastPow) { + i++; + } + integerQuot = quotAndRem[0]; + } else { + if (i == 1) { + break; + } + i = 1; + } + } + } + // To perform rounding + return new BigDecimal(integerQuot, toIntScale(newScale), mc); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this / divisor}. The + * scale of the result is the scale of {@code this}. If rounding is required + * to meet the specified scale, then the specified rounding mode {@code + * roundingMode} is applied. + * + * @param divisor value by which {@code this} is divided. + * @param roundingMode rounding mode to be used to round the result. + * @return {@code this / divisor} rounded according to the given rounding + * mode. + * @throws NullPointerException if {@code divisor == null} or {@code + * roundingMode == null}. + * @throws ArithmeticException if {@code divisor == 0}. + * @throws ArithmeticException if {@code roundingMode == + * RoundingMode.UNNECESSARY} and rounding is necessary according to + * the scale of this. + */ + public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) { + return divide(divisor, (int) scale, roundingMode); + } + + /** + * Returns a {@code BigDecimal} array which contains the integral part of + * {@code this / divisor} at index 0 and the remainder {@code this % divisor} + * at index 1. The quotient is rounded down towards zero to the next integer. + * + * @param divisor value by which {@code this} is divided. + * @return {@code [this.divideToIntegralValue(divisor), + * this.remainder(divisor)]}. + * @throws NullPointerException if {@code divisor == null}. + * @throws ArithmeticException if {@code divisor == 0}. + * @see #divideToIntegralValue + * @see #remainder + */ + public BigDecimal[] divideAndRemainder(BigDecimal divisor) { + BigDecimal quotAndRem[] = new BigDecimal[2]; + + quotAndRem[0] = this.divideToIntegralValue(divisor); + quotAndRem[1] = this.subtract(quotAndRem[0].multiply(divisor)); + return quotAndRem; + } + + /** + * Returns a {@code BigDecimal} array which contains the integral part of + * {@code this / divisor} at index 0 and the remainder {@code this % divisor} + * at index 1. The quotient is rounded down towards zero to the next integer. + * The rounding mode passed with the parameter {@code mc} is not considered. + * But if the precision of {@code mc > 0} and the integral part requires more + * digits, then an {@code ArithmeticException} is thrown. + * + * @param divisor value by which {@code this} is divided. + * @param mc math context which determines the maximal precision of the + * result. + * @return {@code [this.divideToIntegralValue(divisor), + * this.remainder(divisor)]}. + * @throws NullPointerException if {@code divisor == null}. + * @throws ArithmeticException if {@code divisor == 0}. + * @see #divideToIntegralValue + * @see #remainder + */ + public BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc) { + BigDecimal quotAndRem[] = new BigDecimal[2]; + + quotAndRem[0] = this.divideToIntegralValue(divisor, mc); + quotAndRem[1] = this.subtract(quotAndRem[0].multiply(divisor)); + return quotAndRem; + } + + /** + * Returns a new {@code BigDecimal} whose value is the integral part of + * {@code this / divisor}. The quotient is rounded down towards zero to the + * next integer. For example, {@code 0.5/0.2 = 2}. + * + * @param divisor value by which {@code this} is divided. + * @return integral part of {@code this / divisor}. + * @throws NullPointerException if {@code divisor == null}. + * @throws ArithmeticException if {@code divisor == 0}. + */ + public BigDecimal divideToIntegralValue(BigDecimal divisor) { + BigInteger integralValue; // the integer of result + BigInteger powerOfTen; // some power of ten + BigInteger quotAndRem[] = {getUnscaledValue()}; + double newScale = this.scale - divisor.scale; + double tempScale = 0; + int i = 1; + int lastPow = TEN_POW.length - 1; + + if (divisor.isZero()) { + // math.04=Division by zero + throw new ArithmeticException("Division by zero"); //$NON-NLS-1$ + } + if ((divisor.approxPrecision() + newScale > this.approxPrecision() + 1L) + || (this.isZero())) { + /* + * If the divisor's integer part is greater than this's integer part, the + * result must be zero with the appropriate scale + */ + integralValue = BigInteger.ZERO; + } else if (newScale == 0) { + integralValue = getUnscaledValue().divide(divisor.getUnscaledValue()); + } else if (newScale > 0) { + powerOfTen = Multiplication.powerOf10(newScale); + integralValue = getUnscaledValue().divide( + divisor.getUnscaledValue().multiply(powerOfTen)); + integralValue = integralValue.multiply(powerOfTen); + } else { + // (newScale < 0) + powerOfTen = Multiplication.powerOf10(-newScale); + integralValue = getUnscaledValue().multiply(powerOfTen).divide( + divisor.getUnscaledValue()); + // To strip trailing zeros approximating to the preferred scale + while (!integralValue.testBit(0)) { + quotAndRem = integralValue.divideAndRemainder(TEN_POW[i]); + if ((quotAndRem[1].signum() == 0) && (tempScale - i >= newScale)) { + tempScale -= i; + if (i < lastPow) { + i++; + } + integralValue = quotAndRem[0]; + } else { + if (i == 1) { + break; + } + i = 1; + } + } + newScale = tempScale; + } + return ((integralValue.signum() == 0) ? zeroScaledBy(newScale) + : new BigDecimal(integralValue, toIntScale(newScale))); + } + + /** + * Returns a new {@code BigDecimal} whose value is the integral part of + * {@code this / divisor}. The quotient is rounded down towards zero to the + * next integer. The rounding mode passed with the parameter {@code mc} is not + * considered. But if the precision of {@code mc > 0} and the integral part + * requires more digits, then an {@code ArithmeticException} is thrown. + * + * @param divisor value by which {@code this} is divided. + * @param mc math context which determines the maximal precision of the + * result. + * @return integral part of {@code this / divisor}. + * @throws NullPointerException if {@code divisor == null} or {@code mc == + * null}. + * @throws ArithmeticException if {@code divisor == 0}. + * @throws ArithmeticException if {@code mc.getPrecision() > 0} and the result + * requires more digits to be represented. + */ + public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) { + int mcPrecision = mc.getPrecision(); + int diffPrecision = this.precision() - divisor.precision(); + int lastPow = TEN_POW.length - 1; + double diffScale = this.scale - divisor.scale; + double newScale = diffScale; + double quotPrecision = diffPrecision - diffScale + 1; + BigInteger quotAndRem[] = new BigInteger[2]; + // In special cases it call the dual method + if ((mcPrecision == 0) || (this.isZero()) || (divisor.isZero())) { + return this.divideToIntegralValue(divisor); + } + // Let be: this = [u1,s1] and divisor = [u2,s2] + if (quotPrecision <= 0) { + quotAndRem[0] = BigInteger.ZERO; + } else if (diffScale == 0) { + // CASE s1 == s2: to calculate u1 / u2 + quotAndRem[0] = this.getUnscaledValue().divide(divisor.getUnscaledValue()); + } else if (diffScale > 0) { + // CASE s1 >= s2: to calculate u1 / (u2 * 10^(s1-s2) + quotAndRem[0] = this.getUnscaledValue().divide( + divisor.getUnscaledValue().multiply( + Multiplication.powerOf10(diffScale))); + // To chose 10^newScale to get a quotient with at least 'mc.precision()' + // digits + newScale = Math.min(diffScale, Math.max(mcPrecision - quotPrecision + 1, + 0)); + // To calculate: (u1 / (u2 * 10^(s1-s2)) * 10^newScale + quotAndRem[0] = quotAndRem[0].multiply(Multiplication.powerOf10(newScale)); + } else { + // CASE s2 > s1: + /* + * To calculate the minimum power of ten, such that the quotient (u1 * + * 10^exp) / u2 has at least 'mc.precision()' digits. + */ + double exp = Math.min(-diffScale, Math.max((double) mcPrecision + - diffPrecision, 0)); + double compRemDiv; + // Let be: (u1 * 10^exp) / u2 = [q,r] + quotAndRem = this.getUnscaledValue().multiply( + Multiplication.powerOf10(exp)).divideAndRemainder( + divisor.getUnscaledValue()); + newScale += exp; // To fix the scale + exp = -newScale; // The remaining power of ten + // If after division there is a remainder... + if ((quotAndRem[1].signum() != 0) && (exp > 0)) { + // Log10(r) + ((s2 - s1) - exp) > mc.precision ? + compRemDiv = (new BigDecimal(quotAndRem[1])).precision() + exp + - divisor.precision(); + if (compRemDiv == 0) { + // To calculate: (r * 10^exp2) / u2 + quotAndRem[1] = quotAndRem[1].multiply(Multiplication.powerOf10(exp)).divide( + divisor.getUnscaledValue()); + compRemDiv = Math.abs(quotAndRem[1].signum()); + } + if (compRemDiv > 0) { + // The quotient won't fit in 'mc.precision()' digits + // math.06=Division impossible + throw new ArithmeticException("Division impossible"); //$NON-NLS-1$ + } + } + } + // Fast return if the quotient is zero + if (quotAndRem[0].signum() == 0) { + return zeroScaledBy(diffScale); + } + BigInteger strippedBI = quotAndRem[0]; + BigDecimal integralValue = new BigDecimal(quotAndRem[0]); + int resultPrecision = integralValue.precision(); + int i = 1; + // To strip trailing zeros until the specified precision is reached + while (!strippedBI.testBit(0)) { + quotAndRem = strippedBI.divideAndRemainder(TEN_POW[i]); + if ((quotAndRem[1].signum() == 0) + && ((resultPrecision - i >= mcPrecision) || (newScale - i >= diffScale))) { + resultPrecision -= i; + newScale -= i; + if (i < lastPow) { + i++; + } + strippedBI = quotAndRem[0]; + } else { + if (i == 1) { + break; + } + i = 1; + } + } + // To check if the result fit in 'mc.precision()' digits + if (resultPrecision > mcPrecision) { + // math.06=Division impossible + throw new ArithmeticException("Division impossible"); //$NON-NLS-1$ + } + integralValue.scale = toIntScale(newScale); + integralValue.setUnscaledValue(strippedBI); + return integralValue; + } + + /** + * Returns this {@code BigDecimal} as a double value. If {@code this} is too + * big to be represented as an float, then {@code Double.POSITIVE_INFINITY} or + * {@code Double.NEGATIVE_INFINITY} is returned. + *

+ * Note, that if the unscaled value has more than 53 significant digits, then + * this decimal cannot be represented exactly in a double variable. In this + * case the result is rounded. + *

+ * For example, if the instance {@code x1 = new BigDecimal("0.1")} cannot be + * represented exactly as a double, and thus {@code x1.equals(new + * BigDecimal(x1.doubleValue())} returns {@code false} for this case. + *

+ * Similarly, if the instance {@code new BigDecimal(9007199254740993L)} is + * converted to a double, the result is {@code 9.007199254740992E15}. + *

+ * + * @return this {@code BigDecimal} as a double value. + */ + @Override + public double doubleValue() { + return Double.parseDouble(this.toString()); + } + + /** + * Returns {@code true} if {@code x} is a {@code BigDecimal} instance and if + * this instance is equal to this big decimal. Two big decimals are equal if + * their unscaled value and their scale is equal. For example, 1.0 + * (10*10^(-1)) is not equal to 1.00 (100*10^(-2)). Similarly, zero instances + * are not equal if their scale differs. + * + * @param x object to be compared with {@code this}. + * @return true if {@code x} is a {@code BigDecimal} and {@code this == x}. + */ + @Override + public boolean equals(Object x) { + if (this == x) { + return true; + } + if (x instanceof BigDecimal) { + BigDecimal x1 = (BigDecimal) x; + return x1.scale == scale + && (bitLength < SMALL_VALUE_BITS ? (x1.smallValue == smallValue) + : intVal.equals(x1.intVal)); + } + return false; + } + + /** + * Returns this {@code BigDecimal} as a float value. If {@code this} is too + * big to be represented as an float, then {@code Float.POSITIVE_INFINITY} or + * {@code Float.NEGATIVE_INFINITY} is returned. + *

+ * Note, that if the unscaled value has more than 24 significant digits, then + * this decimal cannot be represented exactly in a float variable. In this + * case the result is rounded. + *

+ * For example, if the instance {@code x1 = new BigDecimal("0.1")} cannot be + * represented exactly as a float, and thus {@code x1.equals(new + * BigDecimal(x1.folatValue())} returns {@code false} for this case. + *

+ * Similarly, if the instance {@code new BigDecimal(16777217)} is converted to + * a float, the result is {@code 1.6777216E}7. + * + * @return this {@code BigDecimal} as a float value. + */ + @Override + public float floatValue() { + /* + * A similar code like in doubleValue() could be repeated here, but this + * simple implementation is quite efficient. + */ + float floatResult = signum(); + double powerOfTwo = this.bitLength - (scale / LOG10_2); + if ((powerOfTwo < -149) || (floatResult == 0.0f)) { + // Cases which 'this' is very small + floatResult *= 0.0f; + } else if (powerOfTwo > 129) { + // Cases which 'this' is very large + floatResult *= Float.POSITIVE_INFINITY; + } else { + floatResult = (float) doubleValue(); + } + return floatResult; + } + + /** + * Returns a hash code for this {@code BigDecimal}. + * + * @return hash code for {@code this}. + */ + @Override + public int hashCode() { + if (hashCode != 0) { + return hashCode; + } + if (bitLength < SMALL_VALUE_BITS) { + long longValue = (long) smallValue; + hashCode = (int) (longValue & 0xffffffff); + hashCode = 33 * hashCode + (int) ((longValue >> 32) & 0xffffffff); + hashCode = 17 * hashCode + (int) scale; + return hashCode; + } + hashCode = 17 * intVal.hashCode() + (int) scale; + return hashCode; + } + + /** + * Returns this {@code BigDecimal} as an int value. Any fractional part is + * discarded. If the integral part of {@code this} is too big to be + * represented as an int, then {@code this} % 2^32 is returned. + * + * @return this {@code BigDecimal} as a int value. + */ + @Override + public int intValue() { + /* + * If scale <= -32 there are at least 32 trailing bits zero in 10^(-scale). + * If the scale is positive and very large the long value could be zero. + */ + return ((scale <= -32) || (scale > approxPrecision()) ? 0 + : toBigInteger().intValue()); + } + + /** + * Returns this {@code BigDecimal} as a int value if it has no fractional part + * and if its value fits to the int range ([-2^{31}..2^{31}-1]). If these + * conditions are not met, an {@code ArithmeticException} is thrown. + * + * @return this {@code BigDecimal} as a int value. + * @throws ArithmeticException if rounding is necessary or the number doesn't + * fit in a int. + */ + public int intValueExact() { + return (int) valueExact(32); + } + + /** + * Returns this {@code BigDecimal} as an long value. Any fractional part is + * discarded. If the integral part of {@code this} is too big to be + * represented as an long, then {@code this} % 2^64 is returned. + * + * @return this {@code BigDecimal} as a long value. + */ + @Override + public long longValue() { + /* + * If scale <= -64 there are at least 64 trailing bits zero in 10^(-scale). + * If the scale is positive and very large the long value could be zero. + */ + return ((scale <= -64) || (scale > approxPrecision()) ? 0L + : toBigInteger().longValue()); + } + + /** + * Returns this {@code BigDecimal} as a long value if it has no fractional + * part and if its value fits to the int range ([-2^{63}..2^{63}-1]). If these + * conditions are not met, an {@code ArithmeticException} is thrown. + * + * @return this {@code BigDecimal} as a long value. + * @throws ArithmeticException if rounding is necessary or the number doesn't + * fit in a long. + */ + public long longValueExact() { + return valueExact(64); + } + + /** + * Returns the maximum of this {@code BigDecimal} and {@code val}. + * + * @param val value to be used to compute the maximum with this. + * @return {@code max(this, val}. + * @throws NullPointerException if {@code val == null}. + */ + public BigDecimal max(BigDecimal val) { + return ((compareTo(val) >= 0) ? this : val); + } + + /** + * Returns the minimum of this {@code BigDecimal} and {@code val}. + * + * @param val value to be used to compute the minimum with this. + * @return {@code min(this, val}. + * @throws NullPointerException if {@code val == null}. + */ + public BigDecimal min(BigDecimal val) { + return ((compareTo(val) <= 0) ? this : val); + } + + /** + * Returns a new {@code BigDecimal} instance where the decimal point has been + * moved {@code n} places to the left. If {@code n < 0} then the decimal point + * is moved {@code -n} places to the right. + *

+ * The result is obtained by changing its scale. If the scale of the result + * becomes negative, then its precision is increased such that the scale is + * zero. + *

+ * Note, that {@code movePointLeft(0)} returns a result which is + * mathematically equivalent, but which has {@code scale >= 0}. + * + * @param n number of placed the decimal point has to be moved. + * @return {@code this * 10^(-n}). + */ + public BigDecimal movePointLeft(int n) { + return movePoint(scale + n); + } + + /** + * Returns a new {@code BigDecimal} instance where the decimal point has been + * moved {@code n} places to the right. If {@code n < 0} then the decimal + * point is moved {@code -n} places to the left. + *

+ * The result is obtained by changing its scale. If the scale of the result + * becomes negative, then its precision is increased such that the scale is + * zero. + *

+ * Note, that {@code movePointRight(0)} returns a result which is + * mathematically equivalent, but which has scale >= 0. + * + * @param n number of placed the decimal point has to be moved. + * @return {@code this * 10^n}. + */ + public BigDecimal movePointRight(int n) { + return movePoint(scale - n); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this * multiplicand} + * . The scale of the result is the sum of the scales of the two arguments. + * + * @param multiplicand value to be multiplied with {@code this}. + * @return {@code this * multiplicand}. + * @throws NullPointerException if {@code multiplicand == null}. + */ + public BigDecimal multiply(BigDecimal multiplicand) { + double newScale = this.scale + multiplicand.scale; + + if ((this.isZero()) || (multiplicand.isZero())) { + return zeroScaledBy(newScale); + } + /* + * Let be: this = [u1,s1] and multiplicand = [u2,s2] so: this x multiplicand + * = [ s1 * s2 , s1 + s2 ] + */ + if (this.bitLength + multiplicand.bitLength < SMALL_VALUE_BITS) { + return valueOf(this.smallValue * multiplicand.smallValue, + toIntScale(newScale)); + } + return new BigDecimal(this.getUnscaledValue().multiply( + multiplicand.getUnscaledValue()), toIntScale(newScale)); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this * multiplicand} + * . The result is rounded according to the passed context {@code mc}. + * + * @param multiplicand value to be multiplied with {@code this}. + * @param mc rounding mode and precision for the result of this operation. + * @return {@code this * multiplicand}. + * @throws NullPointerException if {@code multiplicand == null} or {@code mc + * == null}. + */ + public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) { + BigDecimal result = multiply(multiplicand); + + result.inplaceRound(mc); + return result; + } + + /** + * Returns a new {@code BigDecimal} whose value is the {@code -this}. The + * scale of the result is the same as the scale of this. + * + * @return {@code -this} + */ + public BigDecimal negate() { + if (bitLength < SMALL_VALUE_BITS) { + return valueOf(-smallValue, scale); + } + return new BigDecimal(getUnscaledValue().negate(), scale); + } + + /** + * Returns a new {@code BigDecimal} whose value is the {@code -this}. The + * result is rounded according to the passed context {@code mc}. + * + * @param mc rounding mode and precision for the result of this operation. + * @return {@code -this} + */ + public BigDecimal negate(MathContext mc) { + return round(mc).negate(); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code +this}. The scale of + * the result is the same as the scale of this. + * + * @return {@code this} + */ + public BigDecimal plus() { + return this; + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code +this}. The result + * is rounded according to the passed context {@code mc}. + * + * @param mc rounding mode and precision for the result of this operation. + * @return {@code this}, rounded + */ + public BigDecimal plus(MathContext mc) { + return round(mc); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this ^ n}. The scale + * of the result is {@code n} times the scales of {@code this}. + *

+ * {@code x.pow(0)} returns {@code 1}, even if {@code x == 0}. + *

+ * Implementation Note: The implementation is based on the ANSI standard + * X3.274-1996 algorithm. + * + * @param n exponent to which {@code this} is raised. + * @return {@code this ^ n}. + * @throws ArithmeticException if {@code n < 0} or {@code n > 999999999}. + */ + public BigDecimal pow(int n) { + if (n == 0) { + return ONE; + } + if ((n < 0) || (n > 999999999)) { + // math.07=Invalid Operation + throw new ArithmeticException("Invalid Operation"); //$NON-NLS-1$ + } + double newScale = scale * n; + // Let be: this = [u,s] so: this^n = [u^n, s*n] + return ((isZero()) ? zeroScaledBy(newScale) : new BigDecimal( + getUnscaledValue().pow(n), toIntScale(newScale))); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this ^ n}. The + * result is rounded according to the passed context {@code mc}. + *

+ * Implementation Note: The implementation is based on the ANSI standard + * X3.274-1996 algorithm. + * + * @param n exponent to which {@code this} is raised. + * @param mc rounding mode and precision for the result of this operation. + * @return {@code this ^ n}. + * @throws ArithmeticException if {@code n < 0} or {@code n > 999999999}. + */ + public BigDecimal pow(int n, MathContext mc) { + // The ANSI standard X3.274-1996 algorithm + int m = Math.abs(n); + int mcPrecision = mc.getPrecision(); + int elength = (int) Math.log10(m) + 1; // decimal digits in 'n' + int oneBitMask; // mask of bits + BigDecimal accum; // the single accumulator + MathContext newPrecision = mc; // MathContext by default + + // In particular cases, it reduces the problem to call the other 'pow()' + if ((n == 0) || ((isZero()) && (n > 0))) { + return pow(n); + } + if ((m > 999999999) || ((mcPrecision == 0) && (n < 0)) + || ((mcPrecision > 0) && (elength > mcPrecision))) { + // math.07=Invalid Operation + throw new ArithmeticException("Invalid Operation"); //$NON-NLS-1$ + } + if (mcPrecision > 0) { + newPrecision = new MathContext(mcPrecision + elength + 1, + mc.getRoundingMode()); + } + // The result is calculated as if 'n' were positive + accum = round(newPrecision); + oneBitMask = Integer.highestOneBit(m) >> 1; + + while (oneBitMask > 0) { + accum = accum.multiply(accum, newPrecision); + if ((m & oneBitMask) == oneBitMask) { + accum = accum.multiply(this, newPrecision); + } + oneBitMask >>= 1; + } + // If 'n' is negative, the value is divided into 'ONE' + if (n < 0) { + accum = ONE.divide(accum, newPrecision); + } + // The final value is rounded to the destination precision + accum.inplaceRound(mc); + return accum; + } + + /** + * Returns the precision of this {@code BigDecimal}. The precision is the + * number of decimal digits used to represent this decimal. It is equivalent + * to the number of digits of the unscaled value. The precision of {@code 0} + * is {@code 1} (independent of the scale). + * + * @return the precision of this {@code BigDecimal}. + */ + public int precision() { + // Checking if the precision already was calculated + if (precision > 0) { + return precision; + } + double decimalDigits = 1; // the precision to be calculated + double doubleUnsc = 1; // intVal in 'double' + + if (bitLength < SMALL_VALUE_BITS) { + // To calculate the precision for small numbers + if (bitLength >= 1) { + doubleUnsc = smallValue; + } + decimalDigits += Math.log10(Math.abs(doubleUnsc)); + } else { + // (bitLength >= 1024) + /* + * To calculate the precision for large numbers Note that: 2 ^(bitlength() + * - 1) <= intVal < 10 ^(precision()) + */ + decimalDigits += (bitLength - 1) * LOG10_2; + // If after division the number isn't zero, exists an aditional digit + if (getUnscaledValue().divide(Multiplication.powerOf10(decimalDigits)).signum() != 0) { + decimalDigits++; + } + } + precision = (int) decimalDigits; + return precision; + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this % divisor}. + *

+ * The remainder is defined as {@code this - + * this.divideToIntegralValue(divisor) * divisor}. + * + * @param divisor value by which {@code this} is divided. + * @return {@code this % divisor}. + * @throws NullPointerException if {@code divisor == null}. + * @throws ArithmeticException if {@code divisor == 0}. + */ + public BigDecimal remainder(BigDecimal divisor) { + return divideAndRemainder(divisor)[1]; + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this % divisor}. + *

+ * The remainder is defined as {@code this - + * this.divideToIntegralValue(divisor) * divisor}. + *

+ * The specified rounding mode {@code mc} is used for the division only. + * + * @param divisor value by which {@code this} is divided. + * @param mc rounding mode and precision to be used. + * @return {@code this % divisor}. + * @throws NullPointerException if {@code divisor == null}. + * @throws ArithmeticException if {@code divisor == 0}. + * @throws ArithmeticException if {@code mc.getPrecision() > 0} and the result + * of {@code this.divideToIntegralValue(divisor, mc)} requires more + * digits to be represented. + */ + public BigDecimal remainder(BigDecimal divisor, MathContext mc) { + return divideAndRemainder(divisor, mc)[1]; + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this}, rounded + * according to the passed context {@code mc}. + *

+ * If {@code mc.precision = 0}, then no rounding is performed. + *

+ * If {@code mc.precision > 0} and {@code mc.roundingMode == UNNECESSARY}, + * then an {@code ArithmeticException} is thrown if the result cannot be + * represented exactly within the given precision. + * + * @param mc rounding mode and precision for the result of this operation. + * @return {@code this} rounded according to the passed context. + * @throws ArithmeticException if {@code mc.precision > 0} and {@code + * mc.roundingMode == UNNECESSARY} and this cannot be represented + * within the given precision. + */ + public BigDecimal round(MathContext mc) { + BigDecimal thisBD = new BigDecimal(getUnscaledValue(), scale); + + thisBD.inplaceRound(mc); + return thisBD; + } + + /** + * Returns the scale of this {@code BigDecimal}. The scale is the number of + * digits behind the decimal point. The value of this {@code BigDecimal} is + * the unsignedValue * 10^(-scale). If the scale is negative, then this + * {@code BigDecimal} represents a big integer. + * + * @return the scale of this {@code BigDecimal}. + */ + public int scale() { + return (int) scale; + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this} 10^{@code n}. + * The scale of the result is {@code this.scale()} - {@code n}. The precision + * of the result is the precision of {@code this}. + *

+ * This method has the same effect as {@link #movePointRight}, except that the + * precision is not changed. + * + * @param n number of places the decimal point has to be moved. + * @return {@code this * 10^n} + */ + public BigDecimal scaleByPowerOfTen(int n) { + double newScale = scale - n; + if (bitLength < SMALL_VALUE_BITS) { + // Taking care when a 0 is to be scaled + if (smallValue == 0) { + return zeroScaledBy(newScale); + } + return valueOf(smallValue, toIntScale(newScale)); + } + return new BigDecimal(getUnscaledValue(), toIntScale(newScale)); + } + + /** + * Returns a new {@code BigDecimal} instance with the specified scale. If the + * new scale is greater than the old scale, then additional zeros are added to + * the unscaled value. If the new scale is smaller than the old scale, then + * trailing zeros are removed. If the trailing digits are not zeros then an + * ArithmeticException is thrown. + *

+ * If no exception is thrown, then the following equation holds: {@code + * x.setScale(s).compareTo(x) == 0}. + * + * @param newScale scale of the result returned. + * @return a new {@code BigDecimal} instance with the specified scale. + * @throws ArithmeticException if rounding would be necessary. + */ + public BigDecimal setScale(int newScale) { + return setScale(newScale, RoundingMode.UNNECESSARY); + } + + /** + * Returns a new {@code BigDecimal} instance with the specified scale. + *

+ * If the new scale is greater than the old scale, then additional zeros are + * added to the unscaled value. In this case no rounding is necessary. + *

+ * If the new scale is smaller than the old scale, then trailing digits are + * removed. If these trailing digits are not zero, then the remaining unscaled + * value has to be rounded. For this rounding operation the specified rounding + * mode is used. + * + * @param newScale scale of the result returned. + * @param roundingMode rounding mode to be used to round the result. + * @return a new {@code BigDecimal} instance with the specified scale. + * @throws IllegalArgumentException if {@code roundingMode} is not a valid + * rounding mode. + * @throws ArithmeticException if {@code roundingMode == ROUND_UNNECESSARY} + * and rounding is necessary according to the given scale. + */ + public BigDecimal setScale(int newScale, int roundingMode) { + return setScale(newScale, RoundingMode.valueOf(roundingMode)); + } + + /** + * Returns a new {@code BigDecimal} instance with the specified scale. + *

+ * If the new scale is greater than the old scale, then additional zeros are + * added to the unscaled value. In this case no rounding is necessary. + *

+ * If the new scale is smaller than the old scale, then trailing digits are + * removed. If these trailing digits are not zero, then the remaining unscaled + * value has to be rounded. For this rounding operation the specified rounding + * mode is used. + * + * @param newScale scale of the result returned. + * @param roundingMode rounding mode to be used to round the result. + * @return a new {@code BigDecimal} instance with the specified scale. + * @throws NullPointerException if {@code roundingMode == null}. + * @throws ArithmeticException if {@code roundingMode == ROUND_UNNECESSARY} + * and rounding is necessary according to the given scale. + */ + public BigDecimal setScale(int newScale, RoundingMode roundingMode) { + if (roundingMode == null) { + throw new NullPointerException(); + } + double diffScale = newScale - scale; + // Let be: 'this' = [u,s] + if (diffScale == 0) { + return this; + } + if (diffScale > 0) { + // return [u * 10^(s2 - s), newScale] + if (diffScale < DOUBLE_TEN_POW.length + && (this.bitLength + DOUBLE_TEN_POW_BIT_LENGTH[ + (int) diffScale]) < SMALL_VALUE_BITS) { + return valueOf(this.smallValue * DOUBLE_TEN_POW[(int) diffScale], + newScale); + } + return new BigDecimal(Multiplication.multiplyByTenPow(getUnscaledValue(), + (int) diffScale), newScale); + } + // diffScale < 0 + // return [u,s] / [1,newScale] with the appropriate scale and rounding + if (this.bitLength < SMALL_VALUE_BITS + && -diffScale < DOUBLE_TEN_POW.length) { + return dividePrimitiveDoubles(this.smallValue, + DOUBLE_TEN_POW[(int) -diffScale], newScale, roundingMode); + } + return divideBigIntegers(this.getUnscaledValue(), + Multiplication.powerOf10(-diffScale), newScale, roundingMode); + } + + /** + * Returns this {@code BigDecimal} as a short value if it has no fractional + * part and if its value fits to the short range ([-2^{15}..2^{15}-1]). If + * these conditions are not met, an {@code ArithmeticException} is thrown. + * + * @return this {@code BigDecimal} as a short value. + * @throws ArithmeticException if rounding is necessary of the number doesn't + * fit in a short. + */ + public short shortValueExact() { + return (short) valueExact(16); + } + + /** + * Returns the sign of this {@code BigDecimal}. + * + * @return {@code -1} if {@code this < 0}, {@code 0} if {@code this == 0}, + * {@code 1} if {@code this > 0}. + */ + public int signum() { + if (bitLength < SMALL_VALUE_BITS) { + return this.smallValue < 0 ? -1 : this.smallValue > 0 ? 1 : 0; + } + return getUnscaledValue().signum(); + } + + /** + * Returns a new {@code BigDecimal} instance with the same value as {@code + * this} but with a unscaled value where the trailing zeros have been removed. + * If the unscaled value of {@code this} has n trailing zeros, then the scale + * and the precision of the result has been reduced by n. + * + * @return a new {@code BigDecimal} instance equivalent to this where the + * trailing zeros of the unscaled value have been removed. + */ + public BigDecimal stripTrailingZeros() { + int i = 1; // 1 <= i <= 18 + int lastPow = TEN_POW.length - 1; + double newScale = scale; + + if (isZero()) { + return new BigDecimal("0"); + } + BigInteger strippedBI = getUnscaledValue(); + BigInteger[] quotAndRem; + + // while the number is even... + while (!strippedBI.testBit(0)) { + // To divide by 10^i + quotAndRem = strippedBI.divideAndRemainder(TEN_POW[i]); + // To look the remainder + if (quotAndRem[1].signum() == 0) { + // To adjust the scale + newScale -= i; + if (i < lastPow) { + // To set to the next power + i++; + } + strippedBI = quotAndRem[0]; + } else { + if (i == 1) { + // 'this' has no more trailing zeros + break; + } + // To set to the smallest power of ten + i = 1; + } + } + return new BigDecimal(strippedBI, toIntScale(newScale)); + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this - subtrahend}. + * The scale of the result is the maximum of the scales of the two arguments. + * + * @param subtrahend value to be subtracted from {@code this}. + * @return {@code this - subtrahend}. + * @throws NullPointerException if {@code subtrahend == null}. + */ + public BigDecimal subtract(BigDecimal subtrahend) { + double diffScale = this.scale - subtrahend.scale; + // Fast return when some operand is zero + if (this.isZero()) { + if (diffScale <= 0) { + return subtrahend.negate(); + } + if (subtrahend.isZero()) { + return this; + } + } else if (subtrahend.isZero()) { + if (diffScale >= 0) { + return this; + } + } + // Let be: this = [u1,s1] and subtrahend = [u2,s2] so: + if (diffScale == 0) { + // case s1 = s2 : [u1 - u2 , s1] + if (Math.max(this.bitLength, subtrahend.bitLength) + 1 + < SMALL_VALUE_BITS) { + return valueOf(this.smallValue - subtrahend.smallValue, this.scale); + } + return new BigDecimal(this.getUnscaledValue().subtract( + subtrahend.getUnscaledValue()), this.scale); + } else if (diffScale > 0) { + // case s1 > s2 : [ u1 - u2 * 10 ^ (s1 - s2) , s1 ] + if (diffScale < DOUBLE_TEN_POW.length + && Math.max(this.bitLength, subtrahend.bitLength + + DOUBLE_TEN_POW_BIT_LENGTH[(int) diffScale]) + 1 + < SMALL_VALUE_BITS) { + return valueOf(this.smallValue - subtrahend.smallValue + * DOUBLE_TEN_POW[(int) diffScale], this.scale); + } + return new BigDecimal(this.getUnscaledValue().subtract( + Multiplication.multiplyByTenPow(subtrahend.getUnscaledValue(), + (int) diffScale)), this.scale); + } else { + // case s2 > s1 : [ u1 * 10 ^ (s2 - s1) - u2 , s2 ] + diffScale = -diffScale; + if (diffScale < DOUBLE_TEN_POW.length + && Math.max(this.bitLength + + DOUBLE_TEN_POW_BIT_LENGTH[(int) diffScale], + subtrahend.bitLength) + 1 < SMALL_VALUE_BITS) { + return valueOf(this.smallValue * DOUBLE_TEN_POW[(int) diffScale] + - subtrahend.smallValue, subtrahend.scale); + } + return new BigDecimal(Multiplication.multiplyByTenPow( + this.getUnscaledValue(), (int) diffScale).subtract( + subtrahend.getUnscaledValue()), subtrahend.scale); + } + } + + /** + * Returns a new {@code BigDecimal} whose value is {@code this - subtrahend}. + * The result is rounded according to the passed context {@code mc}. + * + * @param subtrahend value to be subtracted from {@code this}. + * @param mc rounding mode and precision for the result of this operation. + * @return {@code this - subtrahend}. + * @throws NullPointerException if {@code subtrahend == null} or {@code mc == + * null}. + */ + public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) { + double diffScale = subtrahend.scale - this.scale; + int thisSignum; + BigDecimal leftOperand; // it will be only the left operand (this) + BigInteger tempBI; + // Some operand is zero or the precision is infinity + if ((subtrahend.isZero()) || (this.isZero()) || (mc.getPrecision() == 0)) { + return subtract(subtrahend).round(mc); + } + // Now: this != 0 and subtrahend != 0 + if (subtrahend.approxPrecision() < diffScale - 1) { + // Cases where it is unnecessary to subtract two numbers with very + // different scales + if (mc.getPrecision() < this.approxPrecision()) { + thisSignum = this.signum(); + if (thisSignum != subtrahend.signum()) { + tempBI = Multiplication.multiplyByPositiveInt( + this.getUnscaledValue(), 10).add(BigInteger.valueOf(thisSignum)); + } else { + tempBI = this.getUnscaledValue().subtract( + BigInteger.valueOf(thisSignum)); + tempBI = Multiplication.multiplyByPositiveInt(tempBI, 10).add( + BigInteger.valueOf(thisSignum * 9)); + } + // Rounding the improved subtracting + leftOperand = new BigDecimal(tempBI, this.scale + 1); + return leftOperand.round(mc); + } + } + // No optimization is done + return subtract(subtrahend).round(mc); + } + + /** + * Returns this {@code BigDecimal} as a big integer instance. A fractional + * part is discarded. + * + * @return this {@code BigDecimal} as a big integer instance. + */ + public BigInteger toBigInteger() { + if ((scale == 0) || (isZero())) { + return getUnscaledValue(); + } else if (scale < 0) { + return getUnscaledValue().multiply(Multiplication.powerOf10(-scale)); + } else { + // (scale > 0) + return getUnscaledValue().divide(Multiplication.powerOf10(scale)); + } + } + + /** + * Returns this {@code BigDecimal} as a big integer instance if it has no + * fractional part. If this {@code BigDecimal} has a fractional part, i.e. if + * rounding would be necessary, an {@code ArithmeticException} is thrown. + * + * @return this {@code BigDecimal} as a big integer value. + * @throws ArithmeticException if rounding is necessary. + */ + public BigInteger toBigIntegerExact() { + if ((scale == 0) || (isZero())) { + return getUnscaledValue(); + } else if (scale < 0) { + return getUnscaledValue().multiply(Multiplication.powerOf10(-scale)); + } else { + // (scale > 0) + BigInteger[] integerAndFraction; + // An optimization before do a heavy division + if ((scale > approxPrecision()) + || (scale > getUnscaledValue().getLowestSetBit())) { + // math.08=Rounding necessary + throw new ArithmeticException("Rounding necessary"); //$NON-NLS-1$ + } + integerAndFraction = getUnscaledValue().divideAndRemainder( + Multiplication.powerOf10(scale)); + if (integerAndFraction[1].signum() != 0) { + // It exists a non-zero fractional part + // math.08=Rounding necessary + throw new ArithmeticException("Rounding necessary"); //$NON-NLS-1$ + } + return integerAndFraction[0]; + } + } + + /** + * Returns a string representation of this {@code BigDecimal}. This + * representation always prints all significant digits of this value. + *

+ * If the scale is negative or if {@code scale - precision >= 6} then + * engineering notation is used. Engineering notation is similar to the + * scientific notation except that the exponent is made to be a multiple of 3 + * such that the integer part is >= 1 and < 1000. + * + * @return a string representation of {@code this} in engineering notation if + * necessary. + */ + public String toEngineeringString() { + String intString = getUnscaledValue().toString(); + if (scale == 0) { + return intString; + } + int begin = (getUnscaledValue().signum() < 0) ? 2 : 1; + int end = intString.length(); + double exponent = -scale + end - begin; + StringBuilder result = new StringBuilder(intString); + + if ((scale > 0) && (exponent >= -6)) { + if (exponent >= 0) { + result.insert(end - (int) scale, '.'); + } else { + result.insert(begin - 1, "0."); //$NON-NLS-1$ + result.insert(begin + 1, CH_ZEROS, 0, -(int) exponent - 1); + } + } else { + int delta = end - begin; + int rem = (int) (exponent % 3); + + if (rem != 0) { + // adjust exponent so it is a multiple of three + if (getUnscaledValue().signum() == 0) { + // zero value + rem = (rem < 0) ? -rem : 3 - rem; + exponent += rem; + } else { + // nonzero value + rem = (rem < 0) ? rem + 3 : rem; + exponent -= rem; + begin += rem; + } + if (delta < 3) { + for (int i = rem - delta; i > 0; i--) { + result.insert(end++, '0'); + } + } + } + if (end - begin >= 1) { + result.insert(begin, '.'); + end++; + } + if (exponent != 0) { + result.insert(end, 'E'); + if (exponent > 0) { + result.insert(++end, '+'); + } + result.insert(++end, Long.toString((long) exponent)); + } + } + return result.toString(); + } + + /** + * Returns a string representation of this {@code BigDecimal}. No scientific + * notation is used. This methods adds zeros where necessary. + *

+ * If this string representation is used to create a new instance, this + * instance is generally not identical to {@code this} as the precision + * changes. + *

+ * {@code x.equals(new BigDecimal(x.toPlainString())} usually returns {@code + * false}. + *

+ * {@code x.compareTo(new BigDecimal(x.toPlainString())} returns {@code 0}. + * + * @return a string representation of {@code this} without exponent part. + */ + public String toPlainString() { + String intStr = getUnscaledValue().toString(); + if ((scale == 0) || ((isZero()) && (scale < 0))) { + return intStr; + } + int begin = (signum() < 0) ? 1 : 0; + double delta = scale; + // We take space for all digits, plus a possible decimal point, plus 'scale' + StringBuilder result = new StringBuilder(intStr.length() + 1 + + Math.abs((int) scale)); + + if (begin == 1) { + // If the number is negative, we insert a '-' character at front + result.append('-'); + } + if (scale > 0) { + delta -= (intStr.length() - begin); + if (delta >= 0) { + result.append("0."); //$NON-NLS-1$ + // To append zeros after the decimal point + for (; delta > CH_ZEROS.length; delta -= CH_ZEROS.length) { + result.append(CH_ZEROS); + } + result.append(CH_ZEROS, 0, (int) delta); + result.append(intStr.substring(begin)); + } else { + delta = begin - delta; + result.append(intStr.substring(begin, (int) delta)); + result.append('.'); + result.append(intStr.substring((int) delta)); + } + } else { + // (scale <= 0) + result.append(intStr.substring(begin)); + // To append trailing zeros + for (; delta < -CH_ZEROS.length; delta += CH_ZEROS.length) { + result.append(CH_ZEROS); + } + result.append(CH_ZEROS, 0, (int) -delta); + } + return result.toString(); + } + + /** + * Returns a canonical string representation of this {@code BigDecimal}. If + * necessary, scientific notation is used. This representation always prints + * all significant digits of this value. + *

+ * If the scale is negative or if {@code scale - precision >= 6} then + * scientific notation is used. + * + * @return a string representation of {@code this} in scientific notation if + * necessary. + */ + @Override + public String toString() { + if (toStringImage != null) { + return toStringImage; + } + if (bitLength < 32) { + // TODO convert to double math dont cast to long :-( + toStringImage = Conversion.toDecimalScaledString((long) smallValue, + (int) scale); + return toStringImage; + } + String intString = getUnscaledValue().toString(); + if (scale == 0) { + return intString; + } + int begin = (getUnscaledValue().signum() < 0) ? 2 : 1; + int end = intString.length(); + double exponent = -scale + end - begin; + StringBuilder result = new StringBuilder(); + + result.append(intString); + if ((scale > 0) && (exponent >= -6)) { + if (exponent >= 0) { + result.insert(end - (int) scale, '.'); + } else { + result.insert(begin - 1, "0."); //$NON-NLS-1$ + result.insert(begin + 1, CH_ZEROS, 0, -(int) exponent - 1); + } + } else { + if (end - begin >= 1) { + result.insert(begin, '.'); + end++; + } + result.insert(end, 'E'); + if (exponent > 0) { + result.insert(++end, '+'); + } + result.insert(++end, Long.toString((long) exponent)); + } + toStringImage = result.toString(); + return toStringImage; + } + + /** + * Returns the unit in the last place (ULP) of this {@code BigDecimal} + * instance. An ULP is the distance to the nearest big decimal with the same + * precision. + *

+ * The amount of a rounding error in the evaluation of a floating-point + * operation is often expressed in ULPs. An error of 1 ULP is often seen as a + * tolerable error. + *

+ * For class {@code BigDecimal}, the ULP of a number is simply 10^(-scale). + *

+ * For example, {@code new BigDecimal(0.1).ulp()} returns {@code 1E-55}. + * + * @return unit in the last place (ULP) of this {@code BigDecimal} instance. + */ + public BigDecimal ulp() { + return valueOf(1, scale); + } + + /** + * Returns the unscaled value (mantissa) of this {@code BigDecimal} instance + * as a {@code BigInteger}. The unscaled value can be computed as {@code this} + * 10^(scale). + * + * @return unscaled value (this * 10^(scale)). + */ + public BigInteger unscaledValue() { + return getUnscaledValue(); + } + + /** + * If the precision already was calculated it returns that value, otherwise it + * calculates a very good approximation efficiently . Note that this value + * will be {@code precision()} or {@code precision()-1} in the worst case. + * + * @return an approximation of {@code precision()} value + */ + private double approxPrecision() { + return (precision > 0) ? precision + : Math.floor((this.bitLength - 1) * LOG10_2) + 1; + } + + private BigInteger getUnscaledValue() { + if (intVal == null) { + intVal = BigInteger.valueOf(smallValue); + } + return intVal; + } + + private void initFrom(String val) { + int begin = 0; // first index to be copied + int offset = 0; + int last = val.length(); // one past the last index to be copied + String scaleString = null; // buffer for scale + StringBuilder unscaledBuffer; // buffer for unscaled value + + unscaledBuffer = new StringBuilder(val.length()); + // To skip a possible '+' symbol + if ((offset < last) && (val.charAt(offset) == '+')) { + offset++; + begin++; + + // Fail if the next character is another sign. + if ((offset < last) + && (val.charAt(offset) == '+' || val.charAt(offset) == '-')) { + throw new NumberFormatException("For input string: \"" + val + "\""); + } + } + int counter = 0; + boolean wasNonZero = false; + // Accumulating all digits until a possible decimal point + for (; (offset < last) && (val.charAt(offset) != '.') + && (val.charAt(offset) != 'e') && (val.charAt(offset) != 'E'); offset++) { + if (!wasNonZero) { + if (val.charAt(offset) == '0') { + counter++; + } else { + wasNonZero = true; + } + } + } + unscaledBuffer.append(val, begin, offset); + // A decimal point was found + if ((offset < last) && (val.charAt(offset) == '.')) { + offset++; + // Accumulating all digits until a possible exponent + begin = offset; + for (; (offset < last) && (val.charAt(offset) != 'e') + && (val.charAt(offset) != 'E'); offset++) { + if (!wasNonZero) { + if (val.charAt(offset) == '0') { + counter++; + } else { + wasNonZero = true; + } + } + } + scale = offset - begin; + unscaledBuffer.append(val, begin, offset); + } else { + scale = 0; + } + // An exponent was found + if ((offset < last) + && ((val.charAt(offset) == 'e') || (val.charAt(offset) == 'E'))) { + offset++; + // Checking for a possible sign of scale + begin = offset; + if ((offset < last) && (val.charAt(offset) == '+')) { + offset++; + if ((offset < last) && (val.charAt(offset) != '-')) { + begin++; + } + } + // Accumulating all remaining digits + scaleString = val.substring(begin, last); + // Checking if the scale is defined + scale = scale - Integer.parseInt(scaleString); + if (scale != (int) scale) { + // math.02=Scale out of range. + throw new NumberFormatException("Scale out of range."); //$NON-NLS-1$ + } + } + // Parsing the unscaled value + String unscaled = unscaledBuffer.toString(); + if (unscaled.length() < 16) { + smallValue = parseUnscaled(unscaled); + if (Double.isNaN(smallValue)) { + throw new NumberFormatException("For input string: \"" + val + "\""); + } + bitLength = bitLength(smallValue); + } else { + setUnscaledValue(new BigInteger(unscaled)); + } + precision = unscaledBuffer.length() - counter; + // Don't count leading zeros in the precision + for (int i = 0; i < unscaledBuffer.length(); ++i) { + char ch = unscaledBuffer.charAt(i); + if (ch != '-' && ch != '0') { + break; + } + --precision; + } + } + + /** + * It does all rounding work of the public method {@code round(MathContext)}, + * performing an inplace rounding without creating a new object. + * + * @param mc the {@code MathContext} for perform the rounding. + * @see #round(MathContext) + */ + private void inplaceRound(MathContext mc) { + int mcPrecision = mc.getPrecision(); + if (approxPrecision() - mcPrecision < 0 || mcPrecision == 0) { + return; + } + int discardedPrecision = precision() - mcPrecision; + // If no rounding is necessary it returns immediately + if ((discardedPrecision <= 0)) { + return; + } + // When the number is small perform an efficient rounding + if (this.bitLength < SMALL_VALUE_BITS) { + smallRound(mc, discardedPrecision); + return; + } + // Getting the integer part and the discarded fraction + BigInteger sizeOfFraction = Multiplication.powerOf10(discardedPrecision); + BigInteger[] integerAndFraction = getUnscaledValue().divideAndRemainder( + sizeOfFraction); + double newScale = scale - discardedPrecision; + int compRem; + BigDecimal tempBD; + // If the discarded fraction is non-zero, perform rounding + if (integerAndFraction[1].signum() != 0) { + // To check if the discarded fraction >= 0.5 + compRem = (integerAndFraction[1].abs().shiftLeftOneBit().compareTo(sizeOfFraction)); + // To look if there is a carry + compRem = roundingBehavior(integerAndFraction[0].testBit(0) ? 1 : 0, + integerAndFraction[1].signum() * (5 + compRem), mc.getRoundingMode()); + if (compRem != 0) { + integerAndFraction[0] = integerAndFraction[0].add(BigInteger.valueOf(compRem)); + } + tempBD = new BigDecimal(integerAndFraction[0]); + // If after to add the increment the precision changed, we normalize the + // size + if (tempBD.precision() > mcPrecision) { + integerAndFraction[0] = integerAndFraction[0].divide(BigInteger.TEN); + newScale--; + } + } + // To update all internal fields + scale = toIntScale(newScale); + precision = mcPrecision; + setUnscaledValue(integerAndFraction[0]); + } + + private boolean isZero() { + return bitLength == 0 && this.smallValue != -1; + } + + private BigDecimal movePoint(double newScale) { + if (isZero()) { + return zeroScaledBy(Math.max(newScale, 0)); + } + /* + * When: 'n'== Integer.MIN_VALUE isn't possible to call to + * movePointRight(-n) since -Integer.MIN_VALUE == Integer.MIN_VALUE + */ + if (newScale >= 0) { + if (bitLength < SMALL_VALUE_BITS) { + return valueOf(smallValue, toIntScale(newScale)); + } + return new BigDecimal(getUnscaledValue(), toIntScale(newScale)); + } + if (-newScale < DOUBLE_TEN_POW.length + && bitLength + DOUBLE_TEN_POW_BIT_LENGTH[(int) -newScale] + < SMALL_VALUE_BITS) { + return valueOf(smallValue * DOUBLE_TEN_POW[(int) -newScale], 0); + } + return new BigDecimal(Multiplication.multiplyByTenPow(getUnscaledValue(), + (int) -newScale), 0); + } + + private void setUnscaledValue(BigInteger unscaledValue) { + this.intVal = unscaledValue; + this.bitLength = unscaledValue.bitLength(); + if (this.bitLength < SMALL_VALUE_BITS) { + this.smallValue = unscaledValue.longValue(); + } + } + + /** + * This method implements an efficient rounding for numbers which unscaled + * value fits in the type {@code long}. + * + * @param mc the context to use + * @param discardedPrecision the number of decimal digits that are discarded + * @see #round(MathContext) + */ + private void smallRound(MathContext mc, int discardedPrecision) { + long sizeOfFraction = (long) DOUBLE_TEN_POW[discardedPrecision]; + long newScale = (long) scale - discardedPrecision; + long unscaledVal = (long) smallValue; // TODO convert to double math dont + // use longs + // Getting the integer part and the discarded fraction + long integer = unscaledVal / sizeOfFraction; + long fraction = unscaledVal % sizeOfFraction; + int compRem; + // If the discarded fraction is non-zero perform rounding + if (fraction != 0) { + // To check if the discarded fraction >= 0.5 + compRem = longCompareTo(Math.abs(fraction) << 1, sizeOfFraction); + // To look if there is a carry + integer += roundingBehavior(((int) integer) & 1, Long.signum(fraction) + * (5 + compRem), mc.getRoundingMode()); + // If after to add the increment the precision changed, we normalize the + // size + if (Math.log10(Math.abs(integer)) >= mc.getPrecision()) { + integer /= 10; + newScale--; + } + } + // To update all internal fields + scale = toIntScale(newScale); + precision = mc.getPrecision(); + smallValue = integer; + bitLength = bitLength(integer); + intVal = null; + } + + /** + * If {@code intVal} has a fractional part throws an exception, otherwise it + * counts the number of bits of value and checks if it's out of the range of + * the primitive type. If the number fits in the primitive type returns this + * number as {@code long}, otherwise throws an exception. + * + * @param bitLengthOfType number of bits of the type whose value will be + * calculated exactly + * @return the exact value of the integer part of {@code BigDecimal} when is + * possible + * @throws ArithmeticException when rounding is necessary or the number don't + * fit in the primitive type + */ + private long valueExact(int bitLengthOfType) { + BigInteger bigInteger = toBigIntegerExact(); + + if (bigInteger.bitLength() < bitLengthOfType) { + // It fits in the primitive type + return bigInteger.longValue(); + } + // math.08=Rounding necessary + throw new ArithmeticException("Rounding necessary"); //$NON-NLS-1$ + } +} diff --git a/gwt/jre/java/math/BigInteger.java b/gwt/jre/java/math/BigInteger.java new file mode 100644 index 0000000..65287fa --- /dev/null +++ b/gwt/jre/java/math/BigInteger.java @@ -0,0 +1,1553 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +import java.io.Serializable; +import java.util.Random; + +/** + * This class represents immutable integer numbers of arbitrary length. Large + * numbers are typically used in security applications and therefore BigIntegers + * offer dedicated functionality like the generation of large prime numbers or + * the computation of modular inverse. + *

+ * Since the class was modeled to offer all the functionality as the + * {@link Integer} class does, it provides even methods that operate bitwise on + * a two's complement representation of large integers. Note however that the + * implementations favors an internal representation where magnitude and sign + * are treated separately. Hence such operations are inefficient and should be + * discouraged. In simple words: Do NOT implement any bit fields based on + * BigInteger. + */ +public class BigInteger extends Number implements Comparable, + Serializable { + + /** + * The {@code BigInteger} constant 1. + */ + public static final BigInteger ONE = new BigInteger(1, 1); + + /* Fields used for the internal representation. */ + + /** + * The {@code BigInteger} constant 10. + */ + public static final BigInteger TEN = new BigInteger(1, 10); + + /** + * The {@code BigInteger} constant 0. + */ + public static final BigInteger ZERO = new BigInteger(0, 0); + + /** + * The {@code BigInteger} constant 0 used for comparison. + */ + static final int EQUALS = 0; + + /** + * The {@code BigInteger} constant 1 used for comparison. + */ + static final int GREATER = 1; + + /** + * The {@code BigInteger} constant -1 used for comparison. + */ + static final int LESS = -1; + + /** + * The {@code BigInteger} constant -1. + */ + static final BigInteger MINUS_ONE = new BigInteger(-1, 1); + + /** + * 2^32. + */ + static final double POW32 = 4294967296d; + + /** + * All the {@code BigInteger} numbers in the range [0,10] are cached. + */ + static final BigInteger[] SMALL_VALUES = { + ZERO, ONE, new BigInteger(1, 2), new BigInteger(1, 3), + new BigInteger(1, 4), new BigInteger(1, 5), new BigInteger(1, 6), + new BigInteger(1, 7), new BigInteger(1, 8), new BigInteger(1, 9), TEN}; + + static final BigInteger[] TWO_POWS; + + /** + * This is the serialVersionUID used by the sun implementation. + */ + private static final long serialVersionUID = -8287574255936472291L; + + static { + TWO_POWS = new BigInteger[32]; + for (int i = 0; i < TWO_POWS.length; i++) { + TWO_POWS[i] = BigInteger.valueOf(1L << i); + } + } + + /** + * Returns a random positive {@code BigInteger} instance in the range [0, + * 2^(bitLength)-1] which is probably prime. The probability that the returned + * {@code BigInteger} is prime is beyond (1-1/2^80). + *

+ * Implementation Note: Currently {@code rnd} is ignored. + * + * @param bitLength length of the new {@code BigInteger} in bits. + * @param rnd random generator used to generate the new {@code BigInteger}. + * @return probably prime random {@code BigInteger} instance. + * @throws IllegalArgumentException if {@code bitLength < 2}. + */ + public static BigInteger probablePrime(int bitLength, Random rnd) { + return new BigInteger(bitLength, 100, rnd); + } + + public static BigInteger valueOf(long val) { + if (val < 0) { + if (val != -1) { + return new BigInteger(-1, -val); + } + return MINUS_ONE; + } else if (val <= 10) { + return SMALL_VALUES[(int) val]; + } else { + // (val > 10) + return new BigInteger(1, val); + } + } + + static BigInteger getPowerOfTwo(int exp) { + if (exp < TWO_POWS.length) { + return TWO_POWS[exp]; + } + int intCount = exp >> 5; + int bitN = exp & 31; + int resDigits[] = new int[intCount + 1]; + resDigits[intCount] = 1 << bitN; + return new BigInteger(1, intCount + 1, resDigits); + } + + static BigInteger valueOf(double val) { + if (val < 0) { + if (val != -1) { + return new BigInteger(-1, -val); + } + return MINUS_ONE; + } else if (val <= 10) { + return SMALL_VALUES[(int) val]; + } else { + // (val > 10) + return new BigInteger(1, val); + } + } + + /** + * @see BigInteger#BigInteger(String, int) + */ + private static void setFromString(BigInteger bi, String val, int radix) { + int sign; + int[] digits; + int numberLength; + int stringLength = val.length(); + int startChar; + int endChar = stringLength; + + if (val.charAt(0) == '-') { + sign = -1; + startChar = 1; + stringLength--; + } else { + sign = 1; + startChar = 0; + } + /* + * We use the following algorithm: split a string into portions of n + * characters and convert each portion to an integer according to the radix. + * Then convert an exp(radix, n) based number to binary using the + * multiplication method. See D. Knuth, The Art of Computer Programming, + * vol. 2. + */ + + int charsPerInt = Conversion.digitFitInInt[radix]; + int bigRadixDigitsLength = stringLength / charsPerInt; + int topChars = stringLength % charsPerInt; + + if (topChars != 0) { + bigRadixDigitsLength++; + } + digits = new int[bigRadixDigitsLength]; + // Get the maximal power of radix that fits in int + int bigRadix = Conversion.bigRadices[radix - 2]; + // Parse an input string and accumulate the BigInteger's magnitude + int digitIndex = 0; // index of digits array + int substrEnd = startChar + ((topChars == 0) ? charsPerInt : topChars); + int newDigit; + + for (int substrStart = startChar; substrStart < endChar; substrStart = substrEnd, substrEnd = substrStart + + charsPerInt) { + int bigRadixDigit = Integer.parseInt( + val.substring(substrStart, substrEnd), radix); + newDigit = Multiplication.multiplyByInt(digits, digitIndex, bigRadix); + newDigit += Elementary.inplaceAdd(digits, digitIndex, bigRadixDigit); + digits[digitIndex++] = newDigit; + } + numberLength = digitIndex; + bi.sign = sign; + bi.numberLength = numberLength; + bi.digits = digits; + bi.cutOffLeadingZeroes(); + } + + /** + * Converts an integral double to an unsigned integer; ie 2^31 will be + * returned as 0x80000000. + * + * @param val + * @return val as an unsigned int + */ + private static native int toUnsignedInt(double val) /*-{ + return ~~val; + }-*/; + + /** + * The magnitude of this big integer. This array is in little endian order and + * each "digit" is a 32-bit unsigned integer. For example: {@code 13} is + * represented as [ 13 ] {@code -13} is represented as [ 13 ] {@code 2^32 + + * 13} is represented as [ 13, 1 ] {@code 2^64 + 13} is represented as [ 13, + * 0, 1 ] {@code 2^31} is represented as [ Integer.MIN_VALUE ] The magnitude + * array may be longer than strictly necessary, which results in additional + * trailing zeros. + * + *

TODO(jat): consider changing to 24-bit integers for better performance + * in browsers. + */ + transient int digits[]; + + /** + * The length of this in measured in ints. Can be less than digits.length(). + */ + transient int numberLength; + + /** + * The sign of this. + */ + transient int sign; + + private transient int firstNonzeroDigit = -2; + + /** + * Cache for the hash code. + */ + private transient int hashCode = 0; + + /** + * Constructs a new {@code BigInteger} from the given two's complement + * representation. The most significant byte is the entry at index 0. The most + * significant bit of this entry determines the sign of the new {@code + * BigInteger} instance. The given array must not be empty. + * + * @param val two's complement representation of the new {@code BigInteger}. + * @throws NullPointerException if {@code val == null}. + * @throws NumberFormatException if the length of {@code val} is zero. + */ + public BigInteger(byte[] val) { + if (val.length == 0) { + // math.12=Zero length BigInteger + throw new NumberFormatException("Zero length BigInteger"); //$NON-NLS-1$ + } + if (val[0] < 0) { + sign = -1; + putBytesNegativeToIntegers(val); + } else { + sign = 1; + putBytesPositiveToIntegers(val); + } + cutOffLeadingZeroes(); + } + + /** + * Constructs a new {@code BigInteger} instance with the given sign and the + * given magnitude. The sign is given as an integer (-1 for negative, 0 for + * zero, 1 for positive). The magnitude is specified as a byte array. The most + * significant byte is the entry at index 0. + * + * @param signum sign of the new {@code BigInteger} (-1 for negative, 0 for + * zero, 1 for positive). + * @param magnitude magnitude of the new {@code BigInteger} with the most + * significant byte first. + * @throws NullPointerException if {@code magnitude == null}. + * @throws NumberFormatException if the sign is not one of -1, 0, 1 or if the + * sign is zero and the magnitude contains non-zero entries. + */ + public BigInteger(int signum, byte[] magnitude) { + if (magnitude == null) { + throw new NullPointerException(); + } + if ((signum < -1) || (signum > 1)) { + // math.13=Invalid signum value + throw new NumberFormatException("Invalid signum value"); //$NON-NLS-1$ + } + if (signum == 0) { + for (byte element : magnitude) { + if (element != 0) { + // math.14=signum-magnitude mismatch + throw new NumberFormatException("signum-magnitude mismatch"); //$NON-NLS-1$ + } + } + } + if (magnitude.length == 0) { + sign = 0; + numberLength = 1; + digits = new int[] {0}; + } else { + sign = signum; + putBytesPositiveToIntegers(magnitude); + cutOffLeadingZeroes(); + } + } + + /** + * Constructs a random {@code BigInteger} instance in the range [0, + * 2^(bitLength)-1] which is probably prime. The probability that the returned + * {@code BigInteger} is prime is beyond (1-1/2^certainty). + * + * @param bitLength length of the new {@code BigInteger} in bits. + * @param certainty tolerated primality uncertainty. + * @param rnd is an optional random generator to be used. + * @throws ArithmeticException if {@code bitLength} < 2. + */ + public BigInteger(int bitLength, int certainty, Random rnd) { + if (bitLength < 2) { + // math.1C=bitLength < 2 + throw new ArithmeticException("bitLength < 2"); //$NON-NLS-1$ + } + BigInteger me = Primality.consBigInteger(bitLength, certainty, rnd); + sign = me.sign; + numberLength = me.numberLength; + digits = me.digits; + } + + /** + * Constructs a random non-negative {@code BigInteger} instance in the range + * [0, 2^(numBits)-1]. + * + * @param numBits maximum length of the new {@code BigInteger} in bits. + * @param rnd is an optional random generator to be used. + * @throws IllegalArgumentException if {@code numBits} < 0. + */ + public BigInteger(int numBits, Random rnd) { + if (numBits < 0) { + // math.1B=numBits must be non-negative + throw new IllegalArgumentException("numBits must be non-negative"); //$NON-NLS-1$ + } + if (numBits == 0) { + sign = 0; + numberLength = 1; + digits = new int[] {0}; + } else { + sign = 1; + numberLength = (numBits + 31) >> 5; + digits = new int[numberLength]; + for (int i = 0; i < numberLength; i++) { + digits[i] = rnd.nextInt(); + } + // Using only the necessary bits + digits[numberLength - 1] >>>= (-numBits) & 31; + cutOffLeadingZeroes(); + } + } + + /** + * Constructs a new {@code BigInteger} instance from the string + * representation. The string representation consists of an optional minus + * sign followed by a non-empty sequence of decimal digits. + * + * @param val string representation of the new {@code BigInteger}. + * @throws NullPointerException if {@code val == null}. + * @throws NumberFormatException if {@code val} is not a valid representation + * of a {@code BigInteger}. + */ + public BigInteger(String val) { + this(val, 10); + } + + /** + * Constructs a new {@code BigInteger} instance from the string + * representation. The string representation consists of an optional minus + * sign followed by a non-empty sequence of digits in the specified radix. For + * the conversion the method {@code Character.digit(char, radix)} is used. + * + * @param val string representation of the new {@code BigInteger}. + * @param radix the base to be used for the conversion. + * @throws NullPointerException if {@code val == null}. + * @throws NumberFormatException if {@code val} is not a valid representation + * of a {@code BigInteger} or if {@code radix < Character.MIN_RADIX} + * or {@code radix > Character.MAX_RADIX}. + */ + public BigInteger(String val, int radix) { + if (val == null) { + throw new NullPointerException(); + } + if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) { + // math.11=Radix out of range + throw new NumberFormatException("Radix out of range"); //$NON-NLS-1$ + } + if (val.length() == 0) { + // math.12=Zero length BigInteger + throw new NumberFormatException("Zero length BigInteger"); //$NON-NLS-1$ + } + setFromString(this, val, radix); + } + + /** + * Constructs a number which array is of size 1. + * + * @param sign the sign of the number + * @param value the only one digit of array + */ + BigInteger(int sign, int value) { + this.sign = sign; + numberLength = 1; + digits = new int[] {value}; + } + + /** + * Creates a new {@code BigInteger} with the given sign and magnitude. This + * constructor does not create a copy, so any changes to the reference will + * affect the new number. + * + * @param signum The sign of the number represented by {@code digits} + * @param digits The magnitude of the number + */ + BigInteger(int signum, int digits[]) { + if (digits.length == 0) { + sign = 0; + numberLength = 1; + this.digits = new int[] {0}; + } else { + sign = signum; + numberLength = digits.length; + this.digits = digits; + cutOffLeadingZeroes(); + } + } + + /** + * Constructs a number without to create new space. This construct should be + * used only if the three fields of representation are known. + * + * @param sign the sign of the number + * @param numberLength the length of the internal array + * @param digits a reference of some array created before + */ + BigInteger(int sign, int numberLength, int[] digits) { + this.sign = sign; + this.numberLength = numberLength; + this.digits = digits; + } + + /** + * Creates a new {@code BigInteger} whose value is equal to the specified + * {@code long}. + * + * @param sign the sign of the number + * @param val the value of the new {@code BigInteger}. + */ + BigInteger(int sign, long val) { + // PRE: (val >= 0) && (sign >= -1) && (sign <= 1) + this.sign = sign; + if ((val & 0xFFFFFFFF00000000L) == 0) { + // It fits in one 'int' + numberLength = 1; + digits = new int[] {(int) val}; + } else { + numberLength = 2; + digits = new int[] {(int) val, (int) (val >> 32)}; + } + } + + /** + * Creates a new {@code BigInteger} whose value is equal to the specified + * {@code double} (which must be an integral value). + * + * @param sign the sign of the number + * @param val the value of the new {@code BigInteger}. + */ + private BigInteger(int sign, double val) { + // PRE: (val >= 0) && (sign >= -1) && (sign <= 1) + // ~~ forces coercion to 32 bits + this.sign = sign; + if (val < POW32) { + // It fits in one 'int' + numberLength = 1; + digits = new int[] { toUnsignedInt(val) }; + } else { + numberLength = 2; + digits = new int[] { toUnsignedInt(val % POW32), + toUnsignedInt(val / POW32)}; + } + } + + /** + * Returns a (new) {@code BigInteger} whose value is the absolute value of + * {@code this}. + * + * @return {@code abs(this)}. + */ + public BigInteger abs() { + return ((sign < 0) ? new BigInteger(1, numberLength, digits) : this); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this + val}. + * + * @param val value to be added to {@code this}. + * @return {@code this + val}. + * @throws NullPointerException if {@code val == null}. + */ + public BigInteger add(BigInteger val) { + return Elementary.add(this, val); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this & val}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @param val value to be and'ed with {@code this}. + * @return {@code this & val}. + * @throws NullPointerException if {@code val == null}. + */ + public BigInteger and(BigInteger val) { + return Logical.and(this, val); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this & ~val}. + * Evaluating {@code x.andNot(val)} returns the same result as {@code + * x.and(val.not())}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @param val value to be not'ed and then and'ed with {@code this}. + * @return {@code this & ~val}. + * @throws NullPointerException if {@code val == null}. + */ + public BigInteger andNot(BigInteger val) { + return Logical.andNot(this, val); + } + + /** + * Use {@code bitLength(0)} if you want to know the length of the binary value + * in bits. + *

+ * Returns the number of bits in the binary representation of {@code this} + * which differ from the sign bit. If {@code this} is positive the result is + * equivalent to the number of bits set in the binary representation of + * {@code this}. If {@code this} is negative the result is equivalent to the + * number of bits set in the binary representation of {@code -this-1}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @return number of bits in the binary representation of {@code this} which + * differ from the sign bit + */ + public int bitCount() { + return BitLevel.bitCount(this); + } + + /** + * Returns the length of the value's two's complement representation without + * leading zeros for positive numbers / without leading ones for negative + * values. + *

+ * The two's complement representation of {@code this} will be at least + * {@code bitLength() + 1} bits long. + *

+ * The value will fit into an {@code int} if {@code bitLength() < 32} or into + * a {@code long} if {@code bitLength() < 64}. + * + * @return the length of the minimal two's complement representation for + * {@code this} without the sign bit. + */ + public int bitLength() { + return BitLevel.bitLength(this); + } + + /** + * Returns a new {@code BigInteger} which has the same binary representation + * as {@code this} but with the bit at position n cleared. The result is + * equivalent to {@code this & ~(2^n)}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @param n position where the bit in {@code this} has to be cleared. + * @return {@code this & ~(2^n)}. + * @throws ArithmeticException if {@code n < 0}. + */ + public BigInteger clearBit(int n) { + if (testBit(n)) { + return BitLevel.flipBit(this, n); + } + return this; + } + + /** + * Compares this {@code BigInteger} with {@code val}. Returns one of the three + * values 1, 0, or -1. + * + * @param val value to be compared with {@code this}. + * @return {@code 1} if {@code this > val}, {@code -1} if {@code this < val} , + * {@code 0} if {@code this == val}. + * @throws NullPointerException if {@code val == null}. + */ + public int compareTo(BigInteger val) { + if (sign > val.sign) { + return GREATER; + } + if (sign < val.sign) { + return LESS; + } + if (numberLength > val.numberLength) { + return sign; + } + if (numberLength < val.numberLength) { + return -val.sign; + } + // Equal sign and equal numberLength + return (sign * Elementary.compareArrays(digits, val.digits, numberLength)); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this / divisor}. + * + * @param divisor value by which {@code this} is divided. + * @return {@code this / divisor}. + * @throws NullPointerException if {@code divisor == null}. + * @throws ArithmeticException if {@code divisor == 0}. + */ + public BigInteger divide(BigInteger divisor) { + if (divisor.sign == 0) { + // math.17=BigInteger divide by zero + throw new ArithmeticException("BigInteger divide by zero"); //$NON-NLS-1$ + } + int divisorSign = divisor.sign; + if (divisor.isOne()) { + return ((divisor.sign > 0) ? this : this.negate()); + } + int thisSign = sign; + int thisLen = numberLength; + int divisorLen = divisor.numberLength; + if (thisLen + divisorLen == 2) { + long val = (digits[0] & 0xFFFFFFFFL) / (divisor.digits[0] & 0xFFFFFFFFL); + if (thisSign != divisorSign) { + val = -val; + } + return valueOf(val); + } + int cmp = ((thisLen != divisorLen) ? ((thisLen > divisorLen) ? 1 : -1) + : Elementary.compareArrays(digits, divisor.digits, thisLen)); + if (cmp == EQUALS) { + return ((thisSign == divisorSign) ? ONE : MINUS_ONE); + } + if (cmp == LESS) { + return ZERO; + } + int resLength = thisLen - divisorLen + 1; + int resDigits[] = new int[resLength]; + int resSign = ((thisSign == divisorSign) ? 1 : -1); + if (divisorLen == 1) { + Division.divideArrayByInt(resDigits, digits, thisLen, divisor.digits[0]); + } else { + Division.divide(resDigits, resLength, digits, thisLen, divisor.digits, + divisorLen); + } + BigInteger result = new BigInteger(resSign, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Returns a {@code BigInteger} array which contains {@code this / divisor} at + * index 0 and {@code this % divisor} at index 1. + * + * @param divisor value by which {@code this} is divided. + * @return {@code [this / divisor, this % divisor]}. + * @throws NullPointerException if {@code divisor == null}. + * @throws ArithmeticException if {@code divisor == 0}. + * @see #divide + * @see #remainder + */ + public BigInteger[] divideAndRemainder(BigInteger divisor) { + int divisorSign = divisor.sign; + if (divisorSign == 0) { + // math.17=BigInteger divide by zero + throw new ArithmeticException("BigInteger divide by zero"); //$NON-NLS-1$ + } + int divisorLen = divisor.numberLength; + int[] divisorDigits = divisor.digits; + if (divisorLen == 1) { + return Division.divideAndRemainderByInteger(this, divisorDigits[0], + divisorSign); + } + // res[0] is a quotient and res[1] is a remainder: + int[] thisDigits = digits; + int thisLen = numberLength; + int cmp = (thisLen != divisorLen) ? ((thisLen > divisorLen) ? 1 : -1) + : Elementary.compareArrays(thisDigits, divisorDigits, thisLen); + if (cmp < 0) { + return new BigInteger[] {ZERO, this}; + } + int thisSign = sign; + int quotientLength = thisLen - divisorLen + 1; + int remainderLength = divisorLen; + int quotientSign = ((thisSign == divisorSign) ? 1 : -1); + int quotientDigits[] = new int[quotientLength]; + int remainderDigits[] = Division.divide(quotientDigits, quotientLength, + thisDigits, thisLen, divisorDigits, divisorLen); + BigInteger result0 = new BigInteger(quotientSign, quotientLength, + quotientDigits); + BigInteger result1 = new BigInteger(thisSign, remainderLength, + remainderDigits); + result0.cutOffLeadingZeroes(); + result1.cutOffLeadingZeroes(); + return new BigInteger[] {result0, result1}; + } + + /** + * Returns this {@code BigInteger} as an double value. If {@code this} is too + * big to be represented as an double, then {@code Double.POSITIVE_INFINITY} + * or {@code Double.NEGATIVE_INFINITY} is returned. Note, that not all + * integers x in the range [-Double.MAX_VALUE, Double.MAX_VALUE] can be + * represented as a double. The double representation has a mantissa of length + * 53. For example, 2^53+1 = 9007199254740993 is returned as double + * 9007199254740992.0. + * + * @return this {@code BigInteger} as a double value + */ + @Override + public double doubleValue() { + return Double.parseDouble(this.toString()); + } + + /** + * Returns {@code true} if {@code x} is a BigInteger instance and if this + * instance is equal to this {@code BigInteger}. + * + * @param x object to be compared with {@code this}. + * @return true if {@code x} is a BigInteger and {@code this == x}, {@code + * false} otherwise. + */ + @Override + public boolean equals(Object x) { + if (this == x) { + return true; + } + if (x instanceof BigInteger) { + BigInteger x1 = (BigInteger) x; + return sign == x1.sign && numberLength == x1.numberLength + && equalsArrays(x1.digits); + } + return false; + } + + /** + * Returns a new {@code BigInteger} which has the same binary representation + * as {@code this} but with the bit at position n flipped. The result is + * equivalent to {@code this ^ 2^n}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @param n position where the bit in {@code this} has to be flipped. + * @return {@code this ^ 2^n}. + * @throws ArithmeticException if {@code n < 0}. + */ + public BigInteger flipBit(int n) { + if (n < 0) { + // math.15=Negative bit address + throw new ArithmeticException("Negative bit address"); //$NON-NLS-1$ + } + return BitLevel.flipBit(this, n); + } + + /** + * Returns this {@code BigInteger} as an float value. If {@code this} is too + * big to be represented as an float, then {@code Float.POSITIVE_INFINITY} or + * {@code Float.NEGATIVE_INFINITY} is returned. Note, that not all integers x + * in the range [-Float.MAX_VALUE, Float.MAX_VALUE] can be represented as a + * float. The float representation has a mantissa of length 24. For example, + * 2^24+1 = 16777217 is returned as float 16777216.0. + * + * @return this {@code BigInteger} as a float value. + */ + @Override + public float floatValue() { + return Float.parseFloat(this.toString()); + } + + /** + * Returns a new {@code BigInteger} whose value is greatest common divisor of + * {@code this} and {@code val}. If {@code this==0} and {@code val==0} then + * zero is returned, otherwise the result is positive. + * + * @param val value with which the greatest common divisor is computed. + * @return {@code gcd(this, val)}. + * @throws NullPointerException if {@code val == null}. + */ + public BigInteger gcd(BigInteger val) { + BigInteger val1 = this.abs(); + BigInteger val2 = val.abs(); + // To avoid a possible division by zero + if (val1.signum() == 0) { + return val2; + } else if (val2.signum() == 0) { + return val1; + } + + // Optimization for small operands + // (op2.bitLength() < 64) and (op1.bitLength() < 64) + if (((val1.numberLength == 1) || ((val1.numberLength == 2) && (val1.digits[1] > 0))) + && (val2.numberLength == 1 || (val2.numberLength == 2 && val2.digits[1] > 0))) { + return BigInteger.valueOf(Division.gcdBinary(val1.longValue(), + val2.longValue())); + } + + return Division.gcdBinary(val1.copy(), val2.copy()); + } + + /** + * Returns the position of the lowest set bit in the two's complement + * representation of this {@code BigInteger}. If all bits are zero (this=0) + * then -1 is returned as result. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @return position of lowest bit if {@code this != 0}, {@code -1} otherwise + */ + public int getLowestSetBit() { + if (sign == 0) { + return -1; + } + // (sign != 0) implies that exists some non zero digit + int i = getFirstNonzeroDigit(); + return ((i << 5) + Integer.numberOfTrailingZeros(digits[i])); + } + + /** + * Returns a hash code for this {@code BigInteger}. + * + * @return hash code for {@code this}. + */ + @Override + public int hashCode() { + if (hashCode != 0) { + return hashCode; + } + for (int i = 0; i < digits.length; i++) { + hashCode = (hashCode * 33 + (digits[i] & 0xffffffff)); + } + hashCode = hashCode * sign; + return hashCode; + } + + /** + * Returns this {@code BigInteger} as an int value. If {@code this} is too big + * to be represented as an int, then {@code this} % 2^32 is returned. + * + * @return this {@code BigInteger} as an int value. + */ + @Override + public int intValue() { + return (sign * digits[0]); + } + + /** + * Tests whether this {@code BigInteger} is probably prime. If {@code true} is + * returned, then this is prime with a probability beyond (1-1/2^certainty). + * If {@code false} is returned, then this is definitely composite. If the + * argument {@code certainty} <= 0, then this method returns true. + * + * @param certainty tolerated primality uncertainty. + * @return {@code true}, if {@code this} is probably prime, {@code false} + * otherwise. + */ + public boolean isProbablePrime(int certainty) { + return Primality.isProbablePrime(abs(), certainty); + } + + /** + * Returns this {@code BigInteger} as an long value. If {@code this} is too + * big to be represented as an long, then {@code this} % 2^64 is returned. + * + * @return this {@code BigInteger} as a long value. + */ + @Override + public long longValue() { + long value = (numberLength > 1) ? (((long) digits[1]) << 32) + | (digits[0] & 0xFFFFFFFFL) : (digits[0] & 0xFFFFFFFFL); + return (sign * value); + } + + /** + * Returns the maximum of this {@code BigInteger} and {@code val}. + * + * @param val value to be used to compute the maximum with {@code this} + * @return {@code max(this, val)} + * @throws NullPointerException if {@code val == null} + */ + public BigInteger max(BigInteger val) { + return ((this.compareTo(val) == GREATER) ? this : val); + } + + /** + * Returns the minimum of this {@code BigInteger} and {@code val}. + * + * @param val value to be used to compute the minimum with {@code this}. + * @return {@code min(this, val)}. + * @throws NullPointerException if {@code val == null}. + */ + public BigInteger min(BigInteger val) { + return ((this.compareTo(val) == LESS) ? this : val); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this mod m}. The + * modulus {@code m} must be positive. The result is guaranteed to be in the + * interval {@code [0, m)} (0 inclusive, m exclusive). The behavior of this + * function is not equivalent to the behavior of the % operator defined for + * the built-in {@code int}'s. + * + * @param m the modulus. + * @return {@code this mod m}. + * @throws NullPointerException if {@code m == null}. + * @throws ArithmeticException if {@code m < 0}. + */ + public BigInteger mod(BigInteger m) { + if (m.sign <= 0) { + // math.18=BigInteger: modulus not positive + throw new ArithmeticException("BigInteger: modulus not positive"); //$NON-NLS-1$ + } + BigInteger rem = remainder(m); + return ((rem.sign < 0) ? rem.add(m) : rem); + } + + // @Override + // public double doubleValue() { + // return Conversion.bigInteger2Double(this); + // } + + /** + * Returns a new {@code BigInteger} whose value is {@code 1/this mod m}. The + * modulus {@code m} must be positive. The result is guaranteed to be in the + * interval {@code [0, m)} (0 inclusive, m exclusive). If {@code this} is not + * relatively prime to m, then an exception is thrown. + * + * @param m the modulus. + * @return {@code 1/this mod m}. + * @throws NullPointerException if {@code m == null} + * @throws ArithmeticException if {@code m < 0 or} if {@code this} is not + * relatively prime to {@code m} + */ + public BigInteger modInverse(BigInteger m) { + if (m.sign <= 0) { + // math.18=BigInteger: modulus not positive + throw new ArithmeticException("BigInteger: modulus not positive"); //$NON-NLS-1$ + } + // If both are even, no inverse exists + if (!(testBit(0) || m.testBit(0))) { + // math.19=BigInteger not invertible. + throw new ArithmeticException("BigInteger not invertible."); //$NON-NLS-1$ + } + if (m.isOne()) { + return ZERO; + } + + // From now on: (m > 1) + BigInteger res = Division.modInverseMontgomery(abs().mod(m), m); + if (res.sign == 0) { + // math.19=BigInteger not invertible. + throw new ArithmeticException("BigInteger not invertible."); //$NON-NLS-1$ + } + + res = ((sign < 0) ? m.subtract(res) : res); + return res; + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this^exponent mod m} + * . The modulus {@code m} must be positive. The result is guaranteed to be in + * the interval {@code [0, m)} (0 inclusive, m exclusive). If the exponent is + * negative, then {@code this.modInverse(m)^(-exponent) mod m)} is computed. + * The inverse of this only exists if {@code this} is relatively prime to m, + * otherwise an exception is thrown. + * + * @param exponent the exponent. + * @param m the modulus. + * @return {@code this^exponent mod val}. + * @throws NullPointerException if {@code m == null} or {@code exponent == + * null}. + * @throws ArithmeticException if {@code m < 0} or if {@code exponent<0} and + * this is not relatively prime to {@code m}. + */ + public BigInteger modPow(BigInteger exponent, BigInteger m) { + if (m.sign <= 0) { + // math.18=BigInteger: modulus not positive + throw new ArithmeticException("BigInteger: modulus not positive"); //$NON-NLS-1$ + } + BigInteger base = this; + + if (m.isOne() | (exponent.sign > 0 & base.sign == 0)) { + return BigInteger.ZERO; + } + if (base.sign == 0 && exponent.sign == 0) { + return BigInteger.ONE; + } + if (exponent.sign < 0) { + base = modInverse(m); + exponent = exponent.negate(); + } + // From now on: (m > 0) and (exponent >= 0) + BigInteger res = (m.testBit(0)) ? Division.oddModPow(base.abs(), exponent, + m) : Division.evenModPow(base.abs(), exponent, m); + if ((base.sign < 0) && exponent.testBit(0)) { + // -b^e mod m == ((-1 mod m) * (b^e mod m)) mod m + res = m.subtract(BigInteger.ONE).multiply(res).mod(m); + } + // else exponent is even, so base^exp is positive + return res; + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this * val}. + * + * @param val value to be multiplied with {@code this}. + * @return {@code this * val}. + * @throws NullPointerException if {@code val == null}. + */ + public BigInteger multiply(BigInteger val) { + // This let us to throw NullPointerException when val == null + if (val.sign == 0) { + return ZERO; + } + if (sign == 0) { + return ZERO; + } + return Multiplication.multiply(this, val); + } + + /** + * Returns a new {@code BigInteger} whose value is the {@code -this}. + * + * @return {@code -this}. + */ + public BigInteger negate() { + return ((sign == 0) ? this : new BigInteger(-sign, numberLength, digits)); + } + + /** + * Returns the smallest integer x > {@code this} which is probably prime as a + * {@code BigInteger} instance. The probability that the returned {@code + * BigInteger} is prime is beyond (1-1/2^80). + * + * @return smallest integer > {@code this} which is robably prime. + * @throws ArithmeticException if {@code this < 0}. + */ + public BigInteger nextProbablePrime() { + if (sign < 0) { + // math.1A=start < 0: {0} + throw new ArithmeticException("start < 0: " + this); //$NON-NLS-1$ + } + return Primality.nextProbablePrime(this); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code ~this}. The result + * of this operation is {@code -this-1}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @return {@code ~this}. + */ + public BigInteger not() { + return Logical.not(this); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this | val}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @param val value to be or'ed with {@code this}. + * @return {@code this | val}. + * @throws NullPointerException if {@code val == null}. + */ + public BigInteger or(BigInteger val) { + return Logical.or(this, val); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this ^ exp}. + * + * @param exp exponent to which {@code this} is raised. + * @return {@code this ^ exp}. + * @throws ArithmeticException if {@code exp < 0}. + */ + public BigInteger pow(int exp) { + if (exp < 0) { + // math.16=Negative exponent + throw new ArithmeticException("Negative exponent"); //$NON-NLS-1$ + } + if (exp == 0) { + return ONE; + } else if (exp == 1 || equals(ONE) || equals(ZERO)) { + return this; + } + + // if even take out 2^x factor which we can + // calculate by shifting. + if (!testBit(0)) { + int x = 1; + while (!testBit(x)) { + x++; + } + return getPowerOfTwo(x * exp).multiply(this.shiftRight(x).pow(exp)); + } + return Multiplication.pow(this, exp); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this % divisor}. + * Regarding signs this methods has the same behavior as the % operator on + * int's, i.e. the sign of the remainder is the same as the sign of this. + * + * @param divisor value by which {@code this} is divided. + * @return {@code this % divisor}. + * @throws NullPointerException if {@code divisor == null}. + * @throws ArithmeticException if {@code divisor == 0}. + */ + public BigInteger remainder(BigInteger divisor) { + if (divisor.sign == 0) { + // math.17=BigInteger divide by zero + throw new ArithmeticException("BigInteger divide by zero"); //$NON-NLS-1$ + } + int thisLen = numberLength; + int divisorLen = divisor.numberLength; + if (((thisLen != divisorLen) ? ((thisLen > divisorLen) ? 1 : -1) + : Elementary.compareArrays(digits, divisor.digits, thisLen)) == LESS) { + return this; + } + int resLength = divisorLen; + int resDigits[] = new int[resLength]; + if (resLength == 1) { + resDigits[0] = Division.remainderArrayByInt(digits, thisLen, + divisor.digits[0]); + } else { + int qLen = thisLen - divisorLen + 1; + resDigits = Division.divide(null, qLen, digits, thisLen, divisor.digits, + divisorLen); + } + BigInteger result = new BigInteger(sign, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Returns a new {@code BigInteger} which has the same binary representation + * as {@code this} but with the bit at position n set. The result is + * equivalent to {@code this | 2^n}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @param n position where the bit in {@code this} has to be set. + * @return {@code this | 2^n}. + * @throws ArithmeticException if {@code n < 0}. + */ + public BigInteger setBit(int n) { + if (!testBit(n)) { + return BitLevel.flipBit(this, n); + } + return this; + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this << n}. The + * result is equivalent to {@code this * 2^n} if n >= 0. The shift distance + * may be negative which means that {@code this} is shifted right. The result + * then corresponds to {@code floor(this / 2^(-n))}. + *

+ * Implementation Note: Usage of this method on negative values is not + * recommended as the current implementation is not efficient. + * + * @param n shift distance. + * @return {@code this << n} if {@code n >= 0}; {@code this >> (-n)}. + * otherwise + */ + public BigInteger shiftLeft(int n) { + if ((n == 0) || (sign == 0)) { + return this; + } + return ((n > 0) ? BitLevel.shiftLeft(this, n) : BitLevel.shiftRight(this, + -n)); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this >> n}. For + * negative arguments, the result is also negative. The shift distance may be + * negative which means that {@code this} is shifted left. + *

+ * Implementation Note: Usage of this method on negative values is not + * recommended as the current implementation is not efficient. + * + * @param n shift distance + * @return {@code this >> n} if {@code n >= 0}; {@code this << (-n)} otherwise + */ + public BigInteger shiftRight(int n) { + if ((n == 0) || (sign == 0)) { + return this; + } + return ((n > 0) ? BitLevel.shiftRight(this, n) : BitLevel.shiftLeft(this, + -n)); + } + + /** + * Returns the sign of this {@code BigInteger}. + * + * @return {@code -1} if {@code this < 0}, {@code 0} if {@code this == 0}, + * {@code 1} if {@code this > 0}. + */ + public int signum() { + return sign; + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this - val}. + * + * @param val value to be subtracted from {@code this}. + * @return {@code this - val}. + * @throws NullPointerException if {@code val == null}. + */ + public BigInteger subtract(BigInteger val) { + return Elementary.subtract(this, val); + } + + /** + * Tests whether the bit at position n in {@code this} is set. The result is + * equivalent to {@code this & (2^n) != 0}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @param n position where the bit in {@code this} has to be inspected. + * @return {@code this & (2^n) != 0}. + * @throws ArithmeticException if {@code n < 0}. + */ + public boolean testBit(int n) { + if (n == 0) { + return ((digits[0] & 1) != 0); + } + if (n < 0) { + // math.15=Negative bit address + throw new ArithmeticException("Negative bit address"); //$NON-NLS-1$ + } + int intCount = n >> 5; + if (intCount >= numberLength) { + return (sign < 0); + } + int digit = digits[intCount]; + n = (1 << (n & 31)); // int with 1 set to the needed position + if (sign < 0) { + int firstNonZeroDigit = getFirstNonzeroDigit(); + if (intCount < firstNonZeroDigit) { + return false; + } else if (firstNonZeroDigit == intCount) { + digit = -digit; + } else { + digit = ~digit; + } + } + return ((digit & n) != 0); + } + + /** + * Returns the two's complement representation of this BigInteger in a byte + * array. + * + * @return two's complement representation of {@code this}. + */ + public byte[] toByteArray() { + if (this.sign == 0) { + return new byte[] {0}; + } + BigInteger temp = this; + int bitLen = bitLength(); + int iThis = getFirstNonzeroDigit(); + int bytesLen = (bitLen >> 3) + 1; + /* + * Puts the little-endian int array representing the magnitude of this + * BigInteger into the big-endian byte array. + */ + byte[] bytes = new byte[bytesLen]; + int firstByteNumber = 0; + int highBytes; + int digitIndex = 0; + int bytesInInteger = 4; + int digit; + int hB; + + if (bytesLen - (numberLength << 2) == 1) { + bytes[0] = (byte) ((sign < 0) ? -1 : 0); + highBytes = 4; + firstByteNumber++; + } else { + hB = bytesLen & 3; + highBytes = (hB == 0) ? 4 : hB; + } + + digitIndex = iThis; + bytesLen -= iThis << 2; + + if (sign < 0) { + digit = -temp.digits[digitIndex]; + digitIndex++; + if (digitIndex == numberLength) { + bytesInInteger = highBytes; + } + for (int i = 0; i < bytesInInteger; i++, digit >>= 8) { + bytes[--bytesLen] = (byte) digit; + } + while (bytesLen > firstByteNumber) { + digit = ~temp.digits[digitIndex]; + digitIndex++; + if (digitIndex == numberLength) { + bytesInInteger = highBytes; + } + for (int i = 0; i < bytesInInteger; i++, digit >>= 8) { + bytes[--bytesLen] = (byte) digit; + } + } + } else { + while (bytesLen > firstByteNumber) { + digit = temp.digits[digitIndex]; + digitIndex++; + if (digitIndex == numberLength) { + bytesInInteger = highBytes; + } + for (int i = 0; i < bytesInInteger; i++, digit >>= 8) { + bytes[--bytesLen] = (byte) digit; + } + } + } + return bytes; + } + + /** + * Returns a string representation of this {@code BigInteger} in decimal form. + * + * @return a string representation of {@code this} in decimal form. + */ + @Override + public String toString() { + return Conversion.toDecimalScaledString(this, 0); + } + + /** + * Returns a string containing a string representation of this {@code + * BigInteger} with base radix. If {@code radix} is less than + * {@link Character#MIN_RADIX} or greater than {@link Character#MAX_RADIX} + * then a decimal representation is returned. The characters of the string + * representation are generated with method {@link Character#forDigit}. + * + * @param radix base to be used for the string representation. + * @return a string representation of this with radix 10. + */ + public String toString(int radix) { + return Conversion.bigInteger2String(this, radix); + } + + /** + * Returns a new {@code BigInteger} whose value is {@code this ^ val}. + *

+ * Implementation Note: Usage of this method is not recommended as the + * current implementation is not efficient. + * + * @param val value to be xor'ed with {@code this} + * @return {@code this ^ val} + * @throws NullPointerException if {@code val == null} + */ + public BigInteger xor(BigInteger val) { + return Logical.xor(this, val); + } + + /* + * Returns a copy of the current instance to achieve immutability + */ + BigInteger copy() { + int[] copyDigits = new int[numberLength]; + System.arraycopy(digits, 0, copyDigits, 0, numberLength); + return new BigInteger(sign, numberLength, copyDigits); + } + + /* Private Methods */ + + /** + * Decreases {@code numberLength} if there are zero high elements. + */ + final void cutOffLeadingZeroes() { + while ((numberLength > 0) && (digits[--numberLength] == 0)) { + // Empty + } + if (digits[numberLength++] == 0) { + sign = 0; + } + } + + boolean equalsArrays(final int[] b) { + int i; + for (i = numberLength - 1; (i >= 0) && (digits[i] == b[i]); i--) { + // Empty + } + return i < 0; + } + + int getFirstNonzeroDigit() { + if (firstNonzeroDigit == -2) { + int i; + if (this.sign == 0) { + i = -1; + } else { + for (i = 0; digits[i] == 0; i++) { + // Empty + } + } + firstNonzeroDigit = i; + } + return firstNonzeroDigit; + } + + /** + * Tests if {@code this.abs()} is equals to {@code ONE}. + */ + boolean isOne() { + return ((numberLength == 1) && (digits[0] == 1)); + } + + BigInteger shiftLeftOneBit() { + return (sign == 0) ? this : BitLevel.shiftLeftOneBit(this); + } + + void unCache() { + firstNonzeroDigit = -2; + } + + /** + * Puts a big-endian byte array into a little-endian applying two complement. + */ + private void putBytesNegativeToIntegers(byte[] byteValues) { + int bytesLen = byteValues.length; + int highBytes = bytesLen & 3; + numberLength = (bytesLen >> 2) + ((highBytes == 0) ? 0 : 1); + digits = new int[numberLength]; + int i = 0; + // Setting the sign + digits[numberLength - 1] = -1; + // Put bytes to the int array starting from the end of the byte array + while (bytesLen > highBytes) { + digits[i] = (byteValues[--bytesLen] & 0xFF) + | (byteValues[--bytesLen] & 0xFF) << 8 + | (byteValues[--bytesLen] & 0xFF) << 16 + | (byteValues[--bytesLen] & 0xFF) << 24; + if (digits[i] != 0) { + digits[i] = -digits[i]; + firstNonzeroDigit = i; + i++; + while (bytesLen > highBytes) { + digits[i] = (byteValues[--bytesLen] & 0xFF) + | (byteValues[--bytesLen] & 0xFF) << 8 + | (byteValues[--bytesLen] & 0xFF) << 16 + | (byteValues[--bytesLen] & 0xFF) << 24; + digits[i] = ~digits[i]; + i++; + } + break; + } + i++; + } + if (highBytes != 0) { + // Put the first bytes in the highest element of the int array + if (firstNonzeroDigit != -2) { + for (int j = 0; j < bytesLen; j++) { + digits[i] = (digits[i] << 8) | (byteValues[j] & 0xFF); + } + digits[i] = ~digits[i]; + } else { + for (int j = 0; j < bytesLen; j++) { + digits[i] = (digits[i] << 8) | (byteValues[j] & 0xFF); + } + digits[i] = -digits[i]; + } + } + } + + /** + * Puts a big-endian byte array into a little-endian int array. + */ + private void putBytesPositiveToIntegers(byte[] byteValues) { + int bytesLen = byteValues.length; + int highBytes = bytesLen & 3; + numberLength = (bytesLen >> 2) + ((highBytes == 0) ? 0 : 1); + digits = new int[numberLength]; + int i = 0; + // Put bytes to the int array starting from the end of the byte array + while (bytesLen > highBytes) { + digits[i++] = (byteValues[--bytesLen] & 0xFF) + | (byteValues[--bytesLen] & 0xFF) << 8 + | (byteValues[--bytesLen] & 0xFF) << 16 + | (byteValues[--bytesLen] & 0xFF) << 24; + } + // Put the first bytes in the highest element of the int array + for (int j = 0; j < bytesLen; j++) { + digits[i] = (digits[i] << 8) | (byteValues[j] & 0xFF); + } + } +} diff --git a/gwt/jre/java/math/BitLevel.java b/gwt/jre/java/math/BitLevel.java new file mode 100644 index 0000000..82e88c9 --- /dev/null +++ b/gwt/jre/java/math/BitLevel.java @@ -0,0 +1,379 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +/** + * Static library that provides all the bit level operations for + * {@link BigInteger}. The operations are:

All operations are provided in immutable way, and some in both mutable + * and immutable. + */ +class BitLevel { + + /** + * @see BigInteger#bitCount() + * @param val + * @return + */ + static int bitCount(BigInteger val) { + int bCount = 0; + + if (val.sign == 0) { + return 0; + } + + int i = val.getFirstNonzeroDigit(); + if (val.sign > 0) { + for (; i < val.numberLength; i++) { + bCount += Integer.bitCount(val.digits[i]); + } + } else { + // (sign < 0) + // this digit absorbs the carry + bCount += Integer.bitCount(-val.digits[i]); + for (i++; i < val.numberLength; i++) { + bCount += Integer.bitCount(~val.digits[i]); + } + // We take the complement sum: + bCount = (val.numberLength << 5) - bCount; + } + return bCount; + } + + /** + * @see BigInteger#bitLength() + * @param val + * @return + */ + static int bitLength(BigInteger val) { + if (val.sign == 0) { + return 0; + } + int bLength = (val.numberLength << 5); + int highDigit = val.digits[val.numberLength - 1]; + + if (val.sign < 0) { + int i = val.getFirstNonzeroDigit(); + // We reduce the problem to the positive case. + if (i == val.numberLength - 1) { + // ~~ is to handle int overflow + highDigit = ~~(highDigit - 1); + } + } + // Subtracting all sign bits + bLength -= Integer.numberOfLeadingZeros(highDigit); + return bLength; + } + + /** + * Performs a flipBit on the BigInteger, returning a BigInteger with the the + * specified bit flipped. + * + * @param val BigInteger to operate on + * @param n the bit to flip + */ + static BigInteger flipBit(BigInteger val, int n) { + int resSign = (val.sign == 0) ? 1 : val.sign; + int intCount = n >> 5; + int bitN = n & 31; + int resLength = Math.max(intCount + 1, val.numberLength) + 1; + int resDigits[] = new int[resLength]; + int i; + + int bitNumber = 1 << bitN; + System.arraycopy(val.digits, 0, resDigits, 0, val.numberLength); + + if (val.sign < 0) { + if (intCount >= val.numberLength) { + resDigits[intCount] = bitNumber; + } else { + // val.sign<0 y intCount < val.numberLength + int firstNonZeroDigit = val.getFirstNonzeroDigit(); + if (intCount > firstNonZeroDigit) { + resDigits[intCount] ^= bitNumber; + } else if (intCount < firstNonZeroDigit) { + resDigits[intCount] = -bitNumber; + for (i = intCount + 1; i < firstNonZeroDigit; i++) { + resDigits[i] = -1; + } + resDigits[i] = resDigits[i]--; + } else { + i = intCount; + resDigits[i] = -((-resDigits[intCount]) ^ bitNumber); + if (resDigits[i] == 0) { + for (i++; resDigits[i] == -1; i++) { + resDigits[i] = 0; + } + resDigits[i]++; + } + } + } + } else { + // case where val is positive + resDigits[intCount] ^= bitNumber; + } + BigInteger result = new BigInteger(resSign, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Performs {@code val <<= count}. + */ + // val should have enough place (and one digit more) + static void inplaceShiftLeft(BigInteger val, int count) { + int intCount = count >> 5; // count of integers + val.numberLength += intCount + + (Integer.numberOfLeadingZeros(val.digits[val.numberLength - 1]) + - (count & 31) >= 0 ? 0 : 1); + shiftLeft(val.digits, val.digits, intCount, count & 31); + val.cutOffLeadingZeroes(); + val.unCache(); + } + + /** + * Performs {@code val >>= count} where {@code val} is a positive number. + */ + static void inplaceShiftRight(BigInteger val, int count) { + int sign = val.signum(); + if (count == 0 || val.signum() == 0) { + return; + } + int intCount = count >> 5; // count of integers + val.numberLength -= intCount; + if (!shiftRight(val.digits, val.numberLength, val.digits, intCount, + count & 31) + && sign < 0) { + // remainder not zero: add one to the result + int i; + for (i = 0; (i < val.numberLength) && (val.digits[i] == -1); i++) { + val.digits[i] = 0; + } + if (i == val.numberLength) { + val.numberLength++; + } + val.digits[i]++; + } + val.cutOffLeadingZeroes(); + val.unCache(); + } + + /** + * Check if there are 1s in the lowest bits of this BigInteger. + * + * @param numberOfBits the number of the lowest bits to check + * @return false if all bits are 0s, true otherwise + */ + static boolean nonZeroDroppedBits(int numberOfBits, int digits[]) { + int intCount = numberOfBits >> 5; + int bitCount = numberOfBits & 31; + int i; + + for (i = 0; (i < intCount) && (digits[i] == 0); i++) { + } + return ((i != intCount) || (digits[i] << (32 - bitCount) != 0)); + } + + /** + * @see BigInteger#shiftLeft(int) + * @param source + * @param count + * @return + */ + static BigInteger shiftLeft(BigInteger source, int count) { + int intCount = count >> 5; + count &= 31; // %= 32 + int resLength = source.numberLength + intCount + ((count == 0) ? 0 : 1); + int resDigits[] = new int[resLength]; + + shiftLeft(resDigits, source.digits, intCount, count); + BigInteger result = new BigInteger(source.sign, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Abstractly shifts left an array of integers in little endian (i.e., + * shift it right). Total shift distance in bits is intCount * 32 + count + * + * @param result the destination array + * @param source the source array + * @param intCount the shift distance in integers + * @param count an additional shift distance in bits + */ + static void shiftLeft(int result[], int source[], int intCount, int count) { + if (count == 0) { + System.arraycopy(source, 0, result, intCount, result.length - intCount); + } else { + int rightShiftCount = 32 - count; + + result[result.length - 1] = 0; + for (int i = result.length - 1; i > intCount; i--) { + result[i] |= source[i - intCount - 1] >>> rightShiftCount; + result[i - 1] = source[i - intCount - 1] << count; + } + } + + for (int i = 0; i < intCount; i++) { + result[i] = 0; + } + } + + static BigInteger shiftLeftOneBit(BigInteger source) { + int srcLen = source.numberLength; + int resLen = srcLen + 1; + int resDigits[] = new int[resLen]; + shiftLeftOneBit(resDigits, source.digits, srcLen); + BigInteger result = new BigInteger(source.sign, resLen, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Shifts the source digits left one bit, creating a value whose magnitude is + * doubled. + * + * @param result an array of digits that will hold the computed result when + * this method returns. The size of this array is {@code srcLen + 1}, + * and the format is the same as {@link BigInteger#digits}. + * @param source the array of digits to shift left, in the same format as + * {@link BigInteger#digits}. + * @param srcLen the length of {@code source}; may be less than {@code + * source.length} + */ + static void shiftLeftOneBit(int result[], int source[], int srcLen) { + int carry = 0; + for (int i = 0; i < srcLen; i++) { + int val = source[i]; + result[i] = (val << 1) | carry; + carry = val >>> 31; + } + if (carry != 0) { + result[srcLen] = carry; + } + } + + /** + * @see BigInteger#shiftRight(int) + * @param source + * @param count + * @return + */ + static BigInteger shiftRight(BigInteger source, int count) { + int intCount = count >> 5; // count of integers + count &= 31; // count of remaining bits + if (intCount >= source.numberLength) { + return ((source.sign < 0) ? BigInteger.MINUS_ONE : BigInteger.ZERO); + } + int i; + int resLength = source.numberLength - intCount; + int resDigits[] = new int[resLength + 1]; + + shiftRight(resDigits, resLength, source.digits, intCount, count); + if (source.sign < 0) { + // Checking if the dropped bits are zeros (the remainder equals to + // 0) + for (i = 0; (i < intCount) && (source.digits[i] == 0); i++) { + } + // If the remainder is not zero, add 1 to the result + if ((i < intCount) + || ((count > 0) && ((source.digits[i] << (32 - count)) != 0))) { + for (i = 0; (i < resLength) && (resDigits[i] == -1); i++) { + resDigits[i] = 0; + } + if (i == resLength) { + resLength++; + } + resDigits[i]++; + } + } + BigInteger result = new BigInteger(source.sign, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Shifts right an array of integers. Total shift distance in bits is intCount + * * 32 + count. + * + * @param result the destination array + * @param resultLen the destination array's length + * @param source the source array + * @param intCount the number of elements to be shifted + * @param count the number of bits to be shifted + * @return dropped bit's are all zero (i.e. remaider is zero) + */ + static boolean shiftRight(int result[], int resultLen, int source[], + int intCount, int count) { + int i; + boolean allZero = true; + for (i = 0; i < intCount; i++) { + allZero &= source[i] == 0; + } + if (count == 0) { + System.arraycopy(source, intCount, result, 0, resultLen); + i = resultLen; + } else { + int leftShiftCount = 32 - count; + + allZero &= (source[i] << leftShiftCount) == 0; + for (i = 0; i < resultLen - 1; i++) { + result[i] = (source[i + intCount] >>> count) + | (source[i + intCount + 1] << leftShiftCount); + } + result[i] = (source[i + intCount] >>> count); + i++; + } + + return allZero; + } + + /** + * Performs a fast bit testing for positive numbers. The bit to to be tested + * must be in the range {@code [0, val.bitLength()-1]} + */ + static boolean testBit(BigInteger val, int n) { + // PRE: 0 <= n < val.bitLength() + return ((val.digits[n >> 5] & (1 << (n & 31))) != 0); + } + + /** + * Just to denote that this class can't be instantiated. + */ + private BitLevel() { + } +} diff --git a/gwt/jre/java/math/Conversion.java b/gwt/jre/java/math/Conversion.java new file mode 100644 index 0000000..14cc0bb --- /dev/null +++ b/gwt/jre/java/math/Conversion.java @@ -0,0 +1,488 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +/** + * Static library that provides {@link BigInteger} base conversion from/to any + * integer represented in a {@link java.lang.String} Object. + */ +class Conversion { + + /** + * bigRadices values are precomputed maximal powers of radices (integer + * numbers from 2 to 36) that fit into unsigned int (32 bits). bigRadices[0] = + * 2 ^ 31, bigRadices[8] = 10 ^ 9, etc. + */ + + static final int bigRadices[] = { + -2147483648, 1162261467, 1073741824, 1220703125, 362797056, 1977326743, + 1073741824, 387420489, 1000000000, 214358881, 429981696, 815730721, + 1475789056, 170859375, 268435456, 410338673, 612220032, 893871739, + 1280000000, 1801088541, 113379904, 148035889, 191102976, 244140625, + 308915776, 387420489, 481890304, 594823321, 729000000, 887503681, + 1073741824, 1291467969, 1544804416, 1838265625, 60466176}; + + /** + * Holds the maximal exponent for each radix, so that + * radixdigitFitInInt[radix] fit in an {@code int} (32 bits). + */ + static final int[] digitFitInInt = { + -1, -1, 31, 19, 15, 13, 11, 11, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, + 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5}; + + /** + * @see BigInteger#toString(int) + * @param val + * @param radix + * @return + */ + static String bigInteger2String(BigInteger val, int radix) { + int sign = val.sign; + int numberLength = val.numberLength; + int digits[] = val.digits; + + if (sign == 0) { + return "0"; //$NON-NLS-1$ + } + if (numberLength == 1) { + int highDigit = digits[numberLength - 1]; + long v = highDigit & 0xFFFFFFFFL; + if (sign < 0) { + v = -v; + } + return Long.toString(v, radix); + } + if ((radix == 10) || (radix < Character.MIN_RADIX) + || (radix > Character.MAX_RADIX)) { + return val.toString(); + } + double bitsForRadixDigit; + bitsForRadixDigit = Math.log(radix) / Math.log(2); + int resLengthInChars = (int) (val.abs().bitLength() / bitsForRadixDigit + ((sign < 0) + ? 1 : 0)) + 1; + + char result[] = new char[resLengthInChars]; + int currentChar = resLengthInChars; + int resDigit; + if (radix != 16) { + int temp[] = new int[numberLength]; + System.arraycopy(digits, 0, temp, 0, numberLength); + int tempLen = numberLength; + int charsPerInt = digitFitInInt[radix]; + int i; + // get the maximal power of radix that fits in int + int bigRadix = bigRadices[radix - 2]; + while (true) { + // divide the array of digits by bigRadix and convert remainders + // to characters collecting them in the char array + resDigit = Division.divideArrayByInt(temp, temp, tempLen, bigRadix); + int previous = currentChar; + do { + result[--currentChar] = Character.forDigit(resDigit % radix, radix); + } while (((resDigit /= radix) != 0) && (currentChar != 0)); + int delta = charsPerInt - previous + currentChar; + for (i = 0; i < delta && currentChar > 0; i++) { + result[--currentChar] = '0'; + } + for (i = tempLen - 1; (i > 0) && (temp[i] == 0); i--) { + // empty + } + tempLen = i + 1; + if ((tempLen == 1) && (temp[0] == 0)) { // the quotient is 0 + break; + } + } + } else { + // radix == 16 + for (int i = 0; i < numberLength; i++) { + for (int j = 0; (j < 8) && (currentChar > 0); j++) { + resDigit = digits[i] >> (j << 2) & 0xf; + result[--currentChar] = Character.forDigit(resDigit, 16); + } + } + } + while (result[currentChar] == '0') { + currentChar++; + } + if (sign == -1) { + result[--currentChar] = '-'; + } + return new String(result, currentChar, resLengthInChars - currentChar); + } + + static long divideLongByBillion(long a) { + long quot; + long rem; + + if (a >= 0) { + long bLong = 1000000000L; + quot = (a / bLong); + rem = (a % bLong); + } else { + /* + * Make the dividend positive shifting it right by 1 bit then get the + * quotient an remainder and correct them properly + */ + long aPos = a >>> 1; + long bPos = 1000000000L >>> 1; + quot = aPos / bPos; + rem = aPos % bPos; + // double the remainder and add 1 if 'a' is odd + rem = (rem << 1) + (a & 1); + } + return ((rem << 32) | (quot & 0xFFFFFFFFL)); + } + + /** + * Builds the correspondent {@code String} representation of {@code val} being + * scaled by {@code scale}. + * + * @see BigInteger#toString() + * @see BigDecimal#toString() + */ + static String toDecimalScaledString(BigInteger val, int scale) { + int sign = val.sign; + int numberLength = val.numberLength; + int digits[] = val.digits; + int resLengthInChars; + int currentChar; + char result[]; + + if (sign == 0) { + switch (scale) { + case 0: + return "0"; //$NON-NLS-1$ + case 1: + return "0.0"; //$NON-NLS-1$ + case 2: + return "0.00"; //$NON-NLS-1$ + case 3: + return "0.000"; //$NON-NLS-1$ + case 4: + return "0.0000"; //$NON-NLS-1$ + case 5: + return "0.00000"; //$NON-NLS-1$ + case 6: + return "0.000000"; //$NON-NLS-1$ + default: + StringBuilder result1 = new StringBuilder(); + if (scale < 0) { + result1.append("0E+"); //$NON-NLS-1$ + } else { + result1.append("0E"); //$NON-NLS-1$ + } + result1.append(-scale); + return result1.toString(); + } + } + // one 32-bit unsigned value may contains 10 decimal digits + resLengthInChars = numberLength * 10 + 1 + 7; + // Explanation why +1+7: + // +1 - one char for sign if needed. + // +7 - For "special case 2" (see below) we have 7 free chars for + // inserting necessary scaled digits. + result = new char[resLengthInChars + 1]; + // allocated [resLengthInChars+1] characters. + // a free latest character may be used for "special case 1" (see + // below) + currentChar = resLengthInChars; + if (numberLength == 1) { + int highDigit = digits[0]; + if (highDigit < 0) { + long v = highDigit & 0xFFFFFFFFL; + do { + long prev = v; + v /= 10; + result[--currentChar] = (char) (0x0030 + ((int) (prev - v * 10))); + } while (v != 0); + } else { + int v = highDigit; + do { + int prev = v; + v /= 10; + result[--currentChar] = (char) (0x0030 + (prev - v * 10)); + } while (v != 0); + } + } else { + int temp[] = new int[numberLength]; + int tempLen = numberLength; + System.arraycopy(digits, 0, temp, 0, tempLen); + BIG_LOOP : while (true) { + // divide the array of digits by bigRadix and convert + // remainders + // to characters collecting them in the char array + long result11 = 0; + for (int i1 = tempLen - 1; i1 >= 0; i1--) { + long temp1 = (result11 << 32) + (temp[i1] & 0xFFFFFFFFL); + long res = divideLongByBillion(temp1); + temp[i1] = (int) res; + result11 = (int) (res >> 32); + } + int resDigit = (int) result11; + int previous = currentChar; + do { + result[--currentChar] = (char) (0x0030 + (resDigit % 10)); + } while (((resDigit /= 10) != 0) && (currentChar != 0)); + int delta = 9 - previous + currentChar; + for (int i = 0; (i < delta) && (currentChar > 0); i++) { + result[--currentChar] = '0'; + } + int j = tempLen - 1; + for (; temp[j] == 0; j--) { + if (j == 0) { // means temp[0] == 0 + break BIG_LOOP; + } + } + tempLen = j + 1; + } + while (result[currentChar] == '0') { + currentChar++; + } + } + boolean negNumber = (sign < 0); + int exponent = resLengthInChars - currentChar - scale - 1; + if (scale == 0) { + if (negNumber) { + result[--currentChar] = '-'; + } + return new String(result, currentChar, resLengthInChars - currentChar); + } + if ((scale > 0) && (exponent >= -6)) { + if (exponent >= 0) { + // special case 1 + int insertPoint = currentChar + exponent; + for (int j = resLengthInChars - 1; j >= insertPoint; j--) { + result[j + 1] = result[j]; + } + result[++insertPoint] = '.'; + if (negNumber) { + result[--currentChar] = '-'; + } + return new String(result, currentChar, resLengthInChars - currentChar + + 1); + } + // special case 2 + for (int j = 2; j < -exponent + 1; j++) { + result[--currentChar] = '0'; + } + result[--currentChar] = '.'; + result[--currentChar] = '0'; + if (negNumber) { + result[--currentChar] = '-'; + } + return new String(result, currentChar, resLengthInChars - currentChar); + } + int startPoint = currentChar + 1; + int endPoint = resLengthInChars; + StringBuilder result1 = new StringBuilder(16 + endPoint - startPoint); + if (negNumber) { + result1.append('-'); + } + if (endPoint - startPoint >= 1) { + result1.append(result[currentChar]); + result1.append('.'); + result1.append(result, currentChar + 1, resLengthInChars - currentChar + - 1); + } else { + result1.append(result, currentChar, resLengthInChars - currentChar); + } + result1.append('E'); + if (exponent > 0) { + result1.append('+'); + } + result1.append(Integer.toString(exponent)); + return result1.toString(); + } + + /* can process only 32-bit numbers */ + static String toDecimalScaledString(long value, int scale) { + int resLengthInChars; + int currentChar; + char result[]; + boolean negNumber = value < 0; + if (negNumber) { + value = -value; + } + if (value == 0) { + switch (scale) { + case 0: + return "0"; //$NON-NLS-1$ + case 1: + return "0.0"; //$NON-NLS-1$ + case 2: + return "0.00"; //$NON-NLS-1$ + case 3: + return "0.000"; //$NON-NLS-1$ + case 4: + return "0.0000"; //$NON-NLS-1$ + case 5: + return "0.00000"; //$NON-NLS-1$ + case 6: + return "0.000000"; //$NON-NLS-1$ + default: + StringBuilder result1 = new StringBuilder(); + if (scale < 0) { + result1.append("0E+"); //$NON-NLS-1$ + } else { + result1.append("0E"); //$NON-NLS-1$ + } + result1.append((scale == Integer.MIN_VALUE) + ? "2147483648" : Integer.toString(-scale)); //$NON-NLS-1$ + return result1.toString(); + } + } + // one 32-bit unsigned value may contains 10 decimal digits + resLengthInChars = 18; + // Explanation why +1+7: + // +1 - one char for sign if needed. + // +7 - For "special case 2" (see below) we have 7 free chars for + // inserting necessary scaled digits. + result = new char[resLengthInChars + 1]; + // Allocated [resLengthInChars+1] characters. + // a free latest character may be used for "special case 1" (see below) + currentChar = resLengthInChars; + long v = value; + do { + long prev = v; + v /= 10; + result[--currentChar] = (char) (0x0030 + (prev - v * 10)); + } while (v != 0); + + long exponent = (long) resLengthInChars - (long) currentChar - scale - 1L; + if (scale == 0) { + if (negNumber) { + result[--currentChar] = '-'; + } + return new String(result, currentChar, resLengthInChars - currentChar); + } + if (scale > 0 && exponent >= -6) { + if (exponent >= 0) { + // special case 1 + int insertPoint = currentChar + (int) exponent; + for (int j = resLengthInChars - 1; j >= insertPoint; j--) { + result[j + 1] = result[j]; + } + result[++insertPoint] = '.'; + if (negNumber) { + result[--currentChar] = '-'; + } + return new String(result, currentChar, resLengthInChars - currentChar + + 1); + } + // special case 2 + for (int j = 2; j < -exponent + 1; j++) { + result[--currentChar] = '0'; + } + result[--currentChar] = '.'; + result[--currentChar] = '0'; + if (negNumber) { + result[--currentChar] = '-'; + } + return new String(result, currentChar, resLengthInChars - currentChar); + } + int startPoint = currentChar + 1; + int endPoint = resLengthInChars; + StringBuilder result1 = new StringBuilder(16 + endPoint - startPoint); + if (negNumber) { + result1.append('-'); + } + if (endPoint - startPoint >= 1) { + result1.append(result[currentChar]); + result1.append('.'); + result1.append(result, currentChar + 1, resLengthInChars - currentChar + - 1); + } else { + result1.append(result, currentChar, resLengthInChars - currentChar); + } + result1.append('E'); + if (exponent > 0) { + result1.append('+'); + } + result1.append(Long.toString(exponent)); + return result1.toString(); + } + + /** + * Just to denote that this class can't be instantiated. + */ + private Conversion() { + } + +// /** +// * @see BigInteger#doubleValue() +// */ + // static double bigInteger2Double(BigInteger val) { + // // val.bitLength() < 64 + // if ((val.numberLength < 2) + // || ((val.numberLength == 2) && (val.digits[1] > 0))) { + // return val.longValue(); + // } + // // val.bitLength() >= 33 * 32 > 1024 + // if (val.numberLength > 32) { + // return ((val.sign > 0) ? Double.POSITIVE_INFINITY + // : Double.NEGATIVE_INFINITY); + // } + // int bitLen = val.abs().bitLength(); + // long exponent = bitLen - 1; + // int delta = bitLen - 54; + // // We need 54 top bits from this, the 53th bit is always 1 in lVal. + // long lVal = val.abs().shiftRight(delta).longValue(); + // /* + // * Take 53 bits from lVal to mantissa. The least significant bit is + // * needed for rounding. + // */ + // long mantissa = lVal & 0x1FFFFFFFFFFFFFL; + // if (exponent == 1023) { + // if (mantissa == 0X1FFFFFFFFFFFFFL) { + // return ((val.sign > 0) ? Double.POSITIVE_INFINITY + // : Double.NEGATIVE_INFINITY); + // } + // if (mantissa == 0x1FFFFFFFFFFFFEL) { + // return ((val.sign > 0) ? Double.MAX_VALUE : -Double.MAX_VALUE); + // } + // } + // // Round the mantissa + // if (((mantissa & 1) == 1) + // && (((mantissa & 2) == 2) || BitLevel.nonZeroDroppedBits(delta, + // val.digits))) { + // mantissa += 2; + // } + // mantissa >>= 1; // drop the rounding bit + // long resSign = (val.sign < 0) ? 0x8000000000000000L : 0; + // exponent = ((1023 + exponent) << 52) & 0x7FF0000000000000L; + // long result = resSign | exponent | mantissa; + // return Double.longBitsToDouble(result); + // } +} diff --git a/gwt/jre/java/math/Division.java b/gwt/jre/java/math/Division.java new file mode 100644 index 0000000..9b676e3 --- /dev/null +++ b/gwt/jre/java/math/Division.java @@ -0,0 +1,1013 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +/** + * Static library that provides all operations related with division and modular + * arithmetic to {@link BigInteger}. Some methods are provided in both mutable + * and immutable way. There are several variants provided listed below: + * + * + */ +class Division { + + /** + * Divides the array 'a' by the array 'b' and gets the quotient and the + * remainder. Implements the Knuth's division algorithm. See D. Knuth, The Art + * of Computer Programming, vol. 2. Steps D1-D8 correspond the steps in the + * algorithm description. + * + * @param quot the quotient + * @param quotLength the quotient's length + * @param a the dividend + * @param aLength the dividend's length + * @param b the divisor + * @param bLength the divisor's length + * @return the remainder + */ + static int[] divide(int quot[], int quotLength, int a[], int aLength, + int b[], int bLength) { + + int normA[] = new int[aLength + 1]; // the normalized dividend + // an extra byte is needed for correct shift + int normB[] = new int[bLength + 1]; // the normalized divisor; + int normBLength = bLength; + /* + * Step D1: normalize a and b and put the results to a1 and b1 the + * normalized divisor's first digit must be >= 2^31 + */ + int divisorShift = Integer.numberOfLeadingZeros(b[bLength - 1]); + if (divisorShift != 0) { + BitLevel.shiftLeft(normB, b, 0, divisorShift); + BitLevel.shiftLeft(normA, a, 0, divisorShift); + } else { + System.arraycopy(a, 0, normA, 0, aLength); + System.arraycopy(b, 0, normB, 0, bLength); + } + int firstDivisorDigit = normB[normBLength - 1]; + // Step D2: set the quotient index + int i = quotLength - 1; + int j = aLength; + + while (i >= 0) { + // Step D3: calculate a guess digit guessDigit + int guessDigit = 0; + if (normA[j] == firstDivisorDigit) { + // set guessDigit to the largest unsigned int value + guessDigit = -1; + } else { + long product = (((normA[j] & 0xffffffffL) << 32) + (normA[j - 1] & 0xffffffffL)); + long res = Division.divideLongByInt(product, firstDivisorDigit); + guessDigit = (int) res; // the quotient of divideLongByInt + int rem = (int) (res >> 32); // the remainder of + // divideLongByInt + // decrease guessDigit by 1 while leftHand > rightHand + if (guessDigit != 0) { + long leftHand = 0; + long rightHand = 0; + boolean rOverflowed = false; + guessDigit++; // to have the proper value in the loop + // below + do { + guessDigit--; + if (rOverflowed) { + break; + } + // leftHand always fits in an unsigned long + leftHand = (guessDigit & 0xffffffffL) + * (normB[normBLength - 2] & 0xffffffffL); + /* + * rightHand can overflow; in this case the loop condition will be + * true in the next step of the loop + */ + rightHand = ((long) rem << 32) + (normA[j - 2] & 0xffffffffL); + long longR = (rem & 0xffffffffL) + + (firstDivisorDigit & 0xffffffffL); + /* + * checks that longR does not fit in an unsigned int; this ensures + * that rightHand will overflow unsigned long in the next step + */ + if (Integer.numberOfLeadingZeros((int) (longR >>> 32)) < 32) { + rOverflowed = true; + } else { + rem = (int) longR; + } + } while (((leftHand ^ 0x8000000000000000L) > (rightHand ^ 0x8000000000000000L))); + } + } + // Step D4: multiply normB by guessDigit and subtract the production + // from normA. + if (guessDigit != 0) { + int borrow = Division.multiplyAndSubtract(normA, j - normBLength, + normB, normBLength, guessDigit); + // Step D5: check the borrow + if (borrow != 0) { + // Step D6: compensating addition + guessDigit--; + long carry = 0; + for (int k = 0; k < normBLength; k++) { + carry += (normA[j - normBLength + k] & 0xffffffffL) + + (normB[k] & 0xffffffffL); + normA[j - normBLength + k] = (int) carry; + carry >>>= 32; + } + } + } + if (quot != null) { + quot[i] = guessDigit; + } + // Step D7 + j--; + i--; + } + /* + * Step D8: we got the remainder in normA. Denormalize it id needed + */ + if (divisorShift != 0) { + // reuse normB + BitLevel.shiftRight(normB, normBLength, normA, 0, divisorShift); + return normB; + } + System.arraycopy(normA, 0, normB, 0, bLength); + return normA; + } + + /** + * Computes the quotient and the remainder after a division by an {@code int} + * number. + * + * @return an array of the form {@code [quotient, remainder]}. + */ + static BigInteger[] divideAndRemainderByInteger(BigInteger val, int divisor, + int divisorSign) { + // res[0] is a quotient and res[1] is a remainder: + int[] valDigits = val.digits; + int valLen = val.numberLength; + int valSign = val.sign; + if (valLen == 1) { + long a = (valDigits[0] & 0xffffffffL); + long b = (divisor & 0xffffffffL); + long quo = a / b; + long rem = a % b; + if (valSign != divisorSign) { + quo = -quo; + } + if (valSign < 0) { + rem = -rem; + } + return new BigInteger[] {BigInteger.valueOf(quo), BigInteger.valueOf(rem)}; + } + int quotientLength = valLen; + int quotientSign = ((valSign == divisorSign) ? 1 : -1); + int quotientDigits[] = new int[quotientLength]; + int remainderDigits[]; + remainderDigits = new int[] {Division.divideArrayByInt(quotientDigits, + valDigits, valLen, divisor)}; + BigInteger result0 = new BigInteger(quotientSign, quotientLength, + quotientDigits); + BigInteger result1 = new BigInteger(valSign, 1, remainderDigits); + result0.cutOffLeadingZeroes(); + result1.cutOffLeadingZeroes(); + return new BigInteger[] {result0, result1}; + } + + /** + * Divides an array by an integer value. Implements the Knuth's division + * algorithm. See D. Knuth, The Art of Computer Programming, vol. 2. + * + * @param dest the quotient + * @param src the dividend + * @param srcLength the length of the dividend + * @param divisor the divisor + * @return remainder + */ + static int divideArrayByInt(int dest[], int src[], final int srcLength, + final int divisor) { + + long rem = 0; + long bLong = divisor & 0xffffffffL; + + for (int i = srcLength - 1; i >= 0; i--) { + long temp = (rem << 32) | (src[i] & 0xffffffffL); + long quot; + if (temp >= 0) { + quot = (temp / bLong); + rem = (temp % bLong); + } else { + /* + * make the dividend positive shifting it right by 1 bit then get the + * quotient an remainder and correct them properly + */ + long aPos = temp >>> 1; + long bPos = divisor >>> 1; + quot = aPos / bPos; + rem = aPos % bPos; + // double the remainder and add 1 if a is odd + rem = (rem << 1) + (temp & 1); + if ((divisor & 1) != 0) { + // the divisor is odd + if (quot <= rem) { + rem -= quot; + } else { + if (quot - rem <= bLong) { + rem += bLong - quot; + quot -= 1; + } else { + rem += (bLong << 1) - quot; + quot -= 2; + } + } + } + } + dest[i] = (int) (quot & 0xffffffffL); + } + return (int) rem; + } + + /** + * Divides an unsigned long a by an unsigned int b. It is supposed that the + * most significant bit of b is set to 1, i.e. b < 0 + * + * @param a the dividend + * @param b the divisor + * @return the long value containing the unsigned integer remainder in the + * left half and the unsigned integer quotient in the right half + */ + static long divideLongByInt(long a, int b) { + long quot; + long rem; + long bLong = b & 0xffffffffL; + + if (a >= 0) { + quot = (a / bLong); + rem = (a % bLong); + } else { + /* + * Make the dividend positive shifting it right by 1 bit then get the + * quotient an remainder and correct them properly + */ + long aPos = a >>> 1; + long bPos = b >>> 1; + quot = aPos / bPos; + rem = aPos % bPos; + // double the remainder and add 1 if a is odd + rem = (rem << 1) + (a & 1); + if ((b & 1) != 0) { // the divisor is odd + if (quot <= rem) { + rem -= quot; + } else { + if (quot - rem <= bLong) { + rem += bLong - quot; + quot -= 1; + } else { + rem += (bLong << 1) - quot; + quot -= 2; + } + } + } + } + return (rem << 32) | (quot & 0xffffffffL); + } + + /** + * Performs modular exponentiation using the Montgomery Reduction. It requires + * that all parameters be positive and the modulus be even. Based The + * square and multiply algorithm and the Montgomery Reduction C. K. Koc - + * Montgomery Reduction with Even Modulus. The square and multiply + * algorithm and the Montgomery Reduction. + * + * @ar.org.fitc.ref "C. K. Koc - Montgomery Reduction with Even Modulus" + * @see BigInteger#modPow(BigInteger, BigInteger) + */ + static BigInteger evenModPow(BigInteger base, BigInteger exponent, + BigInteger modulus) { + // PRE: (base > 0), (exponent > 0), (modulus > 0) and (modulus even) + // STEP 1: Obtain the factorization 'modulus'= q * 2^j. + int j = modulus.getLowestSetBit(); + BigInteger q = modulus.shiftRight(j); + + // STEP 2: Compute x1 := base^exponent (mod q). + BigInteger x1 = oddModPow(base, exponent, q); + + // STEP 3: Compute x2 := base^exponent (mod 2^j). + BigInteger x2 = pow2ModPow(base, exponent, j); + + // STEP 4: Compute q^(-1) (mod 2^j) and y := (x2-x1) * q^(-1) (mod 2^j) + BigInteger qInv = modPow2Inverse(q, j); + BigInteger y = (x2.subtract(x1)).multiply(qInv); + inplaceModPow2(y, j); + if (y.sign < 0) { + y = y.add(BigInteger.getPowerOfTwo(j)); + } + // STEP 5: Compute and return: x1 + q * y + return x1.add(q.multiply(y)); + } + + /** + * Performs the final reduction of the Montgomery algorithm. + * + * @see #monPro(BigInteger, BigInteger, BigInteger, long) + * @see #monSquare(BigInteger, BigInteger, long) + */ + static BigInteger finalSubtraction(int res[], BigInteger modulus) { + + // skipping leading zeros + int modulusLen = modulus.numberLength; + boolean doSub = res[modulusLen] != 0; + if (!doSub) { + int modulusDigits[] = modulus.digits; + doSub = true; + for (int i = modulusLen - 1; i >= 0; i--) { + if (res[i] != modulusDigits[i]) { + doSub = (res[i] != 0) + && ((res[i] & 0xFFFFFFFFL) > (modulusDigits[i] & 0xFFFFFFFFL)); + break; + } + } + } + + BigInteger result = new BigInteger(1, modulusLen + 1, res); + + // if (res >= modulusDigits) compute (res - modulusDigits) + if (doSub) { + Elementary.inplaceSubtract(result, modulus); + } + + result.cutOffLeadingZeroes(); + return result; + } + + /** + * @param m a positive modulus Return the greatest common divisor of op1 and + * op2, + * + * @param op1 must be greater than zero + * @param op2 must be greater than zero + * @see BigInteger#gcd(BigInteger) + * @return {@code GCD(op1, op2)} + */ + static BigInteger gcdBinary(BigInteger op1, BigInteger op2) { + // PRE: (op1 > 0) and (op2 > 0) + + /* + * Divide both number the maximal possible times by 2 without rounding + * gcd(2*a, 2*b) = 2 * gcd(a,b) + */ + int lsb1 = op1.getLowestSetBit(); + int lsb2 = op2.getLowestSetBit(); + int pow2Count = Math.min(lsb1, lsb2); + + BitLevel.inplaceShiftRight(op1, lsb1); + BitLevel.inplaceShiftRight(op2, lsb2); + + BigInteger swap; + // I want op2 > op1 + if (op1.compareTo(op2) == BigInteger.GREATER) { + swap = op1; + op1 = op2; + op2 = swap; + } + + do { // INV: op2 >= op1 && both are odd unless op1 = 0 + + // Optimization for small operands + // (op2.bitLength() < 64) implies by INV (op1.bitLength() < 64) + if ((op2.numberLength == 1) + || ((op2.numberLength == 2) && (op2.digits[1] > 0))) { + op2 = BigInteger.valueOf(Division.gcdBinary(op1.longValue(), + op2.longValue())); + break; + } + + // Implements one step of the Euclidean algorithm + // To reduce one operand if it's much smaller than the other one + if (op2.numberLength > op1.numberLength * 1.2) { + op2 = op2.remainder(op1); + if (op2.signum() != 0) { + BitLevel.inplaceShiftRight(op2, op2.getLowestSetBit()); + } + } else { + + // Use Knuth's algorithm of successive subtract and shifting + do { + Elementary.inplaceSubtract(op2, op1); // both are odd + BitLevel.inplaceShiftRight(op2, op2.getLowestSetBit()); // op2 is even + } while (op2.compareTo(op1) >= BigInteger.EQUALS); + } + // now op1 >= op2 + swap = op2; + op2 = op1; + op1 = swap; + } while (op1.sign != 0); + return op2.shiftLeft(pow2Count); + } + + /** + * Performs the same as {@link #gcdBinary(BigInteger, BigInteger)}, but with + * numbers of 63 bits, represented in positives values of {@code long} type. + * + * @param op1 a positive number + * @param op2 a positive number + * @see #gcdBinary(BigInteger, BigInteger) + * @return GCD(op1, op2) + */ + static long gcdBinary(long op1, long op2) { + // PRE: (op1 > 0) and (op2 > 0) + int lsb1 = Long.numberOfTrailingZeros(op1); + int lsb2 = Long.numberOfTrailingZeros(op2); + int pow2Count = Math.min(lsb1, lsb2); + + if (lsb1 != 0) { + op1 >>>= lsb1; + } + if (lsb2 != 0) { + op2 >>>= lsb2; + } + do { + if (op1 >= op2) { + op1 -= op2; + op1 >>>= Long.numberOfTrailingZeros(op1); + } else { + op2 -= op1; + op2 >>>= Long.numberOfTrailingZeros(op2); + } + } while (op1 != 0); + return (op2 << pow2Count); + } + + /** + * Performs {@code x = x mod (2n)}. + * + * @param x a positive number, it will store the result. + * @param n a positive exponent of {@code 2}. + */ + static void inplaceModPow2(BigInteger x, int n) { + // PRE: (x > 0) and (n >= 0) + int fd = n >> 5; + int leadingZeros; + + if ((x.numberLength < fd) || (x.bitLength() <= n)) { + return; + } + leadingZeros = 32 - (n & 31); + x.numberLength = fd + 1; + x.digits[fd] &= (leadingZeros < 32) ? (-1 >>> leadingZeros) : 0; + x.cutOffLeadingZeroes(); + } + + /** + * + * Based on "New Algorithm for Classical Modular Inverse" Róbert Lórencz. LNCS + * 2523 (2002) + * + * @return a^(-1) mod m + */ + static BigInteger modInverseLorencz(BigInteger a, BigInteger modulo) { + // PRE: a is coprime with modulo, a < modulo + + int max = Math.max(a.numberLength, modulo.numberLength); + int uDigits[] = new int[max + 1]; // enough place to make all the inplace + // operation + int vDigits[] = new int[max + 1]; + System.arraycopy(modulo.digits, 0, uDigits, 0, modulo.numberLength); + System.arraycopy(a.digits, 0, vDigits, 0, a.numberLength); + BigInteger u = new BigInteger(modulo.sign, modulo.numberLength, uDigits); + BigInteger v = new BigInteger(a.sign, a.numberLength, vDigits); + + BigInteger r = new BigInteger(0, 1, new int[max + 1]); // BigInteger.ZERO; + BigInteger s = new BigInteger(1, 1, new int[max + 1]); + s.digits[0] = 1; + // r == 0 && s == 1, but with enough place + + int coefU = 0, coefV = 0; + int n = modulo.bitLength(); + int k; + while (!isPowerOfTwo(u, coefU) && !isPowerOfTwo(v, coefV)) { + + // modification of original algorithm: I calculate how many times the + // algorithm will enter in the same branch of if + k = howManyIterations(u, n); + + if (k != 0) { + BitLevel.inplaceShiftLeft(u, k); + if (coefU >= coefV) { + BitLevel.inplaceShiftLeft(r, k); + } else { + BitLevel.inplaceShiftRight(s, Math.min(coefV - coefU, k)); + if (k - (coefV - coefU) > 0) { + BitLevel.inplaceShiftLeft(r, k - coefV + coefU); + } + } + coefU += k; + } + + k = howManyIterations(v, n); + if (k != 0) { + BitLevel.inplaceShiftLeft(v, k); + if (coefV >= coefU) { + BitLevel.inplaceShiftLeft(s, k); + } else { + BitLevel.inplaceShiftRight(r, Math.min(coefU - coefV, k)); + if (k - (coefU - coefV) > 0) { + BitLevel.inplaceShiftLeft(s, k - coefU + coefV); + } + } + coefV += k; + } + + if (u.signum() == v.signum()) { + if (coefU <= coefV) { + Elementary.completeInPlaceSubtract(u, v); + Elementary.completeInPlaceSubtract(r, s); + } else { + Elementary.completeInPlaceSubtract(v, u); + Elementary.completeInPlaceSubtract(s, r); + } + } else { + if (coefU <= coefV) { + Elementary.completeInPlaceAdd(u, v); + Elementary.completeInPlaceAdd(r, s); + } else { + Elementary.completeInPlaceAdd(v, u); + Elementary.completeInPlaceAdd(s, r); + } + } + if (v.signum() == 0 || u.signum() == 0) { + // math.19: BigInteger not invertible + throw new ArithmeticException("BigInteger not invertible."); + } + } + + if (isPowerOfTwo(v, coefV)) { + r = s; + if (v.signum() != u.signum()) { + u = u.negate(); + } + } + if (u.testBit(n)) { + if (r.signum() < 0) { + r = r.negate(); + } else { + r = modulo.subtract(r); + } + } + if (r.signum() < 0) { + r = r.add(modulo); + } + + return r; + } + + /** + * Calculates a.modInverse(p) Based on: Savas, E; Koc, C "The Montgomery + * Modular Inverse - Revised". + */ + static BigInteger modInverseMontgomery(BigInteger a, BigInteger p) { + if (a.sign == 0) { + // ZERO hasn't inverse + // math.19: BigInteger not invertible + throw new ArithmeticException("BigInteger not invertible."); + } + + if (!p.testBit(0)) { + // montgomery inverse require even modulo + return modInverseLorencz(a, p); + } + + int m = p.numberLength * 32; + // PRE: a \in [1, p - 1] + BigInteger u, v, r, s; + u = p.copy(); // make copy to use inplace method + v = a.copy(); + int max = Math.max(v.numberLength, u.numberLength); + r = new BigInteger(1, 1, new int[max + 1]); + s = new BigInteger(1, 1, new int[max + 1]); + s.digits[0] = 1; + // s == 1 && v == 0 + + int k = 0; + + int lsbu = u.getLowestSetBit(); + int lsbv = v.getLowestSetBit(); + int toShift; + + if (lsbu > lsbv) { + BitLevel.inplaceShiftRight(u, lsbu); + BitLevel.inplaceShiftRight(v, lsbv); + BitLevel.inplaceShiftLeft(r, lsbv); + k += lsbu - lsbv; + } else { + BitLevel.inplaceShiftRight(u, lsbu); + BitLevel.inplaceShiftRight(v, lsbv); + BitLevel.inplaceShiftLeft(s, lsbu); + k += lsbv - lsbu; + } + + r.sign = 1; + while (v.signum() > 0) { + // INV v >= 0, u >= 0, v odd, u odd (except last iteration when v is even + // (0)) + + while (u.compareTo(v) > BigInteger.EQUALS) { + Elementary.inplaceSubtract(u, v); + toShift = u.getLowestSetBit(); + BitLevel.inplaceShiftRight(u, toShift); + Elementary.inplaceAdd(r, s); + BitLevel.inplaceShiftLeft(s, toShift); + k += toShift; + } + + while (u.compareTo(v) <= BigInteger.EQUALS) { + Elementary.inplaceSubtract(v, u); + if (v.signum() == 0) { + break; + } + toShift = v.getLowestSetBit(); + BitLevel.inplaceShiftRight(v, toShift); + Elementary.inplaceAdd(s, r); + BitLevel.inplaceShiftLeft(r, toShift); + k += toShift; + } + } + if (!u.isOne()) { + // in u is stored the gcd + // math.19: BigInteger not invertible. + throw new ArithmeticException("BigInteger not invertible."); + } + if (r.compareTo(p) >= BigInteger.EQUALS) { + Elementary.inplaceSubtract(r, p); + } + + r = p.subtract(r); + + // Have pair: ((BigInteger)r, (Integer)k) where r == a^(-1) * 2^k mod + // (module) + int n1 = calcN(p); + if (k > m) { + r = monPro(r, BigInteger.ONE, p, n1); + k = k - m; + } + + r = monPro(r, BigInteger.getPowerOfTwo(m - k), p, n1); + return r; + } + + /** + * @param x an odd positive number. + * @param n the exponent by which 2 is raised. + * @return {@code x-1 (mod 2n)}. + */ + static BigInteger modPow2Inverse(BigInteger x, int n) { + // PRE: (x > 0), (x is odd), and (n > 0) + BigInteger y = new BigInteger(1, new int[1 << n]); + y.numberLength = 1; + y.digits[0] = 1; + y.sign = 1; + + for (int i = 1; i < n; i++) { + if (BitLevel.testBit(x.multiply(y), i)) { + // Adding 2^i to y (setting the i-th bit) + y.digits[i >> 5] |= (1 << (i & 31)); + } + } + return y; + } + + /** + * Implements the Montgomery Product of two integers represented by {@code + * int} arrays. The arrays are supposed in little endian notation. + * + * @param a The first factor of the product. + * @param b The second factor of the product. + * @param modulus The modulus of the operations. Zmodulus. + * @param n2 The digit modulus'[0]. + * @ar.org.fitc.ref "C. K. Koc - Analyzing and Comparing Montgomery + * Multiplication Algorithms" + * @see #modPowOdd(BigInteger, BigInteger, BigInteger) + */ + static BigInteger monPro(BigInteger a, BigInteger b, BigInteger modulus, + int n2) { + int modulusLen = modulus.numberLength; + int res[] = new int[(modulusLen << 1) + 1]; + Multiplication.multArraysPAP(a.digits, + Math.min(modulusLen, a.numberLength), b.digits, Math.min(modulusLen, + b.numberLength), res); + monReduction(res, modulus, n2); + return finalSubtraction(res, modulus); + } + + /** + * Multiplies an array by int and subtracts it from a subarray of another + * array. + * + * @param a the array to subtract from + * @param start the start element of the subarray of a + * @param b the array to be multiplied and subtracted + * @param bLen the length of b + * @param c the multiplier of b + * @return the carry element of subtraction + */ + static int multiplyAndSubtract(int a[], int start, int b[], int bLen, int c) { + long carry0 = 0; + long carry1 = 0; + + for (int i = 0; i < bLen; i++) { + carry0 = Multiplication.unsignedMultAddAdd(b[i], c, (int) carry0, 0); + carry1 = (a[start + i] & 0xffffffffL) - (carry0 & 0xffffffffL) + carry1; + a[start + i] = (int) carry1; + carry1 >>= 32; // -1 or 0 + carry0 >>>= 32; + } + + carry1 = (a[start + bLen] & 0xffffffffL) - carry0 + carry1; + a[start + bLen] = (int) carry1; + return (int) (carry1 >> 32); // -1 or 0 + } + + /** + * Performs modular exponentiation using the Montgomery Reduction. It requires + * that all parameters be positive and the modulus be odd. > + * + * @see BigInteger#modPow(BigInteger, BigInteger) + * @see #monPro(BigInteger, BigInteger, BigInteger, int) + * @see #slidingWindow(BigInteger, BigInteger, BigInteger, BigInteger, int) + * @see #squareAndMultiply(BigInteger, BigInteger, BigInteger, BigInteger, + * int) + */ + static BigInteger oddModPow(BigInteger base, BigInteger exponent, + BigInteger modulus) { + // PRE: (base > 0), (exponent > 0), (modulus > 0) and (odd modulus) + int k = (modulus.numberLength << 5); // r = 2^k + // n-residue of base [base * r (mod modulus)] + BigInteger a2 = base.shiftLeft(k).mod(modulus); + // n-residue of base [1 * r (mod modulus)] + BigInteger x2 = BigInteger.getPowerOfTwo(k).mod(modulus); + BigInteger res; + // Compute (modulus[0]^(-1)) (mod 2^32) for odd modulus + + int n2 = calcN(modulus); + if (modulus.numberLength == 1) { + res = squareAndMultiply(x2, a2, exponent, modulus, n2); + } else { + res = slidingWindow(x2, a2, exponent, modulus, n2); + } + + return monPro(res, BigInteger.ONE, modulus, n2); + } + + /** + * It requires that all parameters be positive. + * + * @return {@code baseexponent mod (2j)}. + * @see BigInteger#modPow(BigInteger, BigInteger) + */ + static BigInteger pow2ModPow(BigInteger base, BigInteger exponent, int j) { + // PRE: (base > 0), (exponent > 0) and (j > 0) + BigInteger res = BigInteger.ONE; + BigInteger e = exponent.copy(); + BigInteger baseMod2toN = base.copy(); + BigInteger res2; + /* + * If 'base' is odd then it's coprime with 2^j and phi(2^j) = 2^(j-1); so we + * can reduce reduce the exponent (mod 2^(j-1)). + */ + if (base.testBit(0)) { + inplaceModPow2(e, j - 1); + } + inplaceModPow2(baseMod2toN, j); + + for (int i = e.bitLength() - 1; i >= 0; i--) { + res2 = res.copy(); + inplaceModPow2(res2, j); + res = res.multiply(res2); + if (BitLevel.testBit(e, i)) { + res = res.multiply(baseMod2toN); + inplaceModPow2(res, j); + } + } + inplaceModPow2(res, j); + return res; + } + + /** + * Divides a BigInteger by a signed int and returns + * the remainder. + * + * @param dividend the BigInteger to be divided. Must be non-negative. + * @param divisor a signed int + * @return divide % divisor + */ + static int remainder(BigInteger dividend, int divisor) { + return remainderArrayByInt(dividend.digits, dividend.numberLength, divisor); + } + + /** + * Divides an array by an integer value. Implements the Knuth's division + * algorithm. See D. Knuth, The Art of Computer Programming, vol. 2. + * + * @param src the dividend + * @param srcLength the length of the dividend + * @param divisor the divisor + * @return remainder + */ + static int remainderArrayByInt(int src[], final int srcLength, + final int divisor) { + + long result = 0; + + for (int i = srcLength - 1; i >= 0; i--) { + long temp = (result << 32) + (src[i] & 0xffffffffL); + long res = divideLongByInt(temp, divisor); + result = (int) (res >> 32); + } + return (int) result; + } + + /* + * Implements the Montgomery modular exponentiation based in The sliding + * windows algorithm and the MongomeryReduction. + * + * @ar.org.fitc.ref + * "A. Menezes,P. van Oorschot, S. Vanstone - Handbook of Applied Cryptography" + * ; + * + * @see #oddModPow(BigInteger, BigInteger, BigInteger) + */ + static BigInteger slidingWindow(BigInteger x2, BigInteger a2, + BigInteger exponent, BigInteger modulus, int n2) { + // fill odd low pows of a2 + BigInteger pows[] = new BigInteger[8]; + BigInteger res = x2; + int lowexp; + BigInteger x3; + int acc3; + pows[0] = a2; + + x3 = monPro(a2, a2, modulus, n2); + for (int i = 1; i <= 7; i++) { + pows[i] = monPro(pows[i - 1], x3, modulus, n2); + } + + for (int i = exponent.bitLength() - 1; i >= 0; i--) { + if (BitLevel.testBit(exponent, i)) { + lowexp = 1; + acc3 = i; + + for (int j = Math.max(i - 3, 0); j <= i - 1; j++) { + if (BitLevel.testBit(exponent, j)) { + if (j < acc3) { + acc3 = j; + lowexp = (lowexp << (i - j)) ^ 1; + } else { + lowexp = lowexp ^ (1 << (j - acc3)); + } + } + } + + for (int j = acc3; j <= i; j++) { + res = monPro(res, res, modulus, n2); + } + res = monPro(pows[(lowexp - 1) >> 1], res, modulus, n2); + i = acc3; + } else { + res = monPro(res, res, modulus, n2); + } + } + return res; + } + + static BigInteger squareAndMultiply(BigInteger x2, BigInteger a2, + BigInteger exponent, BigInteger modulus, int n2) { + BigInteger res = x2; + for (int i = exponent.bitLength() - 1; i >= 0; i--) { + res = monPro(res, res, modulus, n2); + if (BitLevel.testBit(exponent, i)) { + res = monPro(res, a2, modulus, n2); + } + } + return res; + } + + /** + * Calculate the first digit of the inverse. + */ + private static int calcN(BigInteger a) { + long m0 = a.digits[0] & 0xFFFFFFFFL; + long n2 = 1L; // this is a'[0] + long powerOfTwo = 2L; + do { + if (((m0 * n2) & powerOfTwo) != 0) { + n2 |= powerOfTwo; + } + powerOfTwo <<= 1; + } while (powerOfTwo < 0x100000000L); + n2 = -n2; + return (int) (n2 & 0xFFFFFFFFL); + } + + /** + * Calculate how many iteration of Lorencz's algorithm would perform the same + * operation. + * + * @param bi + * @param n + * @return + */ + private static int howManyIterations(BigInteger bi, int n) { + int i = n - 1; + if (bi.sign > 0) { + while (!bi.testBit(i)) { + i--; + } + return n - 1 - i; + } else { + while (bi.testBit(i)) { + i--; + } + return n - 1 - Math.max(i, bi.getLowestSetBit()); + } + } + + /** + * Returns {@code bi == abs(2^exp)}. + */ + private static boolean isPowerOfTwo(BigInteger bi, int exp) { + boolean result = false; + result = (exp >> 5 == bi.numberLength - 1) + && (bi.digits[bi.numberLength - 1] == 1 << (exp & 31)); + if (result) { + for (int i = 0; result && i < bi.numberLength - 1; i++) { + result = bi.digits[i] == 0; + } + } + return result; + } + + private static void monReduction(int[] res, BigInteger modulus, int n2) { + + /* res + m*modulus_digits */ + int[] modulusDigits = modulus.digits; + int modulusLen = modulus.numberLength; + long outerCarry = 0; + + for (int i = 0; i < modulusLen; i++) { + long innnerCarry = 0; + int m = (int) Multiplication.unsignedMultAddAdd(res[i], n2, 0, 0); + for (int j = 0; j < modulusLen; j++) { + innnerCarry = Multiplication.unsignedMultAddAdd(m, modulusDigits[j], + res[i + j], (int) innnerCarry); + res[i + j] = (int) innnerCarry; + innnerCarry >>>= 32; + } + + outerCarry += (res[i + modulusLen] & 0xFFFFFFFFL) + innnerCarry; + res[i + modulusLen] = (int) outerCarry; + outerCarry >>>= 32; + } + + res[modulusLen << 1] = (int) outerCarry; + + /* res / r */ + for (int j = 0; j < modulusLen + 1; j++) { + res[j] = res[j + modulusLen]; + } + } +} diff --git a/gwt/jre/java/math/Elementary.java b/gwt/jre/java/math/Elementary.java new file mode 100644 index 0000000..58bec5b --- /dev/null +++ b/gwt/jre/java/math/Elementary.java @@ -0,0 +1,457 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +/** + * Static library that provides the basic arithmetic mutable operations for + * {@link BigInteger}. The operations provided are listed below. In addition to this, some Inplace (mutable) methods are + * provided. + */ +class Elementary { + + /** + * @see BigInteger#add(BigInteger) . + * @param op1 + * @param op2 + * @return + */ + static BigInteger add(BigInteger op1, BigInteger op2) { + int resDigits[]; + int resSign; + int op1Sign = op1.sign; + int op2Sign = op2.sign; + + if (op1Sign == 0) { + return op2; + } + if (op2Sign == 0) { + return op1; + } + int op1Len = op1.numberLength; + int op2Len = op2.numberLength; + + if (op1Len + op2Len == 2) { + long a = (op1.digits[0] & 0xFFFFFFFFL); + long b = (op2.digits[0] & 0xFFFFFFFFL); + long res; + int valueLo; + int valueHi; + + if (op1Sign == op2Sign) { + res = a + b; + valueLo = (int) res; + valueHi = (int) (res >>> 32); + return ((valueHi == 0) ? new BigInteger(op1Sign, valueLo) + : new BigInteger(op1Sign, 2, new int[] {valueLo, valueHi})); + } + return BigInteger.valueOf((op1Sign < 0) ? (b - a) : (a - b)); + } else if (op1Sign == op2Sign) { + resSign = op1Sign; + // an augend should not be shorter than addend + resDigits = (op1Len >= op2Len) ? add(op1.digits, op1Len, op2.digits, + op2Len) : add(op2.digits, op2Len, op1.digits, op1Len); + } else { // signs are different + int cmp = ((op1Len != op2Len) ? ((op1Len > op2Len) ? 1 : -1) + : compareArrays(op1.digits, op2.digits, op1Len)); + + if (cmp == BigInteger.EQUALS) { + return BigInteger.ZERO; + } + // a minuend should not be shorter than subtrahend + if (cmp == BigInteger.GREATER) { + resSign = op1Sign; + resDigits = subtract(op1.digits, op1Len, op2.digits, op2Len); + } else { + resSign = op2Sign; + resDigits = subtract(op2.digits, op2Len, op1.digits, op1Len); + } + } + BigInteger res = new BigInteger(resSign, resDigits.length, resDigits); + res.cutOffLeadingZeroes(); + return res; + } + + /** + * Compares two arrays. All elements are treated as unsigned integers. The + * magnitude is the bit chain of elements in big-endian order. + * + * @param a the first array + * @param b the second array + * @param size the size of arrays + * @return 1 if a > b, -1 if a < b, 0 if a == b + */ + static int compareArrays(final int[] a, final int[] b, final int size) { + int i; + for (i = size - 1; (i >= 0) && (a[i] == b[i]); i--) { + // empty + } + return ((i < 0) ? BigInteger.EQUALS + : (a[i] & 0xFFFFFFFFL) < (b[i] & 0xFFFFFFFFL) ? BigInteger.LESS + : BigInteger.GREATER); + } + + /** + * Same as @link #inplaceAdd(BigInteger, BigInteger), but without the + * restriction of non-positive values. + * + * @param op1 any number + * @param op2 any number + */ + static void completeInPlaceAdd(BigInteger op1, BigInteger op2) { + if (op1.sign == 0) { + System.arraycopy(op2.digits, 0, op1.digits, 0, op2.numberLength); + } else if (op2.sign == 0) { + return; + } else if (op1.sign == op2.sign) { + add(op1.digits, op1.digits, op1.numberLength, op2.digits, + op2.numberLength); + } else { + int sign = unsignedArraysCompare(op1.digits, op2.digits, + op1.numberLength, op2.numberLength); + if (sign > 0) { + subtract(op1.digits, op1.digits, op1.numberLength, op2.digits, + op2.numberLength); + } else { + inverseSubtract(op1.digits, op1.digits, op1.numberLength, op2.digits, + op2.numberLength); + op1.sign = -op1.sign; + } + } + op1.numberLength = Math.max(op1.numberLength, op2.numberLength) + 1; + op1.cutOffLeadingZeroes(); + op1.unCache(); + } + + /** + * Same as @link #inplaceSubtract(BigInteger, BigInteger), but without the + * restriction of non-positive values. + * + * @param op1 should have enough space to save the result + * @param op2 + */ + static void completeInPlaceSubtract(BigInteger op1, BigInteger op2) { + int resultSign = op1.compareTo(op2); + if (op1.sign == 0) { + System.arraycopy(op2.digits, 0, op1.digits, 0, op2.numberLength); + op1.sign = -op2.sign; + } else if (op1.sign != op2.sign) { + add(op1.digits, op1.digits, op1.numberLength, op2.digits, + op2.numberLength); + op1.sign = resultSign; + } else { + int sign = unsignedArraysCompare(op1.digits, op2.digits, + op1.numberLength, op2.numberLength); + if (sign > 0) { + subtract(op1.digits, op1.digits, op1.numberLength, op2.digits, + op2.numberLength); // op1 = op1 - op2 + // op1.sign remains equal + } else { + inverseSubtract(op1.digits, op1.digits, op1.numberLength, op2.digits, + op2.numberLength); // op1 = op2 - op1 + op1.sign = -op1.sign; + } + } + op1.numberLength = Math.max(op1.numberLength, op2.numberLength) + 1; + op1.cutOffLeadingZeroes(); + op1.unCache(); + } + + /** + * Performs {@code op1 += op2}. {@code op1} must have enough place to store + * the result (i.e. {@code op1.bitLength() >= op2.bitLength()}). Both should + * be positive (i.e. {@code op1 >= op2}). + * + * @param op1 the input minuend, and the output result. + * @param op2 the addend + */ + static void inplaceAdd(BigInteger op1, BigInteger op2) { + // PRE: op1 >= op2 > 0 + add(op1.digits, op1.digits, op1.numberLength, op2.digits, op2.numberLength); + op1.numberLength = Math.min( + Math.max(op1.numberLength, op2.numberLength) + 1, op1.digits.length); + op1.cutOffLeadingZeroes(); + op1.unCache(); + } + + /** + * Performs: {@code op1 += addend}. The number must to have place to hold a + * possible carry. + */ + static void inplaceAdd(BigInteger op1, final int addend) { + int carry = inplaceAdd(op1.digits, op1.numberLength, addend); + if (carry == 1) { + op1.digits[op1.numberLength] = 1; + op1.numberLength++; + } + op1.unCache(); + } + + /** + * Adds an integer value to the array of integers remembering carry. + * + * @return a possible generated carry (0 or 1) + */ + static int inplaceAdd(int a[], final int aSize, final int addend) { + long carry = addend & 0xFFFFFFFFL; + + for (int i = 0; (carry != 0) && (i < aSize); i++) { + carry += a[i] & 0xFFFFFFFFL; + a[i] = (int) carry; + carry >>= 32; + } + return (int) carry; + } + + /** + * Performs {@code op1 -= op2}. {@code op1} must have enough place to store + * the result (i.e. {@code op1.bitLength() >= op2.bitLength()}). Both should + * be positive (what implies that {@code op1 >= op2}). + * + * @param op1 the input minuend, and the output result. + * @param op2 the subtrahend + */ + static void inplaceSubtract(BigInteger op1, BigInteger op2) { + // PRE: op1 >= op2 > 0 + subtract(op1.digits, op1.digits, op1.numberLength, op2.digits, + op2.numberLength); + op1.cutOffLeadingZeroes(); + op1.unCache(); + } + + /** + * @see BigInteger#subtract(BigInteger) . + * @param op1 + * @param op2 + * @return + */ + static BigInteger subtract(BigInteger op1, BigInteger op2) { + int resSign; + int resDigits[]; + int op1Sign = op1.sign; + int op2Sign = op2.sign; + + if (op2Sign == 0) { + return op1; + } + if (op1Sign == 0) { + return op2.negate(); + } + int op1Len = op1.numberLength; + int op2Len = op2.numberLength; + if (op1Len + op2Len == 2) { + long a = (op1.digits[0] & 0xFFFFFFFFL); + long b = (op2.digits[0] & 0xFFFFFFFFL); + if (op1Sign < 0) { + a = -a; + } + if (op2Sign < 0) { + b = -b; + } + return BigInteger.valueOf(a - b); + } + int cmp = ((op1Len != op2Len) ? ((op1Len > op2Len) ? 1 : -1) + : Elementary.compareArrays(op1.digits, op2.digits, op1Len)); + + if (cmp == BigInteger.LESS) { + resSign = -op2Sign; + resDigits = (op1Sign == op2Sign) ? subtract(op2.digits, op2Len, + op1.digits, op1Len) : add(op2.digits, op2Len, op1.digits, op1Len); + } else { + resSign = op1Sign; + if (op1Sign == op2Sign) { + if (cmp == BigInteger.EQUALS) { + return BigInteger.ZERO; + } + resDigits = subtract(op1.digits, op1Len, op2.digits, op2Len); + } else { + resDigits = add(op1.digits, op1Len, op2.digits, op2Len); + } + } + BigInteger res = new BigInteger(resSign, resDigits.length, resDigits); + res.cutOffLeadingZeroes(); + return res; + } + + /** + * Addss the value represented by {@code b} to the value represented by + * {@code a}. It is assumed the magnitude of a is not less than the magnitude + * of b. + * + * @return {@code a + b} + */ + private static int[] add(int a[], int aSize, int b[], int bSize) { + // PRE: a[] >= b[] + int res[] = new int[aSize + 1]; + add(res, a, aSize, b, bSize); + return res; + } + + /** + * Performs {@code res = a + b}. + */ + private static void add(int res[], int a[], int aSize, int b[], int bSize) { + // PRE: a.length < max(aSize, bSize) + + int i; + long carry = (a[0] & 0xFFFFFFFFL) + (b[0] & 0xFFFFFFFFL); + + res[0] = (int) carry; + carry >>= 32; + + if (aSize >= bSize) { + for (i = 1; i < bSize; i++) { + carry += (a[i] & 0xFFFFFFFFL) + (b[i] & 0xFFFFFFFFL); + res[i] = (int) carry; + carry >>= 32; + } + for (; i < aSize; i++) { + carry += a[i] & 0xFFFFFFFFL; + res[i] = (int) carry; + carry >>= 32; + } + } else { + for (i = 1; i < aSize; i++) { + carry += (a[i] & 0xFFFFFFFFL) + (b[i] & 0xFFFFFFFFL); + res[i] = (int) carry; + carry >>= 32; + } + for (; i < bSize; i++) { + carry += b[i] & 0xFFFFFFFFL; + res[i] = (int) carry; + carry >>= 32; + } + } + if (carry != 0) { + res[i] = (int) carry; + } + } + + /** + * Performs {@code res = b - a}. + */ + private static void inverseSubtract(int res[], int a[], int aSize, int b[], + int bSize) { + int i; + long borrow = 0; + if (aSize < bSize) { + for (i = 0; i < aSize; i++) { + borrow += (b[i] & 0xFFFFFFFFL) - (a[i] & 0xFFFFFFFFL); + res[i] = (int) borrow; + borrow >>= 32; // -1 or 0 + } + for (; i < bSize; i++) { + borrow += b[i] & 0xFFFFFFFFL; + res[i] = (int) borrow; + borrow >>= 32; // -1 or 0 + } + } else { + for (i = 0; i < bSize; i++) { + borrow += (b[i] & 0xFFFFFFFFL) - (a[i] & 0xFFFFFFFFL); + res[i] = (int) borrow; + borrow >>= 32; // -1 or 0 + } + for (; i < aSize; i++) { + borrow -= a[i] & 0xFFFFFFFFL; + res[i] = (int) borrow; + borrow >>= 32; // -1 or 0 + } + } + } + + /** + * Subtracts the value represented by {@code b} from the value represented by + * {@code a}. It is assumed the magnitude of a is not less than the magnitude + * of b. + * + * @return {@code a - b} + */ + private static int[] subtract(int a[], int aSize, int b[], int bSize) { + // PRE: a[] >= b[] + int res[] = new int[aSize]; + subtract(res, a, aSize, b, bSize); + return res; + } + + /** + * Performs {@code res = a - b}. It is assumed the magnitude of a is not less + * than the magnitude of b. + */ + private static void subtract(int res[], int a[], int aSize, int b[], int bSize) { + // PRE: a[] >= b[] + int i; + long borrow = 0; + + for (i = 0; i < bSize; i++) { + borrow += (a[i] & 0xFFFFFFFFL) - (b[i] & 0xFFFFFFFFL); + res[i] = (int) borrow; + borrow >>= 32; // -1 or 0 + } + for (; i < aSize; i++) { + borrow += a[i] & 0xFFFFFFFFL; + res[i] = (int) borrow; + borrow >>= 32; // -1 or 0 + } + } + + /** + * Compares two arrays, representing unsigned integer in little-endian order. + * Returns +1,0,-1 if a is - respective - greater, equal or lesser then b + */ + private static int unsignedArraysCompare(int[] a, int[] b, int aSize, + int bSize) { + if (aSize > bSize) { + return 1; + } else if (aSize < bSize) { + return -1; + } else { + int i; + for (i = aSize - 1; i >= 0 && a[i] == b[i]; i--) { + // empty + } + return i < 0 ? BigInteger.EQUALS + : ((a[i] & 0xFFFFFFFFL) < (b[i] & 0xFFFFFFFFL) ? BigInteger.LESS + : BigInteger.GREATER); + } + } + + /** + * Just to denote that this class can't be instantiated. + */ + private Elementary() { + } + +} diff --git a/gwt/jre/java/math/Logical.java b/gwt/jre/java/math/Logical.java new file mode 100644 index 0000000..d3ab03e --- /dev/null +++ b/gwt/jre/java/math/Logical.java @@ -0,0 +1,926 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +/** + * The library implements some logical operations over {@code BigInteger}. The + * operations provided are listed below. + */ +class Logical { + + /** + * @see BigInteger#and(BigInteger) + * @param val + * @param that + * @return + */ + static BigInteger and(BigInteger val, BigInteger that) { + if (that.sign == 0 || val.sign == 0) { + return BigInteger.ZERO; + } + if (that.equals(BigInteger.MINUS_ONE)) { + return val; + } + if (val.equals(BigInteger.MINUS_ONE)) { + return that; + } + + if (val.sign > 0) { + if (that.sign > 0) { + return andPositive(val, that); + } else { + return andDiffSigns(val, that); + } + } else { + if (that.sign > 0) { + return andDiffSigns(that, val); + } else if (val.numberLength > that.numberLength) { + return andNegative(val, that); + } else { + return andNegative(that, val); + } + } + } + + /** + * Return sign = positive.magnitude & magnitude = -negative.magnitude. + * @param positive + * @param negative + * @return + */ + static BigInteger andDiffSigns(BigInteger positive, BigInteger negative) { + // PRE: positive is positive and negative is negative + int iPos = positive.getFirstNonzeroDigit(); + int iNeg = negative.getFirstNonzeroDigit(); + + // Look if the trailing zeros of the negative will "blank" all + // the positive digits + if (iNeg >= positive.numberLength) { + return BigInteger.ZERO; + } + int resLength = positive.numberLength; + int resDigits[] = new int[resLength]; + + // Must start from max(iPos, iNeg) + int i = Math.max(iPos, iNeg); + if (i == iNeg) { + resDigits[i] = -negative.digits[i] & positive.digits[i]; + i++; + } + int limit = Math.min(negative.numberLength, positive.numberLength); + for (; i < limit; i++) { + resDigits[i] = ~negative.digits[i] & positive.digits[i]; + } + // if the negative was shorter must copy the remaining digits + // from positive + if (i >= negative.numberLength) { + for (; i < positive.numberLength; i++) { + resDigits[i] = positive.digits[i]; + } + } // else positive ended and must "copy" virtual 0's, do nothing then + + BigInteger result = new BigInteger(1, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Return sign = -1, magnitude = -(-longer.magnitude & -shorter.magnitude). + * @param longer + * @param shorter + * @return + */ + static BigInteger andNegative(BigInteger longer, BigInteger shorter) { + // PRE: longer and shorter are negative + // PRE: longer has at least as many digits as shorter + int iLonger = longer.getFirstNonzeroDigit(); + int iShorter = shorter.getFirstNonzeroDigit(); + + // Does shorter matter? + if (iLonger >= shorter.numberLength) { + return longer; + } + + int resLength; + int resDigits[]; + int i = Math.max(iShorter, iLonger); + int digit; + if (iShorter > iLonger) { + digit = -shorter.digits[i] & ~longer.digits[i]; + } else if (iShorter < iLonger) { + digit = ~shorter.digits[i] & -longer.digits[i]; + } else { + digit = -shorter.digits[i] & -longer.digits[i]; + } + if (digit == 0) { + for (i++; i < shorter.numberLength + && (digit = ~(longer.digits[i] | shorter.digits[i])) == 0; i++) { + // digit + } + // = ~longer.digits[i] & ~shorter.digits[i] + if (digit == 0) { + // shorter has only the remaining virtual sign bits + for (; i < longer.numberLength && (digit = ~longer.digits[i]) == 0; i++) { + // empty + } + if (digit == 0) { + resLength = longer.numberLength + 1; + resDigits = new int[resLength]; + resDigits[resLength - 1] = 1; + + BigInteger result = new BigInteger(-1, resLength, resDigits); + return result; + } + } + } + resLength = longer.numberLength; + resDigits = new int[resLength]; + resDigits[i] = -digit; + for (i++; i < shorter.numberLength; i++) { + // resDigits[i] = ~(~longer.digits[i] & ~shorter.digits[i];) + resDigits[i] = longer.digits[i] | shorter.digits[i]; + } + // shorter has only the remaining virtual sign bits + for (; i < longer.numberLength; i++) { + resDigits[i] = longer.digits[i]; + } + + BigInteger result = new BigInteger(-1, resLength, resDigits); + return result; + } + + /** + * @see BigInteger#andNot(BigInteger) + * @param val + * @param that + * @return + */ + static BigInteger andNot(BigInteger val, BigInteger that) { + if (that.sign == 0) { + return val; + } + if (val.sign == 0) { + return BigInteger.ZERO; + } + if (val.equals(BigInteger.MINUS_ONE)) { + return that.not(); + } + if (that.equals(BigInteger.MINUS_ONE)) { + return BigInteger.ZERO; + } + + // if val == that, return 0 + + if (val.sign > 0) { + if (that.sign > 0) { + return andNotPositive(val, that); + } else { + return andNotPositiveNegative(val, that); + } + } else { + if (that.sign > 0) { + return andNotNegativePositive(val, that); + } else { + return andNotNegative(val, that); + } + } + } + + /** + * Return sign = 1, magnitude = -val.magnitude & ~(-that.magnitude). + * @param val + * @param that + * @return + */ + static BigInteger andNotNegative(BigInteger val, BigInteger that) { + // PRE: val < 0 && that < 0 + int iVal = val.getFirstNonzeroDigit(); + int iThat = that.getFirstNonzeroDigit(); + + if (iVal >= that.numberLength) { + return BigInteger.ZERO; + } + + int resLength = that.numberLength; + int resDigits[] = new int[resLength]; + int limit; + int i = iVal; + if (iVal < iThat) { + // resDigits[i] = -val.digits[i] & -1; + resDigits[i] = -val.digits[i]; + limit = Math.min(val.numberLength, iThat); + for (i++; i < limit; i++) { + // resDigits[i] = ~val.digits[i] & -1; + resDigits[i] = ~val.digits[i]; + } + if (i == val.numberLength) { + for (; i < iThat; i++) { + // resDigits[i] = -1 & -1; + resDigits[i] = -1; + } + // resDigits[i] = -1 & ~-that.digits[i]; + resDigits[i] = that.digits[i] - 1; + } else { + // resDigits[i] = ~val.digits[i] & ~-that.digits[i]; + resDigits[i] = ~val.digits[i] & (that.digits[i] - 1); + } + } else if (iThat < iVal) { + // resDigits[i] = -val.digits[i] & ~~that.digits[i]; + resDigits[i] = -val.digits[i] & that.digits[i]; + } else { + // resDigits[i] = -val.digits[i] & ~-that.digits[i]; + resDigits[i] = -val.digits[i] & (that.digits[i] - 1); + } + + limit = Math.min(val.numberLength, that.numberLength); + for (i++; i < limit; i++) { + // resDigits[i] = ~val.digits[i] & ~~that.digits[i]; + resDigits[i] = ~val.digits[i] & that.digits[i]; + } + for (; i < that.numberLength; i++) { + // resDigits[i] = -1 & ~~that.digits[i]; + resDigits[i] = that.digits[i]; + } + + BigInteger result = new BigInteger(1, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Return sign = -1, magnitude = -(-negative.magnitude & ~positive.magnitude). + * @param negative + * @param positive + * @return + */ + static BigInteger andNotNegativePositive(BigInteger negative, + BigInteger positive) { + // PRE: negative < 0 && positive > 0 + int resLength; + int resDigits[]; + int limit; + int digit; + + int iNeg = negative.getFirstNonzeroDigit(); + int iPos = positive.getFirstNonzeroDigit(); + + if (iNeg >= positive.numberLength) { + return negative; + } + + resLength = Math.max(negative.numberLength, positive.numberLength); + int i = iNeg; + if (iPos > iNeg) { + resDigits = new int[resLength]; + limit = Math.min(negative.numberLength, iPos); + for (; i < limit; i++) { + // 1st case: resDigits [i] = -(-negative.digits[i] & (~0)) + // otherwise: resDigits[i] = ~(~negative.digits[i] & ~0) ; + resDigits[i] = negative.digits[i]; + } + if (i == negative.numberLength) { + for (i = iPos; i < positive.numberLength; i++) { + // resDigits[i] = ~(~positive.digits[i] & -1); + resDigits[i] = positive.digits[i]; + } + } + } else { + digit = -negative.digits[i] & ~positive.digits[i]; + if (digit == 0) { + limit = Math.min(positive.numberLength, negative.numberLength); + for (i++; i < limit + && (digit = ~(negative.digits[i] | positive.digits[i])) == 0; i++) { + // digit + } + // = ~negative.digits[i] & ~positive.digits[i] + if (digit == 0) { + // the shorter has only the remaining virtual sign bits + for (; i < positive.numberLength + && (digit = ~positive.digits[i]) == 0; i++) { + // digit = -1 & ~positive.digits[i] + } + for (; i < negative.numberLength + && (digit = ~negative.digits[i]) == 0; i++) { + // empty + } + // digit = ~negative.digits[i] & ~0 + if (digit == 0) { + resLength++; + resDigits = new int[resLength]; + resDigits[resLength - 1] = 1; + + BigInteger result = new BigInteger(-1, resLength, resDigits); + return result; + } + } + } + resDigits = new int[resLength]; + resDigits[i] = -digit; + i++; + } + + limit = Math.min(positive.numberLength, negative.numberLength); + for (; i < limit; i++) { + // resDigits[i] = ~(~negative.digits[i] & ~positive.digits[i]); + resDigits[i] = negative.digits[i] | positive.digits[i]; + } + // Actually one of the next two cycles will be executed + for (; i < negative.numberLength; i++) { + resDigits[i] = negative.digits[i]; + } + for (; i < positive.numberLength; i++) { + resDigits[i] = positive.digits[i]; + } + + BigInteger result = new BigInteger(-1, resLength, resDigits); + return result; + } + + /** + * Return sign = 1, magnitude = val.magnitude & ~that.magnitude. + * @param val + * @param that + * @return + */ + static BigInteger andNotPositive(BigInteger val, BigInteger that) { + // PRE: both arguments are positive + int resDigits[] = new int[val.numberLength]; + + int limit = Math.min(val.numberLength, that.numberLength); + int i; + for (i = val.getFirstNonzeroDigit(); i < limit; i++) { + resDigits[i] = val.digits[i] & ~that.digits[i]; + } + for (; i < val.numberLength; i++) { + resDigits[i] = val.digits[i]; + } + + BigInteger result = new BigInteger(1, val.numberLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Return sign = 1, magnitude = positive.magnitude & ~(-negative.magnitude). + * @param positive + * @param negative + * @return + */ + static BigInteger andNotPositiveNegative(BigInteger positive, + BigInteger negative) { + // PRE: positive > 0 && negative < 0 + int iNeg = negative.getFirstNonzeroDigit(); + int iPos = positive.getFirstNonzeroDigit(); + + if (iNeg >= positive.numberLength) { + return positive; + } + + int resLength = Math.min(positive.numberLength, negative.numberLength); + int resDigits[] = new int[resLength]; + + // Always start from first non zero of positive + int i = iPos; + for (; i < iNeg; i++) { + // resDigits[i] = positive.digits[i] & -1 (~0) + resDigits[i] = positive.digits[i]; + } + if (i == iNeg) { + resDigits[i] = positive.digits[i] & (negative.digits[i] - 1); + i++; + } + for (; i < resLength; i++) { + // resDigits[i] = positive.digits[i] & ~(~negative.digits[i]); + resDigits[i] = positive.digits[i] & negative.digits[i]; + } + + BigInteger result = new BigInteger(1, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Return sign = 1, magnitude = val.magnitude & that.magnitude. + * @param val + * @param that + * @return + */ + static BigInteger andPositive(BigInteger val, BigInteger that) { + // PRE: both arguments are positive + int resLength = Math.min(val.numberLength, that.numberLength); + int i = Math.max(val.getFirstNonzeroDigit(), that.getFirstNonzeroDigit()); + + if (i >= resLength) { + return BigInteger.ZERO; + } + + int resDigits[] = new int[resLength]; + for (; i < resLength; i++) { + resDigits[i] = val.digits[i] & that.digits[i]; + } + + BigInteger result = new BigInteger(1, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * @see BigInteger#not() + * @param val + * @return + */ + static BigInteger not(BigInteger val) { + if (val.sign == 0) { + return BigInteger.MINUS_ONE; + } + if (val.equals(BigInteger.MINUS_ONE)) { + return BigInteger.ZERO; + } + int resDigits[] = new int[val.numberLength + 1]; + int i; + + if (val.sign > 0) { + // ~val = -val + 1 + if (val.digits[val.numberLength - 1] != -1) { + for (i = 0; val.digits[i] == -1; i++) { + // empty + } + } else { + for (i = 0; (i < val.numberLength) && (val.digits[i] == -1); i++) { + // empty + } + if (i == val.numberLength) { + resDigits[i] = 1; + return new BigInteger(-val.sign, i + 1, resDigits); + } + } + // Here a carry 1 was generated + } else { + // (val.sign < 0) + // ~val = -val - 1 + for (i = 0; val.digits[i] == 0; i++) { + resDigits[i] = -1; + } + // Here a borrow -1 was generated + } + // Now, the carry/borrow can be absorbed + resDigits[i] = val.digits[i] + val.sign; + // Copying the remaining unchanged digit + for (i++; i < val.numberLength; i++) { + resDigits[i] = val.digits[i]; + } + return new BigInteger(-val.sign, i, resDigits); + } + + /** + * @see BigInteger#or(BigInteger). + * @param val + * @param that + * @return + */ + static BigInteger or(BigInteger val, BigInteger that) { + if (that.equals(BigInteger.MINUS_ONE) || val.equals(BigInteger.MINUS_ONE)) { + return BigInteger.MINUS_ONE; + } + if (that.sign == 0) { + return val; + } + if (val.sign == 0) { + return that; + } + + if (val.sign > 0) { + if (that.sign > 0) { + if (val.numberLength > that.numberLength) { + return orPositive(val, that); + } else { + return orPositive(that, val); + } + } else { + return orDiffSigns(val, that); + } + } else { + if (that.sign > 0) { + return orDiffSigns(that, val); + } else if (that.getFirstNonzeroDigit() > val.getFirstNonzeroDigit()) { + return orNegative(that, val); + } else { + return orNegative(val, that); + } + } + } + + /** + * Return sign = -1, magnitude = -(positive.magnitude | -negative.magnitude). + * @param positive + * @param negative + * @return + */ + static BigInteger orDiffSigns(BigInteger positive, BigInteger negative) { + // Jumping over the least significant zero bits + int iNeg = negative.getFirstNonzeroDigit(); + int iPos = positive.getFirstNonzeroDigit(); + int i; + int limit; + + // Look if the trailing zeros of the positive will "copy" all + // the negative digits + if (iPos >= negative.numberLength) { + return negative; + } + int resLength = negative.numberLength; + int resDigits[] = new int[resLength]; + + if (iNeg < iPos) { + // We know for sure that this will + // be the first non zero digit in the result + for (i = iNeg; i < iPos; i++) { + resDigits[i] = negative.digits[i]; + } + } else if (iPos < iNeg) { + i = iPos; + resDigits[i] = -positive.digits[i]; + limit = Math.min(positive.numberLength, iNeg); + for (i++; i < limit; i++) { + resDigits[i] = ~positive.digits[i]; + } + if (i != positive.numberLength) { + resDigits[i] = ~(-negative.digits[i] | positive.digits[i]); + } else { + for (; i < iNeg; i++) { + resDigits[i] = -1; + } + // resDigits[i] = ~(-negative.digits[i] | 0); + resDigits[i] = negative.digits[i] - 1; + } + i++; + } else { + // iNeg == iPos + // Applying two complement to negative and to result + i = iPos; + resDigits[i] = -(-negative.digits[i] | positive.digits[i]); + i++; + } + limit = Math.min(negative.numberLength, positive.numberLength); + for (; i < limit; i++) { + // Applying two complement to negative and to result + // resDigits[i] = ~(~negative.digits[i] | positive.digits[i] ); + resDigits[i] = negative.digits[i] & ~positive.digits[i]; + } + for (; i < negative.numberLength; i++) { + resDigits[i] = negative.digits[i]; + } + + BigInteger result = new BigInteger(-1, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Return sign = -1, magnitude = -(-val.magnitude | -that.magnitude). + * @param val + * @param that + * @return + */ + static BigInteger orNegative(BigInteger val, BigInteger that) { + // PRE: val and that are negative; + // PRE: val has at least as many trailing zeros digits as that + int iThat = that.getFirstNonzeroDigit(); + int iVal = val.getFirstNonzeroDigit(); + int i; + + if (iVal >= that.numberLength) { + return that; + } else if (iThat >= val.numberLength) { + return val; + } + + int resLength = Math.min(val.numberLength, that.numberLength); + int resDigits[] = new int[resLength]; + + // Looking for the first non-zero digit of the result + if (iThat == iVal) { + resDigits[iVal] = -(-val.digits[iVal] | -that.digits[iVal]); + i = iVal; + } else { + for (i = iThat; i < iVal; i++) { + resDigits[i] = that.digits[i]; + } + resDigits[i] = that.digits[i] & (val.digits[i] - 1); + } + + for (i++; i < resLength; i++) { + resDigits[i] = val.digits[i] & that.digits[i]; + } + + BigInteger result = new BigInteger(-1, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Return sign = 1, magnitude = longer.magnitude | shorter.magnitude. + * @param longer + * @param shorter + * @return + */ + static BigInteger orPositive(BigInteger longer, BigInteger shorter) { + // PRE: longer and shorter are positive; + // PRE: longer has at least as many digits as shorter + int resLength = longer.numberLength; + int resDigits[] = new int[resLength]; + + int i = Math.min(longer.getFirstNonzeroDigit(), + shorter.getFirstNonzeroDigit()); + for (i = 0; i < shorter.numberLength; i++) { + resDigits[i] = longer.digits[i] | shorter.digits[i]; + } + for (; i < resLength; i++) { + resDigits[i] = longer.digits[i]; + } + + BigInteger result = new BigInteger(1, resLength, resDigits); + return result; + } + + /** + * @see BigInteger#xor(BigInteger) + * @param val + * @param that + * @return + */ + static BigInteger xor(BigInteger val, BigInteger that) { + if (that.sign == 0) { + return val; + } + if (val.sign == 0) { + return that; + } + if (that.equals(BigInteger.MINUS_ONE)) { + return val.not(); + } + if (val.equals(BigInteger.MINUS_ONE)) { + return that.not(); + } + + if (val.sign > 0) { + if (that.sign > 0) { + if (val.numberLength > that.numberLength) { + return xorPositive(val, that); + } else { + return xorPositive(that, val); + } + } else { + return xorDiffSigns(val, that); + } + } else { + if (that.sign > 0) { + return xorDiffSigns(that, val); + } else if (that.getFirstNonzeroDigit() > val.getFirstNonzeroDigit()) { + return xorNegative(that, val); + } else { + return xorNegative(val, that); + } + } + } + + /** + * Return sign = 1, magnitude = -(positive.magnitude ^ -negative.magnitude). + * @param positive + * @param negative + * @return + */ + static BigInteger xorDiffSigns(BigInteger positive, BigInteger negative) { + int resLength = Math.max(negative.numberLength, positive.numberLength); + int resDigits[]; + int iNeg = negative.getFirstNonzeroDigit(); + int iPos = positive.getFirstNonzeroDigit(); + int i; + int limit; + + // The first + if (iNeg < iPos) { + resDigits = new int[resLength]; + i = iNeg; + // resDigits[i] = -(-negative.digits[i]); + resDigits[i] = negative.digits[i]; + limit = Math.min(negative.numberLength, iPos); + // Skip the positive digits while they are zeros + for (i++; i < limit; i++) { + // resDigits[i] = ~(~negative.digits[i]); + resDigits[i] = negative.digits[i]; + } + // if the negative has no more elements, must fill the + // result with the remaining digits of the positive + if (i == negative.numberLength) { + for (; i < positive.numberLength; i++) { + // resDigits[i] = ~(positive.digits[i] ^ -1) -> ~(~positive.digits[i]) + resDigits[i] = positive.digits[i]; + } + } + } else if (iPos < iNeg) { + resDigits = new int[resLength]; + i = iPos; + // Applying two complement to the first non-zero digit of the result + resDigits[i] = -positive.digits[i]; + limit = Math.min(positive.numberLength, iNeg); + for (i++; i < limit; i++) { + // Continue applying two complement the result + resDigits[i] = ~positive.digits[i]; + } + // When the first non-zero digit of the negative is reached, must apply + // two complement (arithmetic negation) to it, and then operate + if (i == iNeg) { + resDigits[i] = ~(positive.digits[i] ^ -negative.digits[i]); + i++; + } else { + // if the positive has no more elements must fill the remaining digits + // with + // the negative ones + for (; i < iNeg; i++) { + // resDigits[i] = ~(0 ^ 0) + resDigits[i] = -1; + } + for (; i < negative.numberLength; i++) { + // resDigits[i] = ~(~negative.digits[i] ^ 0) + resDigits[i] = negative.digits[i]; + } + } + } else { + int digit; + // The first non-zero digit of the positive and negative are the same + i = iNeg; + digit = positive.digits[i] ^ -negative.digits[i]; + if (digit == 0) { + limit = Math.min(positive.numberLength, negative.numberLength); + for (i++; i < limit + && (digit = positive.digits[i] ^ ~negative.digits[i]) == 0; i++) { + // empty + } + if (digit == 0) { + // shorter has only the remaining virtual sign bits + for (; i < positive.numberLength + && (digit = ~positive.digits[i]) == 0; i++) { + // empty + } + for (; i < negative.numberLength + && (digit = ~negative.digits[i]) == 0; i++) { + // empty + } + if (digit == 0) { + resLength = resLength + 1; + resDigits = new int[resLength]; + resDigits[resLength - 1] = 1; + + BigInteger result = new BigInteger(-1, resLength, resDigits); + return result; + } + } + } + resDigits = new int[resLength]; + resDigits[i] = -digit; + i++; + } + + limit = Math.min(negative.numberLength, positive.numberLength); + for (; i < limit; i++) { + resDigits[i] = ~(~negative.digits[i] ^ positive.digits[i]); + } + for (; i < positive.numberLength; i++) { + // resDigits[i] = ~(positive.digits[i] ^ -1) + resDigits[i] = positive.digits[i]; + } + for (; i < negative.numberLength; i++) { + // resDigits[i] = ~(0 ^ ~negative.digits[i]) + resDigits[i] = negative.digits[i]; + } + + BigInteger result = new BigInteger(-1, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Return sign = 0, magnitude = -val.magnitude ^ -that.magnitude. + * @param val + * @param that + * @return + */ + static BigInteger xorNegative(BigInteger val, BigInteger that) { + // PRE: val and that are negative + // PRE: val has at least as many trailing zero digits as that + int resLength = Math.max(val.numberLength, that.numberLength); + int resDigits[] = new int[resLength]; + int iVal = val.getFirstNonzeroDigit(); + int iThat = that.getFirstNonzeroDigit(); + int i = iThat; + int limit; + + if (iVal == iThat) { + resDigits[i] = -val.digits[i] ^ -that.digits[i]; + } else { + resDigits[i] = -that.digits[i]; + limit = Math.min(that.numberLength, iVal); + for (i++; i < limit; i++) { + resDigits[i] = ~that.digits[i]; + } + // Remains digits in that? + if (i == that.numberLength) { + // Jumping over the remaining zero to the first non one + for (; i < iVal; i++) { + // resDigits[i] = 0 ^ -1; + resDigits[i] = -1; + } + // resDigits[i] = -val.digits[i] ^ -1; + resDigits[i] = val.digits[i] - 1; + } else { + resDigits[i] = -val.digits[i] ^ ~that.digits[i]; + } + } + + limit = Math.min(val.numberLength, that.numberLength); + // Perform ^ between that al val until that ends + for (i++; i < limit; i++) { + // resDigits[i] = ~val.digits[i] ^ ~that.digits[i]; + resDigits[i] = val.digits[i] ^ that.digits[i]; + } + // Perform ^ between val digits and -1 until val ends + for (; i < val.numberLength; i++) { + // resDigits[i] = ~val.digits[i] ^ -1 ; + resDigits[i] = val.digits[i]; + } + for (; i < that.numberLength; i++) { + // resDigits[i] = -1 ^ ~that.digits[i] ; + resDigits[i] = that.digits[i]; + } + + BigInteger result = new BigInteger(1, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Return sign = 0, magnitude = longer.magnitude | shorter.magnitude. + * + * @param longer + * @param shorter + * @return + */ + static BigInteger xorPositive(BigInteger longer, BigInteger shorter) { + // PRE: longer and shorter are positive; + // PRE: longer has at least as many digits as shorter + int resLength = longer.numberLength; + int resDigits[] = new int[resLength]; + int i = Math.min(longer.getFirstNonzeroDigit(), + shorter.getFirstNonzeroDigit()); + for (; i < shorter.numberLength; i++) { + resDigits[i] = longer.digits[i] ^ shorter.digits[i]; + } + for (; i < longer.numberLength; i++) { + resDigits[i] = longer.digits[i]; + } + + BigInteger result = new BigInteger(1, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Just to denote that this class can't be instantiated. + */ + private Logical() { + } +} diff --git a/gwt/jre/java/math/MathContext.java b/gwt/jre/java/math/MathContext.java new file mode 100644 index 0000000..c1cbf8c --- /dev/null +++ b/gwt/jre/java/math/MathContext.java @@ -0,0 +1,313 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +import java.io.Serializable; + +/** + * Immutable objects describing settings such as rounding mode and digit + * precision for the numerical operations provided by class {@link BigDecimal}. + */ +public final class MathContext implements Serializable { + + /** + * A {@code MathContext} which corresponds to the IEEE 754r quadruple decimal + * precision format: 34 digit precision and {@link RoundingMode#HALF_EVEN} + * rounding. + */ + public static final MathContext DECIMAL128 = new MathContext(34, + RoundingMode.HALF_EVEN); + + /** + * A {@code MathContext} which corresponds to the IEEE 754r single decimal + * precision format: 7 digit precision and {@link RoundingMode#HALF_EVEN} + * rounding. + */ + public static final MathContext DECIMAL32 = new MathContext(7, + RoundingMode.HALF_EVEN); + + /** + * A {@code MathContext} which corresponds to the IEEE 754r double decimal + * precision format: 16 digit precision and {@link RoundingMode#HALF_EVEN} + * rounding. + */ + public static final MathContext DECIMAL64 = new MathContext(16, + RoundingMode.HALF_EVEN); + + /** + * A {@code MathContext} for unlimited precision with + * {@link RoundingMode#HALF_UP} rounding. + */ + public static final MathContext UNLIMITED = new MathContext(0, + RoundingMode.HALF_UP); + + /** + * An array of {@code char} containing: {@code + * 'p','r','e','c','i','s','i','o','n','='}. It's used to improve the methods + * related to {@code String} conversion. + * + * @see #MathContext(String) + * @see #toString() + */ + private static final char[] chPrecision = { + 'p', 'r', 'e', 'c', 'i', 's', 'i', 'o', 'n', '='}; + + /** + * An array of {@code char} containing: {@code + * 'r','o','u','n','d','i','n','g','M','o','d','e','='}. It's used to improve + * the methods related to {@code String} conversion. + * + * @see #MathContext(String) + * @see #toString() + */ + private static final char[] chRoundingMode = { + 'r', 'o', 'u', 'n', 'd', 'i', 'n', 'g', 'M', 'o', 'd', 'e', '='}; + + /** + * This is the serialVersionUID used by the sun implementation. + */ + private static final long serialVersionUID = 5579720004786848255L; + + /** + * The number of digits to be used for an operation; results are rounded to + * this precision. + */ + private int precision; + + /** + * A {@code RoundingMode} object which specifies the algorithm to be used for + * rounding. + */ + private RoundingMode roundingMode; + + /** + * Constructs a new {@code MathContext} with the specified precision and with + * the rounding mode {@link RoundingMode#HALF_UP HALF_UP}. If the precision + * passed is zero, then this implies that the computations have to be + * performed exact, the rounding mode in this case is irrelevant. + * + * @param precision the precision for the new {@code MathContext}. + * @throws IllegalArgumentException if {@code precision < 0}. + */ + public MathContext(int precision) { + this(precision, RoundingMode.HALF_UP); + } + + /** + * Constructs a new {@code MathContext} with the specified precision and with + * the specified rounding mode. If the precision passed is zero, then this + * implies that the computations have to be performed exact, the rounding mode + * in this case is irrelevant. + * + * @param precision the precision for the new {@code MathContext}. + * @param roundingMode the rounding mode for the new {@code MathContext}. + * @throws IllegalArgumentException if {@code precision < 0}. + * @throws NullPointerException if {@code roundingMode} is {@code null}. + */ + public MathContext(int precision, RoundingMode roundingMode) { + if (precision < 0) { + // math.0C=Digits < 0 + throw new IllegalArgumentException("Digits < 0"); //$NON-NLS-1$ + } + if (roundingMode == null) { + // math.0D=null RoundingMode + throw new NullPointerException("null RoundingMode"); //$NON-NLS-1$ + } + this.precision = precision; + this.roundingMode = roundingMode; + } + + /** + * Constructs a new {@code MathContext} from a string. The string has to + * specify the precision and the rounding mode to be used and has to follow + * the following syntax: + * "precision=<precision> roundingMode=<roundingMode>" This is the + * same form as the one returned by the {@link #toString} method. + * + * @param val a string describing the precision and rounding mode for the new + * {@code MathContext}. + * @throws IllegalArgumentException if the string is not in the correct format + * or if the precision specified is < 0. + */ + public MathContext(String val) { + if (val == null) { + throw new NullPointerException("null string"); + } + char[] charVal = val.toCharArray(); + int i; // Index of charVal + int j; // Index of chRoundingMode + int digit; // It will contain the digit parsed + + if ((charVal.length < 27) || (charVal.length > 45)) { + // math.0E=bad string format + throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$ + } + // Parsing "precision=" String + for (i = 0; (i < chPrecision.length) && (charVal[i] == chPrecision[i]); i++) { + // empty + } + + if (i < chPrecision.length) { + // math.0E=bad string format + throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$ + } + // Parsing the value for "precision="... + digit = Character.digit(charVal[i], 10); + if (digit == -1) { + // math.0E=bad string format + throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$ + } + this.precision = this.precision * 10 + digit; + i++; + + do { + digit = Character.digit(charVal[i], 10); + if (digit == -1) { + if (charVal[i] == ' ') { + // It parsed all the digits + i++; + break; + } + // It isn't a valid digit, and isn't a white space + // math.0E=bad string format + throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$ + } + // Accumulating the value parsed + this.precision = this.precision * 10 + digit; + if (this.precision < 0) { + // math.0E=bad string format + throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$ + } + i++; + } while (true); + // Parsing "roundingMode=" + for (j = 0; (j < chRoundingMode.length) + && (charVal[i] == chRoundingMode[j]); i++, j++) { + // empty + } + + if (j < chRoundingMode.length) { + // math.0E=bad string format + throw new IllegalArgumentException("bad string format"); //$NON-NLS-1$ + } + + // Parsing the value for "roundingMode"... + /* + * don't use implicit calls to RoundingMode.valueOf here, since it will break + * if enum name obfuscation is enabled. + */ + this.roundingMode = RoundingMode.valueOfExplicit(String.valueOf(charVal, i, + charVal.length - i)); + } + + /* Public Methods */ + + /** + * Returns true if x is a {@code MathContext} with the same precision setting + * and the same rounding mode as this {@code MathContext} instance. + * + * @param x object to be compared. + * @return {@code true} if this {@code MathContext} instance is equal to the + * {@code x} argument; {@code false} otherwise. + */ + @Override + public boolean equals(Object x) { + return ((x instanceof MathContext) + && (((MathContext) x).getPrecision() == precision) + && (((MathContext) x).getRoundingMode() == roundingMode)); + } + + /** + * Returns the precision. The precision is the number of digits used for an + * operation. Results are rounded to this precision. The precision is + * guaranteed to be non negative. If the precision is zero, then the + * computations have to be performed exact, results are not rounded in this + * case. + * + * @return the precision. + */ + public int getPrecision() { + return precision; + } + + /** + * Returns the rounding mode. The rounding mode is the strategy to be used to + * round results. + *

+ * The rounding mode is one of {@link RoundingMode#UP}, + * {@link RoundingMode#DOWN}, {@link RoundingMode#CEILING}, + * {@link RoundingMode#FLOOR}, {@link RoundingMode#HALF_UP}, + * {@link RoundingMode#HALF_DOWN}, {@link RoundingMode#HALF_EVEN}, or + * {@link RoundingMode#UNNECESSARY}. + * + * @return the rounding mode. + */ + public RoundingMode getRoundingMode() { + return roundingMode; + } + + /** + * Returns the hash code for this {@code MathContext} instance. + * + * @return the hash code for this {@code MathContext}. + */ + @Override + public int hashCode() { + // Make place for the necessary bits to represent 8 rounding modes + return ((precision << 3) | roundingMode.ordinal()); + } + + /** + * Returns the string representation for this {@code MathContext} instance. + * The string has the form {@code + * "precision= roundingMode=" * } where + * {@code } is an integer describing the number of digits + * used for operations and {@code } is the string + * representation of the rounding mode. + * + * @return a string representation for this {@code MathContext} instance + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(45); + + sb.append(chPrecision); + sb.append(precision); + sb.append(' '); + sb.append(chRoundingMode); + sb.append(roundingMode); + return sb.toString(); + } +} diff --git a/gwt/jre/java/math/Multiplication.java b/gwt/jre/java/math/Multiplication.java new file mode 100644 index 0000000..22fdf49 --- /dev/null +++ b/gwt/jre/java/math/Multiplication.java @@ -0,0 +1,534 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +/** + * Static library that provides all multiplication of {@link BigInteger} + * methods. + */ +class Multiplication { + + /** + * An array with the first powers of five in {@code BigInteger} version. ( + * {@code 5^0,5^1,...,5^31}) + */ + static final BigInteger bigFivePows[] = new BigInteger[32]; + + /** + * An array with the first powers of ten in {@code BigInteger} version. ( + * {@code 10^0,10^1,...,10^31}) + */ + static final BigInteger[] bigTenPows = new BigInteger[32]; + + /** + * An array with powers of five that fit in the type {@code int}. ({@code + * 5^0,5^1,...,5^13}) + */ + static final int fivePows[] = { + 1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, + 48828125, 244140625, 1220703125}; + + /** + * An array with powers of ten that fit in the type {@code int}. ({@code + * 10^0,10^1,...,10^9}) + */ + static final int tenPows[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; + + /** + * Break point in digits (number of {@code int} elements) between Karatsuba + * and Pencil and Paper multiply. + */ + static final int whenUseKaratsuba = 63; // an heuristic value + + static { + int i; + long fivePow = 1L; + + for (i = 0; i <= 18; i++) { + bigFivePows[i] = BigInteger.valueOf(fivePow); + bigTenPows[i] = BigInteger.valueOf(fivePow << i); + fivePow *= 5; + } + for (; i < bigTenPows.length; i++) { + bigFivePows[i] = bigFivePows[i - 1].multiply(bigFivePows[1]); + bigTenPows[i] = bigTenPows[i - 1].multiply(BigInteger.TEN); + } + } + + /** + * Performs the multiplication with the Karatsuba's algorithm. Karatsuba's + * algorithm: + * u = u1 * B + u0
+ * v = v1 * B + v0
+ * + * + * u*v = (u1 * v1) * B2 + ((u1 - u0) * (v0 - v1) + u1 * v1 + + * u0 * v0 ) * B + u0 * v0
+ *
+ * + * @param op1 first factor of the product + * @param op2 second factor of the product + * @return {@code op1 * op2} + * @see #multiply(BigInteger, BigInteger) + */ + static BigInteger karatsuba(BigInteger op1, BigInteger op2) { + BigInteger temp; + if (op2.numberLength > op1.numberLength) { + temp = op1; + op1 = op2; + op2 = temp; + } + if (op2.numberLength < whenUseKaratsuba) { + return multiplyPAP(op1, op2); + } + /* + * Karatsuba: u = u1*B + u0 v = v1*B + v0 u*v = (u1*v1)*B^2 + + * ((u1-u0)*(v0-v1) + u1*v1 + u0*v0)*B + u0*v0 + */ + // ndiv2 = (op1.numberLength / 2) * 32 + int ndiv2 = (op1.numberLength & 0xFFFFFFFE) << 4; + BigInteger upperOp1 = op1.shiftRight(ndiv2); + BigInteger upperOp2 = op2.shiftRight(ndiv2); + BigInteger lowerOp1 = op1.subtract(upperOp1.shiftLeft(ndiv2)); + BigInteger lowerOp2 = op2.subtract(upperOp2.shiftLeft(ndiv2)); + + BigInteger upper = karatsuba(upperOp1, upperOp2); + BigInteger lower = karatsuba(lowerOp1, lowerOp2); + BigInteger middle = karatsuba(upperOp1.subtract(lowerOp1), + lowerOp2.subtract(upperOp2)); + middle = middle.add(upper).add(lower); + middle = middle.shiftLeft(ndiv2); + upper = upper.shiftLeft(ndiv2 << 1); + + return upper.add(middle).add(lower); + } + + static void multArraysPAP(int[] aDigits, int aLen, int[] bDigits, int bLen, + int[] resDigits) { + if (aLen == 0 || bLen == 0) { + return; + } + + if (aLen == 1) { + resDigits[bLen] = multiplyByInt(resDigits, bDigits, bLen, aDigits[0]); + } else if (bLen == 1) { + resDigits[aLen] = multiplyByInt(resDigits, aDigits, aLen, bDigits[0]); + } else { + multPAP(aDigits, bDigits, resDigits, aLen, bLen); + } + } + + /** + * Performs a multiplication of two BigInteger and hides the algorithm used. + * + * @see BigInteger#multiply(BigInteger) + */ + static BigInteger multiply(BigInteger x, BigInteger y) { + return karatsuba(x, y); + } + + /** + * Multiplies a number by a power of five. This method is used in {@code + * BigDecimal} class. + * + * @param val the number to be multiplied + * @param exp a positive {@code int} exponent + * @return {@code val * 5exp} + */ + static BigInteger multiplyByFivePow(BigInteger val, int exp) { + // PRE: exp >= 0 + if (exp < fivePows.length) { + return multiplyByPositiveInt(val, fivePows[exp]); + } else if (exp < bigFivePows.length) { + return val.multiply(bigFivePows[exp]); + } else { + // Large powers of five + return val.multiply(bigFivePows[1].pow(exp)); + } + } + + /** + * Multiplies an array of integers by an integer value. + * + * @param a the array of integers + * @param aSize the number of elements of intArray to be multiplied + * @param factor the multiplier + * @return the top digit of production + */ + static int multiplyByInt(int a[], final int aSize, final int factor) { + return multiplyByInt(a, a, aSize, factor); + } + + /** + * Multiplies a number by a positive integer. + * + * @param val an arbitrary {@code BigInteger} + * @param factor a positive {@code int} number + * @return {@code val * factor} + */ + static BigInteger multiplyByPositiveInt(BigInteger val, int factor) { + int resSign = val.sign; + if (resSign == 0) { + return BigInteger.ZERO; + } + int aNumberLength = val.numberLength; + int[] aDigits = val.digits; + + if (aNumberLength == 1) { + long res = unsignedMultAddAdd(aDigits[0], factor, 0, 0); + int resLo = (int) res; + int resHi = (int) (res >>> 32); + return ((resHi == 0) ? new BigInteger(resSign, resLo) : new BigInteger( + resSign, 2, new int[] {resLo, resHi})); + } + // Common case + int resLength = aNumberLength + 1; + int resDigits[] = new int[resLength]; + + resDigits[aNumberLength] = multiplyByInt(resDigits, aDigits, aNumberLength, + factor); + BigInteger result = new BigInteger(resSign, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + /** + * Multiplies a number by a power of ten. This method is used in {@code + * BigDecimal} class. + * + * @param val the number to be multiplied + * @param exp a positive {@code long} exponent + * @return {@code val * 10exp} + */ + static BigInteger multiplyByTenPow(BigInteger val, int exp) { + // PRE: exp >= 0 + return ((exp < tenPows.length) ? multiplyByPositiveInt(val, + tenPows[(int) exp]) : val.multiply(powerOf10(exp))); + } + + /** + * Multiplies two BigIntegers. Implements traditional scholar algorithm + * described by Knuth. + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
A=a3a2a1a0
B=b2b1b1
b0*a3b0*a2b0*a1b0*a0
b1*a3b1*a2b1*a1b1*a0
+b2*a3b2*a2b2*a1b2*a0
____________________________________
A*B=R=r5r4r3r2r1r0
+ * + *
+ * + * @param op1 first factor of the multiplication {@code op1 >= 0} + * @param op2 second factor of the multiplication {@code op2 >= 0} + * @return a {@code BigInteger} of value {@code op1 * op2} + */ + static BigInteger multiplyPAP(BigInteger a, BigInteger b) { + // PRE: a >= b + int aLen = a.numberLength; + int bLen = b.numberLength; + int resLength = aLen + bLen; + int resSign = (a.sign != b.sign) ? -1 : 1; + // A special case when both numbers don't exceed int + if (resLength == 2) { + long val = unsignedMultAddAdd(a.digits[0], b.digits[0], 0, 0); + int valueLo = (int) val; + int valueHi = (int) (val >>> 32); + return ((valueHi == 0) ? new BigInteger(resSign, valueLo) + : new BigInteger(resSign, 2, new int[] {valueLo, valueHi})); + } + int[] aDigits = a.digits; + int[] bDigits = b.digits; + int resDigits[] = new int[resLength]; + // Common case + multArraysPAP(aDigits, aLen, bDigits, bLen, resDigits); + BigInteger result = new BigInteger(resSign, resLength, resDigits); + result.cutOffLeadingZeroes(); + return result; + } + + static void multPAP(int a[], int b[], int t[], int aLen, int bLen) { + if (a == b && aLen == bLen) { + square(a, aLen, t); + return; + } + + for (int i = 0; i < aLen; i++) { + long carry = 0; + int aI = a[i]; + for (int j = 0; j < bLen; j++) { + carry = unsignedMultAddAdd(aI, b[j], t[i + j], (int) carry); + t[i + j] = (int) carry; + carry >>>= 32; + } + t[i + bLen] = (int) carry; + } + } + + static BigInteger pow(BigInteger base, int exponent) { + // PRE: exp > 0 + BigInteger res = BigInteger.ONE; + BigInteger acc = base; + + for (; exponent > 1; exponent >>= 1) { + if ((exponent & 1) != 0) { + // if odd, multiply one more time by acc + res = res.multiply(acc); + } + // acc = base^(2^i) + // a limit where karatsuba performs a faster square than the square + // algorithm + if (acc.numberLength == 1) { + acc = acc.multiply(acc); // square + } else { + acc = new BigInteger(1, square(acc.digits, acc.numberLength, + new int[acc.numberLength << 1])); + } + } + // exponent == 1, multiply one more time + res = res.multiply(acc); + return res; + } + + /** + * It calculates a power of ten, which exponent could be out of 32-bit range. + * Note that internally this method will be used in the worst case with an + * exponent equals to: {@code Integer.MAX_VALUE - Integer.MIN_VALUE}. + * + * @param exp the exponent of power of ten, it must be positive. + * @return a {@code BigInteger} with value {@code 10exp}. + */ + static BigInteger powerOf10(double exp) { + // PRE: exp >= 0 + int intExp = (int) exp; + // "SMALL POWERS" + if (exp < bigTenPows.length) { + // The largest power that fit in 'long' type + return bigTenPows[intExp]; + } else if (exp <= 50) { + // To calculate: 10^exp + return BigInteger.TEN.pow(intExp); + } else if (exp <= 1000) { + // To calculate: 5^exp * 2^exp + return bigFivePows[1].pow(intExp).shiftLeft(intExp); + } + // "LARGE POWERS" + /* + * To check if there is free memory to allocate a BigInteger of the + * estimated size, measured in bytes: 1 + [exp / log10(2)] + */ + if (exp > 1000000) { + throw new ArithmeticException("power of ten too big"); //$NON-NLS-1$ + } + + if (exp <= Integer.MAX_VALUE) { + // To calculate: 5^exp * 2^exp + return bigFivePows[1].pow(intExp).shiftLeft(intExp); + } + /* + * "HUGE POWERS" + * + * This branch probably won't be executed since the power of ten is too big. + */ + // To calculate: 5^exp + BigInteger powerOfFive = bigFivePows[1].pow(Integer.MAX_VALUE); + BigInteger res = powerOfFive; + long longExp = (long) (exp - Integer.MAX_VALUE); + + intExp = (int) (exp % Integer.MAX_VALUE); + while (longExp > Integer.MAX_VALUE) { + res = res.multiply(powerOfFive); + longExp -= Integer.MAX_VALUE; + } + res = res.multiply(bigFivePows[1].pow(intExp)); + // To calculate: 5^exp << exp + res = res.shiftLeft(Integer.MAX_VALUE); + longExp = (long) (exp - Integer.MAX_VALUE); + while (longExp > Integer.MAX_VALUE) { + res = res.shiftLeft(Integer.MAX_VALUE); + longExp -= Integer.MAX_VALUE; + } + res = res.shiftLeft(intExp); + return res; + } + + /** + * Performs a2. + * + * @param a The number to square. + * @param aLen The length of the number to square. + */ + static int[] square(int[] a, int aLen, int[] res) { + long carry; + + for (int i = 0; i < aLen; i++) { + carry = 0; + for (int j = i + 1; j < aLen; j++) { + carry = unsignedMultAddAdd(a[i], a[j], res[i + j], (int) carry); + res[i + j] = (int) carry; + carry >>>= 32; + } + res[i + aLen] = (int) carry; + } + + BitLevel.shiftLeftOneBit(res, res, aLen << 1); + + carry = 0; + for (int i = 0, index = 0; i < aLen; i++, index++) { + carry = unsignedMultAddAdd(a[i], a[i], res[index], (int) carry); + res[index] = (int) carry; + carry >>>= 32; + index++; + carry += res[index] & 0xFFFFFFFFL; + res[index] = (int) carry; + carry >>>= 32; + } + return res; + } + + /** + * Computes the value unsigned ((uint)a*(uint)b + (uint)c + (uint)d). This + * method could improve the readability and performance of the code. + * + * @param a parameter 1 + * @param b parameter 2 + * @param c parameter 3 + * @param d parameter 4 + * @return value of expression + */ + static long unsignedMultAddAdd(int a, int b, int c, int d) { + return (a & 0xFFFFFFFFL) * (b & 0xFFFFFFFFL) + (c & 0xFFFFFFFFL) + + (d & 0xFFFFFFFFL); + } + + /** + * Multiplies an array of integers by an integer value and saves the result in + * {@code res}. + * + * @param a the array of integers + * @param aSize the number of elements of intArray to be multiplied + * @param factor the multiplier + * @return the top digit of production + */ + private static int multiplyByInt(int res[], int a[], final int aSize, + final int factor) { + long carry = 0; + for (int i = 0; i < aSize; i++) { + carry = unsignedMultAddAdd(a[i], factor, (int) carry, 0); + res[i] = (int) carry; + carry >>>= 32; + } + return (int) carry; + } + + /** + * Just to denote that this class can't be instantiated. + */ + private Multiplication() { + } + +} diff --git a/gwt/jre/java/math/Primality.java b/gwt/jre/java/math/Primality.java new file mode 100644 index 0000000..016d99c --- /dev/null +++ b/gwt/jre/java/math/Primality.java @@ -0,0 +1,303 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +import java.util.Arrays; +import java.util.Random; + +/** + * Provides primality probabilistic methods. + */ +class Primality { + + /** + * It encodes how many iterations of Miller-Rabin test are need to get an + * error bound not greater than {@code 2(-100)}. For example: for a + * {@code 1000}-bit number we need {@code 4} iterations, since {@code BITS[3] + * < 1000 <= BITS[4]}. + */ + private static final int[] BITS = { + 0, 0, 1854, 1233, 927, 747, 627, 543, 480, 431, 393, 361, 335, 314, 295, + 279, 265, 253, 242, 232, 223, 216, 181, 169, 158, 150, 145, 140, 136, + 132, 127, 123, 119, 114, 110, 105, 101, 96, 92, 87, 83, 78, 73, 69, 64, + 59, 54, 49, 44, 38, 32, 26, 1}; + + /** + * It encodes how many i-bit primes there are in the table for {@code + * i=2,...,10}. For example {@code offsetPrimes[6]} says that from index + * {@code 11} exists {@code 7} consecutive {@code 6}-bit prime numbers in the + * array. + */ + private static final int[][] offsetPrimes = { + null, null, {0, 2}, {2, 2}, {4, 2}, {6, 5}, {11, 7}, {18, 13}, {31, 23}, + {54, 43}, {97, 75}}; + + /** + * All prime numbers with bit length lesser than 10 bits. + */ + private static final int primes[] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, + 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, + 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, + 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, + 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, + 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, + 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, + 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, + 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021}; + + /** + * All {@code BigInteger} prime numbers with bit length lesser than 8 bits. + */ + private static final BigInteger BIprimes[] = new BigInteger[primes.length]; + + static { + // To initialize the dual table of BigInteger primes + for (int i = 0; i < primes.length; i++) { + BIprimes[i] = BigInteger.valueOf(primes[i]); + } + } + + /** + * A random number is generated until a probable prime number is found. + * + * @see BigInteger#BigInteger(int,int,Random) + * @see BigInteger#probablePrime(int,Random) + * @see #isProbablePrime(BigInteger, int) + */ + static BigInteger consBigInteger(int bitLength, int certainty, Random rnd) { + // PRE: bitLength >= 2; + // For small numbers get a random prime from the prime table + if (bitLength <= 10) { + int rp[] = offsetPrimes[bitLength]; + return BIprimes[rp[0] + rnd.nextInt(rp[1])]; + } + int shiftCount = (-bitLength) & 31; + int last = (bitLength + 31) >> 5; + BigInteger n = new BigInteger(1, last, new int[last]); + + last--; + do { + // To fill the array with random integers + for (int i = 0; i < n.numberLength; i++) { + n.digits[i] = rnd.nextInt(); + } + // To fix to the correct bitLength + n.digits[last] |= 0x80000000; + n.digits[last] >>>= shiftCount; + // To create an odd number + n.digits[0] |= 1; + } while (!isProbablePrime(n, certainty)); + return n; + } + + /** + * @see BigInteger#isProbablePrime(int) + * @see #millerRabin(BigInteger, int) + * @ar.org.fitc.ref Optimizations: "A. Menezes - Handbook of applied + * Cryptography, Chapter 4". + */ + static boolean isProbablePrime(BigInteger n, int certainty) { + // PRE: n >= 0; + if ((certainty <= 0) || ((n.numberLength == 1) && (n.digits[0] == 2))) { + return true; + } + // To discard all even numbers + if (!n.testBit(0)) { + return false; + } + // To check if 'n' exists in the table (it fit in 10 bits) + if ((n.numberLength == 1) && ((n.digits[0] & 0XFFFFFC00) == 0)) { + return (Arrays.binarySearch(primes, n.digits[0]) >= 0); + } + // To check if 'n' is divisible by some prime of the table + for (int i = 1; i < primes.length; i++) { + if (Division.remainderArrayByInt(n.digits, n.numberLength, primes[i]) == 0) { + return false; + } + } + // To set the number of iterations necessary for Miller-Rabin test + int i; + int bitLength = n.bitLength(); + + for (i = 2; bitLength < BITS[i]; i++) { + // empty + } + certainty = Math.min(i, 1 + ((certainty - 1) >> 1)); + + return millerRabin(n, certainty); + } + + /** + * It uses the sieve of Eratosthenes to discard several composite numbers in + * some appropriate range (at the moment {@code [this, this + 1024]}). After + * this process it applies the Miller-Rabin test to the numbers that were not + * discarded in the sieve. + * + * @see BigInteger#nextProbablePrime() + * @see #millerRabin(BigInteger, int) + */ + static BigInteger nextProbablePrime(BigInteger n) { + // PRE: n >= 0 + int i, j; + int certainty; + int gapSize = 1024; // for searching of the next probable prime number + int modules[] = new int[primes.length]; + boolean isDivisible[] = new boolean[gapSize]; + BigInteger startPoint; + BigInteger probPrime; + // If n < "last prime of table" searches next prime in the table + if ((n.numberLength == 1) && (n.digits[0] >= 0) + && (n.digits[0] < primes[primes.length - 1])) { + for (i = 0; n.digits[0] >= primes[i]; i++) { + // empty + } + return BIprimes[i]; + } + /* + * Creates a "N" enough big to hold the next probable prime Note that: N < + * "next prime" < 2*N + */ + startPoint = new BigInteger(1, n.numberLength, new int[n.numberLength + 1]); + System.arraycopy(n.digits, 0, startPoint.digits, 0, n.numberLength); + // To fix N to the "next odd number" + if (n.testBit(0)) { + Elementary.inplaceAdd(startPoint, 2); + } else { + startPoint.digits[0] |= 1; + } + // To set the improved certainly of Miller-Rabin + j = startPoint.bitLength(); + for (certainty = 2; j < BITS[certainty]; certainty++) { + // empty + } + // To calculate modules: N mod p1, N mod p2, ... for first primes. + for (i = 0; i < primes.length; i++) { + modules[i] = Division.remainder(startPoint, primes[i]) - gapSize; + } + while (true) { + // At this point, all numbers in the gap are initialized as + // probably primes + Arrays.fill(isDivisible, false); + // To discard multiples of first primes + for (i = 0; i < primes.length; i++) { + modules[i] = (modules[i] + gapSize) % primes[i]; + j = (modules[i] == 0) ? 0 : (primes[i] - modules[i]); + for (; j < gapSize; j += primes[i]) { + isDivisible[j] = true; + } + } + // To execute Miller-Rabin for non-divisible numbers by all first + // primes + for (j = 0; j < gapSize; j++) { + if (!isDivisible[j]) { + probPrime = startPoint.copy(); + Elementary.inplaceAdd(probPrime, j); + + if (millerRabin(probPrime, certainty)) { + return probPrime; + } + } + } + Elementary.inplaceAdd(startPoint, gapSize); + } + } + + /** + * The Miller-Rabin primality test. + * + * @param n the input number to be tested. + * @param t the number of trials. + * @return {@code false} if the number is definitely compose, otherwise + * {@code true} with probability {@code 1 - 4(-t)}. + * @ar.org.fitc.ref "D. Knuth, The Art of Computer Programming Vo.2, Section + * 4.5.4., Algorithm P" + */ + private static boolean millerRabin(BigInteger n, int t) { + // PRE: n >= 0, t >= 0 + BigInteger x; // x := UNIFORM{2...n-1} + BigInteger y; // y := x^(q * 2^j) mod n + BigInteger nMinus1 = n.subtract(BigInteger.ONE); // n-1 + int bitLength = nMinus1.bitLength(); // ~ log2(n-1) + // (q,k) such that: n-1 = q * 2^k and q is odd + int k = nMinus1.getLowestSetBit(); + BigInteger q = nMinus1.shiftRight(k); + Random rnd = new Random(); + + for (int i = 0; i < t; i++) { + // To generate a witness 'x', first it use the primes of table + if (i < primes.length) { + x = BIprimes[i]; + } else { + /* + * It generates random witness only if it's necesssary. Note that all + * methods would call Miller-Rabin with t <= 50 so this part is only to + * do more robust the algorithm + */ + do { + x = new BigInteger(bitLength, rnd); + } while ((x.compareTo(n) >= BigInteger.EQUALS) || (x.sign == 0) + || x.isOne()); + } + y = x.modPow(q, n); + if (y.isOne() || y.equals(nMinus1)) { + continue; + } + for (int j = 1; j < k; j++) { + if (y.equals(nMinus1)) { + continue; + } + y = y.multiply(y).mod(n); + if (y.isOne()) { + return false; + } + } + if (!y.equals(nMinus1)) { + return false; + } + } + return true; + } + + /** + * Just to denote that this class can't be instantiated. + */ + private Primality() { + } + +} diff --git a/gwt/jre/java/math/RoundingMode.java b/gwt/jre/java/math/RoundingMode.java new file mode 100644 index 0000000..ef7bdbc --- /dev/null +++ b/gwt/jre/java/math/RoundingMode.java @@ -0,0 +1,214 @@ +/* + * Copyright 2009 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + * + * INCLUDES MODIFICATIONS BY RICHARD ZSCHECH AS WELL AS GOOGLE. + */ +package java.math; + +/** + * Specifies the rounding behavior for operations whose results cannot be + * represented exactly. + */ +public enum RoundingMode { + + /** + * Rounding mode where positive values are rounded towards positive infinity + * and negative values towards negative infinity.
+ * Rule: {@code x.round().abs() >= x.abs()} + */ + UP(BigDecimal.ROUND_UP), + + /** + * Rounding mode where the values are rounded towards zero.
+ * Rule: {@code x.round().abs() <= x.abs()} + */ + DOWN(BigDecimal.ROUND_DOWN), + + /** + * Rounding mode to round towards positive infinity. For positive values this + * rounding mode behaves as {@link #UP}, for negative values as {@link #DOWN}.
+ * Rule: {@code x.round() >= x} + */ + CEILING(BigDecimal.ROUND_CEILING), + + /** + * Rounding mode to round towards negative infinity. For positive values this + * rounding mode behaves as {@link #DOWN}, for negative values as {@link #UP}.
+ * Rule: {@code x.round() <= x} + */ + FLOOR(BigDecimal.ROUND_FLOOR), + + /** + * Rounding mode where values are rounded towards the nearest neighbor. Ties + * are broken by rounding up. + */ + HALF_UP(BigDecimal.ROUND_HALF_UP), + + /** + * Rounding mode where values are rounded towards the nearest neighbor. Ties + * are broken by rounding down. + */ + HALF_DOWN(BigDecimal.ROUND_HALF_DOWN), + + /** + * Rounding mode where values are rounded towards the nearest neighbor. Ties + * are broken by rounding to the even neighbor. + */ + HALF_EVEN(BigDecimal.ROUND_HALF_EVEN), + + /** + * Rounding mode where the rounding operations throws an ArithmeticException + * for the case that rounding is necessary, i.e. for the case that the value + * cannot be represented exactly. + */ + UNNECESSARY(BigDecimal.ROUND_UNNECESSARY); + + /** + * Some constant char arrays for optimized comparisons + */ + private static final char[] chCEILING = {'C','E','I','L','I','N','G'}; + private static final char[] chDOWN = {'D','O','W','N'}; + private static final char[] chFLOOR = {'F','L','O','O','R'}; + private static final char[] chHALF_DOWN = {'H','A','L','F','_','D','O','W','N'}; + private static final char[] chHALF_EVEN = {'H','A','L','F','_','E','V','E','N'}; + private static final char[] chHALF_UP = {'H','A','L','F','_','U','P'}; + private static final char[] chUNNECESSARY = {'U','N','N','E','C','E','S','S','A','R','Y'}; + private static final char[] chUP = {'U','P'}; + + /** + * Converts rounding mode constants from class {@code BigDecimal} into {@code + * RoundingMode} values. + * + * @param mode rounding mode constant as defined in class {@code BigDecimal} + * @return corresponding rounding mode object + */ + public static RoundingMode valueOf(int mode) { + switch (mode) { + case BigDecimal.ROUND_CEILING: + return CEILING; + case BigDecimal.ROUND_DOWN: + return DOWN; + case BigDecimal.ROUND_FLOOR: + return FLOOR; + case BigDecimal.ROUND_HALF_DOWN: + return HALF_DOWN; + case BigDecimal.ROUND_HALF_EVEN: + return HALF_EVEN; + case BigDecimal.ROUND_HALF_UP: + return HALF_UP; + case BigDecimal.ROUND_UNNECESSARY: + return UNNECESSARY; + case BigDecimal.ROUND_UP: + return UP; + default: + // math.00=Invalid rounding mode + throw new IllegalArgumentException("Invalid rounding mode"); //$NON-NLS-1$ + } + } + + /** + * Bypasses calls to the implicit valueOf(String) method, which will break + * if enum name obfuscation is enabled. This should be package visible only. + * + * @param mode rounding mode string as defined in class {@code BigDecimal} + * @return corresponding rounding mode object + */ + static RoundingMode valueOfExplicit(String mode) { + /* + * Note this is optimized to avoid multiple String compares, + * using specific knowledge of the set of allowed enum constants. + */ + + if (mode == null) { + throw new NullPointerException(); + } + + char[] modeChars = mode.toCharArray(); + int len = modeChars.length; + if (len < chUP.length || len > chUNNECESSARY.length) { + throw new IllegalArgumentException(); + } + + char[] targetChars = null; + RoundingMode target = null; + if (modeChars[0] == 'C') { + target = RoundingMode.CEILING; + targetChars = chCEILING; + } else if (modeChars[0] == 'D') { + target = RoundingMode.DOWN; + targetChars = chDOWN; + } else if (modeChars[0] == 'F') { + target = RoundingMode.FLOOR; + targetChars = chFLOOR; + } else if (modeChars[0] == 'H') { + if (len > 6) { + if (modeChars[5] == 'D') { + target = RoundingMode.HALF_DOWN; + targetChars = chHALF_DOWN; + } else if (modeChars[5] == 'E') { + target = RoundingMode.HALF_EVEN; + targetChars = chHALF_EVEN; + } else if (modeChars[5] == 'U') { + target = RoundingMode.HALF_UP; + targetChars = chHALF_UP; + } + } + } else if (modeChars[0] == 'U') { + if (modeChars[1] == 'P') { + target = RoundingMode.UP; + targetChars = chUP; + } else if (modeChars[1] == 'N') { + target = RoundingMode.UNNECESSARY; + targetChars = chUNNECESSARY; + } + } + + if (target != null && len == targetChars.length) { + int i; + for (i = 1; i < len && modeChars[i] == targetChars[i]; i++) { + } + if (i == len) { + return target; + } + } + + throw new IllegalArgumentException(); + } + + /** + * Set the old constant. + * @param rm unused + */ + RoundingMode(int rm) { + // Note that we do not need the old-style rounding mode, so we ignore it. + } +} diff --git a/gwt/jre/java/net/UnknownServiceException.java b/gwt/jre/java/net/UnknownServiceException.java new file mode 100644 index 0000000..d5d5b9a --- /dev/null +++ b/gwt/jre/java/net/UnknownServiceException.java @@ -0,0 +1,21 @@ +package java.net; + +import java.io.IOException; + +public class UnknownServiceException extends IOException { + + public UnknownServiceException() { + // TODO Auto-generated constructor stub + } + + public UnknownServiceException(String s) { + super(s); + // TODO Auto-generated constructor stub + } + + public UnknownServiceException(Exception e) { + super(e); + // TODO Auto-generated constructor stub + } + +} diff --git a/gwt/jre/java/security/SecureRandom.java b/gwt/jre/java/security/SecureRandom.java new file mode 100644 index 0000000..f380e2a --- /dev/null +++ b/gwt/jre/java/security/SecureRandom.java @@ -0,0 +1,121 @@ +package java.security; + +import com.google.gwt.core.client.JsArrayInteger; + +public class SecureRandom extends java.util.Random +{ + private static final double twoToThe24 = 16777216.0; + private static final double twoToThe31 = 2147483648.0; + private static final double twoToThe32 = 4294967296.0; + private static final double twoToTheMinus24 = + 5.9604644775390625e-8; + private static final double twoToTheMinus26 = + 1.490116119384765625e-8; + private static final double twoToTheMinus31 = + 4.656612873077392578125e-10; + private static final double twoToTheMinus53 = + 1.1102230246251565404236316680908203125e-16; + + protected native JsArrayInteger jsNextChunk() /*-{ + var words = $wnd.sjcl.random.randomWords(4); + return words; + }-*/; + + public int next(int numBits) + { + int numBytes = (numBits+7)/8; + byte[] bytes = new byte[numBytes]; + nextBytes(bytes); + + int result=0; + for (int i=0; i key type. + * @param value type. + */ +@Deprecated +public class Hashtable implements Map, + Cloneable { + /* + * This implementation simply delegates to HashMap. + */ + + private HashMap map; + + public Hashtable() { + map = new HashMap(); + } + + public Hashtable clone () + { + Hashtable c = new Hashtable(); + for (Map.Entry e : map.entrySet()) + c.put(e.getKey(), e.getValue()); + + return c; + } + + public Hashtable(int initialSize) { + map = new HashMap(); + } + + public void clear() { + map.clear(); + } + + public boolean containsKey(Object key) { + return map.containsKey(key); + } + + public boolean containsValue(Object value) { + return map.containsValue(value); + } + + public Enumeration elements() { + return Collections.enumeration(map.values()); + } + + public Set> entrySet() { + return map.entrySet(); + } + + public V get(Object key) { + return map.get(key); + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + public Enumeration keys() { + return Collections.enumeration(map.keySet()); + } + + public Set keySet() { + return map.keySet(); + } + + public V put(K key, V value) { + return map.put(key, value); + } + + public void putAll(Map otherMap) { + map.putAll(otherMap); + } + + public V remove(Object key) { + return map.remove(key); + } + + public int size() { + return map.size(); + } + + public Collection values() { + return map.values(); + } + +} diff --git a/gwt/jre/java/util/Properties.java b/gwt/jre/java/util/Properties.java new file mode 100644 index 0000000..8bb22b3 --- /dev/null +++ b/gwt/jre/java/util/Properties.java @@ -0,0 +1,5 @@ +package java.util; + +public class Properties { + +} diff --git a/gwt/jre/java/util/StringTokenizer.java b/gwt/jre/java/util/StringTokenizer.java new file mode 100644 index 0000000..9791d14 --- /dev/null +++ b/gwt/jre/java/util/StringTokenizer.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.util; + + +/** + * String tokenizer is used to break a string apart into tokens. + * + * If returnDelimiters is false, successive calls to nextToken() return maximal + * blocks of characters that do not contain a delimiter. + * + * If returnDelimiters is true, delimiters are considered to be tokens, and + * successive calls to nextToken() return either a one character delimiter, or a + * maximal block of text between delimiters. + */ +public class StringTokenizer { + + private String string; + + private String delimiters; + + private boolean returnDelimiters; + + private int position; + + /** + * Constructs a new StringTokenizer for string using whitespace as the + * delimiter, returnDelimiters is false. + * + * @param string + * the string to be tokenized + */ + public StringTokenizer(String string) { + this(string, " \t\n\r\f", false); //$NON-NLS-1$ + } + + /** + * Constructs a new StringTokenizer for string using the specified + * delimiters, returnDelimiters is false. + * + * @param string + * the string to be tokenized + * @param delimiters + * the delimiters to use + */ + public StringTokenizer(String string, String delimiters) { + this(string, delimiters, false); + } + + /** + * Constructs a new StringTokenizer for string using the specified + * delimiters and returning delimiters as tokens when specified. + * + * @param string + * the string to be tokenized + * @param delimiters + * the delimiters to use + * @param returnDelimiters + * true to return each delimiter as a token + */ + public StringTokenizer(String string, String delimiters, + boolean returnDelimiters) { + if (string != null) { + this.string = string; + this.delimiters = delimiters; + this.returnDelimiters = returnDelimiters; + this.position = 0; + } else + throw new NullPointerException(); + } + + /** + * Returns the number of unprocessed tokens remaining in the string. + * + * @return number of tokens that can be retreived before an exception will + * result + */ + public int countTokens() { + int count = 0; + boolean inToken = false; + for (int i = position, length = string.length(); i < length; i++) { + if (delimiters.indexOf(string.charAt(i), 0) >= 0) { + if (returnDelimiters) + count++; + if (inToken) { + count++; + inToken = false; + } + } else { + inToken = true; + } + } + if (inToken) + count++; + return count; + } + + /** + * Returns true if unprocessed tokens remain. + * + * @return true if unprocessed tokens remain + */ + public boolean hasMoreElements() { + return hasMoreTokens(); + } + + /** + * Returns true if unprocessed tokens remain. + * + * @return true if unprocessed tokens remain + */ + public boolean hasMoreTokens() { + int length = string.length(); + if (position < length) { + if (returnDelimiters) + return true; // there is at least one character and even if + // it is a delimiter it is a token + + // otherwise find a character which is not a delimiter + for (int i = position; i < length; i++) + if (delimiters.indexOf(string.charAt(i), 0) == -1) + return true; + } + return false; + } + + /** + * Returns the next token in the string as an Object. + * + * @return next token in the string as an Object + * @exception NoSuchElementException + * if no tokens remain + */ + public Object nextElement() { + return nextToken(); + } + + /** + * Returns the next token in the string as a String. + * + * @return next token in the string as a String + * @exception NoSuchElementException + * if no tokens remain + */ + public String nextToken() { + int i = position; + int length = string.length(); + + if (i < length) { + if (returnDelimiters) { + if (delimiters.indexOf(string.charAt(position), 0) >= 0) + return String.valueOf(string.charAt(position++)); + for (position++; position < length; position++) + if (delimiters.indexOf(string.charAt(position), 0) >= 0) + return string.substring(i, position); + return string.substring(i); + } + + while (i < length && delimiters.indexOf(string.charAt(i), 0) >= 0) + i++; + position = i; + if (i < length) { + for (position++; position < length; position++) + if (delimiters.indexOf(string.charAt(position), 0) >= 0) + return string.substring(i, position); + return string.substring(i); + } + } + throw new NoSuchElementException(); + } + + /** + * Returns the next token in the string as a String. The delimiters used are + * changed to the specified delimiters. + * + * @param delims + * the new delimiters to use + * @return next token in the string as a String + * @exception NoSuchElementException + * if no tokens remain + */ + public String nextToken(String delims) { + this.delimiters = delims; + return nextToken(); + } +} \ No newline at end of file diff --git a/gwt/src/app/GWT.gwt.xml b/gwt/src/app/GWT.gwt.xml new file mode 100644 index 0000000..afb96ab --- /dev/null +++ b/gwt/src/app/GWT.gwt.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gwt/src/app/service/AsyncException.java b/gwt/src/app/service/AsyncException.java new file mode 100644 index 0000000..7ff4637 --- /dev/null +++ b/gwt/src/app/service/AsyncException.java @@ -0,0 +1,21 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package app.service; + +import org.timepedia.exporter.client.Export; +import org.timepedia.exporter.client.Exportable; + +@Export() +public class AsyncException extends Exception implements Exportable { + + public AsyncException() { + // TODO Auto-generated constructor stub + } + + public AsyncException(String message) { + super(message); + // TODO Auto-generated constructor stub + } +} diff --git a/gwt/src/app/service/JSApplet.java b/gwt/src/app/service/JSApplet.java new file mode 100644 index 0000000..4e2d300 --- /dev/null +++ b/gwt/src/app/service/JSApplet.java @@ -0,0 +1,19 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package app.service; + +import com.google.gwt.core.client.JavaScriptObject; + +public class JSApplet { + +// public void paint( Graphics g ) { +// g.drawString(VERSION_STRING,4,15); +// } + + static public native JavaScriptObject getWindow(Object o) /*-{ + return $wnd; + }-*/; + +} diff --git a/gwt/src/app/service/JSClient.java b/gwt/src/app/service/JSClient.java new file mode 120000 index 0000000..9a385e8 --- /dev/null +++ b/gwt/src/app/service/JSClient.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/JSClient.java \ No newline at end of file diff --git a/gwt/src/app/service/JSDelete.java b/gwt/src/app/service/JSDelete.java new file mode 100644 index 0000000..7b8999f --- /dev/null +++ b/gwt/src/app/service/JSDelete.java @@ -0,0 +1,103 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package app.service; + +import org.timepedia.exporter.client.Export; +import org.timepedia.exporter.client.Exportable; + +import mail.auth.MailServerAuthenticatorNoThread; +import mail.client.EventPropagator; +import core.callback.CallbackChain; +import core.callback.CallbackDefault; +import core.callback.CallbackWithVariables; +import core.constants.ConstantsClient; +import core.crypt.KeyPairFromPassword; +import core.srp.client.SRPClientListener; +import core.util.LogNull; + +@Export +public class JSDelete implements Exportable, SRPClientListener +{ + static LogNull log = new LogNull(JSDelete.class); + + Main main; + + JSDelete (Main main) + { + this.main = main; + } + + static class DeleteInfo + { + String name, password; + KeyPairFromPassword keyPair; + JSResult callback; + + public DeleteInfo(String name, String password, JSResult callback) + { + this.name = name; + this.password = password; + this.callback = callback; + } + } + + public void doDelete ( + String name, String password, + Object callback + ) + { + log.debug("delete", name, password); + + CallbackChain chain = new CallbackChain(); + + DeleteInfo info = new DeleteInfo(name, password, new JSResult(callback)); + + chain.addCallback(new CallbackDefault(info) { + public void onSuccess(Object... arguments) throws Exception { + log.debug("delete_step_genKeyPair"); + + DeleteInfo info = (DeleteInfo)V(0); + JSInvoker.invoke(info.callback.getCallback(), "progress", new Object[] { "Creating verification key pair." }); + info.keyPair = new KeyPairFromPassword(info.password); + info.keyPair.generate_().addCallback(callback).invoke(); + } + }); + + chain.addCallback(new CallbackDefault(info) { + public void onSuccess(Object... arguments) throws Exception { + log.debug("delete_step_doDelete"); + + DeleteInfo info = (DeleteInfo)V(0); + JSInvoker.invoke(info.callback.getCallback(), "progress", new Object[] { "Deleting account." }); + + call( + MailServerAuthenticatorNoThread.delete_( + info.name, info.keyPair, + new JSStreamSessionWebSocket(ConstantsClient.MAIL_SERVER_WEBSOCKET, main.delegate), + JSDelete.this + ) + ); + } + }); + + chain.addCallback(new CallbackWithVariables(info) { + @Override + public void invoke(Object... arguments) { + DeleteInfo info = (DeleteInfo)V(0); + info.callback.invoke(arguments); + } + }); + + main.eventPropagator.signal( + EventPropagator.INVOKE, + chain + ); + } + + public void onSRPStep (String event) + { + main.eventPropagator.signal("onAuthenticationStep", event); + } +} diff --git a/gwt/src/app/service/JSEventPropagator.java b/gwt/src/app/service/JSEventPropagator.java new file mode 120000 index 0000000..17cb802 --- /dev/null +++ b/gwt/src/app/service/JSEventPropagator.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/JSEventPropagator.java \ No newline at end of file diff --git a/gwt/src/app/service/JSHttpDelegate.java b/gwt/src/app/service/JSHttpDelegate.java new file mode 120000 index 0000000..8512875 --- /dev/null +++ b/gwt/src/app/service/JSHttpDelegate.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/JSHttpDelegate.java \ No newline at end of file diff --git a/gwt/src/app/service/JSInvoker.java b/gwt/src/app/service/JSInvoker.java new file mode 100644 index 0000000..5707ce2 --- /dev/null +++ b/gwt/src/app/service/JSInvoker.java @@ -0,0 +1,377 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package app.service; + +import java.util.Collection; + +import mail.client.model.Mail; + +import org.timepedia.exporter.client.Export; +import org.timepedia.exporter.client.Exportable; +import org.timepedia.exporter.client.ExporterUtil; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.JsArray; + +import core.util.LogNull; +import core.util.LogOut; + +@Export +public class JSInvoker implements Exportable +{ + static LogNull log = new LogNull(JSInvoker.class); + + private static native JavaScriptObject _wrap(boolean o) /*-{ + return o; + }-*/; + + private static native JavaScriptObject _wrap(int o) /*-{ + return o; + }-*/; + + private static native JavaScriptObject _wrap(String o) /*-{ + return o; + }-*/; + + private static JsArray _wrap(Object[] o) + { + JsArray a = JavaScriptObject.createArray().cast(); + for (Object i : o) + a.push(wrap(i)); + + return a; + } + + static public JavaScriptObject wrap(Object o) + { + if (o instanceof Boolean) + return _wrap((boolean)(Boolean)o); + else + if (o instanceof Integer) + return _wrap((int)(Integer)o); + else + if (o instanceof String) + return _wrap((String)o); + else + if (o instanceof Object[]) + return _wrap((Object[])o); + else + if (o instanceof Collection) + return _wrap(((Collection)o).toArray()); + else + if (o instanceof Mail) + return wrap(new MailI((Mail)o)); + + try + { + return ExporterUtil.wrap(o); + } + catch (Throwable e) + { + log.debug(e); + return (JavaScriptObject)o; + } + } + + static JavaScriptObject invoke (Object oo, String f, Object[] p) throws Exception + { + try + { + return doInvoke(oo, f, p); + } + catch (Exception e) + { + throw e; + } + catch (Throwable t) + { + throw new Exception(t.toString()); + } + } + + static JavaScriptObject doInvoke (Object oo, String f, Object[] p) throws Throwable + { + JavaScriptObject o = (JavaScriptObject)oo; + + if (p == null || p.length == 0) + return invoke0(o,f); + else + if (p.length == 1) + return invoke1(o,f, + wrap(p[0]) + ); + else + if (p.length == 2) + return invoke2(o,f, + wrap(p[0]), + wrap(p[1]) + ); + else + if (p.length == 3) + return invoke3(o,f, + wrap(p[0]), + wrap(p[1]), + wrap(p[2]) + ); + else + if (p.length == 4) + return invoke4(o,f, + wrap(p[0]), + wrap(p[1]), + wrap(p[2]), + wrap(p[3]) + ); + else + if (p.length == 5) + return invoke5(o,f, + wrap(p[0]), + wrap(p[1]), + wrap(p[2]), + wrap(p[3]), + wrap(p[4]) + ); + else + if (p.length == 6) + return invoke6(o,f, + wrap(p[0]), + wrap(p[1]), + wrap(p[2]), + wrap(p[3]), + wrap(p[4]), + wrap(p[5]) + ); + else + if (p.length == 7) + return invoke7(o,f, + wrap(p[0]), + wrap(p[1]), + wrap(p[2]), + wrap(p[3]), + wrap(p[4]), + wrap(p[5]), + wrap(p[6]) + ); + else + if (p.length == 8) + return invoke8(o,f, + wrap(p[0]), + wrap(p[1]), + wrap(p[2]), + wrap(p[3]), + wrap(p[4]), + wrap(p[5]), + wrap(p[6]), + wrap(p[7]) + ); + else + if (p.length == 9) + return invoke9(o,f, + wrap(p[0]), + wrap(p[1]), + wrap(p[2]), + wrap(p[3]), + wrap(p[4]), + wrap(p[5]), + wrap(p[6]), + wrap(p[7]), + wrap(p[8]) + ); + else + if (p.length == 10) + return invoke10(o,f, + wrap(p[0]), + wrap(p[1]), + wrap(p[2]), + wrap(p[3]), + wrap(p[4]), + wrap(p[5]), + wrap(p[6]), + wrap(p[7]), + wrap(p[8]), + wrap(p[9]) + ); + + return null; + } + + static native JavaScriptObject invoke0 (JavaScriptObject o, String f) /*-{ + return o[f].call(o); + }-*/; + + static native JavaScriptObject invoke1 (JavaScriptObject o, String f, + JavaScriptObject p0 + ) /*-{ + return o[f].call(o, + p0 + ); + }-*/; + + static native JavaScriptObject invoke2 (JavaScriptObject o, String f, + JavaScriptObject p0, + JavaScriptObject p1 + ) /*-{ + return o[f].call(o, + p0, + p1 + ); + }-*/; + + static native JavaScriptObject invoke3 (JavaScriptObject o, String f, + JavaScriptObject p0, + JavaScriptObject p1, + JavaScriptObject p2 + ) /*-{ + return o[f].call(o, + p0, + p1, + p2 + ); + }-*/; + + static native JavaScriptObject invoke4 (JavaScriptObject o, String f, + JavaScriptObject p0, + JavaScriptObject p1, + JavaScriptObject p2, + JavaScriptObject p3 + ) /*-{ + return o[f].call(o, + p0, + p1, + p2, + p3 + ); + }-*/; + + static native JavaScriptObject invoke5 (JavaScriptObject o, String f, + JavaScriptObject p0, + JavaScriptObject p1, + JavaScriptObject p2, + JavaScriptObject p3, + JavaScriptObject p4 + ) /*-{ + return o[f].call(o, + p0, + p1, + p2, + p3, + p4 + ); + }-*/; + + static native JavaScriptObject invoke6 (JavaScriptObject o, String f, + JavaScriptObject p0, + JavaScriptObject p1, + JavaScriptObject p2, + JavaScriptObject p3, + JavaScriptObject p4, + JavaScriptObject p5 + ) /*-{ + return o[f].call(o, + p0, + p1, + p2, + p3, + p4, + p5 + ); + }-*/; + + static native JavaScriptObject invoke7 (JavaScriptObject o, String f, + JavaScriptObject p0, + JavaScriptObject p1, + JavaScriptObject p2, + JavaScriptObject p3, + JavaScriptObject p4, + JavaScriptObject p5, + JavaScriptObject p6 + ) /*-{ + return o[f].call(o, + p0, + p1, + p2, + p3, + p4, + p5, + p6 + ); + }-*/; + + static native JavaScriptObject invoke8 (JavaScriptObject o, String f, + JavaScriptObject p0, + JavaScriptObject p1, + JavaScriptObject p2, + JavaScriptObject p3, + JavaScriptObject p4, + JavaScriptObject p5, + JavaScriptObject p6, + JavaScriptObject p7 + ) /*-{ + return o[f].call(o, + p0, + p1, + p2, + p3, + p4, + p5, + p6, + p7 + ); + }-*/; + + static native JavaScriptObject invoke9 (JavaScriptObject o, String f, + JavaScriptObject p0, + JavaScriptObject p1, + JavaScriptObject p2, + JavaScriptObject p3, + JavaScriptObject p4, + JavaScriptObject p5, + JavaScriptObject p6, + JavaScriptObject p7, + JavaScriptObject p8 + ) /*-{ + return o[f].call(o, + p0, + p1, + p2, + p3, + p4, + p5, + p6, + p7, + p8 + ); + }-*/; + + static native JavaScriptObject invoke10 (JavaScriptObject o, String f, + JavaScriptObject p0, + JavaScriptObject p1, + JavaScriptObject p2, + JavaScriptObject p3, + JavaScriptObject p4, + JavaScriptObject p5, + JavaScriptObject p6, + JavaScriptObject p7, + JavaScriptObject p8, + JavaScriptObject p9 + ) /*-{ + return o[f].call(o, + p0, + p1, + p2, + p3, + p4, + p5, + p6, + p7, + p8, + p9 + ); + }-*/; + + public native static JavaScriptObject getMember(Object o, String s) /*-{ + return o[s]; + }-*/; +} diff --git a/gwt/src/app/service/JSInvokerNo.java b/gwt/src/app/service/JSInvokerNo.java new file mode 100644 index 0000000..30486a6 --- /dev/null +++ b/gwt/src/app/service/JSInvokerNo.java @@ -0,0 +1,323 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package app.service; + +import com.google.gwt.core.client.JavaScriptObject; + +import core.util.Characters; +import core.util.LogNull; +import core.util.LogOut; + +public class JSInvokerNo +{ + static LogNull log = new LogNull(JSInvokerNo.class); + + static String className(Class c) + { + String name = c.getName(); + + int d = name.lastIndexOf('$'); + + if (d != -1) + { + if (d+1 < name.length()) + { + if (Characters.isNumber(name.charAt(d+1))) + return className(c.getSuperclass()); + } + } + + return name; + } + + static String classOf(Object p) + { + if (p == null) + return null; + + return className(p.getClass()); + } + + static JavaScriptObject invoke (Object oo, String f, Object[] p) + { + JavaScriptObject o = (JavaScriptObject)oo; + + if (p == null || p.length == 0) + return invoke0(o,f); + else + if (p.length == 1) + return invoke1(o,f,classOf(p[0]), p[0]); + else + if (p.length == 2) + return invoke2(o,f, + classOf(p[0]), p[0], + classOf(p[1]), p[1] + ); + else + if (p.length == 3) + return invoke3(o,f, + classOf(p[0]), p[0], + classOf(p[1]), p[1], + classOf(p[2]), p[2] + ); + else + if (p.length == 4) + return invoke4(o,f, + classOf(p[0]), p[0], + classOf(p[1]), p[1], + classOf(p[2]), p[2], + classOf(p[3]), p[3] + ); + else + if (p.length == 5) + return invoke5(o,f, + classOf(p[0]), p[0], + classOf(p[1]), p[1], + classOf(p[2]), p[2], + classOf(p[3]), p[3], + classOf(p[4]), p[4] + ); + else + if (p.length == 6) + return invoke6(o,f, + classOf(p[0]), p[0], + classOf(p[1]), p[1], + classOf(p[2]), p[2], + classOf(p[3]), p[3], + classOf(p[4]), p[4], + classOf(p[5]), p[5] + ); + else + if (p.length == 7) + return invoke7(o,f, + classOf(p[0]), p[0], + classOf(p[1]), p[1], + classOf(p[2]), p[2], + classOf(p[3]), p[3], + classOf(p[4]), p[4], + classOf(p[5]), p[5], + classOf(p[6]), p[6] + ); + else + if (p.length == 8) + return invoke8(o,f, + classOf(p[0]), p[0], + classOf(p[1]), p[1], + classOf(p[2]), p[2], + classOf(p[3]), p[3], + classOf(p[4]), p[4], + classOf(p[5]), p[5], + classOf(p[6]), p[6], + classOf(p[7]), p[7] + ); + else + if (p.length == 9) + return invoke9(o,f, + classOf(p[0]), p[0], + classOf(p[1]), p[1], + classOf(p[2]), p[2], + classOf(p[3]), p[3], + classOf(p[4]), p[4], + classOf(p[5]), p[5], + classOf(p[6]), p[6], + classOf(p[7]), p[7], + classOf(p[8]), p[8] + ); + else + if (p.length == 10) + return invoke10(o,f, + classOf(p[0]), p[0], + classOf(p[1]), p[1], + classOf(p[2]), p[2], + classOf(p[3]), p[3], + classOf(p[4]), p[4], + classOf(p[5]), p[5], + classOf(p[6]), p[6], + classOf(p[7]), p[7], + classOf(p[8]), p[8], + classOf(p[9]), p[9] + ); + + return null; + } + + static native JavaScriptObject invoke0 (JavaScriptObject o, String f) /*-{ + return o[f].call(o); + }-*/; + + static native JavaScriptObject invoke1 (JavaScriptObject o, String f, + String c0, Object p0 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0) + ); + }-*/; + + static native JavaScriptObject invoke2 (JavaScriptObject o, String f, + String c0, Object p0, + String c1, Object p1 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0), + $wnd.bindExportable(p1, c1) + ); + }-*/; + + static native JavaScriptObject invoke3 (JavaScriptObject o, String f, + String c0, Object p0, + String c1, Object p1, + String c2, Object p2 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0), + $wnd.bindExportable(p1, c1), + $wnd.bindExportable(p2, c2) + ); + }-*/; + + static native JavaScriptObject invoke4 (JavaScriptObject o, String f, + String c0, Object p0, + String c1, Object p1, + String c2, Object p2, + String c3, Object p3 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0), + $wnd.bindExportable(p1, c1), + $wnd.bindExportable(p2, c2), + $wnd.bindExportable(p3, c3) + ); + }-*/; + + static native JavaScriptObject invoke5 (JavaScriptObject o, String f, + String c0, Object p0, + String c1, Object p1, + String c2, Object p2, + String c3, Object p3, + String c4, Object p4 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0), + $wnd.bindExportable(p1, c1), + $wnd.bindExportable(p2, c2), + $wnd.bindExportable(p3, c3), + $wnd.bindExportable(p4, c4) + ); + }-*/; + + static native JavaScriptObject invoke6 (JavaScriptObject o, String f, + String c0, Object p0, + String c1, Object p1, + String c2, Object p2, + String c3, Object p3, + String c4, Object p4, + String c5, Object p5 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0), + $wnd.bindExportable(p1, c1), + $wnd.bindExportable(p2, c2), + $wnd.bindExportable(p3, c3), + $wnd.bindExportable(p4, c4), + $wnd.bindExportable(p5, c5) + ); + }-*/; + + static native JavaScriptObject invoke7 (JavaScriptObject o, String f, + String c0, Object p0, + String c1, Object p1, + String c2, Object p2, + String c3, Object p3, + String c4, Object p4, + String c5, Object p5, + String c6, Object p6 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0), + $wnd.bindExportable(p1, c1), + $wnd.bindExportable(p2, c2), + $wnd.bindExportable(p3, c3), + $wnd.bindExportable(p4, c4), + $wnd.bindExportable(p5, c5), + $wnd.bindExportable(p6, c6) + ); + }-*/; + + static native JavaScriptObject invoke8 (JavaScriptObject o, String f, + String c0, Object p0, + String c1, Object p1, + String c2, Object p2, + String c3, Object p3, + String c4, Object p4, + String c5, Object p5, + String c6, Object p6, + String c7, Object p7 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0), + $wnd.bindExportable(p1, c1), + $wnd.bindExportable(p2, c2), + $wnd.bindExportable(p3, c3), + $wnd.bindExportable(p4, c4), + $wnd.bindExportable(p5, c5), + $wnd.bindExportable(p6, c6), + $wnd.bindExportable(p7, c7) + ); + }-*/; + + static native JavaScriptObject invoke9 (JavaScriptObject o, String f, + String c0, Object p0, + String c1, Object p1, + String c2, Object p2, + String c3, Object p3, + String c4, Object p4, + String c5, Object p5, + String c6, Object p6, + String c7, Object p7, + String c8, Object p8 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0), + $wnd.bindExportable(p1, c1), + $wnd.bindExportable(p2, c2), + $wnd.bindExportable(p3, c3), + $wnd.bindExportable(p4, c4), + $wnd.bindExportable(p5, c5), + $wnd.bindExportable(p6, c6), + $wnd.bindExportable(p7, c7), + $wnd.bindExportable(p8, c8) + ); + }-*/; + + static native JavaScriptObject invoke10 (JavaScriptObject o, String f, + String c0, Object p0, + String c1, Object p1, + String c2, Object p2, + String c3, Object p3, + String c4, Object p4, + String c5, Object p5, + String c6, Object p6, + String c7, Object p7, + String c8, Object p8, + String c9, Object p9 + ) /*-{ + return o[f].call(o, + $wnd.bindExportable(p0, c0), + $wnd.bindExportable(p1, c1), + $wnd.bindExportable(p2, c2), + $wnd.bindExportable(p3, c3), + $wnd.bindExportable(p4, c4), + $wnd.bindExportable(p5, c5), + $wnd.bindExportable(p6, c6), + $wnd.bindExportable(p7, c7), + $wnd.bindExportable(p8, c8), + $wnd.bindExportable(p9, c9) + ); + }-*/; + + public native static JavaScriptObject getMember(Object o, String s) /*-{ + return o[s]; + }-*/; +} diff --git a/gwt/src/app/service/JSRefill.java b/gwt/src/app/service/JSRefill.java new file mode 120000 index 0000000..2f69191 --- /dev/null +++ b/gwt/src/app/service/JSRefill.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/JSRefill.java \ No newline at end of file diff --git a/gwt/src/app/service/JSResult.java b/gwt/src/app/service/JSResult.java new file mode 120000 index 0000000..465ea03 --- /dev/null +++ b/gwt/src/app/service/JSResult.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/JSResult.java \ No newline at end of file diff --git a/gwt/src/app/service/JSSignUp.java b/gwt/src/app/service/JSSignUp.java new file mode 120000 index 0000000..b872b61 --- /dev/null +++ b/gwt/src/app/service/JSSignUp.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/JSSignUp.java \ No newline at end of file diff --git a/gwt/src/app/service/JSStreamSessionWebSocket.java b/gwt/src/app/service/JSStreamSessionWebSocket.java new file mode 120000 index 0000000..4074101 --- /dev/null +++ b/gwt/src/app/service/JSStreamSessionWebSocket.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/JSStreamSessionWebSocket.java \ No newline at end of file diff --git a/gwt/src/app/service/MailI.java b/gwt/src/app/service/MailI.java new file mode 120000 index 0000000..32154c4 --- /dev/null +++ b/gwt/src/app/service/MailI.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/MailI.java \ No newline at end of file diff --git a/gwt/src/app/service/Main.java b/gwt/src/app/service/Main.java new file mode 120000 index 0000000..34a30dd --- /dev/null +++ b/gwt/src/app/service/Main.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/Main.java \ No newline at end of file diff --git a/gwt/src/app/service/ServiceAppletRunnable.java b/gwt/src/app/service/ServiceAppletRunnable.java new file mode 120000 index 0000000..55c37cc --- /dev/null +++ b/gwt/src/app/service/ServiceAppletRunnable.java @@ -0,0 +1 @@ +../../../../java/app/service/src/app/service/ServiceAppletRunnable.java \ No newline at end of file diff --git a/gwt/src/com/jordanzimmerman/GWT.gwt.xml b/gwt/src/com/jordanzimmerman/GWT.gwt.xml new file mode 100644 index 0000000..afb96ab --- /dev/null +++ b/gwt/src/com/jordanzimmerman/GWT.gwt.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gwt/src/com/jordanzimmerman/Hash256i.java b/gwt/src/com/jordanzimmerman/Hash256i.java new file mode 100644 index 0000000..b774771 --- /dev/null +++ b/gwt/src/com/jordanzimmerman/Hash256i.java @@ -0,0 +1,17 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package com.jordanzimmerman; + +import core.crypt.HashSha256; + +public class Hash256i +{ + HashSha256 hash = new HashSha256(); + + public byte[] hash(byte[] bytes) + { + return hash.hash(bytes); + } +} diff --git a/gwt/src/com/jordanzimmerman/Logz.java b/gwt/src/com/jordanzimmerman/Logz.java new file mode 100644 index 0000000..ea29a56 --- /dev/null +++ b/gwt/src/com/jordanzimmerman/Logz.java @@ -0,0 +1,13 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package com.jordanzimmerman; + +public class Logz { + + public static void println(String string) { + System.out.println(string); + } + +} diff --git a/gwt/src/com/jordanzimmerman/SRPAuthenticationFailedException.java b/gwt/src/com/jordanzimmerman/SRPAuthenticationFailedException.java new file mode 120000 index 0000000..88f998d --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SRPAuthenticationFailedException.java @@ -0,0 +1 @@ +../../../../java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPAuthenticationFailedException.java \ No newline at end of file diff --git a/gwt/src/com/jordanzimmerman/SRPClientSession.java b/gwt/src/com/jordanzimmerman/SRPClientSession.java new file mode 120000 index 0000000..c057a1b --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SRPClientSession.java @@ -0,0 +1 @@ +../../../../java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPClientSession.java \ No newline at end of file diff --git a/gwt/src/com/jordanzimmerman/SRPClientSessionInterface.java b/gwt/src/com/jordanzimmerman/SRPClientSessionInterface.java new file mode 100644 index 0000000..89bdfc9 --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SRPClientSessionInterface.java @@ -0,0 +1,12 @@ +package com.jordanzimmerman; + +public interface SRPClientSessionInterface { + + public void setSalt_s(byte[] bs); + public void setServerPublicKey_B(byte[] publicKey) throws SRPAuthenticationFailedException; + public byte[] getSessionKey_K(); + public byte[] getPublicKey_A(); + public byte[] getEvidenceValue_M1(); + public void validateServerEvidenceValue_M2(byte[] evidence) throws SRPAuthenticationFailedException; + +} diff --git a/gwt/src/com/jordanzimmerman/SRPConstants.java b/gwt/src/com/jordanzimmerman/SRPConstants.java new file mode 120000 index 0000000..cafad1e --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SRPConstants.java @@ -0,0 +1 @@ +../../../../java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPConstants.java \ No newline at end of file diff --git a/gwt/src/com/jordanzimmerman/SRPFactory.java b/gwt/src/com/jordanzimmerman/SRPFactory.java new file mode 120000 index 0000000..9992502 --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SRPFactory.java @@ -0,0 +1 @@ +../../../../java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPFactory.java \ No newline at end of file diff --git a/gwt/src/com/jordanzimmerman/SRPRunner.java b/gwt/src/com/jordanzimmerman/SRPRunner.java new file mode 120000 index 0000000..317b68e --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SRPRunner.java @@ -0,0 +1 @@ +../../../../java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPRunner.java \ No newline at end of file diff --git a/gwt/src/com/jordanzimmerman/SRPServerSession.java b/gwt/src/com/jordanzimmerman/SRPServerSession.java new file mode 120000 index 0000000..46a8330 --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SRPServerSession.java @@ -0,0 +1 @@ +../../../../java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPServerSession.java \ No newline at end of file diff --git a/gwt/src/com/jordanzimmerman/SRPUtils.java b/gwt/src/com/jordanzimmerman/SRPUtils.java new file mode 120000 index 0000000..1a6a19a --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SRPUtils.java @@ -0,0 +1 @@ +../../../../java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPUtils.java \ No newline at end of file diff --git a/gwt/src/com/jordanzimmerman/SRPVerifier.java b/gwt/src/com/jordanzimmerman/SRPVerifier.java new file mode 120000 index 0000000..c02a0bb --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SRPVerifier.java @@ -0,0 +1 @@ +../../../../java/ext/jordanzimmerman/src/com/jordanzimmerman/SRPVerifier.java \ No newline at end of file diff --git a/gwt/src/com/jordanzimmerman/SecureRandomi.java b/gwt/src/com/jordanzimmerman/SecureRandomi.java new file mode 100644 index 0000000..9417dc9 --- /dev/null +++ b/gwt/src/com/jordanzimmerman/SecureRandomi.java @@ -0,0 +1,9 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package com.jordanzimmerman; + +public class SecureRandomi extends java.security.SecureRandom { + +} diff --git a/gwt/src/com/mailiverse/gwt/Mailiverse_GWT.gwt.xml b/gwt/src/com/mailiverse/gwt/Mailiverse_GWT.gwt.xml new file mode 100644 index 0000000..722b2e4 --- /dev/null +++ b/gwt/src/com/mailiverse/gwt/Mailiverse_GWT.gwt.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gwt/src/com/mailiverse/gwt/client/Mailiverse_GWT.java b/gwt/src/com/mailiverse/gwt/client/Mailiverse_GWT.java new file mode 100644 index 0000000..39fb70a --- /dev/null +++ b/gwt/src/com/mailiverse/gwt/client/Mailiverse_GWT.java @@ -0,0 +1,48 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package com.mailiverse.gwt.client; + +import org.timepedia.exporter.client.ExporterUtil; + +import mail.client.model.Original; + +import app.service.Main; + +import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyUpEvent; +import com.google.gwt.event.dom.client.KeyUpHandler; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.DialogBox; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.TextBox; +import com.google.gwt.user.client.ui.VerticalPanel; + +/** + * Entry point classes define onModuleLoad(). + */ +public class Mailiverse_GWT implements EntryPoint { + + /** + * This is the entry point method. + */ + public native void propagateLoad (JavaScriptObject main) /*-{ + $wnd.onMailiverseBootstrapGWT(main); + }-*/; + + + public void onModuleLoad() + { + ExporterUtil.exportAll(); + propagateLoad(ExporterUtil.wrap(new Main())); + } +} diff --git a/gwt/src/core/GWT.gwt.xml b/gwt/src/core/GWT.gwt.xml new file mode 100644 index 0000000..afb96ab --- /dev/null +++ b/gwt/src/core/GWT.gwt.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gwt/src/core/callback/Callback.java b/gwt/src/core/callback/Callback.java new file mode 120000 index 0000000..005bedb --- /dev/null +++ b/gwt/src/core/callback/Callback.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callback/Callback.java \ No newline at end of file diff --git a/gwt/src/core/callback/CallbackChain.java b/gwt/src/core/callback/CallbackChain.java new file mode 120000 index 0000000..7c9f55e --- /dev/null +++ b/gwt/src/core/callback/CallbackChain.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callback/CallbackChain.java \ No newline at end of file diff --git a/gwt/src/core/callback/CallbackDefault.java b/gwt/src/core/callback/CallbackDefault.java new file mode 120000 index 0000000..ca674ef --- /dev/null +++ b/gwt/src/core/callback/CallbackDefault.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callback/CallbackDefault.java \ No newline at end of file diff --git a/gwt/src/core/callback/CallbackEmpty.java b/gwt/src/core/callback/CallbackEmpty.java new file mode 120000 index 0000000..19648a4 --- /dev/null +++ b/gwt/src/core/callback/CallbackEmpty.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callback/CallbackEmpty.java \ No newline at end of file diff --git a/gwt/src/core/callback/CallbackInterface.java b/gwt/src/core/callback/CallbackInterface.java new file mode 120000 index 0000000..c55941d --- /dev/null +++ b/gwt/src/core/callback/CallbackInterface.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callback/CallbackInterface.java \ No newline at end of file diff --git a/gwt/src/core/callback/CallbackSync.java b/gwt/src/core/callback/CallbackSync.java new file mode 120000 index 0000000..1110b96 --- /dev/null +++ b/gwt/src/core/callback/CallbackSync.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callback/CallbackSync.java \ No newline at end of file diff --git a/gwt/src/core/callback/CallbackWithVariables.java b/gwt/src/core/callback/CallbackWithVariables.java new file mode 120000 index 0000000..44733cc --- /dev/null +++ b/gwt/src/core/callback/CallbackWithVariables.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callback/CallbackWithVariables.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/CountDown.java b/gwt/src/core/callbacks/CountDown.java new file mode 120000 index 0000000..8380471 --- /dev/null +++ b/gwt/src/core/callbacks/CountDown.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/CountDown.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/IoOnReceive.java b/gwt/src/core/callbacks/IoOnReceive.java new file mode 120000 index 0000000..0df6ebe --- /dev/null +++ b/gwt/src/core/callbacks/IoOnReceive.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/IoOnReceive.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/IoOpen.java b/gwt/src/core/callbacks/IoOpen.java new file mode 120000 index 0000000..5d4e53c --- /dev/null +++ b/gwt/src/core/callbacks/IoOpen.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/IoOpen.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/IoSend.java b/gwt/src/core/callbacks/IoSend.java new file mode 120000 index 0000000..150f90b --- /dev/null +++ b/gwt/src/core/callbacks/IoSend.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/IoSend.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/IoStop.java b/gwt/src/core/callbacks/IoStop.java new file mode 120000 index 0000000..4232ab8 --- /dev/null +++ b/gwt/src/core/callbacks/IoStop.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/IoStop.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/JSONDeserialize.java b/gwt/src/core/callbacks/JSONDeserialize.java new file mode 120000 index 0000000..7b0f47d --- /dev/null +++ b/gwt/src/core/callbacks/JSONDeserialize.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/JSONDeserialize.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/JSONSerialize.java b/gwt/src/core/callbacks/JSONSerialize.java new file mode 120000 index 0000000..03adb31 --- /dev/null +++ b/gwt/src/core/callbacks/JSONSerialize.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/JSONSerialize.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/Memory.java b/gwt/src/core/callbacks/Memory.java new file mode 120000 index 0000000..4daa732 --- /dev/null +++ b/gwt/src/core/callbacks/Memory.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/Memory.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/SaveArguments.java b/gwt/src/core/callbacks/SaveArguments.java new file mode 120000 index 0000000..5f04809 --- /dev/null +++ b/gwt/src/core/callbacks/SaveArguments.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/SaveArguments.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/Single.java b/gwt/src/core/callbacks/Single.java new file mode 120000 index 0000000..f1bb396 --- /dev/null +++ b/gwt/src/core/callbacks/Single.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/Single.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/Split.java b/gwt/src/core/callbacks/Split.java new file mode 120000 index 0000000..e2adb0f --- /dev/null +++ b/gwt/src/core/callbacks/Split.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/Split.java \ No newline at end of file diff --git a/gwt/src/core/callbacks/SuccessFailure.java b/gwt/src/core/callbacks/SuccessFailure.java new file mode 120000 index 0000000..f7c91a3 --- /dev/null +++ b/gwt/src/core/callbacks/SuccessFailure.java @@ -0,0 +1 @@ +../../../../java/core/src/core/callbacks/SuccessFailure.java \ No newline at end of file diff --git a/gwt/src/core/client/ClientCreateSession.java b/gwt/src/core/client/ClientCreateSession.java new file mode 120000 index 0000000..06a126b --- /dev/null +++ b/gwt/src/core/client/ClientCreateSession.java @@ -0,0 +1 @@ +../../../../java/core/src/core/client/ClientCreateSession.java \ No newline at end of file diff --git a/gwt/src/core/client/ClientTestCreateSession.java b/gwt/src/core/client/ClientTestCreateSession.java new file mode 120000 index 0000000..54c43aa --- /dev/null +++ b/gwt/src/core/client/ClientTestCreateSession.java @@ -0,0 +1 @@ +../../../../java/core/src/core/client/ClientTestCreateSession.java \ No newline at end of file diff --git a/gwt/src/core/client/ClientUserSession.java b/gwt/src/core/client/ClientUserSession.java new file mode 120000 index 0000000..1682a16 --- /dev/null +++ b/gwt/src/core/client/ClientUserSession.java @@ -0,0 +1 @@ +../../../../java/core/src/core/client/ClientUserSession.java \ No newline at end of file diff --git a/gwt/src/core/client/messages/ClientMessagesSerializerJSON.java b/gwt/src/core/client/messages/ClientMessagesSerializerJSON.java new file mode 120000 index 0000000..98ab63b --- /dev/null +++ b/gwt/src/core/client/messages/ClientMessagesSerializerJSON.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/client/messages/ClientMessagesSerializerJSON.java \ No newline at end of file diff --git a/gwt/src/core/client/messages/Delete.java b/gwt/src/core/client/messages/Delete.java new file mode 120000 index 0000000..951c593 --- /dev/null +++ b/gwt/src/core/client/messages/Delete.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/client/messages/Delete.java \ No newline at end of file diff --git a/gwt/src/core/client/messages/Get.java b/gwt/src/core/client/messages/Get.java new file mode 120000 index 0000000..cac97f7 --- /dev/null +++ b/gwt/src/core/client/messages/Get.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/client/messages/Get.java \ No newline at end of file diff --git a/gwt/src/core/client/messages/Message.java b/gwt/src/core/client/messages/Message.java new file mode 120000 index 0000000..10363c0 --- /dev/null +++ b/gwt/src/core/client/messages/Message.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/client/messages/Message.java \ No newline at end of file diff --git a/gwt/src/core/client/messages/Put.java b/gwt/src/core/client/messages/Put.java new file mode 120000 index 0000000..746a17e --- /dev/null +++ b/gwt/src/core/client/messages/Put.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/client/messages/Put.java \ No newline at end of file diff --git a/gwt/src/core/client/messages/Response.java b/gwt/src/core/client/messages/Response.java new file mode 120000 index 0000000..e4d8bff --- /dev/null +++ b/gwt/src/core/client/messages/Response.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/client/messages/Response.java \ No newline at end of file diff --git a/gwt/src/core/connector/ConnectorException.java b/gwt/src/core/connector/ConnectorException.java new file mode 120000 index 0000000..7427326 --- /dev/null +++ b/gwt/src/core/connector/ConnectorException.java @@ -0,0 +1 @@ +../../../../java/core/src/core/connector/ConnectorException.java \ No newline at end of file diff --git a/gwt/src/core/connector/FileInfo.java b/gwt/src/core/connector/FileInfo.java new file mode 120000 index 0000000..2d1aabe --- /dev/null +++ b/gwt/src/core/connector/FileInfo.java @@ -0,0 +1 @@ +../../../../java/core/src/core/connector/FileInfo.java \ No newline at end of file diff --git a/gwt/src/core/connector/async b/gwt/src/core/connector/async new file mode 120000 index 0000000..96c49c4 --- /dev/null +++ b/gwt/src/core/connector/async @@ -0,0 +1 @@ +../../../../java/core/src/core/connector/async \ No newline at end of file diff --git a/gwt/src/core/connector/dropbox/ClientInfoDropbox.java b/gwt/src/core/connector/dropbox/ClientInfoDropbox.java new file mode 120000 index 0000000..edcbddd --- /dev/null +++ b/gwt/src/core/connector/dropbox/ClientInfoDropbox.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/connector/dropbox/ClientInfoDropbox.java \ No newline at end of file diff --git a/gwt/src/core/connector/dropbox/async b/gwt/src/core/connector/dropbox/async new file mode 120000 index 0000000..b6f8492 --- /dev/null +++ b/gwt/src/core/connector/dropbox/async @@ -0,0 +1 @@ +../../../../../java/core/src/core/connector/dropbox/async \ No newline at end of file diff --git a/gwt/src/core/connector/s3/ClientInfoS3.java b/gwt/src/core/connector/s3/ClientInfoS3.java new file mode 120000 index 0000000..b522e8e --- /dev/null +++ b/gwt/src/core/connector/s3/ClientInfoS3.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/connector/s3/ClientInfoS3.java \ No newline at end of file diff --git a/gwt/src/core/connector/s3/async b/gwt/src/core/connector/s3/async new file mode 120000 index 0000000..3c63f49 --- /dev/null +++ b/gwt/src/core/connector/s3/async @@ -0,0 +1 @@ +../../../../../java/core/src/core/connector/s3/async \ No newline at end of file diff --git a/gwt/src/core/connector/sync b/gwt/src/core/connector/sync new file mode 120000 index 0000000..121ba62 --- /dev/null +++ b/gwt/src/core/connector/sync @@ -0,0 +1 @@ +../../../../java/core/src/core/connector/sync \ No newline at end of file diff --git a/gwt/src/core/constants/ConstantsClient.java b/gwt/src/core/constants/ConstantsClient.java new file mode 120000 index 0000000..fc6386d --- /dev/null +++ b/gwt/src/core/constants/ConstantsClient.java @@ -0,0 +1 @@ +../../../../java/core/src/core/constants/ConstantsClient.java \ No newline at end of file diff --git a/gwt/src/core/constants/ConstantsClientPlatform.java b/gwt/src/core/constants/ConstantsClientPlatform.java new file mode 100644 index 0000000..f826da8 --- /dev/null +++ b/gwt/src/core/constants/ConstantsClientPlatform.java @@ -0,0 +1,33 @@ +package core.constants; + +import core.util.JSON_; + +public class ConstantsClientPlatform +{ + public static final String HOST, AUTH_HOST, TOMCAT_HOST, WEB_HOST; + + public static native String jsResolve () /*-{ + return JSON.stringify($wnd.Constants); + }-*/; + + static + { + String host = null, authHost = null, tomcatHost = null, webServer = null; + try + { + Object json = JSON_.parse(jsResolve()); + host = JSON_.getString(json, "HOST"); + authHost = JSON_.getString(json, "AUTH_HOST"); + tomcatHost = JSON_.getString(json, "TOMCAT_HOST"); + webServer = JSON_.getString(json, "WEB_HOST"); + } + catch (Exception e) + { + } + + HOST = host; + AUTH_HOST = authHost; + TOMCAT_HOST = tomcatHost; + WEB_HOST = webServer; + } +} diff --git a/gwt/src/core/constants/ConstantsDropbox.java b/gwt/src/core/constants/ConstantsDropbox.java new file mode 120000 index 0000000..f17cc66 --- /dev/null +++ b/gwt/src/core/constants/ConstantsDropbox.java @@ -0,0 +1 @@ +../../../../java/core/src/core/constants/ConstantsDropbox.java \ No newline at end of file diff --git a/gwt/src/core/constants/ConstantsEnvironmentKeys.java b/gwt/src/core/constants/ConstantsEnvironmentKeys.java new file mode 120000 index 0000000..6c2658b --- /dev/null +++ b/gwt/src/core/constants/ConstantsEnvironmentKeys.java @@ -0,0 +1 @@ +../../../../java/core/src/core/constants/ConstantsEnvironmentKeys.java \ No newline at end of file diff --git a/gwt/src/core/constants/ConstantsMailJson.java b/gwt/src/core/constants/ConstantsMailJson.java new file mode 120000 index 0000000..7ac73b1 --- /dev/null +++ b/gwt/src/core/constants/ConstantsMailJson.java @@ -0,0 +1 @@ +../../../../java/core/src/core/constants/ConstantsMailJson.java \ No newline at end of file diff --git a/gwt/src/core/constants/ConstantsS3.java b/gwt/src/core/constants/ConstantsS3.java new file mode 120000 index 0000000..ecaee43 --- /dev/null +++ b/gwt/src/core/constants/ConstantsS3.java @@ -0,0 +1 @@ +../../../../java/core/src/core/constants/ConstantsS3.java \ No newline at end of file diff --git a/gwt/src/core/constants/ConstantsSettings.java b/gwt/src/core/constants/ConstantsSettings.java new file mode 120000 index 0000000..e373de5 --- /dev/null +++ b/gwt/src/core/constants/ConstantsSettings.java @@ -0,0 +1 @@ +../../../../java/core/src/core/constants/ConstantsSettings.java \ No newline at end of file diff --git a/gwt/src/core/constants/ConstantsStorage.java b/gwt/src/core/constants/ConstantsStorage.java new file mode 120000 index 0000000..efde6b8 --- /dev/null +++ b/gwt/src/core/constants/ConstantsStorage.java @@ -0,0 +1 @@ +../../../../java/core/src/core/constants/ConstantsStorage.java \ No newline at end of file diff --git a/gwt/src/core/constants/ConstantsVersion.java b/gwt/src/core/constants/ConstantsVersion.java new file mode 120000 index 0000000..4bcd88a --- /dev/null +++ b/gwt/src/core/constants/ConstantsVersion.java @@ -0,0 +1 @@ +../../../../java/core/src/core/constants/ConstantsVersion.java \ No newline at end of file diff --git a/gwt/src/core/crypt/Cryptor.java b/gwt/src/core/crypt/Cryptor.java new file mode 120000 index 0000000..a09a36b --- /dev/null +++ b/gwt/src/core/crypt/Cryptor.java @@ -0,0 +1 @@ +../../../../java/core/src/core/crypt/Cryptor.java \ No newline at end of file diff --git a/gwt/src/core/crypt/CryptorAES.java b/gwt/src/core/crypt/CryptorAES.java new file mode 120000 index 0000000..ee84e06 --- /dev/null +++ b/gwt/src/core/crypt/CryptorAES.java @@ -0,0 +1 @@ +../../../../java/core/src/core/crypt/CryptorAES.java \ No newline at end of file diff --git a/gwt/src/core/crypt/CryptorAESIV.java b/gwt/src/core/crypt/CryptorAESIV.java new file mode 100644 index 0000000..c63bdd0 --- /dev/null +++ b/gwt/src/core/crypt/CryptorAESIV.java @@ -0,0 +1,89 @@ +package core.crypt; + +import com.google.gwt.core.client.JavaScriptObject; + +import app.service.JSInvoker; +import core.util.Base64; +import core.util.LogNull; +import core.util.LogOut; +import core.util.SecureRandom; +import core.callback.Callback; +import core.callback.CallbackDefault; +import core.exceptions.CryptoException; + +public class CryptorAESIV extends CryptorJS +{ + static LogNull log = new LogNull(CryptorAESIV.class); + + public static final int AES_KEYSIZE_BYTES = 32; + public static final int AES_IVSIZE_BYTES = 16; + static SecureRandom random = new SecureRandom(); + + String key, iv; + + public CryptorAESIV (byte[] key, byte[] iv) + { + this.key = Base64.encode(key); + this.iv = Base64.encode(iv); + } + + public Callback jsDecrypt_() + { + return new CallbackDefault() { + public void onSuccess(Object... arguments) throws Exception { + log.debug("jsDecrypt_", key, iv); + + jsDecrypt ( + key, + iv, + (String)arguments[0], + JSInvoker.wrap(callback) + ); + } + }; + } + + public Callback jsEncrypt_() + { + return new CallbackDefault() { + public void onSuccess(Object... arguments) throws Exception { + log.debug("jsEncrypt_", key, iv); + + jsEncrypt ( + key, + iv, + (String)arguments[0], + JSInvoker.wrap(callback) + ); + } + }; + } + + public byte[] encrypt(byte[] bytes) throws CryptoException + { + return Base64.decode(jsEncrypt(key, iv, Base64.encode(bytes))); + } + + public byte[] decrypt(byte[] bytes) throws CryptoException + { + return Base64.decode(jsDecrypt(key, iv, Base64.encode(bytes))); + } + + //----------------------------------------------------------------------- + + public native String jsEncrypt(String key64, String iv64, String bytes64) /*-{ + return $wnd.mSupport.aes_encrypt(key64, iv64, bytes64); + }-*/; + + public native String jsDecrypt(String key64, String iv64, String bytes64) /*-{ + return $wnd.mSupport.aes_decrypt(key64, iv64, bytes64); + }-*/; + + public native void jsEncrypt(String key64, String iv64, String bytes64, JavaScriptObject callback) /*-{ + $wnd.mAsync.aes_encrypt(callback, key64, iv64, bytes64); + }-*/; + + public native void jsDecrypt(String key64, String iv64, String bytes64, JavaScriptObject callback) /*-{ + $wnd.mAsync.aes_decrypt(callback, key64, iv64, bytes64); + }-*/; +} diff --git a/gwt/src/core/crypt/CryptorJS.java b/gwt/src/core/crypt/CryptorJS.java new file mode 100644 index 0000000..40a7a7a --- /dev/null +++ b/gwt/src/core/crypt/CryptorJS.java @@ -0,0 +1,40 @@ +package core.crypt; + +import core.callback.Callback; +import core.callback.CallbackChain; +import core.exceptions.CryptoException; +import core.util.Base64; + +public abstract class CryptorJS extends Cryptor +{ + public abstract Callback jsEncrypt_(); + public abstract Callback jsDecrypt_(); + + public Callback encrypt_() + { + CallbackChain chain = new CallbackChain(); + return chain + .addCallback(Base64.encode_()) + .addCallback(jsEncrypt_()) + .addCallback(Base64.decode_()); + } + + public Callback decrypt_() + { + CallbackChain chain = new CallbackChain(); + return chain + .addCallback(Base64.encode_()) + .addCallback(jsDecrypt_()) + .addCallback(Base64.decode_()); + } + + public byte[] encrypt(byte[] bytes) throws CryptoException + { + throw new RuntimeException("Use callbacks in JS mode"); + } + + public byte[] decrypt(byte[] bytes) throws CryptoException + { + throw new RuntimeException("Use callbacks in JS mode"); + } +} diff --git a/gwt/src/core/crypt/CryptorNone.java b/gwt/src/core/crypt/CryptorNone.java new file mode 100644 index 0000000..1377f8b --- /dev/null +++ b/gwt/src/core/crypt/CryptorNone.java @@ -0,0 +1,17 @@ +package core.crypt; + +import core.exceptions.CryptoException; + +public class CryptorNone extends Cryptor { + + @Override + public byte[] encrypt(byte[] bytes) throws CryptoException { + return bytes; + } + + @Override + public byte[] decrypt(byte[] bytes) throws CryptoException { + return bytes; + } + +} diff --git a/gwt/src/core/crypt/CryptorRSA.java b/gwt/src/core/crypt/CryptorRSA.java new file mode 100644 index 0000000..0143cc9 --- /dev/null +++ b/gwt/src/core/crypt/CryptorRSA.java @@ -0,0 +1,24 @@ +package core.crypt; + +import java.io.IOException; + +public abstract class CryptorRSA extends CryptorJS +{ + byte[] publicKeyBytes, privateKeyBytes; + + public byte[] getPublicKey () + { + return publicKeyBytes; + } + + public byte[] getPrivateKey () + { + return privateKeyBytes; + } + + protected void initialize (byte[] publicKeyBytes, byte[] privateKeyBytes) throws IOException + { + this.privateKeyBytes = privateKeyBytes; + this.publicKeyBytes = publicKeyBytes; + } +} diff --git a/gwt/src/core/crypt/CryptorRSAAES.java b/gwt/src/core/crypt/CryptorRSAAES.java new file mode 120000 index 0000000..61ce41d --- /dev/null +++ b/gwt/src/core/crypt/CryptorRSAAES.java @@ -0,0 +1 @@ +../../../../java/core/src/core/crypt/CryptorRSAAES.java \ No newline at end of file diff --git a/gwt/src/core/crypt/CryptorRSAFactory.java b/gwt/src/core/crypt/CryptorRSAFactory.java new file mode 100644 index 0000000..a4ca939 --- /dev/null +++ b/gwt/src/core/crypt/CryptorRSAFactory.java @@ -0,0 +1,57 @@ +package core.crypt; + +import java.io.IOException; +import java.io.InputStream; + +import app.service.JSInvoker; +import core.callback.Callback; +import core.callback.CallbackDefault; +import core.util.Base64; +import core.util.Pair; + +public class CryptorRSAFactory +{ + protected native String jsGenerate(int bits) /*-{ + var keyPair = $wnd.rsa_genKeyPair(bits); + var joined = keyPair.publicKey + "," + keyPair.privateKey; + return joined; + }-*/; + + protected native void jsGenerate(int bits, Object callback) /*-{ + $wnd.mAsync.rsa_genKeyPair( + { invoke: function(keyPair) { callback.invoke(keyPair.publicKey, keyPair.privateKey); } }, + bits + ); + }-*/; + + public Pair generate (int bits) + { + String joined = jsGenerate(bits); + String[] split = joined.split(","); + + return new Pair(Base64.decode(split[0]), Base64.decode(split[1])); + } + + public void generate (int bits, Callback callback) + { + Callback synth = new CallbackDefault() { + public void onSuccess(Object... arguments) throws Exception + { + String split[] = { (String)arguments[0], (String)arguments[1] }; + callback.invoke(new Pair(Base64.decode(split[0]), Base64.decode(split[1]))); + } + }.setReturn(callback); + + jsGenerate(bits, JSInvoker.wrap(synth)); + } + + public static CryptorRSA fromResources(InputStream publicKey, InputStream privateKey) throws IOException { + return new CryptorRSAJS(publicKey, privateKey); + } + + public static CryptorRSA fromString(String publicKey, Object object) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/gwt/src/core/crypt/CryptorRSAFactoryEnvironment.java b/gwt/src/core/crypt/CryptorRSAFactoryEnvironment.java new file mode 100644 index 0000000..1e9916d --- /dev/null +++ b/gwt/src/core/crypt/CryptorRSAFactoryEnvironment.java @@ -0,0 +1,39 @@ +package core.crypt; + +import core.constants.ConstantsEnvironmentKeys; +import core.exceptions.CryptoException; +import core.util.Base64; +import core.util.Environment; + +public class CryptorRSAFactoryEnvironment { + + public static CryptorRSA create(Environment environment) throws CryptoException + { + return createJS(environment); + } + + public static CryptorRSA createJS (Environment env) throws CryptoException + { + try + { + String publicKeyString = env.get(ConstantsEnvironmentKeys.PUBLIC_ENCRYPTION_KEY); + byte[] publicKeyBytes = null; + if (publicKeyString != null) + publicKeyBytes = Base64.decode(publicKeyString); + + String privateKeyString = env.get(ConstantsEnvironmentKeys.PRIVATE_DECRYPTION_KEY); + byte[] privateKeyBytes = null; + if (privateKeyString != null) + privateKeyBytes = Base64.decode(privateKeyString); + + return new CryptorRSAJS ( + publicKeyBytes, + privateKeyBytes + ); + } + catch (Exception e) + { + throw new CryptoException(e); + } + } +} diff --git a/gwt/src/core/crypt/CryptorRSAJS.java b/gwt/src/core/crypt/CryptorRSAJS.java new file mode 100644 index 0000000..013b027 --- /dev/null +++ b/gwt/src/core/crypt/CryptorRSAJS.java @@ -0,0 +1,86 @@ +package core.crypt; + +import java.io.IOException; +import java.io.InputStream; + +import app.service.JSInvoker; + +import com.google.gwt.core.client.JavaScriptObject; + +import core.util.Base64; +import core.util.LogNull; +import core.util.LogOut; +import core.callback.Callback; +import core.callback.CallbackDefault; +import core.util.Streams; + +public class CryptorRSAJS extends CryptorRSA +{ + static LogNull log = new LogNull(CryptorRSAJS.class); + + JavaScriptObject privateKey, publicKey; + + protected void initialize (byte[] publicKeyBytes, byte[] privateKeyBytes) throws IOException + { + super.initialize(publicKeyBytes, privateKeyBytes); + + if (privateKeyBytes != null) + privateKey = jsGetPrivKey(Base64.encode(privateKeyBytes)); + + if (publicKeyBytes != null) + publicKey = jsGetPubKey(Base64.encode(publicKeyBytes)); + } + + public CryptorRSAJS(InputStream pri, InputStream pub) throws IOException + { + initialize( + pub != null ? Streams.readFullyBytes(pub) : null, + pri != null ? Streams.readFullyBytes(pri) : null + ); + } + + public CryptorRSAJS(byte[] publicKeyBytes, byte[] privateKeyBytes) throws IOException + { + initialize(publicKeyBytes, privateKeyBytes); + } + + //------------------------------------------------------------ + + public Callback jsEncrypt_() + { + return new CallbackDefault() { + public void onSuccess(Object... arguments) throws Exception { + log.debug("jsEncrypt_",arguments[0]); + jsEncrypt(publicKey, (String)(arguments[0]), JSInvoker.wrap(callback)); + } + }; + } + + public Callback jsDecrypt_() + { + return new CallbackDefault() { + public void onSuccess(Object... arguments) throws Exception { + log.debug("jsDecrypt_", arguments[0]); + jsDecrypt(privateKey, (String)(arguments[0]), JSInvoker.wrap(callback)); + } + }; + } + + //------------------------------------------------------------ + + public native JavaScriptObject jsGetPrivKey (String pem64) /*-{ + return $wnd.mSupport.rsa_getPrivateKey(pem64); + }-*/; + + public native JavaScriptObject jsGetPubKey (String pem64) /*-{ + return $wnd.mSupport.rsa_getPublicKey(pem64); + }-*/; + + public native void jsEncrypt(JavaScriptObject key, String bytes64, JavaScriptObject callback) /*-{ + return $wnd.mAsync.rsa_encrypt(callback, key, bytes64); + }-*/; + + public native void jsDecrypt(JavaScriptObject key, String bytes64, JavaScriptObject callback) /*-{ + return $wnd.mAsync.rsa_decrypt(callback, key, bytes64); + }-*/; +} diff --git a/gwt/src/core/crypt/CryptorSeed.java b/gwt/src/core/crypt/CryptorSeed.java new file mode 120000 index 0000000..15b7cfe --- /dev/null +++ b/gwt/src/core/crypt/CryptorSeed.java @@ -0,0 +1 @@ +../../../../java/core/src/core/crypt/CryptorSeed.java \ No newline at end of file diff --git a/gwt/src/core/crypt/HashSha1.java b/gwt/src/core/crypt/HashSha1.java new file mode 100644 index 0000000..7a1eeac --- /dev/null +++ b/gwt/src/core/crypt/HashSha1.java @@ -0,0 +1,17 @@ +package core.crypt; + +import core.util.Base64; +import core.util.Strings; + +public class HashSha1 +{ + protected native String jsHash(String bytes64) /*-{ + $wnd.mSupport.sha1_hash(bytes64); + }-*/; + + public byte[] hash(byte[] bytes) + { + return Base64.decode(jsHash(Base64.encode(bytes))); + } + +} diff --git a/gwt/src/core/crypt/HashSha256.java b/gwt/src/core/crypt/HashSha256.java new file mode 100644 index 0000000..0507c64 --- /dev/null +++ b/gwt/src/core/crypt/HashSha256.java @@ -0,0 +1,15 @@ +package core.crypt; + +import core.util.Base64; + +public class HashSha256 +{ + protected native String jsHash(String bytes64) /*-{ + return $wnd.mSupport.sha256_hash(bytes64); + }-*/; + + public byte[] hash(byte[] bytes) + { + return Base64.decode(jsHash(Base64.encode(bytes))); + } +} diff --git a/gwt/src/core/crypt/HmacSha1.java b/gwt/src/core/crypt/HmacSha1.java new file mode 100644 index 0000000..727d3ee --- /dev/null +++ b/gwt/src/core/crypt/HmacSha1.java @@ -0,0 +1,35 @@ +package core.crypt; + +import com.google.gwt.core.client.JavaScriptObject; + +import app.service.JSInvoker; +import core.callback.Callback; +import core.util.Base64; + +public class HmacSha1 +{ + String key64; + + public HmacSha1 (byte[] key) + { + this.key64 = Base64.encode(key); + } + + protected native String jsHmac(String key64, String bytes64) /*-{ + return $wnd.mSupport.sha1_hmac(key64, bytes64); + }-*/; + + protected native void jsHmac(String key64, String bytes64, JavaScriptObject callback) /*-{ + return $wnd.mAsync.sha1_hmac(key64, bytes64, callback); + }-*/; + + public byte[] mac(byte[] bytes) + { + return Base64.decode(jsHmac(key64, Base64.encode(bytes))); + } + + public void mac(byte[] bytes, Callback callback) + { + jsHmac(key64, Base64.encode(bytes), JSInvoker.wrap(callback)); + } +} diff --git a/gwt/src/core/crypt/KeyPairFromPassword.java b/gwt/src/core/crypt/KeyPairFromPassword.java new file mode 120000 index 0000000..ef29754 --- /dev/null +++ b/gwt/src/core/crypt/KeyPairFromPassword.java @@ -0,0 +1 @@ +../../../../java/core/src/core/crypt/KeyPairFromPassword.java \ No newline at end of file diff --git a/gwt/src/core/crypt/KeyPairFromPasswordCryptor.java b/gwt/src/core/crypt/KeyPairFromPasswordCryptor.java new file mode 120000 index 0000000..ba02c71 --- /dev/null +++ b/gwt/src/core/crypt/KeyPairFromPasswordCryptor.java @@ -0,0 +1 @@ +../../../../java/core/src/core/crypt/KeyPairFromPasswordCryptor.java \ No newline at end of file diff --git a/gwt/src/core/crypt/PBE.java b/gwt/src/core/crypt/PBE.java new file mode 100644 index 0000000..a36bd40 --- /dev/null +++ b/gwt/src/core/crypt/PBE.java @@ -0,0 +1,131 @@ +package core.crypt; + +import com.google.gwt.core.client.JavaScriptObject; + +import app.service.JSInvoker; +import core.util.Base64; +import core.util.LogNull; +import core.util.LogOut; +import core.util.Strings; +import core.callback.Callback; +import core.callback.CallbackDefault; +import core.exceptions.CryptoException; + + +/** + * http://stackoverflow.com/questions/992019/java-256-bit-aes-password-based-encryption + */ +public class PBE extends Cryptor +{ + byte[] key; + Cryptor cryptorAES; + + static LogNull log = new LogNull(PBE.class); + + public static final int DEFAULT_ITERATIONS = 131072; + public static final int SHORT_ITERATIONS = 32768; + public static final int DEFAULT_KEYLENGTH = 256; + + /** + * bytes used to salt the key (set before making an instance) + */ + public static final byte[] DEFAULT_SALT_0 = { + (byte)0xc8, (byte)0x73, (byte)0x41, (byte)0x8c, + (byte)0x7e, (byte)0xd8, (byte)0xee, (byte)0x89 + }; + + /** + * bytes used to salt the key (set before making an instance) + */ + public static final byte[] DEFAULT_SALT_1 = { + (byte)0x12, (byte)0x53, (byte)0x14, (byte)0xbb, + (byte)0x7e, (byte)0x97, (byte)0xce, (byte)0x55 + }; + + /** + * bytes used to salt the key (set before making an instance) + */ + public static final byte[] DEFAULT_SALT_2 = { + (byte)0x0a, (byte)0x48, (byte)0x33, (byte)0xfe, + (byte)0xa7, (byte)0xc2, (byte)0x2c, (byte)0x71 + }; + + public static final byte[][] DEFAULT_SALT = { DEFAULT_SALT_0, DEFAULT_SALT_1, DEFAULT_SALT_2 }; + + public PBE (String password, byte[] salt, int iterationCount, int keyLength) throws CryptoException + { + generate(password, salt, iterationCount, keyLength); + } + + public PBE () + { + + } + + public void generate (String password, byte[] salt, int iterationCount, int keyLength) throws CryptoException + { + key = Base64.decode(jsGenKey(password, Base64.encode(salt), iterationCount, keyLength)); + cryptorAES = new CryptorAES (key); + log.debug("computed", Base64.encode(key), " using ", password,"salt",Base64.encode(salt), iterationCount, keyLength); + } + + public Callback generate_ (String password, byte[] salt, int iterationCount, int keyLength) + { + return + new CallbackDefault(password, salt, iterationCount, keyLength) { + public void onSuccess(Object... arguments) throws Exception { + String password = V(0); + byte[] salt = V(1); + int iterationCount = V(2); + int keyLength = V(3); + + jsGenKey( + password, Base64.encode(salt), iterationCount, keyLength, + JSInvoker.wrap( + new CallbackDefault() { + @Override + public void onSuccess(Object... arguments) throws Exception { + String key64 = (String)arguments[0]; + key = Base64.decode(key64); + cryptorAES = new CryptorAES (key); + + callback.invoke(); + } + }.setReturn(callback) + ) + ); + + } + }; + } + + protected native String jsGenKey (String password, String salt64, int iterationCount, int keyLength) /*-{ + return $wnd.mSupport.pbe_genKey(password, salt64, iterationCount, keyLength); + }-*/; + + protected native String jsGenKey (String password, String salt64, int iterationCount, int keyLength, JavaScriptObject callback) /*-{ + return $wnd.mAsync.pbe_genKey(callback, password, salt64, iterationCount, keyLength); + }-*/; + + public byte[] encrypt(byte[] clearText) throws CryptoException + { + return cryptorAES.encrypt(clearText); + } + + public byte[] decrypt(byte[] encrypted) throws CryptoException + { + return cryptorAES.decrypt(encrypted); + } + + @Override + public Callback encrypt_() + { + return cryptorAES.encrypt_(); + } + + @Override + public Callback decrypt_() + { + return cryptorAES.decrypt_(); + } +} diff --git a/gwt/src/core/exceptions/CryptoException.java b/gwt/src/core/exceptions/CryptoException.java new file mode 120000 index 0000000..b1acd6f --- /dev/null +++ b/gwt/src/core/exceptions/CryptoException.java @@ -0,0 +1 @@ +../../../../java/core/src/core/exceptions/CryptoException.java \ No newline at end of file diff --git a/gwt/src/core/exceptions/InternalException.java b/gwt/src/core/exceptions/InternalException.java new file mode 120000 index 0000000..3770e34 --- /dev/null +++ b/gwt/src/core/exceptions/InternalException.java @@ -0,0 +1 @@ +../../../../java/core/src/core/exceptions/InternalException.java \ No newline at end of file diff --git a/gwt/src/core/exceptions/PublicMessageException.java b/gwt/src/core/exceptions/PublicMessageException.java new file mode 120000 index 0000000..9d326d6 --- /dev/null +++ b/gwt/src/core/exceptions/PublicMessageException.java @@ -0,0 +1 @@ +../../../../java/core/src/core/exceptions/PublicMessageException.java \ No newline at end of file diff --git a/gwt/src/core/exceptions/UserExistsException.java b/gwt/src/core/exceptions/UserExistsException.java new file mode 120000 index 0000000..8c13a91 --- /dev/null +++ b/gwt/src/core/exceptions/UserExistsException.java @@ -0,0 +1 @@ +../../../../java/core/src/core/exceptions/UserExistsException.java \ No newline at end of file diff --git a/gwt/src/core/io/IoChain.java b/gwt/src/core/io/IoChain.java new file mode 120000 index 0000000..2f7b6a7 --- /dev/null +++ b/gwt/src/core/io/IoChain.java @@ -0,0 +1 @@ +../../../../java/core/src/core/io/IoChain.java \ No newline at end of file diff --git a/gwt/src/core/io/IoChainAccumulator.java b/gwt/src/core/io/IoChainAccumulator.java new file mode 120000 index 0000000..4f1140f --- /dev/null +++ b/gwt/src/core/io/IoChainAccumulator.java @@ -0,0 +1 @@ +../../../../java/core/src/core/io/IoChainAccumulator.java \ No newline at end of file diff --git a/gwt/src/core/io/IoChainBase64.java b/gwt/src/core/io/IoChainBase64.java new file mode 120000 index 0000000..8e77f54 --- /dev/null +++ b/gwt/src/core/io/IoChainBase64.java @@ -0,0 +1 @@ +../../../../java/core/src/core/io/IoChainBase64.java \ No newline at end of file diff --git a/gwt/src/core/io/IoChainFinishedException.java b/gwt/src/core/io/IoChainFinishedException.java new file mode 120000 index 0000000..f04b3d0 --- /dev/null +++ b/gwt/src/core/io/IoChainFinishedException.java @@ -0,0 +1 @@ +../../../../java/core/src/core/io/IoChainFinishedException.java \ No newline at end of file diff --git a/gwt/src/core/io/IoChainNewLinePackets.java b/gwt/src/core/io/IoChainNewLinePackets.java new file mode 120000 index 0000000..65a01fd --- /dev/null +++ b/gwt/src/core/io/IoChainNewLinePackets.java @@ -0,0 +1 @@ +../../../../java/core/src/core/io/IoChainNewLinePackets.java \ No newline at end of file diff --git a/gwt/src/core/srp/SRPClientSession.java b/gwt/src/core/srp/SRPClientSession.java new file mode 100644 index 0000000..6841093 --- /dev/null +++ b/gwt/src/core/srp/SRPClientSession.java @@ -0,0 +1,84 @@ +package core.srp; + +import java.math.BigInteger; + +import org.json.JSONException; +import org.json.JSONObject; +import org.timepedia.exporter.client.Export; +import org.timepedia.exporter.client.Exportable; + +import com.jordanzimmerman.SRPAuthenticationFailedException; +import com.jordanzimmerman.SRPFactory; + +import core.util.Base64; + +@Export() +public class SRPClientSession extends com.jordanzimmerman.SRPClientSession implements Exportable +{ + protected SRPClientSession(JSONObject json) throws JSONException + { + fConstants = SRPFactory.DEFAULT_CONSTANTS; + + if (json.has("p")) + fPassword = Base64.decode(json.getString("p")); + if (json.has("S")) + fCommonValue_S = new BigInteger(Base64.decode(json.getString("S"))); + if (json.has("M1")) + fEvidenceValue_M1 = new BigInteger(Base64.decode(json.getString("M1"))); + if (json.has("x")) + fPrivateKey_x = new BigInteger(Base64.decode(json.getString("x"))); + if (json.has("A")) + fPublicKey_A = new BigInteger(Base64.decode(json.getString("A"))); + if (json.has("a")) + fRandom_a = new BigInteger(Base64.decode(json.getString("a"))); + if (json.has("K")) + fSessionKey_K = Base64.decode(json.getString("K")); + } + + static public SRPClientSession fromJSON(String json) throws JSONException + { + return new SRPClientSession(new JSONObject(json)); + } + + public String toJSON () throws JSONException + { + JSONObject json = new JSONObject(); + + if (fPassword != null) + json.put("p", Base64.encode(fPassword)); + if (fCommonValue_S != null) + json.put("S", Base64.encode(fCommonValue_S.toByteArray())); + if (fEvidenceValue_M1 != null) + json.put("M1", Base64.encode(fEvidenceValue_M1.toByteArray())); + if (fPrivateKey_x != null) + json.put("x", Base64.encode(fPrivateKey_x.toByteArray())); + if (fPublicKey_A != null) + json.put("A", Base64.encode(fPublicKey_A.toByteArray())); + if (fRandom_a != null) + json.put("a", Base64.encode(fRandom_a.toByteArray())); + if (fSessionKey_K != null) + json.put("K", Base64.encode(fSessionKey_K)); + + return json.toString(); + } + + public void setPassword(String password64) + { + fPassword = Base64.decode(password64); + } + + public void setSalt(String salt64) + { + setSalt_s(Base64.decode(salt64)); + } + + public void setServerPublicKey(String publicKey64) throws Exception + { + setServerPublicKey_B(Base64.decode(publicKey64)); + } + + public void validateServerEvidence(String evidence64) throws Exception + { + validateServerEvidenceValue_M2(Base64.decode(evidence64)); + } +} diff --git a/gwt/src/core/srp/SRPPacketSerializerJSON.java b/gwt/src/core/srp/SRPPacketSerializerJSON.java new file mode 120000 index 0000000..78a47e0 --- /dev/null +++ b/gwt/src/core/srp/SRPPacketSerializerJSON.java @@ -0,0 +1 @@ +../../../../java/core/src/core/srp/SRPPacketSerializerJSON.java \ No newline at end of file diff --git a/gwt/src/core/srp/SRPPackets.java b/gwt/src/core/srp/SRPPackets.java new file mode 120000 index 0000000..58815e7 --- /dev/null +++ b/gwt/src/core/srp/SRPPackets.java @@ -0,0 +1 @@ +../../../../java/core/src/core/srp/SRPPackets.java \ No newline at end of file diff --git a/gwt/src/core/srp/SRPSession.java b/gwt/src/core/srp/SRPSession.java new file mode 120000 index 0000000..ecba3d0 --- /dev/null +++ b/gwt/src/core/srp/SRPSession.java @@ -0,0 +1 @@ +../../../../java/core/src/core/srp/SRPSession.java \ No newline at end of file diff --git a/gwt/src/core/srp/client/SRPClient.java b/gwt/src/core/srp/client/SRPClient.java new file mode 120000 index 0000000..29b7149 --- /dev/null +++ b/gwt/src/core/srp/client/SRPClient.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/srp/client/SRPClient.java \ No newline at end of file diff --git a/gwt/src/core/srp/client/SRPClientAsync.java b/gwt/src/core/srp/client/SRPClientAsync.java new file mode 100644 index 0000000..6042e50 --- /dev/null +++ b/gwt/src/core/srp/client/SRPClientAsync.java @@ -0,0 +1,91 @@ +package core.srp.client; + +import app.service.JSInvoker; + +import com.google.gwt.core.client.JavaScriptObject; +import core.util.Base64; +import core.callback.Callback; +import core.callback.CallbackDefault; + +public class SRPClientAsync +{ + JavaScriptObject key; + + native JavaScriptObject jsInitialize (String password64) /*-{ + return $wnd.mSupport.srp_client_initialize(password64); + }-*/; + + native void jsSetSalt (JavaScriptObject key, String salt64, JavaScriptObject callback) /*-{ + $wnd.mAsync.srp_client_setSalt(callback, key, salt64); + }-*/; + + native void jsSetServerPublicKey (JavaScriptObject key, String server64, JavaScriptObject callback) /*-{ + $wnd.mAsync.srp_client_setServerPublicKey(callback, key, server64); + }-*/; + + native void jsValidateServerEvidence (JavaScriptObject key, String evidence64, JavaScriptObject callback) /*-{ + $wnd.mAsync.srp_client_validateServerEvidence(callback, key, evidence64); + }-*/; + + native String jsGetSessionKey (JavaScriptObject key) /*-{ + return $wnd.mSupport.srp_client_getSessionKey(key); + }-*/; + + native String jsGetPublicKey (JavaScriptObject key) /*-{ + return $wnd.mSupport.srp_client_getPublicKey(key); + }-*/; + + native String jsGetEvidenceValue (JavaScriptObject key) /*-{ + return $wnd.mSupport.srp_client_getEvidenceValue(key); + }-*/; + + public SRPClientAsync (byte[] password) + { + key = jsInitialize(Base64.encode(password)); + } + + public Callback setSalt_(byte[] bs) + { + return new CallbackDefault(Base64.encode(bs)) + { + public void onSuccess(Object... arguments) throws Exception { + jsSetSalt(key, (String)V(0), JSInvoker.wrap(callback)); + } + }; + } + + public Callback setServerPublicKey_(byte[] publicKey) + { + return new CallbackDefault(Base64.encode(publicKey)) + { + public void onSuccess(Object... arguments) throws Exception { + jsSetServerPublicKey(key, (String)V(0), JSInvoker.wrap(callback)); + } + }; + } + + public Callback validateServerEvidenceValue_M2_(byte[] evidence) + { + return new CallbackDefault(Base64.encode(evidence)) + { + public void onSuccess(Object... arguments) throws Exception { + jsValidateServerEvidence(key, (String)V(0), JSInvoker.wrap(callback)); + } + }; + } + + public byte[] getSessionKey() + { + return Base64.decode(jsGetSessionKey(key)); + } + + public byte[] getPublicKey() + { + return Base64.decode(jsGetPublicKey(key)); + } + + public byte[] getEvidenceValue() + { + return Base64.decode(jsGetEvidenceValue(key)); + } +} diff --git a/gwt/src/core/srp/client/SRPClientListener.java b/gwt/src/core/srp/client/SRPClientListener.java new file mode 120000 index 0000000..ed3138f --- /dev/null +++ b/gwt/src/core/srp/client/SRPClientListener.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/srp/client/SRPClientListener.java \ No newline at end of file diff --git a/gwt/src/core/srp/client/SRPClientUserSession.java b/gwt/src/core/srp/client/SRPClientUserSession.java new file mode 120000 index 0000000..920e405 --- /dev/null +++ b/gwt/src/core/srp/client/SRPClientUserSession.java @@ -0,0 +1 @@ +../../../../../java/core/src/core/srp/client/SRPClientUserSession.java \ No newline at end of file diff --git a/gwt/src/core/util/Arrays.java b/gwt/src/core/util/Arrays.java new file mode 120000 index 0000000..521bcab --- /dev/null +++ b/gwt/src/core/util/Arrays.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/Arrays.java \ No newline at end of file diff --git a/gwt/src/core/util/Base16.java b/gwt/src/core/util/Base16.java new file mode 120000 index 0000000..e0d84f2 --- /dev/null +++ b/gwt/src/core/util/Base16.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/Base16.java \ No newline at end of file diff --git a/gwt/src/core/util/Base64.java b/gwt/src/core/util/Base64.java new file mode 100644 index 0000000..fee5a93 --- /dev/null +++ b/gwt/src/core/util/Base64.java @@ -0,0 +1,128 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package core.util; + +import com.google.gwt.core.client.JsArrayInteger; + +import core.callback.Callback; +import core.callback.CallbackDefault; + +public class Base64 +{ + /* + public static String encode(byte[] bytes) + { + return Strings.toString(Base64Impl.encode(bytes)); + } + + public static byte[] decode(String b64) + { + return Base64Impl.decode(b64.getBytes()); + } + + public static byte[] encodeBytes(byte[] bytes) + { + return Base64Impl.encode(bytes); + } + + public static byte[] decodeBytes(byte[] b64) + { + return Base64Impl.decode(b64); + } + */ + + public native static String jsEncode(byte[] bytes) /*-{ + return $wnd.Base64.encode(bytes); + }-*/; + + public native static JsArrayInteger jsDecode(String base64) /*-{ + return $wnd.Base64.decode(base64); + }-*/; + + public native static JsArrayInteger jsEncodeBytes(byte[] bytes) /*-{ + return $wnd.Base64.encodeBytes(bytes); + }-*/; + + public native static JsArrayInteger jsDecodeBytes(byte[] base64) /*-{ + return $wnd.Base64.decodeBytes(base64); + }-*/; + + public static byte[] convert(JsArrayInteger a) + { + byte[] bytes = new byte[a.length()]; + for (int i=0; i c, String p) + { + return new ByteArrayInputStream(Base64.decode(getResource(c.getName() + "." + p))); + } + +} diff --git a/gwt/src/core/util/JSONRegistry.java b/gwt/src/core/util/JSONRegistry.java new file mode 120000 index 0000000..263a4f2 --- /dev/null +++ b/gwt/src/core/util/JSONRegistry.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/JSONRegistry.java \ No newline at end of file diff --git a/gwt/src/core/util/JSONSerializer.java b/gwt/src/core/util/JSONSerializer.java new file mode 120000 index 0000000..6357b58 --- /dev/null +++ b/gwt/src/core/util/JSONSerializer.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/JSONSerializer.java \ No newline at end of file diff --git a/gwt/src/core/util/JSON_.java b/gwt/src/core/util/JSON_.java new file mode 100644 index 0000000..3c1f2dd --- /dev/null +++ b/gwt/src/core/util/JSON_.java @@ -0,0 +1,275 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package core.util; + +import com.google.gwt.json.client.JSONArray; +import com.google.gwt.json.client.JSONBoolean; +import com.google.gwt.json.client.JSONNumber; +import com.google.gwt.json.client.JSONObject; +import com.google.gwt.json.client.JSONParser; +import com.google.gwt.json.client.JSONString; +import com.google.gwt.json.client.JSONValue; + +public class JSON_ +{ + @SuppressWarnings("serial") + public static class JSONException extends Exception { + public JSONException(Exception e) + { + super(e); + } + }; + + public static Object newString(String string) + { + return new JSONString(string); + } + + public static Object newArray () + { + return new JSONArray(); + } + + public static Object newObject () + { + return new JSONObject(); + } + + public static Object newNumber (long v) + { + return new JSONNumber(v); + } + + public static String asString(Object value) + { + return ((JSONString)value).stringValue(); + } + + public static int size(Object a) throws JSONException + { + try + { + return ((JSONArray)a).size(); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static String[] keys(Object _o) throws JSONException + { + try + { + JSONObject o = (JSONObject) _o; + return o.keySet().toArray(new String[0]); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static Object get(Object a, int k) throws JSONException + { + try + { + return ((JSONArray)a).get(k); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static void add (Object a, Object v) throws JSONException + { + try + { + JSONArray ja = (JSONArray)a; + ja.set(ja.size(), (JSONValue)v); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static Object get(Object o, String k) throws JSONException + { + try + { + return ((JSONObject)o).get(k); + } + catch (Exception e) + { + throw new JSONException(e); + } + + } + + public static void put (Object o, String k, Object v) throws JSONException + { + try + { + ((JSONObject)o).put(k, (JSONValue)v); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static boolean has (Object o, String k) throws JSONException + { + try + { + return ((JSONObject)o).containsKey(k); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + //---------------------------------------------- + + public static String getString (Object a, int i) throws JSONException + { + try + { + return ((JSONString)get(a,i)).stringValue(); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static String getString (Object o, String k) throws JSONException + { + try + { + return ((JSONString)get(o,k)).stringValue(); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static Object getArray (Object o, String k) throws JSONException + { + try + { + return get(o,k); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static Object getObject(Object o, String k) throws JSONException + { + try + { + return get(o,k); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static int getInt(Object o, String k) throws JSONException + { + try + { + return (int) ((JSONNumber)get(o,k)).doubleValue(); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static Object getArray(Object a, int i) throws JSONException + { + try + { + return get(a,i); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static long getLong(Object o, int k) throws JSONException + { + try + { + return (long) ((JSONNumber)get(o,k)).doubleValue(); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static long getLong(Object o, String k) throws JSONException + { + try + { + return (long) ((JSONNumber)get(o,k)).doubleValue(); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static Object parse (String s) throws JSONException + { + try + { + return JSONParser.parseStrict(s); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static Object newBoolean(boolean loaded) + { + return JSONBoolean.getInstance(loaded); + } + + public static Object getObject(Object o, int i) throws JSONException + { + try + { + return (JSONObject)get(o,i); + } + catch (Exception e) + { + throw new JSONException(e); + } + } + + public static boolean getBoolean(Object o, String string) throws JSONException + { + try + { + return ((JSONBoolean)get(o, string)).booleanValue(); + } + catch (Exception e) + { + throw new JSONException(e); + } + } +} diff --git a/gwt/src/core/util/LogNull.java b/gwt/src/core/util/LogNull.java new file mode 120000 index 0000000..6726600 --- /dev/null +++ b/gwt/src/core/util/LogNull.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/LogNull.java \ No newline at end of file diff --git a/gwt/src/core/util/LogOut.java b/gwt/src/core/util/LogOut.java new file mode 120000 index 0000000..467cfec --- /dev/null +++ b/gwt/src/core/util/LogOut.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/LogOut.java \ No newline at end of file diff --git a/gwt/src/core/util/LogPlatform.java b/gwt/src/core/util/LogPlatform.java new file mode 100644 index 0000000..3f824ac --- /dev/null +++ b/gwt/src/core/util/LogPlatform.java @@ -0,0 +1,17 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package core.util; + +public class LogPlatform +{ + public native static void println(String s) /*-{ + $wnd.log(s); + }-*/; + + public native static void printException(Object e) /*-{ + $wnd.logException(e); + }-*/; + +} diff --git a/gwt/src/core/util/Maps.java b/gwt/src/core/util/Maps.java new file mode 120000 index 0000000..e9ff5d1 --- /dev/null +++ b/gwt/src/core/util/Maps.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/Maps.java \ No newline at end of file diff --git a/gwt/src/core/util/Pair.java b/gwt/src/core/util/Pair.java new file mode 120000 index 0000000..35d4593 --- /dev/null +++ b/gwt/src/core/util/Pair.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/Pair.java \ No newline at end of file diff --git a/gwt/src/core/util/RunnableWithVariables.java b/gwt/src/core/util/RunnableWithVariables.java new file mode 120000 index 0000000..9527ab1 --- /dev/null +++ b/gwt/src/core/util/RunnableWithVariables.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/RunnableWithVariables.java \ No newline at end of file diff --git a/gwt/src/core/util/SecureRandom.java b/gwt/src/core/util/SecureRandom.java new file mode 100644 index 0000000..ec7f2c1 --- /dev/null +++ b/gwt/src/core/util/SecureRandom.java @@ -0,0 +1,10 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package core.util; + +public class SecureRandom extends java.security.SecureRandom { + + +} diff --git a/gwt/src/core/util/SimpleSerializer.java b/gwt/src/core/util/SimpleSerializer.java new file mode 120000 index 0000000..51130f9 --- /dev/null +++ b/gwt/src/core/util/SimpleSerializer.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/SimpleSerializer.java \ No newline at end of file diff --git a/gwt/src/core/util/Streams.java b/gwt/src/core/util/Streams.java new file mode 120000 index 0000000..7e6693e --- /dev/null +++ b/gwt/src/core/util/Streams.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/Streams.java \ No newline at end of file diff --git a/gwt/src/core/util/Strings.java b/gwt/src/core/util/Strings.java new file mode 120000 index 0000000..d73aef3 --- /dev/null +++ b/gwt/src/core/util/Strings.java @@ -0,0 +1 @@ +../../../../java/core/src/core/util/Strings.java \ No newline at end of file diff --git a/gwt/src/core/util/StringsPlatform.java b/gwt/src/core/util/StringsPlatform.java new file mode 100644 index 0000000..42df5d0 --- /dev/null +++ b/gwt/src/core/util/StringsPlatform.java @@ -0,0 +1,34 @@ +/** + * Author: Timothy Prepscius + * License: GPLv3 Affero + keep my name in the code! + */ +package core.util; + +import com.google.gwt.core.client.JsArrayInteger; + +public class StringsPlatform +{ + public static native String jsToString (byte[] bytes) /*-{ + return $wnd.Utf.toString(bytes); + }-*/; + + public static native JsArrayInteger jsToBytes (String s) /*-{ + return $wnd.Utf.toBytes(s); + }-*/; + + public static String toString(byte[] bytes) + { + return jsToString(bytes); + } + + public static byte[] toBytes(String s) + { + JsArrayInteger a = jsToBytes(s); + byte[] bytes = new byte[a.length()]; + + for (int i=0; i(inflate_()).export(); + } + catch(Exception e) + { + throw new IOException(e); + } + } + + public static Callback inflate_ () + { + CallbackChain chain = new CallbackChain(); + return chain + .addCallback(log.debug_("inflate")) + .addCallback(Base64.encode_()) + .addCallback(jsInflate_()) + .addCallback(Base64.decode_()); + } + + public static Callback deflate_ () + { + CallbackChain chain = new CallbackChain(); + return chain + .addCallback(log.debug_("deflate")) + .addCallback(Base64.encode_()) + .addCallback(jsDeflate_()) + .addCallback(Base64.decode_()) + ; + } +} diff --git a/gwt/src/key/GWT.gwt.xml b/gwt/src/key/GWT.gwt.xml new file mode 100644 index 0000000..afb96ab --- /dev/null +++ b/gwt/src/key/GWT.gwt.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gwt/src/key/auth/KeyServerAuthenticatorNoThread.java b/gwt/src/key/auth/KeyServerAuthenticatorNoThread.java new file mode 120000 index 0000000..a55dc1c --- /dev/null +++ b/gwt/src/key/auth/KeyServerAuthenticatorNoThread.java @@ -0,0 +1 @@ +../../../../java/core/src/key/auth/KeyServerAuthenticatorNoThread.java \ No newline at end of file diff --git a/gwt/src/mail/GWT.gwt.xml b/gwt/src/mail/GWT.gwt.xml new file mode 100644 index 0000000..afb96ab --- /dev/null +++ b/gwt/src/mail/GWT.gwt.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gwt/src/mail/auth/MailServerAuthenticatorNoThread.java b/gwt/src/mail/auth/MailServerAuthenticatorNoThread.java new file mode 120000 index 0000000..e8865f2 --- /dev/null +++ b/gwt/src/mail/auth/MailServerAuthenticatorNoThread.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/auth/MailServerAuthenticatorNoThread.java \ No newline at end of file diff --git a/gwt/src/mail/client/Actions.java b/gwt/src/mail/client/Actions.java new file mode 120000 index 0000000..c14a3f4 --- /dev/null +++ b/gwt/src/mail/client/Actions.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Actions.java \ No newline at end of file diff --git a/gwt/src/mail/client/ArrivalsMonitor.java b/gwt/src/mail/client/ArrivalsMonitor.java new file mode 120000 index 0000000..ac5db14 --- /dev/null +++ b/gwt/src/mail/client/ArrivalsMonitor.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/ArrivalsMonitor.java \ No newline at end of file diff --git a/gwt/src/mail/client/ArrivalsMonitorDefault.java b/gwt/src/mail/client/ArrivalsMonitorDefault.java new file mode 120000 index 0000000..87c610e --- /dev/null +++ b/gwt/src/mail/client/ArrivalsMonitorDefault.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/ArrivalsMonitorDefault.java \ No newline at end of file diff --git a/gwt/src/mail/client/ArrivalsProcessor.java b/gwt/src/mail/client/ArrivalsProcessor.java new file mode 120000 index 0000000..bc8599c --- /dev/null +++ b/gwt/src/mail/client/ArrivalsProcessor.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/ArrivalsProcessor.java \ No newline at end of file diff --git a/gwt/src/mail/client/ArrivalsProcessor.no b/gwt/src/mail/client/ArrivalsProcessor.no new file mode 100644 index 0000000..322ab19 --- /dev/null +++ b/gwt/src/mail/client/ArrivalsProcessor.no @@ -0,0 +1,27 @@ +package mail.client; + +import java.io.ByteArrayInputStream; +import java.util.Date; + +import mail.client.core.Direction; + +public class ArrivalsProcessor extends Servent { + + public boolean alreadyProcessed(String path) { + // TODO Auto-generated method stub + return false; + } + + public void processSuccess(Direction direction, String path, Date date, + ByteArrayInputStream byteArrayInputStream) { + // TODO Auto-generated method stub + + } + + public void processFailure(Direction direction, String path, Date date, + Exception e) { + // TODO Auto-generated method stub + + } + +} diff --git a/gwt/src/mail/client/CacheManager.java b/gwt/src/mail/client/CacheManager.java new file mode 120000 index 0000000..2e76d36 --- /dev/null +++ b/gwt/src/mail/client/CacheManager.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/CacheManager.java \ No newline at end of file diff --git a/gwt/src/mail/client/Client.java b/gwt/src/mail/client/Client.java new file mode 120000 index 0000000..5e91fb1 --- /dev/null +++ b/gwt/src/mail/client/Client.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Client.java \ No newline at end of file diff --git a/gwt/src/mail/client/Constants.java b/gwt/src/mail/client/Constants.java new file mode 120000 index 0000000..a6c5261 --- /dev/null +++ b/gwt/src/mail/client/Constants.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Constants.java \ No newline at end of file diff --git a/gwt/src/mail/client/CyclicalFileCheck.java b/gwt/src/mail/client/CyclicalFileCheck.java new file mode 120000 index 0000000..ef7a928 --- /dev/null +++ b/gwt/src/mail/client/CyclicalFileCheck.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/CyclicalFileCheck.java \ No newline at end of file diff --git a/gwt/src/mail/client/EventDispatcher.java b/gwt/src/mail/client/EventDispatcher.java new file mode 120000 index 0000000..f0e7ce9 --- /dev/null +++ b/gwt/src/mail/client/EventDispatcher.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/EventDispatcher.java \ No newline at end of file diff --git a/gwt/src/mail/client/EventPropagator.java b/gwt/src/mail/client/EventPropagator.java new file mode 120000 index 0000000..39d9df8 --- /dev/null +++ b/gwt/src/mail/client/EventPropagator.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/EventPropagator.java \ No newline at end of file diff --git a/gwt/src/mail/client/EventType.java b/gwt/src/mail/client/EventType.java new file mode 120000 index 0000000..393fce6 --- /dev/null +++ b/gwt/src/mail/client/EventType.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/EventType.java \ No newline at end of file diff --git a/gwt/src/mail/client/Events.java b/gwt/src/mail/client/Events.java new file mode 120000 index 0000000..3e150db --- /dev/null +++ b/gwt/src/mail/client/Events.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Events.java \ No newline at end of file diff --git a/gwt/src/mail/client/Indexer.java b/gwt/src/mail/client/Indexer.java new file mode 120000 index 0000000..1be5d88 --- /dev/null +++ b/gwt/src/mail/client/Indexer.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Indexer.java \ No newline at end of file diff --git a/gwt/src/mail/client/Initializer.java b/gwt/src/mail/client/Initializer.java new file mode 120000 index 0000000..3261a30 --- /dev/null +++ b/gwt/src/mail/client/Initializer.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Initializer.java \ No newline at end of file diff --git a/gwt/src/mail/client/Mailer.java b/gwt/src/mail/client/Mailer.java new file mode 120000 index 0000000..9fb9f63 --- /dev/null +++ b/gwt/src/mail/client/Mailer.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Mailer.java \ No newline at end of file diff --git a/gwt/src/mail/client/Master.java b/gwt/src/mail/client/Master.java new file mode 120000 index 0000000..8c05839 --- /dev/null +++ b/gwt/src/mail/client/Master.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Master.java \ No newline at end of file diff --git a/gwt/src/mail/client/MasterCacheSerializer.java b/gwt/src/mail/client/MasterCacheSerializer.java new file mode 120000 index 0000000..4707b19 --- /dev/null +++ b/gwt/src/mail/client/MasterCacheSerializer.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/MasterCacheSerializer.java \ No newline at end of file diff --git a/gwt/src/mail/client/Servent.java b/gwt/src/mail/client/Servent.java new file mode 120000 index 0000000..8b3bbad --- /dev/null +++ b/gwt/src/mail/client/Servent.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Servent.java \ No newline at end of file diff --git a/gwt/src/mail/client/Store.java b/gwt/src/mail/client/Store.java new file mode 120000 index 0000000..fd044f8 --- /dev/null +++ b/gwt/src/mail/client/Store.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/Store.java \ No newline at end of file diff --git a/gwt/src/mail/client/TrackingConnector.java b/gwt/src/mail/client/TrackingConnector.java new file mode 120000 index 0000000..db0e3de --- /dev/null +++ b/gwt/src/mail/client/TrackingConnector.java @@ -0,0 +1 @@ +../../../../java/core/src/mail/client/TrackingConnector.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/Cache.java b/gwt/src/mail/client/cache/Cache.java new file mode 120000 index 0000000..67123ec --- /dev/null +++ b/gwt/src/mail/client/cache/Cache.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/Cache.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/CacheFlush.java b/gwt/src/mail/client/cache/CacheFlush.java new file mode 120000 index 0000000..57cde14 --- /dev/null +++ b/gwt/src/mail/client/cache/CacheFlush.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/CacheFlush.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/CacheState.java b/gwt/src/mail/client/cache/CacheState.java new file mode 120000 index 0000000..ebcfb03 --- /dev/null +++ b/gwt/src/mail/client/cache/CacheState.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/CacheState.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/ID.java b/gwt/src/mail/client/cache/ID.java new file mode 120000 index 0000000..5778cf3 --- /dev/null +++ b/gwt/src/mail/client/cache/ID.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/ID.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/IndexedCache.java b/gwt/src/mail/client/cache/IndexedCache.java new file mode 120000 index 0000000..c72b35a --- /dev/null +++ b/gwt/src/mail/client/cache/IndexedCache.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/IndexedCache.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/IndexedCacheSerializer.java b/gwt/src/mail/client/cache/IndexedCacheSerializer.java new file mode 120000 index 0000000..14d2d82 --- /dev/null +++ b/gwt/src/mail/client/cache/IndexedCacheSerializer.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/IndexedCacheSerializer.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/Info.java b/gwt/src/mail/client/cache/Info.java new file mode 120000 index 0000000..acbf117 --- /dev/null +++ b/gwt/src/mail/client/cache/Info.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/Info.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/Item.java b/gwt/src/mail/client/cache/Item.java new file mode 120000 index 0000000..ad68815 --- /dev/null +++ b/gwt/src/mail/client/cache/Item.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/Item.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/ItemCacheFactory.java b/gwt/src/mail/client/cache/ItemCacheFactory.java new file mode 120000 index 0000000..3231f4c --- /dev/null +++ b/gwt/src/mail/client/cache/ItemCacheFactory.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/ItemCacheFactory.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/ItemCollection.java b/gwt/src/mail/client/cache/ItemCollection.java new file mode 120000 index 0000000..e385374 --- /dev/null +++ b/gwt/src/mail/client/cache/ItemCollection.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/ItemCollection.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/ItemFactory.java b/gwt/src/mail/client/cache/ItemFactory.java new file mode 120000 index 0000000..fe72ab1 --- /dev/null +++ b/gwt/src/mail/client/cache/ItemFactory.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/ItemFactory.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/ItemOwner.java b/gwt/src/mail/client/cache/ItemOwner.java new file mode 120000 index 0000000..adb4e1e --- /dev/null +++ b/gwt/src/mail/client/cache/ItemOwner.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/ItemOwner.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/ItemSerializer.java b/gwt/src/mail/client/cache/ItemSerializer.java new file mode 120000 index 0000000..3aa44bd --- /dev/null +++ b/gwt/src/mail/client/cache/ItemSerializer.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/ItemSerializer.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/ItemSerializerSync.java b/gwt/src/mail/client/cache/ItemSerializerSync.java new file mode 120000 index 0000000..f7a8436 --- /dev/null +++ b/gwt/src/mail/client/cache/ItemSerializerSync.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/ItemSerializerSync.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/JSON.java b/gwt/src/mail/client/cache/JSON.java new file mode 120000 index 0000000..935643d --- /dev/null +++ b/gwt/src/mail/client/cache/JSON.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/JSON.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/LoadState.java b/gwt/src/mail/client/cache/LoadState.java new file mode 120000 index 0000000..f543363 --- /dev/null +++ b/gwt/src/mail/client/cache/LoadState.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/LoadState.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/Operation.java b/gwt/src/mail/client/cache/Operation.java new file mode 120000 index 0000000..19294fa --- /dev/null +++ b/gwt/src/mail/client/cache/Operation.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/Operation.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/Store.java b/gwt/src/mail/client/cache/Store.java new file mode 120000 index 0000000..74178bb --- /dev/null +++ b/gwt/src/mail/client/cache/Store.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/Store.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/StoreFactory.java b/gwt/src/mail/client/cache/StoreFactory.java new file mode 120000 index 0000000..c8739ec --- /dev/null +++ b/gwt/src/mail/client/cache/StoreFactory.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/StoreFactory.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/StoreLibrary.java b/gwt/src/mail/client/cache/StoreLibrary.java new file mode 120000 index 0000000..d179c68 --- /dev/null +++ b/gwt/src/mail/client/cache/StoreLibrary.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/StoreLibrary.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/StoreSerializer.java b/gwt/src/mail/client/cache/StoreSerializer.java new file mode 120000 index 0000000..f4cb2b0 --- /dev/null +++ b/gwt/src/mail/client/cache/StoreSerializer.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/StoreSerializer.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/Type.java b/gwt/src/mail/client/cache/Type.java new file mode 120000 index 0000000..98fbeab --- /dev/null +++ b/gwt/src/mail/client/cache/Type.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/Type.java \ No newline at end of file diff --git a/gwt/src/mail/client/cache/Version.java b/gwt/src/mail/client/cache/Version.java new file mode 120000 index 0000000..60b4a35 --- /dev/null +++ b/gwt/src/mail/client/cache/Version.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/cache/Version.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/AddressBook.java b/gwt/src/mail/client/model/AddressBook.java new file mode 120000 index 0000000..84f5829 --- /dev/null +++ b/gwt/src/mail/client/model/AddressBook.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/AddressBook.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Attachment.java b/gwt/src/mail/client/model/Attachment.java new file mode 120000 index 0000000..f693cb9 --- /dev/null +++ b/gwt/src/mail/client/model/Attachment.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Attachment.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Attachments.java b/gwt/src/mail/client/model/Attachments.java new file mode 120000 index 0000000..473ed2d --- /dev/null +++ b/gwt/src/mail/client/model/Attachments.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Attachments.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Body.java b/gwt/src/mail/client/model/Body.java new file mode 120000 index 0000000..ffdedc3 --- /dev/null +++ b/gwt/src/mail/client/model/Body.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Body.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/ConstantsMisc.java b/gwt/src/mail/client/model/ConstantsMisc.java new file mode 120000 index 0000000..6a4436f --- /dev/null +++ b/gwt/src/mail/client/model/ConstantsMisc.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/ConstantsMisc.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Conversation.java b/gwt/src/mail/client/model/Conversation.java new file mode 120000 index 0000000..b4001eb --- /dev/null +++ b/gwt/src/mail/client/model/Conversation.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Conversation.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Dictionary.java b/gwt/src/mail/client/model/Dictionary.java new file mode 120000 index 0000000..e3f260b --- /dev/null +++ b/gwt/src/mail/client/model/Dictionary.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Dictionary.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Direction.java b/gwt/src/mail/client/model/Direction.java new file mode 120000 index 0000000..06c8e46 --- /dev/null +++ b/gwt/src/mail/client/model/Direction.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Direction.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Folder.java b/gwt/src/mail/client/model/Folder.java new file mode 120000 index 0000000..53eebfa --- /dev/null +++ b/gwt/src/mail/client/model/Folder.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Folder.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/FolderDefinition.java b/gwt/src/mail/client/model/FolderDefinition.java new file mode 120000 index 0000000..407ba1c --- /dev/null +++ b/gwt/src/mail/client/model/FolderDefinition.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/FolderDefinition.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/FolderFilter.java b/gwt/src/mail/client/model/FolderFilter.java new file mode 120000 index 0000000..6249e29 --- /dev/null +++ b/gwt/src/mail/client/model/FolderFilter.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/FolderFilter.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/FolderFilterSet.java b/gwt/src/mail/client/model/FolderFilterSet.java new file mode 120000 index 0000000..3243b50 --- /dev/null +++ b/gwt/src/mail/client/model/FolderFilterSet.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/FolderFilterSet.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/FolderFilterSimple.java b/gwt/src/mail/client/model/FolderFilterSimple.java new file mode 120000 index 0000000..766d3dc --- /dev/null +++ b/gwt/src/mail/client/model/FolderFilterSimple.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/FolderFilterSimple.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/FolderMaster.java b/gwt/src/mail/client/model/FolderMaster.java new file mode 120000 index 0000000..c048c51 --- /dev/null +++ b/gwt/src/mail/client/model/FolderMaster.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/FolderMaster.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/FolderPart.java b/gwt/src/mail/client/model/FolderPart.java new file mode 120000 index 0000000..a6d3699 --- /dev/null +++ b/gwt/src/mail/client/model/FolderPart.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/FolderPart.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/FolderRepository.java b/gwt/src/mail/client/model/FolderRepository.java new file mode 120000 index 0000000..8c07cbe --- /dev/null +++ b/gwt/src/mail/client/model/FolderRepository.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/FolderRepository.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/FolderSet.java b/gwt/src/mail/client/model/FolderSet.java new file mode 120000 index 0000000..cf89279 --- /dev/null +++ b/gwt/src/mail/client/model/FolderSet.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/FolderSet.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Header.java b/gwt/src/mail/client/model/Header.java new file mode 120000 index 0000000..8e6a931 --- /dev/null +++ b/gwt/src/mail/client/model/Header.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Header.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Identity.java b/gwt/src/mail/client/model/Identity.java new file mode 120000 index 0000000..b9e751a --- /dev/null +++ b/gwt/src/mail/client/model/Identity.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Identity.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Mail.java b/gwt/src/mail/client/model/Mail.java new file mode 120000 index 0000000..3f5cee3 --- /dev/null +++ b/gwt/src/mail/client/model/Mail.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Mail.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Model.java b/gwt/src/mail/client/model/Model.java new file mode 120000 index 0000000..114e353 --- /dev/null +++ b/gwt/src/mail/client/model/Model.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Model.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/ModelFactory.java b/gwt/src/mail/client/model/ModelFactory.java new file mode 120000 index 0000000..4ba578a --- /dev/null +++ b/gwt/src/mail/client/model/ModelFactory.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/ModelFactory.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/ModelSerializer.java b/gwt/src/mail/client/model/ModelSerializer.java new file mode 120000 index 0000000..24a227e --- /dev/null +++ b/gwt/src/mail/client/model/ModelSerializer.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/ModelSerializer.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Original.java b/gwt/src/mail/client/model/Original.java new file mode 120000 index 0000000..7af7f27 --- /dev/null +++ b/gwt/src/mail/client/model/Original.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Original.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Original.java.no b/gwt/src/mail/client/model/Original.java.no new file mode 120000 index 0000000..5712bb8 --- /dev/null +++ b/gwt/src/mail/client/model/Original.java.no @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Original.java.no \ No newline at end of file diff --git a/gwt/src/mail/client/model/Recipients.java b/gwt/src/mail/client/model/Recipients.java new file mode 120000 index 0000000..3ab63a4 --- /dev/null +++ b/gwt/src/mail/client/model/Recipients.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Recipients.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/Settings.java b/gwt/src/mail/client/model/Settings.java new file mode 120000 index 0000000..d1704e1 --- /dev/null +++ b/gwt/src/mail/client/model/Settings.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/Settings.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/TransportState.java b/gwt/src/mail/client/model/TransportState.java new file mode 120000 index 0000000..5099b31 --- /dev/null +++ b/gwt/src/mail/client/model/TransportState.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/TransportState.java \ No newline at end of file diff --git a/gwt/src/mail/client/model/UnregisteredIdentity.java b/gwt/src/mail/client/model/UnregisteredIdentity.java new file mode 120000 index 0000000..e8741e6 --- /dev/null +++ b/gwt/src/mail/client/model/UnregisteredIdentity.java @@ -0,0 +1 @@ +../../../../../java/core/src/mail/client/model/UnregisteredIdentity.java \ No newline at end of file diff --git a/gwt/src/org/json/GWT.gwt.xml b/gwt/src/org/json/GWT.gwt.xml new file mode 100644 index 0000000..afb96ab --- /dev/null +++ b/gwt/src/org/json/GWT.gwt.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/gwt/src/org/json/JSONArray.java b/gwt/src/org/json/JSONArray.java new file mode 120000 index 0000000..3789361 --- /dev/null +++ b/gwt/src/org/json/JSONArray.java @@ -0,0 +1 @@ +../../../../java/ext/json/src/org/json/JSONArray.java \ No newline at end of file diff --git a/gwt/src/org/json/JSONException.java b/gwt/src/org/json/JSONException.java new file mode 120000 index 0000000..bd7619b --- /dev/null +++ b/gwt/src/org/json/JSONException.java @@ -0,0 +1 @@ +../../../../java/ext/json/src/org/json/JSONException.java \ No newline at end of file diff --git a/gwt/src/org/json/JSONObject.java b/gwt/src/org/json/JSONObject.java new file mode 120000 index 0000000..e77c8ba --- /dev/null +++ b/gwt/src/org/json/JSONObject.java @@ -0,0 +1 @@ +../../../../java/ext/json/src/org/json/JSONObject.java \ No newline at end of file diff --git a/gwt/src/org/json/JSONString.java b/gwt/src/org/json/JSONString.java new file mode 120000 index 0000000..3d9e0a2 --- /dev/null +++ b/gwt/src/org/json/JSONString.java @@ -0,0 +1 @@ +../../../../java/ext/json/src/org/json/JSONString.java \ No newline at end of file diff --git a/gwt/src/org/json/JSONStringer.java b/gwt/src/org/json/JSONStringer.java new file mode 120000 index 0000000..22a3304 --- /dev/null +++ b/gwt/src/org/json/JSONStringer.java @@ -0,0 +1 @@ +../../../../java/ext/json/src/org/json/JSONStringer.java \ No newline at end of file diff --git a/gwt/src/org/json/JSONTokener.java b/gwt/src/org/json/JSONTokener.java new file mode 120000 index 0000000..74a6a78 --- /dev/null +++ b/gwt/src/org/json/JSONTokener.java @@ -0,0 +1 @@ +../../../../java/ext/json/src/org/json/JSONTokener.java \ No newline at end of file diff --git a/gwt/src/org/json/JSONWriter.java b/gwt/src/org/json/JSONWriter.java new file mode 120000 index 0000000..b904c5a --- /dev/null +++ b/gwt/src/org/json/JSONWriter.java @@ -0,0 +1 @@ +../../../../java/ext/json/src/org/json/JSONWriter.java \ No newline at end of file diff --git a/gwt/startWebServer b/gwt/startWebServer new file mode 100755 index 0000000..91e3577 --- /dev/null +++ b/gwt/startWebServer @@ -0,0 +1 @@ +cd war && python -m SimpleHTTPServer diff --git a/gwt/war/WEB-INF/lib/gwt-servlet.jar b/gwt/war/WEB-INF/lib/gwt-servlet.jar new file mode 100644 index 0000000..b154974 Binary files /dev/null and b/gwt/war/WEB-INF/lib/gwt-servlet.jar differ diff --git a/gwt/war/web.xml b/gwt/war/web.xml new file mode 100644 index 0000000..3937200 --- /dev/null +++ b/gwt/war/web.xml @@ -0,0 +1,15 @@ + + + + + + + + Mailiverse_GWT.html + + +