summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--archive/src/main/java/java/util/zip/Deflater.java14
-rw-r--r--archive/src/main/java/java/util/zip/ZipFile.java60
-rw-r--r--archive/src/main/native/java_util_zip_Adler32.c9
-rw-r--r--archive/src/main/native/java_util_zip_CRC32.c8
-rw-r--r--archive/src/main/native/java_util_zip_Deflater.c25
-rw-r--r--archive/src/main/native/java_util_zip_Inflater.c27
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java35
-rw-r--r--dalvik/src/main/java/dalvik/system/DexClassLoader.java2
-rw-r--r--icu/src/main/native/BidiWrapperInterface.c44
-rw-r--r--icu/src/main/native/DecimalFormatInterface.cpp108
-rw-r--r--icu/src/main/native/ErrorCode.c62
-rw-r--r--icu/src/main/native/ErrorCode.h8
-rw-r--r--icu/src/main/native/RBNFInterface.cpp112
-rw-r--r--icu/src/main/native/RegExInterface.cpp18
-rw-r--r--icu/src/main/native/ResourceInterface.cpp26
-rw-r--r--luni-kernel/src/main/java/java/lang/Package.java5
-rw-r--r--luni-kernel/src/main/java/java/lang/ref/Reference.java8
-rw-r--r--luni-kernel/src/main/native/java_lang_ProcessManager.c3
-rw-r--r--luni/src/main/java/java/io/FileInputStream.java46
-rw-r--r--luni/src/main/java/java/util/ArrayList.java818
-rw-r--r--luni/src/main/java/java/util/Formatter.java79
-rw-r--r--luni/src/main/java/java/util/HashMap.java2
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java17
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java3
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java171
-rw-r--r--luni/src/main/native/java_net_InetAddress.cpp81
-rw-r--r--luni/src/main/native/java_net_NetworkInterface.c38
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp790
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp10
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp283
-rw-r--r--luni/src/test/java/com/google/coretests/CoreTestRunner.java49
-rw-r--r--luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java2
-rw-r--r--luni/src/test/java/tests/api/java/io/FileTest.java3
-rw-r--r--luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java30
-rw-r--r--luni/src/test/java/tests/api/java/util/ArrayListTest.java91
-rw-r--r--luni/src/test/java/tests/api/java/util/FormatterTest.java30
-rw-r--r--luni/src/test/java/tests/api/java/util/TimeZoneTest.java13
-rw-r--r--math/src/main/java/java/math/BigInt.java6
-rw-r--r--nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java19
-rw-r--r--openssl/src/main/java/org/openssl/NativeBN.java3
-rw-r--r--openssl/src/main/native/BNInterface.c28
-rw-r--r--regex/src/main/java/java/util/regex/MatchResult.java67
-rw-r--r--regex/src/main/java/java/util/regex/Matcher.java752
-rw-r--r--regex/src/main/java/java/util/regex/Pattern.java355
-rw-r--r--regex/src/main/java/java/util/regex/PatternSyntaxException.java56
-rw-r--r--sql/src/main/native/sqlite_jni.c56
-rw-r--r--x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLInputStream.java10
-rw-r--r--x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl.cpp24
-rw-r--r--x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp31
-rw-r--r--x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp8
-rw-r--r--x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_common.h5
-rw-r--r--x-net/src/test/java/tests/api/javax/net/ssl/SSLServerSocketTest.java23
-rw-r--r--x-net/src/test/java/tests/api/javax/net/ssl/SSLSocketTest.java22
-rw-r--r--xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java2
-rw-r--r--xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp50
-rw-r--r--xml/src/test/java/tests/api/javax/xml/parsers/SAXParserTestSupport.java2
-rw-r--r--xml/src/test/java/tests/xml/AllTests.java1
-rw-r--r--xml/src/test/java/tests/xml/NodeTests.java47
58 files changed, 1999 insertions, 2698 deletions
diff --git a/archive/src/main/java/java/util/zip/Deflater.java b/archive/src/main/java/java/util/zip/Deflater.java
index 38771a8..ad17cf2 100644
--- a/archive/src/main/java/java/util/zip/Deflater.java
+++ b/archive/src/main/java/java/util/zip/Deflater.java
@@ -17,9 +17,6 @@
package java.util.zip;
-// BEGIN android-changed
-// import org.apache.harmony.luni.platform.OSResourcesMonitor;
-// END android-changed
/**
* This class compresses data using the <i>DEFLATE</i> algorithm (see <a
@@ -149,8 +146,7 @@ public class Deflater {
throw new IllegalArgumentException();
}
compressLevel = level;
- streamHandle = createStreamWithMemoryEnsurance(compressLevel, strategy,
- noHeader);
+ streamHandle = createStream(compressLevel, strategy, noHeader);
}
/**
@@ -495,13 +491,5 @@ public class Deflater {
return getTotalOutImpl(streamHandle);
}
- private long createStreamWithMemoryEnsurance(int level, int strategy1,
- boolean noHeader1) {
- // BEGIN android-changed
- // OSResourcesMonitor.ensurePhysicalMemoryCapacity();
- // END android-changed
- return createStream(level, strategy1, noHeader1);
- }
-
private native long createStream(int level, int strategy1, boolean noHeader1);
}
diff --git a/archive/src/main/java/java/util/zip/ZipFile.java b/archive/src/main/java/java/util/zip/ZipFile.java
index 653b2c9..b5f3678 100644
--- a/archive/src/main/java/java/util/zip/ZipFile.java
+++ b/archive/src/main/java/java/util/zip/ZipFile.java
@@ -52,12 +52,12 @@ public class ZipFile implements ZipConstants {
File fileToDeleteOnClose;
/**
- * Open zip file for read.
+ * Open ZIP file for read.
*/
public static final int OPEN_READ = 1;
/**
- * Delete zip file when closed.
+ * Delete ZIP file when closed.
*/
public static final int OPEN_DELETE = 4;
@@ -140,7 +140,7 @@ public class ZipFile implements ZipConstants {
}
/**
- * Closes this ZIP file.
+ * Closes this ZIP file. This method is idempotent.
*
* @throws IOException
* if an IOException occurs.
@@ -166,23 +166,32 @@ public class ZipFile implements ZipConstants {
}
}
+ private void checkNotClosed() {
+ if (mRaf == null) {
+ throw new IllegalStateException("Zip File closed.");
+ }
+ }
+
/**
* Returns an enumeration of the entries. The entries are listed in the
* order in which they appear in the ZIP archive.
*
* @return the enumeration of the entries.
+ * @throws IllegalStateException if this ZIP file has been closed.
*/
public Enumeration<? extends ZipEntry> entries() {
+ checkNotClosed();
+
return new Enumeration<ZipEntry>() {
private int i = 0;
public boolean hasMoreElements() {
- if (mRaf == null) throw new IllegalStateException("Zip File closed.");
+ checkNotClosed();
return i < mEntryList.size();
}
public ZipEntry nextElement() {
- if (mRaf == null) throw new IllegalStateException("Zip File closed.");
+ checkNotClosed();
if (i >= mEntryList.size())
throw new NoSuchElementException();
return (ZipEntry) mEntryList.get(i++);
@@ -197,8 +206,10 @@ public class ZipFile implements ZipConstants {
* the name of the entry in the ZIP file.
* @return a {@code ZipEntry} or {@code null} if the entry name does not
* exist in the ZIP file.
+ * @throws IllegalStateException if this ZIP file has been closed.
*/
public ZipEntry getEntry(String entryName) {
+ checkNotClosed();
if (entryName != null) {
ZipEntry ze = mFastLookup.get(entryName);
if (ze == null) ze = mFastLookup.get(entryName + "/");
@@ -215,6 +226,7 @@ public class ZipFile implements ZipConstants {
* @return an input stream of the data contained in the {@code ZipEntry}.
* @throws IOException
* if an {@code IOException} occurs.
+ * @throws IllegalStateException if this ZIP file has been closed.
*/
public InputStream getInputStream(ZipEntry entry) throws IOException {
/*
@@ -229,27 +241,25 @@ public class ZipFile implements ZipConstants {
* Create a ZipInputStream at the right part of the file.
*/
RandomAccessFile raf = mRaf;
- if (raf != null) {
- synchronized (raf) {
- // Unfortunately we don't know the entry data's start position.
- // All we have is the position of the entry's local header.
- // At position 28 we find the length of the extra data.
- // In some cases this length differs from the one coming in
- // the central header!!!
- RAFStream rafstrm = new RAFStream(raf, entry.mLocalHeaderRelOffset + 28);
- int localExtraLenOrWhatever = ler.readShortLE(rafstrm);
- // Now we need to skip the name
- // and this "extra" data or whatever it is:
- rafstrm.skip(entry.nameLen + localExtraLenOrWhatever);
- rafstrm.mLength = rafstrm.mOffset + entry.compressedSize;
- if (entry.compressionMethod == ZipEntry.DEFLATED) {
- return new InflaterInputStream(rafstrm, new Inflater(true));
- } else {
- return rafstrm;
- }
+ synchronized (raf) {
+ // Unfortunately we don't know the entry data's start position.
+ // All we have is the position of the entry's local header.
+ // At position 28 we find the length of the extra data.
+ // In some cases this length differs from the one coming in
+ // the central header!!!
+ RAFStream rafstrm = new RAFStream(raf,
+ entry.mLocalHeaderRelOffset + 28);
+ int localExtraLenOrWhatever = ler.readShortLE(rafstrm);
+ // Now we need to skip the name
+ // and this "extra" data or whatever it is:
+ rafstrm.skip(entry.nameLen + localExtraLenOrWhatever);
+ rafstrm.mLength = rafstrm.mOffset + entry.compressedSize;
+ if (entry.compressionMethod == ZipEntry.DEFLATED) {
+ return new InflaterInputStream(rafstrm, new Inflater(true));
+ } else {
+ return rafstrm;
}
}
- throw new IllegalStateException("Zip File closed");
}
/**
@@ -265,8 +275,10 @@ public class ZipFile implements ZipConstants {
* Returns the number of {@code ZipEntries} in this {@code ZipFile}.
*
* @return the number of entries in this file.
+ * @throws IllegalStateException if this ZIP file has been closed.
*/
public int size() {
+ checkNotClosed();
return mEntryList.size();
}
diff --git a/archive/src/main/native/java_util_zip_Adler32.c b/archive/src/main/native/java_util_zip_Adler32.c
index 1b02a11..0fcf549 100644
--- a/archive/src/main/native/java_util_zip_Adler32.c
+++ b/archive/src/main/native/java_util_zip_Adler32.c
@@ -25,16 +25,11 @@ Java_java_util_zip_Adler32_updateImpl (JNIEnv * env, jobject recv,
jbyteArray buf, int off, int len,
jlong crc)
{
- jbyte *b;
- jboolean isCopy;
- jlong result;
-
- b = (*env)->GetPrimitiveArrayCritical (env, buf, &isCopy);
+ jbyte* b = (*env)->GetPrimitiveArrayCritical (env, buf, NULL);
if (b == NULL) {
- throwNewOutOfMemoryError(env, "");
return 0;
}
- result = (jlong) adler32 ((uLong) crc, (Bytef *) (b + off), (uInt) len);
+ jlong result = (jlong) adler32 ((uLong) crc, (Bytef *) (b + off), (uInt) len);
(*env)->ReleasePrimitiveArrayCritical (env, buf, b, JNI_ABORT);
return result;
diff --git a/archive/src/main/native/java_util_zip_CRC32.c b/archive/src/main/native/java_util_zip_CRC32.c
index cee25e5..fe50fca 100644
--- a/archive/src/main/native/java_util_zip_CRC32.c
+++ b/archive/src/main/native/java_util_zip_CRC32.c
@@ -25,15 +25,11 @@ Java_java_util_zip_CRC32_updateImpl (JNIEnv * env, jobject recv,
jbyteArray buf, int off, int len,
jlong crc)
{
- jbyte *b;
- jlong result;
-
- b = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
+ jbyte* b = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
if (b == NULL) {
- throwNewOutOfMemoryError(env, "");
return -1;
}
- result = crc32 ((uLong) crc, (Bytef *) (b + off), (uInt) len);
+ jlong result = crc32 ((uLong) crc, (Bytef *) (b + off), (uInt) len);
((*env)->ReleasePrimitiveArrayCritical (env, buf, b, JNI_ABORT));
return result;
}
diff --git a/archive/src/main/native/java_util_zip_Deflater.c b/archive/src/main/native/java_util_zip_Deflater.c
index 2e0e268..af0bfcc 100644
--- a/archive/src/main/native/java_util_zip_Deflater.c
+++ b/archive/src/main/native/java_util_zip_Deflater.c
@@ -162,29 +162,19 @@ Java_java_util_zip_Deflater_setInputImpl (JNIEnv * env, jobject recv,
{
PORT_ACCESS_FROM_ENV (env);
- jbyte *in;
- JCLZipStream *stream;
-
- stream = (JCLZipStream *) ((IDATA) handle);
- if (stream->inaddr != NULL) /*Input has already been provided, free the old buffer */
+ JCLZipStream* stream = (JCLZipStream *) ((IDATA) handle);
+ if (stream->inaddr != NULL) {
+ /* Input has already been provided, free the old buffer. */
jclmem_free_memory (env, stream->inaddr);
+ }
stream->inaddr = jclmem_allocate_memory (env, len);
- if (stream->inaddr == NULL)
- {
- throwNewOutOfMemoryError (env, "");
- return;
- }
- in = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (in == NULL) {
- throwNewOutOfMemoryError(env, "");
+ if (stream->inaddr == NULL) {
+ throwNewOutOfMemoryError (env, "");
return;
}
- memcpy (stream->inaddr, (in + off), len);
- ((*env)->ReleasePrimitiveArrayCritical (env, buf, in, JNI_ABORT));
+ (*env)->GetByteArrayRegion(env, buf, off, len, (jbyte*) stream->inaddr);
stream->stream->next_in = (Bytef *) stream->inaddr;
stream->stream->avail_in = len;
-
- return;
}
JNIEXPORT jint JNICALL
@@ -209,7 +199,6 @@ Java_java_util_zip_Deflater_deflateImpl (JNIEnv * env, jobject recv,
sout = stream->stream->total_out;
out = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
if (out == NULL) {
- throwNewOutOfMemoryError(env, "");
return -1;
}
stream->stream->next_out = (Bytef *) out + off;
diff --git a/archive/src/main/native/java_util_zip_Inflater.c b/archive/src/main/native/java_util_zip_Inflater.c
index 4b30d4e..c04a223 100644
--- a/archive/src/main/native/java_util_zip_Inflater.c
+++ b/archive/src/main/native/java_util_zip_Inflater.c
@@ -104,29 +104,20 @@ Java_java_util_zip_Inflater_setInputImpl (JNIEnv * env, jobject recv,
{
PORT_ACCESS_FROM_ENV (env);
- jbyte *in;
- U_8 *baseAddr;
JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle);
-
- if (stream->inaddr != NULL) /*Input has already been provided, free the old buffer */
+ if (stream->inaddr != NULL) {
+ /* Input has already been provided, free the old buffer. */
jclmem_free_memory (env, stream->inaddr);
- baseAddr = jclmem_allocate_memory (env, len);
- if (baseAddr == NULL)
- {
- throwNewOutOfMemoryError (env, "");
- return;
- }
+ }
+ U_8* baseAddr = jclmem_allocate_memory (env, len);
+ if (baseAddr == NULL) {
+ throwNewOutOfMemoryError (env, "");
+ return;
+ }
stream->inaddr = baseAddr;
stream->stream->next_in = (Bytef *) baseAddr;
stream->stream->avail_in = len;
- in = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (in == NULL) {
- throwNewOutOfMemoryError(env, "");
- return;
- }
- memcpy (baseAddr, (in + off), len);
- ((*env)->ReleasePrimitiveArrayCritical (env, buf, in, JNI_ABORT));
- return;
+ (*env)->GetByteArrayRegion(env, buf, off, len, (jbyte*) baseAddr);
}
JNIEXPORT jint JNICALL
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
index b025e11..146c679 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
@@ -271,14 +271,23 @@ public class ZipFileTest extends junit.framework.TestCase {
Enumeration<? extends ZipEntry> enumeration = zfile.entries();
zfile.close();
- zfile = null;
- boolean pass = false;
+ try {
+ enumeration.nextElement();
+ fail("did not detect closed file");
+ } catch (IllegalStateException expected) {
+ }
+
try {
enumeration.hasMoreElements();
- } catch (IllegalStateException e) {
- pass = true;
+ fail("did not detect closed file");
+ } catch (IllegalStateException expected) {
+ }
+
+ try {
+ zfile.entries();
+ fail("did not detect closed file");
+ } catch (IllegalStateException expected) {
}
- assertTrue("did not detect closed jar file", pass);
}
/**
@@ -349,20 +358,15 @@ public class ZipFileTest extends junit.framework.TestCase {
method = "getEntry",
args = {java.lang.String.class}
)
- @KnownFailure("Android does not throw IllegalStateException when using "
- + "getEntry() after close().")
public void test_getEntryLjava_lang_String_Ex() throws IOException {
java.util.zip.ZipEntry zentry = zfile.getEntry("File1.txt");
assertNotNull("Could not obtain ZipEntry", zentry);
- int r;
- InputStream in;
zfile.close();
try {
- zentry = zfile.getEntry("File2.txt");
- fail("IllegalStateException expected"); // Android fails here!
+ zfile.getEntry("File2.txt");
+ fail("IllegalStateException expected");
} catch (IllegalStateException ee) {
- // expected
}
}
@@ -435,16 +439,13 @@ public class ZipFileTest extends junit.framework.TestCase {
method = "size",
args = {}
)
- @KnownFailure("IllegalStateException not thrown when using ZipFile.size() "
- + "after close().")
public void test_size() throws IOException {
assertEquals(6, zfile.size());
zfile.close();
try {
zfile.size();
- fail("IllegalStateException expected"); // Android fails here!
- } catch (IllegalStateException ee) {
- // expected
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException expected) {
}
}
diff --git a/dalvik/src/main/java/dalvik/system/DexClassLoader.java b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
index 73e6fe4..4a440b5 100644
--- a/dalvik/src/main/java/dalvik/system/DexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
@@ -114,7 +114,7 @@ public class DexClassLoader extends ClassLoader {
/* open all Zip and DEX files up front */
for (int i = 0; i < length; i++) {
- System.out.println("My path is: " + dexPathList[i]);
+ //System.out.println("My path is: " + dexPathList[i]);
File pathFile = new File(dexPathList[i]);
mFiles[i] = pathFile;
diff --git a/icu/src/main/native/BidiWrapperInterface.c b/icu/src/main/native/BidiWrapperInterface.c
index 2c6b3cd..55be7a0 100644
--- a/icu/src/main/native/BidiWrapperInterface.c
+++ b/icu/src/main/native/BidiWrapperInterface.c
@@ -43,44 +43,34 @@ JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1close
ubidi_close ((*data).pBiDi);
- if ((*data).embeddingLevels != NULL)
- free((*data).embeddingLevels);
- free(data);
+ free((*data).embeddingLevels);
+ free(data);
}
JNIEXPORT void JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setPara
(JNIEnv * env, jclass clazz, jlong pBiDi, jcharArray text, jint length,
- jbyte paraLevel, jbyteArray embeddingLevels)
+ jbyte paraLevel, jbyteArray newEmbeddingLevels)
{
- UErrorCode err = 0;
- jchar *_text = NULL;
BiDiData *data = (BiDiData *)pBiDi;
- /* Remembering old embedding levels */
- void *embLvls = (*data).embeddingLevels;
-
- _text = (*env)->GetCharArrayElements (env, text, NULL);
-
- if (embeddingLevels != NULL)
- {
- jbyte *el = (*env)->GetByteArrayElements (env, embeddingLevels, NULL);
- (*data).embeddingLevels = malloc(length);
- memcpy(((*data).embeddingLevels), el, length);
- (*env)->ReleaseByteArrayElements (env, embeddingLevels, el, 0);
- } else
- {
- (*data).embeddingLevels = NULL;
- }
+ void *oldEmbeddingLevels = (*data).embeddingLevels;
+
+ // Copy the new embedding levels from the Java heap to the native heap.
+ if (newEmbeddingLevels != NULL) {
+ (*data).embeddingLevels = malloc(length);
+ (*env)->GetByteArrayRegion(env, newEmbeddingLevels, 0, length,
+ (*data).embeddingLevels);
+ } else {
+ (*data).embeddingLevels = NULL;
+ }
+ UErrorCode err = 0;
+ jchar* _text = (*env)->GetCharArrayElements(env, text, NULL);
ubidi_setPara ((*data).pBiDi, _text, length, paraLevel,
((*data).embeddingLevels), &err);
+ (*env)->ReleaseCharArrayElements (env, text, _text, 0);
check_fail (env, err);
- /* Freeing old embedding levels */
- if (embLvls != NULL) {
- free(embLvls);
- }
-
- (*env)->ReleaseCharArrayElements (env, text, _text, 0);
+ free(oldEmbeddingLevels);
}
JNIEXPORT jlong JNICALL Java_org_apache_harmony_text_BidiWrapper_ubidi_1setLine
diff --git a/icu/src/main/native/DecimalFormatInterface.cpp b/icu/src/main/native/DecimalFormatInterface.cpp
index 7e37d6c..252ec33 100644
--- a/icu/src/main/native/DecimalFormatInterface.cpp
+++ b/icu/src/main/native/DecimalFormatInterface.cpp
@@ -29,33 +29,6 @@
#include <string.h>
#include "cutils/log.h"
-
-static UBool icuError(JNIEnv *env, UErrorCode errorcode)
-{
- const char *emsg = u_errorName(errorcode);
- jclass exception;
-
- if (U_FAILURE(errorcode)) {// errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
- switch (errorcode) {
- case U_ILLEGAL_ARGUMENT_ERROR :
- exception = env->FindClass("java/lang/IllegalArgumentException");
- break;
- case U_INDEX_OUTOFBOUNDS_ERROR :
- case U_BUFFER_OVERFLOW_ERROR :
- exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
- break;
- case U_UNSUPPORTED_ERROR :
- exception = env->FindClass("java/lang/UnsupportedOperationException");
- break;
- default :
- exception = env->FindClass("java/lang/RuntimeException");
- }
-
- return (env->ThrowNew(exception, emsg) != 0);
- }
- return 0;
-}
-
static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale,
jstring pattern) {
@@ -78,7 +51,7 @@ static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale,
env->ReleaseStringUTFChars(locale, localeChars);
// check for an error
- if ( icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
return 0;
}
@@ -115,8 +88,8 @@ static void setSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol,
// release previously allocated space
env->ReleaseStringChars(text, textChars);
- // check if an error occured
- icuError(env, status);
+ // check if an error occurred
+ icu4jni_error(env, status);
}
static jstring getSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol) {
@@ -144,7 +117,7 @@ static jstring getSymbol(JNIEnv *env, jclass clazz, jint addr, jint symbol) {
reslenneeded=unum_getSymbol(fmt, (UNumberFormatSymbol) symbol, result,
resultlength, &status);
}
- if (icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
return NULL;
}
@@ -189,7 +162,7 @@ static void setTextAttribute(JNIEnv *env, jclass clazz, jint addr, jint symbol,
env->ReleaseStringChars(text, textChars);
- icuError(env, status);
+ icu4jni_error(env, status);
}
static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr,
@@ -219,7 +192,7 @@ static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr,
(UNumberFormatTextAttribute) symbol, result, resultlength,
&status);
}
- if (icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
return NULL;
}
@@ -246,7 +219,7 @@ static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr,
env->ReleaseStringChars(pattern, pattChars);
- icuError(env, status);
+ icu4jni_error(env, status);
}
static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr,
@@ -274,7 +247,7 @@ static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr,
reslenneeded=unum_toPattern(fmt, localized, result, resultlength,
&status);
}
- if (icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
return NULL;
}
@@ -335,7 +308,7 @@ static jstring formatLong(JNIEnv *env, jclass clazz, jint addr, jlong value,
res->extract(result, reslenneeded + 1, status);
}
- if (icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
free(attrBuffer->buffer);
free(attrBuffer);
free(result);
@@ -444,7 +417,7 @@ static jstring formatDouble(JNIEnv *env, jclass clazz, jint addr, jdouble value,
res->extract(result, reslenneeded + 1, status);
}
- if (icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
free(attrBuffer->buffer);
free(attrBuffer);
free(result);
@@ -510,7 +483,7 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val
// env->ReleaseStringUTFChars(value, valueUTF);
if (scale < 0) {
- icuError(env, U_ILLEGAL_ARGUMENT_ERROR);
+ icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR);
return NULL;
}
@@ -582,7 +555,7 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val
res.extract(result, reslenneeded + 1, status);
- if (icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
if(fieldType != NULL) {
env->ReleaseStringUTFChars(fieldType, fieldName);
}
@@ -671,28 +644,12 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val
static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text,
jobject position) {
-
- const char * textUTF = env->GetStringUTFChars(text, NULL);
- env->ReleaseStringUTFChars(text, textUTF);
-
- const char * parsePositionClassName = "java/text/ParsePosition";
- const char * longClassName = "java/lang/Long";
- const char * doubleClassName = "java/lang/Double";
- const char * bigDecimalClassName = "java/math/BigDecimal";
- const char * bigIntegerClassName = "java/math/BigInteger";
-
- UErrorCode status = U_ZERO_ERROR;
-
- UNumberFormat *fmt = (UNumberFormat *)(int)addr;
-
- jchar *str = (UChar *)env->GetStringChars(text, NULL);
- int strlength = env->GetStringLength(text);
-
- jclass parsePositionClass = env->FindClass(parsePositionClassName);
- jclass longClass = env->FindClass(longClassName);
- jclass doubleClass = env->FindClass(doubleClassName);
- jclass bigDecimalClass = env->FindClass(bigDecimalClassName);
- jclass bigIntegerClass = env->FindClass(bigIntegerClassName);
+ // TODO: cache these?
+ jclass parsePositionClass = env->FindClass("java/text/ParsePosition");
+ jclass longClass = env->FindClass("java/lang/Long");
+ jclass doubleClass = env->FindClass("java/lang/Double");
+ jclass bigDecimalClass = env->FindClass("java/math/BigDecimal");
+ jclass bigIntegerClass = env->FindClass("java/math/BigInteger");
jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass,
"getIndex", "()I");
@@ -707,27 +664,26 @@ static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text,
jmethodID bigIntegerInitMethodID = env->GetMethodID(bigIntegerClass, "<init>", "(Ljava/lang/String;)V");
jmethodID doubleValueMethodID = env->GetMethodID(bigDecimalClass, "doubleValue", "()D");
- bool resultAssigned;
- int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL);
-
// make sure the ParsePosition is valid. Actually icu4c would parse a number
// correctly even if the parsePosition is set to -1, but since the RI fails
// for that case we have to fail too
+ int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL);
+ const int strlength = env->GetStringLength(text);
if(parsePos < 0 || parsePos > strlength) {
return NULL;
}
-
- Formattable res;
-
- const UnicodeString src((UChar*)str, strlength, strlength);
+
ParsePosition pp;
-
pp.setIndex(parsePos);
DigitList digits;
-
+
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
+ Formattable res;
+ bool resultAssigned;
+ jchar *str = (UChar *)env->GetStringChars(text, NULL);
+ const UnicodeString src((UChar*)str, strlength, strlength);
((const DecimalFormat*)fmt)->parse(src, resultAssigned, res, pp, FALSE, digits);
-
env->ReleaseStringChars(text, str);
if(pp.getErrorIndex() == -1) {
@@ -738,20 +694,14 @@ static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text,
return NULL;
}
- Formattable::Type numType;
- numType = res.getType();
+ Formattable::Type numType = res.getType();
UErrorCode fmtStatus;
double resultDouble;
long resultLong;
int64_t resultInt64;
- UnicodeString resultString;
jstring resultStr;
- int resLength;
- const char * resultUTF;
jobject resultObject1, resultObject2;
- jdouble doubleTest;
- jchar * result;
if (resultAssigned)
{
@@ -809,7 +759,7 @@ static jint cloneImpl(JNIEnv *env, jclass clazz, jint addr) {
UNumberFormat *result = unum_clone(fmt, &status);
- if(icuError(env, status) != FALSE) {
+ if(icu4jni_error(env, status) != FALSE) {
return 0;
}
diff --git a/icu/src/main/native/ErrorCode.c b/icu/src/main/native/ErrorCode.c
index b3e43cd..94c4239 100644
--- a/icu/src/main/native/ErrorCode.c
+++ b/icu/src/main/native/ErrorCode.c
@@ -8,50 +8,32 @@
*/
#include "ErrorCode.h"
-
-/* private data members ----------------------------------------------------*/
-
-/**
-* Name of the java runtime exception classes
-*/
-#define ILLEGALARGUMENTEXCEPTION_ "java/lang/IllegalArgumentException"
-#define ARRAYINDEXOUTOFBOUNDSEXCEPTION_ "java/lang/ArrayIndexOutOfBoundsException"
-#define UNSUPPORTEDOPERATIONEXCEPTION_ "java/lang/UnsupportedOperationException"
-#define RUNTIMEEXCEPTION_ "java/lang/RuntimeException"
-
-/* public methods ---------------------------------------------------------*/
+#include "JNIHelp.h"
/**
-* Checks if an error has occured.
-* Throws a generic Java RuntimeException if an error has occured.
-* @param env JNI environment variable
-* @param errorcode code to determine if it is an erro
-* @return 0 if errorcode is not an error, 1 if errorcode is an error, but the
+* Checks if an error has occurred, throwing a suitable exception if so.
+* @param env JNI environment
+* @param errorCode code to determine if it is an error
+* @return 0 if errorCode is not an error, 1 if errorCode is an error, but the
* creation of the exception to be thrown fails
-* @exception thrown if errorcode represents an error
+ * @exception thrown if errorCode represents an error
*/
-UBool icu4jni_error(JNIEnv *env, UErrorCode errorcode)
+UBool icu4jni_error(JNIEnv *env, UErrorCode errorCode)
{
- const char *emsg = u_errorName(errorcode);
- jclass exception;
-
- if (errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
- switch (errorcode) {
- case U_ILLEGAL_ARGUMENT_ERROR :
- exception = (*env)->FindClass(env, ILLEGALARGUMENTEXCEPTION_);
- break;
- case U_INDEX_OUTOFBOUNDS_ERROR :
- case U_BUFFER_OVERFLOW_ERROR :
- exception = (*env)->FindClass(env, ARRAYINDEXOUTOFBOUNDSEXCEPTION_);
- break;
- case U_UNSUPPORTED_ERROR :
- exception = (*env)->FindClass(env, UNSUPPORTEDOPERATIONEXCEPTION_);
- break;
- default :
- exception = (*env)->FindClass(env, RUNTIMEEXCEPTION_);
+ const char* message = u_errorName(errorCode);
+ if (errorCode <= U_ZERO_ERROR || errorCode >= U_ERROR_LIMIT) {
+ return 0;
+ }
+
+ switch (errorCode) {
+ case U_ILLEGAL_ARGUMENT_ERROR:
+ return jniThrowException(env, "java/lang/IllegalArgumentException", message);
+ case U_INDEX_OUTOFBOUNDS_ERROR:
+ case U_BUFFER_OVERFLOW_ERROR:
+ return jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", message);
+ case U_UNSUPPORTED_ERROR:
+ return jniThrowException(env, "java/lang/UnsupportedOperationException", message);
+ default:
+ return jniThrowException(env, "java/lang/RuntimeException", message);
}
-
- return ((*env)->ThrowNew(env, exception, emsg) != 0);
- }
- return 0;
}
diff --git a/icu/src/main/native/ErrorCode.h b/icu/src/main/native/ErrorCode.h
index a5bbfc6..e42a519 100644
--- a/icu/src/main/native/ErrorCode.h
+++ b/icu/src/main/native/ErrorCode.h
@@ -13,6 +13,10 @@
#include "unicode/utypes.h"
#include "unicode/putil.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* Checks if an error has occured.
* Throws a generic Java RuntimeException if an error has occured.
@@ -24,4 +28,8 @@
*/
UBool icu4jni_error(JNIEnv *env, UErrorCode errorcode);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/icu/src/main/native/RBNFInterface.cpp b/icu/src/main/native/RBNFInterface.cpp
index d9bf460..c7486e1 100644
--- a/icu/src/main/native/RBNFInterface.cpp
+++ b/icu/src/main/native/RBNFInterface.cpp
@@ -25,32 +25,6 @@
#include <stdlib.h>
#include <string.h>
-static UBool icuError(JNIEnv *env, UErrorCode errorcode)
-{
- const char *emsg = u_errorName(errorcode);
- jclass exception;
-
- if (errorcode > U_ZERO_ERROR && errorcode < U_ERROR_LIMIT) {
- switch (errorcode) {
- case U_ILLEGAL_ARGUMENT_ERROR :
- exception = env->FindClass("java/lang/IllegalArgumentException");
- break;
- case U_INDEX_OUTOFBOUNDS_ERROR :
- case U_BUFFER_OVERFLOW_ERROR :
- exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
- break;
- case U_UNSUPPORTED_ERROR :
- exception = env->FindClass("java/lang/UnsupportedOperationException");
- break;
- default :
- exception = env->FindClass("java/lang/RuntimeException");
- }
-
- return (env->ThrowNew(exception, emsg) != 0);
- }
- return 0;
-}
-
static jint openRBNFImpl1(JNIEnv* env, jclass clazz,
jint type, jstring locale) {
@@ -72,7 +46,7 @@ static jint openRBNFImpl1(JNIEnv* env, jclass clazz,
} else if(type == 3) {
style = URBNF_COUNT;
} else {
- icuError(env, U_ILLEGAL_ARGUMENT_ERROR);
+ icu4jni_error(env, U_ILLEGAL_ARGUMENT_ERROR);
}
Locale loc = Locale::createFromName(localeChars);
@@ -84,7 +58,7 @@ static jint openRBNFImpl1(JNIEnv* env, jclass clazz,
env->ReleaseStringUTFChars(locale, localeChars);
// check for an error
- if ( icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
return 0;
}
@@ -117,7 +91,7 @@ static jint openRBNFImpl2(JNIEnv* env, jclass clazz,
env->ReleaseStringUTFChars(locale, localeChars);
// check for an error
- if ( icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
return 0;
}
@@ -183,7 +157,7 @@ static jstring formatLongRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jlong va
res.extract(result, reslenneeded + 1, status);
}
- if (icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
free(result);
return NULL;
}
@@ -245,7 +219,7 @@ static jstring formatDoubleRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jdoubl
res.extract(result, reslenneeded + 1, status);
}
- if (icuError(env, status) != FALSE) {
+ if (icu4jni_error(env, status) != FALSE) {
free(result);
return NULL;
}
@@ -265,22 +239,11 @@ static jobject parseRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jstring text,
jobject position, jboolean lenient) {
// LOGI("ENTER parseRBNFImpl");
-
- const char * parsePositionClassName = "java/text/ParsePosition";
- const char * longClassName = "java/lang/Long";
- const char * doubleClassName = "java/lang/Double";
-
-
- UErrorCode status = U_ZERO_ERROR;
-
- UNumberFormat *fmt = (UNumberFormat *)(int)addr;
-
- jchar *str = (UChar *)env->GetStringChars(text, NULL);
- int strlength = env->GetStringLength(text);
-
- jclass parsePositionClass = env->FindClass(parsePositionClassName);
- jclass longClass = env->FindClass(longClassName);
- jclass doubleClass = env->FindClass(doubleClassName);
+
+ // TODO: cache these?
+ jclass parsePositionClass = env->FindClass("java/text/ParsePosition");
+ jclass longClass = env->FindClass("java/lang/Long");
+ jclass doubleClass = env->FindClass("java/lang/Double");
jmethodID getIndexMethodID = env->GetMethodID(parsePositionClass,
"getIndex", "()I");
@@ -292,22 +255,25 @@ static jobject parseRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jstring text,
jmethodID longInitMethodID = env->GetMethodID(longClass, "<init>", "(J)V");
jmethodID dblInitMethodID = env->GetMethodID(doubleClass, "<init>", "(D)V");
- int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL);
-
// make sure the ParsePosition is valid. Actually icu4c would parse a number
// correctly even if the parsePosition is set to -1, but since the RI fails
// for that case we have to fail too
+ int parsePos = env->CallIntMethod(position, getIndexMethodID, NULL);
+ const int strlength = env->GetStringLength(text);
if(parsePos < 0 || parsePos > strlength) {
return NULL;
}
-
+
Formattable res;
-
+
+ jchar *str = (UChar *)env->GetStringChars(text, NULL);
+
const UnicodeString src((UChar*)str, strlength, strlength);
ParsePosition pp;
pp.setIndex(parsePos);
+ UNumberFormat *fmt = (UNumberFormat *)(int)addr;
if(lenient) {
unum_setAttribute(fmt, UNUM_LENIENT_PARSE, JNI_TRUE);
}
@@ -328,35 +294,23 @@ static jobject parseRBNFImpl(JNIEnv *env, jclass clazz, jint addr, jstring text,
return NULL;
}
- Formattable::Type numType;
- numType = res.getType();
- UErrorCode fmtStatus;
-
- double resultDouble;
- long resultLong;
- int64_t resultInt64;
-
- switch(numType) {
- case Formattable::kDouble:
- resultDouble = res.getDouble();
- env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
- return env->NewObject(doubleClass, dblInitMethodID,
- (jdouble) resultDouble);
- case Formattable::kLong:
- resultLong = res.getLong();
- env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
- return env->NewObject(longClass, longInitMethodID,
- (jlong) resultLong);
- case Formattable::kInt64:
- resultInt64 = res.getInt64();
- env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
- return env->NewObject(longClass, longInitMethodID,
- (jlong) resultInt64);
- default:
- break;
+ Formattable::Type numType = res.getType();
+ if (numType == Formattable::kDouble) {
+ double resultDouble = res.getDouble();
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(doubleClass, dblInitMethodID,
+ (jdouble) resultDouble);
+ } else if (numType == Formattable::kLong) {
+ long resultLong = res.getLong();
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(longClass, longInitMethodID, (jlong) resultLong);
+ } else if (numType == Formattable::kInt64) {
+ int64_t resultInt64 = res.getInt64();
+ env->CallVoidMethod(position, setIndexMethodID, (jint) parsePos);
+ return env->NewObject(longClass, longInitMethodID, (jlong) resultInt64);
+ } else {
+ return NULL;
}
-
- return NULL;
}
static JNINativeMethod gMethods[] = {
diff --git a/icu/src/main/native/RegExInterface.cpp b/icu/src/main/native/RegExInterface.cpp
index afa5cc4..0ca3d06 100644
--- a/icu/src/main/native/RegExInterface.cpp
+++ b/icu/src/main/native/RegExInterface.cpp
@@ -32,12 +32,12 @@ static jchar EMPTY_STRING = 0;
* character data it refers to (but does not have a copy of), so we can
* manage memory properly.
*/
-typedef struct RegExDataStruct {
+struct RegExData {
// A pointer to the ICU regular expression
URegularExpression* regex;
// A pointer to (a copy of) the input text that *we* manage
jchar* text;
-} RegExData;
+};
static void throwPatternSyntaxException(JNIEnv* env, UErrorCode status,
jstring pattern, UParseError error)
@@ -63,8 +63,8 @@ static void _close(JNIEnv* env, jclass clazz, RegExData* data)
uregex_close(data->regex);
}
- if (data->text != NULL && data->text != &EMPTY_STRING) {
- free(data->text);
+ if (data->text != &EMPTY_STRING) {
+ delete[] data->text;
}
free(data);
@@ -125,8 +125,8 @@ static void setText(JNIEnv* env, jclass clazz, RegExData* data, jstring text)
return;
}
- if (data->text != NULL && data->text != &EMPTY_STRING) {
- free(data->text);
+ if (data->text != &EMPTY_STRING) {
+ delete[] data->text;
data->text = NULL;
}
@@ -134,11 +134,9 @@ static void setText(JNIEnv* env, jclass clazz, RegExData* data, jstring text)
if (textLen == 0) {
data->text = &EMPTY_STRING;
} else {
- jchar const * textRaw = env->GetStringChars(text, NULL);
- data->text = (jchar*)malloc((textLen + 1) * sizeof(jchar));
- memcpy(data->text, textRaw, textLen * sizeof(jchar));
+ data->text = new jchar[textLen + 1];
+ env->GetStringRegion(text, 0, textLen, data->text);
data->text[textLen] = 0;
- env->ReleaseStringChars(text, textRaw);
}
uregex_setText(data->regex, data->text, textLen, &status);
diff --git a/icu/src/main/native/ResourceInterface.cpp b/icu/src/main/native/ResourceInterface.cpp
index a88e15c..731cf3f 100644
--- a/icu/src/main/native/ResourceInterface.cpp
+++ b/icu/src/main/native/ResourceInterface.cpp
@@ -40,32 +40,6 @@
jclass string_class;
-static UBool icuError(JNIEnv *env, UErrorCode errorcode)
-{
- const char *emsg = u_errorName(errorcode);
- jclass exception;
-
- if (U_FAILURE(errorcode)) {
- switch (errorcode) {
- case U_ILLEGAL_ARGUMENT_ERROR :
- exception = env->FindClass("java/lang/IllegalArgumentException");
- break;
- case U_INDEX_OUTOFBOUNDS_ERROR :
- case U_BUFFER_OVERFLOW_ERROR :
- exception = env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
- break;
- case U_UNSUPPORTED_ERROR :
- exception = env->FindClass("java/lang/UnsupportedOperationException");
- break;
- default :
- exception = env->FindClass("java/lang/RuntimeException");
- }
-
- return (env->ThrowNew(exception, emsg) != 0);
- }
- return 0;
-}
-
static Locale getLocale(JNIEnv *env, jstring locale) {
const char *name = env->GetStringUTFChars(locale, NULL);
Locale result = Locale::createFromName(name);
diff --git a/luni-kernel/src/main/java/java/lang/Package.java b/luni-kernel/src/main/java/java/lang/Package.java
index 2817404..4d98959 100644
--- a/luni-kernel/src/main/java/java/lang/Package.java
+++ b/luni-kernel/src/main/java/java/lang/Package.java
@@ -268,8 +268,8 @@ public class Package implements AnnotatedElement {
*/
public boolean isCompatibleWith(String version)
throws NumberFormatException {
- String[] requested = version.split(".");
- String[] provided = specVersion.split(".");
+ String[] requested = version.split("\\.");
+ String[] provided = specVersion.split("\\.");
for (int i = 0; i < Math.min(requested.length, provided.length); i++) {
int reqNum = Integer.parseInt(requested[i]);
@@ -318,4 +318,3 @@ public class Package implements AnnotatedElement {
return "package " + name;
}
}
-
diff --git a/luni-kernel/src/main/java/java/lang/ref/Reference.java b/luni-kernel/src/main/java/java/lang/ref/Reference.java
index ca7290b..c695830 100644
--- a/luni-kernel/src/main/java/java/lang/ref/Reference.java
+++ b/luni-kernel/src/main/java/java/lang/ref/Reference.java
@@ -49,7 +49,7 @@ public abstract class Reference<T> {
* VM requirement: this field <em>must</em> be called "referent"
* and be an object.
*/
- T referent;
+ volatile T referent;
/**
* If non-null, the queue on which this reference will be enqueued
@@ -58,7 +58,7 @@ public abstract class Reference<T> {
* and be a java.lang.ref.ReferenceQueue.
*/
@SuppressWarnings("unchecked")
- ReferenceQueue queue;
+ volatile ReferenceQueue queue;
/**
* Used internally by java.lang.ref.ReferenceQueue.
@@ -66,7 +66,7 @@ public abstract class Reference<T> {
* and be a java.lang.ref.Reference.
*/
@SuppressWarnings("unchecked")
- Reference queueNext;
+ volatile Reference queueNext;
/**
* Used internally by Dalvik.
@@ -74,7 +74,7 @@ public abstract class Reference<T> {
* and be an int.
*/
@SuppressWarnings("unused")
- private int vmData;
+ volatile private int vmData;
/**
* Constructs a new instance of this class.
diff --git a/luni-kernel/src/main/native/java_lang_ProcessManager.c b/luni-kernel/src/main/native/java_lang_ProcessManager.c
index eaefc9f..46e78f5 100644
--- a/luni-kernel/src/main/native/java_lang_ProcessManager.c
+++ b/luni-kernel/src/main/native/java_lang_ProcessManager.c
@@ -64,8 +64,7 @@ static void java_lang_ProcessManager_close(JNIEnv* env,
jclass clazz, jobject javaDescriptor) {
int fd = (*env)->GetIntField(env, javaDescriptor, descriptorField);
if (closeNow(fd) == -1) {
- jclass ioException = (*env)->FindClass(env, "java/io/IOException");
- (*env)->ThrowNew(env, ioException, strerror(errno));
+ jniThrowIOException(env, errno);
}
}
diff --git a/luni/src/main/java/java/io/FileInputStream.java b/luni/src/main/java/java/io/FileInputStream.java
index 1243262..c236888 100644
--- a/luni/src/main/java/java/io/FileInputStream.java
+++ b/luni/src/main/java/java/io/FileInputStream.java
@@ -312,25 +312,24 @@ public class FileInputStream extends InputStream implements Closeable {
}
openCheck();
synchronized (repositioningLock) {
- // stdin requires special handling
- if (fd == FileDescriptor.in) {
- return (int) fileSystem.ttyRead(buffer, offset, count);
- }
+ // BEGIN android-changed
+ // If you only support Linux, there's nothing special about stdin.
return (int) fileSystem.read(fd.descriptor, buffer, offset, count);
+ // END android-changed
}
}
/**
* Skips {@code count} number of bytes in this stream. Subsequent
- * {@code read()}'s will not return these bytes unless {@code reset()} is
- * used. This method may perform multiple reads to read {@code count} bytes.
+ * {@code read()}s will not return these bytes unless {@code reset()} is
+ * used. If the underlying stream is unseekable, an IOException is thrown.
*
* @param count
* the number of bytes to skip.
* @return the number of bytes actually skipped.
* @throws IOException
- * if {@code count < 0}, this stream is closed or another
- * IOException occurs.
+ * if {@code count < 0}, this stream is closed or unseekable,
+ * or another IOException occurs.
*/
@Override
public long skip(long count) throws IOException {
@@ -344,29 +343,18 @@ public class FileInputStream extends InputStream implements Closeable {
throw new IOException(Msg.getString("KA013")); //$NON-NLS-1$
}
- // stdin requires special handling
- if (fd == FileDescriptor.in) {
- // Read and discard count bytes in 8k chunks
- long skipped = 0, numRead;
- int chunk = count < 8192 ? (int) count : 8192;
- byte[] buffer = new byte[chunk];
- for (long i = count / chunk; i >= 0; i--) {
- numRead = fileSystem.ttyRead(buffer, 0, chunk);
- skipped += numRead;
- if (numRead < chunk) {
- return skipped;
- }
- }
- return skipped;
- }
-
+ // BEGIN android-changed
+ // The RI doesn't treat stdin as special. It throws IOException for
+ // all non-seekable streams, so we do too. If you did want to support
+ // non-seekable streams, the best way to do it would be to recognize
+ // when lseek(2) fails with ESPIPE and call super.skip(count).
synchronized (repositioningLock) {
- final long currentPosition = fileSystem.seek(fd.descriptor, 0L,
- IFileSystem.SEEK_CUR);
- final long newPosition = fileSystem.seek(fd.descriptor,
- currentPosition + count, IFileSystem.SEEK_SET);
- return newPosition - currentPosition;
+ // Our seek returns the new offset, but we know it will throw an
+ // exception if it couldn't perform exactly the seek we asked for.
+ fileSystem.seek(fd.descriptor, count, IFileSystem.SEEK_CUR);
+ return count;
}
+ // END android-changed
}
private synchronized void openCheck() throws IOException {
diff --git a/luni/src/main/java/java/util/ArrayList.java b/luni/src/main/java/java/util/ArrayList.java
index b8c7056..7c46e89 100644
--- a/luni/src/main/java/java/util/ArrayList.java
+++ b/luni/src/main/java/java/util/ArrayList.java
@@ -15,12 +15,16 @@
* limitations under the License.
*/
+// BEGIN android-note
+// New implementation: simpler and faster than Harmony implementation.
+// BEGIN android-note
+
package java.util;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.reflect.Array;
@@ -29,37 +33,38 @@ import java.lang.reflect.Array;
* optional operations adding, removing, and replacing are supported. The
* elements can be any objects.
*
+ * @param <E> The element type of this list.
* @since 1.2
*/
-public class ArrayList<E> extends AbstractList<E> implements List<E>,
- Cloneable, Serializable, RandomAccess {
-
- private static final long serialVersionUID = 8683452581122892189L;
-
- // BEGIN android-added
- /** zero-element array */
- private static final Object[] emptyArray = new Object[0];
- // END android-added
-
- private transient int firstIndex;
+public class ArrayList<E> extends AbstractList<E>
+ implements Cloneable, Serializable, RandomAccess {
+ /**
+ * An empty array of objects (to be shared among all empty lists).
+ */
+ private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
- private transient int lastIndex;
+ /**
+ * The minimum amount by which the capacity of an ArrayList will increase.
+ * This tuning parameter controls a time-space tradeoff. This value (12)
+ * gives empirically good results and is arguably consistent with the
+ * RI's specified default initial capacity of 10: instead of 10, we start
+ * with 0 (sans allocation) and jump to 12.
+ */
+ private static final int MIN_CAPACITY_INCREMENT = 12;
- private transient E[] array;
+ /**
+ * The number of elements in this list.
+ */
+ int size;
/**
- * Constructs a new instance of {@code ArrayList} with zero capacity.
+ * The elements in this list, followed by nulls.
*/
- public ArrayList() {
- // BEGIN android-changed
- // default capacity is zero, not ten
- this(0);
- // END android-changed
- }
+ transient Object[] array;
/**
* Constructs a new instance of {@code ArrayList} with the specified
- * capacity.
+ * initial capacity.
*
* @param capacity
* the initial capacity of this {@code ArrayList}.
@@ -68,37 +73,55 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
if (capacity < 0) {
throw new IllegalArgumentException();
}
- firstIndex = lastIndex = 0;
- array = newElementArray(capacity);
+ array = (capacity == 0 ? EMPTY_OBJECT_ARRAY : new Object[capacity]);
+ }
+
+ /**
+ * Constructs a new {@code ArrayList} instance with zero initial capacity.
+ */
+ public ArrayList() {
+ array = EMPTY_OBJECT_ARRAY;
}
/**
* Constructs a new instance of {@code ArrayList} containing the elements of
- * the specified collection. The initial size of the {@code ArrayList} will
- * be 10% higher than the size of the specified collection.
+ * the specified collection.
*
* @param collection
* the collection of elements to add.
*/
public ArrayList(Collection<? extends E> collection) {
- firstIndex = 0;
- Object[] objects = collection.toArray();
- int size = objects.length;
- array = newElementArray(size + (size / 10));
- System.arraycopy(objects, 0, array, 0, size);
- lastIndex = size;
- modCount = 1;
+ Object[] a = collection.toArray();
+ if (a.getClass() != Object[].class) {
+ Object[] newArray = new Object[a.length];
+ System.arraycopy(a, 0, newArray, 0, a.length);
+ a = newArray;
+ }
+ array = a;
+ size = a.length;
}
- @SuppressWarnings("unchecked")
- private E[] newElementArray(int size) {
- // BEGIN android-added
- if (size == 0) {
- return (E[])emptyArray;
+ /**
+ * Adds the specified object at the end of this {@code ArrayList}.
+ *
+ * @param object
+ * the object to add.
+ * @return always true
+ */
+ @Override public boolean add(E object) {
+ Object[] a = array;
+ int s = size;
+ if (s == a.length) {
+ Object[] newArray = new Object[s +
+ (s < (MIN_CAPACITY_INCREMENT / 2) ?
+ MIN_CAPACITY_INCREMENT : s >> 1)];
+ System.arraycopy(a, 0, newArray, 0, s);
+ array = a = newArray;
}
- // END android-added
-
- return (E[]) new Object[size];
+ a[s] = object;
+ size = s + 1;
+ modCount++;
+ return true;
}
/**
@@ -107,164 +130,136 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* specified location. If the location is equal to the size of this
* {@code ArrayList}, the object is added at the end.
*
- * @param location
+ * @param index
* the index at which to insert the object.
* @param object
* the object to add.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || > size()}
*/
- @Override
- public void add(int location, E object) {
- int size = lastIndex - firstIndex;
- if (0 < location && location < size) {
- if (firstIndex == 0 && lastIndex == array.length) {
- growForInsert(location, 1);
- } else if ((location < size / 2 && firstIndex > 0)
- || lastIndex == array.length) {
- System.arraycopy(array, firstIndex, array, --firstIndex,
- location);
- } else {
- int index = location + firstIndex;
- System.arraycopy(array, index, array, index + 1, size
- - location);
- lastIndex++;
- }
- array[location + firstIndex] = object;
- } else if (location == 0) {
- if (firstIndex == 0) {
- growAtFront(1);
- }
- array[--firstIndex] = object;
- } else if (location == size) {
- if (lastIndex == array.length) {
- growAtEnd(1);
- }
- array[lastIndex++] = object;
- } else {
- throw new IndexOutOfBoundsException();
+ @Override public void add(int index, E object) {
+ Object[] a = array;
+ int s = size;
+ if (index > s) {
+ throwIndexOutOfBoundsException(index, s);
}
+ if (s < a.length) {
+ System.arraycopy(a, index, a, index + 1, s - index);
+ } else {
+ // assert s == a.length;
+ Object[] newArray = new Object[newCapacity(s)];
+ System.arraycopy(a, 0, newArray, 0, index);
+ System.arraycopy(a, index, newArray, index + 1, s - index);
+ array = a = newArray;
+ }
+ a[index] = object;
+ size = s + 1;
modCount++;
}
/**
- * Adds the specified object at the end of this {@code ArrayList}.
+ * This method controls the growth of ArrayList capacities. It represents
+ * a time-space tradeoff: we don't want to grow lists too frequently
+ * (which wastes time and fragments storage), but we don't want to waste
+ * too much space in unused excess capacity.
*
- * @param object
- * the object to add.
- * @return always true
+ * NOTE: This method is inlined into {@link #add(Object)} for performance.
+ * If you change the method, change it there too!
*/
- @Override
- public boolean add(E object) {
- if (lastIndex == array.length) {
- growAtEnd(1);
- }
- array[lastIndex++] = object;
- modCount++;
- return true;
+ private static int newCapacity(int currentCapacity) {
+ int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
+ MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
+ return currentCapacity + increment;
}
/**
- * Inserts the objects in the specified collection at the specified location
- * in this List. The objects are added in the order they are returned from
- * the collection's iterator.
+ * Adds the objects in the specified collection to this {@code ArrayList}.
*
- * @param location
- * the index at which to insert.
* @param collection
* the collection of objects.
* @return {@code true} if this {@code ArrayList} is modified, {@code false}
* otherwise.
- * @throws IndexOutOfBoundsException
- * when {@code location < 0 || > size()}
*/
- @Override
- public boolean addAll(int location, Collection<? extends E> collection) {
- int size = lastIndex - firstIndex;
- if (location < 0 || location > size) {
- throw new IndexOutOfBoundsException();
- }
- if (this == collection) {
- collection = (ArrayList)clone();
- }
- Object[] dumparray = collection.toArray();
- int growSize = dumparray.length;
- if (growSize == 0) {
+ @Override public boolean addAll(Collection<? extends E> collection) {
+ Object[] newPart = collection.toArray();
+ int newPartSize = newPart.length;
+ if (newPartSize == 0) {
return false;
}
-
- if (0 < location && location < size) {
- if (array.length - size < growSize) {
- growForInsert(location, growSize);
- } else if ((location < size / 2 && firstIndex > 0)
- || lastIndex > array.length - growSize) {
- int newFirst = firstIndex - growSize;
- if (newFirst < 0) {
- int index = location + firstIndex;
- System.arraycopy(array, index, array, index - newFirst,
- size - location);
- lastIndex -= newFirst;
- newFirst = 0;
- }
- System.arraycopy(array, firstIndex, array, newFirst, location);
- firstIndex = newFirst;
- } else {
- int index = location + firstIndex;
- System.arraycopy(array, index, array, index + growSize, size
- - location);
- lastIndex += growSize;
- }
- } else if (location == 0) {
- growAtFront(growSize);
- firstIndex -= growSize;
- } else if (location == size) {
- if (lastIndex > array.length - growSize) {
- growAtEnd(growSize);
- }
- lastIndex += growSize;
+ Object[] a = array;
+ int s = size;
+ int newSize = s + newPartSize; // If add overflows, arraycopy will fail
+ if (newSize > a.length) {
+ int newCapacity = newCapacity(newSize - 1); // ~33% growth room
+ Object[] newArray = new Object[newCapacity];
+ System.arraycopy(a, 0, newArray, 0, s);
+ array = a = newArray;
}
-
- System.arraycopy(dumparray, 0, this.array, location + firstIndex,
- growSize);
+ System.arraycopy(newPart, 0, a, s, newPartSize);
+ size = newSize;
modCount++;
return true;
}
/**
- * Adds the objects in the specified collection to this {@code ArrayList}.
+ * Inserts the objects in the specified collection at the specified location
+ * in this List. The objects are added in the order they are returned from
+ * the collection's iterator.
*
+ * @param index
+ * the index at which to insert.
* @param collection
* the collection of objects.
* @return {@code true} if this {@code ArrayList} is modified, {@code false}
* otherwise.
+ * @throws IndexOutOfBoundsException
+ * when {@code location < 0 || > size()}
*/
@Override
- public boolean addAll(Collection<? extends E> collection) {
- Object[] dumpArray = collection.toArray();
- if (dumpArray.length == 0) {
+ public boolean addAll(int index, Collection<? extends E> collection) {
+ Object[] newPart = collection.toArray();
+ int newPartSize = newPart.length;
+ if (newPartSize == 0) {
return false;
}
- if (dumpArray.length > array.length - lastIndex) {
- growAtEnd(dumpArray.length);
+ Object[] a = array;
+ int s = size;
+ if (index > s) {
+ throwIndexOutOfBoundsException(index, s);
}
- System.arraycopy(dumpArray, 0, this.array, lastIndex, dumpArray.length);
- lastIndex += dumpArray.length;
+ int newSize = s + newPartSize; // If add overflows, arraycopy will fail
+ if (newSize <= a.length) {
+ System.arraycopy(a, index, a, index + newPartSize, s - index);
+ } else {
+ int newCapacity = newCapacity(newSize - 1); // ~33% growth room
+ Object[] newArray = new Object[newCapacity];
+ System.arraycopy(a, 0, newArray, 0, index);
+ System.arraycopy(a, index, newArray, index + newPartSize, s-index);
+ array = a = newArray;
+ }
+ System.arraycopy(newPart, 0, a, index, newPartSize);
+ size = newSize;
modCount++;
return true;
}
+ /** This method was extracted to encourage VM to inline callers. */
+ private static void throwIndexOutOfBoundsException(int index, int size) {
+ throw new IndexOutOfBoundsException("Invalid index " + index
+ + ", size is " + size);
+ }
+
/**
* Removes all elements from this {@code ArrayList}, leaving it empty.
*
* @see #isEmpty
* @see #size
*/
- @Override
- public void clear() {
- if (firstIndex != lastIndex) {
- Arrays.fill(array, firstIndex, lastIndex, null);
- firstIndex = lastIndex = 0;
+ @Override public void clear() {
+ if (size != 0) {
+ Arrays.fill(array, 0, size, null);
+ size = 0;
modCount++;
}
}
@@ -276,45 +271,17 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* @return a shallow copy of this {@code ArrayList}
* @see java.lang.Cloneable
*/
- @Override
- @SuppressWarnings("unchecked")
- public Object clone() {
+ @Override public Object clone() {
try {
- ArrayList<E> newList = (ArrayList<E>) super.clone();
- newList.array = array.clone();
- return newList;
+ ArrayList<?> result = (ArrayList<?>) super.clone();
+ result.array = array.clone();
+ return result;
} catch (CloneNotSupportedException e) {
- return null;
+ throw new AssertionError();
}
}
/**
- * Searches this {@code ArrayList} for the specified object.
- *
- * @param object
- * the object to search for.
- * @return {@code true} if {@code object} is an element of this
- * {@code ArrayList}, {@code false} otherwise
- */
- @Override
- public boolean contains(Object object) {
- if (object != null) {
- for (int i = firstIndex; i < lastIndex; i++) {
- if (object.equals(array[i])) {
- return true;
- }
- }
- } else {
- for (int i = firstIndex; i < lastIndex; i++) {
- if (array[i] == null) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
* Ensures that after this operation the {@code ArrayList} can hold the
* specified number of elements without further growing.
*
@@ -322,145 +289,93 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* the minimum capacity asked for.
*/
public void ensureCapacity(int minimumCapacity) {
- if (array.length < minimumCapacity) {
- if (firstIndex > 0) {
- growAtFront(minimumCapacity - array.length);
- } else {
- growAtEnd(minimumCapacity - array.length);
- }
+ Object[] a = array;
+ if (a.length < minimumCapacity) {
+ Object[] newArray = new Object[minimumCapacity];
+ System.arraycopy(a, 0, newArray, 0, size);
+ array = newArray;
+ modCount++;
}
}
- @Override
- public E get(int location) {
- // BEGIN android-changed: slight performance improvement
- int _firstIndex = firstIndex;
- if (0 <= location && location < lastIndex - _firstIndex) {
- return array[_firstIndex + location];
- }
- throw new IndexOutOfBoundsException("Invalid location " + location
- + ", size is " + (lastIndex - _firstIndex));
- // END android-changed
+ @SuppressWarnings("unchecked") @Override public E get(int index) {
+ if (index >= size) {
+ throwIndexOutOfBoundsException(index, size);
+ }
+ return (E) array[index];
}
- private void growAtEnd(int required) {
- int size = lastIndex - firstIndex;
- if (firstIndex >= required - (array.length - lastIndex)) {
- int newLast = lastIndex - firstIndex;
- if (size > 0) {
- System.arraycopy(array, firstIndex, array, 0, size);
- int start = newLast < firstIndex ? firstIndex : newLast;
- Arrays.fill(array, start, array.length, null);
- }
- firstIndex = 0;
- lastIndex = newLast;
- } else {
- int increment = size / 2;
- if (required > increment) {
- increment = required;
- }
- if (increment < 12) {
- increment = 12;
- }
- E[] newArray = newElementArray(size + increment);
- if (size > 0) {
- System.arraycopy(array, firstIndex, newArray, 0, size);
- firstIndex = 0;
- lastIndex = size;
- }
- array = newArray;
- }
+ /**
+ * Returns the number of elements in this {@code ArrayList}.
+ *
+ * @return the number of elements in this {@code ArrayList}.
+ */
+ @Override public int size() {
+ return size;
+ }
+
+ @Override public boolean isEmpty() {
+ return size == 0;
}
- private void growAtFront(int required) {
- int size = lastIndex - firstIndex;
- if (array.length - lastIndex + firstIndex >= required) {
- int newFirst = array.length - size;
- if (size > 0) {
- System.arraycopy(array, firstIndex, array, newFirst, size);
- int length = firstIndex + size > newFirst ? newFirst
- : firstIndex + size;
- Arrays.fill(array, firstIndex, length, null);
+ /**
+ * Searches this {@code ArrayList} for the specified object.
+ *
+ * @param object
+ * the object to search for.
+ * @return {@code true} if {@code object} is an element of this
+ * {@code ArrayList}, {@code false} otherwise
+ */
+ @Override public boolean contains(Object object) {
+ Object[] a = array;
+ int s = size;
+ if (object != null) {
+ for (int i = 0; i < s; i++) {
+ if (object.equals(a[i])) {
+ return true;
+ }
}
- firstIndex = newFirst;
- lastIndex = array.length;
} else {
- int increment = size / 2;
- if (required > increment) {
- increment = required;
- }
- if (increment < 12) {
- increment = 12;
- }
- E[] newArray = newElementArray(size + increment);
- if (size > 0) {
- System.arraycopy(array, firstIndex, newArray, newArray.length
- - size, size);
+ for (int i = 0; i < s; i++) {
+ if (a[i] == null) {
+ return true;
+ }
}
- firstIndex = newArray.length - size;
- lastIndex = newArray.length;
- array = newArray;
}
+ return false;
}
- private void growForInsert(int location, int required) {
- int size = lastIndex - firstIndex;
- int increment = size / 2;
- if (required > increment) {
- increment = required;
- }
- if (increment < 12) {
- increment = 12;
- }
- E[] newArray = newElementArray(size + increment);
- int newFirst = increment - required;
- // Copy elements after location to the new array skipping inserted
- // elements
- System.arraycopy(array, location + firstIndex, newArray, newFirst
- + location + required, size - location);
- // Copy elements before location to the new array from firstIndex
- System.arraycopy(array, firstIndex, newArray, newFirst, location);
- firstIndex = newFirst;
- lastIndex = size + increment;
-
- array = newArray;
- }
-
- @Override
- public int indexOf(Object object) {
+ @Override public int indexOf(Object object) {
+ Object[] a = array;
+ int s = size;
if (object != null) {
- for (int i = firstIndex; i < lastIndex; i++) {
- if (object.equals(array[i])) {
- return i - firstIndex;
+ for (int i = 0; i < s; i++) {
+ if (object.equals(a[i])) {
+ return i;
}
}
} else {
- for (int i = firstIndex; i < lastIndex; i++) {
- if (array[i] == null) {
- return i - firstIndex;
+ for (int i = 0; i < s; i++) {
+ if (a[i] == null) {
+ return i;
}
}
}
return -1;
}
- @Override
- public boolean isEmpty() {
- return lastIndex == firstIndex;
- }
-
- @Override
- public int lastIndexOf(Object object) {
+ @Override public int lastIndexOf(Object object) {
+ Object[] a = array;
if (object != null) {
- for (int i = lastIndex - 1; i >= firstIndex; i--) {
- if (object.equals(array[i])) {
- return i - firstIndex;
+ for (int i = size - 1; i >= 0; i--) {
+ if (object.equals(a[i])) {
+ return i;
}
}
} else {
- for (int i = lastIndex - 1; i >= firstIndex; i--) {
- if (array[i] == null) {
- return i - firstIndex;
+ for (int i = size - 1; i >= 0; i--) {
+ if (a[i] == null) {
+ return i;
}
}
}
@@ -470,99 +385,81 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
/**
* Removes the object at the specified location from this list.
*
- * @param location
+ * @param index
* the index of the object to remove.
* @return the removed object.
* @throws IndexOutOfBoundsException
* when {@code location < 0 || >= size()}
*/
- @Override
- public E remove(int location) {
- E result;
- int size = lastIndex - firstIndex;
- if (0 <= location && location < size) {
- if (location == size - 1) {
- result = array[--lastIndex];
- array[lastIndex] = null;
- } else if (location == 0) {
- result = array[firstIndex];
- array[firstIndex++] = null;
- } else {
- int elementIndex = firstIndex + location;
- result = array[elementIndex];
- if (location < size / 2) {
- System.arraycopy(array, firstIndex, array, firstIndex + 1,
- location);
- array[firstIndex++] = null;
- } else {
- System.arraycopy(array, elementIndex + 1, array,
- elementIndex, size - location - 1);
- array[--lastIndex] = null;
- }
- }
- if (firstIndex == lastIndex) {
- firstIndex = lastIndex = 0;
- }
- } else {
- throw new IndexOutOfBoundsException();
+ @Override public E remove(int index) {
+ Object[] a = array;
+ int s = size;
+ if (index >= s) {
+ throwIndexOutOfBoundsException(index, s);
}
-
+ @SuppressWarnings("unchecked") E result = (E) a[index];
+ System.arraycopy(a, index + 1, a, index, --s - index);
+ a[s] = null; // Prevent memory leak
+ size = s;
modCount++;
return result;
}
- @Override
- public boolean remove(Object object) {
- int location = indexOf(object);
- if (location >= 0) {
- remove(location);
- return true;
+ @Override public boolean remove(Object object) {
+ Object[] a = array;
+ int s = size;
+ if (object != null) {
+ for (int i = 0; i < s; i++) {
+ if (object.equals(a[i])) {
+ System.arraycopy(a, i + 1, a, i, --s - i);
+ a[s] = null; // Prevent memory leak
+ size = s;
+ modCount++;
+ return true;
+ }
+ }
+ } else {
+ for (int i = 0; i < s; i++) {
+ if (a[i] == null) {
+ System.arraycopy(a, i + 1, a, i, --s - i);
+ a[s] = null; // Prevent memory leak
+ size = s;
+ modCount++;
+ return true;
+ }
+ }
}
return false;
}
- /**
- * Removes the objects in the specified range from the start to the end, but
- * not including the end index.
- *
- * @param start
- * the index at which to start removing.
- * @param end
- * the index one after the end of the range to remove.
- * @throws IndexOutOfBoundsException
- * when {@code start < 0, start > end} or {@code end > size()}
- */
- @Override
- protected void removeRange(int start, int end) {
- if (start >= 0 && start <= end && end <= (lastIndex - firstIndex)) {
- if (start == end) {
- return;
- }
- int size = lastIndex - firstIndex;
- if (end == size) {
- Arrays.fill(array, firstIndex + start, lastIndex, null);
- lastIndex = firstIndex + start;
- } else if (start == 0) {
- Arrays.fill(array, firstIndex, firstIndex + end, null);
- firstIndex += end;
- } else {
- System.arraycopy(array, firstIndex + end, array, firstIndex
- + start, size - end);
- int newLast = lastIndex + start - end;
- Arrays.fill(array, newLast, lastIndex, null);
- lastIndex = newLast;
- }
- modCount++;
- } else {
- throw new IndexOutOfBoundsException();
+ @Override protected void removeRange(int fromIndex, int toIndex) {
+ Object[] a = array;
+ int s = size;
+ if (fromIndex >= s) {
+ throw new IndexOutOfBoundsException("fromIndex " + fromIndex
+ + " >= size " + size);
}
+ if (toIndex > s) {
+ throw new IndexOutOfBoundsException("toIndex " + toIndex
+ + " > size " + size);
+ }
+ if (fromIndex > toIndex) {
+ throw new IndexOutOfBoundsException("fromIndex " + fromIndex
+ + " > toIndex " + toIndex);
+ }
+
+ System.arraycopy(a, toIndex, a, fromIndex, s - toIndex);
+ int rangeSize = toIndex - fromIndex;
+ Arrays.fill(a, s - rangeSize, s, null);
+ size = s - rangeSize;
+ modCount++;
}
/**
* Replaces the element at the specified location in this {@code ArrayList}
* with the specified object.
*
- * @param location
+ * @param index
* the index at which to put the specified object.
* @param object
* the object to add.
@@ -570,24 +467,14 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* @throws IndexOutOfBoundsException
* when {@code location < 0 || >= size()}
*/
- @Override
- public E set(int location, E object) {
- if (0 <= location && location < (lastIndex - firstIndex)) {
- E result = array[firstIndex + location];
- array[firstIndex + location] = object;
- return result;
+ @Override public E set(int index, E object) {
+ Object[] a = array;
+ if (index >= size) {
+ throwIndexOutOfBoundsException(index, size);
}
- throw new IndexOutOfBoundsException();
- }
-
- /**
- * Returns the number of elements in this {@code ArrayList}.
- *
- * @return the number of elements in this {@code ArrayList}.
- */
- @Override
- public int size() {
- return lastIndex - firstIndex;
+ @SuppressWarnings("unchecked") E result = (E) a[index];
+ a[index] = object;
+ return result;
}
/**
@@ -596,11 +483,10 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
*
* @return an array of the elements from this {@code ArrayList}
*/
- @Override
- public Object[] toArray() {
- int size = lastIndex - firstIndex;
- Object[] result = new Object[size];
- System.arraycopy(array, firstIndex, result, 0, size);
+ @Override public Object[] toArray() {
+ int s = size;
+ Object[] result = new Object[s];
+ System.arraycopy(array, 0, result, 0, s);
return result;
}
@@ -619,17 +505,16 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* when the type of an element in this {@code ArrayList} cannot
* be stored in the type of the specified array.
*/
- @Override
- @SuppressWarnings("unchecked")
- public <T> T[] toArray(T[] contents) {
- int size = lastIndex - firstIndex;
- if (size > contents.length) {
- Class<?> ct = contents.getClass().getComponentType();
- contents = (T[]) Array.newInstance(ct, size);
+ @Override public <T> T[] toArray(T[] contents) {
+ int s = size;
+ if (contents.length < s) {
+ @SuppressWarnings("unchecked") T[] newArray
+ = (T[]) Array.newInstance(contents.getClass().getComponentType(), s);
+ contents = newArray;
}
- System.arraycopy(array, firstIndex, contents, 0, size);
- if (size < contents.length) {
- contents[size] = null;
+ System.arraycopy(this.array, 0, contents, 0, s);
+ if (contents.length > s) {
+ contents[s] = null;
}
return contents;
}
@@ -641,37 +526,132 @@ public class ArrayList<E> extends AbstractList<E> implements List<E>,
* @see #size
*/
public void trimToSize() {
- int size = lastIndex - firstIndex;
- E[] newArray = newElementArray(size);
- System.arraycopy(array, firstIndex, newArray, 0, size);
- array = newArray;
- firstIndex = 0;
- lastIndex = array.length;
- modCount = 0;
+ int s = size;
+ if (s == array.length) {
+ return;
+ }
+ if (s == 0) {
+ array = EMPTY_OBJECT_ARRAY;
+ } else {
+ Object[] newArray = new Object[s];
+ System.arraycopy(array, 0, newArray, 0, s);
+ array = newArray;
+ }
+ modCount++;
+ }
+
+ @Override public Iterator<E> iterator() {
+ return new ArrayListIterator();
+ }
+
+ private class ArrayListIterator implements Iterator<E> {
+ /** Number of elements remaining in this iteration */
+ private int remaining = size;
+
+ /** Index of element that remove() would remove, or -1 if no such elt */
+ private int removalIndex = -1;
+
+ /** The expected modCount value */
+ private int expectedModCount = modCount;
+
+ public boolean hasNext() {
+ return remaining != 0;
+ }
+
+ @SuppressWarnings("unchecked") public E next() {
+ ArrayList<E> ourList = ArrayList.this;
+ int rem = remaining;
+ if (ourList.modCount != expectedModCount) {
+ throw new ConcurrentModificationException();
+ }
+ if (rem == 0) {
+ throw new NoSuchElementException();
+ }
+ remaining = rem - 1;
+ return (E) ourList.array[removalIndex = ourList.size - rem];
+ }
+
+ public void remove() {
+ Object[] a = array;
+ int removalIdx = removalIndex;
+ if (modCount != expectedModCount) {
+ throw new ConcurrentModificationException();
+ }
+ if (removalIdx < 0) {
+ throw new IllegalStateException();
+ }
+ System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
+ a[--size] = null; // Prevent memory leak
+ removalIndex = -1;
+ expectedModCount = ++modCount;
+ }
}
- private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField(
- "size", Integer.TYPE) }; //$NON-NLS-1$
+ @Override public int hashCode() {
+ Object[] a = array;
+ int hashCode = 1;
+ for (int i = 0, s = size; i < s; i++) {
+ Object e = a[i];
+ hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
+ }
+ return hashCode;
+ }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof List)) {
+ return false;
+ }
+ List<?> that = (List<?>) o;
+ int s = size;
+ if (that.size() != s) {
+ return false;
+ }
+ Object[] a = array;
+ if (that instanceof RandomAccess) {
+ for (int i = 0; i < s; i++) {
+ Object eThis = a[i];
+ Object ethat = that.get(i);
+ if (eThis == null ? ethat != null : !eThis.equals(ethat)) {
+ return false;
+ }
+ }
+ } else { // Argument list is not random access; use its iterator
+ Iterator<?> it = that.iterator();
+ for (int i = 0; i < s; i++) {
+ Object eThis = a[i];
+ Object eThat = it.next();
+ if (eThis == null ? eThat != null : !eThis.equals(eThat)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private static final long serialVersionUID = 8683452581122892189L;
private void writeObject(ObjectOutputStream stream) throws IOException {
- ObjectOutputStream.PutField fields = stream.putFields();
- fields.put("size", lastIndex - firstIndex); //$NON-NLS-1$
- stream.writeFields();
+ stream.defaultWriteObject();
stream.writeInt(array.length);
- Iterator<?> it = iterator();
- while (it.hasNext()) {
- stream.writeObject(it.next());
+ for (int i = 0; i < size; i++) {
+ stream.writeObject(array[i]);
}
}
- @SuppressWarnings("unchecked")
private void readObject(ObjectInputStream stream) throws IOException,
ClassNotFoundException {
- ObjectInputStream.GetField fields = stream.readFields();
- lastIndex = fields.get("size", 0); //$NON-NLS-1$
- array = newElementArray(stream.readInt());
- for (int i = 0; i < lastIndex; i++) {
- array[i] = (E) stream.readObject();
+ stream.defaultReadObject();
+ int cap = stream.readInt();
+ if (cap < size) {
+ throw new InvalidObjectException(
+ "Capacity: " + cap + " < size: " + size);
+ }
+ array = (cap == 0 ? EMPTY_OBJECT_ARRAY : new Object[cap]);
+ for (int i = 0; i < size; i++) {
+ array[i] = stream.readObject();
}
}
-}
+ }
diff --git a/luni/src/main/java/java/util/Formatter.java b/luni/src/main/java/java/util/Formatter.java
index d1dd417..3d8b94e 100644
--- a/luni/src/main/java/java/util/Formatter.java
+++ b/luni/src/main/java/java/util/Formatter.java
@@ -885,7 +885,6 @@ public final class Formatter implements Closeable, Flushable {
if (transformer == null || ! transformer.locale.equals(l)) {
transformer = new Transformer(this, l);
}
- // END android-changed
int currentObjectIndex = 0;
Object lastArgument = null;
@@ -893,12 +892,13 @@ public final class Formatter implements Closeable, Flushable {
while (formatBuffer.hasRemaining()) {
parser.reset();
FormatToken token = parser.getNextFormatToken();
- String result;
String plainText = token.getPlainText();
if (token.getConversionType() == (char) FormatToken.UNSET) {
- result = plainText;
+ outputCharSequence(plainText);
} else {
plainText = plainText.substring(0, plainText.indexOf('%'));
+ outputCharSequence(plainText);
+
Object argument = null;
if (token.requireArgument()) {
int index = token.getArgIndex() == FormatToken.UNSET ? currentObjectIndex++
@@ -908,21 +908,26 @@ public final class Formatter implements Closeable, Flushable {
lastArgument = argument;
hasLastArgumentSet = true;
}
- result = transformer.transform(token, argument);
- result = (null == result ? plainText : plainText + result);
- }
- // if output is made by formattable callback
- if (null != result) {
- try {
- out.append(result);
- } catch (IOException e) {
- lastIOException = e;
- }
+ outputCharSequence(transformer.transform(token, argument));
}
}
+ // END android-changed
return this;
}
+ // BEGIN android-added
+ // Fixes http://code.google.com/p/android/issues/detail?id=1767.
+ private void outputCharSequence(CharSequence cs) {
+ if (cs != null) {
+ try {
+ out.append(cs);
+ } catch (IOException e) {
+ lastIOException = e;
+ }
+ }
+ }
+ // END android-added
+
private Object getArgument(Object[] args, int index, FormatToken token,
Object lastArgument, boolean hasLastArgumentSet) {
if (index == FormatToken.LAST_ARGUMENT_INDEX && !hasLastArgumentSet) {
@@ -1184,13 +1189,13 @@ public final class Formatter implements Closeable, Flushable {
* Gets the formatted string according to the format token and the
* argument.
*/
- String transform(FormatToken token, Object argument) {
+ CharSequence transform(FormatToken token, Object argument) {
/* init data member to print */
this.formatToken = token;
this.arg = argument;
- String result;
+ CharSequence result;
switch (token.getConversionType()) {
case 'B':
case 'b': {
@@ -1254,7 +1259,7 @@ public final class Formatter implements Closeable, Flushable {
if (Character.isUpperCase(token.getConversionType())) {
if (null != result) {
- result = result.toUpperCase(Locale.US);
+ result = result.toString().toUpperCase(Locale.US);
}
}
return result;
@@ -1263,7 +1268,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms the Boolean argument to a formatted string.
*/
- private String transformFromBoolean() {
+ private CharSequence transformFromBoolean() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
int flags = formatToken.getFlags();
@@ -1294,7 +1299,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms the hashcode of the argument to a formatted string.
*/
- private String transformFromHashCode() {
+ private CharSequence transformFromHashCode() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
@@ -1324,7 +1329,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms the String to a formatted string.
*/
- private String transformFromString() {
+ private CharSequence transformFromString() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
int flags = formatToken.getFlags();
@@ -1374,7 +1379,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms the Character to a formatted string.
*/
- private String transformFromCharacter() {
+ private CharSequence transformFromCharacter() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
@@ -1434,7 +1439,7 @@ public final class Formatter implements Closeable, Flushable {
* Transforms percent to a formatted string. Only '-' is legal flag.
* Precision is illegal.
*/
- private String transformFromPercent() {
+ private CharSequence transformFromPercent() {
StringBuilder result = new StringBuilder("%"); //$NON-NLS-1$
int startIndex = 0;
@@ -1462,7 +1467,7 @@ public final class Formatter implements Closeable, Flushable {
* Transforms line separator to a formatted string. Any flag, the width
* or the precision is illegal.
*/
- private String transformFromLineSeparator() {
+ private CharSequence transformFromLineSeparator() {
if (formatToken.isPrecisionSet()) {
throw new IllegalFormatPrecisionException(formatToken
.getPrecision());
@@ -1492,7 +1497,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Pads characters to the formatted string.
*/
- private String padding(StringBuilder source, int startIndex) {
+ private CharSequence padding(StringBuilder source, int startIndex) {
int start = startIndex;
boolean paddingRight = formatToken
.isFlagSet(FormatToken.FLAG_MINUS);
@@ -1520,7 +1525,7 @@ public final class Formatter implements Closeable, Flushable {
width = Math.max(source.length(), width);
}
if (length >= width) {
- return source.toString();
+ return source;
}
char[] paddings = new char[width - length];
@@ -1532,13 +1537,13 @@ public final class Formatter implements Closeable, Flushable {
} else {
source.insert(start, insertString);
}
- return source.toString();
+ return source;
}
/*
* Transforms the Integer to a formatted string.
*/
- private String transformFromInteger() {
+ private CharSequence transformFromInteger() {
int startIndex = 0;
boolean isNegative = false;
StringBuilder result = new StringBuilder();
@@ -1651,7 +1656,7 @@ public final class Formatter implements Closeable, Flushable {
if (isNegative
&& formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
result = wrapParentheses(result);
- return result.toString();
+ return result;
}
if (isNegative && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
@@ -1680,7 +1685,7 @@ public final class Formatter implements Closeable, Flushable {
return result;
}
- private String transformFromSpecialNumber() {
+ private CharSequence transformFromSpecialNumber() {
String source = null;
if (!(arg instanceof Number) || arg instanceof BigDecimal) {
@@ -1713,12 +1718,12 @@ public final class Formatter implements Closeable, Flushable {
formatToken.setPrecision(FormatToken.UNSET);
formatToken.setFlags(formatToken.getFlags()
& (~FormatToken.FLAG_ZERO));
- source = padding(new StringBuilder(source), 0);
+ return padding(new StringBuilder(source), 0);
}
return source;
}
- private String transformFromNull() {
+ private CharSequence transformFromNull() {
formatToken.setFlags(formatToken.getFlags()
& (~FormatToken.FLAG_ZERO));
return padding(new StringBuilder("null"), 0); //$NON-NLS-1$
@@ -1727,7 +1732,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms a BigInteger to a formatted string.
*/
- private String transformFromBigInteger() {
+ private CharSequence transformFromBigInteger() {
int startIndex = 0;
boolean isNegative = false;
StringBuilder result = new StringBuilder();
@@ -1817,7 +1822,7 @@ public final class Formatter implements Closeable, Flushable {
if (isNegative
&& formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
result = wrapParentheses(result);
- return result.toString();
+ return result;
}
if (isNegative && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
@@ -1829,7 +1834,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms a Float,Double or BigDecimal to a formatted string.
*/
- private String transformFromFloat() {
+ private CharSequence transformFromFloat() {
StringBuilder result = new StringBuilder();
int startIndex = 0;
char currentConversionType = formatToken.getConversionType();
@@ -1883,7 +1888,7 @@ public final class Formatter implements Closeable, Flushable {
currentConversionType, arg.getClass());
}
- String specialNumberResult = transformFromSpecialNumber();
+ CharSequence specialNumberResult = transformFromSpecialNumber();
if (null != specialNumberResult) {
return specialNumberResult;
}
@@ -1896,7 +1901,7 @@ public final class Formatter implements Closeable, Flushable {
}
// output result
FloatUtil floatUtil = new FloatUtil(result, formatToken,
- (DecimalFormat) NumberFormat.getInstance(locale), arg);
+ (DecimalFormat) getNumberFormat(), arg);
floatUtil.transform(formatToken, result);
formatToken.setPrecision(FormatToken.UNSET);
@@ -1904,7 +1909,7 @@ public final class Formatter implements Closeable, Flushable {
if (getDecimalFormatSymbols().getMinusSign() == result.charAt(0)) {
if (formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
result = wrapParentheses(result);
- return result.toString();
+ return result;
}
} else {
if (formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
@@ -1933,7 +1938,7 @@ public final class Formatter implements Closeable, Flushable {
/*
* Transforms a Date to a formatted string.
*/
- private String transformFromDateTime() {
+ private CharSequence transformFromDateTime() {
int startIndex = 0;
char currentConversionType = formatToken.getConversionType();
diff --git a/luni/src/main/java/java/util/HashMap.java b/luni/src/main/java/java/util/HashMap.java
index 28978d4..f79601f 100644
--- a/luni/src/main/java/java/util/HashMap.java
+++ b/luni/src/main/java/java/util/HashMap.java
@@ -36,7 +36,7 @@ import java.io.Serializable;
* @param <V> the type of mapped values
*/
public class HashMap<K, V> extends AbstractMap<K, V>
- implements Cloneable, Serializable, Map<K, V> {
+ implements Cloneable, Serializable {
/**
* Min capacity (other than zero) for a HashMap. Must be a power of two
* greater than 1 (and less than 1 << 30).
diff --git a/luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java b/luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java
index 110a0fd..01319e1 100644
--- a/luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java
+++ b/luni/src/main/java/org/apache/harmony/luni/internal/util/ZoneInfo.java
@@ -111,12 +111,23 @@ public class ZoneInfo extends TimeZone {
// Subtract the raw offset from all offsets so it can be changed
// and affect them too.
- // Find whether there exist any observances of DST.
-
for (int i = 0; i < mGmtOffs.length; i++) {
mGmtOffs[i] -= mRawOffset;
+ }
- if (mIsDsts[i] != 0) {
+ // Is this zone still observing DST?
+ // We don't care if they've historically used it: most places have at least once.
+ // We want to know whether the last "schedule info" (the unix times in the mTransitions
+ // array) is in the future. If it is, DST is still relevant.
+ // See http://code.google.com/p/android/issues/detail?id=877.
+ // This test means that for somewhere like Morocco, which tried DST in 2009 but has
+ // no future plans (and thus no future schedule info) will report "true" from
+ // useDaylightTime at the start of 2009 but "false" at the end. This seems appropriate.
+ long currentUnixTime = System.currentTimeMillis() / 1000;
+ if (mTransitions.length > 0) {
+ // (We're really dealing with uint32_t values, so long is most convenient in Java.)
+ long latestScheduleTime = mTransitions[mTransitions.length - 1] & 0xffffffff;
+ if (currentUnixTime < latestScheduleTime) {
mUseDst = true;
}
}
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java
index 7613f0e..bee1557 100644
--- a/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java
+++ b/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java
@@ -108,10 +108,9 @@ public interface IFileSystem {
// BEGIN android-deleted
// public long ttyAvailable() throws IOException;
+ // public long ttyRead(byte[] bytes, int offset, int length) throws IOException;
// END android-deleted
- public long ttyRead(byte[] bytes, int offset, int length) throws IOException;
-
// BEGIN android-added
public int ioctlAvailable(int fileDescriptor) throws IOException;
// END android-added
diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
index 08bdac6..b7a62e2 100644
--- a/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
+++ b/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
@@ -69,7 +69,7 @@ class OSFileSystem implements IFileSystem {
* Note that this value for Windows differs from the one for the
* page size (64K and 4K respectively).
*/
- public native int getAllocGranularity() throws IOException;
+ public native int getAllocGranularity();
public boolean lock(int fileDescriptor, long start, long length, int type,
boolean waitFlag) throws IOException {
@@ -79,160 +79,71 @@ class OSFileSystem implements IFileSystem {
return result != -1;
}
- private native int unlockImpl(int fileDescriptor, long start, long length);
+ // BEGIN android-changed
+ private native void unlockImpl(int fileDescriptor, long start, long length) throws IOException;
public void unlock(int fileDescriptor, long start, long length)
throws IOException {
// Validate arguments
validateLockArgs(IFileSystem.SHARED_LOCK_TYPE, start, length);
- int result = unlockImpl(fileDescriptor, start, length);
- if (result == -1) {
- throw new IOException();
- }
+ unlockImpl(fileDescriptor, start, length);
}
- private native int fflushImpl(int fd, boolean metadata);
-
- public void fflush(int fileDescriptor, boolean metadata)
- throws IOException {
- int result = fflushImpl(fileDescriptor, metadata);
- if (result == -1) {
- throw new IOException();
- }
- }
+ public native void fflush(int fileDescriptor, boolean metadata) throws IOException;
/*
* File position seeking.
*/
-
- private native long seekImpl(int fd, long offset, int whence);
-
- public long seek(int fileDescriptor, long offset, int whence)
- throws IOException {
- long pos = seekImpl(fileDescriptor, offset, whence);
- if (pos == -1) {
- throw new IOException();
- }
- return pos;
- }
+ public native long seek(int fd, long offset, int whence) throws IOException;
/*
* Direct read/write APIs work on addresses.
*/
- private native long readDirectImpl(int fileDescriptor, int address,
- int offset, int length);
-
- public long readDirect(int fileDescriptor, int address, int offset,
- int length) throws IOException {
- long bytesRead = readDirectImpl(fileDescriptor, address, offset, length);
- if (bytesRead < -1) {
- throw new IOException();
- }
- return bytesRead;
- }
-
- private native long writeDirectImpl(int fileDescriptor, int address,
- int offset, int length);
+ public native long readDirect(int fileDescriptor, int address, int offset, int length);
- public long writeDirect(int fileDescriptor, int address, int offset,
- int length) throws IOException {
- long bytesWritten = writeDirectImpl(fileDescriptor, address, offset,
- length);
- if (bytesWritten < 0) {
- throw new IOException();
- }
- return bytesWritten;
- }
+ public native long writeDirect(int fileDescriptor, int address, int offset, int length)
+ throws IOException;
/*
* Indirect read/writes work on byte[]'s
*/
private native long readImpl(int fileDescriptor, byte[] bytes, int offset,
- int length);
+ int length) throws IOException;
public long read(int fileDescriptor, byte[] bytes, int offset, int length)
throws IOException {
if (bytes == null) {
throw new NullPointerException();
}
- long bytesRead = readImpl(fileDescriptor, bytes, offset, length);
- if (bytesRead < -1) {
- /*
- * TODO: bytesRead is never less than -1 so this code
- * does nothing?
- * The native code throws an exception in only one case
- * so perhaps this should be 'bytesRead < 0' to handle
- * any other cases. But the other cases have been
- * ignored until now so fixing this could break things
- */
- throw new IOException();
- }
- return bytesRead;
+ return readImpl(fileDescriptor, bytes, offset, length);
}
private native long writeImpl(int fileDescriptor, byte[] bytes,
- int offset, int length);
+ int offset, int length) throws IOException;
public long write(int fileDescriptor, byte[] bytes, int offset, int length)
throws IOException {
- long bytesWritten = writeImpl(fileDescriptor, bytes, offset, length);
- if (bytesWritten < 0) {
- throw new IOException();
+ if (bytes == null) {
+ throw new NullPointerException();
}
- return bytesWritten;
+ return writeImpl(fileDescriptor, bytes, offset, length);
}
+ // END android-changed
/*
* Scatter/gather calls.
*/
- public long readv(int fileDescriptor, int[] addresses, int[] offsets,
- int[] lengths, int size) throws IOException {
- long bytesRead = readvImpl(fileDescriptor, addresses, offsets, lengths,
- size);
- if (bytesRead < -1) {
- throw new IOException();
- }
- return bytesRead;
- }
+ public native long readv(int fileDescriptor, int[] addresses,
+ int[] offsets, int[] lengths, int size) throws IOException;
- private native long readvImpl(int fileDescriptor, int[] addresses,
- int[] offsets, int[] lengths, int size);
+ public native long writev(int fileDescriptor, int[] addresses, int[] offsets,
+ int[] lengths, int size) throws IOException;
- public long writev(int fileDescriptor, int[] addresses, int[] offsets,
- int[] lengths, int size) throws IOException {
- long bytesWritten = writevImpl(fileDescriptor, addresses, offsets,
- lengths, size);
- if (bytesWritten < 0) {
- throw new IOException();
- }
- return bytesWritten;
- }
-
- private native long writevImpl(int fileDescriptor, int[] addresses,
- int[] offsets, int[] lengths, int size);
-
- private native int closeImpl(int fileDescriptor);
-
- /*
- * (non-Javadoc)
- *
- * @see org.apache.harmony.luni.platform.IFileSystem#close(long)
- */
- public void close(int fileDescriptor) throws IOException {
- int rc = closeImpl(fileDescriptor);
- if (rc == -1) {
- throw new IOException();
- }
- }
-
- public void truncate(int fileDescriptor, long size) throws IOException {
- int rc = truncateImpl(fileDescriptor, size);
- if (rc < 0) {
- throw new IOException();
- }
- }
+ // BEGIN android-changed
+ public native void close(int fileDescriptor) throws IOException;
- private native int truncateImpl(int fileDescriptor, long size);
+ public native void truncate(int fileDescriptor, long size) throws IOException;
+ // END android-changed
public int open(byte[] fileName, int mode) throws FileNotFoundException {
if (fileName == null) {
@@ -254,16 +165,10 @@ class OSFileSystem implements IFileSystem {
private native int openImpl(byte[] fileName, int mode);
- public long transfer(int fileHandler, FileDescriptor socketDescriptor,
- long offset, long count) throws IOException {
- long result = transferImpl(fileHandler, socketDescriptor, offset, count);
- if (result < 0)
- throw new IOException();
- return result;
- }
-
- private native long transferImpl(int fileHandler,
- FileDescriptor socketDescriptor, long offset, long count);
+ // BEGIN android-changed
+ public native long transfer(int fd, FileDescriptor sd, long offset, long count)
+ throws IOException;
+ // END android-changed
// BEGIN android-deleted
// public long ttyAvailable() throws IOException {
@@ -277,17 +182,15 @@ class OSFileSystem implements IFileSystem {
// private native long ttyAvailableImpl();
// END android-deleted
- public long ttyRead(byte[] bytes, int offset, int length) throws IOException {
- long nChar = ttyReadImpl(bytes, offset, length);
- // BEGIN android-changed
- if (nChar < -1) {
- throw new IOException();
- }
- // END android-changed
- return nChar;
- }
-
- private native long ttyReadImpl(byte[] bytes, int offset, int length);
+ // BEGIN android-deleted
+ // public long ttyRead(byte[] bytes, int offset, int length) throws IOException {
+ // if (bytes == null) {
+ // throw new NullPointerException();
+ // }
+ // return ttyReadImpl(bytes, offset, length);
+ // }
+ // private native long ttyReadImpl(byte[] bytes, int offset, int length) throws IOException;
+ // END android-deleted
// BEGIN android-added
public native int ioctlAvailable(int fileDescriptor) throws IOException;
diff --git a/luni/src/main/native/java_net_InetAddress.cpp b/luni/src/main/native/java_net_InetAddress.cpp
index d7b4931..4e58a1f 100644
--- a/luni/src/main/native/java_net_InetAddress.cpp
+++ b/luni/src/main/native/java_net_InetAddress.cpp
@@ -24,7 +24,6 @@
#include <stdio.h>
#include <string.h>
-#include <assert.h>
#include <netdb.h>
#include <errno.h>
@@ -48,19 +47,6 @@ static jstring InetAddress_gethostname(JNIEnv* env, jobject obj)
}
}
-static void throwNullPointerException(JNIEnv* env)
-{
- const char* className = "java/lang/NullPointerException";
-
- jclass exClass = env->FindClass(className);
-
- if (exClass == NULL) {
- LOGE("Unable to find class %s", className);
- } else {
- env->ThrowNew(exClass, NULL);
- }
-}
-
#if LOG_DNS
static void logIpString(struct addrinfo* ai, const char* name)
{
@@ -208,7 +194,7 @@ jobjectArray InetAddress_getallbyname(JNIEnv* env, jobject obj,
jboolean preferIPv4Stack)
{
if (javaName == NULL) {
- throwNullPointerException(env);
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
}
@@ -247,57 +233,44 @@ static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj,
jbyteArray javaAddress)
{
if (javaAddress == NULL) {
- throwNullPointerException(env);
- return NULL;
- }
-
- size_t addrlen = env->GetArrayLength(javaAddress);
- jbyte* rawAddress = env->GetByteArrayElements(javaAddress, NULL);
- if (rawAddress == NULL) {
- throwNullPointerException(env);
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
}
// Convert the raw address bytes into a socket address structure.
- int ret = 0;
struct sockaddr_storage ss;
- struct sockaddr_in *sin = (struct sockaddr_in *) &ss;
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss;
- size_t socklen;
memset(&ss, 0, sizeof(ss));
- switch (addrlen) {
- case 4:
- socklen = sizeof(struct sockaddr_in);
- sin->sin_family = AF_INET;
- memcpy(&sin->sin_addr.s_addr, rawAddress, addrlen);
- env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
- break;
- case 16:
- socklen = sizeof(struct sockaddr_in6);
- sin6->sin6_family = AF_INET6;
- memcpy(&sin6->sin6_addr.s6_addr, rawAddress, addrlen);
- env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
- break;
- default:
- // The caller already throws an exception in this case. Don't worry
- // about it here.
- env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT);
- return NULL;
+
+ size_t socklen;
+ const size_t addressLength = env->GetArrayLength(javaAddress);
+ if (addressLength == 4) {
+ struct sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&ss);
+ sin->sin_family = AF_INET;
+ socklen = sizeof(struct sockaddr_in);
+ jbyte* dst = reinterpret_cast<jbyte*>(&sin->sin_addr.s_addr);
+ env->GetByteArrayRegion(javaAddress, 0, 4, dst);
+ } else if (addressLength == 16) {
+ struct sockaddr_in6 *sin6 = reinterpret_cast<sockaddr_in6*>(&ss);
+ sin6->sin6_family = AF_INET6;
+ socklen = sizeof(struct sockaddr_in6);
+ jbyte* dst = reinterpret_cast<jbyte*>(&sin6->sin6_addr.s6_addr);
+ env->GetByteArrayRegion(javaAddress, 0, 16, dst);
+ } else {
+ // The caller already throws an exception in this case. Don't worry
+ // about it here.
+ return NULL;
}
// Look up the host name from the IP address.
char name[NI_MAXHOST];
- if (ret == 0) {
- ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name),
- NULL, 0, NI_NAMEREQD);
- }
-
- if (ret == 0) {
- return env->NewStringUTF(name);
+ int ret = getnameinfo(reinterpret_cast<sockaddr*>(&ss), socklen,
+ name, sizeof(name), NULL, 0, NI_NAMEREQD);
+ if (ret != 0) {
+ jniThrowException(env, "java/net/UnknownHostException", gai_strerror(ret));
+ return NULL;
}
- jniThrowException(env, "java/net/UnknownHostException", gai_strerror(ret));
- return NULL;
+ return env->NewStringUTF(name);
}
/*
diff --git a/luni/src/main/native/java_net_NetworkInterface.c b/luni/src/main/native/java_net_NetworkInterface.c
index db6d503..e994aea 100644
--- a/luni/src/main/native/java_net_NetworkInterface.c
+++ b/luni/src/main/native/java_net_NetworkInterface.c
@@ -34,27 +34,7 @@
* Throws an IOException with the given message.
*/
static void throwSocketException(JNIEnv *env, const char *message) {
- jclass exClass = (*env)->FindClass(env, "java/net/SocketException");
-
- if(exClass == NULL) {
- LOGE("Unable to find class java/net/SocketException");
- } else {
- (*env)->ThrowNew(env, exClass, message);
- }
-}
-
-
-/**
- * Throws a NullPointerException.
- */
-static void throwNullPointerException(JNIEnv *env) {
- jclass exClass = (*env)->FindClass(env, "java/lang/NullPointerException");
-
- if(exClass == NULL) {
- LOGE("Unable to find class java/lang/NullPointerException");
- } else {
- (*env)->ThrowNew(env, exClass, NULL);
- }
+ jniThrowException(env, "java/net/SocketException", message);
}
/**
@@ -241,24 +221,18 @@ static char * netLookupErrorString(int anErrorNum) {
static int structInToJavaAddress(
JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
- if(java_address == NULL) {
- throwNullPointerException(env);
+ if (java_address == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
return -1;
}
- if((*env)->GetArrayLength(env, java_address) != sizeof(address->s_addr)) {
+ if ((*env)->GetArrayLength(env, java_address) != sizeof(address->s_addr)) {
jniThrowIOException(env, errno);
return -1;
}
- jbyte *java_address_bytes;
-
- java_address_bytes = (*env)->GetByteArrayElements(env, java_address, NULL);
-
- memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
-
- (*env)->ReleaseByteArrayElements(env, java_address, java_address_bytes, 0);
-
+ jbyte* src = (jbyte*)(&(address->s_addr));
+ (*env)->SetByteArrayRegion(env, java_address, 0, sizeof(address->s_addr), src);
return 0;
}
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
index 38f3d36..3e229d0 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
@@ -14,401 +14,316 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+// BEGIN android-note
+// This file corresponds to harmony's OSFileSystem.c and OSFileSystemLinux32.c.
+// It has been greatly simplified by the assumption that the underlying
+// platform is always Linux.
+// END android-note
+
/*
* Common natives supporting the file system interface.
*/
#define HyMaxPath 1024
-#define HyOpenRead 1 /* Values for HyFileOpen */
+
+/* Values for HyFileOpen */
+#define HyOpenRead 1
#define HyOpenWrite 2
#define HyOpenCreate 4
#define HyOpenTruncate 8
#define HyOpenAppend 16
#define HyOpenText 32
-
/* Use this flag with HyOpenCreate, if this flag is specified then
- * trying to create an existing file will fail
+ * trying to create an existing file will fail
*/
#define HyOpenCreateNew 64
-#define HyOpenSync 128
+#define HyOpenSync 128
#define SHARED_LOCK_TYPE 1L
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
-#include <string.h>
-#include <stdio.h>
+#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
#include <sys/sendfile.h>
#include <sys/uio.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-typedef struct socket_struct {
- int sock;
- unsigned short family;
-} socket_struct;
+// An equivalent of the glibc macro of the same name.
+// We want to hide EINTR from Java by simply retrying directly in
+// the native code. We care about all other errors, though.
+#define EINTR_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
static void convertToPlatform(char *path) {
char *pathIndex;
pathIndex = path;
while (*pathIndex != '\0') {
- if(*pathIndex == '\\') {
+ if (*pathIndex == '\\') {
*pathIndex = '/';
}
pathIndex++;
}
}
-static int
-EsTranslateOpenFlags(int flags) {
+static int EsTranslateOpenFlags(int flags) {
int realFlags = 0;
- if(flags & HyOpenAppend) {
+ if (flags & HyOpenAppend) {
realFlags |= O_APPEND;
}
- if(flags & HyOpenTruncate) {
+ if (flags & HyOpenTruncate) {
realFlags |= O_TRUNC;
}
- if(flags & HyOpenCreate) {
+ if (flags & HyOpenCreate) {
realFlags |= O_CREAT;
}
- if(flags & HyOpenCreateNew) {
+ if (flags & HyOpenCreateNew) {
realFlags |= O_EXCL | O_CREAT;
}
#ifdef O_SYNC
- if(flags & HyOpenSync) {
- realFlags |= O_SYNC;
- }
-#endif
- if(flags & HyOpenRead) {
- if(flags & HyOpenWrite) {
+ if (flags & HyOpenSync) {
+ realFlags |= O_SYNC;
+ }
+#endif
+ if (flags & HyOpenRead) {
+ if (flags & HyOpenWrite) {
return (O_RDWR | realFlags);
}
return (O_RDONLY | realFlags);
}
- if(flags & HyOpenWrite) {
+ if (flags & HyOpenWrite) {
return (O_WRONLY | realFlags);
}
return -1;
}
-/**
- * Lock the file identified by the given handle.
- * The range and lock type are given.
- */
-static jint harmony_io_lockImpl(JNIEnv * env, jobject thiz, jint handle,
- jlong start, jlong length, jint typeFlag, jboolean waitFlag) {
+// Checks whether we can safely treat the given jlong as an off_t without
+// accidental loss of precision.
+// TODO: this is bogus; we should use _FILE_OFFSET_BITS=64.
+static bool offsetTooLarge(JNIEnv* env, jlong longOffset) {
+ if (sizeof(off_t) >= sizeof(jlong)) {
+ // We're only concerned about the possibility that off_t is
+ // smaller than jlong. off_t is signed, so we don't need to
+ // worry about signed/unsigned.
+ return false;
+ }
- int rc;
- int waitMode = (waitFlag) ? F_SETLKW : F_SETLK;
- struct flock lock;
+ // TODO: use std::numeric_limits<off_t>::max() and min() when we have them.
+ assert(sizeof(off_t) == sizeof(int));
+ static const off_t off_t_max = INT_MAX;
+ static const off_t off_t_min = INT_MIN;
- memset(&lock, 0, sizeof(lock));
-
- // If start or length overflow the max values we can represent, then max them out.
- if(start > 0x7fffffffL) {
- start = 0x7fffffffL;
- }
- if(length > 0x7fffffffL) {
- length = 0x7fffffffL;
+ if (longOffset > off_t_max || longOffset < off_t_min) {
+ // "Value too large for defined data type".
+ jniThrowIOException(env, EOVERFLOW);
+ return true;
}
+ return false;
+}
+
+static jlong translateLockLength(jlong length) {
+ // FileChannel.tryLock uses Long.MAX_VALUE to mean "lock the whole
+ // file", where POSIX would use 0. We can support that special case,
+ // even for files whose actual length we can't represent. For other
+ // out of range lengths, though, we want our range checking to fire.
+ return (length == 0x7fffffffffffffffLL) ? 0 : length;
+}
+
+static struct flock flockFromStartAndLength(jlong start, jlong length) {
+ struct flock lock;
+ memset(&lock, 0, sizeof(lock));
lock.l_whence = SEEK_SET;
lock.l_start = start;
lock.l_len = length;
- if((typeFlag & SHARED_LOCK_TYPE) == SHARED_LOCK_TYPE) {
+ return lock;
+}
+
+static jint harmony_io_lockImpl(JNIEnv* env, jobject, jint handle,
+ jlong start, jlong length, jint typeFlag, jboolean waitFlag) {
+
+ length = translateLockLength(length);
+ if (offsetTooLarge(env, start) || offsetTooLarge(env, length)) {
+ return -1;
+ }
+
+ struct flock lock(flockFromStartAndLength(start, length));
+
+ if ((typeFlag & SHARED_LOCK_TYPE) == SHARED_LOCK_TYPE) {
lock.l_type = F_RDLCK;
} else {
lock.l_type = F_WRLCK;
}
- do {
- rc = fcntl(handle, waitMode, &lock);
- } while ((rc < 0) && (errno == EINTR));
-
- return (rc == -1) ? -1 : 0;
+ int waitMode = (waitFlag) ? F_SETLKW : F_SETLK;
+ return EINTR_RETRY(fcntl(handle, waitMode, &lock));
}
-/**
- * Unlocks the specified region of the file.
- */
-static jint harmony_io_unlockImpl(JNIEnv * env, jobject thiz, jint handle,
+static void harmony_io_unlockImpl(JNIEnv* env, jobject, jint handle,
jlong start, jlong length) {
- int rc;
- struct flock lock;
-
- memset(&lock, 0, sizeof(lock));
-
- // If start or length overflow the max values we can represent, then max them out.
- if(start > 0x7fffffffL) {
- start = 0x7fffffffL;
- }
- if(length > 0x7fffffffL) {
- length = 0x7fffffffL;
+ length = translateLockLength(length);
+ if (offsetTooLarge(env, start) || offsetTooLarge(env, length)) {
+ return;
}
- lock.l_whence = SEEK_SET;
- lock.l_start = start;
- lock.l_len = length;
+ struct flock lock(flockFromStartAndLength(start, length));
lock.l_type = F_UNLCK;
- do {
- rc = fcntl(handle, F_SETLKW, &lock);
- } while ((rc < 0) && (errno == EINTR));
-
- return (rc == -1) ? -1 : 0;
+ int rc = EINTR_RETRY(fcntl(handle, F_SETLKW, &lock));
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
}
/**
* Returns the granularity of the starting address for virtual memory allocation.
* (It's the same as the page size.)
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: getAllocGranularity
- * Signature: ()I
*/
-static jint harmony_io_getAllocGranularity(JNIEnv * env, jobject thiz) {
- static int allocGranularity = 0;
- if(allocGranularity == 0) {
- allocGranularity = getpagesize();
- }
+static jint harmony_io_getAllocGranularity(JNIEnv* env, jobject) {
+ static int allocGranularity = getpagesize();
return allocGranularity;
}
-/*
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: readvImpl
- * Signature: (I[J[I[I)J
- */
-static jlong harmony_io_readvImpl(JNIEnv *env, jobject thiz, jint fd,
- jintArray jbuffers, jintArray joffsets, jintArray jlengths, jint size) {
-
- jboolean bufsCopied = JNI_FALSE;
- jboolean offsetsCopied = JNI_FALSE;
- jboolean lengthsCopied = JNI_FALSE;
- jint *bufs;
- jint *offsets;
- jint *lengths;
- int i = 0;
- long totalRead = 0;
- struct iovec *vectors = (struct iovec *)malloc(size * sizeof(struct iovec));
- if(vectors == NULL) {
+static jlong harmony_io_readv(JNIEnv* env, jobject, jint fd,
+ jintArray jBuffers, jintArray jOffsets, jintArray jLengths, jint size) {
+ iovec* vectors = new iovec[size];
+ if (vectors == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "native heap");
return -1;
}
- bufs = env->GetIntArrayElements(jbuffers, &bufsCopied);
- offsets = env->GetIntArrayElements(joffsets, &offsetsCopied);
- lengths = env->GetIntArrayElements(jlengths, &lengthsCopied);
- while(i < size) {
- vectors[i].iov_base = (void *)((int)(bufs[i]+offsets[i]));
+ jint *buffers = env->GetIntArrayElements(jBuffers, NULL);
+ jint *offsets = env->GetIntArrayElements(jOffsets, NULL);
+ jint *lengths = env->GetIntArrayElements(jLengths, NULL);
+ for (int i = 0; i < size; ++i) {
+ vectors[i].iov_base = (void *)((int)(buffers[i]+offsets[i]));
vectors[i].iov_len = lengths[i];
- i++;
- }
- totalRead = readv(fd, vectors, size);
- if(bufsCopied) {
- env->ReleaseIntArrayElements(jbuffers, bufs, JNI_ABORT);
}
- if(offsetsCopied) {
- env->ReleaseIntArrayElements(joffsets, offsets, JNI_ABORT);
- }
- if(lengthsCopied) {
- env->ReleaseIntArrayElements(jlengths, lengths, JNI_ABORT);
+ long result = readv(fd, vectors, size);
+ env->ReleaseIntArrayElements(jBuffers, buffers, JNI_ABORT);
+ env->ReleaseIntArrayElements(jOffsets, offsets, JNI_ABORT);
+ env->ReleaseIntArrayElements(jLengths, lengths, JNI_ABORT);
+ delete[] vectors;
+ if (result == -1) {
+ jniThrowIOException(env, errno);
}
- free(vectors);
- return totalRead;
+ return result;
}
-/*
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: writevImpl
- * Signature: (I[J[I[I)J
- */
-static jlong harmony_io_writevImpl(JNIEnv *env, jobject thiz, jint fd,
- jintArray jbuffers, jintArray joffsets, jintArray jlengths, jint size) {
-
- jboolean bufsCopied = JNI_FALSE;
- jboolean offsetsCopied = JNI_FALSE;
- jboolean lengthsCopied = JNI_FALSE;
- jint *bufs;
- jint *offsets;
- jint *lengths;
- int i = 0;
- long totalRead = 0;
- struct iovec *vectors = (struct iovec *)malloc(size * sizeof(struct iovec));
- if(vectors == NULL) {
+static jlong harmony_io_writev(JNIEnv* env, jobject, jint fd,
+ jintArray jBuffers, jintArray jOffsets, jintArray jLengths, jint size) {
+ iovec* vectors = new iovec[size];
+ if (vectors == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "native heap");
return -1;
}
- bufs = env->GetIntArrayElements(jbuffers, &bufsCopied);
- offsets = env->GetIntArrayElements(joffsets, &offsetsCopied);
- lengths = env->GetIntArrayElements(jlengths, &lengthsCopied);
- while(i < size) {
- vectors[i].iov_base = (void *)((int)(bufs[i]+offsets[i]));
+ jint *buffers = env->GetIntArrayElements(jBuffers, NULL);
+ jint *offsets = env->GetIntArrayElements(jOffsets, NULL);
+ jint *lengths = env->GetIntArrayElements(jLengths, NULL);
+ for (int i = 0; i < size; ++i) {
+ vectors[i].iov_base = (void *)((int)(buffers[i]+offsets[i]));
vectors[i].iov_len = lengths[i];
- i++;
}
- totalRead = writev(fd, vectors, size);
- if(bufsCopied) {
- env->ReleaseIntArrayElements(jbuffers, bufs, JNI_ABORT);
- }
- if(offsetsCopied) {
- env->ReleaseIntArrayElements(joffsets, offsets, JNI_ABORT);
- }
- if(lengthsCopied) {
- env->ReleaseIntArrayElements(jlengths, lengths, JNI_ABORT);
+ long result = writev(fd, vectors, size);
+ env->ReleaseIntArrayElements(jBuffers, buffers, JNI_ABORT);
+ env->ReleaseIntArrayElements(jOffsets, offsets, JNI_ABORT);
+ env->ReleaseIntArrayElements(jLengths, lengths, JNI_ABORT);
+ delete[] vectors;
+ if (result == -1) {
+ jniThrowIOException(env, errno);
}
- free(vectors);
- return totalRead;
+ return result;
}
-/*
- * Class: org_apache_harmony_luni_platform_OSFileSystem
- * Method: transferImpl
- * Signature: (IJJ)J
- */
-static jlong harmony_io_transferImpl(JNIEnv *env, jobject thiz, jint fd,
- jobject sd, jlong offset, jlong count) {
-
- int socket;
- off_t off;
+static jlong harmony_io_transfer(JNIEnv* env, jobject, jint fd, jobject sd,
+ jlong offset, jlong count) {
- socket = jniGetFDFromFileDescriptor(env, sd);
- if(socket == 0 || socket == -1) {
+ int socket = jniGetFDFromFileDescriptor(env, sd);
+ if (socket == -1) {
return -1;
}
/* Value of offset is checked in jint scope (checked in java layer)
The conversion here is to guarantee no value lost when converting offset to off_t
*/
- off = offset;
+ off_t off = offset;
- return sendfile(socket,(int)fd,(off_t *)&off,(size_t)count);
+ ssize_t rc = sendfile(socket, fd, &off, count);
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: readDirectImpl
- * Signature: (IJI)J
- */
-static jlong harmony_io_readDirectImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_readDirect(JNIEnv* env, jobject, jint fd,
jint buf, jint offset, jint nbytes) {
- jint result;
- if(nbytes == 0) {
- return (jlong) 0;
+ if (nbytes == 0) {
+ return 0;
}
- result = read(fd, (void *) ((jint *)(buf+offset)), (int) nbytes);
- if(result == 0) {
- return (jlong) -1;
- } else {
- return (jlong) result;
+ jbyte* dst = reinterpret_cast<jbyte*>(buf + offset);
+ jlong rc = EINTR_RETRY(read(fd, dst, nbytes));
+ if (rc == 0) {
+ return -1;
}
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: writeDirectImpl
- * Signature: (IJI)J
- */
-static jlong harmony_io_writeDirectImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_writeDirect(JNIEnv* env, jobject, jint fd,
jint buf, jint offset, jint nbytes) {
-
-
- int rc = 0;
-
- /* write will just do the right thing for HYPORT_TTY_OUT and HYPORT_TTY_ERR */
- rc = write (fd, (const void *) ((jint *)(buf+offset)), (int) nbytes);
-
- if(rc == -1) {
- jniThrowException(env, "java/io/IOException", strerror(errno));
- return -2;
+ jbyte* src = reinterpret_cast<jbyte*>(buf + offset);
+ jlong rc = EINTR_RETRY(write(fd, src, nbytes));
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
}
- return (jlong) rc;
-
+ return rc;
}
-// BEGIN android-changed
-/*
- * Class: org_apache_harmony_io
- * Method: readImpl
- * Signature: (I[BII)J
- */
-static jlong harmony_io_readImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_readImpl(JNIEnv* env, jobject, jint fd,
jbyteArray byteArray, jint offset, jint nbytes) {
- jboolean isCopy;
- jbyte *bytes;
- jlong result;
-
if (nbytes == 0) {
return 0;
}
- bytes = env->GetByteArrayElements(byteArray, &isCopy);
-
- for (;;) {
- result = read(fd, (void *) (bytes + offset), (int) nbytes);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the read() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again. Note that this is different
- * from EAGAIN, which should result in this code throwing
- * an InterruptedIOException.
- */
- }
-
+ jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
+ jlong rc = EINTR_RETRY(read(fd, bytes + offset, nbytes));
env->ReleaseByteArrayElements(byteArray, bytes, 0);
- if (result == 0) {
+ if (rc == 0) {
return -1;
}
-
- if (result == -1) {
+ if (rc == -1) {
if (errno == EAGAIN) {
jniThrowException(env, "java/io/InterruptedIOException",
"Read timed out");
} else {
- jniThrowException(env, "java/io/IOException", strerror(errno));
+ jniThrowIOException(env, errno);
}
}
-
- return result;
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: writeImpl
- * Signature: (I[BII)J
- */
-static jlong harmony_io_writeImpl(JNIEnv * env, jobject thiz, jint fd,
+static jlong harmony_io_writeImpl(JNIEnv* env, jobject, jint fd,
jbyteArray byteArray, jint offset, jint nbytes) {
- jboolean isCopy;
- jbyte *bytes = env->GetByteArrayElements(byteArray, &isCopy);
- jlong result;
-
- for (;;) {
- result = write(fd, (const char *) bytes + offset, (int) nbytes);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the read() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again. Note that this is different
- * from EAGAIN, which should result in this code throwing
- * an InterruptedIOException.
- */
- }
-
+ jbyte* bytes = env->GetByteArrayElements(byteArray, NULL);
+ jlong result = EINTR_RETRY(write(fd, bytes + offset, nbytes));
env->ReleaseByteArrayElements(byteArray, bytes, JNI_ABORT);
if (result == -1) {
@@ -416,157 +331,77 @@ static jlong harmony_io_writeImpl(JNIEnv * env, jobject thiz, jint fd,
jniThrowException(env, "java/io/InterruptedIOException",
"Write timed out");
} else {
- jniThrowException(env, "java/io/IOException", strerror(errno));
+ jniThrowIOException(env, errno);
}
}
-
return result;
}
-// END android-changed
-
-/**
- * Seeks a file descriptor to a given file position.
- *
- * @param env pointer to Java environment
- * @param thiz pointer to object receiving the message
- * @param fd handle of file to be seeked
- * @param offset distance of movement in bytes relative to whence arg
- * @param whence enum value indicating from where the offset is relative
- * The valid values are defined in fsconstants.h.
- * @return the new file position from the beginning of the file, in bytes;
- * or -1 if a problem occurs.
- */
-static jlong harmony_io_seekImpl(JNIEnv * env, jobject thiz, jint fd,
- jlong offset, jint whence) {
-
- int mywhence = 0;
+static jlong harmony_io_seek(JNIEnv* env, jobject, jint fd, jlong offset,
+ jint javaWhence) {
/* Convert whence argument */
- switch (whence) {
- case 1:
- mywhence = 0;
- break;
- case 2:
- mywhence = 1;
- break;
- case 4:
- mywhence = 2;
- break;
- default:
- return -1;
+ int nativeWhence = 0;
+ switch (javaWhence) {
+ case 1:
+ nativeWhence = SEEK_SET;
+ break;
+ case 2:
+ nativeWhence = SEEK_CUR;
+ break;
+ case 4:
+ nativeWhence = SEEK_END;
+ break;
+ default:
+ return -1;
}
-
- off_t localOffset = (int) offset;
-
- if((mywhence < 0) || (mywhence > 2)) {
+ // If the offset is relative, lseek(2) will tell us whether it's too large.
+ // We're just worried about too large an absolute offset, which would cause
+ // us to lie to lseek(2).
+ if (offsetTooLarge(env, offset)) {
return -1;
}
- /* If file offsets are 32 bit, truncate the seek to that range */
- if(sizeof (off_t) < sizeof (jlong)) {
- if(offset > 0x7FFFFFFF) {
- localOffset = 0x7FFFFFFF;
- } else if(offset < -0x7FFFFFFF) {
- localOffset = -0x7FFFFFFF;
- }
+ jlong result = lseek(fd, offset, nativeWhence);
+ if (result == -1) {
+ jniThrowIOException(env, errno);
}
-
- return (jlong) lseek(fd, localOffset, mywhence);
+ return result;
}
-/**
- * Flushes a file state to disk.
- *
- * @param env pointer to Java environment
- * @param thiz pointer to object receiving the message
- * @param fd handle of file to be flushed
- * @param metadata if true also flush metadata,
- * otherwise just flush data is possible.
- * @return zero on success and -1 on failure
- *
- * Method: fflushImpl
- * Signature: (IZ)I
- */
-static jint harmony_io_fflushImpl(JNIEnv * env, jobject thiz, jint fd,
+// TODO: are we supposed to support the 'metadata' flag? (false => fdatasync.)
+static void harmony_io_fflush(JNIEnv* env, jobject, jint fd,
jboolean metadata) {
- return (jint) fsync(fd);
+ int rc = fsync(fd);
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
}
-// BEGIN android-changed
-/**
- * Closes the given file handle
- *
- * @param env pointer to Java environment
- * @param thiz pointer to object receiving the message
- * @param fd handle of file to be closed
- * @return zero on success and -1 on failure
- *
- * Class: org_apache_harmony_io
- * Method: closeImpl
- * Signature: (I)I
- */
-static jint harmony_io_closeImpl(JNIEnv * env, jobject thiz, jint fd) {
- jint result;
-
- for (;;) {
- result = (jint) close(fd);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the close() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again.
- */
+static jint harmony_io_close(JNIEnv* env, jobject, jint fd) {
+ jint rc = EINTR_RETRY(close(fd));
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
}
-
- return result;
+ return rc;
}
-// END android-changed
-
-/*
- * Class: org_apache_harmony_io
- * Method: truncateImpl
- * Signature: (IJ)I
- */
-static jint harmony_io_truncateImpl(JNIEnv * env, jobject thiz, jint fd,
- jlong size) {
-
- int rc;
- off_t length = (off_t) size;
-
- // If file offsets are 32 bit, truncate the newLength to that range
- if(sizeof (off_t) < sizeof (jlong)) {
- if(length > 0x7FFFFFFF) {
- length = 0x7FFFFFFF;
- } else if(length < -0x7FFFFFFF) {
- length = -0x7FFFFFFF;
- }
+static jint harmony_io_truncate(JNIEnv* env, jobject, jint fd, jlong length) {
+ if (offsetTooLarge(env, length)) {
+ return -1;
}
- rc = ftruncate((int)fd, length);
-
- return (jint) rc;
-
+ int rc = ftruncate(fd, length);
+ if (rc == -1) {
+ jniThrowIOException(env, errno);
+ }
+ return rc;
}
-/*
- * Class: org_apache_harmony_io
- * Method: openImpl
- * Signature: ([BI)I
- */
-static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
+static jint harmony_io_openImpl(JNIEnv* env, jobject, jbyteArray path,
jint jflags) {
-
int flags = 0;
- int mode = 0;
- jint * portFD;
- jsize length;
- char pathCopy[HyMaxPath];
+ int mode = 0;
// BEGIN android-changed
// don't want default permissions to allow global access.
@@ -588,7 +423,7 @@ static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
mode = 0600;
break;
case 256:
- flags = HyOpenWrite | HyOpenCreate | HyOpenAppend;
+ flags = HyOpenWrite | HyOpenCreate | HyOpenAppend;
mode = 0600;
break;
}
@@ -596,116 +431,56 @@ static jint harmony_io_openImpl(JNIEnv * env, jobject obj, jbyteArray path,
flags = EsTranslateOpenFlags(flags);
- length = env->GetArrayLength (path);
+ // TODO: clean this up when we clean up the java.io.File equivalent.
+ jsize length = env->GetArrayLength (path);
length = length < HyMaxPath - 1 ? length : HyMaxPath - 1;
+ char pathCopy[HyMaxPath];
env->GetByteArrayRegion (path, 0, length, (jbyte *)pathCopy);
pathCopy[length] = '\0';
convertToPlatform (pathCopy);
- int cc;
-
- if(pathCopy == NULL) {
- jniThrowException(env, "java/lang/NullPointerException", NULL);
- return -1;
- }
-
- do {
- cc = open(pathCopy, flags, mode);
- } while(cc < 0 && errno == EINTR);
-
- if(cc < 0 && errno > 0) {
+ jint cc = EINTR_RETRY(open(pathCopy, flags, mode));
+ // TODO: chase up the callers of this and check they wouldn't rather
+ // have us throw a meaningful IOException right here.
+ if (cc < 0 && errno > 0) {
cc = -errno;
}
-
return cc;
-
-
}
-// BEGIN android-deleted
-#if 0
-/*
- * Answers the number of remaining chars in the stdin.
- *
- * Class: org_apache_harmony_io
- * Method: ttyAvailableImpl
- * Signature: ()J
- */
-static jlong harmony_io_ttyAvailableImpl(JNIEnv *env, jobject thiz) {
-
- int rc;
- off_t curr, end;
-
- int avail = 0;
-
- // when redirected from a file
- curr = lseek(STDIN_FILENO, 0L, 2); /* don't use tell(), it doesn't exist on all platforms, i.e. linux */
- if(curr != -1) {
- end = lseek(STDIN_FILENO, 0L, 4);
- lseek(STDIN_FILENO, curr, 1);
- if(end >= curr) {
- return (jlong) (end - curr);
- }
- }
-
- /* ioctl doesn't work for files on all platforms (i.e. SOLARIS) */
-
- rc = ioctl (STDIN_FILENO, FIONREAD, &avail);
-
- /* 64 bit platforms use a 32 bit value, using IDATA fails on big endian */
- /* Pass in IDATA because ioctl() is device dependent, some devices may write 64 bits */
- if(rc != -1) {
- return (jlong) *(jint *) & avail;
- }
- return (jlong) 0;
-}
-#endif
-// END android-deleted
-
-// BEGIN android-added
-/*
- * Answers the number of remaining bytes in a file descriptor
- * using IOCTL.
- *
- * Class: org_apache_harmony_io
- * Method: ioctlAvailable
- * Signature: ()I
- */
-static jint harmony_io_ioctlAvailable(JNIEnv *env, jobject thiz, jint fd) {
- int avail = 0;
- int rc = ioctl(fd, FIONREAD, &avail);
-
+static jint harmony_io_ioctlAvailable(JNIEnv*env, jobject, jint fd) {
/*
* On underlying platforms Android cares about (read "Linux"),
* ioctl(fd, FIONREAD, &avail) is supposed to do the following:
- *
+ *
* If the fd refers to a regular file, avail is set to
* the difference between the file size and the current cursor.
* This may be negative if the cursor is past the end of the file.
- *
+ *
* If the fd refers to an open socket or the read end of a
* pipe, then avail will be set to a number of bytes that are
* available to be read without blocking.
- *
+ *
* If the fd refers to a special file/device that has some concept
* of buffering, then avail will be set in a corresponding way.
- *
+ *
* If the fd refers to a special device that does not have any
* concept of buffering, then the ioctl call will return a negative
* number, and errno will be set to ENOTTY.
- *
+ *
* If the fd refers to a special file masquerading as a regular file,
* then avail may be returned as negative, in that the special file
* may appear to have zero size and yet a previous read call may have
* actually read some amount of data and caused the cursor to be
* advanced.
*/
-
+ int avail = 0;
+ int rc = ioctl(fd, FIONREAD, &avail);
if (rc >= 0) {
/*
* Success, but make sure not to return a negative number (see
* above).
- */
+ */
if (avail < 0) {
avail = 0;
}
@@ -714,61 +489,10 @@ static jint harmony_io_ioctlAvailable(JNIEnv *env, jobject thiz, jint fd) {
avail = 0;
} else {
/* Something strange is happening. */
- jniThrowException(env, "java/io/IOException", strerror(errno));
- avail = 0;
- }
-
- return (jint) avail;
-}
-// END android-added
-
-/*
- * Reads the number of bytes from stdin.
- *
- * Class: org_apache_harmony_io
- * Method: ttyReadImpl
- * Signature: ([BII)J
- */
-static jlong harmony_io_ttyReadImpl(JNIEnv *env, jobject thiz,
- jbyteArray byteArray, jint offset, jint nbytes) {
-
- jboolean isCopy;
- jbyte *bytes = env->GetByteArrayElements(byteArray, &isCopy);
- jlong result;
-
- for(;;) {
-
- result = (jlong) read(STDIN_FILENO, (char *)(bytes + offset), (int) nbytes);
-
- if ((result != -1) || (errno != EINTR)) {
- break;
- }
-
- /*
- * If we didn't break above, that means that the read() call
- * returned due to EINTR. We shield Java code from this
- * possibility by trying again. Note that this is different
- * from EAGAIN, which should result in this code throwing
- * an InterruptedIOException.
- */
- }
-
- env->ReleaseByteArrayElements(byteArray, bytes, 0);
-
- if (result == 0) {
- return -1;
- }
-
- if (result == -1) {
- if (errno == EAGAIN) {
- jniThrowException(env, "java/io/InterruptedIOException",
- "Read timed out");
- } else {
- jniThrowException(env, "java/io/IOException", strerror(errno));
- }
+ jniThrowIOException(env, errno);
}
- return result;
+ return (jint) avail;
}
/*
@@ -776,32 +500,26 @@ static jlong harmony_io_ttyReadImpl(JNIEnv *env, jobject thiz,
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
+ { "close", "(I)V", (void*) harmony_io_close },
+ { "fflush", "(IZ)V", (void*) harmony_io_fflush },
+ { "getAllocGranularity","()I", (void*) harmony_io_getAllocGranularity },
+ { "ioctlAvailable", "(I)I", (void*) harmony_io_ioctlAvailable },
{ "lockImpl", "(IJJIZ)I", (void*) harmony_io_lockImpl },
- { "getAllocGranularity","()I", (void*) harmony_io_getAllocGranularity },
- { "unlockImpl", "(IJJ)I", (void*) harmony_io_unlockImpl },
- { "fflushImpl", "(IZ)I", (void*) harmony_io_fflushImpl },
- { "seekImpl", "(IJI)J", (void*) harmony_io_seekImpl },
- { "readDirectImpl", "(IIII)J", (void*) harmony_io_readDirectImpl },
- { "writeDirectImpl", "(IIII)J", (void*) harmony_io_writeDirectImpl },
+ { "openImpl", "([BI)I", (void*) harmony_io_openImpl },
+ { "readDirect", "(IIII)J", (void*) harmony_io_readDirect },
{ "readImpl", "(I[BII)J", (void*) harmony_io_readImpl },
+ { "readv", "(I[I[I[II)J",(void*) harmony_io_readv },
+ { "seek", "(IJI)J", (void*) harmony_io_seek },
+ { "transfer", "(ILjava/io/FileDescriptor;JJ)J",
+ (void*) harmony_io_transfer },
+ { "truncate", "(IJ)V", (void*) harmony_io_truncate },
+ { "unlockImpl", "(IJJ)V", (void*) harmony_io_unlockImpl },
+ { "writeDirect", "(IIII)J", (void*) harmony_io_writeDirect },
{ "writeImpl", "(I[BII)J", (void*) harmony_io_writeImpl },
- { "readvImpl", "(I[I[I[II)J",(void*) harmony_io_readvImpl },
- { "writevImpl", "(I[I[I[II)J",(void*) harmony_io_writevImpl },
- { "closeImpl", "(I)I", (void*) harmony_io_closeImpl },
- { "truncateImpl", "(IJ)I", (void*) harmony_io_truncateImpl },
- { "openImpl", "([BI)I", (void*) harmony_io_openImpl },
- { "transferImpl", "(ILjava/io/FileDescriptor;JJ)J",
- (void*) harmony_io_transferImpl },
- // BEGIN android-deleted
- //{ "ttyAvailableImpl", "()J", (void*) harmony_io_ttyAvailableImpl },
- // END android-deleted
- // BEGIN android-added
- { "ioctlAvailable", "(I)I", (void*) harmony_io_ioctlAvailable },
- // END android added
- { "ttyReadImpl", "([BII)J", (void*) harmony_io_ttyReadImpl }
+ { "writev", "(I[I[I[II)J",(void*) harmony_io_writev },
};
-int register_org_apache_harmony_luni_platform_OSFileSystem(JNIEnv *_env) {
- return jniRegisterNativeMethods(_env,
- "org/apache/harmony/luni/platform/OSFileSystem", gMethods,
- NELEM(gMethods));
+int register_org_apache_harmony_luni_platform_OSFileSystem(JNIEnv* _env) {
+ return jniRegisterNativeMethods(_env,
+ "org/apache/harmony/luni/platform/OSFileSystem", gMethods,
+ NELEM(gMethods));
}
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
index 2e814cc..b1493f8 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
@@ -144,9 +144,8 @@ static jbyte harmony_nio_getByteImpl(JNIEnv *_env, jobject _this,
*/
static void harmony_nio_getBytesImpl(JNIEnv *_env, jobject _this, jint pointer,
jbyteArray dst, jint offset, jint length) {
- jbyte *dst_ = (jbyte *)_env->GetPrimitiveArrayCritical(dst, (jboolean *)0);
- memcpy(dst_ + offset, (jbyte *)pointer, length);
- _env->ReleasePrimitiveArrayCritical(dst, dst_, 0);
+ jbyte* src = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(pointer));
+ _env->SetByteArrayRegion(dst, offset, length, src);
}
/*
@@ -166,9 +165,8 @@ static void harmony_nio_putByteImpl(JNIEnv *_env, jobject _this, jint pointer,
*/
static void harmony_nio_putBytesImpl(JNIEnv *_env, jobject _this,
jint pointer, jbyteArray src, jint offset, jint length) {
- jbyte *src_ = (jbyte *)_env->GetPrimitiveArrayCritical(src, (jboolean *)0);
- memcpy((jbyte *)pointer, src_ + offset, length);
- _env->ReleasePrimitiveArrayCritical(src, src_, JNI_ABORT);
+ jbyte* dst = reinterpret_cast<jbyte*>(static_cast<uintptr_t>(pointer));
+ _env->GetByteArrayRegion(src, offset, length, dst);
}
static void
diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index 7b6023a..fd3820b 100644
--- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -178,8 +178,6 @@ struct CachedFields {
jclass byte_class;
jmethodID byte_class_init;
jfieldID byte_class_value;
- jclass string_class;
- jmethodID string_class_init;
jclass socketimpl_class;
jfieldID socketimpl_address;
jfieldID socketimpl_port;
@@ -211,13 +209,6 @@ static void throwSocketException(JNIEnv *env, int errorCode) {
}
/**
- * Throws an IOException with the given message.
- */
-static void throwIOExceptionStr(JNIEnv *env, const char *message) {
- jniThrowException(env, "java/io/IOException", message);
-}
-
-/**
* Throws a NullPointerException.
*/
static void throwNullPointerException(JNIEnv *env) {
@@ -311,8 +302,7 @@ static bool isJavaMappedAddress(jbyte *addressBytes) {
/**
* Converts a native address structure to an InetAddress object.
* Throws a NullPointerException or an IOException in case of
- * error. This is signaled by a return value of -1. The normal
- * return value is 0.
+ * error.
*
* @param sockaddress the sockaddr_storage structure to convert
*
@@ -377,30 +367,30 @@ static void convertIpv4ToMapped(struct sockaddr_in *sin,
* @exception SocketError if the address family is unknown
*/
static int byteArrayToSocketAddress(JNIEnv *env,
- jbyteArray addressByteArray, int port, sockaddr_storage *sockaddress) {
- if (addressByteArray == NULL) {
- throwNullPointerException(env);
- return EFAULT;
+ jbyteArray addressBytes, int port, sockaddr_storage *sockaddress) {
+ if (addressBytes == NULL) {
+ throwNullPointerException(env);
+ return EFAULT;
}
- size_t addressLength = env->GetArrayLength(addressByteArray);
+ size_t addressLength = env->GetArrayLength(addressBytes);
// Convert the IP address bytes to the proper IP address type.
if (addressLength == 4) {
// IPv4 address.
- sockaddr_in *sin = (sockaddr_in *) sockaddress;
+ sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(sockaddress);
memset(sin, 0, sizeof(sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
- jbyte *rawBytes = (jbyte *) &sin->sin_addr.s_addr;
- env->GetByteArrayRegion(addressByteArray, 0, 4, rawBytes);
+ jbyte* dst = reinterpret_cast<jbyte*>(&sin->sin_addr.s_addr);
+ env->GetByteArrayRegion(addressBytes, 0, 4, dst);
} else if (addressLength == 16) {
// IPv6 address.
- sockaddr_in6 *sin6 = (sockaddr_in6 *) sockaddress;
+ sockaddr_in6 *sin6 = reinterpret_cast<sockaddr_in6*>(sockaddress);
memset(sin6, 0, sizeof(sockaddr_in6));
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
- jbyte *rawBytes = (jbyte *) &sin6->sin6_addr.s6_addr;
- env->GetByteArrayRegion(addressByteArray, 0, 16, rawBytes);
+ jbyte* dst = reinterpret_cast<jbyte*>(&sin6->sin6_addr.s6_addr);
+ env->GetByteArrayRegion(addressBytes, 0, 16, dst);
} else {
// Unknown address family.
throwSocketException(env, SOCKERR_BADAF);
@@ -419,20 +409,23 @@ static int byteArrayToSocketAddress(JNIEnv *env,
* @param port the port number
* @param sockaddress the sockaddr_storage structure to write to
*
- * @return 0 on success, -1 on failure
+ * @return 0 on success, a system error code on failure
* @throw UnknownHostException if any error occurs
*
* @exception SocketError if the address family is unknown
*/
-static int inetAddressToSocketAddress(JNIEnv *env,
- jobject inetaddress, int port, sockaddr_storage *sockaddress) {
-
+static int inetAddressToSocketAddress(JNIEnv *env, jobject inetaddress,
+ int port, sockaddr_storage *sockaddress) {
// Get the byte array that stores the IP address bytes in the InetAddress.
- jbyteArray addressByteArray;
- addressByteArray = (jbyteArray)env->GetObjectField(inetaddress,
- gCachedFields.iaddr_ipaddress);
+ if (inetaddress == NULL) {
+ throwNullPointerException(env);
+ return EFAULT;
+ }
+ jbyteArray addressBytes =
+ reinterpret_cast<jbyteArray>(env->GetObjectField(inetaddress,
+ gCachedFields.iaddr_ipaddress));
- return byteArrayToSocketAddress(env, addressByteArray, port, sockaddress);
+ return byteArrayToSocketAddress(env, addressBytes, port, sockaddress);
}
/**
@@ -652,22 +645,17 @@ jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
return env->NewObject(tempClass, tempMethod, anInt);
}
-/**
- * Answer a new java.lang.String object.
- *
- * @param env pointer to the JNI library
- * @param anInt the byte[] constructor argument
- *
- * @return the new String
- */
-
-jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
- jclass tempClass;
- jmethodID tempMethod;
+// Converts a number of milliseconds to a timeval.
+static timeval toTimeval(long ms) {
+ timeval tv;
+ tv.tv_sec = ms / 1000;
+ tv.tv_usec = (ms - tv.tv_sec*1000) * 1000;
+ return tv;
+}
- tempClass = gCachedFields.string_class;
- tempMethod = gCachedFields.string_class_init;
- return env->NewObject(tempClass, tempMethod, (jbyteArray) bytes);
+// Converts a timeval to a number of milliseconds.
+static long toMs(const timeval& tv) {
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
/**
@@ -684,11 +672,10 @@ jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
*/
static int time_msec_clock() {
- struct timeval tp;
+ timeval tp;
struct timezone tzp;
-
gettimeofday(&tp, &tzp);
- return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
+ return toMs(tp);
}
/**
@@ -1102,7 +1089,6 @@ unsigned short ip_checksum(unsigned short* buffer, int size) {
return (unsigned short )(~sum);
}
-
/**
* Wrapper for connect() that converts IPv4 addresses to IPv4-mapped IPv6
* addresses if necessary.
@@ -1177,9 +1163,8 @@ static int doBind(int socket, struct sockaddr_storage *socketAddress) {
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
- unsigned int timeout, unsigned int step, jbyte *ctxt) {
+ int timeout, unsigned int step, jbyte *ctxt) {
int rc = 0;
- struct timeval passedTimeout;
int errorVal;
socklen_t errorValLen = sizeof(int);
struct selectFDSet *context = NULL;
@@ -1239,13 +1224,13 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
* set the timeout value to be used. Because on some unix platforms we
* don't get notified when a socket is closed we only sleep for 100ms
* at a time
+ *
+ * TODO: is this relevant for Android?
*/
- passedTimeout.tv_sec = 0;
if (timeout > 100) {
- passedTimeout.tv_usec = 100 * 1000;
- } else if ((int)timeout >= 0) {
- passedTimeout.tv_usec = timeout * 1000;
+ timeout = 100;
}
+ timeval passedTimeout(toTimeval(timeout));
/* initialize the FD sets for the select */
FD_ZERO(&(context->exceptionSet));
@@ -1259,7 +1244,7 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
&(context->readSet),
&(context->writeSet),
&(context->exceptionSet),
- (int)timeout >= 0 ? &passedTimeout : NULL);
+ timeout >= 0 ? &passedTimeout : NULL);
/* if there is at least one descriptor ready to be checked */
if (0 < rc) {
@@ -1613,7 +1598,6 @@ static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
{&c->integer_class, "java/lang/Integer"},
{&c->boolean_class, "java/lang/Boolean"},
{&c->byte_class, "java/lang/Byte"},
- {&c->string_class, "java/lang/String"},
{&c->socketimpl_class, "java/net/SocketImpl"},
{&c->dpack_class, "java/net/DatagramPacket"}
};
@@ -1635,7 +1619,6 @@ static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
{&c->integer_class_init, c->integer_class, "<init>", "(I)V", false},
{&c->boolean_class_init, c->boolean_class, "<init>", "(Z)V", false},
{&c->byte_class_init, c->byte_class, "<init>", "(B)V", false},
- {&c->string_class_init, c->string_class, "<init>", "([B)V", false},
{&c->iaddr_getbyaddress, c->iaddr_class, "getByAddress",
"([B)Ljava/net/InetAddress;", true}
};
@@ -2684,13 +2667,10 @@ static jint osNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
int spaceAvailable = env->GetArrayLength(data) - offset;
int localCount = count < spaceAvailable? count : spaceAvailable;
- jboolean isCopy;
- jbyte *body = env->GetByteArrayElements(data, &isCopy);
+ jbyte* body = env->GetByteArrayElements(data, NULL);
// set timeout
- struct timeval tv;
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
+ timeval tv(toTimeval(timeout));
setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv,
sizeof(struct timeval));
@@ -2728,8 +2708,7 @@ static jint osNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
int handle = 0;
int result = 0, sent = 0;
- jboolean isCopy;
- jbyte *message = env->GetByteArrayElements(data, &isCopy);
+ jbyte *message = env->GetByteArrayElements(data, NULL);
// Cap write length to available buf size
int spaceAvailable = env->GetArrayLength(data) - offset;
@@ -2875,111 +2854,87 @@ static jint osNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
return sent;
}
-static jint osNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
- jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
- jint countWriteC, jintArray outFlags, jlong timeout) {
- // LOGD("ENTER selectImpl");
-
- struct timeval timeP;
- int result = 0;
- int size = 0;
- jobject gotFD;
- fd_set *fdset_read,*fdset_write;
- int handle;
- jboolean isCopy ;
- jint *flagArray;
- int val;
- unsigned int time_sec = (unsigned int)timeout/1000;
- unsigned int time_msec = (unsigned int)(timeout%1000);
-
- fdset_read = (fd_set *)malloc(sizeof(fd_set));
- fdset_write = (fd_set *)malloc(sizeof(fd_set));
-
- FD_ZERO(fdset_read);
- FD_ZERO(fdset_write);
-
- for (val = 0; val<countReadC; val++) {
-
- gotFD = env->GetObjectArrayElement(readFDArray,val);
-
- handle = jniGetFDFromFileDescriptor(env, gotFD);
-
- FD_SET(handle, fdset_read);
-
- if (0 > (size - handle)) {
- size = handle;
+static bool initFdSet(JNIEnv* env, jobjectArray fdArray, jint count, fd_set* fdSet, int* maxFd) {
+ for (int i = 0; i < count; ++i) {
+ jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
+ if (fileDescriptor == NULL) {
+ return false;
}
- }
-
- for (val = 0; val<countWriteC; val++) {
-
- gotFD = env->GetObjectArrayElement(writeFDArray,val);
-
- handle = jniGetFDFromFileDescriptor(env, gotFD);
-
- FD_SET(handle, fdset_write);
-
- if (0 > (size - handle)) {
- size = handle;
+
+ const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (fd < 0 || fd > 1024) {
+ LOGE("selectImpl: invalid fd %i", fd);
+ continue;
}
- }
-
- /* the size is the max_fd + 1 */
- size =size + 1;
-
- if (0 > size) {
- result = SOCKERR_FDSET_SIZEBAD;
- } else {
- /* only set when timeout >= 0 (non-block)*/
- if (0 <= timeout) {
-
- timeP.tv_sec = time_sec;
- timeP.tv_usec = time_msec*1000;
-
- result = sockSelect(size, fdset_read, fdset_write, NULL, &timeP);
-
- } else {
- result = sockSelect(size, fdset_read, fdset_write, NULL, NULL);
+
+ FD_SET(fd, fdSet);
+
+ if (fd > *maxFd) {
+ *maxFd = fd;
}
}
+ return true;
+}
- if (0 < result) {
- /*output the result to a int array*/
- flagArray = env->GetIntArrayElements(outFlags, &isCopy);
-
- for (val=0; val<countReadC; val++) {
- gotFD = env->GetObjectArrayElement(readFDArray,val);
-
- handle = jniGetFDFromFileDescriptor(env, gotFD);
-
- if (FD_ISSET(handle,fdset_read)) {
- flagArray[val] = SOCKET_OP_READ;
- } else {
- flagArray[val] = SOCKET_OP_NONE;
- }
+static bool translateFdSet(JNIEnv* env, jobjectArray fdArray, jint count, const fd_set& fdSet, jint* flagArray, size_t offset, jint op) {
+ for (int i = 0; i < count; ++i) {
+ jobject fileDescriptor = env->GetObjectArrayElement(fdArray, i);
+ if (fileDescriptor == NULL) {
+ return false;
}
-
- for (val=0; val<countWriteC; val++) {
-
- gotFD = env->GetObjectArrayElement(writeFDArray,val);
-
- handle = jniGetFDFromFileDescriptor(env, gotFD);
-
- if (FD_ISSET(handle,fdset_write)) {
- flagArray[val+countReadC] = SOCKET_OP_WRITE;
- } else {
- flagArray[val+countReadC] = SOCKET_OP_NONE;
- }
+
+ const int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ const bool valid = fd >= 0 && fd < 1024;
+
+ if (valid && FD_ISSET(fd, &fdSet)) {
+ flagArray[i + offset] = op;
+ } else {
+ flagArray[i + offset] = SOCKET_OP_NONE;
}
-
- env->ReleaseIntArrayElements(outFlags, flagArray, 0);
}
+ return true;
+}
- free(fdset_write);
- free(fdset_read);
-
- /* return both correct and error result, let java handle the exception*/
- return result;
+static jint osNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
+ jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
+ jint countWriteC, jintArray outFlags, jlong timeoutMs) {
+ // LOGD("ENTER selectImpl");
+
+ // Initialize the fd_sets.
+ int maxFd = -1;
+ fd_set readFds;
+ fd_set writeFds;
+ FD_ZERO(&readFds);
+ FD_ZERO(&writeFds);
+ bool initialized = initFdSet(env, readFDArray, countReadC, &readFds, &maxFd) &&
+ initFdSet(env, writeFDArray, countWriteC, &writeFds, &maxFd);
+ if (!initialized) {
+ return -1;
+ }
+
+ // Initialize the timeout, if any.
+ timeval tv;
+ timeval* tvp = NULL;
+ if (timeoutMs >= 0) {
+ tv = toTimeval(timeoutMs);
+ tvp = &tv;
+ }
+
+ // Perform the select.
+ int result = sockSelect(maxFd + 1, &readFds, &writeFds, NULL, tvp);
+ if (result < 0) {
+ return result;
+ }
+
+ // Translate the result into the int[] we're supposed to fill in.
+ jint* flagArray = env->GetIntArrayElements(outFlags, NULL);
+ if (flagArray == NULL) {
+ return -1;
+ }
+ bool okay = translateFdSet(env, readFDArray, countReadC, readFds, flagArray, 0, SOCKET_OP_READ) &&
+ translateFdSet(env, writeFDArray, countWriteC, writeFds, flagArray, countReadC, SOCKET_OP_WRITE);
+ env->ReleaseIntArrayElements(outFlags, flagArray, 0);
+ return okay ? 0 : -1;
}
static jobject osNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
@@ -3212,7 +3167,7 @@ static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
throwSocketException(env, convertError(errno));
return NULL;
}
- return newJavaLangInteger(env, timeout.tv_sec * 1000 + timeout.tv_usec/1000);
+ return newJavaLangInteger(env, toMs(timeout));
}
default: {
throwSocketException(env, SOCKERR_OPTUNSUPP);
@@ -3457,9 +3412,7 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
}
case JAVASOCKOPT_SO_RCVTIMEOUT: {
- struct timeval timeout;
- timeout.tv_sec = intVal / 1000;
- timeout.tv_usec = (intVal % 1000) * 1000;
+ timeval timeout(toTimeval(intVal));
result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(struct timeval));
if (0 != result) {
diff --git a/luni/src/test/java/com/google/coretests/CoreTestRunner.java b/luni/src/test/java/com/google/coretests/CoreTestRunner.java
index d469c86..d80fa4e 100644
--- a/luni/src/test/java/com/google/coretests/CoreTestRunner.java
+++ b/luni/src/test/java/com/google/coretests/CoreTestRunner.java
@@ -15,6 +15,8 @@
*/
package com.google.coretests;
+import java.util.ArrayList;
+import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -134,10 +136,10 @@ public class CoreTestRunner extends TestRunner {
* Prints a help screen on the console.
*/
private void showHelp() {
- System.out.println("Usage: run-core-tests {<param>} <test>");
+ System.out.println("Usage: run-core-tests [OPTION]... [TEST]...");
System.out.println();
- System.out.println("Where <test> is a class name, optionally followed");
- System.out.println("by \"#\" and a method name, and <param> is one of");
+ System.out.println("Where each TEST is a class name, optionally followed");
+ System.out.println("by \"#\" and a method name, and each OPTION is one of");
System.out.println("the following:");
System.out.println();
System.out.println(" --include-all");
@@ -185,26 +187,29 @@ public class CoreTestRunner extends TestRunner {
}
/**
- * Tries to create a Test instance from a given string. The string might
+ * Tries to create a Test instance from the given strings. The strings might
* either specify a class only or a class plus a method name, separated by
* a "#".
*/
- private Test createTest(String testCase) throws Exception {
- int p = testCase.indexOf("#");
- if (p != -1) {
- String testName = testCase.substring(p + 1);
- testCase = testCase.substring(0, p);
-
- return TestSuite.createTest(Class.forName(testCase), testName);
- } else {
- return getTest(testCase);
+ private Test createTest(List<String> testCases) throws Exception {
+ TestSuite result = new TestSuite();
+ for (String testCase : testCases) {
+ int p = testCase.indexOf("#");
+ if (p != -1) {
+ String testName = testCase.substring(p + 1);
+ testCase = testCase.substring(0, p);
+
+ result.addTest(TestSuite.createTest(Class.forName(testCase), testName));
+ } else {
+ result.addTest(getTest(testCase));
+ }
}
-
+ return result;
}
@Override
protected TestResult start(String args[]) throws Exception {
- String testName = null;
+ List<String> testNames = new ArrayList<String>();
// String victimName = null;
boolean wait = false;
@@ -269,12 +274,12 @@ public class CoreTestRunner extends TestRunner {
showHelp();
System.exit(1);
} else {
- System.err.println("Unknown argument " + args[i] +
- ", try --help");
- System.exit(1);
+ unknownArgument(args[i]);
}
+ } else if (args[i].startsWith("-")) {
+ unknownArgument(args[i]);
} else {
- testName = args[i];
+ testNames.add(args[i]);
}
}
@@ -288,7 +293,7 @@ public class CoreTestRunner extends TestRunner {
System.out.println();
try {
- return doRun(createTest(testName), wait);
+ return doRun(createTest(testNames), wait);
}
catch(Exception e) {
e.printStackTrace();
@@ -296,4 +301,8 @@ public class CoreTestRunner extends TestRunner {
}
}
+ private static void unknownArgument(String arg) {
+ System.err.println("Unknown argument " + arg + ", try --help");
+ System.exit(1);
+ }
}
diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java b/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java
index cb35324..283c1db 100644
--- a/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java
+++ b/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/PackageTest.java
@@ -312,7 +312,7 @@ public class PackageTest extends junit.framework.TestCase {
method = "isCompatibleWith",
args = {java.lang.String.class}
)
- @KnownFailure("isCompatibleWith returns incorrect value.")
+ @KnownFailure("Dalvik packages are always version '0.0'.")
public void test_isCompatibleWithLjava_lang_String() throws Exception {
Package p = getTestPackage("hyts_c.jar", "p.C");
diff --git a/luni/src/test/java/tests/api/java/io/FileTest.java b/luni/src/test/java/tests/api/java/io/FileTest.java
index 2850826..5c0cb2a 100644
--- a/luni/src/test/java/tests/api/java/io/FileTest.java
+++ b/luni/src/test/java/tests/api/java/io/FileTest.java
@@ -688,10 +688,7 @@ public class FileTest extends junit.framework.TestCase {
method = "delete",
args = {}
)
- @KnownFailure("Non empty directories are deleted on Android.")
public void test_delete() {
- // this test passes in the emulator, but it fails on the device
-
// Test for method boolean java.io.File.delete()
try {
File dir = new File(System.getProperty("java.io.tmpdir"), platformId
diff --git a/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java b/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java
index 3b545e3..dc35610 100644
--- a/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java
+++ b/luni/src/test/java/tests/api/java/io/RandomAccessFileTest.java
@@ -1200,16 +1200,25 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
} catch (IOException e) {
// Expected.
}
+ // BEGIN android-added
+ try {
+ // Android uses 32-bit off_t, so anything larger than a signed 32-bit int won't work.
+ raf.seek(((long) Integer.MAX_VALUE) + 1);
+ fail("Test 2: IOException expected.");
+ } catch (IOException e) {
+ // Expected.
+ }
+ // END android-added
raf.write(testString.getBytes(), 0, testLength);
raf.seek(12);
- assertEquals("Test 2: Seek failed to set file pointer.", 12,
+ assertEquals("Test 3: Seek failed to set file pointer.", 12,
raf.getFilePointer());
raf.close();
try {
raf.seek(1);
- fail("Test 1: IOException expected.");
+ fail("Test 4: IOException expected.");
} catch (IOException e) {
// Expected.
}
@@ -1296,10 +1305,21 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
assertEquals("Test 7: Incorrect file length;",
testLength + 2, raf.length());
+ // BEGIN android-added
+ // Exception testing.
+ try {
+ // Android uses 32-bit off_t, so anything larger than a signed 32-bit int won't work.
+ raf.setLength(((long) Integer.MAX_VALUE) + 1);
+ fail("Test 8: IOException expected.");
+ } catch (IOException e) {
+ // Expected.
+ }
+ // END android-added
+
// Exception testing.
try {
raf.setLength(-1);
- fail("Test 8: IllegalArgumentException expected.");
+ fail("Test 9: IllegalArgumentException expected.");
} catch (IllegalArgumentException e) {
// Expected.
}
@@ -1307,7 +1327,7 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
raf.close();
try {
raf.setLength(truncLength);
- fail("Test 9: IOException expected.");
+ fail("Test 10: IOException expected.");
} catch (IOException e) {
// Expected.
}
@@ -1501,4 +1521,4 @@ public class RandomAccessFileTest extends junit.framework.TestCase {
super.tearDown();
}
-} \ No newline at end of file
+}
diff --git a/luni/src/test/java/tests/api/java/util/ArrayListTest.java b/luni/src/test/java/tests/api/java/util/ArrayListTest.java
index 8aa77cc..0356731 100644
--- a/luni/src/test/java/tests/api/java/util/ArrayListTest.java
+++ b/luni/src/test/java/tests/api/java/util/ArrayListTest.java
@@ -19,7 +19,7 @@ package tests.api.java.util;
import dalvik.annotation.TestTargetNew;
import dalvik.annotation.TestTargets;
import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetClass;
import java.util.ArrayList;
import java.util.Arrays;
@@ -33,13 +33,13 @@ import java.util.Vector;
import tests.support.Support_ListTest;
-@TestTargetClass(ArrayList.class)
+@TestTargetClass(ArrayList.class)
public class ArrayListTest extends junit.framework.TestCase {
List alist;
Object[] objArray;
-
+
/**
* @tests java.util.ArrayList#ArrayList()
*/
@@ -72,7 +72,7 @@ public class ArrayListTest extends junit.framework.TestCase {
// Test for method java.util.ArrayList(int)
ArrayList al = new ArrayList(5);
assertEquals("Incorrect arrayList created", 0, al.size());
-
+
try {
new ArrayList(-10);
fail("IllegalArgumentException expected");
@@ -130,14 +130,14 @@ public class ArrayListTest extends junit.framework.TestCase {
assertNull("Should have returned null", alist.get(25));
assertTrue("Should have returned the old item from slot 25", alist
.get(26) == oldItem);
-
+
try {
alist.add(-1, null);
fail("IndexOutOfBoundsException expected");
} catch (IndexOutOfBoundsException e) {
//expected
}
-
+
try {
alist.add(alist.size() + 1, null);
fail("IndexOutOfBoundsException expected");
@@ -198,9 +198,9 @@ public class ArrayListTest extends junit.framework.TestCase {
assertTrue("Incorrect size: " + alist.size(), alist.size() == 205);
assertNull("Item at slot 100 should be null", alist.get(100));
assertNull("Item at slot 101 should be null", alist.get(101));
- assertEquals("Item at slot 102 should be 'yoink'",
+ assertEquals("Item at slot 102 should be 'yoink'",
"yoink", alist.get(102));
- assertEquals("Item at slot 103 should be 'kazoo'",
+ assertEquals("Item at slot 103 should be 'kazoo'",
"kazoo", alist.get(103));
assertNull("Item at slot 104 should be null", alist.get(104));
alist.addAll(205, listWithNulls);
@@ -228,24 +228,29 @@ public class ArrayListTest extends junit.framework.TestCase {
}
}
- /**
- * @tests java.util.ArrayList#addAll(int, java.util.Collection)
- */
- @TestTargetNew(
- level = TestLevel.PARTIAL_COMPLETE,
- notes = "Verifies IndexOutOfBoundsException.",
- method = "addAll",
- args = {int.class, java.util.Collection.class}
- )
- public void test_addAllILjava_util_Collection_2() {
- // Regression for HARMONY-467
- ArrayList obj = new ArrayList();
- try {
- obj.addAll((int) -1, (Collection) null);
- fail("IndexOutOfBoundsException expected");
- } catch (IndexOutOfBoundsException e) {
- }
- }
+// BEGIN android-removed
+// The spec does not mandate that IndexOutOfBoundsException be thrown in
+// preference to NullPointerException when the caller desserves both.
+//
+// /**
+// * @tests java.util.ArrayList#addAll(int, java.util.Collection)
+// */
+// @TestTargetNew(
+// level = TestLevel.PARTIAL_COMPLETE,
+// notes = "Verifies IndexOutOfBoundsException.",
+// method = "addAll",
+// args = {int.class, java.util.Collection.class}
+// )
+// public void test_addAllILjava_util_Collection_2() {
+// // Regression for HARMONY-467
+// ArrayList obj = new ArrayList();
+// try {
+// obj.addAll((int) -1, (Collection) null);
+// fail("IndexOutOfBoundsException expected");
+// } catch (IndexOutOfBoundsException e) {
+// }
+// }
+// END android-removed
/**
* @tests java.util.ArrayList#addAll(java.util.Collection)
@@ -287,17 +292,17 @@ public class ArrayListTest extends junit.framework.TestCase {
.get(101) == i.next());
assertTrue("Item at slot 103 is wrong: " + alist.get(102), alist
.get(102) == i.next());
-
-
+
+
// Regression test for Harmony-3481
ArrayList<Integer> originalList = new ArrayList<Integer>(12);
for (int j = 0; j < 12; j++) {
originalList.add(j);
}
-
+
originalList.remove(0);
originalList.remove(0);
-
+
ArrayList<Integer> additionalList = new ArrayList<Integer>(11);
for (int j = 0; j < 11; j++) {
additionalList.add(j);
@@ -672,7 +677,7 @@ public class ArrayListTest extends junit.framework.TestCase {
assertTrue("Returned incorrect array: " + i,
retArray[i] == objArray[i]);
}
-
+
String[] strArray = new String[100];
try {
alist.toArray(strArray);
@@ -746,16 +751,16 @@ public class ArrayListTest extends junit.framework.TestCase {
list.remove(0);
assertEquals(1, list.size());
-
+
ArrayList collection = new ArrayList();
collection.add("1");
collection.add("2");
collection.add("3");
assertEquals(3, collection.size());
-
+
list.addAll(0, collection);
assertEquals(4, list.size());
-
+
list.remove(0);
list.remove(0);
assertEquals(2, list.size());
@@ -769,13 +774,13 @@ public class ArrayListTest extends junit.framework.TestCase {
collection.add("10");
collection.add("11");
collection.add("12");
-
+
assertEquals(12, collection.size());
-
+
list.addAll(0, collection);
assertEquals(14, list.size());
}
-
+
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "",
@@ -818,7 +823,7 @@ public class ArrayListTest extends junit.framework.TestCase {
mal.add("f");
mal.add("g");
mal.add("h");
-
+
mal.removeRange(2, 4);
String[] result = new String[6];
@@ -827,30 +832,30 @@ public class ArrayListTest extends junit.framework.TestCase {
new String[] { "a", "b", "e", "f", "g", "h"}));
}
-
+
/**
* Sets up the fixture, for example, open a network connection. This method
* is called before a test is executed.
*/
protected void setUp() throws Exception {
super.setUp();
-
+
objArray = new Object[100];
for (int i = 0; i < objArray.length; i++) {
objArray[i] = new Integer(i);
}
-
+
alist = new ArrayList();
for (int i = 0; i < objArray.length; i++) {
alist.add(objArray[i]);
}
}
-
+
@Override
protected void tearDown() throws Exception {
objArray = null;
alist = null;
-
+
super.tearDown();
}
}
diff --git a/luni/src/test/java/tests/api/java/util/FormatterTest.java b/luni/src/test/java/tests/api/java/util/FormatterTest.java
index b2030c9..6f86818 100644
--- a/luni/src/test/java/tests/api/java/util/FormatterTest.java
+++ b/luni/src/test/java/tests/api/java/util/FormatterTest.java
@@ -800,6 +800,36 @@ public class FormatterTest extends TestCase {
}
}
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Tests that supplying a Formattable works. See http://code.google.com/p/android/issues/detail?id=1767.",
+ method = "format",
+ args = {}
+ )
+ public void test_Formattable() {
+ Formattable ones = new Formattable() {
+ public void formatTo(Formatter formatter, int flags, int width, int precision) throws IllegalFormatException {
+ try {
+ formatter.out().append("111");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+ Formattable twos = new Formattable() {
+ public void formatTo(Formatter formatter, int flags, int width, int precision) throws IllegalFormatException {
+ try {
+ formatter.out().append("222");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+
+ assertEquals("aaa 111?", new Formatter().format("aaa %s?", ones).toString());
+ assertEquals("aaa 111 bbb 222?", new Formatter().format("aaa %s bbb %s?", ones, twos).toString());
+ }
+
/**
* @tests java.util.Formatter#out()
*/
diff --git a/luni/src/test/java/tests/api/java/util/TimeZoneTest.java b/luni/src/test/java/tests/api/java/util/TimeZoneTest.java
index efdb8a1..75e9ae3 100644
--- a/luni/src/test/java/tests/api/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/tests/api/java/util/TimeZoneTest.java
@@ -383,6 +383,19 @@ public class TimeZoneTest extends junit.framework.TestCase {
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "",
+ method = "useDaylightTime",
+ args = {}
+ )
+ public void test_useDaylightTime() {
+ // http://code.google.com/p/android/issues/detail?id=877
+
+ TimeZone asiaTaipei = TimeZone.getTimeZone("Asia/Taipei");
+ assertFalse("Taiwan doesn't use DST", asiaTaipei.useDaylightTime());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
method = "setID",
args = {java.lang.String.class}
)
diff --git a/math/src/main/java/java/math/BigInt.java b/math/src/main/java/java/math/BigInt.java
index cb7990a..581c22f 100644
--- a/math/src/main/java/java/math/BigInt.java
+++ b/math/src/main/java/java/math/BigInt.java
@@ -225,12 +225,6 @@ class BigInt
return a;
}
- public byte[] bigEndianTwosComplement() {
- byte[] a = NativeBN.bn2twosComp(this.bignum, null);
- return a;
- }
-
-
public int sign() {
return NativeBN.sign(this.bignum);
}
diff --git a/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java b/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java
index 91d6d06..a846e70 100644
--- a/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java
+++ b/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/FileChannelTest.java
@@ -1155,6 +1155,25 @@ public class FileChannelTest extends TestCase {
} catch (IllegalArgumentException e) {
// expected
}
+
+ // BEGIN android-added
+ // Android uses 32-bit off_t, so anything larger than a signed 32-bit int won't work...
+ // ...except for the special case of length == Long.MAX_VALUE, which is used to mean "the
+ // whole file". The special case is tested elsewhere.
+ long tooBig = ((long) Integer.MAX_VALUE) + 1;
+ try {
+ readWriteFileChannel.tryLock(tooBig, 1, false);
+ fail("should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ try {
+ readWriteFileChannel.tryLock(0, tooBig, false);
+ fail("should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+ // END android-added
}
/**
diff --git a/openssl/src/main/java/org/openssl/NativeBN.java b/openssl/src/main/java/org/openssl/NativeBN.java
index 44464e0..3597e3c 100644
--- a/openssl/src/main/java/org/openssl/NativeBN.java
+++ b/openssl/src/main/java/org/openssl/NativeBN.java
@@ -79,9 +79,6 @@ public class NativeBN {
public static native int[] bn2litEndInts(int a, int[] to);
- public static native byte[] bn2twosComp(int a, byte[] to);
-
-
public static native int sign(int a);
// Returns -1, 0, 1 AND NOT boolean.
// #define BN_is_negative(a) ((a)->neg != 0)
diff --git a/openssl/src/main/native/BNInterface.c b/openssl/src/main/native/BNInterface.c
index 4132e4f..1a3eb16 100644
--- a/openssl/src/main/native/BNInterface.c
+++ b/openssl/src/main/native/BNInterface.c
@@ -33,12 +33,6 @@
static void
-throwOutOfMemoryException(JNIEnv* env, const char* message)
-{
- jniThrowException(env, "java/lang/OutOfMemoryError", message);
-}
-
-static void
throwNewNullPointerException (JNIEnv* env, const char* message)
{
jniThrowException(env, "java/lang/NullPointerException", message);
@@ -456,27 +450,6 @@ static jintArray NativeBN_bn2litEndInts(JNIEnv* env, jclass cls, BIGNUM* a, jint
}
}
-/**
- * public static native byte[] bn2twosComp(int, byte[])
- */
-static jbyteArray NativeBN_bn2twosComp(JNIEnv* env, jclass cls, BIGNUM* a, jbyteArray to) {
- if (!oneValidHandle(env, a)) return NULL;
- jbyteArray returnJBytes = to;
- unsigned char * tmpBytes;
- int len, byteCnt;
- byteCnt = BN_num_bytes(a);
-// FIXME: Currently ignoring array passed in to:
- returnJBytes = (*env)->NewByteArray(env, byteCnt);
-// FIXME: is it neccessary to check for returnJBytes != NULL?
- tmpBytes = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, returnJBytes, NULL));
- if (tmpBytes != NULL) {
- len = BN_bn2bin(a, tmpBytes);
- (*env)->ReleasePrimitiveArrayCritical(env, returnJBytes, tmpBytes, 0);
- return returnJBytes;
- }
- else return NULL;
-}
-
/**
* public static native int sign(int)
@@ -833,7 +806,6 @@ static JNINativeMethod METHODS[] = {
{ "BN_bn2hex", "(I)Ljava/lang/String;", (void*)NativeBN_BN_bn2hex },
{ "BN_bn2bin", "(I[B)[B", (void*)NativeBN_BN_bn2bin },
{ "bn2litEndInts", "(I[I)[I", (void*)NativeBN_bn2litEndInts },
- { "bn2twosComp", "(I[B)[B", (void*)NativeBN_bn2twosComp },
{ "sign", "(I)I", (void*)NativeBN_sign },
{ "BN_set_negative", "(II)V", (void*)NativeBN_BN_set_negative },
{ "twosCompFitsIntoBytes", "(II)Z", (void*)NativeBN_twosCompFitsIntoBytes },
diff --git a/regex/src/main/java/java/util/regex/MatchResult.java b/regex/src/main/java/java/util/regex/MatchResult.java
index fa67ba6..76c17a8 100644
--- a/regex/src/main/java/java/util/regex/MatchResult.java
+++ b/regex/src/main/java/java/util/regex/MatchResult.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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
*
- * 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
*
- * 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.
+ * 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.regex;
@@ -22,91 +23,75 @@ package java.util.regex;
* pair of parentheses in the regular expression and an additional group for
* the whole regular expression. The start, end, and contents of each group
* can be queried.
- *
+ *
* @see Matcher
* @see Matcher#toMatchResult()
- *
- * @since Android 1.0
*/
public interface MatchResult {
/**
* Returns the index of the first character following the text that matched
- * the whole regular expression.
- *
+ * the whole regular expression.
+ *
* @return the character index.
- *
- * @since Android 1.0
*/
int end();
/**
* Returns the index of the first character following the text that matched
* a given group.
- *
+ *
* @param group
* the group, ranging from 0 to groupCount() - 1, with 0
* representing the whole pattern.
- *
+ *
* @return the character index.
- *
- * @since Android 1.0
*/
int end(int group);
/**
- * Returns the text that matched the whole regular expression.
- *
+ * Returns the text that matched the whole regular expression.
+ *
* @return the text.
- *
- * @since Android 1.0
*/
String group();
/**
* Returns the text that matched a given group of the regular expression.
- *
+ *
* @param group
* the group, ranging from 0 to groupCount() - 1, with 0
* representing the whole pattern.
- *
+ *
* @return the text that matched the group.
- *
- * @since Android 1.0
*/
String group(int group);
/**
* Returns the number of groups in the result, which is always equal to
* the number of groups in the original regular expression.
- *
+ *
* @return the number of groups.
- *
- * @since Android 1.0
*/
int groupCount();
/**
* Returns the index of the first character of the text that matched
- * the whole regular expression.
- *
+ * the whole regular expression.
+ *
* @return the character index.
- *
- * @since Android 1.0
*/
int start();
/**
* Returns the index of the first character of the text that matched a given
* group.
- *
+ *
* @param group
* the group, ranging from 0 to groupCount() - 1, with 0
* representing the whole pattern.
- *
+ *
* @return the character index.
- *
- * @since Android 1.0
*/
int start(int group);
}
diff --git a/regex/src/main/java/java/util/regex/Matcher.java b/regex/src/main/java/java/util/regex/Matcher.java
index e3e4874..be5c782 100644
--- a/regex/src/main/java/java/util/regex/Matcher.java
+++ b/regex/src/main/java/java/util/regex/Matcher.java
@@ -44,8 +44,6 @@ import com.ibm.icu4jni.regex.NativeRegEx;
* {@code Pattern} was successful and at which position the next attempt would
* resume the search. Depending on the application's needs, it may become
* necessary to explicitly {@link #reset()} this state from time to time.
- *
- * @since Android 1.0
*/
public final class Matcher implements MatchResult {
@@ -128,39 +126,99 @@ public final class Matcher implements MatchResult {
}
/**
+ * Appends a literal part of the input plus a replacement for the current
+ * match to a given {@link StringBuffer}. The literal part is exactly the
+ * part of the input between the previous match and the current match. The
+ * method can be used in conjunction with {@link #find()} and
+ * {@link #appendTail(StringBuffer)} to walk through the input and replace
+ * all occurrences of the {@code Pattern} with something else.
+ *
+ * @param buffer
+ * the {@code StringBuffer} to append to.
+ * @param replacement
+ * the replacement text.
+ * @return the {@code Matcher} itself.
+ * @throws IllegalStateException
+ * if no successful match has been made.
+ */
+ public Matcher appendReplacement(StringBuffer buffer, String replacement) {
+ buffer.append(input.substring(appendPos, start()));
+ appendEvaluated(buffer, replacement);
+ appendPos = end();
+
+ return this;
+ }
+
+ /**
+ * Internal helper method to append a given string to a given string buffer.
+ * If the string contains any references to groups, these are replaced by
+ * the corresponding group's contents.
+ *
+ * @param buffer
+ * the string buffer.
+ * @param s
+ * the string to append.
+ */
+ private void appendEvaluated(StringBuffer buffer, String s) {
+ boolean escape = false;
+ boolean dollar = false;
+
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == '\\' && !escape) {
+ escape = true;
+ } else if (c == '$' && !escape) {
+ dollar = true;
+ } else if (c >= '0' && c <= '9' && dollar) {
+ buffer.append(group(c - '0'));
+ dollar = false;
+ } else {
+ buffer.append(c);
+ dollar = false;
+ escape = false;
+ }
+ }
+
+ // This seemingly stupid piece of code reproduces a JDK bug.
+ if (escape) {
+ throw new ArrayIndexOutOfBoundsException(s.length());
+ }
+ }
+
+ /**
* Resets the Matcher. A new input sequence and a new region can be
* specified. Results of a previous find get lost. The next attempt to find
* an occurrence of the Pattern in the string will start at the beginning of
* the region. This is the internal version of reset() to which the several
* public versions delegate.
- *
+ *
* @param input
* the input sequence.
* @param start
* the start of the region.
* @param end
* the end of the region.
- *
+ *
* @return the matcher itself.
*/
private Matcher reset(CharSequence input, int start, int end) {
if (input == null) {
throw new IllegalArgumentException();
}
-
- if (start < 0 || end < 0 || start > input.length() ||
+
+ if (start < 0 || end < 0 || start > input.length() ||
end > input.length() || start > end) {
throw new IllegalArgumentException();
}
// Maybe should have a reset() here, but it makes thing worse...
// NativeRegEx.reset(nativePattern, 0);
-
+
if (!input.equals(this.input)) {
this.input = input.toString();
-
+
NativeRegEx.setText(nativePattern, this.input);
-
+
regionStart = 0;
regionEnd = input.length();
}
@@ -176,22 +234,8 @@ public final class Matcher implements MatchResult {
matchFound = false;
findPos = regionStart;
appendPos = 0;
-
- return this;
- }
- /**
- * Resets the {@code Matcher}. This results in the region being set to the
- * whole input. Results of a previous find get lost. The next attempt to
- * find an occurrence of the {@link Pattern} in the string will start at the
- * beginning of the input.
- *
- * @return the {@code Matcher} itself.
- *
- * @since Android 1.0
- */
- public Matcher reset() {
- return reset(input, 0, input.length());
+ return this;
}
/**
@@ -204,73 +248,24 @@ public final class Matcher implements MatchResult {
* the new input sequence.
*
* @return the {@code Matcher} itself.
- *
- * @since Android 1.0
*/
public Matcher reset(CharSequence input) {
return reset(input, 0, input.length());
}
/**
- * Sets a new pattern for the {@code Matcher}. Results of a previous find
- * get lost. The next attempt to find an occurrence of the {@link Pattern}
- * in the string will start at the beginning of the input.
- *
- * @param pattern
- * the new {@code Pattern}.
- *
+ * Resets the {@code Matcher}. This results in the region being set to the
+ * whole input. Results of a previous find get lost. The next attempt to
+ * find an occurrence of the {@link Pattern} in the string will start at the
+ * beginning of the input.
+ *
* @return the {@code Matcher} itself.
- *
- * @since Android 1.0
*/
- public Matcher usePattern(Pattern pattern) {
- if (pattern == null) {
- throw new IllegalArgumentException();
- }
-
- this.pattern = pattern;
-
- if (nativePattern != 0) {
- NativeRegEx.close(nativePattern);
- }
- nativePattern = NativeRegEx.clone(pattern.mNativePattern);
-
- if (input != null) {
- NativeRegEx.setText(nativePattern, input);
- NativeRegEx.setRegion(nativePattern, regionStart, regionEnd);
- NativeRegEx.useAnchoringBounds(nativePattern, anchoringBounds);
- NativeRegEx.useTransparentBounds(nativePattern, transparentBounds);
- }
-
- matchOffsets = new int[(this.pattern.mGroupCount + 1) * 2];
- matchFound = false;
- return this;
- }
-
- /**
- * Returns the {@link Pattern} instance used inside this matcher.
- *
- * @return the {@code Pattern} instance.
- *
- * @since Android 1.0
- */
- public Pattern pattern() {
- return pattern;
+ public Matcher reset() {
+ return reset(input, 0, input.length());
}
/**
- * Returns the number of groups in the results, which is always equal to
- * the number of groups in the original regular expression.
- *
- * @return the number of groups.
- *
- * @since Android 1.0
- */
- public int groupCount() {
- return pattern.mGroupCount;
- }
-
- /**
* Resets this matcher and sets a region. Only characters inside the region
* are considered for a match.
*
@@ -279,109 +274,150 @@ public final class Matcher implements MatchResult {
* @param end
* the first character after the end of the region.
* @return the {@code Matcher} itself.
- * @since Android 1.0
*/
public Matcher region(int start, int end) {
return reset(input, start, end);
}
+
/**
- * Returns this matcher's region start, that is, the first character that is
- * considered for a match.
- *
- * @return the start of the region.
- * @since Android 1.0
+ * Appends the (unmatched) remainder of the input to the given
+ * {@link StringBuffer}. The method can be used in conjunction with
+ * {@link #find()} and {@link #appendReplacement(StringBuffer, String)} to
+ * walk through the input and replace all matches of the {@code Pattern}
+ * with something else.
+ *
+ * @param buffer
+ * the {@code StringBuffer} to append to.
+ * @return the {@code StringBuffer}.
+ * @throws IllegalStateException
+ * if no successful match has been made.
*/
- public int regionStart() {
- return regionStart;
+ public StringBuffer appendTail(StringBuffer buffer) {
+ if (appendPos < regionEnd) {
+ buffer.append(input.substring(appendPos, regionEnd));
+ }
+
+ return buffer;
}
/**
- * Returns this matcher's region end, that is, the first character that is
- * not considered for a match.
- *
- * @return the end of the region.
- * @since Android 1.0
+ * Replaces the first occurrence of this matcher's pattern in the input with
+ * a given string.
+ *
+ * @param replacement
+ * the replacement text.
+ * @return the modified input string.
*/
- public int regionEnd() {
- return regionEnd;
+ public String replaceFirst(String replacement) {
+ StringBuffer buffer = new StringBuffer(input.length());
+
+ findPos = 0;
+ appendPos = 0;
+ matchFound = false;
+ searching = false;
+
+ if (find()) {
+ appendReplacement(buffer, replacement);
+ }
+
+ return appendTail(buffer).toString();
}
/**
- * Determines whether this matcher has anchoring bounds enabled or not. When
- * anchoring bounds are enabled, the start and end of the input match the
- * '^' and '$' meta-characters, otherwise not. Anchoring bounds are enabled
- * by default.
- *
- * @param value
- * the new value for anchoring bounds.
- * @return the {@code Matcher} itself.
- * @since Android 1.0
+ * Replaces all occurrences of this matcher's pattern in the input with a
+ * given string.
+ *
+ * @param replacement
+ * the replacement text.
+ * @return the modified input string.
*/
- public Matcher useAnchoringBounds(boolean value) {
- anchoringBounds = value;
- NativeRegEx.useAnchoringBounds(nativePattern, value);
- return this;
+ public String replaceAll(String replacement) {
+ StringBuffer buffer = new StringBuffer(input.length());
+
+ findPos = 0;
+ appendPos = 0;
+ matchFound = false;
+ searching = false;
+
+ while (find()) {
+ appendReplacement(buffer, replacement);
+ }
+
+ return appendTail(buffer).toString();
}
-
+
/**
- * Indicates whether this matcher has anchoring bounds enabled. When
- * anchoring bounds are enabled, the start and end of the input match the
- * '^' and '$' meta-characters, otherwise not. Anchoring bounds are enabled
- * by default.
- *
- * @return true if (and only if) the {@code Matcher} uses anchoring bounds.
- * @since Android 1.0
+ * Returns the {@link Pattern} instance used inside this matcher.
+ *
+ * @return the {@code Pattern} instance.
*/
- public boolean hasAnchoringBounds() {
- return anchoringBounds;
+ public Pattern pattern() {
+ return pattern;
}
/**
- * Determines whether this matcher has transparent bounds enabled or not.
- * When transparent bounds are enabled, the parts of the input outside the
- * region are subject to lookahead and lookbehind, otherwise they are not.
- * Transparent bounds are disabled by default.
- *
- * @param value
- * the new value for transparent bounds.
- * @return the {@code Matcher} itself.
- * @since Android 1.0
+ * Returns the text that matched a given group of the regular expression.
+ *
+ * @param group
+ * the group, ranging from 0 to groupCount() - 1, with 0
+ * representing the whole pattern.
+ * @return the text that matched the group.
+ * @throws IllegalStateException
+ * if no successful match has been made.
*/
- public Matcher useTransparentBounds(boolean value) {
- transparentBounds = value;
- NativeRegEx.useTransparentBounds(nativePattern, value);
- return this;
+ public String group(int group) {
+ ensureMatch();
+ int from = matchOffsets[group * 2];
+ int to = matchOffsets[(group * 2) + 1];
+ if (from == -1 || to == -1) {
+ return null;
+ } else {
+ return input.substring(from, to);
+ }
}
-
+
/**
- * Indicates whether this matcher has transparent bounds enabled. When
- * transparent bounds are enabled, the parts of the input outside the region
- * are subject to lookahead and lookbehind, otherwise they are not.
- * Transparent bounds are disabled by default.
- *
- * @return true if (and only if) the {@code Matcher} uses anchoring bounds.
- * @since Android 1.0
+ * Returns the text that matched the whole regular expression.
+ *
+ * @return the text.
+ * @throws IllegalStateException
+ * if no successful match has been made.
*/
- public boolean hasTransparentBounds() {
- return transparentBounds;
+ public String group() {
+ return group(0);
}
-
+
/**
- * Makes sure that a successful match has been made. Is invoked internally
- * from various places in the class.
- *
- * @throws IllegalStateException
- * if no successful match has been made.
- *
- * @since Android 1.0
+ * Returns the next occurrence of the {@link Pattern} in the input. The
+ * method starts the search from the given character in the input.
+ *
+ * @param start
+ * The index in the input at which the find operation is to
+ * begin. If this is less than the start of the region, it is
+ * automatically adjusted to that value. If it is beyond the end
+ * of the region, the method will fail.
+ * @return true if (and only if) a match has been found.
*/
- private void ensureMatch() throws IllegalStateException {
- if (!matchFound) {
- throw new IllegalStateException("No successful match so far");
+ public boolean find(int start) {
+ findPos = start;
+
+ if (findPos < regionStart) {
+ findPos = regionStart;
+ } else if (findPos >= regionEnd) {
+ matchFound = false;
+ return false;
}
+
+ matchFound = NativeRegEx.find(nativePattern, findPos);
+ if (matchFound) {
+ NativeRegEx.startEnd(nativePattern, matchOffsets);
+ findPos = matchOffsets[1];
+ }
+
+ return matchFound;
}
-
+
/**
* Returns the next occurrence of the {@link Pattern} in the input. If a
* previous match was successful, the method continues the search from the
@@ -389,7 +425,6 @@ public final class Matcher implements MatchResult {
* either from the region start (if one has been set), or from position 0.
*
* @return true if (and only if) a match has been found.
- * @since Android 1.0
*/
public boolean find() {
if (!searching) {
@@ -408,34 +443,35 @@ public final class Matcher implements MatchResult {
}
/**
- * Returns the next occurrence of the {@link Pattern} in the input. The
- * method starts the search from the given character in the input.
- *
- * @param start
- * The index in the input at which the find operation is to
- * begin. If this is less than the start of the region, it is
- * automatically adjusted to that value. If it is beyond the end
- * of the region, the method will fail.
- * @return true if (and only if) a match has been found.
- * @since Android 1.0
+ * Returns the index of the first character of the text that matched a given
+ * group.
+ *
+ * @param group
+ * the group, ranging from 0 to groupCount() - 1, with 0
+ * representing the whole pattern.
+ * @return the character index.
+ * @throws IllegalStateException
+ * if no successful match has been made.
*/
- public boolean find(int start) {
- findPos = start;
-
- if (findPos < regionStart) {
- findPos = regionStart;
- } else if (findPos >= regionEnd) {
- matchFound = false;
- return false;
- }
-
- matchFound = NativeRegEx.find(nativePattern, findPos);
- if (matchFound) {
- NativeRegEx.startEnd(nativePattern, matchOffsets);
- findPos = matchOffsets[1];
- }
-
- return matchFound;
+ public int start(int group) throws IllegalStateException {
+ ensureMatch();
+ return matchOffsets[group * 2];
+ }
+
+ /**
+ * Returns the index of the first character following the text that matched
+ * a given group.
+ *
+ * @param group
+ * the group, ranging from 0 to groupCount() - 1, with 0
+ * representing the whole pattern.
+ * @return the character index.
+ * @throws IllegalStateException
+ * if no successful match has been made.
+ */
+ public int end(int group) {
+ ensureMatch();
+ return matchOffsets[(group * 2) + 1];
}
/**
@@ -444,8 +480,6 @@ public final class Matcher implements MatchResult {
*
* @return true if (and only if) the {@code Pattern} matches the entire
* region.
- *
- * @since Android 1.0
*/
public boolean matches() {
matchFound = NativeRegEx.matches(nativePattern, -1);
@@ -458,13 +492,34 @@ public final class Matcher implements MatchResult {
}
/**
+ * Returns a replacement string for the given one that has all backslashes
+ * and dollar signs escaped.
+ *
+ * @param s
+ * the input string.
+ * @return the input string, with all backslashes and dollar signs having
+ * been escaped.
+ */
+ public static String quoteReplacement(String s) {
+ StringBuffer buffer = new StringBuffer(s.length());
+
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == '\\' || c == '$') {
+ buffer.append('\\');
+ }
+ buffer.append(c);
+ }
+
+ return buffer.toString();
+ }
+
+ /**
* Tries to match the {@link Pattern}, starting from the beginning of the
* region (or the beginning of the input, if no region has been set).
* Doesn't require the {@code Pattern} to match against the whole region.
*
* @return true if (and only if) the {@code Pattern} matches.
- *
- * @since Android 1.0
*/
public boolean lookingAt() {
matchFound = NativeRegEx.lookingAt(nativePattern, -1);
@@ -483,27 +538,19 @@ public final class Matcher implements MatchResult {
* @return the character index.
* @throws IllegalStateException
* if no successful match has been made.
- * @since Android 1.0
*/
- public int start() throws IllegalStateException {
+ public int start() {
return start(0);
}
/**
- * Returns the index of the first character of the text that matched a given
- * group.
- *
- * @param group
- * the group, ranging from 0 to groupCount() - 1, with 0
- * representing the whole pattern.
- * @return the character index.
- * @throws IllegalStateException
- * if no successful match has been made.
- * @since Android 1.0
+ * Returns the number of groups in the results, which is always equal to
+ * the number of groups in the original regular expression.
+ *
+ * @return the number of groups.
*/
- public int start(int group) throws IllegalStateException {
- ensureMatch();
- return matchOffsets[group * 2];
+ public int groupCount() {
+ return pattern.mGroupCount;
}
/**
@@ -513,255 +560,166 @@ public final class Matcher implements MatchResult {
* @return the character index.
* @throws IllegalStateException
* if no successful match has been made.
- * @since Android 1.0
*/
public int end() {
return end(0);
}
/**
- * Returns the index of the first character following the text that matched
- * a given group.
- *
- * @param group
- * the group, ranging from 0 to groupCount() - 1, with 0
- * representing the whole pattern.
- * @return the character index.
+ * Converts the current match into a separate {@link MatchResult} instance
+ * that is independent from this matcher. The new object is unaffected when
+ * the state of this matcher changes.
+ *
+ * @return the new {@code MatchResult}.
* @throws IllegalStateException
* if no successful match has been made.
- * @since Android 1.0
*/
- public int end(int group) {
+ public MatchResult toMatchResult() {
ensureMatch();
- return matchOffsets[(group * 2) + 1];
+ return new MatchResultImpl(input, matchOffsets);
}
/**
- * Returns the text that matched the whole regular expression.
- *
- * @return the text.
- * @throws IllegalStateException
- * if no successful match has been made.
- * @since Android 1.0
+ * Determines whether this matcher has anchoring bounds enabled or not. When
+ * anchoring bounds are enabled, the start and end of the input match the
+ * '^' and '$' meta-characters, otherwise not. Anchoring bounds are enabled
+ * by default.
+ *
+ * @param value
+ * the new value for anchoring bounds.
+ * @return the {@code Matcher} itself.
*/
- public String group() {
- return group(0);
+ public Matcher useAnchoringBounds(boolean value) {
+ anchoringBounds = value;
+ NativeRegEx.useAnchoringBounds(nativePattern, value);
+ return this;
}
/**
- * Returns the text that matched a given group of the regular expression.
- *
- * @param group
- * the group, ranging from 0 to groupCount() - 1, with 0
- * representing the whole pattern.
- * @return the text that matched the group.
- * @throws IllegalStateException
- * if no successful match has been made.
- * @since Android 1.0
+ * Indicates whether this matcher has anchoring bounds enabled. When
+ * anchoring bounds are enabled, the start and end of the input match the
+ * '^' and '$' meta-characters, otherwise not. Anchoring bounds are enabled
+ * by default.
+ *
+ * @return true if (and only if) the {@code Matcher} uses anchoring bounds.
*/
- public String group(int group) {
- ensureMatch();
- int from = matchOffsets[group * 2];
- int to = matchOffsets[(group * 2) + 1];
- if (from == -1 || to == -1) {
- return null;
- } else {
- return input.substring(from, to);
- }
+ public boolean hasAnchoringBounds() {
+ return anchoringBounds;
}
/**
- * Indicates whether the last match hit the end of the input.
- *
- * @return true if (and only if) the last match hit the end of the input.
- * @since Android 1.0
- */
- public boolean hitEnd() {
- return NativeRegEx.hitEnd(nativePattern);
- }
-
- /**
- * Indicates whether more input might change a successful match into an
- * unsuccessful one.
- *
- * @return true if (and only if) more input might change a successful match
- * into an unsuccessful one.
- * @since Android 1.0
+ * Determines whether this matcher has transparent bounds enabled or not.
+ * When transparent bounds are enabled, the parts of the input outside the
+ * region are subject to lookahead and lookbehind, otherwise they are not.
+ * Transparent bounds are disabled by default.
+ *
+ * @param value
+ * the new value for transparent bounds.
+ * @return the {@code Matcher} itself.
*/
- public boolean requireEnd() {
- return NativeRegEx.requireEnd(nativePattern);
+ public Matcher useTransparentBounds(boolean value) {
+ transparentBounds = value;
+ NativeRegEx.useTransparentBounds(nativePattern, value);
+ return this;
}
-
+
/**
- * Converts the current match into a separate {@link MatchResult} instance
- * that is independent from this matcher. The new object is unaffected when
- * the state of this matcher changes.
- *
- * @return the new {@code MatchResult}.
+ * Makes sure that a successful match has been made. Is invoked internally
+ * from various places in the class.
+ *
* @throws IllegalStateException
* if no successful match has been made.
- * @since Android 1.0
*/
- public MatchResult toMatchResult() {
- ensureMatch();
- return new MatchResultImpl(input, matchOffsets);
+ private void ensureMatch() {
+ if (!matchFound) {
+ throw new IllegalStateException("No successful match so far");
+ }
}
/**
- * Appends a literal part of the input plus a replacement for the current
- * match to a given {@link StringBuffer}. The literal part is exactly the
- * part of the input between the previous match and the current match. The
- * method can be used in conjunction with {@link #find()} and
- * {@link #appendTail(StringBuffer)} to walk through the input and replace
- * all occurrences of the {@code Pattern} with something else.
- *
- * @param buffer
- * the {@code StringBuffer} to append to.
- * @param replacement
- * the replacement text.
- * @return the {@code Matcher} itself.
- * @throws IllegalStateException
- * if no successful match has been made.
- * @since Android 1.0
+ * Indicates whether this matcher has transparent bounds enabled. When
+ * transparent bounds are enabled, the parts of the input outside the region
+ * are subject to lookahead and lookbehind, otherwise they are not.
+ * Transparent bounds are disabled by default.
+ *
+ * @return true if (and only if) the {@code Matcher} uses anchoring bounds.
*/
- public Matcher appendReplacement(StringBuffer buffer, String replacement)
- throws IllegalStateException {
-
- buffer.append(input.substring(appendPos, start()));
- appendEvaluated(buffer, replacement);
- appendPos = end();
-
- return this;
+ public boolean hasTransparentBounds() {
+ return transparentBounds;
}
/**
- * Appends the (unmatched) remainder of the input to the given
- * {@link StringBuffer}. The method can be used in conjunction with
- * {@link #find()} and {@link #appendReplacement(StringBuffer, String)} to
- * walk through the input and replace all matches of the {@code Pattern}
- * with something else.
- *
- * @param buffer
- * the {@code StringBuffer} to append to.
- * @return the {@code StringBuffer}.
- * @throws IllegalStateException
- * if no successful match has been made.
- * @since Android 1.0
+ * Returns this matcher's region start, that is, the first character that is
+ * considered for a match.
+ *
+ * @return the start of the region.
*/
- public StringBuffer appendTail(StringBuffer buffer) {
- if (appendPos < regionEnd) {
- buffer.append(input.substring(appendPos, regionEnd));
- }
-
- return buffer;
+ public int regionStart() {
+ return regionStart;
}
/**
- * Internal helper method to append a given string to a given string buffer.
- * If the string contains any references to groups, these are replaced by
- * the corresponding group's contents.
- *
- * @param buffer
- * the string buffer.
- * @param s
- * the string to append.
+ * Returns this matcher's region end, that is, the first character that is
+ * not considered for a match.
+ *
+ * @return the end of the region.
*/
- private void appendEvaluated(StringBuffer buffer, String s) {
- boolean escape = false;
- boolean dollar = false;
-
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- if (c == '\\' && !escape) {
- escape = true;
- } else if (c == '$' && !escape) {
- dollar = true;
- } else if (c >= '0' && c <= '9' && dollar) {
- buffer.append(group(c - '0'));
- dollar = false;
- } else {
- buffer.append(c);
- dollar = false;
- escape = false;
- }
- }
-
- // This seemingly stupid piece of code reproduces a JDK bug.
- if (escape) {
- throw new ArrayIndexOutOfBoundsException(s.length());
- }
+ public int regionEnd() {
+ return regionEnd;
}
-
+
/**
- * Replaces all occurrences of this matcher's pattern in the input with a
- * given string.
+ * Indicates whether more input might change a successful match into an
+ * unsuccessful one.
*
- * @param replacement
- * the replacement text.
- * @return the modified input string.
- * @since Android 1.0
+ * @return true if (and only if) more input might change a successful match
+ * into an unsuccessful one.
*/
- public String replaceAll(String replacement) {
- StringBuffer buffer = new StringBuffer(input.length());
-
- findPos = 0;
- appendPos = 0;
- matchFound = false;
- searching = false;
-
- while (find()) {
- appendReplacement(buffer, replacement);
- }
-
- return appendTail(buffer).toString();
+ public boolean requireEnd() {
+ return NativeRegEx.requireEnd(nativePattern);
}
/**
- * Replaces the first occurrence of this matcher's pattern in the input with
- * a given string.
- *
- * @param replacement
- * the replacement text.
- * @return the modified input string.
- * @since Android 1.0
+ * Indicates whether the last match hit the end of the input.
+ *
+ * @return true if (and only if) the last match hit the end of the input.
*/
- public String replaceFirst(String replacement) {
- StringBuffer buffer = new StringBuffer(input.length());
-
- findPos = 0;
- appendPos = 0;
- matchFound = false;
- searching = false;
-
- if (find()) {
- appendReplacement(buffer, replacement);
- }
-
- return appendTail(buffer).toString();
+ public boolean hitEnd() {
+ return NativeRegEx.hitEnd(nativePattern);
}
/**
- * Returns a replacement string for the given one that has all backslashes
- * and dollar signs escaped.
- *
- * @param s
- * the input string.
- * @return the input string, with all backslashes and dollar signs having
- * been escaped.
- * @since Android 1.0
+ * Sets a new pattern for the {@code Matcher}. Results of a previous find
+ * get lost. The next attempt to find an occurrence of the {@link Pattern}
+ * in the string will start at the beginning of the input.
+ *
+ * @param pattern
+ * the new {@code Pattern}.
+ *
+ * @return the {@code Matcher} itself.
*/
- public static String quoteReplacement(String s) {
- StringBuffer buffer = new StringBuffer(s.length());
-
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- if (c == '\\' || c == '$') {
- buffer.append('\\');
- }
- buffer.append(c);
+ public Matcher usePattern(Pattern pattern) {
+ if (pattern == null) {
+ throw new IllegalArgumentException();
}
-
- return buffer.toString();
+
+ this.pattern = pattern;
+
+ if (nativePattern != 0) {
+ NativeRegEx.close(nativePattern);
+ }
+ nativePattern = NativeRegEx.clone(pattern.mNativePattern);
+
+ if (input != null) {
+ NativeRegEx.setText(nativePattern, input);
+ NativeRegEx.setRegion(nativePattern, regionStart, regionEnd);
+ NativeRegEx.useAnchoringBounds(nativePattern, anchoringBounds);
+ NativeRegEx.useTransparentBounds(nativePattern, transparentBounds);
+ }
+
+ matchOffsets = new int[(this.pattern.mGroupCount + 1) * 2];
+ matchFound = false;
+ return this;
}
@Override
diff --git a/regex/src/main/java/java/util/regex/Pattern.java b/regex/src/main/java/java/util/regex/Pattern.java
index 2c71de1..db3bc21 100644
--- a/regex/src/main/java/java/util/regex/Pattern.java
+++ b/regex/src/main/java/java/util/regex/Pattern.java
@@ -47,7 +47,7 @@ import com.ibm.icu4jni.regex.NativeRegEx;
* boolean b2 = Pattern.matches("Hello, A[a-z]*!", "Hello, Robot!"); // false
* </pre>
* <p/>
- * Please consult the <a href="package-summary.html">package documentation</a> for an
+ * Please consult the <a href="package.html">package documentation</a> for an
* overview of the regular expression syntax used in this class as well as
* Android-specific implementation details.
*
@@ -61,8 +61,6 @@ public final class Pattern implements Serializable {
/**
* This constant specifies that a pattern matches Unix line endings ('\n')
* only against the '.', '^', and '$' meta characters.
- *
- * @since Android 1.0
*/
public static final int UNIX_LINES = 0x01;
@@ -76,8 +74,6 @@ public final class Pattern implements Serializable {
* constant. So if case insensitivity is enabled, this automatically extends
* to all Unicode characters. The {@code UNICODE_CASE} constant itself has
* no special consequences.
- *
- * @since Android 1.0
*/
public static final int CASE_INSENSITIVE = 0x02;
@@ -85,8 +81,6 @@ public final class Pattern implements Serializable {
* This constant specifies that a {@code Pattern} may contain whitespace or
* comments. Otherwise comments and whitespace are taken as literal
* characters.
- *
- * @since Android 1.0
*/
public static final int COMMENTS = 0x04;
@@ -94,24 +88,18 @@ public final class Pattern implements Serializable {
* This constant specifies that the meta characters '^' and '$' match only
* the beginning and end end of an input line, respectively. Normally, they
* match the beginning and the end of the complete input.
- *
- * @since Android 1.0
*/
public static final int MULTILINE = 0x08;
/**
* This constant specifies that the whole {@code Pattern} is to be taken
* literally, that is, all meta characters lose their meanings.
- *
- * @since Android 1.0
*/
public static final int LITERAL = 0x10;
/**
* This constant specifies that the '.' meta character matches arbitrary
* characters, including line endings, which is normally not the case.
- *
- * @since Android 1.0
*/
public static final int DOTALL = 0x20;
@@ -126,8 +114,6 @@ public final class Pattern implements Serializable {
* constant. So if case insensitivity is enabled, this automatically extends
* to all Unicode characters. The {@code UNICODE_CASE} constant then has no
* special consequences.
- *
- * @since Android 1.0
*/
public static final int UNICODE_CASE = 0x40;
@@ -135,8 +121,6 @@ public final class Pattern implements Serializable {
* This constant specifies that a character in a {@code Pattern} and a
* character in the input string only match if they are canonically
* equivalent. It is (currently) not supported in Android.
- *
- * @since Android 1.0
*/
public static final int CANON_EQ = 0x80;
@@ -159,24 +143,144 @@ public final class Pattern implements Serializable {
* Holds the number of groups in the pattern.
*/
transient int mGroupCount;
-
+
+
/**
- * Compiles a regular expression, creating a new Pattern instance in the
- * process. This is actually a convenience method that calls {@link
- * #compile(String, int)} with a {@code flags} value of zero.
- *
- * @param pattern
- * the regular expression.
- *
- * @return the new {@code Pattern} instance.
- *
- * @throws PatternSyntaxException
- * if the regular expression is syntactically incorrect.
- *
- * @since Android 1.0
+ * Returns a {@link Matcher} for the {@code Pattern} and a given input. The
+ * {@code Matcher} can be used to match the {@code Pattern} against the
+ * whole input, find occurrences of the {@code Pattern} in the input, or
+ * replace parts of the input.
+ *
+ * @param input
+ * the input to process.
+ *
+ * @return the resulting {@code Matcher}.
*/
- public static Pattern compile(String pattern) throws PatternSyntaxException {
- return new Pattern(pattern, 0);
+ public Matcher matcher(CharSequence input) {
+ return new Matcher(this, input);
+ }
+
+ /**
+ * Splits the given input sequence at occurrences of this {@code Pattern}.
+ *
+ * <p>If this {@code Pattern} does not occur in the input, the result is an
+ * array containing the input (converted from a {@code CharSequence} to
+ * a {@code String}).
+ *
+ * <p>Otherwise, the {@code limit} parameter controls the contents of the
+ * returned array as described below.
+ *
+ * @param inputSeq
+ * the input sequence.
+ * @param limit
+ * Determines the maximum number of entries in the resulting
+ * array, and the treatment of trailing empty strings.
+ * <ul>
+ * <li>For n &gt; 0, the resulting array contains at most n
+ * entries. If this is fewer than the number of matches, the
+ * final entry will contain all remaining input.
+ * <li>For n &lt; 0, the length of the resulting array is
+ * exactly the number of occurrences of the {@code Pattern}
+ * plus one for the text after the final separator.
+ * All entries are included.
+ * <li>For n == 0, the result is as for n &lt; 0, except
+ * trailing empty strings will not be returned. (Note that
+ * the case where the input is itself an empty string is
+ * special, as described above, and the limit parameter does
+ * not apply there.)
+ * </ul>
+ *
+ * @return the resulting array.
+ */
+ public String[] split(CharSequence inputSeq, int limit) {
+ if (inputSeq.length() == 0) {
+ // Unlike Perl, which considers the result of splitting the empty
+ // string to be the empty array, Java returns an array containing
+ // the empty string.
+ return new String[] { "" };
+ }
+
+ int maxLength = limit <= 0 ? Integer.MAX_VALUE : limit;
+
+ String input = inputSeq.toString();
+ ArrayList<String> list = new ArrayList<String>();
+
+ Matcher matcher = new Matcher(this, inputSeq);
+ int savedPos = 0;
+
+ // Add text preceding each occurrence, if enough space.
+ while(matcher.find() && list.size() + 1 < maxLength) {
+ list.add(input.substring(savedPos, matcher.start()));
+ savedPos = matcher.end();
+ }
+
+ // Add trailing text if enough space.
+ if (list.size() < maxLength) {
+ if (savedPos < input.length()) {
+ list.add(input.substring(savedPos));
+ } else {
+ list.add("");
+ }
+ }
+
+ // Remove trailing empty matches in the limit == 0 case.
+ if (limit == 0) {
+ int i = list.size() - 1;
+ while (i >= 0 && "".equals(list.get(i))) {
+ list.remove(i);
+ i--;
+ }
+ }
+
+ return list.toArray(new String[list.size()]);
+ }
+
+ /**
+ * Splits a given input around occurrences of a regular expression. This is
+ * a convenience method that is equivalent to calling the method
+ * {@link #split(java.lang.CharSequence, int)} with a limit of 0.
+ *
+ * @param input
+ * the input sequence.
+ *
+ * @return the resulting array.
+ */
+ public String[] split(CharSequence input) {
+ return split(input, 0);
+ }
+
+ /**
+ * Returns the regular expression that was compiled into this
+ * {@code Pattern}.
+ *
+ * @return the regular expression.
+ */
+ public String pattern() {
+ return pattern;
+ }
+
+ @Override
+ public String toString() {
+ return pattern;
+ }
+
+ /**
+ * Returns the flags that have been set for this {@code Pattern}.
+ *
+ * @return the flags that have been set. A combination of the constants
+ * defined in this class.
+ *
+ * @see #CANON_EQ
+ * @see #CASE_INSENSITIVE
+ * @see #COMMENTS
+ * @see #DOTALL
+ * @see #LITERAL
+ * @see #MULTILINE
+ * @see #UNICODE_CASE
+ * @see #UNIX_LINES
+ */
+ public int flags() {
+ return flags;
}
/**
@@ -208,8 +312,6 @@ public final class Pattern implements Serializable {
* @see #MULTILINE
* @see #UNICODE_CASE
* @see #UNIX_LINES
- *
- * @since Android 1.0
*/
public static Pattern compile(String pattern, int flags) throws PatternSyntaxException {
return new Pattern(pattern, flags);
@@ -238,7 +340,24 @@ public final class Pattern implements Serializable {
compileImpl(pattern, flags);
}
-
+
+ /**
+ * Compiles a regular expression, creating a new Pattern instance in the
+ * process. This is actually a convenience method that calls {@link
+ * #compile(String, int)} with a {@code flags} value of zero.
+ *
+ * @param pattern
+ * the regular expression.
+ *
+ * @return the new {@code Pattern} instance.
+ *
+ * @throws PatternSyntaxException
+ * if the regular expression is syntactically incorrect.
+ */
+ public static Pattern compile(String pattern) {
+ return new Pattern(pattern, 0);
+ }
+
/**
* Compiles the given regular expression using the given flags. Used
* internally only.
@@ -266,56 +385,6 @@ public final class Pattern implements Serializable {
}
/**
- * Returns the regular expression that was compiled into this
- * {@code Pattern}.
- *
- * @return the regular expression.
- *
- * @since Android 1.0
- */
- public String pattern() {
- return pattern;
- }
-
- /**
- * Returns the flags that have been set for this {@code Pattern}.
- *
- * @return the flags that have been set. A combination of the constants
- * defined in this class.
- *
- * @see #CANON_EQ
- * @see #CASE_INSENSITIVE
- * @see #COMMENTS
- * @see #DOTALL
- * @see #LITERAL
- * @see #MULTILINE
- * @see #UNICODE_CASE
- * @see #UNIX_LINES
- *
- * @since Android 1.0
- */
- public int flags() {
- return flags;
- }
-
- /**
- * Returns a {@link Matcher} for the {@code Pattern} and a given input. The
- * {@code Matcher} can be used to match the {@code Pattern} against the
- * whole input, find occurrences of the {@code Pattern} in the input, or
- * replace parts of the input.
- *
- * @param input
- * the input to process.
- *
- * @return the resulting {@code Matcher}.
- *
- * @since Android 1.0
- */
- public Matcher matcher(CharSequence input) {
- return new Matcher(this, input);
- }
-
- /**
* Tries to match a given regular expression against a given input. This is
* actually nothing but a convenience method that compiles the regular
* expression into a {@code Pattern}, builds a {@link Matcher} for it, and
@@ -332,107 +401,12 @@ public final class Pattern implements Serializable {
*
* @see Pattern#compile(java.lang.String, int)
* @see Matcher#matches()
- *
- * @since Android 1.0
*/
- static public boolean matches(String regex, CharSequence input) {
+ public static boolean matches(String regex, CharSequence input) {
return new Matcher(new Pattern(regex, 0), input).matches();
}
/**
- * Splits a given input around occurrences of a regular expression. This is
- * a convenience method that is equivalent to calling the method
- * {@link #split(java.lang.CharSequence, int)} with a limit of 0.
- *
- * @param input
- * the input sequence.
- *
- * @return the resulting array.
- *
- * @since Android 1.0
- */
- public String[] split(CharSequence input) {
- return split(input, 0);
- }
-
- /**
- * Splits the given input sequence at occurrences of this {@code Pattern}.
- *
- * If this {@code Pattern} does not occur in the input, the result is an
- * array containing the input (converted from a {@code CharSequence} to
- * a {@code String}).
- *
- * Otherwise, the {@code limit} parameter controls the contents of the
- * returned array as described below.
- *
- * @param inputSeq
- * the input sequence.
- * @param limit
- * Determines the maximum number of entries in the resulting
- * array, and the treatment of trailing empty strings.
- * <ul>
- * <li>For n &gt; 0, the resulting array contains at most n
- * entries. If this is fewer than the number of matches, the
- * final entry will contain all remaining input.
- * <li>For n &lt; 0, the length of the resulting array is
- * exactly the number of occurrences of the {@code Pattern}
- * plus one for the text after the final separator.
- * All entries are included.
- * <li>For n == 0, the result is as for n &lt; 0, except
- * trailing empty strings will not be returned. (Note that
- * the case where the input is itself an empty string is
- * special, as described above, and the limit parameter does
- * not apply there.)
- * </ul>
- *
- * @return the resulting array.
- *
- * @since Android 1.0
- */
- public String[] split(CharSequence inputSeq, int limit) {
- if (inputSeq.length() == 0) {
- // Unlike Perl, which considers the result of splitting the empty
- // string to be the empty array, Java returns an array containing
- // the empty string.
- return new String[] { "" };
- }
-
- int maxLength = limit <= 0 ? Integer.MAX_VALUE : limit;
-
- String input = inputSeq.toString();
- ArrayList<String> list = new ArrayList<String>();
-
- Matcher matcher = new Matcher(this, inputSeq);
- int savedPos = 0;
-
- // Add text preceding each occurrence, if enough space.
- while(matcher.find() && list.size() + 1 < maxLength) {
- list.add(input.substring(savedPos, matcher.start()));
- savedPos = matcher.end();
- }
-
- // Add trailing text if enough space.
- if (list.size() < maxLength) {
- if (savedPos < input.length()) {
- list.add(input.substring(savedPos));
- } else {
- list.add("");
- }
- }
-
- // Remove trailing empty matches in the limit == 0 case.
- if (limit == 0) {
- int i = list.size() - 1;
- while (i >= 0 && "".equals(list.get(i))) {
- list.remove(i);
- i--;
- }
- }
-
- return list.toArray(new String[list.size()]);
- }
-
- /**
* Quotes a given string using "\Q" and "\E", so that all other
* meta-characters lose their special meaning. If the string is used for a
* {@code Pattern} afterwards, it can only be matched literally.
@@ -441,27 +415,20 @@ public final class Pattern implements Serializable {
* the string to quote.
*
* @return the quoted string.
- *
- * @since Android 1.0
*/
public static String quote(String s) {
- StringBuffer sb = new StringBuffer().append("\\Q");
+ StringBuilder sb = new StringBuilder().append("\\Q"); //$NON-NLS-1$
int apos = 0;
int k;
- while ((k = s.indexOf("\\E", apos)) >= 0) {
- sb.append(s.substring(apos, k + 2)).append("\\\\E\\Q");
+ while ((k = s.indexOf("\\E", apos)) >= 0) { //$NON-NLS-1$
+ sb.append(s.substring(apos, k + 2)).append("\\\\E\\Q"); //$NON-NLS-1$
apos = k + 2;
}
- return sb.append(s.substring(apos)).append("\\E").toString();
+ return sb.append(s.substring(apos)).append("\\E").toString(); //$NON-NLS-1$
}
@Override
- public String toString() {
- return pattern;
- }
-
- @Override
protected void finalize() throws Throwable {
try {
if (mNativePattern != 0) {
@@ -474,7 +441,7 @@ public final class Pattern implements Serializable {
}
/**
- * Provides serialization support
+ * Serialization support
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
diff --git a/regex/src/main/java/java/util/regex/PatternSyntaxException.java b/regex/src/main/java/java/util/regex/PatternSyntaxException.java
index e4d5abd..d59bdd4 100644
--- a/regex/src/main/java/java/util/regex/PatternSyntaxException.java
+++ b/regex/src/main/java/java/util/regex/PatternSyntaxException.java
@@ -1,17 +1,18 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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
*
- * 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
*
- * 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.
+ * 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.regex;
@@ -25,24 +26,22 @@ import java.util.Arrays;
*
* @see Pattern#compile(String)
* @see Pattern#compile(java.lang.String,int)
- *
- * @since Android 1.0
*/
public class PatternSyntaxException extends IllegalArgumentException {
private static final long serialVersionUID = -3864639126226059218L;
-
- /**
- * Holds the syntactically incorrect regular expression, or null if the
- * regular expression is not known.
- */
- private String pattern;
/**
* Holds the description of the syntax error, or null if the description is
* not known.
*/
- private String description;
+ private String desc;
+
+ /**
+ * Holds the syntactically incorrect regular expression, or null if the
+ * regular expression is not known.
+ */
+ private String pattern;
/**
* Holds the index around which the error occured, or -1, in case it is
@@ -63,11 +62,10 @@ public class PatternSyntaxException extends IllegalArgumentException {
* @param index
* the character index around which the error occurred, or -1 if
* the index is not known.
- * @since Android 1.0
*/
public PatternSyntaxException(String description, String pattern, int index) {
+ this.desc = description;
this.pattern = pattern;
- this.description = description;
this.index = index;
}
@@ -76,7 +74,6 @@ public class PatternSyntaxException extends IllegalArgumentException {
*
* @return the regular expression.
*
- * @since Android 1.0
*/
public String getPattern() {
return pattern;
@@ -88,16 +85,15 @@ public class PatternSyntaxException extends IllegalArgumentException {
* original regular expression, and the index at which the error occured.
*
* @return the error message.
- *
- * @since Android 1.0
*/
@Override
public String getMessage() {
+ // BEGIN android-changed
StringBuilder builder = new StringBuilder("Syntax error");
- if (description != null) {
+ if (desc != null) {
builder.append(' ');
- builder.append(description);
+ builder.append(desc);
}
if (index >= 0) {
@@ -118,6 +114,7 @@ public class PatternSyntaxException extends IllegalArgumentException {
}
return builder.toString();
+ // END android-changed
}
/**
@@ -125,10 +122,9 @@ public class PatternSyntaxException extends IllegalArgumentException {
* description is not known.
*
* @return the description.
- * @since Android 1.0
*/
public String getDescription() {
- return description;
+ return desc;
}
/**
@@ -137,10 +133,8 @@ public class PatternSyntaxException extends IllegalArgumentException {
*
* @return the index.
*
- * @since Android 1.0
*/
public int getIndex() {
return index;
}
-
}
diff --git a/sql/src/main/native/sqlite_jni.c b/sql/src/main/native/sqlite_jni.c
index 4923869..1a23769 100644
--- a/sql/src/main/native/sqlite_jni.c
+++ b/sql/src/main/native/sqlite_jni.c
@@ -1,3 +1,5 @@
+#include "JNIHelp.h"
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -276,23 +278,13 @@ freep(char **strp)
static void
throwex(JNIEnv *env, const char *msg)
{
- jclass except = (*env)->FindClass(env, "SQLite/Exception");
-
- (*env)->ExceptionClear(env);
- if (except) {
- (*env)->ThrowNew(env, except, msg);
- }
+ jniThrowException(env, "SQLite/Exception", msg);
}
static void
throwoom(JNIEnv *env, const char *msg)
{
- jclass except = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
-
- (*env)->ExceptionClear(env);
- if (except) {
- (*env)->ThrowNew(env, except, msg);
- }
+ jniThrowException(env, "java/lang/OutOfMemoryError", msg);
}
static void
@@ -305,12 +297,7 @@ throwclosed(JNIEnv *env)
static void
throwioex(JNIEnv *env, const char *msg)
{
- jclass except = (*env)->FindClass(env, "java/io/IOException");
-
- (*env)->ExceptionClear(env);
- if (except) {
- (*env)->ThrowNew(env, except, msg);
- }
+ jniThrowException(env, "java/io/IOException", msg);
}
#endif
@@ -331,16 +318,10 @@ trans2iso(JNIEnv *env, int haveutf, jstring enc, jstring src,
dest->result = 0;
dest->tofree = 0;
if (haveutf) {
- const char *utf = (*env)->GetStringUTFChars(env, src, 0);
-
- if (!utf) {
- return dest->result;
- }
- dest->tofree = malloc(strlen(utf) + 1);
- dest->result = dest->tofree;
- strcpy(dest->result, utf);
- (*env)->ReleaseStringUTFChars(env, src, utf);
- return dest->result;
+ const jsize utfLength = (*env)->GetStringUTFLength(env, src);
+ dest->result = dest->tofree = malloc(utfLength + 1);
+ (*env)->GetStringUTFRegion(env, src, 0, utfLength, dest->result);
+ return dest->result;
}
if (enc) {
bytes = (*env)->CallObjectMethod(env, src,
@@ -1331,11 +1312,10 @@ Java_SQLite_Database__1exec__Ljava_lang_String_2LSQLite_Callback_2_3Ljava_lang_S
}
if (h) {
if (h->sqlite) {
- jboolean b;
jthrowable exc;
int rc = SQLITE_ERROR, nargs, i;
char *err = 0, *p;
- const char *str = (*env)->GetStringUTFChars(env, sql, &b);
+ const char *str = (*env)->GetStringUTFChars(env, sql, NULL);
transstr sqlstr;
struct args {
char *arg;
@@ -3009,10 +2989,9 @@ Java_SQLite_Database_vm_1compile_1args(JNIEnv *env,
hvm *v;
jvalue vv;
jthrowable exc;
- jboolean b;
int rc = SQLITE_ERROR, nargs, i;
char *p;
- const char *str = (*env)->GetStringUTFChars(env, sql, &b);
+ const char *str = (*env)->GetStringUTFChars(env, sql, NULL);
const char *tail;
transstr sqlstr;
struct args {
@@ -3401,7 +3380,7 @@ Java_SQLite_Database_stmt_1prepare(JNIEnv *env, jobject obj, jstring sql,
return;
}
len16 = len16 + sizeof (jchar) - ((char *) tail - (char *) sql16);
- if (len16 < sizeof (jchar)) {
+ if (len16 < (jsize) sizeof (jchar)) {
len16 = sizeof (jchar);
}
v = malloc(sizeof (hvm) + len16);
@@ -3674,19 +3653,16 @@ Java_SQLite_Stmt_bind__ILjava_lang_String_2(JNIEnv *env, jobject obj,
return;
}
if (val) {
- len = (*env)->GetStringLength(env, val);
+ const jsize charCount = (*env)->GetStringLength(env, val);
+ len = charCount * sizeof(jchar);
if (len > 0) {
- const jchar *ch;
-
- len *= sizeof (jchar);
data = sqlite3_malloc(len);
if (!data) {
throwoom(env, "unable to get blob parameter");
return;
}
- ch = (*env)->GetStringChars(env, val, 0);
- memcpy(data, ch, len);
- (*env)->ReleaseStringChars(env, val, ch);
+
+ (*env)->GetStringRegion(env, val, 0, charCount, (jchar*) data);
ret = sqlite3_bind_text16((sqlite3_stmt *) v->vm,
pos, data, len, sqlite3_free);
} else {
diff --git a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLInputStream.java b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLInputStream.java
index 6c23a91..507e14f 100644
--- a/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLInputStream.java
+++ b/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLInputStream.java
@@ -94,10 +94,11 @@ public abstract class SSLInputStream extends InputStream {
* Reads and returns uint64 value.
*/
public long readUint64() throws IOException {
- return (read() << 56) | (read() << 48)
- | (read() << 40) | (read() << 32)
- | (read() << 24) | (read() << 16)
- | (read() << 8) | (read() & 0x00FF);
+ // BEGIN android-changed
+ long hi = readUint32();
+ long lo = readUint32();
+ return (hi << 32) | lo;
+ // END android-changed
}
/**
@@ -131,4 +132,3 @@ public abstract class SSLInputStream extends InputStream {
return i;
}
}
-
diff --git a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl.cpp b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl.cpp
index 13a1e61..2a55bbc 100644
--- a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl.cpp
+++ b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl.cpp
@@ -41,20 +41,10 @@
static jfieldID field_ssl_ctx;
/**
- * Throws java.io.IOexception with the provided message.
+ * Throws java.io.IOException with the provided message.
*/
-static void throwIOExceptionStr(JNIEnv* env, const char* message)
-{
- jclass exClass = env->FindClass("java/io/IOException");
-
- if (exClass == NULL)
- {
- LOGE("Unable to find class java/io/IOException");
- }
- else
- {
- env->ThrowNew(exClass, message);
- }
+static void throwIOExceptionStr(JNIEnv* env, const char* message) {
+ jniThrowException(env, "java/io/IOException", message);
}
/**
@@ -87,9 +77,9 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_init(J
// 'seed == null' when no SecureRandom Object is set
// in the SSLContext.
if (seed != NULL) {
- jboolean iscopy = JNI_FALSE;
- jbyte* randseed = env->GetByteArrayElements(seed, &iscopy);
+ jbyte* randseed = env->GetByteArrayElements(seed, NULL);
RAND_seed((unsigned char*) randseed, 1024);
+ env->ReleaseByteArrayElements(seed, randseed, 0);
} else {
RAND_load_file("/dev/urandom", 1024);
}
@@ -251,8 +241,8 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_setena
ret = SSL_CTX_set_cipher_list(ctx, str);
if(ret == 0) {
- jclass exClass = env->FindClass("java/lang/IllegalArgumentException");
- env->ThrowNew(exClass, "Illegal cipher suite strings.");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Illegal cipher suite strings.");
}
}
diff --git a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp
index feae690..324dacf 100644
--- a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp
+++ b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl.cpp
@@ -47,20 +47,6 @@ static SSL_SESSION *getSslSessionPointer(JNIEnv* env, jobject object) {
}
/**
- * Throws java.io.IOexception with the provided message.
- */
-static void throwIOExceptionStr(JNIEnv* env, const char* message)
-{
- jclass exClass = env->FindClass("java/io/IOException");
-
- if (exClass == NULL) {
- LOGE("Unable to find class java/io/IOException");
- } else {
- env->ThrowNew(exClass, message);
- }
-}
-
-/**
* Gets the peer certificate in the chain and fills a byte array with the
* information therein.
*/
@@ -150,20 +136,15 @@ static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_deserialize
*/
static jbyteArray org_apache_harmony_xnet_provider_jsse_OpenSSLSessionImpl_getid(JNIEnv* env, jobject object)
{
- SSL_SESSION * ssl_session;
- jbyteArray bytes;
- jbyte *tmp;
-
- ssl_session = getSslSessionPointer(env, object);
+ SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
- bytes = env->NewByteArray(ssl_session->session_id_length);
- if (bytes != NULL) {
- tmp = env->GetByteArrayElements(bytes, NULL);
- memcpy(tmp, ssl_session->session_id, ssl_session->session_id_length);
- env->ReleaseByteArrayElements(bytes, tmp, 0);
+ jbyteArray result = env->NewByteArray(ssl_session->session_id_length);
+ if (result != NULL) {
+ jbyte* src = reinterpret_cast<jbyte*>(ssl_session->session_id);
+ env->SetByteArrayRegion(result, 0, ssl_session->session_id_length, src);
}
- return bytes;
+ return result;
}
/**
diff --git a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
index 87f2af3..2e1adb1 100644
--- a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
+++ b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
@@ -989,9 +989,9 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_init(JNIEnv*
// 'seed == null' when no SecureRandom Object is set
// in the SSLContext.
if (seed != NULL) {
- jboolean iscopy = JNI_FALSE;
- jbyte* randseed = env->GetByteArrayElements(seed, &iscopy);
+ jbyte* randseed = env->GetByteArrayElements(seed, NULL);
RAND_seed((unsigned char*) randseed, 1024);
+ env->ReleaseByteArrayElements(seed, randseed, 0);
} else {
RAND_load_file("/dev/urandom", 1024);
}
@@ -1500,8 +1500,8 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_setenabledci
if (ret == 0) {
freeSslErrorState();
- jclass exClass = env->FindClass("java/lang/IllegalArgumentException");
- env->ThrowNew(exClass, "Illegal cipher suite strings.");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Illegal cipher suite strings.");
}
}
diff --git a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_common.h b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_common.h
index 9ed75be..409b4ec 100644
--- a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_common.h
+++ b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_common.h
@@ -76,9 +76,8 @@ static jobjectArray getcertificatebytes(JNIEnv* env,
joa = NULL;
break;
} else {
- jbyte *tmp = env->GetByteArrayElements(bytes, NULL);
- memcpy(tmp, bptr->data, bptr->length);
- env->ReleaseByteArrayElements(bytes, tmp, 0);
+ jbyte* src = reinterpret_cast<jbyte*>(bptr->data);
+ env->SetByteArrayRegion(bytes, 0, bptr->length, src);
env->SetObjectArrayElement(joa, i, bytes);
}
}
diff --git a/x-net/src/test/java/tests/api/javax/net/ssl/SSLServerSocketTest.java b/x-net/src/test/java/tests/api/javax/net/ssl/SSLServerSocketTest.java
index 3c1fb2e..c4bae0a 100644
--- a/x-net/src/test/java/tests/api/javax/net/ssl/SSLServerSocketTest.java
+++ b/x-net/src/test/java/tests/api/javax/net/ssl/SSLServerSocketTest.java
@@ -32,6 +32,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.security.KeyStore;
+import java.security.SecureRandom;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
@@ -585,4 +586,26 @@ public class SSLServerSocketTest extends TestCase {
.createServerSocket();
return sss;
}
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Guard against native resource leakage.",
+ method = "SSLSocket",
+ args = {}
+ )
+ public void test_creationStressTest() throws Exception {
+ KeyManager[] keyManagers = getKeyManagers();
+ // Test the default codepath, which uses /dev/urandom.
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(keyManagers, null, null);
+ for (int i = 0; i < 2048; ++i) {
+ sslContext.getServerSocketFactory().createServerSocket();
+ }
+
+ // Test the other codepath, which copies a seed from a byte[].
+ sslContext.init(keyManagers, null, new SecureRandom());
+ for (int i = 0; i < 2048; ++i) {
+ sslContext.getServerSocketFactory().createServerSocket();
+ }
+ }
}
diff --git a/x-net/src/test/java/tests/api/javax/net/ssl/SSLSocketTest.java b/x-net/src/test/java/tests/api/javax/net/ssl/SSLSocketTest.java
index 5e39cb1..13a0e59 100644
--- a/x-net/src/test/java/tests/api/javax/net/ssl/SSLSocketTest.java
+++ b/x-net/src/test/java/tests/api/javax/net/ssl/SSLSocketTest.java
@@ -26,6 +26,7 @@ import javax.security.cert.X509Certificate;
import java.net.*;
import java.security.KeyStore;
+import java.security.SecureRandom;
import java.lang.String;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -336,6 +337,27 @@ public class SSLSocketTest extends TestCase {
}
}
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Guard against native resource leakage.",
+ method = "SSLSocket",
+ args = {}
+ )
+ public void test_creationStressTest() throws Exception {
+ // Test the default codepath, which uses /dev/urandom.
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, null, null);
+ for (int i = 0; i < 2048; ++i) {
+ sslContext.getSocketFactory().createSocket();
+ }
+
+ // Test the other codepath, which copies a seed from a byte[].
+ sslContext.init(null, null, new SecureRandom());
+ for (int i = 0; i < 2048; ++i) {
+ sslContext.getSocketFactory().createSocket();
+ }
+ }
+
/**
* @throws IOException
* @tests javax.net.ssl.SSLSocket#addHandshakeCompletedListener(HandshakeCompletedListener listener)
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java
index f71d289..2fd16d0 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/InnerNodeImpl.java
@@ -69,7 +69,7 @@ public abstract class InnerNodeImpl extends LeafNodeImpl {
}
public Node getNextSibling() {
- if (parent == null || index >= parent.children.size()) {
+ if (parent == null || index + 1 >= parent.children.size()) {
return null;
}
diff --git a/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
index 40a4116..15f1d28 100644
--- a/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
+++ b/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
@@ -105,16 +105,7 @@ static jclass stringClass;
static jstring emptyString;
/**
- * Throws a NullPointerException.
- *
- * @param msg exception message
- */
-static void throw_NullPointerException(JNIEnv* env, const char* msg) {
- jniThrowException(env, "java/lang/NullPointerException", msg);
-}
-
-/**
- * Throw a NullPointerException.
+ * Throws OutOfMemoryError.
*/
static void throw_OutOfMemoryError(JNIEnv* env) {
jniThrowException(env, "java/lang/OutOfMemoryError", "Out of memory.");
@@ -336,15 +327,9 @@ static jstring internStringOfLength(JNIEnv* env, ParsingContext* parsingContext,
return internString(env, parsingContext, nullTerminated);
}
-/**
- * Throw an assertion error.
- *
- * @param message to show
- */
-static void fail(JNIEnv* env, const char* message) {
- jclass clazz;
- clazz = env->FindClass("java/lang/AssertionError");
- env->ThrowNew(clazz, message);
+static void jniThrowExpatException(JNIEnv* env, XML_Error error) {
+ const char* message = XML_ErrorString(error);
+ jniThrowException(env, "org/apache/harmony/xml/ExpatException", message);
}
/**
@@ -1010,9 +995,7 @@ static void appendString(JNIEnv* env, jobject object, jint pointer, jstring xml,
if (!XML_Parse(parser, (char*) characters, length, isFinal)
&& !env->ExceptionCheck()) {
- jclass clazz = env->FindClass("org/apache/harmony/xml/ExpatException");
- const char* errorMessage = XML_ErrorString(XML_GetErrorCode(parser));
- env->ThrowNew(clazz, errorMessage);
+ jniThrowExpatException(env, XML_GetErrorCode(parser));
}
// We have to temporarily clear an exception before we can release local
@@ -1050,9 +1033,7 @@ static void appendCharacters(JNIEnv* env, jobject object, jint pointer,
if (!XML_Parse(parser, ((char*) characters) + (offset << 1),
length << 1, XML_FALSE) && !env->ExceptionCheck()) {
- jclass clazz = env->FindClass("org/apache/harmony/xml/ExpatException");
- const char* errorMessage = XML_ErrorString(XML_GetErrorCode(parser));
- env->ThrowNew(clazz, errorMessage);
+ jniThrowExpatException(env, XML_GetErrorCode(parser));
}
// We have to temporarily clear an exception before we can release local
@@ -1090,9 +1071,7 @@ static void appendBytes(JNIEnv* env, jobject object, jint pointer,
if (!XML_Parse(parser, ((char*) bytes) + offset, length, XML_FALSE)
&& !env->ExceptionCheck()) {
- jclass clazz = env->FindClass("org/apache/harmony/xml/ExpatException");
- const char* errorMessage = XML_ErrorString(XML_GetErrorCode(parser));
- env->ThrowNew(clazz, errorMessage);
+ jniThrowExpatException(env, XML_GetErrorCode(parser));
}
// We have to temporarily clear an exception before we can release local
@@ -1308,26 +1287,21 @@ static jint getAttributeIndex(JNIEnv* env, jobject clazz,
return getAttributeIndexForQName(
env, clazz, attributePointer, localName);
}
-
int localNameLength = env->GetStringUTFLength(localName);
// Create string in the same format used by Expat: "uri|localName"
+ // TODO: do we have a guarantee that uriLength and localNameLength are small?
char concatenated[uriLength + localNameLength + 2];
// Append uri.
- const char* uriBytes = env->GetStringUTFChars(uri, NULL);
- if (uriBytes == NULL) return -1;
- strcpy(concatenated, uriBytes);
- env->ReleaseStringUTFChars(uri, uriBytes);
+ env->GetStringUTFRegion(uri, 0, uriLength, concatenated);
- // Separarator.
+ // Separator.
concatenated[uriLength] = '|';
// Append local name.
- const char* localNameBytes = env->GetStringUTFChars(localName, NULL);
- if (localNameBytes == NULL) return -1;
- strcpy(concatenated + uriLength + 1, localNameBytes);
- env->ReleaseStringUTFChars(localName, localNameBytes);
+ env->GetStringUTFRegion(localName, 0, localNameLength,
+ concatenated + uriLength + 1);
return findAttributeByName(attributes, concatenated);
}
diff --git a/xml/src/test/java/tests/api/javax/xml/parsers/SAXParserTestSupport.java b/xml/src/test/java/tests/api/javax/xml/parsers/SAXParserTestSupport.java
index bc5e6a1..a1627ba 100644
--- a/xml/src/test/java/tests/api/javax/xml/parsers/SAXParserTestSupport.java
+++ b/xml/src/test/java/tests/api/javax/xml/parsers/SAXParserTestSupport.java
@@ -54,7 +54,7 @@ class SAXParserTestSupport {
public static final String KEY_ERROR = "error";
public static final String KEY_FATAL_ERROR = "fatalError";
public static final String KEY_WARNING = "warning";
- public static final String KEY_END_ELEMENT = "endEement";
+ public static final String KEY_END_ELEMENT = "endElement";
public static final String KEY_END_PREFIX_MAPPING = "endPrefixMapping";
public static final String KEY_IGNORABLE_WHITE_SPACE =
"ignorableWhitespace";
diff --git a/xml/src/test/java/tests/xml/AllTests.java b/xml/src/test/java/tests/xml/AllTests.java
index eefae50..8c089e3 100644
--- a/xml/src/test/java/tests/xml/AllTests.java
+++ b/xml/src/test/java/tests/xml/AllTests.java
@@ -26,6 +26,7 @@ public class AllTests {
suite.addTestSuite(SimpleParserTest.class);
suite.addTestSuite(SimpleBuilderTest.class);
+ suite.addTestSuite(NodeTests.class);
//suite.addTest(tests.org.w3c.dom.AllTests.suite());
suite.addTest(tests.api.javax.xml.parsers.AllTests.suite());
diff --git a/xml/src/test/java/tests/xml/NodeTests.java b/xml/src/test/java/tests/xml/NodeTests.java
new file mode 100644
index 0000000..e46e216
--- /dev/null
+++ b/xml/src/test/java/tests/xml/NodeTests.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * 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 tests.xml;
+
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargetClass;
+
+import junit.framework.TestCase;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import java.io.ByteArrayInputStream;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+@TestTargetClass(Node.class)
+public class NodeTests extends TestCase {
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Issue #779: org.w3c.dom.Node#getNextSibling throws IndexOutOfBoundsException.",
+ method = "getNextSibling",
+ args = {}
+ )
+ public void test_getNextSibling() throws Exception {
+ // Calling getNextSibling when there is no next sibling should return null.
+ // From http://code.google.com/p/android/issues/detail?id=779.
+ ByteArrayInputStream bis = new ByteArrayInputStream("<root/>".getBytes());
+ Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(bis);
+ Node root = document.getDocumentElement();
+ assertNull(root.getNextSibling());
+ }
+}