summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--annotation/src/main/java/java/lang/annotation/Annotation.java26
-rw-r--r--annotation/src/main/java/java/lang/annotation/AnnotationFormatError.java17
-rw-r--r--annotation/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java17
-rw-r--r--annotation/src/main/java/java/lang/annotation/Documented.java4
-rw-r--r--annotation/src/main/java/java/lang/annotation/ElementType.java4
-rw-r--r--annotation/src/main/java/java/lang/annotation/IncompleteAnnotationException.java16
-rw-r--r--annotation/src/main/java/java/lang/annotation/Inherited.java4
-rw-r--r--annotation/src/main/java/java/lang/annotation/Retention.java7
-rw-r--r--annotation/src/main/java/java/lang/annotation/RetentionPolicy.java4
-rw-r--r--annotation/src/main/java/java/lang/annotation/Target.java4
-rw-r--r--annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTypeMismatchExceptionTest.java2
-rw-r--r--annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/IncompleteAnnotationExceptionTest.java2
-rw-r--r--archive/src/main/java/java/util/jar/Attributes.java185
-rw-r--r--archive/src/main/java/java/util/jar/InitManifest.java373
-rw-r--r--archive/src/main/java/java/util/jar/JarEntry.java19
-rw-r--r--archive/src/main/java/java/util/jar/JarException.java7
-rw-r--r--archive/src/main/java/java/util/jar/JarFile.java142
-rw-r--r--archive/src/main/java/java/util/jar/JarInputStream.java25
-rw-r--r--archive/src/main/java/java/util/jar/JarOutputStream.java3
-rw-r--r--archive/src/main/java/java/util/jar/JarVerifier.java213
-rw-r--r--archive/src/main/java/java/util/jar/Manifest.java289
-rw-r--r--archive/src/main/java/java/util/jar/Pack200.java72
-rw-r--r--archive/src/main/java/java/util/zip/Adler32.java10
-rw-r--r--archive/src/main/java/java/util/zip/CRC32.java11
-rw-r--r--archive/src/main/java/java/util/zip/CheckedInputStream.java8
-rw-r--r--archive/src/main/java/java/util/zip/CheckedOutputStream.java7
-rw-r--r--archive/src/main/java/java/util/zip/Checksum.java25
-rw-r--r--archive/src/main/java/java/util/zip/DataFormatException.java7
-rw-r--r--archive/src/main/java/java/util/zip/Deflater.java94
-rw-r--r--archive/src/main/java/java/util/zip/DeflaterOutputStream.java15
-rw-r--r--archive/src/main/java/java/util/zip/GZIPInputStream.java77
-rw-r--r--archive/src/main/java/java/util/zip/GZIPOutputStream.java33
-rw-r--r--archive/src/main/java/java/util/zip/Inflater.java205
-rw-r--r--archive/src/main/java/java/util/zip/InflaterInputStream.java67
-rw-r--r--archive/src/main/java/java/util/zip/ZipConstants.java1
-rw-r--r--archive/src/main/java/java/util/zip/ZipEntry.java74
-rw-r--r--archive/src/main/java/java/util/zip/ZipException.java7
-rw-r--r--archive/src/main/java/java/util/zip/ZipFile.java57
-rw-r--r--archive/src/main/java/java/util/zip/ZipInputStream.java44
-rw-r--r--archive/src/main/java/java/util/zip/ZipOutputStream.java29
-rw-r--r--archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java15
-rw-r--r--archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties13
-rw-r--r--archive/src/main/java/org/apache/harmony/archive/util/Util.java60
-rw-r--r--archive/src/main/native/java_util_zip_Adler32.c15
-rw-r--r--archive/src/main/native/java_util_zip_CRC32.c5
-rw-r--r--archive/src/main/native/java_util_zip_Deflater.c73
-rw-r--r--archive/src/main/native/java_util_zip_Inflater.c56
-rw-r--r--archive/src/main/native/sieb.c14
-rw-r--r--archive/src/main/native/sieb.h5
-rw-r--r--archive/src/main/native/sub.mk3
-rw-r--r--archive/src/main/native/zip.c37
-rw-r--r--archive/src/main/native/zip.h70
-rw-r--r--archive/src/main/native/zipsup.c2
-rw-r--r--archive/src/main/native/zipsup.h26
-rw-r--r--archive/src/test/java-internal/org/apache/harmony/archive/util/UtilTest.java87
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java23
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java42
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java334
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java51
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java721
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java40
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java2
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java37
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java119
-rw-r--r--archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java20
-rw-r--r--auth/src/main/java/javax/security/auth/AuthPermission.java16
-rw-r--r--auth/src/main/java/javax/security/auth/DestroyFailedException.java4
-rw-r--r--auth/src/main/java/javax/security/auth/Destroyable.java6
-rw-r--r--auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java19
-rw-r--r--auth/src/main/java/javax/security/auth/Subject.java40
-rw-r--r--auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java8
-rw-r--r--auth/src/main/java/javax/security/auth/callback/Callback.java2
-rw-r--r--auth/src/main/java/javax/security/auth/callback/CallbackHandler.java4
-rw-r--r--auth/src/main/java/javax/security/auth/callback/PasswordCallback.java12
-rw-r--r--auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java8
-rw-r--r--auth/src/main/java/javax/security/auth/login/LoginException.java4
-rw-r--r--auth/src/main/java/javax/security/auth/x500/X500Principal.java32
-rw-r--r--dalvik/src/main/java/dalvik/system/DexFile.java38
-rw-r--r--dalvik/src/main/java/dalvik/system/PathClassLoader.java12
-rw-r--r--dalvik/src/main/java/dalvik/system/VMDebug.java7
-rw-r--r--icu/src/main/native/DecimalFormatInterface.cpp2
-rw-r--r--icu/src/main/native/ResourceInterface.cpp5
-rw-r--r--logging/src/main/java/java/util/logging/ConsoleHandler.java13
-rw-r--r--logging/src/main/java/java/util/logging/ErrorManager.java22
-rw-r--r--logging/src/main/java/java/util/logging/FileHandler.java80
-rw-r--r--logging/src/main/java/java/util/logging/Filter.java3
-rw-r--r--logging/src/main/java/java/util/logging/Formatter.java35
-rw-r--r--logging/src/main/java/java/util/logging/Handler.java100
-rw-r--r--logging/src/main/java/java/util/logging/Level.java78
-rw-r--r--logging/src/main/java/java/util/logging/LogManager.java229
-rw-r--r--logging/src/main/java/java/util/logging/LogRecord.java111
-rw-r--r--logging/src/main/java/java/util/logging/Logger.java320
-rw-r--r--logging/src/main/java/java/util/logging/LoggingMXBean.java17
-rw-r--r--logging/src/main/java/java/util/logging/LoggingPermission.java16
-rw-r--r--logging/src/main/java/java/util/logging/MemoryHandler.java128
-rw-r--r--logging/src/main/java/java/util/logging/SimpleFormatter.java13
-rw-r--r--logging/src/main/java/java/util/logging/SocketHandler.java16
-rw-r--r--logging/src/main/java/java/util/logging/StreamHandler.java71
-rw-r--r--logging/src/main/java/java/util/logging/XMLFormatter.java136
-rw-r--r--logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LoggerTest.java22
-rw-r--r--logging/src/test/resources/config/java/util/logging/logging.config2
-rw-r--r--luni-kernel/src/main/java/java/lang/Thread.java60
-rw-r--r--luni-kernel/src/main/native/java_lang_ProcessManager.c3
-rw-r--r--luni/src/main/java/java/util/ComparableTimSort.java2
-rw-r--r--luni/src/main/java/java/util/TimSort.java2
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/util/InputStreamExposer.java117
-rw-r--r--luni/src/main/java/org/apache/harmony/luni/util/ThreadLocalCache.java103
-rw-r--r--luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp86
-rw-r--r--[-rwxr-xr-x]luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp1285
-rw-r--r--luni/src/test/java/com/google/coretests/CoreTestResult.java7
-rw-r--r--luni/src/test/java/com/google/coretests/CoreTestRunnable.java14
-rw-r--r--luni/src/test/java/org/apache/harmony/luni/tests/java/lang/ThreadTest.java55
-rw-r--r--luni/src/test/java/tests/api/java/io/InputStreamReaderTest.java6
-rwxr-xr-xnio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/SocketChannelTest.java91
-rw-r--r--prefs/src/main/java/java/util/prefs/Preferences.java14
-rw-r--r--text/src/main/java/java/text/RuleBasedCollator.java2
-rw-r--r--x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp18
118 files changed, 4114 insertions, 3460 deletions
diff --git a/Android.mk b/Android.mk
index b22b4c0..7de73be 100644
--- a/Android.mk
+++ b/Android.mk
@@ -51,7 +51,7 @@ include $(BUILD_JAVA_LIBRARY)
# resource with a "#" in its name, but Perforce doesn't
# allow us to submit such a file. So we create it here
# on-the-fly.
-TMP_RESOURCE_DIR := /tmp/
+TMP_RESOURCE_DIR := $(OUT_DIR)/tmp/
TMP_RESOURCE_FILE := org/apache/harmony/luni/tests/java/lang/test\#.properties
$(TMP_RESOURCE_DIR)$(TMP_RESOURCE_FILE):
diff --git a/annotation/src/main/java/java/lang/annotation/Annotation.java b/annotation/src/main/java/java/lang/annotation/Annotation.java
index 43ad1bb..00707b1 100644
--- a/annotation/src/main/java/java/lang/annotation/Annotation.java
+++ b/annotation/src/main/java/java/lang/annotation/Annotation.java
@@ -22,17 +22,15 @@ package java.lang.annotation;
* itself is <i>not</i> an annotation, and neither is an interface that simply
* extends this one. Only the compiler is able to create proper annotation
* types.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public interface Annotation {
/**
* Returns the type of this annotation.
- *
+ *
* @return A {@code Class} instance representing the annotation type.
- *
- * @since Android 1.0
*/
Class<? extends Annotation> annotationType();
@@ -70,14 +68,12 @@ public interface Annotation {
* calling their {@code equals()} method.
* </li>
* </ul>
- *
+ *
* @param obj
* The object to compare to.
- *
- * @return {@code true} if {@code obj} is equal to this annotation,
- * {@code false} otherwise.
- *
- * @since Android 1.0
+ *
+ * @return {@code true} if {@code obj} is equal to this annotation,
+ * {@code false} otherwise.
*/
boolean equals(Object obj);
@@ -111,10 +107,8 @@ public interface Annotation {
* calling their {@code hashCode} method.
* </li>
* </ul>
- *
+ *
* @return the hash code.
- *
- * @since Android 1.0
*/
int hashCode();
@@ -123,11 +117,9 @@ public interface Annotation {
* strictly defined what the representation has to look like, but it usually
* consists of the name of the annotation, preceded by a "@". If the
* annotation contains field members, their names and values are also
- * included in the result.
+ * included in the result.
*
* @return the {@code String} that represents this annotation.
- *
- * @since Android 1.0
*/
String toString();
}
diff --git a/annotation/src/main/java/java/lang/annotation/AnnotationFormatError.java b/annotation/src/main/java/java/lang/annotation/AnnotationFormatError.java
index ce5c3a0..67775c7 100644
--- a/annotation/src/main/java/java/lang/annotation/AnnotationFormatError.java
+++ b/annotation/src/main/java/java/lang/annotation/AnnotationFormatError.java
@@ -22,8 +22,8 @@ package java.lang.annotation;
* syntactically incorrect and the annotation parser is unable to process it.
* This exception is unlikely to ever occur, given that the code has been
* compiled by an ordinary Java compiler.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public class AnnotationFormatError extends Error {
@@ -31,11 +31,9 @@ public class AnnotationFormatError extends Error {
/**
* Constructs an instance with the message provided.
- *
+ *
* @param message
* the details of the error.
- *
- * @since Android 1.0
*/
public AnnotationFormatError(String message) {
super(message);
@@ -43,14 +41,11 @@ public class AnnotationFormatError extends Error {
/**
* Constructs an instance with a message and a cause.
- *
+ *
* @param message
* the details of the error.
- *
* @param cause
* the cause of the error or {@code null} if none.
- *
- * @since Android 1.0
*/
public AnnotationFormatError(String message, Throwable cause) {
super(message, cause);
@@ -60,11 +55,9 @@ public class AnnotationFormatError extends Error {
* Constructs an instance with a cause. If the cause is not
* {@code null}, then {@code cause.toString()} is used as the
* error's message.
- *
+ *
* @param cause
* the cause of the error or {@code null} if none.
- *
- * @since Android 1.0
*/
public AnnotationFormatError(Throwable cause) {
super(cause == null ? null : cause.toString(), cause);
diff --git a/annotation/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java b/annotation/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java
index 5bb3cbf..0ff79ec 100644
--- a/annotation/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java
+++ b/annotation/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java
@@ -24,8 +24,8 @@ import org.apache.harmony.annotation.internal.nls.Messages;
/**
* Indicates that an annotation type has changed since it was compiled or
* serialized.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public class AnnotationTypeMismatchException extends RuntimeException {
@@ -37,16 +37,13 @@ public class AnnotationTypeMismatchException extends RuntimeException {
/**
* Constructs an instance for the given type element and the type found.
- *
+ *
* @param element
* the annotation type element.
- *
* @param foundType
* the invalid type that was found. This is actually the textual
* type description found in the binary class representation,
* so it may not be human-readable.
- *
- * @since Android 1.0
*/
public AnnotationTypeMismatchException(Method element, String foundType) {
super(Messages.getString("annotation.1", element, foundType)); //$NON-NLS-1$
@@ -56,10 +53,8 @@ public class AnnotationTypeMismatchException extends RuntimeException {
/**
* Returns the method object for the invalid type.
- *
+ *
* @return a {@link Method} instance.
- *
- * @since Android 1.0
*/
public Method element() {
return element;
@@ -67,10 +62,8 @@ public class AnnotationTypeMismatchException extends RuntimeException {
/**
* Returns the invalid type.
- *
+ *
* @return a string describing the invalid data.
- *
- * @since Android 1.0
*/
public String foundType() {
return foundType;
diff --git a/annotation/src/main/java/java/lang/annotation/Documented.java b/annotation/src/main/java/java/lang/annotation/Documented.java
index 2849fd2..7e7f72f 100644
--- a/annotation/src/main/java/java/lang/annotation/Documented.java
+++ b/annotation/src/main/java/java/lang/annotation/Documented.java
@@ -20,8 +20,8 @@ package java.lang.annotation;
/**
* Defines a meta-annotation for indicating that an annotation is documented and
* considered part of the public API.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/annotation/src/main/java/java/lang/annotation/ElementType.java b/annotation/src/main/java/java/lang/annotation/ElementType.java
index 92f5109..f0f52aa 100644
--- a/annotation/src/main/java/java/lang/annotation/ElementType.java
+++ b/annotation/src/main/java/java/lang/annotation/ElementType.java
@@ -21,8 +21,8 @@ package java.lang.annotation;
* Defines an enumeration for Java program elements. It is used in conjunction
* with the {@link Target} meta-annotation to restrict the use of an annotation
* to certain program elements.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public enum ElementType {
/**
diff --git a/annotation/src/main/java/java/lang/annotation/IncompleteAnnotationException.java b/annotation/src/main/java/java/lang/annotation/IncompleteAnnotationException.java
index 3a31551..a5d2068 100644
--- a/annotation/src/main/java/java/lang/annotation/IncompleteAnnotationException.java
+++ b/annotation/src/main/java/java/lang/annotation/IncompleteAnnotationException.java
@@ -23,8 +23,8 @@ import org.apache.harmony.annotation.internal.nls.Messages;
* Indicates that an element of an annotation type was accessed that was added
* after the type was compiled or serialized. This does not apply to new
* elements that have default values.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public class IncompleteAnnotationException extends RuntimeException {
@@ -37,13 +37,11 @@ public class IncompleteAnnotationException extends RuntimeException {
/**
* Constructs an instance with the incomplete annotation type and the name
* of the element that's missing.
- *
+ *
* @param annotationType
* the annotation type.
* @param elementName
* the name of the incomplete element.
- *
- * @since Android 1.0
*/
public IncompleteAnnotationException(
Class<? extends Annotation> annotationType, String elementName) {
@@ -54,10 +52,8 @@ public class IncompleteAnnotationException extends RuntimeException {
/**
* Returns the annotation type.
- *
+ *
* @return a Class instance.
- *
- * @since Android 1.0
*/
public Class<? extends Annotation> annotationType() {
return annotationType;
@@ -65,10 +61,8 @@ public class IncompleteAnnotationException extends RuntimeException {
/**
* Returns the incomplete element's name.
- *
+ *
* @return the name of the element.
- *
- * @since Android 1.0
*/
public String elementName() {
return elementName;
diff --git a/annotation/src/main/java/java/lang/annotation/Inherited.java b/annotation/src/main/java/java/lang/annotation/Inherited.java
index cf16928..730d30a 100644
--- a/annotation/src/main/java/java/lang/annotation/Inherited.java
+++ b/annotation/src/main/java/java/lang/annotation/Inherited.java
@@ -20,8 +20,8 @@ package java.lang.annotation;
/**
* Defines a meta-annotation for indicating that an annotation is automatically
* inherited.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/annotation/src/main/java/java/lang/annotation/Retention.java b/annotation/src/main/java/java/lang/annotation/Retention.java
index 198fccc..275739e 100644
--- a/annotation/src/main/java/java/lang/annotation/Retention.java
+++ b/annotation/src/main/java/java/lang/annotation/Retention.java
@@ -21,15 +21,12 @@ package java.lang.annotation;
* Defines a meta-annotation for determining the scope of retention for an
* annotation. If the retention annotation is not set {@code
* RetentionPolicy.CLASS} is used as default retention.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
- // BEGIN android-changed
- // copied from newer version of harmony
RetentionPolicy value();
- // END android-changed
}
diff --git a/annotation/src/main/java/java/lang/annotation/RetentionPolicy.java b/annotation/src/main/java/java/lang/annotation/RetentionPolicy.java
index 014b910..70de3b0 100644
--- a/annotation/src/main/java/java/lang/annotation/RetentionPolicy.java
+++ b/annotation/src/main/java/java/lang/annotation/RetentionPolicy.java
@@ -21,8 +21,8 @@ package java.lang.annotation;
* Defines an enumeration for annotation retention policies. Used in conjunction
* with the {@link Retention} annotation to specify an annotation's time-to-live
* in the overall development life cycle.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public enum RetentionPolicy {
/**
diff --git a/annotation/src/main/java/java/lang/annotation/Target.java b/annotation/src/main/java/java/lang/annotation/Target.java
index 1f53fa0..4ba0938 100644
--- a/annotation/src/main/java/java/lang/annotation/Target.java
+++ b/annotation/src/main/java/java/lang/annotation/Target.java
@@ -20,8 +20,8 @@ package java.lang.annotation;
/**
* Defines a meta-annotation for determining what {@link ElementType}s an
* annotation can be applied to.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTypeMismatchExceptionTest.java b/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTypeMismatchExceptionTest.java
index 1134887..5430286 100644
--- a/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTypeMismatchExceptionTest.java
+++ b/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTypeMismatchExceptionTest.java
@@ -65,7 +65,7 @@ public class AnnotationTypeMismatchExceptionTest extends TestCase {
Method m = methods[0];
AnnotationTypeMismatchException e = new AnnotationTypeMismatchException(
m, "some type");
- assertNotNull("can not instanciate AnnotationTypeMismatchException", e);
+ assertNotNull("can not instantiate AnnotationTypeMismatchException", e);
assertSame("wrong method name", m, e.element());
assertEquals("wrong found type", "some type", e.foundType());
}
diff --git a/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/IncompleteAnnotationExceptionTest.java b/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/IncompleteAnnotationExceptionTest.java
index de56330..5c718ed 100644
--- a/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/IncompleteAnnotationExceptionTest.java
+++ b/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/IncompleteAnnotationExceptionTest.java
@@ -80,7 +80,7 @@ public class IncompleteAnnotationExceptionTest extends TestCase {
String elementName = "some element";
IncompleteAnnotationException e = new IncompleteAnnotationException(
clazz, elementName);
- assertNotNull("can not instanciate IncompleteAnnotationException", e);
+ assertNotNull("can not instantiate IncompleteAnnotationException", e);
assertSame("wrong annotation type", clazz, e.annotationType());
assertSame("wrong element name", elementName, e.elementName());
}
diff --git a/archive/src/main/java/java/util/jar/Attributes.java b/archive/src/main/java/java/util/jar/Attributes.java
index 5a4d923..4ee94df 100644
--- a/archive/src/main/java/java/util/jar/Attributes.java
+++ b/archive/src/main/java/java/util/jar/Attributes.java
@@ -17,6 +17,7 @@
package java.util.jar;
+import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -28,7 +29,6 @@ import org.apache.harmony.archive.util.Util;
* The {@code Attributes} class is used to store values for manifest entries.
* Attribute keys are generally instances of {@code Attributes.Name}. Values
* associated with attribute keys are of type {@code String}.
- * @since Android 1.0
*/
public class Attributes implements Cloneable, Map<Object, Object> {
@@ -37,8 +37,6 @@ public class Attributes implements Cloneable, Map<Object, Object> {
* {@link Attributes.Name}) of a JAR file manifest to arbitrary values. The
* attribute names thus are obtained from the {@link Manifest} for
* convenience.
- *
- * @since Android 1.0
*/
protected Map<Object, Object> map;
@@ -46,46 +44,35 @@ public class Attributes implements Cloneable, Map<Object, Object> {
* The name part of the name/value pairs constituting an attribute as
* defined by the specification of the JAR manifest. May be composed of the
* following ASCII signs as defined in the EBNF below:
- *
+ *
* <pre>
* name = alphanum *headerchar
* headerchar = alphanum | - | _
- * alphanum = {A-Z} | {a-z} | {0-9}
+ * alphanum = {A-Z} | {a-z} | {0-9}
* </pre>
- *
- * @since Android 1.0
*/
public static class Name {
- private final String name;
+ private final byte[] name;
private int hashCode;
/**
* The class path (a main attribute).
- *
- * @since Android 1.0
*/
public static final Name CLASS_PATH = new Name("Class-Path"); //$NON-NLS-1$
/**
* The version of the manifest file (a main attribute).
- *
- * @since Android 1.0
*/
- public static final Name MANIFEST_VERSION = new Name(
- "Manifest-Version"); //$NON-NLS-1$
+ public static final Name MANIFEST_VERSION = new Name("Manifest-Version"); //$NON-NLS-1$
/**
* The main class's name (for stand-alone applications).
- *
- * @since Android 1.0
*/
public static final Name MAIN_CLASS = new Name("Main-Class"); //$NON-NLS-1$
/**
* Defines the signature version of the JAR file.
- *
- * @since Android 1.0
*/
public static final Name SIGNATURE_VERSION = new Name(
"Signature-Version"); //$NON-NLS-1$
@@ -98,16 +85,12 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* The {@code Sealed} manifest attribute which may have the value
* {@code true} for sealed archives.
- *
- * @since Android 1.0
*/
public static final Name SEALED = new Name("Sealed"); //$NON-NLS-1$
/**
* The {@code Implementation-Title} attribute whose value is a string
* that defines the title of the extension implementation.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_TITLE = new Name(
"Implementation-Title"); //$NON-NLS-1$
@@ -115,8 +98,6 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* The {@code Implementation-Version} attribute defining the version of
* the extension implementation.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_VERSION = new Name(
"Implementation-Version"); //$NON-NLS-1$
@@ -124,8 +105,6 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* The {@code Implementation-Vendor} attribute defining the organization
* that maintains the extension implementation.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_VENDOR = new Name(
"Implementation-Vendor"); //$NON-NLS-1$
@@ -133,8 +112,6 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* The {@code Specification-Title} attribute defining the title of the
* extension specification.
- *
- * @since Android 1.0
*/
public static final Name SPECIFICATION_TITLE = new Name(
"Specification-Title"); //$NON-NLS-1$
@@ -142,8 +119,6 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* The {@code Specification-Version} attribute defining the version of
* the extension specification.
- *
- * @since Android 1.0
*/
public static final Name SPECIFICATION_VERSION = new Name(
"Specification-Version"); //$NON-NLS-1$
@@ -151,8 +126,6 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* The {@code Specification-Vendor} attribute defining the organization
* that maintains the extension specification.
- *
- * @since Android 1.0
*/
public static final Name SPECIFICATION_VENDOR = new Name(
"Specification-Vendor"); //$NON-NLS-1$
@@ -160,23 +133,17 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* The {@code Extension-List} attribute defining the extensions that are
* needed by the applet.
- *
- * @since Android 1.0
*/
public static final Name EXTENSION_LIST = new Name("Extension-List"); //$NON-NLS-1$
/**
* The {@code Extension-Name} attribute which defines the unique name of
* the extension.
- *
- * @since Android 1.0
*/
public static final Name EXTENSION_NAME = new Name("Extension-Name"); //$NON-NLS-1$
/**
* The {@code Extension-Installation} attribute.
- *
- * @since Android 1.0
*/
public static final Name EXTENSION_INSTALLATION = new Name(
"Extension-Installation"); //$NON-NLS-1$
@@ -185,8 +152,6 @@ public class Attributes implements Cloneable, Map<Object, Object> {
* The {@code Implementation-Vendor-Id} attribute specifies the vendor
* of an extension implementation if the applet requires an
* implementation from a specific vendor.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_VENDOR_ID = new Name(
"Implementation-Vendor-Id"); //$NON-NLS-1$
@@ -195,91 +160,112 @@ public class Attributes implements Cloneable, Map<Object, Object> {
* The {@code Implementation-URL} attribute specifying a URL that can be
* used to obtain the most recent version of the extension if the
* required version is not already installed.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_URL = new Name(
"Implementation-URL"); //$NON-NLS-1$
+ static final Name NAME = new Name("Name");
+
/**
* A String which must satisfy the following EBNF grammar to specify an
* additional attribute:
- *
+ *
* <pre>
* name = alphanum *headerchar
* headerchar = alphanum | - | _
* alphanum = {A-Z} | {a-z} | {0-9}
* </pre>
- *
+ *
* @param s
* The Attribute string.
* @exception IllegalArgumentException
* if the string does not satisfy the EBNF grammar.
- * @since Android 1.0
*/
public Name(String s) {
int i = s.length();
- if (i == 0 || i > 70) {
+ if (i == 0 || i > Manifest.LINE_LENGTH_LIMIT - 2) {
throw new IllegalArgumentException();
}
+
+ name = new byte[i];
+
for (; --i >= 0;) {
char ch = s.charAt(i);
if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| ch == '_' || ch == '-' || (ch >= '0' && ch <= '9'))) {
throw new IllegalArgumentException(s);
}
+ name[i] = (byte) ch;
}
- name = s;
+ }
+
+ /**
+ * A private constructor for a trusted attribute name.
+ */
+ Name(byte[] buf) {
+ name = buf;
+ }
+
+ byte[] getBytes() {
+ return name;
}
/**
* Returns this attribute name.
- *
+ *
* @return the attribute name.
- * @since Android 1.0
*/
@Override
public String toString() {
- return name;
+ try {
+ return new String(name, "ISO-8859-1");
+ } catch (UnsupportedEncodingException iee) {
+ throw new InternalError(iee.getLocalizedMessage());
+ }
}
/**
* returns whether the argument provided is the same as the attribute
* name.
- *
+ *
* @return if the attribute names correspond.
- * @param an
+ * @param object
* An attribute name to be compared with this name.
- * @since Android 1.0
*/
@Override
- public boolean equals(Object an) {
- if (an == null) {
+ public boolean equals(Object object) {
+ if (object == null || object.getClass() != getClass()
+ || object.hashCode() != hashCode()) {
return false;
}
- return an.getClass() == this.getClass()
- && name.equalsIgnoreCase(((Name) an).name);
+
+ return Util.equalsIgnoreCase(name, ((Name) object).name);
}
/**
* Computes a hash code of the name.
- *
+ *
* @return the hash value computed from the name.
- * @since Android 1.0
*/
@Override
public int hashCode() {
if (hashCode == 0) {
- hashCode = Util.toASCIILowerCase("name").hashCode();
+ int hash = 0, multiplier = 1;
+ for (int i = name.length - 1; i >= 0; i--) {
+ // 'A' & 0xDF == 'a' & 0xDF, ..., 'Z' & 0xDF == 'z' & 0xDF
+ hash += (name[i] & 0xDF) * multiplier;
+ int shifted = multiplier << 5;
+ multiplier = shifted - multiplier;
+ }
+ hashCode = hash;
}
return hashCode;
}
+
}
/**
* Constructs an {@code Attributes} instance.
- *
- * @since Android 1.0
*/
public Attributes() {
map = new HashMap<Object, Object>();
@@ -288,23 +274,21 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Constructs an {@code Attributes} instance obtaining keys and values from
* the parameter {@code attrib}.
- *
+ *
* @param attrib
* The attributes to obtain entries from.
- * @since Android 1.0
*/
@SuppressWarnings("unchecked")
public Attributes(Attributes attrib) {
- map = (Map<Object, Object>)((HashMap) attrib.map).clone();
+ map = (Map<Object, Object>) ((HashMap) attrib.map).clone();
}
/**
* Constructs an {@code Attributes} instance with initial capacity of size
* {@code size}.
- *
+ *
* @param size
* Initial size of this {@code Attributes} instance.
- * @since Android 1.0
*/
public Attributes(int size) {
map = new HashMap<Object, Object>(size);
@@ -312,8 +296,6 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Removes all key/value pairs from this {@code Attributes}.
- *
- * @since Android 1.0
*/
public void clear() {
map.clear();
@@ -321,11 +303,10 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Determines whether this {@code Attributes} contains the specified key.
- *
+ *
* @param key
* The key to search for.
* @return {@code true} if the key is found, {@code false} otherwise.
- * @since Android 1.0
*/
public boolean containsKey(Object key) {
return map.containsKey(key);
@@ -333,11 +314,10 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Determines whether this {@code Attributes} contains the specified value.
- *
+ *
* @param value
* the value to search for.
* @return {@code true} if the value is found, {@code false} otherwise.
- * @since Android 1.0
*/
public boolean containsValue(Object value) {
return map.containsValue(value);
@@ -346,9 +326,8 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Returns a set containing map entries for each of the key/value pair
* contained in this {@code Attributes}.
- *
+ *
* @return a set of Map.Entry's
- * @since Android 1.0
*/
public Set<Map.Entry<Object, Object>> entrySet() {
return map.entrySet();
@@ -356,12 +335,11 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Returns the value associated with the parameter key.
- *
+ *
* @param key
* the key to search for.
* @return Object associated with key, or {@code null} if key does not
* exist.
- * @since Android 1.0
*/
public Object get(Object key) {
return map.get(key);
@@ -369,9 +347,8 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Determines whether this {@code Attributes} contains any keys.
- *
+ *
* @return {@code true} if one or more keys exist, {@code false} otherwise.
- * @since Android 1.0
*/
public boolean isEmpty() {
return map.isEmpty();
@@ -380,9 +357,8 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Returns a {@code Set} containing all the keys found in this {@code
* Attributes}.
- *
+ *
* @return a {@code Set} of all keys.
- * @since Android 1.0
*/
public Set<Object> keySet() {
return map.keySet();
@@ -390,7 +366,7 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Stores key/value pairs in this {@code Attributes}.
- *
+ *
* @param key
* the key to associate with value.
* @param value
@@ -399,21 +375,20 @@ public class Attributes implements Cloneable, Map<Object, Object> {
* @exception ClassCastException
* when key is not an {@code Attributes.Name} or value is not
* a {@code String}.
- *@since Android 1.0
*/
- @SuppressWarnings("cast") // Require cast to force ClassCastException
+ @SuppressWarnings("cast")
+ // Require cast to force ClassCastException
public Object put(Object key, Object value) {
- return map.put((Name)key, (String)value);
+ return map.put((Name) key, (String) value);
}
/**
- * Stores all the key/value pairs in the argument in this {@code Attributes}
- * .
- *
+ * Stores all the key/value pairs in the argument in this {@code
+ * Attributes}.
+ *
* @param attrib
- * the associations to store (must be of type {@code Attributes}
- * ).
- * @since Android 1.0
+ * the associations to store (must be of type {@code
+ * Attributes}).
*/
public void putAll(Map<?, ?> attrib) {
if (attrib == null || !(attrib instanceof Attributes)) {
@@ -425,12 +400,11 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Deletes the key/value pair with key {@code key} from this {@code
* Attributes}.
- *
+ *
* @param key
* the key to remove.
* @return the values associated with the removed key, {@code null} if not
* present.
- * @since Android 1.0
*/
public Object remove(Object key) {
return map.remove(key);
@@ -439,20 +413,18 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Returns the number of key/value pairs associated with this {@code
* Attributes}.
- *
+ *
* @return the size of this {@code Attributes}.
- * @since Android 1.0
*/
public int size() {
return map.size();
}
/**
- * Returns a collection of all the values present in this {@code Attributes}
- * .
- *
+ * Returns a collection of all the values present in this {@code
+ * Attributes}.
+ *
* @return a collection of all values present.
- * @since Android 1.0
*/
public Collection<Object> values() {
return map.values();
@@ -473,9 +445,8 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Returns the hash code of this {@code Attributes}.
- *
+ *
* @return the hash code of this object.
- * @since Android 1.0
*/
@Override
public int hashCode() {
@@ -486,12 +457,11 @@ public class Attributes implements Cloneable, Map<Object, Object> {
* Determines if this {@code Attributes} and the parameter {@code
* Attributes} are equal. Two {@code Attributes} instances are equal if they
* contain the same keys and values.
- *
+ *
* @param obj
* the object with which this {@code Attributes} is compared.
* @return {@code true} if the {@code Attributes} are equal, {@code false}
* otherwise.
- * @since Android 1.0
*/
@Override
public boolean equals(Object obj) {
@@ -507,12 +477,11 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Returns the value associated with the parameter {@code Attributes.Name}
* key.
- *
+ *
* @param name
* the key to obtain the value for.
* @return the {@code String} associated with name, or {@code null} if name
* is not a valid key.
- * @since Android 1.0
*/
public String getValue(Attributes.Name name) {
return (String) map.get(name);
@@ -520,12 +489,11 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Returns the string associated with the parameter name.
- *
+ *
* @param name
* the key to obtain the value for.
* @return the string associated with name, or {@code null} if name is not a
* valid key.
- * @since Android 1.0
*/
public String getValue(String name) {
return (String) map.get(new Attributes.Name(name));
@@ -534,13 +502,12 @@ public class Attributes implements Cloneable, Map<Object, Object> {
/**
* Stores the value {@code val} associated with the key {@code name} in this
* {@code Attributes}.
- *
+ *
* @param name
* the key to store.
* @param val
* the value to store in this {@code Attributes}.
* @return the value being stored.
- * @since Android 1.0
*/
public String putValue(String name, String val) {
return (String) map.put(new Attributes.Name(name), val);
diff --git a/archive/src/main/java/java/util/jar/InitManifest.java b/archive/src/main/java/java/util/jar/InitManifest.java
index 47fdf1c..bf9c397 100644
--- a/archive/src/main/java/java/util/jar/InitManifest.java
+++ b/archive/src/main/java/java/util/jar/InitManifest.java
@@ -17,279 +17,206 @@
package java.util.jar;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.UTFDataFormatException;
-import java.security.AccessController;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
import java.util.Map;
import org.apache.harmony.archive.internal.nls.Messages;
-import org.apache.harmony.luni.util.PriviAction;
-import org.apache.harmony.luni.util.Util;
+import org.apache.harmony.luni.util.ThreadLocalCache;
class InitManifest {
- private final byte[] inbuf = new byte[1024];
- private int inbufCount = 0, inbufPos = 0;
+ private byte[] buf;
- private byte[] buffer = new byte[5];
+ private int pos;
- private char[] charbuf = new char[0];
+ Attributes.Name name;
- private final ByteArrayOutputStream out = new ByteArrayOutputStream(256);
+ String value;
- private String encoding;
+ CharsetDecoder decoder = ThreadLocalCache.utf8Decoder.get();
+ CharBuffer cBuf = ThreadLocalCache.charBuffer.get();
- private boolean usingUTF8 = true;
-
- private final Map<String, Attributes.Name> attributeNames = new HashMap<String, Attributes.Name>();
+ InitManifest(byte[] buf, Attributes main, Attributes.Name ver)
+ throws IOException {
- private final byte[] mainAttributesChunk;
+ this.buf = buf;
- InitManifest(InputStream is, Attributes main, Map<String, Attributes> entries, Map<String, byte[]> chunks,
- String verString) throws IOException {
- encoding = AccessController.doPrivileged(new PriviAction<String>(
- "manifest.read.encoding")); //$NON-NLS-1$
- if ("".equals(encoding)) { //$NON-NLS-1$
- encoding = null;
+ // check a version attribute
+ if (!readHeader() || (ver != null && !name.equals(ver))) {
+ throw new IOException(Messages.getString(
+ "archive.2D", ver)); //$NON-NLS-1$
}
- Attributes current = main;
- ArrayList<String> list = new ArrayList<String>();
-
- // Return the chunk of main attributes in the manifest.
- mainAttributesChunk = nextChunk(is, list);
-
- Iterator<String> it = list.iterator();
- while (it.hasNext()) {
- addAttribute(it.next(), current);
+ main.put(name, value);
+ while (readHeader()) {
+ main.put(name, value);
}
+ }
- // Check for version attribute
- if (verString != null && main.getValue(verString) == null) {
- throw new IOException(Messages.getString("archive.2D", verString)); //$NON-NLS-1$
- }
+ void initEntries(Map<String, Attributes> entries,
+ Map<String, Manifest.Chunk> chunks) throws IOException {
- list.clear();
- byte[] chunk = null;
- while (chunks == null ? readLines(is, list) : (chunk = nextChunk(is,
- list)) != null) {
- it = list.iterator();
- String line = it.next();
- if (line.length() < 7
- || !Util.toASCIILowerCase(line.substring(0, 5)).equals("name:")) { //$NON-NLS-1$
+ int mark = pos;
+ while (readHeader()) {
+ if (!Attributes.Name.NAME.equals(name)) {
throw new IOException(Messages.getString("archive.23")); //$NON-NLS-1$
}
- // Name: length required space char
- String name = line.substring(6, line.length());
- current = new Attributes(12);
- if (chunks != null) {
- chunks.put(name, chunk);
+ String entryNameValue = value;
+
+ Attributes entry = entries.get(entryNameValue);
+ if (entry == null) {
+ entry = new Attributes(12);
}
- entries.put(name, current);
- while (it.hasNext()) {
- addAttribute(it.next(), current);
+
+ while (readHeader()) {
+ entry.put(name, value);
+ }
+
+ if (chunks != null) {
+ if (chunks.get(entryNameValue) != null) {
+ // TODO A bug: there might be several verification chunks for
+ // the same name. I believe they should be used to update
+ // signature in order of appearance; there are two ways to fix
+ // this: either use a list of chunks, or decide on used
+ // signature algorithm in advance and reread the chunks while
+ // updating the signature; for now a defensive error is thrown
+ throw new IOException(Messages.getString("archive.34")); //$NON-NLS-1$
+ }
+ chunks.put(entryNameValue, new Manifest.Chunk(mark, pos));
+ mark = pos;
}
- list.clear();
+
+ entries.put(entryNameValue, entry);
}
+ }
+
+ int getPos() {
+ return pos;
+ }
+ /**
+ * Number of subsequent line breaks.
+ */
+ int linebreak = 0;
+
+ /**
+ * Read a single line from the manifest buffer.
+ */
+ private boolean readHeader() throws IOException {
+ if (linebreak > 1) {
+ // break a section on an empty line
+ linebreak = 0;
+ return false;
+ }
+ readName();
+ linebreak = 0;
+ readValue();
+ // if the last line break is missed, the line
+ // is ignored by the reference implementation
+ return linebreak > 0;
}
- byte[] getMainAttributesChunk() {
- return mainAttributesChunk;
+ private byte[] wrap(int mark, int pos) {
+ byte[] buffer = new byte[pos - mark];
+ System.arraycopy(buf, mark, buffer, 0, pos - mark);
+ return buffer;
}
- private void addLine(int length, List<String> lines) throws IOException {
- if (encoding != null) {
- lines.add(new String(buffer, 0, length, encoding));
- } else {
- if (usingUTF8) {
- try {
- if (charbuf.length < length) {
- charbuf = new char[length];
- }
- lines.add(Util.convertUTF8WithBuf(buffer, charbuf, 0,
- length));
- } catch (UTFDataFormatException e) {
- usingUTF8 = false;
+ private void readName() throws IOException {
+ int i = 0;
+ int mark = pos;
+
+ while (pos < buf.length) {
+ byte b = buf[pos++];
+
+ if (b == ':') {
+ byte[] nameBuffer = wrap(mark, pos - 1);
+
+ if (buf[pos++] != ' ') {
+ throw new IOException(Messages.getString(
+ "archive.30", nameBuffer)); //$NON-NLS-1$
}
+
+ name = new Attributes.Name(nameBuffer);
+ return;
}
- if (!usingUTF8) {
- if (charbuf.length < length) {
- charbuf = new char[length];
- }
- // If invalid UTF8, convert bytes to chars setting the upper
- // bytes to zeros
- int charOffset = 0;
- int offset = 0;
- for (int i = length; --i >= 0;) {
- charbuf[charOffset++] = (char) (buffer[offset++] & 0xff);
- }
- lines.add(new String(charbuf, 0, length));
+
+ if (!((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_'
+ || b == '-' || (b >= '0' && b <= '9'))) {
+ throw new IOException(Messages.getString("archive.30", b)); //$NON-NLS-1$
}
}
+ if (i > 0) {
+ throw new IOException(Messages.getString(
+ "archive.30", wrap(mark, buf.length))); //$NON-NLS-1$
+ }
}
- private byte[] nextChunk(InputStream in, List<String> lines)
- throws IOException {
- if (inbufCount == -1) {
- return null;
- }
+ private void readValue() throws IOException {
byte next;
- int pos = 0;
- boolean blankline = false, lastCr = false;
- out.reset();
- while (true) {
- if (inbufPos == inbufCount) {
- if ((inbufCount = in.read(inbuf)) == -1) {
- if (out.size() == 0) {
- return null;
- }
- if (blankline) {
- addLine(pos, lines);
- }
- return out.toByteArray();
- }
- if (inbufCount == inbuf.length && in.available() == 0) {
- /* archive.2E = "line too long" */
- throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
- }
- inbufPos = 0;
- }
- next = inbuf[inbufPos++];
- if (lastCr) {
- if (next != '\n') {
- inbufPos--;
- next = '\r';
+ boolean lastCr = false;
+ int mark = pos;
+ int last = pos;
+
+ decoder.reset();
+ cBuf.clear();
+
+ while (pos < buf.length) {
+ next = buf[pos++];
+
+ switch (next) {
+ case 0:
+ throw new IOException(Messages.getString("archive.2F")); //$NON-NLS-1$
+ case '\n':
+ if (lastCr) {
+ lastCr = false;
} else {
- if (out.size() == 0) {
- continue;
- }
- out.write('\r');
+ linebreak++;
}
- lastCr = false;
- } else if (next == '\r') {
+ continue;
+ case '\r':
lastCr = true;
+ linebreak++;
continue;
- }
- if (blankline) {
- if (next == ' ') {
- out.write(next);
- blankline = false;
- continue;
- }
- addLine(pos, lines);
- if (next == '\n') {
- out.write(next);
- return out.toByteArray();
- }
- pos = 0;
- } else if (next == '\n') {
- if (out.size() == 0) {
+ case ' ':
+ if (linebreak == 1) {
+ decode(mark, last, false);
+ mark = pos;
+ linebreak = 0;
continue;
}
- out.write(next);
- blankline = true;
- continue;
}
- blankline = false;
- out.write(next);
- if (pos == buffer.length) {
- byte[] newBuf = new byte[buffer.length * 2];
- System.arraycopy(buffer, 0, newBuf, 0, buffer.length);
- buffer = newBuf;
+
+ if (linebreak >= 1) {
+ pos--;
+ break;
}
- buffer[pos++] = next;
+ last = pos;
}
- }
- private boolean readLines(InputStream in, List<String> lines)
- throws IOException {
- if (inbufCount == -1) {
- return false;
- }
- byte next;
- int pos = 0;
- boolean blankline = false, lastCr = false;
- while (true) {
- if (inbufPos == inbufCount) {
- if ((inbufCount = in.read(inbuf)) == -1) {
- if (blankline) {
- addLine(pos, lines);
- }
- return lines.size() != 0;
- }
- if (inbufCount == inbuf.length && in.available() == 0) {
- /* archive.2E = "line too long" */
- throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
- }
- inbufPos = 0;
- }
- next = inbuf[inbufPos++];
- if (lastCr) {
- if (next != '\n') {
- inbufPos--;
- next = '\r';
- }
- lastCr = false;
- } else if (next == '\r') {
- lastCr = true;
- continue;
- }
- if (blankline) {
- if (next == ' ') {
- blankline = false;
- continue;
- }
- addLine(pos, lines);
- if (next == '\n') {
- return true;
- }
- pos = 0;
- } else if (next == '\n') {
- if (pos == 0 && lines.size() == 0) {
- continue;
- }
- blankline = true;
- continue;
- }
- blankline = false;
- if (pos == buffer.length) {
- byte[] newBuf = new byte[buffer.length * 2];
- System.arraycopy(buffer, 0, newBuf, 0, buffer.length);
- buffer = newBuf;
- }
- buffer[pos++] = next;
+ decode(mark, last, true);
+ while (CoderResult.OVERFLOW == decoder.flush(cBuf)) {
+ enlargeBuffer();
}
+ value = new String(cBuf.array(), cBuf.arrayOffset(), cBuf.position());
}
- /* Get the next attribute and add it */
- private void addAttribute(String line, Attributes current)
+ private void decode(int mark, int pos, boolean endOfInput)
throws IOException {
- String header;
- int hdrIdx = line.indexOf(':');
- if (hdrIdx < 1) {
- throw new IOException(Messages.getString("archive.2F", line)); //$NON-NLS-1$
- }
- header = line.substring(0, hdrIdx);
- Attributes.Name name = attributeNames.get(header);
- if (name == null) {
- try {
- name = new Attributes.Name(header);
- } catch (IllegalArgumentException e) {
- throw new IOException(e.toString());
- }
- attributeNames.put(header, name);
- }
- if (hdrIdx + 1 >= line.length() || line.charAt(hdrIdx + 1) != ' ') {
- throw new IOException(Messages.getString("archive.2F", line)); //$NON-NLS-1$
+ ByteBuffer bBuf = ByteBuffer.wrap(buf, mark, pos - mark);
+ while (CoderResult.OVERFLOW == decoder.decode(bBuf, cBuf, endOfInput)) {
+ enlargeBuffer();
}
- // +2 due to required SPACE char
- current.put(name, line.substring(hdrIdx + 2, line.length()));
+ }
+
+ private void enlargeBuffer() {
+ CharBuffer newBuf = CharBuffer.allocate(cBuf.capacity() * 2);
+ newBuf.put(cBuf.array(), cBuf.arrayOffset(), cBuf.position());
+ cBuf = newBuf;
+ ThreadLocalCache.charBuffer.set(cBuf);
}
}
diff --git a/archive/src/main/java/java/util/jar/JarEntry.java b/archive/src/main/java/java/util/jar/JarEntry.java
index b8dabee..869e4b4 100644
--- a/archive/src/main/java/java/util/jar/JarEntry.java
+++ b/archive/src/main/java/java/util/jar/JarEntry.java
@@ -33,27 +33,27 @@ import javax.security.auth.x500.X500Principal;
/**
* Represents a single file in a JAR archive together with the manifest
* attributes and digital signatures associated with it.
- *
- * @since Android 1.0
+ *
+ * @see JarFile
+ * @see JarInputStream
*/
public class JarEntry extends ZipEntry {
private Attributes attributes;
JarFile parentJar;
-
+
CodeSigner signers[];
// Cached factory used to build CertPath-s in <code>getCodeSigners()</code>.
private CertificateFactory factory;
- private boolean isFactoryChecked = false;
+ private boolean isFactoryChecked = false;
/**
* Creates a new {@code JarEntry} named name.
*
* @param name
* The name of the new {@code JarEntry}.
- * @since Android 1.0
*/
public JarEntry(String name) {
super(name);
@@ -64,7 +64,6 @@ public class JarEntry extends ZipEntry {
*
* @param entry
* The ZipEntry to obtain values from.
- * @since Android 1.0
*/
public JarEntry(ZipEntry entry) {
super(entry);
@@ -78,7 +77,6 @@ public class JarEntry extends ZipEntry {
* @exception IOException
* If an error occurs obtaining the {@code Attributes}.
* @see Attributes
- * @since Android 1.0
*/
public Attributes getAttributes() throws IOException {
if (attributes != null || parentJar == null) {
@@ -99,7 +97,6 @@ public class JarEntry extends ZipEntry {
*
* @return the certificate for this entry.
* @see java.security.cert.Certificate
- * @since Android 1.0
*/
public Certificate[] getCertificates() {
if (null == parentJar) {
@@ -122,12 +119,11 @@ public class JarEntry extends ZipEntry {
*
* @param je
* The {@code JarEntry} to obtain values from.
- * @since Android 1.0
*/
public JarEntry(JarEntry je) {
super(je);
parentJar = je.parentJar;
- attributes = je.attributes;
+ attributes = je.attributes;
signers = je.signers;
}
@@ -139,7 +135,6 @@ public class JarEntry extends ZipEntry {
*
* @return the code signers for the JAR entry.
* @see CodeSigner
- * @since Android 1.0
*/
public CodeSigner[] getCodeSigners() {
if (null == signers) {
@@ -155,7 +150,7 @@ public class JarEntry extends ZipEntry {
}
private CodeSigner[] getCodeSigners(Certificate[] certs) {
- if(null == certs) {
+ if (null == certs) {
return null;
}
diff --git a/archive/src/main/java/java/util/jar/JarException.java b/archive/src/main/java/java/util/jar/JarException.java
index f18d639..d6943c4 100644
--- a/archive/src/main/java/java/util/jar/JarException.java
+++ b/archive/src/main/java/java/util/jar/JarException.java
@@ -22,8 +22,6 @@ import java.util.zip.ZipException;
/**
* This runtime exception is thrown when a problem occurs while reading a JAR
* file.
- *
- * @since Android 1.0
*/
public class JarException extends ZipException {
@@ -31,8 +29,6 @@ public class JarException extends ZipException {
/**
* Constructs a new {@code JarException} instance.
- *
- * @since Android 1.0
*/
public JarException() {
super();
@@ -41,10 +37,9 @@ public class JarException extends ZipException {
/**
* Constructs a new {@code JarException} instance with the specified
* message.
- *
+ *
* @param detailMessage
* the detail message for the exception.
- * @since Android 1.0
*/
public JarException(String detailMessage) {
super(detailMessage);
diff --git a/archive/src/main/java/java/util/jar/JarFile.java b/archive/src/main/java/java/util/jar/JarFile.java
index 9af9056..d6e8339 100644
--- a/archive/src/main/java/java/util/jar/JarFile.java
+++ b/archive/src/main/java/java/util/jar/JarFile.java
@@ -29,7 +29,6 @@ import java.io.File;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.security.MessageDigest;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -39,17 +38,14 @@ import org.apache.harmony.archive.util.Util;
/**
* {@code JarFile} is used to read jar entries and their associated data from
* jar files.
- *
+ *
* @see JarInputStream
* @see JarEntry
- * @since Android 1.0
*/
public class JarFile extends ZipFile {
/**
* The MANIFEST file name.
- *
- * @since Android 1.0
*/
public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; //$NON-NLS-1$
@@ -70,62 +66,68 @@ public class JarFile extends ZipFile {
private ZipEntry zipEntry;
- private JarVerifier verifier;
-
private JarVerifier.VerifierEntry entry;
- private MessageDigest digest;
-
- JarFileInputStream(InputStream is, ZipEntry ze, JarVerifier ver) {
+ JarFileInputStream(InputStream is, ZipEntry ze,
+ JarVerifier.VerifierEntry e) {
super(is);
- if (ver != null) {
- zipEntry = ze;
- verifier = ver;
- count = zipEntry.getSize();
- entry = verifier.initEntry(ze.getName());
- if (entry != null) {
- digest = entry.digest;
- }
- }
+ zipEntry = ze;
+ count = zipEntry.getSize();
+ entry = e;
}
@Override
public int read() throws IOException {
- int r = super.read();
- if (entry != null) {
+ if (count > 0) {
+ int r = super.read();
if (r != -1) {
- digest.update((byte) r);
+ entry.write(r);
count--;
+ } else {
+ count = 0;
}
- if (r == -1 || count <= 0) {
- JarVerifier.VerifierEntry temp = entry;
- entry = null;
- verifier.verifySignatures(temp, zipEntry);
+ if (count == 0) {
+ entry.verify();
}
+ return r;
+ } else {
+ return -1;
}
- return r;
}
@Override
public int read(byte[] buf, int off, int nbytes) throws IOException {
- int r = super.read(buf, off, nbytes);
- if (entry != null) {
+ if (count > 0) {
+ int r = super.read(buf, off, nbytes);
if (r != -1) {
int size = r;
if (count < size) {
size = (int) count;
}
- digest.update(buf, off, size);
- count -= r;
+ entry.write(buf, off, size);
+ count -= size;
+ } else {
+ count = 0;
}
- if (r == -1 || count <= 0) {
- JarVerifier.VerifierEntry temp = entry;
- entry = null;
- verifier.verifySignatures(temp, zipEntry);
+ if (count == 0) {
+ entry.verify();
}
+ return r;
+ } else {
+ return -1;
+ }
+ }
+
+ // BEGIN android-added
+ @Override
+ public int available() throws IOException {
+ if (count > 0) {
+ return super.available();
+ } else {
+ return 0;
}
- return r;
}
+ // END android-added
@Override
public long skip(long nbytes) throws IOException {
@@ -146,12 +148,11 @@ public class JarFile extends ZipFile {
/**
* Create a new {@code JarFile} using the contents of the specified file.
- *
+ *
* @param file
* the JAR file as {@link File}.
* @throws IOException
* If the file cannot be read.
- * @since Android 1.0
*/
public JarFile(File file) throws IOException {
this(file, true);
@@ -159,14 +160,13 @@ public class JarFile extends ZipFile {
/**
* Create a new {@code JarFile} using the contents of the specified file.
- *
+ *
* @param file
* the JAR file as {@link File}.
* @param verify
* if this JAR file is signed whether it must be verified.
* @throws IOException
* If the file cannot be read.
- * @since Android 1.0
*/
public JarFile(File file, boolean verify) throws IOException {
super(file);
@@ -178,7 +178,7 @@ public class JarFile extends ZipFile {
/**
* Create a new {@code JarFile} using the contents of file.
- *
+ *
* @param file
* the JAR file as {@link File}.
* @param verify
@@ -188,7 +188,6 @@ public class JarFile extends ZipFile {
* {@link ZipFile#OPEN_DELETE OPEN_DELETE}.
* @throws IOException
* If the file cannot be read.
- * @since Android 1.0
*/
public JarFile(File file, boolean verify, int mode) throws IOException {
super(file, mode);
@@ -201,12 +200,11 @@ public class JarFile extends ZipFile {
/**
* Create a new {@code JarFile} from the contents of the file specified by
* filename.
- *
+ *
* @param filename
* the file name referring to the JAR file.
* @throws IOException
* if file name cannot be opened for reading.
- * @since Android 1.0
*/
public JarFile(String filename) throws IOException {
this(filename, true);
@@ -216,14 +214,13 @@ public class JarFile extends ZipFile {
/**
* Create a new {@code JarFile} from the contents of the file specified by
* {@code filename}.
- *
+ *
* @param filename
* the file name referring to the JAR file.
* @param verify
* if this JAR filed is signed whether it must be verified.
* @throws IOException
* If file cannot be opened or read.
- * @since Android 1.0
*/
public JarFile(String filename, boolean verify) throws IOException {
super(filename);
@@ -236,11 +233,10 @@ public class JarFile extends ZipFile {
/**
* Return an enumeration containing the {@code JarEntrys} contained in this
* {@code JarFile}.
- *
+ *
* @return the {@code Enumeration} containing the JAR entries.
* @throws IllegalStateException
* if this {@code JarFile} is closed.
- * @since Android 1.0
*/
@Override
public Enumeration<JarEntry> entries() {
@@ -260,7 +256,7 @@ public class JarFile extends ZipFile {
public JarEntry nextElement() {
JarEntry je = new JarEntry(ze.nextElement());
- je.parentJar = jf;
+ je.parentJar = jf;
return je;
}
}
@@ -270,11 +266,10 @@ public class JarFile extends ZipFile {
/**
* Return the {@code JarEntry} specified by its name or {@code null} if no
* such entry exists.
- *
+ *
* @param name
* the name of the entry in the JAR file.
* @return the JAR entry defined by the name.
- * @since Android 1.0
*/
public JarEntry getJarEntry(String name) {
return (JarEntry) getEntry(name);
@@ -302,14 +297,13 @@ public class JarFile extends ZipFile {
/**
* Returns the {@code Manifest} object associated with this {@code JarFile}
* or {@code null} if no MANIFEST entry exists.
- *
+ *
* @return the MANIFEST.
* @throws IOException
* if an error occurs reading the MANIFEST file.
* @throws IllegalStateException
* if the jar file is closed.
* @see Manifest
- * @since Android 1.0
*/
public Manifest getManifest() throws IOException {
// BEGIN android-added
@@ -358,10 +352,14 @@ public class JarFile extends ZipFile {
if (verifier == null) {
break;
}
- } else if (verifier != null && entryName.length() > dirLength
- && (Util.ASCIIIgnoreCaseRegionMatches(entryName, entryName.length() - 3, ".SF", 0 ,3) //$NON-NLS-1$
- || Util.ASCIIIgnoreCaseRegionMatches(entryName, entryName.length() - 4, ".DSA", 0 ,4) //$NON-NLS-1$
- || Util.ASCIIIgnoreCaseRegionMatches(entryName, entryName.length() - 4, ".RSA", 0 ,4))){ //$NON-NLS-1$
+ } else if (verifier != null
+ && entryName.length() > dirLength
+ && (Util.ASCIIIgnoreCaseRegionMatches(entryName,
+ entryName.length() - 3, ".SF", 0, 3) //$NON-NLS-1$
+ || Util.ASCIIIgnoreCaseRegionMatches(entryName,
+ entryName.length() - 4, ".DSA", 0, 4) //$NON-NLS-1$
+ || Util.ASCIIIgnoreCaseRegionMatches(entryName,
+ entryName.length() - 4, ".RSA", 0, 4))) { //$NON-NLS-1$
signed = true;
InputStream is = super.getInputStream(entry);
// BEGIN android-modified
@@ -379,13 +377,12 @@ public class JarFile extends ZipFile {
/**
* Return an {@code InputStream} for reading the decompressed contents of
* ZIP entry.
- *
+ *
* @param ze
* the ZIP entry to be read.
* @return the input stream to read from.
* @throws IOException
* if an error occurred while creating the input stream.
- * @since Android 1.0
*/
@Override
public InputStream getInputStream(ZipEntry ze) throws IOException {
@@ -395,8 +392,7 @@ public class JarFile extends ZipFile {
if (verifier != null) {
verifier.setManifest(getManifest());
if (manifest != null) {
- verifier.mainAttributesChunk = manifest
- .getMainAttributesChunk();
+ verifier.mainAttributesEnd = manifest.getMainAttributesEnd();
}
if (verifier.readCertificates()) {
verifier.removeMetaEntries();
@@ -412,19 +408,24 @@ public class JarFile extends ZipFile {
if (in == null) {
return null;
}
- return new JarFileInputStream(in, ze, ze.getSize() >= 0 ? verifier
- : null);
+ if (verifier == null || ze.getSize() == -1) {
+ return in;
+ }
+ JarVerifier.VerifierEntry entry = verifier.initEntry(ze.getName());
+ if (entry == null) {
+ return in;
+ }
+ return new JarFileInputStream(in, ze, entry);
}
/**
* Return the {@code JarEntry} specified by name or {@code null} if no such
* entry exists.
- *
+ *
* @param name
* the name of the entry in the JAR file.
* @return the ZIP entry extracted.
- * @since Android 1.0
- */
+ */
@Override
public ZipEntry getEntry(String name) {
ZipEntry ze = super.getEntry(name);
@@ -432,16 +433,16 @@ public class JarFile extends ZipFile {
return ze;
}
JarEntry je = new JarEntry(ze);
- je.parentJar = this;
+ je.parentJar = this;
return je;
}
// BEGIN android-modified
private ZipEntry[] getMetaEntriesImpl(byte[] buf) {
int n = 0;
-
+
List<ZipEntry> list = new ArrayList<ZipEntry>();
-
+
Enumeration<? extends ZipEntry> allEntries = entries();
while (allEntries.hasMoreElements()) {
ZipEntry ze = allEntries.nextElement();
@@ -463,10 +464,9 @@ public class JarFile extends ZipFile {
// BEGIN android-added
/**
* Closes this {@code JarFile}.
- *
+ *
* @throws IOException
* if an error occurs.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
diff --git a/archive/src/main/java/java/util/jar/JarInputStream.java b/archive/src/main/java/java/util/jar/JarInputStream.java
index ef353ab..c803183 100644
--- a/archive/src/main/java/java/util/jar/JarInputStream.java
+++ b/archive/src/main/java/java/util/jar/JarInputStream.java
@@ -24,14 +24,13 @@ import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
-import org.apache.harmony.archive.util.Util;
+import org.apache.harmony.luni.util.Util;
/**
* The input stream from which the JAR file to be read may be fetched. It is
* used like the {@code ZipInputStream}.
- *
+ *
* @see ZipInputStream
- * @since Android 1.0
*/
public class JarInputStream extends ZipInputStream {
@@ -51,7 +50,7 @@ public class JarInputStream extends ZipInputStream {
/**
* Constructs a new {@code JarInputStream} from an input stream.
- *
+ *
* @param stream
* the input stream containing the JAR file.
* @param verify
@@ -59,7 +58,6 @@ public class JarInputStream extends ZipInputStream {
* @throws IOException
* If an error occurs reading entries from the input stream.
* @see ZipInputStream#ZipInputStream(InputStream)
- * @since Android 1.0
*/
public JarInputStream(InputStream stream, boolean verify)
throws IOException {
@@ -84,8 +82,8 @@ public class JarInputStream extends ZipInputStream {
if (verify) {
verifier.setManifest(manifest);
if (manifest != null) {
- verifier.mainAttributesChunk = manifest
- .getMainAttributesChunk();
+ verifier.mainAttributesEnd = manifest
+ .getMainAttributesEnd();
}
}
@@ -103,13 +101,12 @@ public class JarInputStream extends ZipInputStream {
/**
* Constructs a new {@code JarInputStream} from an input stream.
- *
+ *
* @param stream
* the input stream containing the JAR file.
* @throws IOException
* If an error occurs reading entries from the input stream.
* @see ZipInputStream#ZipInputStream(InputStream)
- * @since Android 1.0
*/
public JarInputStream(InputStream stream) throws IOException {
this(stream, true);
@@ -120,7 +117,6 @@ public class JarInputStream extends ZipInputStream {
* JarInputStream} or {@code null} if no manifest entry exists.
*
* @return the MANIFEST specifying the contents of the JAR file.
- * @since Android 1.0
*/
public Manifest getManifest() {
return manifest;
@@ -133,7 +129,6 @@ public class JarInputStream extends ZipInputStream {
* @return the next JAR entry.
* @throws IOException
* if an error occurs while reading the entry.
- * @since Android 1.0
*/
public JarEntry getNextJarEntry() throws IOException {
return (JarEntry) getNextEntry();
@@ -142,7 +137,7 @@ public class JarInputStream extends ZipInputStream {
/**
* Reads up to {@code length} of decompressed data and stores it in
* {@code buffer} starting at {@code offset}.
- *
+ *
* @param buffer
* Buffer to store into
* @param offset
@@ -152,7 +147,6 @@ public class JarInputStream extends ZipInputStream {
* @return Number of uncompressed bytes read
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
@@ -175,9 +169,7 @@ public class JarInputStream extends ZipInputStream {
throw e;
}
} else {
- verifier.verifySignatures(
- (JarVerifier.VerifierEntry) verStream,
- jarEntry);
+ ((JarVerifier.VerifierEntry) verStream).verify();
}
}
} else {
@@ -194,7 +186,6 @@ public class JarInputStream extends ZipInputStream {
* @return the next extracted ZIP entry.
* @throws IOException
* if an error occurs while reading the entry.
- * @since Android 1.0
*/
@Override
public ZipEntry getNextEntry() throws IOException {
diff --git a/archive/src/main/java/java/util/jar/JarOutputStream.java b/archive/src/main/java/java/util/jar/JarOutputStream.java
index 640f4ef..e901d87 100644
--- a/archive/src/main/java/java/util/jar/JarOutputStream.java
+++ b/archive/src/main/java/java/util/jar/JarOutputStream.java
@@ -25,8 +25,6 @@ import java.util.zip.ZipOutputStream;
/**
* The {@code JarOutputStream} is used to write data in the {@code JarFile}
* format to an arbitrary output stream
- *
- * @since Android 1.0
*/
public class JarOutputStream extends ZipOutputStream {
@@ -79,7 +77,6 @@ public class JarOutputStream extends ZipOutputStream {
* @throws IOException
* if an error occurs writing to the entry.
* @see ZipEntry
- * @since Android 1.0
*/
@Override
public void putNextEntry(ZipEntry ze) throws IOException {
diff --git a/archive/src/main/java/java/util/jar/JarVerifier.java b/archive/src/main/java/java/util/jar/JarVerifier.java
index b9173f2..6c1ee93 100644
--- a/archive/src/main/java/java/util/jar/JarVerifier.java
+++ b/archive/src/main/java/java/util/jar/JarVerifier.java
@@ -31,13 +31,12 @@ import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
-import java.util.zip.ZipEntry;
import org.apache.harmony.archive.internal.nls.Messages;
import org.apache.harmony.luni.util.Base64;
import org.apache.harmony.security.utils.JarUtils;
-import org.apache.harmony.archive.util.Util;
+import org.apache.harmony.luni.util.Util;
// BEGIN android-added
import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK;
@@ -65,65 +64,81 @@ class JarVerifier {
private HashMap<String, byte[]> metaEntries = new HashMap<String, byte[]>(5);
- private final Hashtable<String, HashMap<String, Attributes>> signatures =
- new Hashtable<String, HashMap<String, Attributes>>(5);
+ private final Hashtable<String, HashMap<String, Attributes>> signatures = new Hashtable<String, HashMap<String, Attributes>>(
+ 5);
- private final Hashtable<String, Certificate[]> certificates =
- new Hashtable<String, Certificate[]>(5);
+ private final Hashtable<String, Certificate[]> certificates = new Hashtable<String, Certificate[]>(
+ 5);
- private final Hashtable<String, Certificate[]> verifiedEntries =
- new Hashtable<String, Certificate[]>();
+ private final Hashtable<String, Certificate[]> verifiedEntries = new Hashtable<String, Certificate[]>();
- byte[] mainAttributesChunk;
+ int mainAttributesEnd;
- // BEGIN android-added
- private static long measureCount = 0;
-
- private static long averageTime = 0;
- // END android-added
-
/**
- * TODO Type description
+ * Stores and a hash and a message digest and verifies that massage digest
+ * matches the hash.
*/
- static class VerifierEntry extends OutputStream {
+ class VerifierEntry extends OutputStream {
- MessageDigest digest;
+ private String name;
- byte[] hash;
+ private MessageDigest digest;
- Certificate[] certificates;
+ private byte[] hash;
- VerifierEntry(MessageDigest digest, byte[] hash,
+ private Certificate[] certificates;
+
+ VerifierEntry(String name, MessageDigest digest, byte[] hash,
Certificate[] certificates) {
+ this.name = name;
this.digest = digest;
this.hash = hash;
this.certificates = certificates;
}
- /*
- * (non-Javadoc)
- *
- * @see java.io.OutputStream#write(int)
+ /**
+ * Updates a digest with one byte.
*/
@Override
public void write(int value) {
digest.update((byte) value);
}
- /*
- * (non-Javadoc)
- *
- * @see java.io.OutputStream#write(byte[], int, int)
+ /**
+ * Updates a digest with byte array.
*/
@Override
public void write(byte[] buf, int off, int nbytes) {
digest.update(buf, off, nbytes);
}
+
+ /**
+ * Verifies that the digests stored in the manifest match the decrypted
+ * digests from the .SF file. This indicates the validity of the
+ * signing, not the integrity of the file, as it's digest must be
+ * calculated and verified when its contents are read.
+ *
+ * @throws SecurityException
+ * if the digest value stored in the manifest does <i>not</i>
+ * agree with the decrypted digest as recovered from the
+ * <code>.SF</code> file.
+ * @see #initEntry(String)
+ */
+ void verify() {
+ byte[] d = digest.digest();
+ if (!MessageDigest.isEqual(d, Base64.decode(hash))) {
+ throw new SecurityException(Messages.getString(
+ "archive.32", new Object[] { //$NON-NLS-1$
+ JarFile.MANIFEST_NAME, name, jarName }));
+ }
+ verifiedEntries.put(name, certificates);
+ }
+
}
/**
* Constructs and returns a new instance of {@code JarVerifier}.
- *
+ *
* @param name
* the name of the JAR file being verified.
*/
@@ -136,13 +151,12 @@ class JarVerifier {
* stream. This method constructs and returns a new {@link VerifierEntry}
* which contains the certificates used to sign the entry and its hash value
* as specified in the JAR MANIFEST format.
- *
+ *
* @param name
* the name of an entry in a JAR file which is <b>not</b> in the
* {@code META-INF} directory.
* @return a new instance of {@link VerifierEntry} which can be used by
* callers as an {@link OutputStream}.
- * @since Android 1.0
*/
VerifierEntry initEntry(String name) {
// If no manifest is present by the time an entry is found,
@@ -159,8 +173,8 @@ class JarVerifier {
}
Vector<Certificate> certs = new Vector<Certificate>();
- Iterator<Map.Entry<String, HashMap<String, Attributes>>> it =
- signatures.entrySet().iterator();
+ Iterator<Map.Entry<String, HashMap<String, Attributes>>> it = signatures
+ .entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, HashMap<String, Attributes>> entry = it.next();
HashMap<String, Attributes> hm = entry.getValue();
@@ -197,18 +211,18 @@ class JarVerifier {
}
byte[] hashBytes;
try {
- hashBytes = hash.getBytes("ISO8859_1"); //$NON-NLS-1$
+ hashBytes = hash.getBytes("ISO-8859-1"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.toString());
}
try {
// BEGIN android-changed
- return new VerifierEntry(OpenSSLMessageDigestJDK.getInstance(algorithm),
+ return new VerifierEntry(name, OpenSSLMessageDigestJDK.getInstance(algorithm),
hashBytes, certificatesArray);
// END android-changed
} catch (NoSuchAlgorithmException e) {
- // Ignored
+ // ignored
}
}
return null;
@@ -219,7 +233,7 @@ class JarVerifier {
* entry in the {@code META-INF} directory including the manifest
* file itself. Files associated with the signing of a JAR would also be
* added to this collection.
- *
+ *
* @param name
* the name of the file located in the {@code META-INF}
* directory.
@@ -234,7 +248,7 @@ class JarVerifier {
/**
* If the associated JAR file is signed, check on the validity of all of the
* known signatures.
- *
+ *
* @return {@code true} if the associated JAR is signed and an internal
* check verifies the validity of the signature(s). {@code false} if
* the associated JAR file has no entries at all in its {@code
@@ -243,12 +257,10 @@ class JarVerifier {
* <p>
* Will also return {@code true} if the JAR file is <i>not</i>
* signed.
- * </p>
* @throws SecurityException
* if the JAR file is signed and it is determined that a
* signature block file contains an invalid signature for the
* corresponding signature file.
- * @since Android 1.0
*/
synchronized boolean readCertificates() {
if (metaEntries == null) {
@@ -281,6 +293,12 @@ class JarVerifier {
return;
}
+ byte[] manifest = metaEntries.get(JarFile.MANIFEST_NAME);
+ // Manifest entry is required for any verifications.
+ if (manifest == null) {
+ return;
+ }
+
byte[] sBlockBytes = metaEntries.get(certFile);
try {
Certificate[] signerCertChain = JarUtils.verifySignature(
@@ -288,7 +306,7 @@ class JarVerifier {
new ByteArrayInputStream(sBlockBytes));
/*
* Recursive call in loading security provider related class which
- * is in a signed JAR.
+ * is in a signed JAR.
*/
if (null == metaEntries) {
return;
@@ -299,74 +317,70 @@ class JarVerifier {
} catch (IOException e) {
return;
} catch (GeneralSecurityException e) {
- /* [MSG "archive.30", "{0} failed verification of {1}"] */
- throw new SecurityException(
- Messages.getString("archive.30", jarName, signatureFile)); //$NON-NLS-1$
+ /* [MSG "archive.31", "{0} failed verification of {1}"] */
+ throw new SecurityException(Messages.getString(
+ "archive.31", jarName, signatureFile)); //$NON-NLS-1$
}
// Verify manifest hash in .sf file
Attributes attributes = new Attributes();
- HashMap<String, Attributes> hm = new HashMap<String, Attributes>();
+ HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
try {
- new InitManifest(new ByteArrayInputStream(sfBytes), attributes, hm,
- null, "Signature-Version"); //$NON-NLS-1$
+ InitManifest im = new InitManifest(sfBytes, attributes, Attributes.Name.SIGNATURE_VERSION);
+ im.initEntries(entries, null);
} catch (IOException e) {
return;
}
boolean createdBySigntool = false;
- String createdByValue = attributes.getValue("Created-By"); //$NON-NLS-1$
- if (createdByValue != null) {
- createdBySigntool = createdByValue.indexOf("signtool") != -1; //$NON-NLS-1$
+ String createdBy = attributes.getValue("Created-By"); //$NON-NLS-1$
+ if (createdBy != null) {
+ createdBySigntool = createdBy.indexOf("signtool") != -1; //$NON-NLS-1$
}
// Use .SF to verify the mainAttributes of the manifest
// If there is no -Digest-Manifest-Main-Attributes entry in .SF
// file, such as those created before java 1.5, then we ignore
// such verification.
- // FIXME: The meaning of createdBySigntool
- if (mainAttributesChunk != null && !createdBySigntool) {
+ if (mainAttributesEnd > 0 && !createdBySigntool) {
String digestAttribute = "-Digest-Manifest-Main-Attributes"; //$NON-NLS-1$
- if (!verify(attributes, digestAttribute, mainAttributesChunk,
- false, true)) {
- /* [MSG "archive.30", "{0} failed verification of {1}"] */
- throw new SecurityException(
- Messages.getString("archive.30", jarName, signatureFile)); //$NON-NLS-1$
+ if (!verify(attributes, digestAttribute, manifest, 0,
+ mainAttributesEnd, false, true)) {
+ /* [MSG "archive.31", "{0} failed verification of {1}"] */
+ throw new SecurityException(Messages.getString(
+ "archive.31", jarName, signatureFile)); //$NON-NLS-1$
}
}
- byte[] manifest = metaEntries.get(JarFile.MANIFEST_NAME);
- if (manifest == null) {
- return;
- }
- // Use .SF to verify the whole manifest
+ // Use .SF to verify the whole manifest.
String digestAttribute = createdBySigntool ? "-Digest" //$NON-NLS-1$
: "-Digest-Manifest"; //$NON-NLS-1$
- if (!verify(attributes, digestAttribute, manifest, false, false)) {
- Iterator<Map.Entry<String, Attributes>> it = hm.entrySet()
+ if (!verify(attributes, digestAttribute, manifest, 0, manifest.length,
+ false, false)) {
+ Iterator<Map.Entry<String, Attributes>> it = entries.entrySet()
.iterator();
while (it.hasNext()) {
Map.Entry<String, Attributes> entry = it.next();
- byte[] chunk = man.getChunk(entry.getKey());
+ Manifest.Chunk chunk = man.getChunk(entry.getKey());
if (chunk == null) {
return;
}
- if (!verify(entry.getValue(), "-Digest", chunk, //$NON-NLS-1$
- createdBySigntool, false)) {
- /* [MSG "archive.31", "{0} has invalid digest for {1} in {2}"] */
- throw new SecurityException(
- Messages.getString("archive.31", //$NON-NLS-1$
- new Object[] { signatureFile, entry.getKey(), jarName }));
+ if (!verify(entry.getValue(), "-Digest", manifest, //$NON-NLS-1$
+ chunk.start, chunk.end, createdBySigntool, false)) {
+ throw new SecurityException(Messages.getString(
+ "archive.32", //$NON-NLS-1$
+ new Object[] { signatureFile, entry.getKey(),
+ jarName }));
}
}
}
metaEntries.put(signatureFile, null);
- signatures.put(signatureFile, hm);
+ signatures.put(signatureFile, entries);
}
/**
* Associate this verifier with the specified {@link Manifest} object.
- *
+ *
* @param mf
* a {@code java.util.jar.Manifest} object.
*/
@@ -375,36 +389,9 @@ class JarVerifier {
}
/**
- * Verifies that the digests stored in the manifest match the decrypted
- * digests from the .SF file. This indicates the validity of the signing,
- * not the integrity of the file, as it's digest must be calculated and
- * verified when its contents are read.
- *
- * @param entry
- * the {@link VerifierEntry} associated with the specified
- * {@code zipEntry}.
- * @param zipEntry
- * an entry in the JAR file
- * @throws SecurityException
- * if the digest value stored in the manifest does <i>not</i>
- * agree with the decrypted digest as recovered from the
- * {@code .SF} file.
- * @see #initEntry(String)
- */
- void verifySignatures(VerifierEntry entry, ZipEntry zipEntry) {
- byte[] digest = entry.digest.digest();
- if (!MessageDigest.isEqual(digest, Base64.decode(entry.hash))) {
- /* [MSG "archive.31", "{0} has invalid digest for {1} in {2}"] */
- throw new SecurityException(Messages.getString("archive.31", new Object[] { //$NON-NLS-1$
- JarFile.MANIFEST_NAME, zipEntry.getName(), jarName }));
- }
- verifiedEntries.put(zipEntry.getName(), entry.certificates);
- }
-
- /**
- * Returns a {@code boolean} indication of whether or not the
- * associated JAR file is signed.
- *
+ * Returns a <code>boolean</code> indication of whether or not the
+ * associated jar file is signed.
+ *
* @return {@code true} if the JAR is signed, {@code false}
* otherwise.
*/
@@ -413,7 +400,7 @@ class JarVerifier {
}
private boolean verify(Attributes attributes, String entry, byte[] data,
- boolean ignoreSecondEndline, boolean ignorable) {
+ int start, int end, boolean ignoreSecondEndline, boolean ignorable) {
String algorithms = attributes.getValue("Digest-Algorithms"); //$NON-NLS-1$
if (algorithms == null) {
algorithms = "SHA SHA1"; //$NON-NLS-1$
@@ -434,16 +421,16 @@ class JarVerifier {
} catch (NoSuchAlgorithmException e) {
continue;
}
- if (ignoreSecondEndline && data[data.length - 1] == '\n'
- && data[data.length - 2] == '\n') {
- md.update(data, 0, data.length - 1);
+ if (ignoreSecondEndline && data[end - 1] == '\n'
+ && data[end - 2] == '\n') {
+ md.update(data, start, end - 1 - start);
} else {
- md.update(data, 0, data.length);
+ md.update(data, start, end - start);
}
byte[] b = md.digest();
byte[] hashBytes;
try {
- hashBytes = hash.getBytes("ISO8859_1"); //$NON-NLS-1$
+ hashBytes = hash.getBytes("ISO-8859-1"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.toString());
}
@@ -456,7 +443,7 @@ class JarVerifier {
* Returns all of the {@link java.security.cert.Certificate} instances that
* were used to verify the signature on the JAR entry called
* {@code name}.
- *
+ *
* @param name
* the name of a JAR entry.
* @return an array of {@link java.security.cert.Certificate}.
@@ -472,7 +459,7 @@ class JarVerifier {
/**
* Remove all entries from the internal collection of data held about each
* JAR entry in the {@code META-INF} directory.
- *
+ *
* @see #addMetaEntry(String, byte[])
*/
void removeMetaEntries() {
@@ -483,7 +470,7 @@ class JarVerifier {
* Returns a {@code Vector} of all of the
* {@link java.security.cert.Certificate}s that are associated with the
* signing of the named signature file.
- *
+ *
* @param signatureFileName
* the name of a signature file.
* @param certificates
diff --git a/archive/src/main/java/java/util/jar/Manifest.java b/archive/src/main/java/java/util/jar/Manifest.java
index 3b0d89a..b28f3fb 100644
--- a/archive/src/main/java/java/util/jar/Manifest.java
+++ b/archive/src/main/java/java/util/jar/Manifest.java
@@ -17,47 +17,65 @@
package java.util.jar;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.security.AccessController;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
-import org.apache.harmony.luni.util.PriviAction;
+import org.apache.harmony.archive.internal.nls.Messages;
+import org.apache.harmony.luni.util.InputStreamExposer;
+import org.apache.harmony.luni.util.ThreadLocalCache;
/**
* The {@code Manifest} class is used to obtain attribute information for a
* {@code JarFile} and its entries.
- *
- * @since Android 1.0
*/
public class Manifest implements Cloneable {
- private static final int LINE_LENGTH_LIMIT = 70;
+ static final int LINE_LENGTH_LIMIT = 72;
private static final byte[] LINE_SEPARATOR = new byte[] { '\r', '\n' };
- private static final Attributes.Name NAME_ATTRIBUTE = new Attributes.Name("Name"); //$NON-NLS-1$
+ private static final byte[] VALUE_SEPARATOR = new byte[] { ':', ' ' };
+
+ private static final Attributes.Name NAME_ATTRIBUTE = new Attributes.Name(
+ "Name"); //$NON-NLS-1$
private Attributes mainAttributes = new Attributes();
- private HashMap<String, Attributes> entryAttributes = new HashMap<String, Attributes>();
+ private HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
+
+ static class Chunk {
+ int start;
+ int end;
+
+ Chunk(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+ }
+
+ private HashMap<String, Chunk> chunks;
- private HashMap<String, byte[]> chunks;
+ /**
+ * Manifest bytes are used for delayed entry parsing.
+ */
+ private InitManifest im;
/**
- * The data chunk of main attributes in the manifest is needed in
+ * The end of the main attributes section in the manifest is needed in
* verification.
*/
- private byte[] mainAttributesChunk;
+ private int mainEnd;
/**
* Creates a new {@code Manifest} instance.
- *
- * @since Android 1.0
*/
public Manifest() {
super();
@@ -66,12 +84,11 @@ public class Manifest implements Cloneable {
/**
* Creates a new {@code Manifest} instance using the attributes obtained
* from the input stream.
- *
+ *
* @param is
* {@code InputStream} to parse for attributes.
* @throws IOException
* if an IO error occurs while creating this {@code Manifest}
- * @since Android 1.0
*/
public Manifest(InputStream is) throws IOException {
super();
@@ -81,20 +98,20 @@ public class Manifest implements Cloneable {
/**
* Creates a new {@code Manifest} instance. The new instance will have the
* same attributes as those found in the parameter {@code Manifest}.
- *
+ *
* @param man
* {@code Manifest} instance to obtain attributes from.
- * @since Android 1.0
*/
@SuppressWarnings("unchecked")
public Manifest(Manifest man) {
mainAttributes = (Attributes) man.mainAttributes.clone();
- entryAttributes = (HashMap<String, Attributes>) man.entryAttributes.clone();
+ entries = (HashMap<String, Attributes>) ((HashMap<String, Attributes>) man
+ .getEntries()).clone();
}
Manifest(InputStream is, boolean readChunks) throws IOException {
if (readChunks) {
- chunks = new HashMap<String, byte[]>();
+ chunks = new HashMap<String, Chunk>();
}
read(is);
}
@@ -102,23 +119,21 @@ public class Manifest implements Cloneable {
/**
* Resets the both the main attributes as well as the entry attributes
* associated with this {@code Manifest}.
- *
- * @since Android 1.0
*/
public void clear() {
- entryAttributes.clear();
+ im = null;
+ entries.clear();
mainAttributes.clear();
}
/**
* Returns the {@code Attributes} associated with the parameter entry
* {@code name}.
- *
+ *
* @param name
* the name of the entry to obtain {@code Attributes} from.
* @return the Attributes for the entry or {@code null} if the entry does
* not exist.
- * @since Android 1.0
*/
public Attributes getAttributes(String name) {
return getEntries().get(name);
@@ -127,20 +142,31 @@ public class Manifest implements Cloneable {
/**
* Returns a map containing the {@code Attributes} for each entry in the
* {@code Manifest}.
- *
+ *
* @return the map of entry attributes.
- * @since Android 1.0
*/
public Map<String, Attributes> getEntries() {
- return entryAttributes;
+ initEntries();
+ return entries;
+ }
+
+ private void initEntries() {
+ if (im == null) {
+ return;
+ }
+ // try {
+ // im.initEntries(entries, chunks);
+ // } catch (IOException ioe) {
+ // throw new RuntimeException(ioe);
+ // }
+ // im = null;
}
/**
* Returns the main {@code Attributes} of the {@code JarFile}.
- *
+ *
* @return main {@code Attributes} associated with the source {@code
* JarFile}.
- * @since Android 1.0
*/
public Attributes getMainAttributes() {
return mainAttributes;
@@ -149,9 +175,8 @@ public class Manifest implements Cloneable {
/**
* Creates a copy of this {@code Manifest}. The returned {@code Manifest}
* will equal the {@code Manifest} from which it was cloned.
- *
+ *
* @return a copy of this instance.
- * @since Android 1.0
*/
@Override
public Object clone() {
@@ -161,12 +186,11 @@ public class Manifest implements Cloneable {
/**
* Writes out the attribute information of the receiver to the specified
* {@code OutputStream}.
- *
+ *
* @param os
* The {@code OutputStream} to write to.
* @throws IOException
* If an error occurs writing the {@code Manifest}.
- * @since Android 1.0
*/
public void write(OutputStream os) throws IOException {
write(this, os);
@@ -175,39 +199,98 @@ public class Manifest implements Cloneable {
/**
* Constructs a new {@code Manifest} instance obtaining attribute
* information from the specified input stream.
- *
+ *
* @param is
* The {@code InputStream} to read from.
* @throws IOException
* If an error occurs reading the {@code Manifest}.
- * @since Android 1.0
*/
public void read(InputStream is) throws IOException {
- InitManifest initManifest = new InitManifest(is, mainAttributes, entryAttributes,
- chunks, null);
- mainAttributesChunk = initManifest.getMainAttributesChunk();
+ byte[] buf;
+ // Try to read get a reference to the bytes directly
+ try {
+ buf = InputStreamExposer.expose(is);
+ } catch (UnsupportedOperationException uoe) {
+ buf = readFully(is);
+ }
+
+ if (buf.length == 0) {
+ return;
+ }
+
+ // a workaround for HARMONY-5662
+ // replace EOF and NUL with another new line
+ // which does not trigger an error
+ byte b = buf[buf.length - 1];
+ if (0 == b || 26 == b) {
+ buf[buf.length - 1] = '\n';
+ }
+
+ // Attributes.Name.MANIFEST_VERSION is not used for
+ // the second parameter for RI compatibility
+ im = new InitManifest(buf, mainAttributes, null);
+ mainEnd = im.getPos();
+ // FIXME
+ im.initEntries(entries, chunks);
+ im = null;
+ }
+
+ /*
+ * Helper to read the entire contents of the manifest from the
+ * given input stream. Usually we can do this in a single read
+ * but we need to account for 'infinite' streams, by ensuring we
+ * have a line feed within a reasonable number of characters.
+ */
+ private byte[] readFully(InputStream is) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8192];
+
+ while (true) {
+ int count = is.read(buffer);
+ if (count == -1) {
+ // TODO: Do we need to copy this, or can we live with junk at the end?
+ return baos.toByteArray();
+ }
+ baos.write(buffer, 0, count);
+
+ if (!containsLine(buffer, count)) {
+ throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /*
+ * Check to see if the buffer contains a newline or carriage
+ * return character within the first 'length' bytes. Used to
+ * check the validity of the manifest input stream.
+ */
+ private boolean containsLine(byte[] buffer, int length) {
+ for (int i = 0; i < length; i++) {
+ if (buffer[i] == 0x0A || buffer[i] == 0x0D) {
+ return true;
+ }
+ }
+ return false;
}
/**
* Returns the hash code for this instance.
- *
+ *
* @return this {@code Manifest}'s hashCode.
- * @since Android 1.0
*/
@Override
public int hashCode() {
- return mainAttributes.hashCode() ^ entryAttributes.hashCode();
+ return mainAttributes.hashCode() ^ getEntries().hashCode();
}
/**
* Determines if the receiver is equal to the parameter object. Two {@code
* Manifest}s are equal if they have identical main attributes as well as
* identical entry attributes.
- *
+ *
* @param o
* the object to compare against.
* @return {@code true} if the manifests are equal, {@code false} otherwise
- * @since Android 1.0
*/
@Override
public boolean equals(Object o) {
@@ -220,10 +303,10 @@ public class Manifest implements Cloneable {
if (!mainAttributes.equals(((Manifest) o).mainAttributes)) {
return false;
}
- return entryAttributes.equals(((Manifest) o).entryAttributes);
+ return getEntries().equals(((Manifest) o).getEntries());
}
- byte[] getChunk(String name) {
+ Chunk getChunk(String name) {
return chunks.get(name);
}
@@ -231,114 +314,84 @@ public class Manifest implements Cloneable {
chunks = null;
}
- byte[] getMainAttributesChunk() {
- return mainAttributesChunk;
+ int getMainAttributesEnd() {
+ return mainEnd;
}
/**
* Writes out the attribute information of the specified manifest to the
* specified {@code OutputStream}
- *
+ *
* @param manifest
* the manifest to write out.
* @param out
* The {@code OutputStream} to write to.
* @throws IOException
* If an error occurs writing the {@code Manifest}.
- * @since Android 1.0
*/
static void write(Manifest manifest, OutputStream out) throws IOException {
- Charset charset = null;
- String encoding = AccessController.doPrivileged(new PriviAction<String>(
- "manifest.write.encoding")); //$NON-NLS-1$
- if (encoding != null) {
- if (encoding.length() == 0) {
- encoding = "UTF8"; //$NON-NLS-1$
- }
- charset = Charset.forName(encoding);
- }
- String version = manifest.mainAttributes.getValue(Attributes.Name.MANIFEST_VERSION);
+ CharsetEncoder encoder = ThreadLocalCache.utf8Encoder.get();
+ ByteBuffer buffer = ThreadLocalCache.byteBuffer.get();
+
+ String version = manifest.mainAttributes
+ .getValue(Attributes.Name.MANIFEST_VERSION);
if (version != null) {
- writeEntry(out, charset, Attributes.Name.MANIFEST_VERSION, version);
+ writeEntry(out, Attributes.Name.MANIFEST_VERSION, version, encoder,
+ buffer);
Iterator<?> entries = manifest.mainAttributes.keySet().iterator();
while (entries.hasNext()) {
Attributes.Name name = (Attributes.Name) entries.next();
if (!name.equals(Attributes.Name.MANIFEST_VERSION)) {
- writeEntry(out, charset, name, manifest.mainAttributes.getValue(name));
+ writeEntry(out, name, manifest.mainAttributes
+ .getValue(name), encoder, buffer);
}
}
}
out.write(LINE_SEPARATOR);
- Iterator<String> i = manifest.entryAttributes.keySet().iterator();
+ Iterator<String> i = manifest.getEntries().keySet().iterator();
while (i.hasNext()) {
String key = i.next();
- writeEntry(out, charset, NAME_ATTRIBUTE, key);
- Attributes attrib = manifest.entryAttributes.get(key);
+ writeEntry(out, NAME_ATTRIBUTE, key, encoder, buffer);
+ Attributes attrib = manifest.entries.get(key);
Iterator<?> entries = attrib.keySet().iterator();
while (entries.hasNext()) {
Attributes.Name name = (Attributes.Name) entries.next();
- writeEntry(out, charset, name, attrib.getValue(name));
+ writeEntry(out, name, attrib.getValue(name), encoder, buffer);
}
out.write(LINE_SEPARATOR);
}
}
- private static void writeEntry(OutputStream os, Charset charset, Attributes.Name name,
- String value) throws IOException {
- int offset = 0;
- int limit = LINE_LENGTH_LIMIT;
- byte[] out = (name.toString() + ": ").getBytes("ISO8859_1"); //$NON-NLS-1$ //$NON-NLS-2$
- if (out.length > limit) {
- while (out.length - offset >= limit) {
- int len = out.length - offset;
- if (len > limit) {
- len = limit;
- }
- if (offset > 0) {
- os.write(' ');
- }
- os.write(out, offset, len);
- os.write(LINE_SEPARATOR);
- offset += len;
- limit = LINE_LENGTH_LIMIT - 1;
- }
- }
- int size = out.length - offset;
- final byte[] outBuf = new byte[LINE_LENGTH_LIMIT];
- System.arraycopy(out, offset, outBuf, 0, size);
- for (int i = 0; i < value.length(); i++) {
- char[] oneChar = new char[1];
- oneChar[0] = value.charAt(i);
- byte[] buf;
- if (oneChar[0] < 128 || charset == null) {
- byte[] oneByte = new byte[1];
- oneByte[0] = (byte) oneChar[0];
- buf = oneByte;
- } else {
- buf = charset.encode(CharBuffer.wrap(oneChar, 0, 1)).array();
- }
- if (size + buf.length > limit) {
- if (limit != LINE_LENGTH_LIMIT) {
- os.write(' ');
- }
- os.write(outBuf, 0, size);
- os.write(LINE_SEPARATOR);
- limit = LINE_LENGTH_LIMIT - 1;
- size = 0;
- }
- if (buf.length == 1) {
- outBuf[size] = buf[0];
- } else {
- System.arraycopy(buf, 0, outBuf, size, buf.length);
- }
- size += buf.length;
+ private static void writeEntry(OutputStream os, Attributes.Name name,
+ String value, CharsetEncoder encoder, ByteBuffer bBuf)
+ throws IOException {
+ byte[] out = name.getBytes();
+ if (out.length > LINE_LENGTH_LIMIT) {
+ throw new IOException(Messages.getString(
+ "archive.33", name, Integer.valueOf(LINE_LENGTH_LIMIT))); //$NON-NLS-1$
}
- if (size > 0) {
- if (limit != LINE_LENGTH_LIMIT) {
- os.write(' ');
+
+ os.write(out);
+ os.write(VALUE_SEPARATOR);
+
+ encoder.reset();
+ bBuf.clear().limit(LINE_LENGTH_LIMIT - out.length - 2);
+
+ CharBuffer cBuf = CharBuffer.wrap(value);
+ CoderResult r;
+
+ while (true) {
+ r = encoder.encode(cBuf, bBuf, true);
+ if (CoderResult.UNDERFLOW == r) {
+ r = encoder.flush(bBuf);
}
- os.write(outBuf, 0, size);
+ os.write(bBuf.array(), bBuf.arrayOffset(), bBuf.position());
os.write(LINE_SEPARATOR);
+ if (CoderResult.UNDERFLOW == r) {
+ break;
+ }
+ os.write(' ');
+ bBuf.clear().limit(LINE_LENGTH_LIMIT - 1);
}
}
}
diff --git a/archive/src/main/java/java/util/jar/Pack200.java b/archive/src/main/java/java/util/jar/Pack200.java
index e0689e0..8145fa1 100644
--- a/archive/src/main/java/java/util/jar/Pack200.java
+++ b/archive/src/main/java/java/util/jar/Pack200.java
@@ -27,8 +27,6 @@ import java.util.SortedMap;
/**
* Class factory for {@link Pack200.Packer} and {@link Pack200.Unpacker}.
- *
- * @since Android 1.0
*/
public abstract class Pack200 {
@@ -39,8 +37,8 @@ public abstract class Pack200 {
/**
* Prevent this class from being instantiated.
*/
- private Pack200(){
- //do nothing
+ private Pack200() {
+ // do nothing
}
/**
@@ -50,10 +48,8 @@ public abstract class Pack200 {
* {@code 'java.util.jar.Pack200.Packer'}. If this system property is
* defined an instance of the specified class is returned, otherwise the
* system's default implementation is returned.
- * </p>
*
* @return an instance of {@code Packer}
- * @since Android 1.0
*/
public static Pack200.Packer newPacker() {
return (Packer) AccessController
@@ -82,10 +78,8 @@ public abstract class Pack200 {
* property {@code 'java.util.jar.Pack200.Unpacker'}. If this system
* property is defined an instance of the specified class is returned,
* otherwise the system's default implementation is returned.
- * </p>
*
* @return a instance of {@code Unpacker}.
- * @since Android 1.0
*/
public static Pack200.Unpacker newUnpacker() {
return (Unpacker) AccessController
@@ -107,150 +101,109 @@ public abstract class Pack200 {
/**
* The interface defining the API for converting a JAR file to an output
* stream in the Pack200 format.
- *
- * @since Android 1.0
*/
public static interface Packer {
/**
* the format of a class attribute name.
- *
- * @since Android 1.0
*/
static final String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; //$NON-NLS-1$
/**
* the format of a code attribute name.
- *
- * @since Android 1.0
*/
static final String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; //$NON-NLS-1$
/**
* the deflation hint to set in the output archive.
- *
- * @since Android 1.0
*/
static final String DEFLATE_HINT = "pack.deflate.hint";//$NON-NLS-1$
/**
* the indicated amount of effort to use in compressing the archive.
- *
- * @since Android 1.0
*/
static final String EFFORT = "pack.effort";//$NON-NLS-1$
/**
* a String representation for {@code error}.
- *
- * @since Android 1.0
*/
static final String ERROR = "error";//$NON-NLS-1$
/**
* a String representation of {@code false}.
- *
- * @since Android 1.0
*/
static final String FALSE = "false";//$NON-NLS-1$
/**
* the format of a field attribute name.
- *
- * @since Android 1.0
*/
static final String FIELD_ATTRIBUTE_PFX = "pack.field.attribute.";//$NON-NLS-1$
/**
* a String representation for {@code keep}.
- *
- * @since Android 1.0
*/
static final String KEEP = "keep";//$NON-NLS-1$
/**
* decide if all elements shall transmit in their original order.
- *
- * @since Android 1.0
*/
static final String KEEP_FILE_ORDER = "pack.keep.file.order";//$NON-NLS-1$
/**
* a String representation for {@code latest}.
- *
- * @since Android 1.0
*/
static final String LATEST = "latest";//$NON-NLS-1$
/**
* the format of a method attribute name.
- *
- * @since Android 1.0
*/
static final String METHOD_ATTRIBUTE_PFX = "pack.method.attribute.";//$NON-NLS-1$
/**
* if it shall attempt to determine the latest modification time if this
* is set to {@code LATEST}.
- *
- * @since Android 1.0
*/
static final String MODIFICATION_TIME = "pack.modification.time";//$NON-NLS-1$
/**
* a String representation of {@code pass}.
- *
- * @since Android 1.0
*/
static final String PASS = "pass";//$NON-NLS-1$
/**
* the file that will not be compressed.
- *
- * @since Android 1.0
*/
static final String PASS_FILE_PFX = "pack.pass.file.";//$NON-NLS-1$
/**
* packer progress as a percentage.
- *
- * @since Android 1.0
*/
static final String PROGRESS = "pack.progress";//$NON-NLS-1$
/**
* The number of bytes of each archive segment.
- *
- * @since Android 1.0
*/
static final String SEGMENT_LIMIT = "pack.segment.limit";//$NON-NLS-1$
/**
* a String representation of {@code strip}.
- *
- * @since Android 1.0
*/
static final String STRIP = "strip";//$NON-NLS-1$
/**
* a String representation of {@code true}.
- *
- * @since Android 1.0
*/
static final String TRUE = "true";//$NON-NLS-1$
/**
* the action to take if an unknown attribute is encountered.
- *
- * @since Android 1.0
*/
static final String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute";//$NON-NLS-1$
/**
* Returns a sorted map of the properties of this packer.
- *
+ *
* @return the properties of the packer.
- * @since Android 1.0
*/
SortedMap<String, String> properties();
@@ -263,7 +216,6 @@ public abstract class Pack200 {
* stream of compressed data.
* @throws IOException
* if I/O exception occurs.
- * @since Android 1.0
*/
void pack(JarFile in, OutputStream out) throws IOException;
@@ -277,7 +229,6 @@ public abstract class Pack200 {
* stream of compressed data.
* @throws IOException
* if I/O exception occurs.
- * @since Android 1.0
*/
void pack(JarInputStream in, OutputStream out) throws IOException;
@@ -301,52 +252,39 @@ public abstract class Pack200 {
/**
* The interface defining the API for converting a packed stream in the
* Pack200 format to a JAR file.
- *
- * @since Android 1.0
*/
public static interface Unpacker {
/**
* The String indicating if the unpacker should ignore all transmitted
* values,can be replaced by either {@code true} or {@code false}.
- *
- * @since Android 1.0
*/
static final String DEFLATE_HINT = "unpack.deflate.hint";//$NON-NLS-1$
/**
* a String representation of {@code false}.
- *
- * @since Android 1.0
*/
static final String FALSE = "false";//$NON-NLS-1$
/**
* a String representation of {@code keep}.
- *
- * @since Android 1.0
*/
static final String KEEP = "keep";//$NON-NLS-1$
/**
* the progress as a {@code percentage}.
- *
- * @since Android 1.0
*/
static final String PROGRESS = "unpack.progress";//$NON-NLS-1$
/**
* a String representation of {@code true}.
- *
- * @since Android 1.0
*/
static final String TRUE = "true";//$NON-NLS-1$
/**
* Returns a sorted map of the properties of this unpacker.
- *
+ *
* @return the properties of unpacker.
- * @since Android 1.0
*/
SortedMap<String, String> properties();
@@ -359,7 +297,6 @@ public abstract class Pack200 {
* JAR output stream of uncompressed data.
* @throws IOException
* if I/O exception occurs.
- * @since Android 1.0
*/
void unpack(InputStream in, JarOutputStream out) throws IOException;
@@ -373,7 +310,6 @@ public abstract class Pack200 {
* JAR output stream of uncompressed data.
* @throws IOException
* if I/O exception occurs.
- * @since Android 1.0
*/
void unpack(File in, JarOutputStream out) throws IOException;
diff --git a/archive/src/main/java/java/util/zip/Adler32.java b/archive/src/main/java/java/util/zip/Adler32.java
index 8eaa18e..a5f77d7 100644
--- a/archive/src/main/java/java/util/zip/Adler32.java
+++ b/archive/src/main/java/java/util/zip/Adler32.java
@@ -17,14 +17,12 @@
package java.util.zip;
-
/**
* The Adler-32 class is used to compute the {@code Adler32} checksum from a set
* of data. Compared to the CRC-32 algorithm it trades reliabilty for speed.
* Refer to RFC 1950 for the specification.
- *
+ *
* @see CRC32
- * @since Android 1.0
*/
public class Adler32 implements java.util.zip.Checksum {
@@ -34,7 +32,6 @@ public class Adler32 implements java.util.zip.Checksum {
* Returns the {@code Adler32} checksum for all input received.
*
* @return The checksum for this instance.
- * @since Android 1.0
*/
public long getValue() {
return adler;
@@ -42,8 +39,6 @@ public class Adler32 implements java.util.zip.Checksum {
/**
* Reset this instance to its initial checksum.
- *
- * @since Android 1.0
*/
public void reset() {
adler = 1;
@@ -55,7 +50,6 @@ public class Adler32 implements java.util.zip.Checksum {
*
* @param i
* the byte to update checksum with.
- * @since Android 1.0
*/
public void update(int i) {
adler = updateByteImpl(i, adler);
@@ -66,7 +60,6 @@ public class Adler32 implements java.util.zip.Checksum {
*
* @param buf
* bytes to update checksum with.
- * @since Android 1.0
*/
public void update(byte[] buf) {
update(buf, 0, buf.length);
@@ -85,7 +78,6 @@ public class Adler32 implements java.util.zip.Checksum {
* @throws ArrayIndexOutOfBoundsException
* if {@code offset > buf.length} or {@code nbytes} is negative
* or {@code offset + nbytes > buf.length}.
- * @since Android 1.0
*/
public void update(byte[] buf, int off, int nbytes) {
// avoid int overflow, check null buf
diff --git a/archive/src/main/java/java/util/zip/CRC32.java b/archive/src/main/java/java/util/zip/CRC32.java
index 36dc376..59e8f81 100644
--- a/archive/src/main/java/java/util/zip/CRC32.java
+++ b/archive/src/main/java/java/util/zip/CRC32.java
@@ -17,12 +17,9 @@
package java.util.zip;
-
/**
* The CRC32 class is used to compute a CRC32 checksum from data provided as
* input value.
- *
- * @since Android 1.0
*/
public class CRC32 implements java.util.zip.Checksum {
@@ -34,7 +31,6 @@ public class CRC32 implements java.util.zip.Checksum {
* Returns the CRC32 checksum for all input received.
*
* @return The checksum for this instance.
- * @since Android 1.0
*/
public long getValue() {
return crc;
@@ -42,8 +38,6 @@ public class CRC32 implements java.util.zip.Checksum {
/**
* Resets the CRC32 checksum to it initial state.
- *
- * @since Android 1.0
*/
public void reset() {
tbytes = crc = 0;
@@ -52,10 +46,9 @@ public class CRC32 implements java.util.zip.Checksum {
/**
* Updates this checksum with the byte value provided as integer.
- *
+ *
* @param val
* represents the byte to update the checksum.
- * @since Android 1.0
*/
public void update(int val) {
crc = updateByteImpl((byte) val, crc);
@@ -66,7 +59,6 @@ public class CRC32 implements java.util.zip.Checksum {
*
* @param buf
* the buffer holding the data to update the checksum with.
- * @since Android 1.0
*/
public void update(byte[] buf) {
update(buf, 0, buf.length);
@@ -82,7 +74,6 @@ public class CRC32 implements java.util.zip.Checksum {
* the offset in {@code buf} to obtain data from.
* @param nbytes
* the number of bytes to read from {@code buf}.
- * @since Android 1.0
*/
public void update(byte[] buf, int off, int nbytes) {
// avoid int overflow, check null buf
diff --git a/archive/src/main/java/java/util/zip/CheckedInputStream.java b/archive/src/main/java/java/util/zip/CheckedInputStream.java
index 659125a..6513e66 100644
--- a/archive/src/main/java/java/util/zip/CheckedInputStream.java
+++ b/archive/src/main/java/java/util/zip/CheckedInputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.IOException;
import java.io.InputStream;
@@ -26,8 +25,6 @@ import java.io.InputStream;
* same time as the data, on which the checksum is computed, is read from a
* stream. The purpose of this checksum is to establish data integrity,
* comparing the computed checksum against a published checksum value.
- *
- * @since Android 1.0
*/
public class CheckedInputStream extends java.io.FilterInputStream {
@@ -42,7 +39,6 @@ public class CheckedInputStream extends java.io.FilterInputStream {
* the input stream to calculate checksum from.
* @param csum
* an entity implementing the checksum algorithm.
- * @since Android 1.0
*/
public CheckedInputStream(InputStream is, Checksum csum) {
super(is);
@@ -57,7 +53,6 @@ public class CheckedInputStream extends java.io.FilterInputStream {
* otherwise.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
@Override
public int read() throws IOException {
@@ -84,7 +79,6 @@ public class CheckedInputStream extends java.io.FilterInputStream {
* end of the filtered stream while reading the data.
* @throws IOException
* if this stream is closed or some I/O error occurs.
- * @since Android 1.0
*/
@Override
public int read(byte[] buf, int off, int nbytes) throws IOException {
@@ -99,7 +93,6 @@ public class CheckedInputStream extends java.io.FilterInputStream {
* Returns the checksum calculated on the stream read so far.
*
* @return the updated checksum.
- * @since Android 1.0
*/
public Checksum getChecksum() {
return check;
@@ -114,7 +107,6 @@ public class CheckedInputStream extends java.io.FilterInputStream {
* @throws IOException
* if this stream is closed or another I/O error occurs.
* @return the number of bytes skipped.
- * @since Android 1.0
*/
@Override
public long skip(long nbytes) throws IOException {
diff --git a/archive/src/main/java/java/util/zip/CheckedOutputStream.java b/archive/src/main/java/java/util/zip/CheckedOutputStream.java
index 9699492..08fe799 100644
--- a/archive/src/main/java/java/util/zip/CheckedOutputStream.java
+++ b/archive/src/main/java/java/util/zip/CheckedOutputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.IOException;
import java.io.OutputStream;
@@ -26,8 +25,6 @@ import java.io.OutputStream;
* of all data written to a stream. The purpose of this checksum is to establish
* data integrity, by publishing the checksum to other parties wanting to read
* the non corrupted data.
- *
- * @since Android 1.0
*/
public class CheckedOutputStream extends java.io.FilterOutputStream {
@@ -42,7 +39,6 @@ public class CheckedOutputStream extends java.io.FilterOutputStream {
* the output stream to calculate checksum for.
* @param cs
* an entity implementing the checksum algorithm.
- * @since Android 1.0
*/
public CheckedOutputStream(OutputStream os, Checksum cs) {
super(os);
@@ -53,7 +49,6 @@ public class CheckedOutputStream extends java.io.FilterOutputStream {
* Returns the checksum calculated on the stream read so far.
*
* @return the updated checksum.
- * @since Android 1.0
*/
public Checksum getChecksum() {
return check;
@@ -67,7 +62,6 @@ public class CheckedOutputStream extends java.io.FilterOutputStream {
* the data value to written to the output stream.
* @throws IOException
* if an IO error has occurred.
- * @since Android 1.0
*/
@Override
public void write(int val) throws IOException {
@@ -88,7 +82,6 @@ public class CheckedOutputStream extends java.io.FilterOutputStream {
* number of bytes to write to the output stream.
* @throws IOException
* if an IO error has occurred.
- * @since Android 1.0
*/
@Override
public void write(byte[] buf, int off, int nbytes) throws IOException {
diff --git a/archive/src/main/java/java/util/zip/Checksum.java b/archive/src/main/java/java/util/zip/Checksum.java
index 0405c08..901ff7a 100644
--- a/archive/src/main/java/java/util/zip/Checksum.java
+++ b/archive/src/main/java/java/util/zip/Checksum.java
@@ -20,8 +20,6 @@ package java.util.zip;
/**
* Holds information about a checksum which was computed with the methods
* implementing a checksum algorithm.
- *
- * @since Android 1.0
*/
public interface Checksum {
@@ -29,37 +27,32 @@ public interface Checksum {
* Returns the current calculated checksum value.
*
* @return the checksum.
- * @since Android 1.0
*/
public long getValue();
/**
* Resets the checksum value applied before beginning calculations on a new
* stream of data.
- *
- * @since Android 1.0
*/
public void reset();
/**
- * Updates the checksum value with the given byte.
- *
- * @param val
- * the byte to update the checksum with.
- * @since Android 1.0
- */
- public void update(int val);
-
- /**
* Updates the checksum with the given bytes.
- *
+ *
* @param buf
* the byte array from which to read the bytes.
* @param off
* the initial position in {@code buf} to read the bytes from.
* @param nbytes
* the number of bytes to read from {@code buf}.
- * @since Android 1.0
*/
public void update(byte[] buf, int off, int nbytes);
+
+ /**
+ * Updates the checksum value with the given byte.
+ *
+ * @param val
+ * the byte to update the checksum with.
+ */
+ public void update(int val);
}
diff --git a/archive/src/main/java/java/util/zip/DataFormatException.java b/archive/src/main/java/java/util/zip/DataFormatException.java
index 9ffe2ab..1e9c5a2 100644
--- a/archive/src/main/java/java/util/zip/DataFormatException.java
+++ b/archive/src/main/java/java/util/zip/DataFormatException.java
@@ -20,8 +20,6 @@ package java.util.zip;
/**
* {@code DataFormatException} is used to indicate an error in the format of a
* particular data stream which is to be uncompressed.
- *
- * @since Android 1.0
*/
public class DataFormatException extends Exception {
@@ -29,8 +27,6 @@ public class DataFormatException extends Exception {
/**
* Constructs a new {@code DataFormatException} instance.
- *
- * @since Android 1.0
*/
public DataFormatException() {
super();
@@ -39,10 +35,9 @@ public class DataFormatException extends Exception {
/**
* Constructs a new {@code DataFormatException} instance with the specified
* message.
- *
+ *
* @param detailMessage
* the detail message for the exception.
- * @since Android 1.0
*/
public DataFormatException(String detailMessage) {
super(detailMessage);
diff --git a/archive/src/main/java/java/util/zip/Deflater.java b/archive/src/main/java/java/util/zip/Deflater.java
index f91f1ca..38771a8 100644
--- a/archive/src/main/java/java/util/zip/Deflater.java
+++ b/archive/src/main/java/java/util/zip/Deflater.java
@@ -17,6 +17,10 @@
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
* href="http://www.gzip.org/algorithm.txt">specification</a>).
@@ -24,83 +28,65 @@ package java.util.zip;
* Basically this class is part of the API to the stream based ZLIB compression
* library and is used as such by {@code DeflaterOutputStream} and its
* descendants.
- * </p>
* <p>
* The typical usage of a {@code Deflater} instance outside this package
* consists of a specific call to one of its constructors before being passed to
* an instance of {@code DeflaterOutputStream}.
- * </p>
- *
+ *
* @see DeflaterOutputStream
* @see Inflater
- * @since Android 1.0
*/
public class Deflater {
/**
* Upper bound for the compression level range.
- *
- * @since Android 1.0
*/
public static final int BEST_COMPRESSION = 9;
/**
* Lower bound for compression level range.
- *
- * @since Android 1.0
*/
public static final int BEST_SPEED = 1;
-
+
/**
* Usage of the default compression level.
- *
- * @since Android 1.0
*/
public static final int DEFAULT_COMPRESSION = -1;
-
+
/**
* Default value for compression strategy.
- *
- * @since Android 1.0
*/
public static final int DEFAULT_STRATEGY = 0;
-
+
/**
* Default value for compression method.
- *
- * @since Android 1.0
*/
public static final int DEFLATED = 8;
-
+
/**
* Possible value for compression strategy.
- *
- * @since Android 1.0
*/
public static final int FILTERED = 1;
-
+
/**
* Possible value for compression strategy.
- *
- * @since Android 1.0
*/
public static final int HUFFMAN_ONLY = 2;
-
+
/**
* Possible value for compression level.
- *
- * @since Android 1.0
*/
public static final int NO_COMPRESSION = 0;
private static final int Z_NO_FLUSH = 0;
private static final int Z_FINISH = 4;
-
+
// Fill in the JNI id caches
private static native void oneTimeInitialization();
-
- // A stub buffer used when deflate() called while inputBuffer has not been set.
+
+ // A stub buffer used when deflate() called while inputBuffer has not been
+ // set.
private static final byte[] STUB_INPUT_BUFFER = new byte[0];
static {
@@ -120,21 +106,19 @@ public class Deflater {
private byte[] inputBuffer;
private int inRead;
-
+
private int inLength;
-
+
/**
* Constructs a new {@code Deflater} instance with default compression
* level. The strategy can be specified with {@link #setStrategy}, only. A
* header is added to the output by default; use constructor {@code
* Deflater(level, boolean)} if you need to omit the header.
- *
- * @since Android 1.0
*/
public Deflater() {
this(DEFAULT_COMPRESSION, false);
}
-
+
/**
* Constructs a new {@code Deflater} instance with a specific compression
* level. The strategy can be specified with {@code setStrategy}, only. A
@@ -143,7 +127,6 @@ public class Deflater {
*
* @param level
* the compression level in the range between 0 and 9.
- * @since Android 1.0
*/
public Deflater(int level) {
this(level, false);
@@ -159,7 +142,6 @@ public class Deflater {
* the compression level in the range between 0 and 9.
* @param noHeader
* {@code true} indicates that no ZLIB header should be written.
- * @since Android 1.0
*/
public Deflater(int level, boolean noHeader) {
super();
@@ -167,7 +149,8 @@ public class Deflater {
throw new IllegalArgumentException();
}
compressLevel = level;
- streamHandle = createStream(compressLevel, strategy, noHeader);
+ streamHandle = createStreamWithMemoryEnsurance(compressLevel, strategy,
+ noHeader);
}
/**
@@ -178,7 +161,6 @@ public class Deflater {
* buffer to write compressed data to.
* @return number of bytes of compressed data written to {@code buf}.
* @see #deflate(byte[], int, int)
- * @since Android 1.0
*/
public int deflate(byte[] buf) {
return deflate(buf, 0, buf.length);
@@ -195,7 +177,6 @@ public class Deflater {
* @param nbytes
* maximum number of bytes of compressed data to be written.
* @return the number of bytes of compressed data written to {@code buf}.
- * @since Android 1.0
*/
public synchronized int deflate(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -224,8 +205,6 @@ public class Deflater {
* finalize()}, it can be called explicitly in order to free native
* resources before the next GC cycle. After {@code end()} was called other
* methods will typically throw an {@code IllegalStateException}.
- *
- * @since Android 1.0
*/
public synchronized void end() {
if (streamHandle != -1) {
@@ -245,7 +224,6 @@ public class Deflater {
* to it.
*
* @see #finished
- * @since Android 1.0
*/
public synchronized void finish() {
flushParm = Z_FINISH;
@@ -256,7 +234,6 @@ public class Deflater {
* compressed.
*
* @return true if all data has been compressed, false otherwise.
- * @since Android 1.0
*/
public synchronized boolean finished() {
return finished;
@@ -271,7 +248,6 @@ public class Deflater {
* used.
* @see #setDictionary(byte[])
* @see #setDictionary(byte[], int, int)
- * @since Android 1.0
*/
public synchronized int getAdler() {
if (streamHandle == -1) {
@@ -287,14 +263,13 @@ public class Deflater {
* Returns the total number of bytes of input consumed by the {@code Deflater}.
*
* @return number of bytes of input read.
- * @since Android 1.0
*/
public synchronized int getTotalIn() {
if (streamHandle == -1) {
throw new IllegalStateException();
}
- return (int)getTotalInImpl(streamHandle);
+ return (int) getTotalInImpl(streamHandle);
}
private synchronized native long getTotalInImpl(long handle);
@@ -303,14 +278,13 @@ public class Deflater {
* Returns the total number of compressed bytes output by this {@code Deflater}.
*
* @return number of compressed bytes output.
- * @since Android 1.0
*/
public synchronized int getTotalOut() {
if (streamHandle == -1) {
throw new IllegalStateException();
}
- return (int)getTotalOutImpl(streamHandle);
+ return (int) getTotalOutImpl(streamHandle);
}
private synchronized native long getTotalOutImpl(long handle);
@@ -327,7 +301,6 @@ public class Deflater {
* @see #finished()
* @see #setInput(byte[])
* @see #setInput(byte[], int, int)
- * @since Android 1.0
*/
public synchronized boolean needsInput() {
if (inputBuffer == null) {
@@ -343,7 +316,6 @@ public class Deflater {
* {@code true} if the {@code Deflater} is to be reused.
*
* @see #finished
- * @since Android 1.0
*/
public synchronized void reset() {
if (streamHandle == -1) {
@@ -367,7 +339,6 @@ public class Deflater {
* @param buf
* the buffer containing the dictionary data bytes.
* @see Deflater#Deflater(int, boolean)
- * @since Android 1.0
*/
public void setDictionary(byte[] buf) {
setDictionary(buf, 0, buf.length);
@@ -378,7 +349,7 @@ public class Deflater {
* setDictionary() can only be called if this {@code Deflater} supports the writing
* of ZLIB headers. This is the default behaviour but can be overridden
* using {@code Deflater(int, boolean)}.
- *
+ *
* @param buf
* the buffer containing the dictionary data bytes.
* @param off
@@ -386,7 +357,6 @@ public class Deflater {
* @param nbytes
* the length of the data.
* @see Deflater#Deflater(int, boolean)
- * @since Android 1.0
*/
public synchronized void setDictionary(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -410,7 +380,6 @@ public class Deflater {
*
* @param buf
* the buffer.
- * @since Android 1.0
*/
public void setInput(byte[] buf) {
setInput(buf, 0, buf.length);
@@ -427,7 +396,6 @@ public class Deflater {
* the offset of the data.
* @param nbytes
* the length of the data.
- * @since Android 1.0
*/
public synchronized void setInput(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -463,7 +431,6 @@ public class Deflater {
* compression level to use
* @exception IllegalArgumentException
* If the compression level is invalid.
- * @since Android 1.0
*/
public synchronized void setLevel(int level) {
if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
@@ -485,7 +452,6 @@ public class Deflater {
* @exception IllegalArgumentException
* If the strategy specified is not one of FILTERED,
* HUFFMAN_ONLY or DEFAULT_STRATEGY.
- * @since Android 1.0
*/
public synchronized void setStrategy(int strategy) {
if (strategy < DEFAULT_STRATEGY || strategy > HUFFMAN_ONLY) {
@@ -496,14 +462,14 @@ public class Deflater {
}
this.strategy = strategy;
}
-
+
/**
* Returns a long int of total number of bytes read by the {@code Deflater}. This
* method performs the same as {@code getTotalIn} except it returns a long value
* instead of an integer
*
+ * @see #getTotalIn()
* @return total number of bytes read by {@code Deflater}.
- * @since Android 1.0
*/
public synchronized long getBytesRead() {
// Throw NPE here
@@ -518,8 +484,8 @@ public class Deflater {
* method performs the same as {@code getTotalOut} except it returns a long
* value instead of an integer
*
+ * @see #getTotalOut()
* @return bytes exactly write by {@code Deflater}
- * @since Android 1.0
*/
public synchronized long getBytesWritten() {
// Throw NPE here
@@ -529,5 +495,13 @@ 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/DeflaterOutputStream.java b/archive/src/main/java/java/util/zip/DeflaterOutputStream.java
index 773e4c4..03769fb 100644
--- a/archive/src/main/java/java/util/zip/DeflaterOutputStream.java
+++ b/archive/src/main/java/java/util/zip/DeflaterOutputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -28,24 +27,19 @@ import org.apache.harmony.archive.internal.nls.Messages;
* This class provides an implementation of {@code FilterOutputStream} that
* compresses data using the <i>DEFLATE</i> algorithm. Basically it wraps the
* {@code Deflater} class and takes care of the buffering.
- *
+ *
* @see Deflater
- * @since Android 1.0
*/
public class DeflaterOutputStream extends FilterOutputStream {
static final int BUF_SIZE = 512;
/**
* The buffer for the data to be written to.
- *
- * @since Android 1.0
*/
protected byte[] buf;
/**
* The deflater used.
- *
- * @since Android 1.0
*/
protected Deflater def;
@@ -61,7 +55,6 @@ public class DeflaterOutputStream extends FilterOutputStream {
* @param def
* is the specific {@code Deflater} that is used to compress
* data.
- * @since Android 1.0
*/
public DeflaterOutputStream(OutputStream os, Deflater def) {
this(os, def, BUF_SIZE);
@@ -76,7 +69,6 @@ public class DeflaterOutputStream extends FilterOutputStream {
*
* @param os
* is the OutputStream where to write the compressed data to.
- * @since Android 1.0
*/
public DeflaterOutputStream(OutputStream os) {
this(os, new Deflater());
@@ -94,7 +86,6 @@ public class DeflaterOutputStream extends FilterOutputStream {
* data.
* @param bsize
* is the size to be used for the internal buffer.
- * @since Android 1.0
*/
public DeflaterOutputStream(OutputStream os, Deflater def, int bsize) {
super(os);
@@ -114,7 +105,6 @@ public class DeflaterOutputStream extends FilterOutputStream {
*
* @throws IOException
* If an error occurs during deflation.
- * @since Android 1.0
*/
protected void deflate() throws IOException {
int x = 0;
@@ -132,7 +122,6 @@ public class DeflaterOutputStream extends FilterOutputStream {
* @throws IOException
* If an error occurs while closing the data compression
* process.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
@@ -149,7 +138,6 @@ public class DeflaterOutputStream extends FilterOutputStream {
*
* @throws IOException
* If an error occurs.
- * @since Android 1.0
*/
public void finish() throws IOException {
if (done) {
@@ -186,7 +174,6 @@ public class DeflaterOutputStream extends FilterOutputStream {
* the number of bytes of data to read from the buffer.
* @throws IOException
* If an error occurs during writing.
- * @since Android 1.0
*/
@Override
public void write(byte[] buffer, int off, int nbytes) throws IOException {
diff --git a/archive/src/main/java/java/util/zip/GZIPInputStream.java b/archive/src/main/java/java/util/zip/GZIPInputStream.java
index fc70d62..bb84f5b 100644
--- a/archive/src/main/java/java/util/zip/GZIPInputStream.java
+++ b/archive/src/main/java/java/util/zip/GZIPInputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -28,49 +27,40 @@ import org.apache.harmony.archive.internal.nls.Messages;
* The {@code GZIPInputStream} class is used to read data stored in the GZIP
* format, reading and decompressing GZIP data from the underlying stream into
* its buffer.
- *
- * @since Android 1.0
*/
-public class GZIPInputStream extends java.util.zip.InflaterInputStream {
+public class GZIPInputStream extends InflaterInputStream {
+
+ private static final int FCOMMENT = 16;
+
+ private static final int FEXTRA = 4;
+
+ private static final int FHCRC = 2;
+
+ private static final int FNAME = 8;
+
+ /**
+ * The magic header for the GZIP format.
+ */
+ public final static int GZIP_MAGIC = 0x8b1f;
/**
* The checksum algorithm used when handling uncompressed data.
- *
- * @since Android 1.0
*/
protected CRC32 crc = new CRC32();
/**
* Indicates the end of the input stream.
- *
- * @since Android 1.0
*/
protected boolean eos = false;
/**
- * The magic header for the GZIP format.
- *
- * @since Android 1.0
- */
- public final static int GZIP_MAGIC = 0x8b1f;
-
- private static final int FHCRC = 2;
-
- private static final int FEXTRA = 4;
-
- private static final int FNAME = 8;
-
- private static final int FCOMMENT = 16;
-
- /**
* Construct a {@code GZIPInputStream} to read from GZIP data from the
* underlying stream.
- *
+ *
* @param is
* the {@code InputStream} to read data from.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public GZIPInputStream(InputStream is) throws IOException {
this(is, BUF_SIZE);
@@ -86,7 +76,6 @@ public class GZIPInputStream extends java.util.zip.InflaterInputStream {
* the internal read buffer size.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public GZIPInputStream(InputStream is, int size) throws IOException {
super(is, new Inflater(true), size);
@@ -134,6 +123,15 @@ public class GZIPInputStream extends java.util.zip.InflaterInputStream {
}
}
+ /**
+ * Closes this stream and any underlying streams.
+ */
+ @Override
+ public void close() throws IOException {
+ eos = true;
+ super.close();
+ }
+
private long getLong(byte[] buffer, int off) {
long l = 0;
l |= (buffer[off] & 0xFF);
@@ -147,12 +145,23 @@ public class GZIPInputStream extends java.util.zip.InflaterInputStream {
return (buffer[off] & 0xFF) | ((buffer[off + 1] & 0xFF) << 8);
}
+ /**
+ * Reads and decompresses GZIP data from the underlying stream into the
+ * given buffer.
+ *
+ * @param buffer
+ * Buffer to receive data
+ * @param off
+ * Offset in buffer to store data
+ * @param nbytes
+ * Number of bytes to read
+ */
@Override
public int read(byte[] buffer, int off, int nbytes) throws IOException {
if (closed) {
throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
}
- if(eof){
+ if (eof) {
return -1;
}
// avoid int overflow, check null buffer
@@ -164,17 +173,15 @@ public class GZIPInputStream extends java.util.zip.InflaterInputStream {
} else if (!eos) {
eos = true;
// Get non-compressed bytes read by fill
- // BEGIN android-changed
- // copied from newer version of harmony
int size = inf.getRemaining();
final int trailerSize = 8; // crc (4 bytes) + total out (4
- // bytes)
+ // bytes)
byte[] b = new byte[trailerSize];
int copySize = (size > trailerSize) ? trailerSize : size;
System.arraycopy(buf, len - size, b, 0, copySize);
- readFully(b, copySize, trailerSize - copySize);
- // END android-changed
+ readFully(b, copySize, trailerSize - copySize);
+
if (getLong(b, 0) != crc.getValue()) {
throw new IOException(Messages.getString("archive.20")); //$NON-NLS-1$
}
@@ -186,12 +193,6 @@ public class GZIPInputStream extends java.util.zip.InflaterInputStream {
}
throw new ArrayIndexOutOfBoundsException();
}
-
- @Override
- public void close() throws IOException {
- eos = true;
- super.close();
- }
private void readFully(byte[] buffer, int offset, int length)
throws IOException {
diff --git a/archive/src/main/java/java/util/zip/GZIPOutputStream.java b/archive/src/main/java/java/util/zip/GZIPOutputStream.java
index fa41e19..f146da1 100644
--- a/archive/src/main/java/java/util/zip/GZIPOutputStream.java
+++ b/archive/src/main/java/java/util/zip/GZIPOutputStream.java
@@ -17,22 +17,17 @@
package java.util.zip;
-
import java.io.IOException;
import java.io.OutputStream;
/**
* The {@code GZIPOutputStream} class is used to write data to a stream in the
* GZIP storage format.
- *
- * @since Android 1.0
*/
public class GZIPOutputStream extends DeflaterOutputStream {
/**
* The checksum algorithm used when treating uncompressed data.
- *
- * @since Android 1.0
*/
protected CRC32 crc = new CRC32();
@@ -44,7 +39,6 @@ public class GZIPOutputStream extends DeflaterOutputStream {
* the {@code OutputStream} to write data to.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public GZIPOutputStream(OutputStream os) throws IOException {
this(os, BUF_SIZE);
@@ -61,7 +55,6 @@ public class GZIPOutputStream extends DeflaterOutputStream {
* the internal buffer size.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public GZIPOutputStream(OutputStream os, int size) throws IOException {
super(os, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size);
@@ -76,10 +69,9 @@ public class GZIPOutputStream extends DeflaterOutputStream {
/**
* Indicates to the stream that all data has been written out, and any GZIP
* terminal data can now be written.
- *
+ *
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
@Override
public void finish() throws IOException {
@@ -88,24 +80,29 @@ public class GZIPOutputStream extends DeflaterOutputStream {
writeLong(crc.tbytes);
}
+ /**
+ * Write up to nbytes of data from the given buffer, starting at offset off,
+ * to the underlying stream in GZIP format.
+ */
@Override
public void write(byte[] buffer, int off, int nbytes) throws IOException {
super.write(buffer, off, nbytes);
crc.update(buffer, off, nbytes);
}
- private int writeShort(int i) throws IOException {
- out.write(i & 0xFF);
- out.write((i >> 8) & 0xFF);
+ private long writeLong(long i) throws IOException {
+ // Write out the long value as an unsigned int
+ int unsigned = (int) i;
+ out.write(unsigned & 0xFF);
+ out.write((unsigned >> 8) & 0xFF);
+ out.write((unsigned >> 16) & 0xFF);
+ out.write((unsigned >> 24) & 0xFF);
return i;
}
- private long writeLong(long i) throws IOException {
- // Write out the long value as an unsigned int
- out.write((int) (i & 0xFF));
- out.write((int) (i >> 8) & 0xFF);
- out.write((int) (i >> 16) & 0xFF);
- out.write((int) (i >> 24) & 0xFF);
+ private int writeShort(int i) throws IOException {
+ out.write(i & 0xFF);
+ out.write((i >> 8) & 0xFF);
return i;
}
}
diff --git a/archive/src/main/java/java/util/zip/Inflater.java b/archive/src/main/java/java/util/zip/Inflater.java
index 9b93e54..cb1ce68 100644
--- a/archive/src/main/java/java/util/zip/Inflater.java
+++ b/archive/src/main/java/java/util/zip/Inflater.java
@@ -30,45 +30,65 @@ import java.io.FileDescriptor;
* Basically this class is part of the API to the stream based ZLIB compression
* library and is used as such by {@code InflaterInputStream} and its
* descendants.
- * </p>
* <p>
* The typical usage of a {@code Inflater} outside this package consists of a
* specific call to one of its constructors before being passed to an instance
* of {@code InflaterInputStream}.
- * </p>
- *
+ *
* @see InflaterInputStream
* @see Deflater
- * @since Android 1.0
*/
public class Inflater {
+ private static final byte MAGIC_NUMBER = 120;
+
+ static {
+ oneTimeInitialization();
+ }
+
+ // Fill in the JNI id caches
+ private static native void oneTimeInitialization();
+
private boolean finished; // Set by the inflateImpl native
- private boolean needsDictionary; // Set by the inflateImpl native
+ private boolean gotFirstByte = false;
- private long streamHandle = -1;
+ int inLength;
int inRead;
-
- int inLength;
- // Fill in the JNI id caches
- private static native void oneTimeInitialization();
+ private boolean needsDictionary; // Set by the inflateImpl native
- static {
- oneTimeInitialization();
- }
-
- private static final byte MAGIC_NUMBER = 120;
- private boolean gotFirstByte = false;
private boolean pass_magic_number_check = true;
-
+
+ private long streamHandle = -1;
+
+ /**
+ * This constructor creates an inflater that expects a header from the input
+ * stream. Use {@code Inflater(boolean)} if the input comes without a ZLIB
+ * header.
+ */
+ public Inflater() {
+ this(false);
+ }
+
+ /**
+ * This constructor allows to create an inflater that expects no header from
+ * the input stream.
+ *
+ * @param noHeader
+ * {@code true} indicates that no ZLIB header comes with the
+ * input.
+ */
+ public Inflater(boolean noHeader) {
+ streamHandle = createStream(noHeader);
+ }
+
+ private native long createStream(boolean noHeader1);
+
/**
* Release any resources associated with this {@code Inflater}. Any unused
* input/output is discarded. This is also called by the finalize method.
- *
- * @since Android 1.0
*/
public synchronized void end() {
if (streamHandle != -1) {
@@ -91,10 +111,9 @@ public class Inflater {
* stream. If deflated bytes remain and {@code needsInput()} returns {@code
* true} this method will return {@code false}. This method should be
* called after all deflated input is supplied to the {@code Inflater}.
- *
+ *
* @return {@code true} if all input has been inflated, {@code false}
* otherwise.
- * @since Android 1.0
*/
public synchronized boolean finished() {
return finished;
@@ -103,10 +122,9 @@ public class Inflater {
/**
* Returns the <i>Adler32</i> checksum of either all bytes inflated, or the
* checksum of the preset dictionary if one has been supplied.
- *
+ *
* @return The <i>Adler32</i> checksum associated with this
* {@code Inflater}.
- * @since Android 1.0 .
*/
public synchronized int getAdler() {
if (streamHandle == -1) {
@@ -118,11 +136,40 @@ public class Inflater {
private native synchronized int getAdlerImpl(long handle);
/**
+ * Returns the total number of bytes read by the {@code Inflater}. This
+ * method performs the same as {@code getTotalIn()} except that it returns a
+ * {@code long} value instead of an integer.
+ *
+ * @return the total number of bytes read.
+ */
+ public synchronized long getBytesRead() {
+ // Throw NPE here
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+ return getTotalInImpl(streamHandle);
+ }
+
+ /**
+ * Returns a the total number of bytes read by the {@code Inflater}. This
+ * method performs the same as {@code getTotalOut} except it returns a
+ * {@code long} value instead of an integer.
+ *
+ * @return the total bytes written to the output buffer.
+ */
+ public synchronized long getBytesWritten() {
+ // Throw NPE here
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+ return getTotalOutImpl(streamHandle);
+ }
+
+ /**
* Returns the number of bytes of current input remaining to be read by the
* inflater.
- *
+ *
* @return the number of bytes of unread input.
- * @since Android 1.0
*/
public synchronized int getRemaining() {
return inLength - inRead;
@@ -131,9 +178,8 @@ public class Inflater {
/**
* Returns total number of bytes of input read by the {@code Inflater}. The
* result value is limited by {@code Integer.MAX_VALUE}.
- *
+ *
* @return the total number of bytes read.
- * @since Android 1.0
*/
public synchronized int getTotalIn() {
if (streamHandle == -1) {
@@ -149,9 +195,8 @@ public class Inflater {
/**
* Returns total number of bytes written to the output buffer by the {@code
* Inflater}. The result value is limited by {@code Integer.MAX_VALUE}.
- *
+ *
* @return the total bytes of output data written.
- * @since Android 1.0
*/
public synchronized int getTotalOut() {
if (streamHandle == -1) {
@@ -166,14 +211,13 @@ public class Inflater {
/**
* Inflates bytes from current input and stores them in {@code buf}.
- *
+ *
* @param buf
* the buffer where decompressed data bytes are written.
* @return the number of bytes inflated.
* @throws DataFormatException
* if the underlying stream is corrupted or was not compressed
* using a {@code Deflater}.
- * @since Android 1.0
*/
public int inflate(byte[] buf) throws DataFormatException {
return inflate(buf, 0, buf.length);
@@ -182,7 +226,7 @@ public class Inflater {
/**
* Inflates up to n bytes from the current input and stores them in {@code
* buf} starting at {@code off}.
- *
+ *
* @param buf
* the buffer to write inflated bytes to.
* @param off
@@ -205,7 +249,7 @@ public class Inflater {
if (streamHandle == -1) {
throw new IllegalStateException();
}
-
+
if (!pass_magic_number_check) {
throw new DataFormatException();
}
@@ -213,7 +257,7 @@ public class Inflater {
if (needsInput()) {
return 0;
}
-
+
boolean neededDict = needsDictionary;
needsDictionary = false;
int result = inflateImpl(buf, off, nbytes, streamHandle);
@@ -229,41 +273,15 @@ public class Inflater {
int nbytes, long handle);
/**
- * This constructor creates an inflater that expects a header from the input
- * stream. Use {@code Inflater(boolean)} if the input comes without a ZLIB
- * header.
- *
- * @since Android 1.0
- * @since Android 1.0
- */
- public Inflater() {
- this(false);
- }
-
- /**
- * This constructor allows to create an inflater that expects no header from
- * the input stream.
- *
- * @param noHeader
- * {@code true} indicates that no ZLIB header comes with the
- * input.
- * @since Android 1.0
- */
- public Inflater(boolean noHeader) {
- streamHandle = createStream(noHeader);
- }
-
- /**
* Indicates whether the input bytes were compressed with a preset
* dictionary. This method should be called prior to {@code inflate()} to
* determine whether a dictionary is required. If so {@code setDictionary()}
* should be called with the appropriate dictionary prior to calling {@code
* inflate()}.
- *
+ *
* @return {@code true} if a preset dictionary is required for inflation.
* @see #setDictionary(byte[])
* @see #setDictionary(byte[], int, int)
- * @since Android 1.0
*/
public synchronized boolean needsDictionary() {
return needsDictionary;
@@ -271,11 +289,10 @@ public class Inflater {
/**
* Indicates that input has to be passed to the inflater.
- *
+ *
* @return {@code true} if {@code setInput} has to be called before
* inflation can proceed.
* @see #setInput(byte[])
- * @since Android 1.0
*/
public synchronized boolean needsInput() {
return inRead == inLength;
@@ -284,8 +301,6 @@ public class Inflater {
/**
* Resets the {@code Inflater}. Should be called prior to inflating a new
* set of data.
- *
- * @since Android 1.0
*/
public synchronized void reset() {
if (streamHandle == -1) {
@@ -303,11 +318,10 @@ public class Inflater {
* Sets the preset dictionary to be used for inflation to {@code buf}.
* {@code needsDictionary()} can be called to determine whether the current
* input was deflated using a preset dictionary.
- *
+ *
* @param buf
* The buffer containing the dictionary bytes.
* @see #needsDictionary
- * @since Android 1.0
*/
public synchronized void setDictionary(byte[] buf) {
setDictionary(buf, 0, buf.length);
@@ -316,7 +330,11 @@ public class Inflater {
/**
* Like {@code setDictionary(byte[])}, allowing to define a specific region
* inside {@code buf} to be used as a dictionary.
- *
+ * <p>
+ * The dictionary should be set if the {@link #inflate(byte[])} returned
+ * zero bytes inflated and {@link #needsDictionary()} returns
+ * <code>true</code>.
+ *
* @param buf
* the buffer containing the dictionary data bytes.
* @param off
@@ -324,7 +342,6 @@ public class Inflater {
* @param nbytes
* the length of the data.
* @see #needsDictionary
- * @since Android 1.0
*/
public synchronized void setDictionary(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -345,11 +362,10 @@ public class Inflater {
/**
* Sets the current input to to be decrompressed. This method should only be
* called if {@code needsInput()} returns {@code true}.
- *
+ *
* @param buf
* the input buffer.
* @see #needsInput
- * @since Android 1.0
*/
public synchronized void setInput(byte[] buf) {
setInput(buf, 0, buf.length);
@@ -360,7 +376,7 @@ public class Inflater {
* {@code off} and ending at {@code nbytes - 1} where data is written after
* decompression. This method should only be called if {@code needsInput()}
* returns {@code true}.
- *
+ *
* @param buf
* the input buffer.
* @param off
@@ -368,7 +384,6 @@ public class Inflater {
* @param nbytes
* the number of bytes to read.
* @see #needsInput
- * @since Android 1.0
*/
public synchronized void setInput(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -394,10 +409,9 @@ public class Inflater {
// And at a first glance it doesn't look like the first byte has
// to be 120.
// END android-note
- if(!gotFirstByte && nbytes>0)
- {
- pass_magic_number_check = (buf[off] == MAGIC_NUMBER || nbytes > 1);
- gotFirstByte = true;
+ if (!gotFirstByte && nbytes > 0) {
+ pass_magic_number_check = (buf[off] == MAGIC_NUMBER || nbytes > 1);
+ gotFirstByte = true;
}
}
@@ -407,14 +421,13 @@ public class Inflater {
* off} and ending at {@code nbytes - 1}. This method should only be called
* if {@code needsInput()} returns {@code true}.
*
- * @param file
+ * @param fd
* the input file.
* @param off
* the offset to read from in buffer.
* @param nbytes
* the number of bytes to read.
* @see #needsInput
- * @since Android 1.0
*/
synchronized int setFileInput(FileDescriptor fd, long off, int nbytes) {
if (streamHandle == -1) {
@@ -426,38 +439,6 @@ public class Inflater {
}
// END android-added
- /**
- * Returns the total number of bytes read by the {@code Inflater}. This
- * method performs the same as {@code getTotalIn()} except that it returns a
- * {@code long} value instead of an integer.
- *
- * @return the total number of bytes read.
- * @since Android 1.0
- */
- public synchronized long getBytesRead() {
- // Throw NPE here
- if (streamHandle == -1) {
- throw new NullPointerException();
- }
- return getTotalInImpl(streamHandle);
- }
-
- /**
- * Returns a the total number of bytes read by the {@code Inflater}. This
- * method performs the same as {@code getTotalOut} except it returns a
- * {@code long} value instead of an integer.
- *
- * @return the total bytes written to the output buffer.
- * @since Android 1.0
- */
- public synchronized long getBytesWritten() {
- // Throw NPE here
- if (streamHandle == -1) {
- throw new NullPointerException();
- }
- return getTotalOutImpl(streamHandle);
- }
-
private native synchronized void setInputImpl(byte[] buf, int off,
int nbytes, long handle);
@@ -465,6 +446,4 @@ public class Inflater {
private native synchronized int setFileInputImpl(FileDescriptor fd, long off,
int nbytes, long handle);
// END android-added
-
- private native long createStream(boolean noHeader1);
}
diff --git a/archive/src/main/java/java/util/zip/InflaterInputStream.java b/archive/src/main/java/java/util/zip/InflaterInputStream.java
index 5d3bda0..1fd3602 100644
--- a/archive/src/main/java/java/util/zip/InflaterInputStream.java
+++ b/archive/src/main/java/java/util/zip/InflaterInputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
@@ -31,31 +30,24 @@ import org.apache.harmony.archive.internal.nls.Messages;
* (see <a href="http://www.gzip.org/algorithm.txt">specification</a>).
* Basically it wraps the {@code Inflater} class and takes care of the
* buffering.
- *
+ *
* @see Inflater
* @see DeflaterOutputStream
- * @since Android 1.0
*/
public class InflaterInputStream extends FilterInputStream {
/**
* The inflater used for this stream.
- *
- * @since Android 1.0
*/
protected Inflater inf;
/**
* The input buffer used for decompression.
- *
- * @since Android 1.0
*/
protected byte[] buf;
/**
* The length of the buffer.
- *
- * @since Android 1.0
*/
protected int len;
@@ -74,10 +66,9 @@ public class InflaterInputStream extends FilterInputStream {
* InputStream} from which the compressed data is to be read from. Default
* settings for the {@code Inflater} and internal buffer are be used. In
* particular the Inflater expects a ZLIB header from the input stream.
- *
+ *
* @param is
* the {@code InputStream} to read data from.
- * @since Android 1.0
*/
public InflaterInputStream(InputStream is) {
this(is, new Inflater(), BUF_SIZE);
@@ -86,12 +77,11 @@ public class InflaterInputStream extends FilterInputStream {
/**
* This constructor lets you pass a specifically initialized Inflater,
* for example one that expects no ZLIB header.
- *
+ *
* @param is
* the {@code InputStream} to read data from.
* @param inf
* the specific {@code Inflater} for uncompressing data.
- * @since Android 1.0
*/
public InflaterInputStream(InputStream is, Inflater inf) {
this(is, inf, BUF_SIZE);
@@ -100,14 +90,13 @@ public class InflaterInputStream extends FilterInputStream {
/**
* This constructor lets you specify both the {@code Inflater} as well as
* the internal buffer size to be used.
- *
+ *
* @param is
* the {@code InputStream} to read data from.
* @param inf
* the specific {@code Inflater} for uncompressing data.
* @param bsize
* the size to be used for the internal buffer.
- * @since Android 1.0
*/
public InflaterInputStream(InputStream is, Inflater inf, int bsize) {
super(is);
@@ -129,11 +118,10 @@ public class InflaterInputStream extends FilterInputStream {
/**
* Reads a single byte of decompressed data.
- *
+ *
* @return the byte read.
* @throws IOException
* if an error occurs reading the byte.
- * @since Android 1.0
*/
@Override
public int read() throws IOException {
@@ -147,7 +135,7 @@ public class InflaterInputStream extends FilterInputStream {
/**
* Reads up to {@code nbytes} of decompressed data and stores it in
* {@code buffer} starting at {@code off}.
- *
+ *
* @param buffer
* the buffer to write data to.
* @param off
@@ -157,7 +145,6 @@ public class InflaterInputStream extends FilterInputStream {
* @return Number of uncompressed bytes read
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
@Override
public int read(byte[] buffer, int off, int nbytes) throws IOException {
@@ -197,7 +184,7 @@ public class InflaterInputStream extends FilterInputStream {
if (len == -1) {
throw new EOFException();
}
- throw (IOException)(new IOException().initCause(e));
+ throw (IOException) (new IOException().initCause(e));
}
if (result > 0) {
return result;
@@ -208,20 +195,18 @@ public class InflaterInputStream extends FilterInputStream {
return -1;
} else if (len == -1) {
throw new EOFException();
- // If result == 0, fill() and try again
+ // If result == 0, fill() and try again
}
} while (true);
}
throw new ArrayIndexOutOfBoundsException();
}
-
/**
* Fills the input buffer with data to be decompressed.
- *
+ *
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
protected void fill() throws IOException {
if (closed) {
@@ -246,17 +231,21 @@ public class InflaterInputStream extends FilterInputStream {
/**
* Skips up to n bytes of uncompressed data.
- *
+ *
* @param nbytes
* the number of bytes to skip.
* @return the number of uncompressed bytes skipped.
* @throws IOException
* if an error occurs skipping.
- * @since Android 1.0
*/
@Override
public long skip(long nbytes) throws IOException {
if (nbytes >= 0) {
+ // BEGIN android-changed
+ if (buf == null) {
+ buf = new byte[BUF_SIZE];
+ }
+ // END android-changed
long count = 0, rem = 0;
while (count < nbytes) {
int x = read(buf, 0,
@@ -275,11 +264,10 @@ public class InflaterInputStream extends FilterInputStream {
/**
* Returns whether data can be read from this stream.
- *
+ *
* @return 0 if this stream has been closed, 1 otherwise.
* @throws IOException
* If an error occurs.
- * @since Android 1.0
*/
@Override
public int available() throws IOException {
@@ -295,10 +283,9 @@ public class InflaterInputStream extends FilterInputStream {
/**
* Closes the input stream.
- *
+ *
* @throws IOException
* If an error occurs closing the input stream.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
@@ -309,17 +296,15 @@ public class InflaterInputStream extends FilterInputStream {
super.close();
}
}
-
+
/**
- * This implementation overrides the super type implementation to do nothing
- * at all.
- *
+ * Marks the current position in the stream. This implementation overrides
+ * the super type implementation to do nothing at all.
+ *
* @param readlimit
* of no use.
- * @since Android 1.0
*/
@Override
- @SuppressWarnings("unused")
public void mark(int readlimit) {
// do nothing
}
@@ -328,22 +313,20 @@ public class InflaterInputStream extends FilterInputStream {
* Reset the position of the stream to the last marked position. This
* implementation overrides the supertype implementation and always throws
* an {@link IOException IOException} when called.
- *
+ *
* @throws IOException
* if the method is called
- * @since Android 1.0
*/
@Override
- public void reset() throws IOException{
+ public void reset() throws IOException {
throw new IOException();
}
-
+
/**
* Returns whether the receiver implements {@code mark} semantics. This type
* does not support {@code mark()}, so always responds {@code false}.
- *
+ *
* @return false, always
- * @since Android 1.0
*/
@Override
public boolean markSupported() {
diff --git a/archive/src/main/java/java/util/zip/ZipConstants.java b/archive/src/main/java/java/util/zip/ZipConstants.java
index d804b0e..d00adc9 100644
--- a/archive/src/main/java/java/util/zip/ZipConstants.java
+++ b/archive/src/main/java/java/util/zip/ZipConstants.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
interface ZipConstants {
public static final long LOCSIG = 0x4034b50, EXTSIG = 0x8074b50,
diff --git a/archive/src/main/java/java/util/zip/ZipEntry.java b/archive/src/main/java/java/util/zip/ZipEntry.java
index 2cc7a9c..9774b6a 100644
--- a/archive/src/main/java/java/util/zip/ZipEntry.java
+++ b/archive/src/main/java/java/util/zip/ZipEntry.java
@@ -36,10 +36,9 @@ import java.util.GregorianCalendar;
* itself. For example when reading a <i>ZIP-file</i> you will first retrieve
* all its entries in a collection and then read the data for a specific entry
* through an input stream.
- *
+ *
* @see ZipFile
* @see ZipOutputStream
- * @since Android 1.0
*/
public class ZipEntry implements ZipConstants, Cloneable {
String name, comment;
@@ -94,26 +93,21 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Zip entry state: Deflated.
- *
- * @since Android 1.0
*/
public static final int DEFLATED = 8;
/**
* Zip entry state: Stored.
- *
- * @since Android 1.0
*/
public static final int STORED = 0;
/**
* Constructs a new {@code ZipEntry} with the specified name.
- *
+ *
* @param name
* the name of the ZIP entry.
* @throws IllegalArgumentException
* if the name length is outside the range (> 0xFFFF).
- * @since Android 1.0
*/
public ZipEntry(String name) {
if (name == null) {
@@ -147,11 +141,10 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Gets the comment for this {@code ZipEntry}.
- *
+ *
* @return the comment for this {@code ZipEntry}, or {@code null} if there
* is no comment. If we're reading an archive with
* {@code ZipInputStream} the comment is not available.
- * @since Android 1.0
*/
public String getComment() {
return comment;
@@ -159,10 +152,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Gets the compressed size of this {@code ZipEntry}.
- *
+ *
* @return the compressed size, or -1 if the compressed size has not been
* set.
- * @since Android 1.0
*/
public long getCompressedSize() {
return compressedSize;
@@ -170,9 +162,8 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Gets the checksum for this {@code ZipEntry}.
- *
+ *
* @return the checksum, or -1 if the checksum has not been set.
- * @since Android 1.0
*/
public long getCrc() {
return crc;
@@ -180,10 +171,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Gets the extra information for this {@code ZipEntry}.
- *
+ *
* @return a byte array containing the extra information, or {@code null} if
* there is none.
- * @since Android 1.0
*/
public byte[] getExtra() {
return extra;
@@ -191,10 +181,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Gets the compression method for this {@code ZipEntry}.
- *
+ *
* @return the compression method, either {@code DEFLATED}, {@code STORED}
* or -1 if the compression method has not been set.
- * @since Android 1.0
*/
public int getMethod() {
return compressionMethod;
@@ -202,9 +191,8 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Gets the name of this {@code ZipEntry}.
- *
+ *
* @return the entry name.
- * @since Android 1.0
*/
public String getName() {
return name;
@@ -212,10 +200,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Gets the uncompressed size of this {@code ZipEntry}.
- *
+ *
* @return the uncompressed size, or {@code -1} if the size has not been
* set.
- * @since Android 1.0
*/
public long getSize() {
return size;
@@ -223,10 +210,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Gets the last modification time of this {@code ZipEntry}.
- *
+ *
* @return the last modification time as the number of milliseconds since
* Jan. 1, 1970.
- * @since Android 1.0
*/
public long getTime() {
if (time != -1) {
@@ -242,10 +228,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Determine whether or not this {@code ZipEntry} is a directory.
- *
+ *
* @return {@code true} when this {@code ZipEntry} is a directory, {@code
* false} otherwise.
- * @since Android 1.0
*/
public boolean isDirectory() {
return name.charAt(name.length() - 1) == '/';
@@ -253,10 +238,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the comment for this {@code ZipEntry}.
- *
+ *
* @param string
* the comment for this entry.
- * @since Android 1.0
*/
public void setComment(String string) {
if (string == null || string.length() <= 0xFFFF) {
@@ -268,10 +252,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the compressed size for this {@code ZipEntry}.
- *
+ *
* @param value
* the compressed size (in bytes).
- * @since Android 1.0
*/
public void setCompressedSize(long value) {
compressedSize = value;
@@ -279,12 +262,11 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the checksum for this {@code ZipEntry}.
- *
+ *
* @param value
* the checksum for this entry.
* @throws IllegalArgumentException
* if {@code value} is < 0 or > 0xFFFFFFFFL.
- * @since Android 1.0
*/
public void setCrc(long value) {
if (value >= 0 && value <= 0xFFFFFFFFL) {
@@ -296,12 +278,11 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the extra information for this {@code ZipEntry}.
- *
+ *
* @param data
* a byte array containing the extra information.
* @throws IllegalArgumentException
* when the length of data is greater than 0xFFFF bytes.
- * @since Android 1.0
*/
public void setExtra(byte[] data) {
if (data == null || data.length <= 0xFFFF) {
@@ -313,13 +294,12 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the compression method for this {@code ZipEntry}.
- *
+ *
* @param value
* the compression method, either {@code DEFLATED} or {@code
* STORED}.
* @throws IllegalArgumentException
* when value is not {@code DEFLATED} or {@code STORED}.
- * @since Android 1.0
*/
public void setMethod(int value) {
if (value != STORED && value != DEFLATED) {
@@ -330,12 +310,11 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the uncompressed size of this {@code ZipEntry}.
- *
+ *
* @param value
* the uncompressed size for this entry.
* @throws IllegalArgumentException
* if {@code value} < 0 or {@code value} > 0xFFFFFFFFL.
- * @since Android 1.0
*/
public void setSize(long value) {
if (value >= 0 && value <= 0xFFFFFFFFL) {
@@ -347,11 +326,10 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Sets the modification time of this {@code ZipEntry}.
- *
+ *
* @param value
* the modification time as the number of milliseconds since Jan.
* 1, 1970.
- * @since Android 1.0
*/
public void setTime(long value) {
GregorianCalendar cal = new GregorianCalendar();
@@ -372,9 +350,8 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Returns the string representation of this {@code ZipEntry}.
- *
+ *
* @return the string representation of this {@code ZipEntry}.
- * @since Android 1.0
*/
@Override
public String toString() {
@@ -401,10 +378,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Constructs a new {@code ZipEntry} using the values obtained from {@code
* ze}.
- *
+ *
* @param ze
* the {@code ZipEntry} from which to obtain values.
- * @since Android 1.0
*/
public ZipEntry(ZipEntry ze) {
name = ze.name;
@@ -434,9 +410,8 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Returns a shallow copy of this entry.
- *
+ *
* @return a copy of this entry.
- * @since Android 1.0
*/
@Override
public Object clone() {
@@ -445,9 +420,8 @@ public class ZipEntry implements ZipConstants, Cloneable {
/**
* Returns the hash code for this {@code ZipEntry}.
- *
+ *
* @return the hash code of the entry.
- * @since Android 1.0
*/
@Override
public int hashCode() {
@@ -471,7 +445,7 @@ public class ZipEntry implements ZipConstants, Cloneable {
* readIntLE, so we're going to read the entire header at once
* and then parse the results out without using any function calls.
* Uglier, but should be much faster.
- *
+ *
* Note that some lines look a bit different, because the corresponding
* fields or locals are long and so we need to do & 0xffffffffl to avoid
* problems induced by sign extension.
@@ -549,7 +523,7 @@ public class ZipEntry implements ZipConstants, Cloneable {
int count;
int len = b.length;
int off = 0;
-
+
while (len > 0) {
count = in.read(b, off, len);
if (count <= 0)
diff --git a/archive/src/main/java/java/util/zip/ZipException.java b/archive/src/main/java/java/util/zip/ZipException.java
index 590117b..6dab26f 100644
--- a/archive/src/main/java/java/util/zip/ZipException.java
+++ b/archive/src/main/java/java/util/zip/ZipException.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.IOException;
/**
@@ -26,7 +25,6 @@ import java.io.IOException;
*
* @see ZipFile
* @see ZipInputStream
- * @since Android 1.0
*/
public class ZipException extends IOException {
@@ -34,8 +32,6 @@ public class ZipException extends IOException {
/**
* Constructs a new {@code ZipException} instance.
- *
- * @since Android 1.0
*/
public ZipException() {
super();
@@ -44,10 +40,9 @@ public class ZipException extends IOException {
/**
* Constructs a new {@code ZipException} instance with the specified
* message.
- *
+ *
* @param detailMessage
* the detail message for the exception.
- * @since Android 1.0
*/
public ZipException(String detailMessage) {
super(detailMessage);
diff --git a/archive/src/main/java/java/util/zip/ZipFile.java b/archive/src/main/java/java/util/zip/ZipFile.java
index f1415d9..653b2c9 100644
--- a/archive/src/main/java/java/util/zip/ZipFile.java
+++ b/archive/src/main/java/java/util/zip/ZipFile.java
@@ -37,17 +37,13 @@ import java.util.NoSuchElementException;
* While {@code ZipInputStream} provides stream based read access to a
* <i>ZIP-archive</i>, this class implements more efficient (file based) access
* and makes use of the <i>central directory</i> within a <i>ZIP-archive</i>.
- * </p>
* <p>
* Use {@code ZipOutputStream} if you want to create an archive.
- * </p>
* <p>
* A temporary ZIP file can be marked for automatic deletion upon closing it.
- * </p>
- *
+ *
* @see ZipEntry
* @see ZipOutputStream
- * @since Android 1.0
*/
public class ZipFile implements ZipConstants {
@@ -57,28 +53,23 @@ public class ZipFile implements ZipConstants {
/**
* Open zip file for read.
- *
- * @since Android 1.0
*/
public static final int OPEN_READ = 1;
/**
* Delete zip file when closed.
- *
- * @since Android 1.0
*/
public static final int OPEN_DELETE = 4;
/**
* Constructs a new {@code ZipFile} with the specified file.
- *
+ *
* @param file
* the file to read from.
* @throws ZipException
* if a ZIP error occurs.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public ZipFile(File file) throws ZipException, IOException {
this(file, OPEN_READ);
@@ -88,22 +79,31 @@ public class ZipFile implements ZipConstants {
* Opens a file as <i>ZIP-archive</i>. "mode" must be {@code OPEN_READ} or
* {@code OPEN_DELETE} . The latter sets the "delete on exit" flag through a
* file.
- *
+ *
* @param file
* the ZIP file to read.
* @param mode
* the mode of the file open operation.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public ZipFile(File file, int mode) throws IOException {
- if (mode == (OPEN_READ | OPEN_DELETE))
- fileToDeleteOnClose = file; // file.deleteOnExit();
- else if (mode != OPEN_READ)
- throw new IllegalArgumentException("invalid mode");
-
fileName = file.getPath();
+ if (mode == OPEN_READ || mode == (OPEN_READ | OPEN_DELETE)) {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(fileName);
+ }
+ if ((mode & OPEN_DELETE) != 0) {
+ if (security != null) {
+ security.checkDelete(fileName);
+ }
+ fileToDeleteOnClose = file; // file.deleteOnExit();
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+
mRaf = new RandomAccessFile(fileName, "r");
mEntryList = new ArrayList<ZipEntry>();
@@ -124,12 +124,11 @@ public class ZipFile implements ZipConstants {
/**
* Opens a ZIP archived file.
- *
+ *
* @param name
* the name of the ZIP file.
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
public ZipFile(String name) throws IOException {
this(new File(name), OPEN_READ);
@@ -142,10 +141,9 @@ public class ZipFile implements ZipConstants {
/**
* Closes this ZIP file.
- *
+ *
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
public void close() throws IOException {
RandomAccessFile raf = mRaf;
@@ -171,9 +169,8 @@ public class ZipFile implements ZipConstants {
/**
* 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.
- * @since Android 1.0
*/
public Enumeration<? extends ZipEntry> entries() {
return new Enumeration<ZipEntry>() {
@@ -195,12 +192,11 @@ public class ZipFile implements ZipConstants {
/**
* Gets the ZIP entry with the specified name from this {@code ZipFile}.
- *
+ *
* @param entryName
* 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.
- * @since Android 1.0
*/
public ZipEntry getEntry(String entryName) {
if (entryName != null) {
@@ -213,13 +209,12 @@ public class ZipFile implements ZipConstants {
/**
* Returns an input stream on the data of the specified {@code ZipEntry}.
- *
+ *
* @param entry
* the ZipEntry.
* @return an input stream of the data contained in the {@code ZipEntry}.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public InputStream getInputStream(ZipEntry entry) throws IOException {
/*
@@ -259,9 +254,8 @@ public class ZipFile implements ZipConstants {
/**
* Gets the file name of this {@code ZipFile}.
- *
+ *
* @return the file name of this {@code ZipFile}.
- * @since Android 1.0
*/
public String getName() {
return fileName;
@@ -269,9 +263,8 @@ public class ZipFile implements ZipConstants {
/**
* Returns the number of {@code ZipEntries} in this {@code ZipFile}.
- *
+ *
* @return the number of entries in this file.
- * @since Android 1.0
*/
public int size() {
return mEntryList.size();
diff --git a/archive/src/main/java/java/util/zip/ZipInputStream.java b/archive/src/main/java/java/util/zip/ZipInputStream.java
index 262fa3f..1a35b1c 100644
--- a/archive/src/main/java/java/util/zip/ZipInputStream.java
+++ b/archive/src/main/java/java/util/zip/ZipInputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -36,18 +35,14 @@ import org.apache.harmony.luni.util.Util;
* the so called ZIP entries. Therefore when reading from a {@code
* ZipInputStream} first the entry's attributes will be retrieved with {@code
* getNextEntry} before its data is read.
- * </p>
* <p>
* While {@code InflaterInputStream} can read a compressed <i>ZIP-archive</i>
* entry, this extension can read uncompressed entries as well.
- * </p>
* <p>
* Use {@code ZipFile} if you can access the archive as a file directly.
- * </p>
- *
+ *
* @see ZipEntry
* @see ZipFile
- * @since Android 1.0
*/
public class ZipInputStream extends InflaterInputStream implements ZipConstants {
static final int DEFLATED = 8;
@@ -58,7 +53,7 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
static final int ZIPLocalHeaderVersionNeeded = 20;
- // BEGI android-removed
+ // BEGIN android-removed
// private boolean zipClosed = false;
// END android-removed
@@ -82,10 +77,9 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
/**
* Constructs a new {@code ZipInputStream} from the specified input stream.
- *
+ *
* @param stream
* the input stream to representing a ZIP archive.
- * @since Android 1.0
*/
public ZipInputStream(InputStream stream) {
super(new PushbackInputStream(stream, BUF_SIZE), new Inflater(true));
@@ -96,10 +90,9 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
/**
* Closes this {@code ZipInputStream}.
- *
+ *
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
@@ -113,10 +106,9 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
/**
* Closes the current ZIP entry and positions to read the next entry.
- *
+ *
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public void closeEntry() throws IOException {
// BEGIN android-changed
@@ -173,13 +165,12 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
/**
* Reads the next entry from this {@code ZipInputStream}.
- *
+ *
* @return the next {@code ZipEntry} contained in the input stream.
* @throws IOException
* if the stream is not positioned at the beginning of an entry
* or if an other {@code IOException} occurs.
* @see ZipEntry
- * @since Android 1.0
*/
public ZipEntry getNextEntry() throws IOException {
if (currentEntry != null) {
@@ -274,6 +265,18 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
/* Read 4 bytes from the buffer and store it as an int */
+ /**
+ * Reads up to the specified number of uncompressed bytes into the buffer
+ * starting at the offset.
+ *
+ * @param buffer
+ * a byte array
+ * @param start
+ * the starting offset into the buffer
+ * @param length
+ * the number of bytes to read
+ * @return the number of bytes read
+ */
@Override
public int read(byte[] buffer, int start, int length) throws IOException {
// BEGIN android-changed
@@ -340,13 +343,12 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
/**
* Skips up to the specified number of bytes in the current ZIP entry.
- *
+ *
* @param value
* the number of bytes to skip.
* @return the number of bytes skipped.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
@Override
public long skip(long value) throws IOException {
@@ -364,15 +366,14 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
return skipped;
}
throw new IllegalArgumentException();
-}
+ }
/**
* Returns 0 if the {@code EOF} has been reached, otherwise returns 1.
- *
+ *
* @return 0 after {@code EOF} of current entry, 1 otherwise.
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
@Override
public int available() throws IOException {
@@ -389,11 +390,10 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants
/**
* creates a {@link ZipEntry } with the given name.
- *
+ *
* @param name
* the name of the entry.
* @return the created {@code ZipEntry}.
- * @since Android 1.0
*/
protected ZipEntry createZipEntry(String name) {
return new ZipEntry(name);
diff --git a/archive/src/main/java/java/util/zip/ZipOutputStream.java b/archive/src/main/java/java/util/zip/ZipOutputStream.java
index 4ddf643..58e781f 100644
--- a/archive/src/main/java/java/util/zip/ZipOutputStream.java
+++ b/archive/src/main/java/java/util/zip/ZipOutputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -32,33 +31,26 @@ import org.apache.harmony.archive.internal.nls.Messages;
* {@code ZipOutputStream} is used to write {@code ZipEntries} to the underlying
* stream. Output from {@code ZipOutputStream} conforms to the {@code ZipFile}
* file format.
- * </p>
* <p>
* While {@code DeflaterOutputStream} can write a compressed <i>ZIP-archive</i>
* entry, this extension can write uncompressed entries as well. In this case
* special rules apply, for this purpose refer to the <a
* href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">file format
* specification</a>.
- * </p>
- *
+ *
* @see ZipEntry
* @see ZipFile
- * @since Android 1.0
*/
public class ZipOutputStream extends DeflaterOutputStream implements
ZipConstants {
/**
* Indicates deflated entries.
- *
- * @since Android 1.0
*/
public static final int DEFLATED = 8;
/**
* Indicates uncompressed entries.
- *
- * @since Android 1.0
*/
public static final int STORED = 0;
@@ -90,7 +82,6 @@ public class ZipOutputStream extends DeflaterOutputStream implements
*
* @param p1
* the {@code OutputStream} to write the data to.
- * @since Android 1.0
*/
public ZipOutputStream(OutputStream p1) {
super(p1, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
@@ -102,7 +93,6 @@ public class ZipOutputStream extends DeflaterOutputStream implements
*
* @throws IOException
* If an error occurs closing the stream.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
@@ -119,7 +109,6 @@ public class ZipOutputStream extends DeflaterOutputStream implements
*
* @throws IOException
* If an error occurs closing the entry.
- * @since Android 1.0
*/
public void closeEntry() throws IOException {
if (cDir == null) {
@@ -205,7 +194,6 @@ public class ZipOutputStream extends DeflaterOutputStream implements
*
* @throws IOException
* if an error occurs while terminating the stream.
- * @since Android 1.0
*/
@Override
public void finish() throws IOException {
@@ -253,7 +241,6 @@ public class ZipOutputStream extends DeflaterOutputStream implements
* @throws IOException
* If an error occurs storing the entry.
* @see #write
- * @since Android 1.0
*/
public void putNextEntry(ZipEntry ze) throws java.io.IOException {
if (currentEntry != null) {
@@ -286,7 +273,8 @@ public class ZipOutputStream extends DeflaterOutputStream implements
nameLength = utf8Count(ze.name);
if (nameLength > 0xffff) {
/* [MSG "archive.2A", "Name too long: {0}"] */
- throw new IllegalArgumentException(Messages.getString("archive.2A", ze.name)); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString(
+ "archive.2A", ze.name)); //$NON-NLS-1$
}
def.setLevel(compressLevel);
@@ -338,7 +326,6 @@ public class ZipOutputStream extends DeflaterOutputStream implements
*
* @param comment
* the comment associated with the file.
- * @since Android 1.0
*/
public void setComment(String comment) {
if (comment.length() > 0xFFFF) {
@@ -355,7 +342,6 @@ public class ZipOutputStream extends DeflaterOutputStream implements
* @param level
* the compression level (ranging from -1 to 8).
* @see Deflater
- * @since Android 1.0
*/
public void setLevel(int level) {
if (level < Deflater.DEFAULT_COMPRESSION
@@ -372,7 +358,6 @@ public class ZipOutputStream extends DeflaterOutputStream implements
*
* @param method
* the compression method to use.
- * @since Android 1.0
*/
public void setMethod(int method) {
if (method != STORED && method != DEFLATED) {
@@ -398,11 +383,17 @@ public class ZipOutputStream extends DeflaterOutputStream implements
}
+ /**
+ * Writes data for the current entry to the underlying stream.
+ *
+ * @exception IOException
+ * If an error occurs writing to the stream
+ */
@Override
public void write(byte[] buffer, int off, int nbytes)
throws java.io.IOException {
// avoid int overflow, check null buf
- if ((off > buffer.length) || (nbytes < 0) || (off < 0)
+ if ((off < 0 || (nbytes < 0) || off > buffer.length)
|| (buffer.length - off < nbytes)) {
throw new IndexOutOfBoundsException();
}
diff --git a/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java b/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java
index 764f34d..3ba50fa 100644
--- a/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java
+++ b/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java
@@ -27,7 +27,6 @@
package org.apache.harmony.archive.internal.nls;
-
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;
@@ -50,7 +49,7 @@ import org.apache.harmony.luni.util.MsgHelp;
* is looked up, or resource bundle support is not available, the key itself
* will be returned as the associated message. This means that the <em>KEY</em>
* should a reasonable human-readable (english) string.
- *
+ *
*/
public class Messages {
@@ -61,7 +60,7 @@ public class Messages {
/**
* Retrieves a message which has no arguments.
- *
+ *
* @param msg
* String the key to look up.
* @return String the message for that key in the system message bundle.
@@ -74,7 +73,7 @@ public class Messages {
/**
* Retrieves a message which takes 1 argument.
- *
+ *
* @param msg
* String the key to look up.
* @param arg
@@ -87,7 +86,7 @@ public class Messages {
/**
* Retrieves a message which takes 1 integer argument.
- *
+ *
* @param msg
* String the key to look up.
* @param arg
@@ -100,7 +99,7 @@ public class Messages {
/**
* Retrieves a message which takes 1 character argument.
- *
+ *
* @param msg
* String the key to look up.
* @param arg
@@ -113,7 +112,7 @@ public class Messages {
/**
* Retrieves a message which takes 2 arguments.
- *
+ *
* @param msg
* String the key to look up.
* @param arg1
@@ -128,7 +127,7 @@ public class Messages {
/**
* Retrieves a message which takes several arguments.
- *
+ *
* @param msg
* String the key to look up.
* @param args
diff --git a/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties b/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
index 1ae5c5e..e909af0 100644
--- a/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
+++ b/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
@@ -60,8 +60,11 @@ archive.29=Entry already exists: {0}
archive.2A=Name too long: {0}
archive.2B=String is too long
archive.2C=No active entry
-archive.2D=Missing version string\: {0}
-archive.2E=Line too long
-archive.2F=Invalid attribute {0}
-archive.30={0} failed verification of {1}
-archive.31={0} has invalid digest for {1} in {2}
+archive.2D=Missing version attribute\: {0}
+archive.2E=Manifest is too long
+archive.2F=NUL character in a manifest
+archive.30=Invalid attribute {0}
+archive.31={0} failed verification of {1}
+archive.32={0} has invalid digest for {1} in {2}
+archive.33=A length of the encoded header name "{1}" exceeded maximum length {2}
+archive.34=A jar verifier does not support more than one entry with the same name
diff --git a/archive/src/main/java/org/apache/harmony/archive/util/Util.java b/archive/src/main/java/org/apache/harmony/archive/util/Util.java
index bed3e91..b15108a 100644
--- a/archive/src/main/java/org/apache/harmony/archive/util/Util.java
+++ b/archive/src/main/java/org/apache/harmony/archive/util/Util.java
@@ -30,39 +30,49 @@ public class Util {
return false;
}
- s1 = s1.substring(start1, start1 + length);
- s2 = s2.substring(start2, start2 + length);
-
- return toASCIILowerCase(s1).equals(toASCIILowerCase(s2));
+ char c1, c2;
+ for (int i = 0; i < length; i++) {
+ if ((c1 = s1.charAt(start1++)) != (c2 = s2.charAt(start2++))
+ && toASCIIUpperCase(c1) != toASCIIUpperCase(c2)) {
+ return false;
+ }
+ }
+ return true;
}
throw new NullPointerException();
}
- public static String toASCIILowerCase(String s) {
- int len = s.length();
- StringBuilder buffer = new StringBuilder(len);
- for (int i = 0; i < len; i++) {
- char c = s.charAt(i);
- if ('A' <= c && c <= 'Z') {
- buffer.append((char) (c + ('a' - 'A')));
- } else {
- buffer.append(c);
+ public static final boolean equalsIgnoreCase(byte[] buf1, byte[] buf2) {
+ if (buf1 == buf2) {
+ return true;
+ }
+
+ if (buf1 == null || buf2 == null || buf1.length != buf2.length) {
+ return false;
+ }
+
+ byte b1, b2;
+
+ for (int i = 0; i < buf1.length; i++) {
+ if ((b1 = buf1[i]) != (b2 = buf2[i])
+ && toASCIIUpperCase(b1) != toASCIIUpperCase(b2)) {
+ return false;
}
}
- return buffer.toString();
+ return true;
}
- public static String toASCIIUpperCase(String s) {
- int len = s.length();
- StringBuilder buffer = new StringBuilder(len);
- for (int i = 0; i < len; i++) {
- char c = s.charAt(i);
- if ('a' <= c && c <= 'z') {
- buffer.append((char) (c - ('a' - 'A')));
- } else {
- buffer.append(c);
- }
+ static final char toASCIIUpperCase(char c) {
+ if ('a' <= c && c <= 'z') {
+ return (char) (c - ('a' - 'A'));
+ }
+ return c;
+ }
+
+ static final byte toASCIIUpperCase(byte b) {
+ if ('a' <= b && b <= 'z') {
+ return (byte) (b - ('a' - 'A'));
}
- return buffer.toString();
+ return b;
}
}
diff --git a/archive/src/main/native/java_util_zip_Adler32.c b/archive/src/main/native/java_util_zip_Adler32.c
index a7a182a..1b02a11 100644
--- a/archive/src/main/native/java_util_zip_Adler32.c
+++ b/archive/src/main/native/java_util_zip_Adler32.c
@@ -15,23 +15,25 @@
* limitations under the License.
*/
+#include "jni.h"
#include "hy2sie.h"
-
#include "zlib.h"
-
+#include "sieb.h"
JNIEXPORT jlong JNICALL
Java_java_util_zip_Adler32_updateImpl (JNIEnv * env, jobject recv,
jbyteArray buf, int off, int len,
jlong crc)
{
- PORT_ACCESS_FROM_ENV (env);
-
jbyte *b;
jboolean isCopy;
jlong result;
b = (*env)->GetPrimitiveArrayCritical (env, buf, &isCopy);
+ if (b == NULL) {
+ throwNewOutOfMemoryError(env, "");
+ return 0;
+ }
result = (jlong) adler32 ((uLong) crc, (Bytef *) (b + off), (uInt) len);
(*env)->ReleasePrimitiveArrayCritical (env, buf, b, JNI_ABORT);
@@ -42,9 +44,8 @@ JNIEXPORT jlong JNICALL
Java_java_util_zip_Adler32_updateByteImpl (JNIEnv * env, jobject recv,
jint val, jlong crc)
{
- PORT_ACCESS_FROM_ENV (env);
-
- return adler32 ((uLong) crc, (Bytef *) (&val), 1);
+ Bytef bytefVal = val;
+ return adler32 ((uLong) crc, (Bytef *) (&bytefVal), 1);
}
diff --git a/archive/src/main/native/java_util_zip_CRC32.c b/archive/src/main/native/java_util_zip_CRC32.c
index 0688868..cee25e5 100644
--- a/archive/src/main/native/java_util_zip_CRC32.c
+++ b/archive/src/main/native/java_util_zip_CRC32.c
@@ -16,6 +16,7 @@
*/
#include "hy2sie.h"
+#include "sieb.h"
#include "zlib.h"
@@ -28,8 +29,10 @@ Java_java_util_zip_CRC32_updateImpl (JNIEnv * env, jobject recv,
jlong result;
b = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (b == NULL)
+ if (b == NULL) {
+ throwNewOutOfMemoryError(env, "");
return -1;
+ }
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 c8bd199..2e0e268 100644
--- a/archive/src/main/native/java_util_zip_Deflater.c
+++ b/archive/src/main/native/java_util_zip_Deflater.c
@@ -18,11 +18,13 @@
#include "hy2sie.h"
#include "zlib.h"
-#include "zipsup.h"
-
+#include "zip.h"
+#include "jni.h"
+#ifndef HY_ZIP_API
void zfree PROTOTYPE ((void *opaque, void *address));
void *zalloc PROTOTYPE ((void *opaque, U_32 items, U_32 size));
+#endif
static struct {
@@ -52,10 +54,10 @@ Java_java_util_zip_Deflater_setDictionaryImpl (JNIEnv * env, jobject recv,
if (err != Z_OK)
{
jclmem_free_memory (env, dBytes);
- throwNewIllegalArgumentException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
return;
}
- stream->dict = dBytes;
+ stream->dict = (U_8*) dBytes;
}
JNIEXPORT jlong JNICALL
@@ -94,9 +96,8 @@ JNIEXPORT jlong JNICALL
Java_java_util_zip_Deflater_createStream (JNIEnv * env, jobject recv,
jint level, jint strategy,
jboolean noHeader)
-{
+{
PORT_ACCESS_FROM_ENV (env);
-
JCLZipStream *jstream;
z_stream *stream;
int err = 0;
@@ -109,7 +110,12 @@ Java_java_util_zip_Deflater_createStream (JNIEnv * env, jobject recv,
// results in 2 x 128K being allocated per Deflater, which is
// not acceptable.
// END android-changed
-
+#ifdef HY_ZIP_API
+ VMI_ACCESS_FROM_ENV (env);
+ VMIZipFunctionTable *zipFuncs;
+ zipFuncs = (*VMI)->GetZipFunctions(VMI);
+#endif
+
/*Allocate mem for wrapped struct */
jstream = jclmem_allocate_memory (env, sizeof (JCLZipStream));
if (jstream == NULL)
@@ -141,11 +147,10 @@ Java_java_util_zip_Deflater_createStream (JNIEnv * env, jobject recv,
mlevel, /*Memory allocation for internal compression state. 9 uses the most. */
// END android-changed
strategy);
- if (err != Z_OK)
- {
- throwNewIllegalArgumentException (env, "");
- return -1;
- }
+ if (err != Z_OK) {
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
+ return -1;
+ }
return (jlong) ((IDATA) jstream);
}
@@ -170,8 +175,10 @@ Java_java_util_zip_Deflater_setInputImpl (JNIEnv * env, jobject recv,
return;
}
in = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (in == NULL)
+ if (in == NULL) {
+ throwNewOutOfMemoryError(env, "");
return;
+ }
memcpy (stream->inaddr, (in + off), len);
((*env)->ReleasePrimitiveArrayCritical (env, buf, in, JNI_ABORT));
stream->stream->next_in = (Bytef *) stream->inaddr;
@@ -185,8 +192,6 @@ Java_java_util_zip_Deflater_deflateImpl (JNIEnv * env, jobject recv,
jbyteArray buf, int off, int len,
jlong handle, int flushParm)
{
- PORT_ACCESS_FROM_ENV (env);
-
jbyte *out;
JCLZipStream *stream;
jint err = 0;
@@ -203,29 +208,34 @@ Java_java_util_zip_Deflater_deflateImpl (JNIEnv * env, jobject recv,
sin = stream->stream->total_in;
sout = stream->stream->total_out;
out = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (out == NULL)
+ if (out == NULL) {
+ throwNewOutOfMemoryError(env, "");
return -1;
+ }
stream->stream->next_out = (Bytef *) out + off;
err = deflate (stream->stream, flushParm);
((*env)->ReleasePrimitiveArrayCritical (env, buf, out, 0));
- if (err != Z_OK)
- {
- if (err == Z_STREAM_END)
- {
- ((*env)->
- SetBooleanField (env, recv,
- gCachedFields.finished,
- JNI_TRUE));
- return stream->stream->total_out - sout;
- }
+ if (err != Z_OK) {
+ if (err == Z_MEM_ERROR) {
+ throwNewOutOfMemoryError(env, "");
+ return 0;
}
+ if (err == Z_STREAM_END)
+ {
+ ((*env)->
+ SetBooleanField (env, recv,
+ gCachedFields.finished,
+ JNI_TRUE));
+ return stream->stream->total_out - sout;
+ }
+ }
if (flushParm != Z_FINISH)
{
/* Need to update the number of input bytes read. */
((*env)->
SetIntField (env, recv,
- gCachedFields.inRead,
- (jint) stream->stream->total_in - sin + inBytes));
+ gCachedFields.inRead,
+ (jint) stream->stream->total_in - sin + inBytes));
}
return stream->stream->total_out - sout;
}
@@ -262,8 +272,6 @@ Java_java_util_zip_Deflater_setLevelsImpl (JNIEnv * env, jobject recv,
int level, int strategy,
jlong handle)
{
- PORT_ACCESS_FROM_ENV (env);
-
JCLZipStream *stream;
jbyte b = 0;
int err = 0;
@@ -276,8 +284,9 @@ Java_java_util_zip_Deflater_setLevelsImpl (JNIEnv * env, jobject recv,
stream = (JCLZipStream *) ((IDATA) handle);
stream->stream->next_out = (Bytef *) & b;
err = deflateParams (stream->stream, level, strategy);
- if (err != Z_OK)
- throwNewIllegalStateException (env, "");
+ if (err != Z_OK) {
+ THROW_ZIP_EXCEPTION(env, err, IllegalStateException);
+ }
}
JNIEXPORT void JNICALL
diff --git a/archive/src/main/native/java_util_zip_Inflater.c b/archive/src/main/native/java_util_zip_Inflater.c
index d3a7d7c..4b30d4e 100644
--- a/archive/src/main/native/java_util_zip_Inflater.c
+++ b/archive/src/main/native/java_util_zip_Inflater.c
@@ -16,6 +16,7 @@
*/
#include "hy2sie.h"
+#include "zip.h"
#include "zlib.h"
#include <memory.h>
@@ -24,6 +25,7 @@
#include <fcntl.h>
+void throwNewDataFormatException (JNIEnv * env, const char *message);
void zfree PROTOTYPE ((void *opaque, void *address));
void *zalloc PROTOTYPE ((void *opaque, U_32 items, U_32 size));
@@ -36,27 +38,6 @@ static struct {
} gCachedFields;
-// Contents from Harmony's inflater.h was put here:
-//
-typedef struct JCLZipStream
-{
- U_8 *inaddr;
- int inCap;
- U_8 *dict;
- z_stream *stream;
-} JCLZipStream;
-
-
-
-/**
- * Throw java.util.zip.DataFormatException
- */
-void
-throwNewDataFormatException (JNIEnv * env, const char *message)
-{
- jniThrowException(env, "java/util/zip/DataFormatException", message);
-}
-
/* Create a new stream . This stream cannot be used until it has been properly initialized. */
JNIEXPORT jlong JNICALL
@@ -69,6 +50,11 @@ Java_java_util_zip_Inflater_createStream (JNIEnv * env, jobject recv,
z_stream *stream;
int err = 0;
int wbits = 15; /*Use MAX for fastest */
+#ifdef HY_ZIP_API
+ VMI_ACCESS_FROM_ENV (env);
+ VMIZipFunctionTable *zipFuncs;
+ zipFuncs = (*VMI)->GetZipFunctions(VMI);
+#endif
/*Allocate mem for wrapped struct */
jstream = jclmem_allocate_memory (env, sizeof (JCLZipStream));
@@ -104,7 +90,7 @@ Java_java_util_zip_Inflater_createStream (JNIEnv * env, jobject recv,
{
jclmem_free_memory (env, stream);
jclmem_free_memory (env, jstream);
- throwNewIllegalArgumentException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
return -1;
}
@@ -134,8 +120,10 @@ Java_java_util_zip_Inflater_setInputImpl (JNIEnv * env, jobject recv,
stream->stream->next_in = (Bytef *) baseAddr;
stream->stream->avail_in = len;
in = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (in == NULL)
+ if (in == NULL) {
+ throwNewOutOfMemoryError(env, "");
return;
+ }
memcpy (baseAddr, (in + off), len);
((*env)->ReleasePrimitiveArrayCritical (env, buf, in, JNI_ABORT));
return;
@@ -176,8 +164,6 @@ Java_java_util_zip_Inflater_inflateImpl (JNIEnv * env, jobject recv,
jbyteArray buf, int off, int len,
jlong handle)
{
- PORT_ACCESS_FROM_ENV (env);
-
jbyte *out;
JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle);
jint err = 0;
@@ -192,9 +178,10 @@ Java_java_util_zip_Inflater_inflateImpl (JNIEnv * env, jobject recv,
sin = stream->stream->total_in;
sout = stream->stream->total_out;
out = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
-
- if (out == NULL)
+ if (out == NULL) {
+ throwNewOutOfMemoryError(env, "");
return -1;
+ }
stream->stream->next_out = (Bytef *) out + off;
err = inflate (stream->stream, Z_SYNC_FLUSH);
((*env)->ReleasePrimitiveArrayCritical (env, buf, out, 0));
@@ -217,7 +204,7 @@ Java_java_util_zip_Inflater_inflateImpl (JNIEnv * env, jobject recv,
}
else
{
- throwNewDataFormatException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, DataFormatException);
return -1;
}
}
@@ -280,7 +267,7 @@ Java_java_util_zip_Inflater_setDictionaryImpl (JNIEnv * env, jobject recv,
if (err != Z_OK)
{
jclmem_free_memory (env, dBytes);
- throwNewIllegalArgumentException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
return;
}
stream->dict = dBytes;
@@ -297,11 +284,19 @@ Java_java_util_zip_Inflater_resetImpl (JNIEnv * env, jobject recv,
err = inflateReset (stream->stream);
if (err != Z_OK)
{
- throwNewIllegalArgumentException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
return;
}
}
+/**
+ * Throw java.util.zip.DataFormatException
+ */
+void
+throwNewDataFormatException (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/util/zip/DataFormatException", message);
+}
JNIEXPORT jlong JNICALL
Java_java_util_zip_Inflater_getTotalOutImpl (JNIEnv * env, jobject recv,
@@ -311,6 +306,7 @@ Java_java_util_zip_Inflater_getTotalOutImpl (JNIEnv * env, jobject recv,
stream = (JCLZipStream *) ((IDATA) handle);
return stream->stream->total_out;
+
}
JNIEXPORT jlong JNICALL
diff --git a/archive/src/main/native/sieb.c b/archive/src/main/native/sieb.c
index ab9430b..6881cf6 100644
--- a/archive/src/main/native/sieb.c
+++ b/archive/src/main/native/sieb.c
@@ -10,20 +10,6 @@ void throwNewOutOfMemoryError (JNIEnv * env, const char *message)
jniThrowException(env, "java/lang/OutOfMemoryError", message);
}
-// Throw java.lang.IllegalStateException
-void throwNewIllegalStateException (JNIEnv * env, const char *message)
-{
- jniThrowException(env, "java/lang/IllegalStateException", message);
-}
-
-// Throw java.lang.IllegalArgumentException
-void throwNewIllegalArgumentException (JNIEnv * env, const char *message)
-{
- jniThrowException(env, "java/lang/IllegalArgumentException", message);
-}
-
-
-
void * sieb_malloc (JNIEnv * env, size_t byteCnt) {
void * adr = malloc(byteCnt);
if (adr == 0) {
diff --git a/archive/src/main/native/sieb.h b/archive/src/main/native/sieb.h
index 536c806..541ad90 100644
--- a/archive/src/main/native/sieb.h
+++ b/archive/src/main/native/sieb.h
@@ -7,9 +7,8 @@
-void throwNewOutOfMemoryError (JNIEnv * env, const char *message);
-void throwNewIllegalArgumentException (JNIEnv * env, const char *message);
-void throwNewIllegalStateException (JNIEnv * env, const char *message);
+void throwNewOutOfMemoryError (JNIEnv * env,
+ const char *message);
void * sieb_malloc (JNIEnv * env, size_t byteCnt);
diff --git a/archive/src/main/native/sub.mk b/archive/src/main/native/sub.mk
index 047c319..694c185 100644
--- a/archive/src/main/native/sub.mk
+++ b/archive/src/main/native/sub.mk
@@ -7,7 +7,8 @@ LOCAL_SRC_FILES := \
java_util_zip_CRC32.c \
java_util_zip_Deflater.c \
java_util_zip_Inflater.c \
- zipalloc.c \
+ zip.c \
+ zipalloc.c \
sieb.c
LOCAL_C_INCLUDES += \
diff --git a/archive/src/main/native/zip.c b/archive/src/main/native/zip.c
new file mode 100644
index 0000000..3d15d2a
--- /dev/null
+++ b/archive/src/main/native/zip.c
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "zip.h"
+#include "jni.h"
+
+/**
+ * Throw java.lang.IllegalStateException
+ */
+void
+throwNewIllegalStateException (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/lang/IllegalStateException", message);
+}
+
+/**
+ * Throw java.lang.IllegalArgumentException
+ */
+void
+throwNewIllegalArgumentException (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/lang/IllegalArgumentException", message);
+}
diff --git a/archive/src/main/native/zip.h b/archive/src/main/native/zip.h
new file mode 100644
index 0000000..1452073
--- /dev/null
+++ b/archive/src/main/native/zip.h
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(zip_h)
+#define zip_h
+
+#ifndef HY_ZIP_API
+#include "zipsup.h"
+#else /* HY_ZIP_API */
+#include "vmizip.h"
+#endif /* HY_ZIP_API */
+
+#include "hymutex.h"
+
+typedef struct JCLZipFile
+{
+ struct JCLZipFile *last;
+ struct JCLZipFile *next;
+#ifndef HY_ZIP_API
+ HyZipFile hyZipFile;
+#else
+ VMIZipFile hyZipFile;
+#endif
+} JCLZipFile;
+
+/* Fake JCLZipFile entry. last, next must be in the same position as JCLZipFile */
+typedef struct JCLZipFileLink
+{
+ JCLZipFile *last;
+ JCLZipFile *next;
+ MUTEX mutex;
+} JCLZipFileLink;
+
+// Contents from Harmony's inflater.h was put here:
+//
+typedef struct JCLZipStream
+{
+ U_8 *inaddr;
+ int inCap;
+ U_8 *dict;
+ z_stream *stream;
+} JCLZipStream;
+
+#define THROW_ZIP_EXCEPTION(env, err, type) \
+ if (err == Z_MEM_ERROR) { \
+ throwNewOutOfMemoryError(env, ""); \
+ } else { \
+ throwNew##type(env, (const char*) zError(err)); \
+ }
+
+void throwNewIllegalStateException PROTOTYPE((JNIEnv* env,
+ const char* message));
+void throwNewIllegalArgumentException PROTOTYPE((JNIEnv* env,
+ const char* message));
+
+#endif /* zip_h */
diff --git a/archive/src/main/native/zipsup.c b/archive/src/main/native/zipsup.c
index 1bbe51f..22ea7e9 100644
--- a/archive/src/main/native/zipsup.c
+++ b/archive/src/main/native/zipsup.c
@@ -1438,7 +1438,7 @@ retry:
return ZIP_ERR_FILE_CORRUPT; /* should never happen! */
}
result = zip_establishCache (portLib, zipFile);
- if (result)
+ if (!result)
{
/* (silently start operating without a cache if we couldn't make a new one) */
}
diff --git a/archive/src/main/native/zipsup.h b/archive/src/main/native/zipsup.h
index adc086a..67a2eda 100644
--- a/archive/src/main/native/zipsup.h
+++ b/archive/src/main/native/zipsup.h
@@ -34,23 +34,17 @@ extern "C"
#include "zlib.h"
-// Contents from Harmony's inflater.h was put here:
-//
-typedef struct JCLZipStream
-{
- U_8 *inaddr;
- U_8 *dict;
- z_stream *stream;
-} JCLZipStream;
-
-
typedef struct HyZipCachePool HyZipCachePool;
HyZipCachePool *
zipsup_GetZipCachePool(HyPortLibrary * portLib);
+#if defined(HY_LOCAL_ZLIB)
+#define HY_ZIP_DLL_NAME "z"
+#else
#define HY_ZIP_DLL_NAME "hyzlib"
+#endif
#define ZIP_INTERNAL_MAX 80
#define ZIP_CM_Reduced1 2
@@ -156,18 +150,6 @@ zipsup_GetZipCachePool(HyPortLibrary * portLib);
-// Contents from Harmony's zip.h were put in java_util_zip_ZipFile.c
-// and here:
-typedef struct JCLZipFile
-{
- struct JCLZipFile *last;
- struct JCLZipFile *next;
- HyZipFile hyZipFile;
-} JCLZipFile;
-
-
-
-
#include "hymutex.h"
extern MUTEX zip_GlobalMutex;
diff --git a/archive/src/test/java-internal/org/apache/harmony/archive/util/UtilTest.java b/archive/src/test/java-internal/org/apache/harmony/archive/util/UtilTest.java
new file mode 100644
index 0000000..9c28dc2
--- /dev/null
+++ b/archive/src/test/java-internal/org/apache/harmony/archive/util/UtilTest.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.archive.util;
+
+import junit.framework.TestCase;
+
+public class UtilTest extends TestCase {
+ private static final String ASCII_ALPHABET_LC = "abcdefghijklmnopqrstuvwxyz";
+ private static final String ASCII_ALPHABET_UC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private static final byte[] ASCII_ALPHABET_LC_BYTES;
+ private static final byte[] ASCII_ALPHABET_UC_BYTES;
+
+ static {
+ ASCII_ALPHABET_LC_BYTES = new byte[ASCII_ALPHABET_LC.length()];
+ for (int i = 0; i < ASCII_ALPHABET_LC_BYTES.length; i++) {
+ final char c = ASCII_ALPHABET_LC.charAt(i);
+ final byte b = (byte) c;
+ assert ((char) b) == c;
+ ASCII_ALPHABET_LC_BYTES[i] = b;
+ }
+
+ ASCII_ALPHABET_UC_BYTES = new byte[ASCII_ALPHABET_UC.length()];
+ for (int i = 0; i < ASCII_ALPHABET_UC_BYTES.length; i++) {
+ final char c = ASCII_ALPHABET_UC.charAt(i);
+ final byte b = (byte) c;
+ assert ((char) b) == c;
+ ASCII_ALPHABET_UC_BYTES[i] = b;
+ }
+ }
+
+ public void testASCIIIgnoreCaseRegionMatches() {
+ final String s1 = ASCII_ALPHABET_LC;
+ final String s2 = ASCII_ALPHABET_UC;
+ for (int i = 0; i < s1.length(); i++) {
+ assertTrue(Util.ASCIIIgnoreCaseRegionMatches(s1, i, s2, i, s1
+ .length()
+ - i));
+ }
+ }
+
+ public void testToASCIIUpperCaseByte() {
+ for (int i = 0; i < ASCII_ALPHABET_LC_BYTES.length; i++) {
+ assertEquals(ASCII_ALPHABET_UC_BYTES[i], Util
+ .toASCIIUpperCase(ASCII_ALPHABET_LC_BYTES[i]));
+ }
+ for (int i = 0; i < ASCII_ALPHABET_UC_BYTES.length; i++) {
+ assertEquals(ASCII_ALPHABET_UC_BYTES[i], Util
+ .toASCIIUpperCase(ASCII_ALPHABET_UC_BYTES[i]));
+ }
+ }
+
+ public void testToASCIIUpperCaseChar() {
+ for (int i = 0; i < ASCII_ALPHABET_LC.length(); i++) {
+ assertEquals(ASCII_ALPHABET_UC.charAt(i), Util
+ .toASCIIUpperCase(ASCII_ALPHABET_LC.charAt(i)));
+ }
+ for (int i = 0; i < ASCII_ALPHABET_UC.length(); i++) {
+ assertEquals(ASCII_ALPHABET_UC.charAt(i), Util
+ .toASCIIUpperCase(ASCII_ALPHABET_UC.charAt(i)));
+ }
+ }
+
+ public void testEqualsIgnoreCaseByteArrayByteArray() {
+ assertTrue(Util.equalsIgnoreCase(ASCII_ALPHABET_LC_BYTES,
+ ASCII_ALPHABET_LC_BYTES));
+ assertTrue(Util.equalsIgnoreCase(ASCII_ALPHABET_LC_BYTES,
+ ASCII_ALPHABET_UC_BYTES));
+ assertTrue(Util.equalsIgnoreCase(ASCII_ALPHABET_UC_BYTES,
+ ASCII_ALPHABET_UC_BYTES));
+ }
+
+}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java
index 0a8b037..0b3d2cf 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java
@@ -421,6 +421,27 @@ public class AttributesTest extends TestCase {
assertNull(attribute.get(name));
}
+ /**
+ * @tests java.util.jar.Attributes.hashCode()
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "hashCode",
+ args = {}
+ )
+ public void test_hashCode_consistent_with_map() {
+ MockAttributes mockAttr = new MockAttributes();
+ mockAttr.putValue("1", "one");
+ assertEquals(mockAttr.getMap().hashCode(), mockAttr.hashCode());
+ }
+
+ private static class MockAttributes extends Attributes {
+ public Map<Object, Object> getMap() {
+ return map;
+ }
+ }
+
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "",
@@ -470,7 +491,7 @@ public class AttributesTest extends TestCase {
}
@TestTargetNew(
- level = TestLevel.COMPLETE,
+ level = TestLevel.PARTIAL_COMPLETE,
notes = "",
method = "hashCode",
args = {}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
index 40eff3b..90144be 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
@@ -72,6 +72,29 @@ public class JarEntryTest extends TestCase {
}
/**
+ * @throws IOException
+ * @tests java.util.jar.JarEntry#JarEntry(java.util.jar.JarEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "JarEntry",
+ args = {java.util.jar.JarEntry.class}
+ )
+ public void test_ConstructorLjava_util_jar_JarEntry_on_null() throws IOException {
+ JarEntry newJarEntry = new JarEntry(jarFile.getJarEntry(entryName));
+ assertNotNull(newJarEntry);
+
+ jarEntry = null;
+ try {
+ newJarEntry = new JarEntry(jarEntry);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ }
+
+ /**
* @tests java.util.jar.JarEntry#JarEntry(java.util.zip.ZipEntry)
*/
@TestTargetNew(
@@ -163,10 +186,21 @@ public class JarEntryTest extends TestCase {
JarEntry jarEntry2 = jarFile.getJarEntry("Test.class");
InputStream in = jarFile.getInputStream(jarEntry1);
byte[] buffer = new byte[1024];
+ // BEGIN android-changed
+ // the certificates are non-null too early and in.available() fails
+ // while (in.available() > 0) {
+ // assertNull("getCertificates() should be null until the entry is read",
+ // jarEntry1.getCertificates());
+ // assertNull(jarEntry2.getCertificates());
+ // in.read(buffer);
+ // }
while (in.read(buffer) >= 0);
in.close();
+ // END android-changed
+ assertEquals("the file is fully read", -1, in.read());
assertNotNull(jarEntry1.getCertificates());
assertNotNull(jarEntry2.getCertificates());
+ in.close();
}
/**
@@ -187,8 +221,14 @@ public class JarEntryTest extends TestCase {
InputStream in = jarFile.getInputStream(jarEntry);
byte[] buffer = new byte[1024];
while (in.available() > 0) {
+ // BEGIN android-changed
+ // the code signers are non-null too early
+ // assertNull("getCodeSigners() should be null until the entry is read",
+ // jarEntry.getCodeSigners());
+ // END android-changed
in.read(buffer);
}
+ assertEquals("the file is fully read", -1, in.read());
CodeSigner[] codeSigners = jarEntry.getCodeSigners();
assertEquals(2, codeSigners.length);
List<?> certs_bob = codeSigners[0].getSignerCertPath()
@@ -240,7 +280,7 @@ public class JarEntryTest extends TestCase {
}
@TestTargetNew(
- level = TestLevel.COMPLETE,
+ level = TestLevel.PARTIAL_COMPLETE,
notes = "",
method = "JarEntry",
args = {java.util.jar.JarEntry.class}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
index 720f78d..96321a4 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
@@ -14,13 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.harmony.archive.tests.java.util.jar;
import dalvik.annotation.AndroidOnly;
import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargets;
import dalvik.annotation.TestLevel;
import dalvik.annotation.TestTargetNew;
@@ -73,13 +71,17 @@ public class JarFileTest extends TestCase {
private final String jarName3 = "hyts_manifest1.jar";
private final String jarName4 = "hyts_signed.jar";
-
+
private final String jarName5 = "hyts_signed_inc.jar";
+ private final String integrateJar = "Integrate.jar";
+
private final String entryName = "foo/bar/A.class";
private final String entryName3 = "coucou/FileAccess.class";
+ private final String integrateJarEntry = "Test.class";
+
private File resources;
// custom security manager
@@ -102,7 +104,7 @@ public class JarFileTest extends TestCase {
* @tests java.util.jar.JarFile#JarFile(java.io.File)
*/
@TestTargetNew(
- level = TestLevel.COMPLETE,
+ level = TestLevel.PARTIAL_COMPLETE,
notes = "",
method = "JarFile",
args = {java.io.File.class}
@@ -300,6 +302,27 @@ public class JarFileTest extends TestCase {
}
/**
+ * Constructs JarFile object.
+ *
+ * @tests java.util.jar.JarFile#JarFile(java.io.File)
+ * @tests java.util.jar.JarFile#JarFile(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "JarFile",
+ args = {java.io.File.class}
+ )
+ public void testConstructor_file() throws IOException {
+ File f = new File(resources, jarName);
+ Support_Resources.copyFile(resources, null, jarName);
+ assertTrue(new JarFile(f).getEntry(entryName).getName().equals(
+ entryName));
+ assertTrue(new JarFile(f.getPath()).getEntry(entryName).getName()
+ .equals(entryName));
+ }
+
+ /**
* @tests java.util.jar.JarFile#entries()
*/
@TestTargetNew(
@@ -316,11 +339,11 @@ public class JarFileTest extends TestCase {
Support_Resources.copyFile(resources, null, jarName);
JarFile jarFile = new JarFile(new File(resources, jarName));
Enumeration<JarEntry> e = jarFile.entries();
- int i = 0;
- while (e.hasMoreElements()) {
- i++;
+ int i;
+ for (i = 0; e.hasMoreElements(); i++) {
e.nextElement();
}
+ assertEquals(jarFile.size(), i);
jarFile.close();
assertEquals(6, i);
}
@@ -336,24 +359,20 @@ public class JarFileTest extends TestCase {
JarFile jarFile = new JarFile(new File(resources, jarName));
Enumeration<JarEntry> enumeration = jarFile.entries();
jarFile.close();
- boolean pass = false;
try {
enumeration.hasMoreElements();
+ fail("hasMoreElements() did not detect a closed jar file");
} catch (IllegalStateException e) {
- pass = true;
}
- assertTrue("hasMoreElements did not detect closed jar file", pass);
Support_Resources.copyFile(resources, null, jarName);
jarFile = new JarFile(new File(resources, jarName));
enumeration = jarFile.entries();
jarFile.close();
- pass = false;
try {
enumeration.nextElement();
+ fail("nextElement() did not detect closed jar file");
} catch (IllegalStateException e) {
- pass = true;
}
- assertTrue("nextElement did not detect closed jar file", pass);
}
/**
@@ -361,7 +380,7 @@ public class JarFileTest extends TestCase {
* @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
*/
@TestTargetNew(
- level = TestLevel.COMPLETE,
+ level = TestLevel.PARTIAL_COMPLETE,
notes = "",
method = "getEntry",
args = {java.lang.String.class}
@@ -442,6 +461,92 @@ public class JarFileTest extends TestCase {
}
}
+
+ /**
+ * @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "getEntry",
+ args = {java.lang.String.class}
+ )
+ public void testGetJarEntry() throws Exception {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ assertEquals("Error in returned entry", 311, jarFile.getEntry(
+ entryName).getSize());
+ jarFile.close();
+
+ // tests for signed jars
+ // test all signed jars in the /Testres/Internal/SignedJars directory
+ String jarDirUrl = Support_Resources
+ .getResourceURL("/../internalres/signedjars");
+ Vector<String> signedJars = new Vector<String>();
+ try {
+ InputStream is = new URL(jarDirUrl + "/jarlist.txt").openStream();
+ while (is.available() > 0) {
+ StringBuilder linebuff = new StringBuilder(80); // Typical line
+ // length
+ done: while (true) {
+ int nextByte = is.read();
+ switch (nextByte) {
+ case -1:
+ break done;
+ case (byte) '\r':
+ if (linebuff.length() == 0) {
+ // ignore
+ }
+ break done;
+ case (byte) '\n':
+ if (linebuff.length() == 0) {
+ // ignore
+ }
+ break done;
+ default:
+ linebuff.append((char) nextByte);
+ }
+ }
+ if (linebuff.length() == 0) {
+ break;
+ }
+ String line = linebuff.toString();
+ signedJars.add(line);
+ }
+ is.close();
+ } catch (IOException e) {
+ // no list of jars found
+ }
+
+ for (int i = 0; i < signedJars.size(); i++) {
+ String jarName = signedJars.get(i);
+ try {
+ File file = Support_Resources.getExternalLocalFile(jarDirUrl
+ + "/" + jarName);
+ jarFile = new JarFile(file, true);
+ boolean foundCerts = false;
+ Enumeration<JarEntry> e = jarFile.entries();
+ while (e.hasMoreElements()) {
+ JarEntry entry = e.nextElement();
+ InputStream is = jarFile.getInputStream(entry);
+ is.skip(100000);
+ is.close();
+ Certificate[] certs = entry.getCertificates();
+ if (certs != null && certs.length > 0) {
+ foundCerts = true;
+ break;
+ }
+ }
+ assertTrue(
+ "No certificates found during signed jar test for jar \""
+ + jarName + "\"", foundCerts);
+ } catch (IOException e) {
+ fail("Exception during signed jar test for jar \"" + jarName
+ + "\": " + e.toString());
+ }
+ }
+ }
+
/**
* @tests java.util.jar.JarFile#getManifest()
*/
@@ -540,85 +645,6 @@ public class JarFileTest extends TestCase {
}
/**
- * @throws IOException
- * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "getInputStream",
- args = {java.util.zip.ZipEntry.class}
- )
- public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException {
- File localFile = null;
- try {
- Support_Resources.copyFile(resources, null, jarName);
- localFile = new File(resources, jarName);
- } catch (Exception e) {
- fail("Failed to create local file: " + e);
- }
-
- byte[] b = new byte[1024];
- try {
- JarFile jf = new JarFile(localFile);
- java.io.InputStream is = jf.getInputStream(jf.getEntry(entryName));
- // BEGIN android-removed
- // jf.close();
- // END android-removed
- assertTrue("Returned invalid stream", is.available() > 0);
- int r = is.read(b, 0, 1024);
- is.close();
- StringBuffer sb = new StringBuffer(r);
- for (int i = 0; i < r; i++) {
- sb.append((char) (b[i] & 0xff));
- }
- String contents = sb.toString();
- assertTrue("Incorrect stream read", contents.indexOf("bar") > 0);
- // BEGIN android-added
- jf.close();
- // END android-added
- } catch (Exception e) {
- fail("Exception during test: " + e.toString());
- }
-
- try {
- JarFile jf = new JarFile(localFile);
- InputStream in = jf.getInputStream(new JarEntry("invalid"));
- assertNull("Got stream for non-existent entry", in);
- } catch (Exception e) {
- fail("Exception during test 2: " + e);
- }
-
- try {
- Support_Resources.copyFile(resources, null, jarName);
- File signedFile = new File(resources, jarName);
- JarFile jf = new JarFile(signedFile);
- JarEntry jre = new JarEntry("foo/bar/A.class");
- jf.getInputStream(jre);
- // InputStream returned in any way, exception can be thrown in case
- // of reading from this stream only.
- // fail("Should throw ZipException");
- } catch (ZipException ee) {
- // expected
- }
-
- try {
- Support_Resources.copyFile(resources, null, jarName);
- File signedFile = new File(resources, jarName);
- JarFile jf = new JarFile(signedFile);
- JarEntry jre = new JarEntry("foo/bar/A.class");
- jf.close();
- jf.getInputStream(jre);
- // InputStream returned in any way, exception can be thrown in case
- // of reading from this stream only.
- // The same for IOException
- fail("Should throw IllegalStateException");
- } catch (IllegalStateException ee) {
- // expected
- }
- }
-
- /**
* @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
*/
@TestTargetNew(
@@ -660,7 +686,7 @@ public class JarFileTest extends TestCase {
} catch (Exception e) {
fail("Exception during test 4: " + e);
}
-
+
try {
JarFile jar = new JarFile(signedFile);
JarEntry entry = new JarEntry(entryName3);
@@ -682,7 +708,7 @@ public class JarFileTest extends TestCase {
} catch (Exception e) {
fail("Failed to create local file 5: " + e);
}
-
+
try {
JarFile jar = new JarFile(signedFile);
JarEntry entry = new JarEntry(entryName3);
@@ -732,7 +758,37 @@ public class JarFileTest extends TestCase {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
ZipEntry zipEntry = entries.nextElement();
- jarFile.getInputStream(zipEntry);
+ jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+ }
+ }
+
+ /**
+ * The jar is intact, but the entry object is modified.
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "getInputStream",
+ args = {ZipEntry.class}
+ )
+ public void testJarVerificationModifiedEntry() throws IOException {
+ Support_Resources.copyFile(resources, null, integrateJar);
+ File f = new File(resources, integrateJar);
+
+ JarFile jarFile = new JarFile(f);
+ ZipEntry zipEntry = jarFile.getJarEntry(integrateJarEntry);
+ zipEntry.setSize(zipEntry.getSize() + 1);
+ jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+
+ jarFile = new JarFile(f);
+ zipEntry = jarFile.getJarEntry(integrateJarEntry);
+ zipEntry.setSize(zipEntry.getSize() - 1);
+ try {
+ //jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+ jarFile.getInputStream(zipEntry).read(new byte[5000], 0, 5000);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // desired
}
}
@@ -781,7 +837,6 @@ public class JarFileTest extends TestCase {
Enumeration<JarEntry> entries = jarFile.entries();
int count = 0;
while (entries.hasMoreElements()) {
-
ZipEntry zipEntry = entries.nextElement();
jarFile.getInputStream(zipEntry);
count++;
@@ -818,7 +873,7 @@ public class JarFileTest extends TestCase {
while (in.available() > 0) {
in.read(buffer);
}
- fail("should throw Security Exception");
+ fail("SecurityException expected");
} catch (SecurityException e) {
// desired
}
@@ -827,7 +882,7 @@ public class JarFileTest extends TestCase {
/*
* In the Modified.jar, the main attributes of META-INF/MANIFEST.MF is
* tampered manually. Hence the RI 5.0 JarFile.getInputStream of any
- * JarEntry will throw security exception, but the apache harmony will not.
+ * JarEntry will throw security exception.
*/
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
@@ -846,7 +901,7 @@ public class JarFileTest extends TestCase {
ZipEntry zipEntry = entries.nextElement();
try {
jarFile.getInputStream(zipEntry);
- fail("should throw Security Exception");
+ fail("SecurityException expected");
} catch (SecurityException e) {
// desired
}
@@ -927,4 +982,83 @@ public class JarFileTest extends TestCase {
// Can not check IOException
}
+
+ /**
+ * @throws IOException
+ * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException {
+ File localFile = null;
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ localFile = new File(resources, jarName);
+ } catch (Exception e) {
+ fail("Failed to create local file: " + e);
+ }
+
+ byte[] b = new byte[1024];
+ try {
+ JarFile jf = new JarFile(localFile);
+ java.io.InputStream is = jf.getInputStream(jf.getEntry(entryName));
+ // BEGIN android-removed
+ // jf.close();
+ // END android-removed
+ assertTrue("Returned invalid stream", is.available() > 0);
+ int r = is.read(b, 0, 1024);
+ is.close();
+ StringBuffer sb = new StringBuffer(r);
+ for (int i = 0; i < r; i++) {
+ sb.append((char) (b[i] & 0xff));
+ }
+ String contents = sb.toString();
+ assertTrue("Incorrect stream read", contents.indexOf("bar") > 0);
+ // BEGIN android-added
+ jf.close();
+ // END android-added
+ } catch (Exception e) {
+ fail("Exception during test: " + e.toString());
+ }
+
+ try {
+ JarFile jf = new JarFile(localFile);
+ InputStream in = jf.getInputStream(new JarEntry("invalid"));
+ assertNull("Got stream for non-existent entry", in);
+ } catch (Exception e) {
+ fail("Exception during test 2: " + e);
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ File signedFile = new File(resources, jarName);
+ JarFile jf = new JarFile(signedFile);
+ JarEntry jre = new JarEntry("foo/bar/A.class");
+ jf.getInputStream(jre);
+ // InputStream returned in any way, exception can be thrown in case
+ // of reading from this stream only.
+ // fail("Should throw ZipException");
+ } catch (ZipException ee) {
+ // expected
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ File signedFile = new File(resources, jarName);
+ JarFile jf = new JarFile(signedFile);
+ JarEntry jre = new JarEntry("foo/bar/A.class");
+ jf.close();
+ jf.getInputStream(jre);
+ // InputStream returned in any way, exception can be thrown in case
+ // of reading from this stream only.
+ // The same for IOException
+ fail("Should throw IllegalStateException");
+ } catch (IllegalStateException ee) {
+ // expected
+ }
+ }
}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java
index e652137..acdad71 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java
@@ -48,7 +48,7 @@ public class JarOutputStreamTest extends junit.framework.TestCase {
method = "putNextEntry",
args = {java.util.zip.ZipEntry.class}
)
- public void test_putNextEntryLjava_util_zip_ZipEntry() {
+ public void test_putNextEntryLjava_util_zip_ZipEntry() throws Exception {
// testClass file`s actual extension is .class, since having .class
// extension files in source dir causes
// problems on eclipse, the extension is changed into .ser or it can be
@@ -76,35 +76,30 @@ public class JarOutputStreamTest extends junit.framework.TestCase {
File outputJar = null;
JarOutputStream jout = null;
- try {
- // open the output jarfile
- outputJar = File.createTempFile("hyts_", ".jar");
- jout = new JarOutputStream(new FileOutputStream(outputJar),
- newman);
- jout.putNextEntry(new JarEntry(entryName));
- } catch (Exception e) {
- fail("Error creating JarOutputStream: " + e);
- }
+ // open the output jarfile
+ outputJar = File.createTempFile("hyts_", ".jar");
+ jout = new JarOutputStream(new FileOutputStream(outputJar),
+ newman);
+ jout.putNextEntry(new JarEntry(entryName));
+
File resources = Support_Resources.createTempFolder();
- try {
- // read in the class file, and output it to the jar
- Support_Resources.copyFile(resources, null, testClass);
- URL jarURL = new URL((new File(resources, testClass)).toURL()
- .toString());
- InputStream jis = jarURL.openStream();
-
- byte[] bytes = new byte[1024];
- int len;
- while ((len = jis.read(bytes)) != -1) {
- jout.write(bytes, 0, len);
- }
-
- jout.flush();
- jout.close();
- jis.close();
- } catch (Exception e) {
- fail("Error writing JAR file for testing: " + e);
+
+ // read in the class file, and output it to the jar
+ Support_Resources.copyFile(resources, null, testClass);
+ URL jarURL = new URL((new File(resources, testClass)).toURL()
+ .toString());
+ InputStream jis = jarURL.openStream();
+
+ byte[] bytes = new byte[1024];
+ int len;
+ while ((len = jis.read(bytes)) != -1) {
+ jout.write(bytes, 0, len);
}
+
+ jout.flush();
+ jout.close();
+ jis.close();
+
String res = null;
// set up the VM parameters
String[] args = new String[2];
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java
index 57e4744..42b2543 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java
@@ -14,12 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.harmony.archive.tests.java.util.jar;
-import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargets;
+import dalvik.annotation.KnownFailure;
import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
import dalvik.annotation.TestTargetNew;
import java.io.ByteArrayInputStream;
@@ -28,14 +27,15 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
import java.net.URL;
+import java.net.MalformedURLException;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import junit.framework.TestCase;
+
import tests.support.resource.Support_Resources;
@TestTargetClass(Manifest.class)
@@ -49,6 +49,10 @@ public class ManifestTest extends TestCase {
private Manifest m2;
+ private final String ATT_ENTRY_NAME = "HasAttributes.txt";
+
+ private final String MANIFEST_NAME = "manifest/hyts_MANIFEST.MF";
+
private File resources;
@Override
@@ -68,6 +72,19 @@ public class ManifestTest extends TestCase {
}
}
+ private Manifest getManifest(String fileName) {
+ try {
+ Support_Resources.copyFile(resources, null, fileName);
+ JarFile jarFile = new JarFile(new File(resources, fileName));
+ Manifest m = jarFile.getManifest();
+ jarFile.close();
+ return m;
+ } catch (Exception e) {
+ fail("Exception during setup: " + e.toString());
+ return null;
+ }
+ }
+
/**
* @tests java.util.jar.Manifest#Manifest()
*/
@@ -87,264 +104,136 @@ public class ManifestTest extends TestCase {
}
/**
- * @tests java.util.jar.Manifest#Manifest(java.io.InputStream)
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "IOException checking missed.",
- method = "Manifest",
- args = {java.io.InputStream.class}
- )
- public void test_ConstructorLjava_io_InputStream() {
- // Test for method java.util.jar.Manifest(java.io.InputStream)
- /*
- * ByteArrayOutputStream baos = new ByteArrayOutputStream();
- * m2.write(baos); InputSteam is = new ByteArrayInputStream
- * (baos.toByteArray()); Manifest myManifest = new Manifest (is);
- * assertTrue("Manifests should be equal", myManifest.equals(m2));
- */
-
- Manifest manifest = null;
- InputStream is = null;
- try {
- is = new URL(Support_Resources.getURL("manifest/hyts_MANIFEST.MF"))
- .openStream();
- } catch (MalformedURLException e1) {
- fail("Failed to create InputStream object");
- } catch (IOException e1) {
- fail("Failed to create InputStream object");
- }
- try {
- manifest = new Manifest(is);
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
- Attributes main = manifest.getMainAttributes();
- assertEquals("Bundle-Name not correct", "ClientSupport", main
- .getValue("Bundle-Name"));
- assertEquals(
- "Bundle-Description not correct",
-
- "Provides SessionService, AuthenticationService. Extends RegistryService.",
- main.getValue("Bundle-Description"));
- assertEquals("Bundle-Activator not correct",
- "com.ibm.ive.eccomm.client.support.ClientSupportActivator",
- main.getValue("Bundle-Activator"));
- assertEquals(
- "Import-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client",
- main.getValue("Import-Package"));
- assertEquals(
- "Import-Service not correct",
-
- "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService",
- main.getValue("Import-Service"));
- assertEquals(
- "Export-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0",
- main.getValue("Export-Package"));
- assertEquals(
- "Export-Service not correct",
-
- "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService",
- main.getValue("Export-Service"));
- assertEquals("Bundle-Vendor not correct", "IBM", main
- .getValue("Bundle-Vendor"));
- assertEquals("Bundle-Version not correct", "1.2.0", main
- .getValue("Bundle-Version"));
- try {
- is.close();
- } catch (IOException e1) {
- fail("Failed to close InputStream object");
- }
- try {
- manifest = new Manifest(is);
- fail("IOException expected");
- } catch (MalformedURLException e) {
- fail("IOException expected");
- } catch (IOException e) {
- // expected
- }
- }
-
- /**
- * @tests java.util.jar.Manifest#clear()
+ * @tests java.util.jar.Manifest#Manifest(java.util.jar.Manifest)
*/
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "clear",
- args = {}
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "Manifest",
+ args = {java.util.jar.Manifest.class}
)
- public void test_clear() {
- // Test for method void java.util.jar.Manifest.clear()
- m2.clear();
- assertTrue("Should have no entries", m2.getEntries().isEmpty());
- assertTrue("Should have no main attributes", m2.getMainAttributes()
- .isEmpty());
+ public void testCopyingConstructor() throws IOException {
+ Manifest firstManifest = new Manifest(new URL(Support_Resources
+ .getURL(MANIFEST_NAME)).openStream());
+ Manifest secondManifest = new Manifest(firstManifest);
+ assertEquals(firstManifest, secondManifest);
}
/**
- * @tests java.util.jar.Manifest#getAttributes(java.lang.String)
+ * @tests java.util.jar.Manifest#Manifest(Manifest)
*/
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "getAttributes",
- args = {java.lang.String.class}
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "Manifest",
+ args = {java.util.jar.Manifest.class}
)
- public void test_getAttributesLjava_lang_String() {
- // Test for method java.util.jar.Attributes
- // java.util.jar.Manifest.getAttributes(java.lang.String)
- assertNull("Should not exist", m2.getAttributes("Doesn't Exist"));
- assertEquals("Should exist", "OK", m2
- .getAttributes("HasAttributes.txt").get(
- new Attributes.Name("MyAttribute")));
+ public void test_ConstructorLjava_util_jar_Manifest() {
+ // Test for method java.util.jar.Manifest()
+ Manifest emptyManifest = new Manifest();
+ Manifest emptyClone = new Manifest(emptyManifest);
+ assertTrue("Should have no entries", emptyClone.getEntries().isEmpty());
+ assertTrue("Should have no main attributes", emptyClone
+ .getMainAttributes().isEmpty());
+ assertEquals(emptyClone, emptyManifest);
+ assertEquals(emptyClone, emptyManifest.clone());
}
- /**
- * @tests java.util.jar.Manifest#getEntries()
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "getEntries",
- args = {}
- )
- public void test_getEntries() {
- // Test for method java.util.Map java.util.jar.Manifest.getEntries()
- Map<String, Attributes> myMap = m2.getEntries();
- assertNull("Shouldn't exist", myMap.get("Doesn't exist"));
- assertEquals("Should exist", "OK", myMap.get("HasAttributes.txt").get(
- new Attributes.Name("MyAttribute")));
-
+ private void assertAttribute(Attributes attr, String name, String value) {
+ assertEquals("Incorrect " + name, value, attr.getValue(name));
}
- /**
- * @tests java.util.jar.Manifest#getMainAttributes()
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "getMainAttributes",
- args = {}
- )
- public void test_getMainAttributes() {
- // Test for method java.util.jar.Attributes
- // java.util.jar.Manifest.getMainAttributes()
- Attributes a = m.getMainAttributes();
- assertEquals("Manifest_Version should return 1.0", "1.0", a
- .get(Attributes.Name.MANIFEST_VERSION));
+ private void checkManifest(Manifest manifest) {
+ Attributes main = manifest.getMainAttributes();
+ assertAttribute(main, "Bundle-Name", "ClientSupport");
+ assertAttribute(main, "Bundle-Description",
+ "Provides SessionService, AuthenticationService. Extends RegistryService.");
+ assertAttribute(main, "Bundle-Activator",
+ "com.ibm.ive.eccomm.client.support.ClientSupportActivator");
+ assertAttribute(
+ main,
+ "Import-Package",
+ "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client");
+ assertAttribute(
+ main,
+ "Import-Service",
+ "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService");
+ assertAttribute(
+ main,
+ "Export-Package",
+ "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0");
+ assertAttribute(
+ main,
+ "Export-Service",
+ "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService");
+ assertAttribute(main, "Bundle-Vendor", "IBM");
+ assertAttribute(main, "Bundle-Version", "1.2.0");
}
/**
- * @tests {@link java.util.jar.Manifest#read(java.io.InputStream)
+ * @tests java.util.jar.Manifest#Manifest(java.io.InputStream)
*/
@TestTargetNew(
level = TestLevel.COMPLETE,
- notes = "",
- method = "read",
+ notes = "IOException checking missed.",
+ method = "Manifest",
args = {java.io.InputStream.class}
)
- public void test_readLjava_io_InputStream() {
- // Regression for HARMONY-89
- InputStream is = new InputStreamImpl();
- try {
- new Manifest().read(is);
- fail("Assert 0: Should have thrown IOException");
- } catch (IOException e) {
- // expected
- }
+ public void test_ConstructorLjava_io_InputStream() throws IOException {
+ Manifest m = getManifest(attJarName);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ m.write(baos);
+ InputStream is = new ByteArrayInputStream(baos.toByteArray());
+ Manifest mCopy = new Manifest(is);
+ assertEquals(m, mCopy);
- Manifest manifest = new Manifest();
- try {
- manifest.read(new URL(Support_Resources
- .getURL("manifest/hyts_MANIFEST.MF")).openStream());
- } catch (MalformedURLException e) {
- fail("Can nor read manifest");
- } catch (IOException e) {
- fail("Can nor read manifest");
- }
- Attributes main = manifest.getMainAttributes();
- assertEquals("Bundle-Name not correct", "ClientSupport", main
- .getValue("Bundle-Name"));
- assertEquals(
- "Bundle-Description not correct",
-
- "Provides SessionService, AuthenticationService. Extends RegistryService.",
- main.getValue("Bundle-Description"));
- assertEquals("Bundle-Activator not correct",
- "com.ibm.ive.eccomm.client.support.ClientSupportActivator",
- main.getValue("Bundle-Activator"));
- assertEquals(
- "Import-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client",
- main.getValue("Import-Package"));
- assertEquals(
- "Import-Service not correct",
-
- "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService",
- main.getValue("Import-Service"));
- assertEquals(
- "Export-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0",
- main.getValue("Export-Package"));
- assertEquals(
- "Export-Service not correct",
-
- "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService",
- main.getValue("Export-Service"));
- assertEquals("Bundle-Vendor not correct", "IBM", main
- .getValue("Bundle-Vendor"));
- assertEquals("Bundle-Version not correct", "1.2.0", main
- .getValue("Bundle-Version"));
- }
+ Manifest manifest = new Manifest(new URL(Support_Resources
+ .getURL(MANIFEST_NAME)).openStream());
+ checkManifest(manifest);
- // helper class
- class InputStreamImpl extends InputStream {
- public InputStreamImpl() {
- super();
- }
+ // regression test for HARMONY-5424
+ String manifestContent = "Manifest-Version: 1.0\nCreated-By: Apache\nPackage: \nBuild-Jdk: 1.4.1_01\n\n"
+ + "Name: \nSpecification-Title: foo\nSpecification-Version: 1.0\nSpecification-Vendor: \n"
+ + "Implementation-Title: \nImplementation-Version: 1.0\nImplementation-Vendor: \n\n";
+ ByteArrayInputStream bis = new ByteArrayInputStream(manifestContent
+ .getBytes("ISO-8859-1"));
- @Override
- public int read() {
- return 0;
- }
+
+ Manifest mf = new Manifest(bis);
+ assertEquals("Should be 4 main attributes", 4, mf.getMainAttributes()
+ .size());
+
+ Map<String, Attributes> entries = mf.getEntries();
+ assertEquals("Should be one named entry", 1, entries.size());
+
+ Attributes namedEntryAttributes = (Attributes) (entries.get(""));
+ assertEquals("Should be 6 named entry attributes", 6,
+ namedEntryAttributes.size());
}
/**
- * @tests java.util.jar.Manifest#Manifest(Manifest)
+ * @tests java.util.jar.Manifest#clear()
*/
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "Manifest",
- args = {java.util.jar.Manifest.class}
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clear",
+ args = {}
)
- public void test_ConstructorLjava_util_jar_Manifest() {
- // Test for method java.util.jar.Manifest()
- Manifest emptyManifest = new Manifest();
- Manifest emptyClone = new Manifest(emptyManifest);
- assertTrue("Should have no entries", emptyClone.getEntries().isEmpty());
- assertTrue("Should have no main attributes", emptyClone
- .getMainAttributes().isEmpty());
- assertEquals(emptyClone, emptyManifest);
- assertEquals(emptyClone, emptyManifest.clone());
+ public void test_clear() {
+ m2.clear();
+ assertTrue("Should have no entries", m2.getEntries().isEmpty());
+ assertTrue("Should have no main attributes", m2.getMainAttributes()
+ .isEmpty());
}
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "clone",
- args = {}
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clone",
+ args = {}
)
- public void test_clone() {
+ public void test_clone() throws IOException {
Manifest emptyManifest = new Manifest();
Manifest emptyClone = (Manifest) emptyManifest.clone();
assertTrue("Should have no entries", emptyClone.getEntries().isEmpty());
@@ -354,88 +243,25 @@ public class ManifestTest extends TestCase {
assertEquals(emptyManifest.clone().getClass().getName(),
"java.util.jar.Manifest");
- Manifest manifest = null;
- try {
- manifest = new Manifest(new URL(Support_Resources
- .getURL("manifest/hyts_MANIFEST.MF")).openStream());
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
+ Manifest manifest = new Manifest(new URL(Support_Resources
+ .getURL("manifest/hyts_MANIFEST.MF")).openStream());
Manifest manifestClone = (Manifest) manifest.clone();
- Attributes main = manifestClone.getMainAttributes();
- assertEquals("Bundle-Name not correct", "ClientSupport", main
- .getValue("Bundle-Name"));
- assertEquals(
- "Bundle-Description not correct",
-
- "Provides SessionService, AuthenticationService. Extends RegistryService.",
- main.getValue("Bundle-Description"));
- assertEquals("Bundle-Activator not correct",
- "com.ibm.ive.eccomm.client.support.ClientSupportActivator",
- main.getValue("Bundle-Activator"));
- assertEquals(
- "Import-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client",
- main.getValue("Import-Package"));
- assertEquals(
- "Import-Service not correct",
-
- "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService",
- main.getValue("Import-Service"));
- assertEquals(
- "Export-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0",
- main.getValue("Export-Package"));
- assertEquals(
- "Export-Service not correct",
-
- "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService",
- main.getValue("Export-Service"));
- assertEquals("Bundle-Vendor not correct", "IBM", main
- .getValue("Bundle-Vendor"));
- assertEquals("Bundle-Version not correct", "1.2.0", main
- .getValue("Bundle-Version"));
+ manifestClone.getMainAttributes();
+ checkManifest(manifestClone);
}
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "equals",
- args = {java.lang.Object.class}
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "equals",
+ args = {java.lang.Object.class}
)
- public void test_equals() {
- Manifest manifest1 = null;
- Manifest manifest2 = null;
+ public void test_equals() throws IOException {
+ Manifest manifest1 = new Manifest(new URL(Support_Resources.getURL(
+ "manifest/hyts_MANIFEST.MF")).openStream());
+ Manifest manifest2 = new Manifest(new URL(Support_Resources.getURL(
+ "manifest/hyts_MANIFEST.MF")).openStream());
Manifest manifest3 = new Manifest();
- InputStream is = null;
- try {
- is = new URL(Support_Resources.getURL("manifest/hyts_MANIFEST.MF"))
- .openStream();
- } catch (MalformedURLException e1) {
- fail("Failed to create InputStream object");
- } catch (IOException e1) {
- fail("Failed to create InputStream object");
- }
- try {
- manifest1 = new Manifest(is);
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
-
- try {
- manifest2 = new Manifest(new URL(Support_Resources
- .getURL("manifest/hyts_MANIFEST.MF")).openStream());
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
assertTrue(manifest1.equals(manifest1));
assertTrue(manifest1.equals(manifest2));
@@ -444,27 +270,69 @@ public class ManifestTest extends TestCase {
}
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "hashCode",
- args = {}
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "hashCode",
+ args = {}
)
- public void test_hashCode() {
- Manifest manifest1 = null;
+ public void test_hashCode() throws IOException {
+ Manifest manifest1 = new Manifest(new URL(Support_Resources
+ .getURL("manifest/hyts_MANIFEST.MF")).openStream());
Manifest manifest2 = new Manifest();
- InputStream is = null;
- try {
- manifest1 = new Manifest(new URL(Support_Resources
- .getURL("manifest/hyts_MANIFEST.MF")).openStream());
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
assertEquals(manifest1.hashCode(), manifest1.hashCode());
assertNotSame(manifest1.hashCode(), manifest2.hashCode());
}
+ /**
+ * @tests java.util.jar.Manifest#getAttributes(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getAttributes",
+ args = {String.class}
+ )
+ public void test_getAttributesLjava_lang_String() {
+ assertNull("Should not exist",
+ m2.getAttributes("Doesn't Exist"));
+ assertEquals("Should exist", "OK", m2.getAttributes("HasAttributes.txt").get(
+ new Attributes.Name("MyAttribute")));
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#getEntries()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getEntries",
+ args = {}
+ )
+ public void test_getEntries() {
+ Map<String, Attributes> myMap = m2.getEntries();
+ assertNull("Shouldn't exist", myMap.get("Doesn't exist"));
+ assertEquals("Should exist",
+ "OK", myMap.get("HasAttributes.txt").get(
+ new Attributes.Name("MyAttribute")));
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#getMainAttributes()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getMainAttributes",
+ args = {}
+ )
+ public void test_getMainAttributes() {
+ // Test for method java.util.jar.Attributes
+ // java.util.jar.Manifest.getMainAttributes()
+ Attributes a = m.getMainAttributes();
+ assertEquals("Manifest_Version should return 1.0", "1.0", a.get(
+ Attributes.Name.MANIFEST_VERSION));
+ }
+
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "",
@@ -510,4 +378,219 @@ public class ManifestTest extends TestCase {
assertTrue(manifest1.equals(manifest2));
}
+
+ /**
+ * Ensures compatibility with manifests produced by gcc.
+ *
+ * @see <a
+ * href="http://issues.apache.org/jira/browse/HARMONY-5662">HARMONY-5662</a>
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "Manifest",
+ args = {InputStream.class}
+ )
+ public void testNul() throws IOException {
+ String manifestContent =
+ "Manifest-Version: 1.0\nCreated-By: nasty gcc tool\n\n\0";
+
+ byte[] bytes = manifestContent.getBytes("ISO-8859-1");
+ new Manifest(new ByteArrayInputStream(bytes)); // the last NUL is ok
+
+ bytes[bytes.length - 1] = 26;
+ new Manifest(new ByteArrayInputStream(bytes)); // the last EOF is ok
+
+ bytes[bytes.length - 1] = 'A'; // the last line ignored
+ new Manifest(new ByteArrayInputStream(bytes));
+
+ bytes[2] = 0; // NUL char in Manifest
+ try {
+ new Manifest(new ByteArrayInputStream(bytes));
+ fail("IOException expected");
+ } catch (IOException e) {
+ // desired
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "Manifest",
+ args = {InputStream.class}
+ )
+ @KnownFailure("CharsetDecoder fails with an IllegalStateException")
+ public void testDecoding() throws IOException {
+ Manifest m = getManifest(attJarName);
+ final byte[] bVendor = new byte[] { (byte) 0xd0, (byte) 0x9C,
+ (byte) 0xd0, (byte) 0xb8, (byte) 0xd0, (byte) 0xbb,
+ (byte) 0xd0, (byte) 0xb0, (byte) 0xd1, (byte) 0x8f, ' ',
+ (byte) 0xd0, (byte) 0xb4, (byte) 0xd0, (byte) 0xbe,
+ (byte) 0xd1, (byte) 0x87, (byte) 0xd1, (byte) 0x83,
+ (byte) 0xd0, (byte) 0xbd, (byte) 0xd1, (byte) 0x8C,
+ (byte) 0xd0, (byte) 0xba, (byte) 0xd0, (byte) 0xb0, ' ',
+ (byte) 0xd0, (byte) 0x9C, (byte) 0xd0, (byte) 0xb0,
+ (byte) 0xd1, (byte) 0x88, (byte) 0xd0, (byte) 0xb0 };
+
+ final byte[] bSpec = new byte[] { (byte) 0xe1, (byte) 0x88,
+ (byte) 0xb0, (byte) 0xe1, (byte) 0x88, (byte) 0x8b,
+ (byte) 0xe1, (byte) 0x88, (byte) 0x9d, ' ', (byte) 0xe1,
+ (byte) 0x9a, (byte) 0xa0, (byte) 0xe1, (byte) 0x9a,
+ (byte) 0xb1, (byte) 0xe1, (byte) 0x9b, (byte) 0x81,
+ (byte) 0xe1, (byte) 0x9a, (byte) 0xa6, ' ', (byte) 0xd8,
+ (byte) 0xb3, (byte) 0xd9, (byte) 0x84, (byte) 0xd8,
+ (byte) 0xa7, (byte) 0xd9, (byte) 0x85, ' ', (byte) 0xd8,
+ (byte) 0xb9, (byte) 0xd8, (byte) 0xb3, (byte) 0xd9,
+ (byte) 0x84, (byte) 0xd8, (byte) 0xa7, (byte) 0xd9,
+ (byte) 0x85, (byte) 0xd8, (byte) 0xa9, ' ', (byte) 0xdc,
+ (byte) 0xab, (byte) 0xdc, (byte) 0xa0, (byte) 0xdc,
+ (byte) 0xa1, (byte) 0xdc, (byte) 0x90, ' ', (byte) 0xe0,
+ (byte) 0xa6, (byte) 0xb6, (byte) 0xe0, (byte) 0xa6,
+ (byte) 0xbe, (byte) 0xe0, (byte) 0xa6, (byte) 0xa8,
+ (byte) 0xe0, (byte) 0xa7, (byte) 0x8d, (byte) 0xe0,
+ (byte) 0xa6, (byte) 0xa4, (byte) 0xe0, (byte) 0xa6,
+ (byte) 0xbf, ' ', (byte) 0xd0, (byte) 0xa0, (byte) 0xd0,
+ (byte) 0xb5, (byte) 0xd0, (byte) 0xba, (byte) 0xd1,
+ (byte) 0x8a, (byte) 0xd0, (byte) 0xb5, (byte) 0xd0,
+ (byte) 0xbb, ' ', (byte) 0xd0, (byte) 0x9c, (byte) 0xd0,
+ (byte) 0xb8, (byte) 0xd1, (byte) 0x80, ' ', (byte) 0xe0,
+ (byte) 0xa6, (byte) 0xb6, (byte) 0xe0, (byte) 0xa6,
+ (byte) 0xbe, (byte) 0xe0, (byte) 0xa6, (byte) 0xa8,
+ (byte) 0xe0, (byte) 0xa7, (byte) 0x8d, (byte) 0xe0,
+ (byte) 0xa6, (byte) 0xa4, (byte) 0xe0, (byte) 0xa6,
+ (byte) 0xbf, ' ', (byte) 0xe0, (byte) 0xbd, (byte) 0x9e,
+ (byte) 0xe0, (byte) 0xbd, (byte) 0xb2, (byte) 0xe0,
+ (byte) 0xbc, (byte) 0x8b, (byte) 0xe0, (byte) 0xbd,
+ (byte) 0x96, (byte) 0xe0, (byte) 0xbd, (byte) 0x91,
+ (byte) 0xe0, (byte) 0xbd, (byte) 0xba, ' ', (byte) 0xd0,
+ (byte) 0x9c, (byte) 0xd0, (byte) 0xb0, (byte) 0xd1,
+ (byte) 0x88, (byte) 0xd0, (byte) 0xb0, (byte) 0xd1,
+ (byte) 0x80, ' ', (byte) 0xe1, (byte) 0x8f, (byte) 0x99,
+ (byte) 0xe1, (byte) 0x8e, (byte) 0xaf, (byte) 0xe1,
+ (byte) 0x8f, (byte) 0xb1, ' ', (byte) 0xcf, (byte) 0xa8,
+ (byte) 0xce, (byte) 0xb9, (byte) 0xcf, (byte) 0x81,
+ (byte) 0xce, (byte) 0xb7, (byte) 0xce, (byte) 0xbd,
+ (byte) 0xce, (byte) 0xb7, ' ', (byte) 0xde, (byte) 0x90,
+ (byte) 0xde, (byte) 0xaa, (byte) 0xde, (byte) 0x85,
+ (byte) 0xde, (byte) 0xa6, ' ', (byte) 0xe0, (byte) 0xbd,
+ (byte) 0x82, (byte) 0xe0, (byte) 0xbd, (byte) 0x9e,
+ (byte) 0xe0, (byte) 0xbd, (byte) 0xb2, (byte) 0xe0,
+ (byte) 0xbc, (byte) 0x8b, (byte) 0xe0, (byte) 0xbd,
+ (byte) 0x96, (byte) 0xe0, (byte) 0xbd, (byte) 0x91,
+ (byte) 0xe0, (byte) 0xbd, (byte) 0xba, ' ', (byte) 0xce,
+ (byte) 0x95, (byte) 0xce, (byte) 0xb9, (byte) 0xcf,
+ (byte) 0x81, (byte) 0xce, (byte) 0xae, (byte) 0xce,
+ (byte) 0xbd, (byte) 0xce, (byte) 0xb7, ' ', (byte) 0xd8,
+ (byte) 0xb5, (byte) 0xd9, (byte) 0x84, (byte) 0xd8,
+ (byte) 0xad, ' ', (byte) 0xe0, (byte) 0xaa, (byte) 0xb6,
+ (byte) 0xe0, (byte) 0xaa, (byte) 0xbe, (byte) 0xe0,
+ (byte) 0xaa, (byte) 0x82, (byte) 0xe0, (byte) 0xaa,
+ (byte) 0xa4, (byte) 0xe0, (byte) 0xaa, (byte) 0xbf, ' ',
+ (byte) 0xe5, (byte) 0xb9, (byte) 0xb3, (byte) 0xe5,
+ (byte) 0x92, (byte) 0x8c, ' ', (byte) 0xd7, (byte) 0xa9,
+ (byte) 0xd7, (byte) 0x9c, (byte) 0xd7, (byte) 0x95,
+ (byte) 0xd7, (byte) 0x9d, ' ', (byte) 0xd7, (byte) 0xa4,
+ (byte) 0xd7, (byte) 0xa8, (byte) 0xd7, (byte) 0x99,
+ (byte) 0xd7, (byte) 0x93, (byte) 0xd7, (byte) 0x9f, ' ',
+ (byte) 0xe5, (byte) 0x92, (byte) 0x8c, (byte) 0xe5,
+ (byte) 0xb9, (byte) 0xb3, ' ', (byte) 0xe5, (byte) 0x92,
+ (byte) 0x8c, (byte) 0xe5, (byte) 0xb9, (byte) 0xb3, ' ',
+ (byte) 0xd8, (byte) 0xaa, (byte) 0xd9, (byte) 0x89,
+ (byte) 0xd9, (byte) 0x86, (byte) 0xda, (byte) 0x86,
+ (byte) 0xd9, (byte) 0x84, (byte) 0xd9, (byte) 0x89,
+ (byte) 0xd9, (byte) 0x82, ' ', (byte) 0xe0, (byte) 0xae,
+ (byte) 0x85, (byte) 0xe0, (byte) 0xae, (byte) 0xae,
+ (byte) 0xe0, (byte) 0xaf, (byte) 0x88, (byte) 0xe0,
+ (byte) 0xae, (byte) 0xa4, (byte) 0xe0, (byte) 0xae,
+ (byte) 0xbf, ' ', (byte) 0xe0, (byte) 0xb0, (byte) 0xb6,
+ (byte) 0xe0, (byte) 0xb0, (byte) 0xbe, (byte) 0xe0,
+ (byte) 0xb0, (byte) 0x82, (byte) 0xe0, (byte) 0xb0,
+ (byte) 0xa4, (byte) 0xe0, (byte) 0xb0, (byte) 0xbf, ' ',
+ (byte) 0xe0, (byte) 0xb8, (byte) 0xaa, (byte) 0xe0,
+ (byte) 0xb8, (byte) 0xb1, (byte) 0xe0, (byte) 0xb8,
+ (byte) 0x99, (byte) 0xe0, (byte) 0xb8, (byte) 0x95,
+ (byte) 0xe0, (byte) 0xb8, (byte) 0xb4, (byte) 0xe0,
+ (byte) 0xb8, (byte) 0xa0, (byte) 0xe0, (byte) 0xb8,
+ (byte) 0xb2, (byte) 0xe0, (byte) 0xb8, (byte) 0x9e, ' ',
+ (byte) 0xe1, (byte) 0x88, (byte) 0xb0, (byte) 0xe1,
+ (byte) 0x88, (byte) 0x8b, (byte) 0xe1, (byte) 0x88,
+ (byte) 0x9d, ' ', (byte) 0xe0, (byte) 0xb7, (byte) 0x83,
+ (byte) 0xe0, (byte) 0xb7, (byte) 0x8f, (byte) 0xe0,
+ (byte) 0xb6, (byte) 0xb8, (byte) 0xe0, (byte) 0xb6,
+ (byte) 0xba, ' ', (byte) 0xe0, (byte) 0xa4, (byte) 0xb6,
+ (byte) 0xe0, (byte) 0xa4, (byte) 0xbe, (byte) 0xe0,
+ (byte) 0xa4, (byte) 0xa8, (byte) 0xe0, (byte) 0xa5,
+ (byte) 0x8d, (byte) 0xe0, (byte) 0xa4, (byte) 0xa4,
+ (byte) 0xe0, (byte) 0xa4, (byte) 0xbf, (byte) 0xe0,
+ (byte) 0xa4, (byte) 0x83, ' ', (byte) 0xe1, (byte) 0x83,
+ (byte) 0x9b, (byte) 0xe1, (byte) 0x83, (byte) 0xa8,
+ (byte) 0xe1, (byte) 0x83, (byte) 0x95, (byte) 0xe1,
+ (byte) 0x83, (byte) 0x98, (byte) 0xe1, (byte) 0x83,
+ (byte) 0x93, (byte) 0xe1, (byte) 0x83, (byte) 0x9d,
+ (byte) 0xe1, (byte) 0x83, (byte) 0x91, (byte) 0xe1,
+ (byte) 0x83, (byte) 0x90 };
+ // TODO Cannot make the following word work, encoder changes needed
+ // (byte) 0xed, (byte) 0xa0, (byte) 0x80,
+ // (byte) 0xed, (byte) 0xbc, (byte) 0xb2, (byte) 0xed,
+ // (byte) 0xa0, (byte) 0x80, (byte) 0xed, (byte) 0xbc,
+ // (byte) 0xb0, (byte) 0xed, (byte) 0xa0, (byte) 0x80,
+ // (byte) 0xed, (byte) 0xbd, (byte) 0x85, (byte) 0xed,
+ // (byte) 0xa0, (byte) 0x80, (byte) 0xed, (byte) 0xbc,
+ // (byte) 0xb0, (byte) 0xed, (byte) 0xa0, (byte) 0x80,
+ // (byte) 0xed, (byte) 0xbc, (byte) 0xb9, (byte) 0xed,
+ // (byte) 0xa0, (byte) 0x80, (byte) 0xed, (byte) 0xbc,
+ // (byte) 0xb8, (byte) 0xed, (byte) 0xa0, (byte) 0x80,
+ // (byte) 0xed, (byte) 0xbc, (byte) 0xb9, ' '
+
+ final String vendor = new String(bVendor, "UTF-8");
+ final String spec = new String(bSpec, "UTF-8");
+ m.getMainAttributes()
+ .put(Attributes.Name.IMPLEMENTATION_VENDOR, vendor);
+ m.getAttributes(ATT_ENTRY_NAME).put(
+ Attributes.Name.IMPLEMENTATION_VENDOR, vendor);
+ m.getEntries().get(ATT_ENTRY_NAME).put(
+ Attributes.Name.SPECIFICATION_TITLE, spec);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ m.write(baos);
+ m = new Manifest(new ByteArrayInputStream(baos.toByteArray()));
+
+ assertEquals(vendor, m.getMainAttributes().get(
+ Attributes.Name.IMPLEMENTATION_VENDOR));
+ assertEquals(vendor, m.getEntries().get(ATT_ENTRY_NAME).get(
+ Attributes.Name.IMPLEMENTATION_VENDOR));
+ assertEquals(spec, m.getAttributes(ATT_ENTRY_NAME).get(
+ Attributes.Name.SPECIFICATION_TITLE));
+ }
+
+ /**
+ * @tests {@link java.util.jar.Manifest#read(java.io.InputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "",
+ method = "read",
+ args = {InputStream.class}
+ )
+ public void testRead() {
+ // Regression for HARMONY-89
+ InputStream is = new InputStreamImpl();
+ try {
+ new Manifest().read(is);
+ fail("IOException expected");
+ } catch (IOException e) {
+ // desired
+ }
+ }
+
+ // helper class
+ private class InputStreamImpl extends InputStream {
+ public InputStreamImpl() {
+ super();
+ }
+
+ @Override
+ public int read() {
+ return 0;
+ }
+ }
}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java
index 75060bd..1e8ddb4 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java
@@ -25,6 +25,8 @@ import dalvik.annotation.TestTargetNew;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -310,7 +312,43 @@ public class GZIPInputStreamTest extends junit.framework.TestCase {
}
}
- @Override
+ /**
+ * Regression test for HARMONY-3703.
+ * @tests java.util.zip.GZIPInputStream#read()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "read",
+ args = {byte[].class}
+ )
+ public void test_read() throws IOException {
+ GZIPInputStream gis = null;
+ int result = 0;
+ byte[] buffer = new byte[] {1,2,3,4,5,6,7,8,9,10};
+ File f = new File(resources.getAbsolutePath() + "test.gz");
+ FileOutputStream out = new FileOutputStream(f);
+ GZIPOutputStream gout = new GZIPOutputStream(out);
+
+ // write 100 bytes to the stream
+ for(int i = 0; i < 10; i++) {
+ gout.write(buffer);
+ }
+ gout.finish();
+ out.write(1);
+ out.close();
+
+ gis = new GZIPInputStream(new FileInputStream(f));
+ buffer = new byte[100];
+ gis.read(buffer);
+ result = gis.read();
+ gis.close();
+ f.delete();
+
+ assertEquals("Incorrect value returned at the end of the file", -1, result);
+ }
+
+ @Override
protected void setUp() {
resources = Support_Resources.createTempFolder();
}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java
index 9b23b56..b71ce63 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java
@@ -201,8 +201,6 @@ public class GZIPOutputStreamTest extends junit.framework.TestCase {
int r = 0;
try {
outGZIP.write(byteArray, 0, 11);
- } catch (ArrayIndexOutOfBoundsException e) {
- r = 1;
} catch (IndexOutOfBoundsException ee) {
r = 1;
}
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
index 8b89180..6039c5b 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
@@ -409,6 +409,22 @@ public class InflaterTest extends junit.framework.TestCase {
}
/**
+ * @tests java.util.zip.Inflater#Inflater()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Inflater",
+ args = {}
+ )
+ public void test_Constructor() {
+ // test method of java.util.zip.inflater.Inflater()
+ Inflater inflate = new Inflater();
+ assertNotNull("failed to create the instance of inflater",
+ inflate);
+ }
+
+ /**
* @tests java.util.zip.Inflater#inflate(byte[], int, int)
*/
@TestTargetNew(
@@ -504,27 +520,6 @@ public class InflaterTest extends junit.framework.TestCase {
}
/**
- * @tests java.util.zip.Inflater#Inflater()
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "Inflater",
- args = {}
- )
- public void test_Constructor() {
- // test method of java.util.zip.inflater.Inflater()
- try {
- Inflater inflate = new Inflater();
- assertNotNull("failed to create the instance of inflater", inflate);
-
- } catch (Exception e) {
-
- assertTrue("Inflate () constructor threw an exception", true);
- }
- }
-
- /**
* @tests java.util.zip.Inflater#Inflater(boolean)
*/
@TestTargetNew(
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 5530a2e..c9e7bb8 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
@@ -67,7 +67,7 @@ public class ZipFileTest extends junit.framework.TestCase {
public void checkPermission(Permission perm) {
// only check if it's a FilePermission because Locale checks
// for a PropertyPermission with action"read" to get system props.
- if (perm instanceof FilePermission
+ if (perm instanceof FilePermission
&& perm.getActions().equals(forbidenPermissionAction)) {
throw new SecurityException();
}
@@ -145,7 +145,7 @@ public class ZipFileTest extends junit.framework.TestCase {
public void test_ConstructorLjava_lang_String() throws IOException {
String oldUserDir = System.getProperty("user.dir");
System.setProperty("user.dir", System.getProperty("java.io.tmpdir"));
-
+
zfile.close(); // about to reopen the same temp file
ZipFile zip = new ZipFile(tempFileName);
zip.close();
@@ -260,7 +260,7 @@ public class ZipFileTest extends junit.framework.TestCase {
method = "entries",
args = {}
)
- public void test_entries() {
+ public void test_entries() throws Exception {
// Test for method java.util.Enumeration java.util.zip.ZipFile.entries()
Enumeration<? extends ZipEntry> enumer = zfile.entries();
int c = 0;
@@ -270,20 +270,16 @@ public class ZipFileTest extends junit.framework.TestCase {
}
assertTrue("Incorrect number of entries returned: " + c, c == 6);
+ Enumeration<? extends ZipEntry> enumeration = zfile.entries();
+ zfile.close();
+ zfile = null;
+ boolean pass = false;
try {
- Enumeration<? extends ZipEntry> enumeration = zfile.entries();
- zfile.close();
- zfile = null;
- boolean pass = false;
- try {
- enumeration.hasMoreElements();
- } catch (IllegalStateException e) {
- pass = true;
- }
- assertTrue("did not detect closed jar file", pass);
- } catch (Exception e) {
- fail("Exception during entries test: " + e.toString());
+ enumeration.hasMoreElements();
+ } catch (IllegalStateException e) {
+ pass = true;
}
+ assertTrue("did not detect closed jar file", pass);
}
/**
@@ -454,6 +450,99 @@ public class ZipFileTest extends junit.framework.TestCase {
}
/**
+ * @tests java.io.InputStream#reset()
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ @KnownFailure("ZipEntry.getInputStream().reset() fails with an IOException")
+ public void test_reset() throws IOException {
+ // read an uncompressed entry
+ ZipEntry zentry = zfile.getEntry("File1.txt");
+ InputStream is = zfile.getInputStream(zentry);
+ byte[] rbuf1 = new byte[6];
+ byte[] rbuf2 = new byte[6];
+ int r1, r2;
+ r1 = is.read(rbuf1);
+ assertEquals(rbuf1.length, r1);
+ r2 = is.read(rbuf2);
+ assertEquals(rbuf2.length, r2);
+
+ is.reset();
+ r2 = is.read(rbuf2);
+ assertEquals(rbuf2.length, r2);
+ is.close();
+
+ // read a compressed entry
+ byte[] rbuf3 = new byte[4185];
+ ZipEntry zentry2 = zfile.getEntry("File3.txt");
+ is = zfile.getInputStream(zentry2);
+ r1 = is.read(rbuf3);
+ assertEquals(4183, r1);
+ is.reset();
+
+ r1 = is.read(rbuf3);
+ assertEquals(4183, r1);
+ is.close();
+
+ is = zfile.getInputStream(zentry2);
+ r1 = is.read(rbuf3, 0, 3000);
+ assertEquals(3000, r1);
+ is.reset();
+ r1 = is.read(rbuf3, 0, 3000);
+ assertEquals(3000, r1);
+ is.close();
+ }
+
+ /**
+ * @tests java.io.InputStream#reset()
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ @KnownFailure("ZipEntry.getInputStream().reset() fails with an IOException")
+ public void test_reset_subtest0() throws IOException {
+ // read an uncompressed entry
+ ZipEntry zentry = zfile.getEntry("File1.txt");
+ InputStream is = zfile.getInputStream(zentry);
+ byte[] rbuf1 = new byte[12];
+ byte[] rbuf2 = new byte[12];
+ int r = is.read(rbuf1, 0, 4);
+ assertEquals(4, r);
+ is.mark(0);
+ r = is.read(rbuf1);
+ assertEquals(8, r);
+ assertEquals(-1, is.read());
+
+ is.reset();
+ r = is.read(rbuf2);
+ assertEquals(8, r);
+ assertEquals(-1, is.read());
+ is.close();
+
+ // read a compressed entry
+ byte[] rbuf3 = new byte[4185];
+ ZipEntry zentry2 = zfile.getEntry("File3.txt");
+ is = zfile.getInputStream(zentry2);
+ r = is.read(rbuf3, 0, 3000);
+ assertEquals(3000, r);
+ is.mark(0);
+ r = is.read(rbuf3);
+ assertEquals(1183, r);
+ assertEquals(-1, is.read());
+
+ is.reset();
+ r = is.read(rbuf3);
+ assertEquals(1183, r);
+ assertEquals(-1, is.read());
+ is.close();
+ }
+
+ /**
* Sets up the fixture, for example, open a network connection. This method
* is called before a test is executed.
*/
diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
index 9a5f63a..8ca551d 100644
--- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
+++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
@@ -170,11 +170,8 @@ public class ZipOutputStreamTest extends junit.framework.TestCase {
public void test_setCommentLjava_lang_String() {
// There is no way to get the comment back, so no way to determine if
// the comment is set correct
- try {
- zos.setComment("test setComment");
- } catch (Exception e) {
- fail("Trying to set comment failed");
- }
+ zos.setComment("test setComment");
+
try {
zos.setComment(new String(new byte[0xFFFF + 1]));
fail("Comment over 0xFFFF in length should throw exception");
@@ -301,6 +298,17 @@ public class ZipOutputStreamTest extends junit.framework.TestCase {
} catch (IndexOutOfBoundsException e) {
// expected
}
+
+ // Regression for HARMONY-4405
+ try {
+ zip.write(null, 0, -2);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // Close stream because ZIP is invalid
+ stream.close();
}
/**
@@ -337,6 +345,8 @@ public class ZipOutputStreamTest extends junit.framework.TestCase {
} catch (IOException e2) {
// expected
}
+
+ zip1.close();
}
@Override
diff --git a/auth/src/main/java/javax/security/auth/AuthPermission.java b/auth/src/main/java/javax/security/auth/AuthPermission.java
index 06ea3fb..697d5c7 100644
--- a/auth/src/main/java/javax/security/auth/AuthPermission.java
+++ b/auth/src/main/java/javax/security/auth/AuthPermission.java
@@ -26,33 +26,31 @@ import org.apache.harmony.auth.internal.nls.Messages;
* <i>target name</i> of the permission specifies which methods are allowed
* without specifying the concrete action lists. Possible target names and
* associated authentication permissions are:
- *
+ *
* <pre>
* doAs invoke Subject.doAs methods.
* doAsPrivileged invoke the Subject.doAsPrivileged methods.
* getSubject invoke Subject.getSubject().
* getSubjectFromDomainCombiner invoke SubjectDomainCombiner.getSubject().
* setReadOnly invoke Subject.setReadonly().
- * modifyPrincipals modify the set of principals
+ * modifyPrincipals modify the set of principals
* associated with a Subject.
* modifyPublicCredentials modify the set of public credentials
* associated with a Subject.
* modifyPrivateCredentials modify the set of private credentials
* associated with a Subject.
- * refreshCredential invoke the refresh method on a credential of a
+ * refreshCredential invoke the refresh method on a credential of a
* refreshable credential class.
* destroyCredential invoke the destroy method on a credential of a
* destroyable credential class.
* createLoginContext.<i>name</i> instantiate a LoginContext with the
* specified name. The wildcard name ('*')
* allows to a LoginContext of any name.
- * getLoginConfiguration invoke the getConfiguration method of
+ * getLoginConfiguration invoke the getConfiguration method of
* javax.security.auth.login.Configuration.
- * refreshLoginConfiguration Invoke the refresh method of
+ * refreshLoginConfiguration Invoke the refresh method of
* javax.security.auth.login.Configuration.
* </pre>
- *
- * @since Android 1.0
*/
public final class AuthPermission extends BasicPermission {
@@ -77,7 +75,7 @@ public final class AuthPermission extends BasicPermission {
/**
* Creates an authentication permission with the specified target name.
- *
+ *
* @param name
* the target name of this authentication permission.
*/
@@ -87,7 +85,7 @@ public final class AuthPermission extends BasicPermission {
/**
* Creates an authentication permission with the specified target name.
- *
+ *
* @param name
* the target name of this authentication permission.
* @param actions
diff --git a/auth/src/main/java/javax/security/auth/DestroyFailedException.java b/auth/src/main/java/javax/security/auth/DestroyFailedException.java
index a5438a6..27d4dfd 100644
--- a/auth/src/main/java/javax/security/auth/DestroyFailedException.java
+++ b/auth/src/main/java/javax/security/auth/DestroyFailedException.java
@@ -19,8 +19,6 @@ package javax.security.auth;
/**
* Signals that the {@link Destroyable#destroy()} method failed.
- *
- * @since Android 1.0
*/
public class DestroyFailedException extends Exception {
@@ -35,7 +33,7 @@ public class DestroyFailedException extends Exception {
/**
* Creates an exception of type {@code DestroyFailedException}.
- *
+ *
* @param message
* A detail message that describes the reason for this exception.
*/
diff --git a/auth/src/main/java/javax/security/auth/Destroyable.java b/auth/src/main/java/javax/security/auth/Destroyable.java
index 6194db6..b4d0fa2 100644
--- a/auth/src/main/java/javax/security/auth/Destroyable.java
+++ b/auth/src/main/java/javax/security/auth/Destroyable.java
@@ -20,8 +20,6 @@ package javax.security.auth;
/**
* Allows for special treatment of sensitive information, when it comes to
* destroying or clearing of the data.
- *
- * @since Android 1.0
*/
public interface Destroyable {
@@ -29,7 +27,7 @@ public interface Destroyable {
* Erases the sensitive information. Once an object is destroyed any calls
* to its methods will throw an {@code IllegalStateException}. If it does
* not succeed a DestroyFailedException is thrown.
- *
+ *
* @throws DestroyFailedException
* if the information cannot be erased.
*/
@@ -37,7 +35,7 @@ public interface Destroyable {
/**
* Returns {@code true} once an object has been safely destroyed.
- *
+ *
* @return whether the object has been safely destroyed.
*/
boolean isDestroyed();
diff --git a/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java b/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java
index d92ede5..35072b8 100644
--- a/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java
+++ b/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java
@@ -31,11 +31,11 @@ import org.apache.harmony.auth.internal.nls.Messages;
* Protects private credential objects belonging to a {@code Subject}. It has
* only one action which is "read". The target name of this permission has a
* special syntax:
- *
+ *
* <pre>
* targetName = CredentialClass {PrincipalClass &quot;PrincipalName&quot;}*
* </pre>
- *
+ *
* First it states a credential class and is followed then by a list of one or
* more principals identifying the subject.
* <p>
@@ -43,12 +43,11 @@ import org.apache.harmony.auth.internal.nls.Messages;
* Principal} class followed by the principal name in quotes. For example, the
* following file may define permission to read the private credentials of a
* principal named "Bob": "com.sun.PrivateCredential com.sun.Principal \"Bob\""
- * </p>
+ * <p>
* The syntax also allows the use of the wildcard "*" in place of {@code
* CredentialClass} or {@code PrincipalClass} and/or {@code PrincipalName}.
- *
+ *
* @see Principal
- * @since Android 1.0
*/
public final class PrivateCredentialPermission extends Permission {
@@ -69,7 +68,7 @@ public final class PrivateCredentialPermission extends Permission {
* Creates a new permission for private credentials specified by the target
* name {@code name} and an {@code action}. The action is always
* {@code "read"}.
- *
+ *
* @param name
* the target name of the permission.
* @param action
@@ -197,13 +196,13 @@ public final class PrivateCredentialPermission extends Permission {
* dimension of the array corresponds to the number of principals. The
* second dimension defines either the name of the {@code PrincipalClass}
* [x][0] or the value of {@code PrincipalName} [x][1].
- *
+ * <p>
* This corresponds to the the target name's syntax:
- *
+ *
* <pre>
* targetName = CredentialClass {PrincipalClass &quot;PrincipalName&quot;}*
* </pre>
- *
+ *
* @return the principal classes and names associated with this {@code
* PrivateCredentialPermission}.
*/
@@ -225,7 +224,7 @@ public final class PrivateCredentialPermission extends Permission {
/**
* Returns the class name of the credential associated with this permission.
- *
+ *
* @return the class name of the credential associated with this permission.
*/
public String getCredentialClass() {
diff --git a/auth/src/main/java/javax/security/auth/Subject.java b/auth/src/main/java/javax/security/auth/Subject.java
index 5a4cceb..5bf6bba 100644
--- a/auth/src/main/java/javax/security/auth/Subject.java
+++ b/auth/src/main/java/javax/security/auth/Subject.java
@@ -51,8 +51,6 @@ import org.apache.harmony.auth.internal.nls.Messages;
* <li>Credentials (public and private) such as certificates, keys, or
* authentication proofs such as tickets</li>
* </ul>
- * </p>
- * @since Android 1.0
*/
public final class Subject implements Serializable {
@@ -104,7 +102,7 @@ public final class Subject implements Serializable {
/**
* The constructor for the subject, setting its public and private
* credentials and principals according to the arguments.
- *
+ *
* @param readOnly
* {@code true} if this {@code Subject} is read-only, thus
* preventing any modifications to be done.
@@ -135,7 +133,7 @@ public final class Subject implements Serializable {
/**
* Runs the code defined by {@code action} using the permissions granted to
* the {@code Subject} itself and to the code as well.
- *
+ *
* @param subject
* the distinguished {@code Subject}.
* @param action
@@ -154,7 +152,7 @@ public final class Subject implements Serializable {
* Run the code defined by {@code action} using the permissions granted to
* the {@code Subject} and to the code itself, additionally providing a more
* specific context.
- *
+ *
* @param subject
* the distinguished {@code Subject}.
* @param action
@@ -209,7 +207,7 @@ public final class Subject implements Serializable {
/**
* Runs the code defined by {@code action} using the permissions granted to
* the subject and to the code itself.
- *
+ *
* @param subject
* the distinguished {@code Subject}.
* @param action
@@ -231,7 +229,7 @@ public final class Subject implements Serializable {
* Runs the code defined by {@code action} using the permissions granted to
* the subject and to the code itself, additionally providing a more
* specific context.
- *
+ *
* @param subject
* the distinguished {@code Subject}.
* @param action
@@ -290,7 +288,7 @@ public final class Subject implements Serializable {
* Checks two Subjects for equality. More specifically if the principals,
* public and private credentials are equal, equality for two {@code
* Subjects} is implied.
- *
+ *
* @param obj
* the {@code Object} checked for equality with this {@code
* Subject}.
@@ -320,18 +318,18 @@ public final class Subject implements Serializable {
/**
* Returns this {@code Subject}'s {@link Principal}.
- *
+ *
* @return this {@code Subject}'s {@link Principal}.
*/
public Set<Principal> getPrincipals() {
return principals;
}
-
+
/**
* Returns this {@code Subject}'s {@link Principal} which is a subclass of
* the {@code Class} provided.
- *
+ *
* @param c
* the {@code Class} as a criteria which the {@code Principal}
* returned must satisfy.
@@ -345,7 +343,7 @@ public final class Subject implements Serializable {
/**
* Returns the private credentials associated with this {@code Subject}.
- *
+ *
* @return the private credentials associated with this {@code Subject}.
*/
public Set<Object> getPrivateCredentials() {
@@ -355,7 +353,7 @@ public final class Subject implements Serializable {
/**
* Returns this {@code Subject}'s private credentials which are a subclass
* of the {@code Class} provided.
- *
+ *
* @param c
* the {@code Class} as a criteria which the private credentials
* returned must satisfy.
@@ -369,18 +367,18 @@ public final class Subject implements Serializable {
/**
* Returns the public credentials associated with this {@code Subject}.
- *
+ *
* @return the public credentials associated with this {@code Subject}.
*/
public Set<Object> getPublicCredentials() {
return publicCredentials;
}
-
+
/**
* Returns this {@code Subject}'s public credentials which are a subclass of
* the {@code Class} provided.
- *
+ *
* @param c
* the {@code Class} as a criteria which the public credentials
* returned must satisfy.
@@ -394,7 +392,7 @@ public final class Subject implements Serializable {
/**
* Returns a hash code of this {@code Subject}.
- *
+ *
* @return a hash code of this {@code Subject}.
*/
@Override
@@ -417,7 +415,7 @@ public final class Subject implements Serializable {
/**
* Returns whether this {@code Subject} is read-only or not.
- *
+ *
* @return whether this {@code Subject} is read-only or not.
*/
public boolean isReadOnly() {
@@ -426,7 +424,7 @@ public final class Subject implements Serializable {
/**
* Returns a {@code String} representation of this {@code Subject}.
- *
+ *
* @return a {@code String} representation of this {@code Subject}.
*/
@Override
@@ -479,7 +477,7 @@ public final class Subject implements Serializable {
/**
* Returns the {@code Subject} that was last associated with the {@code
* context} provided as argument.
- *
+ *
* @param context
* the {@code context} that was associated with the
* {@code Subject}.
@@ -781,4 +779,4 @@ public final class Subject implements Serializable {
}
}
}
-}
+} \ No newline at end of file
diff --git a/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java b/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java
index 6a8f00b..4b91084 100644
--- a/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java
+++ b/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java
@@ -25,8 +25,6 @@ import java.util.Set;
/**
* Merges permissions based on code source and code signers with permissions
* granted to the specified {@link Subject}.
- *
- * @since Android 1.0
*/
public class SubjectDomainCombiner implements DomainCombiner {
@@ -39,7 +37,7 @@ public class SubjectDomainCombiner implements DomainCombiner {
/**
* Creates a domain combiner for the entity provided in {@code subject}.
- *
+ *
* @param subject
* the entity to which this domain combiner is associated.
*/
@@ -53,7 +51,7 @@ public class SubjectDomainCombiner implements DomainCombiner {
/**
* Returns the entity to which this domain combiner is associated.
- *
+ *
* @return the entity to which this domain combiner is associated.
*/
public Subject getSubject() {
@@ -68,7 +66,7 @@ public class SubjectDomainCombiner implements DomainCombiner {
/**
* Merges the {@code ProtectionDomain} with the {@code Principal}s
* associated with the subject of this {@code SubjectDomainCombiner}.
- *
+ *
* @param currentDomains
* the {@code ProtectionDomain}s associated with the context of
* the current thread. The domains must be sorted according to
diff --git a/auth/src/main/java/javax/security/auth/callback/Callback.java b/auth/src/main/java/javax/security/auth/callback/Callback.java
index 6cf46b8..4854d3f 100644
--- a/auth/src/main/java/javax/security/auth/callback/Callback.java
+++ b/auth/src/main/java/javax/security/auth/callback/Callback.java
@@ -20,8 +20,6 @@ package javax.security.auth.callback;
/**
* Defines an empty base interface for all {@code Callback}s used during
* authentication.
- *
- * @since Android 1.0
*/
public interface Callback {
} \ No newline at end of file
diff --git a/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java b/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java
index 952b81a..21bf30b 100644
--- a/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java
+++ b/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java
@@ -27,8 +27,6 @@ import java.io.IOException;
* also possible to configure a system-default {@code CallbackHandler} by
* setting the {@code auth.login.defaultCallbackHandler} property in the
* standard {@code security.properties} file.
- *
- * @since Android 1.0
*/
public interface CallbackHandler {
@@ -42,7 +40,7 @@ public interface CallbackHandler {
* values. If a {@code CallbackHandler} is not able to handle a specific
* {@code Callback}, it needs to throw an
* {@link UnsupportedCallbackException}.
- *
+ *
* @param callbacks
* the array of {@code Callback}s that need handling
* @throws IOException
diff --git a/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java b/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java
index 00020fe..3617b75 100644
--- a/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java
+++ b/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java
@@ -25,8 +25,6 @@ import org.apache.harmony.auth.internal.nls.Messages;
/**
* Is used in conjunction with a {@link CallbackHandler} to retrieve a password
* when needed.
- *
- * @since Android 1.0
*/
public class PasswordCallback implements Callback, Serializable {
@@ -47,7 +45,7 @@ public class PasswordCallback implements Callback, Serializable {
/**
* Creates a new {@code PasswordCallback} instance.
- *
+ *
* @param prompt
* the message that should be displayed to the user
* @param echoOn
@@ -62,7 +60,7 @@ public class PasswordCallback implements Callback, Serializable {
/**
* Returns the prompt that was specified when creating this {@code
* PasswordCallback}
- *
+ *
* @return the prompt
*/
public String getPrompt() {
@@ -72,7 +70,7 @@ public class PasswordCallback implements Callback, Serializable {
/**
* Queries whether this {@code PasswordCallback} expects user input to be
* echoed, which is specified during the creation of the object.
- *
+ *
* @return {@code true} if (and only if) user input should be echoed
*/
public boolean isEchoOn() {
@@ -83,7 +81,7 @@ public class PasswordCallback implements Callback, Serializable {
* Sets the password. The {@link CallbackHandler} that performs the actual
* provisioning or input of the password needs to call this method to hand
* back the password to the security service that requested it.
- *
+ *
* @param password
* the password. A copy of this is stored, so subsequent changes
* to the input array do not affect the {@code PasswordCallback}.
@@ -101,7 +99,7 @@ public class PasswordCallback implements Callback, Serializable {
* Returns the password. The security service that needs the password
* usually calls this method once the {@link CallbackHandler} has finished
* its work.
- *
+ *
* @return the password. A copy of the internal password is created and
* returned, so subsequent changes to the internal password do not
* affect the result.
diff --git a/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java b/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java
index d40ff45..bee7bd3 100644
--- a/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java
+++ b/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java
@@ -20,8 +20,6 @@ package javax.security.auth.callback;
/**
* Thrown when a {@link CallbackHandler} does not support a particular {@link
* Callback}.
- *
- * @since Android 1.0
*/
public class UnsupportedCallbackException extends Exception {
@@ -32,7 +30,7 @@ public class UnsupportedCallbackException extends Exception {
/**
* Creates a new exception instance and initializes it with just the
* unsupported {@code Callback}, but no error message.
- *
+ *
* @param callback
* the {@code Callback}
*/
@@ -44,7 +42,7 @@ public class UnsupportedCallbackException extends Exception {
/**
* Creates a new exception instance and initializes it with both the
* unsupported {@code Callback} and an error message.
- *
+ *
* @param callback
* the {@code Callback}
* @param message
@@ -57,7 +55,7 @@ public class UnsupportedCallbackException extends Exception {
/**
* Returns the unsupported {@code Callback} that triggered this exception.
- *
+ *
* @return the {@code Callback}
*/
public Callback getCallback() {
diff --git a/auth/src/main/java/javax/security/auth/login/LoginException.java b/auth/src/main/java/javax/security/auth/login/LoginException.java
index a1d6ec0..9433c43 100644
--- a/auth/src/main/java/javax/security/auth/login/LoginException.java
+++ b/auth/src/main/java/javax/security/auth/login/LoginException.java
@@ -21,8 +21,6 @@ import java.security.GeneralSecurityException;
/**
* Base class for exceptions that are thrown when a login error occurs.
- *
- * @since Android 1.0
*/
public class LoginException extends GeneralSecurityException {
@@ -37,7 +35,7 @@ public class LoginException extends GeneralSecurityException {
/**
* Creates a new exception instance and initializes it with a given message.
- *
+ *
* @param message the error message
*/
public LoginException(String message) {
diff --git a/auth/src/main/java/javax/security/auth/x500/X500Principal.java b/auth/src/main/java/javax/security/auth/x500/X500Principal.java
index fa9dfe8..41f3a6d 100644
--- a/auth/src/main/java/javax/security/auth/x500/X500Principal.java
+++ b/auth/src/main/java/javax/security/auth/x500/X500Principal.java
@@ -29,13 +29,11 @@ import org.apache.harmony.security.x501.Name;
/**
* Represents an X.500 principal, which holds the distinguished name of some
- * network entity. An example of a distinguished name is {@code "O=Google,
- * OU=Android, C=US"}. The class can be instantiated from a byte representation
+ * network entity. An example of a distinguished name is {@code "O=SomeOrg,
+ * OU=SomeOrgUnit, C=US"}. The class can be instantiated from a byte representation
* of an object identifier (OID), an ASN.1 DER-encoded version, or a simple
* string holding the distinguished name. The representations must follow either
* RFC 2253, RFC 1779, or RFC2459.
- *
- * @since Android 1.0
*/
public final class X500Principal implements Serializable, Principal {
@@ -65,10 +63,10 @@ public final class X500Principal implements Serializable, Principal {
/**
* Creates a new X500Principal from a given ASN.1 DER encoding of a
* distinguished name.
- *
+ *
* @param name
* the ASN.1 DER-encoded distinguished name
- *
+ *
* @throws IllegalArgumentException
* if the ASN.1 DER-encoded distinguished name is incorrect
*/
@@ -91,11 +89,11 @@ public final class X500Principal implements Serializable, Principal {
/**
* Creates a new X500Principal from a given ASN.1 DER encoding of a
* distinguished name.
- *
+ *
* @param in
* an {@code InputStream} holding the ASN.1 DER-encoded
* distinguished name
- *
+ *
* @throws IllegalArgumentException
* if the ASN.1 DER-encoded distinguished name is incorrect
*/
@@ -118,10 +116,10 @@ public final class X500Principal implements Serializable, Principal {
/**
* Creates a new X500Principal from a string representation of a
* distinguished name.
- *
+ *
* @param name
* the string representation of the distinguished name
- *
+ *
* @throws IllegalArgumentException
* if the string representation of the distinguished name is
* incorrect
@@ -155,8 +153,8 @@ public final class X500Principal implements Serializable, Principal {
/**
* Returns an ASN.1 DER-encoded representation of the distinguished name
- * contained in this X.500 principal.
- *
+ * contained in this X.500 principal.
+ *
* @return the ASN.1 DER-encoded representation
*/
public byte[] getEncoded() {
@@ -167,9 +165,9 @@ public final class X500Principal implements Serializable, Principal {
}
/**
- * Returns a human-readable string representation of the distinguished name
+ * Returns a human-readable string representation of the distinguished name
* contained in this X.500 principal.
- *
+ *
* @return the string representation
*/
public String getName() {
@@ -185,12 +183,12 @@ public final class X500Principal implements Serializable, Principal {
* some canonicalizing operations like removing leading and trailing
* whitespace, lower-casing the whole name, and bringing it into a
* normalized Unicode representation.
- *
+ *
* @param format
* the name of the format to use for the representation
- *
+ *
* @return the string representation
- *
+ *
* @throws IllegalArgumentException
* if the {@code format} argument is not one of the three
* mentioned above
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index da51e45..00de314 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -38,11 +38,13 @@ public final class DexFile {
/**
* Opens a DEX file from a given File object. This will usually be a ZIP/JAR
- * file with a "classes.dex" inside. The method should not be used for files
- * inside the Dalvik cache.
- *
- * @cts What will happen if we refer to the Dalvik cache? Should be either
- * specified or throw an exception...
+ * file with a "classes.dex" inside.
+ *
+ * The VM will generate the name of the coresponding file in
+ * /data/dalvik-cache and open it, possibly creating or updating
+ * it first if system permissions allow. Don't pass in the name of
+ * a file in /data/dalvik-cache, as the named file is expected to be
+ * in its original (pre-dexopt) state.
*
* @param file
* the File object referencing the actual DEX file
@@ -57,11 +59,13 @@ public final class DexFile {
/**
* Opens a DEX file from a given filename. This will usually be a ZIP/JAR
- * file with a "classes.dex" inside. The method should not be used for files
- * inside the Dalvik cache.
- *
- * @cts What will happen if we refer to the Dalvik cache? Should be either
- * specified or throw an exception...
+ * file with a "classes.dex" inside.
+ *
+ * The VM will generate the name of the coresponding file in
+ * /data/dalvik-cache and open it, possibly creating or updating
+ * it first if system permissions allow. Don't pass in the name of
+ * a file in /data/dalvik-cache, as the named file is expected to be
+ * in its original (pre-dexopt) state.
*
* @param fileName
* the filename of the DEX file
@@ -190,11 +194,23 @@ public final class DexFile {
* @cts Exception comment is a bit cryptic. What exception will be thrown?
*/
public Class loadClass(String name, ClassLoader loader) {
+ String slashName = name.replace('.', '/');
+ return loadClassBinaryName(slashName, loader);
+ }
+
+ /**
+ * See {@link #loadClass(String, ClassLoader)}.
+ *
+ * This takes a "binary" class name to better match ClassLoader semantics.
+ *
+ * {@hide}
+ */
+ public Class loadClassBinaryName(String name, ClassLoader loader) {
return defineClass(name, loader, mCookie,
null);
//new ProtectionDomain(name) /*DEBUG ONLY*/);
}
-
+
native private static Class defineClass(String name, ClassLoader loader,
int cookie, ProtectionDomain pd);
diff --git a/dalvik/src/main/java/dalvik/system/PathClassLoader.java b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
index c80aef8..597eb5b 100644
--- a/dalvik/src/main/java/dalvik/system/PathClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
@@ -56,8 +56,8 @@ public class PathClassLoader extends ClassLoader {
/**
* Creates a {@code PathClassLoader} that operates on a given list of files
* and directories. This method is equivalent to calling
- * {@link #PathClassLoader(String, String, ClassLoader) with a {@code null}
- * value for the second argument (see description there).
+ * {@link #PathClassLoader(String, String, ClassLoader)} with a
+ * {@code null} value for the second argument (see description there).
*
* @param path
* the list of files and directories
@@ -179,8 +179,9 @@ public class PathClassLoader extends ClassLoader {
* parent ClassLoader has failed to find a loaded class of the same name.
*
* @param name
- * The name of the class to search for, in a human-readable form
- * like "java.lang.String" or "java.net.URLClassLoader$3$1".
+ * The "binary name" of the class to search for, in a
+ * human-readable form like "java.lang.String" or
+ * "java.net.URLClassLoader$3$1".
* @return the {@link Class} object representing the class
* @throws ClassNotFoundException
* if the class cannot be found
@@ -199,8 +200,7 @@ public class PathClassLoader extends ClassLoader {
//System.out.println("My path is: " + mPaths[i]);
if (mDexs[i] != null) {
- String slashName = name.replace('.', '/');
- Class clazz = mDexs[i].loadClass(slashName, this);
+ Class clazz = mDexs[i].loadClassBinaryName(name, this);
if (clazz != null)
return clazz;
} else if (mZips[i] != null) {
diff --git a/dalvik/src/main/java/dalvik/system/VMDebug.java b/dalvik/src/main/java/dalvik/system/VMDebug.java
index efc25d6..06a67b6 100644
--- a/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -275,6 +275,13 @@ public final class VMDebug {
*/
public static native void dumpHprofData(String fileName) throws IOException;
+ /**
+ * Primes the register map cache.
+ *
+ * @hide
+ */
+ public static native boolean cacheRegisterMap(String classAndMethodDesc);
+
/* don't ask */
static native void printThis(Object thisThing, int count, int thing);
diff --git a/icu/src/main/native/DecimalFormatInterface.cpp b/icu/src/main/native/DecimalFormatInterface.cpp
index 6221826..7e37d6c 100644
--- a/icu/src/main/native/DecimalFormatInterface.cpp
+++ b/icu/src/main/native/DecimalFormatInterface.cpp
@@ -15,6 +15,7 @@
* the VM-specific behavior isolated in VMThread.
*/
+#define LOG_TAG "DecimalFormatInterface"
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
#include "unicode/unum.h"
@@ -28,7 +29,6 @@
#include <string.h>
#include "cutils/log.h"
-#define LOG_TAG "DecimalFormatInterface"
static UBool icuError(JNIEnv *env, UErrorCode errorcode)
{
diff --git a/icu/src/main/native/ResourceInterface.cpp b/icu/src/main/native/ResourceInterface.cpp
index 5f9d442..a88e15c 100644
--- a/icu/src/main/native/ResourceInterface.cpp
+++ b/icu/src/main/native/ResourceInterface.cpp
@@ -943,7 +943,7 @@ static jobjectArray getContentImpl(JNIEnv* env, jclass clazz,
- jclass obj_class = env->FindClass("java/lang/Object");
+ jclass obj_class = env->FindClass("[Ljava/lang/Object;");
jclass integer_class = env->FindClass("java/lang/Integer");
jmethodID integerInit = env->GetMethodID(integer_class, "<init>", "(I)V");
jobjectArray result;
@@ -1207,7 +1207,8 @@ endOfCalendar:
intCurrencySymbol = env->NewStringUTF("XXX");
}
if(currencySymbol == NULL) {
- currencySymbol = env->NewStringUTF("\u00a4");
+ // creating a new string explicitly with the UTF-8 encoding of "\u00a4"
+ currencySymbol = env->NewStringUTF("\xc2\xa4");
}
counter += 2;
diff --git a/logging/src/main/java/java/util/logging/ConsoleHandler.java b/logging/src/main/java/java/util/logging/ConsoleHandler.java
index a88cf0c..ef365ca 100644
--- a/logging/src/main/java/java/util/logging/ConsoleHandler.java
+++ b/logging/src/main/java/java/util/logging/ConsoleHandler.java
@@ -38,19 +38,13 @@ package java.util.logging;
* handler will use to encode log messages, defaults to {@code null} if this
* property is not found or has an invalid value.
* </ul>
- * </p>
* <p>
* This class is not thread-safe.
- * </p>
- *
- * @since Android 1.0
*/
public class ConsoleHandler extends StreamHandler {
/**
* Constructs a {@code ConsoleHandler} object.
- *
- * @since Android 1.0
*/
public ConsoleHandler() {
super(System.err);
@@ -58,8 +52,6 @@ public class ConsoleHandler extends StreamHandler {
/**
* Closes this handler. The {@code System.err} is flushed but not closed.
- *
- * @since Android 1.0
*/
@Override
public void close() {
@@ -68,16 +60,13 @@ public class ConsoleHandler extends StreamHandler {
/**
* Logs a record if necessary. A flush operation will be done.
- *
+ *
* @param record
* the log record to be logged.
- *
- * @since Android 1.0
*/
@Override
public void publish(LogRecord record) {
super.publish(record);
super.flush();
-
}
}
diff --git a/logging/src/main/java/java/util/logging/ErrorManager.java b/logging/src/main/java/java/util/logging/ErrorManager.java
index 6f5084c..708ddfa 100644
--- a/logging/src/main/java/java/util/logging/ErrorManager.java
+++ b/logging/src/main/java/java/util/logging/ErrorManager.java
@@ -24,51 +24,37 @@ import org.apache.harmony.logging.internal.nls.Messages;
* error that may happen during logging. {@code Handlers} should report errors
* to an {@code ErrorManager}, instead of throwing exceptions, which would
* interfere with the log issuer's execution.
- *
- * @since Android 1.0
*/
public class ErrorManager {
/**
* The error code indicating a failure that does not fit in any of the
* specific types of failures that follow.
- *
- * @since Android 1.0
*/
public static final int GENERIC_FAILURE = 0;
/**
* The error code indicating a failure when writing to an output stream.
- *
- * @since Android 1.0
*/
public static final int WRITE_FAILURE = 1;
/**
* The error code indicating a failure when flushing an output stream.
- *
- * @since Android 1.0
*/
public static final int FLUSH_FAILURE = 2;
/**
* The error code indicating a failure when closing an output stream.
- *
- * @since Android 1.0
*/
public static final int CLOSE_FAILURE = 3;
/**
* The error code indicating a failure when opening an output stream.
- *
- * @since Android 1.0
*/
public static final int OPEN_FAILURE = 4;
/**
* The error code indicating a failure when formatting the error messages.
- *
- * @since Android 1.0
*/
public static final int FORMAT_FAILURE = 5;
@@ -85,20 +71,16 @@ public class ErrorManager {
/**
* Constructs an instance of {@code ErrorManager}.
- *
- * @since Android 1.0
*/
public ErrorManager() {
super();
}
/**
- * <p>
* Reports an error using the given message, exception and error code. This
* implementation will write out the message to {@link System#err} on the
* first call and all subsequent calls are ignored. A subclass of this class
* should override this method.
- * </p>
*
* @param message
* the error message, which may be {@code null}.
@@ -108,8 +90,6 @@ public class ErrorManager {
* @param errorCode
* the error code that identifies the type of error; see the
* constant fields of this class for possible values.
- *
- * @since Android 1.0
*/
public void error(String message, Exception exception, int errorCode) {
synchronized (this) {
@@ -119,7 +99,7 @@ public class ErrorManager {
called = true;
}
System.err.println(this.getClass().getName()
- + ": " + FAILURES[errorCode]); //$NON-NLS-1$
+ + ": " + FAILURES[errorCode]); //$NON-NLS-1$
if (message != null) {
// logging.1E=Error message - {0}
System.err.println(Messages.getString("logging.1E", message)); //$NON-NLS-1$
diff --git a/logging/src/main/java/java/util/logging/FileHandler.java b/logging/src/main/java/java/util/logging/FileHandler.java
index af71a6d..e1eba9e 100644
--- a/logging/src/main/java/java/util/logging/FileHandler.java
+++ b/logging/src/main/java/java/util/logging/FileHandler.java
@@ -38,48 +38,45 @@ import org.apache.harmony.logging.internal.nls.Messages;
* When a set of files is used and a given amount of data has been written to
* one file, then this file is closed and another file is opened. The name of
* these files are generated by given name pattern, see below for details.
- * </p>
+ * When the files have all been filled the Handler returns to the first and goes
+ * through the set again.
* <p>
* By default, the I/O buffering mechanism is enabled, but when each log record
* is complete, it is flushed out.
- * </p>
* <p>
* {@code XMLFormatter} is the default formatter for {@code FileHandler}.
- * </p>
* <p>
* {@code FileHandler} reads the following {@code LogManager} properties for
* initialization; if a property is not defined or has an invalid value, a
* default value is used.
* <ul>
- * <li>java.util.logging.FileHandler.level specifies the level for this
- * {@code Handler}, defaults to {@code Level.ALL}.</li>
+ * <li>java.util.logging.FileHandler.append specifies whether this
+ * {@code FileHandler} should append onto existing files, defaults to
+ * {@code false}.</li>
+ * <li>java.util.logging.FileHandler.count specifies how many output files to
+ * rotate, defaults to 1.</li>
* <li>java.util.logging.FileHandler.filter specifies the {@code Filter} class
* name, defaults to no {@code Filter}.</li>
* <li>java.util.logging.FileHandler.formatter specifies the {@code Formatter}
* class, defaults to {@code java.util.logging.XMLFormatter}.</li>
* <li>java.util.logging.FileHandler.encoding specifies the character set
* encoding name, defaults to the default platform encoding.</li>
+ * <li>java.util.logging.FileHandler.level specifies the level for this
+ * {@code Handler}, defaults to {@code Level.ALL}.</li>
* <li>java.util.logging.FileHandler.limit specifies the maximum number of
* bytes to write to any one file, defaults to zero, which means no limit.</li>
- * <li>java.util.logging.FileHandler.count specifies how many output files to
- * rotate, defaults to 1.</li>
* <li>java.util.logging.FileHandler.pattern specifies name pattern for the
* output files. See below for details. Defaults to "%h/java%u.log".</li>
- * <li>java.util.logging.FileHandler.append specifies whether this
- * {@code FileHandler} should append onto existing files, defaults to
- * {@code false}.</li>
* </ul>
- * </p>
* <p>
* Name pattern is a string that may include some special substrings, which will
* be replaced to generate output files:
- * </p>
* <ul>
* <li>"/" represents the local pathname separator</li>
- * <li>"%t" represents the system's temporary directory</li>
+ * <li>"%g" represents the generation number to distinguish rotated logs</li>
* <li>"%h" represents the home directory of the current user, which is
* specified by "user.home" system property</li>
- * <li>"%g" represents the generation number to distinguish rotated logs</li>
+ * <li>"%t" represents the system's temporary directory</li>
* <li>"%u" represents a unique number to resolve conflicts</li>
* <li>"%%" represents the percent sign character '%'</li>
* </ul>
@@ -88,7 +85,6 @@ import org.apache.harmony.logging.internal.nls.Messages;
* follow the sequence 0, 1, 2.... If the file count is larger than one, but the
* generation field("%g") has not been specified in the pattern, then the
* generation number after a dot will be added to the end of the file name.
- * </p>
* <p>
* The "%u" unique field is used to avoid conflicts and is set to 0 at first. If
* one {@code FileHandler} tries to open the filename which is currently in use
@@ -98,8 +94,6 @@ import org.apache.harmony.logging.internal.nls.Messages;
* value will be added to the end of the filename in question immediately to the
* right of a dot. The generation of unique IDs for avoiding conflicts is only
* guaranteed to work reliably when using a local disk file system.
- * </p>
- * @since Android 1.0
*/
public class FileHandler extends StreamHandler {
@@ -150,7 +144,7 @@ public class FileHandler extends StreamHandler {
/**
* Construct a {@code FileHandler} using {@code LogManager} properties or
* their default value.
- *
+ *
* @throws IOException
* if any I/O error occurs.
* @throws SecurityException
@@ -159,7 +153,6 @@ public class FileHandler extends StreamHandler {
* handler; required permissions include
* {@code LogPermission("control")},
* {@code FilePermission("write")} etc.
- * @since Android 1.0
*/
public FileHandler() throws IOException {
init(null, null, null, null);
@@ -232,21 +225,22 @@ public class FileHandler extends StreamHandler {
setOutputStream(output);
}
+ @SuppressWarnings("nls")
private void initProperties(String p, Boolean a, Integer l, Integer c) {
- super.initProperties("ALL", null, "java.util.logging.XMLFormatter", //$NON-NLS-1$//$NON-NLS-2$
+ super.initProperties("ALL", null, "java.util.logging.XMLFormatter",
null);
String className = this.getClass().getName();
- pattern = (null == p) ? getStringProperty(className + ".pattern", //$NON-NLS-1$
+ pattern = (null == p) ? getStringProperty(className + ".pattern",
DEFAULT_PATTERN) : p;
- if (null == pattern || "".equals(pattern)) { //$NON-NLS-1$
+ if (null == pattern || "".equals(pattern)) {
// logging.19=Pattern cannot be empty
- throw new NullPointerException(Messages.getString("logging.19")); //$NON-NLS-1$
+ throw new NullPointerException(Messages.getString("logging.19"));
}
- append = (null == a) ? getBooleanProperty(className + ".append", //$NON-NLS-1$
+ append = (null == a) ? getBooleanProperty(className + ".append",
DEFAULT_APPEND) : a.booleanValue();
- count = (null == c) ? getIntProperty(className + ".count", //$NON-NLS-1$
+ count = (null == c) ? getIntProperty(className + ".count",
DEFAULT_COUNT) : c.intValue();
- limit = (null == l) ? getIntProperty(className + ".limit", //$NON-NLS-1$
+ limit = (null == l) ? getIntProperty(className + ".limit",
DEFAULT_LIMIT) : l.intValue();
count = count < 1 ? DEFAULT_COUNT : count;
limit = limit < 0 ? DEFAULT_LIMIT : limit;
@@ -279,7 +273,7 @@ public class FileHandler extends StreamHandler {
/**
* Transform the pattern to the valid file name, replacing any patterns, and
* applying generation and uniqueID if present.
- *
+ *
* @param gen
* generation of this file
* @return transformed filename ready for use.
@@ -396,9 +390,9 @@ public class FileHandler extends StreamHandler {
* Constructs a new {@code FileHandler}. The given name pattern is used as
* output filename, the file limit is set to zero (no limit), the file count
* is set to one; the remaining configuration is done using
- * {@code LogManager} properties or their default values. This handler write
- * to only one file without size limit.
- *
+ * {@code LogManager} properties or their default values. This handler
+ * writes to only one file with no size limit.
+ *
* @param pattern
* the name pattern for the output file.
* @throws IOException
@@ -413,7 +407,6 @@ public class FileHandler extends StreamHandler {
* if the pattern is empty.
* @throws NullPointerException
* if the pattern is {@code null}.
- * @since Android 1.0
*/
public FileHandler(String pattern) throws IOException {
if (pattern.equals("")) { //$NON-NLS-1$
@@ -429,9 +422,9 @@ public class FileHandler extends StreamHandler {
* output filename, the file limit is set to zero (no limit), the file count
* is initialized to one and the value of {@code append} becomes the new
* instance's append mode. The remaining configuration is done using
- * {@code LogManager} properties. This handler write to only one file
- * without size limit.
- *
+ * {@code LogManager} properties. This handler writes to only one file
+ * with no size limit.
+ *
* @param pattern
* the name pattern for the output file.
* @param append
@@ -448,11 +441,10 @@ public class FileHandler extends StreamHandler {
* if {@code pattern} is empty.
* @throws NullPointerException
* if {@code pattern} is {@code null}.
- * @since Android 1.0
*/
public FileHandler(String pattern, boolean append) throws IOException {
if (pattern.equals("")) { //$NON-NLS-1$
- throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
}
init(pattern, Boolean.valueOf(append), Integer.valueOf(DEFAULT_LIMIT),
@@ -466,7 +458,7 @@ public class FileHandler extends StreamHandler {
* is done using {@code LogManager} properties. This handler is configured
* to write to a rotating set of count files, when the limit of bytes has
* been written to one output file, another file will be opened instead.
- *
+ *
* @param pattern
* the name pattern for the output file.
* @param limit
@@ -487,11 +479,10 @@ public class FileHandler extends StreamHandler {
* {@code count < 1}.
* @throws NullPointerException
* if {@code pattern} is {@code null}.
- * @since Android 1.0
*/
public FileHandler(String pattern, int limit, int count) throws IOException {
if (pattern.equals("")) { //$NON-NLS-1$
- throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
}
if (limit < 0 || count < 1) {
// logging.1B=The limit and count property must be larger than 0 and
@@ -509,7 +500,7 @@ public class FileHandler extends StreamHandler {
* {@code LogManager} properties. This handler is configured to write to a
* rotating set of count files, when the limit of bytes has been written to
* one output file, another file will be opened instead.
- *
+ *
* @param pattern
* the name pattern for the output file.
* @param limit
@@ -532,12 +523,11 @@ public class FileHandler extends StreamHandler {
* {@code count < 1}.
* @throws NullPointerException
* if {@code pattern} is {@code null}.
- * @since Android 1.0
*/
public FileHandler(String pattern, int limit, int count, boolean append)
throws IOException {
if (pattern.equals("")) { //$NON-NLS-1$
- throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
}
if (limit < 0 || count < 1) {
// logging.1B=The limit and count property must be larger than 0 and
@@ -550,14 +540,13 @@ public class FileHandler extends StreamHandler {
/**
* Flushes and closes all opened files.
- *
+ *
* @throws SecurityException
* if a security manager exists and it determines that the
* caller does not have the required permissions to control this
* handler; required permissions include
* {@code LogPermission("control")},
* {@code FilePermission("write")} etc.
- * @since Android 1.0
*/
@Override
public void close() {
@@ -577,10 +566,9 @@ public class FileHandler extends StreamHandler {
/**
* Publish a {@code LogRecord}.
- *
+ *
* @param record
* the log record to publish.
- * @since Android 1.0
*/
@Override
public void publish(LogRecord record) {
diff --git a/logging/src/main/java/java/util/logging/Filter.java b/logging/src/main/java/java/util/logging/Filter.java
index e81f216..f5dbd9f 100644
--- a/logging/src/main/java/java/util/logging/Filter.java
+++ b/logging/src/main/java/java/util/logging/Filter.java
@@ -20,8 +20,6 @@ package java.util.logging;
/**
* A {@code Filter} provides a mechanism for exercising fine-grained control
* over which records get logged.
- *
- * @since Android 1.0
*/
public interface Filter {
@@ -32,7 +30,6 @@ public interface Filter {
* the {@link LogRecord} to be checked.
* @return {@code true} if the supplied log record needs to be logged,
* {@code false} otherwise.
- * @since Android 1.0
*/
boolean isLoggable(LogRecord record);
}
diff --git a/logging/src/main/java/java/util/logging/Formatter.java b/logging/src/main/java/java/util/logging/Formatter.java
index 2941c24..f9b0d25 100644
--- a/logging/src/main/java/java/util/logging/Formatter.java
+++ b/logging/src/main/java/java/util/logging/Formatter.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.text.MessageFormat;
@@ -26,41 +25,24 @@ import java.util.ResourceBundle;
* string representation. Head and tail strings are sometimes used to wrap a set
* of records. The {@code getHead} and {@code getTail} methods are used for this
* purpose.
- *
- * @since Android 1.0
*/
public abstract class Formatter {
- /*
- * -------------------------------------------------------------------
- * Constructors
- * -------------------------------------------------------------------
- */
-
/**
* Constructs a {@code Formatter} object.
- *
- * @since Android 1.0
*/
protected Formatter() {
super();
}
- /*
- * -------------------------------------------------------------------
- * Methods
- * -------------------------------------------------------------------
- */
-
/**
* Converts a {@link LogRecord} object into a string representation. The
* resulted string is usually localized and includes the message field of
* the record.
- *
+ *
* @param r
* the log record to be formatted into a string.
* @return the formatted string.
- * @since Android 1.0
*/
public abstract String format(LogRecord r);
@@ -71,16 +53,13 @@ public abstract class Formatter {
* <p>
* The message string is firstly localized using the {@code ResourceBundle}
* object associated with the supplied {@code LogRecord}.
- * </p>
* <p>
* Notice : if message contains "{0", then java.text.MessageFormat is used.
* Otherwise no formatting is performed.
- * </p>
- *
+ *
* @param r
* the log record to be formatted.
* @return the string resulted from the formatting.
- * @since Android 1.0
*/
public String formatMessage(LogRecord r) {
String pattern = r.getMessage();
@@ -114,14 +93,12 @@ public abstract class Formatter {
/**
* Gets the head string used to wrap a set of log records. This base class
* always returns an empty string.
- *
+ *
* @param h
* the target handler.
* @return the head string used to wrap a set of log records, empty in this
* implementation.
- * @since Android 1.0
*/
- @SuppressWarnings("unused")
public String getHead(Handler h) {
return ""; //$NON-NLS-1$
}
@@ -129,17 +106,13 @@ public abstract class Formatter {
/**
* Gets the tail string used to wrap a set of log records. This base class
* always returns the empty string.
- *
+ *
* @param h
* the target handler.
* @return the tail string used to wrap a set of log records, empty in this
* implementation.
- * @since Android 1.0
*/
- @SuppressWarnings("unused")
public String getTail(Handler h) {
return ""; //$NON-NLS-1$
}
-
}
-
diff --git a/logging/src/main/java/java/util/logging/Handler.java b/logging/src/main/java/java/util/logging/Handler.java
index d28bce0..a5b92a0 100644
--- a/logging/src/main/java/java/util/logging/Handler.java
+++ b/logging/src/main/java/java/util/logging/Handler.java
@@ -15,13 +15,12 @@
* limitations under the License.
*/
-
package java.util.logging;
+import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
-import java.io.UnsupportedEncodingException;
import org.apache.harmony.logging.internal.nls.Messages;
@@ -29,24 +28,11 @@ import org.apache.harmony.logging.internal.nls.Messages;
* A {@code Handler} object accepts a logging request and exports the desired
* messages to a target, for example, a file, the console, etc. It can be
* disabled by setting its logging level to {@code Level.OFF}.
- *
- * @since Android 1.0
*/
public abstract class Handler {
- /*
- * -------------------------------------------------------------------
- * Constants
- * -------------------------------------------------------------------
- */
private static final Level DEFAULT_LEVEL = Level.ALL;
- /*
- * -------------------------------------------------------------------
- * Instance variables
- * -------------------------------------------------------------------
- */
-
// the error manager to report errors during logging
private ErrorManager errorMan;
@@ -65,18 +51,10 @@ public abstract class Handler {
// class name, used for property reading
private String prefix;
- /*
- * -------------------------------------------------------------------
- * Constructors
- * -------------------------------------------------------------------
- */
-
/**
* Constructs a {@code Handler} object with a default error manager instance
* {@code ErrorManager}, the default encoding, and the default logging
* level {@code Level.ALL}. It has no filter and no formatter.
- *
- * @since Android 1.0
*/
protected Handler() {
this.errorMan = new ErrorManager();
@@ -87,12 +65,6 @@ public abstract class Handler {
this.prefix = this.getClass().getName();
}
- /*
- * -------------------------------------------------------------------
- * Methods
- * -------------------------------------------------------------------
- */
-
// get a instance from given class name, using Class.forName()
private Object getDefaultInstance(String className) {
Object result = null;
@@ -102,7 +74,7 @@ public abstract class Handler {
try {
result = Class.forName(className).newInstance();
} catch (Exception e) {
- //ignore
+ // ignore
}
return result;
}
@@ -110,7 +82,8 @@ public abstract class Handler {
// get a instance from given class name, using context classloader
private Object getCustomizeInstance(final String className)
throws Exception {
- Class<?> c = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
+ Class<?> c = AccessController
+ .doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws Exception {
ClassLoader loader = Thread.currentThread()
.getContextClassLoader();
@@ -126,22 +99,22 @@ public abstract class Handler {
// print error message in some format
void printInvalidPropMessage(String key, String value, Exception e) {
// logging.12=Invalid property value for
- String msg = new StringBuilder().append(Messages.getString("logging.12")) //$NON-NLS-1$
+ String msg = new StringBuilder().append(
+ Messages.getString("logging.12")) //$NON-NLS-1$
.append(prefix).append(":").append(key).append("/").append( //$NON-NLS-1$//$NON-NLS-2$
value).toString();
errorMan.error(msg, e, ErrorManager.GENERIC_FAILURE);
}
- /*
+ /**
* init the common properties, including filter, level, formatter, and
* encoding
*/
- @SuppressWarnings("unused")
void initProperties(String defaultLevel, String defaultFilter,
String defaultFormatter, String defaultEncoding) {
LogManager manager = LogManager.getLogManager();
- //set filter
+ // set filter
final String filterName = manager.getProperty(prefix + ".filter"); //$NON-NLS-1$
if (null != filterName) {
try {
@@ -154,7 +127,7 @@ public abstract class Handler {
filter = (Filter) getDefaultInstance(defaultFilter);
}
- //set level
+ // set level
String levelName = manager.getProperty(prefix + ".level"); //$NON-NLS-1$
if (null != levelName) {
try {
@@ -167,7 +140,7 @@ public abstract class Handler {
level = Level.parse(defaultLevel);
}
- //set formatter
+ // set formatter
final String formatterName = manager.getProperty(prefix + ".formatter"); //$NON-NLS-1$
if (null != formatterName) {
try {
@@ -180,7 +153,7 @@ public abstract class Handler {
formatter = (Formatter) getDefaultInstance(defaultFormatter);
}
- //set encoding
+ // set encoding
final String encodingName = manager.getProperty(prefix + ".encoding"); //$NON-NLS-1$
try {
internalSetEncoding(encodingName);
@@ -193,37 +166,31 @@ public abstract class Handler {
* Closes this handler. A flush operation will be performed and all the
* associated resources will be freed. Client applications should not use
* this handler after closing it.
- *
+ *
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- *
- * @since Android 1.0
*/
public abstract void close();
/**
* Flushes any buffered output.
- *
- * @since Android 1.0
*/
public abstract void flush();
/**
* Accepts a logging request and sends it to the the target.
- *
+ *
* @param record
* the log record to be logged; {@code null} records are ignored.
- * @since Android 1.0
*/
public abstract void publish(LogRecord record);
/**
* Gets the character encoding used by this handler, {@code null} for
* default encoding.
- *
+ *
* @return the character encoding used by this handler.
- * @since Android 1.0
*/
public String getEncoding() {
return this.encoding;
@@ -232,12 +199,11 @@ public abstract class Handler {
/**
* Gets the error manager used by this handler to report errors during
* logging.
- *
+ *
* @return the error manager used by this handler.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public ErrorManager getErrorManager() {
LogManager.getLogManager().checkAccess();
@@ -246,9 +212,8 @@ public abstract class Handler {
/**
* Gets the filter used by this handler.
- *
+ *
* @return the filter used by this handler (possibly {@code null}).
- * @since Android 1.0
*/
public Filter getFilter() {
return this.filter;
@@ -256,9 +221,8 @@ public abstract class Handler {
/**
* Gets the formatter used by this handler to format the logging messages.
- *
+ *
* @return the formatter used by this handler (possibly {@code null}).
- * @since Android 1.0
*/
public Formatter getFormatter() {
return this.formatter;
@@ -267,9 +231,8 @@ public abstract class Handler {
/**
* Gets the logging level of this handler, records with levels lower than
* this value will be dropped.
- *
+ *
* @return the logging level of this handler.
- * @since Android 1.0
*/
public Level getLevel() {
return this.level;
@@ -278,12 +241,11 @@ public abstract class Handler {
/**
* Determines whether the supplied log record needs to be logged. The
* logging levels will be checked as well as the filter.
- *
+ *
* @param record
* the log record to be checked.
* @return {@code true} if the supplied log record needs to be logged,
* otherwise {@code false}.
- * @since Android 1.0
*/
public boolean isLoggable(LogRecord record) {
if (null == record) {
@@ -302,14 +264,13 @@ public abstract class Handler {
* {@code ErrorManager} is used for that purpose. No security checks are
* done, therefore this is compatible with environments where the caller
* is non-privileged.
- *
+ *
* @param msg
* the error message, may be {@code null}.
* @param ex
* the associated exception, may be {@code null}.
* @param code
* an {@code ErrorManager} error code.
- * @since Android 1.0
*/
protected void reportError(String msg, Exception ex, int code) {
this.errorMan.error(msg, ex, code);
@@ -319,12 +280,11 @@ public abstract class Handler {
* Sets the character encoding used by this handler. A {@code null} value
* indicates the use of the default encoding. This internal method does
* not check security.
- *
+ *
* @param newEncoding
* the character encoding to set.
* @throws UnsupportedEncodingException
* if the specified encoding is not supported by the runtime.
- * @since Android 1.0
*/
void internalSetEncoding(String newEncoding)
throws UnsupportedEncodingException {
@@ -347,7 +307,7 @@ public abstract class Handler {
/**
* Sets the character encoding used by this handler, {@code null} indicates
* a default encoding.
- *
+ *
* @param encoding
* the character encoding to set.
* @throws SecurityException
@@ -355,7 +315,6 @@ public abstract class Handler {
* have the required permission.
* @throws UnsupportedEncodingException
* if the specified encoding is not supported by the runtime.
- * @since Android 1.0
*/
public void setEncoding(String encoding) throws SecurityException,
UnsupportedEncodingException {
@@ -365,7 +324,7 @@ public abstract class Handler {
/**
* Sets the error manager for this handler.
- *
+ *
* @param em
* the error manager to set.
* @throws NullPointerException
@@ -373,7 +332,6 @@ public abstract class Handler {
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setErrorManager(ErrorManager em) {
LogManager.getLogManager().checkAccess();
@@ -385,13 +343,12 @@ public abstract class Handler {
/**
* Sets the filter to be used by this handler.
- *
+ *
* @param newFilter
* the filter to set, may be {@code null}.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setFilter(Filter newFilter) {
LogManager.getLogManager().checkAccess();
@@ -401,7 +358,7 @@ public abstract class Handler {
/**
* Sets the formatter to be used by this handler. This internal method does
* not check security.
- *
+ *
* @param newFormatter
* the formatter to set.
*/
@@ -414,7 +371,7 @@ public abstract class Handler {
/**
* Sets the formatter to be used by this handler.
- *
+ *
* @param newFormatter
* the formatter to set.
* @throws NullPointerException
@@ -422,7 +379,6 @@ public abstract class Handler {
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setFormatter(Formatter newFormatter) {
LogManager.getLogManager().checkAccess();
@@ -432,7 +388,7 @@ public abstract class Handler {
/**
* Sets the logging level of the messages logged by this handler, levels
* lower than this value will be dropped.
- *
+ *
* @param newLevel
* the logging level to set.
* @throws NullPointerException
@@ -440,7 +396,6 @@ public abstract class Handler {
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setLevel(Level newLevel) {
if (null == newLevel) {
@@ -450,4 +405,3 @@ public abstract class Handler {
this.level = newLevel;
}
}
-
diff --git a/logging/src/main/java/java/util/logging/Level.java b/logging/src/main/java/java/util/logging/Level.java
index 32ba017..f988127 100644
--- a/logging/src/main/java/java/util/logging/Level.java
+++ b/logging/src/main/java/java/util/logging/Level.java
@@ -41,8 +41,6 @@ import dalvik.system.VMStack;
* INFO, WARNING, SEVERE. There are two additional predefined levels, which are
* ALL and OFF. ALL indicates logging all messages, and OFF indicates logging no
* messages.
- * </p>
- * @since Android 1.0
*/
public class Level implements Serializable {
@@ -52,70 +50,52 @@ public class Level implements Serializable {
/**
* The OFF level provides no logging messages.
- *
- * @since Android 1.0
*/
public static final Level OFF = new Level("OFF", Integer.MAX_VALUE); //$NON-NLS-1$
/**
* The SEVERE level provides severe failure messages.
- *
- * @since Android 1.0
*/
public static final Level SEVERE = new Level("SEVERE", 1000); //$NON-NLS-1$
/**
* The WARNING level provides warnings.
- *
- * @since Android 1.0
*/
public static final Level WARNING = new Level("WARNING", 900); //$NON-NLS-1$
/**
* The INFO level provides informative messages.
- *
- * @since Android 1.0
*/
public static final Level INFO = new Level("INFO", 800); //$NON-NLS-1$
/**
* The CONFIG level provides static configuration messages.
- *
- * @since Android 1.0
*/
public static final Level CONFIG = new Level("CONFIG", 700); //$NON-NLS-1$
/**
* The FINE level provides tracing messages.
- *
- * @since Android 1.0
*/
public static final Level FINE = new Level("FINE", 500); //$NON-NLS-1$
/**
* The FINER level provides more detailed tracing messages.
- *
- * @since Android 1.0
*/
public static final Level FINER = new Level("FINER", 400); //$NON-NLS-1$
/**
* The FINEST level provides highly detailed tracing messages.
- *
- * @since Android 1.0
*/
public static final Level FINEST = new Level("FINEST", 300); //$NON-NLS-1$
/**
* The ALL level provides all logging messages.
- *
- * @since Android 1.0
*/
public static final Level ALL = new Level("ALL", Integer.MIN_VALUE); //$NON-NLS-1$
/**
* Parses a level name into a {@code Level} object.
- *
+ *
* @param name
* the name of the desired {@code level}, which cannot be
* {@code null}.
@@ -124,13 +104,8 @@ public class Level implements Serializable {
* if {@code name} is {@code null}.
* @throws IllegalArgumentException
* if {@code name} is not valid.
- * @since Android 1.0
*/
public static Level parse(String name) throws IllegalArgumentException {
- // BEGIN android-note
- // final modifier removed and IAE added to get closer to the RI
- // copied from newer version of harmony
- // END android-note
if (name == null) {
// logging.1C=The 'name' parameter is null.
throw new NullPointerException(Messages.getString("logging.1C")); //$NON-NLS-1$
@@ -155,8 +130,8 @@ public class Level implements Serializable {
if (isNameAnInt) {
/*
- * Loop through levels a second time, so that the
- * returned instance will be passed on the order of construction.
+ * Loop through levels a second time, so that the returned
+ * instance will be passed on the order of construction.
*/
for (Level level : levels) {
if (nameAsInt == level.intValue()) {
@@ -168,7 +143,8 @@ public class Level implements Serializable {
if (!isNameAnInt) {
// logging.1D=Cannot parse this name: {0}
- throw new IllegalArgumentException(Messages.getString("logging.1D", name)); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString(
+ "logging.1D", name)); //$NON-NLS-1$
}
return new Level(name, nameAsInt);
@@ -176,21 +152,21 @@ public class Level implements Serializable {
/**
* The name of this Level.
- *
+ *
* @serial
*/
private final String name;
/**
* The integer value indicating the level.
- *
+ *
* @serial
*/
private final int value;
/**
* The name of the resource bundle used to localize the level name.
- *
+ *
* @serial
*/
private final String resourceBundleName;
@@ -204,14 +180,13 @@ public class Level implements Serializable {
/**
* Constructs an instance of {@code Level} taking the supplied name and
* level value.
- *
+ *
* @param name
* the name of the level.
* @param level
* an integer value indicating the level.
* @throws NullPointerException
* if {@code name} is {@code null}.
- * @since Android 1.0
*/
protected Level(String name, int level) {
this(name, level, null);
@@ -220,7 +195,7 @@ public class Level implements Serializable {
/**
* Constructs an instance of {@code Level} taking the supplied name, level
* value and resource bundle name.
- *
+ *
* @param name
* the name of the level.
* @param level
@@ -229,7 +204,6 @@ public class Level implements Serializable {
* the name of the resource bundle to use.
* @throws NullPointerException
* if {@code name} is {@code null}.
- * @since Android 1.0
*/
protected Level(String name, int level, String resourceBundleName) {
if (name == null) {
@@ -256,9 +230,8 @@ public class Level implements Serializable {
/**
* Gets the name of this level.
- *
+ *
* @return this level's name.
- * @since Android 1.0
*/
public String getName() {
return this.name;
@@ -266,9 +239,8 @@ public class Level implements Serializable {
/**
* Gets the name of the resource bundle associated with this level.
- *
+ *
* @return the name of this level's resource bundle.
- * @since Android 1.0
*/
public String getResourceBundleName() {
return this.resourceBundleName;
@@ -276,20 +248,17 @@ public class Level implements Serializable {
/**
* Gets the integer value indicating this level.
- *
+ *
* @return this level's integer value.
- * @since Android 1.0
*/
public final int intValue() {
return this.value;
}
/**
- * <p>
* Serialization helper method to maintain singletons and add any new
* levels.
- * </p>
- *
+ *
* @return the resolved instance.
*/
private Object readResolve() {
@@ -298,7 +267,7 @@ public class Level implements Serializable {
if (value != level.value) {
continue;
}
- if (!name.equals(name)) {
+ if (!name.equals(level.name)) {
continue;
}
if (resourceBundleName == level.resourceBundleName) {
@@ -316,7 +285,7 @@ public class Level implements Serializable {
/**
* Serialization helper to setup transient resource bundle instance.
- *
+ *
* @param in
* the input stream to read the instance data from.
* @throws IOException
@@ -324,7 +293,8 @@ public class Level implements Serializable {
* @throws ClassNotFoundException
* if a class is not found.
*/
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ private void readObject(ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
in.defaultReadObject();
if (resourceBundleName != null) {
try {
@@ -339,9 +309,8 @@ public class Level implements Serializable {
* Gets the localized name of this level. The default locale is used. If no
* resource bundle is associated with this level then the original level
* name is returned.
- *
+ *
* @return the localized name of this level.
- * @since Android 1.0
*/
public String getLocalizedName() {
if (rb == null) {
@@ -358,12 +327,11 @@ public class Level implements Serializable {
/**
* Compares two {@code Level} objects for equality. They are considered to
* be equal if they have the same level value.
- *
+ *
* @param o
* the other object to compare this level to.
* @return {@code true} if this object equals to the supplied object,
* {@code false} otherwise.
- * @since Android 1.0
*/
@Override
public boolean equals(Object o) {
@@ -380,9 +348,8 @@ public class Level implements Serializable {
/**
* Returns the hash code of this {@code Level} object.
- *
+ *
* @return this level's hash code.
- * @since Android 1.0
*/
@Override
public int hashCode() {
@@ -392,9 +359,8 @@ public class Level implements Serializable {
/**
* Returns the string representation of this {@code Level} object. In
* this case, it is the level's name.
- *
+ *
* @return the string representation of this level.
- * @since Android 1.0
*/
@Override
public final String toString() {
diff --git a/logging/src/main/java/java/util/logging/LogManager.java b/logging/src/main/java/java/util/logging/LogManager.java
index 8409b81..308daaf 100644
--- a/logging/src/main/java/java/util/logging/LogManager.java
+++ b/logging/src/main/java/java/util/logging/LogManager.java
@@ -24,6 +24,10 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+// BEGIN android-removed
+//import java.lang.management.ManagementFactory;
+//import java.lang.reflect.Method;
+// END android-removed
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
@@ -33,13 +37,11 @@ import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
+
// BEGIN android-removed
-// import java.lang.management.ManagementFactory;
-// import java.lang.reflect.Method;
-// import javax.management.MBeanServer;
-// import javax.management.ObjectName;
-// import javax.management.ObjectInstance;
-// import javax.management.MalformedObjectNameException;
+//import javax.management.MBeanServer;
+//import javax.management.ObjectInstance;
+//import javax.management.ObjectName;
// END android-removed
import org.apache.harmony.logging.internal.nls.Messages;
@@ -49,23 +51,19 @@ import org.apache.harmony.logging.internal.nls.Messages;
* logging framework, and to manage a hierarchical namespace of all named
* {@code Logger} objects.
* <p>
- *
* There is only one global {@code LogManager} instance in the
* application, which can be get by calling static method
* {@link #getLogManager()}. This instance is created and
* initialized during class initialization and cannot be changed.
- * </p>
* <p>
* The {@code LogManager} class can be specified by
* java.util.logging.manager system property, if the property is unavailable or
* invalid, the default class {@link java.util.logging.LogManager} will
* be used.
- * </p>
* <p>
- * When initialization, {@code LogManager} read its configuration from a
+ * On initialization, {@code LogManager} reads its configuration from a
* properties file, which by default is the "lib/logging.properties" in the JRE
* directory.
- * </p>
* <p>
* However, two optional system properties can be used to customize the initial
* configuration process of {@code LogManager}.
@@ -73,31 +71,26 @@ import org.apache.harmony.logging.internal.nls.Messages;
* <li>"java.util.logging.config.class"</li>
* <li>"java.util.logging.config.file"</li>
* </ul>
- * </p>
* <p>
* These two properties can be set in three ways, by the Preferences API, by the
* "java" command line property definitions, or by system property definitions
* passed to JNI_CreateJavaVM.
- * </p>
* <p>
* The "java.util.logging.config.class" should specifies a class name. If it is
* set, this given class will be loaded and instantiated during
* {@code LogManager} initialization, so that this object's default
* constructor can read the initial configuration and define properties for
* {@code LogManager}.
- * </p>
* <p>
* If "java.util.logging.config.class" property is not set, or it is invalid, or
* some exception is thrown during the instantiation, then the
* "java.util.logging.config.file" system property can be used to specify a
* properties file. The {@code LogManager} will read initial
* configuration from this file.
- * </p>
* <p>
* If neither of these properties is defined, or some exception is thrown
* during these two properties using, the {@code LogManager} will read
* its initial configuration from default properties file, as described above.
- * </p>
* <p>
* The global logging properties may include:
* <ul>
@@ -113,22 +106,18 @@ import org.apache.harmony.logging.internal.nls.Messages;
* some logger, etc. These classes will be loaded and instantiated during
* {@code LogManager} configuration</li>
* </ul>
- * </p>
* <p>
* This class, together with any handler and configuration classes associated
* with it, <b>must</b> be loaded from the system classpath when
* {@code LogManager} configuration occurs.
- * </p>
* <p>
* Besides global properties, the properties for loggers and Handlers can be
* specified in the property files. The names of these properties will start
* with the complete dot separated names for the handlers or loggers.
- * </p>
* <p>
* In the {@code LogManager}'s hierarchical namespace,
* {@code Loggers} are organized based on their dot separated names. For
* example, "x.y.z" is child of "x.y".
- * </p>
* <p>
* Levels for {@code Loggers} can be defined by properties whose name end
* with ".level". Thus "alogger.level" defines a level for the logger named as
@@ -136,23 +125,15 @@ import org.apache.harmony.logging.internal.nls.Messages;
* properties are read and applied in the same order as they are specified in
* the property file. The root logger's level can be defined by the property
* named as ".level".
- * </p>
* <p>
* All methods on this type can be taken as being thread safe.
- * </p>
- *
+ *
*/
public class LogManager {
- /*
- * -------------------------------------------------------------------
- * Class variables
- * -------------------------------------------------------------------
- */
// The line separator of the underlying OS
// Use privileged code to read the line.separator system property
- private static final String lineSeparator =
- getPrivilegedSystemProperty("line.separator"); //$NON-NLS-1$
+ private static final String lineSeparator = getPrivilegedSystemProperty("line.separator"); //$NON-NLS-1$
// The shared logging permission
private static final LoggingPermission perm = new LoggingPermission(
@@ -160,63 +141,55 @@ public class LogManager {
// the singleton instance
static LogManager manager;
-
+
/**
* The {@code String} value of the {@link LoggingMXBean}'s ObjectName.
- *
- * @since Android 1.0
*/
- public static final String LOGGING_MXBEAN_NAME =
- "java.util.logging:type=Logging"; //$NON-NLS-1$
+ public static final String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging"; //$NON-NLS-1$
/**
* Get the {@code LoggingMXBean} instance. this implementation always throws
* an UnsupportedOperationException.
- *
+ *
* @return the {@code LoggingMXBean} instance
*/
public static LoggingMXBean getLoggingMXBean() {
- // BEGIN android-added
- throw new UnsupportedOperationException();
- // END android-added
- // BEGIN android-removed
- // try {
- // ObjectName loggingMXBeanName = new ObjectName(LOGGING_MXBEAN_NAME);
- // MBeanServer platformBeanServer =
- // ManagementFactory.getPlatformMBeanServer();
- // Set loggingMXBeanSet = platformBeanServer.queryMBeans(
- // loggingMXBeanName, null);
- //
- // if (loggingMXBeanSet.size() != 1) {
- // // logging.21=There Can Be Only One logging MX bean.
- // throw new AssertionError(Messages.getString("logging.21"));
- // }
- //
- // Iterator i = loggingMXBeanSet.iterator();
- // ObjectInstance loggingMXBeanOI = (ObjectInstance) i.next();
- // String lmxbcn = loggingMXBeanOI.getClassName();
- // Class lmxbc = Class.forName(lmxbcn);
- // Method giMethod = lmxbc.getDeclaredMethod("getInstance");
- // giMethod.setAccessible(true);
- // LoggingMXBean lmxb = (LoggingMXBean)
- // giMethod.invoke(null, new Object[] {});
- //
- // return lmxb;
- // } catch (Exception e) {
- // //TODO
- // //e.printStackTrace();
- // }
- // // logging.22=Exception occurred while getting the logging MX bean.
- // throw new AssertionError(Messages.getString("logging.22")); //$NON-NLS-1$
- // END android-removed
- }
+ // BEGIN android-added
+ throw new UnsupportedOperationException();
+ // END android-added
+ // BEGIN android-removed
+ // try {
+ // ObjectName loggingMXBeanName = new ObjectName(LOGGING_MXBEAN_NAME);
+ // MBeanServer platformBeanServer = ManagementFactory
+ // .getPlatformMBeanServer();
+ // Set<?> loggingMXBeanSet = platformBeanServer.queryMBeans(
+ // loggingMXBeanName, null);
+ //
+ // if (loggingMXBeanSet.size() != 1) {
+ // // logging.21=There Can Be Only One logging MX bean.
+ // throw new AssertionError(Messages.getString("logging.21")); //$NON-NLS-1$
+ // }
+ //
+ // Iterator<?> i = loggingMXBeanSet.iterator();
+ // ObjectInstance loggingMXBeanOI = (ObjectInstance) i.next();
+ // String lmxbcn = loggingMXBeanOI.getClassName();
+ // Class<?> lmxbc = Class.forName(lmxbcn);
+ // Method giMethod = lmxbc.getDeclaredMethod("getInstance"); //$NON-NLS-1$
+ // giMethod.setAccessible(true);
+ // LoggingMXBean lmxb = (LoggingMXBean) giMethod.invoke(null,
+ // new Object[] {});
+ //
+ // return lmxb;
+ // } catch (Exception e) {
+ // // TODO
+ // // e.printStackTrace();
+ // }
+ // // logging.22=Exception occurred while getting the logging MX bean.
+ // throw new AssertionError(Messages.getString("logging.22")); //$NON-NLS-1$
+ // END android-removed
+ }
- /*
- * -------------------------------------------------------------------
- * Instance variables
- * -------------------------------------------------------------------
- */
- //FIXME: use weak reference to avoid heap memory leak
+ // FIXME: use weak reference to avoid heap memory leak
private Hashtable<String, Logger> loggers;
// the configuration properties
@@ -225,19 +198,13 @@ public class LogManager {
// the property change listener
private PropertyChangeSupport listeners;
- /*
- * -------------------------------------------------------------------
- * Global initialization
- * -------------------------------------------------------------------
- */
-
static {
// init LogManager singleton instance
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
- String className = System.getProperty(
- "java.util.logging.manager"); //$NON-NLS-1$
-
+ String className = System
+ .getProperty("java.util.logging.manager"); //$NON-NLS-1$
+
if (null != className) {
manager = (LogManager) getInstanceByClass(className);
}
@@ -256,7 +223,7 @@ public class LogManager {
Logger root = new Logger("", null); //$NON-NLS-1$
root.setLevel(Level.INFO);
Logger.global.setParent(root);
-
+
manager.addLogger(root);
manager.addLogger(Logger.global);
return null;
@@ -290,11 +257,6 @@ public class LogManager {
}
/*
- * -------------------------------------------------------------------
- * Methods
- * -------------------------------------------------------------------
- */
- /*
* Package private utilities Returns the line separator of the underlying
* OS.
*/
@@ -307,7 +269,7 @@ public class LogManager {
* that it is trusted to modify the configuration for logging framework. If
* the check passes, just return, otherwise {@code SecurityException}
* will be thrown.
- *
+ *
* @throws SecurityException
* if there is a security manager in operation and the invoker
* of this method does not have the required security permission
@@ -330,7 +292,7 @@ public class LogManager {
* unexpectedly garbage collected it is necessary for <i>applications</i>
* to maintain references to them.
* </p>
- *
+ *
* @param logger
* the logger to be added.
* @return true if the given logger is added into the namespace
@@ -347,7 +309,6 @@ public class LogManager {
return true;
}
-
private void addToFamilyTree(Logger logger, String name) {
Logger parent = null;
// find parent
@@ -359,8 +320,8 @@ public class LogManager {
if (parent != null) {
logger.internalSetParent(parent);
break;
- } else if (getProperty(parentName+".level") != null || //$NON-NLS-1$
- getProperty(parentName+".handlers") != null) { //$NON-NLS-1$
+ } else if (getProperty(parentName + ".level") != null || //$NON-NLS-1$
+ getProperty(parentName + ".handlers") != null) { //$NON-NLS-1$
parent = Logger.getLogger(parentName);
logger.internalSetParent(parent);
break;
@@ -371,16 +332,22 @@ public class LogManager {
}
// find children
- //TODO: performance can be improved here?
+ // TODO: performance can be improved here?
Collection<Logger> allLoggers = loggers.values();
- for (Logger child : allLoggers) {
+ for (final Logger child : allLoggers) {
Logger oldParent = child.getParent();
if (parent == oldParent
&& (name.length() == 0 || child.getName().startsWith(
name + '.'))) {
- child.setParent(logger);
+ final Logger thisLogger = logger;
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ child.setParent(thisLogger);
+ return null;
+ }
+ });
if (null != oldParent) {
- //-- remove from old parent as the parent has been changed
+ // -- remove from old parent as the parent has been changed
oldParent.removeChild(child);
}
}
@@ -389,7 +356,7 @@ public class LogManager {
/**
* Get the logger with the given name.
- *
+ *
* @param name
* name of logger
* @return logger with given name, or {@code null} if nothing is found.
@@ -400,7 +367,7 @@ public class LogManager {
/**
* Get a {@code Enumeration} of all registered logger names.
- *
+ *
* @return enumeration of registered logger names
*/
public synchronized Enumeration<String> getLoggerNames() {
@@ -409,7 +376,7 @@ public class LogManager {
/**
* Get the global {@code LogManager} instance.
- *
+ *
* @return the global {@code LogManager} instance
*/
public static LogManager getLogManager() {
@@ -418,7 +385,7 @@ public class LogManager {
/**
* Get the value of property with given name.
- *
+ *
* @param name
* the name of property
* @return the value of property
@@ -433,7 +400,7 @@ public class LogManager {
* <p>
* Notice : No {@code PropertyChangeEvent} are fired.
* </p>
- *
+ *
* @throws IOException
* if any IO related problems happened.
* @throws SecurityException
@@ -443,19 +410,20 @@ public class LogManager {
public void readConfiguration() throws IOException {
checkAccess();
// check config class
- String configClassName = System.getProperty(
- "java.util.logging.config.class"); //$NON-NLS-1$
- if (null == configClassName || null == getInstanceByClass(configClassName)) {
- // if config class failed, check config file
- String configFile = System.getProperty(
- "java.util.logging.config.file"); //$NON-NLS-1$
+ String configClassName = System
+ .getProperty("java.util.logging.config.class"); //$NON-NLS-1$
+ if (null == configClassName
+ || null == getInstanceByClass(configClassName)) {
+ // if config class failed, check config file
+ String configFile = System
+ .getProperty("java.util.logging.config.file"); //$NON-NLS-1$
if (null == configFile) {
// if cannot find configFile, use default logging.properties
configFile = new StringBuilder().append(
System.getProperty("java.home")).append(File.separator) //$NON-NLS-1$
.append("lib").append(File.separator).append( //$NON-NLS-1$
- "logging.properties").toString(); //$NON-NLS-1$
+ "logging.properties").toString(); //$NON-NLS-1$
}
InputStream input = null;
@@ -463,7 +431,7 @@ public class LogManager {
// BEGIN android-removed
// input = new BufferedInputStream(new FileInputStream(configFile));
// END android-removed
-
+
// BEGIN android-added
try {
input = new BufferedInputStream(
@@ -504,13 +472,12 @@ public class LogManager {
return clazz.newInstance();
} catch (Exception e) {
try {
- Class<?> clazz = Thread.currentThread()
- .getContextClassLoader().loadClass(className);
+ Class<?> clazz = Thread.currentThread().getContextClassLoader()
+ .loadClass(className);
return clazz.newInstance();
} catch (Exception innerE) {
- //logging.20=Loading class "{0}" failed
- System.err.println(Messages.getString(
- "logging.20", className)); //$NON-NLS-1$
+ // logging.20=Loading class "{0}" failed
+ System.err.println(Messages.getString("logging.20", className)); //$NON-NLS-1$
System.err.println(innerE);
return null;
}
@@ -523,7 +490,7 @@ public class LogManager {
throws IOException {
reset();
props.load(ins);
-
+
// parse property "config" and apply setting
String configs = props.getProperty("config"); //$NON-NLS-1$
if (null != configs) {
@@ -533,27 +500,25 @@ public class LogManager {
getInstanceByClass(configerName);
}
}
-
+
// set levels for logger
Collection<Logger> allLoggers = loggers.values();
- for(Logger logger : allLoggers){
- String property = props.getProperty(
- logger.getName()+".level"); //$NON-NLS-1$
- if(null != property){
+ for (Logger logger : allLoggers) {
+ String property = props.getProperty(logger.getName() + ".level"); //$NON-NLS-1$
+ if (null != property) {
logger.setLevel(Level.parse(property));
}
}
listeners.firePropertyChange(null, null, null);
}
-
/**
* Re-initialize the properties and configuration from the given
* {@code InputStream}
* <p>
* Notice : No {@code PropertyChangeEvent} are fired.
* </p>
- *
+ *
* @param ins
* the input stream
* @throws IOException
@@ -574,7 +539,7 @@ public class LogManager {
* level is set to null, except the root logger's level is set to
* {@code Level.INFO}.
* </p>
- *
+ *
* @throws SecurityException
* if security manager exists and it determines that caller does
* not have the required permissions to perform this action.
@@ -583,10 +548,10 @@ public class LogManager {
checkAccess();
props = new Properties();
Enumeration<String> names = getLoggerNames();
- while(names.hasMoreElements()){
+ while (names.hasMoreElements()) {
String name = names.nextElement();
Logger logger = getLogger(name);
- if(logger != null){
+ if (logger != null) {
logger.reset();
}
}
@@ -599,7 +564,7 @@ public class LogManager {
/**
* Add a {@code PropertyChangeListener}, which will be invoked when
* the properties are reread.
- *
+ *
* @param l
* the {@code PropertyChangeListener} to be added.
* @throws SecurityException
@@ -607,7 +572,7 @@ public class LogManager {
* not have the required permissions to perform this action.
*/
public void addPropertyChangeListener(PropertyChangeListener l) {
- if(l == null){
+ if (l == null) {
throw new NullPointerException();
}
checkAccess();
@@ -617,7 +582,7 @@ public class LogManager {
/**
* Remove a {@code PropertyChangeListener}, do nothing if the given
* listener is not found.
- *
+ *
* @param l
* the {@code PropertyChangeListener} to be removed.
* @throws SecurityException
diff --git a/logging/src/main/java/java/util/logging/LogRecord.java b/logging/src/main/java/java/util/logging/LogRecord.java
index b8a98ef..0a8e257 100644
--- a/logging/src/main/java/java/util/logging/LogRecord.java
+++ b/logging/src/main/java/java/util/logging/LogRecord.java
@@ -40,9 +40,6 @@ import org.apache.harmony.logging.internal.nls.Messages;
* {@code getSourceClassName} or {@code getSourceMethodName} if they expect to
* use them after passing the {@code LogRecord} object to another thread or
* transmitting it over RMI.
- * </p>
- *
- * @since Android 1.0
*/
public class LogRecord implements Serializable {
@@ -65,70 +62,70 @@ public class LogRecord implements Serializable {
/**
* The logging level.
- *
+ *
* @serial
*/
private Level level;
/**
* The sequence number.
- *
+ *
* @serial
*/
private long sequenceNumber;
/**
* The name of the class that issued the logging call.
- *
+ *
* @serial
*/
private String sourceClassName;
/**
* The name of the method that issued the logging call.
- *
+ *
* @serial
*/
private String sourceMethodName;
/**
* The original message text.
- *
+ *
* @serial
*/
private String message;
/**
* The ID of the thread that issued the logging call.
- *
+ *
* @serial
*/
private int threadID;
/**
* The time that the event occurred, in milliseconds since 1970.
- *
+ *
* @serial
*/
private long millis;
/**
* The associated {@code Throwable} object if any.
- *
+ *
* @serial
*/
private Throwable thrown;
/**
* The name of the source logger.
- *
+ *
* @serial
*/
private String loggerName;
/**
* The name of the resource bundle used to localize the log message.
- *
+ *
* @serial
*/
private String resourceBundleName;
@@ -148,14 +145,13 @@ public class LogRecord implements Serializable {
* sequence property is set to a new unique value, allocated in increasing
* order within the virtual machine. The thread ID is set to a unique value
* for the current thread. All other properties are set to {@code null}.
- *
+ *
* @param level
* the logging level, may not be {@code null}.
* @param msg
* the raw message.
* @throws NullPointerException
* if {@code level} is {@code null}.
- * @since Android 1.0
*/
public LogRecord(Level level, String msg) {
if (null == level) {
@@ -188,9 +184,8 @@ public class LogRecord implements Serializable {
/**
* Gets the logging level.
- *
+ *
* @return the logging level.
- * @since Android 1.0
*/
public Level getLevel() {
return level;
@@ -198,12 +193,11 @@ public class LogRecord implements Serializable {
/**
* Sets the logging level.
- *
+ *
* @param level
* the level to set.
* @throws NullPointerException
* if {@code level} is {@code null}.
- * @since Android 1.0
*/
public void setLevel(Level level) {
if (null == level) {
@@ -215,9 +209,8 @@ public class LogRecord implements Serializable {
/**
* Gets the name of the logger.
- *
+ *
* @return the logger name.
- * @since Android 1.0
*/
public String getLoggerName() {
return loggerName;
@@ -225,10 +218,9 @@ public class LogRecord implements Serializable {
/**
* Sets the name of the logger.
- *
+ *
* @param loggerName
* the logger name to set.
- * @since Android 1.0
*/
public void setLoggerName(String loggerName) {
this.loggerName = loggerName;
@@ -236,9 +228,8 @@ public class LogRecord implements Serializable {
/**
* Gets the raw message.
- *
+ *
* @return the raw message, may be {@code null}.
- * @since Android 1.0
*/
public String getMessage() {
return message;
@@ -248,10 +239,9 @@ public class LogRecord implements Serializable {
* Sets the raw message. When this record is formatted by a logger that has
* a localization resource bundle that contains an entry for {@code message},
* then the raw message is replaced with its localized version.
- *
+ *
* @param message
* the raw message to set, may be {@code null}.
- * @since Android 1.0
*/
public void setMessage(String message) {
this.message = message;
@@ -259,9 +249,8 @@ public class LogRecord implements Serializable {
/**
* Gets the time when this event occurred, in milliseconds since 1970.
- *
+ *
* @return the time when this event occurred, in milliseconds since 1970.
- * @since Android 1.0
*/
public long getMillis() {
return millis;
@@ -269,10 +258,9 @@ public class LogRecord implements Serializable {
/**
* Sets the time when this event occurred, in milliseconds since 1970.
- *
+ *
* @param millis
* the time when this event occurred, in milliseconds since 1970.
- * @since Android 1.0
*/
public void setMillis(long millis) {
this.millis = millis;
@@ -280,10 +268,9 @@ public class LogRecord implements Serializable {
/**
* Gets the parameters.
- *
+ *
* @return the array of parameters or {@code null} if there are no
* parameters.
- * @since Android 1.0
*/
public Object[] getParameters() {
return parameters;
@@ -291,10 +278,9 @@ public class LogRecord implements Serializable {
/**
* Sets the parameters.
- *
+ *
* @param parameters
* the array of parameters to set, may be {@code null}.
- * @since Android 1.0
*/
public void setParameters(Object[] parameters) {
this.parameters = parameters;
@@ -303,21 +289,20 @@ public class LogRecord implements Serializable {
/**
* Gets the resource bundle used to localize the raw message during
* formatting.
- *
+ *
* @return the associated resource bundle, {@code null} if none is
* available or the message is not localizable.
- * @since Android 1.0
*/
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
/**
- * Sets the resource bundle.
- *
+ * Sets the resource bundle used to localize the raw message during
+ * formatting.
+ *
* @param resourceBundle
* the resource bundle to set, may be {@code null}.
- * @since Android 1.0
*/
public void setResourceBundle(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
@@ -325,10 +310,9 @@ public class LogRecord implements Serializable {
/**
* Gets the name of the resource bundle.
- *
+ *
* @return the name of the resource bundle, {@code null} if none is
* available or the message is not localizable.
- * @since Android 1.0
*/
public String getResourceBundleName() {
return resourceBundleName;
@@ -336,10 +320,9 @@ public class LogRecord implements Serializable {
/**
* Sets the name of the resource bundle.
- *
+ *
* @param resourceBundleName
* the name of the resource bundle to set.
- * @since Android 1.0
*/
public void setResourceBundleName(String resourceBundleName) {
this.resourceBundleName = resourceBundleName;
@@ -347,9 +330,8 @@ public class LogRecord implements Serializable {
/**
* Gets the sequence number.
- *
+ *
* @return the sequence number.
- * @since Android 1.0
*/
public long getSequenceNumber() {
return sequenceNumber;
@@ -359,10 +341,9 @@ public class LogRecord implements Serializable {
* Sets the sequence number. It is usually not necessary to call this method
* to change the sequence number because the number is allocated when this
* instance is constructed.
- *
+ *
* @param sequenceNumber
* the sequence number to set.
- * @since Android 1.0
*/
public void setSequenceNumber(long sequenceNumber) {
this.sequenceNumber = sequenceNumber;
@@ -371,9 +352,8 @@ public class LogRecord implements Serializable {
/**
* Gets the name of the class that is the source of this log record. This
* information can be changed, may be {@code null} and is untrusted.
- *
+ *
* @return the name of the source class of this log record (possiblity {@code null})
- * @since Android 1.0
*/
public String getSourceClassName() {
initSource();
@@ -394,7 +374,8 @@ public class LogRecord implements Serializable {
break FINDLOG;
}
}
- while(++i<elements.length && elements[i].getClassName().equals(current)) {
+ while (++i < elements.length
+ && elements[i].getClassName().equals(current)) {
// do nothing
}
if (i < elements.length) {
@@ -407,11 +388,10 @@ public class LogRecord implements Serializable {
/**
* Sets the name of the class that is the source of this log record.
- *
+ *
* @param sourceClassName
* the name of the source class of this log record, may be
* {@code null}.
- * @since Android 1.0
*/
public void setSourceClassName(String sourceClassName) {
sourceInited = true;
@@ -420,9 +400,8 @@ public class LogRecord implements Serializable {
/**
* Gets the name of the method that is the source of this log record.
- *
+ *
* @return the name of the source method of this log record.
- * @since Android 1.0
*/
public String getSourceMethodName() {
initSource();
@@ -431,11 +410,10 @@ public class LogRecord implements Serializable {
/**
* Sets the name of the method that is the source of this log record.
- *
+ *
* @param sourceMethodName
* the name of the source method of this log record, may be
* {@code null}.
- * @since Android 1.0
*/
public void setSourceMethodName(String sourceMethodName) {
sourceInited = true;
@@ -448,9 +426,8 @@ public class LogRecord implements Serializable {
* <p>
* Notice : the ID doesn't necessary map the OS thread ID
* </p>
- *
+ *
* @return the ID of the thread originating this log record.
- * @since Android 1.0
*/
public int getThreadID() {
return threadID;
@@ -458,10 +435,9 @@ public class LogRecord implements Serializable {
/**
* Sets the ID of the thread originating this log record.
- *
+ *
* @param threadID
* the new ID of the thread originating this log record.
- * @since Android 1.0
*/
public void setThreadID(int threadID) {
this.threadID = threadID;
@@ -469,9 +445,8 @@ public class LogRecord implements Serializable {
/**
* Gets the {@code Throwable} object associated with this log record.
- *
+ *
* @return the {@code Throwable} object associated with this log record.
- * @since Android 1.0
*/
public Throwable getThrown() {
return thrown;
@@ -479,11 +454,10 @@ public class LogRecord implements Serializable {
/**
* Sets the {@code Throwable} object associated with this log record.
- *
+ *
* @param thrown
* the new {@code Throwable} object to associate with this log
* record.
- * @since Android 1.0
*/
public void setThrown(Throwable thrown) {
this.thrown = thrown;
@@ -514,12 +488,13 @@ public class LogRecord implements Serializable {
in.defaultReadObject();
byte major = in.readByte();
byte minor = in.readByte();
- //only check MAJOR version
+ // only check MAJOR version
if (major != MAJOR) {
// logging.5=Different version - {0}.{1}
- throw new IOException(Messages.getString("logging.5", major, minor)); //$NON-NLS-1$
+ throw new IOException(Messages.getString("logging.5", //$NON-NLS-1$
+ Byte.valueOf(major), Byte.valueOf(minor)));
}
-
+
int length = in.readInt();
if (length >= 0) {
parameters = new Object[length];
diff --git a/logging/src/main/java/java/util/logging/Logger.java b/logging/src/main/java/java/util/logging/Logger.java
index cd88ca0..fe124d3 100644
--- a/logging/src/main/java/java/util/logging/Logger.java
+++ b/logging/src/main/java/java/util/logging/Logger.java
@@ -24,7 +24,6 @@ import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
-import java.util.StringTokenizer;
import org.apache.harmony.logging.internal.nls.Messages;
@@ -39,7 +38,6 @@ import org.apache.harmony.logging.internal.nls.Messages;
* namespace hierarchy managed by a log manager. The naming convention is
* usually the same as java package's naming convention, that is using
* dot-separated strings. Anonymous loggers do not belong to any namespace.
- * </p>
* <p>
* Loggers "inherit" log level setting from their parent if their own level is
* set to {@code null}. This is also true for the resource bundle. The logger's
@@ -49,36 +47,28 @@ import org.apache.harmony.logging.internal.nls.Messages;
* context, "inherit" only means that "behavior" is inherited. The internal
* field values will not change, for example, {@code getLevel()} still returns
* {@code null}.
- * </p>
* <p>
* When loading a given resource bundle, the logger first tries to use the
* context classloader. If that fails, it tries the system classloader. And if
* that still fails, it searches up the class stack and uses each class's
* classloader to try to locate the resource bundle.
- * </p>
* <p>
* Some log methods accept log requests that do not specify the source class and
* source method. In these cases, the logging framework will automatically infer
* the calling class and method, but this is not guaranteed to be accurate.
- * </p>
* <p>
* Once a {@code LogRecord} object has been passed into the logging framework,
* it is owned by the logging framework and the client applications should not
* use it any longer.
- * </p>
* <p>
* All methods of this class are thread-safe.
- * </p>
- *
+ *
* @see LogManager
- * @since Android 1.0
*/
public class Logger {
/**
* The global logger is provided as convenience for casual use.
- *
- * @since Android 1.0
*/
public final static Logger global = new Logger("global", null); //$NON-NLS-1$
@@ -116,27 +106,19 @@ public class Logger {
private boolean isNamed;
private List<Logger> childs;
-
+
private LogManager manager;
// BEGIN android-changed
private volatile boolean handlerInited;
// END android-changed
-
- /*
- * -------------------------------------------------------------------
- * Constructors
- * -------------------------------------------------------------------
- */
-
/**
* Constructs a {@code Logger} object with the supplied name and resource
* bundle name; {@code notifiyParentHandlers} is set to {@code true}.
* <p>
- * Notice : Loggers use a naming hierarchy. Thus "z.x.y" is a child of "z.x".
- * </p>
- *
+ * Notice : Loggers use a naming hierarchy. Thus "z.x.y" is a child of "z.x".
+ *
* @param name
* the name of this logger, may be {@code null} for anonymous
* loggers.
@@ -145,7 +127,6 @@ public class Logger {
* messages, may be {@code null}.
* @throws MissingResourceException
* if the specified resource bundle can not be loaded.
- * @since Android 1.0
*/
protected Logger(String name, String resourceBundleName) {
// try to load the specified resource bundle first
@@ -164,24 +145,24 @@ public class Logger {
// any logger is not anonymous by default
this.isNamed = true;
- //-- 'null' means that level will be inherited from parent (see getLevel)
- //-- Level.INFO is default level if we don't set it. It will be
- //-- changed to parent level or to configLevel after adding to the
- //-- family tree. As of this, actually, setting to Level.INFO is
- //-- not needed here.
+ // -- 'null' means that level will be inherited from parent (see
+ // getLevel)
+ // -- Level.INFO is default level if we don't set it. It will be
+ // -- changed to parent level or to configLevel after adding to the
+ // -- family tree. As of this, actually, setting to Level.INFO is
+ // -- not needed here.
this.levelObjVal = null;
this.levelIntVal = Level.INFO.intValue();
}
- //-- should be called under the lm lock
+ // -- should be called under the lm lock
private void setLevelImpl(Level newLevel) {
// update levels for the whole hierarchy
int oldVal = levelIntVal;
levelObjVal = newLevel;
if (null == newLevel) {
- levelIntVal = null != parent
- ? parent.levelIntVal
- : Level.INFO.intValue();
+ levelIntVal = null != parent ? parent.levelIntVal : Level.INFO
+ .intValue();
} else {
levelIntVal = newLevel.intValue();
}
@@ -190,7 +171,7 @@ public class Logger {
}
}
- //-- should be called under the lm lock
+ // -- should be called under the lm lock
private void forceChildsToInherit() {
for (Logger child : childs) {
if (null == child.levelObjVal) { // should inherit
@@ -199,15 +180,9 @@ public class Logger {
}
}
- /*
- * -------------------------------------------------------------------
- * Methods
- * -------------------------------------------------------------------
- */
-
/**
* Load the specified resource bundle, use privileged code.
- *
+ *
* @param resourceBundleName
* the name of the resource bundle to load, cannot be {@code null}.
* @return the loaded resource bundle.
@@ -216,8 +191,8 @@ public class Logger {
*/
static ResourceBundle loadResourceBundle(String resourceBundleName) {
// try context class loader to load the resource
- ClassLoader cl = AccessController.doPrivileged(
- new PrivilegedAction<ClassLoader>() {
+ ClassLoader cl = AccessController
+ .doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
@@ -231,12 +206,11 @@ public class Logger {
}
}
// try system class loader to load the resource
- cl = AccessController.doPrivileged(
- new PrivilegedAction<ClassLoader>() {
- public ClassLoader run() {
- return ClassLoader.getSystemClassLoader();
- }
- });
+ cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return ClassLoader.getSystemClassLoader();
+ }
+ });
if (null != cl) {
try {
return ResourceBundle.getBundle(resourceBundleName, Locale
@@ -257,8 +231,8 @@ public class Logger {
for (int i = 1; i < classes.length; i++) {
final int index = i;
try {
- cl = AccessController.doPrivileged(
- new PrivilegedAction<ClassLoader>() {
+ cl = AccessController
+ .doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return classes[index].getClassLoader();
}
@@ -274,7 +248,7 @@ public class Logger {
}
// logging.8=Failed to load the specified resource bundle "{0}".
throw new MissingResourceException(Messages.getString("logging.8", //$NON-NLS-1$
- resourceBundleName), resourceBundleName, null);
+ resourceBundleName), resourceBundleName, null);
}
/**
@@ -284,10 +258,8 @@ public class Logger {
* <p>
* The anonymous loggers' parent is set to be the root logger. This way it
* inherits the default logging level and handlers from the root logger.
- * </p>
- *
+ *
* @return a new instance of anonymous logger.
- * @since Android 1.0
*/
public static Logger getAnonymousLogger() {
return getAnonymousLogger(null);
@@ -300,14 +272,12 @@ public class Logger {
* <p>
* The anonymous loggers' parent is set to be the root logger. This way it
* inherits default logging level and handlers from the root logger.
- * </p>
- *
+ *
* @param resourceBundleName
* the name of the resource bundle used to localize log messages.
* @return a new instance of anonymous logger.
* @throws MissingResourceException
* if the specified resource bundle can not be loaded.
- * @since Android 1.0
*/
public static Logger getAnonymousLogger(String resourceBundleName) {
final Logger l = new Logger(null, resourceBundleName);
@@ -324,26 +294,24 @@ public class Logger {
private static void updateResourceBundle(Logger l, String resourceBundleName) {
synchronized (l) {
if (null == l.getResourceBundleName()) {
- if(null == resourceBundleName){
+ if (null == resourceBundleName) {
return;
}
/*
- * load the resource bundle if none is specified
- * before
+ * load the resource bundle if none is specified before
*/
l.resBundle = loadResourceBundle(resourceBundleName);
l.resBundleName = resourceBundleName;
} else if (!l.getResourceBundleName().equals(resourceBundleName)) {
/*
- * throw exception if the specified resource bundles
- * are inconsistent with each other, i.e., different
- * names
+ * throw exception if the specified resource bundles are
+ * inconsistent with each other, i.e., different names
*/
- // logging.9=The specified resource bundle name "{0}" is
+ // logging.9=The specified resource bundle name "{0}" is
// inconsistent with the existing one "{1}".
throw new IllegalArgumentException(Messages.getString(
"logging.9", //$NON-NLS-1$
- resourceBundleName, l.getResourceBundleName()));
+ resourceBundleName, l.getResourceBundleName()));
}
}
}
@@ -378,11 +346,12 @@ public class Logger {
* Gets a named logger. The returned logger may already exist or may be
* newly created. In the latter case, its level will be set to the
* configured level according to the {@code LogManager}'s properties.
- *
+ *
* @param name
* the name of the logger to get, cannot be {@code null}.
* @return a named logger.
- * @since Android 1.0
+ * @throws MissingResourceException
+ * If the specified resource bundle can not be loaded.
*/
public static Logger getLogger(String name) {
return getLoggerWithRes(name, null, false);
@@ -391,7 +360,7 @@ public class Logger {
/**
* Gets a named logger associated with the supplied resource bundle. The
* resource bundle will be used to localize logging messages.
- *
+ *
* @param name
* the name of the logger to get, cannot be {@code null}.
* @param resourceBundleName
@@ -403,7 +372,6 @@ public class Logger {
* @throws MissingResourceException
* if the name of the resource bundle cannot be found.
* @return a named logger.
- * @since Android 1.0
*/
public static Logger getLogger(String name, String resourceBundleName) {
return getLoggerWithRes(name, resourceBundleName, true);
@@ -412,13 +380,12 @@ public class Logger {
/**
* Adds a handler to this logger. The {@code name} will be fed with log
* records received by this logger.
- *
+ *
* @param handler
* the handler object to add, cannot be {@code null}.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void addHandler(Handler handler) {
if (null == handler) {
@@ -430,25 +397,25 @@ public class Logger {
LogManager.getLogManager().checkAccess();
}
initHandler();
- synchronized(this){
+ synchronized (this) {
this.handlers.add(handler);
}
}
-
+
/*
- * Be cautious to avoid deadlock when using this method, it gets lock on manager
- * at first, and then gets lock on this Logger, so any methods should not hold
- * lock on this Logger when invoking this method.
+ * Be cautious to avoid deadlock when using this method, it gets lock on manager
+ * at first, and then gets lock on this Logger, so any methods should not hold
+ * lock on this Logger when invoking this method.
*/
private void initHandler() {
- if(!handlerInited){
+ if (!handlerInited) {
synchronized (this) {
if (!handlerInited) {
// BEGIN android-added
/*
* Force LogManager to be initialized, since its
* class init code performs necessary one-time setup.
- */
+ */
LogManager.getLogManager();
// END android-added
if (handlers == null) {
@@ -463,26 +430,27 @@ public class Logger {
if (null == handlerStr) {
return;
}
- StringTokenizer st = new StringTokenizer(handlerStr, " "); //$NON-NLS-1$
- while (st.hasMoreTokens()) {
- String handlerName = st.nextToken();
- // BEGIN android-changed
- // deal with non-existing handler
- try {
- Handler handler = (Handler) LogManager
- .getInstanceByClass(handlerName);
- handlers.add(handler);
- String level = manager.getProperty(handlerName
- + ".level"); //$NON-NLS-1$
- if (null != level) {
- handler.setLevel(Level.parse(level));
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- // END android-changed
+ String[] strs = handlerStr.split(",|\\s"); //$NON-NLS-1$
+ for (int i = 0; i < strs.length; i++) {
+ String handlerName = strs[i];
+ if (handlerName.equals("")) { //$NON-NLS-1$
+ continue;
+ }
+ // BEGIN android-changed
+ // deal with non-existing handler
+ try {
+ Handler handler = (Handler) LogManager.getInstanceByClass(handlerName);
+ handlers.add(handler);
+ String level = manager.getProperty(handlerName + ".level"); //$NON-NLS-1$
+ if (null != level) {
+ handler.setLevel(Level.parse(level));
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
}
- handlerInited = true;
+ // END android-changed
+ }
+ handlerInited = true;
}
}
}
@@ -490,13 +458,12 @@ public class Logger {
/**
* Gets all the handlers associated with this logger.
- *
+ *
* @return an array of all the handlers associated with this logger.
- * @since Android 1.0
*/
public Handler[] getHandlers() {
initHandler();
- synchronized(this){
+ synchronized (this) {
return handlers.toArray(new Handler[handlers.size()]);
}
}
@@ -504,13 +471,12 @@ public class Logger {
/**
* Removes a handler from this logger. If the specified handler does not
* exist then this method has no effect.
- *
+ *
* @param handler
* the handler to be removed.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void removeHandler(Handler handler) {
// Anonymous loggers can always remove handlers
@@ -521,16 +487,15 @@ public class Logger {
return;
}
initHandler();
- synchronized(this){
+ synchronized (this) {
this.handlers.remove(handler);
}
}
/**
* Gets the filter used by this logger.
- *
+ *
* @return the filter used by this logger, may be {@code null}.
- * @since Android 1.0
*/
public Filter getFilter() {
return this.filter;
@@ -538,13 +503,12 @@ public class Logger {
/**
* Sets the filter used by this logger.
- *
+ *
* @param newFilter
* the filter to set, may be {@code null}.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setFilter(Filter newFilter) {
// Anonymous loggers can always set the filter
@@ -557,9 +521,8 @@ public class Logger {
/**
* Gets the logging level of this logger. A {@code null} level indicates
* that this logger inherits its parent's level.
- *
+ *
* @return the logging level of this logger.
- * @since Android 1.0
*/
public Level getLevel() {
return levelObjVal;
@@ -568,13 +531,12 @@ public class Logger {
/**
* Sets the logging level for this logger. A {@code null} level indicates
* that this logger will inherit its parent's level.
- *
+ *
* @param newLevel
* the logging level to set.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setLevel(Level newLevel) {
// Anonymous loggers can always set the level
@@ -590,10 +552,9 @@ public class Logger {
* Gets the flag which indicates whether to use the handlers of this
* logger's parent to publish incoming log records, potentially recursively
* up the namespace.
- *
+ *
* @return {@code true} if set to use parent's handlers, {@code false}
* otherwise.
- * @since Android 1.0
*/
public boolean getUseParentHandlers() {
return this.notifyParentHandlers;
@@ -602,13 +563,12 @@ public class Logger {
/**
* Sets the flag which indicates whether to use the handlers of this
* logger's parent, potentially recursively up the namespace.
- *
+ *
* @param notifyParentHandlers
* the new flag indicating whether to use the parent's handlers.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setUseParentHandlers(boolean notifyParentHandlers) {
// Anonymous loggers can always set the useParentHandlers flag
@@ -621,9 +581,8 @@ public class Logger {
/**
* Gets the nearest parent of this logger in the namespace, a {@code null}
* value will be returned if called on the root logger.
- *
+ *
* @return the parent of this logger in the namespace.
- * @since Android 1.0
*/
public Logger getParent() {
return parent;
@@ -633,14 +592,14 @@ public class Logger {
* Sets the parent of this logger in the namespace. This method should
* usually be used by the {@code LogManager} object only. This method does
* not check security.
- *
+ *
* @param newParent
* the parent logger to set.
- * @since Android 1.0
*/
void internalSetParent(Logger newParent) {
- //All hierarchy related modifications should get LogManager lock at first
- synchronized(LogManager.getLogManager()){
+ // All hierarchy related modifications should get LogManager lock at
+ // first
+ synchronized (LogManager.getLogManager()) {
parent = newParent;
// -- update level after setting a parent.
// -- if level == null we should inherit the parent's level
@@ -654,13 +613,12 @@ public class Logger {
/**
* Sets the parent of this logger in the namespace. This method should be
* used by the {@code LogManager} object only.
- *
+ *
* @param parent
* the parent logger to set.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setParent(Logger parent) {
if (null == parent) {
@@ -680,12 +638,10 @@ public class Logger {
childs.remove(child);
}
-
/**
* Gets the name of this logger, {@code null} for anonymous loggers.
- *
+ *
* @return the name of this logger.
- * @since Android 1.0
*/
public String getName() {
return this.name;
@@ -695,9 +651,8 @@ public class Logger {
* Gets the loaded resource bundle used by this logger to localize logging
* messages. If the value is {@code null}, the parent's resource bundle will be
* inherited.
- *
+ *
* @return the loaded resource bundle used by this logger.
- * @since Android 1.0
*/
public ResourceBundle getResourceBundle() {
return this.resBundle;
@@ -707,9 +662,8 @@ public class Logger {
* Gets the name of the loaded resource bundle used by this logger to
* localize logging messages. If the value is {@code null}, the parent's resource
* bundle name will be inherited.
- *
+ *
* @return the name of the loaded resource bundle used by this logger.
- * @since Android 1.0
*/
public String getResourceBundleName() {
return this.resBundleName;
@@ -734,12 +688,11 @@ public class Logger {
* Determines whether this logger will actually log messages of the
* specified level. The effective level used to do the determination may be
* inherited from its parent. The default level is {@code Level.INFO}.
- *
+ *
* @param l
* the level to check.
* @return {@code true} if this logger will actually log this level,
* otherwise {@code false}.
- * @since Android 1.0
*/
public boolean isLoggable(Level l) {
return internalIsLoggable(l);
@@ -775,12 +728,11 @@ public class Logger {
* Logs a message indicating that a method has been entered. A log record
* with log level {@code Level.FINER}, log message "ENTRY", the specified
* source class name and source method name is submitted for logging.
- *
+ *
* @param sourceClass
* the calling class name.
* @param sourceMethod
* the method name.
- * @since Android 1.0
*/
public void entering(String sourceClass, String sourceMethod) {
if (internalIsLoggable(Level.FINER)) {
@@ -798,14 +750,13 @@ public class Logger {
* with log level {@code Level.FINER}, log message "ENTRY", the specified
* source class name, source method name and one parameter is submitted for
* logging.
- *
+ *
* @param sourceClass
* the source class name.
* @param sourceMethod
* the source method name.
* @param param
* the parameter for the method call.
- * @since Android 1.0
*/
public void entering(String sourceClass, String sourceMethod, Object param) {
if (internalIsLoggable(Level.FINER)) {
@@ -824,14 +775,13 @@ public class Logger {
* with log level {@code Level.FINER}, log message "ENTRY", the specified
* source class name, source method name and array of parameters is
* submitted for logging.
- *
+ *
* @param sourceClass
* the source class name.
* @param sourceMethod
* the source method name.
* @param params
* an array of parameters for the method call.
- * @since Android 1.0
*/
public void entering(String sourceClass, String sourceMethod,
Object[] params) {
@@ -858,12 +808,11 @@ public class Logger {
* Logs a message indicating that a method is exited. A log record with log
* level {@code Level.FINER}, log message "RETURN", the specified source
* class name and source method name is submitted for logging.
- *
+ *
* @param sourceClass
* the calling class name.
* @param sourceMethod
* the method name.
- * @since Android 1.0
*/
public void exiting(String sourceClass, String sourceMethod) {
if (internalIsLoggable(Level.FINER)) {
@@ -880,14 +829,13 @@ public class Logger {
* Logs a message indicating that a method is exited. A log record with log
* level {@code Level.FINER}, log message "RETURN", the specified source
* class name, source method name and return value is submitted for logging.
- *
+ *
* @param sourceClass
* the source class name.
* @param sourceMethod
* the source method name.
* @param result
* the return value of the method call.
- * @since Android 1.0
*/
public void exiting(String sourceClass, String sourceMethod, Object result) {
if (internalIsLoggable(Level.FINER)) {
@@ -906,14 +854,13 @@ public class Logger {
* log level {@code Level.FINER}, log message "THROW", the specified source
* class name, source method name and the {@code Throwable} object is
* submitted for logging.
- *
+ *
* @param sourceClass
* the source class name.
* @param sourceMethod
* the source method name.
* @param thrown
* the {@code Throwable} object.
- * @since Android 1.0
*/
public void throwing(String sourceClass, String sourceMethod,
Throwable thrown) {
@@ -931,10 +878,9 @@ public class Logger {
/**
* Logs a message of level {@code Level.SEVERE}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void severe(String msg) {
if (internalIsLoggable(Level.SEVERE)) {
@@ -948,10 +894,9 @@ public class Logger {
/**
* Logs a message of level {@code Level.WARNING}; the message is
* transmitted to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void warning(String msg) {
if (internalIsLoggable(Level.WARNING)) {
@@ -965,10 +910,9 @@ public class Logger {
/**
* Logs a message of level {@code Level.INFO}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void info(String msg) {
if (internalIsLoggable(Level.INFO)) {
@@ -982,10 +926,9 @@ public class Logger {
/**
* Logs a message of level {@code Level.CONFIG}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void config(String msg) {
if (internalIsLoggable(Level.CONFIG)) {
@@ -999,10 +942,9 @@ public class Logger {
/**
* Logs a message of level {@code Level.FINE}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void fine(String msg) {
if (internalIsLoggable(Level.FINE)) {
@@ -1016,10 +958,9 @@ public class Logger {
/**
* Logs a message of level {@code Level.FINER}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void finer(String msg) {
if (internalIsLoggable(Level.FINER)) {
@@ -1033,10 +974,9 @@ public class Logger {
/**
* Logs a message of level {@code Level.FINEST}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void finest(String msg) {
if (internalIsLoggable(Level.FINEST)) {
@@ -1050,12 +990,11 @@ public class Logger {
/**
* Logs a message of the specified level. The message is transmitted to all
* subscribed handlers.
- *
+ *
* @param logLevel
* the level of the specified message.
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void log(Level logLevel, String msg) {
if (internalIsLoggable(logLevel)) {
@@ -1069,14 +1008,13 @@ public class Logger {
/**
* Logs a message of the specified level with the supplied parameter. The
* message is then transmitted to all subscribed handlers.
- *
+ *
* @param logLevel
* the level of the given message.
* @param msg
* the message to log.
* @param param
* the parameter associated with the event that is logged.
- * @since Android 1.0
*/
public void log(Level logLevel, String msg, Object param) {
if (internalIsLoggable(logLevel)) {
@@ -1091,14 +1029,13 @@ public class Logger {
/**
* Logs a message of the specified level with the supplied parameter array.
* The message is then transmitted to all subscribed handlers.
- *
+ *
* @param logLevel
* the level of the given message
* @param msg
* the message to log.
* @param params
* the parameter array associated with the event that is logged.
- * @since Android 1.0
*/
public void log(Level logLevel, String msg, Object[] params) {
if (internalIsLoggable(logLevel)) {
@@ -1113,7 +1050,7 @@ public class Logger {
/**
* Logs a message of the specified level with the supplied {@code Throwable}
* object. The message is then transmitted to all subscribed handlers.
- *
+ *
* @param logLevel
* the level of the given message.
* @param msg
@@ -1121,7 +1058,6 @@ public class Logger {
* @param thrown
* the {@code Throwable} object associated with the event that is
* logged.
- * @since Android 1.0
*/
public void log(Level logLevel, String msg, Throwable thrown) {
if (internalIsLoggable(logLevel)) {
@@ -1144,10 +1080,9 @@ public class Logger {
* logging action, subclasses of this class can override this method to
* catch all logging activities.
* </p>
- *
+ *
* @param record
* the log record to be logged.
- * @since Android 1.0
*/
public void log(LogRecord record) {
if (internalIsLoggable(record.getLevel())) {
@@ -1158,8 +1093,7 @@ public class Logger {
}
initHandler();
/*
- * call the handlers of this logger, throw any exception that
- * occurs
+ * call the handlers of this logger, throw any exception that occurs
*/
Handler[] allHandlers = getHandlers();
for (Handler element : allHandlers) {
@@ -1182,7 +1116,7 @@ public class Logger {
/**
* Logs a message of the given level with the specified source class name
* and source method name.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1191,7 +1125,6 @@ public class Logger {
* the source method name.
* @param msg
* the message to be logged.
- * @since Android 1.0
*/
public void logp(Level logLevel, String sourceClass, String sourceMethod,
String msg) {
@@ -1208,7 +1141,7 @@ public class Logger {
/**
* Logs a message of the given level with the specified source class name,
* source method name and parameter.
- *
+ *
* @param logLevel
* the level of the given message
* @param sourceClass
@@ -1219,7 +1152,6 @@ public class Logger {
* the message to be logged
* @param param
* the parameter associated with the event that is logged.
- * @since Android 1.0
*/
public void logp(Level logLevel, String sourceClass, String sourceMethod,
String msg, Object param) {
@@ -1237,7 +1169,7 @@ public class Logger {
/**
* Logs a message of the given level with the specified source class name,
* source method name and parameter array.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1248,7 +1180,6 @@ public class Logger {
* the message to be logged.
* @param params
* the parameter array associated with the event that is logged.
- * @since Android 1.0
*/
public void logp(Level logLevel, String sourceClass, String sourceMethod,
String msg, Object[] params) {
@@ -1266,7 +1197,7 @@ public class Logger {
/**
* Logs a message of the given level with the specified source class name,
* source method name and {@code Throwable} object.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1277,7 +1208,6 @@ public class Logger {
* the message to be logged.
* @param thrown
* the {@code Throwable} object.
- * @since Android 1.0
*/
public void logp(Level logLevel, String sourceClass, String sourceMethod,
String msg, Throwable thrown) {
@@ -1297,7 +1227,7 @@ public class Logger {
* and source method name, using the given resource bundle to localize the
* message. If {@code bundleName} is null, the empty string or not valid then
* the message is not localized.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1308,7 +1238,6 @@ public class Logger {
* the name of the resource bundle used to localize the message.
* @param msg
* the message to be logged.
- * @since Android 1.0
*/
public void logrb(Level logLevel, String sourceClass, String sourceMethod,
String bundleName, String msg) {
@@ -1334,7 +1263,7 @@ public class Logger {
* source method name and parameter, using the given resource bundle to
* localize the message. If {@code bundleName} is null, the empty string
* or not valid then the message is not localized.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1347,7 +1276,6 @@ public class Logger {
* the message to be logged.
* @param param
* the parameter associated with the event that is logged.
- * @since Android 1.0
*/
public void logrb(Level logLevel, String sourceClass, String sourceMethod,
String bundleName, String msg, Object param) {
@@ -1374,7 +1302,7 @@ public class Logger {
* source method name and parameter array, using the given resource bundle
* to localize the message. If {@code bundleName} is null, the empty string
* or not valid then the message is not localized.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1387,7 +1315,6 @@ public class Logger {
* the message to be logged.
* @param params
* the parameter array associated with the event that is logged.
- * @since Android 1.0
*/
public void logrb(Level logLevel, String sourceClass, String sourceMethod,
String bundleName, String msg, Object[] params) {
@@ -1414,7 +1341,7 @@ public class Logger {
* source method name and {@code Throwable} object, using the given resource
* bundle to localize the message. If {@code bundleName} is null, the empty
* string or not valid then the message is not localized.
- *
+ *
* @param logLevel
* the level of the given message
* @param sourceClass
@@ -1427,7 +1354,6 @@ public class Logger {
* the message to be logged.
* @param thrown
* the {@code Throwable} object.
- * @since Android 1.0
*/
public void logrb(Level logLevel, String sourceClass, String sourceMethod,
String bundleName, String msg, Throwable thrown) {
@@ -1459,25 +1385,30 @@ public class Logger {
}
void setManager(LogManager manager) {
- if(this.manager != manager){
+ if (this.manager != manager) {
this.manager = manager;
- handlerInited = false;
+ handlerInited = false;
}
- //init level here, but let handlers be for lazy loading
- String configedLevel = manager.getProperty(name+ ".level"); //$NON-NLS-1$
+ // init level here, but let handlers be for lazy loading
+ final String configedLevel = manager.getProperty(name + ".level"); //$NON-NLS-1$
if (null != configedLevel) {
try {
- setLevel(Level.parse(configedLevel));
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ setLevel(Level.parse(configedLevel));
+ return null;
+ }
+ });
} catch (IllegalArgumentException e) {
- //ignore
+ // ignore
}
- }
+ }
}
synchronized void reset() {
levelObjVal = null;
levelIntVal = Level.INFO.intValue();
- if(handlers != null){
+ if (handlers != null) {
for (Handler element : handlers) {
// close all handlers, when unknown exceptions happen,
// ignore them and go on
@@ -1492,4 +1423,3 @@ public class Logger {
handlerInited = false;
}
}
-
diff --git a/logging/src/main/java/java/util/logging/LoggingMXBean.java b/logging/src/main/java/java/util/logging/LoggingMXBean.java
index f6b49a6..18cc4cc 100644
--- a/logging/src/main/java/java/util/logging/LoggingMXBean.java
+++ b/logging/src/main/java/java/util/logging/LoggingMXBean.java
@@ -25,29 +25,28 @@ import java.util.List;
* The ObjectName for identifying the {@code LoggingMXBean} in a bean server is
* {@link LogManager#LOGGING_MXBEAN_NAME}.
* </p>
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public interface LoggingMXBean {
+
/**
* Gets the string value of the logging level of a logger. An empty string
* is returned when the logger's level is defined by its parent. A
* {@code null} is returned if the specified logger does not exist.
- *
+ *
* @param loggerName
* the name of the logger lookup.
* @return a {@code String} if the logger is found, otherwise {@code null}.
* @see Level#getName()
- * @since Android 1.0
*/
String getLoggerLevel(String loggerName);
/**
* Gets a list of all currently registered logger names. This is performed
* using the {@link LogManager#getLoggerNames()}.
- *
+ *
* @return a list of logger names.
- * @since Android 1.0
*/
List<String> getLoggerNames();
@@ -55,18 +54,17 @@ public interface LoggingMXBean {
* Gets the name of the parent logger of a logger. If the logger doesn't
* exist then {@code null} is returned. If the logger is the root logger,
* then an empty {@code String} is returned.
- *
+ *
* @param loggerName
* the name of the logger to lookup.
* @return a {@code String} if the logger was found, otherwise {@code null}.
- * @since Android 1.0
*/
String getParentLoggerName(String loggerName);
/**
* Sets the log level of a logger. LevelName set to {@code null} means the
* level is inherited from the nearest non-null ancestor.
- *
+ *
* @param loggerName
* the name of the logger to set the level on, which must not be
* {@code null}.
@@ -79,7 +77,6 @@ public interface LoggingMXBean {
* if a security manager exists and the caller doesn't have
* LoggingPermission("control").
* @see Level#parse(String)
- * @since Android 1.0
*/
void setLoggerLevel(String loggerName, String levelName);
}
diff --git a/logging/src/main/java/java/util/logging/LoggingPermission.java b/logging/src/main/java/java/util/logging/LoggingPermission.java
index fb6d4f8..aa41a2c 100644
--- a/logging/src/main/java/java/util/logging/LoggingPermission.java
+++ b/logging/src/main/java/java/util/logging/LoggingPermission.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.io.Serializable;
@@ -27,20 +26,12 @@ import org.apache.harmony.logging.internal.nls.Messages;
/**
* The permission required to control the logging when run with a
* {@code SecurityManager}.
- *
*/
public final class LoggingPermission extends BasicPermission implements Guard,
Serializable {
- //for serialization compatibility with J2SE 1.4.2
- private static final long serialVersionUID =63564341580231582L;
-
-
- /*
- * -------------------------------------------------------------------
- * Constructors
- * -------------------------------------------------------------------
- */
+ // for serialization compatibility with J2SE 1.4.2
+ private static final long serialVersionUID = 63564341580231582L;
/**
* Constructs a {@code LoggingPermission} object required to control the
@@ -50,7 +41,7 @@ public final class LoggingPermission extends BasicPermission implements Guard,
* and depends on the security policy file, therefore programmers shouldn't
* normally use them directly.
* </p>
- *
+ *
* @param name
* currently must be "control".
* @param actions
@@ -71,4 +62,3 @@ public final class LoggingPermission extends BasicPermission implements Guard,
}
}
-
diff --git a/logging/src/main/java/java/util/logging/MemoryHandler.java b/logging/src/main/java/java/util/logging/MemoryHandler.java
index c1e8670..3312083 100644
--- a/logging/src/main/java/java/util/logging/MemoryHandler.java
+++ b/logging/src/main/java/java/util/logging/MemoryHandler.java
@@ -22,7 +22,6 @@ import java.security.PrivilegedExceptionAction;
import org.apache.harmony.logging.internal.nls.Messages;
-
/**
* A {@code Handler} put the description of log events into a cycled memory
* buffer.
@@ -30,68 +29,61 @@ import org.apache.harmony.logging.internal.nls.Messages;
* Mostly this {@code MemoryHandler} just puts the given {@code LogRecord} into
* the internal buffer and doesn't perform any formatting or any other process.
* When the buffer is full, the earliest buffered records will be discarded.
- * </p>
* <p>
* Every {@code MemoryHandler} has a target handler, and push action can be
* triggered so that all buffered records will be output to the target handler
* and normally the latter will publish the records. After the push action, the
* buffer will be cleared.
- * </p>
* <p>
- * The push action can be triggered in three ways:
- * <ul>
- * <li>The push method is called explicitly</li>
- * <li>When a new {@code LogRecord} is put into the internal buffer, and it has
- * a level which is not less than the specified push level.</li>
- * <li>A subclass extends this {@code MemoryHandler} and call push method
- * implicitly according to some criteria.</li>
- * </ul>
- * </p>
+ * The push method can be called directly, but will also be called automatically
+ * if a new <code>LogRecord</code> is added that has a level greater than or
+ * equal to than the value defined for the property
+ * java.util.logging.MemoryHandler.push.
* <p>
* {@code MemoryHandler} will read following {@code LogManager} properties for
* initialization, if given properties are not defined or has invalid values,
* default value will be used.
* <ul>
- * <li>java.util.logging.MemoryHandler.level specifies the level for this
- * {@code Handler}, defaults to {@code Level.ALL}.</li>
* <li>java.util.logging.MemoryHandler.filter specifies the {@code Filter}
* class name, defaults to no {@code Filter}.</li>
- * <li>java.util.logging.MemoryHandler.size specifies the buffer size in number
- * of {@code LogRecord}, defaults to 1000.</li>
+ * <li>java.util.logging.MemoryHandler.level specifies the level for this
+ * {@code Handler}, defaults to {@code Level.ALL}.</li>
* <li>java.util.logging.MemoryHandler.push specifies the push level, defaults
* to level.SEVERE.</li>
+ * <li>java.util.logging.MemoryHandler.size specifies the buffer size in number
+ * of {@code LogRecord}, defaults to 1000.</li>
* <li>java.util.logging.MemoryHandler.target specifies the class of the target
* {@code Handler}, no default value, which means this property must be
* specified either by property setting or by constructor.</li>
* </ul>
- * </p>
*/
public class MemoryHandler extends Handler {
- //default maximum buffered number of LogRecord
+ // default maximum buffered number of LogRecord
private static final int DEFAULT_SIZE = 1000;
- //target handler
+
+ // target handler
private Handler target;
-
- //buffer size
+
+ // buffer size
private int size = DEFAULT_SIZE;
-
- //push level
+
+ // push level
private Level push = Level.SEVERE;
- //LogManager instance for convenience
+ // LogManager instance for convenience
private final LogManager manager = LogManager.getLogManager();
-
- //buffer
+
+ // buffer
private LogRecord[] buffer;
-
- //current position in buffer
+
+ // current position in buffer
private int cursor;
-
+
/**
* Default constructor, construct and init a {@code MemoryHandler} using
* {@code LogManager} properties or default values.
- *
+ *
* @throws RuntimeException
* if property value are invalid and no default value could be
* used.
@@ -99,55 +91,57 @@ public class MemoryHandler extends Handler {
public MemoryHandler() {
super();
String className = this.getClass().getName();
- //init target
- final String targetName = manager.getProperty(className+".target"); //$NON-NLS-1$
+ // init target
+ final String targetName = manager.getProperty(className + ".target"); //$NON-NLS-1$
try {
- Class<?> targetClass = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>(){
- public Class<?> run() throws Exception{
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- if(loader == null){
- loader = ClassLoader.getSystemClassLoader();
- }
- return loader.loadClass(targetName);
- }
- });
+ Class<?> targetClass = AccessController
+ .doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
+ public Class<?> run() throws Exception {
+ ClassLoader loader = Thread.currentThread()
+ .getContextClassLoader();
+ if (loader == null) {
+ loader = ClassLoader.getSystemClassLoader();
+ }
+ return loader.loadClass(targetName);
+ }
+ });
target = (Handler) targetClass.newInstance();
} catch (Exception e) {
// logging.10=Cannot load target handler:{0}
throw new RuntimeException(Messages.getString("logging.10", //$NON-NLS-1$
targetName));
}
- //init size
- String sizeString = manager.getProperty(className+".size"); //$NON-NLS-1$
+ // init size
+ String sizeString = manager.getProperty(className + ".size"); //$NON-NLS-1$
if (null != sizeString) {
try {
size = Integer.parseInt(sizeString);
- if(size <= 0){
+ if (size <= 0) {
size = DEFAULT_SIZE;
}
} catch (Exception e) {
- printInvalidPropMessage(className+".size", sizeString, e); //$NON-NLS-1$
+ printInvalidPropMessage(className + ".size", sizeString, e); //$NON-NLS-1$
}
}
- //init push level
- String pushName = manager.getProperty(className+".push"); //$NON-NLS-1$
+ // init push level
+ String pushName = manager.getProperty(className + ".push"); //$NON-NLS-1$
if (null != pushName) {
try {
push = Level.parse(pushName);
} catch (Exception e) {
- printInvalidPropMessage(className+".push", pushName, e); //$NON-NLS-1$
+ printInvalidPropMessage(className + ".push", pushName, e); //$NON-NLS-1$
}
}
- //init other properties which are common for all Handler
- initProperties("ALL", null, "java.util.logging.SimpleFormatter", null); //$NON-NLS-1$//$NON-NLS-2$
+ // init other properties which are common for all Handler
+ initProperties("ALL", null, "java.util.logging.SimpleFormatter", null); //$NON-NLS-1$//$NON-NLS-2$
buffer = new LogRecord[size];
}
-
+
/**
* Construct and init a {@code MemoryHandler} using given target, size and
* push level, other properties using {@code LogManager} properties or
* default values.
- *
+ *
* @param target
* the given {@code Handler} to output
* @param size
@@ -156,7 +150,7 @@ public class MemoryHandler extends Handler {
* @param pushLevel
* the push level
* @throws IllegalArgumentException
- * if {@code size}<=0
+ * if {@code size <= 0}
* @throws RuntimeException
* if property value are invalid and no default value could be
* used.
@@ -171,13 +165,13 @@ public class MemoryHandler extends Handler {
this.target = target;
this.size = size;
this.push = pushLevel;
- initProperties("ALL", null, "java.util.logging.SimpleFormatter", null); //$NON-NLS-1$//$NON-NLS-2$
+ initProperties("ALL", null, "java.util.logging.SimpleFormatter", null); //$NON-NLS-1$//$NON-NLS-2$
buffer = new LogRecord[size];
}
-
+
/**
* Close this handler and target handler, free all associated resources.
- *
+ *
* @throws SecurityException
* if security manager exists and it determines that caller does
* not have the required permissions to control this handler.
@@ -204,7 +198,7 @@ public class MemoryHandler extends Handler {
* Furthermore if the record's level is not less than the push level, the
* push action is triggered to output all the buffered records to the target
* handler, and the target handler will publish them.
- *
+ *
* @param record
* the log record
*/
@@ -225,7 +219,7 @@ public class MemoryHandler extends Handler {
/**
* Return the push level.
- *
+ *
* @return the push level
*/
public Level getPushLevel() {
@@ -233,18 +227,14 @@ public class MemoryHandler extends Handler {
}
/**
- * <p>
* Check if given {@code LogRecord} would be put into this
* {@code MemoryHandler}'s internal buffer.
- * </p>
* <p>
* The given {@code LogRecord} is loggable if and only if it has appropriate
* level and it pass any associated filter's check.
- * </p>
* <p>
* Note that the push level is not used for this check.
- * </p>
- *
+ *
* @param record
* the given {@code LogRecord}
* @return the given {@code LogRecord} if it should be logged, {@code false}
@@ -261,13 +251,13 @@ public class MemoryHandler extends Handler {
*/
public void push() {
for (int i = cursor; i < size; i++) {
- if(null != buffer[i]) {
+ if (null != buffer[i]) {
target.publish(buffer[i]);
}
buffer[i] = null;
}
for (int i = 0; i < cursor; i++) {
- if(null != buffer[i]) {
+ if (null != buffer[i]) {
target.publish(buffer[i]);
}
buffer[i] = null;
@@ -276,15 +266,15 @@ public class MemoryHandler extends Handler {
}
/**
- * Set the push level. The push level is used to check the push action
+ * Set the push level. The push level is used to check the push action
* triggering. When a new {@code LogRecord} is put into the internal
- * buffer and its level is not less than the push level, the push action
+ * buffer and its level is not less than the push level, the push action
* will be triggered. Note that set new push level won't trigger push action.
- *
+ *
* @param newLevel
* the new level to set.
* @throws SecurityException
- * if security manager exists and it determines that caller
+ * if security manager exists and it determines that caller
* does not have the required permissions to control this handler.
*/
public void setPushLevel(Level newLevel) {
diff --git a/logging/src/main/java/java/util/logging/SimpleFormatter.java b/logging/src/main/java/java/util/logging/SimpleFormatter.java
index 1595796..def4ad3 100644
--- a/logging/src/main/java/java/util/logging/SimpleFormatter.java
+++ b/logging/src/main/java/java/util/logging/SimpleFormatter.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.io.PrintWriter;
@@ -26,13 +25,10 @@ import java.util.Date;
/**
* {@code SimpleFormatter} can be used to print a summary of the information
* contained in a {@code LogRecord} object in a human readable format.
- * @since Android 1.0
*/
public class SimpleFormatter extends Formatter {
/**
* Constructs a new {@code SimpleFormatter}.
- *
- * @since Android 1.0
*/
public SimpleFormatter() {
super();
@@ -41,11 +37,10 @@ public class SimpleFormatter extends Formatter {
/**
* Converts a {@link LogRecord} object into a human readable string
* representation.
- *
+ *
* @param r
* the log record to be formatted into a string.
* @return the formatted string.
- * @since Android 1.0
*/
@Override
public String format(LogRecord r) {
@@ -53,7 +48,8 @@ public class SimpleFormatter extends Formatter {
sb.append(MessageFormat.format("{0, date} {0, time} ", //$NON-NLS-1$
new Object[] { new Date(r.getMillis()) }));
sb.append(r.getSourceClassName()).append(" "); //$NON-NLS-1$
- sb.append(r.getSourceMethodName()).append(LogManager.getSystemLineSeparator()); //$NON-NLS-1$
+ sb.append(r.getSourceMethodName()).append(
+ LogManager.getSystemLineSeparator());
sb.append(r.getLevel().getName()).append(": "); //$NON-NLS-1$
sb.append(formatMessage(r)).append(LogManager.getSystemLineSeparator());
if (null != r.getThrown()) {
@@ -66,7 +62,7 @@ public class SimpleFormatter extends Formatter {
t.printStackTrace(pw);
sb.append(sw.toString());
} finally {
- if(pw != null){
+ if (pw != null) {
try {
pw.close();
} catch (Exception e) {
@@ -78,4 +74,3 @@ public class SimpleFormatter extends Formatter {
return sb.toString();
}
}
-
diff --git a/logging/src/main/java/java/util/logging/SocketHandler.java b/logging/src/main/java/java/util/logging/SocketHandler.java
index 8626007..38cfd64 100644
--- a/logging/src/main/java/java/util/logging/SocketHandler.java
+++ b/logging/src/main/java/java/util/logging/SocketHandler.java
@@ -15,12 +15,11 @@
* limitations under the License.
*/
-
package java.util.logging;
-import java.net.Socket;
import java.io.BufferedOutputStream;
import java.io.IOException;
+import java.net.Socket;
import org.apache.harmony.logging.internal.nls.Messages;
@@ -48,16 +47,14 @@ import org.apache.harmony.logging.internal.nls.Messages;
* <li>java.util.logging.SocketHandler.encoding specifies the port number that
* this handler should connect to. There's no default value for this property.
* </ul>
- * </p>
* <p>
* This handler buffers the outgoing messages, but flushes each time a log
* record has been published.
- * </p>
* <p>
* This class is not thread-safe.
- * </p>
*/
public class SocketHandler extends StreamHandler {
+
// default level
private static final String DEFAULT_LEVEL = "ALL"; //$NON-NLS-1$
@@ -71,7 +68,7 @@ public class SocketHandler extends StreamHandler {
* Constructs a {@code SocketHandler} object using the properties read by
* the log manager, including the host name and port number. Default
* formatting uses the XMLFormatter class and level is set to ALL.
- *
+ *
* @throws IOException
* if failed to connect to the specified host and port.
* @throws IllegalArgumentException
@@ -92,7 +89,7 @@ public class SocketHandler extends StreamHandler {
* Constructs a {@code SocketHandler} object using the specified host name
* and port number together with other properties read by the log manager.
* Default formatting uses the XMLFormatter class and level is set to ALL.
- *
+ *
* @param host
* the host name
* @param port
@@ -146,7 +143,7 @@ public class SocketHandler extends StreamHandler {
/**
* Closes this handler. The network connection to the host is also closed.
- *
+ *
* @throws SecurityException
* If a security manager determines that the caller does not
* have the required permission to control this handler.
@@ -168,7 +165,7 @@ public class SocketHandler extends StreamHandler {
/**
* Logs a record if necessary. A flush operation will be done afterwards.
- *
+ *
* @param record
* the log record to be logged.
*/
@@ -177,5 +174,4 @@ public class SocketHandler extends StreamHandler {
super.publish(record);
super.flush();
}
-
}
diff --git a/logging/src/main/java/java/util/logging/StreamHandler.java b/logging/src/main/java/java/util/logging/StreamHandler.java
index ee12190..7049d45 100644
--- a/logging/src/main/java/java/util/logging/StreamHandler.java
+++ b/logging/src/main/java/java/util/logging/StreamHandler.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.io.OutputStream;
@@ -30,30 +29,26 @@ import org.apache.harmony.logging.internal.nls.Messages;
* is, objects of the class {@link java.io.OutputStream}.
* <p>
* A {@code StreamHandler} object reads the following properties from the log
- * manager to initialize itself:
+ * manager to initialize itself. A default value will be used if a property is
+ * not found or has an invalid value.
* <ul>
- * <li>java.util.logging.StreamHandler.level specifies the logging level,
- * defaults to {@code Level.INFO} if this property is not found or has an
- * invalid value.
+ * <li>java.util.logging.StreamHandler.encoding specifies the encoding this
+ * handler will use to encode log messages. Default is the encoding used by the
+ * current platform.
* <li>java.util.logging.StreamHandler.filter specifies the name of the filter
- * class to be associated with this handler, defaults to {@code null} if this
- * property is not found or has an invalid value.
+ * class to be associated with this handler. No <code>Filter</code> is used by
+ * default.
* <li>java.util.logging.StreamHandler.formatter specifies the name of the
- * formatter class to be associated with this handler, defaults to
- * {@code java.util.logging.SimpleFormatter} if this property is not found or
- * has an invalid value.
- * <li>java.util.logging.StreamHandler.encoding specifies the encoding this
- * handler will use to encode log messages, defaults to {@code null} if this
- * property is not found or has an invalid value.
+ * formatter class to be associated with this handler. Default is
+ * {@code java.util.logging.SimpleFormatter}.
+ * <li>java.util.logging.StreamHandler.level specifies the logging level.
+ * Defaults is {@code Level.INFO}.
* </ul>
- * </p>
* <p>
* This class is not thread-safe.
- * </p>
- *
- * @since Android 1.0
*/
public class StreamHandler extends Handler {
+
// the output stream this handler writes to
private OutputStream os;
@@ -66,11 +61,9 @@ public class StreamHandler extends Handler {
/**
* Constructs a {@code StreamHandler} object. The new stream handler
* does not have an associated output stream.
- *
- * @since Android 1.0
*/
public StreamHandler() {
- initProperties("INFO", null, "java.util.logging.SimpleFormatter", //$NON-NLS-1$//$NON-NLS-2$
+ initProperties("INFO", null, "java.util.logging.SimpleFormatter", //$NON-NLS-1$//$NON-NLS-2$
null);
this.os = null;
this.writer = null;
@@ -80,7 +73,7 @@ public class StreamHandler extends Handler {
/**
* Constructs a {@code StreamHandler} object with the supplied output
* stream. Default properties are read.
- *
+ *
* @param os
* the output stream this handler writes to.
*/
@@ -106,14 +99,13 @@ public class StreamHandler extends Handler {
/**
* Constructs a {@code StreamHandler} object with the supplied output stream
* and formatter.
- *
+ *
* @param os
* the output stream this handler writes to.
* @param formatter
* the formatter this handler uses to format the output.
* @throws NullPointerException
* if {@code os} or {@code formatter} is {@code null}.
- * @since Android 1.0
*/
public StreamHandler(OutputStream os, Formatter formatter) {
this();
@@ -160,7 +152,7 @@ public class StreamHandler extends Handler {
/**
* Sets the output stream this handler writes to. Note it does nothing else.
- *
+ *
* @param newOs
* the new output stream
*/
@@ -168,13 +160,12 @@ public class StreamHandler extends Handler {
this.os = newOs;
}
-
/**
* Sets the output stream this handler writes to. If there's an existing
* output stream, the tail string of the associated formatter will be
- * written to it. Then it will be flushed, closed and replaced with
+ * written to it. Then it will be flushed, closed and replaced with
* {@code os}.
- *
+ *
* @param os
* the new output stream.
* @throws SecurityException
@@ -197,7 +188,7 @@ public class StreamHandler extends Handler {
/**
* Sets the character encoding used by this handler. A {@code null} value
* indicates that the default encoding should be used.
- *
+ *
* @param encoding
* the character encoding to set.
* @throws SecurityException
@@ -205,12 +196,11 @@ public class StreamHandler extends Handler {
* have the required permission.
* @throws UnsupportedEncodingException
* if the specified encoding is not supported by the runtime.
- * @since Android 1.0
*/
@Override
public void setEncoding(String encoding) throws SecurityException,
UnsupportedEncodingException {
- //flush first before set new encoding
+ // flush first before set new encoding
this.flush();
super.setEncoding(encoding);
// renew writer only if the writer exists
@@ -234,7 +224,7 @@ public class StreamHandler extends Handler {
/**
* Closes this handler, but the underlying output stream is only closed if
* {@code closeStream} is {@code true}. Security is not checked.
- *
+ *
* @param closeStream
* whether to close the underlying output stream.
*/
@@ -264,11 +254,10 @@ public class StreamHandler extends Handler {
* this handler is written out. A flush operation and a subsequent close
* operation is then performed upon the output stream. Client applications
* should not use a handler after closing it.
- *
+ *
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
@Override
public void close() {
@@ -278,8 +267,6 @@ public class StreamHandler extends Handler {
/**
* Flushes any buffered output.
- *
- * @since Android 1.0
*/
@Override
public void flush() {
@@ -291,7 +278,8 @@ public class StreamHandler extends Handler {
this.os.flush();
}
} catch (Exception e) {
- // logging.16=Exception occurred while flushing the output stream.
+ // logging.16=Exception occurred while flushing the output
+ // stream.
getErrorManager().error(Messages.getString("logging.16"), //$NON-NLS-1$
e, ErrorManager.FLUSH_FAILURE);
}
@@ -309,10 +297,9 @@ public class StreamHandler extends Handler {
* </ul>
* If it is the first time a log record is written out, the head string of
* the formatter associated with this handler is written out first.
- *
+ *
* @param record
* the log record to be logged.
- * @since Android 1.0
*/
@Override
public synchronized void publish(LogRecord record) {
@@ -325,7 +312,8 @@ public class StreamHandler extends Handler {
try {
msg = getFormatter().format(record);
} catch (Exception e) {
- // logging.17=Exception occurred while formatting the log record.
+ // logging.17=Exception occurred while formatting the log
+ // record.
getErrorManager().error(Messages.getString("logging.17"), //$NON-NLS-1$
e, ErrorManager.FORMAT_FAILURE);
}
@@ -345,13 +333,11 @@ public class StreamHandler extends Handler {
* {@code false}.
* <p>
* Notice : Case of no output stream will return {@code false}.
- * </p>
- *
+ *
* @param record
* the log record to be checked.
* @return {@code true} if {@code record} needs to be logged, {@code false}
* otherwise.
- * @since Android 1.0
*/
@Override
public boolean isLoggable(LogRecord record) {
@@ -363,5 +349,4 @@ public class StreamHandler extends Handler {
}
return false;
}
-
}
diff --git a/logging/src/main/java/java/util/logging/XMLFormatter.java b/logging/src/main/java/java/util/logging/XMLFormatter.java
index 6279d8c..ff96813 100644
--- a/logging/src/main/java/java/util/logging/XMLFormatter.java
+++ b/logging/src/main/java/java/util/logging/XMLFormatter.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.security.AccessController;
@@ -30,8 +29,6 @@ import java.util.ResourceBundle;
* {@code XMLFormatter} uses the output handler's encoding if it is specified,
* otherwise the default platform encoding is used instead. UTF-8 is the
* recommended encoding.
- *
- * @since Android 1.0
*/
public class XMLFormatter extends Formatter {
@@ -42,8 +39,6 @@ public class XMLFormatter extends Formatter {
/**
* Constructs a new {@code XMLFormatter}.
- *
- * @since Android 1.0
*/
public XMLFormatter() {
super();
@@ -51,61 +46,63 @@ public class XMLFormatter extends Formatter {
/**
* Converts a {@code LogRecord} into an XML string.
- *
+ *
* @param r
* the log record to be formatted.
* @return the log record formatted as an XML string.
- * @since Android 1.0
*/
+ @SuppressWarnings("nls")
@Override
public String format(LogRecord r) {
- //call a method of LogRecord to ensure not null
+ // call a method of LogRecord to ensure not null
long time = r.getMillis();
- //format to date
- String date = MessageFormat.format("{0, date} {0, time}", //$NON-NLS-1$
+ // format to date
+ String date = MessageFormat.format("{0, date} {0, time}",
new Object[] { new Date(time) });
StringBuilder sb = new StringBuilder();
- sb.append(("<record>")).append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(("<date>")).append(date).append(("</date>")) //$NON-NLS-1$ //$NON-NLS-2$
+ sb.append(("<record>")).append(lineSeperator);
+ sb.append(indent).append(("<date>")).append(date).append(("</date>"))
.append(lineSeperator);
- sb.append(indent).append(("<millis>")).append(time).append( //$NON-NLS-1$
- ("</millis>")).append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(("<sequence>")).append(r.getSequenceNumber()) //$NON-NLS-1$
- .append(("</sequence>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<millis>")).append(time).append(
+ ("</millis>")).append(lineSeperator);
+ sb.append(indent).append(("<sequence>")).append(r.getSequenceNumber())
+ .append(("</sequence>")).append(lineSeperator);
if (null != r.getLoggerName()) {
- sb.append(indent).append(("<logger>")).append(r.getLoggerName()) //$NON-NLS-1$
- .append(("</logger>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<logger>")).append(r.getLoggerName())
+ .append(("</logger>")).append(lineSeperator);
}
- sb.append(indent).append(("<level>")).append(r.getLevel().getName()) //$NON-NLS-1$
- .append(("</level>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<level>")).append(r.getLevel().getName())
+ .append(("</level>")).append(lineSeperator);
if (null != r.getSourceClassName()) {
- sb.append(indent).append(("<class>")) //$NON-NLS-1$
- .append(r.getSourceClassName()).append(("</class>")) //$NON-NLS-1$
+ sb.append(indent).append(("<class>"))
+ .append(r.getSourceClassName()).append(("</class>"))
.append(lineSeperator);
}
if (null != r.getSourceMethodName()) {
- sb.append(indent).append(("<method>")).append( //$NON-NLS-1$
- r.getSourceMethodName()).append(("</method>")).append( //$NON-NLS-1$
+ sb.append(indent).append(("<method>")).append(
+ r.getSourceMethodName()).append(("</method>")).append(
lineSeperator);
}
- sb.append(indent).append(("<thread>")).append(r.getThreadID()).append( //$NON-NLS-1$
- ("</thread>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<thread>")).append(r.getThreadID()).append(
+ ("</thread>")).append(lineSeperator);
formatMessages(r, sb);
Object[] params;
if ((params = r.getParameters()) != null) {
for (Object element : params) {
- sb.append(indent).append(("<param>")).append(element).append( //$NON-NLS-1$
- ("</param>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<param>")).append(element).append(
+ ("</param>")).append(lineSeperator);
}
}
formatThrowable(r, sb);
- sb.append(("</record>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(("</record>")).append(lineSeperator);
return sb.toString();
}
+ @SuppressWarnings("nls")
private void formatMessages(LogRecord r, StringBuilder sb) {
- //get localized message if has, but don't call Formatter.formatMessage to parse pattern string
+ // get localized message if has, but don't call Formatter.formatMessage
+ // to parse pattern string
ResourceBundle rb = r.getResourceBundle();
String pattern = r.getMessage();
if (null != rb && null != pattern) {
@@ -118,49 +115,50 @@ public class XMLFormatter extends Formatter {
if (message == null) {
message = pattern;
- sb.append(indent).append(("<message>")).append(message).append( //$NON-NLS-1$
- ("</message>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<message>")).append(message).append(
+ ("</message>")).append(lineSeperator);
} else {
- sb.append(indent).append(("<message>")).append(message).append( //$NON-NLS-1$
- ("</message>")).append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(("<key>")).append(pattern).append( //$NON-NLS-1$
- ("</key>")).append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(("<catalog>")).append( //$NON-NLS-1$
- r.getResourceBundleName()).append(("</catalog>")) //$NON-NLS-1$
+ sb.append(indent).append(("<message>")).append(message).append(
+ ("</message>")).append(lineSeperator);
+ sb.append(indent).append(("<key>")).append(pattern).append(
+ ("</key>")).append(lineSeperator);
+ sb.append(indent).append(("<catalog>")).append(
+ r.getResourceBundleName()).append(("</catalog>"))
.append(lineSeperator);
}
- } else if(null != pattern){
- sb.append(indent).append(("<message>")).append(pattern).append( //$NON-NLS-1$
- ("</message>")).append(lineSeperator); //$NON-NLS-1$
- } else{
- sb.append(indent).append(("<message/>")); //$NON-NLS-1$
+ } else if (null != pattern) {
+ sb.append(indent).append(("<message>")).append(pattern).append(
+ ("</message>")).append(lineSeperator);
+ } else {
+ sb.append(indent).append(("<message/>"));
}
}
+ @SuppressWarnings("nls")
private void formatThrowable(LogRecord r, StringBuilder sb) {
Throwable t;
if ((t = r.getThrown()) != null) {
- sb.append(indent).append("<exception>").append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(indent).append("<message>").append( //$NON-NLS-1$
- t.toString()).append("</message>").append(lineSeperator); //$NON-NLS-1$
- //format throwable's stack trace
+ sb.append(indent).append("<exception>").append(lineSeperator);
+ sb.append(indent).append(indent).append("<message>").append(
+ t.toString()).append("</message>").append(lineSeperator);
+ // format throwable's stack trace
StackTraceElement[] elements = t.getStackTrace();
for (StackTraceElement e : elements) {
- sb.append(indent).append(indent).append("<frame>").append( //$NON-NLS-1$
+ sb.append(indent).append(indent).append("<frame>").append(
lineSeperator);
sb.append(indent).append(indent).append(indent).append(
- "<class>").append(e.getClassName()).append("</class>") //$NON-NLS-1$//$NON-NLS-2$
+ "<class>").append(e.getClassName()).append("</class>")
.append(lineSeperator);
sb.append(indent).append(indent).append(indent).append(
- "<method>").append(e.getMethodName()).append( //$NON-NLS-1$
- "</method>").append(lineSeperator); //$NON-NLS-1$
+ "<method>").append(e.getMethodName()).append(
+ "</method>").append(lineSeperator);
sb.append(indent).append(indent).append(indent)
- .append("<line>").append(e.getLineNumber()).append( //$NON-NLS-1$
- "</line>").append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(indent).append("</frame>").append( //$NON-NLS-1$
+ .append("<line>").append(e.getLineNumber()).append(
+ "</line>").append(lineSeperator);
+ sb.append(indent).append(indent).append("</frame>").append(
lineSeperator);
}
- sb.append(indent).append("</exception>").append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append("</exception>").append(lineSeperator);
}
}
@@ -168,54 +166,48 @@ public class XMLFormatter extends Formatter {
* Returns the header string for a set of log records formatted as XML
* strings, using the output handler's encoding if it is defined, otherwise
* using the default platform encoding.
- *
+ *
* @param h
* the output handler, may be {@code null}.
* @return the header string for log records formatted as XML strings.
- * @since Android 1.0
*/
+ @SuppressWarnings("nls")
@Override
public String getHead(Handler h) {
String encoding = null;
- if(null != h) {
+ if (null != h) {
encoding = h.getEncoding();
}
if (null == encoding) {
- encoding = getSystemProperty("file.encoding"); //$NON-NLS-1$
+ encoding = getSystemProperty("file.encoding");
}
StringBuilder sb = new StringBuilder();
- sb.append("<?xml version=\"1.0\" encoding=\"").append(encoding).append( //$NON-NLS-1$
- "\" standalone=\"no\"?>").append(lineSeperator); //$NON-NLS-1$
- sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">").append(lineSeperator); //$NON-NLS-1$
- sb.append(("<log>")); //$NON-NLS-1$
+ sb.append("<?xml version=\"1.0\" encoding=\"").append(encoding).append(
+ "\" standalone=\"no\"?>").append(lineSeperator);
+ sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">").append(lineSeperator);
+ sb.append(("<log>"));
return sb.toString();
}
/**
* Returns the tail string for a set of log records formatted as XML
* strings.
- *
+ *
* @param h
* the output handler, may be {@code null}.
* @return the tail string for log records formatted as XML strings.
- * @since Android 1.0
*/
@Override
- @SuppressWarnings("unused")
public String getTail(Handler h) {
return "</log>"; //$NON-NLS-1$
}
- //use privilege code to get system property
+ // use privilege code to get system property
private static String getSystemProperty(final String key) {
- return AccessController.doPrivileged(
- new PrivilegedAction<String>() {
+ return AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty(key);
}
});
}
-
}
-
-
diff --git a/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LoggerTest.java b/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LoggerTest.java
index 3a06078..f2bd62d 100644
--- a/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LoggerTest.java
+++ b/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LoggerTest.java
@@ -29,6 +29,8 @@ import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.LoggingPermission;
+import java.io.File;
+import java.io.FileInputStream;
import junit.framework.TestCase;
@@ -4628,6 +4630,26 @@ public class LoggerTest extends TestCase {
}
}
+ /*
+ * test initHandler
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "initHandler",
+ args = {}
+ )
+ public void test_initHandler() throws Exception {
+ File logProps = new File(LOGGING_CONFIG_FILE);
+ LogManager lm = LogManager.getLogManager();
+ lm.readConfiguration(new FileInputStream(logProps));
+
+ Logger log = Logger.getLogger("");
+ // can log properly
+ Handler[] handlers = log.getHandlers();
+ assertEquals(2, handlers.length);
+ }
+
/*
* A mock logger, used to test the protected constructors and fields.
diff --git a/logging/src/test/resources/config/java/util/logging/logging.config b/logging/src/test/resources/config/java/util/logging/logging.config
index f4c5146..6e7394b 100644
--- a/logging/src/test/resources/config/java/util/logging/logging.config
+++ b/logging/src/test/resources/config/java/util/logging/logging.config
@@ -1,3 +1,3 @@
-handlers=org.apache.harmony.logging.tests.java.util.logging.LogManagerTest$MockHandler java.util.logging.ConsoleHandler
+handlers=org.apache.harmony.logging.tests.java.util.logging.LogManagerTest$MockHandler , java.util.logging.ConsoleHandler
.level=ALL
org.apache.harmony.logging.tests.java.util.logging.LogManagerTest$MockHandler.level=OFF \ No newline at end of file
diff --git a/luni-kernel/src/main/java/java/lang/Thread.java b/luni-kernel/src/main/java/java/lang/Thread.java
index 3cde7e1..89d7ed6 100644
--- a/luni-kernel/src/main/java/java/lang/Thread.java
+++ b/luni-kernel/src/main/java/java/lang/Thread.java
@@ -73,6 +73,8 @@ import org.apache.harmony.security.fortress.SecurityUtils;
*/
public class Thread implements Runnable {
+ private static final int NANOS_PER_MILLI = 1000000;
+
/** Park states */
private static class ParkState {
/** park state indicating unparked */
@@ -973,7 +975,16 @@ public class Thread implements Runnable {
* @since Android 1.0
*/
public final void join() throws InterruptedException {
- join(0, 0);
+ VMThread t = vmThread;
+ if (t == null) {
+ return;
+ }
+
+ synchronized (t) {
+ while (isAlive()) {
+ t.wait();
+ }
+ }
}
/**
@@ -1008,18 +1019,45 @@ public class Thread implements Runnable {
* @since Android 1.0
*/
public final void join(long millis, int nanos) throws InterruptedException {
- if (millis < 0 || nanos < 0 || nanos > 999999) {
+ if (millis < 0 || nanos < 0 || nanos >= NANOS_PER_MILLI) {
throw new IllegalArgumentException();
}
- VMThread t;
+ // avoid overflow: if total > 292,277 years, just wait forever
+ boolean overflow = millis >= (Long.MAX_VALUE - nanos) / NANOS_PER_MILLI;
+ boolean forever = (millis | nanos) == 0;
+ if (forever | overflow) {
+ join();
+ return;
+ }
- t = this.vmThread;
+ VMThread t = vmThread;
+ if (t == null) {
+ return;
+ }
+
+ synchronized (t) {
+ if (!isAlive()) {
+ return;
+ }
+
+ // guaranteed not to overflow
+ long nanosToWait = millis * NANOS_PER_MILLI + nanos;
- if (t != null) {
- synchronized (t) {
- if (isAlive())
- t.wait(millis, nanos);
+ // wait until this thread completes or the timeout has elapsed
+ long start = System.nanoTime();
+ while (true) {
+ t.wait(millis, nanos);
+ if (!isAlive()) {
+ break;
+ }
+ long nanosElapsed = System.nanoTime() - start;
+ long nanosRemaining = nanosToWait - nanosElapsed;
+ if (nanosRemaining <= 0) {
+ break;
+ }
+ millis = nanosRemaining / NANOS_PER_MILLI;
+ nanos = (int) (nanosRemaining - millis * NANOS_PER_MILLI);
}
}
}
@@ -1491,8 +1529,8 @@ public class Thread implements Runnable {
break;
}
case ParkState.UNPARKED: {
- long millis = nanos / 1000000;
- nanos %= 1000000;
+ long millis = nanos / NANOS_PER_MILLI;
+ nanos %= NANOS_PER_MILLI;
parkState = ParkState.PARKED;
try {
@@ -1554,7 +1592,7 @@ public class Thread implements Runnable {
if (delayMillis <= 0) {
parkState = ParkState.UNPARKED;
} else {
- parkFor(delayMillis * 1000000);
+ parkFor(delayMillis * NANOS_PER_MILLI);
}
}
}
diff --git a/luni-kernel/src/main/native/java_lang_ProcessManager.c b/luni-kernel/src/main/native/java_lang_ProcessManager.c
index fcff1df..eaefc9f 100644
--- a/luni-kernel/src/main/native/java_lang_ProcessManager.c
+++ b/luni-kernel/src/main/native/java_lang_ProcessManager.c
@@ -91,7 +91,8 @@ static void java_lang_ProcessManager_watchChildren(JNIEnv* env, jobject o) {
while (1) {
int status;
- pid_t pid = wait(&status);
+ /* wait for children in our process group */
+ pid_t pid = waitpid(0, &status, 0);
if (pid >= 0) {
// Extract real status.
diff --git a/luni/src/main/java/java/util/ComparableTimSort.java b/luni/src/main/java/java/util/ComparableTimSort.java
index 882add1..cda4b12 100644
--- a/luni/src/main/java/java/util/ComparableTimSort.java
+++ b/luni/src/main/java/java/util/ComparableTimSort.java
@@ -150,7 +150,7 @@ class ComparableTimSort {
// If array is small, do a "mini-TimSort" with no merges
if (nRemaining < MIN_MERGE) {
- int initRunLen = countRunAndMakeAscending(a, lo, nRemaining);
+ int initRunLen = countRunAndMakeAscending(a, lo, hi);
binarySort(a, lo, hi, lo + initRunLen);
return;
}
diff --git a/luni/src/main/java/java/util/TimSort.java b/luni/src/main/java/java/util/TimSort.java
index 9c27ddc..4a9c05b 100644
--- a/luni/src/main/java/java/util/TimSort.java
+++ b/luni/src/main/java/java/util/TimSort.java
@@ -182,7 +182,7 @@ class TimSort<T> {
// If array is small, do a "mini-TimSort" with no merges
if (nRemaining < MIN_MERGE) {
- int initRunLen = countRunAndMakeAscending(a, lo, nRemaining, c);
+ int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
binarySort(a, lo, hi, lo + initRunLen, c);
return;
}
diff --git a/luni/src/main/java/org/apache/harmony/luni/util/InputStreamExposer.java b/luni/src/main/java/org/apache/harmony/luni/util/InputStreamExposer.java
new file mode 100644
index 0000000..d7c2ab8
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/luni/util/InputStreamExposer.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.luni.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * The class contains static {@link java.io.InputStream} utilities.
+ */
+public class InputStreamExposer {
+
+ /**
+ * Provides access to a protected underlying buffer of
+ * <code>ByteArrayInputStream</code>.
+ */
+ private static final Field BAIS_BUF;
+
+ /**
+ * Provides access to a protected position in the underlying buffer of
+ * <code>ByteArrayInputStream</code>.
+ */
+ private static final Field BAIS_POS;
+
+ static {
+ final Field[] f = new Field[2];
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ try {
+ f[0] = ByteArrayInputStream.class.getDeclaredField("buf");
+ f[0].setAccessible(true);
+ f[1] = ByteArrayInputStream.class.getDeclaredField("pos");
+ f[1].setAccessible(true);
+ } catch (NoSuchFieldException nsfe) {
+ throw new InternalError(nsfe.getLocalizedMessage());
+ }
+ return null;
+ }
+ });
+ BAIS_BUF = f[0];
+ BAIS_POS = f[1];
+ }
+
+ /**
+ * Reads all bytes from {@link java.io.ByteArrayInputStream} using its
+ * underlying buffer directly.
+ *
+ * @return an underlying buffer, if a current position is at the buffer
+ * beginning, and an end position is at the buffer end, or a copy of
+ * the underlying buffer part.
+ */
+ private static byte[] expose(ByteArrayInputStream bais) {
+ byte[] buffer, buf;
+ int pos;
+ synchronized (bais) {
+ int available = bais.available();
+ try {
+ buf = (byte[]) BAIS_BUF.get(bais);
+ pos = BAIS_POS.getInt(bais);
+ } catch (IllegalAccessException iae) {
+ throw new InternalError(iae.getLocalizedMessage());
+ }
+ if (pos == 0 && available == buf.length) {
+ buffer = buf;
+ } else {
+ buffer = new byte[available];
+ System.arraycopy(buf, pos, buffer, 0, available);
+ }
+ bais.skip(available);
+ }
+ return buffer;
+ }
+
+ /**
+ * The utility method for reading the whole input stream into a snapshot
+ * buffer. To speed up the access it works with an underlying buffer for a
+ * given {@link java.io.ByteArrayInputStream}.
+ *
+ * @param is
+ * the stream to be read.
+ * @return the snapshot wrapping the buffer where the bytes are read to.
+ * @throws UnsupportedOperationException if the input stream data cannot be exposed
+ */
+ public static byte[] expose(InputStream is) throws IOException, UnsupportedOperationException {
+ // BEGIN android-changed
+ // if (is instanceof ExposedByteArrayInputStream) {
+ // return ((ExposedByteArrayInputStream) is).expose();
+ // }
+
+ if (is.getClass().equals(ByteArrayInputStream.class)) {
+ return expose((ByteArrayInputStream) is);
+ }
+
+ // We don't know how to do this
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/luni/util/ThreadLocalCache.java b/luni/src/main/java/org/apache/harmony/luni/util/ThreadLocalCache.java
new file mode 100644
index 0000000..cdfe0c8
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/luni/util/ThreadLocalCache.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.luni.util;
+
+import java.lang.ref.SoftReference;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+
+/**
+ * The class extends the functionality of {@link java.lang.ThreadLocal} with
+ * possibility of discarding the thread local storage content when a heap is
+ * exhausted.
+ */
+public class ThreadLocalCache<T> {
+
+ private SoftReference<ThreadLocal<T>> storage = new SoftReference<ThreadLocal<T>>(
+ null);
+
+ private ThreadLocal<T> getThreadLocal() {
+ ThreadLocal<T> tls = storage.get();
+ if (tls == null) {
+ tls = new ThreadLocal<T>() {
+ public T initialValue() {
+ return ThreadLocalCache.this.initialValue();
+ }
+ };
+ storage = new SoftReference<ThreadLocal<T>>(tls);
+ }
+ return tls;
+ }
+
+ /**
+ * Returns the initial value for the cache for the current thread.
+ */
+ protected T initialValue() {
+ return null;
+ }
+
+ /**
+ * Returns the thread local value of this object.
+ */
+ public T get() {
+ return getThreadLocal().get();
+ }
+
+ /**
+ * Sets the value of this variable for the current thread. Might be useful
+ * for expanding the thread local cache.
+ */
+ public void set(T value) {
+ getThreadLocal().set(value);
+ }
+
+ /**
+ * Discards the cache for all threads.
+ */
+ public void remove() {
+ storage.clear();
+ }
+
+ public static ThreadLocalCache<CharsetDecoder> utf8Decoder = new ThreadLocalCache<CharsetDecoder>() {
+ protected CharsetDecoder initialValue() {
+ return Charset.forName("UTF-8").newDecoder();
+ }
+ };
+
+ public static ThreadLocalCache<CharsetEncoder> utf8Encoder = new ThreadLocalCache<CharsetEncoder>() {
+ protected CharsetEncoder initialValue() {
+ return Charset.forName("UTF-8").newEncoder();
+ }
+ };
+
+ public static ThreadLocalCache<java.nio.ByteBuffer> byteBuffer = new ThreadLocalCache<java.nio.ByteBuffer>() {
+ protected java.nio.ByteBuffer initialValue() {
+ return java.nio.ByteBuffer.allocate(72); // >=
+ // Manifest.LINE_LENGTH_LIMIT
+ }
+ };
+
+ public static ThreadLocalCache<CharBuffer> charBuffer = new ThreadLocalCache<CharBuffer>() {
+ protected CharBuffer initialValue() {
+ return CharBuffer.allocate(72); // no specific requirement
+ }
+ };
+
+}
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 5bd7907..3f7b0b1 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
@@ -14,14 +14,26 @@
* limitations under the License.
*/
+#define LOG_TAG "OSMemory"
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
#include "utils/misc.h"
+#include "utils/Log.h"
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+/*
+ * Cached dalvik.system.VMRuntime pieces.
+ */
+static struct {
+ jmethodID method_trackExternalAllocation;
+ jmethodID method_trackExternalFree;
+
+ jobject runtimeInstance;
+} gIDCache;
+
#undef MMAP_READ_ONLY
#define MMAP_READ_ONLY 1L
#undef MMAP_READ_WRITE
@@ -55,11 +67,28 @@ static jint harmony_nio_getPointerSizeImpl(JNIEnv *_env, jclass _this) {
* Signature: (I)I
*/
static jint harmony_nio_mallocImpl(JNIEnv *_env, jobject _this, jint size) {
- void *returnValue = malloc(size);
- if(returnValue == NULL) {
- jniThrowException(_env, "java.lang.OutOfMemoryError", "");
+ jboolean allowed = _env->CallBooleanMethod(gIDCache.runtimeInstance,
+ gIDCache.method_trackExternalAllocation, (jlong) size);
+ if (!allowed) {
+ LOGW("External allocation of %d bytes was rejected\n", size);
+ jniThrowException(_env, "java/lang/OutOfMemoryError", NULL);
+ return 0;
}
- return (jint)returnValue;
+
+ LOGV("OSMemory alloc %d\n", size);
+ void *returnValue = malloc(size + sizeof(jlong));
+ if (returnValue == NULL) {
+ jniThrowException(_env, "java/lang/OutOfMemoryError", NULL);
+ return 0;
+ }
+
+ /*
+ * Tuck a copy of the size at the head of the buffer. We need this
+ * so harmony_nio_freeImpl() knows how much memory is being freed.
+ */
+ jlong* adjptr = (jlong*) returnValue;
+ *adjptr++ = size;
+ return (jint)adjptr;
}
/*
@@ -68,7 +97,12 @@ static jint harmony_nio_mallocImpl(JNIEnv *_env, jobject _this, jint size) {
* Signature: (I)V
*/
static void harmony_nio_freeImpl(JNIEnv *_env, jobject _this, jint pointer) {
- free((void *)pointer);
+ jlong* adjptr = (jlong*) pointer;
+ jint size = *--adjptr;
+ LOGV("OSMemory free %d\n", size);
+ _env->CallVoidMethod(gIDCache.runtimeInstance,
+ gIDCache.method_trackExternalFree, (jlong) size);
+ free((void *)adjptr);
}
/*
@@ -577,6 +611,46 @@ static JNINativeMethod gMethods[] = {
{ "flushImpl", "(IJ)I", (void*) harmony_nio_flushImpl }
};
int register_org_apache_harmony_luni_platform_OSMemory(JNIEnv *_env) {
- return jniRegisterNativeMethods(_env, "org/apache/harmony/luni/platform/OSMemory",
+ /*
+ * We need to call VMRuntime.trackExternal{Allocation,Free}. Cache
+ * method IDs and a reference to the singleton.
+ */
+ static const char* kVMRuntimeName = "dalvik/system/VMRuntime";
+ jmethodID method_getRuntime;
+ jclass clazz;
+
+ clazz = _env->FindClass(kVMRuntimeName);
+ if (clazz == NULL) {
+ LOGE("Unable to find class %s\n", kVMRuntimeName);
+ return -1;
+ }
+ gIDCache.method_trackExternalAllocation = _env->GetMethodID(clazz,
+ "trackExternalAllocation", "(J)Z");
+ gIDCache.method_trackExternalFree = _env->GetMethodID(clazz,
+ "trackExternalFree", "(J)V");
+ method_getRuntime = _env->GetStaticMethodID(clazz,
+ "getRuntime", "()Ldalvik/system/VMRuntime;");
+
+ if (gIDCache.method_trackExternalAllocation == NULL ||
+ gIDCache.method_trackExternalFree == NULL ||
+ method_getRuntime == NULL)
+ {
+ LOGE("Unable to find VMRuntime methods\n");
+ return -1;
+ }
+
+ jobject instance = _env->CallStaticObjectMethod(clazz, method_getRuntime);
+ if (instance == NULL) {
+ LOGE("Unable to obtain VMRuntime instance\n");
+ return -1;
+ }
+ gIDCache.runtimeInstance = _env->NewGlobalRef(instance);
+
+ /*
+ * Register methods.
+ */
+ return jniRegisterNativeMethods(_env,
+ "org/apache/harmony/luni/platform/OSMemory",
gMethods, NELEM(gMethods));
}
+
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 f79c019..e105f5c 100755..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
@@ -33,9 +33,13 @@
#include <cutils/properties.h>
#include <cutils/adb_networking.h>
-#include <utils/LogSocket.h>
#include "AndroidSystemNatives.h"
+// Temporary hack to build on systems that don't have up-to-date libc headers.
+#ifndef IPV6_TCLASS
+#define IPV6_TCLASS 67
+#endif
+
/**
* @name Socket Errors
* Error codes for socket operations
@@ -145,6 +149,9 @@
// wait for 500000 usec = 0.5 second
#define SEND_RETRY_TIME 500000
+// Local constants for getOrSetSocketOption
+#define SOCKOPT_GET 1
+#define SOCKOPT_SET 2
struct CachedFields {
jfieldID fd_descriptor;
@@ -238,30 +245,59 @@ static int javaAddressToStructIn(
}
/**
- * Converts a native address structure to a 4-byte array. Throws a
+ * Converts a native address structure to a Java byte array. 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.
+ *
+ * @param address the sockaddr_storage structure to convert
+ *
+ * @exception SocketException the address family is unknown, or out of memory
+ *
*/
-static int structInToJavaAddress(
- JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
-
- if (java_address == NULL) {
- return -1;
+static jbyteArray socketAddressToAddressBytes(JNIEnv *env,
+ struct sockaddr_storage *address) {
+
+ void *rawAddress;
+ size_t addressLength;
+ if (address->ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) address;
+ rawAddress = &sin->sin_addr.s_addr;
+ addressLength = 4;
+ } else if (address->ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
+ rawAddress = &sin6->sin6_addr.s6_addr;
+ addressLength = 16;
+ } else {
+ throwSocketException(env, SOCKERR_BADAF);
+ return NULL;
}
- if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
- return -1;
+ jbyteArray byteArray = env->NewByteArray(addressLength);
+ if (byteArray == NULL) {
+ throwSocketException(env, SOCKERR_NOBUFFERS);
+ return NULL;
}
+ env->SetByteArrayRegion(byteArray, 0, addressLength, (jbyte *) rawAddress);
- jbyte *java_address_bytes;
-
- java_address_bytes = env->GetByteArrayElements(java_address, NULL);
-
- memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
-
- env->ReleaseByteArrayElements(java_address, java_address_bytes, 0);
+ return byteArray;
+}
- return 0;
+/**
+ * Returns the port number in a sockaddr_storage structure.
+ *
+ * @param address the sockaddr_storage structure to get the port from
+ *
+ * @return the port number, or -1 if the address family is unknown.
+ */
+static int getSocketAddressPort(struct sockaddr_storage *address) {
+ switch (address->ss_family) {
+ case AF_INET:
+ return ntohs(((struct sockaddr_in *) address)->sin_port);
+ case AF_INET6:
+ return ntohs(((struct sockaddr_in6 *) address)->sin6_port);
+ default:
+ return -1;
+ }
}
/**
@@ -269,68 +305,79 @@ static int structInToJavaAddress(
* 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.
+ *
+ * @param sockaddress the sockaddr_storage structure to convert
+ *
+ * @return a jobject representing an InetAddress
*/
-static int socketAddressToInetAddress(JNIEnv *env,
- struct sockaddr_in *sockaddress, jobject inetaddress, int *port) {
+static jobject socketAddressToInetAddress(JNIEnv *env,
+ struct sockaddr_storage *sockaddress) {
- jbyteArray ipaddress;
- int result;
-
- ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
- gCachedFields.iaddr_ipaddress);
-
- if (structInToJavaAddress(env, &sockaddress->sin_addr, ipaddress) < 0) {
- return -1;
- }
-
- *port = ntohs(sockaddress->sin_port);
+ jbyteArray byteArray = socketAddressToAddressBytes(env, sockaddress);
+ if (byteArray == NULL) // Exception has already been thrown.
+ return NULL;
- return 0;
+ return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_getbyaddress, byteArray);
}
/**
- * Converts an InetAddress object to a native address structure.
- * Throws a NullPointerException or an IOException in case of
+ * Converts an InetAddress object and port number to a native address structure.
+ * Throws a NullPointerException or a SocketException in case of
* error. This is signaled by a return value of -1. The normal
* return value is 0.
+ *
+ * @param inetaddress the InetAddress object to convert
+ * @param port the port number
+ * @param sockaddress the sockaddr_storage structure to write to
+ *
+ * @return 0 on success, -1 on failure
+ *
+ * @exception SocketError if the address family is unknown
*/
static int inetAddressToSocketAddress(JNIEnv *env,
- jobject inetaddress, int port, struct sockaddr_in *sockaddress) {
-
- jbyteArray ipaddress;
- int result;
+ jobject inetaddress, int port, struct sockaddr_storage *sockaddress) {
- ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
+ // Get the byte array that stores the IP address bytes in the InetAddress.
+ jbyteArray addressByteArray;
+ addressByteArray = (jbyteArray)env->GetObjectField(inetaddress,
gCachedFields.iaddr_ipaddress);
-
- memset(sockaddress, 0, sizeof(sockaddress));
-
- sockaddress->sin_family = AF_INET;
- sockaddress->sin_port = htons(port);
-
- if (javaAddressToStructIn(env, ipaddress, &(sockaddress->sin_addr)) < 0) {
- return -1;
+ if (addressByteArray == NULL) {
+ throwNullPointerException(env);
+ return -1;
}
- return 0;
-}
-
-static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) {
- jbyteArray bytes;
- int success;
-
- bytes = env->NewByteArray(4);
-
- if (bytes == NULL) {
- return NULL;
+ // Get the raw IP address bytes.
+ jbyte *addressBytes = env->GetByteArrayElements(addressByteArray, NULL);
+ if (addressBytes == NULL) {
+ throwNullPointerException(env);
+ return -1;
}
- if (structInToJavaAddress(env, address, bytes) < 0) {
- return NULL;
+ // Convert the IP address bytes to the proper IP address type.
+ size_t addressLength = env->GetArrayLength(addressByteArray);
+ int result = 0;
+ if (addressLength == 4) {
+ // IPv4 address.
+ struct sockaddr_in *sin = (struct sockaddr_in *) sockaddress;
+ memset(sin, 0, sizeof(struct sockaddr_in));
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(port);
+ memcpy(&sin->sin_addr.s_addr, addressBytes, 4);
+ } else if (addressLength == 16) {
+ // IPv6 address.
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sockaddress;
+ memset(sin6, 0, sizeof(struct sockaddr_in6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(port);
+ memcpy(&sin6->sin6_addr.s6_addr, addressBytes, 16);
+ } else {
+ // Unknown address family.
+ throwSocketException(env, SOCKERR_BADAF);
+ result = -1;
}
-
- return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
- gCachedFields.iaddr_getbyaddress, bytes);
+ env->ReleaseByteArrayElements(addressByteArray, addressBytes, 0);
+ return result;
}
/**
@@ -427,15 +474,77 @@ static int time_msec_clock() {
}
/**
- * check if the passed sockaddr_in struct contains a localhost address
+ * Check if the passed sockaddr_storage struct contains a localhost address
*
- * @param[in] address pointer to the address to check
+ * @param address address pointer to the address to check
*
* @return 0 if the passed address isn't a localhost address
*/
-static int isLocalhost(struct sockaddr_in *address) {
- // return address == 127.0.0.1
- return (unsigned int) address->sin_addr.s_addr == 16777343;
+static int isLocalHost(struct sockaddr_storage *address) {
+ if (address->ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) address;
+ return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK));
+ } else if (address->ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
+ return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Decide whether to use ADB networking for the given socket address.
+ *
+ * @param address pointer to sockaddr_storage structure to check
+ *
+ * @return true if ADB networking should be used, false otherwise.
+ */
+static bool useAdbNetworkingForAddress(struct sockaddr_storage *address) {
+ return useAdbNetworking && !isLocalHost(address) &&
+ address->ss_family == AF_INET;
+}
+
+/**
+ * Convert a sockaddr_storage structure to a string for logging purposes.
+ *
+ * @param address pointer to sockaddr_storage structure to print
+ *
+ * @return a string with the textual representation of the address.
+ *
+ * @note Returns a statically allocated buffer, so is not thread-safe.
+ */
+static char *socketAddressToString(struct sockaddr_storage *address) {
+ static char invalidString[] = "<invalid>";
+ static char ipString[INET6_ADDRSTRLEN + sizeof("[]:65535")];
+
+ char tmp[INET6_ADDRSTRLEN];
+ int port;
+ // TODO: getnameinfo seems to want its length parameter to be exactly
+ // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
+ // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
+ // then remove this hack.
+ int size = (address->ss_family == AF_INET) ?
+ sizeof(sockaddr_in) : sizeof(sockaddr_in6);
+ int result = getnameinfo((struct sockaddr *)address,
+ size, tmp, sizeof(tmp), NULL, 0,
+ NI_NUMERICHOST);
+
+ if (result != 0)
+ return invalidString;
+
+ if (address->ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
+ port = ntohs(sin6->sin6_port);
+ sprintf(ipString, "[%s]:%d", tmp, port);
+ return ipString;
+ } else if (address->ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) address;
+ port = ntohs(sin->sin_port);
+ sprintf(ipString, "%s:%d", tmp, port);
+ return ipString;
+ } else {
+ return invalidString;
+ }
}
/**
@@ -728,7 +837,6 @@ static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout, int
}
} else if (0 > result) {
- log_socket_close(handle, result);
throwSocketException(env, result);
}
poll = 0;
@@ -745,7 +853,6 @@ static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout, int
continue; // try again
} else if (0 > result) {
- log_socket_close(handle, result);
throwSocketException(env, result);
}
poll = 0;
@@ -756,6 +863,24 @@ static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout, int
}
/**
+ * Obtain the socket address family from an existing socket.
+ *
+ * @param socket the filedescriptor of the socket to examine
+ *
+ * @return an integer, the address family of the socket
+ */
+static int getSocketAddressFamily(int socket) {
+ struct sockaddr_storage ss;
+ socklen_t namelen = sizeof(ss);
+ int ret = getsockname(socket, (struct sockaddr*) &ss, &namelen);
+ if (ret != 0) {
+ return AF_UNSPEC;
+ } else {
+ return ss.ss_family;
+ }
+}
+
+/**
* A helper method, to set the connect context to a Long object.
*
* @param env pointer to the JNI library
@@ -803,6 +928,77 @@ unsigned short ip_checksum(unsigned short* buffer, int size) {
}
/**
+ * Converts an IPv4 address to an IPv4-mapped IPv6 address. Performs no error
+ * checking.
+ *
+ * @param address the address to convert. Must contain an IPv4 address.
+ * @param outputAddress the converted address. Will contain an IPv6 address.
+ * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
+ */
+static void ipv4ToMappedAddress(struct sockaddr_storage *address,
+ struct sockaddr_storage *outputAddress, bool mapUnspecified) {
+ memset(outputAddress, 0, sizeof(struct sockaddr_storage));
+ const struct sockaddr_in *sin = ((struct sockaddr_in *) address);
+ struct sockaddr_in6 *sin6 = ((struct sockaddr_in6 *) outputAddress);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
+ if (sin->sin_addr.s_addr != 0 || mapUnspecified) {
+ sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
+ }
+ sin6->sin6_port = sin->sin_port;
+}
+
+/**
+ * Wrapper for connect() that converts IPv4 addresses to IPv4-mapped IPv6
+ * addresses if necessary.
+ *
+ * @param socket the filedescriptor of the socket to connect
+ * @param socketAddress the address to connect to
+ */
+static int doConnect(int socket, struct sockaddr_storage *socketAddress) {
+ struct sockaddr_storage mappedAddress;
+ struct sockaddr_storage *realAddress;
+ if (socketAddress->ss_family == AF_INET &&
+ getSocketAddressFamily(socket) == AF_INET6) {
+ ipv4ToMappedAddress(socketAddress, &mappedAddress, true);
+ realAddress = &mappedAddress;
+ } else {
+ realAddress = socketAddress;
+ }
+ int ret;
+ do {
+ ret = connect(socket, (struct sockaddr *) realAddress,
+ sizeof(struct sockaddr_storage));
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+/**
+ * Wrapper for bind() that converts IPv4 addresses to IPv4-mapped IPv6
+ * addresses if necessary.
+ *
+ * @param socket the filedescriptor of the socket to connect
+ * @param socketAddress the address to connect to
+ */
+static int doBind(int socket, struct sockaddr_storage *socketAddress) {
+ struct sockaddr_storage mappedAddress;
+ struct sockaddr_storage *realAddress;
+ if (socketAddress->ss_family == AF_INET &&
+ getSocketAddressFamily(socket) == AF_INET6) {
+ ipv4ToMappedAddress(socketAddress, &mappedAddress, false);
+ realAddress = &mappedAddress;
+ } else {
+ realAddress = socketAddress;
+ }
+ int ret;
+ do {
+ ret = bind(socket, (struct sockaddr *) realAddress,
+ sizeof(struct sockaddr_storage));
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+/**
* Establish a connection to a peer with a timeout. This function is called
* repeatedly in order to carry out the connect and to allow other tasks to
* proceed on certain platforms. The caller must first call with
@@ -823,7 +1019,7 @@ unsigned short ip_checksum(unsigned short* buffer, int size) {
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
-static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
+static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
unsigned int timeout, unsigned int step, jbyte *ctxt) {
int rc = 0;
struct timeval passedTimeout;
@@ -838,16 +1034,14 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
context->sock = handle;
context->nfds = handle + 1;
- if (useAdbNetworking && !isLocalhost(&addr)) {
+ if (useAdbNetworkingForAddress(&addr)) {
// LOGD("+connect to address 0x%08x (via adb)",
// addr.sin_addr.s_addr);
- rc = adb_networking_connect_fd(handle, &addr);
+ rc = adb_networking_connect_fd(handle, (struct sockaddr_in *) &addr);
// LOGD("-connect ret %d errno %d (via adb)", rc, errno);
} else {
- log_socket_connect(handle, ntohl(addr.sin_addr.s_addr),
- ntohs(addr.sin_port));
/* set the socket to non-blocking */
int block = JNI_TRUE;
rc = ioctl(handle, FIONBIO, &block);
@@ -857,10 +1051,7 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
// LOGD("+connect to address 0x%08x (via normal) on handle %d",
// addr.sin_addr.s_addr, handle);
- do {
- rc = connect(handle, (struct sockaddr *) &addr,
- sizeof(struct sockaddr));
- } while (rc < 0 && errno == EINTR);
+ rc = doConnect(handle, &addr);
// LOGD("-connect to address 0x%08x (via normal) returned %d",
// addr.sin_addr.s_addr, (int) rc);
@@ -971,6 +1162,89 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
return SOCKERR_ARGSINVALID;
}
+
+/**
+ * Helper method to get or set socket options
+ *
+ * @param action SOCKOPT_GET to get an option, SOCKOPT_SET to set it
+ * @param socket the file descriptor of the socket to use
+ * @param ipv4Option the option value to use for an IPv4 socket
+ * @param ipv6Option the option value to use for an IPv6 socket
+ * @param optionValue the value of the socket option to get or set
+ * @param optionLength the length of the socket option to get or set
+ *
+ * @return the value of the socket call, or -1 on failure inside this function
+ *
+ * @note on internal failure, the errno variable will be set appropriately
+ */
+static int getOrSetSocketOption(int action, int socket, int ipv4Option,
+ int ipv6Option, void *optionValue, socklen_t *optionLength) {
+ int option;
+ int protocol;
+ int family = getSocketAddressFamily(socket);
+ switch (family) {
+ case AF_INET:
+ option = ipv4Option;
+ protocol = IPPROTO_IP;
+ break;
+ case AF_INET6:
+ option = ipv6Option;
+ protocol = IPPROTO_IPV6;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+ if (action == SOCKOPT_GET) {
+ return getsockopt(socket, protocol, option, &optionValue, optionLength);
+ } else if (action == SOCKOPT_SET) {
+ return setsockopt(socket, protocol, option, &optionValue,
+ *optionLength);
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+ * Find the interface index that was set for this socket by the IP_MULTICAST_IF
+ * or IPV6_MULTICAST_IF socket option.
+ *
+ * @param socket the socket to examine
+ *
+ * @return the interface index, or -1 on failure
+ *
+ * @note on internal failure, the errno variable will be set appropriately
+ */
+static int interfaceIndexFromMulticastSocket(int socket) {
+ int family = getSocketAddressFamily(socket);
+ socklen_t requestLength;
+ int interfaceIndex;
+ int result;
+ if (family == AF_INET) {
+ // IP_MULTICAST_IF returns a pointer to a struct ip_mreqn.
+ struct ip_mreqn tempRequest;
+ requestLength = sizeof(tempRequest);
+ result = getsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &tempRequest,
+ &requestLength);
+ interfaceIndex = tempRequest.imr_ifindex;
+ } else if (family == AF_INET6) {
+ // IPV6_MULTICAST_IF returns a pointer to an integer.
+ requestLength = sizeof(interfaceIndex);
+ result = getsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ &interfaceIndex, &requestLength);
+ } else {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ if (result == 0)
+ return interfaceIndex;
+ else
+ return -1;
+}
+
+
/**
* Join/Leave the nominated multicast group on the specified socket.
* Implemented by setting the multicast 'add membership'/'drop membership'
@@ -994,103 +1268,112 @@ static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
*/
static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
int ignoreIF, int setSockOptVal) {
+ struct sockaddr_storage sockaddrP;
int result;
- struct ip_mreq ipmreqP;
- struct sockaddr_in sockaddrP;
- int length = sizeof(struct ip_mreq);
- socklen_t lengthIF = sizeof(struct sockaddr_in);
-
- /*
- * JNI objects needed to access the information in the optVal oject
- * passed in. The object passed in is a GenericIPMreq object
- */
- jclass cls;
- jfieldID multiaddrID;
- jfieldID interfaceAddrID;
- jobject multiaddr;
- jobject interfaceAddr;
+ // By default, let the system decide which interface to use.
+ int interfaceIndex = 0;
/*
- * check whether we are getting an InetAddress or an Generic IPMreq, for now
- * we support both so that we will not break the tests
+ * Check whether we are getting an InetAddress or an Generic IPMreq. For now
+ * we support both so that we will not break the tests. If an InetAddress
+ * is passed in, only support IPv4 as obtaining an interface from an
+ * InetAddress is complex and should be done by the Java caller.
*/
if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
+ /*
+ * optVal is an InetAddress. Construct a multicast request structure
+ * from this address. Support IPv4 only.
+ */
+ struct ip_mreqn multicastRequest;
+ socklen_t length = sizeof(multicastRequest);
+ memset(&multicastRequest, 0, length);
- ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
+ // If ignoreIF is false, determine the index of the interface to use.
if (!ignoreIF) {
-
- result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockaddrP,
- &lengthIF);
-
- if (0 != result) {
- throwSocketException (env, convertError(errno));
+ interfaceIndex = interfaceIndexFromMulticastSocket(handle);
+ multicastRequest.imr_ifindex = interfaceIndex;
+ if (interfaceIndex == -1) {
+ throwSocketException(env, convertError(errno));
return;
}
-
- memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
}
+ // Convert the inetAddress to an IPv4 address structure.
result = inetAddressToSocketAddress(env, optVal, 0, &sockaddrP);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ if (result < 0) // Exception has already been thrown.
+ return;
+ if (sockaddrP.ss_family != AF_INET) {
+ throwSocketException(env, SOCKERR_BADAF);
return;
}
+ struct sockaddr_in *sin = (struct sockaddr_in *) &sockaddrP;
+ multicastRequest.imr_multiaddr = sin->sin_addr;
- memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
-
- result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+ result = setsockopt(handle, IPPROTO_IP, setSockOptVal,
+ &multicastRequest, length);
if (0 != result) {
throwSocketException (env, convertError(errno));
return;
}
-
} else {
+ /*
+ * optVal is a GenericIPMreq object. Extract the relevant fields from
+ * it and construct a multicast request structure from these. Support
+ * both IPv4 and IPv6.
+ */
+ jclass cls;
+ jfieldID multiaddrID;
+ jfieldID interfaceIdxID;
+ jobject multiaddr;
- /* we need the multicast address regardless of the type of address */
+ // Get the multicast address to join or leave.
cls = env->GetObjectClass(optVal);
multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
multiaddr = env->GetObjectField(optVal, multiaddrID);
- result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
- return;
+ // Get the interface index to use.
+ if (! ignoreIF) {
+ interfaceIdxID = env->GetFieldID(cls, "interfaceIdx", "I");
+ interfaceIndex = env->GetIntField(optVal, interfaceIdxID);
}
- memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
-
- /* we need to use an IP_MREQ as it is an IPV4 address */
- interfaceAddrID = env->GetFieldID(cls, "interfaceAddr",
- "Ljava/net/InetAddress;");
- interfaceAddr = env->GetObjectField(optVal, interfaceAddrID);
-
- ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
-
- /*
- * if an interfaceAddr was passed then use that value, otherwise set the
- * interface to all 0 to indicate the system should select the interface
- * used
- */
- if (!ignoreIF) {
- if (NULL != interfaceAddr) {
-
- result = inetAddressToSocketAddress(env, interfaceAddr, 0,
- &sockaddrP);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
- return;
- }
-
- memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
+ result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
+ if (result < 0) // Exception has already been thrown.
+ return;
- }
+ struct ip_mreqn ipv4Request;
+ struct ipv6_mreq ipv6Request;
+ void *multicastRequest;
+ socklen_t requestLength;
+ int level;
+ int family = getSocketAddressFamily(handle);
+ switch (family) {
+ case AF_INET:
+ requestLength = sizeof(ipv4Request);
+ memset(&ipv4Request, 0, requestLength);
+ ipv4Request.imr_multiaddr =
+ ((struct sockaddr_in *) &sockaddrP)->sin_addr;
+ ipv4Request.imr_ifindex = interfaceIndex;
+ multicastRequest = &ipv4Request;
+ level = IPPROTO_IP;
+ break;
+ case AF_INET6:
+ requestLength = sizeof(ipv6Request);
+ memset(&ipv6Request, 0, requestLength);
+ ipv6Request.ipv6mr_multiaddr =
+ ((struct sockaddr_in6 *) &sockaddrP)->sin6_addr;
+ ipv6Request.ipv6mr_interface = interfaceIndex;
+ multicastRequest = &ipv6Request;
+ level = IPPROTO_IPV6;
+ break;
+ default:
+ throwSocketException (env, SOCKERR_BADAF);
+ return;
}
/* join/drop the multicast address */
- result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+ result = setsockopt(handle, level, setSockOptVal, multicastRequest,
+ requestLength);
if (0 != result) {
throwSocketException (env, convertError(errno));
return;
@@ -1339,38 +1622,48 @@ static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
}
-static void osNetworkSystem_createSocketImpl(JNIEnv* env, jclass clazz,
- jobject fileDescriptor, jboolean preferIPv4Stack) {
- // LOGD("ENTER createSocketImpl");
-
- int ret = socket(PF_INET, SOCK_STREAM, 0);
+/**
+ * Helper function to create a socket of the specified type and bind it to a
+ * Java file descriptor.
+ *
+ * @param fileDescriptor the file descriptor to bind the socket to
+ * @param type the socket type to create, e.g., SOCK_STREAM
+ *
+ * @return the socket file descriptor, or -1 on failure
+ *
+ */
+static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor,
+ int type) {
+ if (fileDescriptor == NULL) {
+ throwNullPointerException(env);
+ errno = EBADF;
+ return -1;
+ }
- if (ret < 0) {
+ int sock;
+ sock = socket(PF_INET6, type, 0);
+ if (sock < 0 && errno == EAFNOSUPPORT) {
+ sock = socket(PF_INET, type, 0);
+ }
+ if (sock < 0) {
int err = convertError(errno);
throwSocketException(env, err);
- return;
}
+ jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
+ return sock;
+}
- jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
- return;
+static void osNetworkSystem_createSocketImpl(JNIEnv* env, jclass clazz,
+ jobject fileDescriptor, jboolean preferIPv4Stack) {
+ // LOGD("ENTER createSocketImpl");
+ createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
}
static void osNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
jobject fileDescriptor, jboolean preferIPv4Stack) {
// LOGD("ENTER createDatagramSocketImpl");
-
- int ret = socket(PF_INET, SOCK_DGRAM, 0);
-
- if (ret < 0) {
- int err = convertError(errno);
- throwSocketException(env, err);
- return;
- }
-
- jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
-
- return;
+ createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
}
static jint osNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
@@ -1379,7 +1672,7 @@ static jint osNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
// LOGD("ENTER readSocketDirectImpl");
int handle;
- jbyte *message = (jbyte *)address;
+ jbyte *message = (jbyte *)address + offset;
int result, ret, localCount;
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
@@ -1405,11 +1698,9 @@ static jint osNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
return -1;
} else if (ret == -1) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
- add_recv_stats(handle, ret);
return ret;
}
@@ -1437,7 +1728,7 @@ static jint osNetworkSystem_readSocketImpl(JNIEnv* env, jclass clazz,
}
result = osNetworkSystem_readSocketDirectImpl(env, clazz, fileDescriptor,
- (jint) message, offset, count, timeout);
+ (jint) message, 0, localCount, timeout);
if (result > 0) {
env->SetByteArrayRegion(data, offset, result, (jbyte *)message);
@@ -1455,7 +1746,7 @@ static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
// LOGD("ENTER writeSocketDirectImpl");
int handle;
- jbyte *message = (jbyte *)address;
+ jbyte *message = (jbyte *)address + offset;
int result = 0, sent = 0;
if (count <= 0) {
@@ -1472,7 +1763,6 @@ static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
if (result < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
if (SOCKERR_WOULDBLOCK == err){
jclass socketExClass,errorCodeExClass;
@@ -1499,7 +1789,7 @@ static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
if (!socketExConstructor) {
return 0;
}
- socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString);
+ socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString);
socketExCauseMethod = env->GetMethodID(socketExClass,"initCause","(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
env->CallObjectMethod(socketEx,socketExCauseMethod,errorCodeEx);
env->Throw((jthrowable)socketEx);
@@ -1509,7 +1799,6 @@ static jint osNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
return 0;
}
- add_send_stats(handle, result);
return result;
}
@@ -1539,13 +1828,13 @@ static jint osNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
env->GetByteArrayRegion(data, offset, count, message);
result = osNetworkSystem_writeSocketDirectImpl(env, clazz, fileDescriptor,
- (jint) message, offset, count);
+ (jint) message, 0, count);
if (( jbyte *)message != internalBuffer) {
- free(( jbyte *)message);
+ free(( jbyte *)message);
}
#undef INTERNAL_SEND_BUFFER_MAX
- return result;
+ return result;
}
static void osNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
@@ -1581,36 +1870,25 @@ static jint osNetworkSystem_connectWithTimeoutSocketImpl(JNIEnv* env,
int handle;
int result = 0;
- struct sockaddr_in address;
+ struct sockaddr_storage address;
jbyte *context = NULL;
- memset(&address, 0, sizeof(address));
-
- address.sin_family = AF_INET;
-
- result = inetAddressToSocketAddress(env, inetAddr, port,
- (struct sockaddr_in *) &address);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ result = inetAddressToSocketAddress(env, inetAddr, port, &address);
+ if (result < 0)
return result;
- }
// Check if we're using adb networking and redirect in case it is used.
- if (useAdbNetworking && !isLocalhost(&address)) {
+ if (useAdbNetworkingForAddress(&address)) {
return osNetworkSystem_connectSocketImpl(env, clazz, fileDescriptor,
trafficClass, inetAddr, port);
}
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return -1;
}
- address.sin_port = htons(port);
-
context = (jbyte *)env->GetPrimitiveArrayCritical(passContext, NULL);
switch (step) {
@@ -1651,7 +1929,7 @@ static void osNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
int result = 0;
int handle;
- struct sockaddr_in address;
+ struct sockaddr_storage address;
jbyte *context = NULL;
int remainingTimeout = timeout;
int passedTimeout = 0;
@@ -1664,53 +1942,117 @@ static void osNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
finishTime = time_msec_clock() + (int) timeout;
}
-
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return;
- } else {
- result = inetAddressToSocketAddress(env, inetAddr, remotePort,
- (struct sockaddr_in *) &address);
+ }
- if (result < 0) {
+ result = inetAddressToSocketAddress(env, inetAddr, remotePort, &address);
+ if (result < 0) // Exception has already been thrown.
+ return;
+
+ // Check if we're using adb networking and redirect in case it is used.
+ if (useAdbNetworkingForAddress(&address)) {
+ int retVal = osNetworkSystem_connectSocketImpl(env, clazz,
+ fileDescriptor, trafficClass, inetAddr, remotePort);
+ if (retVal != 0) {
throwSocketException(env, SOCKERR_BADSOCKET);
- return;
}
+ return;
+ }
- // Check if we're using adb networking and redirect in case it is used.
- if (useAdbNetworking && !isLocalhost(&address)) {
- int retVal = osNetworkSystem_connectSocketImpl(env, clazz,
- fileDescriptor, trafficClass, inetAddr, remotePort);
- if (retVal != 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
- }
- return;
+ /*
+ * we will be looping checking for when we are connected so allocate
+ * the descriptor sets that we will use
+ */
+ context =(jbyte *) malloc(sizeof(struct selectFDSet));
+ if (NULL == context) {
+ throwSocketException(env, SOCKERR_NOBUFFERS);
+ return;
+ }
+
+ result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
+ if (0 == result) {
+ /* ok we connected right away so we are done */
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
+ goto bail;
+ } else if (result != SOCKERR_NOTCONNECTED) {
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
+ context);
+ /* we got an error other than NOTCONNECTED so we cannot continue */
+ if (SOCKERR_EACCES == result) {
+ jniThrowException(env, "java/lang/SecurityException",
+ netLookupErrorString(result));
+ } else {
+ throwSocketException(env, result);
}
+ goto bail;
+ }
+
+ while (SOCKERR_NOTCONNECTED == result) {
+ passedTimeout = remainingTimeout;
/*
- * we will be looping checking for when we are connected so allocate
- * the descriptor sets that we will use
+ * ok now try and connect. Depending on the platform this may sleep
+ * for up to passedTimeout milliseconds
*/
- context =(jbyte *) malloc(sizeof(struct selectFDSet));
+ result = sockConnectWithTimeout(handle, address, passedTimeout,
+ SOCKET_STEP_CHECK, context);
- if (NULL == context) {
- throwSocketException(env, SOCKERR_NOBUFFERS);
- return;
+ /*
+ * now check if the socket is still connected.
+ * Do it here as some platforms seem to think they
+ * are connected if the socket is closed on them.
+ */
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ goto bail;
}
- result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
+ /*
+ * check if we are now connected,
+ * if so we can finish the process and return
+ */
if (0 == result) {
- /* ok we connected right away so we are done */
- sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
goto bail;
- } else if (result != SOCKERR_NOTCONNECTED) {
- log_socket_close(handle, result);
- sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
- context);
- /* we got an error other than NOTCONNECTED so we cannot continue */
- if (SOCKERR_EACCES == result) {
+ }
+
+ /*
+ * if the error is SOCKERR_NOTCONNECTED then we have not yet
+ * connected and we may not be done yet
+ */
+ if (SOCKERR_NOTCONNECTED == result) {
+ /* check if the timeout has expired */
+ if (hasTimeout) {
+ remainingTimeout = finishTime - time_msec_clock();
+ if (remainingTimeout <= 0) {
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ jniThrowException(env,
+ "java/net/SocketTimeoutException",
+ netLookupErrorString(result));
+ goto bail;
+ }
+ } else {
+ remainingTimeout = 100;
+ }
+ } else {
+ sockConnectWithTimeout(handle, address, remainingTimeout,
+ SOCKET_STEP_DONE, context);
+ if ((SOCKERR_CONNRESET == result) ||
+ (SOCKERR_CONNECTION_REFUSED == result) ||
+ (SOCKERR_ADDRNOTAVAIL == result) ||
+ (SOCKERR_ADDRINUSE == result) ||
+ (SOCKERR_ENETUNREACH == result)) {
+ jniThrowException(env, "java/net/ConnectException",
+ netLookupErrorString(result));
+ } else if (SOCKERR_EACCES == result) {
jniThrowException(env, "java/lang/SecurityException",
netLookupErrorString(result));
} else {
@@ -1718,81 +2060,6 @@ static void osNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
}
goto bail;
}
-
- while (SOCKERR_NOTCONNECTED == result) {
- passedTimeout = remainingTimeout;
-
- /*
- * ok now try and connect. Depending on the platform this may sleep
- * for up to passedTimeout milliseconds
- */
- result = sockConnectWithTimeout(handle, address, passedTimeout,
- SOCKET_STEP_CHECK, context);
-
- /*
- * now check if the socket is still connected.
- * Do it here as some platforms seem to think they
- * are connected if the socket is closed on them.
- */
- handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
- if (handle == 0 || handle == -1) {
- sockConnectWithTimeout(handle, address, 0,
- SOCKET_STEP_DONE, context);
- throwSocketException(env, SOCKERR_BADSOCKET);
- goto bail;
- }
-
- /*
- * check if we are now connected,
- * if so we can finish the process and return
- */
- if (0 == result) {
- sockConnectWithTimeout(handle, address, 0,
- SOCKET_STEP_DONE, context);
- goto bail;
- }
-
- /*
- * if the error is SOCKERR_NOTCONNECTED then we have not yet
- * connected and we may not be done yet
- */
- if (SOCKERR_NOTCONNECTED == result) {
- /* check if the timeout has expired */
- if (hasTimeout) {
- remainingTimeout = finishTime - time_msec_clock();
- if (remainingTimeout <= 0) {
- log_socket_close(handle, result);
- sockConnectWithTimeout(handle, address, 0,
- SOCKET_STEP_DONE, context);
- jniThrowException(env,
- "java/net/SocketTimeoutException",
- netLookupErrorString(result));
- goto bail;
- }
- } else {
- remainingTimeout = 100;
- }
- } else {
- log_socket_close(handle, result);
- sockConnectWithTimeout(handle, address, remainingTimeout,
- SOCKET_STEP_DONE, context);
- if ((SOCKERR_CONNRESET == result) ||
- (SOCKERR_CONNECTION_REFUSED == result) ||
- (SOCKERR_ADDRNOTAVAIL == result) ||
- (SOCKERR_ADDRINUSE == result) ||
- (SOCKERR_ENETUNREACH == result)) {
- jniThrowException(env, "java/net/ConnectException",
- netLookupErrorString(result));
- } else if (SOCKERR_EACCES == result) {
- jniThrowException(env, "java/lang/SecurityException",
- netLookupErrorString(result));
- } else {
- throwSocketException(env, result);
- }
- goto bail;
- }
- }
}
bail:
@@ -1807,37 +2074,25 @@ static jint osNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port) {
//LOGD("ENTER direct-call connectSocketImpl\n");
- struct sockaddr_in address;
+ struct sockaddr_storage address;
int ret;
int handle;
- jbyteArray java_in_addr;
-
- memset(&address, 0, sizeof(address));
- address.sin_family = AF_INET;
-
- ret = inetAddressToSocketAddress(env, inetAddr, port,
- (struct sockaddr_in *) &address);
-
- if (ret < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ ret = inetAddressToSocketAddress(env, inetAddr, port, &address);
+ if (ret < 0)
return ret;
- }
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return -1;
}
- address.sin_port = htons(port);
-
- if (useAdbNetworking && !isLocalhost(&address)) {
+ if (useAdbNetworkingForAddress(&address)) {
// LOGD("+connect to address 0x%08x port %d (via adb)",
// address.sin_addr.s_addr, (int) port);
- ret = adb_networking_connect_fd(handle, &address);
+ ret = adb_networking_connect_fd(handle, (struct sockaddr_in *) &address);
// LOGD("-connect ret %d errno %d (via adb)", ret, errno);
} else {
@@ -1866,27 +2121,21 @@ static void osNetworkSystem_socketBindImpl(JNIEnv* env, jclass clazz,
jobject fileDescriptor, jint port, jobject inetAddress) {
// LOGD("ENTER socketBindImpl");
- struct sockaddr_in sockaddress;
+ struct sockaddr_storage sockaddress;
int ret;
int handle;
- ret = inetAddressToSocketAddress(env, inetAddress, port,
- (struct sockaddr_in *) &sockaddress);
-
- if (ret < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddress);
+ if (ret < 0)
return;
- }
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return;
}
- ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
-
+ ret = doBind(handle, &sockaddress);
if (ret < 0) {
jniThrowException(env, "java/net/BindException",
netLookupErrorString(convertError(errno)));
@@ -1912,7 +2161,6 @@ static void osNetworkSystem_listenStreamSocketImpl(JNIEnv* env, jclass clazz,
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return;
}
@@ -1928,9 +2176,8 @@ static jint osNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
int result;
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
@@ -1943,7 +2190,6 @@ static jint osNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
} else if (SOCKERR_INTERRUPTED == result) {
continue;
} else if (0 > result) {
- log_socket_close(handle, result);
throwSocketException(env, result);
return 0;
}
@@ -1953,11 +2199,9 @@ static jint osNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
if (0 > result) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
- add_recv_stats(handle, result);
return result;
}
@@ -1965,10 +2209,7 @@ static void osNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass clazz,
jobject fdServer, jobject newSocket, jobject fdnewSocket, jint timeout) {
// LOGD("ENTER acceptSocketImpl");
- union {
- struct sockaddr address;
- struct sockaddr_in in_address;
- } sa;
+ struct sockaddr_storage sa;
int ret;
int retFD;
@@ -1982,55 +2223,47 @@ static void osNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass clazz,
}
result = pollSelectWait(env, fdServer, timeout, SELECT_READ_TYPE);
-
if (0 > result) {
return;
}
handle = jniGetFDFromFileDescriptor(env, fdServer);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return;
}
do {
addrlen = sizeof(sa);
- ret = accept(handle, &(sa.address), &addrlen);
+ ret = accept(handle, (struct sockaddr *) &sa, &addrlen);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return;
}
retFD = ret;
- /* For AF_INET / inetOrLocal == true only: put
- * peer address and port in instance variables
- * We don't bother for UNIX domain sockets, since most peers are
- * anonymous anyway
+ /*
+ * For network sockets, put the peer address and port in instance variables.
+ * We don't bother to do this for UNIX domain sockets, since most peers are
+ * anonymous anyway.
*/
- if (sa.address.sa_family == AF_INET) {
- // inetOrLocal should also be true
-
- jobject inetAddress;
-
- inetAddress = structInToInetAddress(env, &(sa.in_address.sin_addr));
-
- if (inetAddress == NULL) {
+ if (sa.ss_family == AF_INET || sa.ss_family == AF_INET6) {
+ jobject inetAddress = socketAddressToInetAddress(env, &sa);
+ if (ret == -1) {
close(retFD);
- newSocket = NULL;
+ newSocket = NULL; // Exception has already been thrown.
return;
}
env->SetObjectField(newSocket,
gCachedFields.socketimpl_address, inetAddress);
- env->SetIntField(newSocket, gCachedFields.socketimpl_port,
- ntohs(sa.in_address.sin_port));
+ int port = getSocketAddressPort(&sa);
+ env->SetIntField(newSocket, gCachedFields.socketimpl_port, port);
}
jniSetFileDescriptorOfFD(env, fdnewSocket, retFD);
@@ -2066,7 +2299,6 @@ static void osNetworkSystem_sendUrgentDataImpl(JNIEnv* env, jclass clazz,
result = send(handle, (jbyte *) &value, 1, MSG_OOB);
if (result < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
}
}
@@ -2077,20 +2309,16 @@ static void osNetworkSystem_connectDatagramImpl2(JNIEnv* env, jclass clazz,
int handle = jniGetFDFromFileDescriptor(env, fd);
- struct sockaddr_in sockAddr;
+ struct sockaddr_storage sockAddr;
int ret;
ret = inetAddressToSocketAddress(env, inetAddress, port, &sockAddr);
+ if (ret < 0) // Exception has already been thrown.
+ return;
+ ret = doConnect(handle, &sockAddr);
if (ret < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
- return;
- }
- log_socket_connect(handle, ntohl(sockAddr.sin_addr.s_addr), port);
- int result = connect(handle, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
- if (result < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
}
}
@@ -2101,18 +2329,13 @@ static void osNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass clazz,
int handle = jniGetFDFromFileDescriptor(env, fd);
- struct sockaddr_in *sockAddr;
- socklen_t sockAddrLen = sizeof(struct sockaddr_in);
- sockAddr = (struct sockaddr_in *) malloc(sockAddrLen);
- memset(sockAddr, 0, sockAddrLen);
-
- sockAddr->sin_family = AF_UNSPEC;
- int result = connect(handle, (struct sockaddr *)sockAddr, sockAddrLen);
- free(sockAddr);
+ struct sockaddr_storage sockAddr;
+ memset(&sockAddr, 0, sizeof(sockAddr));
+ sockAddr.ss_family = AF_UNSPEC;
+ int result = doConnect(handle, &sockAddr);
if (result < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
}
}
@@ -2122,29 +2345,23 @@ static jboolean osNetworkSystem_socketBindImpl2(JNIEnv* env, jclass clazz,
jobject inetAddress) {
// LOGD("ENTER socketBindImpl2");
- struct sockaddr_in sockaddress;
+ struct sockaddr_storage sockaddress;
int ret;
int handle;
- ret = inetAddressToSocketAddress(env, inetAddress, port,
- (struct sockaddr_in *) &sockaddress);
-
- if (ret < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddress);
+ if (ret < 0) // Exception has already been thrown.
return 0;
- }
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
- ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
-
+ ret = doBind(handle, &sockaddress);
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
jniThrowException(env, "java/net/BindException", netLookupErrorString(err));
return 0;
}
@@ -2164,30 +2381,29 @@ static jint osNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
}
int handle = jniGetFDFromFileDescriptor(env, fd);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
- struct sockaddr_in sockAddr;
+ struct sockaddr_storage sockAddr;
socklen_t sockAddrLen = sizeof(sockAddr);
-
- int length = recvfrom(handle, NULL, 0, MSG_PEEK,
- (struct sockaddr *)&sockAddr, &sockAddrLen);
-
+ ssize_t length;
+ do {
+ length = recvfrom(handle, NULL, 0, MSG_PEEK,
+ (struct sockaddr *)&sockAddr, &sockAddrLen);
+ } while (length < 0 && errno == EINTR);
if (length < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
- if (socketAddressToInetAddress(env, &sockAddr, sender, &port) < 0) {
- throwIOExceptionStr(env, "Address conversion failed");
+ sender = socketAddressToInetAddress(env, &sockAddr);
+ if (sender == NULL) // Exception has already been thrown.
return -1;
- }
- add_recv_stats(handle, length);
+
+ port = getSocketAddressPort(&sockAddr);
return port;
}
@@ -2202,44 +2418,41 @@ static jint osNetworkSystem_receiveDatagramDirectImpl(JNIEnv* env, jclass clazz,
}
int handle = jniGetFDFromFileDescriptor(env, fd);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
- struct sockaddr_in sockAddr;
+ struct sockaddr_storage sockAddr;
socklen_t sockAddrLen = sizeof(sockAddr);
int mode = peek ? MSG_PEEK : 0;
- int actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
- (struct sockaddr *)&sockAddr, &sockAddrLen);
-
+ ssize_t actualLength;
+ do {
+ actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
+ (struct sockaddr *)&sockAddr, &sockAddrLen);
+ } while (actualLength < 0 && errno == EINTR);
if (actualLength < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
if (packet != NULL) {
- int port = ntohs(sockAddr.sin_port);
- jbyteArray addr = env->NewByteArray(sizeof(struct in_addr));
- if ((structInToJavaAddress(env, &sockAddr.sin_addr, addr)) < 0) {
- jniThrowException(env, "java/net/SocketException",
- "Could not set address of packet.");
+ jbyteArray addr = socketAddressToAddressBytes(env, &sockAddr);
+ if (addr == NULL) // Exception has already been thrown.
return 0;
- }
+ int port = getSocketAddressPort(&sockAddr);
jobject sender = env->CallStaticObjectMethod(
gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
addr);
env->SetObjectField(packet, gCachedFields.dpack_address, sender);
env->SetIntField(packet, gCachedFields.dpack_port, port);
- env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
+ env->SetIntField(packet, gCachedFields.dpack_length,
+ (jint) actualLength);
}
- add_recv_stats(handle, actualLength);
- return actualLength;
+ return (jint) actualLength;
}
static jint osNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
@@ -2256,7 +2469,7 @@ static jint osNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
}
int actualLength = osNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
- packet, (jint)bytes, offset, localLength, receiveTimeout, peek);
+ packet, (jint)bytes, 0, localLength, receiveTimeout, peek);
if (actualLength > 0) {
env->SetByteArrayRegion(data, offset, actualLength, bytes);
@@ -2297,7 +2510,6 @@ static jint osNetworkSystem_recvConnectedDatagramDirectImpl(JNIEnv* env,
if ( packet != NULL) {
env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
}
- add_recv_stats(handle, actualLength);
return actualLength;
}
@@ -2315,7 +2527,7 @@ static jint osNetworkSystem_recvConnectedDatagramImpl(JNIEnv* env, jclass clazz,
}
int actualLength = osNetworkSystem_recvConnectedDatagramDirectImpl(env,
- clazz, fd, packet, (jint)bytes, offset, localLength,
+ clazz, fd, packet, (jint)bytes, 0, localLength,
receiveTimeout, peek);
if (actualLength > 0) {
@@ -2331,8 +2543,6 @@ static jint osNetworkSystem_sendDatagramDirectImpl(JNIEnv* env, jclass clazz,
jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
// LOGD("ENTER sendDatagramDirectImpl");
- int result = 0;
-
int handle = jniGetFDFromFileDescriptor(env, fd);
if (handle == 0 || handle == -1) {
@@ -2340,29 +2550,28 @@ static jint osNetworkSystem_sendDatagramDirectImpl(JNIEnv* env, jclass clazz,
return 0;
}
- struct sockaddr_in receiver;
-
+ struct sockaddr_storage receiver;
if (inetAddressToSocketAddress(env, inetAddress, port, &receiver) < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ // Exception has already been thrown.
return 0;
}
- result = sendto(handle, (char*)(address + offset), length, SOCKET_NOFLAGS,
- (struct sockaddr*)&receiver, sizeof(receiver));
-
+ ssize_t result = 0;
+ do {
+ result = sendto(handle, (char*)(address + offset), length,
+ SOCKET_NOFLAGS, (struct sockaddr*)&receiver, sizeof(receiver));
+ } while (result < 0 && errno == EINTR);
if (result < 0) {
int err = convertError(errno);
if ((SOCKERR_CONNRESET == err)
|| (SOCKERR_CONNECTION_REFUSED == err)) {
return 0;
} else {
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
}
- add_send_stats(handle, result);
- return result;
+ return (jint) result;
}
static jint osNetworkSystem_sendDatagramImpl(JNIEnv* env, jclass clazz,
@@ -2398,12 +2607,10 @@ static jint osNetworkSystem_sendConnectedDatagramDirectImpl(JNIEnv* env,
if ((SOCKERR_CONNRESET == err) || (SOCKERR_CONNECTION_REFUSED == err)) {
return 0;
} else {
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
}
- add_send_stats(handle, length);
return result;
}
@@ -2424,23 +2631,11 @@ static void osNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
// LOGD("ENTER createServerStreamSocketImpl");
- if (fileDescriptor == NULL) {
- throwNullPointerException(env);
- return;
- }
-
- int handle = socket(PF_INET, SOCK_STREAM, 0);
-
- if (handle < 0) {
- int err = convertError(errno);
- throwSocketException(env, err);
+ int handle = createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
+ if (handle < 0)
return;
- }
-
- jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
int value = 1;
-
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
}
@@ -2448,18 +2643,11 @@ static void osNetworkSystem_createMulticastSocketImpl(JNIEnv* env,
jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
// LOGD("ENTER createMulticastSocketImpl");
- int handle = socket(PF_INET, SOCK_DGRAM, 0);
-
- if (handle < 0) {
- int err = convertError(errno);
- throwSocketException(env, err);
+ int handle = createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
+ if (handle < 0)
return;
- }
-
- jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
int value = 1;
-
// setsockopt(handle, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(jbyte));
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
}
@@ -2505,7 +2693,6 @@ static jint osNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
* to the Java input stream
*/
if (0 < result) {
- add_recv_stats(handle, result);
return result;
} else if (0 == result) {
return -1;
@@ -2516,7 +2703,6 @@ static jint osNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
netLookupErrorString(SOCKERR_TIMEOUT));
} else {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
}
return 0;
@@ -2560,7 +2746,6 @@ static jint osNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
}
env->ReleaseByteArrayElements(data, message, 0);
int err = convertError(result);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
@@ -2568,7 +2753,6 @@ static jint osNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
}
env->ReleaseByteArrayElements(data, message, 0);
- add_send_stats(handle, sent);
return sent;
}
@@ -2590,7 +2774,6 @@ static void osNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject obj,
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return;
}
@@ -2613,7 +2796,6 @@ static void osNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject obj,
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return;
}
@@ -2625,26 +2807,19 @@ static jint osNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
// LOGD("ENTER sendDatagramImpl2");
jbyte *message;
- jbyte nhostAddrBytes[4];
unsigned short nPort;
- int result = 0, sent = 0;
+ int ret = 0, sent = 0;
int handle = 0;
- struct sockaddr_in sockaddrP;
+ struct sockaddr_storage sockaddrP;
if (inetAddress != NULL) {
-
- result = inetAddressToSocketAddress(env, inetAddress, port,
- (struct sockaddr_in *) &sockaddrP);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddrP);
+ if (ret < 0) // Exception has already been thrown.
return 0;
- }
handle = jniGetFDFromFileDescriptor(env, fd);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
}
@@ -2663,18 +2838,19 @@ static jint osNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
if (handle == 0 || handle == -1) {
throwSocketException(env,
- sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
+ sent == 0 ? SOCKERR_BADDESC : SOCKERR_INTERRUPTED);
free(message);
return 0;
}
- result = sendto(handle, (char *) (message + sent),
- (int) (length - sent), SOCKET_NOFLAGS,
- (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
-
+ ssize_t result;
+ do {
+ result = sendto(handle, (char *) (message + sent),
+ (int) (length - sent), SOCKET_NOFLAGS,
+ (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
+ } while (result < 0 && errno == EINTR);
if (result < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
free(message);
return 0;
@@ -2684,7 +2860,6 @@ static jint osNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
}
free(message);
- add_send_stats(handle, sent);
return sent;
}
@@ -2757,10 +2932,10 @@ static jint osNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
}
if (0 < result) {
- /*output the result to a int array*/
- flagArray = env->GetIntArrayElements(outFlags, &isCopy);
+ /*output the result to a int array*/
+ flagArray = env->GetIntArrayElements(outFlags, &isCopy);
- for (val=0; val<countReadC; val++) {
+ for (val=0; val<countReadC; val++) {
gotFD = env->GetObjectArrayElement(readFDArray,val);
handle = jniGetFDFromFileDescriptor(env, gotFD);
@@ -2799,33 +2974,30 @@ static jobject osNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
jclass clazz, jobject fileDescriptor, jboolean preferIPv6Addresses) {
// LOGD("ENTER getSocketLocalAddressImpl");
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
memset(&addr, 0, addrLen);
- int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
- int result;
+ int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (handle == 0 || handle == -1) {
throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
return NULL;
}
+ int result;
result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
// Spec says ignore all errors
-
- return structInToInetAddress(env, &(addr.sin_addr));
-
+ return socketAddressToInetAddress(env, &addr);
}
static jint osNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
jobject fileDescriptor, jboolean preferIPv6Addresses) {
// LOGD("ENTER getSocketLocalPortImpl");
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
@@ -2842,7 +3014,7 @@ static jint osNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
// The java spec does not indicate any exceptions on this call
return 0;
} else {
- return ntohs(addr.sin_port);
+ return getSocketAddressPort(&addr);
}
}
@@ -2856,12 +3028,12 @@ static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
unsigned char byteValue = 0;
socklen_t byteSize = sizeof(unsigned char);
int result;
- struct sockaddr_in sockVal;
+ struct sockaddr_storage sockVal;
socklen_t sockSize = sizeof(sockVal);
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return NULL;
}
@@ -2896,7 +3068,9 @@ static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
return newJavaLangByte(env, 0);
}
- result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteValue, &byteSize);
+ result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS, &byteValue,
+ &byteSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return NULL;
@@ -2912,7 +3086,42 @@ static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
throwSocketException(env, convertError(errno));
return NULL;
}
- return structInToInetAddress(env, &(sockVal.sin_addr));
+ // This option is IPv4-only.
+ sockVal.ss_family = AF_INET;
+ return socketAddressToInetAddress(env, &sockVal);
+ }
+ case JAVASOCKOPT_IP_MULTICAST_IF2: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+ return NULL;
+ }
+ struct ip_mreqn multicastRequest;
+ int interfaceIndex;
+ socklen_t optionLength;
+ int addressFamily = getSocketAddressFamily(handle);
+ switch (addressFamily) {
+ case AF_INET:
+ optionLength = sizeof(multicastRequest);
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
+ &multicastRequest, &optionLength);
+ if (result == 0)
+ interfaceIndex = multicastRequest.imr_ifindex;
+ break;
+ case AF_INET6:
+ optionLength = sizeof(interfaceIndex);
+ result = getsockopt(handle, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ &interfaceIndex, &optionLength);
+ break;
+ default:
+ throwSocketException(env, SOCKERR_BADAF);
+ return NULL;
+ }
+
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+
+ return newJavaLangInteger(env, interfaceIndex);
}
case JAVASOCKOPT_SO_SNDBUF: {
result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
@@ -2963,7 +3172,10 @@ static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
return newJavaLangBoolean(env, intValue);
}
case JAVASOCKOPT_IP_MULTICAST_LOOP: {
- result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intValue, &intSize);
+ result = getOrSetSocketOption(SOCKOPT_GET, handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP, &intValue,
+ &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return NULL;
@@ -2971,7 +3183,8 @@ static jobject osNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
return newJavaLangBoolean(env, intValue);
}
case JAVASOCKOPT_IP_TOS: {
- result = getsockopt(handle, IPPROTO_IP, IP_TOS, &intValue, &intSize);
+ result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_TOS,
+ IPV6_TCLASS, &intValue, &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return NULL;
@@ -3001,9 +3214,11 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
// LOGD("ENTER setSocketOptionImpl");
int handle, result;
- int intVal, intSize = sizeof(int);
- unsigned char byteVal, byteSize = sizeof(unsigned char);
- struct sockaddr_in sockVal;
+ int intVal;
+ socklen_t intSize = sizeof(int);
+ unsigned char byteVal;
+ socklen_t byteSize = sizeof(unsigned char);
+ struct sockaddr_storage sockVal;
int sockSize = sizeof(sockVal);
if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
@@ -3014,7 +3229,7 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
byteVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
} else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
if (inetAddressToSocketAddress(env, optVal, 0, &sockVal) < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ // Exception has already been thrown.
return;
}
} else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
@@ -3026,7 +3241,7 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return;
}
@@ -3056,11 +3271,13 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
break;
}
- case JAVASOCKOPT_MCAST_TTL: {
+ case JAVASOCKOPT_MCAST_TTL: {
if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
return;
}
- result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteVal, byteSize);
+ result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS, &byteVal,
+ &byteSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return;
@@ -3071,23 +3288,28 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
mcastAddDropMembership(env, handle, optVal,
(anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
- return;
+ break;
}
case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
mcastAddDropMembership(env, handle, optVal,
(anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
- return;
+ break;
}
case JAVASOCKOPT_MCAST_INTERFACE: {
if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
return;
}
+ // This call is IPv4 only.
+ if (getSocketAddressFamily(handle) != AF_INET) {
+ throwSocketException(env, SOCKERR_BADAF);
+ return;
+ }
struct ip_mreqn mcast_req;
memset(&mcast_req, 0, sizeof(mcast_req));
- memcpy(&(mcast_req.imr_address), &(sockVal.sin_addr),
- sizeof(struct in_addr));
+ struct sockaddr_in *sin = (struct sockaddr_in *) &sockVal;
+ mcast_req.imr_address = sin->sin_addr;
result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
&mcast_req, sizeof(mcast_req));
if (0 != result) {
@@ -3097,6 +3319,42 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
break;
}
+ case JAVASOCKOPT_IP_MULTICAST_IF2: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+ return;
+ }
+ int addressFamily = getSocketAddressFamily(handle);
+ int interfaceIndex = intVal;
+ void *optionValue;
+ socklen_t optionLength;
+ struct ip_mreqn multicastRequest;
+ switch (addressFamily) {
+ case AF_INET:
+ // IP_MULTICAST_IF expects a pointer to a struct ip_mreqn.
+ memset(&multicastRequest, 0, sizeof(multicastRequest));
+ multicastRequest.imr_ifindex = interfaceIndex;
+ optionValue = &multicastRequest;
+ optionLength = sizeof(multicastRequest);
+ break;
+ case AF_INET6:
+ // IPV6_MULTICAST_IF expects a pointer to an integer.
+ optionValue = &interfaceIndex;
+ optionLength = sizeof(interfaceIndex);
+ break;
+ default:
+ throwSocketException(env, SOCKERR_BADAF);
+ return;
+ }
+ result = getOrSetSocketOption(SOCKOPT_SET, handle,
+ IP_MULTICAST_IF, IPV6_MULTICAST_IF, optionValue,
+ &optionLength);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
case JAVASOCKOPT_SO_SNDBUF: {
result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
if (0 != result) {
@@ -3151,7 +3409,10 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
}
case JAVASOCKOPT_IP_MULTICAST_LOOP: {
- result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intVal, intSize);
+ result = getOrSetSocketOption(SOCKOPT_SET, handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP, &intVal,
+ &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return;
@@ -3160,7 +3421,8 @@ static void osNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
}
case JAVASOCKOPT_IP_TOS: {
- result = setsockopt(handle, IPPROTO_IP, IP_TOS, &intVal, intSize);
+ result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_TOS,
+ IPV6_TCLASS, &intVal, &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return;
@@ -3215,8 +3477,6 @@ static void osNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
return;
}
- log_socket_close(handle, SOCKET_CLOSE_LOCAL);
-
jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
close(handle);
@@ -3311,6 +3571,7 @@ static void osNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
}
+// TODO: rewrite this method in Java and make it support IPv6.
static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
// LOGD("ENTER inheritedChannelImpl");
diff --git a/luni/src/test/java/com/google/coretests/CoreTestResult.java b/luni/src/test/java/com/google/coretests/CoreTestResult.java
index 9a821cd..802eff8 100644
--- a/luni/src/test/java/com/google/coretests/CoreTestResult.java
+++ b/luni/src/test/java/com/google/coretests/CoreTestResult.java
@@ -131,6 +131,7 @@ public class CoreTestResult extends TestResult {
// Ignored
}
if (thread.isAlive()) {
+ StackTraceElement[] trace = thread.getStackTrace();
runnable.stop();
thread.stop();
try {
@@ -138,8 +139,10 @@ public class CoreTestResult extends TestResult {
} catch (InterruptedException ex) {
// Ignored
}
-
- addError(test, new CoreTestTimeout("Test timed out"));
+
+ CoreTestTimeout timeout = new CoreTestTimeout("Test timed out");
+ timeout.setStackTrace(trace);
+ addError(test, timeout);
}
} else {
runnable.run();
diff --git a/luni/src/test/java/com/google/coretests/CoreTestRunnable.java b/luni/src/test/java/com/google/coretests/CoreTestRunnable.java
index ab49e47..ed7797e 100644
--- a/luni/src/test/java/com/google/coretests/CoreTestRunnable.java
+++ b/luni/src/test/java/com/google/coretests/CoreTestRunnable.java
@@ -137,18 +137,18 @@ public class CoreTestRunnable implements Runnable {
Throwable throwable = null;
File file = File.createTempFile("isolation", ".tmp");
-
- fProcess = Runtime.getRuntime().exec(
- (IS_DALVIK ? "dalvikvm" : "java") +
+
+ String program = (IS_DALVIK ? "dalvikvm" : "java") +
" -classpath " + System.getProperty("java.class.path") +
" -Djava.home=" + System.getProperty("java.home") +
" -Duser.home=" + System.getProperty("user.home") +
- " -Djava.io.tmpdir=" + System.getProperty("user.home") +
+ " -Djava.io.tmpdir=" + System.getProperty("java.io.tmpdir") +
" com.google.coretests.CoreTestIsolator" +
" " + fTest.getClass().getName() +
" " + fTest.getName() +
- " " + file.getAbsolutePath());
-
+ " " + file.getAbsolutePath();
+ fProcess = Runtime.getRuntime().exec(program);
+
int result = fProcess.waitFor();
if (result != TestRunner.SUCCESS_EXIT) {
@@ -158,7 +158,7 @@ public class CoreTestRunnable implements Runnable {
throwable = (Throwable)ois.readObject();
ois.close();
} catch (Exception ex) {
- throwable = new RuntimeException("Error isolating test", ex);
+ throwable = new RuntimeException("Error isolating test: " + program, ex);
}
}
diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/ThreadTest.java b/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/ThreadTest.java
index 47eb166..a24f457 100644
--- a/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/ThreadTest.java
+++ b/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/ThreadTest.java
@@ -23,9 +23,10 @@ import java.lang.Thread.UncaughtExceptionHandler;
import java.security.Permission;
import java.util.Map;
import java.util.concurrent.Semaphore;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.atomic.AtomicReference;
import dalvik.annotation.AndroidOnly;
-import dalvik.annotation.KnownFailure;
import dalvik.annotation.TestLevel;
import dalvik.annotation.TestTargetClass;
import dalvik.annotation.TestTargetNew;
@@ -913,7 +914,7 @@ public class ThreadTest extends junit.framework.TestCase {
} catch (InterruptedException e) {
fail("Join failed ");
}
- assertTrue("Joined thread is still alive", !st.isAlive());
+ assertFalse("Joined thread is still alive", st.isAlive());
boolean result = true;
Thread th = new Thread("test");
try {
@@ -938,6 +939,44 @@ public class ThreadTest extends junit.framework.TestCase {
st.start();
}
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "Regression test for when join() failed due to spurious wakeups",
+ method = "join",
+ args = {long.class, int.class}
+ )
+ public void test_joinWithSpuriousInterruption() throws InterruptedException {
+ final Thread parker = new Thread() {
+ @Override
+ public void run() {
+ for (int i = 0; i < 10; i++) {
+ // we used to get spurious wakeups upon unparking
+ LockSupport.park();
+ }
+ }
+ };
+ Thread unparker = new Thread() {
+ @Override
+ public void run() {
+ for (int i = 0; i < 10; i++) {
+ try {
+ Thread.sleep(100);
+ LockSupport.unpark(parker);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ }
+ };
+
+ long startNanos = System.nanoTime();
+ parker.start();
+ unparker.start();
+ parker.join(500, 500000);
+ long netWaitTime = System.nanoTime() - startNanos;
+ assertTrue("Expected to wait at least 500000000ns, but was " + netWaitTime + "ns",
+ netWaitTime > 500000000);
+ }
+
/**
* @tests java.lang.Thread#join(long)
*/
@@ -1919,23 +1958,33 @@ public class ThreadTest extends junit.framework.TestCase {
public void run() {
while (!sem.hasQueuedThreads()) {}
sem.release();
+
+ // RUNNABLE
while (run) {}
+
try {
+ // WAITING
sem.acquire();
} catch (InterruptedException e) {
fail("InterruptedException was thrown.");
}
+
+ // BLOCKED
synchronized (lock) {
lock.equals(new Object());
}
synchronized (lock) {
try {
sem.release();
+
+ // TIMED_WAITING
lock.wait(Long.MAX_VALUE);
} catch (InterruptedException e) {
// expected
}
}
+
+ // TERMINATED upon return
}
};
assertEquals(Thread.State.NEW, th.getState());
@@ -1976,7 +2025,7 @@ public class ThreadTest extends junit.framework.TestCase {
}
assertEquals(Thread.State.TERMINATED, th.getState());
}
- boolean run = true;
+ volatile boolean run = true;
/**
* @tests java.lang.Thread#getUncaughtExceptionHandler
diff --git a/luni/src/test/java/tests/api/java/io/InputStreamReaderTest.java b/luni/src/test/java/tests/api/java/io/InputStreamReaderTest.java
index bb3f8f5..748105a 100644
--- a/luni/src/test/java/tests/api/java/io/InputStreamReaderTest.java
+++ b/luni/src/test/java/tests/api/java/io/InputStreamReaderTest.java
@@ -726,10 +726,12 @@ public class InputStreamReaderTest extends TestCase {
char[] chars = new char[8192];
int at = 0;
- outer:
for (;;) {
int amt = isr.read(chars);
- if (amt <= 0) break;
+ if (amt <= 0) {
+ break;
+ }
+
for (int i = 0; i < amt; i++) {
char c = chars[i];
if (at < prefixLength) {
diff --git a/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/SocketChannelTest.java b/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/SocketChannelTest.java
index b7a1012..ce34dba 100755
--- a/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/SocketChannelTest.java
+++ b/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/SocketChannelTest.java
@@ -29,6 +29,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.BindException;
import java.net.ConnectException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
@@ -4114,6 +4116,95 @@ public class SocketChannelTest extends TestCase {
}
}
+ /**
+ * @throws IOException
+ * @tests java.nio.channels.SocketChannel#read(ByteBuffer)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "read",
+ args = {java.nio.ByteBuffer[].class}
+ )
+ public void test_socketChannel_read_DirectByteBuffer() throws InterruptedException, IOException {
+
+ ServerThread server = new ServerThread();
+ server.start();
+ Thread.currentThread().sleep(1000);
+
+ InetSocketAddress address = new InetSocketAddress(InetAddress
+ .getByName("localhost"), port);
+
+ // First test with array based byte buffer
+ SocketChannel sc = SocketChannel.open();
+ sc.connect(address);
+
+ ByteBuffer buf = ByteBuffer.allocate(data.length);
+ buf.limit(data.length / 2);
+ sc.read(buf);
+
+ buf.limit(buf.capacity());
+ sc.read(buf);
+ sc.close();
+
+ // Make sure the buffer is filled correctly
+ buf.rewind();
+ assertSameContent(data, buf);
+
+ // Now test with direct byte buffer
+ sc = SocketChannel.open();
+ sc.connect(address);
+
+ buf = ByteBuffer.allocateDirect(data.length);
+ buf.limit(data.length / 2);
+ sc.read(buf);
+
+ buf.limit(buf.capacity());
+ sc.read(buf);
+ sc.close();
+
+ // Make sure the buffer is filled correctly
+ buf.rewind();
+ assertSameContent(data, buf);
+ }
+
+ private void assertSameContent(byte[] data, ByteBuffer buf) {
+ for (byte b : data) {
+ if (b != buf.get()) {
+ int pos = buf.position() - 1;
+ fail("Content not equal. Buffer position: " +
+ (pos) + " expected: " + b + " was: " + buf.get(pos));
+ }
+ }
+ }
+
+ public static boolean done = false;
+ public static int port = Support_PortManager.getNextPort();
+ public static byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+ static class ServerThread extends Thread {
+ @Override
+ public void run() {
+ try {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ InetSocketAddress addr = new InetSocketAddress(InetAddress
+ .getByAddress(new byte[] {0, 0, 0, 0}), port);
+ ssc.socket().bind(addr, 0);
+
+ ByteBuffer buf = ByteBuffer.allocate(10);
+ buf.put(data);
+
+ while (!done) {
+ SocketChannel sc = ssc.accept();
+ buf.rewind();
+ sc.write(buf);
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
class MockSocketChannel extends SocketChannel {
private boolean isWriteCalled = false;
diff --git a/prefs/src/main/java/java/util/prefs/Preferences.java b/prefs/src/main/java/java/util/prefs/Preferences.java
index b7a0c70..719c89a 100644
--- a/prefs/src/main/java/java/util/prefs/Preferences.java
+++ b/prefs/src/main/java/java/util/prefs/Preferences.java
@@ -1006,15 +1006,11 @@ public abstract class Preferences {
//parse node's absolute path from class instance
private static String getNodeName(Class<?> c){
- // ??? PREFS TODO change back to harmony code once getPackage
- // delivers the correct results
- // Package p = c.getPackage();
- // if(null == p){
- // return "/<unnamed>"; //$NON-NLS-1$
- // }
- // return "/"+p.getName().replace('.', '/'); //$NON-NLS-1$
- int dotIndex = c.getName().lastIndexOf(".");
- return "/" + c.getName().substring(0, dotIndex).replace(".", "/");
+ Package p = c.getPackage();
+ if(null == p){
+ return "/<unnamed>"; //$NON-NLS-1$
+ }
+ return "/"+p.getName().replace('.', '/'); //$NON-NLS-1$
}
/**
diff --git a/text/src/main/java/java/text/RuleBasedCollator.java b/text/src/main/java/java/text/RuleBasedCollator.java
index 41a51e2..6418962 100644
--- a/text/src/main/java/java/text/RuleBasedCollator.java
+++ b/text/src/main/java/java/text/RuleBasedCollator.java
@@ -390,7 +390,7 @@ public class RuleBasedCollator extends Collator {
/**
* Returns the collation rules of this collator. These {@code rules} can be
- * fed into the {@link #RuleBasedCollator(String)} constructor.
+ * fed into the {@code RuleBasedCollator(String)} constructor.
* <p>
* Note that the {@code rules} are actually interpreted as a delta to the
* standard Unicode Collation Algorithm (UCA). Hence, an empty {@code rules}
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 250cf83..8f36632 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
@@ -36,8 +36,6 @@
#include <openssl/rand.h>
#include <openssl/ssl.h>
-#include <utils/LogSocket.h>
-
#include "org_apache_harmony_xnet_provider_jsse_common.h"
/**
@@ -670,8 +668,11 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
// LOGD("Doing SSL_Read()");
int result = SSL_read(ssl, buf, len);
- int error = SSL_get_error(ssl, result);
- freeSslErrorState();
+ int error = SSL_ERROR_NONE;
+ if (result <= 0) {
+ error = SSL_get_error(ssl, result);
+ freeSslErrorState();
+ }
// LOGD("Returned from SSL_Read() with result %d, error code %d", result, error);
// If we have been successful in moving data around, check whether it
@@ -693,7 +694,6 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
switch (error) {
// Sucessfully read at least one byte.
case SSL_ERROR_NONE: {
- add_recv_stats(fd, result);
return result;
}
@@ -786,8 +786,11 @@ static int sslWrite(SSL* ssl, const char* buf, jint len, int* sslReturnCode,
// LOGD("Doing SSL_write() with %d bytes to go", len);
int result = SSL_write(ssl, buf, len);
- int error = SSL_get_error(ssl, result);
- freeSslErrorState();
+ int error = SSL_ERROR_NONE;
+ if (result <= 0) {
+ error = SSL_get_error(ssl, result);
+ freeSslErrorState();
+ }
// LOGD("Returned from SSL_write() with result %d, error code %d", result, error);
// If we have been successful in moving data around, check whether it
@@ -861,7 +864,6 @@ static int sslWrite(SSL* ssl, const char* buf, jint len, int* sslReturnCode,
}
}
}
- add_send_stats(fd, count);
// LOGD("Successfully wrote %d bytes", count);
return count;