# HG changeset patch # User asaha # Date 1397670790 25200 # Node ID 956d11daac9d3f67e41553cb7a6e1e7ca4a9cf4e # Parent 971bf0a51f751f14eb5d26a898ca6aef906d2dea# Parent af3ee8f2292cd352b1e2632b96e2a4234457b890 Merge diff -r 971bf0a51f75 -r 956d11daac9d jdk/make/CompileDemos.gmk --- a/jdk/make/CompileDemos.gmk Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/make/CompileDemos.gmk Wed Apr 16 10:53:10 2014 -0700 @@ -176,7 +176,6 @@ $(eval $(call SetupDemo,JTop,management,,JTop,,,README*)) $(eval $(call SetupDemo,MemoryMonitor,management,,MemoryMonitor,,,README*)) $(eval $(call SetupDemo,VerboseGC,management,,VerboseGC,,,README*)) -$(eval $(call SetupDemo,zipfs,nio,,,,,README* *.java,,,,Main-Class: \n)) ifndef OPENJDK $(eval $(call SetupDemo,Laffy,jfc,,,,closed/,*)) diff -r 971bf0a51f75 -r 956d11daac9d jdk/make/CopyFiles.gmk --- a/jdk/make/CopyFiles.gmk Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/make/CopyFiles.gmk Wed Apr 16 10:53:10 2014 -0700 @@ -158,15 +158,6 @@ ########################################################################################## -CONTENT_TYPES_SRC = $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/lib - -$(LIBDIR)/content-types.properties: $(CONTENT_TYPES_SRC)/content-types.properties - $(call install-file) - -COPY_FILES += $(LIBDIR)/content-types.properties - -########################################################################################## - CALENDARS_SRC := $(JDK_TOPDIR)/src/share/lib $(LIBDIR)/calendars.properties: $(CALENDARS_SRC)/calendars.properties diff -r 971bf0a51f75 -r 956d11daac9d jdk/make/CopyIntoClasses.gmk --- a/jdk/make/CopyIntoClasses.gmk Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/make/CopyIntoClasses.gmk Wed Apr 16 10:53:10 2014 -0700 @@ -26,7 +26,7 @@ # Copy icu and _dict files used by the text break iterator COPY_PATTERNS := .icu _dict .dat _options .js aliasmap .spp .wav .css \ - .png .gif .xml .dtd .txt oqlhelp.html + .png .gif .xml .dtd .txt oqlhelp.html content-types.properties # These directories should not be copied at all EXCLUDES += \ diff -r 971bf0a51f75 -r 956d11daac9d jdk/make/CreateJars.gmk --- a/jdk/make/CreateJars.gmk Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/make/CreateJars.gmk Wed Apr 16 10:53:10 2014 -0700 @@ -160,11 +160,13 @@ javax/swing/JWindowBeanInfo.class \ javax/swing/SwingBeanInfoBase.class \ javax/swing/text/JTextComponentBeanInfo.class \ + jdk/nio/zipfs \ META-INF/services/com.sun.jdi.connect.Connector \ META-INF/services/com.sun.jdi.connect.spi.TransportService \ META-INF/services/com.sun.tools.attach.spi.AttachProvider \ META-INF/services/com.sun.tools.xjc.Plugin \ META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor \ + META-INF/services/java.nio.file.spi.FileSystemProvider \ org/relaxng/datatype \ sun/awt/HKSCS.class \ sun/awt/motif/X11GB2312.class \ @@ -356,6 +358,16 @@ ########################################################################################## +$(eval $(call SetupArchive,BUILD_ZIPFS_JAR, , \ + SRCS := $(JDK_OUTPUTDIR)/classes, \ + INCLUDES := jdk/nio/zipfs, \ + EXTRA_FILES := META-INF/services/java.nio.file.spi.FileSystemProvider, \ + JAR := $(IMAGES_OUTPUTDIR)/lib/ext/zipfs.jar, \ + SKIP_METAINF := true, \ + CHECK_COMPRESS_JAR := true)) + +########################################################################################## + ifndef OPENJDK ifeq ($(ENABLE_JFR), true) $(eval $(call SetupArchive,BUILD_JFR_JAR, , \ @@ -660,11 +672,6 @@ ########################################################################################## -$(IMAGES_OUTPUTDIR)/lib/ext/zipfs.jar: $(JDK_OUTPUTDIR)/demo/nio/zipfs/zipfs.jar - $(install-file) - -########################################################################################## - # This file is imported from hotspot in Import.gmk. Copying it into images/lib so that # all jars can be found in one place when creating images in Images.gmk. It needs to be # done here so that clean targets can be simple and accurate. diff -r 971bf0a51f75 -r 956d11daac9d jdk/make/data/jdwp/jdwp.spec --- a/jdk/make/data/jdwp/jdwp.spec Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/make/data/jdwp/jdwp.spec Wed Apr 16 10:53:10 2014 -0700 @@ -1079,7 +1079,7 @@ (Command InvokeMethod=3 "Invokes a static method. " "The method must be member of the class type " - "or one of its superclasses, superinterfaces, or implemented interfaces. " + "or one of its superclasses. " "Access control is not enforced; for example, private " "methods can be invoked." "

" diff -r 971bf0a51f75 -r 956d11daac9d jdk/make/profile-includes.txt --- a/jdk/make/profile-includes.txt Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/make/profile-includes.txt Wed Apr 16 10:53:10 2014 -0700 @@ -56,7 +56,6 @@ $(OPENJDK_TARGET_CPU_LEGACY_LIB)/server/Xusage.txt \ calendars.properties \ classlist \ - content-types.properties \ currency.data \ ext/localedata.jar \ ext/meta-index \ diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/macosx/classes/sun/font/CFontManager.java --- a/jdk/src/macosx/classes/sun/font/CFontManager.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/macosx/classes/sun/font/CFontManager.java Wed Apr 16 10:53:10 2014 -0700 @@ -27,6 +27,8 @@ import java.awt.*; import java.io.File; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; @@ -38,6 +40,7 @@ import sun.awt.FontConfiguration; import sun.awt.HeadlessToolkit; +import sun.misc.ThreadGroupUtils; import sun.lwawt.macosx.*; public class CFontManager extends SunFontManager { @@ -215,24 +218,19 @@ }); } }; - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - /* The thread must be a member of a thread group - * which will not get GCed before VM exit. - * Make its parent the top-level thread group. - */ - ThreadGroup tg = - Thread.currentThread().getThreadGroup(); - for (ThreadGroup tgn = tg; - tgn != null; - tg = tgn, tgn = tg.getParent()); - fileCloser = new Thread(tg, fileCloserRunnable); - fileCloser.setContextClassLoader(null); - Runtime.getRuntime().addShutdownHook(fileCloser); - return null; - } - }); + AccessController.doPrivileged( + (PrivilegedAction) () -> { + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + fileCloser = new Thread(rootTG, fileCloserRunnable); + fileCloser.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(fileCloser); + return null; + } + ); } } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/macosx/classes/sun/lwawt/LWToolkit.java --- a/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java Wed Apr 16 10:53:10 2014 -0700 @@ -35,6 +35,7 @@ import sun.awt.*; import sun.print.*; +import sun.misc.ThreadGroupUtils; import static sun.lwawt.LWWindowPeer.PeerType; @@ -70,30 +71,17 @@ protected final void init() { AWTAutoShutdown.notifyToolkitThreadBusy(); - ThreadGroup mainTG = AccessController.doPrivileged( - new PrivilegedAction() { - public ThreadGroup run() { - ThreadGroup currentTG = Thread.currentThread().getThreadGroup(); - ThreadGroup parentTG = currentTG.getParent(); - while (parentTG != null) { - currentTG = parentTG; - parentTG = currentTG.getParent(); - } - return currentTG; - } - } - ); + ThreadGroup rootTG = AccessController.doPrivileged( + (PrivilegedAction) ThreadGroupUtils::getRootThreadGroup); Runtime.getRuntime().addShutdownHook( - new Thread(mainTG, new Runnable() { - public void run() { - shutdown(); - waitForRunState(STATE_CLEANUP); - } + new Thread(rootTG, () -> { + shutdown(); + waitForRunState(STATE_CLEANUP); }) ); - Thread toolkitThread = new Thread(mainTG, this, "AWT-LW"); + Thread toolkitThread = new Thread(rootTG, this, "AWT-LW"); toolkitThread.setDaemon(true); toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); toolkitThread.start(); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/macosx/classes/sun/lwawt/macosx/CClipboard.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CClipboard.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CClipboard.java Wed Apr 16 10:53:10 2014 -0700 @@ -58,7 +58,7 @@ @Override protected void setContentsNative(Transferable contents) { - + FlavorTable flavorMap = getDefaultFlavorTable(); // Don't use delayed Clipboard rendering for the Transferable's data. // If we did that, we would call Transferable.getTransferData on // the Toolkit thread, which is a security hole. diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java --- a/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/LWCToolkit.java Wed Apr 16 10:53:10 2014 -0700 @@ -483,8 +483,12 @@ private static final String APPKIT_THREAD_NAME = "AppKit Thread"; // Intended to be called from the LWCToolkit.m only. - private static void installToolkitThreadNameInJava() { + private static void installToolkitThreadInJava() { Thread.currentThread().setName(APPKIT_THREAD_NAME); + AccessController.doPrivileged((PrivilegedAction) () -> { + Thread.currentThread().setContextClassLoader(null); + return null; + }); } @Override diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/macosx/lib/content-types.properties --- a/jdk/src/macosx/lib/content-types.properties Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +0,0 @@ -#sun.net.www MIME content-types table -# -# Property fields: -# -# ::= 'description' '=' -# ::= 'file_extensions' '=' -# ::= 'icon' '=' -# ::= 'browser' | 'application' | 'save' | 'unknown' -# ::= 'application' '=' -# - -# -# The "we don't know anything about this data" type(s). -# Used internally to mark unrecognized types. -# -content/unknown: description=Unknown Content -unknown/unknown: description=Unknown Data Type - -# -# The template we should use for temporary files when launching an application -# to view a document of given type. -# -temp.file.template: /tmp/%s - -# -# The "real" types. -# -application/octet-stream: \ - description=Generic Binary Stream;\ - file_extensions=.saveme,.dump,.hqx,.arc,.o,.a,.bin,.exe,.z,.gz - -application/oda: \ - description=ODA Document;\ - file_extensions=.oda - -application/pdf: \ - description=Adobe PDF Format;\ - file_extensions=.pdf - -application/postscript: \ - description=Postscript File;\ - file_extensions=.eps,.ai,.ps;\ - icon=ps;\ - action=application;\ - application=imagetool %s - -application/x-dvi: \ - description=TeX DVI File;\ - file_extensions=.dvi;\ - action=application;\ - application=xdvi %s - -application/x-hdf: \ - description=Hierarchical Data Format;\ - file_extensions=.hdf;\ - action=save - -application/x-latex: \ - description=LaTeX Source;\ - file_extensions=.latex - -application/x-netcdf: \ - description=Unidata netCDF Data Format;\ - file_extensions=.nc,.cdf;\ - action=save - -application/x-tex: \ - description=TeX Source;\ - file_extensions=.tex - -application/x-texinfo: \ - description=Gnu Texinfo;\ - file_extensions=.texinfo,.texi - -application/x-troff: \ - description=Troff Source;\ - file_extensions=.t,.tr,.roff;\ - action=application;\ - application=xterm -title troff -e sh -c \"nroff %s | col | more -w\" - -application/x-troff-man: \ - description=Troff Manpage Source;\ - file_extensions=.man;\ - action=application;\ - application=xterm -title troff -e sh -c \"nroff -man %s | col | more -w\" - -application/x-troff-me: \ - description=Troff ME Macros;\ - file_extensions=.me;\ - action=application;\ - application=xterm -title troff -e sh -c \"nroff -me %s | col | more -w\" - -application/x-troff-ms: \ - description=Troff MS Macros;\ - file_extensions=.ms;\ - action=application;\ - application=xterm -title troff -e sh -c \"nroff -ms %s | col | more -w\" - -application/x-wais-source: \ - description=Wais Source;\ - file_extensions=.src,.wsrc - -application/zip: \ - description=Zip File;\ - file_extensions=.zip;\ - icon=zip;\ - action=save - -application/x-bcpio: \ - description=Old Binary CPIO Archive;\ - file_extensions=.bcpio; action=save - -application/x-cpio: \ - description=Unix CPIO Archive;\ - file_extensions=.cpio; action=save - -application/x-gtar: \ - description=Gnu Tar Archive;\ - file_extensions=.gtar;\ - icon=tar;\ - action=save - -application/x-shar: \ - description=Shell Archive;\ - file_extensions=.sh,.shar;\ - action=save - -application/x-sv4cpio: \ - description=SVR4 CPIO Archive;\ - file_extensions=.sv4cpio; action=save - -application/x-sv4crc: \ - description=SVR4 CPIO with CRC;\ - file_extensions=.sv4crc; action=save - -application/x-tar: \ - description=Tar Archive;\ - file_extensions=.tar;\ - icon=tar;\ - action=save - -application/x-ustar: \ - description=US Tar Archive;\ - file_extensions=.ustar;\ - action=save - -audio/basic: \ - description=Basic Audio;\ - file_extensions=.snd,.au;\ - icon=audio;\ - action=application;\ - application=audiotool %s - -audio/x-aiff: \ - description=Audio Interchange Format File;\ - file_extensions=.aifc,.aif,.aiff;\ - icon=aiff - -audio/x-wav: \ - description=Wav Audio;\ - file_extensions=.wav;\ - icon=wav - -image/gif: \ - description=GIF Image;\ - file_extensions=.gif;\ - icon=gif;\ - action=browser - -image/ief: \ - description=Image Exchange Format;\ - file_extensions=.ief - -image/jpeg: \ - description=JPEG Image;\ - file_extensions=.jfif,.jfif-tbnl,.jpe,.jpg,.jpeg;\ - icon=jpeg;\ - action=browser;\ - application=imagetool %s - -image/tiff: \ - description=TIFF Image;\ - file_extensions=.tif,.tiff;\ - icon=tiff - -image/vnd.fpx: \ - description=FlashPix Image;\ - file_extensions=.fpx,.fpix - -image/x-cmu-rast: \ - description=CMU Raster Image;\ - file_extensions=.ras - -image/x-portable-anymap: \ - description=PBM Anymap Format;\ - file_extensions=.pnm - -image/x-portable-bitmap: \ - description=PBM Bitmap Format;\ - file_extensions=.pbm - -image/x-portable-graymap: \ - description=PBM Graymap Format;\ - file_extensions=.pgm - -image/x-portable-pixmap: \ - description=PBM Pixmap Format;\ - file_extensions=.ppm - -image/x-rgb: \ - description=RGB Image;\ - file_extensions=.rgb - -image/x-xbitmap: \ - description=X Bitmap Image;\ - file_extensions=.xbm,.xpm - -image/x-xwindowdump: \ - description=X Window Dump Image;\ - file_extensions=.xwd - -image/png: \ - description=PNG Image;\ - file_extensions=.png;\ - icon=png;\ - action=browser - -text/html: \ - description=HTML Document;\ - file_extensions=.htm,.html;\ - icon=html - -text/plain: \ - description=Plain Text;\ - file_extensions=.text,.c,.cc,.c++,.h,.pl,.txt,.java,.el;\ - icon=text;\ - action=browser - -text/tab-separated-values: \ - description=Tab Separated Values Text;\ - file_extensions=.tsv - -text/x-setext: \ - description=Structure Enhanced Text;\ - file_extensions=.etx - -video/mpeg: \ - description=MPEG Video Clip;\ - file_extensions=.mpg,.mpe,.mpeg;\ - icon=mpeg;\ - action=application;\ - application=mpeg_play %s - -video/quicktime: \ - description=QuickTime Video Clip;\ - file_extensions=.mov,.qt - -application/x-troff-msvideo: \ - description=AVI Video;\ - file_extensions=.avi;\ - icon=avi - -video/x-sgi-movie: \ - description=SGI Movie;\ - file_extensions=.movie,.mv - -message/rfc822: \ - description=Internet Email Message;\ - file_extensions=.mime - -application/xml: \ - description=XML document;\ - file_extensions=.xml - - - diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/macosx/native/sun/awt/LWCToolkit.m --- a/jdk/src/macosx/native/sun/awt/LWCToolkit.m Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/macosx/native/sun/awt/LWCToolkit.m Wed Apr 16 10:53:10 2014 -0700 @@ -233,15 +233,16 @@ Java_sun_lwawt_macosx_LWCToolkit_initIDs (JNIEnv *env, jclass klass) { // set thread names - dispatch_async(dispatch_get_main_queue(), ^(void){ - [[NSThread currentThread] setName:@"AppKit Thread"]; - - JNIEnv *env = [ThreadUtilities getJNIEnv]; - static JNF_CLASS_CACHE(jc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit"); - static JNF_STATIC_MEMBER_CACHE(jsm_installToolkitThreadNameInJava, jc_LWCToolkit, "installToolkitThreadNameInJava", "()V"); - JNFCallStaticVoidMethod(env, jsm_installToolkitThreadNameInJava); - }); - + if (![ThreadUtilities isAWTEmbedded]) { + dispatch_async(dispatch_get_main_queue(), ^(void){ + [[NSThread currentThread] setName:@"AppKit Thread"]; + JNIEnv *env = [ThreadUtilities getJNIEnv]; + static JNF_CLASS_CACHE(jc_LWCToolkit, "sun/lwawt/macosx/LWCToolkit"); + static JNF_STATIC_MEMBER_CACHE(jsm_installToolkitThreadInJava, jc_LWCToolkit, "installToolkitThreadInJava", "()V"); + JNFCallStaticVoidMethod(env, jsm_installToolkitThreadInJava); + }); + } + gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS; jclass inputEventClazz = (*env)->FindClass(env, "java/awt/event/InputEvent"); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/macosx/native/sun/awt/awt.m --- a/jdk/src/macosx/native/sun/awt/awt.m Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/macosx/native/sun/awt/awt.m Wed Apr 16 10:53:10 2014 -0700 @@ -363,6 +363,7 @@ // AppKit Application. NSApplication *app = [NSApplicationAWT sharedApplication]; isEmbedded = ![NSApp isKindOfClass:[NSApplicationAWT class]]; + [ThreadUtilities setAWTEmbedded:isEmbedded]; if (!isEmbedded) { // Install run loop observers and set the AppKit Java thread name @@ -433,6 +434,14 @@ if (isSWTInWebStart(env)) { forceEmbeddedMode = YES; } + JNIEnv* env = [ThreadUtilities getJNIEnvUncached]; + jclass jc_ThreadGroupUtils = (*env)->FindClass(env, "sun/misc/ThreadGroupUtils"); + jmethodID sjm_getRootThreadGroup = (*env)->GetStaticMethodID(env, jc_ThreadGroupUtils, "getRootThreadGroup", "()Ljava/lang/ThreadGroup;"); + jobject rootThreadGroup = (*env)->CallStaticObjectMethod(env, jc_ThreadGroupUtils, sjm_getRootThreadGroup); + [ThreadUtilities setAppkitThreadGroup:(*env)->NewGlobalRef(env, rootThreadGroup)]; + // The current thread was attached in getJNIEnvUnchached. + // Detach it back. It will be reattached later if needed with a proper TG + [ThreadUtilities detachCurrentThread]; BOOL headless = isHeadless(env); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h --- a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.h Wed Apr 16 10:53:10 2014 -0700 @@ -127,6 +127,10 @@ + (JNIEnv*)getJNIEnv; + (JNIEnv*)getJNIEnvUncached; ++ (void)detachCurrentThread; ++ (void)setAppkitThreadGroup:(jobject)group; ++ (void)setAWTEmbedded:(BOOL)embedded; ++ (BOOL)isAWTEmbedded; //Wrappers for the corresponding JNFRunLoop methods with a check for main thread + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m --- a/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/macosx/native/sun/osxapp/ThreadUtilities.m Wed Apr 16 10:53:10 2014 -0700 @@ -33,23 +33,45 @@ // The following must be named "jvm", as there are extern references to it in AWT JavaVM *jvm = NULL; static JNIEnv *appKitEnv = NULL; +static jobject appkitThreadGroup = NULL; +static BOOL awtEmbedded = NO; + +inline void attachCurrentThread(void** env) { + if ([NSThread isMainThread]) { + JavaVMAttachArgs args; + args.version = JNI_VERSION_1_4; + args.name = "AppKit Thread"; + args.group = appkitThreadGroup; + (*jvm)->AttachCurrentThreadAsDaemon(jvm, env, &args); + } else { + (*jvm)->AttachCurrentThreadAsDaemon(jvm, env, NULL); + } +} @implementation ThreadUtilities + (JNIEnv*)getJNIEnv { AWT_ASSERT_APPKIT_THREAD; if (appKitEnv == NULL) { - (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void **)&appKitEnv, NULL); + attachCurrentThread((void **)&appKitEnv); } return appKitEnv; } + (JNIEnv*)getJNIEnvUncached { JNIEnv *env = NULL; - (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void **)&env, nil); + attachCurrentThread((void **)&env); return env; } ++ (void)detachCurrentThread { + (*jvm)->DetachCurrentThread(jvm); +} + ++ (void)setAppkitThreadGroup:(jobject)group { + appkitThreadGroup = group; +} + + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block { if ([NSThread isMainThread] && wait == YES) { block(); @@ -66,6 +88,14 @@ } } ++ (void)setAWTEmbedded:(BOOL)embedded { + awtEmbedded = embedded; +} + ++ (BOOL)isAWTEmbedded { + return awtEmbedded; +} + @end diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/com/sun/jmx/remote/security/SubjectDelegator.java --- a/jdk/src/share/classes/com/sun/jmx/remote/security/SubjectDelegator.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/com/sun/jmx/remote/security/SubjectDelegator.java Wed Apr 16 10:53:10 2014 -0700 @@ -35,6 +35,8 @@ import javax.management.remote.SubjectDelegationPermission; import com.sun.jmx.remote.util.CacheMap; +import java.util.ArrayList; +import java.util.Collection; public class SubjectDelegator { private static final int PRINCIPALS_CACHE_SIZE = 10; @@ -53,11 +55,14 @@ boolean removeCallerContext) throws SecurityException { + if (System.getSecurityManager() != null && authenticatedACC == null) { + throw new SecurityException("Illegal AccessControlContext: null"); + } if (principalsCache == null || accCache == null) { principalsCache = - new CacheMap(PRINCIPALS_CACHE_SIZE); + new CacheMap<>(PRINCIPALS_CACHE_SIZE); accCache = - new CacheMap(ACC_CACHE_SIZE); + new CacheMap<>(ACC_CACHE_SIZE); } // Retrieve the principals for the given @@ -101,14 +106,15 @@ // principal in the delegated subject // final Principal[] dp = delegatedPrincipals; + final Collection permissions = new ArrayList<>(dp.length); + for(Principal p : dp) { + final String pname = p.getClass().getName() + "." + p.getName(); + permissions.add(new SubjectDelegationPermission(pname)); + } PrivilegedAction action = new PrivilegedAction() { public Void run() { - for (int i = 0 ; i < dp.length ; i++) { - final String pname = - dp[i].getClass().getName() + "." + dp[i].getName(); - Permission sdp = - new SubjectDelegationPermission(pname); + for (Permission sdp : permissions) { AccessController.checkPermission(sdp); } return null; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/com/sun/jndi/dns/DnsClient.java --- a/jdk/src/share/classes/com/sun/jndi/dns/DnsClient.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/com/sun/jndi/dns/DnsClient.java Wed Apr 16 10:53:10 2014 -0700 @@ -30,13 +30,14 @@ import java.net.DatagramPacket; import java.net.InetAddress; import java.net.Socket; +import java.security.SecureRandom; import javax.naming.*; import java.util.Collections; import java.util.Map; import java.util.HashMap; -import java.util.Set; -import java.util.HashSet; + +import sun.security.jca.JCAUtil; // Some of this code began life as part of sun.javaos.net.DnsClient // originally by sritchie@eng 1/96. It was first hacked up for JNDI @@ -77,6 +78,8 @@ }; private static final int DEFAULT_PORT = 53; + private static final int TRANSACTION_ID_BOUND = 0x10000; + private static final SecureRandom random = JCAUtil.getSecureRandom(); private InetAddress[] servers; private int[] serverPorts; private int timeout; // initial timeout on UDP queries in ms @@ -85,7 +88,7 @@ private DatagramSocket udpSocket; // Requests sent - private Set reqs; + private Map reqs; // Responses received private Map resps; @@ -134,7 +137,8 @@ throw ne; } } - reqs = Collections.synchronizedSet(new HashSet()); + reqs = Collections.synchronizedMap( + new HashMap()); resps = Collections.synchronizedMap(new HashMap()); } @@ -153,10 +157,6 @@ } } - - private int ident = 0; // used to set the msg ID field - private Object identLock = new Object(); - /* * If recursion is true, recursion is requested on the query. * If auth is true, only authoritative responses are accepted; other @@ -167,15 +167,19 @@ throws NamingException { int xid; - synchronized (identLock) { - ident = 0xFFFF & (ident + 1); - xid = ident; - } + Packet pkt; + ResourceRecord collision; - // enqueue the outstanding request - reqs.add(xid); + do { + // Generate a random transaction ID + xid = random.nextInt(TRANSACTION_ID_BOUND); + pkt = makeQueryPacket(fqdn, xid, qclass, qtype, recursion); - Packet pkt = makeQueryPacket(fqdn, xid, qclass, qtype, recursion); + // enqueue the outstanding request + collision = reqs.putIfAbsent(xid, new ResourceRecord(pkt.getData(), + pkt.length(), Header.HEADER_SIZE, true, false)); + + } while (collision != null); Exception caughtException = null; boolean[] doNotRetry = new boolean[servers.length]; @@ -305,11 +309,8 @@ ResourceRecords queryZone(DnsName zone, int qclass, boolean recursion) throws NamingException { - int xid; - synchronized (identLock) { - ident = 0xFFFF & (ident + 1); - xid = ident; - } + int xid = random.nextInt(TRANSACTION_ID_BOUND); + Packet pkt = makeQueryPacket(zone, xid, qclass, ResourceRecord.QTYPE_AXFR, recursion); Exception caughtException = null; @@ -390,6 +391,7 @@ DatagramPacket opkt = new DatagramPacket( pkt.getData(), pkt.length(), server, port); DatagramPacket ipkt = new DatagramPacket(new byte[8000], 8000); + // Packets may only be sent to or received from this server address udpSocket.connect(server, port); int pktTimeout = (timeout * (1 << retry)); try { @@ -542,6 +544,9 @@ * Checks the header of an incoming DNS response. * Returns true if it matches the given xid and throws a naming * exception, if appropriate, based on the response code. + * + * Also checks that the domain name, type and class in the response + * match those in the original query. */ private boolean isMatchResponse(byte[] pkt, int xid) throws NamingException { @@ -551,7 +556,7 @@ throw new CommunicationException("DNS error: expecting response"); } - if (!reqs.contains(xid)) { // already received, ignore the response + if (!reqs.containsKey(xid)) { // already received, ignore the response return false; } @@ -560,14 +565,47 @@ if (debug) { dprint("XID MATCH:" + xid); } + checkResponseCode(hdr); + if (!hdr.query && hdr.numQuestions == 1) { - checkResponseCode(hdr); - // remove the response for the xid if received by some other thread. - synchronized (queuesLock) { - resps.remove(xid); - reqs.remove(xid); + ResourceRecord rr = new ResourceRecord(pkt, pkt.length, + Header.HEADER_SIZE, true, false); + + // Retrieve the original query + ResourceRecord query = reqs.get(xid); + int qtype = query.getType(); + int qclass = query.getRrclass(); + DnsName qname = query.getName(); + + // Check that the type/class/name in the query section of the + // response match those in the original query + if ((qtype == ResourceRecord.QTYPE_STAR || + qtype == rr.getType()) && + (qclass == ResourceRecord.QCLASS_STAR || + qclass == rr.getRrclass()) && + qname.equals(rr.getName())) { + + if (debug) { + dprint("MATCH NAME:" + qname + " QTYPE:" + qtype + + " QCLASS:" + qclass); + } + + // Remove the response for the xid if received by some other + // thread. + synchronized (queuesLock) { + resps.remove(xid); + reqs.remove(xid); + } + return true; + + } else { + if (debug) { + dprint("NO-MATCH NAME:" + qname + " QTYPE:" + qtype + + " QCLASS:" + qclass); + } + } } - return true; + return false; } // @@ -576,7 +614,7 @@ // enqueue only the first response, responses for retries are ignored. // synchronized (queuesLock) { - if (reqs.contains(hdr.xid)) { // enqueue only the first response + if (reqs.containsKey(hdr.xid)) { // enqueue only the first response resps.put(hdr.xid, pkt); } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java --- a/jdk/src/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/com/sun/jndi/ldap/LdapBindingEnumeration.java Wed Apr 16 10:53:10 2014 -0700 @@ -25,6 +25,10 @@ package com.sun.jndi.ldap; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.Vector; import javax.naming.*; import javax.naming.directory.*; @@ -36,6 +40,8 @@ final class LdapBindingEnumeration extends AbstractLdapNamingEnumeration { + private final AccessControlContext acc = AccessController.getContext(); + LdapBindingEnumeration(LdapCtx homeCtx, LdapResult answer, Name remain, Continuation cont) throws NamingException { @@ -52,7 +58,16 @@ if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) { // serialized object or object reference - obj = Obj.decodeObject(attrs); + try { + obj = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Object run() throws NamingException { + return Obj.decodeObject(attrs); + } + }, acc); + } catch (PrivilegedActionException e) { + throw (NamingException)e.getException(); + } } if (obj == null) { // DirContext object diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java --- a/jdk/src/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/com/sun/jndi/ldap/LdapSearchEnumeration.java Wed Apr 16 10:53:10 2014 -0700 @@ -25,6 +25,10 @@ package com.sun.jndi.ldap; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.Vector; import javax.naming.*; import javax.naming.directory.*; @@ -40,6 +44,8 @@ private Name startName; // prefix of names of search results private LdapCtx.SearchArgs searchArgs = null; + private final AccessControlContext acc = AccessController.getContext(); + LdapSearchEnumeration(LdapCtx homeCtx, LdapResult search_results, String starter, LdapCtx.SearchArgs args, Continuation cont) throws NamingException { @@ -112,8 +118,16 @@ if (attrs.get(Obj.JAVA_ATTRIBUTES[Obj.CLASSNAME]) != null) { // Entry contains Java-object attributes (ser/ref object) // serialized object or object reference - obj = Obj.decodeObject(attrs); - + try { + obj = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public Object run() throws NamingException { + return Obj.decodeObject(attrs); + } + }, acc); + } catch (PrivilegedActionException e) { + throw (NamingException)e.getException(); + } } if (obj == null) { obj = new LdapCtx(homeCtx, dn); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/com/sun/media/sound/JDK13Services.java --- a/jdk/src/share/classes/com/sun/media/sound/JDK13Services.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/com/sun/media/sound/JDK13Services.java Wed Apr 16 10:53:10 2014 -0700 @@ -25,27 +25,33 @@ package com.sun.media.sound; +import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Properties; import javax.sound.midi.Receiver; import javax.sound.midi.Sequencer; import javax.sound.midi.Synthesizer; import javax.sound.midi.Transmitter; +import javax.sound.midi.spi.MidiDeviceProvider; +import javax.sound.midi.spi.MidiFileReader; +import javax.sound.midi.spi.MidiFileWriter; +import javax.sound.midi.spi.SoundbankReader; import javax.sound.sampled.Clip; import javax.sound.sampled.Port; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.TargetDataLine; +import javax.sound.sampled.spi.AudioFileReader; +import javax.sound.sampled.spi.AudioFileWriter; +import javax.sound.sampled.spi.FormatConversionProvider; +import javax.sound.sampled.spi.MixerProvider; /** - * JDK13Services uses the Service class in JDK 1.3 - * to discover a list of service providers installed - * in the system. - * + * JDK13Services uses the Service class in JDK 1.3 to discover a list of service + * providers installed in the system. + *

* This class is public because it is called from javax.sound.midi.MidiSystem * and javax.sound.sampled.AudioSystem. The alternative would be to make * JSSecurityManager public, which is considered worse. @@ -54,80 +60,55 @@ */ public final class JDK13Services { - /** The default for the length of the period to hold the cache. - This value is given in milliseconds. It is equivalent to - 1 minute. - */ - private static final long DEFAULT_CACHING_PERIOD = 60000; - - /** Filename of the properties file for default provider properties. - This file is searched in the subdirectory "lib" of the JRE directory - (this behaviour is hardcoded). - */ + /** + * Filename of the properties file for default provider properties. This + * file is searched in the subdirectory "lib" of the JRE directory (this + * behaviour is hardcoded). + */ private static final String PROPERTIES_FILENAME = "sound.properties"; - /** Cache for the providers. - Class objects of the provider type (MixerProvider, MidiDeviceProvider - ...) are used as keys. The values are instances of ProviderCache. - */ - private static final Map providersCacheMap = new HashMap(); - - - /** The length of the period to hold the cache. - This value is given in milliseconds. - */ - private static long cachingPeriod = DEFAULT_CACHING_PERIOD; - - /** Properties loaded from the properties file for default provider - properties. - */ + /** + * Properties loaded from the properties file for default provider + * properties. + */ private static Properties properties; - - /** Private, no-args constructor to ensure against instantiation. + /** + * Private, no-args constructor to ensure against instantiation. */ private JDK13Services() { } - - /** Set the period provider lists are cached. - This method is only intended for testing. + /** + * Obtains a List containing installed instances of the providers for the + * requested service. The returned List is immutable. + * + * @param serviceClass The type of providers requested. This should be one + * of AudioFileReader.class, AudioFileWriter.class, + * FormatConversionProvider.class, MixerProvider.class, + * MidiDeviceProvider.class, MidiFileReader.class, + * MidiFileWriter.class or SoundbankReader.class. + * + * @return A List of providers of the requested type. This List is + * immutable. */ - public static void setCachingPeriod(int seconds) { - cachingPeriod = seconds * 1000L; + public static List getProviders(final Class serviceClass) { + final List providers; + if (!MixerProvider.class.equals(serviceClass) + && !FormatConversionProvider.class.equals(serviceClass) + && !AudioFileReader.class.equals(serviceClass) + && !AudioFileWriter.class.equals(serviceClass) + && !MidiDeviceProvider.class.equals(serviceClass) + && !SoundbankReader.class.equals(serviceClass) + && !MidiFileWriter.class.equals(serviceClass) + && !MidiFileReader.class.equals(serviceClass)) { + providers = new ArrayList<>(0); + } else { + providers = JSSecurityManager.getProviders(serviceClass); + } + return Collections.unmodifiableList(providers); } - - /** Obtains a List containing installed instances of the - providers for the requested service. - The List of providers is cached for the period of time given by - {@link #cachingPeriod cachingPeriod}. During this period, the same - List instance is returned for the same type of provider. After this - period, a new instance is constructed and returned. The returned - List is immutable. - @param serviceClass The type of providers requested. This should be one - of AudioFileReader.class, AudioFileWriter.class, - FormatConversionProvider.class, MixerProvider.class, - MidiDeviceProvider.class, MidiFileReader.class, MidiFileWriter.class or - SoundbankReader.class. - @return A List of providers of the requested type. This List is - immutable. - */ - public static synchronized List getProviders(Class serviceClass) { - ProviderCache cache = (ProviderCache) providersCacheMap.get(serviceClass); - if (cache == null) { - cache = new ProviderCache(); - providersCacheMap.put(serviceClass, cache); - } - if (cache.providers == null || - System.currentTimeMillis() > cache.lastUpdate + cachingPeriod) { - cache.providers = Collections.unmodifiableList(JSSecurityManager.getProviders(serviceClass)); - cache.lastUpdate = System.currentTimeMillis(); - } - return cache.providers; - } - - /** Obtain the provider class name part of a default provider property. @param typeClass The type of the default provider property. This should be one of Receiver.class, Transmitter.class, Sequencer.class, @@ -219,14 +200,4 @@ } return properties; } - - // INNER CLASSES - - private static class ProviderCache { - // System time of the last update in milliseconds. - public long lastUpdate; - - // The providers. - public List providers; - } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/com/sun/media/sound/JSSecurityManager.java --- a/jdk/src/share/classes/com/sun/media/sound/JSSecurityManager.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/com/sun/media/sound/JSSecurityManager.java Wed Apr 16 10:53:10 2014 -0700 @@ -185,8 +185,8 @@ return thread; } - static List getProviders(final Class providerClass) { - List p = new ArrayList<>(); + static synchronized List getProviders(final Class providerClass) { + List p = new ArrayList<>(7); // ServiceLoader creates "lazy" iterator instance, but it ensures that // next/hasNext run with permissions that are restricted by whatever // creates the ServiceLoader instance, so it requires to be called from diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java --- a/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/com/sun/rowset/CachedRowSetImpl.java Wed Apr 16 10:53:10 2014 -0700 @@ -37,6 +37,7 @@ import javax.sql.rowset.serial.*; import com.sun.rowset.internal.*; import com.sun.rowset.providers.*; +import sun.reflect.misc.ReflectUtil; /** * The standard implementation of the CachedRowSet interface. @@ -2959,13 +2960,9 @@ // create new instance of the class SQLData obj = null; try { - obj = (SQLData)c.newInstance(); - } catch (java.lang.InstantiationException ex) { - throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(), - ex.getMessage())); - } catch (java.lang.IllegalAccessException ex) { - throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(), - ex.getMessage())); + obj = (SQLData) ReflectUtil.newInstance(c); + } catch(Exception ex) { + throw new SQLException("Unable to Instantiate: ", ex); } // get the attributes from the struct Object attribs[] = s.getAttributes(map); @@ -5710,13 +5707,9 @@ // create new instance of the class SQLData obj = null; try { - obj = (SQLData)c.newInstance(); - } catch (java.lang.InstantiationException ex) { - throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(), - ex.getMessage())); - } catch (java.lang.IllegalAccessException ex) { - throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(), - ex.getMessage())); + obj = (SQLData) ReflectUtil.newInstance(c); + } catch(Exception ex) { + throw new SQLException("Unable to Instantiate: ", ex); } // get the attributes from the struct Object attribs[] = s.getAttributes(map); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java --- a/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java Wed Apr 16 10:53:10 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import javax.sql.*; import java.util.*; import java.io.*; +import sun.reflect.misc.ReflectUtil; import com.sun.rowset.*; import java.text.MessageFormat; @@ -572,13 +573,9 @@ // create new instance of the class SQLData obj = null; try { - obj = (SQLData)c.newInstance(); - } catch (java.lang.InstantiationException ex) { - throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(), - ex.getMessage())); - } catch (java.lang.IllegalAccessException ex) { - throw new SQLException(MessageFormat.format(resBundle.handleGetObject("cachedrowsetimpl.unableins").toString(), - ex.getMessage())); + obj = (SQLData)ReflectUtil.newInstance(c); + } catch (Exception ex) { + throw new SQLException("Unable to Instantiate: ", ex); } // get the attributes from the struct Object attribs[] = s.getAttributes(map); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/awt/EventQueue.java --- a/jdk/src/share/classes/java/awt/EventQueue.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/awt/EventQueue.java Wed Apr 16 10:53:10 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1061,11 +1061,11 @@ t.setContextClassLoader(classLoader); t.setPriority(Thread.NORM_PRIORITY + 1); t.setDaemon(false); + AWTAutoShutdown.getInstance().notifyThreadBusy(t); return t; } } ); - AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread); dispatchThread.start(); } } finally { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java --- a/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/awt/datatransfer/SystemFlavorMap.java Wed Apr 16 10:53:10 2014 -0700 @@ -46,6 +46,7 @@ import java.util.Set; import java.util.WeakHashMap; +import sun.awt.AppContext; import sun.awt.datatransfer.DataTransferer; /** @@ -65,10 +66,7 @@ */ private static String JavaMIME = "JAVA_DATAFLAVOR:"; - /** - * System singleton which maps a thread's ClassLoader to a SystemFlavorMap. - */ - private static final WeakHashMap flavorMaps = new WeakHashMap<>(); + private static final Object FLAVOR_MAP_KEY = new Object(); /** * Copied from java.util.Properties. @@ -183,22 +181,12 @@ * @return the default FlavorMap for this thread's ClassLoader */ public static FlavorMap getDefaultFlavorMap() { - ClassLoader contextClassLoader = - Thread.currentThread().getContextClassLoader(); - if (contextClassLoader == null) { - contextClassLoader = ClassLoader.getSystemClassLoader(); + AppContext context = AppContext.getAppContext(); + FlavorMap fm = (FlavorMap) context.get(FLAVOR_MAP_KEY); + if (fm == null) { + fm = new SystemFlavorMap(); + context.put(FLAVOR_MAP_KEY, fm); } - - FlavorMap fm; - - synchronized(flavorMaps) { - fm = flavorMaps.get(contextClassLoader); - if (fm == null) { - fm = new SystemFlavorMap(); - flavorMaps.put(contextClassLoader, fm); - } - } - return fm; } @@ -239,26 +227,11 @@ } }); - BufferedReader flavormapURL = + String url = java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public BufferedReader run() { - String url = Toolkit.getProperty("AWT.DnD.flavorMapFileURL", null); - - if (url == null) { - return null; - } - - try { - return new BufferedReader - (new InputStreamReader - (new URL(url).openStream(), "ISO-8859-1")); - } catch (MalformedURLException e) { - System.err.println("MalformedURLException:" + e + " while reading AWT.DnD.flavorMapFileURL:" + url); - } catch (IOException e) { - System.err.println("IOException:" + e + " while reading AWT.DnD.flavorMapFileURL:" + url); - } - return null; + new java.security.PrivilegedAction() { + public String run() { + return Toolkit.getProperty("AWT.DnD.flavorMapFileURL", null); } }); @@ -270,6 +243,19 @@ } } + BufferedReader flavormapURL = null; + if (url != null) { + try { + flavormapURL = new BufferedReader(new InputStreamReader(new URL(url).openStream(), "ISO-8859-1")); + } catch (MalformedURLException e) { + System.err.println("MalformedURLException:" + e + " while reading AWT.DnD.flavorMapFileURL:" + url); + } catch (IOException e) { + System.err.println("IOException:" + e + " while reading AWT.DnD.flavorMapFileURL:" + url); + } catch (SecurityException e) { + // ignored + } + } + if (flavormapURL != null) { try { parseAndStoreReader(flavormapURL); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/lang/Thread.java --- a/jdk/src/share/classes/java/lang/Thread.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/lang/Thread.java Wed Apr 16 10:53:10 2014 -0700 @@ -366,6 +366,8 @@ throw new NullPointerException("name cannot be null"); } + this.name = name.toCharArray(); + Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); if (g == null) { @@ -402,7 +404,6 @@ this.group = g; this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); - this.name = name.toCharArray(); if (security == null || isCCLOverridden(parent.getClass())) this.contextClassLoader = parent.getContextClassLoader(); else diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java --- a/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java Wed Apr 16 10:53:10 2014 -0700 @@ -140,7 +140,7 @@ * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a * static field containing this value, and they must accordingly implement this method. */ - protected abstract SpeciesData speciesData(); + /*non-public*/ abstract SpeciesData speciesData(); @Override final Object internalProperties() { @@ -156,7 +156,7 @@ return Arrays.asList(boundValues); } - public final Object arg(int i) { + /*non-public*/ final Object arg(int i) { try { switch (speciesData().fieldType(i)) { case 'L': return argL(i); @@ -170,22 +170,22 @@ } throw new InternalError("unexpected type: " + speciesData().types+"."+i); } - public final Object argL(int i) throws Throwable { return speciesData().getters[i].invokeBasic(this); } - public final int argI(int i) throws Throwable { return (int) speciesData().getters[i].invokeBasic(this); } - public final float argF(int i) throws Throwable { return (float) speciesData().getters[i].invokeBasic(this); } - public final double argD(int i) throws Throwable { return (double) speciesData().getters[i].invokeBasic(this); } - public final long argJ(int i) throws Throwable { return (long) speciesData().getters[i].invokeBasic(this); } + /*non-public*/ final Object argL(int i) throws Throwable { return speciesData().getters[i].invokeBasic(this); } + /*non-public*/ final int argI(int i) throws Throwable { return (int) speciesData().getters[i].invokeBasic(this); } + /*non-public*/ final float argF(int i) throws Throwable { return (float) speciesData().getters[i].invokeBasic(this); } + /*non-public*/ final double argD(int i) throws Throwable { return (double) speciesData().getters[i].invokeBasic(this); } + /*non-public*/ final long argJ(int i) throws Throwable { return (long) speciesData().getters[i].invokeBasic(this); } // // cloning API // - public abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable; - public abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable; - public abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable; - public abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable; - public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable; - public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable; + /*non-public*/ abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable; + /*non-public*/ abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable; + /*non-public*/ abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable; + /*non-public*/ abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable; + /*non-public*/ abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable; + /*non-public*/ abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable; // The following is a grossly irregular hack: @Override MethodHandle reinvokerTarget() { @@ -203,39 +203,39 @@ private // make it private to force users to access the enclosing class first static final class Species_L extends BoundMethodHandle { final Object argL0; - public Species_L(MethodType mt, LambdaForm lf, Object argL0) { + /*non-public*/ Species_L(MethodType mt, LambdaForm lf, Object argL0) { super(mt, lf); this.argL0 = argL0; } // The following is a grossly irregular hack: @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; } @Override - public SpeciesData speciesData() { + /*non-public*/ SpeciesData speciesData() { return SPECIES_DATA; } - public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class); + /*non-public*/ static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class); @Override - public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable { + /*non-public*/ final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable { return new Species_L(mt, lf, argL0); } @Override - public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable { + /*non-public*/ final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable { return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg); } @Override - public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable { + /*non-public*/ final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable { return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg); } @Override - public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable { + /*non-public*/ final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable { return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg); } @Override - public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable { + /*non-public*/ final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable { return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg); } @Override - public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable { + /*non-public*/ final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable { return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg); } } @@ -338,10 +338,10 @@ final MethodHandle[] getters; final SpeciesData[] extensions; - public int fieldCount() { + /*non-public*/ int fieldCount() { return types.length(); } - public char fieldType(int i) { + /*non-public*/ char fieldType(int i) { return types.charAt(i); } @@ -551,30 +551,30 @@ * final Object argL0; * final Object argL1; * final int argI2; - * public Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) { + * Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) { * super(mt, lf); * this.argL0 = argL0; * this.argL1 = argL1; * this.argI2 = argI2; * } - * public final SpeciesData speciesData() { return SPECIES_DATA; } - * public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class); - * public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) { + * final SpeciesData speciesData() { return SPECIES_DATA; } + * static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class); + * final BoundMethodHandle clone(MethodType mt, LambdaForm lf) { * return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2); * } - * public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) { + * final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) { * return SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } - * public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) { + * final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) { * return SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } - * public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) { + * final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) { * return SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } - * public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) { + * final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) { * return SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } - * public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) { + * final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) { * return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg); * } * } @@ -588,11 +588,12 @@ final String className = SPECIES_PREFIX_PATH + types; final String sourceFile = SPECIES_PREFIX_NAME + types; - cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null); + final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC + cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null); cw.visitSource(sourceFile, null); // emit static types and SPECIES_DATA fields - cw.visitField(ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd(); + cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd(); // emit bound argument fields for (int i = 0; i < types.length(); ++i) { @@ -605,7 +606,7 @@ MethodVisitor mv; // emit constructor - mv = cw.visitMethod(ACC_PUBLIC, "", makeSignature(types, true), null, null); + mv = cw.visitMethod(NOT_ACC_PUBLIC, "", makeSignature(types, true), null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); @@ -629,7 +630,7 @@ mv.visitEnd(); // emit implementation of reinvokerTarget() - mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null); + mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, className, "argL0", JLO_SIG); @@ -639,7 +640,7 @@ mv.visitEnd(); // emit implementation of speciesData() - mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null); + mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null); mv.visitCode(); mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG); mv.visitInsn(ARETURN); @@ -647,7 +648,7 @@ mv.visitEnd(); // emit clone() - mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE); + mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE); mv.visitCode(); // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...) // obtain constructor @@ -670,7 +671,7 @@ // for each type, emit cloneExtendT() for (Class c : TYPES) { char t = Wrapper.basicTypeChar(c); - mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE); + mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE); mv.visitCode(); // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg) // obtain constructor @@ -697,7 +698,7 @@ } // emit class initializer - mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "", VOID_SIG, null, null); + mv = cw.visitMethod(NOT_ACC_PUBLIC | ACC_STATIC, "", VOID_SIG, null, null); mv.visitCode(); mv.visitLdcInsn(types); mv.visitLdcInsn(Type.getObjectType(className)); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- a/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Apr 16 10:53:10 2014 -0700 @@ -272,8 +272,9 @@ * Set up class file generation. */ private void classFilePrologue() { + final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); - cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null); + cw.visit(Opcodes.V1_8, NOT_ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null); cw.visitSource(sourceFile, null); String invokerDesc = invokerType.toMethodDescriptorString(); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/lang/invoke/MethodHandles.java --- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java Wed Apr 16 10:53:10 2014 -0700 @@ -2070,6 +2070,7 @@ */ public static MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) { + reorder = reorder.clone(); checkReorder(reorder, newType, target.type()); return target.permuteArguments(newType, reorder); } @@ -2264,6 +2265,7 @@ throw newIllegalArgumentException("no argument type to remove"); ArrayList> ptypes = new ArrayList<>(oldType.parameterList()); ptypes.addAll(pos, valueTypes); + if (ptypes.size() != inargs) throw newIllegalArgumentException("valueTypes"); MethodType newType = MethodType.methodType(oldType.returnType(), ptypes); return target.dropArguments(newType, pos, dropped); } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/nio/file/Files.java --- a/jdk/src/share/classes/java/nio/file/Files.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/nio/file/Files.java Wed Apr 16 10:53:10 2014 -0700 @@ -38,7 +38,6 @@ import java.io.UncheckedIOException; import java.io.Writer; import java.nio.channels.Channels; -import java.nio.channels.FileChannel; import java.nio.channels.SeekableByteChannel; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; @@ -739,7 +738,7 @@ // don't have permission to get absolute path se = x; } - // find a decendent that exists + // find a descendant that exists Path parent = dir.getParent(); while (parent != null) { try { @@ -1400,7 +1399,7 @@ return target; } - // -- Miscellenous -- + // -- Miscellaneous -- /** * Reads the target of a symbolic link (optional operation). @@ -1535,7 +1534,7 @@ private static class FileTypeDetectors{ static final FileTypeDetector defaultFileTypeDetector = createDefaultFileTypeDetector(); - static final List installeDetectors = + static final List installedDetectors = loadInstalledDetectors(); // creates the default file type detector @@ -1614,7 +1613,7 @@ throws IOException { // try installed file type detectors - for (FileTypeDetector detector: FileTypeDetectors.installeDetectors) { + for (FileTypeDetector detector: FileTypeDetectors.installedDetectors) { String result = detector.probeContentType(path); if (result != null) return result; @@ -1922,7 +1921,7 @@ * * * {@code "posix:permissions,owner,size"} - * Reads the POSX file permissions, owner, and file size. + * Reads the POSIX file permissions, owner, and file size. * * * @@ -2448,7 +2447,7 @@ } /** - * Used by isReadbale, isWritable, isExecutable to test access to a file. + * Used by isReadable, isWritable, isExecutable to test access to a file. */ private static boolean isAccessible(Path path, AccessMode... modes) { try { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java --- a/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java Wed Apr 16 10:53:10 2014 -0700 @@ -81,7 +81,7 @@ // installed providers private static volatile List installedProviders; - // used to avoid recursive loading of instaled providers + // used to avoid recursive loading of installed providers private static boolean loadingProviders = false; private static Void checkPermission() { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/security/Provider.java --- a/jdk/src/share/classes/java/security/Provider.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/security/Provider.java Wed Apr 16 10:53:10 2014 -0700 @@ -1332,7 +1332,7 @@ addEngine("SSLContext", false, null); addEngine("TrustManagerFactory", false, null); // JGSS - addEngine("GssApiMechanism", true, "sun.security.jgss.GSSCaller"); + addEngine("GssApiMechanism", false, null); // SASL addEngine("SaslClientFactory", false, null); addEngine("SaslServerFactory", false, null); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/util/ServiceLoader.java --- a/jdk/src/share/classes/java/util/ServiceLoader.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/util/ServiceLoader.java Wed Apr 16 10:53:10 2014 -0700 @@ -382,7 +382,7 @@ return p; } catch (Throwable x) { fail(service, - "Provider " + cn + " could not be instantiated: " + x, + "Provider " + cn + " could not be instantiated", x); } throw new Error(); // This cannot happen diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/util/jar/JarVerifier.java --- a/jdk/src/share/classes/java/util/jar/JarVerifier.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/util/jar/JarVerifier.java Wed Apr 16 10:53:10 2014 -0700 @@ -676,6 +676,8 @@ } else { matchUnsigned = true; } + } else { + matchUnsigned = true; } } @@ -778,23 +780,7 @@ // true if file is part of the signature mechanism itself static boolean isSigningRelated(String name) { - name = name.toUpperCase(Locale.ENGLISH); - if (!name.startsWith("META-INF/")) { - return false; - } - name = name.substring(9); - if (name.indexOf('/') != -1) { - return false; - } - if (name.endsWith(".DSA") - || name.endsWith(".RSA") - || name.endsWith(".SF") - || name.endsWith(".EC") - || name.startsWith("SIG-") - || name.equals("MANIFEST.MF")) { - return true; - } - return false; + return SignatureFileVerifier.isSigningRelated(name); } private Enumeration unsignedEntryNames(JarFile jar) { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/util/logging/LogManager.java --- a/jdk/src/share/classes/java/util/logging/LogManager.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/util/logging/LogManager.java Wed Apr 16 10:53:10 2014 -0700 @@ -464,7 +464,7 @@ Logger result = getLogger(name); if (result == null) { // only allocate the new logger once - Logger newLogger = new Logger(name, resourceBundleName, caller, this); + Logger newLogger = new Logger(name, resourceBundleName, caller, this, false); do { if (addLogger(newLogger)) { // We successfully added the new Logger that we @@ -511,13 +511,13 @@ } while (logger == null); // LogManager will set the sysLogger's handlers via LogManager.addLogger method. - if (logger != sysLogger && sysLogger.getHandlers().length == 0) { + if (logger != sysLogger && sysLogger.accessCheckedHandlers().length == 0) { // if logger already exists but handlers not set final Logger l = logger; AccessController.doPrivileged(new PrivilegedAction() { @Override public Void run() { - for (Handler hdl : l.getHandlers()) { + for (Handler hdl : l.accessCheckedHandlers()) { sysLogger.addHandler(hdl); } return null; @@ -835,7 +835,7 @@ Logger result = findLogger(name); if (result == null) { // only allocate the new system logger once - Logger newLogger = new Logger(name, resourceBundleName, null, getOwner()); + Logger newLogger = new Logger(name, resourceBundleName, null, getOwner(), true); do { if (addLocalLogger(newLogger)) { // We successfully added the new Logger that we @@ -1527,7 +1527,7 @@ // We do not call the protected Logger two args constructor here, // to avoid calling LogManager.getLogManager() from within the // RootLogger constructor. - super("", null, null, LogManager.this); + super("", null, null, LogManager.this, true); } @Override @@ -1550,9 +1550,9 @@ } @Override - public Handler[] getHandlers() { + Handler[] accessCheckedHandlers() { initializeGlobalHandlers(); - return super.getHandlers(); + return super.accessCheckedHandlers(); } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/java/util/logging/Logger.java --- a/jdk/src/share/classes/java/util/logging/Logger.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/java/util/logging/Logger.java Wed Apr 16 10:53:10 2014 -0700 @@ -277,6 +277,7 @@ private volatile Level levelObject; private volatile int levelValue; // current effective level value private WeakReference callersClassLoaderRef; + private final boolean isSystemLogger; /** * GLOBAL_LOGGER_NAME is a name for the global logger. @@ -370,11 +371,12 @@ * no corresponding resource can be found. */ protected Logger(String name, String resourceBundleName) { - this(name, resourceBundleName, null, LogManager.getLogManager()); + this(name, resourceBundleName, null, LogManager.getLogManager(), false); } - Logger(String name, String resourceBundleName, Class caller, LogManager manager) { + Logger(String name, String resourceBundleName, Class caller, LogManager manager, boolean isSystemLogger) { this.manager = manager; + this.isSystemLogger = isSystemLogger; setupResourceInfo(resourceBundleName, caller); this.name = name; levelValue = Level.INFO.intValue(); @@ -401,6 +403,7 @@ private Logger(String name) { // The manager field is not initialized here. this.name = name; + this.isSystemLogger = true; levelValue = Level.INFO.intValue(); } @@ -635,7 +638,7 @@ // cleanup some Loggers that have been GC'ed manager.drainLoggerRefQueueBounded(); Logger result = new Logger(null, resourceBundleName, - Reflection.getCallerClass(), manager); + Reflection.getCallerClass(), manager, false); result.anonymous = true; Logger root = manager.getLogger(""); result.doSetParent(root); @@ -727,15 +730,23 @@ Logger logger = this; while (logger != null) { - for (Handler handler : logger.getHandlers()) { + final Handler[] loggerHandlers = isSystemLogger + ? logger.accessCheckedHandlers() + : logger.getHandlers(); + + for (Handler handler : loggerHandlers) { handler.publish(record); } - if (!logger.getUseParentHandlers()) { + final boolean useParentHdls = isSystemLogger + ? logger.useParentHandlers + : logger.getUseParentHandlers(); + + if (!useParentHdls) { break; } - logger = logger.getParent(); + logger = isSystemLogger ? logger.parent : logger.getParent(); } } @@ -1762,6 +1773,12 @@ * @return an array of all registered Handlers */ public Handler[] getHandlers() { + return accessCheckedHandlers(); + } + + // This method should ideally be marked final - but unfortunately + // it needs to be overridden by LogManager.RootLogger + Handler[] accessCheckedHandlers() { return handlers.toArray(emptyHandlers); } @@ -2149,12 +2166,14 @@ if (trb.userBundle != null) { return trb; } - final String rbName = target.getResourceBundleName(); + final String rbName = isSystemLogger + ? trb.resourceBundleName + : target.getResourceBundleName(); if (rbName != null) { return LoggerBundle.get(rbName, findResourceBundle(rbName, true)); } - target = target.getParent(); + target = isSystemLogger ? target.parent : target.getParent(); } return NO_RESOURCE_BUNDLE; } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/javax/script/ScriptEngineManager.java --- a/jdk/src/share/classes/javax/script/ScriptEngineManager.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/javax/script/ScriptEngineManager.java Wed Apr 16 10:53:10 2014 -0700 @@ -81,23 +81,28 @@ nameAssociations = new HashMap(); extensionAssociations = new HashMap(); mimeTypeAssociations = new HashMap(); - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - initEngines(loader); - return null; - } - }); + initEngines(loader); + } + + private ServiceLoader getServiceLoader(final ClassLoader loader) { + if (loader != null) { + return ServiceLoader.load(ScriptEngineFactory.class, loader); + } else { + return ServiceLoader.loadInstalled(ScriptEngineFactory.class); + } } private void initEngines(final ClassLoader loader) { Iterator itr = null; try { - ServiceLoader sl; - if (loader != null) { - sl = ServiceLoader.load(ScriptEngineFactory.class, loader); - } else { - sl = ServiceLoader.loadInstalled(ScriptEngineFactory.class); - } + ServiceLoader sl = AccessController.doPrivileged( + new PrivilegedAction>() { + @Override + public ServiceLoader run() { + return getServiceLoader(loader); + } + }); + itr = sl.iterator(); } catch (ServiceConfigurationError err) { System.err.println("Can't find ScriptEngineFactory providers: " + diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/javax/security/auth/Subject.java --- a/jdk/src/share/classes/javax/security/auth/Subject.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/javax/security/auth/Subject.java Wed Apr 16 10:53:10 2014 -0700 @@ -959,14 +959,30 @@ /** * Reads this object from a stream (i.e., deserializes it) */ + @SuppressWarnings("unchecked") private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { - s.defaultReadObject(); + ObjectInputStream.GetField gf = s.readFields(); + + readOnly = gf.get("readOnly", false); + + Set inputPrincs = (Set)gf.get("principals", null); // Rewrap the principals into a SecureSet - principals = Collections.synchronizedSet(new SecureSet - (this, PRINCIPAL_SET, principals)); + if (inputPrincs == null) { + throw new NullPointerException + (ResourcesMgr.getString("invalid.null.input.s.")); + } + try { + principals = Collections.synchronizedSet(new SecureSet + (this, PRINCIPAL_SET, inputPrincs)); + } catch (NullPointerException npe) { + // Sometimes people deserialize the principals set only. + // Subject is not accessible, so just don't fail. + principals = Collections.synchronizedSet + (new SecureSet(this, PRINCIPAL_SET)); + } // The Credential {@code Set} is not serialized, but we do not // want the default deserialization routine to set it to null. diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java --- a/jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/javax/sql/rowset/RowSetProvider.java Wed Apr 16 10:53:10 2014 -0700 @@ -28,8 +28,11 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.sql.SQLException; +import java.util.PropertyPermission; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; +import javax.sql.rowset.spi.SyncFactoryException; +import sun.reflect.misc.ReflectUtil; /** * A factory API that enables applications to obtain a @@ -129,15 +132,11 @@ factoryClassName = getSystemProperty(ROWSET_FACTORY_NAME); if (factoryClassName != null) { trace("Found system property, value=" + factoryClassName); - factory = (RowSetFactory) getFactoryClass(factoryClassName, null, true).newInstance(); + factory = (RowSetFactory) ReflectUtil.newInstance(getFactoryClass(factoryClassName, null, true)); } - } catch (ClassNotFoundException e) { - throw new SQLException( - "RowSetFactory: " + factoryClassName + " not found", e); - } catch (Exception e) { - throw new SQLException( - "RowSetFactory: " + factoryClassName + " could not be instantiated: " + e, - e); + } catch (Exception e) { + throw new SQLException( "RowSetFactory: " + factoryClassName + + " could not be instantiated: ", e); } // Check to see if we found the RowSetFactory via a System property @@ -182,6 +181,16 @@ throws SQLException { trace("***In newInstance()"); + + if(factoryClassName == null) { + throw new SQLException("Error: factoryClassName cannot be null"); + } + try { + ReflectUtil.checkPackageAccess(factoryClassName); + } catch (java.security.AccessControlException e) { + throw new SQLException("Access Exception",e); + } + try { Class providerClass = getFactoryClass(factoryClassName, cl, false); RowSetFactory instance = (RowSetFactory) providerClass.newInstance(); @@ -291,8 +300,9 @@ public String run() { return System.getProperty(propName); } - }); + }, null, new PropertyPermission(propName, "read")); } catch (SecurityException se) { + trace("error getting " + propName + ": "+ se); if (debug) { se.printStackTrace(); } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/javax/sql/rowset/serial/SQLInputImpl.java --- a/jdk/src/share/classes/javax/sql/rowset/serial/SQLInputImpl.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/javax/sql/rowset/serial/SQLInputImpl.java Wed Apr 16 10:53:10 2014 -0700 @@ -27,6 +27,7 @@ import java.sql.*; import java.util.Arrays; import java.util.Map; +import sun.reflect.misc.ReflectUtil; /** * An input stream used for custom mapping user-defined types (UDTs). @@ -476,13 +477,9 @@ // create new instance of the class SQLData obj = null; try { - obj = (SQLData)c.newInstance(); - } catch (java.lang.InstantiationException ex) { - throw new SQLException("Unable to instantiate: " + - ex.getMessage()); - } catch (java.lang.IllegalAccessException ex) { - throw new SQLException("Unable to instantiate: " + - ex.getMessage()); + obj = (SQLData)ReflectUtil.newInstance(c); + } catch (Exception ex) { + throw new SQLException("Unable to Instantiate: ", ex); } // get the attributes from the struct Object attribs[] = s.getAttributes(map); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/javax/sql/rowset/spi/SyncFactory.java --- a/jdk/src/share/classes/javax/sql/rowset/spi/SyncFactory.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/javax/sql/rowset/spi/SyncFactory.java Wed Apr 16 10:53:10 2014 -0700 @@ -37,8 +37,11 @@ import java.io.FileNotFoundException; import java.security.AccessController; import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import javax.naming.*; +import sun.reflect.misc.ReflectUtil; /** * The Service Provider Interface (SPI) mechanism that generates SyncProvider @@ -329,7 +332,7 @@ // Local implementation class names and keys from Properties // file, translate names into Class objects using Class.forName // and store mappings - Properties properties = new Properties(); + final Properties properties = new Properties(); if (implementations == null) { implementations = new Hashtable<>(); @@ -356,10 +359,11 @@ public String run() { return System.getProperty("rowset.properties"); } - }, null, new PropertyPermission("rowset.properties","read")); + }, null, new PropertyPermission("rowset.properties", "read")); } catch (Exception ex) { + System.out.println("errorget rowset.properties: " + ex); strRowsetProperties = null; - } + }; if (strRowsetProperties != null) { // Load user's implementation of SyncProvider @@ -380,14 +384,27 @@ ClassLoader cl = Thread.currentThread().getContextClassLoader(); - try (InputStream stream = - (cl == null) ? ClassLoader.getSystemResourceAsStream(ROWSET_PROPERTIES) - : cl.getResourceAsStream(ROWSET_PROPERTIES)) { - if (stream == null) { - throw new SyncFactoryException( - "Resource " + ROWSET_PROPERTIES + " not found"); + try { + AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + try (InputStream stream = (cl == null) ? + ClassLoader.getSystemResourceAsStream(ROWSET_PROPERTIES) + : cl.getResourceAsStream(ROWSET_PROPERTIES)) { + if (stream == null) { + throw new SyncFactoryException("Resource " + ROWSET_PROPERTIES + " not found"); + } + properties.load(stream); + } + return null; + }); + } catch (PrivilegedActionException ex) { + Throwable e = ex.getException(); + if (e instanceof SyncFactoryException) { + throw (SyncFactoryException) e; + } else { + SyncFactoryException sfe = new SyncFactoryException(); + sfe.initCause(ex.getException()); + throw sfe; } - properties.load(stream); } parseProperties(properties); @@ -411,7 +428,7 @@ public String run() { return System.getProperty(ROWSET_SYNC_PROVIDER); } - }, null, new PropertyPermission(ROWSET_SYNC_PROVIDER,"read")); + }, null, new PropertyPermission(ROWSET_SYNC_PROVIDER, "read")); } catch (Exception ex) { providerImpls = null; } @@ -547,6 +564,14 @@ return new com.sun.rowset.providers.RIOptimisticProvider(); } + try { + ReflectUtil.checkPackageAccess(providerID); + } catch (java.security.AccessControlException e) { + SyncFactoryException sfe = new SyncFactoryException(); + sfe.initCause(e); + throw sfe; + } + // Attempt to invoke classname from registered SyncProvider list Class c = null; try { @@ -555,7 +580,7 @@ /** * The SyncProvider implementation of the user will be in * the classpath. We need to find the ClassLoader which loads - * this SyncFactory and try to laod the SyncProvider class from + * this SyncFactory and try to load the SyncProvider class from * there. **/ c = Class.forName(providerID, true, cl); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/javax/swing/JTable.java --- a/jdk/src/share/classes/javax/swing/JTable.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/javax/swing/JTable.java Wed Apr 16 10:53:10 2014 -0700 @@ -4042,7 +4042,7 @@ } // Restore the lead int viewLeadIndex = modelSelection.getLeadSelectionIndex(); - if (viewLeadIndex != -1) { + if (viewLeadIndex != -1 && !modelSelection.isSelectionEmpty()) { viewLeadIndex = convertRowIndexToView(viewLeadIndex); } SwingUtilities2.setLeadAnchorWithoutSelection( diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/JarFileSystemProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/JarFileSystemProvider.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.nio.file.*; +import java.nio.file.spi.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.FileSystemProvider; + +import java.net.URI; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.channels.FileChannel; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +class JarFileSystemProvider extends ZipFileSystemProvider +{ + + @Override + public String getScheme() { + return "jar"; + } + + @Override + protected Path uriToPath(URI uri) { + String scheme = uri.getScheme(); + if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) { + throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'"); + } + try { + String uristr = uri.toString(); + int end = uristr.indexOf("!/"); + uristr = uristr.substring(4, (end == -1) ? uristr.length() : end); + uri = new URI(uristr); + return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null)) + .toAbsolutePath(); + } catch (URISyntaxException e) { + throw new AssertionError(e); //never thrown + } + } + + @Override + public Path getPath(URI uri) { + FileSystem fs = getFileSystem(uri); + String path = uri.getFragment(); + if (path == null) { + String uristr = uri.toString(); + int off = uristr.indexOf("!/"); + if (off != -1) + path = uristr.substring(off + 2); + } + if (path != null) + return fs.getPath(path); + throw new IllegalArgumentException("URI: " + + uri + + " does not contain path fragment ex. jar:///c:/foo.zip!/BAR"); + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,2 @@ +jdk.nio.zipfs.ZipFileSystemProvider + diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipCoder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipCoder.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.util.Arrays; + +/** + * Utility class for zipfile name and comment decoding and encoding + * + * @author Xueming Shen + */ + +final class ZipCoder { + + String toString(byte[] ba, int length) { + CharsetDecoder cd = decoder().reset(); + int len = (int)(length * cd.maxCharsPerByte()); + char[] ca = new char[len]; + if (len == 0) + return new String(ca); + ByteBuffer bb = ByteBuffer.wrap(ba, 0, length); + CharBuffer cb = CharBuffer.wrap(ca); + CoderResult cr = cd.decode(bb, cb, true); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + cr = cd.flush(cb); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + return new String(ca, 0, cb.position()); + } + + String toString(byte[] ba) { + return toString(ba, ba.length); + } + + byte[] getBytes(String s) { + CharsetEncoder ce = encoder().reset(); + char[] ca = s.toCharArray(); + int len = (int)(ca.length * ce.maxBytesPerChar()); + byte[] ba = new byte[len]; + if (len == 0) + return ba; + ByteBuffer bb = ByteBuffer.wrap(ba); + CharBuffer cb = CharBuffer.wrap(ca); + CoderResult cr = ce.encode(cb, bb, true); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + cr = ce.flush(bb); + if (!cr.isUnderflow()) + throw new IllegalArgumentException(cr.toString()); + if (bb.position() == ba.length) // defensive copy? + return ba; + else + return Arrays.copyOf(ba, bb.position()); + } + + // assume invoked only if "this" is not utf8 + byte[] getBytesUTF8(String s) { + if (isutf8) + return getBytes(s); + if (utf8 == null) + utf8 = new ZipCoder(Charset.forName("UTF-8")); + return utf8.getBytes(s); + } + + String toStringUTF8(byte[] ba, int len) { + if (isutf8) + return toString(ba, len); + if (utf8 == null) + utf8 = new ZipCoder(Charset.forName("UTF-8")); + return utf8.toString(ba, len); + } + + boolean isUTF8() { + return isutf8; + } + + private Charset cs; + private boolean isutf8; + private ZipCoder utf8; + + private ZipCoder(Charset cs) { + this.cs = cs; + this.isutf8 = cs.name().equals("UTF-8"); + } + + static ZipCoder get(Charset charset) { + return new ZipCoder(charset); + } + + static ZipCoder get(String csn) { + try { + return new ZipCoder(Charset.forName(csn)); + } catch (Throwable t) { + t.printStackTrace(); + } + return new ZipCoder(Charset.defaultCharset()); + } + + private final ThreadLocal decTL = new ThreadLocal<>(); + private final ThreadLocal encTL = new ThreadLocal<>(); + + private CharsetDecoder decoder() { + CharsetDecoder dec = decTL.get(); + if (dec == null) { + dec = cs.newDecoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + decTL.set(dec); + } + return dec; + } + + private CharsetEncoder encoder() { + CharsetEncoder enc = encTL.get(); + if (enc == null) { + enc = cs.newEncoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT); + encTL.set(enc); + } + return enc; + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipConstants.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipConstants.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +/** + * + * @author Xueming Shen + */ + +class ZipConstants { + /* + * Compression methods + */ + static final int METHOD_STORED = 0; + static final int METHOD_DEFLATED = 8; + static final int METHOD_DEFLATED64 = 9; + static final int METHOD_BZIP2 = 12; + static final int METHOD_LZMA = 14; + static final int METHOD_LZ77 = 19; + static final int METHOD_AES = 99; + + /* + * General purpose big flag + */ + static final int FLAG_ENCRYPTED = 0x01; + static final int FLAG_DATADESCR = 0x08; // crc, size and csize in dd + static final int FLAG_EFS = 0x800; // If this bit is set the filename and + // comment fields for this file must be + // encoded using UTF-8. + /* + * Header signatures + */ + static long LOCSIG = 0x04034b50L; // "PK\003\004" + static long EXTSIG = 0x08074b50L; // "PK\007\008" + static long CENSIG = 0x02014b50L; // "PK\001\002" + static long ENDSIG = 0x06054b50L; // "PK\005\006" + + /* + * Header sizes in bytes (including signatures) + */ + static final int LOCHDR = 30; // LOC header size + static final int EXTHDR = 16; // EXT header size + static final int CENHDR = 46; // CEN header size + static final int ENDHDR = 22; // END header size + + /* + * Local file (LOC) header field offsets + */ + static final int LOCVER = 4; // version needed to extract + static final int LOCFLG = 6; // general purpose bit flag + static final int LOCHOW = 8; // compression method + static final int LOCTIM = 10; // modification time + static final int LOCCRC = 14; // uncompressed file crc-32 value + static final int LOCSIZ = 18; // compressed size + static final int LOCLEN = 22; // uncompressed size + static final int LOCNAM = 26; // filename length + static final int LOCEXT = 28; // extra field length + + /* + * Extra local (EXT) header field offsets + */ + static final int EXTCRC = 4; // uncompressed file crc-32 value + static final int EXTSIZ = 8; // compressed size + static final int EXTLEN = 12; // uncompressed size + + /* + * Central directory (CEN) header field offsets + */ + static final int CENVEM = 4; // version made by + static final int CENVER = 6; // version needed to extract + static final int CENFLG = 8; // encrypt, decrypt flags + static final int CENHOW = 10; // compression method + static final int CENTIM = 12; // modification time + static final int CENCRC = 16; // uncompressed file crc-32 value + static final int CENSIZ = 20; // compressed size + static final int CENLEN = 24; // uncompressed size + static final int CENNAM = 28; // filename length + static final int CENEXT = 30; // extra field length + static final int CENCOM = 32; // comment length + static final int CENDSK = 34; // disk number start + static final int CENATT = 36; // internal file attributes + static final int CENATX = 38; // external file attributes + static final int CENOFF = 42; // LOC header offset + + /* + * End of central directory (END) header field offsets + */ + static final int ENDSUB = 8; // number of entries on this disk + static final int ENDTOT = 10; // total number of entries + static final int ENDSIZ = 12; // central directory size in bytes + static final int ENDOFF = 16; // offset of first CEN header + static final int ENDCOM = 20; // zip file comment length + + /* + * ZIP64 constants + */ + static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006" + static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007" + static final int ZIP64_ENDHDR = 56; // ZIP64 end header size + static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size + static final int ZIP64_EXTHDR = 24; // EXT header size + static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID + + static final int ZIP64_MINVAL32 = 0xFFFF; + static final long ZIP64_MINVAL = 0xFFFFFFFFL; + + /* + * Zip64 End of central directory (END) header field offsets + */ + static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir + static final int ZIP64_ENDVEM = 12; // version made by + static final int ZIP64_ENDVER = 14; // version needed to extract + static final int ZIP64_ENDNMD = 16; // number of this disk + static final int ZIP64_ENDDSK = 20; // disk number of start + static final int ZIP64_ENDTOD = 24; // total number of entries on this disk + static final int ZIP64_ENDTOT = 32; // total number of entries + static final int ZIP64_ENDSIZ = 40; // central directory size in bytes + static final int ZIP64_ENDOFF = 48; // offset of first CEN header + static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector + + /* + * Zip64 End of central directory locator field offsets + */ + static final int ZIP64_LOCDSK = 4; // disk number start + static final int ZIP64_LOCOFF = 8; // offset of zip64 end + static final int ZIP64_LOCTOT = 16; // total number of disks + + /* + * Zip64 Extra local (EXT) header field offsets + */ + static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value + static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte + static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte + + /* + * Extra field header ID + */ + static final int EXTID_ZIP64 = 0x0001; // ZIP64 + static final int EXTID_NTFS = 0x000a; // NTFS + static final int EXTID_UNIX = 0x000d; // UNIX + static final int EXTID_EFS = 0x0017; // Strong Encryption + static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp + + /* + * fields access methods + */ + /////////////////////////////////////////////////////// + static final int CH(byte[] b, int n) { + return Byte.toUnsignedInt(b[n]); + } + + static final int SH(byte[] b, int n) { + return Byte.toUnsignedInt(b[n]) | (Byte.toUnsignedInt(b[n + 1]) << 8); + } + + static final long LG(byte[] b, int n) { + return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL; + } + + static final long LL(byte[] b, int n) { + return (LG(b, n)) | (LG(b, n + 4) << 32); + } + + static final long GETSIG(byte[] b) { + return LG(b, 0); + } + + // local file (LOC) header fields + static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature + static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract + static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags + static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method + static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time + static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data + static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size + static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size + static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length + static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length + + // extra local (EXT) header fields + static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data + static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size + static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size + + // end of central directory header (END) fields + static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk + static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries + static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size + static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset + static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment + static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);} + + // zip64 end of central directory recoder fields + static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk + static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries + static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size + static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset + static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset + + // central directory header (CEN) fields + static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); } + static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); } + static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); } + static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); } + static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);} + static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);} + static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);} + static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);} + static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);} + static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);} + static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);} + static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);} + static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);} + static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);} + static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);} + static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);} + + /* The END header is followed by a variable length comment of size < 64k. */ + static final long END_MAXLEN = 0xFFFF + ENDHDR; + static final int READBLOCKSZ = 128; +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipDirectoryStream.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipDirectoryStream.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.nio.file.DirectoryStream; +import java.nio.file.ClosedDirectoryStreamException; +import java.nio.file.NotDirectoryException; +import java.nio.file.Path; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.io.IOException; + +/** + * + * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal + */ + +class ZipDirectoryStream implements DirectoryStream { + + private final ZipFileSystem zipfs; + private final byte[] path; + private final DirectoryStream.Filter filter; + private volatile boolean isClosed; + private volatile Iterator itr; + + ZipDirectoryStream(ZipPath zipPath, + DirectoryStream.Filter filter) + throws IOException + { + this.zipfs = zipPath.getFileSystem(); + this.path = zipPath.getResolvedPath(); + this.filter = filter; + // sanity check + if (!zipfs.isDirectory(path)) + throw new NotDirectoryException(zipPath.toString()); + } + + @Override + public synchronized Iterator iterator() { + if (isClosed) + throw new ClosedDirectoryStreamException(); + if (itr != null) + throw new IllegalStateException("Iterator has already been returned"); + + try { + itr = zipfs.iteratorOf(path, filter); + } catch (IOException e) { + throw new IllegalStateException(e); + } + return new Iterator() { + private Path next; + @Override + public boolean hasNext() { + if (isClosed) + return false; + return itr.hasNext(); + } + + @Override + public synchronized Path next() { + if (isClosed) + throw new NoSuchElementException(); + return itr.next(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public synchronized void close() throws IOException { + isClosed = true; + } + + +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipFileAttributeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipFileAttributeView.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.nio.file.attribute.*; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; + +/* + * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal + */ + +class ZipFileAttributeView implements BasicFileAttributeView +{ + private static enum AttrID { + size, + creationTime, + lastAccessTime, + lastModifiedTime, + isDirectory, + isRegularFile, + isSymbolicLink, + isOther, + fileKey, + compressedSize, + crc, + method + }; + + private final ZipPath path; + private final boolean isZipView; + + private ZipFileAttributeView(ZipPath path, boolean isZipView) { + this.path = path; + this.isZipView = isZipView; + } + + static V get(ZipPath path, Class type) { + if (type == null) + throw new NullPointerException(); + if (type == BasicFileAttributeView.class) + return (V)new ZipFileAttributeView(path, false); + if (type == ZipFileAttributeView.class) + return (V)new ZipFileAttributeView(path, true); + return null; + } + + static ZipFileAttributeView get(ZipPath path, String type) { + if (type == null) + throw new NullPointerException(); + if (type.equals("basic")) + return new ZipFileAttributeView(path, false); + if (type.equals("zip")) + return new ZipFileAttributeView(path, true); + return null; + } + + @Override + public String name() { + return isZipView ? "zip" : "basic"; + } + + public ZipFileAttributes readAttributes() throws IOException + { + return path.getAttributes(); + } + + @Override + public void setTimes(FileTime lastModifiedTime, + FileTime lastAccessTime, + FileTime createTime) + throws IOException + { + path.setTimes(lastModifiedTime, lastAccessTime, createTime); + } + + void setAttribute(String attribute, Object value) + throws IOException + { + try { + if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime) + setTimes ((FileTime)value, null, null); + if (AttrID.valueOf(attribute) == AttrID.lastAccessTime) + setTimes (null, (FileTime)value, null); + if (AttrID.valueOf(attribute) == AttrID.creationTime) + setTimes (null, null, (FileTime)value); + return; + } catch (IllegalArgumentException x) {} + throw new UnsupportedOperationException("'" + attribute + + "' is unknown or read-only attribute"); + } + + Map readAttributes(String attributes) + throws IOException + { + ZipFileAttributes zfas = readAttributes(); + LinkedHashMap map = new LinkedHashMap<>(); + if ("*".equals(attributes)) { + for (AttrID id : AttrID.values()) { + try { + map.put(id.name(), attribute(id, zfas)); + } catch (IllegalArgumentException x) {} + } + } else { + String[] as = attributes.split(","); + for (String a : as) { + try { + map.put(a, attribute(AttrID.valueOf(a), zfas)); + } catch (IllegalArgumentException x) {} + } + } + return map; + } + + Object attribute(AttrID id, ZipFileAttributes zfas) { + switch (id) { + case size: + return zfas.size(); + case creationTime: + return zfas.creationTime(); + case lastAccessTime: + return zfas.lastAccessTime(); + case lastModifiedTime: + return zfas.lastModifiedTime(); + case isDirectory: + return zfas.isDirectory(); + case isRegularFile: + return zfas.isRegularFile(); + case isSymbolicLink: + return zfas.isSymbolicLink(); + case isOther: + return zfas.isOther(); + case fileKey: + return zfas.fileKey(); + case compressedSize: + if (isZipView) + return zfas.compressedSize(); + break; + case crc: + if (isZipView) + return zfas.crc(); + break; + case method: + if (isZipView) + return zfas.method(); + break; + } + return null; + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipFileAttributes.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipFileAttributes.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.util.Arrays; +import java.util.Formatter; +import static jdk.nio.zipfs.ZipUtils.*; + +/** + * + * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal + */ + +class ZipFileAttributes implements BasicFileAttributes +{ + private final ZipFileSystem.Entry e; + + ZipFileAttributes(ZipFileSystem.Entry e) { + this.e = e; + } + + ///////// basic attributes /////////// + @Override + public FileTime creationTime() { + if (e.ctime != -1) + return FileTime.fromMillis(e.ctime); + return null; + } + + @Override + public boolean isDirectory() { + return e.isDir(); + } + + @Override + public boolean isOther() { + return false; + } + + @Override + public boolean isRegularFile() { + return !e.isDir(); + } + + @Override + public FileTime lastAccessTime() { + if (e.atime != -1) + return FileTime.fromMillis(e.atime); + return null; + } + + @Override + public FileTime lastModifiedTime() { + return FileTime.fromMillis(e.mtime); + } + + @Override + public long size() { + return e.size; + } + + @Override + public boolean isSymbolicLink() { + return false; + } + + @Override + public Object fileKey() { + return null; + } + + ///////// zip entry attributes /////////// + public long compressedSize() { + return e.csize; + } + + public long crc() { + return e.crc; + } + + public int method() { + return e.method; + } + + public byte[] extra() { + if (e.extra != null) + return Arrays.copyOf(e.extra, e.extra.length); + return null; + } + + public byte[] comment() { + if (e.comment != null) + return Arrays.copyOf(e.comment, e.comment.length); + return null; + } + + public String toString() { + StringBuilder sb = new StringBuilder(1024); + Formatter fm = new Formatter(sb); + if (creationTime() != null) + fm.format(" creationTime : %tc%n", creationTime().toMillis()); + else + fm.format(" creationTime : null%n"); + + if (lastAccessTime() != null) + fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis()); + else + fm.format(" lastAccessTime : null%n"); + fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis()); + fm.format(" isRegularFile : %b%n", isRegularFile()); + fm.format(" isDirectory : %b%n", isDirectory()); + fm.format(" isSymbolicLink : %b%n", isSymbolicLink()); + fm.format(" isOther : %b%n", isOther()); + fm.format(" fileKey : %s%n", fileKey()); + fm.format(" size : %d%n", size()); + fm.format(" compressedSize : %d%n", compressedSize()); + fm.format(" crc : %x%n", crc()); + fm.format(" method : %d%n", method()); + fm.close(); + return sb.toString(); + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipFileStore.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipFileStore.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.FileStore; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.FileStoreAttributeView; +import java.nio.file.attribute.BasicFileAttributeView; +import java.util.Formatter; + +/* + * + * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal + */ + +class ZipFileStore extends FileStore { + + private final ZipFileSystem zfs; + + ZipFileStore(ZipPath zpath) { + this.zfs = zpath.getFileSystem(); + } + + @Override + public String name() { + return zfs.toString() + "/"; + } + + @Override + public String type() { + return "zipfs"; + } + + @Override + public boolean isReadOnly() { + return zfs.isReadOnly(); + } + + @Override + public boolean supportsFileAttributeView(Class type) { + return (type == BasicFileAttributeView.class || + type == ZipFileAttributeView.class); + } + + @Override + public boolean supportsFileAttributeView(String name) { + return name.equals("basic") || name.equals("zip"); + } + + @Override + @SuppressWarnings("unchecked") + public V getFileStoreAttributeView(Class type) { + if (type == null) + throw new NullPointerException(); + return (V)null; + } + + @Override + public long getTotalSpace() throws IOException { + return new ZipFileStoreAttributes(this).totalSpace(); + } + + @Override + public long getUsableSpace() throws IOException { + return new ZipFileStoreAttributes(this).usableSpace(); + } + + @Override + public long getUnallocatedSpace() throws IOException { + return new ZipFileStoreAttributes(this).unallocatedSpace(); + } + + @Override + public Object getAttribute(String attribute) throws IOException { + if (attribute.equals("totalSpace")) + return getTotalSpace(); + if (attribute.equals("usableSpace")) + return getUsableSpace(); + if (attribute.equals("unallocatedSpace")) + return getUnallocatedSpace(); + throw new UnsupportedOperationException("does not support the given attribute"); + } + + private static class ZipFileStoreAttributes { + final FileStore fstore; + final long size; + + public ZipFileStoreAttributes(ZipFileStore fileStore) + throws IOException + { + Path path = FileSystems.getDefault().getPath(fileStore.name()); + this.size = Files.size(path); + this.fstore = Files.getFileStore(path); + } + + public long totalSpace() { + return size; + } + + public long usableSpace() throws IOException { + if (!fstore.isReadOnly()) + return fstore.getUsableSpace(); + return 0; + } + + public long unallocatedSpace() throws IOException { + if (!fstore.isReadOnly()) + return fstore.getUnallocatedSpace(); + return 0; + } + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipFileSystem.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipFileSystem.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,2386 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.*; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.*; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.regex.Pattern; +import java.util.zip.CRC32; +import java.util.zip.Inflater; +import java.util.zip.Deflater; +import java.util.zip.InflaterInputStream; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.ZipException; +import java.util.zip.ZipError; +import static java.lang.Boolean.*; +import static jdk.nio.zipfs.ZipConstants.*; +import static jdk.nio.zipfs.ZipUtils.*; +import static java.nio.file.StandardOpenOption.*; +import static java.nio.file.StandardCopyOption.*; + +/** + * A FileSystem built on a zip file + * + * @author Xueming Shen + */ + +class ZipFileSystem extends FileSystem { + + private final ZipFileSystemProvider provider; + private final ZipPath defaultdir; + private boolean readOnly = false; + private final Path zfpath; + private final ZipCoder zc; + + // configurable by env map + private final String defaultDir; // default dir for the file system + private final String nameEncoding; // default encoding for name/comment + private final boolean useTempFile; // use a temp file for newOS, default + // is to use BAOS for better performance + private final boolean createNew; // create a new zip if not exists + private static final boolean isWindows = AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("os.name") + .startsWith("Windows")); + + ZipFileSystem(ZipFileSystemProvider provider, + Path zfpath, + Map env) + throws IOException + { + // configurable env setup + this.createNew = "true".equals(env.get("create")); + this.nameEncoding = env.containsKey("encoding") ? + (String)env.get("encoding") : "UTF-8"; + this.useTempFile = TRUE.equals(env.get("useTempFile")); + this.defaultDir = env.containsKey("default.dir") ? + (String)env.get("default.dir") : "/"; + if (this.defaultDir.charAt(0) != '/') + throw new IllegalArgumentException("default dir should be absolute"); + + this.provider = provider; + this.zfpath = zfpath; + if (Files.notExists(zfpath)) { + if (createNew) { + try (OutputStream os = Files.newOutputStream(zfpath, CREATE_NEW, WRITE)) { + new END().write(os, 0); + } + } else { + throw new FileSystemNotFoundException(zfpath.toString()); + } + } + // sm and existence check + zfpath.getFileSystem().provider().checkAccess(zfpath, AccessMode.READ); + if (!Files.isWritable(zfpath)) + this.readOnly = true; + this.zc = ZipCoder.get(nameEncoding); + this.defaultdir = new ZipPath(this, getBytes(defaultDir)); + this.ch = Files.newByteChannel(zfpath, READ); + this.cen = initCEN(); + } + + @Override + public FileSystemProvider provider() { + return provider; + } + + @Override + public String getSeparator() { + return "/"; + } + + @Override + public boolean isOpen() { + return isOpen; + } + + @Override + public boolean isReadOnly() { + return readOnly; + } + + private void checkWritable() throws IOException { + if (readOnly) + throw new ReadOnlyFileSystemException(); + } + + @Override + public Iterable getRootDirectories() { + ArrayList pathArr = new ArrayList<>(); + pathArr.add(new ZipPath(this, new byte[]{'/'})); + return pathArr; + } + + ZipPath getDefaultDir() { // package private + return defaultdir; + } + + @Override + public ZipPath getPath(String first, String... more) { + String path; + if (more.length == 0) { + path = first; + } else { + StringBuilder sb = new StringBuilder(); + sb.append(first); + for (String segment: more) { + if (segment.length() > 0) { + if (sb.length() > 0) + sb.append('/'); + sb.append(segment); + } + } + path = sb.toString(); + } + return new ZipPath(this, getBytes(path)); + } + + @Override + public UserPrincipalLookupService getUserPrincipalLookupService() { + throw new UnsupportedOperationException(); + } + + @Override + public WatchService newWatchService() { + throw new UnsupportedOperationException(); + } + + FileStore getFileStore(ZipPath path) { + return new ZipFileStore(path); + } + + @Override + public Iterable getFileStores() { + ArrayList list = new ArrayList<>(1); + list.add(new ZipFileStore(new ZipPath(this, new byte[]{'/'}))); + return list; + } + + private static final Set supportedFileAttributeViews = + Collections.unmodifiableSet( + new HashSet(Arrays.asList("basic", "zip"))); + + @Override + public Set supportedFileAttributeViews() { + return supportedFileAttributeViews; + } + + @Override + public String toString() { + return zfpath.toString(); + } + + Path getZipFile() { + return zfpath; + } + + private static final String GLOB_SYNTAX = "glob"; + private static final String REGEX_SYNTAX = "regex"; + + @Override + public PathMatcher getPathMatcher(String syntaxAndInput) { + int pos = syntaxAndInput.indexOf(':'); + if (pos <= 0 || pos == syntaxAndInput.length()) { + throw new IllegalArgumentException(); + } + String syntax = syntaxAndInput.substring(0, pos); + String input = syntaxAndInput.substring(pos + 1); + String expr; + if (syntax.equals(GLOB_SYNTAX)) { + expr = toRegexPattern(input); + } else { + if (syntax.equals(REGEX_SYNTAX)) { + expr = input; + } else { + throw new UnsupportedOperationException("Syntax '" + syntax + + "' not recognized"); + } + } + // return matcher + final Pattern pattern = Pattern.compile(expr); + return new PathMatcher() { + @Override + public boolean matches(Path path) { + return pattern.matcher(path.toString()).matches(); + } + }; + } + + @Override + public void close() throws IOException { + beginWrite(); + try { + if (!isOpen) + return; + isOpen = false; // set closed + } finally { + endWrite(); + } + if (!streams.isEmpty()) { // unlock and close all remaining streams + Set copy = new HashSet<>(streams); + for (InputStream is: copy) + is.close(); + } + beginWrite(); // lock and sync + try { + sync(); + ch.close(); // close the ch just in case no update + } finally { // and sync dose not close the ch + endWrite(); + } + + synchronized (inflaters) { + for (Inflater inf : inflaters) + inf.end(); + } + synchronized (deflaters) { + for (Deflater def : deflaters) + def.end(); + } + + IOException ioe = null; + synchronized (tmppaths) { + for (Path p: tmppaths) { + try { + Files.deleteIfExists(p); + } catch (IOException x) { + if (ioe == null) + ioe = x; + else + ioe.addSuppressed(x); + } + } + } + provider.removeFileSystem(zfpath, this); + if (ioe != null) + throw ioe; + } + + ZipFileAttributes getFileAttributes(byte[] path) + throws IOException + { + Entry e; + beginRead(); + try { + ensureOpen(); + e = getEntry0(path); + if (e == null) { + IndexNode inode = getInode(path); + if (inode == null) + return null; + e = new Entry(inode.name); // pseudo directory + e.method = METHOD_STORED; // STORED for dir + e.mtime = e.atime = e.ctime = -1;// -1 for all times + } + } finally { + endRead(); + } + return new ZipFileAttributes(e); + } + + void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime) + throws IOException + { + checkWritable(); + beginWrite(); + try { + ensureOpen(); + Entry e = getEntry0(path); // ensureOpen checked + if (e == null) + throw new NoSuchFileException(getString(path)); + if (e.type == Entry.CEN) + e.type = Entry.COPY; // copy e + if (mtime != null) + e.mtime = mtime.toMillis(); + if (atime != null) + e.atime = atime.toMillis(); + if (ctime != null) + e.ctime = ctime.toMillis(); + update(e); + } finally { + endWrite(); + } + } + + boolean exists(byte[] path) + throws IOException + { + beginRead(); + try { + ensureOpen(); + return getInode(path) != null; + } finally { + endRead(); + } + } + + boolean isDirectory(byte[] path) + throws IOException + { + beginRead(); + try { + IndexNode n = getInode(path); + return n != null && n.isDir(); + } finally { + endRead(); + } + } + + private ZipPath toZipPath(byte[] path) { + // make it absolute + byte[] p = new byte[path.length + 1]; + p[0] = '/'; + System.arraycopy(path, 0, p, 1, path.length); + return new ZipPath(this, p); + } + + // returns the list of child paths of "path" + Iterator iteratorOf(byte[] path, + DirectoryStream.Filter filter) + throws IOException + { + beginWrite(); // iteration of inodes needs exclusive lock + try { + ensureOpen(); + IndexNode inode = getInode(path); + if (inode == null) + throw new NotDirectoryException(getString(path)); + List list = new ArrayList<>(); + IndexNode child = inode.child; + while (child != null) { + ZipPath zp = toZipPath(child.name); + if (filter == null || filter.accept(zp)) + list.add(zp); + child = child.sibling; + } + return list.iterator(); + } finally { + endWrite(); + } + } + + void createDirectory(byte[] dir, FileAttribute... attrs) + throws IOException + { + checkWritable(); + dir = toDirectoryPath(dir); + beginWrite(); + try { + ensureOpen(); + if (dir.length == 0 || exists(dir)) // root dir, or exiting dir + throw new FileAlreadyExistsException(getString(dir)); + checkParents(dir); + Entry e = new Entry(dir, Entry.NEW); + e.method = METHOD_STORED; // STORED for dir + update(e); + } finally { + endWrite(); + } + } + + void copyFile(boolean deletesrc, byte[]src, byte[] dst, CopyOption... options) + throws IOException + { + checkWritable(); + if (Arrays.equals(src, dst)) + return; // do nothing, src and dst are the same + + beginWrite(); + try { + ensureOpen(); + Entry eSrc = getEntry0(src); // ensureOpen checked + if (eSrc == null) + throw new NoSuchFileException(getString(src)); + if (eSrc.isDir()) { // spec says to create dst dir + createDirectory(dst); + return; + } + boolean hasReplace = false; + boolean hasCopyAttrs = false; + for (CopyOption opt : options) { + if (opt == REPLACE_EXISTING) + hasReplace = true; + else if (opt == COPY_ATTRIBUTES) + hasCopyAttrs = true; + } + Entry eDst = getEntry0(dst); + if (eDst != null) { + if (!hasReplace) + throw new FileAlreadyExistsException(getString(dst)); + } else { + checkParents(dst); + } + Entry u = new Entry(eSrc, Entry.COPY); // copy eSrc entry + u.name(dst); // change name + if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH) + { + u.type = eSrc.type; // make it the same type + if (deletesrc) { // if it's a "rename", take the data + u.bytes = eSrc.bytes; + u.file = eSrc.file; + } else { // if it's not "rename", copy the data + if (eSrc.bytes != null) + u.bytes = Arrays.copyOf(eSrc.bytes, eSrc.bytes.length); + else if (eSrc.file != null) { + u.file = getTempPathForEntry(null); + Files.copy(eSrc.file, u.file, REPLACE_EXISTING); + } + } + } + if (!hasCopyAttrs) + u.mtime = u.atime= u.ctime = System.currentTimeMillis(); + update(u); + if (deletesrc) + updateDelete(eSrc); + } finally { + endWrite(); + } + } + + // Returns an output stream for writing the contents into the specified + // entry. + OutputStream newOutputStream(byte[] path, OpenOption... options) + throws IOException + { + checkWritable(); + boolean hasCreateNew = false; + boolean hasCreate = false; + boolean hasAppend = false; + for (OpenOption opt: options) { + if (opt == READ) + throw new IllegalArgumentException("READ not allowed"); + if (opt == CREATE_NEW) + hasCreateNew = true; + if (opt == CREATE) + hasCreate = true; + if (opt == APPEND) + hasAppend = true; + } + beginRead(); // only need a readlock, the "update()" will + try { // try to obtain a writelock when the os is + ensureOpen(); // being closed. + Entry e = getEntry0(path); + if (e != null) { + if (e.isDir() || hasCreateNew) + throw new FileAlreadyExistsException(getString(path)); + if (hasAppend) { + InputStream is = getInputStream(e); + OutputStream os = getOutputStream(new Entry(e, Entry.NEW)); + copyStream(is, os); + is.close(); + return os; + } + return getOutputStream(new Entry(e, Entry.NEW)); + } else { + if (!hasCreate && !hasCreateNew) + throw new NoSuchFileException(getString(path)); + checkParents(path); + return getOutputStream(new Entry(path, Entry.NEW)); + } + } finally { + endRead(); + } + } + + // Returns an input stream for reading the contents of the specified + // file entry. + InputStream newInputStream(byte[] path) throws IOException { + beginRead(); + try { + ensureOpen(); + Entry e = getEntry0(path); + if (e == null) + throw new NoSuchFileException(getString(path)); + if (e.isDir()) + throw new FileSystemException(getString(path), "is a directory", null); + return getInputStream(e); + } finally { + endRead(); + } + } + + private void checkOptions(Set options) { + // check for options of null type and option is an intance of StandardOpenOption + for (OpenOption option : options) { + if (option == null) + throw new NullPointerException(); + if (!(option instanceof StandardOpenOption)) + throw new IllegalArgumentException(); + } + } + + // Returns a Writable/ReadByteChannel for now. Might consdier to use + // newFileChannel() instead, which dump the entry data into a regular + // file on the default file system and create a FileChannel on top of + // it. + SeekableByteChannel newByteChannel(byte[] path, + Set options, + FileAttribute... attrs) + throws IOException + { + checkOptions(options); + if (options.contains(StandardOpenOption.WRITE) || + options.contains(StandardOpenOption.APPEND)) { + checkWritable(); + beginRead(); + try { + final WritableByteChannel wbc = Channels.newChannel( + newOutputStream(path, options.toArray(new OpenOption[0]))); + long leftover = 0; + if (options.contains(StandardOpenOption.APPEND)) { + Entry e = getEntry0(path); + if (e != null && e.size >= 0) + leftover = e.size; + } + final long offset = leftover; + return new SeekableByteChannel() { + long written = offset; + public boolean isOpen() { + return wbc.isOpen(); + } + + public long position() throws IOException { + return written; + } + + public SeekableByteChannel position(long pos) + throws IOException + { + throw new UnsupportedOperationException(); + } + + public int read(ByteBuffer dst) throws IOException { + throw new UnsupportedOperationException(); + } + + public SeekableByteChannel truncate(long size) + throws IOException + { + throw new UnsupportedOperationException(); + } + + public int write(ByteBuffer src) throws IOException { + int n = wbc.write(src); + written += n; + return n; + } + + public long size() throws IOException { + return written; + } + + public void close() throws IOException { + wbc.close(); + } + }; + } finally { + endRead(); + } + } else { + beginRead(); + try { + ensureOpen(); + Entry e = getEntry0(path); + if (e == null || e.isDir()) + throw new NoSuchFileException(getString(path)); + final ReadableByteChannel rbc = + Channels.newChannel(getInputStream(e)); + final long size = e.size; + return new SeekableByteChannel() { + long read = 0; + public boolean isOpen() { + return rbc.isOpen(); + } + + public long position() throws IOException { + return read; + } + + public SeekableByteChannel position(long pos) + throws IOException + { + throw new UnsupportedOperationException(); + } + + public int read(ByteBuffer dst) throws IOException { + int n = rbc.read(dst); + if (n > 0) { + read += n; + } + return n; + } + + public SeekableByteChannel truncate(long size) + throws IOException + { + throw new NonWritableChannelException(); + } + + public int write (ByteBuffer src) throws IOException { + throw new NonWritableChannelException(); + } + + public long size() throws IOException { + return size; + } + + public void close() throws IOException { + rbc.close(); + } + }; + } finally { + endRead(); + } + } + } + + // Returns a FileChannel of the specified entry. + // + // This implementation creates a temporary file on the default file system, + // copy the entry data into it if the entry exists, and then create a + // FileChannel on top of it. + FileChannel newFileChannel(byte[] path, + Set options, + FileAttribute... attrs) + throws IOException + { + checkOptions(options); + final boolean forWrite = (options.contains(StandardOpenOption.WRITE) || + options.contains(StandardOpenOption.APPEND)); + beginRead(); + try { + ensureOpen(); + Entry e = getEntry0(path); + if (forWrite) { + checkWritable(); + if (e == null) { + if (!options.contains(StandardOpenOption.CREATE_NEW)) + throw new NoSuchFileException(getString(path)); + } else { + if (options.contains(StandardOpenOption.CREATE_NEW)) + throw new FileAlreadyExistsException(getString(path)); + if (e.isDir()) + throw new FileAlreadyExistsException("directory <" + + getString(path) + "> exists"); + } + options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile + } else if (e == null || e.isDir()) { + throw new NoSuchFileException(getString(path)); + } + + final boolean isFCH = (e != null && e.type == Entry.FILECH); + final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path); + final FileChannel fch = tmpfile.getFileSystem() + .provider() + .newFileChannel(tmpfile, options, attrs); + final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH); + if (forWrite) { + u.flag = FLAG_DATADESCR; + u.method = METHOD_DEFLATED; + } + // is there a better way to hook into the FileChannel's close method? + return new FileChannel() { + public int write(ByteBuffer src) throws IOException { + return fch.write(src); + } + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + return fch.write(srcs, offset, length); + } + public long position() throws IOException { + return fch.position(); + } + public FileChannel position(long newPosition) + throws IOException + { + fch.position(newPosition); + return this; + } + public long size() throws IOException { + return fch.size(); + } + public FileChannel truncate(long size) + throws IOException + { + fch.truncate(size); + return this; + } + public void force(boolean metaData) + throws IOException + { + fch.force(metaData); + } + public long transferTo(long position, long count, + WritableByteChannel target) + throws IOException + { + return fch.transferTo(position, count, target); + } + public long transferFrom(ReadableByteChannel src, + long position, long count) + throws IOException + { + return fch.transferFrom(src, position, count); + } + public int read(ByteBuffer dst) throws IOException { + return fch.read(dst); + } + public int read(ByteBuffer dst, long position) + throws IOException + { + return fch.read(dst, position); + } + public long read(ByteBuffer[] dsts, int offset, int length) + throws IOException + { + return fch.read(dsts, offset, length); + } + public int write(ByteBuffer src, long position) + throws IOException + { + return fch.write(src, position); + } + public MappedByteBuffer map(MapMode mode, + long position, long size) + throws IOException + { + throw new UnsupportedOperationException(); + } + public FileLock lock(long position, long size, boolean shared) + throws IOException + { + return fch.lock(position, size, shared); + } + public FileLock tryLock(long position, long size, boolean shared) + throws IOException + { + return fch.tryLock(position, size, shared); + } + protected void implCloseChannel() throws IOException { + fch.close(); + if (forWrite) { + u.mtime = System.currentTimeMillis(); + u.size = Files.size(u.file); + + update(u); + } else { + if (!isFCH) // if this is a new fch for reading + removeTempPathForEntry(tmpfile); + } + } + }; + } finally { + endRead(); + } + } + + // the outstanding input streams that need to be closed + private Set streams = + Collections.synchronizedSet(new HashSet()); + + // the ex-channel and ex-path that need to close when their outstanding + // input streams are all closed by the obtainers. + private Set exChClosers = new HashSet<>(); + + private Set tmppaths = Collections.synchronizedSet(new HashSet()); + private Path getTempPathForEntry(byte[] path) throws IOException { + Path tmpPath = createTempFileInSameDirectoryAs(zfpath); + if (path != null) { + Entry e = getEntry0(path); + if (e != null) { + try (InputStream is = newInputStream(path)) { + Files.copy(is, tmpPath, REPLACE_EXISTING); + } + } + } + return tmpPath; + } + + private void removeTempPathForEntry(Path path) throws IOException { + Files.delete(path); + tmppaths.remove(path); + } + + // check if all parents really exit. ZIP spec does not require + // the existence of any "parent directory". + private void checkParents(byte[] path) throws IOException { + beginRead(); + try { + while ((path = getParent(path)) != null && path.length != 0) { + if (!inodes.containsKey(IndexNode.keyOf(path))) { + throw new NoSuchFileException(getString(path)); + } + } + } finally { + endRead(); + } + } + + private static byte[] ROOTPATH = new byte[0]; + private static byte[] getParent(byte[] path) { + int off = path.length - 1; + if (off > 0 && path[off] == '/') // isDirectory + off--; + while (off > 0 && path[off] != '/') { off--; } + if (off <= 0) + return ROOTPATH; + return Arrays.copyOf(path, off + 1); + } + + private final void beginWrite() { + rwlock.writeLock().lock(); + } + + private final void endWrite() { + rwlock.writeLock().unlock(); + } + + private final void beginRead() { + rwlock.readLock().lock(); + } + + private final void endRead() { + rwlock.readLock().unlock(); + } + + /////////////////////////////////////////////////////////////////// + + private volatile boolean isOpen = true; + private final SeekableByteChannel ch; // channel to the zipfile + final byte[] cen; // CEN & ENDHDR + private END end; + private long locpos; // position of first LOC header (usually 0) + + private final ReadWriteLock rwlock = new ReentrantReadWriteLock(); + + // name -> pos (in cen), IndexNode itself can be used as a "key" + private LinkedHashMap inodes; + + final byte[] getBytes(String name) { + return zc.getBytes(name); + } + + final String getString(byte[] name) { + return zc.toString(name); + } + + protected void finalize() throws IOException { + close(); + } + + private long getDataPos(Entry e) throws IOException { + if (e.locoff == -1) { + Entry e2 = getEntry0(e.name); + if (e2 == null) + throw new ZipException("invalid loc for entry <" + e.name + ">"); + e.locoff = e2.locoff; + } + byte[] buf = new byte[LOCHDR]; + if (readFullyAt(buf, 0, buf.length, e.locoff) != buf.length) + throw new ZipException("invalid loc for entry <" + e.name + ">"); + return locpos + e.locoff + LOCHDR + LOCNAM(buf) + LOCEXT(buf); + } + + // Reads len bytes of data from the specified offset into buf. + // Returns the total number of bytes read. + // Each/every byte read from here (except the cen, which is mapped). + final long readFullyAt(byte[] buf, int off, long len, long pos) + throws IOException + { + ByteBuffer bb = ByteBuffer.wrap(buf); + bb.position(off); + bb.limit((int)(off + len)); + return readFullyAt(bb, pos); + } + + private final long readFullyAt(ByteBuffer bb, long pos) + throws IOException + { + synchronized(ch) { + return ch.position(pos).read(bb); + } + } + + // Searches for end of central directory (END) header. The contents of + // the END header will be read and placed in endbuf. Returns the file + // position of the END header, otherwise returns -1 if the END header + // was not found or an error occurred. + private END findEND() throws IOException + { + byte[] buf = new byte[READBLOCKSZ]; + long ziplen = ch.size(); + long minHDR = (ziplen - END_MAXLEN) > 0 ? ziplen - END_MAXLEN : 0; + long minPos = minHDR - (buf.length - ENDHDR); + + for (long pos = ziplen - buf.length; pos >= minPos; pos -= (buf.length - ENDHDR)) + { + int off = 0; + if (pos < 0) { + // Pretend there are some NUL bytes before start of file + off = (int)-pos; + Arrays.fill(buf, 0, off, (byte)0); + } + int len = buf.length - off; + if (readFullyAt(buf, off, len, pos + off) != len) + zerror("zip END header not found"); + + // Now scan the block backwards for END header signature + for (int i = buf.length - ENDHDR; i >= 0; i--) { + if (buf[i+0] == (byte)'P' && + buf[i+1] == (byte)'K' && + buf[i+2] == (byte)'\005' && + buf[i+3] == (byte)'\006' && + (pos + i + ENDHDR + ENDCOM(buf, i) == ziplen)) { + // Found END header + buf = Arrays.copyOfRange(buf, i, i + ENDHDR); + END end = new END(); + end.endsub = ENDSUB(buf); + end.centot = ENDTOT(buf); + end.cenlen = ENDSIZ(buf); + end.cenoff = ENDOFF(buf); + end.comlen = ENDCOM(buf); + end.endpos = pos + i; + if (end.cenlen == ZIP64_MINVAL || + end.cenoff == ZIP64_MINVAL || + end.centot == ZIP64_MINVAL32) + { + // need to find the zip64 end; + byte[] loc64 = new byte[ZIP64_LOCHDR]; + if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR) + != loc64.length) { + return end; + } + long end64pos = ZIP64_LOCOFF(loc64); + byte[] end64buf = new byte[ZIP64_ENDHDR]; + if (readFullyAt(end64buf, 0, end64buf.length, end64pos) + != end64buf.length) { + return end; + } + // end64 found, re-calcualte everything. + end.cenlen = ZIP64_ENDSIZ(end64buf); + end.cenoff = ZIP64_ENDOFF(end64buf); + end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g + end.endpos = end64pos; + } + return end; + } + } + } + zerror("zip END header not found"); + return null; //make compiler happy + } + + // Reads zip file central directory. Returns the file position of first + // CEN header, otherwise returns -1 if an error occurred. If zip->msg != NULL + // then the error was a zip format error and zip->msg has the error text. + // Always pass in -1 for knownTotal; it's used for a recursive call. + private byte[] initCEN() throws IOException { + end = findEND(); + if (end.endpos == 0) { + inodes = new LinkedHashMap<>(10); + locpos = 0; + buildNodeTree(); + return null; // only END header present + } + if (end.cenlen > end.endpos) + zerror("invalid END header (bad central directory size)"); + long cenpos = end.endpos - end.cenlen; // position of CEN table + + // Get position of first local file (LOC) header, taking into + // account that there may be a stub prefixed to the zip file. + locpos = cenpos - end.cenoff; + if (locpos < 0) + zerror("invalid END header (bad central directory offset)"); + + // read in the CEN and END + byte[] cen = new byte[(int)(end.cenlen + ENDHDR)]; + if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { + zerror("read CEN tables failed"); + } + // Iterate through the entries in the central directory + inodes = new LinkedHashMap<>(end.centot + 1); + int pos = 0; + int limit = cen.length - ENDHDR; + while (pos < limit) { + if (CENSIG(cen, pos) != CENSIG) + zerror("invalid CEN header (bad signature)"); + int method = CENHOW(cen, pos); + int nlen = CENNAM(cen, pos); + int elen = CENEXT(cen, pos); + int clen = CENCOM(cen, pos); + if ((CENFLG(cen, pos) & 1) != 0) + zerror("invalid CEN header (encrypted entry)"); + if (method != METHOD_STORED && method != METHOD_DEFLATED) + zerror("invalid CEN header (unsupported compression method: " + method + ")"); + if (pos + CENHDR + nlen > limit) + zerror("invalid CEN header (bad header size)"); + byte[] name = Arrays.copyOfRange(cen, pos + CENHDR, pos + CENHDR + nlen); + IndexNode inode = new IndexNode(name, pos); + inodes.put(inode, inode); + // skip ext and comment + pos += (CENHDR + nlen + elen + clen); + } + if (pos + ENDHDR != cen.length) { + zerror("invalid CEN header (bad header size)"); + } + buildNodeTree(); + return cen; + } + + private void ensureOpen() throws IOException { + if (!isOpen) + throw new ClosedFileSystemException(); + } + + // Creates a new empty temporary file in the same directory as the + // specified file. A variant of Files.createTempFile. + private Path createTempFileInSameDirectoryAs(Path path) + throws IOException + { + Path parent = path.toAbsolutePath().getParent(); + Path dir = (parent == null) ? path.getFileSystem().getPath(".") : parent; + Path tmpPath = Files.createTempFile(dir, "zipfstmp", null); + tmppaths.add(tmpPath); + return tmpPath; + } + + ////////////////////update & sync ////////////////////////////////////// + + private boolean hasUpdate = false; + + // shared key. consumer guarantees the "writeLock" before use it. + private final IndexNode LOOKUPKEY = IndexNode.keyOf(null); + + private void updateDelete(IndexNode inode) { + beginWrite(); + try { + removeFromTree(inode); + inodes.remove(inode); + hasUpdate = true; + } finally { + endWrite(); + } + } + + private void update(Entry e) { + beginWrite(); + try { + IndexNode old = inodes.put(e, e); + if (old != null) { + removeFromTree(old); + } + if (e.type == Entry.NEW || e.type == Entry.FILECH || e.type == Entry.COPY) { + IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(e.name))); + e.sibling = parent.child; + parent.child = e; + } + hasUpdate = true; + } finally { + endWrite(); + } + } + + // copy over the whole LOC entry (header if necessary, data and ext) from + // old zip to the new one. + private long copyLOCEntry(Entry e, boolean updateHeader, + OutputStream os, + long written, byte[] buf) + throws IOException + { + long locoff = e.locoff; // where to read + e.locoff = written; // update the e.locoff with new value + + // calculate the size need to write out + long size = 0; + // if there is A ext + if ((e.flag & FLAG_DATADESCR) != 0) { + if (e.size >= ZIP64_MINVAL || e.csize >= ZIP64_MINVAL) + size = 24; + else + size = 16; + } + // read loc, use the original loc.elen/nlen + if (readFullyAt(buf, 0, LOCHDR , locoff) != LOCHDR) + throw new ZipException("loc: reading failed"); + if (updateHeader) { + locoff += LOCHDR + LOCNAM(buf) + LOCEXT(buf); // skip header + size += e.csize; + written = e.writeLOC(os) + size; + } else { + os.write(buf, 0, LOCHDR); // write out the loc header + locoff += LOCHDR; + // use e.csize, LOCSIZ(buf) is zero if FLAG_DATADESCR is on + // size += LOCNAM(buf) + LOCEXT(buf) + LOCSIZ(buf); + size += LOCNAM(buf) + LOCEXT(buf) + e.csize; + written = LOCHDR + size; + } + int n; + while (size > 0 && + (n = (int)readFullyAt(buf, 0, buf.length, locoff)) != -1) + { + if (size < n) + n = (int)size; + os.write(buf, 0, n); + size -= n; + locoff += n; + } + return written; + } + + // sync the zip file system, if there is any udpate + private void sync() throws IOException { + //System.out.printf("->sync(%s) starting....!%n", toString()); + // check ex-closer + if (!exChClosers.isEmpty()) { + for (ExChannelCloser ecc : exChClosers) { + if (ecc.streams.isEmpty()) { + ecc.ch.close(); + Files.delete(ecc.path); + exChClosers.remove(ecc); + } + } + } + if (!hasUpdate) + return; + Path tmpFile = createTempFileInSameDirectoryAs(zfpath); + try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(tmpFile, WRITE))) + { + ArrayList elist = new ArrayList<>(inodes.size()); + long written = 0; + byte[] buf = new byte[8192]; + Entry e = null; + + // write loc + for (IndexNode inode : inodes.values()) { + if (inode instanceof Entry) { // an updated inode + e = (Entry)inode; + try { + if (e.type == Entry.COPY) { + // entry copy: the only thing changed is the "name" + // and "nlen" in LOC header, so we udpate/rewrite the + // LOC in new file and simply copy the rest (data and + // ext) without enflating/deflating from the old zip + // file LOC entry. + written += copyLOCEntry(e, true, os, written, buf); + } else { // NEW, FILECH or CEN + e.locoff = written; + written += e.writeLOC(os); // write loc header + if (e.bytes != null) { // in-memory, deflated + os.write(e.bytes); // already + written += e.bytes.length; + } else if (e.file != null) { // tmp file + try (InputStream is = Files.newInputStream(e.file)) { + int n; + if (e.type == Entry.NEW) { // deflated already + while ((n = is.read(buf)) != -1) { + os.write(buf, 0, n); + written += n; + } + } else if (e.type == Entry.FILECH) { + // the data are not deflated, use ZEOS + try (OutputStream os2 = new EntryOutputStream(e, os)) { + while ((n = is.read(buf)) != -1) { + os2.write(buf, 0, n); + } + } + written += e.csize; + if ((e.flag & FLAG_DATADESCR) != 0) + written += e.writeEXT(os); + } + } + Files.delete(e.file); + tmppaths.remove(e.file); + } else { + // dir, 0-length data + } + } + elist.add(e); + } catch (IOException x) { + x.printStackTrace(); // skip any in-accurate entry + } + } else { // unchanged inode + if (inode.pos == -1) { + continue; // pseudo directory node + } + e = Entry.readCEN(this, inode.pos); + try { + written += copyLOCEntry(e, false, os, written, buf); + elist.add(e); + } catch (IOException x) { + x.printStackTrace(); // skip any wrong entry + } + } + } + + // now write back the cen and end table + end.cenoff = written; + for (Entry entry : elist) { + written += entry.writeCEN(os); + } + end.centot = elist.size(); + end.cenlen = written - end.cenoff; + end.write(os, written); + } + if (!streams.isEmpty()) { + // + // TBD: ExChannelCloser should not be necessary if we only + // sync when being closed, all streams should have been + // closed already. Keep the logic here for now. + // + // There are outstanding input streams open on existing "ch", + // so, don't close the "cha" and delete the "file for now, let + // the "ex-channel-closer" to handle them + ExChannelCloser ecc = new ExChannelCloser( + createTempFileInSameDirectoryAs(zfpath), + ch, + streams); + Files.move(zfpath, ecc.path, REPLACE_EXISTING); + exChClosers.add(ecc); + streams = Collections.synchronizedSet(new HashSet()); + } else { + ch.close(); + Files.delete(zfpath); + } + + Files.move(tmpFile, zfpath, REPLACE_EXISTING); + hasUpdate = false; // clear + /* + if (isOpen) { + ch = zfpath.newByteChannel(READ); // re-fresh "ch" and "cen" + cen = initCEN(); + } + */ + //System.out.printf("->sync(%s) done!%n", toString()); + } + + private IndexNode getInode(byte[] path) { + if (path == null) + throw new NullPointerException("path"); + IndexNode key = IndexNode.keyOf(path); + IndexNode inode = inodes.get(key); + if (inode == null && + (path.length == 0 || path[path.length -1] != '/')) { + // if does not ends with a slash + path = Arrays.copyOf(path, path.length + 1); + path[path.length - 1] = '/'; + inode = inodes.get(key.as(path)); + } + return inode; + } + + private Entry getEntry0(byte[] path) throws IOException { + IndexNode inode = getInode(path); + if (inode instanceof Entry) + return (Entry)inode; + if (inode == null || inode.pos == -1) + return null; + return Entry.readCEN(this, inode.pos); + } + + public void deleteFile(byte[] path, boolean failIfNotExists) + throws IOException + { + checkWritable(); + + IndexNode inode = getInode(path); + if (inode == null) { + if (path != null && path.length == 0) + throw new ZipException("root directory can't not be delete"); + if (failIfNotExists) + throw new NoSuchFileException(getString(path)); + } else { + if (inode.isDir() && inode.child != null) + throw new DirectoryNotEmptyException(getString(path)); + updateDelete(inode); + } + } + + private static void copyStream(InputStream is, OutputStream os) + throws IOException + { + byte[] copyBuf = new byte[8192]; + int n; + while ((n = is.read(copyBuf)) != -1) { + os.write(copyBuf, 0, n); + } + } + + // Returns an out stream for either + // (1) writing the contents of a new entry, if the entry exits, or + // (2) updating/replacing the contents of the specified existing entry. + private OutputStream getOutputStream(Entry e) throws IOException { + + if (e.mtime == -1) + e.mtime = System.currentTimeMillis(); + if (e.method == -1) + e.method = METHOD_DEFLATED; // TBD: use default method + // store size, compressed size, and crc-32 in LOC header + e.flag = 0; + if (zc.isUTF8()) + e.flag |= FLAG_EFS; + OutputStream os; + if (useTempFile) { + e.file = getTempPathForEntry(null); + os = Files.newOutputStream(e.file, WRITE); + } else { + os = new ByteArrayOutputStream((e.size > 0)? (int)e.size : 8192); + } + return new EntryOutputStream(e, os); + } + + private InputStream getInputStream(Entry e) + throws IOException + { + InputStream eis = null; + + if (e.type == Entry.NEW) { + if (e.bytes != null) + eis = new ByteArrayInputStream(e.bytes); + else if (e.file != null) + eis = Files.newInputStream(e.file); + else + throw new ZipException("update entry data is missing"); + } else if (e.type == Entry.FILECH) { + // FILECH result is un-compressed. + eis = Files.newInputStream(e.file); + // TBD: wrap to hook close() + // streams.add(eis); + return eis; + } else { // untouced CEN or COPY + eis = new EntryInputStream(e, ch); + } + if (e.method == METHOD_DEFLATED) { + // MORE: Compute good size for inflater stream: + long bufSize = e.size + 2; // Inflater likes a bit of slack + if (bufSize > 65536) + bufSize = 8192; + final long size = e.size; + eis = new InflaterInputStream(eis, getInflater(), (int)bufSize) { + + private boolean isClosed = false; + public void close() throws IOException { + if (!isClosed) { + releaseInflater(inf); + this.in.close(); + isClosed = true; + streams.remove(this); + } + } + // Override fill() method to provide an extra "dummy" byte + // at the end of the input stream. This is required when + // using the "nowrap" Inflater option. (it appears the new + // zlib in 7 does not need it, but keep it for now) + protected void fill() throws IOException { + if (eof) { + throw new EOFException( + "Unexpected end of ZLIB input stream"); + } + len = this.in.read(buf, 0, buf.length); + if (len == -1) { + buf[0] = 0; + len = 1; + eof = true; + } + inf.setInput(buf, 0, len); + } + private boolean eof; + + public int available() throws IOException { + if (isClosed) + return 0; + long avail = size - inf.getBytesWritten(); + return avail > (long) Integer.MAX_VALUE ? + Integer.MAX_VALUE : (int) avail; + } + }; + } else if (e.method == METHOD_STORED) { + // TBD: wrap/ it does not seem necessary + } else { + throw new ZipException("invalid compression method"); + } + streams.add(eis); + return eis; + } + + // Inner class implementing the input stream used to read + // a (possibly compressed) zip file entry. + private class EntryInputStream extends InputStream { + private final SeekableByteChannel zfch; // local ref to zipfs's "ch". zipfs.ch might + // point to a new channel after sync() + private long pos; // current position within entry data + protected long rem; // number of remaining bytes within entry + protected final long size; // uncompressed size of this entry + + EntryInputStream(Entry e, SeekableByteChannel zfch) + throws IOException + { + this.zfch = zfch; + rem = e.csize; + size = e.size; + pos = getDataPos(e); + } + public int read(byte b[], int off, int len) throws IOException { + ensureOpen(); + if (rem == 0) { + return -1; + } + if (len <= 0) { + return 0; + } + if (len > rem) { + len = (int) rem; + } + // readFullyAt() + long n = 0; + ByteBuffer bb = ByteBuffer.wrap(b); + bb.position(off); + bb.limit(off + len); + synchronized(zfch) { + n = zfch.position(pos).read(bb); + } + if (n > 0) { + pos += n; + rem -= n; + } + if (rem == 0) { + close(); + } + return (int)n; + } + public int read() throws IOException { + byte[] b = new byte[1]; + if (read(b, 0, 1) == 1) { + return b[0] & 0xff; + } else { + return -1; + } + } + public long skip(long n) throws IOException { + ensureOpen(); + if (n > rem) + n = rem; + pos += n; + rem -= n; + if (rem == 0) { + close(); + } + return n; + } + public int available() { + return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem; + } + public long size() { + return size; + } + public void close() { + rem = 0; + streams.remove(this); + } + } + + class EntryOutputStream extends DeflaterOutputStream + { + private CRC32 crc; + private Entry e; + private long written; + + EntryOutputStream(Entry e, OutputStream os) + throws IOException + { + super(os, getDeflater()); + if (e == null) + throw new NullPointerException("Zip entry is null"); + this.e = e; + crc = new CRC32(); + } + + @Override + public void write(byte b[], int off, int len) throws IOException { + if (e.type != Entry.FILECH) // only from sync + ensureOpen(); + if (off < 0 || len < 0 || off > b.length - len) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + switch (e.method) { + case METHOD_DEFLATED: + super.write(b, off, len); + break; + case METHOD_STORED: + written += len; + out.write(b, off, len); + break; + default: + throw new ZipException("invalid compression method"); + } + crc.update(b, off, len); + } + + @Override + public void close() throws IOException { + // TBD ensureOpen(); + switch (e.method) { + case METHOD_DEFLATED: + finish(); + e.size = def.getBytesRead(); + e.csize = def.getBytesWritten(); + e.crc = crc.getValue(); + break; + case METHOD_STORED: + // we already know that both e.size and e.csize are the same + e.size = e.csize = written; + e.crc = crc.getValue(); + break; + default: + throw new ZipException("invalid compression method"); + } + //crc.reset(); + if (out instanceof ByteArrayOutputStream) + e.bytes = ((ByteArrayOutputStream)out).toByteArray(); + + if (e.type == Entry.FILECH) { + releaseDeflater(def); + return; + } + super.close(); + releaseDeflater(def); + update(e); + } + } + + static void zerror(String msg) { + throw new ZipError(msg); + } + + // Maxmum number of de/inflater we cache + private final int MAX_FLATER = 20; + // List of available Inflater objects for decompression + private final List inflaters = new ArrayList<>(); + + // Gets an inflater from the list of available inflaters or allocates + // a new one. + private Inflater getInflater() { + synchronized (inflaters) { + int size = inflaters.size(); + if (size > 0) { + Inflater inf = inflaters.remove(size - 1); + return inf; + } else { + return new Inflater(true); + } + } + } + + // Releases the specified inflater to the list of available inflaters. + private void releaseInflater(Inflater inf) { + synchronized (inflaters) { + if (inflaters.size() < MAX_FLATER) { + inf.reset(); + inflaters.add(inf); + } else { + inf.end(); + } + } + } + + // List of available Deflater objects for compression + private final List deflaters = new ArrayList<>(); + + // Gets an deflater from the list of available deflaters or allocates + // a new one. + private Deflater getDeflater() { + synchronized (deflaters) { + int size = deflaters.size(); + if (size > 0) { + Deflater def = deflaters.remove(size - 1); + return def; + } else { + return new Deflater(Deflater.DEFAULT_COMPRESSION, true); + } + } + } + + // Releases the specified inflater to the list of available inflaters. + private void releaseDeflater(Deflater def) { + synchronized (deflaters) { + if (inflaters.size() < MAX_FLATER) { + def.reset(); + deflaters.add(def); + } else { + def.end(); + } + } + } + + // End of central directory record + static class END { + int disknum; + int sdisknum; + int endsub; // endsub + int centot; // 4 bytes + long cenlen; // 4 bytes + long cenoff; // 4 bytes + int comlen; // comment length + byte[] comment; + + /* members of Zip64 end of central directory locator */ + int diskNum; + long endpos; + int disktot; + + void write(OutputStream os, long offset) throws IOException { + boolean hasZip64 = false; + long xlen = cenlen; + long xoff = cenoff; + if (xlen >= ZIP64_MINVAL) { + xlen = ZIP64_MINVAL; + hasZip64 = true; + } + if (xoff >= ZIP64_MINVAL) { + xoff = ZIP64_MINVAL; + hasZip64 = true; + } + int count = centot; + if (count >= ZIP64_MINVAL32) { + count = ZIP64_MINVAL32; + hasZip64 = true; + } + if (hasZip64) { + long off64 = offset; + //zip64 end of central directory record + writeInt(os, ZIP64_ENDSIG); // zip64 END record signature + writeLong(os, ZIP64_ENDHDR - 12); // size of zip64 end + writeShort(os, 45); // version made by + writeShort(os, 45); // version needed to extract + writeInt(os, 0); // number of this disk + writeInt(os, 0); // central directory start disk + writeLong(os, centot); // number of directory entires on disk + writeLong(os, centot); // number of directory entires + writeLong(os, cenlen); // length of central directory + writeLong(os, cenoff); // offset of central directory + + //zip64 end of central directory locator + writeInt(os, ZIP64_LOCSIG); // zip64 END locator signature + writeInt(os, 0); // zip64 END start disk + writeLong(os, off64); // offset of zip64 END + writeInt(os, 1); // total number of disks (?) + } + writeInt(os, ENDSIG); // END record signature + writeShort(os, 0); // number of this disk + writeShort(os, 0); // central directory start disk + writeShort(os, count); // number of directory entries on disk + writeShort(os, count); // total number of directory entries + writeInt(os, xlen); // length of central directory + writeInt(os, xoff); // offset of central directory + if (comment != null) { // zip file comment + writeShort(os, comment.length); + writeBytes(os, comment); + } else { + writeShort(os, 0); + } + } + } + + // Internal node that links a "name" to its pos in cen table. + // The node itself can be used as a "key" to lookup itself in + // the HashMap inodes. + static class IndexNode { + byte[] name; + int hashcode; // node is hashable/hashed by its name + int pos = -1; // position in cen table, -1 menas the + // entry does not exists in zip file + IndexNode(byte[] name, int pos) { + name(name); + this.pos = pos; + } + + final static IndexNode keyOf(byte[] name) { // get a lookup key; + return new IndexNode(name, -1); + } + + final void name(byte[] name) { + this.name = name; + this.hashcode = Arrays.hashCode(name); + } + + final IndexNode as(byte[] name) { // reuse the node, mostly + name(name); // as a lookup "key" + return this; + } + + boolean isDir() { + return name != null && + (name.length == 0 || name[name.length - 1] == '/'); + } + + public boolean equals(Object other) { + if (!(other instanceof IndexNode)) { + return false; + } + return Arrays.equals(name, ((IndexNode)other).name); + } + + public int hashCode() { + return hashcode; + } + + IndexNode() {} + IndexNode sibling; + IndexNode child; // 1st child + } + + static class Entry extends IndexNode { + + static final int CEN = 1; // entry read from cen + static final int NEW = 2; // updated contents in bytes or file + static final int FILECH = 3; // fch update in "file" + static final int COPY = 4; // copy of a CEN entry + + + byte[] bytes; // updated content bytes + Path file; // use tmp file to store bytes; + int type = CEN; // default is the entry read from cen + + // entry attributes + int version; + int flag; + int method = -1; // compression method + long mtime = -1; // last modification time (in DOS time) + long atime = -1; // last access time + long ctime = -1; // create time + long crc = -1; // crc-32 of entry data + long csize = -1; // compressed size of entry data + long size = -1; // uncompressed size of entry data + byte[] extra; + + // cen + int versionMade; + int disk; + int attrs; + long attrsEx; + long locoff; + byte[] comment; + + Entry() {} + + Entry(byte[] name) { + name(name); + this.mtime = this.ctime = this.atime = System.currentTimeMillis(); + this.crc = 0; + this.size = 0; + this.csize = 0; + this.method = METHOD_DEFLATED; + } + + Entry(byte[] name, int type) { + this(name); + this.type = type; + } + + Entry (Entry e, int type) { + name(e.name); + this.version = e.version; + this.ctime = e.ctime; + this.atime = e.atime; + this.mtime = e.mtime; + this.crc = e.crc; + this.size = e.size; + this.csize = e.csize; + this.method = e.method; + this.extra = e.extra; + this.versionMade = e.versionMade; + this.disk = e.disk; + this.attrs = e.attrs; + this.attrsEx = e.attrsEx; + this.locoff = e.locoff; + this.comment = e.comment; + this.type = type; + } + + Entry (byte[] name, Path file, int type) { + this(name, type); + this.file = file; + this.method = METHOD_STORED; + } + + int version() throws ZipException { + if (method == METHOD_DEFLATED) + return 20; + else if (method == METHOD_STORED) + return 10; + throw new ZipException("unsupported compression method"); + } + + ///////////////////// CEN ////////////////////// + static Entry readCEN(ZipFileSystem zipfs, int pos) + throws IOException + { + return new Entry().cen(zipfs, pos); + } + + private Entry cen(ZipFileSystem zipfs, int pos) + throws IOException + { + byte[] cen = zipfs.cen; + if (CENSIG(cen, pos) != CENSIG) + zerror("invalid CEN header (bad signature)"); + versionMade = CENVEM(cen, pos); + version = CENVER(cen, pos); + flag = CENFLG(cen, pos); + method = CENHOW(cen, pos); + mtime = dosToJavaTime(CENTIM(cen, pos)); + crc = CENCRC(cen, pos); + csize = CENSIZ(cen, pos); + size = CENLEN(cen, pos); + int nlen = CENNAM(cen, pos); + int elen = CENEXT(cen, pos); + int clen = CENCOM(cen, pos); + disk = CENDSK(cen, pos); + attrs = CENATT(cen, pos); + attrsEx = CENATX(cen, pos); + locoff = CENOFF(cen, pos); + + pos += CENHDR; + name(Arrays.copyOfRange(cen, pos, pos + nlen)); + + pos += nlen; + if (elen > 0) { + extra = Arrays.copyOfRange(cen, pos, pos + elen); + pos += elen; + readExtra(zipfs); + } + if (clen > 0) { + comment = Arrays.copyOfRange(cen, pos, pos + clen); + } + return this; + } + + int writeCEN(OutputStream os) throws IOException + { + int written = CENHDR; + int version0 = version(); + long csize0 = csize; + long size0 = size; + long locoff0 = locoff; + int elen64 = 0; // extra for ZIP64 + int elenNTFS = 0; // extra for NTFS (a/c/mtime) + int elenEXTT = 0; // extra for Extended Timestamp + boolean foundExtraTime = false; // if time stamp NTFS, EXTT present + + // confirm size/length + int nlen = (name != null) ? name.length : 0; + int elen = (extra != null) ? extra.length : 0; + int eoff = 0; + int clen = (comment != null) ? comment.length : 0; + if (csize >= ZIP64_MINVAL) { + csize0 = ZIP64_MINVAL; + elen64 += 8; // csize(8) + } + if (size >= ZIP64_MINVAL) { + size0 = ZIP64_MINVAL; // size(8) + elen64 += 8; + } + if (locoff >= ZIP64_MINVAL) { + locoff0 = ZIP64_MINVAL; + elen64 += 8; // offset(8) + } + if (elen64 != 0) { + elen64 += 4; // header and data sz 4 bytes + } + while (eoff + 4 < elen) { + int tag = SH(extra, eoff); + int sz = SH(extra, eoff + 2); + if (tag == EXTID_EXTT || tag == EXTID_NTFS) { + foundExtraTime = true; + } + eoff += (4 + sz); + } + if (!foundExtraTime) { + if (isWindows) { // use NTFS + elenNTFS = 36; // total 36 bytes + } else { // Extended Timestamp otherwise + elenEXTT = 9; // only mtime in cen + } + } + writeInt(os, CENSIG); // CEN header signature + if (elen64 != 0) { + writeShort(os, 45); // ver 4.5 for zip64 + writeShort(os, 45); + } else { + writeShort(os, version0); // version made by + writeShort(os, version0); // version needed to extract + } + writeShort(os, flag); // general purpose bit flag + writeShort(os, method); // compression method + // last modification time + writeInt(os, (int)javaToDosTime(mtime)); + writeInt(os, crc); // crc-32 + writeInt(os, csize0); // compressed size + writeInt(os, size0); // uncompressed size + writeShort(os, name.length); + writeShort(os, elen + elen64 + elenNTFS + elenEXTT); + + if (comment != null) { + writeShort(os, Math.min(clen, 0xffff)); + } else { + writeShort(os, 0); + } + writeShort(os, 0); // starting disk number + writeShort(os, 0); // internal file attributes (unused) + writeInt(os, 0); // external file attributes (unused) + writeInt(os, locoff0); // relative offset of local header + writeBytes(os, name); + if (elen64 != 0) { + writeShort(os, EXTID_ZIP64);// Zip64 extra + writeShort(os, elen64 - 4); // size of "this" extra block + if (size0 == ZIP64_MINVAL) + writeLong(os, size); + if (csize0 == ZIP64_MINVAL) + writeLong(os, csize); + if (locoff0 == ZIP64_MINVAL) + writeLong(os, locoff); + } + if (elenNTFS != 0) { + writeShort(os, EXTID_NTFS); + writeShort(os, elenNTFS - 4); + writeInt(os, 0); // reserved + writeShort(os, 0x0001); // NTFS attr tag + writeShort(os, 24); + writeLong(os, javaToWinTime(mtime)); + writeLong(os, javaToWinTime(atime)); + writeLong(os, javaToWinTime(ctime)); + } + if (elenEXTT != 0) { + writeShort(os, EXTID_EXTT); + writeShort(os, elenEXTT - 4); + if (ctime == -1) + os.write(0x3); // mtime and atime + else + os.write(0x7); // mtime, atime and ctime + writeInt(os, javaToUnixTime(mtime)); + } + if (extra != null) // whatever not recognized + writeBytes(os, extra); + if (comment != null) //TBD: 0, Math.min(commentBytes.length, 0xffff)); + writeBytes(os, comment); + return CENHDR + nlen + elen + clen + elen64 + elenNTFS + elenEXTT; + } + + ///////////////////// LOC ////////////////////// + static Entry readLOC(ZipFileSystem zipfs, long pos) + throws IOException + { + return readLOC(zipfs, pos, new byte[1024]); + } + + static Entry readLOC(ZipFileSystem zipfs, long pos, byte[] buf) + throws IOException + { + return new Entry().loc(zipfs, pos, buf); + } + + Entry loc(ZipFileSystem zipfs, long pos, byte[] buf) + throws IOException + { + assert (buf.length >= LOCHDR); + if (zipfs.readFullyAt(buf, 0, LOCHDR , pos) != LOCHDR) + throw new ZipException("loc: reading failed"); + if (LOCSIG(buf) != LOCSIG) + throw new ZipException("loc: wrong sig ->" + + Long.toString(LOCSIG(buf), 16)); + //startPos = pos; + version = LOCVER(buf); + flag = LOCFLG(buf); + method = LOCHOW(buf); + mtime = dosToJavaTime(LOCTIM(buf)); + crc = LOCCRC(buf); + csize = LOCSIZ(buf); + size = LOCLEN(buf); + int nlen = LOCNAM(buf); + int elen = LOCEXT(buf); + + name = new byte[nlen]; + if (zipfs.readFullyAt(name, 0, nlen, pos + LOCHDR) != nlen) { + throw new ZipException("loc: name reading failed"); + } + if (elen > 0) { + extra = new byte[elen]; + if (zipfs.readFullyAt(extra, 0, elen, pos + LOCHDR + nlen) + != elen) { + throw new ZipException("loc: ext reading failed"); + } + } + pos += (LOCHDR + nlen + elen); + if ((flag & FLAG_DATADESCR) != 0) { + // Data Descriptor + Entry e = zipfs.getEntry0(name); // get the size/csize from cen + if (e == null) + throw new ZipException("loc: name not found in cen"); + size = e.size; + csize = e.csize; + pos += (method == METHOD_STORED ? size : csize); + if (size >= ZIP64_MINVAL || csize >= ZIP64_MINVAL) + pos += 24; + else + pos += 16; + } else { + if (extra != null && + (size == ZIP64_MINVAL || csize == ZIP64_MINVAL)) { + // zip64 ext: must include both size and csize + int off = 0; + while (off + 20 < elen) { // HeaderID+DataSize+Data + int sz = SH(extra, off + 2); + if (SH(extra, off) == EXTID_ZIP64 && sz == 16) { + size = LL(extra, off + 4); + csize = LL(extra, off + 12); + break; + } + off += (sz + 4); + } + } + pos += (method == METHOD_STORED ? size : csize); + } + return this; + } + + int writeLOC(OutputStream os) + throws IOException + { + writeInt(os, LOCSIG); // LOC header signature + int version = version(); + int nlen = (name != null) ? name.length : 0; + int elen = (extra != null) ? extra.length : 0; + boolean foundExtraTime = false; // if extra timestamp present + int eoff = 0; + int elen64 = 0; + int elenEXTT = 0; + int elenNTFS = 0; + if ((flag & FLAG_DATADESCR) != 0) { + writeShort(os, version()); // version needed to extract + writeShort(os, flag); // general purpose bit flag + writeShort(os, method); // compression method + // last modification time + writeInt(os, (int)javaToDosTime(mtime)); + // store size, uncompressed size, and crc-32 in data descriptor + // immediately following compressed entry data + writeInt(os, 0); + writeInt(os, 0); + writeInt(os, 0); + } else { + if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) { + elen64 = 20; //headid(2) + size(2) + size(8) + csize(8) + writeShort(os, 45); // ver 4.5 for zip64 + } else { + writeShort(os, version()); // version needed to extract + } + writeShort(os, flag); // general purpose bit flag + writeShort(os, method); // compression method + // last modification time + writeInt(os, (int)javaToDosTime(mtime)); + writeInt(os, crc); // crc-32 + if (elen64 != 0) { + writeInt(os, ZIP64_MINVAL); + writeInt(os, ZIP64_MINVAL); + } else { + writeInt(os, csize); // compressed size + writeInt(os, size); // uncompressed size + } + } + while (eoff + 4 < elen) { + int tag = SH(extra, eoff); + int sz = SH(extra, eoff + 2); + if (tag == EXTID_EXTT || tag == EXTID_NTFS) { + foundExtraTime = true; + } + eoff += (4 + sz); + } + if (!foundExtraTime) { + if (isWindows) { + elenNTFS = 36; // NTFS, total 36 bytes + } else { // on unix use "ext time" + elenEXTT = 9; + if (atime != -1) + elenEXTT += 4; + if (ctime != -1) + elenEXTT += 4; + } + } + writeShort(os, name.length); + writeShort(os, elen + elen64 + elenNTFS + elenEXTT); + writeBytes(os, name); + if (elen64 != 0) { + writeShort(os, EXTID_ZIP64); + writeShort(os, 16); + writeLong(os, size); + writeLong(os, csize); + } + if (elenNTFS != 0) { + writeShort(os, EXTID_NTFS); + writeShort(os, elenNTFS - 4); + writeInt(os, 0); // reserved + writeShort(os, 0x0001); // NTFS attr tag + writeShort(os, 24); + writeLong(os, javaToWinTime(mtime)); + writeLong(os, javaToWinTime(atime)); + writeLong(os, javaToWinTime(ctime)); + } + if (elenEXTT != 0) { + writeShort(os, EXTID_EXTT); + writeShort(os, elenEXTT - 4);// size for the folowing data block + int fbyte = 0x1; + if (atime != -1) // mtime and atime + fbyte |= 0x2; + if (ctime != -1) // mtime, atime and ctime + fbyte |= 0x4; + os.write(fbyte); // flags byte + writeInt(os, javaToUnixTime(mtime)); + if (atime != -1) + writeInt(os, javaToUnixTime(atime)); + if (ctime != -1) + writeInt(os, javaToUnixTime(ctime)); + } + if (extra != null) { + writeBytes(os, extra); + } + return LOCHDR + name.length + elen + elen64 + elenNTFS + elenEXTT; + } + + // Data Descriptior + int writeEXT(OutputStream os) + throws IOException + { + writeInt(os, EXTSIG); // EXT header signature + writeInt(os, crc); // crc-32 + if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) { + writeLong(os, csize); + writeLong(os, size); + return 24; + } else { + writeInt(os, csize); // compressed size + writeInt(os, size); // uncompressed size + return 16; + } + } + + // read NTFS, UNIX and ZIP64 data from cen.extra + void readExtra(ZipFileSystem zipfs) throws IOException { + if (extra == null) + return; + int elen = extra.length; + int off = 0; + int newOff = 0; + while (off + 4 < elen) { + // extra spec: HeaderID+DataSize+Data + int pos = off; + int tag = SH(extra, pos); + int sz = SH(extra, pos + 2); + pos += 4; + if (pos + sz > elen) // invalid data + break; + switch (tag) { + case EXTID_ZIP64 : + if (size == ZIP64_MINVAL) { + if (pos + 8 > elen) // invalid zip64 extra + break; // fields, just skip + size = LL(extra, pos); + pos += 8; + } + if (csize == ZIP64_MINVAL) { + if (pos + 8 > elen) + break; + csize = LL(extra, pos); + pos += 8; + } + if (locoff == ZIP64_MINVAL) { + if (pos + 8 > elen) + break; + locoff = LL(extra, pos); + pos += 8; + } + break; + case EXTID_NTFS: + pos += 4; // reserved 4 bytes + if (SH(extra, pos) != 0x0001) + break; + if (SH(extra, pos + 2) != 24) + break; + // override the loc field, datatime here is + // more "accurate" + mtime = winToJavaTime(LL(extra, pos + 4)); + atime = winToJavaTime(LL(extra, pos + 12)); + ctime = winToJavaTime(LL(extra, pos + 20)); + break; + case EXTID_EXTT: + // spec says the Extened timestamp in cen only has mtime + // need to read the loc to get the extra a/ctime + byte[] buf = new byte[LOCHDR]; + if (zipfs.readFullyAt(buf, 0, buf.length , locoff) + != buf.length) + throw new ZipException("loc: reading failed"); + if (LOCSIG(buf) != LOCSIG) + throw new ZipException("loc: wrong sig ->" + + Long.toString(LOCSIG(buf), 16)); + + int locElen = LOCEXT(buf); + if (locElen < 9) // EXTT is at lease 9 bytes + break; + int locNlen = LOCNAM(buf); + buf = new byte[locElen]; + if (zipfs.readFullyAt(buf, 0, buf.length , locoff + LOCHDR + locNlen) + != buf.length) + throw new ZipException("loc extra: reading failed"); + int locPos = 0; + while (locPos + 4 < buf.length) { + int locTag = SH(buf, locPos); + int locSZ = SH(buf, locPos + 2); + locPos += 4; + if (locTag != EXTID_EXTT) { + locPos += locSZ; + continue; + } + int flag = CH(buf, locPos++); + if ((flag & 0x1) != 0) { + mtime = unixToJavaTime(LG(buf, locPos)); + locPos += 4; + } + if ((flag & 0x2) != 0) { + atime = unixToJavaTime(LG(buf, locPos)); + locPos += 4; + } + if ((flag & 0x4) != 0) { + ctime = unixToJavaTime(LG(buf, locPos)); + locPos += 4; + } + break; + } + break; + default: // unknown tag + System.arraycopy(extra, off, extra, newOff, sz + 4); + newOff += (sz + 4); + } + off += (sz + 4); + } + if (newOff != 0 && newOff != extra.length) + extra = Arrays.copyOf(extra, newOff); + else + extra = null; + } + } + + private static class ExChannelCloser { + Path path; + SeekableByteChannel ch; + Set streams; + ExChannelCloser(Path path, + SeekableByteChannel ch, + Set streams) + { + this.path = path; + this.ch = ch; + this.streams = streams; + } + } + + // ZIP directory has two issues: + // (1) ZIP spec does not require the ZIP file to include + // directory entry + // (2) all entries are not stored/organized in a "tree" + // structure. + // A possible solution is to build the node tree ourself as + // implemented below. + private IndexNode root; + + private void addToTree(IndexNode inode, HashSet dirs) { + if (dirs.contains(inode)) { + return; + } + IndexNode parent; + byte[] name = inode.name; + byte[] pname = getParent(name); + if (inodes.containsKey(LOOKUPKEY.as(pname))) { + parent = inodes.get(LOOKUPKEY); + } else { // pseudo directory entry + parent = new IndexNode(pname, -1); + inodes.put(parent, parent); + } + addToTree(parent, dirs); + inode.sibling = parent.child; + parent.child = inode; + if (name[name.length -1] == '/') + dirs.add(inode); + } + + private void removeFromTree(IndexNode inode) { + IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(inode.name))); + IndexNode child = parent.child; + if (child.equals(inode)) { + parent.child = child.sibling; + } else { + IndexNode last = child; + while ((child = child.sibling) != null) { + if (child.equals(inode)) { + last.sibling = child.sibling; + break; + } else { + last = child; + } + } + } + } + + private void buildNodeTree() throws IOException { + beginWrite(); + try { + HashSet dirs = new HashSet<>(); + IndexNode root = new IndexNode(ROOTPATH, -1); + inodes.put(root, root); + dirs.add(root); + for (IndexNode node : inodes.keySet().toArray(new IndexNode[0])) { + addToTree(node, dirs); + } + } finally { + endWrite(); + } + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.io.*; +import java.nio.channels.*; +import java.nio.file.*; +import java.nio.file.DirectoryStream.Filter; +import java.nio.file.attribute.*; +import java.nio.file.spi.FileSystemProvider; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.zip.ZipError; +import java.util.concurrent.ExecutorService; + +/* + * + * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal + */ + +public class ZipFileSystemProvider extends FileSystemProvider { + + + private final Map filesystems = new HashMap<>(); + + public ZipFileSystemProvider() {} + + @Override + public String getScheme() { + return "jar"; + } + + protected Path uriToPath(URI uri) { + String scheme = uri.getScheme(); + if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) { + throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'"); + } + try { + // only support legacy JAR URL syntax jar:{uri}!/{entry} for now + String spec = uri.getRawSchemeSpecificPart(); + int sep = spec.indexOf("!/"); + if (sep != -1) + spec = spec.substring(0, sep); + return Paths.get(new URI(spec)).toAbsolutePath(); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + } + + private boolean ensureFile(Path path) { + try { + BasicFileAttributes attrs = + Files.readAttributes(path, BasicFileAttributes.class); + if (!attrs.isRegularFile()) + throw new UnsupportedOperationException(); + return true; + } catch (IOException ioe) { + return false; + } + } + + @Override + public FileSystem newFileSystem(URI uri, Map env) + throws IOException + { + Path path = uriToPath(uri); + synchronized(filesystems) { + Path realPath = null; + if (ensureFile(path)) { + realPath = path.toRealPath(); + if (filesystems.containsKey(realPath)) + throw new FileSystemAlreadyExistsException(); + } + ZipFileSystem zipfs = null; + try { + zipfs = new ZipFileSystem(this, path, env); + } catch (ZipError ze) { + String pname = path.toString(); + if (pname.endsWith(".zip") || pname.endsWith(".jar")) + throw ze; + // assume NOT a zip/jar file + throw new UnsupportedOperationException(); + } + filesystems.put(realPath, zipfs); + return zipfs; + } + } + + @Override + public FileSystem newFileSystem(Path path, Map env) + throws IOException + { + if (path.getFileSystem() != FileSystems.getDefault()) { + throw new UnsupportedOperationException(); + } + ensureFile(path); + try { + return new ZipFileSystem(this, path, env); + } catch (ZipError ze) { + String pname = path.toString(); + if (pname.endsWith(".zip") || pname.endsWith(".jar")) + throw ze; + throw new UnsupportedOperationException(); + } + } + + @Override + public Path getPath(URI uri) { + + String spec = uri.getSchemeSpecificPart(); + int sep = spec.indexOf("!/"); + if (sep == -1) + throw new IllegalArgumentException("URI: " + + uri + + " does not contain path info ex. jar:file:/c:/foo.zip!/BAR"); + return getFileSystem(uri).getPath(spec.substring(sep + 1)); + } + + + @Override + public FileSystem getFileSystem(URI uri) { + synchronized (filesystems) { + ZipFileSystem zipfs = null; + try { + zipfs = filesystems.get(uriToPath(uri).toRealPath()); + } catch (IOException x) { + // ignore the ioe from toRealPath(), return FSNFE + } + if (zipfs == null) + throw new FileSystemNotFoundException(); + return zipfs; + } + } + + // Checks that the given file is a UnixPath + static final ZipPath toZipPath(Path path) { + if (path == null) + throw new NullPointerException(); + if (!(path instanceof ZipPath)) + throw new ProviderMismatchException(); + return (ZipPath)path; + } + + @Override + public void checkAccess(Path path, AccessMode... modes) throws IOException { + toZipPath(path).checkAccess(modes); + } + + @Override + public void copy(Path src, Path target, CopyOption... options) + throws IOException + { + toZipPath(src).copy(toZipPath(target), options); + } + + @Override + public void createDirectory(Path path, FileAttribute... attrs) + throws IOException + { + toZipPath(path).createDirectory(attrs); + } + + @Override + public final void delete(Path path) throws IOException { + toZipPath(path).delete(); + } + + @Override + @SuppressWarnings("unchecked") + public V + getFileAttributeView(Path path, Class type, LinkOption... options) + { + return ZipFileAttributeView.get(toZipPath(path), type); + } + + @Override + public FileStore getFileStore(Path path) throws IOException { + return toZipPath(path).getFileStore(); + } + + @Override + public boolean isHidden(Path path) { + return toZipPath(path).isHidden(); + } + + @Override + public boolean isSameFile(Path path, Path other) throws IOException { + return toZipPath(path).isSameFile(other); + } + + @Override + public void move(Path src, Path target, CopyOption... options) + throws IOException + { + toZipPath(src).move(toZipPath(target), options); + } + + @Override + public AsynchronousFileChannel newAsynchronousFileChannel(Path path, + Set options, + ExecutorService exec, + FileAttribute... attrs) + throws IOException + { + throw new UnsupportedOperationException(); + } + + @Override + public SeekableByteChannel newByteChannel(Path path, + Set options, + FileAttribute... attrs) + throws IOException + { + return toZipPath(path).newByteChannel(options, attrs); + } + + @Override + public DirectoryStream newDirectoryStream( + Path path, Filter filter) throws IOException + { + return toZipPath(path).newDirectoryStream(filter); + } + + @Override + public FileChannel newFileChannel(Path path, + Set options, + FileAttribute... attrs) + throws IOException + { + return toZipPath(path).newFileChannel(options, attrs); + } + + @Override + public InputStream newInputStream(Path path, OpenOption... options) + throws IOException + { + return toZipPath(path).newInputStream(options); + } + + @Override + public OutputStream newOutputStream(Path path, OpenOption... options) + throws IOException + { + return toZipPath(path).newOutputStream(options); + } + + @Override + public A + readAttributes(Path path, Class type, LinkOption... options) + throws IOException + { + if (type == BasicFileAttributes.class || type == ZipFileAttributes.class) + return (A)toZipPath(path).getAttributes(); + return null; + } + + @Override + public Map + readAttributes(Path path, String attribute, LinkOption... options) + throws IOException + { + return toZipPath(path).readAttributes(attribute, options); + } + + @Override + public Path readSymbolicLink(Path link) throws IOException { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void setAttribute(Path path, String attribute, + Object value, LinkOption... options) + throws IOException + { + toZipPath(path).setAttribute(attribute, value, options); + } + + ////////////////////////////////////////////////////////////// + void removeFileSystem(Path zfpath, ZipFileSystem zfs) throws IOException { + synchronized (filesystems) { + zfpath = zfpath.toRealPath(); + if (filesystems.get(zfpath) == zfs) + filesystems.remove(zfpath); + } + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipInfo.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Map; +import static jdk.nio.zipfs.ZipConstants.*; +import static jdk.nio.zipfs.ZipUtils.*; + +/** + * Print all loc and cen headers of the ZIP file + * + * @author Xueming Shen + */ + +public class ZipInfo { + + public static void main(String[] args) throws Throwable { + if (args.length < 1) { + print("Usage: java ZipInfo zfname"); + } else { + Map env = Collections.emptyMap(); + ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider() + .newFileSystem(Paths.get(args[0]), env)); + byte[] cen = zfs.cen; + if (cen == null) { + print("zip file is empty%n"); + return; + } + int pos = 0; + byte[] buf = new byte[1024]; + int no = 1; + while (pos + CENHDR < cen.length) { + print("----------------#%d--------------------%n", no++); + printCEN(cen, pos); + + // use size CENHDR as the extra bytes to read, just in case the + // loc.extra is bigger than the cen.extra, try to avoid to read + // twice + long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR; + if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) + ZipFileSystem.zerror("read loc header failed"); + if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) { + // have to read the second time; + len = LOCHDR + LOCNAM(buf) + LOCEXT(buf); + if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) + ZipFileSystem.zerror("read loc header failed"); + } + printLOC(buf); + pos += CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos); + } + zfs.close(); + } + } + + static void print(String fmt, Object... objs) { + System.out.printf(fmt, objs); + } + + static void printLOC(byte[] loc) { + print("%n"); + print("[Local File Header]%n"); + print(" Signature : %#010x%n", LOCSIG(loc)); + if (LOCSIG(loc) != LOCSIG) { + print(" Wrong signature!"); + return; + } + print(" Version : %#6x [%d.%d]%n", + LOCVER(loc), LOCVER(loc) / 10, LOCVER(loc) % 10); + print(" Flag : %#6x%n", LOCFLG(loc)); + print(" Method : %#6x%n", LOCHOW(loc)); + print(" LastMTime : %#10x [%tc]%n", + LOCTIM(loc), dosToJavaTime(LOCTIM(loc))); + print(" CRC : %#10x%n", LOCCRC(loc)); + print(" CSize : %#10x%n", LOCSIZ(loc)); + print(" Size : %#10x%n", LOCLEN(loc)); + print(" NameLength : %#6x [%s]%n", + LOCNAM(loc), new String(loc, LOCHDR, LOCNAM(loc))); + print(" ExtraLength : %#6x%n", LOCEXT(loc)); + if (LOCEXT(loc) != 0) + printExtra(loc, LOCHDR + LOCNAM(loc), LOCEXT(loc)); + } + + static void printCEN(byte[] cen, int off) { + print("[Central Directory Header]%n"); + print(" Signature : %#010x%n", CENSIG(cen, off)); + if (CENSIG(cen, off) != CENSIG) { + print(" Wrong signature!"); + return; + } + print(" VerMadeby : %#6x [%d, %d.%d]%n", + CENVEM(cen, off), (CENVEM(cen, off) >> 8), + (CENVEM(cen, off) & 0xff) / 10, + (CENVEM(cen, off) & 0xff) % 10); + print(" VerExtract : %#6x [%d.%d]%n", + CENVER(cen, off), CENVER(cen, off) / 10, CENVER(cen, off) % 10); + print(" Flag : %#6x%n", CENFLG(cen, off)); + print(" Method : %#6x%n", CENHOW(cen, off)); + print(" LastMTime : %#10x [%tc]%n", + CENTIM(cen, off), dosToJavaTime(CENTIM(cen, off))); + print(" CRC : %#10x%n", CENCRC(cen, off)); + print(" CSize : %#10x%n", CENSIZ(cen, off)); + print(" Size : %#10x%n", CENLEN(cen, off)); + print(" NameLen : %#6x [%s]%n", + CENNAM(cen, off), new String(cen, off + CENHDR, CENNAM(cen, off))); + print(" ExtraLen : %#6x%n", CENEXT(cen, off)); + if (CENEXT(cen, off) != 0) + printExtra(cen, off + CENHDR + CENNAM(cen, off), CENEXT(cen, off)); + print(" CommentLen : %#6x%n", CENCOM(cen, off)); + print(" DiskStart : %#6x%n", CENDSK(cen, off)); + print(" Attrs : %#6x%n", CENATT(cen, off)); + print(" AttrsEx : %#10x%n", CENATX(cen, off)); + print(" LocOff : %#10x%n", CENOFF(cen, off)); + + } + + static long locoff(byte[] cen, int pos) { + long locoff = CENOFF(cen, pos); + if (locoff == ZIP64_MINVAL) { //ZIP64 + int off = pos + CENHDR + CENNAM(cen, pos); + int end = off + CENEXT(cen, pos); + while (off + 4 < end) { + int tag = SH(cen, off); + int sz = SH(cen, off + 2); + if (tag != EXTID_ZIP64) { + off += 4 + sz; + continue; + } + off += 4; + if (CENLEN(cen, pos) == ZIP64_MINVAL) + off += 8; + if (CENSIZ(cen, pos) == ZIP64_MINVAL) + off += 8; + return LL(cen, off); + } + // should never be here + } + return locoff; + } + + static void printExtra(byte[] extra, int off, int len) { + int end = off + len; + while (off + 4 <= end) { + int tag = SH(extra, off); + int sz = SH(extra, off + 2); + print(" [tag=0x%04x, sz=%d, data= ", tag, sz); + if (off + sz > end) { + print(" Error: Invalid extra data, beyond extra length"); + break; + } + off += 4; + for (int i = 0; i < sz; i++) + print("%02x ", extra[off + i]); + print("]%n"); + switch (tag) { + case EXTID_ZIP64 : + print(" ->ZIP64: "); + int pos = off; + while (pos + 8 <= off + sz) { + print(" *0x%x ", LL(extra, pos)); + pos += 8; + } + print("%n"); + break; + case EXTID_NTFS: + print(" ->PKWare NTFS%n"); + // 4 bytes reserved + if (SH(extra, off + 4) != 0x0001 || SH(extra, off + 6) != 24) + print(" Error: Invalid NTFS sub-tag or subsz"); + print(" mtime:%tc%n", + winToJavaTime(LL(extra, off + 8))); + print(" atime:%tc%n", + winToJavaTime(LL(extra, off + 16))); + print(" ctime:%tc%n", + winToJavaTime(LL(extra, off + 24))); + break; + case EXTID_EXTT: + print(" ->Info-ZIP Extended Timestamp: flag=%x%n",extra[off]); + pos = off + 1 ; + while (pos + 4 <= off + sz) { + print(" *%tc%n", + unixToJavaTime(LG(extra, pos))); + pos += 4; + } + break; + default: + print(" ->[tag=%x, size=%d]%n", tag, sz); + } + off += sz; + } + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipPath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipPath.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.io.*; +import java.net.URI; +import java.nio.channels.*; +import java.nio.file.*; +import java.nio.file.DirectoryStream.Filter; +import java.nio.file.attribute.*; +import java.util.*; +import static java.nio.file.StandardOpenOption.*; +import static java.nio.file.StandardCopyOption.*; + + +/** + * + * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal + */ + +class ZipPath implements Path { + + private final ZipFileSystem zfs; + private final byte[] path; + private volatile int[] offsets; + private int hashcode = 0; // cached hashcode (created lazily) + + ZipPath(ZipFileSystem zfs, byte[] path) { + this(zfs, path, false); + } + + ZipPath(ZipFileSystem zfs, byte[] path, boolean normalized) + { + this.zfs = zfs; + if (normalized) + this.path = path; + else + this.path = normalize(path); + } + + @Override + public ZipPath getRoot() { + if (this.isAbsolute()) + return new ZipPath(zfs, new byte[]{path[0]}); + else + return null; + } + + @Override + public Path getFileName() { + initOffsets(); + int count = offsets.length; + if (count == 0) + return null; // no elements so no name + if (count == 1 && path[0] != '/') + return this; + int lastOffset = offsets[count-1]; + int len = path.length - lastOffset; + byte[] result = new byte[len]; + System.arraycopy(path, lastOffset, result, 0, len); + return new ZipPath(zfs, result); + } + + @Override + public ZipPath getParent() { + initOffsets(); + int count = offsets.length; + if (count == 0) // no elements so no parent + return null; + int len = offsets[count-1] - 1; + if (len <= 0) // parent is root only (may be null) + return getRoot(); + byte[] result = new byte[len]; + System.arraycopy(path, 0, result, 0, len); + return new ZipPath(zfs, result); + } + + @Override + public int getNameCount() { + initOffsets(); + return offsets.length; + } + + @Override + public ZipPath getName(int index) { + initOffsets(); + if (index < 0 || index >= offsets.length) + throw new IllegalArgumentException(); + int begin = offsets[index]; + int len; + if (index == (offsets.length-1)) + len = path.length - begin; + else + len = offsets[index+1] - begin - 1; + // construct result + byte[] result = new byte[len]; + System.arraycopy(path, begin, result, 0, len); + return new ZipPath(zfs, result); + } + + @Override + public ZipPath subpath(int beginIndex, int endIndex) { + initOffsets(); + if (beginIndex < 0 || + beginIndex >= offsets.length || + endIndex > offsets.length || + beginIndex >= endIndex) + throw new IllegalArgumentException(); + + // starting offset and length + int begin = offsets[beginIndex]; + int len; + if (endIndex == offsets.length) + len = path.length - begin; + else + len = offsets[endIndex] - begin - 1; + // construct result + byte[] result = new byte[len]; + System.arraycopy(path, begin, result, 0, len); + return new ZipPath(zfs, result); + } + + @Override + public ZipPath toRealPath(LinkOption... options) throws IOException { + ZipPath realPath = new ZipPath(zfs, getResolvedPath()).toAbsolutePath(); + realPath.checkAccess(); + return realPath; + } + + boolean isHidden() { + return false; + } + + @Override + public ZipPath toAbsolutePath() { + if (isAbsolute()) { + return this; + } else { + //add / bofore the existing path + byte[] defaultdir = zfs.getDefaultDir().path; + int defaultlen = defaultdir.length; + boolean endsWith = (defaultdir[defaultlen - 1] == '/'); + byte[] t = null; + if (endsWith) + t = new byte[defaultlen + path.length]; + else + t = new byte[defaultlen + 1 + path.length]; + System.arraycopy(defaultdir, 0, t, 0, defaultlen); + if (!endsWith) + t[defaultlen++] = '/'; + System.arraycopy(path, 0, t, defaultlen, path.length); + return new ZipPath(zfs, t, true); // normalized + } + } + + @Override + public URI toUri() { + try { + return new URI("jar", + zfs.getZipFile().toUri() + + "!" + + zfs.getString(toAbsolutePath().path), + null); + } catch (Exception ex) { + throw new AssertionError(ex); + } + } + + private boolean equalsNameAt(ZipPath other, int index) { + int mbegin = offsets[index]; + int mlen = 0; + if (index == (offsets.length-1)) + mlen = path.length - mbegin; + else + mlen = offsets[index + 1] - mbegin - 1; + int obegin = other.offsets[index]; + int olen = 0; + if (index == (other.offsets.length - 1)) + olen = other.path.length - obegin; + else + olen = other.offsets[index + 1] - obegin - 1; + if (mlen != olen) + return false; + int n = 0; + while(n < mlen) { + if (path[mbegin + n] != other.path[obegin + n]) + return false; + n++; + } + return true; + } + + @Override + public Path relativize(Path other) { + final ZipPath o = checkPath(other); + if (o.equals(this)) + return new ZipPath(getFileSystem(), new byte[0], true); + if (/* this.getFileSystem() != o.getFileSystem() || */ + this.isAbsolute() != o.isAbsolute()) { + throw new IllegalArgumentException(); + } + int mc = this.getNameCount(); + int oc = o.getNameCount(); + int n = Math.min(mc, oc); + int i = 0; + while (i < n) { + if (!equalsNameAt(o, i)) + break; + i++; + } + int dotdots = mc - i; + int len = dotdots * 3 - 1; + if (i < oc) + len += (o.path.length - o.offsets[i] + 1); + byte[] result = new byte[len]; + + int pos = 0; + while (dotdots > 0) { + result[pos++] = (byte)'.'; + result[pos++] = (byte)'.'; + if (pos < len) // no tailing slash at the end + result[pos++] = (byte)'/'; + dotdots--; + } + if (i < oc) + System.arraycopy(o.path, o.offsets[i], + result, pos, + o.path.length - o.offsets[i]); + return new ZipPath(getFileSystem(), result); + } + + @Override + public ZipFileSystem getFileSystem() { + return zfs; + } + + @Override + public boolean isAbsolute() { + return (this.path.length > 0 && path[0] == '/'); + } + + @Override + public ZipPath resolve(Path other) { + final ZipPath o = checkPath(other); + if (o.isAbsolute()) + return o; + byte[] resolved = null; + if (this.path[path.length - 1] == '/') { + resolved = new byte[path.length + o.path.length]; + System.arraycopy(path, 0, resolved, 0, path.length); + System.arraycopy(o.path, 0, resolved, path.length, o.path.length); + } else { + resolved = new byte[path.length + 1 + o.path.length]; + System.arraycopy(path, 0, resolved, 0, path.length); + resolved[path.length] = '/'; + System.arraycopy(o.path, 0, resolved, path.length + 1, o.path.length); + } + return new ZipPath(zfs, resolved); + } + + @Override + public Path resolveSibling(Path other) { + if (other == null) + throw new NullPointerException(); + Path parent = getParent(); + return (parent == null) ? other : parent.resolve(other); + } + + @Override + public boolean startsWith(Path other) { + final ZipPath o = checkPath(other); + if (o.isAbsolute() != this.isAbsolute() || + o.path.length > this.path.length) + return false; + int olast = o.path.length; + for (int i = 0; i < olast; i++) { + if (o.path[i] != this.path[i]) + return false; + } + olast--; + return o.path.length == this.path.length || + o.path[olast] == '/' || + this.path[olast + 1] == '/'; + } + + @Override + public boolean endsWith(Path other) { + final ZipPath o = checkPath(other); + int olast = o.path.length - 1; + if (olast > 0 && o.path[olast] == '/') + olast--; + int last = this.path.length - 1; + if (last > 0 && this.path[last] == '/') + last--; + if (olast == -1) // o.path.length == 0 + return last == -1; + if ((o.isAbsolute() &&(!this.isAbsolute() || olast != last)) || + (last < olast)) + return false; + for (; olast >= 0; olast--, last--) { + if (o.path[olast] != this.path[last]) + return false; + } + return o.path[olast + 1] == '/' || + last == -1 || this.path[last] == '/'; + } + + @Override + public ZipPath resolve(String other) { + return resolve(getFileSystem().getPath(other)); + } + + @Override + public final Path resolveSibling(String other) { + return resolveSibling(getFileSystem().getPath(other)); + } + + @Override + public final boolean startsWith(String other) { + return startsWith(getFileSystem().getPath(other)); + } + + @Override + public final boolean endsWith(String other) { + return endsWith(getFileSystem().getPath(other)); + } + + @Override + public Path normalize() { + byte[] resolved = getResolved(); + if (resolved == path) // no change + return this; + return new ZipPath(zfs, resolved, true); + } + + private ZipPath checkPath(Path path) { + if (path == null) + throw new NullPointerException(); + if (!(path instanceof ZipPath)) + throw new ProviderMismatchException(); + return (ZipPath) path; + } + + // create offset list if not already created + private void initOffsets() { + if (offsets == null) { + int count, index; + // count names + count = 0; + index = 0; + while (index < path.length) { + byte c = path[index++]; + if (c != '/') { + count++; + while (index < path.length && path[index] != '/') + index++; + } + } + // populate offsets + int[] result = new int[count]; + count = 0; + index = 0; + while (index < path.length) { + byte c = path[index]; + if (c == '/') { + index++; + } else { + result[count++] = index++; + while (index < path.length && path[index] != '/') + index++; + } + } + synchronized (this) { + if (offsets == null) + offsets = result; + } + } + } + + // resolved path for locating zip entry inside the zip file, + // the result path does not contain ./ and .. components + private volatile byte[] resolved = null; + byte[] getResolvedPath() { + byte[] r = resolved; + if (r == null) { + if (isAbsolute()) + r = getResolved(); + else + r = toAbsolutePath().getResolvedPath(); + if (r[0] == '/') + r = Arrays.copyOfRange(r, 1, r.length); + resolved = r; + } + return resolved; + } + + // removes redundant slashs, replace "\" to zip separator "/" + // and check for invalid characters + private byte[] normalize(byte[] path) { + if (path.length == 0) + return path; + byte prevC = 0; + for (int i = 0; i < path.length; i++) { + byte c = path[i]; + if (c == '\\') + return normalize(path, i); + if (c == (byte)'/' && prevC == '/') + return normalize(path, i - 1); + if (c == '\u0000') + throw new InvalidPathException(zfs.getString(path), + "Path: nul character not allowed"); + prevC = c; + } + return path; + } + + private byte[] normalize(byte[] path, int off) { + byte[] to = new byte[path.length]; + int n = 0; + while (n < off) { + to[n] = path[n]; + n++; + } + int m = n; + byte prevC = 0; + while (n < path.length) { + byte c = path[n++]; + if (c == (byte)'\\') + c = (byte)'/'; + if (c == (byte)'/' && prevC == (byte)'/') + continue; + if (c == '\u0000') + throw new InvalidPathException(zfs.getString(path), + "Path: nul character not allowed"); + to[m++] = c; + prevC = c; + } + if (m > 1 && to[m - 1] == '/') + m--; + return (m == to.length)? to : Arrays.copyOf(to, m); + } + + // Remove DotSlash(./) and resolve DotDot (..) components + private byte[] getResolved() { + if (path.length == 0) + return path; + for (int i = 0; i < path.length; i++) { + byte c = path[i]; + if (c == (byte)'.') + return resolve0(); + } + return path; + } + + // TBD: performance, avoid initOffsets + private byte[] resolve0() { + byte[] to = new byte[path.length]; + int nc = getNameCount(); + int[] lastM = new int[nc]; + int lastMOff = -1; + int m = 0; + for (int i = 0; i < nc; i++) { + int n = offsets[i]; + int len = (i == offsets.length - 1)? + (path.length - n):(offsets[i + 1] - n - 1); + if (len == 1 && path[n] == (byte)'.') { + if (m == 0 && path[0] == '/') // absolute path + to[m++] = '/'; + continue; + } + if (len == 2 && path[n] == '.' && path[n + 1] == '.') { + if (lastMOff >= 0) { + m = lastM[lastMOff--]; // retreat + continue; + } + if (path[0] == '/') { // "/../xyz" skip + if (m == 0) + to[m++] = '/'; + } else { // "../xyz" -> "../xyz" + if (m != 0 && to[m-1] != '/') + to[m++] = '/'; + while (len-- > 0) + to[m++] = path[n++]; + } + continue; + } + if (m == 0 && path[0] == '/' || // absolute path + m != 0 && to[m-1] != '/') { // not the first name + to[m++] = '/'; + } + lastM[++lastMOff] = m; + while (len-- > 0) + to[m++] = path[n++]; + } + if (m > 1 && to[m - 1] == '/') + m--; + return (m == to.length)? to : Arrays.copyOf(to, m); + } + + @Override + public String toString() { + return zfs.getString(path); + } + + @Override + public int hashCode() { + int h = hashcode; + if (h == 0) + hashcode = h = Arrays.hashCode(path); + return h; + } + + @Override + public boolean equals(Object obj) { + return obj != null && + obj instanceof ZipPath && + this.zfs == ((ZipPath)obj).zfs && + compareTo((Path) obj) == 0; + } + + @Override + public int compareTo(Path other) { + final ZipPath o = checkPath(other); + int len1 = this.path.length; + int len2 = o.path.length; + + int n = Math.min(len1, len2); + byte v1[] = this.path; + byte v2[] = o.path; + + int k = 0; + while (k < n) { + int c1 = v1[k] & 0xff; + int c2 = v2[k] & 0xff; + if (c1 != c2) + return c1 - c2; + k++; + } + return len1 - len2; + } + + public WatchKey register( + WatchService watcher, + WatchEvent.Kind[] events, + WatchEvent.Modifier... modifiers) { + if (watcher == null || events == null || modifiers == null) { + throw new NullPointerException(); + } + throw new UnsupportedOperationException(); + } + + @Override + public WatchKey register(WatchService watcher, WatchEvent.Kind... events) { + return register(watcher, events, new WatchEvent.Modifier[0]); + } + + @Override + public final File toFile() { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator iterator() { + return new Iterator() { + private int i = 0; + + @Override + public boolean hasNext() { + return (i < getNameCount()); + } + + @Override + public Path next() { + if (i < getNameCount()) { + Path result = getName(i); + i++; + return result; + } else { + throw new NoSuchElementException(); + } + } + + @Override + public void remove() { + throw new ReadOnlyFileSystemException(); + } + }; + } + + ///////////////////////////////////////////////////////////////////// + + + void createDirectory(FileAttribute... attrs) + throws IOException + { + zfs.createDirectory(getResolvedPath(), attrs); + } + + InputStream newInputStream(OpenOption... options) throws IOException + { + if (options.length > 0) { + for (OpenOption opt : options) { + if (opt != READ) + throw new UnsupportedOperationException("'" + opt + "' not allowed"); + } + } + return zfs.newInputStream(getResolvedPath()); + } + + DirectoryStream newDirectoryStream(Filter filter) + throws IOException + { + return new ZipDirectoryStream(this, filter); + } + + void delete() throws IOException { + zfs.deleteFile(getResolvedPath(), true); + } + + void deleteIfExists() throws IOException { + zfs.deleteFile(getResolvedPath(), false); + } + + ZipFileAttributes getAttributes() throws IOException + { + ZipFileAttributes zfas = zfs.getFileAttributes(getResolvedPath()); + if (zfas == null) + throw new NoSuchFileException(toString()); + return zfas; + } + + void setAttribute(String attribute, Object value, LinkOption... options) + throws IOException + { + String type = null; + String attr = null; + int colonPos = attribute.indexOf(':'); + if (colonPos == -1) { + type = "basic"; + attr = attribute; + } else { + type = attribute.substring(0, colonPos++); + attr = attribute.substring(colonPos); + } + ZipFileAttributeView view = ZipFileAttributeView.get(this, type); + if (view == null) + throw new UnsupportedOperationException("view <" + view + "> is not supported"); + view.setAttribute(attr, value); + } + + void setTimes(FileTime mtime, FileTime atime, FileTime ctime) + throws IOException + { + zfs.setTimes(getResolvedPath(), mtime, atime, ctime); + } + + Map readAttributes(String attributes, LinkOption... options) + throws IOException + + { + String view = null; + String attrs = null; + int colonPos = attributes.indexOf(':'); + if (colonPos == -1) { + view = "basic"; + attrs = attributes; + } else { + view = attributes.substring(0, colonPos++); + attrs = attributes.substring(colonPos); + } + ZipFileAttributeView zfv = ZipFileAttributeView.get(this, view); + if (zfv == null) { + throw new UnsupportedOperationException("view not supported"); + } + return zfv.readAttributes(attrs); + } + + FileStore getFileStore() throws IOException { + // each ZipFileSystem only has one root (as requested for now) + if (exists()) + return zfs.getFileStore(this); + throw new NoSuchFileException(zfs.getString(path)); + } + + boolean isSameFile(Path other) throws IOException { + if (this.equals(other)) + return true; + if (other == null || + this.getFileSystem() != other.getFileSystem()) + return false; + this.checkAccess(); + ((ZipPath)other).checkAccess(); + return Arrays.equals(this.getResolvedPath(), + ((ZipPath)other).getResolvedPath()); + } + + SeekableByteChannel newByteChannel(Set options, + FileAttribute... attrs) + throws IOException + { + return zfs.newByteChannel(getResolvedPath(), options, attrs); + } + + + FileChannel newFileChannel(Set options, + FileAttribute... attrs) + throws IOException + { + return zfs.newFileChannel(getResolvedPath(), options, attrs); + } + + void checkAccess(AccessMode... modes) throws IOException { + boolean w = false; + boolean x = false; + for (AccessMode mode : modes) { + switch (mode) { + case READ: + break; + case WRITE: + w = true; + break; + case EXECUTE: + x = true; + break; + default: + throw new UnsupportedOperationException(); + } + } + ZipFileAttributes attrs = zfs.getFileAttributes(getResolvedPath()); + if (attrs == null && (path.length != 1 || path[0] != '/')) + throw new NoSuchFileException(toString()); + if (w) { + if (zfs.isReadOnly()) + throw new AccessDeniedException(toString()); + } + if (x) + throw new AccessDeniedException(toString()); + } + + boolean exists() { + if (path.length == 1 && path[0] == '/') + return true; + try { + return zfs.exists(getResolvedPath()); + } catch (IOException x) {} + return false; + } + + OutputStream newOutputStream(OpenOption... options) throws IOException + { + if (options.length == 0) + return zfs.newOutputStream(getResolvedPath(), + CREATE_NEW, WRITE); + return zfs.newOutputStream(getResolvedPath(), options); + } + + void move(ZipPath target, CopyOption... options) + throws IOException + { + if (Files.isSameFile(this.zfs.getZipFile(), target.zfs.getZipFile())) + { + zfs.copyFile(true, + getResolvedPath(), target.getResolvedPath(), + options); + } else { + copyToTarget(target, options); + delete(); + } + } + + void copy(ZipPath target, CopyOption... options) + throws IOException + { + if (Files.isSameFile(this.zfs.getZipFile(), target.zfs.getZipFile())) + zfs.copyFile(false, + getResolvedPath(), target.getResolvedPath(), + options); + else + copyToTarget(target, options); + } + + private void copyToTarget(ZipPath target, CopyOption... options) + throws IOException + { + boolean replaceExisting = false; + boolean copyAttrs = false; + for (CopyOption opt : options) { + if (opt == REPLACE_EXISTING) + replaceExisting = true; + else if (opt == COPY_ATTRIBUTES) + copyAttrs = true; + } + // attributes of source file + ZipFileAttributes zfas = getAttributes(); + // check if target exists + boolean exists; + if (replaceExisting) { + try { + target.deleteIfExists(); + exists = false; + } catch (DirectoryNotEmptyException x) { + exists = true; + } + } else { + exists = target.exists(); + } + if (exists) + throw new FileAlreadyExistsException(target.toString()); + + if (zfas.isDirectory()) { + // create directory or file + target.createDirectory(); + } else { + InputStream is = zfs.newInputStream(getResolvedPath()); + try { + OutputStream os = target.newOutputStream(); + try { + byte[] buf = new byte[8192]; + int n = 0; + while ((n = is.read(buf)) != -1) { + os.write(buf, 0, n); + } + } finally { + os.close(); + } + } finally { + is.close(); + } + } + if (copyAttrs) { + BasicFileAttributeView view = + ZipFileAttributeView.get(target, BasicFileAttributeView.class); + try { + view.setTimes(zfas.lastModifiedTime(), + zfas.lastAccessTime(), + zfas.creationTime()); + } catch (IOException x) { + // rollback? + try { + target.delete(); + } catch (IOException ignore) { } + throw x; + } + } + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/jdk/nio/zipfs/ZipUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/jdk/nio/zipfs/ZipUtils.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.nio.zipfs; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Date; +import java.util.regex.PatternSyntaxException; +import java.util.concurrent.TimeUnit; + +/** + * + * @author Xueming Shen + */ + +class ZipUtils { + + /* + * Writes a 16-bit short to the output stream in little-endian byte order. + */ + public static void writeShort(OutputStream os, int v) throws IOException { + os.write(v & 0xff); + os.write((v >>> 8) & 0xff); + } + + /* + * Writes a 32-bit int to the output stream in little-endian byte order. + */ + public static void writeInt(OutputStream os, long v) throws IOException { + os.write((int)(v & 0xff)); + os.write((int)((v >>> 8) & 0xff)); + os.write((int)((v >>> 16) & 0xff)); + os.write((int)((v >>> 24) & 0xff)); + } + + /* + * Writes a 64-bit int to the output stream in little-endian byte order. + */ + public static void writeLong(OutputStream os, long v) throws IOException { + os.write((int)(v & 0xff)); + os.write((int)((v >>> 8) & 0xff)); + os.write((int)((v >>> 16) & 0xff)); + os.write((int)((v >>> 24) & 0xff)); + os.write((int)((v >>> 32) & 0xff)); + os.write((int)((v >>> 40) & 0xff)); + os.write((int)((v >>> 48) & 0xff)); + os.write((int)((v >>> 56) & 0xff)); + } + + /* + * Writes an array of bytes to the output stream. + */ + public static void writeBytes(OutputStream os, byte[] b) + throws IOException + { + os.write(b, 0, b.length); + } + + /* + * Writes an array of bytes to the output stream. + */ + public static void writeBytes(OutputStream os, byte[] b, int off, int len) + throws IOException + { + os.write(b, off, len); + } + + /* + * Append a slash at the end, if it does not have one yet + */ + public static byte[] toDirectoryPath(byte[] dir) { + if (dir.length != 0 && dir[dir.length - 1] != '/') { + dir = Arrays.copyOf(dir, dir.length + 1); + dir[dir.length - 1] = '/'; + } + return dir; + } + + /* + * Converts DOS time to Java time (number of milliseconds since epoch). + */ + public static long dosToJavaTime(long dtime) { + Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80), + (int)(((dtime >> 21) & 0x0f) - 1), + (int)((dtime >> 16) & 0x1f), + (int)((dtime >> 11) & 0x1f), + (int)((dtime >> 5) & 0x3f), + (int)((dtime << 1) & 0x3e)); + return d.getTime(); + } + + /* + * Converts Java time to DOS time. + */ + public static long javaToDosTime(long time) { + Date d = new Date(time); + int year = d.getYear() + 1900; + if (year < 1980) { + return (1 << 21) | (1 << 16); + } + return (year - 1980) << 25 | (d.getMonth() + 1) << 21 | + d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 | + d.getSeconds() >> 1; + } + + + // used to adjust values between Windows and java epoch + private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L; + public static final long winToJavaTime(long wtime) { + return TimeUnit.MILLISECONDS.convert( + wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS, TimeUnit.MICROSECONDS); + } + + public static final long javaToWinTime(long time) { + return (TimeUnit.MICROSECONDS.convert(time, TimeUnit.MILLISECONDS) + - WINDOWS_EPOCH_IN_MICROSECONDS) * 10; + } + + public static final long unixToJavaTime(long utime) { + return TimeUnit.MILLISECONDS.convert(utime, TimeUnit.SECONDS); + } + + public static final long javaToUnixTime(long time) { + return TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS); + } + + private static final String regexMetaChars = ".^$+{[]|()"; + private static final String globMetaChars = "\\*?[{"; + private static boolean isRegexMeta(char c) { + return regexMetaChars.indexOf(c) != -1; + } + private static boolean isGlobMeta(char c) { + return globMetaChars.indexOf(c) != -1; + } + private static char EOL = 0; //TBD + private static char next(String glob, int i) { + if (i < glob.length()) { + return glob.charAt(i); + } + return EOL; + } + + /* + * Creates a regex pattern from the given glob expression. + * + * @throws PatternSyntaxException + */ + public static String toRegexPattern(String globPattern) { + boolean inGroup = false; + StringBuilder regex = new StringBuilder("^"); + + int i = 0; + while (i < globPattern.length()) { + char c = globPattern.charAt(i++); + switch (c) { + case '\\': + // escape special characters + if (i == globPattern.length()) { + throw new PatternSyntaxException("No character to escape", + globPattern, i - 1); + } + char next = globPattern.charAt(i++); + if (isGlobMeta(next) || isRegexMeta(next)) { + regex.append('\\'); + } + regex.append(next); + break; + case '/': + regex.append(c); + break; + case '[': + // don't match name separator in class + regex.append("[[^/]&&["); + if (next(globPattern, i) == '^') { + // escape the regex negation char if it appears + regex.append("\\^"); + i++; + } else { + // negation + if (next(globPattern, i) == '!') { + regex.append('^'); + i++; + } + // hyphen allowed at start + if (next(globPattern, i) == '-') { + regex.append('-'); + i++; + } + } + boolean hasRangeStart = false; + char last = 0; + while (i < globPattern.length()) { + c = globPattern.charAt(i++); + if (c == ']') { + break; + } + if (c == '/') { + throw new PatternSyntaxException("Explicit 'name separator' in class", + globPattern, i - 1); + } + // TBD: how to specify ']' in a class? + if (c == '\\' || c == '[' || + c == '&' && next(globPattern, i) == '&') { + // escape '\', '[' or "&&" for regex class + regex.append('\\'); + } + regex.append(c); + + if (c == '-') { + if (!hasRangeStart) { + throw new PatternSyntaxException("Invalid range", + globPattern, i - 1); + } + if ((c = next(globPattern, i++)) == EOL || c == ']') { + break; + } + if (c < last) { + throw new PatternSyntaxException("Invalid range", + globPattern, i - 3); + } + regex.append(c); + hasRangeStart = false; + } else { + hasRangeStart = true; + last = c; + } + } + if (c != ']') { + throw new PatternSyntaxException("Missing ']", globPattern, i - 1); + } + regex.append("]]"); + break; + case '{': + if (inGroup) { + throw new PatternSyntaxException("Cannot nest groups", + globPattern, i - 1); + } + regex.append("(?:(?:"); + inGroup = true; + break; + case '}': + if (inGroup) { + regex.append("))"); + inGroup = false; + } else { + regex.append('}'); + } + break; + case ',': + if (inGroup) { + regex.append(")|(?:"); + } else { + regex.append(','); + } + break; + case '*': + if (next(globPattern, i) == '*') { + // crosses directory boundaries + regex.append(".*"); + i++; + } else { + // within directory boundary + regex.append("[^/]*"); + } + break; + case '?': + regex.append("[^/]"); + break; + default: + if (isRegexMeta(c)) { + regex.append('\\'); + } + regex.append(c); + } + } + if (inGroup) { + throw new PatternSyntaxException("Missing '}", globPattern, i - 1); + } + return regex.append('$').toString(); + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/awt/AWTAutoShutdown.java --- a/jdk/src/share/classes/sun/awt/AWTAutoShutdown.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/awt/AWTAutoShutdown.java Wed Apr 16 10:53:10 2014 -0700 @@ -27,13 +27,15 @@ import java.awt.AWTEvent; -import java.util.Collections; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Map; import java.util.Set; import sun.util.logging.PlatformLogger; +import sun.misc.ThreadGroupUtils; /** * This class is to let AWT shutdown automatically when a user is done @@ -215,7 +217,10 @@ synchronized (activationLock) { synchronized (mainLock) { if (!isReadyToShutdown() && blockerThread == null) { - activateBlockerThread(); + AccessController.doPrivileged((PrivilegedAction) () -> { + activateBlockerThread(); + return null; + }); } else { mainLock.notifyAll(); timeoutPassed = false; @@ -331,9 +336,12 @@ /** * Creates and starts a new blocker thread. Doesn't return until * the new blocker thread starts. + * + * Must be called with {@link sun.security.util.SecurityConstants#MODIFY_THREADGROUP_PERMISSION} */ private void activateBlockerThread() { - Thread thread = new Thread(this, "AWT-Shutdown"); + Thread thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), this, "AWT-Shutdown"); + thread.setContextClassLoader(null); thread.setDaemon(false); blockerThread = thread; thread.start(); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/awt/SunToolkit.java --- a/jdk/src/share/classes/sun/awt/SunToolkit.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/awt/SunToolkit.java Wed Apr 16 10:53:10 2014 -0700 @@ -40,6 +40,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.security.PrivilegedAction; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/awt/datatransfer/ClipboardTransferable.java --- a/jdk/src/share/classes/sun/awt/datatransfer/ClipboardTransferable.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/awt/datatransfer/ClipboardTransferable.java Wed Apr 16 10:53:10 2014 -0700 @@ -85,7 +85,7 @@ // read it. Map cached_data = new HashMap<>(formats.length, 1.0f); DataTransferer.getInstance() - .getFlavorsForFormats(formats, SunClipboard.flavorMap) + .getFlavorsForFormats(formats, SunClipboard.getDefaultFlavorTable()) .entrySet() .forEach(entry -> fetchOneFlavor(clipboard, entry.getKey(), entry.getValue(), cached_data)); flavors = DataTransferer.setToSortedDataFlavorArray(flavorsToData.keySet()); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/awt/datatransfer/SunClipboard.java --- a/jdk/src/share/classes/sun/awt/datatransfer/SunClipboard.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/awt/datatransfer/SunClipboard.java Wed Apr 16 10:53:10 2014 -0700 @@ -63,9 +63,6 @@ public abstract class SunClipboard extends Clipboard implements PropertyChangeListener { - public static final FlavorTable flavorMap = - (FlavorTable)SystemFlavorMap.getDefaultFlavorMap(); - private AppContext contentsContext = null; private final Object CLIPBOARD_FLAVOR_LISTENER_KEY; @@ -167,7 +164,7 @@ long[] formats = getClipboardFormatsOpenClose(); return DataTransferer.getInstance(). - getFlavorsForFormatsAsArray(formats, flavorMap); + getFlavorsForFormatsAsArray(formats, getDefaultFlavorTable()); } /** @@ -213,7 +210,7 @@ long[] formats = getClipboardFormats(); Long lFormat = DataTransferer.getInstance(). - getFlavorsForFormats(formats, flavorMap).get(flavor); + getFlavorsForFormats(formats, getDefaultFlavorTable()).get(flavor); if (lFormat == null) { throw new UnsupportedFlavorException(flavor); @@ -344,7 +341,7 @@ private static Set formatArrayAsDataFlavorSet(long[] formats) { return (formats == null) ? null : DataTransferer.getInstance(). - getFlavorsForFormatsAsSet(formats, flavorMap); + getFlavorsForFormatsAsSet(formats, getDefaultFlavorTable()); } @@ -447,4 +444,8 @@ } } } + + public static FlavorTable getDefaultFlavorTable() { + return (FlavorTable) SystemFlavorMap.getDefaultFlavorMap(); + } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/font/CreatedFontTracker.java --- a/jdk/src/share/classes/sun/font/CreatedFontTracker.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/font/CreatedFontTracker.java Wed Apr 16 10:53:10 2014 -0700 @@ -27,12 +27,15 @@ import java.io.File; import java.io.OutputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import sun.awt.AppContext; +import sun.misc.ThreadGroupUtils; public class CreatedFontTracker { @@ -112,28 +115,18 @@ static void init() { if (t == null) { // Add a shutdown hook to remove the temp file. - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - /* The thread must be a member of a thread group - * which will not get GCed before VM exit. - * Make its parent the top-level thread group. - */ - ThreadGroup tg = - Thread.currentThread().getThreadGroup(); - for (ThreadGroup tgn = tg; - tgn != null; - tg = tgn, tgn = tg.getParent()); - t = new Thread(tg, new Runnable() { - public void run() { - runHooks(); - } - }); - t.setContextClassLoader(null); - Runtime.getRuntime().addShutdownHook(t); - return null; - } - }); + AccessController.doPrivileged( + (PrivilegedAction) () -> { + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + t = new Thread(rootTG, TempFileDeletionHook::runHooks); + t.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(t); + return null; + }); } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/font/SunFontManager.java --- a/jdk/src/share/classes/sun/font/SunFontManager.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/font/SunFontManager.java Wed Apr 16 10:53:10 2014 -0700 @@ -52,6 +52,7 @@ import sun.awt.AppContext; import sun.awt.FontConfiguration; import sun.awt.SunToolkit; +import sun.misc.ThreadGroupUtils; import sun.java2d.FontSupport; import sun.util.logging.PlatformLogger; @@ -2527,24 +2528,18 @@ }); } }; - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - /* The thread must be a member of a thread group - * which will not get GCed before VM exit. - * Make its parent the top-level thread group. - */ - ThreadGroup tg = - Thread.currentThread().getThreadGroup(); - for (ThreadGroup tgn = tg; - tgn != null; - tg = tgn, tgn = tg.getParent()); - fileCloser = new Thread(tg, fileCloserRunnable); - fileCloser.setContextClassLoader(null); - Runtime.getRuntime().addShutdownHook(fileCloser); - return null; - } - }); + AccessController.doPrivileged( + (PrivilegedAction) () -> { + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + fileCloser = new Thread(rootTG, fileCloserRunnable); + fileCloser.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(fileCloser); + return null; + }); } } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/java2d/Disposer.java --- a/jdk/src/share/classes/sun/java2d/Disposer.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/java2d/Disposer.java Wed Apr 16 10:53:10 2014 -0700 @@ -25,10 +25,14 @@ package sun.java2d; +import sun.misc.ThreadGroupUtils; + import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.PhantomReference; import java.lang.ref.WeakReference; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Hashtable; @@ -77,27 +81,21 @@ } } disposerInstance = new Disposer(); - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - /* The thread must be a member of a thread group - * which will not get GCed before VM exit. - * Make its parent the top-level thread group. - */ - ThreadGroup tg = Thread.currentThread().getThreadGroup(); - for (ThreadGroup tgn = tg; - tgn != null; - tg = tgn, tgn = tg.getParent()); - Thread t = - new Thread(tg, disposerInstance, "Java2D Disposer"); - t.setContextClassLoader(null); - t.setDaemon(true); - t.setPriority(Thread.MAX_PRIORITY); - t.start(); - return null; - } - } - ); + AccessController.doPrivileged( + (PrivilegedAction) () -> { + /* The thread must be a member of a thread group + * which will not get GCed before VM exit. + * Make its parent the top-level thread group. + */ + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + Thread t = new Thread(rootTG, disposerInstance, "Java2D Disposer"); + t.setContextClassLoader(null); + t.setDaemon(true); + t.setPriority(Thread.MAX_PRIORITY); + t.start(); + return null; + } + ); } /** diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/java2d/opengl/OGLRenderQueue.java --- a/jdk/src/share/classes/sun/java2d/opengl/OGLRenderQueue.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/java2d/opengl/OGLRenderQueue.java Wed Apr 16 10:53:10 2014 -0700 @@ -25,6 +25,7 @@ package sun.java2d.opengl; +import sun.misc.ThreadGroupUtils; import sun.java2d.pipe.RenderBuffer; import sun.java2d.pipe.RenderQueue; import static sun.java2d.pipe.BufferedOpCodes.*; @@ -47,14 +48,8 @@ * The thread must be a member of a thread group * which will not get GCed before VM exit. */ - flusher = AccessController.doPrivileged(new PrivilegedAction() { - public QueueFlusher run() { - ThreadGroup rootThreadGroup = Thread.currentThread().getThreadGroup(); - while (rootThreadGroup.getParent() != null) { - rootThreadGroup = rootThreadGroup.getParent(); - } - return new QueueFlusher(rootThreadGroup); - } + flusher = AccessController.doPrivileged((PrivilegedAction) () -> { + return new QueueFlusher(ThreadGroupUtils.getRootThreadGroup()); }); } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/misc/InnocuousThread.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/misc/InnocuousThread.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNUNSAFE General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUNSAFET + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICUNSAFELAR PUNSAFERPOSE. See the GNUNSAFE General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNUNSAFE General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 UNSAFESA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 UNSAFESA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.misc; + +import java.security.AccessControlContext; +import java.security.ProtectionDomain; + +/** + * A thread that has no permissions, is not a member of any user-defined + * ThreadGroup and supports the ability to erase ThreadLocals. + * + * @implNote Based on the implementation of InnocuousForkJoinWorkerThread. + */ +public final class InnocuousThread extends Thread { + private static final Unsafe UNSAFE; + private static final ThreadGroup THREADGROUP; + private static final AccessControlContext ACC; + private static final long THREADLOCALS; + private static final long INHERITABLETHREADLOCALS; + private static final long INHERITEDACCESSCONTROLCONTEXT; + + public InnocuousThread(Runnable target) { + super(THREADGROUP, target, "anInnocuousThread"); + UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC); + eraseThreadLocals(); + } + + @Override + public ClassLoader getContextClassLoader() { + // always report system class loader + return ClassLoader.getSystemClassLoader(); + } + + @Override + public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { + // silently fail + } + + @Override + public void setContextClassLoader(ClassLoader cl) { + throw new SecurityException("setContextClassLoader"); + } + + // ensure run method is run only once + private volatile boolean hasRun; + + @Override + public void run() { + if (Thread.currentThread() == this && !hasRun) { + hasRun = true; + super.run(); + } + } + + /** + * Drops all thread locals (and inherited thread locals). + */ + public void eraseThreadLocals() { + UNSAFE.putObject(this, THREADLOCALS, null); + UNSAFE.putObject(this, INHERITABLETHREADLOCALS, null); + } + + // Use Unsafe to access Thread group and ThreadGroup parent fields + static { + try { + ACC = new AccessControlContext(new ProtectionDomain[] { + new ProtectionDomain(null, null) + }); + + // Find and use topmost ThreadGroup as parent of new group + UNSAFE = Unsafe.getUnsafe(); + Class tk = Thread.class; + Class gk = ThreadGroup.class; + + THREADLOCALS = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocals")); + INHERITABLETHREADLOCALS = UNSAFE.objectFieldOffset + (tk.getDeclaredField("inheritableThreadLocals")); + INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset + (tk.getDeclaredField("inheritedAccessControlContext")); + + long tg = UNSAFE.objectFieldOffset(tk.getDeclaredField("group")); + long gp = UNSAFE.objectFieldOffset(gk.getDeclaredField("parent")); + ThreadGroup group = (ThreadGroup) + UNSAFE.getObject(Thread.currentThread(), tg); + + while (group != null) { + ThreadGroup parent = (ThreadGroup)UNSAFE.getObject(group, gp); + if (parent == null) + break; + group = parent; + } + THREADGROUP = new ThreadGroup(group, "InnocuousThreadGroup"); + } catch (Exception e) { + throw new Error(e); + } + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/misc/ThreadGroupUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/share/classes/sun/misc/ThreadGroupUtils.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.misc; + +/** + * A utility class needed to access the root {@code ThreadGroup} + * + * The class should not depend on any others, because it' called from JNI_OnLoad of the AWT + * native library. Triggering class loading could could lead to a deadlock. + */ +public final class ThreadGroupUtils { + + private ThreadGroupUtils() { + // Avoid instantiation + } + + /** + * Returns a root thread group. + * Should be called with {@link sun.security.util.SecurityConstants#MODIFY_THREADGROUP_PERMISSION} + * + * @return a root {@code ThreadGroup} + */ + public static ThreadGroup getRootThreadGroup() { + ThreadGroup currentTG = Thread.currentThread().getThreadGroup(); + ThreadGroup parentTG = currentTG.getParent(); + while (parentTG != null) { + currentTG = parentTG; + parentTG = currentTG.getParent(); + } + return currentTG; + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/net/www/MimeTable.java --- a/jdk/src/share/classes/sun/net/www/MimeTable.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/net/www/MimeTable.java Wed Apr 16 10:53:10 2014 -0700 @@ -225,39 +225,28 @@ public synchronized void load() { Properties entries = new Properties(); File file = null; - try { - InputStream is; - // First try to load the user-specific table, if it exists - String userTablePath = - System.getProperty("content.types.user.table"); - if (userTablePath != null) { - file = new File(userTablePath); - if (!file.exists()) { - // No user-table, try to load the default built-in table. - file = new File(System.getProperty("java.home") + - File.separator + - "lib" + - File.separator + - "content-types.properties"); - } + InputStream in; + + // First try to load the user-specific table, if it exists + String userTablePath = System.getProperty("content.types.user.table"); + if (userTablePath != null && (file = new File(userTablePath)).exists()) { + try { + in = new FileInputStream(file); + } catch (FileNotFoundException e) { + System.err.println("Warning: " + file.getPath() + + " mime table not found."); + return; } - else { - // No user table, try to load the default built-in table. - file = new File(System.getProperty("java.home") + - File.separator + - "lib" + - File.separator + - "content-types.properties"); - } + } else { + in = MimeTable.class.getResourceAsStream("content-types.properties"); + if (in == null) + throw new InternalError("default mime table not found"); + } - is = new BufferedInputStream(new FileInputStream(file)); - entries.load(is); - is.close(); - } - catch (IOException e) { - System.err.println("Warning: default mime table not found: " + - file.getPath()); - return; + try (BufferedInputStream bin = new BufferedInputStream(in)) { + entries.load(bin); + } catch (IOException e) { + System.err.println("Warning: " + e.getMessage()); } parse(entries); } @@ -380,18 +369,6 @@ return MimeEntry.UNKNOWN; } - public synchronized boolean save(String filename) { - if (filename == null) { - filename = System.getProperty("user.home" + - File.separator + - "lib" + - File.separator + - "content-types.properties"); - } - - return saveAsProperties(new File(filename)); - } - public Properties getAsProperties() { Properties properties = new Properties(); Enumeration e = elements(); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/nio/ch/Invoker.java --- a/jdk/src/share/classes/sun/nio/ch/Invoker.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/Invoker.java Wed Apr 16 10:53:10 2014 -0700 @@ -130,6 +130,18 @@ // clear interrupt Thread.interrupted(); + + // clear thread locals when in default thread pool + if (System.getSecurityManager() != null) { + Thread me = Thread.currentThread(); + if (me instanceof sun.misc.InnocuousThread) { + GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get(); + ((sun.misc.InnocuousThread)me).eraseThreadLocals(); + if (thisGroupAndInvokeCount != null) { + myGroupAndInvokeCount.set(thisGroupAndInvokeCount); + } + } + } } /** diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/nio/ch/ThreadPool.java --- a/jdk/src/share/classes/sun/nio/ch/ThreadPool.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/nio/ch/ThreadPool.java Wed Apr 16 10:53:10 2014 -0700 @@ -27,6 +27,7 @@ import java.util.concurrent.*; import java.security.AccessController; +import java.security.PrivilegedAction; import sun.security.action.GetPropertyAction; import sun.security.action.GetIntegerAction; @@ -39,14 +40,6 @@ "java.nio.channels.DefaultThreadPool.threadFactory"; private static final String DEFAULT_THREAD_POOL_INITIAL_SIZE = "java.nio.channels.DefaultThreadPool.initialSize"; - private static final ThreadFactory defaultThreadFactory = new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setDaemon(true); - return t; - } - }; private final ExecutorService executor; @@ -79,7 +72,22 @@ } static ThreadFactory defaultThreadFactory() { - return defaultThreadFactory; + if (System.getSecurityManager() == null) { + return (Runnable r) -> { + Thread t = new Thread(r); + t.setDaemon(true); + return t; + }; + } else { + return (Runnable r) -> { + PrivilegedAction action = () -> { + Thread t = new sun.misc.InnocuousThread(r); + t.setDaemon(true); + return t; + }; + return AccessController.doPrivileged(action); + }; + } } private static class DefaultThreadPoolHolder { @@ -100,7 +108,7 @@ // default to thread factory that creates daemon threads ThreadFactory threadFactory = getDefaultThreadPoolThreadFactory(); if (threadFactory == null) - threadFactory = defaultThreadFactory; + threadFactory = defaultThreadFactory(); // create thread pool ExecutorService executor = Executors.newCachedThreadPool(threadFactory); return new ThreadPool(executor, false, initialSize); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/security/provider/SeedGenerator.java --- a/jdk/src/share/classes/sun/security/provider/SeedGenerator.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/security/provider/SeedGenerator.java Wed Apr 16 10:53:10 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -179,8 +179,8 @@ md.update(p.getProperty(s).getBytes()); } - md.update - (InetAddress.getLocalHost().toString().getBytes()); + // Include network adapter names (and a Mac address) + addNetworkAdapterInfo(md); // The temporary dir File f = new File(p.getProperty("java.io.tmpdir")); @@ -221,6 +221,31 @@ return md.digest(); } + /* + * Include network adapter names and, if available, a Mac address + * + * See also java.util.concurrent.ThreadLocalRandom.initialSeed() + */ + private static void addNetworkAdapterInfo(MessageDigest md) { + + try { + Enumeration ifcs = + NetworkInterface.getNetworkInterfaces(); + while (ifcs.hasMoreElements()) { + NetworkInterface ifc = ifcs.nextElement(); + md.update(ifc.toString().getBytes()); + if (!ifc.isVirtual()) { // skip fake addresses + byte[] bs = ifc.getHardwareAddress(); + if (bs != null) { + md.update(bs); + break; + } + } + } + } catch (Exception ignore) { + } + } + /** * Helper function to convert a long into a byte array (least significant * byte first). diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java --- a/jdk/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java Wed Apr 16 10:53:10 2014 -0700 @@ -75,7 +75,7 @@ private PublicKey prevPubKey; private final static Set SIGNATURE_PRIMITIVE_SET = - EnumSet.of(CryptoPrimitive.SIGNATURE); + Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); private final static DisabledAlgorithmConstraints certPathDefaultConstraints = new DisabledAlgorithmConstraints( diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/security/rsa/RSAPadding.java --- a/jdk/src/share/classes/sun/security/rsa/RSAPadding.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/security/rsa/RSAPadding.java Wed Apr 16 10:53:10 2014 -0700 @@ -25,11 +25,9 @@ package sun.security.rsa; -import java.math.BigInteger; import java.util.*; import java.security.*; -import java.security.interfaces.*; import java.security.spec.*; import javax.crypto.BadPaddingException; @@ -41,21 +39,41 @@ /** * RSA padding and unpadding. * - * Format of PKCS#1 v1.5 padding is: + * The various PKCS#1 versions can be found in the EMC/RSA Labs + * web site, which is currently: + * + * http://www.emc.com/emc-plus/rsa-labs/index.htm + * + * or in the IETF RFCs derived from the above PKCS#1 standards. + * + * RFC 2313: v1.5 + * RFC 2437: v2.0 + * RFC 3447: v2.1 + * + * The format of PKCS#1 v1.5 padding is: + * * 0x00 | BT | PS...PS | 0x00 | data...data + * * where BT is the blocktype (1 or 2). The length of the entire string * must be the same as the size of the modulus (i.e. 128 byte for a 1024 bit * key). Per spec, the padding string must be at least 8 bytes long. That * leaves up to (length of key in bytes) - 11 bytes for the data. * - * OAEP padding is a bit more complicated and has a number of options. - * We support: + * OAEP padding was introduced in PKCS#1 v2.0 and is a bit more complicated + * and has a number of options. We support: + * * . arbitrary hash functions ('Hash' in the specification), MessageDigest * implementation must be available * . MGF1 as the mask generation function * . the empty string as the default value for label L and whatever * specified in javax.crypto.spec.OAEPParameterSpec * + * The algorithms (representations) are forwards-compatible: that is, + * the algorithm described in previous releases are in later releases. + * However, additional comments/checks/clarifications were added to the + * later versions based on real-world experience (e.g. stricter v1.5 + * format checking.) + * * Note: RSA keys should be at least 512 bits long * * @since 1.5 @@ -156,7 +174,8 @@ throw new InvalidAlgorithmParameterException ("Unsupported MGF algo: " + mgfName); } - mgfMdName = ((MGF1ParameterSpec)spec.getMGFParameters()).getDigestAlgorithm(); + mgfMdName = ((MGF1ParameterSpec)spec.getMGFParameters()) + .getDigestAlgorithm(); PSource pSrc = spec.getPSource(); String pSrcAlgo = pSrc.getAlgorithm(); if (!pSrcAlgo.equalsIgnoreCase("PSpecified")) { @@ -198,7 +217,7 @@ */ private static byte[] getInitialHash(MessageDigest md, byte[] digestInput) { - byte[] result = null; + byte[] result; if ((digestInput == null) || (digestInput.length == 0)) { String digestName = md.getAlgorithm(); result = emptyHashes.get(digestName); @@ -213,8 +232,8 @@ } /** - * Return the maximum size of the plaintext data that can be processed using - * this object. + * Return the maximum size of the plaintext data that can be processed + * using this object. */ public int getMaxDataSize() { return maxDataSize; @@ -262,7 +281,7 @@ */ public byte[] unpad(byte[] padded) throws BadPaddingException { if (padded.length != paddedSize) { - throw new BadPaddingException("Padded length must be " + paddedSize); + throw new BadPaddingException("Decryption error"); } switch (type) { case PAD_NONE: @@ -282,7 +301,8 @@ */ private byte[] padV15(byte[] data) throws BadPaddingException { byte[] padded = new byte[paddedSize]; - System.arraycopy(data, 0, padded, paddedSize - data.length, data.length); + System.arraycopy(data, 0, padded, paddedSize - data.length, + data.length); int psSize = paddedSize - 3 - data.length; int k = 0; padded[k++] = 0; @@ -317,55 +337,53 @@ } /** - * PKCS#1 v1.5 unpadding (blocktype 1 and 2). + * PKCS#1 v1.5 unpadding (blocktype 1 (signature) and 2 (encryption)). * * Note that we want to make it a constant-time operation */ private byte[] unpadV15(byte[] padded) throws BadPaddingException { int k = 0; - BadPaddingException bpe = null; + boolean bp = false; if (padded[k++] != 0) { - bpe = new BadPaddingException("Data must start with zero"); + bp = true; } - if (padded[k++] != type && bpe == null) { - bpe = new BadPaddingException("Blocktype mismatch: " + padded[1]); + if (padded[k++] != type) { + bp = true; } int p = 0; while (k < padded.length) { int b = padded[k++] & 0xff; - if (b == 0 && p == 0) { + if ((b == 0) && (p == 0)) { p = k; } - if (k == padded.length && p == 0 && bpe == null) { - bpe = new BadPaddingException("Padding string not terminated"); + if ((k == padded.length) && (p == 0)) { + bp = true; } if ((type == PAD_BLOCKTYPE_1) && (b != 0xff) && - p == 0 && bpe == null) { - bpe = new BadPaddingException("Padding byte not 0xff: " + b); + (p == 0)) { + bp = true; } } int n = padded.length - p; - if (n > maxDataSize && bpe == null) { - bpe = new BadPaddingException("Padding string too short"); + if (n > maxDataSize) { + bp = true; } // copy useless padding array for a constant-time method - // - // Is it necessary? byte[] padding = new byte[p]; System.arraycopy(padded, 0, padding, 0, p); byte[] data = new byte[n]; System.arraycopy(padded, p, data, 0, n); - if (bpe == null) { - bpe = new BadPaddingException("Unused exception"); - } else { + BadPaddingException bpe = new BadPaddingException("Decryption error"); + + if (bp) { throw bpe; + } else { + return data; } - - return data; } /** @@ -424,10 +442,11 @@ */ private byte[] unpadOAEP(byte[] padded) throws BadPaddingException { byte[] EM = padded; + boolean bp = false; int hLen = lHash.length; if (EM[0] != 0) { - throw new BadPaddingException("Data must start with zero"); + bp = true; } int seedStart = 1; @@ -442,29 +461,48 @@ // verify lHash == lHash' for (int i = 0; i < hLen; i++) { if (lHash[i] != EM[dbStart + i]) { - throw new BadPaddingException("lHash mismatch"); + bp = true; + } + } + + int padStart = dbStart + hLen; + int onePos = -1; + + for (int i = padStart; i < EM.length; i++) { + int value = EM[i]; + if (onePos == -1) { + if (value == 0x00) { + // continue; + } else if (value == 0x01) { + onePos = i; + } else { // Anything other than {0,1} is bad. + bp = true; + } } } - // skip over padding (0x00 bytes) - int i = dbStart + hLen; - while (EM[i] == 0) { - i++; - if (i >= EM.length) { - throw new BadPaddingException("Padding string not terminated"); - } + // We either ran off the rails or found something other than 0/1. + if (onePos == -1) { + bp = true; + onePos = EM.length - 1; // Don't inadvertently return any data. } - if (EM[i++] != 1) { - throw new BadPaddingException - ("Padding string not terminated by 0x01 byte"); - } + int mStart = onePos + 1; + + // copy useless padding array for a constant-time method + byte [] tmp = new byte[mStart - padStart]; + System.arraycopy(EM, padStart, tmp, 0, tmp.length); - int mLen = EM.length - i; - byte[] m = new byte[mLen]; - System.arraycopy(EM, i, m, 0, mLen); + byte [] m = new byte[EM.length - mStart]; + System.arraycopy(EM, mStart, m, 0, m.length); + + BadPaddingException bpe = new BadPaddingException("Decryption error"); - return m; + if (bp) { + throw bpe; + } else { + return m; + } } /** @@ -499,5 +537,4 @@ } } } - } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java --- a/jdk/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java Wed Apr 16 10:53:10 2014 -0700 @@ -68,7 +68,7 @@ // performance optimization private final static Set SIGNATURE_PRIMITIVE_SET = - EnumSet.of(CryptoPrimitive.SIGNATURE); + Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); // supported pairs of signature and hash algorithm private final static Map supportedMap; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/security/tools/jarsigner/Main.java --- a/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java Wed Apr 16 10:53:10 2014 -0700 @@ -90,9 +90,6 @@ private static final String META_INF = "META-INF/"; - // prefix for new signature-related files in META-INF directory - private static final String SIG_PREFIX = META_INF + "SIG-"; - private static final Class[] PARAM_STRING = { String.class }; private static final String NONE = "NONE"; @@ -1522,22 +1519,7 @@ * . META-INF/*.EC */ private boolean signatureRelated(String name) { - String ucName = name.toUpperCase(Locale.ENGLISH); - if (ucName.equals(JarFile.MANIFEST_NAME) || - ucName.equals(META_INF) || - (ucName.startsWith(SIG_PREFIX) && - ucName.indexOf("/") == ucName.lastIndexOf("/"))) { - return true; - } - - if (ucName.startsWith(META_INF) && - SignatureFileVerifier.isBlockOrSF(ucName)) { - // .SF/.DSA/.RSA/.EC files in META-INF subdirs - // are not considered signature-related - return (ucName.indexOf("/") == ucName.lastIndexOf("/")); - } - - return false; + return SignatureFileVerifier.isSigningRelated(name); } Map cacheForSignerInfo = new IdentityHashMap<>(); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java --- a/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java Wed Apr 16 10:53:10 2014 -0700 @@ -152,6 +152,52 @@ return false; } + /** + * Yet another utility method used by JarVerifier and JarSigner + * to determine what files are signature related, which includes + * the MANIFEST, SF files, known signature block files, and other + * unknown signature related files (those starting with SIG- with + * an optional [A-Z0-9]{1,3} extension right inside META-INF). + * + * @param s file name + * @return true if the input file name is signature related + */ + public static boolean isSigningRelated(String name) { + name = name.toUpperCase(Locale.ENGLISH); + if (!name.startsWith("META-INF/")) { + return false; + } + name = name.substring(9); + if (name.indexOf('/') != -1) { + return false; + } + if (isBlockOrSF(name) || name.equals("MANIFEST.MF")) { + return true; + } else if (name.startsWith("SIG-")) { + // check filename extension + // see http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Digital_Signatures + // for what filename extensions are legal + int extIndex = name.lastIndexOf('.'); + if (extIndex != -1) { + String ext = name.substring(extIndex + 1); + // validate length first + if (ext.length() > 3 || ext.length() < 1) { + return false; + } + // then check chars, must be in [a-zA-Z0-9] per the jar spec + for (int index = 0; index < ext.length(); index++) { + char cc = ext.charAt(index); + // chars are promoted to uppercase so skip lowercase checks + if ((cc < 'A' || cc > 'Z') && (cc < '0' || cc > '9')) { + return false; + } + } + } + return true; // no extension is OK + } + return false; + } + /** get digest from cache */ private MessageDigest getDigest(String algorithm) diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/Demo.java --- a/jdk/src/share/demo/nio/zipfs/Demo.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,709 +0,0 @@ -/* - * Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.nio.file.*; -import java.nio.file.spi.*; -import java.nio.file.attribute.*; -import java.net.*; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; - -import static java.nio.file.StandardOpenOption.*; -import static java.nio.file.StandardCopyOption.*; -/* - * ZipFileSystem usage demo - * - * java Demo action ZipfileName [...] - * - * @author Xueming Shen - */ - -public class Demo { - - static enum Action { - rename, // - // rename entry src to dst inside zipfile - - movein, // - // move an external src file into zipfile - // as entry dst - - moveout, // - // move a zipfile entry src out to dst - - copy, // - // copy entry src to dst inside zipfile - - copyin, // - // copy an external src file into zipfile - // as entry dst - - copyin_attrs, // - // copy an external src file into zipfile - // as entry dst, with attributes (timestamp) - - copyout, // - // copy zipfile entry src" out to file dst - - copyout_attrs, // - - zzmove, // - // move entry path/dir from zfsrc to zfdst - - zzcopy, // - // copy path from zipfile zfsrc to zipfile - // zfdst - - attrs, // - // printout the attributes of entry path - - attrsspace, // - // printout the storespace attrs of entry path - - setmtime, // - // set the lastModifiedTime of entry path - - setatime, // - setctime, // - - lsdir, // - // list dir's direct child files/dirs - - mkdir, // - - mkdirs, // - - rmdirs, // - - list, // - // recursively list all entries of dir - // via DirectoryStream - - tlist, // - // list with buildDirTree=true - - vlist, // - // recursively verbose list all entries of - // dir via DirectoryStream - - walk, // - // recursively walk all entries of dir - // via Files.walkFileTree - - twalk, // - // walk with buildDirTree=true - - extract, // - - update, // - - delete, // - - add, // - - create, // - // create a new zipfile if it doesn't exit - // and then add the file(s) into it. - - attrs2, // - // test different ways to print attrs - - prof, - } - - public static void main(String[] args) throws Throwable { - FileSystemProvider provider = getZipFSProvider(); - if (provider == null) { - System.err.println("ZIP filesystem provider is not installed"); - System.exit(1); - } - - Action action = Action.valueOf(args[0]); - Map env = env = new HashMap<>(); - if (action == Action.create) - env.put("create", "true"); - try (FileSystem fs = provider.newFileSystem(Paths.get(args[1]), env)) { - Path path, src, dst; - switch (action) { - case rename: - src = fs.getPath(args[2]); - dst = fs.getPath(args[3]); - Files.move(src, dst); - break; - case moveout: - src = fs.getPath(args[2]); - dst = Paths.get(args[3]); - Files.move(src, dst); - break; - case movein: - src = Paths.get(args[2]); - dst = fs.getPath(args[3]); - Files.move(src, dst); - break; - case copy: - src = fs.getPath(args[2]); - dst = fs.getPath(args[3]); - Files.copy(src, dst); - break; - case copyout: - src = fs.getPath(args[2]); - dst = Paths.get(args[3]); - Files.copy(src, dst); - break; - case copyin: - src = Paths.get(args[2]); - dst = fs.getPath(args[3]); - Files.copy(src, dst); - break; - case copyin_attrs: - src = Paths.get(args[2]); - dst = fs.getPath(args[3]); - Files.copy(src, dst, COPY_ATTRIBUTES); - break; - case copyout_attrs: - src = fs.getPath(args[2]); - dst = Paths.get(args[3]); - Files.copy(src, dst, COPY_ATTRIBUTES); - break; - case zzmove: - try (FileSystem fs2 = provider.newFileSystem(Paths.get(args[2]), env)) { - z2zmove(fs, fs2, args[3]); - } - break; - case zzcopy: - try (FileSystem fs2 = provider.newFileSystem(Paths.get(args[2]), env)) { - z2zcopy(fs, fs2, args[3]); - } - break; - case attrs: - for (int i = 2; i < args.length; i++) { - path = fs.getPath(args[i]); - System.out.println(path); - System.out.println( - Files.readAttributes(path, BasicFileAttributes.class).toString()); - } - break; - case setmtime: - DateFormat df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); - Date newDatetime = df.parse(args[2]); - for (int i = 3; i < args.length; i++) { - path = fs.getPath(args[i]); - Files.setAttribute(path, "lastModifiedTime", - FileTime.fromMillis(newDatetime.getTime())); - System.out.println( - Files.readAttributes(path, BasicFileAttributes.class).toString()); - } - break; - case setctime: - df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); - newDatetime = df.parse(args[2]); - for (int i = 3; i < args.length; i++) { - path = fs.getPath(args[i]); - Files.setAttribute(path, "creationTime", - FileTime.fromMillis(newDatetime.getTime())); - System.out.println( - Files.readAttributes(path, BasicFileAttributes.class).toString()); - } - break; - case setatime: - df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); - newDatetime = df.parse(args[2]); - for (int i = 3; i < args.length; i++) { - path = fs.getPath(args[i]); - Files.setAttribute(path, "lastAccessTime", - FileTime.fromMillis(newDatetime.getTime())); - System.out.println( - Files.readAttributes(path, BasicFileAttributes.class).toString()); - } - break; - case attrsspace: - path = fs.getPath("/"); - FileStore fstore = Files.getFileStore(path); - System.out.printf("filestore[%s]%n", fstore.name()); - System.out.printf(" totalSpace: %d%n", - (Long)fstore.getAttribute("totalSpace")); - System.out.printf(" usableSpace: %d%n", - (Long)fstore.getAttribute("usableSpace")); - System.out.printf(" unallocSpace: %d%n", - (Long)fstore.getAttribute("unallocatedSpace")); - break; - case list: - case tlist: - if (args.length < 3) - list(fs.getPath("/"), false); - else - list(fs.getPath(args[2]), false); - break; - case vlist: - if (args.length < 3) - list(fs.getPath("/"), true); - else - list(fs.getPath(args[2]), true); - break; - case twalk: - case walk: - walk(fs.getPath((args.length > 2)? args[2] : "/")); - break; - case extract: - if (args.length == 2) { - extract(fs, "/"); - } else { - for (int i = 2; i < args.length; i++) { - extract(fs, args[i]); - } - } - break; - case delete: - for (int i = 2; i < args.length; i++) - Files.delete(fs.getPath(args[i])); - break; - case create: - case add: - case update: - for (int i = 2; i < args.length; i++) { - update(fs, args[i]); - } - break; - case lsdir: - path = fs.getPath(args[2]); - final String fStr = (args.length > 3)?args[3]:""; - try (DirectoryStream ds = Files.newDirectoryStream(path, - new DirectoryStream.Filter() { - @Override - public boolean accept(Path path) { - return path.toString().contains(fStr); - } - })) - { - for (Path p : ds) - System.out.println(p); - } - break; - case mkdir: - Files.createDirectory(fs.getPath(args[2])); - break; - case mkdirs: - mkdirs(fs.getPath(args[2])); - break; - case attrs2: - for (int i = 2; i < args.length; i++) { - path = fs.getPath(args[i]); - System.out.printf("%n%s%n", path); - System.out.println("-------(1)---------"); - System.out.println( - Files.readAttributes(path, BasicFileAttributes.class).toString()); - System.out.println("-------(2)---------"); - Map map = Files.readAttributes(path, "zip:*"); - for (Map.Entry e : map.entrySet()) { - System.out.printf(" %s : %s%n", e.getKey(), e.getValue()); - } - System.out.println("-------(3)---------"); - map = Files.readAttributes(path, "size,lastModifiedTime,isDirectory"); - for (Map.Entry e : map.entrySet()) { - System.out.printf(" %s : %s%n", e.getKey(), e.getValue()); - } - } - break; - case prof: - list(fs.getPath("/"), false); - while (true) { - Thread.sleep(10000); - //list(fs.getPath("/"), true); - System.out.println("sleeping..."); - } - } - } catch (Exception x) { - x.printStackTrace(); - } - } - - private static FileSystemProvider getZipFSProvider() { - for (FileSystemProvider provider : FileSystemProvider.installedProviders()) { - if ("jar".equals(provider.getScheme())) - return provider; - } - return null; - } - - @SuppressWarnings("unused") - /** - * Not used in demo, but included for demonstrational purposes. - */ - private static byte[] getBytes(String name) { - return name.getBytes(); - } - - @SuppressWarnings("unused") - /** - * Not used in demo, but included for demonstrational purposes. - */ - private static String getString(byte[] name) { - return new String(name); - } - - private static void walk(Path path) throws IOException - { - Files.walkFileTree( - path, - new SimpleFileVisitor() { - private int indent = 0; - private void indent() { - int n = 0; - while (n++ < indent) - System.out.printf(" "); - } - - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attrs) - { - indent(); - System.out.printf("%s%n", file.getFileName().toString()); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attrs) - { - indent(); - System.out.printf("[%s]%n", dir.toString()); - indent += 2; - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, - IOException ioe) - { - indent -= 2; - return FileVisitResult.CONTINUE; - } - }); - } - - private static void update(FileSystem fs, String path) throws Throwable{ - Path src = FileSystems.getDefault().getPath(path); - if (Files.isDirectory(src)) { - try (DirectoryStream ds = Files.newDirectoryStream(src)) { - for (Path child : ds) - update(fs, child.toString()); - } - } else { - Path dst = fs.getPath(path); - Path parent = dst.getParent(); - if (parent != null && Files.notExists(parent)) - mkdirs(parent); - Files.copy(src, dst, REPLACE_EXISTING); - } - } - - private static void extract(FileSystem fs, String path) throws Throwable{ - Path src = fs.getPath(path); - if (Files.isDirectory(src)) { - try (DirectoryStream ds = Files.newDirectoryStream(src)) { - for (Path child : ds) - extract(fs, child.toString()); - } - } else { - if (path.startsWith("/")) - path = path.substring(1); - Path dst = FileSystems.getDefault().getPath(path); - Path parent = dst.getParent(); - if (Files.notExists(parent)) - mkdirs(parent); - Files.copy(src, dst, REPLACE_EXISTING); - } - } - - // use DirectoryStream - private static void z2zcopy(FileSystem src, FileSystem dst, String path) - throws IOException - { - Path srcPath = src.getPath(path); - Path dstPath = dst.getPath(path); - - if (Files.isDirectory(srcPath)) { - if (!Files.exists(dstPath)) { - try { - mkdirs(dstPath); - } catch (FileAlreadyExistsException x) {} - } - try (DirectoryStream ds = Files.newDirectoryStream(srcPath)) { - for (Path child : ds) { - z2zcopy(src, dst, - path + (path.endsWith("/")?"":"/") + child.getFileName()); - } - } - } else { - //System.out.println("copying..." + path); - Files.copy(srcPath, dstPath); - } - } - - // use TreeWalk to move - private static void z2zmove(FileSystem src, FileSystem dst, String path) - throws IOException - { - final Path srcPath = src.getPath(path).toAbsolutePath(); - final Path dstPath = dst.getPath(path).toAbsolutePath(); - - Files.walkFileTree(srcPath, new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attrs) - { - Path dst = srcPath.relativize(file); - dst = dstPath.resolve(dst); - try { - Path parent = dstPath.getParent(); - if (parent != null && Files.notExists(parent)) - mkdirs(parent); - Files.move(file, dst); - } catch (IOException x) { - x.printStackTrace(); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attrs) - { - Path dst = srcPath.relativize(dir); - dst = dstPath.resolve(dst); - try { - - if (Files.notExists(dst)) - mkdirs(dst); - } catch (IOException x) { - x.printStackTrace(); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, - IOException ioe) - throws IOException - { - try { - Files.delete(dir); - } catch (IOException x) { - //x.printStackTrace(); - } - return FileVisitResult.CONTINUE; - } - }); - - } - - private static void mkdirs(Path path) throws IOException { - path = path.toAbsolutePath(); - Path parent = path.getParent(); - if (parent != null) { - if (Files.notExists(parent)) - mkdirs(parent); - } - Files.createDirectory(path); - } - - @SuppressWarnings("unused") - /** - * Not used in demo, but included for demonstrational purposes. - */ - private static void rmdirs(Path path) throws IOException { - while (path != null && path.getNameCount() != 0) { - Files.delete(path); - path = path.getParent(); - } - } - - private static void list(Path path, boolean verbose ) throws IOException { - if (!"/".equals(path.toString())) { - System.out.printf(" %s%n", path.toString()); - if (verbose) - System.out.println(Files.readAttributes(path, BasicFileAttributes.class).toString()); - } - if (Files.notExists(path)) - return; - if (Files.isDirectory(path)) { - try (DirectoryStream ds = Files.newDirectoryStream(path)) { - for (Path child : ds) - list(child, verbose); - } - } - } - - @SuppressWarnings("unused") - /** - * Checks that the content of two paths are equal. - * Not used in demo, but included for demonstrational purposes. - */ - private static void checkEqual(Path src, Path dst) throws IOException - { - //System.out.printf("checking <%s> vs <%s>...%n", - // src.toString(), dst.toString()); - - //streams - byte[] bufSrc = new byte[8192]; - byte[] bufDst = new byte[8192]; - try (InputStream isSrc = Files.newInputStream(src); - InputStream isDst = Files.newInputStream(dst)) - { - int nSrc = 0; - while ((nSrc = isSrc.read(bufSrc)) != -1) { - int nDst = 0; - while (nDst < nSrc) { - int n = isDst.read(bufDst, nDst, nSrc - nDst); - if (n == -1) { - System.out.printf("checking <%s> vs <%s>...%n", - src.toString(), dst.toString()); - throw new RuntimeException("CHECK FAILED!"); - } - nDst += n; - } - while (--nSrc >= 0) { - if (bufSrc[nSrc] != bufDst[nSrc]) { - System.out.printf("checking <%s> vs <%s>...%n", - src.toString(), dst.toString()); - throw new RuntimeException("CHECK FAILED!"); - } - nSrc--; - } - } - } - - // channels - - try (SeekableByteChannel chSrc = Files.newByteChannel(src); - SeekableByteChannel chDst = Files.newByteChannel(dst)) - { - if (chSrc.size() != chDst.size()) { - System.out.printf("src[%s].size=%d, dst[%s].size=%d%n", - chSrc.toString(), chSrc.size(), - chDst.toString(), chDst.size()); - throw new RuntimeException("CHECK FAILED!"); - } - ByteBuffer bbSrc = ByteBuffer.allocate(8192); - ByteBuffer bbDst = ByteBuffer.allocate(8192); - - int nSrc = 0; - while ((nSrc = chSrc.read(bbSrc)) != -1) { - int nDst = chDst.read(bbDst); - if (nSrc != nDst) { - System.out.printf("checking <%s> vs <%s>...%n", - src.toString(), dst.toString()); - throw new RuntimeException("CHECK FAILED!"); - } - while (--nSrc >= 0) { - if (bbSrc.get(nSrc) != bbDst.get(nSrc)) { - System.out.printf("checking <%s> vs <%s>...%n", - src.toString(), dst.toString()); - throw new RuntimeException("CHECK FAILED!"); - } - nSrc--; - } - bbSrc.flip(); - bbDst.flip(); - } - } catch (IOException x) { - x.printStackTrace(); - } - } - - private static void fchCopy(Path src, Path dst) throws IOException - { - Set read = new HashSet<>(); - read.add(READ); - Set openwrite = new HashSet<>(); - openwrite.add(CREATE_NEW); - openwrite.add(WRITE); - - try (FileChannel srcFc = src.getFileSystem().provider().newFileChannel(src, read); - FileChannel dstFc = dst.getFileSystem().provider().newFileChannel(dst, openwrite)) - { - ByteBuffer bb = ByteBuffer.allocate(8192); - while (srcFc.read(bb) >= 0) { - bb.flip(); - dstFc.write(bb); - bb.clear(); - } - } - } - - private static void chCopy(Path src, Path dst) throws IOException - { - Set read = new HashSet<>(); - read.add(READ); - Set openwrite = new HashSet<>(); - openwrite.add(CREATE_NEW); - openwrite.add(WRITE); - - try (SeekableByteChannel srcCh = Files.newByteChannel(src, read); - SeekableByteChannel dstCh = Files.newByteChannel(dst, openwrite)) - { - ByteBuffer bb = ByteBuffer.allocate(8192); - while (srcCh.read(bb) >= 0) { - bb.flip(); - dstCh.write(bb); - bb.clear(); - } - } - } - - private static void streamCopy(Path src, Path dst) throws IOException - { - byte[] buf = new byte[8192]; - try (InputStream isSrc = Files.newInputStream(src); - OutputStream osDst = Files.newOutputStream(dst)) - { - int n = 0; - while ((n = isSrc.read(buf)) != -1) { - osDst.write(buf, 0, n); - } - } - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/README.txt --- a/jdk/src/share/demo/nio/zipfs/README.txt Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -ZipFileSystem is a file system provider that treats the contents of a zip or -JAR file as a java.nio.file.FileSystem. - -The factory methods defined by the java.nio.file.FileSystems class can be -used to create a FileSystem, eg: - - // use file type detection - Path jarfile = Paths.get("foo.jar"); - FileSystem fs = FileSystems.newFileSystem(jarfile, null); - --or - - // locate file system by the legacy JAR URL syntax - Map env = Collections.emptyMap(); - URI uri = URI.create("jar:file:/mydir/foo.jar"); - FileSystem fs = FileSystems.newFileSystem(uri, env); - -Once a FileSystem is created then classes in the java.nio.file package -can be used to access files in the zip/JAR file, eg: - - Path mf = fs.getPath("/META-INF/MANIFEST.MF"); - InputStream in = mf.newInputStream(); - -See Demo.java for more interesting usages. - - diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/META-INF/services/java.nio.file.spi.FileSystemProvider --- a/jdk/src/share/demo/nio/zipfs/src/META-INF/services/java.nio.file.spi.FileSystemProvider Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -com.sun.nio.zipfs.ZipFileSystemProvider - diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/JarFileSystemProvider.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/JarFileSystemProvider.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - -package com.sun.nio.zipfs; - -import java.nio.file.*; -import java.nio.file.spi.*; -import java.nio.file.attribute.*; -import java.nio.file.spi.FileSystemProvider; - -import java.net.URI; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.channels.FileChannel; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -public class JarFileSystemProvider extends ZipFileSystemProvider -{ - - @Override - public String getScheme() { - return "jar"; - } - - @Override - protected Path uriToPath(URI uri) { - String scheme = uri.getScheme(); - if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) { - throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'"); - } - try { - String uristr = uri.toString(); - int end = uristr.indexOf("!/"); - uristr = uristr.substring(4, (end == -1) ? uristr.length() : end); - uri = new URI(uristr); - return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null)) - .toAbsolutePath(); - } catch (URISyntaxException e) { - throw new AssertionError(e); //never thrown - } - } - - @Override - public Path getPath(URI uri) { - FileSystem fs = getFileSystem(uri); - String path = uri.getFragment(); - if (path == null) { - String uristr = uri.toString(); - int off = uristr.indexOf("!/"); - if (off != -1) - path = uristr.substring(off + 2); - } - if (path != null) - return fs.getPath(path); - throw new IllegalArgumentException("URI: " - + uri - + " does not contain path fragment ex. jar:///c:/foo.zip!/BAR"); - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipCoder.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipCoder.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.nio.zipfs; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.util.Arrays; - -/** - * Utility class for zipfile name and comment decoding and encoding - * - * @author Xueming Shen - */ - -final class ZipCoder { - - String toString(byte[] ba, int length) { - CharsetDecoder cd = decoder().reset(); - int len = (int)(length * cd.maxCharsPerByte()); - char[] ca = new char[len]; - if (len == 0) - return new String(ca); - ByteBuffer bb = ByteBuffer.wrap(ba, 0, length); - CharBuffer cb = CharBuffer.wrap(ca); - CoderResult cr = cd.decode(bb, cb, true); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - cr = cd.flush(cb); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - return new String(ca, 0, cb.position()); - } - - String toString(byte[] ba) { - return toString(ba, ba.length); - } - - byte[] getBytes(String s) { - CharsetEncoder ce = encoder().reset(); - char[] ca = s.toCharArray(); - int len = (int)(ca.length * ce.maxBytesPerChar()); - byte[] ba = new byte[len]; - if (len == 0) - return ba; - ByteBuffer bb = ByteBuffer.wrap(ba); - CharBuffer cb = CharBuffer.wrap(ca); - CoderResult cr = ce.encode(cb, bb, true); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - cr = ce.flush(bb); - if (!cr.isUnderflow()) - throw new IllegalArgumentException(cr.toString()); - if (bb.position() == ba.length) // defensive copy? - return ba; - else - return Arrays.copyOf(ba, bb.position()); - } - - // assume invoked only if "this" is not utf8 - byte[] getBytesUTF8(String s) { - if (isutf8) - return getBytes(s); - if (utf8 == null) - utf8 = new ZipCoder(Charset.forName("UTF-8")); - return utf8.getBytes(s); - } - - String toStringUTF8(byte[] ba, int len) { - if (isutf8) - return toString(ba, len); - if (utf8 == null) - utf8 = new ZipCoder(Charset.forName("UTF-8")); - return utf8.toString(ba, len); - } - - boolean isUTF8() { - return isutf8; - } - - private Charset cs; - private boolean isutf8; - private ZipCoder utf8; - - private ZipCoder(Charset cs) { - this.cs = cs; - this.isutf8 = cs.name().equals("UTF-8"); - } - - static ZipCoder get(Charset charset) { - return new ZipCoder(charset); - } - - static ZipCoder get(String csn) { - try { - return new ZipCoder(Charset.forName(csn)); - } catch (Throwable t) { - t.printStackTrace(); - } - return new ZipCoder(Charset.defaultCharset()); - } - - private final ThreadLocal decTL = new ThreadLocal<>(); - private final ThreadLocal encTL = new ThreadLocal<>(); - - private CharsetDecoder decoder() { - CharsetDecoder dec = decTL.get(); - if (dec == null) { - dec = cs.newDecoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT); - decTL.set(dec); - } - return dec; - } - - private CharsetEncoder encoder() { - CharsetEncoder enc = encTL.get(); - if (enc == null) { - enc = cs.newEncoder() - .onMalformedInput(CodingErrorAction.REPORT) - .onUnmappableCharacter(CodingErrorAction.REPORT); - encTL.set(enc); - } - return enc; - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipConstants.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipConstants.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.nio.zipfs; - - -/** - * - * @author Xueming Shen - */ - -class ZipConstants { - /* - * Compression methods - */ - static final int METHOD_STORED = 0; - static final int METHOD_DEFLATED = 8; - static final int METHOD_DEFLATED64 = 9; - static final int METHOD_BZIP2 = 12; - static final int METHOD_LZMA = 14; - static final int METHOD_LZ77 = 19; - static final int METHOD_AES = 99; - - /* - * General purpose big flag - */ - static final int FLAG_ENCRYPTED = 0x01; - static final int FLAG_DATADESCR = 0x08; // crc, size and csize in dd - static final int FLAG_EFS = 0x800; // If this bit is set the filename and - // comment fields for this file must be - // encoded using UTF-8. - /* - * Header signatures - */ - static long LOCSIG = 0x04034b50L; // "PK\003\004" - static long EXTSIG = 0x08074b50L; // "PK\007\008" - static long CENSIG = 0x02014b50L; // "PK\001\002" - static long ENDSIG = 0x06054b50L; // "PK\005\006" - - /* - * Header sizes in bytes (including signatures) - */ - static final int LOCHDR = 30; // LOC header size - static final int EXTHDR = 16; // EXT header size - static final int CENHDR = 46; // CEN header size - static final int ENDHDR = 22; // END header size - - /* - * Local file (LOC) header field offsets - */ - static final int LOCVER = 4; // version needed to extract - static final int LOCFLG = 6; // general purpose bit flag - static final int LOCHOW = 8; // compression method - static final int LOCTIM = 10; // modification time - static final int LOCCRC = 14; // uncompressed file crc-32 value - static final int LOCSIZ = 18; // compressed size - static final int LOCLEN = 22; // uncompressed size - static final int LOCNAM = 26; // filename length - static final int LOCEXT = 28; // extra field length - - /* - * Extra local (EXT) header field offsets - */ - static final int EXTCRC = 4; // uncompressed file crc-32 value - static final int EXTSIZ = 8; // compressed size - static final int EXTLEN = 12; // uncompressed size - - /* - * Central directory (CEN) header field offsets - */ - static final int CENVEM = 4; // version made by - static final int CENVER = 6; // version needed to extract - static final int CENFLG = 8; // encrypt, decrypt flags - static final int CENHOW = 10; // compression method - static final int CENTIM = 12; // modification time - static final int CENCRC = 16; // uncompressed file crc-32 value - static final int CENSIZ = 20; // compressed size - static final int CENLEN = 24; // uncompressed size - static final int CENNAM = 28; // filename length - static final int CENEXT = 30; // extra field length - static final int CENCOM = 32; // comment length - static final int CENDSK = 34; // disk number start - static final int CENATT = 36; // internal file attributes - static final int CENATX = 38; // external file attributes - static final int CENOFF = 42; // LOC header offset - - /* - * End of central directory (END) header field offsets - */ - static final int ENDSUB = 8; // number of entries on this disk - static final int ENDTOT = 10; // total number of entries - static final int ENDSIZ = 12; // central directory size in bytes - static final int ENDOFF = 16; // offset of first CEN header - static final int ENDCOM = 20; // zip file comment length - - /* - * ZIP64 constants - */ - static final long ZIP64_ENDSIG = 0x06064b50L; // "PK\006\006" - static final long ZIP64_LOCSIG = 0x07064b50L; // "PK\006\007" - static final int ZIP64_ENDHDR = 56; // ZIP64 end header size - static final int ZIP64_LOCHDR = 20; // ZIP64 end loc header size - static final int ZIP64_EXTHDR = 24; // EXT header size - static final int ZIP64_EXTID = 0x0001; // Extra field Zip64 header ID - - static final int ZIP64_MINVAL32 = 0xFFFF; - static final long ZIP64_MINVAL = 0xFFFFFFFFL; - - /* - * Zip64 End of central directory (END) header field offsets - */ - static final int ZIP64_ENDLEN = 4; // size of zip64 end of central dir - static final int ZIP64_ENDVEM = 12; // version made by - static final int ZIP64_ENDVER = 14; // version needed to extract - static final int ZIP64_ENDNMD = 16; // number of this disk - static final int ZIP64_ENDDSK = 20; // disk number of start - static final int ZIP64_ENDTOD = 24; // total number of entries on this disk - static final int ZIP64_ENDTOT = 32; // total number of entries - static final int ZIP64_ENDSIZ = 40; // central directory size in bytes - static final int ZIP64_ENDOFF = 48; // offset of first CEN header - static final int ZIP64_ENDEXT = 56; // zip64 extensible data sector - - /* - * Zip64 End of central directory locator field offsets - */ - static final int ZIP64_LOCDSK = 4; // disk number start - static final int ZIP64_LOCOFF = 8; // offset of zip64 end - static final int ZIP64_LOCTOT = 16; // total number of disks - - /* - * Zip64 Extra local (EXT) header field offsets - */ - static final int ZIP64_EXTCRC = 4; // uncompressed file crc-32 value - static final int ZIP64_EXTSIZ = 8; // compressed size, 8-byte - static final int ZIP64_EXTLEN = 16; // uncompressed size, 8-byte - - /* - * Extra field header ID - */ - static final int EXTID_ZIP64 = 0x0001; // ZIP64 - static final int EXTID_NTFS = 0x000a; // NTFS - static final int EXTID_UNIX = 0x000d; // UNIX - static final int EXTID_EFS = 0x0017; // Strong Encryption - static final int EXTID_EXTT = 0x5455; // Info-ZIP Extended Timestamp - - /* - * fields access methods - */ - /////////////////////////////////////////////////////// - static final int CH(byte[] b, int n) { - return Byte.toUnsignedInt(b[n]); - } - - static final int SH(byte[] b, int n) { - return Byte.toUnsignedInt(b[n]) | (Byte.toUnsignedInt(b[n + 1]) << 8); - } - - static final long LG(byte[] b, int n) { - return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL; - } - - static final long LL(byte[] b, int n) { - return (LG(b, n)) | (LG(b, n + 4) << 32); - } - - static final long GETSIG(byte[] b) { - return LG(b, 0); - } - - // local file (LOC) header fields - static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature - static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract - static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags - static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method - static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time - static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data - static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size - static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size - static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length - static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length - - // extra local (EXT) header fields - static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data - static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size - static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size - - // end of central directory header (END) fields - static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk - static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries - static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size - static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset - static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment - static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);} - - // zip64 end of central directory recoder fields - static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk - static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries - static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size - static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset - static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset - - // central directory header (CEN) fields - static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); } - static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); } - static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); } - static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); } - static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);} - static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);} - static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);} - static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);} - static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);} - static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);} - static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);} - static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);} - static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);} - static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);} - static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);} - static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);} - - /* The END header is followed by a variable length comment of size < 64k. */ - static final long END_MAXLEN = 0xFFFF + ENDHDR; - static final int READBLOCKSZ = 128; -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipDirectoryStream.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipDirectoryStream.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.nio.zipfs; - -import java.nio.file.DirectoryStream; -import java.nio.file.ClosedDirectoryStreamException; -import java.nio.file.NotDirectoryException; -import java.nio.file.Path; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.io.IOException; - -/** - * - * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal - */ - -public class ZipDirectoryStream implements DirectoryStream { - - private final ZipFileSystem zipfs; - private final byte[] path; - private final DirectoryStream.Filter filter; - private volatile boolean isClosed; - private volatile Iterator itr; - - ZipDirectoryStream(ZipPath zipPath, - DirectoryStream.Filter filter) - throws IOException - { - this.zipfs = zipPath.getFileSystem(); - this.path = zipPath.getResolvedPath(); - this.filter = filter; - // sanity check - if (!zipfs.isDirectory(path)) - throw new NotDirectoryException(zipPath.toString()); - } - - @Override - public synchronized Iterator iterator() { - if (isClosed) - throw new ClosedDirectoryStreamException(); - if (itr != null) - throw new IllegalStateException("Iterator has already been returned"); - - try { - itr = zipfs.iteratorOf(path, filter); - } catch (IOException e) { - throw new IllegalStateException(e); - } - return new Iterator() { - private Path next; - @Override - public boolean hasNext() { - if (isClosed) - return false; - return itr.hasNext(); - } - - @Override - public synchronized Path next() { - if (isClosed) - throw new NoSuchElementException(); - return itr.next(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - - @Override - public synchronized void close() throws IOException { - isClosed = true; - } - - -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileAttributeView.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileAttributeView.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - - -package com.sun.nio.zipfs; - -import java.nio.file.attribute.*; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; - -/* - * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal - */ - -public class ZipFileAttributeView implements BasicFileAttributeView -{ - private static enum AttrID { - size, - creationTime, - lastAccessTime, - lastModifiedTime, - isDirectory, - isRegularFile, - isSymbolicLink, - isOther, - fileKey, - compressedSize, - crc, - method - }; - - private final ZipPath path; - private final boolean isZipView; - - private ZipFileAttributeView(ZipPath path, boolean isZipView) { - this.path = path; - this.isZipView = isZipView; - } - - static V get(ZipPath path, Class type) { - if (type == null) - throw new NullPointerException(); - if (type == BasicFileAttributeView.class) - return (V)new ZipFileAttributeView(path, false); - if (type == ZipFileAttributeView.class) - return (V)new ZipFileAttributeView(path, true); - return null; - } - - static ZipFileAttributeView get(ZipPath path, String type) { - if (type == null) - throw new NullPointerException(); - if (type.equals("basic")) - return new ZipFileAttributeView(path, false); - if (type.equals("zip")) - return new ZipFileAttributeView(path, true); - return null; - } - - @Override - public String name() { - return isZipView ? "zip" : "basic"; - } - - public ZipFileAttributes readAttributes() throws IOException - { - return path.getAttributes(); - } - - @Override - public void setTimes(FileTime lastModifiedTime, - FileTime lastAccessTime, - FileTime createTime) - throws IOException - { - path.setTimes(lastModifiedTime, lastAccessTime, createTime); - } - - void setAttribute(String attribute, Object value) - throws IOException - { - try { - if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime) - setTimes ((FileTime)value, null, null); - if (AttrID.valueOf(attribute) == AttrID.lastAccessTime) - setTimes (null, (FileTime)value, null); - if (AttrID.valueOf(attribute) == AttrID.creationTime) - setTimes (null, null, (FileTime)value); - return; - } catch (IllegalArgumentException x) {} - throw new UnsupportedOperationException("'" + attribute + - "' is unknown or read-only attribute"); - } - - Map readAttributes(String attributes) - throws IOException - { - ZipFileAttributes zfas = readAttributes(); - LinkedHashMap map = new LinkedHashMap<>(); - if ("*".equals(attributes)) { - for (AttrID id : AttrID.values()) { - try { - map.put(id.name(), attribute(id, zfas)); - } catch (IllegalArgumentException x) {} - } - } else { - String[] as = attributes.split(","); - for (String a : as) { - try { - map.put(a, attribute(AttrID.valueOf(a), zfas)); - } catch (IllegalArgumentException x) {} - } - } - return map; - } - - Object attribute(AttrID id, ZipFileAttributes zfas) { - switch (id) { - case size: - return zfas.size(); - case creationTime: - return zfas.creationTime(); - case lastAccessTime: - return zfas.lastAccessTime(); - case lastModifiedTime: - return zfas.lastModifiedTime(); - case isDirectory: - return zfas.isDirectory(); - case isRegularFile: - return zfas.isRegularFile(); - case isSymbolicLink: - return zfas.isSymbolicLink(); - case isOther: - return zfas.isOther(); - case fileKey: - return zfas.fileKey(); - case compressedSize: - if (isZipView) - return zfas.compressedSize(); - break; - case crc: - if (isZipView) - return zfas.crc(); - break; - case method: - if (isZipView) - return zfas.method(); - break; - } - return null; - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileAttributes.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileAttributes.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - - -package com.sun.nio.zipfs; - -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileTime; -import java.util.Arrays; -import java.util.Formatter; -import static com.sun.nio.zipfs.ZipUtils.*; - -/** - * - * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal - */ - -public class ZipFileAttributes implements BasicFileAttributes - -{ - private final ZipFileSystem.Entry e; - - ZipFileAttributes(ZipFileSystem.Entry e) { - this.e = e; - } - - ///////// basic attributes /////////// - @Override - public FileTime creationTime() { - if (e.ctime != -1) - return FileTime.fromMillis(e.ctime); - return null; - } - - @Override - public boolean isDirectory() { - return e.isDir(); - } - - @Override - public boolean isOther() { - return false; - } - - @Override - public boolean isRegularFile() { - return !e.isDir(); - } - - @Override - public FileTime lastAccessTime() { - if (e.atime != -1) - return FileTime.fromMillis(e.atime); - return null; - } - - @Override - public FileTime lastModifiedTime() { - return FileTime.fromMillis(e.mtime); - } - - @Override - public long size() { - return e.size; - } - - @Override - public boolean isSymbolicLink() { - return false; - } - - @Override - public Object fileKey() { - return null; - } - - ///////// zip entry attributes /////////// - public long compressedSize() { - return e.csize; - } - - public long crc() { - return e.crc; - } - - public int method() { - return e.method; - } - - public byte[] extra() { - if (e.extra != null) - return Arrays.copyOf(e.extra, e.extra.length); - return null; - } - - public byte[] comment() { - if (e.comment != null) - return Arrays.copyOf(e.comment, e.comment.length); - return null; - } - - public String toString() { - StringBuilder sb = new StringBuilder(1024); - Formatter fm = new Formatter(sb); - if (creationTime() != null) - fm.format(" creationTime : %tc%n", creationTime().toMillis()); - else - fm.format(" creationTime : null%n"); - - if (lastAccessTime() != null) - fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis()); - else - fm.format(" lastAccessTime : null%n"); - fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis()); - fm.format(" isRegularFile : %b%n", isRegularFile()); - fm.format(" isDirectory : %b%n", isDirectory()); - fm.format(" isSymbolicLink : %b%n", isSymbolicLink()); - fm.format(" isOther : %b%n", isOther()); - fm.format(" fileKey : %s%n", fileKey()); - fm.format(" size : %d%n", size()); - fm.format(" compressedSize : %d%n", compressedSize()); - fm.format(" crc : %x%n", crc()); - fm.format(" method : %d%n", method()); - fm.close(); - return sb.toString(); - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileStore.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileStore.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.nio.zipfs; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.FileStore; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileAttributeView; -import java.nio.file.attribute.FileStoreAttributeView; -import java.nio.file.attribute.BasicFileAttributeView; -import java.util.Formatter; - -/* - * - * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal - */ - -public class ZipFileStore extends FileStore { - - private final ZipFileSystem zfs; - - ZipFileStore(ZipPath zpath) { - this.zfs = zpath.getFileSystem(); - } - - @Override - public String name() { - return zfs.toString() + "/"; - } - - @Override - public String type() { - return "zipfs"; - } - - @Override - public boolean isReadOnly() { - return zfs.isReadOnly(); - } - - @Override - public boolean supportsFileAttributeView(Class type) { - return (type == BasicFileAttributeView.class || - type == ZipFileAttributeView.class); - } - - @Override - public boolean supportsFileAttributeView(String name) { - return name.equals("basic") || name.equals("zip"); - } - - @Override - @SuppressWarnings("unchecked") - public V getFileStoreAttributeView(Class type) { - if (type == null) - throw new NullPointerException(); - return (V)null; - } - - @Override - public long getTotalSpace() throws IOException { - return new ZipFileStoreAttributes(this).totalSpace(); - } - - @Override - public long getUsableSpace() throws IOException { - return new ZipFileStoreAttributes(this).usableSpace(); - } - - @Override - public long getUnallocatedSpace() throws IOException { - return new ZipFileStoreAttributes(this).unallocatedSpace(); - } - - @Override - public Object getAttribute(String attribute) throws IOException { - if (attribute.equals("totalSpace")) - return getTotalSpace(); - if (attribute.equals("usableSpace")) - return getUsableSpace(); - if (attribute.equals("unallocatedSpace")) - return getUnallocatedSpace(); - throw new UnsupportedOperationException("does not support the given attribute"); - } - - private static class ZipFileStoreAttributes { - final FileStore fstore; - final long size; - - public ZipFileStoreAttributes(ZipFileStore fileStore) - throws IOException - { - Path path = FileSystems.getDefault().getPath(fileStore.name()); - this.size = Files.size(path); - this.fstore = Files.getFileStore(path); - } - - public long totalSpace() { - return size; - } - - public long usableSpace() throws IOException { - if (!fstore.isReadOnly()) - return fstore.getUsableSpace(); - return 0; - } - - public long unallocatedSpace() throws IOException { - if (!fstore.isReadOnly()) - return fstore.getUnallocatedSpace(); - return 0; - } - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystem.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2398 +0,0 @@ -/* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.nio.zipfs; - -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.EOFException; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.MappedByteBuffer; -import java.nio.channels.*; -import java.nio.file.*; -import java.nio.file.attribute.*; -import java.nio.file.spi.*; -import java.util.*; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.regex.Pattern; -import java.util.zip.CRC32; -import java.util.zip.Inflater; -import java.util.zip.Deflater; -import java.util.zip.InflaterInputStream; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.ZipException; -import java.util.zip.ZipError; -import static java.lang.Boolean.*; -import static com.sun.nio.zipfs.ZipConstants.*; -import static com.sun.nio.zipfs.ZipUtils.*; -import static java.nio.file.StandardOpenOption.*; -import static java.nio.file.StandardCopyOption.*; - -/** - * A FileSystem built on a zip file - * - * @author Xueming Shen - */ - -public class ZipFileSystem extends FileSystem { - - private final ZipFileSystemProvider provider; - private final ZipPath defaultdir; - private boolean readOnly = false; - private final Path zfpath; - private final ZipCoder zc; - - // configurable by env map - private final String defaultDir; // default dir for the file system - private final String nameEncoding; // default encoding for name/comment - private final boolean useTempFile; // use a temp file for newOS, default - // is to use BAOS for better performance - private final boolean createNew; // create a new zip if not exists - private static final boolean isWindows = - System.getProperty("os.name").startsWith("Windows"); - - ZipFileSystem(ZipFileSystemProvider provider, - Path zfpath, - Map env) - throws IOException - { - // configurable env setup - this.createNew = "true".equals(env.get("create")); - this.nameEncoding = env.containsKey("encoding") ? - (String)env.get("encoding") : "UTF-8"; - this.useTempFile = TRUE.equals(env.get("useTempFile")); - this.defaultDir = env.containsKey("default.dir") ? - (String)env.get("default.dir") : "/"; - if (this.defaultDir.charAt(0) != '/') - throw new IllegalArgumentException("default dir should be absolute"); - - this.provider = provider; - this.zfpath = zfpath; - if (Files.notExists(zfpath)) { - if (createNew) { - try (OutputStream os = Files.newOutputStream(zfpath, CREATE_NEW, WRITE)) { - new END().write(os, 0); - } - } else { - throw new FileSystemNotFoundException(zfpath.toString()); - } - } - // sm and existence check - zfpath.getFileSystem().provider().checkAccess(zfpath, AccessMode.READ); - if (!Files.isWritable(zfpath)) - this.readOnly = true; - this.zc = ZipCoder.get(nameEncoding); - this.defaultdir = new ZipPath(this, getBytes(defaultDir)); - this.ch = Files.newByteChannel(zfpath, READ); - this.cen = initCEN(); - } - - @Override - public FileSystemProvider provider() { - return provider; - } - - @Override - public String getSeparator() { - return "/"; - } - - @Override - public boolean isOpen() { - return isOpen; - } - - @Override - public boolean isReadOnly() { - return readOnly; - } - - private void checkWritable() throws IOException { - if (readOnly) - throw new ReadOnlyFileSystemException(); - } - - @Override - public Iterable getRootDirectories() { - ArrayList pathArr = new ArrayList<>(); - pathArr.add(new ZipPath(this, new byte[]{'/'})); - return pathArr; - } - - ZipPath getDefaultDir() { // package private - return defaultdir; - } - - @Override - public ZipPath getPath(String first, String... more) { - String path; - if (more.length == 0) { - path = first; - } else { - StringBuilder sb = new StringBuilder(); - sb.append(first); - for (String segment: more) { - if (segment.length() > 0) { - if (sb.length() > 0) - sb.append('/'); - sb.append(segment); - } - } - path = sb.toString(); - } - return new ZipPath(this, getBytes(path)); - } - - @Override - public UserPrincipalLookupService getUserPrincipalLookupService() { - throw new UnsupportedOperationException(); - } - - @Override - public WatchService newWatchService() { - throw new UnsupportedOperationException(); - } - - FileStore getFileStore(ZipPath path) { - return new ZipFileStore(path); - } - - @Override - public Iterable getFileStores() { - ArrayList list = new ArrayList<>(1); - list.add(new ZipFileStore(new ZipPath(this, new byte[]{'/'}))); - return list; - } - - private static final Set supportedFileAttributeViews = - Collections.unmodifiableSet( - new HashSet(Arrays.asList("basic", "zip"))); - - @Override - public Set supportedFileAttributeViews() { - return supportedFileAttributeViews; - } - - @Override - public String toString() { - return zfpath.toString(); - } - - Path getZipFile() { - return zfpath; - } - - private static final String GLOB_SYNTAX = "glob"; - private static final String REGEX_SYNTAX = "regex"; - - @Override - public PathMatcher getPathMatcher(String syntaxAndInput) { - int pos = syntaxAndInput.indexOf(':'); - if (pos <= 0 || pos == syntaxAndInput.length()) { - throw new IllegalArgumentException(); - } - String syntax = syntaxAndInput.substring(0, pos); - String input = syntaxAndInput.substring(pos + 1); - String expr; - if (syntax.equals(GLOB_SYNTAX)) { - expr = toRegexPattern(input); - } else { - if (syntax.equals(REGEX_SYNTAX)) { - expr = input; - } else { - throw new UnsupportedOperationException("Syntax '" + syntax + - "' not recognized"); - } - } - // return matcher - final Pattern pattern = Pattern.compile(expr); - return new PathMatcher() { - @Override - public boolean matches(Path path) { - return pattern.matcher(path.toString()).matches(); - } - }; - } - - @Override - public void close() throws IOException { - beginWrite(); - try { - if (!isOpen) - return; - isOpen = false; // set closed - } finally { - endWrite(); - } - if (!streams.isEmpty()) { // unlock and close all remaining streams - Set copy = new HashSet<>(streams); - for (InputStream is: copy) - is.close(); - } - beginWrite(); // lock and sync - try { - sync(); - ch.close(); // close the ch just in case no update - } finally { // and sync dose not close the ch - endWrite(); - } - - synchronized (inflaters) { - for (Inflater inf : inflaters) - inf.end(); - } - synchronized (deflaters) { - for (Deflater def : deflaters) - def.end(); - } - - IOException ioe = null; - synchronized (tmppaths) { - for (Path p: tmppaths) { - try { - Files.deleteIfExists(p); - } catch (IOException x) { - if (ioe == null) - ioe = x; - else - ioe.addSuppressed(x); - } - } - } - provider.removeFileSystem(zfpath, this); - if (ioe != null) - throw ioe; - } - - ZipFileAttributes getFileAttributes(byte[] path) - throws IOException - { - Entry e; - beginRead(); - try { - ensureOpen(); - e = getEntry0(path); - if (e == null) { - IndexNode inode = getInode(path); - if (inode == null) - return null; - e = new Entry(inode.name); // pseudo directory - e.method = METHOD_STORED; // STORED for dir - e.mtime = e.atime = e.ctime = -1;// -1 for all times - } - } finally { - endRead(); - } - return new ZipFileAttributes(e); - } - - void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime) - throws IOException - { - checkWritable(); - beginWrite(); - try { - ensureOpen(); - Entry e = getEntry0(path); // ensureOpen checked - if (e == null) - throw new NoSuchFileException(getString(path)); - if (e.type == Entry.CEN) - e.type = Entry.COPY; // copy e - if (mtime != null) - e.mtime = mtime.toMillis(); - if (atime != null) - e.atime = atime.toMillis(); - if (ctime != null) - e.ctime = ctime.toMillis(); - update(e); - } finally { - endWrite(); - } - } - - boolean exists(byte[] path) - throws IOException - { - beginRead(); - try { - ensureOpen(); - return getInode(path) != null; - } finally { - endRead(); - } - } - - boolean isDirectory(byte[] path) - throws IOException - { - beginRead(); - try { - IndexNode n = getInode(path); - return n != null && n.isDir(); - } finally { - endRead(); - } - } - - private ZipPath toZipPath(byte[] path) { - // make it absolute - byte[] p = new byte[path.length + 1]; - p[0] = '/'; - System.arraycopy(path, 0, p, 1, path.length); - return new ZipPath(this, p); - } - - // returns the list of child paths of "path" - Iterator iteratorOf(byte[] path, - DirectoryStream.Filter filter) - throws IOException - { - beginWrite(); // iteration of inodes needs exclusive lock - try { - ensureOpen(); - IndexNode inode = getInode(path); - if (inode == null) - throw new NotDirectoryException(getString(path)); - List list = new ArrayList<>(); - IndexNode child = inode.child; - while (child != null) { - ZipPath zp = toZipPath(child.name); - if (filter == null || filter.accept(zp)) - list.add(zp); - child = child.sibling; - } - return list.iterator(); - } finally { - endWrite(); - } - } - - void createDirectory(byte[] dir, FileAttribute... attrs) - throws IOException - { - checkWritable(); - dir = toDirectoryPath(dir); - beginWrite(); - try { - ensureOpen(); - if (dir.length == 0 || exists(dir)) // root dir, or exiting dir - throw new FileAlreadyExistsException(getString(dir)); - checkParents(dir); - Entry e = new Entry(dir, Entry.NEW); - e.method = METHOD_STORED; // STORED for dir - update(e); - } finally { - endWrite(); - } - } - - void copyFile(boolean deletesrc, byte[]src, byte[] dst, CopyOption... options) - throws IOException - { - checkWritable(); - if (Arrays.equals(src, dst)) - return; // do nothing, src and dst are the same - - beginWrite(); - try { - ensureOpen(); - Entry eSrc = getEntry0(src); // ensureOpen checked - if (eSrc == null) - throw new NoSuchFileException(getString(src)); - if (eSrc.isDir()) { // spec says to create dst dir - createDirectory(dst); - return; - } - boolean hasReplace = false; - boolean hasCopyAttrs = false; - for (CopyOption opt : options) { - if (opt == REPLACE_EXISTING) - hasReplace = true; - else if (opt == COPY_ATTRIBUTES) - hasCopyAttrs = true; - } - Entry eDst = getEntry0(dst); - if (eDst != null) { - if (!hasReplace) - throw new FileAlreadyExistsException(getString(dst)); - } else { - checkParents(dst); - } - Entry u = new Entry(eSrc, Entry.COPY); // copy eSrc entry - u.name(dst); // change name - if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH) - { - u.type = eSrc.type; // make it the same type - if (deletesrc) { // if it's a "rename", take the data - u.bytes = eSrc.bytes; - u.file = eSrc.file; - } else { // if it's not "rename", copy the data - if (eSrc.bytes != null) - u.bytes = Arrays.copyOf(eSrc.bytes, eSrc.bytes.length); - else if (eSrc.file != null) { - u.file = getTempPathForEntry(null); - Files.copy(eSrc.file, u.file, REPLACE_EXISTING); - } - } - } - if (!hasCopyAttrs) - u.mtime = u.atime= u.ctime = System.currentTimeMillis(); - update(u); - if (deletesrc) - updateDelete(eSrc); - } finally { - endWrite(); - } - } - - // Returns an output stream for writing the contents into the specified - // entry. - OutputStream newOutputStream(byte[] path, OpenOption... options) - throws IOException - { - checkWritable(); - boolean hasCreateNew = false; - boolean hasCreate = false; - boolean hasAppend = false; - for (OpenOption opt: options) { - if (opt == READ) - throw new IllegalArgumentException("READ not allowed"); - if (opt == CREATE_NEW) - hasCreateNew = true; - if (opt == CREATE) - hasCreate = true; - if (opt == APPEND) - hasAppend = true; - } - beginRead(); // only need a readlock, the "update()" will - try { // try to obtain a writelock when the os is - ensureOpen(); // being closed. - Entry e = getEntry0(path); - if (e != null) { - if (e.isDir() || hasCreateNew) - throw new FileAlreadyExistsException(getString(path)); - if (hasAppend) { - InputStream is = getInputStream(e); - OutputStream os = getOutputStream(new Entry(e, Entry.NEW)); - copyStream(is, os); - is.close(); - return os; - } - return getOutputStream(new Entry(e, Entry.NEW)); - } else { - if (!hasCreate && !hasCreateNew) - throw new NoSuchFileException(getString(path)); - checkParents(path); - return getOutputStream(new Entry(path, Entry.NEW)); - } - } finally { - endRead(); - } - } - - // Returns an input stream for reading the contents of the specified - // file entry. - InputStream newInputStream(byte[] path) throws IOException { - beginRead(); - try { - ensureOpen(); - Entry e = getEntry0(path); - if (e == null) - throw new NoSuchFileException(getString(path)); - if (e.isDir()) - throw new FileSystemException(getString(path), "is a directory", null); - return getInputStream(e); - } finally { - endRead(); - } - } - - private void checkOptions(Set options) { - // check for options of null type and option is an intance of StandardOpenOption - for (OpenOption option : options) { - if (option == null) - throw new NullPointerException(); - if (!(option instanceof StandardOpenOption)) - throw new IllegalArgumentException(); - } - } - - // Returns a Writable/ReadByteChannel for now. Might consdier to use - // newFileChannel() instead, which dump the entry data into a regular - // file on the default file system and create a FileChannel on top of - // it. - SeekableByteChannel newByteChannel(byte[] path, - Set options, - FileAttribute... attrs) - throws IOException - { - checkOptions(options); - if (options.contains(StandardOpenOption.WRITE) || - options.contains(StandardOpenOption.APPEND)) { - checkWritable(); - beginRead(); - try { - final WritableByteChannel wbc = Channels.newChannel( - newOutputStream(path, options.toArray(new OpenOption[0]))); - long leftover = 0; - if (options.contains(StandardOpenOption.APPEND)) { - Entry e = getEntry0(path); - if (e != null && e.size >= 0) - leftover = e.size; - } - final long offset = leftover; - return new SeekableByteChannel() { - long written = offset; - public boolean isOpen() { - return wbc.isOpen(); - } - - public long position() throws IOException { - return written; - } - - public SeekableByteChannel position(long pos) - throws IOException - { - throw new UnsupportedOperationException(); - } - - public int read(ByteBuffer dst) throws IOException { - throw new UnsupportedOperationException(); - } - - public SeekableByteChannel truncate(long size) - throws IOException - { - throw new UnsupportedOperationException(); - } - - public int write(ByteBuffer src) throws IOException { - int n = wbc.write(src); - written += n; - return n; - } - - public long size() throws IOException { - return written; - } - - public void close() throws IOException { - wbc.close(); - } - }; - } finally { - endRead(); - } - } else { - beginRead(); - try { - ensureOpen(); - Entry e = getEntry0(path); - if (e == null || e.isDir()) - throw new NoSuchFileException(getString(path)); - final ReadableByteChannel rbc = - Channels.newChannel(getInputStream(e)); - final long size = e.size; - return new SeekableByteChannel() { - long read = 0; - public boolean isOpen() { - return rbc.isOpen(); - } - - public long position() throws IOException { - return read; - } - - public SeekableByteChannel position(long pos) - throws IOException - { - throw new UnsupportedOperationException(); - } - - public int read(ByteBuffer dst) throws IOException { - int n = rbc.read(dst); - if (n > 0) { - read += n; - } - return n; - } - - public SeekableByteChannel truncate(long size) - throws IOException - { - throw new NonWritableChannelException(); - } - - public int write (ByteBuffer src) throws IOException { - throw new NonWritableChannelException(); - } - - public long size() throws IOException { - return size; - } - - public void close() throws IOException { - rbc.close(); - } - }; - } finally { - endRead(); - } - } - } - - // Returns a FileChannel of the specified entry. - // - // This implementation creates a temporary file on the default file system, - // copy the entry data into it if the entry exists, and then create a - // FileChannel on top of it. - FileChannel newFileChannel(byte[] path, - Set options, - FileAttribute... attrs) - throws IOException - { - checkOptions(options); - final boolean forWrite = (options.contains(StandardOpenOption.WRITE) || - options.contains(StandardOpenOption.APPEND)); - beginRead(); - try { - ensureOpen(); - Entry e = getEntry0(path); - if (forWrite) { - checkWritable(); - if (e == null) { - if (!options.contains(StandardOpenOption.CREATE_NEW)) - throw new NoSuchFileException(getString(path)); - } else { - if (options.contains(StandardOpenOption.CREATE_NEW)) - throw new FileAlreadyExistsException(getString(path)); - if (e.isDir()) - throw new FileAlreadyExistsException("directory <" - + getString(path) + "> exists"); - } - options.remove(StandardOpenOption.CREATE_NEW); // for tmpfile - } else if (e == null || e.isDir()) { - throw new NoSuchFileException(getString(path)); - } - - final boolean isFCH = (e != null && e.type == Entry.FILECH); - final Path tmpfile = isFCH ? e.file : getTempPathForEntry(path); - final FileChannel fch = tmpfile.getFileSystem() - .provider() - .newFileChannel(tmpfile, options, attrs); - final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH); - if (forWrite) { - u.flag = FLAG_DATADESCR; - u.method = METHOD_DEFLATED; - } - // is there a better way to hook into the FileChannel's close method? - return new FileChannel() { - public int write(ByteBuffer src) throws IOException { - return fch.write(src); - } - public long write(ByteBuffer[] srcs, int offset, int length) - throws IOException - { - return fch.write(srcs, offset, length); - } - public long position() throws IOException { - return fch.position(); - } - public FileChannel position(long newPosition) - throws IOException - { - fch.position(newPosition); - return this; - } - public long size() throws IOException { - return fch.size(); - } - public FileChannel truncate(long size) - throws IOException - { - fch.truncate(size); - return this; - } - public void force(boolean metaData) - throws IOException - { - fch.force(metaData); - } - public long transferTo(long position, long count, - WritableByteChannel target) - throws IOException - { - return fch.transferTo(position, count, target); - } - public long transferFrom(ReadableByteChannel src, - long position, long count) - throws IOException - { - return fch.transferFrom(src, position, count); - } - public int read(ByteBuffer dst) throws IOException { - return fch.read(dst); - } - public int read(ByteBuffer dst, long position) - throws IOException - { - return fch.read(dst, position); - } - public long read(ByteBuffer[] dsts, int offset, int length) - throws IOException - { - return fch.read(dsts, offset, length); - } - public int write(ByteBuffer src, long position) - throws IOException - { - return fch.write(src, position); - } - public MappedByteBuffer map(MapMode mode, - long position, long size) - throws IOException - { - throw new UnsupportedOperationException(); - } - public FileLock lock(long position, long size, boolean shared) - throws IOException - { - return fch.lock(position, size, shared); - } - public FileLock tryLock(long position, long size, boolean shared) - throws IOException - { - return fch.tryLock(position, size, shared); - } - protected void implCloseChannel() throws IOException { - fch.close(); - if (forWrite) { - u.mtime = System.currentTimeMillis(); - u.size = Files.size(u.file); - - update(u); - } else { - if (!isFCH) // if this is a new fch for reading - removeTempPathForEntry(tmpfile); - } - } - }; - } finally { - endRead(); - } - } - - // the outstanding input streams that need to be closed - private Set streams = - Collections.synchronizedSet(new HashSet()); - - // the ex-channel and ex-path that need to close when their outstanding - // input streams are all closed by the obtainers. - private Set exChClosers = new HashSet<>(); - - private Set tmppaths = Collections.synchronizedSet(new HashSet()); - private Path getTempPathForEntry(byte[] path) throws IOException { - Path tmpPath = createTempFileInSameDirectoryAs(zfpath); - if (path != null) { - Entry e = getEntry0(path); - if (e != null) { - try (InputStream is = newInputStream(path)) { - Files.copy(is, tmpPath, REPLACE_EXISTING); - } - } - } - return tmpPath; - } - - private void removeTempPathForEntry(Path path) throws IOException { - Files.delete(path); - tmppaths.remove(path); - } - - // check if all parents really exit. ZIP spec does not require - // the existence of any "parent directory". - private void checkParents(byte[] path) throws IOException { - beginRead(); - try { - while ((path = getParent(path)) != null && path.length != 0) { - if (!inodes.containsKey(IndexNode.keyOf(path))) { - throw new NoSuchFileException(getString(path)); - } - } - } finally { - endRead(); - } - } - - private static byte[] ROOTPATH = new byte[0]; - private static byte[] getParent(byte[] path) { - int off = path.length - 1; - if (off > 0 && path[off] == '/') // isDirectory - off--; - while (off > 0 && path[off] != '/') { off--; } - if (off <= 0) - return ROOTPATH; - return Arrays.copyOf(path, off + 1); - } - - private final void beginWrite() { - rwlock.writeLock().lock(); - } - - private final void endWrite() { - rwlock.writeLock().unlock(); - } - - private final void beginRead() { - rwlock.readLock().lock(); - } - - private final void endRead() { - rwlock.readLock().unlock(); - } - - /////////////////////////////////////////////////////////////////// - - private volatile boolean isOpen = true; - private final SeekableByteChannel ch; // channel to the zipfile - final byte[] cen; // CEN & ENDHDR - private END end; - private long locpos; // position of first LOC header (usually 0) - - private final ReadWriteLock rwlock = new ReentrantReadWriteLock(); - - // name -> pos (in cen), IndexNode itself can be used as a "key" - private LinkedHashMap inodes; - - final byte[] getBytes(String name) { - return zc.getBytes(name); - } - - final String getString(byte[] name) { - return zc.toString(name); - } - - protected void finalize() throws IOException { - close(); - } - - private long getDataPos(Entry e) throws IOException { - if (e.locoff == -1) { - Entry e2 = getEntry0(e.name); - if (e2 == null) - throw new ZipException("invalid loc for entry <" + e.name + ">"); - e.locoff = e2.locoff; - } - byte[] buf = new byte[LOCHDR]; - if (readFullyAt(buf, 0, buf.length, e.locoff) != buf.length) - throw new ZipException("invalid loc for entry <" + e.name + ">"); - return locpos + e.locoff + LOCHDR + LOCNAM(buf) + LOCEXT(buf); - } - - // Reads len bytes of data from the specified offset into buf. - // Returns the total number of bytes read. - // Each/every byte read from here (except the cen, which is mapped). - final long readFullyAt(byte[] buf, int off, long len, long pos) - throws IOException - { - ByteBuffer bb = ByteBuffer.wrap(buf); - bb.position(off); - bb.limit((int)(off + len)); - return readFullyAt(bb, pos); - } - - private final long readFullyAt(ByteBuffer bb, long pos) - throws IOException - { - synchronized(ch) { - return ch.position(pos).read(bb); - } - } - - // Searches for end of central directory (END) header. The contents of - // the END header will be read and placed in endbuf. Returns the file - // position of the END header, otherwise returns -1 if the END header - // was not found or an error occurred. - private END findEND() throws IOException - { - byte[] buf = new byte[READBLOCKSZ]; - long ziplen = ch.size(); - long minHDR = (ziplen - END_MAXLEN) > 0 ? ziplen - END_MAXLEN : 0; - long minPos = minHDR - (buf.length - ENDHDR); - - for (long pos = ziplen - buf.length; pos >= minPos; pos -= (buf.length - ENDHDR)) - { - int off = 0; - if (pos < 0) { - // Pretend there are some NUL bytes before start of file - off = (int)-pos; - Arrays.fill(buf, 0, off, (byte)0); - } - int len = buf.length - off; - if (readFullyAt(buf, off, len, pos + off) != len) - zerror("zip END header not found"); - - // Now scan the block backwards for END header signature - for (int i = buf.length - ENDHDR; i >= 0; i--) { - if (buf[i+0] == (byte)'P' && - buf[i+1] == (byte)'K' && - buf[i+2] == (byte)'\005' && - buf[i+3] == (byte)'\006' && - (pos + i + ENDHDR + ENDCOM(buf, i) == ziplen)) { - // Found END header - buf = Arrays.copyOfRange(buf, i, i + ENDHDR); - END end = new END(); - end.endsub = ENDSUB(buf); - end.centot = ENDTOT(buf); - end.cenlen = ENDSIZ(buf); - end.cenoff = ENDOFF(buf); - end.comlen = ENDCOM(buf); - end.endpos = pos + i; - if (end.cenlen == ZIP64_MINVAL || - end.cenoff == ZIP64_MINVAL || - end.centot == ZIP64_MINVAL32) - { - // need to find the zip64 end; - byte[] loc64 = new byte[ZIP64_LOCHDR]; - if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR) - != loc64.length) { - return end; - } - long end64pos = ZIP64_LOCOFF(loc64); - byte[] end64buf = new byte[ZIP64_ENDHDR]; - if (readFullyAt(end64buf, 0, end64buf.length, end64pos) - != end64buf.length) { - return end; - } - // end64 found, re-calcualte everything. - end.cenlen = ZIP64_ENDSIZ(end64buf); - end.cenoff = ZIP64_ENDOFF(end64buf); - end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g - end.endpos = end64pos; - } - return end; - } - } - } - zerror("zip END header not found"); - return null; //make compiler happy - } - - // Reads zip file central directory. Returns the file position of first - // CEN header, otherwise returns -1 if an error occurred. If zip->msg != NULL - // then the error was a zip format error and zip->msg has the error text. - // Always pass in -1 for knownTotal; it's used for a recursive call. - private byte[] initCEN() throws IOException { - end = findEND(); - if (end.endpos == 0) { - inodes = new LinkedHashMap<>(10); - locpos = 0; - buildNodeTree(); - return null; // only END header present - } - if (end.cenlen > end.endpos) - zerror("invalid END header (bad central directory size)"); - long cenpos = end.endpos - end.cenlen; // position of CEN table - - // Get position of first local file (LOC) header, taking into - // account that there may be a stub prefixed to the zip file. - locpos = cenpos - end.cenoff; - if (locpos < 0) - zerror("invalid END header (bad central directory offset)"); - - // read in the CEN and END - byte[] cen = new byte[(int)(end.cenlen + ENDHDR)]; - if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { - zerror("read CEN tables failed"); - } - // Iterate through the entries in the central directory - inodes = new LinkedHashMap<>(end.centot + 1); - int pos = 0; - int limit = cen.length - ENDHDR; - while (pos < limit) { - if (CENSIG(cen, pos) != CENSIG) - zerror("invalid CEN header (bad signature)"); - int method = CENHOW(cen, pos); - int nlen = CENNAM(cen, pos); - int elen = CENEXT(cen, pos); - int clen = CENCOM(cen, pos); - if ((CENFLG(cen, pos) & 1) != 0) - zerror("invalid CEN header (encrypted entry)"); - if (method != METHOD_STORED && method != METHOD_DEFLATED) - zerror("invalid CEN header (unsupported compression method: " + method + ")"); - if (pos + CENHDR + nlen > limit) - zerror("invalid CEN header (bad header size)"); - byte[] name = Arrays.copyOfRange(cen, pos + CENHDR, pos + CENHDR + nlen); - IndexNode inode = new IndexNode(name, pos); - inodes.put(inode, inode); - // skip ext and comment - pos += (CENHDR + nlen + elen + clen); - } - if (pos + ENDHDR != cen.length) { - zerror("invalid CEN header (bad header size)"); - } - buildNodeTree(); - return cen; - } - - private void ensureOpen() throws IOException { - if (!isOpen) - throw new ClosedFileSystemException(); - } - - // Creates a new empty temporary file in the same directory as the - // specified file. A variant of Files.createTempFile. - private Path createTempFileInSameDirectoryAs(Path path) - throws IOException - { - Path parent = path.toAbsolutePath().getParent(); - Path dir = (parent == null) ? path.getFileSystem().getPath(".") : parent; - Path tmpPath = Files.createTempFile(dir, "zipfstmp", null); - tmppaths.add(tmpPath); - return tmpPath; - } - - ////////////////////update & sync ////////////////////////////////////// - - private boolean hasUpdate = false; - - // shared key. consumer guarantees the "writeLock" before use it. - private final IndexNode LOOKUPKEY = IndexNode.keyOf(null); - - private void updateDelete(IndexNode inode) { - beginWrite(); - try { - removeFromTree(inode); - inodes.remove(inode); - hasUpdate = true; - } finally { - endWrite(); - } - } - - private void update(Entry e) { - beginWrite(); - try { - IndexNode old = inodes.put(e, e); - if (old != null) { - removeFromTree(old); - } - if (e.type == Entry.NEW || e.type == Entry.FILECH || e.type == Entry.COPY) { - IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(e.name))); - e.sibling = parent.child; - parent.child = e; - } - hasUpdate = true; - } finally { - endWrite(); - } - } - - // copy over the whole LOC entry (header if necessary, data and ext) from - // old zip to the new one. - private long copyLOCEntry(Entry e, boolean updateHeader, - OutputStream os, - long written, byte[] buf) - throws IOException - { - long locoff = e.locoff; // where to read - e.locoff = written; // update the e.locoff with new value - - // calculate the size need to write out - long size = 0; - // if there is A ext - if ((e.flag & FLAG_DATADESCR) != 0) { - if (e.size >= ZIP64_MINVAL || e.csize >= ZIP64_MINVAL) - size = 24; - else - size = 16; - } - // read loc, use the original loc.elen/nlen - if (readFullyAt(buf, 0, LOCHDR , locoff) != LOCHDR) - throw new ZipException("loc: reading failed"); - if (updateHeader) { - locoff += LOCHDR + LOCNAM(buf) + LOCEXT(buf); // skip header - size += e.csize; - written = e.writeLOC(os) + size; - } else { - os.write(buf, 0, LOCHDR); // write out the loc header - locoff += LOCHDR; - // use e.csize, LOCSIZ(buf) is zero if FLAG_DATADESCR is on - // size += LOCNAM(buf) + LOCEXT(buf) + LOCSIZ(buf); - size += LOCNAM(buf) + LOCEXT(buf) + e.csize; - written = LOCHDR + size; - } - int n; - while (size > 0 && - (n = (int)readFullyAt(buf, 0, buf.length, locoff)) != -1) - { - if (size < n) - n = (int)size; - os.write(buf, 0, n); - size -= n; - locoff += n; - } - return written; - } - - // sync the zip file system, if there is any udpate - private void sync() throws IOException { - //System.out.printf("->sync(%s) starting....!%n", toString()); - // check ex-closer - if (!exChClosers.isEmpty()) { - for (ExChannelCloser ecc : exChClosers) { - if (ecc.streams.isEmpty()) { - ecc.ch.close(); - Files.delete(ecc.path); - exChClosers.remove(ecc); - } - } - } - if (!hasUpdate) - return; - Path tmpFile = createTempFileInSameDirectoryAs(zfpath); - try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(tmpFile, WRITE))) - { - ArrayList elist = new ArrayList<>(inodes.size()); - long written = 0; - byte[] buf = new byte[8192]; - Entry e = null; - - // write loc - for (IndexNode inode : inodes.values()) { - if (inode instanceof Entry) { // an updated inode - e = (Entry)inode; - try { - if (e.type == Entry.COPY) { - // entry copy: the only thing changed is the "name" - // and "nlen" in LOC header, so we udpate/rewrite the - // LOC in new file and simply copy the rest (data and - // ext) without enflating/deflating from the old zip - // file LOC entry. - written += copyLOCEntry(e, true, os, written, buf); - } else { // NEW, FILECH or CEN - e.locoff = written; - written += e.writeLOC(os); // write loc header - if (e.bytes != null) { // in-memory, deflated - os.write(e.bytes); // already - written += e.bytes.length; - } else if (e.file != null) { // tmp file - try (InputStream is = Files.newInputStream(e.file)) { - int n; - if (e.type == Entry.NEW) { // deflated already - while ((n = is.read(buf)) != -1) { - os.write(buf, 0, n); - written += n; - } - } else if (e.type == Entry.FILECH) { - // the data are not deflated, use ZEOS - try (OutputStream os2 = new EntryOutputStream(e, os)) { - while ((n = is.read(buf)) != -1) { - os2.write(buf, 0, n); - } - } - written += e.csize; - if ((e.flag & FLAG_DATADESCR) != 0) - written += e.writeEXT(os); - } - } - Files.delete(e.file); - tmppaths.remove(e.file); - } else { - // dir, 0-length data - } - } - elist.add(e); - } catch (IOException x) { - x.printStackTrace(); // skip any in-accurate entry - } - } else { // unchanged inode - if (inode.pos == -1) { - continue; // pseudo directory node - } - e = Entry.readCEN(this, inode.pos); - try { - written += copyLOCEntry(e, false, os, written, buf); - elist.add(e); - } catch (IOException x) { - x.printStackTrace(); // skip any wrong entry - } - } - } - - // now write back the cen and end table - end.cenoff = written; - for (Entry entry : elist) { - written += entry.writeCEN(os); - } - end.centot = elist.size(); - end.cenlen = written - end.cenoff; - end.write(os, written); - } - if (!streams.isEmpty()) { - // - // TBD: ExChannelCloser should not be necessary if we only - // sync when being closed, all streams should have been - // closed already. Keep the logic here for now. - // - // There are outstanding input streams open on existing "ch", - // so, don't close the "cha" and delete the "file for now, let - // the "ex-channel-closer" to handle them - ExChannelCloser ecc = new ExChannelCloser( - createTempFileInSameDirectoryAs(zfpath), - ch, - streams); - Files.move(zfpath, ecc.path, REPLACE_EXISTING); - exChClosers.add(ecc); - streams = Collections.synchronizedSet(new HashSet()); - } else { - ch.close(); - Files.delete(zfpath); - } - - Files.move(tmpFile, zfpath, REPLACE_EXISTING); - hasUpdate = false; // clear - /* - if (isOpen) { - ch = zfpath.newByteChannel(READ); // re-fresh "ch" and "cen" - cen = initCEN(); - } - */ - //System.out.printf("->sync(%s) done!%n", toString()); - } - - private IndexNode getInode(byte[] path) { - if (path == null) - throw new NullPointerException("path"); - IndexNode key = IndexNode.keyOf(path); - IndexNode inode = inodes.get(key); - if (inode == null && - (path.length == 0 || path[path.length -1] != '/')) { - // if does not ends with a slash - path = Arrays.copyOf(path, path.length + 1); - path[path.length - 1] = '/'; - inode = inodes.get(key.as(path)); - } - return inode; - } - - private Entry getEntry0(byte[] path) throws IOException { - IndexNode inode = getInode(path); - if (inode instanceof Entry) - return (Entry)inode; - if (inode == null || inode.pos == -1) - return null; - return Entry.readCEN(this, inode.pos); - } - - public void deleteFile(byte[] path, boolean failIfNotExists) - throws IOException - { - checkWritable(); - - IndexNode inode = getInode(path); - if (inode == null) { - if (path != null && path.length == 0) - throw new ZipException("root directory can't not be delete"); - if (failIfNotExists) - throw new NoSuchFileException(getString(path)); - } else { - if (inode.isDir() && inode.child != null) - throw new DirectoryNotEmptyException(getString(path)); - updateDelete(inode); - } - } - - private static void copyStream(InputStream is, OutputStream os) - throws IOException - { - byte[] copyBuf = new byte[8192]; - int n; - while ((n = is.read(copyBuf)) != -1) { - os.write(copyBuf, 0, n); - } - } - - // Returns an out stream for either - // (1) writing the contents of a new entry, if the entry exits, or - // (2) updating/replacing the contents of the specified existing entry. - private OutputStream getOutputStream(Entry e) throws IOException { - - if (e.mtime == -1) - e.mtime = System.currentTimeMillis(); - if (e.method == -1) - e.method = METHOD_DEFLATED; // TBD: use default method - // store size, compressed size, and crc-32 in LOC header - e.flag = 0; - if (zc.isUTF8()) - e.flag |= FLAG_EFS; - OutputStream os; - if (useTempFile) { - e.file = getTempPathForEntry(null); - os = Files.newOutputStream(e.file, WRITE); - } else { - os = new ByteArrayOutputStream((e.size > 0)? (int)e.size : 8192); - } - return new EntryOutputStream(e, os); - } - - private InputStream getInputStream(Entry e) - throws IOException - { - InputStream eis = null; - - if (e.type == Entry.NEW) { - if (e.bytes != null) - eis = new ByteArrayInputStream(e.bytes); - else if (e.file != null) - eis = Files.newInputStream(e.file); - else - throw new ZipException("update entry data is missing"); - } else if (e.type == Entry.FILECH) { - // FILECH result is un-compressed. - eis = Files.newInputStream(e.file); - // TBD: wrap to hook close() - // streams.add(eis); - return eis; - } else { // untouced CEN or COPY - eis = new EntryInputStream(e, ch); - } - if (e.method == METHOD_DEFLATED) { - // MORE: Compute good size for inflater stream: - long bufSize = e.size + 2; // Inflater likes a bit of slack - if (bufSize > 65536) - bufSize = 8192; - final long size = e.size; - eis = new InflaterInputStream(eis, getInflater(), (int)bufSize) { - - private boolean isClosed = false; - public void close() throws IOException { - if (!isClosed) { - releaseInflater(inf); - this.in.close(); - isClosed = true; - streams.remove(this); - } - } - // Override fill() method to provide an extra "dummy" byte - // at the end of the input stream. This is required when - // using the "nowrap" Inflater option. (it appears the new - // zlib in 7 does not need it, but keep it for now) - protected void fill() throws IOException { - if (eof) { - throw new EOFException( - "Unexpected end of ZLIB input stream"); - } - len = this.in.read(buf, 0, buf.length); - if (len == -1) { - buf[0] = 0; - len = 1; - eof = true; - } - inf.setInput(buf, 0, len); - } - private boolean eof; - - public int available() throws IOException { - if (isClosed) - return 0; - long avail = size - inf.getBytesWritten(); - return avail > (long) Integer.MAX_VALUE ? - Integer.MAX_VALUE : (int) avail; - } - }; - } else if (e.method == METHOD_STORED) { - // TBD: wrap/ it does not seem necessary - } else { - throw new ZipException("invalid compression method"); - } - streams.add(eis); - return eis; - } - - // Inner class implementing the input stream used to read - // a (possibly compressed) zip file entry. - private class EntryInputStream extends InputStream { - private final SeekableByteChannel zfch; // local ref to zipfs's "ch". zipfs.ch might - // point to a new channel after sync() - private long pos; // current position within entry data - protected long rem; // number of remaining bytes within entry - protected final long size; // uncompressed size of this entry - - EntryInputStream(Entry e, SeekableByteChannel zfch) - throws IOException - { - this.zfch = zfch; - rem = e.csize; - size = e.size; - pos = getDataPos(e); - } - public int read(byte b[], int off, int len) throws IOException { - ensureOpen(); - if (rem == 0) { - return -1; - } - if (len <= 0) { - return 0; - } - if (len > rem) { - len = (int) rem; - } - // readFullyAt() - long n = 0; - ByteBuffer bb = ByteBuffer.wrap(b); - bb.position(off); - bb.limit(off + len); - synchronized(zfch) { - n = zfch.position(pos).read(bb); - } - if (n > 0) { - pos += n; - rem -= n; - } - if (rem == 0) { - close(); - } - return (int)n; - } - public int read() throws IOException { - byte[] b = new byte[1]; - if (read(b, 0, 1) == 1) { - return b[0] & 0xff; - } else { - return -1; - } - } - public long skip(long n) throws IOException { - ensureOpen(); - if (n > rem) - n = rem; - pos += n; - rem -= n; - if (rem == 0) { - close(); - } - return n; - } - public int available() { - return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem; - } - public long size() { - return size; - } - public void close() { - rem = 0; - streams.remove(this); - } - } - - class EntryOutputStream extends DeflaterOutputStream - { - private CRC32 crc; - private Entry e; - private long written; - - EntryOutputStream(Entry e, OutputStream os) - throws IOException - { - super(os, getDeflater()); - if (e == null) - throw new NullPointerException("Zip entry is null"); - this.e = e; - crc = new CRC32(); - } - - @Override - public void write(byte b[], int off, int len) throws IOException { - if (e.type != Entry.FILECH) // only from sync - ensureOpen(); - if (off < 0 || len < 0 || off > b.length - len) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - switch (e.method) { - case METHOD_DEFLATED: - super.write(b, off, len); - break; - case METHOD_STORED: - written += len; - out.write(b, off, len); - break; - default: - throw new ZipException("invalid compression method"); - } - crc.update(b, off, len); - } - - @Override - public void close() throws IOException { - // TBD ensureOpen(); - switch (e.method) { - case METHOD_DEFLATED: - finish(); - e.size = def.getBytesRead(); - e.csize = def.getBytesWritten(); - e.crc = crc.getValue(); - break; - case METHOD_STORED: - // we already know that both e.size and e.csize are the same - e.size = e.csize = written; - e.crc = crc.getValue(); - break; - default: - throw new ZipException("invalid compression method"); - } - //crc.reset(); - if (out instanceof ByteArrayOutputStream) - e.bytes = ((ByteArrayOutputStream)out).toByteArray(); - - if (e.type == Entry.FILECH) { - releaseDeflater(def); - return; - } - super.close(); - releaseDeflater(def); - update(e); - } - } - - static void zerror(String msg) { - throw new ZipError(msg); - } - - // Maxmum number of de/inflater we cache - private final int MAX_FLATER = 20; - // List of available Inflater objects for decompression - private final List inflaters = new ArrayList<>(); - - // Gets an inflater from the list of available inflaters or allocates - // a new one. - private Inflater getInflater() { - synchronized (inflaters) { - int size = inflaters.size(); - if (size > 0) { - Inflater inf = inflaters.remove(size - 1); - return inf; - } else { - return new Inflater(true); - } - } - } - - // Releases the specified inflater to the list of available inflaters. - private void releaseInflater(Inflater inf) { - synchronized (inflaters) { - if (inflaters.size() < MAX_FLATER) { - inf.reset(); - inflaters.add(inf); - } else { - inf.end(); - } - } - } - - // List of available Deflater objects for compression - private final List deflaters = new ArrayList<>(); - - // Gets an deflater from the list of available deflaters or allocates - // a new one. - private Deflater getDeflater() { - synchronized (deflaters) { - int size = deflaters.size(); - if (size > 0) { - Deflater def = deflaters.remove(size - 1); - return def; - } else { - return new Deflater(Deflater.DEFAULT_COMPRESSION, true); - } - } - } - - // Releases the specified inflater to the list of available inflaters. - private void releaseDeflater(Deflater def) { - synchronized (deflaters) { - if (inflaters.size() < MAX_FLATER) { - def.reset(); - deflaters.add(def); - } else { - def.end(); - } - } - } - - // End of central directory record - static class END { - int disknum; - int sdisknum; - int endsub; // endsub - int centot; // 4 bytes - long cenlen; // 4 bytes - long cenoff; // 4 bytes - int comlen; // comment length - byte[] comment; - - /* members of Zip64 end of central directory locator */ - int diskNum; - long endpos; - int disktot; - - void write(OutputStream os, long offset) throws IOException { - boolean hasZip64 = false; - long xlen = cenlen; - long xoff = cenoff; - if (xlen >= ZIP64_MINVAL) { - xlen = ZIP64_MINVAL; - hasZip64 = true; - } - if (xoff >= ZIP64_MINVAL) { - xoff = ZIP64_MINVAL; - hasZip64 = true; - } - int count = centot; - if (count >= ZIP64_MINVAL32) { - count = ZIP64_MINVAL32; - hasZip64 = true; - } - if (hasZip64) { - long off64 = offset; - //zip64 end of central directory record - writeInt(os, ZIP64_ENDSIG); // zip64 END record signature - writeLong(os, ZIP64_ENDHDR - 12); // size of zip64 end - writeShort(os, 45); // version made by - writeShort(os, 45); // version needed to extract - writeInt(os, 0); // number of this disk - writeInt(os, 0); // central directory start disk - writeLong(os, centot); // number of directory entires on disk - writeLong(os, centot); // number of directory entires - writeLong(os, cenlen); // length of central directory - writeLong(os, cenoff); // offset of central directory - - //zip64 end of central directory locator - writeInt(os, ZIP64_LOCSIG); // zip64 END locator signature - writeInt(os, 0); // zip64 END start disk - writeLong(os, off64); // offset of zip64 END - writeInt(os, 1); // total number of disks (?) - } - writeInt(os, ENDSIG); // END record signature - writeShort(os, 0); // number of this disk - writeShort(os, 0); // central directory start disk - writeShort(os, count); // number of directory entries on disk - writeShort(os, count); // total number of directory entries - writeInt(os, xlen); // length of central directory - writeInt(os, xoff); // offset of central directory - if (comment != null) { // zip file comment - writeShort(os, comment.length); - writeBytes(os, comment); - } else { - writeShort(os, 0); - } - } - } - - // Internal node that links a "name" to its pos in cen table. - // The node itself can be used as a "key" to lookup itself in - // the HashMap inodes. - static class IndexNode { - byte[] name; - int hashcode; // node is hashable/hashed by its name - int pos = -1; // position in cen table, -1 menas the - // entry does not exists in zip file - IndexNode(byte[] name, int pos) { - name(name); - this.pos = pos; - } - - final static IndexNode keyOf(byte[] name) { // get a lookup key; - return new IndexNode(name, -1); - } - - final void name(byte[] name) { - this.name = name; - this.hashcode = Arrays.hashCode(name); - } - - final IndexNode as(byte[] name) { // reuse the node, mostly - name(name); // as a lookup "key" - return this; - } - - boolean isDir() { - return name != null && - (name.length == 0 || name[name.length - 1] == '/'); - } - - public boolean equals(Object other) { - if (!(other instanceof IndexNode)) { - return false; - } - return Arrays.equals(name, ((IndexNode)other).name); - } - - public int hashCode() { - return hashcode; - } - - IndexNode() {} - IndexNode sibling; - IndexNode child; // 1st child - } - - static class Entry extends IndexNode { - - static final int CEN = 1; // entry read from cen - static final int NEW = 2; // updated contents in bytes or file - static final int FILECH = 3; // fch update in "file" - static final int COPY = 4; // copy of a CEN entry - - - byte[] bytes; // updated content bytes - Path file; // use tmp file to store bytes; - int type = CEN; // default is the entry read from cen - - // entry attributes - int version; - int flag; - int method = -1; // compression method - long mtime = -1; // last modification time (in DOS time) - long atime = -1; // last access time - long ctime = -1; // create time - long crc = -1; // crc-32 of entry data - long csize = -1; // compressed size of entry data - long size = -1; // uncompressed size of entry data - byte[] extra; - - // cen - int versionMade; - int disk; - int attrs; - long attrsEx; - long locoff; - byte[] comment; - - Entry() {} - - Entry(byte[] name) { - name(name); - this.mtime = this.ctime = this.atime = System.currentTimeMillis(); - this.crc = 0; - this.size = 0; - this.csize = 0; - this.method = METHOD_DEFLATED; - } - - Entry(byte[] name, int type) { - this(name); - this.type = type; - } - - Entry (Entry e, int type) { - name(e.name); - this.version = e.version; - this.ctime = e.ctime; - this.atime = e.atime; - this.mtime = e.mtime; - this.crc = e.crc; - this.size = e.size; - this.csize = e.csize; - this.method = e.method; - this.extra = e.extra; - this.versionMade = e.versionMade; - this.disk = e.disk; - this.attrs = e.attrs; - this.attrsEx = e.attrsEx; - this.locoff = e.locoff; - this.comment = e.comment; - this.type = type; - } - - Entry (byte[] name, Path file, int type) { - this(name, type); - this.file = file; - this.method = METHOD_STORED; - } - - int version() throws ZipException { - if (method == METHOD_DEFLATED) - return 20; - else if (method == METHOD_STORED) - return 10; - throw new ZipException("unsupported compression method"); - } - - ///////////////////// CEN ////////////////////// - static Entry readCEN(ZipFileSystem zipfs, int pos) - throws IOException - { - return new Entry().cen(zipfs, pos); - } - - private Entry cen(ZipFileSystem zipfs, int pos) - throws IOException - { - byte[] cen = zipfs.cen; - if (CENSIG(cen, pos) != CENSIG) - zerror("invalid CEN header (bad signature)"); - versionMade = CENVEM(cen, pos); - version = CENVER(cen, pos); - flag = CENFLG(cen, pos); - method = CENHOW(cen, pos); - mtime = dosToJavaTime(CENTIM(cen, pos)); - crc = CENCRC(cen, pos); - csize = CENSIZ(cen, pos); - size = CENLEN(cen, pos); - int nlen = CENNAM(cen, pos); - int elen = CENEXT(cen, pos); - int clen = CENCOM(cen, pos); - disk = CENDSK(cen, pos); - attrs = CENATT(cen, pos); - attrsEx = CENATX(cen, pos); - locoff = CENOFF(cen, pos); - - pos += CENHDR; - name(Arrays.copyOfRange(cen, pos, pos + nlen)); - - pos += nlen; - if (elen > 0) { - extra = Arrays.copyOfRange(cen, pos, pos + elen); - pos += elen; - readExtra(zipfs); - } - if (clen > 0) { - comment = Arrays.copyOfRange(cen, pos, pos + clen); - } - return this; - } - - int writeCEN(OutputStream os) throws IOException - { - int written = CENHDR; - int version0 = version(); - long csize0 = csize; - long size0 = size; - long locoff0 = locoff; - int elen64 = 0; // extra for ZIP64 - int elenNTFS = 0; // extra for NTFS (a/c/mtime) - int elenEXTT = 0; // extra for Extended Timestamp - boolean foundExtraTime = false; // if time stamp NTFS, EXTT present - - // confirm size/length - int nlen = (name != null) ? name.length : 0; - int elen = (extra != null) ? extra.length : 0; - int eoff = 0; - int clen = (comment != null) ? comment.length : 0; - if (csize >= ZIP64_MINVAL) { - csize0 = ZIP64_MINVAL; - elen64 += 8; // csize(8) - } - if (size >= ZIP64_MINVAL) { - size0 = ZIP64_MINVAL; // size(8) - elen64 += 8; - } - if (locoff >= ZIP64_MINVAL) { - locoff0 = ZIP64_MINVAL; - elen64 += 8; // offset(8) - } - if (elen64 != 0) { - elen64 += 4; // header and data sz 4 bytes - } - while (eoff + 4 < elen) { - int tag = SH(extra, eoff); - int sz = SH(extra, eoff + 2); - if (tag == EXTID_EXTT || tag == EXTID_NTFS) { - foundExtraTime = true; - } - eoff += (4 + sz); - } - if (!foundExtraTime) { - if (isWindows) { // use NTFS - elenNTFS = 36; // total 36 bytes - } else { // Extended Timestamp otherwise - elenEXTT = 9; // only mtime in cen - } - } - writeInt(os, CENSIG); // CEN header signature - if (elen64 != 0) { - writeShort(os, 45); // ver 4.5 for zip64 - writeShort(os, 45); - } else { - writeShort(os, version0); // version made by - writeShort(os, version0); // version needed to extract - } - writeShort(os, flag); // general purpose bit flag - writeShort(os, method); // compression method - // last modification time - writeInt(os, (int)javaToDosTime(mtime)); - writeInt(os, crc); // crc-32 - writeInt(os, csize0); // compressed size - writeInt(os, size0); // uncompressed size - writeShort(os, name.length); - writeShort(os, elen + elen64 + elenNTFS + elenEXTT); - - if (comment != null) { - writeShort(os, Math.min(clen, 0xffff)); - } else { - writeShort(os, 0); - } - writeShort(os, 0); // starting disk number - writeShort(os, 0); // internal file attributes (unused) - writeInt(os, 0); // external file attributes (unused) - writeInt(os, locoff0); // relative offset of local header - writeBytes(os, name); - if (elen64 != 0) { - writeShort(os, EXTID_ZIP64);// Zip64 extra - writeShort(os, elen64 - 4); // size of "this" extra block - if (size0 == ZIP64_MINVAL) - writeLong(os, size); - if (csize0 == ZIP64_MINVAL) - writeLong(os, csize); - if (locoff0 == ZIP64_MINVAL) - writeLong(os, locoff); - } - if (elenNTFS != 0) { - writeShort(os, EXTID_NTFS); - writeShort(os, elenNTFS - 4); - writeInt(os, 0); // reserved - writeShort(os, 0x0001); // NTFS attr tag - writeShort(os, 24); - writeLong(os, javaToWinTime(mtime)); - writeLong(os, javaToWinTime(atime)); - writeLong(os, javaToWinTime(ctime)); - } - if (elenEXTT != 0) { - writeShort(os, EXTID_EXTT); - writeShort(os, elenEXTT - 4); - if (ctime == -1) - os.write(0x3); // mtime and atime - else - os.write(0x7); // mtime, atime and ctime - writeInt(os, javaToUnixTime(mtime)); - } - if (extra != null) // whatever not recognized - writeBytes(os, extra); - if (comment != null) //TBD: 0, Math.min(commentBytes.length, 0xffff)); - writeBytes(os, comment); - return CENHDR + nlen + elen + clen + elen64 + elenNTFS + elenEXTT; - } - - ///////////////////// LOC ////////////////////// - static Entry readLOC(ZipFileSystem zipfs, long pos) - throws IOException - { - return readLOC(zipfs, pos, new byte[1024]); - } - - static Entry readLOC(ZipFileSystem zipfs, long pos, byte[] buf) - throws IOException - { - return new Entry().loc(zipfs, pos, buf); - } - - Entry loc(ZipFileSystem zipfs, long pos, byte[] buf) - throws IOException - { - assert (buf.length >= LOCHDR); - if (zipfs.readFullyAt(buf, 0, LOCHDR , pos) != LOCHDR) - throw new ZipException("loc: reading failed"); - if (LOCSIG(buf) != LOCSIG) - throw new ZipException("loc: wrong sig ->" - + Long.toString(LOCSIG(buf), 16)); - //startPos = pos; - version = LOCVER(buf); - flag = LOCFLG(buf); - method = LOCHOW(buf); - mtime = dosToJavaTime(LOCTIM(buf)); - crc = LOCCRC(buf); - csize = LOCSIZ(buf); - size = LOCLEN(buf); - int nlen = LOCNAM(buf); - int elen = LOCEXT(buf); - - name = new byte[nlen]; - if (zipfs.readFullyAt(name, 0, nlen, pos + LOCHDR) != nlen) { - throw new ZipException("loc: name reading failed"); - } - if (elen > 0) { - extra = new byte[elen]; - if (zipfs.readFullyAt(extra, 0, elen, pos + LOCHDR + nlen) - != elen) { - throw new ZipException("loc: ext reading failed"); - } - } - pos += (LOCHDR + nlen + elen); - if ((flag & FLAG_DATADESCR) != 0) { - // Data Descriptor - Entry e = zipfs.getEntry0(name); // get the size/csize from cen - if (e == null) - throw new ZipException("loc: name not found in cen"); - size = e.size; - csize = e.csize; - pos += (method == METHOD_STORED ? size : csize); - if (size >= ZIP64_MINVAL || csize >= ZIP64_MINVAL) - pos += 24; - else - pos += 16; - } else { - if (extra != null && - (size == ZIP64_MINVAL || csize == ZIP64_MINVAL)) { - // zip64 ext: must include both size and csize - int off = 0; - while (off + 20 < elen) { // HeaderID+DataSize+Data - int sz = SH(extra, off + 2); - if (SH(extra, off) == EXTID_ZIP64 && sz == 16) { - size = LL(extra, off + 4); - csize = LL(extra, off + 12); - break; - } - off += (sz + 4); - } - } - pos += (method == METHOD_STORED ? size : csize); - } - return this; - } - - int writeLOC(OutputStream os) - throws IOException - { - writeInt(os, LOCSIG); // LOC header signature - int version = version(); - int nlen = (name != null) ? name.length : 0; - int elen = (extra != null) ? extra.length : 0; - boolean foundExtraTime = false; // if extra timestamp present - int eoff = 0; - int elen64 = 0; - int elenEXTT = 0; - int elenNTFS = 0; - if ((flag & FLAG_DATADESCR) != 0) { - writeShort(os, version()); // version needed to extract - writeShort(os, flag); // general purpose bit flag - writeShort(os, method); // compression method - // last modification time - writeInt(os, (int)javaToDosTime(mtime)); - // store size, uncompressed size, and crc-32 in data descriptor - // immediately following compressed entry data - writeInt(os, 0); - writeInt(os, 0); - writeInt(os, 0); - } else { - if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) { - elen64 = 20; //headid(2) + size(2) + size(8) + csize(8) - writeShort(os, 45); // ver 4.5 for zip64 - } else { - writeShort(os, version()); // version needed to extract - } - writeShort(os, flag); // general purpose bit flag - writeShort(os, method); // compression method - // last modification time - writeInt(os, (int)javaToDosTime(mtime)); - writeInt(os, crc); // crc-32 - if (elen64 != 0) { - writeInt(os, ZIP64_MINVAL); - writeInt(os, ZIP64_MINVAL); - } else { - writeInt(os, csize); // compressed size - writeInt(os, size); // uncompressed size - } - } - while (eoff + 4 < elen) { - int tag = SH(extra, eoff); - int sz = SH(extra, eoff + 2); - if (tag == EXTID_EXTT || tag == EXTID_NTFS) { - foundExtraTime = true; - } - eoff += (4 + sz); - } - if (!foundExtraTime) { - if (isWindows) { - elenNTFS = 36; // NTFS, total 36 bytes - } else { // on unix use "ext time" - elenEXTT = 9; - if (atime != -1) - elenEXTT += 4; - if (ctime != -1) - elenEXTT += 4; - } - } - writeShort(os, name.length); - writeShort(os, elen + elen64 + elenNTFS + elenEXTT); - writeBytes(os, name); - if (elen64 != 0) { - writeShort(os, EXTID_ZIP64); - writeShort(os, 16); - writeLong(os, size); - writeLong(os, csize); - } - if (elenNTFS != 0) { - writeShort(os, EXTID_NTFS); - writeShort(os, elenNTFS - 4); - writeInt(os, 0); // reserved - writeShort(os, 0x0001); // NTFS attr tag - writeShort(os, 24); - writeLong(os, javaToWinTime(mtime)); - writeLong(os, javaToWinTime(atime)); - writeLong(os, javaToWinTime(ctime)); - } - if (elenEXTT != 0) { - writeShort(os, EXTID_EXTT); - writeShort(os, elenEXTT - 4);// size for the folowing data block - int fbyte = 0x1; - if (atime != -1) // mtime and atime - fbyte |= 0x2; - if (ctime != -1) // mtime, atime and ctime - fbyte |= 0x4; - os.write(fbyte); // flags byte - writeInt(os, javaToUnixTime(mtime)); - if (atime != -1) - writeInt(os, javaToUnixTime(atime)); - if (ctime != -1) - writeInt(os, javaToUnixTime(ctime)); - } - if (extra != null) { - writeBytes(os, extra); - } - return LOCHDR + name.length + elen + elen64 + elenNTFS + elenEXTT; - } - - // Data Descriptior - int writeEXT(OutputStream os) - throws IOException - { - writeInt(os, EXTSIG); // EXT header signature - writeInt(os, crc); // crc-32 - if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) { - writeLong(os, csize); - writeLong(os, size); - return 24; - } else { - writeInt(os, csize); // compressed size - writeInt(os, size); // uncompressed size - return 16; - } - } - - // read NTFS, UNIX and ZIP64 data from cen.extra - void readExtra(ZipFileSystem zipfs) throws IOException { - if (extra == null) - return; - int elen = extra.length; - int off = 0; - int newOff = 0; - while (off + 4 < elen) { - // extra spec: HeaderID+DataSize+Data - int pos = off; - int tag = SH(extra, pos); - int sz = SH(extra, pos + 2); - pos += 4; - if (pos + sz > elen) // invalid data - break; - switch (tag) { - case EXTID_ZIP64 : - if (size == ZIP64_MINVAL) { - if (pos + 8 > elen) // invalid zip64 extra - break; // fields, just skip - size = LL(extra, pos); - pos += 8; - } - if (csize == ZIP64_MINVAL) { - if (pos + 8 > elen) - break; - csize = LL(extra, pos); - pos += 8; - } - if (locoff == ZIP64_MINVAL) { - if (pos + 8 > elen) - break; - locoff = LL(extra, pos); - pos += 8; - } - break; - case EXTID_NTFS: - pos += 4; // reserved 4 bytes - if (SH(extra, pos) != 0x0001) - break; - if (SH(extra, pos + 2) != 24) - break; - // override the loc field, datatime here is - // more "accurate" - mtime = winToJavaTime(LL(extra, pos + 4)); - atime = winToJavaTime(LL(extra, pos + 12)); - ctime = winToJavaTime(LL(extra, pos + 20)); - break; - case EXTID_EXTT: - // spec says the Extened timestamp in cen only has mtime - // need to read the loc to get the extra a/ctime - byte[] buf = new byte[LOCHDR]; - if (zipfs.readFullyAt(buf, 0, buf.length , locoff) - != buf.length) - throw new ZipException("loc: reading failed"); - if (LOCSIG(buf) != LOCSIG) - throw new ZipException("loc: wrong sig ->" - + Long.toString(LOCSIG(buf), 16)); - - int locElen = LOCEXT(buf); - if (locElen < 9) // EXTT is at lease 9 bytes - break; - int locNlen = LOCNAM(buf); - buf = new byte[locElen]; - if (zipfs.readFullyAt(buf, 0, buf.length , locoff + LOCHDR + locNlen) - != buf.length) - throw new ZipException("loc extra: reading failed"); - int locPos = 0; - while (locPos + 4 < buf.length) { - int locTag = SH(buf, locPos); - int locSZ = SH(buf, locPos + 2); - locPos += 4; - if (locTag != EXTID_EXTT) { - locPos += locSZ; - continue; - } - int flag = CH(buf, locPos++); - if ((flag & 0x1) != 0) { - mtime = unixToJavaTime(LG(buf, locPos)); - locPos += 4; - } - if ((flag & 0x2) != 0) { - atime = unixToJavaTime(LG(buf, locPos)); - locPos += 4; - } - if ((flag & 0x4) != 0) { - ctime = unixToJavaTime(LG(buf, locPos)); - locPos += 4; - } - break; - } - break; - default: // unknown tag - System.arraycopy(extra, off, extra, newOff, sz + 4); - newOff += (sz + 4); - } - off += (sz + 4); - } - if (newOff != 0 && newOff != extra.length) - extra = Arrays.copyOf(extra, newOff); - else - extra = null; - } - } - - private static class ExChannelCloser { - Path path; - SeekableByteChannel ch; - Set streams; - ExChannelCloser(Path path, - SeekableByteChannel ch, - Set streams) - { - this.path = path; - this.ch = ch; - this.streams = streams; - } - } - - // ZIP directory has two issues: - // (1) ZIP spec does not require the ZIP file to include - // directory entry - // (2) all entries are not stored/organized in a "tree" - // structure. - // A possible solution is to build the node tree ourself as - // implemented below. - private IndexNode root; - - private void addToTree(IndexNode inode, HashSet dirs) { - if (dirs.contains(inode)) { - return; - } - IndexNode parent; - byte[] name = inode.name; - byte[] pname = getParent(name); - if (inodes.containsKey(LOOKUPKEY.as(pname))) { - parent = inodes.get(LOOKUPKEY); - } else { // pseudo directory entry - parent = new IndexNode(pname, -1); - inodes.put(parent, parent); - } - addToTree(parent, dirs); - inode.sibling = parent.child; - parent.child = inode; - if (name[name.length -1] == '/') - dirs.add(inode); - } - - private void removeFromTree(IndexNode inode) { - IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(inode.name))); - IndexNode child = parent.child; - if (child.equals(inode)) { - parent.child = child.sibling; - } else { - IndexNode last = child; - while ((child = child.sibling) != null) { - if (child.equals(inode)) { - last.sibling = child.sibling; - break; - } else { - last = child; - } - } - } - } - - private void buildNodeTree() throws IOException { - beginWrite(); - try { - HashSet dirs = new HashSet<>(); - IndexNode root = new IndexNode(ROOTPATH, -1); - inodes.put(root, root); - dirs.add(root); - for (IndexNode node : inodes.keySet().toArray(new IndexNode[0])) { - addToTree(node, dirs); - } - } finally { - endWrite(); - } - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystemProvider.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipFileSystemProvider.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,327 +0,0 @@ -/* - * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.nio.zipfs; - -import java.io.*; -import java.nio.channels.*; -import java.nio.file.*; -import java.nio.file.DirectoryStream.Filter; -import java.nio.file.attribute.*; -import java.nio.file.spi.FileSystemProvider; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.zip.ZipError; -import java.util.concurrent.ExecutorService; - -/* - * - * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal - */ - -public class ZipFileSystemProvider extends FileSystemProvider { - - - private final Map filesystems = new HashMap<>(); - - public ZipFileSystemProvider() {} - - @Override - public String getScheme() { - return "jar"; - } - - protected Path uriToPath(URI uri) { - String scheme = uri.getScheme(); - if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) { - throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'"); - } - try { - // only support legacy JAR URL syntax jar:{uri}!/{entry} for now - String spec = uri.getRawSchemeSpecificPart(); - int sep = spec.indexOf("!/"); - if (sep != -1) - spec = spec.substring(0, sep); - return Paths.get(new URI(spec)).toAbsolutePath(); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e.getMessage(), e); - } - } - - private boolean ensureFile(Path path) { - try { - BasicFileAttributes attrs = - Files.readAttributes(path, BasicFileAttributes.class); - if (!attrs.isRegularFile()) - throw new UnsupportedOperationException(); - return true; - } catch (IOException ioe) { - return false; - } - } - - @Override - public FileSystem newFileSystem(URI uri, Map env) - throws IOException - { - Path path = uriToPath(uri); - synchronized(filesystems) { - Path realPath = null; - if (ensureFile(path)) { - realPath = path.toRealPath(); - if (filesystems.containsKey(realPath)) - throw new FileSystemAlreadyExistsException(); - } - ZipFileSystem zipfs = null; - try { - zipfs = new ZipFileSystem(this, path, env); - } catch (ZipError ze) { - String pname = path.toString(); - if (pname.endsWith(".zip") || pname.endsWith(".jar")) - throw ze; - // assume NOT a zip/jar file - throw new UnsupportedOperationException(); - } - filesystems.put(realPath, zipfs); - return zipfs; - } - } - - @Override - public FileSystem newFileSystem(Path path, Map env) - throws IOException - { - if (path.getFileSystem() != FileSystems.getDefault()) { - throw new UnsupportedOperationException(); - } - ensureFile(path); - try { - return new ZipFileSystem(this, path, env); - } catch (ZipError ze) { - String pname = path.toString(); - if (pname.endsWith(".zip") || pname.endsWith(".jar")) - throw ze; - throw new UnsupportedOperationException(); - } - } - - @Override - public Path getPath(URI uri) { - - String spec = uri.getSchemeSpecificPart(); - int sep = spec.indexOf("!/"); - if (sep == -1) - throw new IllegalArgumentException("URI: " - + uri - + " does not contain path info ex. jar:file:/c:/foo.zip!/BAR"); - return getFileSystem(uri).getPath(spec.substring(sep + 1)); - } - - - @Override - public FileSystem getFileSystem(URI uri) { - synchronized (filesystems) { - ZipFileSystem zipfs = null; - try { - zipfs = filesystems.get(uriToPath(uri).toRealPath()); - } catch (IOException x) { - // ignore the ioe from toRealPath(), return FSNFE - } - if (zipfs == null) - throw new FileSystemNotFoundException(); - return zipfs; - } - } - - // Checks that the given file is a UnixPath - static final ZipPath toZipPath(Path path) { - if (path == null) - throw new NullPointerException(); - if (!(path instanceof ZipPath)) - throw new ProviderMismatchException(); - return (ZipPath)path; - } - - @Override - public void checkAccess(Path path, AccessMode... modes) throws IOException { - toZipPath(path).checkAccess(modes); - } - - @Override - public void copy(Path src, Path target, CopyOption... options) - throws IOException - { - toZipPath(src).copy(toZipPath(target), options); - } - - @Override - public void createDirectory(Path path, FileAttribute... attrs) - throws IOException - { - toZipPath(path).createDirectory(attrs); - } - - @Override - public final void delete(Path path) throws IOException { - toZipPath(path).delete(); - } - - @Override - @SuppressWarnings("unchecked") - public V - getFileAttributeView(Path path, Class type, LinkOption... options) - { - return ZipFileAttributeView.get(toZipPath(path), type); - } - - @Override - public FileStore getFileStore(Path path) throws IOException { - return toZipPath(path).getFileStore(); - } - - @Override - public boolean isHidden(Path path) { - return toZipPath(path).isHidden(); - } - - @Override - public boolean isSameFile(Path path, Path other) throws IOException { - return toZipPath(path).isSameFile(other); - } - - @Override - public void move(Path src, Path target, CopyOption... options) - throws IOException - { - toZipPath(src).move(toZipPath(target), options); - } - - @Override - public AsynchronousFileChannel newAsynchronousFileChannel(Path path, - Set options, - ExecutorService exec, - FileAttribute... attrs) - throws IOException - { - throw new UnsupportedOperationException(); - } - - @Override - public SeekableByteChannel newByteChannel(Path path, - Set options, - FileAttribute... attrs) - throws IOException - { - return toZipPath(path).newByteChannel(options, attrs); - } - - @Override - public DirectoryStream newDirectoryStream( - Path path, Filter filter) throws IOException - { - return toZipPath(path).newDirectoryStream(filter); - } - - @Override - public FileChannel newFileChannel(Path path, - Set options, - FileAttribute... attrs) - throws IOException - { - return toZipPath(path).newFileChannel(options, attrs); - } - - @Override - public InputStream newInputStream(Path path, OpenOption... options) - throws IOException - { - return toZipPath(path).newInputStream(options); - } - - @Override - public OutputStream newOutputStream(Path path, OpenOption... options) - throws IOException - { - return toZipPath(path).newOutputStream(options); - } - - @Override - public A - readAttributes(Path path, Class type, LinkOption... options) - throws IOException - { - if (type == BasicFileAttributes.class || type == ZipFileAttributes.class) - return (A)toZipPath(path).getAttributes(); - return null; - } - - @Override - public Map - readAttributes(Path path, String attribute, LinkOption... options) - throws IOException - { - return toZipPath(path).readAttributes(attribute, options); - } - - @Override - public Path readSymbolicLink(Path link) throws IOException { - throw new UnsupportedOperationException("Not supported."); - } - - @Override - public void setAttribute(Path path, String attribute, - Object value, LinkOption... options) - throws IOException - { - toZipPath(path).setAttribute(attribute, value, options); - } - - ////////////////////////////////////////////////////////////// - void removeFileSystem(Path zfpath, ZipFileSystem zfs) throws IOException { - synchronized (filesystems) { - zfpath = zfpath.toRealPath(); - if (filesystems.get(zfpath) == zfs) - filesystems.remove(zfpath); - } - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipInfo.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipInfo.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.nio.zipfs; - -import java.nio.file.Paths; -import java.util.Collections; -import java.util.Map; -import static com.sun.nio.zipfs.ZipConstants.*; -import static com.sun.nio.zipfs.ZipUtils.*; - -/** - * Print all loc and cen headers of the ZIP file - * - * @author Xueming Shen - */ - -public class ZipInfo { - - public static void main(String[] args) throws Throwable { - if (args.length < 1) { - print("Usage: java ZipInfo zfname"); - } else { - Map env = Collections.emptyMap(); - ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider() - .newFileSystem(Paths.get(args[0]), env)); - byte[] cen = zfs.cen; - if (cen == null) { - print("zip file is empty%n"); - return; - } - int pos = 0; - byte[] buf = new byte[1024]; - int no = 1; - while (pos + CENHDR < cen.length) { - print("----------------#%d--------------------%n", no++); - printCEN(cen, pos); - - // use size CENHDR as the extra bytes to read, just in case the - // loc.extra is bigger than the cen.extra, try to avoid to read - // twice - long len = LOCHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENHDR; - if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) - ZipFileSystem.zerror("read loc header failed"); - if (LOCEXT(buf) > CENEXT(cen, pos) + CENHDR) { - // have to read the second time; - len = LOCHDR + LOCNAM(buf) + LOCEXT(buf); - if (zfs.readFullyAt(buf, 0, len, locoff(cen, pos)) != len) - ZipFileSystem.zerror("read loc header failed"); - } - printLOC(buf); - pos += CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos); - } - zfs.close(); - } - } - - static void print(String fmt, Object... objs) { - System.out.printf(fmt, objs); - } - - static void printLOC(byte[] loc) { - print("%n"); - print("[Local File Header]%n"); - print(" Signature : %#010x%n", LOCSIG(loc)); - if (LOCSIG(loc) != LOCSIG) { - print(" Wrong signature!"); - return; - } - print(" Version : %#6x [%d.%d]%n", - LOCVER(loc), LOCVER(loc) / 10, LOCVER(loc) % 10); - print(" Flag : %#6x%n", LOCFLG(loc)); - print(" Method : %#6x%n", LOCHOW(loc)); - print(" LastMTime : %#10x [%tc]%n", - LOCTIM(loc), dosToJavaTime(LOCTIM(loc))); - print(" CRC : %#10x%n", LOCCRC(loc)); - print(" CSize : %#10x%n", LOCSIZ(loc)); - print(" Size : %#10x%n", LOCLEN(loc)); - print(" NameLength : %#6x [%s]%n", - LOCNAM(loc), new String(loc, LOCHDR, LOCNAM(loc))); - print(" ExtraLength : %#6x%n", LOCEXT(loc)); - if (LOCEXT(loc) != 0) - printExtra(loc, LOCHDR + LOCNAM(loc), LOCEXT(loc)); - } - - static void printCEN(byte[] cen, int off) { - print("[Central Directory Header]%n"); - print(" Signature : %#010x%n", CENSIG(cen, off)); - if (CENSIG(cen, off) != CENSIG) { - print(" Wrong signature!"); - return; - } - print(" VerMadeby : %#6x [%d, %d.%d]%n", - CENVEM(cen, off), (CENVEM(cen, off) >> 8), - (CENVEM(cen, off) & 0xff) / 10, - (CENVEM(cen, off) & 0xff) % 10); - print(" VerExtract : %#6x [%d.%d]%n", - CENVER(cen, off), CENVER(cen, off) / 10, CENVER(cen, off) % 10); - print(" Flag : %#6x%n", CENFLG(cen, off)); - print(" Method : %#6x%n", CENHOW(cen, off)); - print(" LastMTime : %#10x [%tc]%n", - CENTIM(cen, off), dosToJavaTime(CENTIM(cen, off))); - print(" CRC : %#10x%n", CENCRC(cen, off)); - print(" CSize : %#10x%n", CENSIZ(cen, off)); - print(" Size : %#10x%n", CENLEN(cen, off)); - print(" NameLen : %#6x [%s]%n", - CENNAM(cen, off), new String(cen, off + CENHDR, CENNAM(cen, off))); - print(" ExtraLen : %#6x%n", CENEXT(cen, off)); - if (CENEXT(cen, off) != 0) - printExtra(cen, off + CENHDR + CENNAM(cen, off), CENEXT(cen, off)); - print(" CommentLen : %#6x%n", CENCOM(cen, off)); - print(" DiskStart : %#6x%n", CENDSK(cen, off)); - print(" Attrs : %#6x%n", CENATT(cen, off)); - print(" AttrsEx : %#10x%n", CENATX(cen, off)); - print(" LocOff : %#10x%n", CENOFF(cen, off)); - - } - - static long locoff(byte[] cen, int pos) { - long locoff = CENOFF(cen, pos); - if (locoff == ZIP64_MINVAL) { //ZIP64 - int off = pos + CENHDR + CENNAM(cen, pos); - int end = off + CENEXT(cen, pos); - while (off + 4 < end) { - int tag = SH(cen, off); - int sz = SH(cen, off + 2); - if (tag != EXTID_ZIP64) { - off += 4 + sz; - continue; - } - off += 4; - if (CENLEN(cen, pos) == ZIP64_MINVAL) - off += 8; - if (CENSIZ(cen, pos) == ZIP64_MINVAL) - off += 8; - return LL(cen, off); - } - // should never be here - } - return locoff; - } - - static void printExtra(byte[] extra, int off, int len) { - int end = off + len; - while (off + 4 <= end) { - int tag = SH(extra, off); - int sz = SH(extra, off + 2); - print(" [tag=0x%04x, sz=%d, data= ", tag, sz); - if (off + sz > end) { - print(" Error: Invalid extra data, beyond extra length"); - break; - } - off += 4; - for (int i = 0; i < sz; i++) - print("%02x ", extra[off + i]); - print("]%n"); - switch (tag) { - case EXTID_ZIP64 : - print(" ->ZIP64: "); - int pos = off; - while (pos + 8 <= off + sz) { - print(" *0x%x ", LL(extra, pos)); - pos += 8; - } - print("%n"); - break; - case EXTID_NTFS: - print(" ->PKWare NTFS%n"); - // 4 bytes reserved - if (SH(extra, off + 4) != 0x0001 || SH(extra, off + 6) != 24) - print(" Error: Invalid NTFS sub-tag or subsz"); - print(" mtime:%tc%n", - winToJavaTime(LL(extra, off + 8))); - print(" atime:%tc%n", - winToJavaTime(LL(extra, off + 16))); - print(" ctime:%tc%n", - winToJavaTime(LL(extra, off + 24))); - break; - case EXTID_EXTT: - print(" ->Info-ZIP Extended Timestamp: flag=%x%n",extra[off]); - pos = off + 1 ; - while (pos + 4 <= off + sz) { - print(" *%tc%n", - unixToJavaTime(LG(extra, pos))); - pos += 4; - } - break; - default: - print(" ->[tag=%x, size=%d]%n", tag, sz); - } - off += sz; - } - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipPath.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipPath.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,884 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.nio.zipfs; - -import java.io.*; -import java.net.URI; -import java.nio.channels.*; -import java.nio.file.*; -import java.nio.file.DirectoryStream.Filter; -import java.nio.file.attribute.*; -import java.util.*; -import static java.nio.file.StandardOpenOption.*; -import static java.nio.file.StandardCopyOption.*; - - -/** - * - * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal - */ - -public class ZipPath implements Path { - - private final ZipFileSystem zfs; - private final byte[] path; - private volatile int[] offsets; - private int hashcode = 0; // cached hashcode (created lazily) - - ZipPath(ZipFileSystem zfs, byte[] path) { - this(zfs, path, false); - } - - ZipPath(ZipFileSystem zfs, byte[] path, boolean normalized) - { - this.zfs = zfs; - if (normalized) - this.path = path; - else - this.path = normalize(path); - } - - @Override - public ZipPath getRoot() { - if (this.isAbsolute()) - return new ZipPath(zfs, new byte[]{path[0]}); - else - return null; - } - - @Override - public Path getFileName() { - initOffsets(); - int count = offsets.length; - if (count == 0) - return null; // no elements so no name - if (count == 1 && path[0] != '/') - return this; - int lastOffset = offsets[count-1]; - int len = path.length - lastOffset; - byte[] result = new byte[len]; - System.arraycopy(path, lastOffset, result, 0, len); - return new ZipPath(zfs, result); - } - - @Override - public ZipPath getParent() { - initOffsets(); - int count = offsets.length; - if (count == 0) // no elements so no parent - return null; - int len = offsets[count-1] - 1; - if (len <= 0) // parent is root only (may be null) - return getRoot(); - byte[] result = new byte[len]; - System.arraycopy(path, 0, result, 0, len); - return new ZipPath(zfs, result); - } - - @Override - public int getNameCount() { - initOffsets(); - return offsets.length; - } - - @Override - public ZipPath getName(int index) { - initOffsets(); - if (index < 0 || index >= offsets.length) - throw new IllegalArgumentException(); - int begin = offsets[index]; - int len; - if (index == (offsets.length-1)) - len = path.length - begin; - else - len = offsets[index+1] - begin - 1; - // construct result - byte[] result = new byte[len]; - System.arraycopy(path, begin, result, 0, len); - return new ZipPath(zfs, result); - } - - @Override - public ZipPath subpath(int beginIndex, int endIndex) { - initOffsets(); - if (beginIndex < 0 || - beginIndex >= offsets.length || - endIndex > offsets.length || - beginIndex >= endIndex) - throw new IllegalArgumentException(); - - // starting offset and length - int begin = offsets[beginIndex]; - int len; - if (endIndex == offsets.length) - len = path.length - begin; - else - len = offsets[endIndex] - begin - 1; - // construct result - byte[] result = new byte[len]; - System.arraycopy(path, begin, result, 0, len); - return new ZipPath(zfs, result); - } - - @Override - public ZipPath toRealPath(LinkOption... options) throws IOException { - ZipPath realPath = new ZipPath(zfs, getResolvedPath()).toAbsolutePath(); - realPath.checkAccess(); - return realPath; - } - - boolean isHidden() { - return false; - } - - @Override - public ZipPath toAbsolutePath() { - if (isAbsolute()) { - return this; - } else { - //add / bofore the existing path - byte[] defaultdir = zfs.getDefaultDir().path; - int defaultlen = defaultdir.length; - boolean endsWith = (defaultdir[defaultlen - 1] == '/'); - byte[] t = null; - if (endsWith) - t = new byte[defaultlen + path.length]; - else - t = new byte[defaultlen + 1 + path.length]; - System.arraycopy(defaultdir, 0, t, 0, defaultlen); - if (!endsWith) - t[defaultlen++] = '/'; - System.arraycopy(path, 0, t, defaultlen, path.length); - return new ZipPath(zfs, t, true); // normalized - } - } - - @Override - public URI toUri() { - try { - return new URI("jar", - zfs.getZipFile().toUri() + - "!" + - zfs.getString(toAbsolutePath().path), - null); - } catch (Exception ex) { - throw new AssertionError(ex); - } - } - - private boolean equalsNameAt(ZipPath other, int index) { - int mbegin = offsets[index]; - int mlen = 0; - if (index == (offsets.length-1)) - mlen = path.length - mbegin; - else - mlen = offsets[index + 1] - mbegin - 1; - int obegin = other.offsets[index]; - int olen = 0; - if (index == (other.offsets.length - 1)) - olen = other.path.length - obegin; - else - olen = other.offsets[index + 1] - obegin - 1; - if (mlen != olen) - return false; - int n = 0; - while(n < mlen) { - if (path[mbegin + n] != other.path[obegin + n]) - return false; - n++; - } - return true; - } - - @Override - public Path relativize(Path other) { - final ZipPath o = checkPath(other); - if (o.equals(this)) - return new ZipPath(getFileSystem(), new byte[0], true); - if (/* this.getFileSystem() != o.getFileSystem() || */ - this.isAbsolute() != o.isAbsolute()) { - throw new IllegalArgumentException(); - } - int mc = this.getNameCount(); - int oc = o.getNameCount(); - int n = Math.min(mc, oc); - int i = 0; - while (i < n) { - if (!equalsNameAt(o, i)) - break; - i++; - } - int dotdots = mc - i; - int len = dotdots * 3 - 1; - if (i < oc) - len += (o.path.length - o.offsets[i] + 1); - byte[] result = new byte[len]; - - int pos = 0; - while (dotdots > 0) { - result[pos++] = (byte)'.'; - result[pos++] = (byte)'.'; - if (pos < len) // no tailing slash at the end - result[pos++] = (byte)'/'; - dotdots--; - } - if (i < oc) - System.arraycopy(o.path, o.offsets[i], - result, pos, - o.path.length - o.offsets[i]); - return new ZipPath(getFileSystem(), result); - } - - @Override - public ZipFileSystem getFileSystem() { - return zfs; - } - - @Override - public boolean isAbsolute() { - return (this.path.length > 0 && path[0] == '/'); - } - - @Override - public ZipPath resolve(Path other) { - final ZipPath o = checkPath(other); - if (o.isAbsolute()) - return o; - byte[] resolved = null; - if (this.path[path.length - 1] == '/') { - resolved = new byte[path.length + o.path.length]; - System.arraycopy(path, 0, resolved, 0, path.length); - System.arraycopy(o.path, 0, resolved, path.length, o.path.length); - } else { - resolved = new byte[path.length + 1 + o.path.length]; - System.arraycopy(path, 0, resolved, 0, path.length); - resolved[path.length] = '/'; - System.arraycopy(o.path, 0, resolved, path.length + 1, o.path.length); - } - return new ZipPath(zfs, resolved); - } - - @Override - public Path resolveSibling(Path other) { - if (other == null) - throw new NullPointerException(); - Path parent = getParent(); - return (parent == null) ? other : parent.resolve(other); - } - - @Override - public boolean startsWith(Path other) { - final ZipPath o = checkPath(other); - if (o.isAbsolute() != this.isAbsolute() || - o.path.length > this.path.length) - return false; - int olast = o.path.length; - for (int i = 0; i < olast; i++) { - if (o.path[i] != this.path[i]) - return false; - } - olast--; - return o.path.length == this.path.length || - o.path[olast] == '/' || - this.path[olast + 1] == '/'; - } - - @Override - public boolean endsWith(Path other) { - final ZipPath o = checkPath(other); - int olast = o.path.length - 1; - if (olast > 0 && o.path[olast] == '/') - olast--; - int last = this.path.length - 1; - if (last > 0 && this.path[last] == '/') - last--; - if (olast == -1) // o.path.length == 0 - return last == -1; - if ((o.isAbsolute() &&(!this.isAbsolute() || olast != last)) || - (last < olast)) - return false; - for (; olast >= 0; olast--, last--) { - if (o.path[olast] != this.path[last]) - return false; - } - return o.path[olast + 1] == '/' || - last == -1 || this.path[last] == '/'; - } - - @Override - public ZipPath resolve(String other) { - return resolve(getFileSystem().getPath(other)); - } - - @Override - public final Path resolveSibling(String other) { - return resolveSibling(getFileSystem().getPath(other)); - } - - @Override - public final boolean startsWith(String other) { - return startsWith(getFileSystem().getPath(other)); - } - - @Override - public final boolean endsWith(String other) { - return endsWith(getFileSystem().getPath(other)); - } - - @Override - public Path normalize() { - byte[] resolved = getResolved(); - if (resolved == path) // no change - return this; - return new ZipPath(zfs, resolved, true); - } - - private ZipPath checkPath(Path path) { - if (path == null) - throw new NullPointerException(); - if (!(path instanceof ZipPath)) - throw new ProviderMismatchException(); - return (ZipPath) path; - } - - // create offset list if not already created - private void initOffsets() { - if (offsets == null) { - int count, index; - // count names - count = 0; - index = 0; - while (index < path.length) { - byte c = path[index++]; - if (c != '/') { - count++; - while (index < path.length && path[index] != '/') - index++; - } - } - // populate offsets - int[] result = new int[count]; - count = 0; - index = 0; - while (index < path.length) { - byte c = path[index]; - if (c == '/') { - index++; - } else { - result[count++] = index++; - while (index < path.length && path[index] != '/') - index++; - } - } - synchronized (this) { - if (offsets == null) - offsets = result; - } - } - } - - // resolved path for locating zip entry inside the zip file, - // the result path does not contain ./ and .. components - private volatile byte[] resolved = null; - byte[] getResolvedPath() { - byte[] r = resolved; - if (r == null) { - if (isAbsolute()) - r = getResolved(); - else - r = toAbsolutePath().getResolvedPath(); - if (r[0] == '/') - r = Arrays.copyOfRange(r, 1, r.length); - resolved = r; - } - return resolved; - } - - // removes redundant slashs, replace "\" to zip separator "/" - // and check for invalid characters - private byte[] normalize(byte[] path) { - if (path.length == 0) - return path; - byte prevC = 0; - for (int i = 0; i < path.length; i++) { - byte c = path[i]; - if (c == '\\') - return normalize(path, i); - if (c == (byte)'/' && prevC == '/') - return normalize(path, i - 1); - if (c == '\u0000') - throw new InvalidPathException(zfs.getString(path), - "Path: nul character not allowed"); - prevC = c; - } - return path; - } - - private byte[] normalize(byte[] path, int off) { - byte[] to = new byte[path.length]; - int n = 0; - while (n < off) { - to[n] = path[n]; - n++; - } - int m = n; - byte prevC = 0; - while (n < path.length) { - byte c = path[n++]; - if (c == (byte)'\\') - c = (byte)'/'; - if (c == (byte)'/' && prevC == (byte)'/') - continue; - if (c == '\u0000') - throw new InvalidPathException(zfs.getString(path), - "Path: nul character not allowed"); - to[m++] = c; - prevC = c; - } - if (m > 1 && to[m - 1] == '/') - m--; - return (m == to.length)? to : Arrays.copyOf(to, m); - } - - // Remove DotSlash(./) and resolve DotDot (..) components - private byte[] getResolved() { - if (path.length == 0) - return path; - for (int i = 0; i < path.length; i++) { - byte c = path[i]; - if (c == (byte)'.') - return resolve0(); - } - return path; - } - - // TBD: performance, avoid initOffsets - private byte[] resolve0() { - byte[] to = new byte[path.length]; - int nc = getNameCount(); - int[] lastM = new int[nc]; - int lastMOff = -1; - int m = 0; - for (int i = 0; i < nc; i++) { - int n = offsets[i]; - int len = (i == offsets.length - 1)? - (path.length - n):(offsets[i + 1] - n - 1); - if (len == 1 && path[n] == (byte)'.') { - if (m == 0 && path[0] == '/') // absolute path - to[m++] = '/'; - continue; - } - if (len == 2 && path[n] == '.' && path[n + 1] == '.') { - if (lastMOff >= 0) { - m = lastM[lastMOff--]; // retreat - continue; - } - if (path[0] == '/') { // "/../xyz" skip - if (m == 0) - to[m++] = '/'; - } else { // "../xyz" -> "../xyz" - if (m != 0 && to[m-1] != '/') - to[m++] = '/'; - while (len-- > 0) - to[m++] = path[n++]; - } - continue; - } - if (m == 0 && path[0] == '/' || // absolute path - m != 0 && to[m-1] != '/') { // not the first name - to[m++] = '/'; - } - lastM[++lastMOff] = m; - while (len-- > 0) - to[m++] = path[n++]; - } - if (m > 1 && to[m - 1] == '/') - m--; - return (m == to.length)? to : Arrays.copyOf(to, m); - } - - @Override - public String toString() { - return zfs.getString(path); - } - - @Override - public int hashCode() { - int h = hashcode; - if (h == 0) - hashcode = h = Arrays.hashCode(path); - return h; - } - - @Override - public boolean equals(Object obj) { - return obj != null && - obj instanceof ZipPath && - this.zfs == ((ZipPath)obj).zfs && - compareTo((Path) obj) == 0; - } - - @Override - public int compareTo(Path other) { - final ZipPath o = checkPath(other); - int len1 = this.path.length; - int len2 = o.path.length; - - int n = Math.min(len1, len2); - byte v1[] = this.path; - byte v2[] = o.path; - - int k = 0; - while (k < n) { - int c1 = v1[k] & 0xff; - int c2 = v2[k] & 0xff; - if (c1 != c2) - return c1 - c2; - k++; - } - return len1 - len2; - } - - public WatchKey register( - WatchService watcher, - WatchEvent.Kind[] events, - WatchEvent.Modifier... modifiers) { - if (watcher == null || events == null || modifiers == null) { - throw new NullPointerException(); - } - throw new UnsupportedOperationException(); - } - - @Override - public WatchKey register(WatchService watcher, WatchEvent.Kind... events) { - return register(watcher, events, new WatchEvent.Modifier[0]); - } - - @Override - public final File toFile() { - throw new UnsupportedOperationException(); - } - - @Override - public Iterator iterator() { - return new Iterator() { - private int i = 0; - - @Override - public boolean hasNext() { - return (i < getNameCount()); - } - - @Override - public Path next() { - if (i < getNameCount()) { - Path result = getName(i); - i++; - return result; - } else { - throw new NoSuchElementException(); - } - } - - @Override - public void remove() { - throw new ReadOnlyFileSystemException(); - } - }; - } - - ///////////////////////////////////////////////////////////////////// - - - void createDirectory(FileAttribute... attrs) - throws IOException - { - zfs.createDirectory(getResolvedPath(), attrs); - } - - InputStream newInputStream(OpenOption... options) throws IOException - { - if (options.length > 0) { - for (OpenOption opt : options) { - if (opt != READ) - throw new UnsupportedOperationException("'" + opt + "' not allowed"); - } - } - return zfs.newInputStream(getResolvedPath()); - } - - DirectoryStream newDirectoryStream(Filter filter) - throws IOException - { - return new ZipDirectoryStream(this, filter); - } - - void delete() throws IOException { - zfs.deleteFile(getResolvedPath(), true); - } - - void deleteIfExists() throws IOException { - zfs.deleteFile(getResolvedPath(), false); - } - - ZipFileAttributes getAttributes() throws IOException - { - ZipFileAttributes zfas = zfs.getFileAttributes(getResolvedPath()); - if (zfas == null) - throw new NoSuchFileException(toString()); - return zfas; - } - - void setAttribute(String attribute, Object value, LinkOption... options) - throws IOException - { - String type = null; - String attr = null; - int colonPos = attribute.indexOf(':'); - if (colonPos == -1) { - type = "basic"; - attr = attribute; - } else { - type = attribute.substring(0, colonPos++); - attr = attribute.substring(colonPos); - } - ZipFileAttributeView view = ZipFileAttributeView.get(this, type); - if (view == null) - throw new UnsupportedOperationException("view <" + view + "> is not supported"); - view.setAttribute(attr, value); - } - - void setTimes(FileTime mtime, FileTime atime, FileTime ctime) - throws IOException - { - zfs.setTimes(getResolvedPath(), mtime, atime, ctime); - } - - Map readAttributes(String attributes, LinkOption... options) - throws IOException - - { - String view = null; - String attrs = null; - int colonPos = attributes.indexOf(':'); - if (colonPos == -1) { - view = "basic"; - attrs = attributes; - } else { - view = attributes.substring(0, colonPos++); - attrs = attributes.substring(colonPos); - } - ZipFileAttributeView zfv = ZipFileAttributeView.get(this, view); - if (zfv == null) { - throw new UnsupportedOperationException("view not supported"); - } - return zfv.readAttributes(attrs); - } - - FileStore getFileStore() throws IOException { - // each ZipFileSystem only has one root (as requested for now) - if (exists()) - return zfs.getFileStore(this); - throw new NoSuchFileException(zfs.getString(path)); - } - - boolean isSameFile(Path other) throws IOException { - if (this.equals(other)) - return true; - if (other == null || - this.getFileSystem() != other.getFileSystem()) - return false; - this.checkAccess(); - ((ZipPath)other).checkAccess(); - return Arrays.equals(this.getResolvedPath(), - ((ZipPath)other).getResolvedPath()); - } - - SeekableByteChannel newByteChannel(Set options, - FileAttribute... attrs) - throws IOException - { - return zfs.newByteChannel(getResolvedPath(), options, attrs); - } - - - FileChannel newFileChannel(Set options, - FileAttribute... attrs) - throws IOException - { - return zfs.newFileChannel(getResolvedPath(), options, attrs); - } - - void checkAccess(AccessMode... modes) throws IOException { - boolean w = false; - boolean x = false; - for (AccessMode mode : modes) { - switch (mode) { - case READ: - break; - case WRITE: - w = true; - break; - case EXECUTE: - x = true; - break; - default: - throw new UnsupportedOperationException(); - } - } - ZipFileAttributes attrs = zfs.getFileAttributes(getResolvedPath()); - if (attrs == null && (path.length != 1 || path[0] != '/')) - throw new NoSuchFileException(toString()); - if (w) { - if (zfs.isReadOnly()) - throw new AccessDeniedException(toString()); - } - if (x) - throw new AccessDeniedException(toString()); - } - - boolean exists() { - if (path.length == 1 && path[0] == '/') - return true; - try { - return zfs.exists(getResolvedPath()); - } catch (IOException x) {} - return false; - } - - OutputStream newOutputStream(OpenOption... options) throws IOException - { - if (options.length == 0) - return zfs.newOutputStream(getResolvedPath(), - CREATE_NEW, WRITE); - return zfs.newOutputStream(getResolvedPath(), options); - } - - void move(ZipPath target, CopyOption... options) - throws IOException - { - if (Files.isSameFile(this.zfs.getZipFile(), target.zfs.getZipFile())) - { - zfs.copyFile(true, - getResolvedPath(), target.getResolvedPath(), - options); - } else { - copyToTarget(target, options); - delete(); - } - } - - void copy(ZipPath target, CopyOption... options) - throws IOException - { - if (Files.isSameFile(this.zfs.getZipFile(), target.zfs.getZipFile())) - zfs.copyFile(false, - getResolvedPath(), target.getResolvedPath(), - options); - else - copyToTarget(target, options); - } - - private void copyToTarget(ZipPath target, CopyOption... options) - throws IOException - { - boolean replaceExisting = false; - boolean copyAttrs = false; - for (CopyOption opt : options) { - if (opt == REPLACE_EXISTING) - replaceExisting = true; - else if (opt == COPY_ATTRIBUTES) - copyAttrs = true; - } - // attributes of source file - ZipFileAttributes zfas = getAttributes(); - // check if target exists - boolean exists; - if (replaceExisting) { - try { - target.deleteIfExists(); - exists = false; - } catch (DirectoryNotEmptyException x) { - exists = true; - } - } else { - exists = target.exists(); - } - if (exists) - throw new FileAlreadyExistsException(target.toString()); - - if (zfas.isDirectory()) { - // create directory or file - target.createDirectory(); - } else { - InputStream is = zfs.newInputStream(getResolvedPath()); - try { - OutputStream os = target.newOutputStream(); - try { - byte[] buf = new byte[8192]; - int n = 0; - while ((n = is.read(buf)) != -1) { - os.write(buf, 0, n); - } - } finally { - os.close(); - } - } finally { - is.close(); - } - } - if (copyAttrs) { - BasicFileAttributeView view = - ZipFileAttributeView.get(target, BasicFileAttributeView.class); - try { - view.setTimes(zfas.lastModifiedTime(), - zfas.lastAccessTime(), - zfas.creationTime()); - } catch (IOException x) { - // rollback? - try { - target.delete(); - } catch (IOException ignore) { } - throw x; - } - } - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipUtils.java --- a/jdk/src/share/demo/nio/zipfs/src/com/sun/nio/zipfs/ZipUtils.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This source code is provided to illustrate the usage of a given feature - * or technique and has been deliberately simplified. Additional steps - * required for a production-quality application, such as security checks, - * input validation and proper error handling, might not be present in - * this sample code. - */ - - -package com.sun.nio.zipfs; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Arrays; -import java.util.Date; -import java.util.regex.PatternSyntaxException; -import java.util.concurrent.TimeUnit; - -/** - * - * @author Xueming Shen - */ - -class ZipUtils { - - /* - * Writes a 16-bit short to the output stream in little-endian byte order. - */ - public static void writeShort(OutputStream os, int v) throws IOException { - os.write(v & 0xff); - os.write((v >>> 8) & 0xff); - } - - /* - * Writes a 32-bit int to the output stream in little-endian byte order. - */ - public static void writeInt(OutputStream os, long v) throws IOException { - os.write((int)(v & 0xff)); - os.write((int)((v >>> 8) & 0xff)); - os.write((int)((v >>> 16) & 0xff)); - os.write((int)((v >>> 24) & 0xff)); - } - - /* - * Writes a 64-bit int to the output stream in little-endian byte order. - */ - public static void writeLong(OutputStream os, long v) throws IOException { - os.write((int)(v & 0xff)); - os.write((int)((v >>> 8) & 0xff)); - os.write((int)((v >>> 16) & 0xff)); - os.write((int)((v >>> 24) & 0xff)); - os.write((int)((v >>> 32) & 0xff)); - os.write((int)((v >>> 40) & 0xff)); - os.write((int)((v >>> 48) & 0xff)); - os.write((int)((v >>> 56) & 0xff)); - } - - /* - * Writes an array of bytes to the output stream. - */ - public static void writeBytes(OutputStream os, byte[] b) - throws IOException - { - os.write(b, 0, b.length); - } - - /* - * Writes an array of bytes to the output stream. - */ - public static void writeBytes(OutputStream os, byte[] b, int off, int len) - throws IOException - { - os.write(b, off, len); - } - - /* - * Append a slash at the end, if it does not have one yet - */ - public static byte[] toDirectoryPath(byte[] dir) { - if (dir.length != 0 && dir[dir.length - 1] != '/') { - dir = Arrays.copyOf(dir, dir.length + 1); - dir[dir.length - 1] = '/'; - } - return dir; - } - - /* - * Converts DOS time to Java time (number of milliseconds since epoch). - */ - public static long dosToJavaTime(long dtime) { - Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80), - (int)(((dtime >> 21) & 0x0f) - 1), - (int)((dtime >> 16) & 0x1f), - (int)((dtime >> 11) & 0x1f), - (int)((dtime >> 5) & 0x3f), - (int)((dtime << 1) & 0x3e)); - return d.getTime(); - } - - /* - * Converts Java time to DOS time. - */ - public static long javaToDosTime(long time) { - Date d = new Date(time); - int year = d.getYear() + 1900; - if (year < 1980) { - return (1 << 21) | (1 << 16); - } - return (year - 1980) << 25 | (d.getMonth() + 1) << 21 | - d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 | - d.getSeconds() >> 1; - } - - - // used to adjust values between Windows and java epoch - private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L; - public static final long winToJavaTime(long wtime) { - return TimeUnit.MILLISECONDS.convert( - wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS, TimeUnit.MICROSECONDS); - } - - public static final long javaToWinTime(long time) { - return (TimeUnit.MICROSECONDS.convert(time, TimeUnit.MILLISECONDS) - - WINDOWS_EPOCH_IN_MICROSECONDS) * 10; - } - - public static final long unixToJavaTime(long utime) { - return TimeUnit.MILLISECONDS.convert(utime, TimeUnit.SECONDS); - } - - public static final long javaToUnixTime(long time) { - return TimeUnit.SECONDS.convert(time, TimeUnit.MILLISECONDS); - } - - private static final String regexMetaChars = ".^$+{[]|()"; - private static final String globMetaChars = "\\*?[{"; - private static boolean isRegexMeta(char c) { - return regexMetaChars.indexOf(c) != -1; - } - private static boolean isGlobMeta(char c) { - return globMetaChars.indexOf(c) != -1; - } - private static char EOL = 0; //TBD - private static char next(String glob, int i) { - if (i < glob.length()) { - return glob.charAt(i); - } - return EOL; - } - - /* - * Creates a regex pattern from the given glob expression. - * - * @throws PatternSyntaxException - */ - public static String toRegexPattern(String globPattern) { - boolean inGroup = false; - StringBuilder regex = new StringBuilder("^"); - - int i = 0; - while (i < globPattern.length()) { - char c = globPattern.charAt(i++); - switch (c) { - case '\\': - // escape special characters - if (i == globPattern.length()) { - throw new PatternSyntaxException("No character to escape", - globPattern, i - 1); - } - char next = globPattern.charAt(i++); - if (isGlobMeta(next) || isRegexMeta(next)) { - regex.append('\\'); - } - regex.append(next); - break; - case '/': - regex.append(c); - break; - case '[': - // don't match name separator in class - regex.append("[[^/]&&["); - if (next(globPattern, i) == '^') { - // escape the regex negation char if it appears - regex.append("\\^"); - i++; - } else { - // negation - if (next(globPattern, i) == '!') { - regex.append('^'); - i++; - } - // hyphen allowed at start - if (next(globPattern, i) == '-') { - regex.append('-'); - i++; - } - } - boolean hasRangeStart = false; - char last = 0; - while (i < globPattern.length()) { - c = globPattern.charAt(i++); - if (c == ']') { - break; - } - if (c == '/') { - throw new PatternSyntaxException("Explicit 'name separator' in class", - globPattern, i - 1); - } - // TBD: how to specify ']' in a class? - if (c == '\\' || c == '[' || - c == '&' && next(globPattern, i) == '&') { - // escape '\', '[' or "&&" for regex class - regex.append('\\'); - } - regex.append(c); - - if (c == '-') { - if (!hasRangeStart) { - throw new PatternSyntaxException("Invalid range", - globPattern, i - 1); - } - if ((c = next(globPattern, i++)) == EOL || c == ']') { - break; - } - if (c < last) { - throw new PatternSyntaxException("Invalid range", - globPattern, i - 3); - } - regex.append(c); - hasRangeStart = false; - } else { - hasRangeStart = true; - last = c; - } - } - if (c != ']') { - throw new PatternSyntaxException("Missing ']", globPattern, i - 1); - } - regex.append("]]"); - break; - case '{': - if (inGroup) { - throw new PatternSyntaxException("Cannot nest groups", - globPattern, i - 1); - } - regex.append("(?:(?:"); - inGroup = true; - break; - case '}': - if (inGroup) { - regex.append("))"); - inGroup = false; - } else { - regex.append('}'); - } - break; - case ',': - if (inGroup) { - regex.append(")|(?:"); - } else { - regex.append(','); - } - break; - case '*': - if (next(globPattern, i) == '*') { - // crosses directory boundaries - regex.append(".*"); - i++; - } else { - // within directory boundary - regex.append("[^/]*"); - } - break; - case '?': - regex.append("[^/]"); - break; - default: - if (isRegexMeta(c)) { - regex.append('\\'); - } - regex.append(c); - } - } - if (inGroup) { - throw new PatternSyntaxException("Missing '}", globPattern, i - 1); - } - return regex.append('$').toString(); - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -5166,39 +5166,7 @@ } else if (log_file[0] != '\0' && (errstrm = fopen(log_file,"a+")) != NULL) { return; } else { - char log_file_name[PATH_MAX+100]; - char tmpdir[PATH_MAX]; -#ifdef WIN32 - int n = GetTempPath(PATH_MAX,tmpdir); //API returns with trailing '\' - if (n < 1 || n > PATH_MAX) { - sprintf(tmpdir,"C:\\"); - } - sprintf(log_file_name, "%sunpack.log", tmpdir); -#else - sprintf(tmpdir,"/tmp"); - sprintf(log_file_name, "/tmp/unpack.log"); -#endif - if ((errstrm = fopen(log_file_name, "a+")) != NULL) { - log_file = errstrm_name = saveStr(log_file_name); - return ; - } - - char *tname = tempnam(tmpdir,"#upkg"); - if (tname == NULL) return; - sprintf(log_file_name, "%s", tname); - ::free(tname); - if ((errstrm = fopen(log_file_name, "a+")) != NULL) { - log_file = errstrm_name = saveStr(log_file_name); - return ; - } -#ifndef WIN32 - sprintf(log_file_name, "/dev/null"); - // On windows most likely it will fail. - if ( (errstrm = fopen(log_file_name, "a+")) != NULL) { - log_file = errstrm_name = saveStr(log_file_name); - return ; - } -#endif + fprintf(stderr, "Can not open log file %s\n", log_file); // Last resort // (Do not use stdout, since it might be jarout->jarfp.) errstrm = stderr; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/awt/giflib/dgif_lib.c --- a/jdk/src/share/native/sun/awt/giflib/dgif_lib.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/awt/giflib/dgif_lib.c Wed Apr 16 10:53:10 2014 -0700 @@ -435,9 +435,7 @@ Private->PixelCount = (long)GifFile->Image.Width * (long)GifFile->Image.Height; - DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */ - - return GIF_OK; + return DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */ } /****************************************************************************** diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/awt/image/gif/gifdecoder.c --- a/jdk/src/share/native/sun/awt/image/gif/gifdecoder.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/awt/image/gif/gifdecoder.c Wed Apr 16 10:53:10 2014 -0700 @@ -249,6 +249,7 @@ /* fill the block */ len = (*env)->CallIntMethod(env, this, readID, blockh, remain, blockLength + 1); + if (len > blockLength + 1) len = blockLength + 1; if ((*env)->ExceptionOccurred(env)) { return 0; } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c Wed Apr 16 10:53:10 2014 -0700 @@ -945,6 +945,9 @@ JPEGImageReader_readInputDataID, sb->hstreamBuffer, 0, sb->bufferLength); + if ((ret > 0) && ((unsigned int)ret > sb->bufferLength)) { + ret = sb->bufferLength; + } if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, data, &(src->next_input_byte))) { cinfo->err->error_exit((j_common_ptr) cinfo); @@ -1041,6 +1044,7 @@ JPEGImageReader_readInputDataID, sb->hstreamBuffer, offset, buflen); + if ((ret > 0) && ((unsigned int)ret > buflen)) ret = buflen; if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, data, &(src->next_input_byte))) { cinfo->err->error_exit((j_common_ptr) cinfo); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/awt/image/jpeg/jdmarker.c --- a/jdk/src/share/native/sun/awt/image/jpeg/jdmarker.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/awt/image/jpeg/jdmarker.c Wed Apr 16 10:53:10 2014 -0700 @@ -349,6 +349,12 @@ TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, compptr->dc_tbl_no, compptr->ac_tbl_no); + + /* This CSi (cc) should differ from the previous CSi */ + for (ci = 0; ci < i; ci++) { + if (cinfo->cur_comp_info[ci] == compptr) + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); + } } /* Collect the additional scan parameters Ss, Se, Ah/Al. */ diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/awt/image/jpeg/jpegdecoder.c --- a/jdk/src/share/native/sun/awt/image/jpeg/jpegdecoder.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/awt/image/jpeg/jpegdecoder.c Wed Apr 16 10:53:10 2014 -0700 @@ -289,6 +289,7 @@ buflen = (*env)->GetArrayLength(env, src->hInputBuffer); ret = (*env)->CallIntMethod(env, src->hInputStream, InputStream_readID, src->hInputBuffer, 0, buflen); + if (ret > buflen) ret = buflen; if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); } @@ -349,6 +350,7 @@ } ret = (*env)->CallIntMethod(env, src->hInputStream, InputStream_readID, src->hInputBuffer, offset, buflen); + if ((ret > 0) && ((unsigned int)ret > buflen)) ret = buflen; if ((*env)->ExceptionOccurred(env) || !GET_ARRAYS(env, src)) { cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); } @@ -424,6 +426,7 @@ ret = (*env)->CallIntMethod(env, src->hInputStream, InputStream_readID, src->hInputBuffer, 0, buflen); + if (ret > buflen) ret = buflen; if ((*env)->ExceptionOccurred(env)) { cinfo->err->error_exit((struct jpeg_common_struct *) cinfo); } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/awt/libpng/pngrtran.c --- a/jdk/src/share/native/sun/awt/libpng/pngrtran.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/awt/libpng/pngrtran.c Wed Apr 16 10:53:10 2014 -0700 @@ -1862,6 +1862,9 @@ info_ptr->bit_depth = 8; info_ptr->num_trans = 0; + + if (png_ptr->palette == NULL) + png_error (png_ptr, "Palette is NULL in indexed image"); } else { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/awt/libpng/pngset.c --- a/jdk/src/share/native/sun/awt/libpng/pngset.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/awt/libpng/pngset.c Wed Apr 16 10:53:10 2014 -0700 @@ -512,6 +512,17 @@ } } + if ((num_palette > 0 && palette == NULL) || + (num_palette == 0 +# ifdef PNG_MNG_FEATURES_SUPPORTED + && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 +# endif + )) + { + png_error(png_ptr, "Invalid palette"); + return; + } + /* It may not actually be necessary to set png_ptr->palette here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c --- a/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c Wed Apr 16 10:53:10 2014 -0700 @@ -228,6 +228,49 @@ } } +/* + * We have to make sure that awt_setPixels can be safely applied to the given pair of + * raster and mlib image. + * + * In particular, make sure that + * - dimension is the same + * - number of channels in mlib image corresponds to the number of bands in the raster + * - sample size in image and raster are the same. + * + * Returns: + * -1 to indicate failure, + * 1 to indicate success + */ +static int setPixelsFormMlibImage(JNIEnv *env, RasterS_t *rasterP, mlib_image* img) { + if (rasterP->width != img->width || rasterP->height != img->height) { + /* dimension does not match */ + return -1; + } + + if (rasterP->numBands != img->channels) { + /* number of bands does not match */ + return -1; + } + + switch (rasterP->dataType) { + case BYTE_DATA_TYPE: + if (img->type != MLIB_BYTE) { + return -1; + } + break; + case SHORT_DATA_TYPE: + if (img->type != MLIB_SHORT && img->type != MLIB_USHORT) { + return -1; + } + break; + default: + /* awt_setPixels does not support such rasters */ + return -1; + } + + return awt_setPixels(env, rasterP, mlib_ImageGetData(img)); +} + /*************************************************************************** * External Functions * ***************************************************************************/ @@ -700,7 +743,9 @@ /* Means that we couldn't write directly into the destination buffer */ if (ddata == NULL) { - retStatus = awt_setPixels(env, dstRasterP, mlib_ImageGetData(dst)); + if (storeRasterArray(env, srcRasterP, dstRasterP, dst) < 0) { + retStatus = setPixelsFormMlibImage(env, dstRasterP, dst); + } } /* Release the pinned memory */ @@ -1107,7 +1152,7 @@ /* Need to store it back into the array */ if (storeRasterArray(env, srcRasterP, dstRasterP, dst) < 0) { (*env)->ExceptionClear(env); // Could not store the array, try another way - retStatus = awt_setPixels(env, dstRasterP, mlib_ImageGetData(dst)); + retStatus = setPixelsFormMlibImage(env, dstRasterP, dst); } } @@ -1433,6 +1478,14 @@ retStatus = 0; } + /* Release the LUT */ + for (i=0; i < lut_nbands; i++) { + (*env)->ReleasePrimitiveArrayCritical(env, jtable[i].jArray, + (jbyte *) jtable[i].table, JNI_ABORT); + } + free ((void *) jtable); + free ((void *) tbl); + /* * Means that we couldn't write directly into * the destination buffer @@ -1446,13 +1499,6 @@ } } - /* Release the LUT */ - for (i=0; i < lut_nbands; i++) { - (*env)->ReleasePrimitiveArrayCritical(env, jtable[i].jArray, - (jbyte *) jtable[i].table, JNI_ABORT); - } - free ((void *) jtable); - free ((void *) tbl); /* Release the pinned memory */ freeArray(env, srcImageP, src, sdata, dstImageP, dst, ddata); @@ -1670,18 +1716,20 @@ retStatus = 0; } + /* Release the LUT */ + for (i=0; i < lut_nbands; i++) { + (*env)->ReleasePrimitiveArrayCritical(env, jtable[i].jArray, + (jbyte *) jtable[i].table, JNI_ABORT); + } + /* * Means that we couldn't write directly into * the destination buffer */ if (ddata == NULL) { - retStatus = awt_setPixels(env, dstRasterP, mlib_ImageGetData(dst)); - } - - /* Release the LUT */ - for (i=0; i < lut_nbands; i++) { - (*env)->ReleasePrimitiveArrayCritical(env, jtable[i].jArray, - (jbyte *) jtable[i].table, JNI_ABORT); + if (storeRasterArray(env, srcRasterP, dstRasterP, dst) < 0) { + retStatus = setPixelsFormMlibImage(env, dstRasterP, dst); + } } /* Release the pinned memory */ @@ -2643,7 +2691,7 @@ } } else if (mlibImP->type == MLIB_SHORT) { - return awt_setPixels(env, rasterP, mlibImP->data); + return setPixelsFormMlibImage(env, rasterP, mlibImP); } } else { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp --- a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -154,6 +154,7 @@ TTGlyphID glyphCode = (TTGlyphID) LE_GET_GLYPH(gid); if ((glyphCode >= firstGlyph) && (glyphCode < lastGlyph)) { LEReferenceToArrayOf valueArray(lookupTable8, success, &lookupTable8->valueArray[0], glyphCount); + if (LE_FAILURE(success)) { return newGlyph; } newGlyph = SWAPW(valueArray(glyphCode - firstGlyph, success)); } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp --- a/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/font/layout/ContextualSubstSubtables.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -110,6 +110,8 @@ LEErrorCode &success, le_bool backtrack) { + if (LE_FAILURE(success)) { return FALSE; } + le_int32 direction = 1; le_int32 match = 0; @@ -255,6 +257,7 @@ le_uint16 matchCount = SWAPW(subRuleTable->glyphCount) - 1; le_uint16 substCount = SWAPW(subRuleTable->substCount); LEReferenceToArrayOf inputGlyphArray(base, success, subRuleTable->inputGlyphArray, matchCount+2); + if (LE_FAILURE(success)) { return 0; } if (matchGlyphIDs(inputGlyphArray, matchCount, glyphIterator)) { LEReferenceToArrayOf substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &subRuleTable->inputGlyphArray[matchCount], substCount); @@ -315,6 +318,7 @@ LEReferenceToArrayOf classArray(base, success, subClassRuleTable->classArray, matchCount+1); + if (LE_FAILURE(success)) { return 0; } if (matchGlyphClasses(classArray, matchCount, glyphIterator, classDefinitionTable, success)) { LEReferenceToArrayOf substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) &subClassRuleTable->classArray[matchCount], substCount); @@ -573,7 +577,7 @@ if (matchGlyphClasses(inputClassArray, inputGlyphCount, glyphIterator, inputClassDefinitionTable, success)) { LEReferenceToArrayOf substLookupRecordArray(base, success, (const SubstitutionLookupRecord *) lookaheadClassArray.getAlias(lookaheadGlyphCount + 1, success), substCount); - + if (LE_FAILURE(success)) { return 0; } applySubstitutionLookups(lookupProcessor, substLookupRecordArray, substCount, glyphIterator, fontInstance, position, success); return inputGlyphCount + 1; @@ -601,9 +605,10 @@ le_uint16 backtrkGlyphCount = SWAPW(backtrackGlyphCount); le_uint16 inputGlyphCount = (le_uint16) SWAPW(backtrackCoverageTableOffsetArray[backtrkGlyphCount]); LEReferenceToArrayOf inputCoverageTableOffsetArray(base, success, &backtrackCoverageTableOffsetArray[backtrkGlyphCount + 1], inputGlyphCount+2); // offset + if (LE_FAILURE(success)) { return 0; } const le_uint16 lookaheadGlyphCount = (le_uint16) SWAPW(inputCoverageTableOffsetArray[inputGlyphCount]); - if( LE_FAILURE(success) ) { return 0; } + if( LE_FAILURE(success)) { return 0; } LEReferenceToArrayOf lookaheadCoverageTableOffsetArray(base, success, inputCoverageTableOffsetArray.getAlias(inputGlyphCount + 1, success), lookaheadGlyphCount+2); if( LE_FAILURE(success) ) { return 0; } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp --- a/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/font/layout/LigatureSubstProc2.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -95,7 +95,7 @@ if (actionOffset != 0) { LEReferenceTo ap(stHeader, success, ligActionOffset); // byte offset - ap.addObject(ligActionIndex - 1, success); // index offset ( one before the actual start, because we will pre-increment) + ap.addObject(ligActionIndex, success); LEReferenceToArrayOf ligatureTable(stHeader, success, ligatureOffset, LE_UNBOUNDED_ARRAY); LigatureActionEntry action; le_int32 offset, i = 0; @@ -111,7 +111,6 @@ do { le_uint32 componentGlyph = componentStack[m--]; // pop off - ap.addObject(success); action = SWAPL(*ap.getAlias()); if (m < 0) { @@ -145,7 +144,8 @@ LE_DEBUG_BAD_FONT("m<0") } #endif - } while (!(action & lafLast) && (m>=0) ); // stop if last bit is set, or if run out of items + ap.addObject(success); + } while (LE_SUCCESS(success) && !(action & lafLast) && (m>=0) ); // stop if last bit is set, or if run out of items while (mm >= 0) { if (++m >= nComponents) { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/font/layout/LookupProcessor.cpp --- a/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/font/layout/LookupProcessor.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -282,6 +282,7 @@ for (le_uint16 feature = 0; feature < featureCount; feature += 1) { LEReferenceToArrayOf featureIndexArray(langSysTable, success, langSysTable->featureIndexArray, featureCount); + if (LE_FAILURE(success)) { continue; } le_uint16 featureIndex = SWAPW(featureIndexArray.getObject(feature,success)); // don't add the required feature to the list more than once... diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp --- a/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -67,6 +67,7 @@ LEPoint markAnchor; LEReferenceTo markArray(base, success, (const MarkArray *) ((char *) this + SWAPW(markArrayOffset))); + if(LE_FAILURE(success)) return 0; le_int32 markClass = markArray->getMarkClass(markArray, markGlyph, markCoverage, fontInstance, markAnchor, success); le_uint16 mcCount = SWAPW(classCount); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/font/layout/OpenTypeUtilities.cpp --- a/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/font/layout/OpenTypeUtilities.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -79,8 +79,8 @@ Offset OpenTypeUtilities::getTagOffset(LETag tag, const LEReferenceToArrayOf &records, LEErrorCode &success) { + if(LE_FAILURE(success)) return 0; const TagAndOffsetRecord *r0 = (const TagAndOffsetRecord*)records.getAlias(); - if(LE_FAILURE(success)) return 0; le_uint32 recordCount = records.getCount(); le_uint8 bit = highBit(recordCount); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.cpp --- a/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/font/layout/SegmentArrayProcessor.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -73,6 +73,7 @@ if (offset != 0) { LEReferenceToArrayOf glyphArray(subtableHeader, success, offset, LE_UNBOUNDED_ARRAY); + if (LE_FAILURE(success)) { continue; } TTGlyphID newGlyph = SWAPW(glyphArray(LE_GET_GLYPH(thisGlyph) - firstGlyph, success)); glyphStorage[glyph] = LE_SET_GLYPH(thisGlyph, newGlyph); } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp --- a/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/font/layout/StateTableProcessor.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -97,6 +97,7 @@ LEReferenceToArrayOf stateArray(stHeader, success, currentState, LE_UNBOUNDED_ARRAY); EntryTableIndex entryTableIndex = stateArray.getObject((le_uint8)classCode, success); + if (LE_FAILURE(success)) { break; } LE_STATE_PATIENCE_CURR(le_int32, currGlyph); currentState = processStateEntry(glyphStorage, currGlyph, entryTableIndex); LE_STATE_PATIENCE_INCR(currGlyph); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c Wed Apr 16 10:53:10 2014 -0700 @@ -81,7 +81,7 @@ cmsUInt32Number surround; cmsFloat64Number n, Nbb, Ncb, z, FL, D; - cmsContext ContextID; + cmsContext ContextID; } cmsCIECAM02; @@ -467,6 +467,7 @@ CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; + memset(&clr, 0, sizeof(clr)); _cmsAssert(lpMod != NULL); _cmsAssert(pIn != NULL); _cmsAssert(pOut != NULL); @@ -491,6 +492,7 @@ CAM02COLOR clr; cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel; + memset(&clr, 0, sizeof(clr)); _cmsAssert(lpMod != NULL); _cmsAssert(pIn != NULL); _cmsAssert(pOut != NULL); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c Wed Apr 16 10:53:10 2014 -0700 @@ -59,8 +59,8 @@ // IT8.7 / CGATS.17-200x handling ----------------------------------------------------------------------------- -#define MAXID 128 // Max lenght of identifier -#define MAXSTR 1024 // Max lenght of string +#define MAXID 128 // Max length of identifier +#define MAXSTR 1024 // Max length of string #define MAXTABLES 255 // Max Number of tables in a single stream #define MAXINCLUDE 20 // Max number of nested includes @@ -383,28 +383,28 @@ //Forward declaration of some internal functions static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size); -// Checks if c is a separator +// Checks whatever c is a separator static cmsBool isseparator(int c) { - return (c == ' ') || (c == '\t') || (c == '\r'); + return (c == ' ') || (c == '\t') ; } -// Checks whatever if c is a valid identifier char +// Checks whatever c is a valid identifier char static cmsBool ismiddle(int c) { return (!isseparator(c) && (c != '#') && (c !='\"') && (c != '\'') && (c > 32) && (c < 127)); } -// Checks whatsever if c is a valid identifier middle char. +// Checks whatsever c is a valid identifier middle char. static cmsBool isidchar(int c) { return isalnum(c) || ismiddle(c); } -// Checks whatsever if c is a valid identifier first char. +// Checks whatsever c is a valid identifier first char. static cmsBool isfirstidchar(int c) { @@ -436,7 +436,6 @@ } - // Makes a file path based on a given reference path // NOTE: this function doesn't check if the path exists or even if it's legal static @@ -634,6 +633,7 @@ cmsFloat64Number dnum = 0.0; int sign = 1; + // keep safe if (Buffer == NULL) return 0.0; if (*Buffer == '-' || *Buffer == '+') { @@ -869,6 +869,14 @@ // Next line + case '\r': + NextCh(it8); + if (it8 ->ch == '\n') + NextCh(it8); + it8->sy = SEOLN; + it8->lineno++; + break; + case '\n': NextCh(it8); it8->sy = SEOLN; @@ -878,7 +886,7 @@ // Comment case '#': NextCh(it8); - while (it8->ch && it8->ch != '\n') + while (it8->ch && it8->ch != '\n' && it8->ch != '\r') NextCh(it8); it8->sy = SCOMMENT; @@ -996,6 +1004,9 @@ { switch (it8->sy) { + case SEOLN: // Empty value + Buffer[0]=0; + break; case SIDENT: strncpy(Buffer, it8->id, max); Buffer[max-1]=0; break; @@ -1145,9 +1156,9 @@ if (*Key != '#') { // Comments are ignored if (cmsstrcasecmp(Key, p->Keyword) == 0) - break; + break; } - } + } if (p == NULL) return FALSE; @@ -1157,11 +1168,13 @@ for (; p != NULL; p = p->NextSubkey) { + if (p ->Subkey == NULL) continue; + if (LastPtr) *LastPtr = p; if (cmsstrcasecmp(Subkey, p->Subkey) == 0) - return TRUE; - } + return TRUE; + } return FALSE; } @@ -1284,7 +1297,7 @@ it8 ->nTable = nTable; - return nTable; + return (cmsInt32Number) nTable; } @@ -1389,7 +1402,7 @@ cmsIT8* it8 = (cmsIT8*) hIT8; char Buffer[1024]; - sprintf(Buffer, "%d", Val); + sprintf(Buffer, "%u", Val); return AddToList(it8, &GetTable(it8)->HeaderList, cProp, NULL, Buffer, WRITE_HEXADECIMAL) != NULL; } @@ -1426,6 +1439,8 @@ { const char *v = cmsIT8GetProperty(hIT8, cProp); + if (v == NULL) return 0.0; + return ParseFloatNumber(v); } @@ -1458,7 +1473,7 @@ t -> nSamples = 10; } - t -> DataFormat = (char**) AllocChunk (it8, (t->nSamples + 1) * sizeof(char *)); + t -> DataFormat = (char**) AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * sizeof(char *)); if (t->DataFormat == NULL) { SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array"); @@ -1514,7 +1529,7 @@ t-> nSamples = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); t-> nPatches = atoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); - t-> Data = (char**)AllocChunk (it8, (t->nSamples + 1) * (t->nPatches + 1) *sizeof (char*)); + t-> Data = (char**)AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * ((cmsUInt32Number) t->nPatches + 1) *sizeof (char*)); if (t->Data == NULL) { SynError(it8, "AllocateDataSet: Unable to allocate data array"); @@ -1573,7 +1588,7 @@ if (str == NULL) str = " "; - // Lenghth to write + // Length to write len = (cmsUInt32Number) strlen(str); f ->Used += len; @@ -2097,7 +2112,7 @@ NextCh(it8); // If a newline is found, then this is a type string - if (it8 ->ch == '\n') { + if (it8 ->ch == '\n' || it8->ch == '\r') { cmsIT8SetSheetType(it8, it8 ->id); InSymbol(it8); @@ -2212,7 +2227,7 @@ char Buffer[256]; char *Type = p ->Value; - int nTable = k; + int nTable = (int) k; snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type ); @@ -2566,6 +2581,8 @@ Buffer = cmsIT8GetDataRowCol(hIT8, row, col); + if (Buffer == NULL) return 0.0; + return ParseFloatNumber(Buffer); } @@ -2778,7 +2795,7 @@ if (Formatter == NULL) strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); else - strcpy(it8->DoubleFormatter, Formatter); + strncpy(it8->DoubleFormatter, Formatter, sizeof(it8->DoubleFormatter)); it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c Wed Apr 16 10:53:10 2014 -0700 @@ -270,7 +270,7 @@ // m2 holds CHAD from output white to D50 times abs. col. scaling // Observer is not adapted, undo the chromatic adaptation - _cmsMAT3per(m, &m3, ChromaticAdaptationMatrixOut); + _cmsMAT3per(m, &m2, ChromaticAdaptationMatrixOut); m3 = *ChromaticAdaptationMatrixIn; if (!_cmsMAT3inverse(&m3, &m4)) return FALSE; @@ -411,57 +411,61 @@ // Handle PCS mismatches. A specialized stage is added to the LUT in such case switch (InPCS) { - case cmsSigXYZData: // Input profile operates in XYZ - - switch (OutPCS) { + case cmsSigXYZData: // Input profile operates in XYZ - case cmsSigXYZData: // XYZ -> XYZ - if (!IsEmptyLayer(m, off)) - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - break; + switch (OutPCS) { - case cmsSigLabData: // XYZ -> Lab - if (!IsEmptyLayer(m, off)) - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)); - break; + case cmsSigXYZData: // XYZ -> XYZ + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + break; - default: - return FALSE; // Colorspace mismatch - } - break; - + case cmsSigLabData: // XYZ -> Lab + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) + return FALSE; + break; - case cmsSigLabData: // Input profile operates in Lab - - switch (OutPCS) { + default: + return FALSE; // Colorspace mismatch + } + break; - case cmsSigXYZData: // Lab -> XYZ + case cmsSigLabData: // Input profile operates in Lab - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)); - if (!IsEmptyLayer(m, off)) - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - break; + switch (OutPCS) { + + case cmsSigXYZData: // Lab -> XYZ - case cmsSigLabData: // Lab -> Lab + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID))) + return FALSE; + if (!IsEmptyLayer(m, off) && + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl))) + return FALSE; + break; - if (!IsEmptyLayer(m, off)) { - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)); - cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)); - cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID)); - } - break; + case cmsSigLabData: // Lab -> Lab - default: - return FALSE; // Mismatch + if (!IsEmptyLayer(m, off)) { + if (!cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocLab2XYZ(Result ->ContextID)) || + !cmsPipelineInsertStage(Result, cmsAT_END, cmsStageAllocMatrix(Result ->ContextID, 3, 3, m_as_dbl, off_as_dbl)) || + !cmsPipelineInsertStage(Result, cmsAT_END, _cmsStageAllocXYZ2Lab(Result ->ContextID))) + return FALSE; } break; + default: + return FALSE; // Mismatch + } + break; - // On colorspaces other than PCS, check for same space - default: - if (InPCS != OutPCS) return FALSE; - break; + // On colorspaces other than PCS, check for same space + default: + if (InPCS != OutPCS) return FALSE; + break; } return TRUE; @@ -497,7 +501,8 @@ cmsFloat64Number AdaptationStates[], cmsUInt32Number dwFlags) { - cmsPipeline* Lut, *Result; + cmsPipeline* Lut = NULL; + cmsPipeline* Result; cmsHPROFILE hProfile; cmsMAT3 m; cmsVEC3 off; @@ -593,8 +598,11 @@ } // Concatenate to the output LUT - cmsPipelineCat(Result, Lut); + if (!cmsPipelineCat(Result, Lut)) + goto Error; + cmsPipelineFree(Lut); + Lut = NULL; // Update current space CurrentColorSpace = ColorSpaceOut; @@ -604,6 +612,7 @@ Error: + if (Lut != NULL) cmsPipelineFree(Lut); if (Result != NULL) cmsPipelineFree(Result); return NULL; @@ -742,7 +751,8 @@ if (CLUT == NULL) goto Error; // This is the one and only MPE in this LUT - cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); + if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) + goto Error; // Sample it. We cannot afford pre/post linearization this time. if (!cmsStageSampleCLut16bit(CLUT, BlackPreservingGrayOnlySampler, (void*) &bp, 0)) @@ -959,7 +969,8 @@ CLUT = cmsStageAllocCLut16bit(ContextID, nGridPoints, 4, 4, NULL); if (CLUT == NULL) goto Cleanup; - cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT); + if (!cmsPipelineInsertStage(Result, cmsAT_BEGIN, CLUT)) + goto Cleanup; cmsStageSampleCLut16bit(CLUT, BlackPreservingSampler, (void*) &bp, 0); @@ -1057,7 +1068,7 @@ } // The plug-in registration. User can add new intents or override default routines -cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data) { cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data; cmsIntentsList* fl; @@ -1072,7 +1083,7 @@ fl = SearchIntent(Plugin ->Intent); if (fl == NULL) { - fl = (cmsIntentsList*) _cmsPluginMalloc(sizeof(cmsIntentsList)); + fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList)); if (fl == NULL) return FALSE; } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c Wed Apr 16 10:53:10 2014 -0700 @@ -302,8 +302,6 @@ return NULL; } - - chunk ->BlockSize = Initial; chunk ->Used = 0; chunk ->next = NULL; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c Wed Apr 16 10:53:10 2014 -0700 @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2012 Marti Maria Saguer +// Copyright (c) 1998-2013 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -99,7 +99,7 @@ static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves; // As a way to install new parametric curves -cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data) { cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data; _cmsParametricCurvesCollection* fl; @@ -110,7 +110,7 @@ return TRUE; } - fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(sizeof(_cmsParametricCurvesCollection)); + fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(id, sizeof(_cmsParametricCurvesCollection)); if (fl == NULL) return FALSE; // Copy the parameters @@ -258,7 +258,8 @@ } p ->InterpParams = _cmsComputeInterpParams(ContextID, p ->nEntries, 1, 1, p->Table16, CMS_LERP_FLAGS_16BITS); - return p; + if (p->InterpParams != NULL) + return p; Error: if (p -> Segments) _cmsFree(ContextID, p ->Segments); @@ -423,7 +424,7 @@ if (e > 0) Val = pow(e, Params[0]) + Params[5]; else - Val = 0; + Val = Params[5]; } else Val = R*Params[3] + Params[6]; @@ -458,7 +459,7 @@ e = Params[1]*R + Params[2]; if (e < 0) - Val = 0; + Val = Params[3]; else Val = pow(e, Params[0]) + Params[3]; break; @@ -478,7 +479,7 @@ e = Params[2] * pow(R, Params[0]) + Params[3]; if (e <= 0) - Val = 0; + Val = Params[4]; else Val = Params[1]*log10(e) + Params[4]; break; @@ -544,7 +545,7 @@ // Type == 0 means segment is sampled if (g ->Segments[i].Type == 0) { - cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0); + cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0) / (g ->Segments[i].x1 - g ->Segments[i].x0); cmsFloat32Number Out; // Setup the table (TODO: clean that) @@ -629,20 +630,21 @@ // Use a segmented curve to store the floating point table cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]) { - cmsCurveSegment Seg[2]; + cmsCurveSegment Seg[3]; - // Initialize segmented curve part up to 0 - Seg[0].x0 = -1; + // A segmented tone curve should have function segments in the first and last positions + // Initialize segmented curve part up to 0 to constant value = samples[0] + Seg[0].x0 = MINUS_INF; Seg[0].x1 = 0; Seg[0].Type = 6; Seg[0].Params[0] = 1; Seg[0].Params[1] = 0; Seg[0].Params[2] = 0; - Seg[0].Params[3] = 0; + Seg[0].Params[3] = values[0]; Seg[0].Params[4] = 0; - // From zero to any + // From zero to 1 Seg[1].x0 = 0; Seg[1].x1 = 1.0; Seg[1].Type = 0; @@ -650,7 +652,19 @@ Seg[1].nGridPoints = nEntries; Seg[1].SampledPoints = (cmsFloat32Number*) values; - return cmsBuildSegmentedToneCurve(ContextID, 2, Seg); + // Final segment is constant = lastsample + Seg[2].x0 = 1.0; + Seg[2].x1 = PLUS_INF; + Seg[2].Type = 6; + + Seg[2].Params[0] = 1; + Seg[2].Params[1] = 0; + Seg[2].Params[2] = 0; + Seg[2].Params[3] = values[nEntries-1]; + Seg[2].Params[4] = 0; + + + return cmsBuildSegmentedToneCurve(ContextID, 3, Seg); } // Parametric curves @@ -993,7 +1007,7 @@ if (Tab == NULL) return FALSE; - if (cmsIsToneCurveLinear(Tab)) return FALSE; // Nothing to do + if (cmsIsToneCurveLinear(Tab)) return TRUE; // Nothing to do nItems = Tab -> nEntries; @@ -1020,11 +1034,20 @@ if (z[i] == 0.) Zeros++; if (z[i] >= 65535.) Poles++; - if (z[i] < z[i-1]) return FALSE; // Non-Monotonic + if (z[i] < z[i-1]) { + cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic."); + return FALSE; + } } - if (Zeros > (nItems / 3)) return FALSE; // Degenerated, mostly zeros - if (Poles > (nItems / 3)) return FALSE; // Degenerated, mostly poles + if (Zeros > (nItems / 3)) { + cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros."); + return FALSE; + } + if (Poles > (nItems / 3)) { + cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles."); + return FALSE; + } // Seems ok for (i=0; i < nItems; i++) { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c Wed Apr 16 10:53:10 2014 -0700 @@ -249,13 +249,10 @@ cmsFloat64Number dE1, dE2, ErrorRatio; // Assume in-gamut by default. - dE1 = 0.; - dE2 = 0; ErrorRatio = 1.0; // Convert input to Lab - if (t -> hInput != NULL) - cmsDoTransform(t -> hInput, In, &LabIn1, 1); + cmsDoTransform(t -> hInput, In, &LabIn1, 1); // converts from PCS to colorant. This always // does return in-gamut values, @@ -267,7 +264,7 @@ memmove(&LabIn2, &LabOut1, sizeof(cmsCIELab)); // Try again, but this time taking Check as input - cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); + cmsDoTransform(t -> hForward, &LabOut1, Proof2, 1); cmsDoTransform(t -> hReverse, Proof2, &LabOut2, 1); // Take difference of direct value @@ -374,7 +371,7 @@ ProfileList[nGamutPCSposition] = hLab; BPCList[nGamutPCSposition] = 0; AdaptationList[nGamutPCSposition] = 1.0; - Intents[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC; + IntentList[nGamutPCSposition] = INTENT_RELATIVE_COLORIMETRIC; ColorSpace = cmsGetColorSpace(hGamut); @@ -385,45 +382,48 @@ // 16 bits to Lab double Chain.hInput = cmsCreateExtendedTransform(ContextID, - nGamutPCSposition + 1, - ProfileList, - BPCList, - Intents, - AdaptationList, - NULL, 0, - dwFormat, TYPE_Lab_DBL, - cmsFLAGS_NOCACHE); + nGamutPCSposition + 1, + ProfileList, + BPCList, + IntentList, + AdaptationList, + NULL, 0, + dwFormat, TYPE_Lab_DBL, + cmsFLAGS_NOCACHE); // Does create the forward step. Lab double to device dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); Chain.hForward = cmsCreateTransformTHR(ContextID, - hLab, TYPE_Lab_DBL, - hGamut, dwFormat, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE); + hLab, TYPE_Lab_DBL, + hGamut, dwFormat, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE); // Does create the backwards step Chain.hReverse = cmsCreateTransformTHR(ContextID, hGamut, dwFormat, - hLab, TYPE_Lab_DBL, - INTENT_RELATIVE_COLORIMETRIC, - cmsFLAGS_NOCACHE); + hLab, TYPE_Lab_DBL, + INTENT_RELATIVE_COLORIMETRIC, + cmsFLAGS_NOCACHE); // All ok? - if (Chain.hForward && Chain.hReverse) { + if (Chain.hInput && Chain.hForward && Chain.hReverse) { // Go on, try to compute gamut LUT from PCS. This consist on a single channel containing // dE when doing a transform back and forth on the colorimetric intent. Gamut = cmsPipelineAlloc(ContextID, 3, 1); - if (Gamut != NULL) { - CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); - cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT); - - cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); + CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); + if (!cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT)) { + cmsPipelineFree(Gamut); + Gamut = NULL; + } + else { + cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); + } } } else diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c Wed Apr 16 10:53:10 2014 -0700 @@ -83,7 +83,6 @@ // Set the interpolation method - cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) { // Invoke factory, possibly in the Plug-in @@ -831,7 +830,7 @@ register cmsUInt16Number Output[], register const cmsInterpParams* p16) { - const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; + const cmsUInt16Number* LutTable; cmsS15Fixed16Number fk; cmsS15Fixed16Number k0, rk; int K0, K1; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c Wed Apr 16 10:53:10 2014 -0700 @@ -154,7 +154,6 @@ return iohandler; Error: - if (fm) _cmsFree(ContextID, fm); if (iohandler) _cmsFree(ContextID, iohandler); return NULL; @@ -223,12 +222,17 @@ // Writes data to memory, also keeps used space for further reference. static -cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) +cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, const void *Ptr) { FILEMEM* ResData = (FILEMEM*) iohandler ->stream; if (ResData == NULL) return FALSE; // Housekeeping + // Check for available space. Clip. + if (iohandler ->UsedSpace + size > ResData->Size) { + size = ResData ->Size - iohandler ->UsedSpace; + } + if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing memmove(ResData ->Block + ResData ->Pointer, Ptr, size); @@ -350,7 +354,7 @@ return nReaded; } -// Position file pointer in the file +// Postion file pointer in the file static cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset) { @@ -389,13 +393,15 @@ return TRUE; } -// Create a iohandler for disk based files. if FileName is NULL, then 'stream' member is also set -// to NULL and no real writting is performed. This only happens in writting access mode +// Create a iohandler for disk based files. cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const char* FileName, const char* AccessMode) { cmsIOHANDLER* iohandler = NULL; FILE* fm = NULL; + _cmsAssert(FileName != NULL); + _cmsAssert(AccessMode != NULL); + iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); if (iohandler == NULL) return NULL; @@ -432,11 +438,8 @@ iohandler ->UsedSpace = 0; // Keep track of the original file - if (FileName != NULL) { - - strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1); - iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0; - } + strncpy(iohandler -> PhysicalFile, FileName, sizeof(iohandler -> PhysicalFile)-1); + iohandler -> PhysicalFile[sizeof(iohandler -> PhysicalFile)-1] = 0; iohandler ->Read = FileRead; iohandler ->Seek = FileSeek; @@ -616,6 +619,31 @@ return _cmsSearchTag(Icc, sig, FALSE) >= 0; } +/* + * Enforces that the profile version is per. spec. + * Operates on the big endian bytes from the profile. + * Called before converting to platform endianness. + * Byte 0 is BCD major version, so max 9. + * Byte 1 is 2 BCD digits, one per nibble. + * Reserved bytes 2 & 3 must be 0. + */ +static cmsUInt32Number _validatedVersion(cmsUInt32Number DWord) +{ + cmsUInt8Number* pByte = (cmsUInt8Number*)&DWord; + cmsUInt8Number temp1; + cmsUInt8Number temp2; + + if (*pByte > 0x09) *pByte = (cmsUInt8Number)9; + temp1 = *(pByte+1) & 0xf0; + temp2 = *(pByte+1) & 0x0f; + if (temp1 > 0x90) temp1 = 0x90; + if (temp2 > 9) temp2 = 0x09; + *(pByte+1) = (cmsUInt8Number)(temp1 | temp2); + *(pByte+2) = (cmsUInt8Number)0; + *(pByte+3) = (cmsUInt8Number)0; + + return DWord; +} // Read profile header and validate it cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) @@ -643,12 +671,15 @@ Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); + Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent); Icc -> flags = _cmsAdjustEndianess32(Header.flags); Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); Icc -> model = _cmsAdjustEndianess32(Header.model); + Icc -> creator = _cmsAdjustEndianess32(Header.creator); + _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes); - Icc -> Version = _cmsAdjustEndianess32(Header.version); + Icc -> Version = _cmsAdjustEndianess32(_validatedVersion(Header.version)); // Get size as reported in header HeaderSize = _cmsAdjustEndianess32(Header.size); @@ -815,28 +846,33 @@ cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return (cmsUInt32Number) Icc ->manufacturer; + return Icc ->manufacturer; } void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> manufacturer = (cmsUInt32Number) manufacturer; + Icc -> manufacturer = manufacturer; +} + +cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile) +{ + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + return Icc ->creator; } cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - return (cmsUInt32Number) Icc ->model; + return Icc ->model; } void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> model = (cmsUInt32Number) model; + Icc -> model = model; } - void CMSEXPORT cmsGetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number* Flags) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; @@ -1073,7 +1109,6 @@ return cmsOpenProfileFromMemTHR(NULL, MemPtr, dwSize); } - static cmsBool SanityCheck(_cmsICCPROFILE* profile) { @@ -1112,11 +1147,13 @@ cmsIOHANDLER* io = Icc ->IOhandler; cmsTagDescriptor* TagDescriptor; cmsTagTypeSignature TypeBase; + cmsTagTypeSignature Type; cmsTagTypeHandler* TypeHandler; + cmsFloat64Number Version = cmsGetProfileVersion((cmsHPROFILE) Icc); + cmsTagTypeHandler LocalTypeHandler; for (i=0; i < Icc -> TagCount; i++) { - if (Icc ->TagNames[i] == 0) continue; // Linked tags are not written @@ -1168,7 +1205,16 @@ TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]); if (TagDescriptor == NULL) continue; // Unsupported, ignore it - TypeHandler = Icc ->TagTypeHandlers[i]; + if (TagDescriptor ->DecideType != NULL) { + + Type = TagDescriptor ->DecideType(Version, Data); + } + else { + + Type = TagDescriptor ->SupportedTypes[0]; + } + + TypeHandler = _cmsGetTagTypeHandler(Type); if (TypeHandler == NULL) { cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]); @@ -1179,9 +1225,10 @@ if (!_cmsWriteTypeBase(io, TypeBase)) return FALSE; - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - if (!TypeHandler ->WritePtr(TypeHandler, io, Data, TagDescriptor ->ElemCount)) { + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, io, Data, TagDescriptor ->ElemCount)) { char String[5]; @@ -1318,8 +1365,8 @@ // Should we just calculate the needed space? if (MemPtr == NULL) { - *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); - return (*BytesNeeded == 0 ? FALSE : TRUE); + *BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL); + return (*BytesNeeded == 0 ? FALSE : TRUE); } // That is a real write operation @@ -1357,10 +1404,11 @@ cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; if (TypeHandler != NULL) { + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; - TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameters - TypeHandler ->ICCVersion = Icc ->Version; - TypeHandler ->FreePtr(TypeHandler, Icc -> TagPtrs[i]); + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); } else _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); @@ -1404,6 +1452,7 @@ _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; cmsIOHANDLER* io = Icc ->IOhandler; cmsTagTypeHandler* TypeHandler; + cmsTagTypeHandler LocalTypeHandler; cmsTagDescriptor* TagDescriptor; cmsTagTypeSignature BaseType; cmsUInt32Number Offset, TagSize; @@ -1427,7 +1476,7 @@ // Seek to its location if (!io -> Seek(io, Offset)) - return NULL; + return NULL; // Search for support on this tag TagDescriptor = _cmsGetTagDescriptor(sig); @@ -1444,14 +1493,15 @@ // Get type handler TypeHandler = _cmsGetTagTypeHandler(BaseType); if (TypeHandler == NULL) return NULL; + LocalTypeHandler = *TypeHandler; // Read the tag Icc -> TagTypeHandlers[n] = TypeHandler; - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - Icc -> TagPtrs[n] = TypeHandler ->ReadPtr(TypeHandler, io, &ElemCount, TagSize); + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + Icc -> TagPtrs[n] = LocalTypeHandler.ReadPtr(&LocalTypeHandler, io, &ElemCount, TagSize); // The tag type is supported, but something wrong happend and we cannot read the tag. // let know the user about this (although it is just a warning) @@ -1472,7 +1522,7 @@ _cmsTagSignature2String(String, sig); cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "'%s' Inconsistent number of items: expected %d, got %d", - String, TagDescriptor ->ElemCount, ElemCount); + String, TagDescriptor ->ElemCount, ElemCount); } @@ -1504,6 +1554,7 @@ { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; cmsTagTypeHandler* TypeHandler = NULL; + cmsTagTypeHandler LocalTypeHandler; cmsTagDescriptor* TagDescriptor = NULL; cmsTagTypeSignature Type; int i; @@ -1534,9 +1585,10 @@ if (TypeHandler != NULL) { - TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameter - TypeHandler ->ICCVersion = Icc ->Version; - TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]); + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter + LocalTypeHandler.ICCVersion = Icc ->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); } } } @@ -1575,7 +1627,7 @@ // Let the tag descriptor to decide the type base on depending on // the data. This is useful for example on parametric curves, where // curves specified by a table cannot be saved as parametric and needs - // to be revented to single v2-curves, even on v4 profiles. + // to be casted to single v2-curves, even on v4 profiles. Type = TagDescriptor ->DecideType(Version, data); } @@ -1613,9 +1665,10 @@ Icc ->TagSizes[i] = 0; Icc ->TagOffsets[i] = 0; - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; - Icc ->TagPtrs[i] = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount); + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; + Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount); if (Icc ->TagPtrs[i] == NULL) { @@ -1642,6 +1695,7 @@ int i; cmsIOHANDLER* MemIO; cmsTagTypeHandler* TypeHandler = NULL; + cmsTagTypeHandler LocalTypeHandler; cmsTagDescriptor* TagDescriptor = NULL; cmsUInt32Number rc; cmsUInt32Number Offset, TagSize; @@ -1657,15 +1711,16 @@ Offset = Icc ->TagOffsets[i]; TagSize = Icc ->TagSizes[i]; - // read the data directly, don't keep copy if (data != NULL) { if (BufferSize < TagSize) - TagSize = BufferSize; + TagSize = BufferSize; if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0; if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0; + + return TagSize; } return Icc ->TagSizes[i]; @@ -1679,9 +1734,11 @@ TagSize = Icc ->TagSizes[i]; if (BufferSize < TagSize) - TagSize = BufferSize; + TagSize = BufferSize; memmove(data, Icc ->TagPtrs[i], TagSize); + + return TagSize; } return Icc ->TagSizes[i]; @@ -1697,7 +1754,7 @@ if (data == NULL) { MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); } else{ - MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); + MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); } if (MemIO == NULL) return 0; @@ -1705,20 +1762,22 @@ TypeHandler = Icc ->TagTypeHandlers[i]; TagDescriptor = _cmsGetTagDescriptor(sig); if (TagDescriptor == NULL) { - cmsCloseIOhandler(MemIO); - return 0; + cmsCloseIOhandler(MemIO); + return 0; } + // FIXME: No handling for TypeHandler == NULL here? // Serialize - TypeHandler ->ContextID = Icc ->ContextID; - TypeHandler ->ICCVersion = Icc ->Version; + LocalTypeHandler = *TypeHandler; + LocalTypeHandler.ContextID = Icc ->ContextID; + LocalTypeHandler.ICCVersion = Icc ->Version; if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { cmsCloseIOhandler(MemIO); return 0; } - if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { + if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { cmsCloseIOhandler(MemIO); return 0; } @@ -1756,7 +1815,7 @@ // Using this function you can collapse several tag entries to the same block in the profile cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSignature dest) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; int i; if (!_cmsNewTag(Icc, sig, &i)) return FALSE; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c Wed Apr 16 10:53:10 2014 -0700 @@ -129,7 +129,6 @@ Tag = (cmsMAT3*) cmsReadTag(hProfile, cmsSigChromaticAdaptationTag); if (Tag != NULL) { - *Dest = *Tag; return TRUE; } @@ -193,7 +192,8 @@ if (GrayTRC == NULL) return NULL; Lut = cmsPipelineAlloc(ContextID, 1, 3); - if (Lut == NULL) return NULL; + if (Lut == NULL) + goto Error; if (cmsGetPCS(hProfile) == cmsSigLabData) { @@ -204,28 +204,35 @@ EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero); - if (EmptyTab == NULL) { - - cmsPipelineFree(Lut); - return NULL; - } + if (EmptyTab == NULL) + goto Error; LabCurves[0] = GrayTRC; LabCurves[1] = EmptyTab; LabCurves[2] = EmptyTab; - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL)); - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, OneToThreeInputMatrix, NULL)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, LabCurves))) { + cmsFreeToneCurve(EmptyTab); + goto Error; + } cmsFreeToneCurve(EmptyTab); } else { - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC)); - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL)); + + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &GrayTRC)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 1, GrayInputMatrix, NULL))) + goto Error; } return Lut; + +Error: + cmsFreeToneCurve(GrayTRC); + cmsPipelineFree(Lut); + return NULL; } // RGB Matrix shaper @@ -259,49 +266,31 @@ Lut = cmsPipelineAlloc(ContextID, 3, 3); if (Lut != NULL) { - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)); - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, NULL))) + goto Error; // Note that it is certainly possible a single profile would have a LUT based // tag for output working in lab and a matrix-shaper for the fallback cases. // This is not allowed by the spec, but this code is tolerant to those cases if (cmsGetPCS(hProfile) == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID))) + goto Error; } } return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; } // Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded -/*static -cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) -{ - cmsContext ContextID = cmsGetProfileContextID(hProfile); - cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); - cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile); - - if (Lut == NULL) return NULL; - - // If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding, - // and since the formatter has already accomodated to 0..1.0, we should undo this change - if ( spc == cmsSigLabData) - { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); - } - else - if (spc == cmsSigXYZData) - { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); - } - - return Lut; -} -*/ static cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) { @@ -316,23 +305,31 @@ // these need to be normalized into the appropriate ranges (Lab = 100,0,0, XYZ=1.0,1.0,1.0) if ( spc == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) + goto Error; } else if (spc == cmsSigXYZData) { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) + goto Error; } if ( PCS == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) + goto Error; } else if( PCS == cmsSigXYZData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) + goto Error; } return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; } @@ -359,8 +356,11 @@ return NULL; } - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)); - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) { + cmsPipelineFree(Lut); + return NULL; + } return Lut; } @@ -395,12 +395,18 @@ return Lut; // If the input is Lab, add also a conversion at the begin - if (cmsGetColorSpace(hProfile) == cmsSigLabData) - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); + if (cmsGetColorSpace(hProfile) == cmsSigLabData && + !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; // Add a matrix for conversion V2 to V4 Lab PCS - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; + return Lut; +Error: + cmsPipelineFree(Lut); + return NULL; } // Lut was not found, try to create a matrix-shaper @@ -445,21 +451,27 @@ if (cmsGetPCS(hProfile) == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL))) + goto Error; } else { - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickYMatrix, NULL))) + goto Error; } - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 1, &RevGrayTRC))) + goto Error; + cmsFreeToneCurve(RevGrayTRC); - return Lut; + +Error: + cmsFreeToneCurve(RevGrayTRC); + cmsPipelineFree(Lut); + return NULL; } - - static cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) { @@ -506,15 +518,21 @@ // This is not allowed by the spec, but this code is tolerant to those cases if (cmsGetPCS(hProfile) == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID))) + goto Error; } - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)); - cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)) || + !cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes))) + goto Error; } cmsFreeToneCurveTriple(InvShapes); return Lut; +Error: + cmsFreeToneCurveTriple(InvShapes); + cmsPipelineFree(Lut); + return NULL; } @@ -540,30 +558,6 @@ // Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded -/*static -cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) -{ - cmsContext ContextID = cmsGetProfileContextID(hProfile); - cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); - cmsColorSpaceSignature PCS = cmsGetPCS(hProfile); - - if (Lut == NULL) return NULL; - - // If PCS is Lab or XYZ, the floating point tag is accepting data in the space encoding, - // and since the formatter has already accomodated to 0..1.0, we should undo this change - if ( PCS == cmsSigLabData) - { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); - } - else - if (PCS == cmsSigXYZData) - { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); - } - - return Lut; -}*/ - static cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) { @@ -578,25 +572,33 @@ // and since the formatter has already accomodated to 0..1.0, we should undo this change if ( PCS == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) + goto Error; } else if (PCS == cmsSigXYZData) { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) + goto Error; } // the output can be Lab or XYZ, in which case normalisation is needed on the end of the pipeline if ( dataSpace == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) + goto Error; } - else if ( dataSpace == cmsSigXYZData) + else if (dataSpace == cmsSigXYZData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) + goto Error; } return Lut; + +Error: + cmsPipelineFree(Lut); + return NULL; } // Create an output MPE LUT from agiven profile. Version mismatches are handled here @@ -636,30 +638,35 @@ // Now it is time for a controversial stuff. I found that for 3D LUTS using // Lab used as indexer space, trilinear interpolation should be used if (cmsGetPCS(hProfile) == cmsSigLabData) - ChangeInterpolationToTrilinear(Lut); + ChangeInterpolationToTrilinear(Lut); // We need to adjust data only for Lab and Lut16 type if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) return Lut; // Add a matrix for conversion V4 to V2 Lab PCS - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; // If the output is Lab, add also a conversion at the end if (cmsGetColorSpace(hProfile) == cmsSigLabData) - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; return Lut; +Error: + cmsPipelineFree(Lut); + return NULL; } // Lut not found, try to create a matrix-shaper // Check if this is a grayscale profile. - if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { + if (cmsGetColorSpace(hProfile) == cmsSigGrayData) { - // if so, build appropiate conversion tables. - // The tables are the PCS iluminant, scaled across GrayTRC - return BuildGrayOutputPipeline(hProfile); + // if so, build appropiate conversion tables. + // The tables are the PCS iluminant, scaled across GrayTRC + return BuildGrayOutputPipeline(hProfile); } // Not gray, create a normal matrix-shaper, which only operates in XYZ space @@ -681,25 +688,32 @@ if (spc == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID))) + goto Error; } else if (spc == cmsSigXYZData) { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID))) + goto Error; } if (PCS == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID))) + goto Error; } else if (PCS == cmsSigXYZData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID))) + goto Error; } - return Lut; + return Lut; +Error: + cmsPipelineFree(Lut); + return NULL; } // This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The @@ -721,15 +735,21 @@ if (nc == NULL) return NULL; Lut = cmsPipelineAlloc(ContextID, 0, 0); - if (Lut == NULL) { - cmsFreeNamedColorList(nc); - return NULL; - } + if (Lut == NULL) + goto Error; + + if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE))) + goto Error; - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE)); if (cmsGetColorSpace(hProfile) == cmsSigLabData) - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error; + return Lut; +Error: + cmsPipelineFree(Lut); + cmsFreeNamedColorList(nc); + return NULL; } if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence @@ -760,10 +780,10 @@ Lut = cmsPipelineDup(Lut); if (Lut == NULL) return NULL; - // Now it is time for a controversial stuff. I found that for 3D LUTS using - // Lab used as indexer space, trilinear interpolation should be used + // Now it is time for a controversial stuff. I found that for 3D LUTS using + // Lab used as indexer space, trilinear interpolation should be used if (cmsGetColorSpace(hProfile) == cmsSigLabData) - ChangeInterpolationToTrilinear(Lut); + ChangeInterpolationToTrilinear(Lut); // After reading it, we have info about the original type OriginalType = _cmsGetTagTrueType(hProfile, tag16); @@ -774,16 +794,20 @@ // Here it is possible to get Lab on both sides if (cmsGetPCS(hProfile) == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); + if(!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error2; } if (cmsGetColorSpace(hProfile) == cmsSigLabData) { - cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + if(!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) + goto Error2; } return Lut; - +Error2: + cmsPipelineFree(Lut); + return NULL; } // --------------------------------------------------------------------------------------------------------------- diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c Wed Apr 16 10:53:10 2014 -0700 @@ -264,10 +264,10 @@ if (NewElem ->TheCurves != NULL) { for (i=0; i < NewElem ->nCurves; i++) { if (NewElem ->TheCurves[i]) - cmsFreeToneCurve(Data ->TheCurves[i]); + cmsFreeToneCurve(NewElem ->TheCurves[i]); } } - _cmsFree(mpe ->ContextID, Data ->TheCurves); + _cmsFree(mpe ->ContextID, NewElem ->TheCurves); _cmsFree(mpe ->ContextID, NewElem); return NULL; } @@ -392,6 +392,8 @@ void MatrixElemTypeFree(cmsStage* mpe) { _cmsStageMatrixData* Data = (_cmsStageMatrixData*) mpe ->Data; + if (Data == NULL) + return; if (Data ->Double) _cmsFree(mpe ->ContextID, Data ->Double); @@ -526,10 +528,15 @@ if (Data ->Tab.T) { - if (Data ->HasFloatValues) + if (Data ->HasFloatValues) { NewElem ->Tab.TFloat = (cmsFloat32Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.TFloat, Data ->nEntries * sizeof (cmsFloat32Number)); - else + if (NewElem ->Tab.TFloat == NULL) + goto Error; + } else { NewElem ->Tab.T = (cmsUInt16Number*) _cmsDupMem(mpe ->ContextID, Data ->Tab.T, Data ->nEntries * sizeof (cmsUInt16Number)); + if (NewElem ->Tab.TFloat == NULL) + goto Error; + } } NewElem ->Params = _cmsComputeInterpParamsEx(mpe ->ContextID, @@ -538,8 +545,14 @@ Data ->Params ->nOutputs, NewElem ->Tab.T, Data ->Params ->dwFlags); - - return (void*) NewElem; + if (NewElem->Params != NULL) + return (void*) NewElem; + Error: + if (NewElem->Tab.T) + // This works for both types + _cmsFree(mpe ->ContextID, NewElem -> Tab.T); + _cmsFree(mpe ->ContextID, NewElem); + return NULL; } @@ -636,7 +649,6 @@ for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nGridPoints; - return cmsStageAllocCLut16bitGranular(ContextID, Dimensions, inputChan, outputChan, Table); } @@ -706,15 +718,12 @@ } } - NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); if (NewElem ->Params == NULL) { cmsStageFree(NewMPE); return NULL; } - - return NewMPE; } @@ -772,7 +781,7 @@ int i, t, nTotalPoints, index, rest; int nInputs, nOutputs; cmsUInt32Number* nSamples; - cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; + cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; _cmsStageCLutData* clut; if (mpe == NULL) return FALSE; @@ -785,7 +794,9 @@ nInputs = clut->Params ->nInputs; nOutputs = clut->Params ->nOutputs; - if (nInputs >= cmsMAXCHANNELS) return FALSE; + if (nInputs <= 0) return FALSE; + if (nOutputs <= 0) return FALSE; + if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; nTotalPoints = CubeSize(nSamples, nInputs); @@ -832,14 +843,16 @@ int i, t, nTotalPoints, index, rest; int nInputs, nOutputs; cmsUInt32Number* nSamples; - cmsFloat32Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; + cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; nSamples = clut->Params ->nSamples; nInputs = clut->Params ->nInputs; nOutputs = clut->Params ->nOutputs; - if (nInputs >= cmsMAXCHANNELS) return FALSE; + if (nInputs <= 0) return FALSE; + if (nOutputs <= 0) return FALSE; + if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE; if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; nTotalPoints = CubeSize(nSamples, nInputs); @@ -1021,8 +1034,7 @@ mpe = cmsStageAllocToneCurves(ContextID, 3, LabTable); cmsFreeToneCurveTriple(LabTable); - if (mpe == NULL) return mpe; - + if (mpe == NULL) return NULL; mpe ->Implements = cmsSigLabV2toV4; return mpe; } @@ -1248,12 +1260,22 @@ NULL); if (NewMPE == NULL) return NULL; - NewMPE ->Implements = mpe ->Implements; + NewMPE ->Implements = mpe ->Implements; + + if (mpe ->DupElemPtr) { + + NewMPE ->Data = mpe ->DupElemPtr(mpe); + + if (NewMPE->Data == NULL) { - if (mpe ->DupElemPtr) - NewMPE ->Data = mpe ->DupElemPtr(mpe); - else + cmsStageFree(NewMPE); + return NULL; + } + + } else { + NewMPE ->Data = NULL; + } return NewMPE; } @@ -1266,7 +1288,7 @@ static void BlessLUT(cmsPipeline* lut) { - // We can set the input/output channels only if we have elements. + // We can set the input/ouput channels only if we have elements. if (lut ->Elements != NULL) { cmsStage *First, *Last; @@ -1466,12 +1488,12 @@ } -void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) +int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe) { cmsStage* Anterior = NULL, *pt; - _cmsAssert(lut != NULL); - _cmsAssert(mpe != NULL); + if (lut == NULL || mpe == NULL) + return FALSE; switch (loc) { @@ -1495,9 +1517,11 @@ } break; default:; + return FALSE; } BlessLUT(lut); + return TRUE; } // Unlink an element and return the pointer to it @@ -1559,7 +1583,7 @@ // Concatenate two LUT into a new single one cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2) { - cmsStage* mpe, *NewMPE; + cmsStage* mpe; // If both LUTS does not have elements, we need to inherit // the number of channels @@ -1574,17 +1598,12 @@ mpe = mpe ->Next) { // We have to dup each element - NewMPE = cmsStageDup(mpe); - - if (NewMPE == NULL) { - return FALSE; - } - - cmsPipelineInsertStage(l1, cmsAT_END, NewMPE); + if (!cmsPipelineInsertStage(l1, cmsAT_END, cmsStageDup(mpe))) + return FALSE; } - BlessLUT(l1); - return TRUE; + BlessLUT(l1); + return TRUE; } @@ -1714,16 +1733,11 @@ cmsFloat32Number fx[4], x[4], xd[4], fxd[4]; cmsVEC3 tmp, tmp2; cmsMAT3 Jacobian; - cmsFloat64Number LastResult[4]; - // Only 3->3 and 4->3 are supported if (lut ->InputChannels != 3 && lut ->InputChannels != 4) return FALSE; if (lut ->OutputChannels != 3) return FALSE; - // Mark result of -1 - LastResult[0] = LastResult[1] = LastResult[2] = -1.0f; - // Take the hint as starting point if specified if (Hint == NULL) { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c Wed Apr 16 10:53:10 2014 -0700 @@ -338,7 +338,7 @@ Error: // Free resources as something went wrong - if (MD5 != NULL) _cmsFree(ContextID, MD5); + // "MD5" cannot be other than NULL here, so no need to free it if (Mem != NULL) _cmsFree(ContextID, Mem); memmove(Icc, &Keep, sizeof(_cmsICCPROFILE)); return FALSE; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c Wed Apr 16 10:53:10 2014 -0700 @@ -359,9 +359,9 @@ if (Best == -1) Best = 0; - v = mlu ->Entries + Best; + v = mlu ->Entries + Best; - if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; + if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; if (len != NULL) *len = v ->Len; @@ -475,6 +475,35 @@ } + +// Get the number of translations in the MLU object +cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu) +{ + if (mlu == NULL) return 0; + return mlu->UsedEntries; +} + +// Get the language and country codes for a specific MLU index +cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu, + cmsUInt32Number idx, + char LanguageCode[3], + char CountryCode[3]) +{ + _cmsMLUentry *entry; + + if (mlu == NULL) return FALSE; + + if (idx >= (cmsUInt32Number) mlu->UsedEntries) return FALSE; + + entry = &mlu->Entries[idx]; + + *(cmsUInt16Number *)LanguageCode = _cmsAdjustEndianess16(entry->Language); + *(cmsUInt16Number *)CountryCode = _cmsAdjustEndianess16(entry->Country); + + return TRUE; +} + + // Named color lists -------------------------------------------------------------------------------------------- // Grow the list to keep at least NumElements @@ -517,9 +546,9 @@ while (v -> Allocated < n) GrowNamedColorList(v); - strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix) - 1); - strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix) - 1); - v->Prefix[sizeof(v ->Prefix) - 1] = v->Suffix[sizeof(v ->Suffix) - 1] = 0; + strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)-1); + strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)-1); + v->Prefix[32] = v->Suffix[32] = 0; v -> ColorantCount = ColorantCount; @@ -529,8 +558,9 @@ // Free a list void CMSEXPORT cmsFreeNamedColorList(cmsNAMEDCOLORLIST* v) { + if (v == NULL) return; if (v ->List) _cmsFree(v ->ContextID, v ->List); - if (v) _cmsFree(v ->ContextID, v); + _cmsFree(v ->ContextID, v); } cmsNAMEDCOLORLIST* CMSEXPORT cmsDupNamedColorList(const cmsNAMEDCOLORLIST* v) @@ -576,11 +606,8 @@ if (Name != NULL) { - strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, - sizeof(NamedColorList ->List[NamedColorList ->nColors].Name) - 1); - - NamedColorList ->List[NamedColorList ->nColors]. - Name[sizeof(NamedColorList ->List[NamedColorList ->nColors].Name) - 1] = 0; + strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, cmsMAX_PATH-1); + NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0; } else @@ -891,7 +918,6 @@ { _cmsDICT* old_dict = (_cmsDICT*) hDict; cmsHANDLE hNew; - _cmsDICT* new_dict; cmsDICTentry *entry; _cmsAssert(old_dict != NULL); @@ -899,8 +925,6 @@ hNew = cmsDictAlloc(old_dict ->ContextID); if (hNew == NULL) return NULL; - new_dict = (_cmsDICT*) hNew; - // Walk the list freeing all nodes entry = old_dict ->head; while (entry != NULL) { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c Wed Apr 16 10:53:10 2014 -0700 @@ -27,6 +27,7 @@ // However, the following notice accompanied the original version of this // file: // + //--------------------------------------------------------------------------------- // // Little Color Management System @@ -81,10 +82,6 @@ int nInputs; int nOutputs; - // Since there is no limitation of the output number of channels, this buffer holding the connexion CLUT-shaper - // has to be dynamically allocated. This is not the case of first step shaper-CLUT, which is limited to max inputs - cmsUInt16Number* StageDEF; - _cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS]; @@ -202,8 +199,6 @@ { cmsBool AnyOpt = FALSE, Opt; - AnyOpt = FALSE; - do { Opt = FALSE; @@ -253,6 +248,7 @@ { Prelin16Data* p16 = (Prelin16Data*) D; cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS]; + cmsUInt16Number StageDEF[cmsMAXCHANNELS]; int i; for (i=0; i < p16 ->nInputs; i++) { @@ -260,11 +256,11 @@ p16 ->EvalCurveIn16[i](&Input[i], &StageABC[i], p16 ->ParamsCurveIn16[i]); } - p16 ->EvalCLUT(StageABC, p16 ->StageDEF, p16 ->CLUTparams); + p16 ->EvalCLUT(StageABC, StageDEF, p16 ->CLUTparams); for (i=0; i < p16 ->nOutputs; i++) { - p16 ->EvalCurveOut16[i](&p16->StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]); + p16 ->EvalCurveOut16[i](&StageDEF[i], &Output[i], p16 ->ParamsCurveOut16[i]); } } @@ -274,7 +270,6 @@ { Prelin16Data* p16 = (Prelin16Data*) ptr; - _cmsFree(ContextID, p16 ->StageDEF); _cmsFree(ContextID, p16 ->EvalCurveOut16); _cmsFree(ContextID, p16 ->ParamsCurveOut16); @@ -289,7 +284,6 @@ if (Duped == NULL) return NULL; - Duped ->StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number)); Duped ->EvalCurveOut16 = _cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16)); Duped ->ParamsCurveOut16 = _cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* )); @@ -328,7 +322,6 @@ p16 ->EvalCLUT = ColorMap ->Interpolation.Lerp16; - p16 -> StageDEF = _cmsCalloc(ContextID, p16 ->nOutputs, sizeof(cmsUInt16Number)); p16 -> EvalCurveOut16 = (_cmsInterpFn16*) _cmsCalloc(ContextID, nOutputs, sizeof(_cmsInterpFn16)); p16 -> ParamsCurveOut16 = (cmsInterpParams**) _cmsCalloc(ContextID, nOutputs, sizeof(cmsInterpParams* )); @@ -413,7 +406,7 @@ int i, index; if (CLUT -> Type != cmsSigCLutElemType) { - cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut MPE"); + cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) Attempt to PatchLUT on non-lut stage"); return FALSE; } @@ -579,8 +572,8 @@ static cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags) { - cmsPipeline* Src; - cmsPipeline* Dest; + cmsPipeline* Src = NULL; + cmsPipeline* Dest = NULL; cmsStage* mpe; cmsStage* CLUT; cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; @@ -593,7 +586,6 @@ cmsToneCurve** DataSetOut; Prelin16Data* p16; - // This is a loosy optimization! does not apply in floating-point cases if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE; @@ -607,10 +599,10 @@ Src = *Lut; - // Named color pipelines cannot be optimized either - for (mpe = cmsPipelineGetPtrToFirstStage(Src); - mpe != NULL; - mpe = cmsStageNext(mpe)) { + // Named color pipelines cannot be optimized either + for (mpe = cmsPipelineGetPtrToFirstStage(Src); + mpe != NULL; + mpe = cmsStageNext(mpe)) { if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; } @@ -632,7 +624,8 @@ // All seems ok, proceed. NewPreLin = cmsStageDup(PreLin); - cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin); + if(!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, NewPreLin)) + goto Error; // Remove prelinearization. Since we have duplicated the curve // in destination LUT, the sampling shoud be applied after this stage. @@ -646,7 +639,9 @@ if (CLUT == NULL) return FALSE; // Add the CLUT to the destination LUT - cmsPipelineInsertStage(Dest, cmsAT_END, CLUT); + if (!cmsPipelineInsertStage(Dest, cmsAT_END, CLUT)) { + goto Error; + } // Postlinearization tables are kept unless indicated by flags if (*dwFlags & cmsFLAGS_CLUT_POST_LINEARIZATION) { @@ -662,7 +657,8 @@ // All seems ok, proceed. NewPostLin = cmsStageDup(PostLin); - cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin); + if (!cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin)) + goto Error; // In destination LUT, the sampling shoud be applied after this stage. cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin); @@ -673,10 +669,18 @@ // Now its time to do the sampling. We have to ignore pre/post linearization // The source LUT whithout pre/post curves is passed as parameter. if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) { - +Error: // Ops, something went wrong, Restore stages - if (KeepPreLin != NULL) cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin); - if (KeepPostLin != NULL) cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin); + if (KeepPreLin != NULL) { + if (!cmsPipelineInsertStage(Src, cmsAT_BEGIN, KeepPreLin)) { + _cmsAssert(0); // This never happens + } + } + if (KeepPostLin != NULL) { + if (!cmsPipelineInsertStage(Src, cmsAT_END, KeepPostLin)) { + _cmsAssert(0); // This never happens + } + } cmsPipelineFree(Dest); return FALSE; } @@ -703,12 +707,11 @@ else { p16 = PrelinOpt16alloc(Dest ->ContextID, - DataCLUT ->Params, - Dest ->InputChannels, - DataSetIn, - Dest ->OutputChannels, - DataSetOut); - + DataCLUT ->Params, + Dest ->InputChannels, + DataSetIn, + Dest ->OutputChannels, + DataSetOut); _cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup); } @@ -1062,7 +1065,8 @@ LutPlusCurves = cmsPipelineDup(OriginalLut); if (LutPlusCurves == NULL) goto Error; - cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse)); + if (!cmsPipelineInsertStage(LutPlusCurves, cmsAT_BEGIN, cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, TransReverse))) + goto Error; // Create the result LUT OptimizedLUT = cmsPipelineAlloc(OriginalLut ->ContextID, OriginalLut ->InputChannels, OriginalLut ->OutputChannels); @@ -1071,13 +1075,15 @@ OptimizedPrelinMpe = cmsStageAllocToneCurves(OriginalLut ->ContextID, OriginalLut ->InputChannels, Trans); // Create and insert the curves at the beginning - cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe); + if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_BEGIN, OptimizedPrelinMpe)) + goto Error; // Allocate the CLUT for result OptimizedCLUTmpe = cmsStageAllocCLut16bit(OriginalLut ->ContextID, nGridPoints, OriginalLut ->InputChannels, OriginalLut ->OutputChannels, NULL); // Add the CLUT to the destination LUT - cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe); + if (!cmsPipelineInsertStage(OptimizedLUT, cmsAT_END, OptimizedCLUTmpe)) + goto Error; // Resample the LUT if (!cmsStageSampleCLut16bit(OptimizedCLUTmpe, XFormSampler16, (void*) LutPlusCurves, 0)) goto Error; @@ -1205,13 +1211,14 @@ for (i=0; i < nCurves; i++) { c16->Curves[i] = _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number)); + if (c16->Curves[i] == NULL) { + for (j=0; j < i; j++) { _cmsFree(ContextID, c16->Curves[j]); } _cmsFree(ContextID, c16->Curves); _cmsFree(ContextID, c16); - return NULL; } @@ -1340,7 +1347,8 @@ // Maybe the curves are linear at the end if (!AllCurvesAreLinear(ObtainedCurves)) { - cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves); + if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, ObtainedCurves)) + goto Error; // If the curves are to be applied in 8 bits, we can save memory if (_cmsFormatterIs8bit(*InputFormat)) { @@ -1348,6 +1356,7 @@ _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) ObtainedCurves ->Data; Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 256, Data ->TheCurves); + if (c16 == NULL) goto Error; *dwFlags |= cmsFLAGS_NOCACHE; _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves8, c16, CurvesFree, CurvesDup); @@ -1357,6 +1366,7 @@ _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) cmsStageData(ObtainedCurves); Curves16Data* c16 = CurvesAlloc(Dest ->ContextID, Data ->nCurves, 65536, Data ->TheCurves); + if (c16 == NULL) goto Error; *dwFlags |= cmsFLAGS_NOCACHE; _cmsPipelineSetOptimizationParameters(Dest, FastEvaluateCurves16, c16, CurvesFree, CurvesDup); } @@ -1366,7 +1376,8 @@ // LUT optimizes to nothing. Set the identity LUT cmsStageFree(ObtainedCurves); - cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels)); + if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageAllocIdentity(Dest ->ContextID, Src ->InputChannels))) + goto Error; *dwFlags |= cmsFLAGS_NOCACHE; _cmsPipelineSetOptimizationParameters(Dest, FastIdentity16, (void*) Dest, NULL, NULL); @@ -1596,10 +1607,14 @@ if (!Dest) return FALSE; // Assamble the new LUT - cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1)); + if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1))) + goto Error; + if (!IdentityMat) - cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset)); - cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2)); + if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset))) + goto Error; + if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2))) + goto Error; // If identity on matrix, we can further optimize the curves, so call the join curves routine if (IdentityMat) { @@ -1621,6 +1636,10 @@ cmsPipelineFree(Src); *Lut = Dest; return TRUE; +Error: + // Leave Src unchanged + cmsPipelineFree(Dest); + return FALSE; } @@ -1650,7 +1669,7 @@ static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization; // Register new ways to optimize -cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterOptimizationPlugin(cmsContext id, cmsPluginBase* Data) { cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data; _cmsOptimizationCollection* fl; @@ -1664,7 +1683,7 @@ // Optimizer callback is required if (Plugin ->OptimizePtr == NULL) return FALSE; - fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(sizeof(_cmsOptimizationCollection)); + fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(id, sizeof(_cmsOptimizationCollection)); if (fl == NULL) return FALSE; // Copy the parameters diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c Wed Apr 16 10:53:10 2014 -0700 @@ -317,6 +317,23 @@ } static +cmsUInt8Number* Unroll3BytesSkip1SwapSwapFirst(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + wIn[2] = FROM_8_TO_16(*accum); accum++; // B + wIn[1] = FROM_8_TO_16(*accum); accum++; // G + wIn[0] = FROM_8_TO_16(*accum); accum++; // R + accum++; // A + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info, register cmsUInt16Number wIn[], register cmsUInt8Number* accum, @@ -2901,6 +2918,9 @@ { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll3BytesSkip1Swap}, { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll3BytesSkip1SwapFirst}, + { CHANNELS_SH(3)|EXTRA_SH(1)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), + ANYSPACE, Unroll3BytesSkip1SwapSwapFirst}, + { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Unroll4Bytes}, { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Unroll4BytesReverse}, { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapFirst}, @@ -3166,7 +3186,7 @@ // Formatters management -cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterFormattersPlugin(cmsContext id, cmsPluginBase* Data) { cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data; cmsFormattersFactoryList* fl ; @@ -3178,7 +3198,7 @@ return TRUE; } - fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(sizeof(cmsFormattersFactoryList)); + fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(id, sizeof(cmsFormattersFactoryList)); if (fl == NULL) return FALSE; fl ->Factory = Plugin ->FormattersFactory; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c Wed Apr 16 10:53:10 2014 -0700 @@ -898,9 +898,11 @@ { switch (ColorSpace) { + case cmsSigMCH1Data: case cmsSig1colorData: case cmsSigGrayData: return 1; + case cmsSigMCH2Data: case cmsSig2colorData: return 2; case cmsSigXYZData: @@ -912,10 +914,12 @@ case cmsSigHsvData: case cmsSigHlsData: case cmsSigCmyData: + case cmsSigMCH3Data: case cmsSig3colorData: return 3; case cmsSigLuvKData: case cmsSigCmykData: + case cmsSigMCH4Data: case cmsSig4colorData: return 4; case cmsSigMCH5Data: diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c Wed Apr 16 10:53:10 2014 -0700 @@ -125,10 +125,14 @@ pOut[0] = pIn[7]; #else - _cmsAssert(Result != NULL); +# ifdef CMS_DONT_USE_INT64 + (*Result)[0] = QWord[0]; + (*Result)[1] = QWord[1]; +# else *Result = *QWord; +# endif #endif } @@ -543,10 +547,10 @@ static _cmsSubAllocator* PluginPool = NULL; // Specialized malloc for plug-ins, that is freed upon exit. -void* _cmsPluginMalloc(cmsUInt32Number size) +void* _cmsPluginMalloc(cmsContext id, cmsUInt32Number size) { if (PluginPool == NULL) - PluginPool = _cmsCreateSubAlloc(0, 4*1024); + PluginPool = _cmsCreateSubAlloc(id, 4*1024); return _cmsSubAlloc(PluginPool, size); } @@ -555,6 +559,11 @@ // Main plug-in dispatcher cmsBool CMSEXPORT cmsPlugin(void* Plug_in) { + return cmsPluginTHR(NULL, Plug_in); +} + +cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) +{ cmsPluginBase* Plugin; for (Plugin = (cmsPluginBase*) Plug_in; @@ -583,35 +592,35 @@ break; case cmsPluginTagTypeSig: - if (!_cmsRegisterTagTypePlugin(Plugin)) return FALSE; + if (!_cmsRegisterTagTypePlugin(id, Plugin)) return FALSE; break; case cmsPluginTagSig: - if (!_cmsRegisterTagPlugin(Plugin)) return FALSE; + if (!_cmsRegisterTagPlugin(id, Plugin)) return FALSE; break; case cmsPluginFormattersSig: - if (!_cmsRegisterFormattersPlugin(Plugin)) return FALSE; + if (!_cmsRegisterFormattersPlugin(id, Plugin)) return FALSE; break; case cmsPluginRenderingIntentSig: - if (!_cmsRegisterRenderingIntentPlugin(Plugin)) return FALSE; + if (!_cmsRegisterRenderingIntentPlugin(id, Plugin)) return FALSE; break; case cmsPluginParametricCurveSig: - if (!_cmsRegisterParametricCurvesPlugin(Plugin)) return FALSE; + if (!_cmsRegisterParametricCurvesPlugin(id, Plugin)) return FALSE; break; case cmsPluginMultiProcessElementSig: - if (!_cmsRegisterMultiProcessElementPlugin(Plugin)) return FALSE; + if (!_cmsRegisterMultiProcessElementPlugin(id, Plugin)) return FALSE; break; case cmsPluginOptimizationSig: - if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE; + if (!_cmsRegisterOptimizationPlugin(id, Plugin)) return FALSE; break; case cmsPluginTransformSig: - if (!_cmsRegisterTransformPlugin(Plugin)) return FALSE; + if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE; break; default: @@ -630,14 +639,14 @@ { _cmsRegisterMemHandlerPlugin(NULL); _cmsRegisterInterpPlugin(NULL); - _cmsRegisterTagTypePlugin(NULL); - _cmsRegisterTagPlugin(NULL); - _cmsRegisterFormattersPlugin(NULL); - _cmsRegisterRenderingIntentPlugin(NULL); - _cmsRegisterParametricCurvesPlugin(NULL); - _cmsRegisterMultiProcessElementPlugin(NULL); - _cmsRegisterOptimizationPlugin(NULL); - _cmsRegisterTransformPlugin(NULL); + _cmsRegisterTagTypePlugin(NULL, NULL); + _cmsRegisterTagPlugin(NULL, NULL); + _cmsRegisterFormattersPlugin(NULL, NULL); + _cmsRegisterRenderingIntentPlugin(NULL, NULL); + _cmsRegisterParametricCurvesPlugin(NULL, NULL); + _cmsRegisterMultiProcessElementPlugin(NULL, NULL); + _cmsRegisterOptimizationPlugin(NULL, NULL); + _cmsRegisterTransformPlugin(NULL, NULL); if (PluginPool != NULL) _cmsSubAllocDestroy(PluginPool); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c Wed Apr 16 10:53:10 2014 -0700 @@ -806,7 +806,6 @@ mpe = Pipeline ->Elements; - switch (cmsStageInputChannels(mpe)) { case 3: @@ -838,8 +837,6 @@ mpe = mpe ->Next; } - - if (cmsStageType(mpe) == cmsSigCLutElemType) { _cmsIOPrintf(m, "/Table "); @@ -854,7 +851,6 @@ _cmsIOPrintf(m, " >>\n"); _cmsIOPrintf(m, "]\n"); - return 1; } @@ -950,6 +946,7 @@ rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); cmsPipelineFree(DeviceLink); + if (rc == 0) return 0; } break; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c Wed Apr 16 10:53:10 2014 -0700 @@ -56,6 +56,8 @@ #include "lcms2_internal.h" +#define cmsmin(a, b) (((a) < (b)) ? (a) : (b)) +#define cmsmax(a, b) (((a) > (b)) ? (a) : (b)) // This file contains routines for resampling and LUT optimization, black point detection // and black preservation. @@ -67,13 +69,13 @@ static cmsHTRANSFORM CreateRoundtripXForm(cmsHPROFILE hProfile, cmsUInt32Number nIntent) { - cmsHPROFILE hLab = cmsCreateLab4Profile(NULL); + cmsContext ContextID = cmsGetProfileContextID(hProfile); + cmsHPROFILE hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); cmsHTRANSFORM xform; cmsBool BPC[4] = { FALSE, FALSE, FALSE, FALSE }; cmsFloat64Number States[4] = { 1.0, 1.0, 1.0, 1.0 }; cmsHPROFILE hProfiles[4]; cmsUInt32Number Intents[4]; - cmsContext ContextID = cmsGetProfileContextID(hProfile); hProfiles[0] = hLab; hProfiles[1] = hProfile; hProfiles[2] = hProfile; hProfiles[3] = hLab; Intents[0] = INTENT_RELATIVE_COLORIMETRIC; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = INTENT_RELATIVE_COLORIMETRIC; @@ -141,8 +143,8 @@ cmsCloseProfile(hLab); if (xform == NULL) { + // Something went wrong. Get rid of open resources and return zero as black - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } @@ -173,7 +175,6 @@ // Lab (0, 0, 0) -> [Perceptual] Profile -> CMYK -> [Rel. colorimetric] Profile -> Lab static cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile) - { cmsHTRANSFORM hRoundTrip; cmsCIELab LabIn, LabOut; @@ -218,17 +219,27 @@ // involves to turn BP to neutral and to use only L component. cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags) { + cmsProfileClassSignature devClass; - // Zero for black point - if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) { + // Make sure the device class is adequate + devClass = cmsGetDeviceClass(hProfile); + if (devClass == cmsSigLinkClass || + devClass == cmsSigAbstractClass || + devClass == cmsSigNamedColorClass) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; + // Make sure intent is adequate + if (Intent != INTENT_PERCEPTUAL && + Intent != INTENT_RELATIVE_COLORIMETRIC && + Intent != INTENT_SATURATION) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; } // v4 + perceptual & saturation intents does have its own black point, and it is // well specified enough to use it. Black point tag is deprecated in V4. - if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) && (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) { @@ -303,7 +314,7 @@ { double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0; double sum_y = 0, sum_yx = 0, sum_yx2 = 0; - double disc; + double d, a, b, c; int i; cmsMAT3 m; cmsVEC3 v, res; @@ -333,14 +344,32 @@ if (!_cmsMAT3solve(&res, &m, &v)) return 0; - // y = t x2 + u x + c - // x = ( - u + Sqrt( u^2 - 4 t c ) ) / ( 2 t ) - disc = res.n[1]*res.n[1] - 4.0 * res.n[0] * res.n[2]; - if (disc < 0) return -1; + + a = res.n[2]; + b = res.n[1]; + c = res.n[0]; + + if (fabs(a) < 1.0E-10) { + + return cmsmin(0, cmsmax(50, -c/b )); + } + else { - return ( -1.0 * res.n[1] + sqrt( disc )) / (2.0 * res.n[0]); + d = b*b - 4.0 * a * c; + if (d <= 0) { + return 0; + } + else { + + double rt = (-b + sqrt(d)) / (2.0 * a); + + return cmsmax(0, cmsmin(50, rt)); + } + } + } +/* static cmsBool IsMonotonic(int n, const cmsFloat64Number Table[]) { @@ -361,6 +390,7 @@ return TRUE; } +*/ // Calculates the black point of a destination profile. // This algorithm comes from the Adobe paper disclosing its black point compensation method. @@ -369,21 +399,30 @@ cmsColorSpaceSignature ColorSpace; cmsHTRANSFORM hRoundTrip = NULL; cmsCIELab InitialLab, destLab, Lab; - + cmsFloat64Number inRamp[256], outRamp[256]; cmsFloat64Number MinL, MaxL; - cmsBool NearlyStraightMidRange = FALSE; - cmsFloat64Number L; - cmsFloat64Number x[101], y[101]; - cmsFloat64Number lo, hi, NonMonoMin; - int n, l, i, NonMonoIndx; + cmsBool NearlyStraightMidrange = TRUE; + cmsFloat64Number yRamp[256]; + cmsFloat64Number x[256], y[256]; + cmsFloat64Number lo, hi; + int n, l; + cmsProfileClassSignature devClass; + // Make sure the device class is adequate + devClass = cmsGetDeviceClass(hProfile); + if (devClass == cmsSigLinkClass || + devClass == cmsSigAbstractClass || + devClass == cmsSigNamedColorClass) { + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; + } // Make sure intent is adequate if (Intent != INTENT_PERCEPTUAL && Intent != INTENT_RELATIVE_COLORIMETRIC && Intent != INTENT_SATURATION) { - BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; - return FALSE; + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; } @@ -415,10 +454,8 @@ return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags); } - // It is one of the valid cases!, presto chargo hocus pocus, go for the Adobe magic + // It is one of the valid cases!, use Adobe algorithm - // Step 1 - // ====== // Set a first guess, that should work on good profiles. if (Intent == INTENT_RELATIVE_COLORIMETRIC) { @@ -449,71 +486,68 @@ hRoundTrip = CreateRoundtripXForm(hProfile, Intent); if (hRoundTrip == NULL) return FALSE; - // Calculate Min L* - Lab = InitialLab; - Lab.L = 0; - cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); - MinL = destLab.L; + // Compute ramps - // Calculate Max L* - Lab = InitialLab; - Lab.L = 100; - cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); - MaxL = destLab.L; + for (l=0; l < 256; l++) { - // Step 3 - // ====== - - // check if quadratic estimation needs to be done. - if (Intent == INTENT_RELATIVE_COLORIMETRIC) { + Lab.L = (cmsFloat64Number) (l * 100.0) / 255.0; + Lab.a = cmsmin(50, cmsmax(-50, InitialLab.a)); + Lab.b = cmsmin(50, cmsmax(-50, InitialLab.b)); - // Conceptually, this code tests how close the source l and converted L are to one another in the mid-range - // of the values. If the converted ramp of L values is close enough to a straight line y=x, then InitialLab - // is good enough to be the DestinationBlackPoint, - NearlyStraightMidRange = TRUE; - - for (l=0; l <= 100; l++) { + cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); - Lab.L = l; - Lab.a = InitialLab.a; - Lab.b = InitialLab.b; - - cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); - - L = destLab.L; - - // Check the mid range in 20% after MinL - if (L > (MinL + 0.2 * (MaxL - MinL))) { + inRamp[l] = Lab.L; + outRamp[l] = destLab.L; + } - // Is close enough? - if (fabs(L - l) > 4.0) { + // Make monotonic + for (l = 254; l > 0; --l) { + outRamp[l] = cmsmin(outRamp[l], outRamp[l+1]); + } - // Too far away, profile is buggy! - NearlyStraightMidRange = FALSE; - break; - } - } - } - } - else { - // Check is always performed for perceptual and saturation intents - NearlyStraightMidRange = FALSE; + // Check + if (! (outRamp[0] < outRamp[255])) { + + cmsDeleteTransform(hRoundTrip); + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; } - // If no furter checking is needed, we are done - if (NearlyStraightMidRange) { + // Test for mid range straight (only on relative colorimetric) + + NearlyStraightMidrange = TRUE; + MinL = outRamp[0]; MaxL = outRamp[255]; + if (Intent == INTENT_RELATIVE_COLORIMETRIC) { + + for (l=0; l < 256; l++) { - cmsLab2XYZ(NULL, BlackPoint, &InitialLab); - cmsDeleteTransform(hRoundTrip); - return TRUE; + if (! ((inRamp[l] <= MinL + 0.2 * (MaxL - MinL) ) || + (fabs(inRamp[l] - outRamp[l]) < 4.0 ))) + NearlyStraightMidrange = FALSE; + } + + // If the mid range is straight (as determined above) then the + // DestinationBlackPoint shall be the same as initialLab. + // Otherwise, the DestinationBlackPoint shall be determined + // using curve fitting. + + if (NearlyStraightMidrange) { + + cmsLab2XYZ(NULL, BlackPoint, &InitialLab); + cmsDeleteTransform(hRoundTrip); + return TRUE; + } } - // The round-trip curve normally looks like a nearly constant section at the black point, + + // curve fitting: The round-trip curve normally looks like a nearly constant section at the black point, // with a corner and a nearly straight line to the white point. - // STEP 4 - // ======= + for (l=0; l < 256; l++) { + + yRamp[l] = (outRamp[l] - MinL) / (MaxL - MinL); + } // find the black point using the least squares error quadratic curve fitting @@ -528,62 +562,32 @@ hi = 0.25; } - // Capture points for the fitting. + // Capture shadow points for the fitting. n = 0; - for (l=0; l <= 100; l++) { - - cmsFloat64Number ff; + for (l=0; l < 256; l++) { - Lab.L = (cmsFloat64Number) l; - Lab.a = InitialLab.a; - Lab.b = InitialLab.b; - - cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); - - ff = (destLab.L - MinL)/(MaxL - MinL); + cmsFloat64Number ff = yRamp[l]; if (ff >= lo && ff < hi) { - - x[n] = Lab.L; - y[n] = ff; + x[n] = inRamp[l]; + y[n] = yRamp[l]; n++; } - - } - - // This part is not on the Adobe paper, but I found is necessary for getting any result. - - if (IsMonotonic(n, y)) { - - // Monotonic means lower point is stil valid - cmsLab2XYZ(NULL, BlackPoint, &InitialLab); - cmsDeleteTransform(hRoundTrip); - return TRUE; - } - - // No suitable points, regret and use safer algorithm - if (n == 0) { - cmsDeleteTransform(hRoundTrip); - return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags); } - NonMonoMin = 100; - NonMonoIndx = 0; - for (i=0; i < n; i++) { - - if (y[i] < NonMonoMin) { - NonMonoIndx = i; - NonMonoMin = y[i]; - } + // No suitable points + if (n < 3 ) { + cmsDeleteTransform(hRoundTrip); + BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; + return FALSE; } - Lab.L = x[NonMonoIndx]; // fit and get the vertex of quadratic curve Lab.L = RootOfLeastSquaresFitQuadraticCurve(n, x, y); - if (Lab.L < 0.0 || Lab.L > 50.0) { // clip to zero L* if the vertex is negative + if (Lab.L < 0.0) { // clip to zero L* if the vertex is negative Lab.L = 0; } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c Wed Apr 16 10:53:10 2014 -0700 @@ -91,7 +91,7 @@ // Register a new type handler. This routine is shared between normal types and MPE static -cmsBool RegisterTypesPlugin(cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount) +cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount) { cmsPluginTagType* Plugin = (cmsPluginTagType*) Data; _cmsTagTypeLinkedList *pt, *Anterior = NULL; @@ -118,7 +118,7 @@ } // Registering happens in plug-in memory pool - pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagTypeLinkedList)); + pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList)); if (pt == NULL) return FALSE; pt ->Handler = Plugin ->Handler; @@ -208,10 +208,10 @@ cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; // Let's take the offsets to each element - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); if (ElementOffsets == NULL) goto Error; - ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); if (ElementSizes == NULL) goto Error; for (i=0; i < Count; i++) { @@ -257,10 +257,10 @@ cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL; // Create table - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); if (ElementOffsets == NULL) goto Error; - ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number *)); + ElementSizes = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number)); if (ElementSizes == NULL) goto Error; // Keep starting position of curve offsets @@ -456,6 +456,7 @@ void* Type_Chromaticity_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n) { return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsCIExyYTRIPLE)); + cmsUNUSED_PARAMETER(n); } @@ -1106,8 +1107,6 @@ { cmsUInt32Number Count; cmsToneCurve* NewGamma; - cmsUInt16Number Linear[2] = { 0, 0xffff }; - *nItems = 0; if (!_cmsReadUInt32Number(io, &Count)) return NULL; @@ -1115,11 +1114,14 @@ switch (Count) { case 0: // Linear. - - NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, 2, Linear); - if (!NewGamma) return NULL; - *nItems = 1; - return NewGamma; + { + cmsFloat64Number SingleGamma = 1.0; + + NewGamma = cmsBuildParametricToneCurve(self ->ContextID, 1, &SingleGamma); + if (!NewGamma) return NULL; + *nItems = 1; + return NewGamma; + } case 1: // Specified as the exponent of gamma function { @@ -1210,6 +1212,7 @@ if (ICCVersion < 4.0) return cmsSigCurveType; if (Curve ->nSegments != 1) return cmsSigCurveType; // Only 1-segment curves can be saved as parametric if (Curve ->Segments[0].Type < 0) return cmsSigCurveType; // Only non-inverted curves + if (Curve ->Segments[0].Type > 5) return cmsSigCurveType; // Only ICC parametric curves return cmsSigParametricCurveType; } @@ -1386,6 +1389,9 @@ { cmsICCMeasurementConditions mc; + + memset(&mc, 0, sizeof(mc)); + if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL; if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL; if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL; @@ -1640,7 +1646,6 @@ static cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels) { - cmsStage* mpe; cmsUInt8Number* Temp = NULL; int i, j; cmsToneCurve* Tables[cmsMAXCHANNELS]; @@ -1669,11 +1674,8 @@ _cmsFree(ContextID, Temp); Temp = NULL; - - mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables); - if (mpe == NULL) goto Error; - - cmsPipelineInsertStage(lut, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) + goto Error; for (i=0; i < nChannels; i++) cmsFreeToneCurve(Tables[i]); @@ -1701,21 +1703,30 @@ if (Tables) { - if (Tables ->TheCurves[i]->nEntries != 256) { - cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization"); - return FALSE; + // Usual case of identity curves + if ((Tables ->TheCurves[i]->nEntries == 2) && + (Tables->TheCurves[i]->Table16[0] == 0) && + (Tables->TheCurves[i]->Table16[1] == 65535)) { + + for (j=0; j < 256; j++) { + if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) j)) return FALSE; + } } - - } - - for (j=0; j < 256; j++) { - - if (Tables != NULL) - val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); else - val = (cmsUInt8Number) j; - - if (!_cmsWriteUInt8Number(io, val)) return FALSE; + if (Tables ->TheCurves[i]->nEntries != 256) { + cmsSignalError(ContextID, cmsERROR_RANGE, "LUT8 needs 256 entries on prelinearization"); + return FALSE; + } + else + for (j=0; j < 256; j++) { + + if (Tables != NULL) + val = (cmsUInt8Number) FROM_16_TO_8(Tables->TheCurves[i]->Table16[j]); + else + val = (cmsUInt8Number) j; + + if (!_cmsWriteUInt8Number(io, val)) return FALSE; + } } } return TRUE; @@ -1724,7 +1735,7 @@ // Check overflow static -size_t uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) +cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) { cmsUInt32Number rv = 1, rc; @@ -1736,13 +1747,13 @@ rv *= a; // Check for overflow - if (rv > UINT_MAX / a) return (size_t) -1; + if (rv > UINT_MAX / a) return (cmsUInt32Number) -1; } rc = rv * n; - if (rv != rc / n) return (size_t) -1; + if (rv != rc / n) return (cmsUInt32Number) -1; return rc; } @@ -1757,7 +1768,6 @@ cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; cmsUInt8Number* Temp = NULL; cmsPipeline* NewLUT = NULL; - cmsStage *mpemat, *mpeclut; cmsUInt32Number nTabSize, i; cmsFloat64Number Matrix[3*3]; @@ -1796,9 +1806,8 @@ // Only operates if not identity... if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { - mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL); - if (mpemat == NULL) goto Error; - cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, mpemat); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_BEGIN, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) + goto Error; } // Get input tables @@ -1806,13 +1815,10 @@ // Get 3D CLUT. Check the overflow.... nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); - if (nTabSize == (size_t) -1) goto Error; + if (nTabSize == (cmsUInt32Number) -1) goto Error; if (nTabSize > 0) { cmsUInt16Number *PtrW, *T; - cmsUInt32Number Tsize; - - Tsize = (cmsUInt32Number) nTabSize * sizeof(cmsUInt16Number); PtrW = T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); if (T == NULL) goto Error; @@ -1829,10 +1835,8 @@ _cmsFree(self ->ContextID, Temp); Temp = NULL; - - mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T); - if (mpeclut == NULL) goto Error; - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) + goto Error; _cmsFree(self ->ContextID, T); } @@ -1934,7 +1938,7 @@ if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE; nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels); - if (nTabSize == (size_t) -1) return FALSE; + if (nTabSize == (cmsUInt32Number) -1) return FALSE; if (nTabSize > 0) { // The 3D CLUT. @@ -1983,7 +1987,6 @@ static cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries) { - cmsStage* mpe; int i; cmsToneCurve* Tables[cmsMAXCHANNELS]; @@ -2007,10 +2010,8 @@ // Add the table (which may certainly be an identity, but this is up to the optimizer, not the reading code) - mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables); - if (mpe == NULL) goto Error; - - cmsPipelineInsertStage(lut, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, nChannels, Tables))) + goto Error; for (i=0; i < nChannels; i++) cmsFreeToneCurve(Tables[i]); @@ -2031,7 +2032,9 @@ int j; cmsUInt32Number i; cmsUInt16Number val; - int nEntries = 256; + int nEntries; + + _cmsAssert(Tables != NULL); nEntries = Tables->TheCurves[0]->nEntries; @@ -2039,11 +2042,7 @@ for (j=0; j < nEntries; j++) { - if (Tables != NULL) - val = Tables->TheCurves[i]->Table16[j]; - else - val = _cmsQuantizeVal(j, nEntries); - + val = Tables->TheCurves[i]->Table16[j]; if (!_cmsWriteUInt16Number(io, val)) return FALSE; } } @@ -2057,7 +2056,6 @@ { cmsUInt8Number InputChannels, OutputChannels, CLUTpoints; cmsPipeline* NewLUT = NULL; - cmsStage *mpemat, *mpeclut; cmsUInt32Number nTabSize; cmsFloat64Number Matrix[3*3]; cmsUInt16Number InputEntries, OutputEntries; @@ -2094,9 +2092,8 @@ // Only operates on 3 channels if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { - mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL); - if (mpemat == NULL) goto Error; - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpemat); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL))) + goto Error; } if (!_cmsReadUInt16Number(io, &InputEntries)) goto Error; @@ -2110,7 +2107,7 @@ // Get 3D CLUT nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); - if (nTabSize == (size_t) -1) goto Error; + if (nTabSize == (cmsUInt32Number) -1) goto Error; if (nTabSize > 0) { cmsUInt16Number *T; @@ -2123,13 +2120,10 @@ goto Error; } - mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T); - if (mpeclut == NULL) { - _cmsFree(self ->ContextID, T); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) { + _cmsFree(self ->ContextID, T); goto Error; } - - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut); _cmsFree(self ->ContextID, T); } @@ -2159,7 +2153,7 @@ _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL; _cmsStageMatrixData* MatMPE = NULL; _cmsStageCLutData* clut = NULL; - int InputChannels, OutputChannels, clutPoints; + int i, InputChannels, OutputChannels, clutPoints; // Disassemble the LUT into components. mpe = NewLUT -> Elements; @@ -2234,13 +2228,13 @@ if (PreMPE != NULL) { if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE; } else { - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + if (!_cmsWriteUInt16Number(io, 2)) return FALSE; } if (PostMPE != NULL) { if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PostMPE ->TheCurves[0]->nEntries)) return FALSE; } else { - if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + if (!_cmsWriteUInt16Number(io, 2)) return FALSE; } @@ -2249,9 +2243,16 @@ if (PreMPE != NULL) { if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE; } + else { + for (i=0; i < InputChannels; i++) { + + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; + } + } nTabSize = uipow(OutputChannels, clutPoints, InputChannels); - if (nTabSize == (size_t) -1) return FALSE; + if (nTabSize == (cmsUInt32Number) -1) return FALSE; if (nTabSize > 0) { // The 3D CLUT. if (clut != NULL) { @@ -2263,7 +2264,13 @@ if (PostMPE != NULL) { if (!Write16bitTables(self ->ContextID, io, PostMPE)) return FALSE; } - + else { + for (i=0; i < OutputChannels; i++) { + + if (!_cmsWriteUInt16Number(io, 0)) return FALSE; + if (!_cmsWriteUInt16Number(io, 0xffff)) return FALSE; + } + } return TRUE; @@ -2479,7 +2486,6 @@ cmsUInt32Number offsetM; // Offset to first "M" curve cmsUInt32Number offsetC; // Offset to CLUT cmsUInt32Number offsetA; // Offset to first "A" curve - cmsStage* mpe; cmsPipeline* NewLUT = NULL; @@ -2501,37 +2507,35 @@ if (NewLUT == NULL) return NULL; if (offsetA!= 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan))) + goto Error; } if (offsetC != 0) { - mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) + goto Error; } if (offsetM != 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan))) + goto Error; } if (offsetMat != 0) { - mpe = ReadMatrix(self, io, BaseOffset + offsetMat); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) + goto Error; } if (offsetB != 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan))) + goto Error; } *nItems = 1; return NewLUT; +Error: + cmsPipelineFree(NewLUT); + return NULL; cmsUNUSED_PARAMETER(SizeOfTag); } @@ -2798,7 +2802,6 @@ cmsUInt32Number offsetM; // Offset to first "M" curve cmsUInt32Number offsetC; // Offset to CLUT cmsUInt32Number offsetA; // Offset to first "A" curve - cmsStage* mpe; cmsPipeline* NewLUT = NULL; @@ -2821,37 +2824,35 @@ if (NewLUT == NULL) return NULL; if (offsetB != 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan))) + goto Error; } if (offsetMat != 0) { - mpe = ReadMatrix(self, io, BaseOffset + offsetMat); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadMatrix(self, io, BaseOffset + offsetMat))) + goto Error; } if (offsetM != 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan))) + goto Error; } if (offsetC != 0) { - mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan))) + goto Error; } if (offsetA!= 0) { - mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan); - if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan))) + goto Error; } *nItems = 1; return NewLUT; +Error: + cmsPipelineFree(NewLUT); + return NULL; cmsUNUSED_PARAMETER(SizeOfTag); } @@ -3287,7 +3288,7 @@ SizeOfTag -= sizeof(cmsUInt32Number); if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error; - if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; + if (SizeOfTag < sizeof(cmsUInt64Number)) goto Error; SizeOfTag -= sizeof(cmsUInt64Number); if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error; @@ -4292,6 +4293,9 @@ if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; + if (InputChans == 0) goto Error; + if (OutputChans == 0) goto Error; + if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16) goto Error; @@ -4381,7 +4385,6 @@ { cmsStageSignature ElementSig; cmsTagTypeHandler* TypeHandler; - cmsStage *mpe = NULL; cmsUInt32Number nItems; cmsPipeline *NewLUT = (cmsPipeline *) Cargo; @@ -4409,11 +4412,8 @@ if (TypeHandler ->ReadPtr != NULL) { // This is a real element which should be read and processed - mpe = (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag); - if (mpe == NULL) return FALSE; - - // All seems ok, insert element - cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); + if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, (cmsStage*) TypeHandler ->ReadPtr(self, io, &nItems, SizeOfTag))) + return FALSE; } return TRUE; @@ -4479,10 +4479,10 @@ outputChan = cmsPipelineOutputChannels(Lut); ElemCount = cmsPipelineStageCount(Lut); - ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *)); + ElementOffsets = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); if (ElementOffsets == NULL) goto Error; - ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number *)); + ElementSizes = (cmsUInt32Number *) _cmsCalloc(self ->ContextID, ElemCount, sizeof(cmsUInt32Number)); if (ElementSizes == NULL) goto Error; // Write the head @@ -4825,10 +4825,10 @@ static cmsBool AllocElem(cmsContext ContextID, _cmsDICelem* e, cmsUInt32Number Count) { - e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number *)); + e->Offsets = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); if (e->Offsets == NULL) return FALSE; - e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number *)); + e->Sizes = (cmsUInt32Number *) _cmsCalloc(ContextID, Count, sizeof(cmsUInt32Number)); if (e->Sizes == NULL) { _cmsFree(ContextID, e -> Offsets); @@ -4844,7 +4844,7 @@ void FreeElem(_cmsDICelem* e) { if (e ->Offsets != NULL) _cmsFree(e -> ContextID, e -> Offsets); - if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e ->Sizes); + if (e ->Sizes != NULL) _cmsFree(e -> ContextID, e -> Sizes); e->Offsets = e ->Sizes = NULL; } @@ -5084,7 +5084,7 @@ if (!_cmsReadUInt32Number(io, &Count)) return NULL; SizeOfTag -= sizeof(cmsUInt32Number); - // Get rec lenghth + // Get rec length if (!_cmsReadUInt32Number(io, &Length)) return NULL; SizeOfTag -= sizeof(cmsUInt32Number); @@ -5118,14 +5118,22 @@ if (!ReadOneMLUC(self, io, &a.DisplayValue, i, &DisplayValueMLU)) goto Error; } + if (NameWCS == NULL || ValueWCS == NULL) { + + cmsSignalError(self->ContextID, cmsERROR_CORRUPTION_DETECTED, "Bad dictionary Name/Value"); + rc = FALSE; + } + else { + rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU); + } if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS); if (ValueWCS != NULL) _cmsFree(self ->ContextID, ValueWCS); if (DisplayNameMLU != NULL) cmsMLUfree(DisplayNameMLU); if (DisplayValueMLU != NULL) cmsMLUfree(DisplayValueMLU); - if (!rc) return FALSE; + if (!rc) goto Error; } FreeArray(&a); @@ -5277,14 +5285,14 @@ #define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList)) // Both kind of plug-ins share same structure -cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data) { - return RegisterTypesPlugin(Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT); + return RegisterTypesPlugin(id, Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT); } -cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data) { - return RegisterTypesPlugin(Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT); + return RegisterTypesPlugin(id, Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT); } @@ -5391,7 +5399,9 @@ { cmsSigScreeningTag, { 1, 1, { cmsSigScreeningType}, NULL }, &SupportedTags[59]}, { cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]}, { cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]}, - { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL}, NULL} + { cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]}, + { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, NULL} + }; @@ -5406,7 +5416,7 @@ #define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList)) -cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data) { cmsPluginTag* Plugin = (cmsPluginTag*) Data; _cmsTagLinkedList *pt, *Anterior; @@ -5430,7 +5440,7 @@ pt = pt ->Next; } - pt = (_cmsTagLinkedList*) _cmsPluginMalloc(sizeof(_cmsTagLinkedList)); + pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList)); if (pt == NULL) return FALSE; pt ->Signature = Plugin ->Signature; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c Wed Apr 16 10:53:10 2014 -0700 @@ -208,9 +208,26 @@ if (TransferFunction) { + // Tries to minimize space. Thanks to Richard Hughes for this nice idea if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error; - if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error; - if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error; + + if (TransferFunction[1] == TransferFunction[0]) { + + if (!cmsLinkTag (hICC, cmsSigGreenTRCTag, cmsSigRedTRCTag)) goto Error; + + } else { + + if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error; + } + + if (TransferFunction[2] == TransferFunction[0]) { + + if (!cmsLinkTag (hICC, cmsSigBlueTRCTag, cmsSigRedTRCTag)) goto Error; + + } else { + + if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error; + } } if (Primaries) { @@ -303,7 +320,6 @@ { cmsHPROFILE hICC; cmsPipeline* Pipeline; - cmsStage* Lin; int nChannels; hICC = cmsCreateProfilePlaceholder(ContextID); @@ -327,10 +343,8 @@ // Copy tables to Pipeline - Lin = cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions); - if (Lin == NULL) goto Error; - - cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Lin); + if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions))) + goto Error; // Create tags if (!SetTextTags(hICC, L"Linearization built-in")) goto Error; @@ -344,6 +358,7 @@ return hICC; Error: + cmsPipelineFree(Pipeline); if (hICC) cmsCloseProfile(hICC); @@ -451,9 +466,10 @@ if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error; - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)); - cmsPipelineInsertStage(LUT, cmsAT_END, CLUT); - cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)) || + !cmsPipelineInsertStage(LUT, cmsAT_END, CLUT) || + !cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels))) + goto Error; // Create tags if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error; @@ -504,7 +520,8 @@ LUT = cmsPipelineAlloc(ContextID, 3, 3); if (LUT == NULL) goto Error; - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3))) + goto Error; if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; cmsPipelineFree(LUT); @@ -550,7 +567,8 @@ LUT = cmsPipelineAlloc(ContextID, 3, 3); if (LUT == NULL) goto Error; - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) + goto Error; if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; cmsPipelineFree(LUT); @@ -595,7 +613,8 @@ LUT = cmsPipelineAlloc(ContextID, 3, 3); if (LUT == NULL) goto Error; - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3))) + goto Error; if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; cmsPipelineFree(LUT); @@ -734,81 +753,83 @@ // contrast, Saturation and white point displacement cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, - int nLUTPoints, - cmsFloat64Number Bright, - cmsFloat64Number Contrast, - cmsFloat64Number Hue, - cmsFloat64Number Saturation, - int TempSrc, - int TempDest) + int nLUTPoints, + cmsFloat64Number Bright, + cmsFloat64Number Contrast, + cmsFloat64Number Hue, + cmsFloat64Number Saturation, + int TempSrc, + int TempDest) { - cmsHPROFILE hICC; - cmsPipeline* Pipeline; - BCHSWADJUSTS bchsw; - cmsCIExyY WhitePnt; - cmsStage* CLUT; - cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; - int i; + cmsHPROFILE hICC; + cmsPipeline* Pipeline; + BCHSWADJUSTS bchsw; + cmsCIExyY WhitePnt; + cmsStage* CLUT; + cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS]; + int i; - - bchsw.Brightness = Bright; - bchsw.Contrast = Contrast; - bchsw.Hue = Hue; - bchsw.Saturation = Saturation; + bchsw.Brightness = Bright; + bchsw.Contrast = Contrast; + bchsw.Hue = Hue; + bchsw.Saturation = Saturation; - cmsWhitePointFromTemp(&WhitePnt, TempSrc ); - cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); + cmsWhitePointFromTemp(&WhitePnt, TempSrc ); + cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt); - cmsWhitePointFromTemp(&WhitePnt, TempDest); - cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); + cmsWhitePointFromTemp(&WhitePnt, TempDest); + cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt); - hICC = cmsCreateProfilePlaceholder(ContextID); - if (!hICC) // can't allocate - return NULL; + hICC = cmsCreateProfilePlaceholder(ContextID); + if (!hICC) // can't allocate + return NULL; - cmsSetDeviceClass(hICC, cmsSigAbstractClass); - cmsSetColorSpace(hICC, cmsSigLabData); - cmsSetPCS(hICC, cmsSigLabData); + cmsSetDeviceClass(hICC, cmsSigAbstractClass); + cmsSetColorSpace(hICC, cmsSigLabData); + cmsSetPCS(hICC, cmsSigLabData); - cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); - + cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL); - // Creates a Pipeline with 3D grid only - Pipeline = cmsPipelineAlloc(ContextID, 3, 3); - if (Pipeline == NULL) { - cmsCloseProfile(hICC); - return NULL; - } + // Creates a Pipeline with 3D grid only + Pipeline = cmsPipelineAlloc(ContextID, 3, 3); + if (Pipeline == NULL) { + cmsCloseProfile(hICC); + return NULL; + } - for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; - CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); - if (CLUT == NULL) return NULL; + for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints; + CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL); + if (CLUT == NULL) return NULL; - if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { + if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) { + + // Shouldn't reach here + goto Error; + } - // Shouldn't reach here - cmsPipelineFree(Pipeline); - cmsCloseProfile(hICC); - return NULL; - } + if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) { + goto Error; + } - cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT); - - // Create tags + // Create tags + if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; - if (!SetTextTags(hICC, L"BCHS built-in")) return NULL; + cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); - cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ()); + cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); - cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline); + // Pipeline is already on virtual profile + cmsPipelineFree(Pipeline); - // Pipeline is already on virtual profile - cmsPipelineFree(Pipeline); + // Ok, done + return hICC; - // Ok, done - return hICC; +Error: + cmsPipelineFree(Pipeline); + cmsCloseProfile(hICC); + return NULL; } @@ -856,7 +877,8 @@ PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab); cmsFreeToneCurve(EmptyTab); - cmsPipelineInsertStage(LUT, cmsAT_END, PostLin); + if (!cmsPipelineInsertStage(LUT, cmsAT_END, PostLin)) + goto Error; if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error; if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error; @@ -999,6 +1021,7 @@ { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}}, { TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }}, { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, @@ -1059,6 +1082,7 @@ cmsContext ContextID = cmsGetTransformContextID(hTransform); const cmsAllowedLUT* AllowedLUT; cmsTagSignature DestinationTag; + cmsProfileClassSignature deviceClass; _cmsAssert(hTransform != NULL); @@ -1080,13 +1104,15 @@ // Time to fix the Lab2/Lab4 issue. if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) { - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID))) + goto Error; } // On the output side too if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) { - cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID)); + if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID))) + goto Error; } @@ -1108,8 +1134,9 @@ FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2); FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2); + deviceClass = cmsGetDeviceClass(hProfile); - if (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) + if (deviceClass == cmsSigOutputClass) DestinationTag = cmsSigBToA0Tag; else DestinationTag = cmsSigAToB0Tag; @@ -1136,10 +1163,12 @@ // Put identity curves if needed if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)); + if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn))) + goto Error; if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType) - cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut)); + if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut))) + goto Error; AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); } @@ -1168,10 +1197,22 @@ if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error; } - if (xform ->Sequence != NULL) { + if ((deviceClass == cmsSigLinkClass) && (xform ->Sequence != NULL)) { if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error; } + // Set the white point + if (deviceClass == cmsSigInputClass) { + if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->EntryWhitePoint)) goto Error; + } + else { + if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->ExitWhitePoint)) goto Error; + } + + + // Per 7.2.15 in spec 4.3 + cmsSetHeaderRenderingIntent(hProfile, xform ->RenderingIntent); + cmsPipelineFree(LUT); return hProfile; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c Wed Apr 16 10:53:10 2014 -0700 @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -76,48 +76,48 @@ // Obtains WhitePoint from Temperature cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number TempK) { - cmsFloat64Number x, y; - cmsFloat64Number T, T2, T3; - // cmsFloat64Number M1, M2; + cmsFloat64Number x, y; + cmsFloat64Number T, T2, T3; + // cmsFloat64Number M1, M2; - _cmsAssert(WhitePoint != NULL); + _cmsAssert(WhitePoint != NULL); - T = TempK; - T2 = T*T; // Square - T3 = T2*T; // Cube + T = TempK; + T2 = T*T; // Square + T3 = T2*T; // Cube - // For correlated color temperature (T) between 4000K and 7000K: + // For correlated color temperature (T) between 4000K and 7000K: - if (T >= 4000. && T <= 7000.) - { - x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; - } - else - // or for correlated color temperature (T) between 7000K and 25000K: + if (T >= 4000. && T <= 7000.) + { + x = -4.6070*(1E9/T3) + 2.9678*(1E6/T2) + 0.09911*(1E3/T) + 0.244063; + } + else + // or for correlated color temperature (T) between 7000K and 25000K: - if (T > 7000.0 && T <= 25000.0) - { - x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; - } - else { - cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp"); - return FALSE; - } + if (T > 7000.0 && T <= 25000.0) + { + x = -2.0064*(1E9/T3) + 1.9018*(1E6/T2) + 0.24748*(1E3/T) + 0.237040; + } + else { + cmsSignalError(0, cmsERROR_RANGE, "cmsWhitePointFromTemp: invalid temp"); + return FALSE; + } - // Obtain y(x) + // Obtain y(x) - y = -3.000*(x*x) + 2.870*x - 0.275; + y = -3.000*(x*x) + 2.870*x - 0.275; - // wave factors (not used, but here for futures extensions) + // wave factors (not used, but here for futures extensions) - // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); - // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); + // M1 = (-1.3515 - 1.7703*x + 5.9114 *y)/(0.0241 + 0.2562*x - 0.7341*y); + // M2 = (0.0300 - 31.4424*x + 30.0717*y)/(0.0241 + 0.2562*x - 0.7341*y); - WhitePoint -> x = x; - WhitePoint -> y = y; - WhitePoint -> Y = 1.0; + WhitePoint -> x = x; + WhitePoint -> y = y; + WhitePoint -> Y = 1.0; - return TRUE; + return TRUE; } @@ -266,7 +266,7 @@ {{ 0.8951, 0.2664, -0.1614 }}, {{ -0.7502, 1.7135, 0.0367 }}, {{ 0.0389, -0.0685, 1.0296 }} - }}; + }}; if (ConeMatrix == NULL) ConeMatrix = &LamRigg; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c Wed Apr 16 10:53:10 2014 -0700 @@ -396,7 +396,7 @@ static _cmsTransformCollection* TransformCollection = NULL; // Register new ways to transform -cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Data) +cmsBool _cmsRegisterTransformPlugin(cmsContext id, cmsPluginBase* Data) { cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; _cmsTransformCollection* fl; @@ -412,7 +412,7 @@ if (Plugin ->Factory == NULL) return FALSE; - fl = (_cmsTransformCollection*) _cmsPluginMalloc(sizeof(_cmsTransformCollection)); + fl = (_cmsTransformCollection*) _cmsPluginMalloc(id, sizeof(_cmsTransformCollection)); if (fl == NULL) return FALSE; // Copy the parameters @@ -651,6 +651,22 @@ // ---------------------------------------------------------------------------------------------------------------- +static +void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src) +{ + if (src == NULL) { + wtPt ->X = cmsD50X; + wtPt ->Y = cmsD50Y; + wtPt ->Z = cmsD50Z; + } + else { + wtPt ->X = src->X; + wtPt ->Y = src->Y; + wtPt ->Z = src->Z; + } + +} + // New to lcms 2.0 -- have all parameters available. cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], @@ -664,7 +680,6 @@ cmsUInt32Number dwFlags) { _cmsTRANSFORM* xform; - cmsBool FloatTransform; cmsColorSpaceSignature EntryColorSpace; cmsColorSpaceSignature ExitColorSpace; cmsPipeline* Lut; @@ -681,9 +696,7 @@ if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK; } - // On floating point transforms, inhibit optimizations - FloatTransform = (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)); - + // On floating point transforms, inhibit cache if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat)) dwFlags |= cmsFLAGS_NOCACHE; @@ -730,6 +743,10 @@ xform ->ExitColorSpace = ExitColorSpace; xform ->RenderingIntent = Intents[nProfiles-1]; + // Take white points + SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag)); + SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag)); + // Create a gamut check LUT if requested if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK)) diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h Wed Apr 16 10:53:10 2014 -0700 @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2011 Marti Maria Saguer +// Copyright (c) 1998-2013 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -52,7 +52,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.4 +// Version 2.5 // #ifndef _lcms2_H @@ -101,7 +101,7 @@ #endif // Version/release -#define LCMS_VERSION 2040 +#define LCMS_VERSION 2050 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -367,6 +367,7 @@ cmsSigPreview1Tag = 0x70726531, // 'pre1' cmsSigPreview2Tag = 0x70726532, // 'pre2' cmsSigProfileDescriptionTag = 0x64657363, // 'desc' + cmsSigProfileDescriptionMLTag = 0x6473636d, // 'dscm' cmsSigProfileSequenceDescTag = 0x70736571, // 'pseq' cmsSigProfileSequenceIdTag = 0x70736964, // 'psid' cmsSigPs2CRD0Tag = 0x70736430, // 'psd0' @@ -1014,6 +1015,7 @@ // Plug-In registering --------------------------------------------------------------------------------------------------- CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin); +CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin); CMSAPI void CMSEXPORT cmsUnregisterPlugins(void); // Error logging ---------------------------------------------------------------------------------------------------------- @@ -1190,7 +1192,7 @@ // Where to place/locate the stages in the pipeline chain typedef enum { cmsAT_BEGIN, cmsAT_END } cmsStageLoc; -CMSAPI void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe); +CMSAPI int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe); CMSAPI void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe); // This function is quite useful to analyze the structure of a Pipeline and retrieve the Stage elements @@ -1274,6 +1276,13 @@ const char LanguageCode[3], const char CountryCode[3], char ObtainedLanguage[3], char ObtainedCountry[3]); +CMSAPI cmsUInt32Number CMSEXPORT cmsMLUtranslationsCount(const cmsMLU* mlu); + +CMSAPI cmsBool CMSEXPORT cmsMLUtranslationsCodes(const cmsMLU* mlu, + cmsUInt32Number idx, + char LanguageCode[3], + char CountryCode[3]); + // Undercolorremoval & black generation ------------------------------------------------------------------------------------- typedef struct { @@ -1424,6 +1433,7 @@ CMSAPI void CMSEXPORT cmsSetHeaderFlags(cmsHPROFILE hProfile, cmsUInt32Number Flags); CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderManufacturer(cmsHPROFILE hProfile); CMSAPI void CMSEXPORT cmsSetHeaderManufacturer(cmsHPROFILE hProfile, cmsUInt32Number manufacturer); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderCreator(cmsHPROFILE hProfile); CMSAPI cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile); CMSAPI void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model); CMSAPI void CMSEXPORT cmsSetHeaderAttributes(cmsHPROFILE hProfile, cmsUInt64Number Flags); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h Wed Apr 16 10:53:10 2014 -0700 @@ -27,7 +27,7 @@ // However, the following notice accompanied the original version of this // file: // -//--------------------------------------------------------------------------------- + // // Little Color Management System // Copyright (c) 1998-2011 Marti Maria Saguer @@ -196,7 +196,7 @@ // Plug-In registering --------------------------------------------------------------- // Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once. -void* _cmsPluginMalloc(cmsUInt32Number size); +void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size); // Memory management cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin); @@ -205,28 +205,28 @@ cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin); // Parametric curves -cmsBool _cmsRegisterParametricCurvesPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Formatters management -cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Tag type management -cmsBool _cmsRegisterTagTypePlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterTagTypePlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Tag management -cmsBool _cmsRegisterTagPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterTagPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Intent management -cmsBool _cmsRegisterRenderingIntentPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Multi Process elements -cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Optimization -cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // Transform -cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Plugin); +cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin); // --------------------------------------------------------------------------------------------------------- @@ -263,7 +263,7 @@ cmsUInt16Number Country; cmsUInt32Number StrW; // Offset to current unicode string - cmsUInt32Number Len; // Lenght in bytes + cmsUInt32Number Len; // Length in bytes } _cmsMLUentry; @@ -330,9 +330,11 @@ cmsColorSpaceSignature ColorSpace; cmsColorSpaceSignature PCS; cmsUInt32Number RenderingIntent; + cmsUInt32Number flags; cmsUInt32Number manufacturer, model; cmsUInt64Number attributes; + cmsUInt32Number creator; cmsProfileID ProfileID; @@ -585,6 +587,10 @@ cmsColorSpaceSignature EntryColorSpace; cmsColorSpaceSignature ExitColorSpace; + // White points (informative only) + cmsCIEXYZ EntryWhitePoint; + cmsCIEXYZ ExitWhitePoint; + // Profiles used to create the transform cmsSEQ* Sequence; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/management/Flag.c --- a/jdk/src/share/native/sun/management/Flag.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/management/Flag.c Wed Apr 16 10:53:10 2014 -0700 @@ -97,12 +97,12 @@ return 0; } - if (count == 0) { + if (count <= 0) { JNU_ThrowIllegalArgumentException(env, 0); return 0; } - gsize = count * sizeof(jmmVMGlobal); + gsize = (size_t)count * sizeof(jmmVMGlobal); globals = (jmmVMGlobal*) malloc(gsize); if (globals == NULL) { JNU_ThrowOutOfMemoryError(env, 0); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/share/native/sun/management/GcInfoBuilder.c --- a/jdk/src/share/native/sun/management/GcInfoBuilder.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/share/native/sun/management/GcInfoBuilder.c Wed Apr 16 10:53:10 2014 -0700 @@ -59,12 +59,12 @@ return; } - if (num_attributes == 0) { + if (num_attributes <= 0) { JNU_ThrowIllegalArgumentException(env, "Invalid num_attributes"); return; } - ext_att_info = (jmmExtAttributeInfo*) malloc(num_attributes * + ext_att_info = (jmmExtAttributeInfo*) malloc((size_t)num_attributes * sizeof(jmmExtAttributeInfo)); if (ext_att_info == NULL) { JNU_ThrowOutOfMemoryError(env, 0); @@ -78,7 +78,7 @@ return; } - nativeTypes = (jchar*) malloc(num_attributes * sizeof(jchar)); + nativeTypes = (jchar*) malloc((size_t)num_attributes * sizeof(jchar)); if (nativeTypes == NULL) { free(ext_att_info); JNU_ThrowOutOfMemoryError(env, 0); @@ -188,11 +188,16 @@ return 0; } + if (ext_att_count <= 0) { + JNU_ThrowIllegalArgumentException(env, "Invalid ext_att_count"); + return 0; + } + gc_stat.usage_before_gc = usageBeforeGC; gc_stat.usage_after_gc = usageAfterGC; gc_stat.gc_ext_attribute_values_size = ext_att_count; if (ext_att_count > 0) { - gc_stat.gc_ext_attribute_values = (jvalue*) malloc(ext_att_count * + gc_stat.gc_ext_attribute_values = (jvalue*) malloc((size_t)ext_att_count * sizeof(jvalue)); if (gc_stat.gc_ext_attribute_values == NULL) { JNU_ThrowOutOfMemoryError(env, 0); @@ -212,7 +217,7 @@ } // convert the ext_att_types to native types - nativeTypes = (jchar*) malloc(ext_att_count * sizeof(jchar)); + nativeTypes = (jchar*) malloc((size_t)ext_att_count * sizeof(jchar)); if (nativeTypes == NULL) { if (gc_stat.gc_ext_attribute_values != NULL) { free(gc_stat.gc_ext_attribute_values); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/awt/X11/XClipboard.java --- a/jdk/src/solaris/classes/sun/awt/X11/XClipboard.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XClipboard.java Wed Apr 16 10:53:10 2014 -0700 @@ -86,7 +86,7 @@ protected synchronized void setContentsNative(Transferable contents) { SortedMap formatMap = DataTransferer.getInstance().getFormatsForTransferable - (contents, DataTransferer.adaptFlavorMap(flavorMap)); + (contents, DataTransferer.adaptFlavorMap(getDefaultFlavorTable())); long[] formats = DataTransferer.keysToLongArray(formatMap); if (!selection.setOwner(contents, formatMap, formats, @@ -125,7 +125,7 @@ private void checkChangeHere(Transferable contents) { if (areFlavorListenersRegistered()) { checkChange(DataTransferer.getInstance(). - getFormatsForTransferableAsArray(contents, flavorMap)); + getFormatsForTransferableAsArray(contents, getDefaultFlavorTable())); } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/awt/X11/XToolkit.java --- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Wed Apr 16 10:53:10 2014 -0700 @@ -50,7 +50,8 @@ import sun.awt.datatransfer.DataTransferer; import sun.font.FontConfigManager; import sun.java2d.SunGraphicsEnvironment; -import sun.misc.PerformanceLogger; +import sun.misc.*; +import sun.misc.ThreadGroupUtils; import sun.print.PrintJob2D; import sun.security.action.GetPropertyAction; import sun.security.action.GetBooleanAction; @@ -254,33 +255,25 @@ } finally { awtUnlock(); } - PrivilegedAction a = new PrivilegedAction() { - public Void run() { - ThreadGroup mainTG = Thread.currentThread().getThreadGroup(); - ThreadGroup parentTG = mainTG.getParent(); - while (parentTG != null) { - mainTG = parentTG; - parentTG = mainTG.getParent(); - } - Thread shutdownThread = new Thread(mainTG, "XToolkt-Shutdown-Thread") { - public void run() { - XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance(); - if (peer != null) { - peer.dispose(); - } - if (xs != null) { - ((XAWTXSettings)xs).dispose(); - } - freeXKB(); - if (log.isLoggable(PlatformLogger.Level.FINE)) { - dumpPeers(); - } + PrivilegedAction a = () -> { + Thread shutdownThread = new Thread(ThreadGroupUtils.getRootThreadGroup(), "XToolkt-Shutdown-Thread") { + public void run() { + XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance(); + if (peer != null) { + peer.dispose(); + } + if (xs != null) { + ((XAWTXSettings)xs).dispose(); } - }; - shutdownThread.setContextClassLoader(null); - Runtime.getRuntime().addShutdownHook(shutdownThread); - return null; - } + freeXKB(); + if (log.isLoggable(PlatformLogger.Level.FINE)) { + dumpPeers(); + } + } + }; + shutdownThread.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(shutdownThread); + return null; }; AccessController.doPrivileged(a); } @@ -322,21 +315,13 @@ init(); XWM.init(); - PrivilegedAction action = new PrivilegedAction() { - public Thread run() { - ThreadGroup currentTG = Thread.currentThread().getThreadGroup(); - ThreadGroup parentTG = currentTG.getParent(); - while (parentTG != null) { - currentTG = parentTG; - parentTG = currentTG.getParent(); - } - Thread thread = new Thread(currentTG, XToolkit.this, "AWT-XAWT"); - thread.setPriority(Thread.NORM_PRIORITY + 1); - thread.setDaemon(true); - return thread; - } - }; - toolkitThread = AccessController.doPrivileged(action); + toolkitThread = AccessController.doPrivileged((PrivilegedAction) () -> { + Thread thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), XToolkit.this, "AWT-XAWT"); + thread.setContextClassLoader(null); + thread.setPriority(Thread.NORM_PRIORITY + 1); + thread.setDaemon(true); + return thread; + }); toolkitThread.start(); } } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java --- a/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/awt/X11GraphicsDevice.java Wed Apr 16 10:53:10 2014 -0700 @@ -42,6 +42,8 @@ import sun.java2d.xr.XRGraphicsConfig; import sun.java2d.loops.SurfaceType; +import sun.misc.ThreadGroupUtils; + /** * This is an implementation of a GraphicsDevice object for a single * X11 screen. @@ -423,28 +425,19 @@ // is already in the original DisplayMode at that time, this // hook will have no effect) shutdownHookRegistered = true; - PrivilegedAction a = new PrivilegedAction() { - public Void run() { - ThreadGroup mainTG = Thread.currentThread().getThreadGroup(); - ThreadGroup parentTG = mainTG.getParent(); - while (parentTG != null) { - mainTG = parentTG; - parentTG = mainTG.getParent(); + PrivilegedAction a = () -> { + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + Runnable r = () -> { + Window old = getFullScreenWindow(); + if (old != null) { + exitFullScreenExclusive(old); + setDisplayMode(origDisplayMode); } - Runnable r = new Runnable() { - public void run() { - Window old = getFullScreenWindow(); - if (old != null) { - exitFullScreenExclusive(old); - setDisplayMode(origDisplayMode); - } - } - }; - Thread t = new Thread(mainTG, r,"Display-Change-Shutdown-Thread-"+screen); - t.setContextClassLoader(null); - Runtime.getRuntime().addShutdownHook(t); - return null; - } + }; + Thread t = new Thread(rootTG, r,"Display-Change-Shutdown-Thread-"+screen); + t.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(t); + return null; }; AccessController.doPrivileged(a); } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/net/www/content-types.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/solaris/classes/sun/net/www/content-types.properties Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,280 @@ +#sun.net.www MIME content-types table +# +# Property fields: +# +# ::= 'description' '=' +# ::= 'file_extensions' '=' +# ::= 'icon' '=' +# ::= 'browser' | 'application' | 'save' | 'unknown' +# ::= 'application' '=' +# + +# +# The "we don't know anything about this data" type(s). +# Used internally to mark unrecognized types. +# +content/unknown: description=Unknown Content +unknown/unknown: description=Unknown Data Type + +# +# The template we should use for temporary files when launching an application +# to view a document of given type. +# +temp.file.template: /tmp/%s + +# +# The "real" types. +# +application/octet-stream: \ + description=Generic Binary Stream;\ + file_extensions=.saveme,.dump,.hqx,.arc,.o,.a,.bin,.exe,.z,.gz + +application/oda: \ + description=ODA Document;\ + file_extensions=.oda + +application/pdf: \ + description=Adobe PDF Format;\ + file_extensions=.pdf + +application/postscript: \ + description=Postscript File;\ + file_extensions=.eps,.ai,.ps;\ + icon=ps;\ + action=application;\ + application=imagetool %s + +application/x-dvi: \ + description=TeX DVI File;\ + file_extensions=.dvi;\ + action=application;\ + application=xdvi %s + +application/x-hdf: \ + description=Hierarchical Data Format;\ + file_extensions=.hdf;\ + action=save + +application/x-latex: \ + description=LaTeX Source;\ + file_extensions=.latex + +application/x-netcdf: \ + description=Unidata netCDF Data Format;\ + file_extensions=.nc,.cdf;\ + action=save + +application/x-tex: \ + description=TeX Source;\ + file_extensions=.tex + +application/x-texinfo: \ + description=Gnu Texinfo;\ + file_extensions=.texinfo,.texi + +application/x-troff: \ + description=Troff Source;\ + file_extensions=.t,.tr,.roff;\ + action=application;\ + application=xterm -title troff -e sh -c \"nroff %s | col | more -w\" + +application/x-troff-man: \ + description=Troff Manpage Source;\ + file_extensions=.man;\ + action=application;\ + application=xterm -title troff -e sh -c \"nroff -man %s | col | more -w\" + +application/x-troff-me: \ + description=Troff ME Macros;\ + file_extensions=.me;\ + action=application;\ + application=xterm -title troff -e sh -c \"nroff -me %s | col | more -w\" + +application/x-troff-ms: \ + description=Troff MS Macros;\ + file_extensions=.ms;\ + action=application;\ + application=xterm -title troff -e sh -c \"nroff -ms %s | col | more -w\" + +application/x-wais-source: \ + description=Wais Source;\ + file_extensions=.src,.wsrc + +application/zip: \ + description=Zip File;\ + file_extensions=.zip;\ + icon=zip;\ + action=save + +application/x-bcpio: \ + description=Old Binary CPIO Archive;\ + file_extensions=.bcpio; action=save + +application/x-cpio: \ + description=Unix CPIO Archive;\ + file_extensions=.cpio; action=save + +application/x-gtar: \ + description=Gnu Tar Archive;\ + file_extensions=.gtar;\ + icon=tar;\ + action=save + +application/x-shar: \ + description=Shell Archive;\ + file_extensions=.sh,.shar;\ + action=save + +application/x-sv4cpio: \ + description=SVR4 CPIO Archive;\ + file_extensions=.sv4cpio; action=save + +application/x-sv4crc: \ + description=SVR4 CPIO with CRC;\ + file_extensions=.sv4crc; action=save + +application/x-tar: \ + description=Tar Archive;\ + file_extensions=.tar;\ + icon=tar;\ + action=save + +application/x-ustar: \ + description=US Tar Archive;\ + file_extensions=.ustar;\ + action=save + +audio/basic: \ + description=Basic Audio;\ + file_extensions=.snd,.au;\ + icon=audio;\ + action=application;\ + application=audiotool %s + +audio/x-aiff: \ + description=Audio Interchange Format File;\ + file_extensions=.aifc,.aif,.aiff;\ + icon=aiff + +audio/x-wav: \ + description=Wav Audio;\ + file_extensions=.wav;\ + icon=wav + +image/gif: \ + description=GIF Image;\ + file_extensions=.gif;\ + icon=gif;\ + action=browser + +image/ief: \ + description=Image Exchange Format;\ + file_extensions=.ief + +image/jpeg: \ + description=JPEG Image;\ + file_extensions=.jfif,.jfif-tbnl,.jpe,.jpg,.jpeg;\ + icon=jpeg;\ + action=browser;\ + application=imagetool %s + +image/tiff: \ + description=TIFF Image;\ + file_extensions=.tif,.tiff;\ + icon=tiff + +image/vnd.fpx: \ + description=FlashPix Image;\ + file_extensions=.fpx,.fpix + +image/x-cmu-rast: \ + description=CMU Raster Image;\ + file_extensions=.ras + +image/x-portable-anymap: \ + description=PBM Anymap Format;\ + file_extensions=.pnm + +image/x-portable-bitmap: \ + description=PBM Bitmap Format;\ + file_extensions=.pbm + +image/x-portable-graymap: \ + description=PBM Graymap Format;\ + file_extensions=.pgm + +image/x-portable-pixmap: \ + description=PBM Pixmap Format;\ + file_extensions=.ppm + +image/x-rgb: \ + description=RGB Image;\ + file_extensions=.rgb + +image/x-xbitmap: \ + description=X Bitmap Image;\ + file_extensions=.xbm,.xpm + +image/x-xwindowdump: \ + description=X Window Dump Image;\ + file_extensions=.xwd + +image/png: \ + description=PNG Image;\ + file_extensions=.png;\ + icon=png;\ + action=browser + +image/bmp: \ + description=Bitmap Image;\ + file_extensions=.bmp; + +text/html: \ + description=HTML Document;\ + file_extensions=.htm,.html;\ + icon=html + +text/plain: \ + description=Plain Text;\ + file_extensions=.text,.c,.cc,.c++,.h,.pl,.txt,.java,.el;\ + icon=text;\ + action=browser + +text/tab-separated-values: \ + description=Tab Separated Values Text;\ + file_extensions=.tsv + +text/x-setext: \ + description=Structure Enhanced Text;\ + file_extensions=.etx + +video/mpeg: \ + description=MPEG Video Clip;\ + file_extensions=.mpg,.mpe,.mpeg;\ + icon=mpeg;\ + action=application;\ + application=mpeg_play %s + +video/quicktime: \ + description=QuickTime Video Clip;\ + file_extensions=.mov,.qt + +application/x-troff-msvideo: \ + description=AVI Video;\ + file_extensions=.avi;\ + icon=avi + +video/x-sgi-movie: \ + description=SGI Movie;\ + file_extensions=.movie,.mv + +message/rfc822: \ + description=Internet Email Message;\ + file_extensions=.mime + +application/xml: \ + description=XML document;\ + file_extensions=.xml + + + diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java --- a/jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxNativeDispatcher.java Wed Apr 16 10:53:10 2014 -0700 @@ -77,7 +77,7 @@ } private static native int fgetxattr0(int filedes, long nameAddress, - long valueAdddress, int valueLen) throws UnixException; + long valueAddress, int valueLen) throws UnixException; /** * fsetxattr(int filedes, const char *name, const void *value, size_t size, int flags); @@ -94,7 +94,7 @@ } private static native void fsetxattr0(int filedes, long nameAddress, - long valueAdddress, int valueLen) throws UnixException; + long valueAddress, int valueLen) throws UnixException; /** * fremovexattr(int filedes, const char *name); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/nio/fs/MagicFileTypeDetector.java --- a/jdk/src/solaris/classes/sun/nio/fs/MagicFileTypeDetector.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/nio/fs/MagicFileTypeDetector.java Wed Apr 16 10:53:10 2014 -0700 @@ -36,7 +36,7 @@ class MagicFileTypeDetector extends AbstractFileTypeDetector { - private static final String UNKNOW_MIME_TYPE = "application/octet-stream"; + private static final String UNKNOWN_MIME_TYPE = "application/octet-stream"; // true if libmagic is available and successfully loaded private final boolean libmagicAvailable; @@ -57,7 +57,7 @@ try { byte[] type = probe0(buffer.address()); String mimeType = (type == null) ? null : new String(type); - return UNKNOW_MIME_TYPE.equals(mimeType) ? null : mimeType; + return UNKNOWN_MIME_TYPE.equals(mimeType) ? null : mimeType; } finally { buffer.release(); } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java --- a/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java Wed Apr 16 10:53:10 2014 -0700 @@ -290,7 +290,7 @@ return acl; } - // Retrns true if NFSv4 ACLs not enabled on file system + // Returns true if NFSv4 ACLs not enabled on file system private static boolean isAclsEnabled(int fd) { try { long enabled = fpathconf(fd, _PC_ACL_ENABLED); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java --- a/jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisWatchService.java Wed Apr 16 10:53:10 2014 -0700 @@ -627,14 +627,14 @@ /** * Update watch key's events. If ENTRY_MODIFY changes to be enabled - * then register each file in the direcory; If ENTRY_MODIFY changed to + * then register each file in the directory; If ENTRY_MODIFY changed to * be disabled then unregister each file. */ void updateEvents(SolarisWatchKey key, Set> events) throws UnixException { - // update events, rembering if ENTRY_MODIFY was previously + // update events, remembering if ENTRY_MODIFY was previously // enabled or disabled. boolean oldModifyEnabled = key.events() .contains(StandardWatchEventKinds.ENTRY_MODIFY); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java --- a/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java Wed Apr 16 10:53:10 2014 -0700 @@ -48,7 +48,7 @@ // filter (may be null) private final DirectoryStream.Filter filter; - // used to coorindate closing of directory stream + // used to coordinate closing of directory stream private final ReentrantReadWriteLock streamLock = new ReentrantReadWriteLock(true); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java --- a/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java Wed Apr 16 10:53:10 2014 -0700 @@ -133,7 +133,7 @@ private static final String OWNER_NAME = "owner"; private static final String GROUP_NAME = "group"; - // the names of the posix attributes (incudes basic) + // the names of the posix attributes (includes basic) static final Set posixAttributeNames = Util.newSet(basicAttributeNames, PERMISSIONS_NAME, OWNER_NAME, GROUP_NAME); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java --- a/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileSystem.java Wed Apr 16 10:53:10 2014 -0700 @@ -339,7 +339,7 @@ }; } - // Override if the platform has different path match requrement, such as + // Override if the platform has different path match requirement, such as // case insensitive or Unicode canonical equal on MacOSX Pattern compilePathMatchPattern(String expr) { return Pattern.compile(expr); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/demo/jni/Poller/Poller.c --- a/jdk/src/solaris/demo/jni/Poller/Poller.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/demo/jni/Poller/Poller.c Wed Apr 16 10:53:10 2014 -0700 @@ -318,7 +318,7 @@ ioevent_t *ioeh; - if (handle < 0 || handle > MAX_HANDLES) + if (handle < 0 || handle >= MAX_HANDLES) { STATE_EXCEPTION("DestroyPoller - handle out of range"); return; @@ -366,7 +366,7 @@ int retval; ioevent_t *ioeh; - if (handle < 0 || handle > MAX_HANDLES) + if (handle < 0 || handle >= MAX_HANDLES) return STATE_EXCEPTION("AddFd - handle out of range"); ioeh = &IOE_handles[handle]; @@ -459,7 +459,7 @@ return fd; } - /* +/* * Class: Poller * Method: nativeRemoveFd * Signature: (II)I @@ -469,7 +469,7 @@ { ioevent_t *ioeh; - if (handle < 0 || handle > MAX_HANDLES) + if (handle < 0 || handle >= MAX_HANDLES) return STATE_EXCEPTION("RemoveFd - handle out of range"); ioeh = &IOE_handles[handle]; @@ -576,7 +576,7 @@ int i; ioevent_t *ioeh; - if (handle < 0 || handle > MAX_HANDLES) + if (handle < 0 || handle >= MAX_HANDLES) return STATE_EXCEPTION("IsMember - handle out of range"); ioeh = &IOE_handles[handle]; @@ -629,7 +629,7 @@ ioevent_t *ioeh; jboolean isCopy1,isCopy2; - if (handle < 0 || handle > MAX_HANDLES) + if (handle < 0 || handle >= MAX_HANDLES) return STATE_EXCEPTION("nativeWait - handle out of range"); ioeh = &IOE_handles[handle]; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/lib/content-types.properties --- a/jdk/src/solaris/lib/content-types.properties Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,280 +0,0 @@ -#sun.net.www MIME content-types table -# -# Property fields: -# -# ::= 'description' '=' -# ::= 'file_extensions' '=' -# ::= 'icon' '=' -# ::= 'browser' | 'application' | 'save' | 'unknown' -# ::= 'application' '=' -# - -# -# The "we don't know anything about this data" type(s). -# Used internally to mark unrecognized types. -# -content/unknown: description=Unknown Content -unknown/unknown: description=Unknown Data Type - -# -# The template we should use for temporary files when launching an application -# to view a document of given type. -# -temp.file.template: /tmp/%s - -# -# The "real" types. -# -application/octet-stream: \ - description=Generic Binary Stream;\ - file_extensions=.saveme,.dump,.hqx,.arc,.o,.a,.bin,.exe,.z,.gz - -application/oda: \ - description=ODA Document;\ - file_extensions=.oda - -application/pdf: \ - description=Adobe PDF Format;\ - file_extensions=.pdf - -application/postscript: \ - description=Postscript File;\ - file_extensions=.eps,.ai,.ps;\ - icon=ps;\ - action=application;\ - application=imagetool %s - -application/x-dvi: \ - description=TeX DVI File;\ - file_extensions=.dvi;\ - action=application;\ - application=xdvi %s - -application/x-hdf: \ - description=Hierarchical Data Format;\ - file_extensions=.hdf;\ - action=save - -application/x-latex: \ - description=LaTeX Source;\ - file_extensions=.latex - -application/x-netcdf: \ - description=Unidata netCDF Data Format;\ - file_extensions=.nc,.cdf;\ - action=save - -application/x-tex: \ - description=TeX Source;\ - file_extensions=.tex - -application/x-texinfo: \ - description=Gnu Texinfo;\ - file_extensions=.texinfo,.texi - -application/x-troff: \ - description=Troff Source;\ - file_extensions=.t,.tr,.roff;\ - action=application;\ - application=xterm -title troff -e sh -c \"nroff %s | col | more -w\" - -application/x-troff-man: \ - description=Troff Manpage Source;\ - file_extensions=.man;\ - action=application;\ - application=xterm -title troff -e sh -c \"nroff -man %s | col | more -w\" - -application/x-troff-me: \ - description=Troff ME Macros;\ - file_extensions=.me;\ - action=application;\ - application=xterm -title troff -e sh -c \"nroff -me %s | col | more -w\" - -application/x-troff-ms: \ - description=Troff MS Macros;\ - file_extensions=.ms;\ - action=application;\ - application=xterm -title troff -e sh -c \"nroff -ms %s | col | more -w\" - -application/x-wais-source: \ - description=Wais Source;\ - file_extensions=.src,.wsrc - -application/zip: \ - description=Zip File;\ - file_extensions=.zip;\ - icon=zip;\ - action=save - -application/x-bcpio: \ - description=Old Binary CPIO Archive;\ - file_extensions=.bcpio; action=save - -application/x-cpio: \ - description=Unix CPIO Archive;\ - file_extensions=.cpio; action=save - -application/x-gtar: \ - description=Gnu Tar Archive;\ - file_extensions=.gtar;\ - icon=tar;\ - action=save - -application/x-shar: \ - description=Shell Archive;\ - file_extensions=.sh,.shar;\ - action=save - -application/x-sv4cpio: \ - description=SVR4 CPIO Archive;\ - file_extensions=.sv4cpio; action=save - -application/x-sv4crc: \ - description=SVR4 CPIO with CRC;\ - file_extensions=.sv4crc; action=save - -application/x-tar: \ - description=Tar Archive;\ - file_extensions=.tar;\ - icon=tar;\ - action=save - -application/x-ustar: \ - description=US Tar Archive;\ - file_extensions=.ustar;\ - action=save - -audio/basic: \ - description=Basic Audio;\ - file_extensions=.snd,.au;\ - icon=audio;\ - action=application;\ - application=audiotool %s - -audio/x-aiff: \ - description=Audio Interchange Format File;\ - file_extensions=.aifc,.aif,.aiff;\ - icon=aiff - -audio/x-wav: \ - description=Wav Audio;\ - file_extensions=.wav;\ - icon=wav - -image/gif: \ - description=GIF Image;\ - file_extensions=.gif;\ - icon=gif;\ - action=browser - -image/ief: \ - description=Image Exchange Format;\ - file_extensions=.ief - -image/jpeg: \ - description=JPEG Image;\ - file_extensions=.jfif,.jfif-tbnl,.jpe,.jpg,.jpeg;\ - icon=jpeg;\ - action=browser;\ - application=imagetool %s - -image/tiff: \ - description=TIFF Image;\ - file_extensions=.tif,.tiff;\ - icon=tiff - -image/vnd.fpx: \ - description=FlashPix Image;\ - file_extensions=.fpx,.fpix - -image/x-cmu-rast: \ - description=CMU Raster Image;\ - file_extensions=.ras - -image/x-portable-anymap: \ - description=PBM Anymap Format;\ - file_extensions=.pnm - -image/x-portable-bitmap: \ - description=PBM Bitmap Format;\ - file_extensions=.pbm - -image/x-portable-graymap: \ - description=PBM Graymap Format;\ - file_extensions=.pgm - -image/x-portable-pixmap: \ - description=PBM Pixmap Format;\ - file_extensions=.ppm - -image/x-rgb: \ - description=RGB Image;\ - file_extensions=.rgb - -image/x-xbitmap: \ - description=X Bitmap Image;\ - file_extensions=.xbm,.xpm - -image/x-xwindowdump: \ - description=X Window Dump Image;\ - file_extensions=.xwd - -image/png: \ - description=PNG Image;\ - file_extensions=.png;\ - icon=png;\ - action=browser - -image/bmp: \ - description=Bitmap Image;\ - file_extensions=.bmp; - -text/html: \ - description=HTML Document;\ - file_extensions=.htm,.html;\ - icon=html - -text/plain: \ - description=Plain Text;\ - file_extensions=.text,.c,.cc,.c++,.h,.pl,.txt,.java,.el;\ - icon=text;\ - action=browser - -text/tab-separated-values: \ - description=Tab Separated Values Text;\ - file_extensions=.tsv - -text/x-setext: \ - description=Structure Enhanced Text;\ - file_extensions=.etx - -video/mpeg: \ - description=MPEG Video Clip;\ - file_extensions=.mpg,.mpe,.mpeg;\ - icon=mpeg;\ - action=application;\ - application=mpeg_play %s - -video/quicktime: \ - description=QuickTime Video Clip;\ - file_extensions=.mov,.qt - -application/x-troff-msvideo: \ - description=AVI Video;\ - file_extensions=.avi;\ - icon=avi - -video/x-sgi-movie: \ - description=SGI Movie;\ - file_extensions=.movie,.mv - -message/rfc822: \ - description=Internet Email Message;\ - file_extensions=.mime - -application/xml: \ - description=XML document;\ - file_extensions=.xml - - - diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.c --- a/jdk/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.c Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.c Wed Apr 16 10:53:10 2014 -0700 @@ -76,7 +76,7 @@ adPath[*count].st_ino = statBuf.st_ino; adPath[*count].st_dev = statBuf.st_dev; strncpy(adPath[*count].path, path, MAX_NAME_LENGTH); - adPath[*count].path[MAX_NAME_LENGTH] = 0; + adPath[*count].path[MAX_NAME_LENGTH - 1] = 0; (*count)++; TRACE1("Added audio device %s\n", path); } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java --- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java Wed Apr 16 10:53:10 2014 -0700 @@ -39,6 +39,7 @@ import static sun.awt.shell.Win32ShellFolder2.*; import sun.awt.OSInfo; +import sun.misc.ThreadGroupUtils; // NOTE: This class supersedes Win32ShellFolderManager, which was removed // from distribution after version 1.4.2. @@ -503,23 +504,16 @@ } } }; - comThread = - AccessController.doPrivileged( - new PrivilegedAction() { - public Thread run() { + comThread = AccessController.doPrivileged((PrivilegedAction) () -> { /* The thread must be a member of a thread group * which will not get GCed before VM exit. * Make its parent the top-level thread group. */ - ThreadGroup tg = Thread.currentThread().getThreadGroup(); - for (ThreadGroup tgn = tg; - tgn != null; - tg = tgn, tgn = tg.getParent()); - Thread thread = new Thread(tg, comRun, "Swing-Shell"); + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + Thread thread = new Thread(rootTG, comRun, "Swing-Shell"); thread.setDaemon(true); return thread; } - } ); return comThread; } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/awt/windows/WClipboard.java --- a/jdk/src/windows/classes/sun/awt/windows/WClipboard.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/awt/windows/WClipboard.java Wed Apr 16 10:53:10 2014 -0700 @@ -62,7 +62,6 @@ @Override protected void setContentsNative(Transferable contents) { - // Don't use delayed Clipboard rendering for the Transferable's data. // If we did that, we would call Transferable.getTransferData on // the Toolkit thread, which is a security hole. @@ -71,7 +70,7 @@ // translated. Then, for each format, translate the data and post // it to the Clipboard. Map formatMap = WDataTransferer.getInstance(). - getFormatsForTransferable(contents, flavorMap); + getFormatsForTransferable(contents, getDefaultFlavorTable()); openClipboard(this); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/awt/windows/WToolkit.java --- a/jdk/src/windows/classes/sun/awt/windows/WToolkit.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/awt/windows/WToolkit.java Wed Apr 16 10:53:10 2014 -0700 @@ -40,6 +40,7 @@ import sun.awt.AWTPermissions; import sun.awt.LightweightFrame; import sun.awt.SunToolkit; +import sun.misc.ThreadGroupUtils; import sun.awt.Win32GraphicsDevice; import sun.awt.Win32GraphicsEnvironment; import sun.awt.datatransfer.DataTransferer; @@ -224,7 +225,7 @@ private static native void postDispose(); - private static native boolean startToolkitThread(Runnable thread); + private static native boolean startToolkitThread(Runnable thread, ThreadGroup rootThreadGroup); public WToolkit() { // Startup toolkit threads @@ -241,8 +242,11 @@ */ AWTAutoShutdown.notifyToolkitThreadBusy(); - if (!startToolkitThread(this)) { - Thread toolkitThread = new Thread(this, "AWT-Windows"); + // Find a root TG and attach Appkit thread to it + ThreadGroup rootTG = AccessController.doPrivileged( + (PrivilegedAction) ThreadGroupUtils::getRootThreadGroup); + if (!startToolkitThread(this, rootTG)) { + Thread toolkitThread = new Thread(rootTG, this, "AWT-Windows"); toolkitThread.setDaemon(true); toolkitThread.start(); } @@ -268,32 +272,21 @@ } private final void registerShutdownHook() { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - ThreadGroup currentTG = - Thread.currentThread().getThreadGroup(); - ThreadGroup parentTG = currentTG.getParent(); - while (parentTG != null) { - currentTG = parentTG; - parentTG = currentTG.getParent(); - } - Thread shutdown = new Thread(currentTG, new Runnable() { - @Override - public void run() { - shutdown(); - } - }); - shutdown.setContextClassLoader(null); - Runtime.getRuntime().addShutdownHook(shutdown); - return null; - } - }); + AccessController.doPrivileged((PrivilegedAction) () -> { + Thread shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), this::shutdown); + shutdown.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(shutdown); + return null; + }); } @Override public void run() { - Thread.currentThread().setPriority(Thread.NORM_PRIORITY+1); + AccessController.doPrivileged((PrivilegedAction) () -> { + Thread.currentThread().setContextClassLoader(null); + return null; + }); + Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 1); boolean startPump = init(); if (startPump) { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java --- a/jdk/src/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java Wed Apr 16 10:53:10 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,8 +36,9 @@ import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; -import sun.awt.SunToolkit; + import sun.awt.AWTAccessor; +import sun.misc.ThreadGroupUtils; import sun.awt.Win32GraphicsConfig; import sun.awt.windows.WComponentPeer; import sun.java2d.InvalidPipeException; @@ -92,21 +93,12 @@ public D3DScreenUpdateManager() { done = false; AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { - ThreadGroup currentTG = - Thread.currentThread().getThreadGroup(); - ThreadGroup parentTG = currentTG.getParent(); - while (parentTG != null) { - currentTG = parentTG; - parentTG = currentTG.getParent(); - } - Thread shutdown = new Thread(currentTG, new Runnable() { - public void run() { - done = true; - wakeUpUpdateThread(); - } - }); + (PrivilegedAction) () -> { + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + Thread shutdown = new Thread(rootTG, () -> { + done = true; + wakeUpUpdateThread(); + }); shutdown.setContextClassLoader(null); try { Runtime.getRuntime().addShutdownHook(shutdown); @@ -115,7 +107,6 @@ } return null; } - } ); } @@ -354,21 +345,17 @@ */ private synchronized void startUpdateThread() { if (screenUpdater == null) { - screenUpdater = (Thread)java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object run() { - ThreadGroup tg = - Thread.currentThread().getThreadGroup(); - for (ThreadGroup tgn = tg; - tgn != null; tg = tgn, tgn = tg.getParent()); - Thread t = new Thread(tg, D3DScreenUpdateManager.this, - "D3D Screen Updater"); + screenUpdater = AccessController.doPrivileged( + (PrivilegedAction) () -> { + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + Thread t = new Thread(rootTG, + D3DScreenUpdateManager.this, + "D3D Screen Updater"); // REMIND: should it be higher? t.setPriority(Thread.NORM_PRIORITY + 2); t.setDaemon(true); return t; - } - }); + }); screenUpdater.start(); } else { wakeUpUpdateThread(); diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/net/www/content-types.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/windows/classes/sun/net/www/content-types.properties Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,276 @@ +#sun.net.www MIME content-types table +# +# Property fields: +# +# ::= 'description' '=' +# ::= 'file_extensions' '=' +# ::= 'icon' '=' +# ::= 'browser' | 'application' | 'save' | 'unknown' +# ::= 'application' '=' +# + +# +# The "we don't know anything about this data" type(s). +# Used internally to mark unrecognized types. +# +content/unknown: description=Unknown Content +unknown/unknown: description=Unknown Data Type + +# +# The template we should use for temporary files when launching an application +# to view a document of given type. +# +temp.file.template: c:\\temp\\%s + +# +# The "real" types. +# +application/octet-stream: \ + description=Generic Binary Stream;\ + file_extensions=.saveme,.dump,.hqx,.arc,.obj,.lib,.bin,.exe,.zip,.gz + +application/oda: \ + description=ODA Document;\ + file_extensions=.oda + +application/pdf: \ + description=Adobe PDF Format;\ + file_extensions=.pdf + +application/postscript: \ + description=Postscript File;\ + file_extensions=.eps,.ai,.ps;\ + icon=ps + +application/rtf: \ + description=Wordpad Document;\ + file_extensions=.rtf;\ + action=application;\ + application=wordpad.exe %s + +application/x-dvi: \ + description=TeX DVI File;\ + file_extensions=.dvi + +application/x-hdf: \ + description=Hierarchical Data Format;\ + file_extensions=.hdf;\ + action=save + +application/x-latex: \ + description=LaTeX Source;\ + file_extensions=.latex + +application/x-netcdf: \ + description=Unidata netCDF Data Format;\ + file_extensions=.nc,.cdf;\ + action=save + +application/x-tex: \ + description=TeX Source;\ + file_extensions=.tex + +application/x-texinfo: \ + description=Gnu Texinfo;\ + file_extensions=.texinfo,.texi + +application/x-troff: \ + description=Troff Source;\ + file_extensions=.t,.tr,.roff + +application/x-troff-man: \ + description=Troff Manpage Source;\ + file_extensions=.man + +application/x-troff-me: \ + description=Troff ME Macros;\ + file_extensions=.me + +application/x-troff-ms: \ + description=Troff MS Macros;\ + file_extensions=.ms + +application/x-wais-source: \ + description=Wais Source;\ + file_extensions=.src,.wsrc + +application/zip: \ + description=Zip File;\ + file_extensions=.zip;\ + icon=zip;\ + action=save + +application/x-bcpio: \ + description=Old Binary CPIO Archive;\ + file_extensions=.bcpio;\ + action=save + +application/x-cpio: \ + description=Unix CPIO Archive;\ + file_extensions=.cpio;\ + action=save + +application/x-gtar: \ + description=Gnu Tar Archive;\ + file_extensions=.gtar;\ + icon=tar;\ + action=save + +application/x-shar: \ + description=Shell Archive;\ + file_extensions=.sh,.shar;\ + action=save + +application/x-sv4cpio: \ + description=SVR4 CPIO Archive;\ + file_extensions=.sv4cpio;\ + action=save + +application/x-sv4crc: \ + description=SVR4 CPIO with CRC;\ + file_extensions=.sv4crc;\ + action=save + +application/x-tar: \ + description=Tar Archive;\ + file_extensions=.tar;\ + icon=tar;\ + action=save + +application/x-ustar: \ + description=US Tar Archive;\ + file_extensions=.ustar;\ + action=save + +audio/basic: \ + description=Basic Audio;\ + file_extensions=.snd,.au;\ + icon=audio + +audio/x-aiff: \ + description=Audio Interchange Format File;\ + file_extensions=.aifc,.aif,.aiff;\ + icon=aiff + +audio/x-wav: \ + description=Wav Audio;\ + file_extensions=.wav;\ + icon=wav;\ + action=application;\ + application=mplayer.exe %s + +image/gif: \ + description=GIF Image;\ + file_extensions=.gif;\ + icon=gif;\ + action=browser + +image/ief: \ + description=Image Exchange Format;\ + file_extensions=.ief + +image/jpeg: \ + description=JPEG Image;\ + file_extensions=.jfif,.jfif-tbnl,.jpe,.jpg,.jpeg;\ + icon=jpeg;\ + action=browser + +image/tiff: \ + description=TIFF Image;\ + file_extensions=.tif,.tiff;\ + icon=tiff + +image/vnd.fpx: \ + description=FlashPix Image;\ + file_extensions=.fpx,.fpix + +image/x-cmu-rast: \ + description=CMU Raster Image;\ + file_extensions=.ras + +image/x-portable-anymap: \ + description=PBM Anymap Image;\ + file_extensions=.pnm + +image/x-portable-bitmap: \ + description=PBM Bitmap Image;\ + file_extensions=.pbm + +image/x-portable-graymap: \ + description=PBM Graymap Image;\ + file_extensions=.pgm + +image/x-portable-pixmap: \ + description=PBM Pixmap Image;\ + file_extensions=.ppm + +image/x-rgb: \ + description=RGB Image;\ + file_extensions=.rgb + +image/x-xbitmap: \ + description=X Bitmap Image;\ + file_extensions=.xbm,.xpm + +image/x-xwindowdump: \ + description=X Window Dump Image;\ + file_extensions=.xwd + +image/png: \ + description=PNG Image;\ + file_extensions=.png;\ + icon=png;\ + action=browser + +image/bmp: \ + description=Bitmap Image;\ + file_extensions=.bmp; + +text/html: \ + description=HTML Document;\ + file_extensions=.htm,.html;\ + icon=html + +text/plain: \ + description=Plain Text;\ + file_extensions=.text,.c,.cc,.c++,.h,.pl,.txt,.java,.el;\ + icon=text;\ + action=browser + +text/tab-separated-values: \ + description=Tab Separated Values Text;\ + file_extensions=.tsv + +text/x-setext: \ + description=Structure Enhanced Text;\ + file_extensions=.etx + +video/mpeg: \ + description=MPEG Video Clip;\ + file_extensions=.mpg,.mpe,.mpeg;\ + icon=mpeg + +video/quicktime: \ + description=QuickTime Video Clip;\ + file_extensions=.mov,.qt + +application/x-troff-msvideo: \ + description=AVI Video;\ + file_extensions=.avi;\ + icon=avi;\ + action=application;\ + application=mplayer.exe %s + +video/x-sgi-movie: \ + description=SGI Movie;\ + file_extensions=.movie,.mv + +message/rfc822: \ + description=Internet Email Message;\ + file_extensions=.mime + +application/xml: \ + description=XML document;\ + file_extensions=.xml + + diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsAclFileAttributeView.java Wed Apr 16 10:53:10 2014 -0700 @@ -61,7 +61,7 @@ this.followLinks = followLinks; } - // permision check + // permission check private void checkAccess(WindowsPath file, boolean checkRead, boolean checkWrite) diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsConstants.java Wed Apr 16 10:53:10 2014 -0700 @@ -94,7 +94,7 @@ public static final int ERROR_NOT_READY = 21; public static final int ERROR_SHARING_VIOLATION = 32; public static final int ERROR_FILE_EXISTS = 80; - public static final int ERROR_INVALID_PARAMATER = 87; + public static final int ERROR_INVALID_PARAMETER = 87; public static final int ERROR_DISK_FULL = 112; public static final int ERROR_INSUFFICIENT_BUFFER = 122; public static final int ERROR_INVALID_LEVEL = 124; diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java Wed Apr 16 10:53:10 2014 -0700 @@ -98,9 +98,9 @@ lastAccessTime, lastWriteTime); } catch (WindowsException x) { - // If ERROR_INVALID_PARAMATER is returned and the volume is + // If ERROR_INVALID_PARAMETER is returned and the volume is // FAT then adjust to the FAT epoch and retry. - if (followLinks && x.lastError() == ERROR_INVALID_PARAMATER) { + if (followLinks && x.lastError() == ERROR_INVALID_PARAMETER) { try { if (WindowsFileStore.create(file).type().equals("FAT")) { SetFileTime(handle, @@ -157,7 +157,7 @@ private static final String HIDDEN_NAME = "hidden"; private static final String ATTRIBUTES_NAME = "attributes"; - // the names of the DOS attribtues (includes basic) + // the names of the DOS attributes (includes basic) static final Set dosAttributeNames = Util.newSet(basicAttributeNames, READONLY_NAME, ARCHIVE_NAME, SYSTEM_NAME, HIDDEN_NAME, ATTRIBUTES_NAME); @@ -223,7 +223,7 @@ { file.checkWrite(); - // GetFileAttribtues & SetFileAttributes do not follow links so when + // GetFileAttributes & SetFileAttributes do not follow links so when // following links we need the final target String path = WindowsLinkSupport.getFinalPath(file, followLinks); try { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java Wed Apr 16 10:53:10 2014 -0700 @@ -384,7 +384,7 @@ file.getPathForExceptionMessage(), null, "Permissions does not allow requested access"); - // for write access we neeed to check if the DOS readonly attribute + // for write access we need to check if the DOS readonly attribute // and if the volume is read-only if (w) { try { @@ -553,7 +553,7 @@ } /* - * Windows treates symbolic links to directories differently than it + * Windows treats symbolic links to directories differently than it * does to other file types. For that reason we need to check if the * target is a directory (or a directory junction). */ diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Wed Apr 16 10:53:10 2014 -0700 @@ -917,7 +917,7 @@ } } private static native void CreateHardLink0(long newFileBuffer, - long existingFiletBuffer) throws WindowsException; + long existingFileBuffer) throws WindowsException; /** * GetFullPathName( diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/nio/fs/WindowsPath.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java Wed Apr 16 10:53:10 2014 -0700 @@ -133,7 +133,7 @@ /** * Special implementation with attached/cached attributes (used to quicken - * file tree traveral) + * file tree traversal) */ private static class WindowsPathWithAttributes extends WindowsPath implements BasicFileAttributesHolder diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsSecurity.java Wed Apr 16 10:53:10 2014 -0700 @@ -129,11 +129,11 @@ int genericRead, int genericWrite, int genericExecute, int genericAll) throws WindowsException { - int privilegies = TOKEN_QUERY; - long hToken = OpenThreadToken(GetCurrentThread(), privilegies, false); + int privileges = TOKEN_QUERY; + long hToken = OpenThreadToken(GetCurrentThread(), privileges, false); if (hToken == 0L && processTokenWithDuplicateAccess != 0L) hToken = DuplicateTokenEx(processTokenWithDuplicateAccess, - privilegies); + privileges); boolean hasRight = false; if (hToken != 0L) { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsUserDefinedFileAttributeView.java Wed Apr 16 10:53:10 2014 -0700 @@ -200,7 +200,7 @@ public List list() throws IOException { if (System.getSecurityManager() != null) checkAccess(file.getPathForPermissionCheck(), true, false); - // use stream APIs on Windwos Server 2003 and newer + // use stream APIs on Windows Server 2003 and newer if (file.getFileSystem().supportsStreamEnumeration()) { return listUsingStreamEnumeration(); } else { diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java --- a/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/classes/sun/nio/fs/WindowsWatchService.java Wed Apr 16 10:53:10 2014 -0700 @@ -556,7 +556,7 @@ // ReadDirectoryChangesW failed criticalError = true; } else { - // ERROR_MORE_DATA is a warning about incomplite + // ERROR_MORE_DATA is a warning about incomplete // data transfer over TCP/UDP stack. For the case // [messageSize] is zero in the most of cases. diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/lib/content-types.properties --- a/jdk/src/windows/lib/content-types.properties Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +0,0 @@ -#sun.net.www MIME content-types table -# -# Property fields: -# -# ::= 'description' '=' -# ::= 'file_extensions' '=' -# ::= 'icon' '=' -# ::= 'browser' | 'application' | 'save' | 'unknown' -# ::= 'application' '=' -# - -# -# The "we don't know anything about this data" type(s). -# Used internally to mark unrecognized types. -# -content/unknown: description=Unknown Content -unknown/unknown: description=Unknown Data Type - -# -# The template we should use for temporary files when launching an application -# to view a document of given type. -# -temp.file.template: c:\\temp\\%s - -# -# The "real" types. -# -application/octet-stream: \ - description=Generic Binary Stream;\ - file_extensions=.saveme,.dump,.hqx,.arc,.obj,.lib,.bin,.exe,.zip,.gz - -application/oda: \ - description=ODA Document;\ - file_extensions=.oda - -application/pdf: \ - description=Adobe PDF Format;\ - file_extensions=.pdf - -application/postscript: \ - description=Postscript File;\ - file_extensions=.eps,.ai,.ps;\ - icon=ps - -application/rtf: \ - description=Wordpad Document;\ - file_extensions=.rtf;\ - action=application;\ - application=wordpad.exe %s - -application/x-dvi: \ - description=TeX DVI File;\ - file_extensions=.dvi - -application/x-hdf: \ - description=Hierarchical Data Format;\ - file_extensions=.hdf;\ - action=save - -application/x-latex: \ - description=LaTeX Source;\ - file_extensions=.latex - -application/x-netcdf: \ - description=Unidata netCDF Data Format;\ - file_extensions=.nc,.cdf;\ - action=save - -application/x-tex: \ - description=TeX Source;\ - file_extensions=.tex - -application/x-texinfo: \ - description=Gnu Texinfo;\ - file_extensions=.texinfo,.texi - -application/x-troff: \ - description=Troff Source;\ - file_extensions=.t,.tr,.roff - -application/x-troff-man: \ - description=Troff Manpage Source;\ - file_extensions=.man - -application/x-troff-me: \ - description=Troff ME Macros;\ - file_extensions=.me - -application/x-troff-ms: \ - description=Troff MS Macros;\ - file_extensions=.ms - -application/x-wais-source: \ - description=Wais Source;\ - file_extensions=.src,.wsrc - -application/zip: \ - description=Zip File;\ - file_extensions=.zip;\ - icon=zip;\ - action=save - -application/x-bcpio: \ - description=Old Binary CPIO Archive;\ - file_extensions=.bcpio;\ - action=save - -application/x-cpio: \ - description=Unix CPIO Archive;\ - file_extensions=.cpio;\ - action=save - -application/x-gtar: \ - description=Gnu Tar Archive;\ - file_extensions=.gtar;\ - icon=tar;\ - action=save - -application/x-shar: \ - description=Shell Archive;\ - file_extensions=.sh,.shar;\ - action=save - -application/x-sv4cpio: \ - description=SVR4 CPIO Archive;\ - file_extensions=.sv4cpio;\ - action=save - -application/x-sv4crc: \ - description=SVR4 CPIO with CRC;\ - file_extensions=.sv4crc;\ - action=save - -application/x-tar: \ - description=Tar Archive;\ - file_extensions=.tar;\ - icon=tar;\ - action=save - -application/x-ustar: \ - description=US Tar Archive;\ - file_extensions=.ustar;\ - action=save - -audio/basic: \ - description=Basic Audio;\ - file_extensions=.snd,.au;\ - icon=audio - -audio/x-aiff: \ - description=Audio Interchange Format File;\ - file_extensions=.aifc,.aif,.aiff;\ - icon=aiff - -audio/x-wav: \ - description=Wav Audio;\ - file_extensions=.wav;\ - icon=wav;\ - action=application;\ - application=mplayer.exe %s - -image/gif: \ - description=GIF Image;\ - file_extensions=.gif;\ - icon=gif;\ - action=browser - -image/ief: \ - description=Image Exchange Format;\ - file_extensions=.ief - -image/jpeg: \ - description=JPEG Image;\ - file_extensions=.jfif,.jfif-tbnl,.jpe,.jpg,.jpeg;\ - icon=jpeg;\ - action=browser - -image/tiff: \ - description=TIFF Image;\ - file_extensions=.tif,.tiff;\ - icon=tiff - -image/vnd.fpx: \ - description=FlashPix Image;\ - file_extensions=.fpx,.fpix - -image/x-cmu-rast: \ - description=CMU Raster Image;\ - file_extensions=.ras - -image/x-portable-anymap: \ - description=PBM Anymap Image;\ - file_extensions=.pnm - -image/x-portable-bitmap: \ - description=PBM Bitmap Image;\ - file_extensions=.pbm - -image/x-portable-graymap: \ - description=PBM Graymap Image;\ - file_extensions=.pgm - -image/x-portable-pixmap: \ - description=PBM Pixmap Image;\ - file_extensions=.ppm - -image/x-rgb: \ - description=RGB Image;\ - file_extensions=.rgb - -image/x-xbitmap: \ - description=X Bitmap Image;\ - file_extensions=.xbm,.xpm - -image/x-xwindowdump: \ - description=X Window Dump Image;\ - file_extensions=.xwd - -image/png: \ - description=PNG Image;\ - file_extensions=.png;\ - icon=png;\ - action=browser - -image/bmp: \ - description=Bitmap Image;\ - file_extensions=.bmp; - -text/html: \ - description=HTML Document;\ - file_extensions=.htm,.html;\ - icon=html - -text/plain: \ - description=Plain Text;\ - file_extensions=.text,.c,.cc,.c++,.h,.pl,.txt,.java,.el;\ - icon=text;\ - action=browser - -text/tab-separated-values: \ - description=Tab Separated Values Text;\ - file_extensions=.tsv - -text/x-setext: \ - description=Structure Enhanced Text;\ - file_extensions=.etx - -video/mpeg: \ - description=MPEG Video Clip;\ - file_extensions=.mpg,.mpe,.mpeg;\ - icon=mpeg - -video/quicktime: \ - description=QuickTime Video Clip;\ - file_extensions=.mov,.qt - -application/x-troff-msvideo: \ - description=AVI Video;\ - file_extensions=.avi;\ - icon=avi;\ - action=application;\ - application=mplayer.exe %s - -video/x-sgi-movie: \ - description=SGI Movie;\ - file_extensions=.movie,.mv - -message/rfc822: \ - description=Internet Email Message;\ - file_extensions=.mime - -application/xml: \ - description=XML document;\ - file_extensions=.xml - - diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/native/sun/windows/awt_InputMethod.cpp --- a/jdk/src/windows/native/sun/windows/awt_InputMethod.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_InputMethod.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -320,13 +320,18 @@ // current language ID (returned from 'getJavaIDFromLangID') is in // ASCII encoding, so we use 'GetStringUTFChars' to retrieve requested // language ID from the 'localeString' object. - const char * current = getJavaIDFromLangID(AwtComponent::GetInputLanguage()); jboolean isCopy; const char * requested = env->GetStringUTFChars(localeString, &isCopy); - if ((current != NULL) && (strcmp(current, requested) == 0)) { - env->ReleaseStringUTFChars(localeString, requested); + CHECK_NULL_RETURN(requested, JNI_FALSE); + + const char * current = getJavaIDFromLangID(AwtComponent::GetInputLanguage()); + if (current != NULL) { + if (strcmp(current, requested) == 0) { + env->ReleaseStringUTFChars(localeString, requested); + free((void *)current); + return JNI_TRUE; + } free((void *)current); - return JNI_TRUE; } // get list of available HKLs. Adding the user's preferred layout on top of the layout @@ -334,7 +339,10 @@ // looking up suitable layout. int layoutCount = ::GetKeyboardLayoutList(0, NULL) + 1; // +1 for user's preferred HKL HKL FAR * hKLList = (HKL FAR *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(HKL), layoutCount); - DASSERT(!safe_ExceptionOccurred(env)); + if (hKLList == NULL) { + env->ReleaseStringUTFChars(localeString, requested); + return JNI_FALSE; + } ::GetKeyboardLayoutList(layoutCount - 1, &(hKLList[1])); hKLList[0] = getDefaultKeyboardLayout(); // put user's preferred layout on top of the list @@ -342,20 +350,23 @@ jboolean retValue = JNI_FALSE; for (int i = 0; i < layoutCount; i++) { const char * supported = getJavaIDFromLangID(LOWORD(hKLList[i])); - if ((supported != NULL) && (strcmp(supported, requested) == 0)) { - // use special message to call ActivateKeyboardLayout() in main thread. - if (AwtToolkit::GetInstance().SendMessage(WM_AWT_ACTIVATEKEYBOARDLAYOUT, (WPARAM)onActivate, (LPARAM)hKLList[i])) { - //also need to change the same keyboard layout for the Java AWT-EventQueue thread - AwtToolkit::activateKeyboardLayout(hKLList[i]); - retValue = JNI_TRUE; + if (supported != NULL) { + if (strcmp(supported, requested) == 0) { + // use special message to call ActivateKeyboardLayout() in main thread. + if (AwtToolkit::GetInstance().SendMessage(WM_AWT_ACTIVATEKEYBOARDLAYOUT, (WPARAM)onActivate, (LPARAM)hKLList[i])) { + //also need to change the same keyboard layout for the Java AWT-EventQueue thread + AwtToolkit::activateKeyboardLayout(hKLList[i]); + retValue = JNI_TRUE; + } + free((void *)supported); + break; } - break; + free((void *)supported); } } env->ReleaseStringUTFChars(localeString, requested); free(hKLList); - free((void *)current); return retValue; CATCH_BAD_ALLOC_RET(JNI_FALSE); @@ -445,7 +456,7 @@ // get list of available HKLs int layoutCount = ::GetKeyboardLayoutList(0, NULL); HKL FAR * hKLList = (HKL FAR *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(HKL), layoutCount); - DASSERT(!safe_ExceptionOccurred(env)); + CHECK_NULL_RETURN(hKLList, NULL); ::GetKeyboardLayoutList(layoutCount, hKLList); // get list of Java locale names while getting rid of duplicates @@ -453,8 +464,13 @@ int destIndex = 0; int javaLocaleNameCount = 0; int current = 0; + const char ** javaLocaleNames = (const char **)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(char *), layoutCount); - DASSERT(!safe_ExceptionOccurred(env)); + if (javaLocaleNames == NULL) { + free(hKLList); + return NULL; + } + for (; srcIndex < layoutCount; srcIndex++) { const char * srcLocaleName = getJavaIDFromLangID(LOWORD(hKLList[srcIndex])); @@ -477,18 +493,33 @@ } } + jobjectArray locales = NULL; // convert it to an array of Java locale objects jclass localeClass = env->FindClass("java/util/Locale"); - jobjectArray locales = env->NewObjectArray(javaLocaleNameCount, localeClass, NULL); + if (localeClass != NULL) { + locales = env->NewObjectArray(javaLocaleNameCount, localeClass, NULL); + if (locales != NULL) { + + for (current = 0; current < javaLocaleNameCount; current++) { + jobject obj = CreateLocaleObject(env, javaLocaleNames[current]); + if (env->ExceptionCheck()) { + env->DeleteLocalRef(locales); + locales = NULL; + break; + } + env->SetObjectArrayElement(locales, + current, + obj); + } + + } + env->DeleteLocalRef(localeClass); + } + for (current = 0; current < javaLocaleNameCount; current++) { - env->SetObjectArrayElement(locales, - current, - CreateLocaleObject(env, javaLocaleNames[current])); free((void *)javaLocaleNames[current]); } - DASSERT(!safe_ExceptionOccurred(env)); - env->DeleteLocalRef(localeClass); free(hKLList); free(javaLocaleNames); return locales; @@ -542,6 +573,7 @@ // create Locale object jobject langtagObj = env->NewStringUTF(name); + CHECK_NULL_RETURN(langtagObj, NULL); jobject localeObj = JNU_CallStaticMethodByName(env, NULL, "java/util/Locale", diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/native/sun/windows/awt_MenuItem.cpp --- a/jdk/src/windows/native/sun/windows/awt_MenuItem.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_MenuItem.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -152,6 +152,9 @@ if (dw == ERROR_OUTOFMEMORY) { jstring errorMsg = JNU_NewStringPlatform(env, L"too many menu handles"); + if (errorMsg == NULL) { + throw std::bad_alloc(); + } createError = JNU_NewObjectByName(env, "java/lang/OutOfMemoryError", "(Ljava/lang/String;)V", errorMsg); @@ -164,16 +167,19 @@ NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buf, 0, NULL); jstring s = JNU_NewStringPlatform(env, buf); + if (s == NULL) { + throw std::bad_alloc(); + } createError = JNU_NewObjectByName(env, "java/lang/InternalError", "(Ljava/lang/String;)V", s); LocalFree(buf); env->DeleteLocalRef(s); } + if (createError == NULL) { + throw std::bad_alloc(); + } env->SetObjectField(self, AwtObject::createErrorID, createError); - if (createError != NULL) - { - env->DeleteLocalRef(createError); - } + env->DeleteLocalRef(createError); return FALSE; } return TRUE; @@ -238,12 +244,18 @@ jobject self = GetPeer(env); jobject target = env->GetObjectField(self, AwtObject::targetID); jobject font = JNU_CallMethodByName(env, 0, target, "getFont_NoClientCode", "()Ljava/awt/Font;").l; + env->DeleteLocalRef(target); + if (env->ExceptionCheck()) { + throw std::bad_alloc(); + } if (font == NULL) { font = env->NewLocalRef(GetDefaultFont(env)); + if (env->ExceptionCheck()) { + throw std::bad_alloc(); + } } - env->DeleteLocalRef(target); return font; } @@ -251,13 +263,22 @@ AwtMenuItem::GetDefaultFont(JNIEnv *env) { if (AwtMenuItem::systemFont == NULL) { jclass cls = env->FindClass("sun/awt/windows/WMenuItemPeer"); - DASSERT(cls != NULL); + if (cls == NULL) { + throw std::bad_alloc(); + } AwtMenuItem::systemFont = env->CallStaticObjectMethod(cls, AwtMenuItem::getDefaultFontMID); - DASSERT(AwtMenuItem::systemFont); + if (env->ExceptionCheck()) { + env->DeleteLocalRef(cls); + throw std::bad_alloc(); + } AwtMenuItem::systemFont = env->NewGlobalRef(AwtMenuItem::systemFont); + if (systemFont == NULL) { + env->DeleteLocalRef(cls); + throw std::bad_alloc(); + } } return AwtMenuItem::systemFont; } @@ -284,8 +305,19 @@ DWORD crBack,crText; HBRUSH hbrBack; - jobject font = GetFont(env); + jobject font; + try { + font = GetFont(env); + } catch (std::bad_alloc&) { + env->DeleteLocalRef(target); + throw; + } + jstring text = GetJavaString(env); + if (env->ExceptionCheck()) { + env->DeleteLocalRef(target); + throw std::bad_alloc(); + } size = AwtFont::getMFStringSize(hDC, font, text); /* 4700350: If the font size is taller than the menubar, change to the @@ -294,7 +326,13 @@ */ if (IsTopMenu() && size.cy > ::GetSystemMetrics(SM_CYMENU)) { env->DeleteLocalRef(font); - font = env->NewLocalRef(GetDefaultFont(env)); + try { + font = env->NewLocalRef(GetDefaultFont(env)); + } catch (std::bad_alloc&) { + env->DeleteLocalRef(target); + env->DeleteLocalRef(text); + throw; + } size = AwtFont::getMFStringSize(hDC, font, text); } @@ -452,6 +490,10 @@ /* font is a java.awt.Font */ jobject font = GetFont(env); jstring text = GetJavaString(env); + if (env->ExceptionCheck()) { + env->DeleteLocalRef(font); + throw std::bad_alloc(); + } SIZE size = AwtFont::getMFStringSize(hDC, font, text); /* 4700350: If the font size is taller than the menubar, change to the @@ -459,7 +501,14 @@ * client area. -bchristi */ if (IsTopMenu() && size.cy > ::GetSystemMetrics(SM_CYMENU)) { - jobject defFont = GetDefaultFont(env); + jobject defFont; + try { + defFont = GetDefaultFont(env); + } catch (std::bad_alloc&) { + env->DeleteLocalRef(text); + env->DeleteLocalRef(font); + throw; + } env->DeleteLocalRef(font); font = env->NewLocalRef(defFont); size = AwtFont::getMFStringSize(hDC, font, text); @@ -468,13 +517,31 @@ jstring fontName = (jstring)JNU_CallMethodByName(env, 0,font, "getName", "()Ljava/lang/String;").l; + if (env->ExceptionCheck()) { + env->DeleteLocalRef(text); + env->DeleteLocalRef(font); + throw std::bad_alloc(); + } + /* fontMetrics is a Hsun_awt_windows_WFontMetrics */ jobject fontMetrics = GetFontMetrics(env, font); - + if (env->ExceptionCheck()) { + env->DeleteLocalRef(text); + env->DeleteLocalRef(font); + env->DeleteLocalRef(fontName); + throw std::bad_alloc(); + } // int height = env->GetIntField(fontMetrics, AwtFont::heightID); int height = (jint)JNU_CallMethodByName(env, 0, fontMetrics, "getHeight", "()I").i; + if (env->ExceptionCheck()) { + env->DeleteLocalRef(text); + env->DeleteLocalRef(font); + env->DeleteLocalRef(fontName); + env->DeleteLocalRef(fontMetrics); + throw std::bad_alloc(); + } measureInfo.itemHeight = height; measureInfo.itemHeight += measureInfo.itemHeight/3; @@ -520,10 +587,14 @@ if (env->PushLocalFrame(2) < 0) return NULL; jclass cls = env->FindClass("java/awt/Toolkit"); + CHECK_NULL_RETURN(cls, NULL); jobject toolkitLocal = env->CallStaticObjectMethod(cls, AwtToolkit::getDefaultToolkitMID); + env->DeleteLocalRef(cls); + CHECK_NULL_RETURN(toolkitLocal, NULL); toolkit = env->NewGlobalRef(toolkitLocal); - DASSERT(!safe_ExceptionOccurred(env)); + env->DeleteLocalRef(toolkitLocal); + CHECK_NULL_RETURN(toolkit, NULL); env->PopLocalFrame(0); } /* @@ -739,6 +810,10 @@ { empty = JNU_NewStringPlatform(env, TEXT("")); } + if (env->ExceptionCheck()) { + badAlloc = 1; + goto ret; + } LPCTSTR labelPtr; if (empty != NULL) { @@ -846,10 +921,9 @@ TRY; AwtMenuItem::fontID = env->GetFieldID(cls, "font", "Ljava/awt/Font;"); + CHECK_NULL(AwtMenuItem::fontID); AwtMenuItem::appContextID = env->GetFieldID(cls, "appContext", "Lsun/awt/AppContext;"); - DASSERT(AwtMenuItem::fontID != NULL); - CATCH_BAD_ALLOC; } @@ -868,11 +942,9 @@ TRY; AwtMenuItem::labelID = env->GetFieldID(cls, "label", "Ljava/lang/String;"); + CHECK_NULL(AwtMenuItem::labelID); AwtMenuItem::enabledID = env->GetFieldID(cls, "enabled", "Z"); - DASSERT(AwtMenuItem::labelID != NULL); - DASSERT(AwtMenuItem::enabledID != NULL); - CATCH_BAD_ALLOC; } @@ -892,8 +964,6 @@ AwtMenuItem::stateID = env->GetFieldID(cls, "state", "Z"); - DASSERT(AwtMenuItem::stateID != NULL); - CATCH_BAD_ALLOC; } @@ -917,15 +987,13 @@ TRY; AwtMenuItem::isCheckboxID = env->GetFieldID(cls, "isCheckbox", "Z"); + CHECK_NULL(AwtMenuItem::isCheckboxID); AwtMenuItem::shortcutLabelID = env->GetFieldID(cls, "shortcutLabel", "Ljava/lang/String;"); + CHECK_NULL(AwtMenuItem::shortcutLabelID); AwtMenuItem::getDefaultFontMID = env->GetStaticMethodID(cls, "getDefaultFont", "()Ljava/awt/Font;"); - DASSERT(AwtMenuItem::isCheckboxID != NULL); - DASSERT(AwtMenuItem::shortcutLabelID != NULL); - DASSERT(AwtMenuItem::getDefaultFontMID != NULL); - CATCH_BAD_ALLOC; } diff -r 971bf0a51f75 -r 956d11daac9d jdk/src/windows/native/sun/windows/awt_Toolkit.cpp --- a/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Wed Apr 16 10:53:10 2014 -0700 @@ -351,6 +351,7 @@ HANDLE hCompleted; jobject thread; + jobject threadGroup; }; void ToolkitThreadProc(void *param) @@ -363,7 +364,7 @@ JavaVMAttachArgs attachArgs; attachArgs.version = JNI_VERSION_1_2; attachArgs.name = "AWT-Windows"; - attachArgs.group = NULL; + attachArgs.group = data->threadGroup; jint res = jvm->AttachCurrentThreadAsDaemon((void **)&env, &attachArgs); if (res < 0) { @@ -402,17 +403,18 @@ /* * Class: sun_awt_windows_WToolkit * Method: startToolkitThread - * Signature: (Ljava/lang/Runnable;)Z + * Signature: (Ljava/lang/Runnable;Ljava/lang/ThreadGroup)Z */ JNIEXPORT jboolean JNICALL -Java_sun_awt_windows_WToolkit_startToolkitThread(JNIEnv *env, jclass cls, jobject thread) +Java_sun_awt_windows_WToolkit_startToolkitThread(JNIEnv *env, jclass cls, jobject thread, jobject threadGroup) { AwtToolkit& tk = AwtToolkit::GetInstance(); ToolkitThreadProc_Data data; data.result = false; data.thread = env->NewGlobalRef(thread); - if (data.thread == NULL) { + data.threadGroup = env->NewGlobalRef(threadGroup); + if (data.thread == NULL || data.threadGroup == NULL) { return JNI_FALSE; } data.hCompleted = ::CreateEvent(NULL, FALSE, FALSE, NULL); @@ -430,6 +432,7 @@ ::CloseHandle(data.hCompleted); env->DeleteGlobalRef(data.thread); + env->DeleteGlobalRef(data.threadGroup); return result ? JNI_TRUE : JNI_FALSE; } diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/demo/zipfs/Basic.java --- a/jdk/test/demo/zipfs/Basic.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.nio.file.*; -import java.nio.file.attribute.*; -import java.nio.file.spi.FileSystemProvider; -import java.util.*; -import java.net.URI; -import java.io.IOException; - -/** - * Basic test for zip provider - */ - -public class Basic { - public static void main(String[] args) throws Exception { - Path zipfile = Paths.get(args[0]); - - // Test: zip should should be returned in provider list - boolean found = false; - - for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { - if (provider.getScheme().equalsIgnoreCase("jar")) { - found = true; - break; - } - } - if (!found) - throw new RuntimeException("'jar' provider not installed"); - - // Test: FileSystems#newFileSystem(Path) - Map env = new HashMap(); - FileSystems.newFileSystem(zipfile, null).close(); - - // Test: FileSystems#newFileSystem(URI) - URI uri = new URI("jar", zipfile.toUri().toString(), null); - FileSystem fs = FileSystems.newFileSystem(uri, env, null); - - // Test: exercise toUri method - String expected = uri.toString() + "!/foo"; - String actual = fs.getPath("/foo").toUri().toString(); - if (!actual.equals(expected)) { - throw new RuntimeException("toUri returned '" + actual + - "', expected '" + expected + "'"); - } - - // Test: exercise directory iterator and retrieval of basic attributes - Files.walkFileTree(fs.getPath("/"), new FileTreePrinter()); - - // Test: DirectoryStream - found = false; - try (DirectoryStream stream = Files.newDirectoryStream(fs.getPath("/"))) { - for (Path entry: stream) { - found = entry.toString().equals("/META-INF/"); - if (found) break; - } - } - - if (!found) - throw new RuntimeException("Expected file not found"); - - // Test: copy file from zip file to current (scratch) directory - Path source = fs.getPath("/META-INF/services/java.nio.file.spi.FileSystemProvider"); - if (Files.exists(source)) { - Path target = Paths.get(source.getFileName().toString()); - Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); - try { - long s1 = Files.readAttributes(source, BasicFileAttributes.class).size(); - long s2 = Files.readAttributes(target, BasicFileAttributes.class).size(); - if (s2 != s1) - throw new RuntimeException("target size != source size"); - } finally { - Files.delete(target); - } - } - - // Test: FileStore - FileStore store = Files.getFileStore(fs.getPath("/")); - if (!store.supportsFileAttributeView("basic")) - throw new RuntimeException("BasicFileAttributeView should be supported"); - - // Test: ClosedFileSystemException - fs.close(); - if (fs.isOpen()) - throw new RuntimeException("FileSystem should be closed"); - try { - fs.provider().checkAccess(fs.getPath("/missing"), AccessMode.READ); - } catch (ClosedFileSystemException x) { } - } - - // FileVisitor that pretty prints a file tree - static class FileTreePrinter extends SimpleFileVisitor { - private int indent = 0; - - private void indent() { - StringBuilder sb = new StringBuilder(indent); - for (int i=0; i %s", s, path); - } catch (Exception x) { - exc = x; - out.format("%s -> %s", s, x); - } - out.println(); - } - - Path path() { - return path; - } - - void fail() { - throw new RuntimeException("PathOps failed"); - } - - void checkPath() { - if (path == null) { - throw new InternalError("path is null"); - } - } - - void check(Object result, String expected) { - out.format("\tExpected: %s\n", expected); - out.format("\tActual: %s\n", result); - if (result == null) { - if (expected == null) return; - } else { - // compare string representations - if (expected != null && result.toString().equals(expected.toString())) - return; - } - fail(); - } - - void check(Object result, boolean expected) { - check(result, Boolean.toString(expected)); - } - - PathOps root(String expected) { - out.println("check root"); - checkPath(); - check(path.getRoot(), expected); - return this; - } - - PathOps parent(String expected) { - out.println("check parent"); - checkPath(); - check(path.getParent(), expected); - return this; - } - - PathOps name(String expected) { - out.println("check name"); - checkPath(); - check(path.getFileName(), expected); - return this; - } - - PathOps element(int index, String expected) { - out.format("check element %d\n", index); - checkPath(); - check(path.getName(index), expected); - return this; - } - - PathOps subpath(int startIndex, int endIndex, String expected) { - out.format("test subpath(%d,%d)\n", startIndex, endIndex); - checkPath(); - check(path.subpath(startIndex, endIndex), expected); - return this; - } - - PathOps starts(String prefix) { - out.format("test startsWith with %s\n", prefix); - checkPath(); - Path s = fs.getPath(prefix); - check(path.startsWith(s), true); - return this; - } - - PathOps notStarts(String prefix) { - out.format("test not startsWith with %s\n", prefix); - checkPath(); - Path s = fs.getPath(prefix); - check(path.startsWith(s), false); - return this; - } - - PathOps ends(String suffix) { - out.format("test endsWith %s\n", suffix); - checkPath(); - Path s = fs.getPath(suffix); - check(path.endsWith(s), true); - return this; - } - - PathOps notEnds(String suffix) { - out.format("test not endsWith %s\n", suffix); - checkPath(); - Path s = fs.getPath(suffix); - check(path.endsWith(s), false); - return this; - } - - PathOps absolute() { - out.println("check path is absolute"); - checkPath(); - check(path.isAbsolute(), true); - return this; - } - - PathOps notAbsolute() { - out.println("check path is not absolute"); - checkPath(); - check(path.isAbsolute(), false); - return this; - } - - PathOps resolve(String other, String expected) { - out.format("test resolve %s\n", other); - checkPath(); - check(path.resolve(other), expected); - return this; - } - - PathOps relativize(String other, String expected) { - out.format("test relativize %s\n", other); - checkPath(); - Path that = fs.getPath(other); - check(path.relativize(that), expected); - return this; - } - - PathOps normalize(String expected) { - out.println("check normalized path"); - checkPath(); - check(path.normalize(), expected); - return this; - } - - PathOps string(String expected) { - out.println("check string representation"); - checkPath(); - check(path, expected); - return this; - } - - PathOps isSameFile(String target) { - try { - out.println("check two paths are same"); - checkPath(); - check(Files.isSameFile(path, test(target).path()), true); - } catch (IOException ioe) { - fail(); - } - return this; - } - - PathOps invalid() { - if (!(exc instanceof InvalidPathException)) { - out.println("InvalidPathException not thrown as expected"); - fail(); - } - return this; - } - - static PathOps test(String s) { - return new PathOps(s); - } - - // -- PathOpss -- - - static void header(String s) { - out.println(); - out.println(); - out.println("-- " + s + " --"); - } - - static void doPathOpTests() { - header("Path operations"); - - // all components - test("/a/b/c") - .root("/") - .parent("/a/b") - .name("c"); - - // root component only - test("/") - .root("/") - .parent(null) - .name(null); - - // no root component - test("a/b") - .root(null) - .parent("a") - .name("b"); - - // name component only - test("foo") - .root(null) - .parent(null) - .name("foo"); - - // startsWith - test("") - .starts("") - .notStarts("/"); - test("/") - .starts("/") - .notStarts("/foo"); - test("/foo") - .starts("/") - .starts("/foo") - .notStarts("/f") - .notStarts(""); - test("/foo/bar") - .starts("/") - .starts("/foo") - .starts("/foo/") - .starts("/foo/bar") - .notStarts("/f") - .notStarts("foo") - .notStarts("foo/bar") - .notStarts(""); - test("foo") - .starts("foo") - .notStarts("f"); - test("foo/bar") - .starts("foo") - .starts("foo/") - .starts("foo/bar") - .notStarts("f") - .notStarts("/foo") - .notStarts("/foo/bar"); - - // endsWith - test("") - .ends("") - .notEnds("/"); - test("/") - .ends("/") - .notEnds("foo") - .notEnds("/foo"); - test("/foo") - .ends("foo") - .ends("/foo") - .notEnds("/"); - test("/foo/bar") - .ends("bar") - .ends("foo/bar") - .ends("foo/bar/") - .ends("/foo/bar") - .notEnds("/bar"); - test("/foo/bar/") - .ends("bar") - .ends("foo/bar") - .ends("foo/bar/") - .ends("/foo/bar") - .notEnds("/bar"); - test("foo") - .ends("foo"); - test("foo/bar") - .ends("bar") - .ends("bar/") - .ends("foo/bar/") - .ends("foo/bar"); - - - // elements - test("a/b/c") - .element(0,"a") - .element(1,"b") - .element(2,"c"); - - // isAbsolute - test("/") - .absolute(); - test("/tmp") - .absolute(); - test("tmp") - .notAbsolute(); - test("") - .notAbsolute(); - - // resolve - test("/tmp") - .resolve("foo", "/tmp/foo") - .resolve("/foo", "/foo"); - test("tmp") - .resolve("foo", "tmp/foo") - .resolve("/foo", "/foo"); - - // relativize - test("/a/b/c") - .relativize("/a/b/c", "") - .relativize("/a/b/c/d/e", "d/e") - .relativize("/a/x", "../../x"); - - // normalize - test("/") - .normalize("/"); - test("foo") - .normalize("foo"); - test("/foo") - .normalize("/foo"); - test(".") - .normalize(""); - test("..") - .normalize(".."); - test("/..") - .normalize("/"); - test("/../..") - .normalize("/"); - test("foo/.") - .normalize("foo"); - test("./foo") - .normalize("foo"); - test("foo/..") - .normalize(""); - test("../foo") - .normalize("../foo"); - test("../../foo") - .normalize("../../foo"); - test("foo/bar/..") - .normalize("foo"); - test("foo/bar/gus/../..") - .normalize("foo"); - test("/foo/bar/gus/../..") - .normalize("/foo"); - test("/./.") - .normalize("/"); - test("/.") - .normalize("/"); - test("/./abc") - .normalize("/abc"); - // invalid - test("foo\u0000bar") - .invalid(); - test("\u0000foo") - .invalid(); - test("bar\u0000") - .invalid(); - test("//foo\u0000bar") - .invalid(); - test("//\u0000foo") - .invalid(); - test("//bar\u0000") - .invalid(); - - // normalization - test("//foo//bar") - .string("/foo/bar") - .root("/") - .parent("/foo") - .name("bar"); - - // isSameFile - test("/fileDoesNotExist") - .isSameFile("/fileDoesNotExist"); - } - - static void npes() { - header("NullPointerException"); - - Path path = fs.getPath("foo"); - - try { - path.resolve((String)null); - throw new RuntimeException("NullPointerException not thrown"); - } catch (NullPointerException npe) { - } - - try { - path.relativize(null); - throw new RuntimeException("NullPointerException not thrown"); - } catch (NullPointerException npe) { - } - - try { - path.compareTo(null); - throw new RuntimeException("NullPointerException not thrown"); - } catch (NullPointerException npe) { - } - - try { - path.startsWith((Path)null); - throw new RuntimeException("NullPointerException not thrown"); - } catch (NullPointerException npe) { - } - - try { - path.endsWith((Path)null); - throw new RuntimeException("NullPointerException not thrown"); - } catch (NullPointerException npe) { - } - - } - - public static void main(String[] args) throws Throwable { - - Path zipfile = Paths.get(args[0]); - fs = FileSystems.newFileSystem(zipfile, null); - npes(); - doPathOpTests(); - fs.close(); - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/demo/zipfs/ZFSTests.java --- a/jdk/test/demo/zipfs/ZFSTests.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* @test - @bug 7156873 - @summary ZipFileSystem regression tests - */ - - -import java.net.URI; -import java.nio.file.*; -import java.util.Map; -import java.util.HashMap; - -public class ZFSTests { - - public static void main(String[] args) throws Throwable { - test7156873(); - } - - static void test7156873() throws Throwable { - String DIRWITHSPACE = "testdir with spaces"; - Path dir = Paths.get(DIRWITHSPACE); - Path path = Paths.get(DIRWITHSPACE, "file.zip"); - try { - Files.createDirectory(dir); - URI uri = URI.create("jar:" + path.toUri()); - Map env = new HashMap(); - env.put("create", "true"); - try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {} - } finally { - Files.deleteIfExists(path); - Files.deleteIfExists(dir); - } - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/demo/zipfs/ZipFSTester.java --- a/jdk/test/demo/zipfs/ZipFSTester.java Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,750 +0,0 @@ -/* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.nio.file.*; -import java.nio.file.spi.*; -import java.nio.file.attribute.*; -import java.net.*; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.zip.*; - -import static java.nio.file.StandardOpenOption.*; -import static java.nio.file.StandardCopyOption.*; - -/* - * Tests various zipfs operations. - */ - -public class ZipFSTester { - - public static void main(String[] args) throws Throwable { - - try (FileSystem fs = newZipFileSystem(Paths.get(args[0]), - new HashMap())) - { - test0(fs); - test1(fs); - test2(fs); // more tests - testTime(Paths.get(args[0])); - } - } - - static void test0(FileSystem fs) - throws Exception - { - List list = new LinkedList<>(); - try (ZipFile zf = new ZipFile(fs.toString())) { - Enumeration zes = zf.entries(); - while (zes.hasMoreElements()) { - list.add(zes.nextElement().getName()); - } - for (String pname : list) { - Path path = fs.getPath(pname); - if (!Files.exists(path)) - throw new RuntimeException("path existence check failed!"); - while ((path = path.getParent()) != null) { - if (!Files.exists(path)) - throw new RuntimeException("parent existence check failed!"); - } - } - } - } - - static void test1(FileSystem fs0) - throws Exception - { - Random rdm = new Random(); - // clone a fs and test on it - Path tmpfsPath = getTempPath(); - Map env = new HashMap(); - env.put("create", "true"); - try (FileSystem copy = newZipFileSystem(tmpfsPath, env)) { - z2zcopy(fs0, copy, "/", 0); - } - - try (FileSystem fs = newZipFileSystem(tmpfsPath, new HashMap())) { - - FileSystemProvider provider = fs.provider(); - // newFileSystem(path...) should not throw exception - try (FileSystem fsPath = provider.newFileSystem(tmpfsPath, new HashMap())){} - try (FileSystem fsUri = provider.newFileSystem( - new URI("jar", tmpfsPath.toUri().toString(), null), - new HashMap())) - { - throw new RuntimeException("newFileSystem(uri...) does not throw exception"); - } catch (FileSystemAlreadyExistsException fsaee) {} - - // prepare a src - Path src = getTempPath(); - String tmpName = src.toString(); - OutputStream os = Files.newOutputStream(src); - byte[] bits = new byte[12345]; - rdm.nextBytes(bits); - os.write(bits); - os.close(); - - try { - provider.newFileSystem(new File(System.getProperty("test.src", ".")).toPath(), - new HashMap()); - throw new RuntimeException("newFileSystem() opens a directory as zipfs"); - } catch (UnsupportedOperationException uoe) {} - - try { - provider.newFileSystem(src, new HashMap()); - throw new RuntimeException("newFileSystem() opens a non-zip file as zipfs"); - } catch (UnsupportedOperationException uoe) {} - - - // copyin - Path dst = getPathWithParents(fs, tmpName); - Files.copy(src, dst); - checkEqual(src, dst); - - // copy - Path dst2 = getPathWithParents(fs, "/xyz" + rdm.nextInt(100) + - "/efg" + rdm.nextInt(100) + "/foo.class"); - Files.copy(dst, dst2); - //dst.moveTo(dst2); - checkEqual(src, dst2); - - // delete - Files.delete(dst); - if (Files.exists(dst)) - throw new RuntimeException("Failed!"); - - // moveout - Path dst3 = Paths.get(tmpName + "_Tmp"); - Files.move(dst2, dst3); - checkEqual(src, dst3); - if (Files.exists(dst2)) - throw new RuntimeException("Failed!"); - - // copyback + move - Files.copy(dst3, dst); - Path dst4 = getPathWithParents(fs, tmpName + "_Tmp0"); - Files.move(dst, dst4); - checkEqual(src, dst4); - - // delete - Files.delete(dst4); - if (Files.exists(dst4)) - throw new RuntimeException("Failed!"); - Files.delete(dst3); - if (Files.exists(dst3)) - throw new RuntimeException("Failed!"); - - // move (existing entry) - Path dst5 = fs.getPath("META-INF/MANIFEST.MF"); - if (Files.exists(dst5)) { - Path dst6 = fs.getPath("META-INF/MANIFEST.MF_TMP"); - Files.move(dst5, dst6); - walk(fs.getPath("/")); - } - - // newInputStream on dir - Path parent = dst2.getParent(); - try { - Files.newInputStream(parent); - throw new RuntimeException("Failed"); - } catch (FileSystemException e) { - e.printStackTrace(); // expected fse - } - - // rmdirs - try { - rmdirs(parent); - } catch (IOException x) { - x.printStackTrace(); - } - - // newFileChannel() copy in, out and verify via fch - fchCopy(src, dst); // in - checkEqual(src, dst); - Path tmp = Paths.get(tmpName + "_Tmp"); - fchCopy(dst, tmp); // out - checkEqual(src, tmp); - Files.delete(tmp); - - // test channels - channel(fs, dst); - Files.delete(dst); - Files.delete(src); - } finally { - if (Files.exists(tmpfsPath)) - Files.delete(tmpfsPath); - } - } - - static void test2(FileSystem fs) throws Exception { - - Path fs1Path = getTempPath(); - Path fs2Path = getTempPath(); - Path fs3Path = getTempPath(); - - // create a new filesystem, copy everything from fs - Map env = new HashMap(); - env.put("create", "true"); - FileSystem fs0 = newZipFileSystem(fs1Path, env); - - final FileSystem fs2 = newZipFileSystem(fs2Path, env); - final FileSystem fs3 = newZipFileSystem(fs3Path, env); - - System.out.println("copy src: fs -> fs0..."); - z2zcopy(fs, fs0, "/", 0); // copy fs -> fs1 - fs0.close(); // dump to file - - System.out.println("open fs0 as fs1"); - env = new HashMap(); - final FileSystem fs1 = newZipFileSystem(fs1Path, env); - - System.out.println("listing..."); - final ArrayList files = new ArrayList<>(); - final ArrayList dirs = new ArrayList<>(); - list(fs1.getPath("/"), files, dirs); - - Thread t0 = new Thread(new Runnable() { - public void run() { - List list = new ArrayList<>(dirs); - Collections.shuffle(list); - for (String path : list) { - try { - z2zcopy(fs1, fs2, path, 0); - } catch (Exception x) { - x.printStackTrace(); - } - } - } - - }); - - Thread t1 = new Thread(new Runnable() { - public void run() { - List list = new ArrayList<>(dirs); - Collections.shuffle(list); - for (String path : list) { - try { - z2zcopy(fs1, fs2, path, 1); - } catch (Exception x) { - x.printStackTrace(); - } - } - } - - }); - - Thread t2 = new Thread(new Runnable() { - public void run() { - List list = new ArrayList<>(dirs); - Collections.shuffle(list); - for (String path : list) { - try { - z2zcopy(fs1, fs2, path, 2); - } catch (Exception x) { - x.printStackTrace(); - } - } - } - - }); - - Thread t3 = new Thread(new Runnable() { - public void run() { - List list = new ArrayList<>(files); - Collections.shuffle(list); - while (!list.isEmpty()) { - Iterator itr = list.iterator(); - while (itr.hasNext()) { - String path = itr.next(); - try { - if (Files.exists(fs2.getPath(path))) { - z2zmove(fs2, fs3, path); - itr.remove(); - } - } catch (FileAlreadyExistsException x){ - itr.remove(); - } catch (Exception x) { - x.printStackTrace(); - } - } - } - } - - }); - - System.out.println("copying/removing..."); - t0.start(); t1.start(); t2.start(); t3.start(); - t0.join(); t1.join(); t2.join(); t3.join(); - - System.out.println("closing: fs1, fs2"); - fs1.close(); - fs2.close(); - - int failed = 0; - System.out.println("checkEqual: fs vs fs3"); - for (String path : files) { - try { - checkEqual(fs.getPath(path), fs3.getPath(path)); - } catch (IOException x) { - //x.printStackTrace(); - failed++; - } - } - System.out.println("closing: fs3"); - fs3.close(); - - System.out.println("opening: fs3 as fs4"); - FileSystem fs4 = newZipFileSystem(fs3Path, env); - - - ArrayList files2 = new ArrayList<>(); - ArrayList dirs2 = new ArrayList<>(); - list(fs4.getPath("/"), files2, dirs2); - - System.out.println("checkEqual: fs vs fs4"); - for (String path : files2) { - checkEqual(fs.getPath(path), fs4.getPath(path)); - } - System.out.println("walking: fs4"); - walk(fs4.getPath("/")); - System.out.println("closing: fs4"); - fs4.close(); - System.out.printf("failed=%d%n", failed); - - Files.delete(fs1Path); - Files.delete(fs2Path); - Files.delete(fs3Path); - } - - // test file stamp - static void testTime(Path src) throws Exception { - BasicFileAttributes attrs = Files - .getFileAttributeView(src, BasicFileAttributeView.class) - .readAttributes(); - // create a new filesystem, copy this file into it - Map env = new HashMap(); - env.put("create", "true"); - Path fsPath = getTempPath(); - FileSystem fs = newZipFileSystem(fsPath, env); - - System.out.println("test copy with timestamps..."); - // copyin - Path dst = getPathWithParents(fs, "me"); - Files.copy(src, dst, COPY_ATTRIBUTES); - checkEqual(src, dst); - System.out.println("mtime: " + attrs.lastModifiedTime()); - System.out.println("ctime: " + attrs.creationTime()); - System.out.println("atime: " + attrs.lastAccessTime()); - System.out.println(" ==============>"); - BasicFileAttributes dstAttrs = Files - .getFileAttributeView(dst, BasicFileAttributeView.class) - .readAttributes(); - System.out.println("mtime: " + dstAttrs.lastModifiedTime()); - System.out.println("ctime: " + dstAttrs.creationTime()); - System.out.println("atime: " + dstAttrs.lastAccessTime()); - - // 1-second granularity - if (attrs.lastModifiedTime().to(TimeUnit.SECONDS) != - dstAttrs.lastModifiedTime().to(TimeUnit.SECONDS) || - attrs.lastAccessTime().to(TimeUnit.SECONDS) != - dstAttrs.lastAccessTime().to(TimeUnit.SECONDS) || - attrs.creationTime().to(TimeUnit.SECONDS) != - dstAttrs.creationTime().to(TimeUnit.SECONDS)) { - throw new RuntimeException("Timestamp Copy Failed!"); - } - Files.delete(fsPath); - } - - private static FileSystem newZipFileSystem(Path path, Map env) - throws Exception - { - return FileSystems.newFileSystem( - new URI("jar", path.toUri().toString(), null), env, null); - } - - private static Path getTempPath() throws IOException - { - File tmp = File.createTempFile("testzipfs_", "zip"); - tmp.delete(); // we need a clean path, no file - return tmp.toPath(); - } - - private static void list(Path path, List files, List dirs ) - throws IOException - { - if (Files.isDirectory(path)) { - try (DirectoryStream ds = Files.newDirectoryStream(path)) { - for (Path child : ds) - list(child, files, dirs); - } - dirs.add(path.toString()); - } else { - files.add(path.toString()); - } - } - - private static void z2zcopy(FileSystem src, FileSystem dst, String path, - int method) - throws IOException - { - Path srcPath = src.getPath(path); - Path dstPath = dst.getPath(path); - - if (Files.isDirectory(srcPath)) { - if (!Files.exists(dstPath)) { - try { - mkdirs(dstPath); - } catch (FileAlreadyExistsException x) {} - } - try (DirectoryStream ds = Files.newDirectoryStream(srcPath)) { - for (Path child : ds) { - z2zcopy(src, dst, - path + (path.endsWith("/")?"":"/") + child.getFileName(), - method); - } - } - } else { - try { - if (Files.exists(dstPath)) - return; - switch (method) { - case 0: - Files.copy(srcPath, dstPath); - break; - case 1: - chCopy(srcPath, dstPath); - break; - case 2: - //fchCopy(srcPath, dstPath); - streamCopy(srcPath, dstPath); - break; - } - } catch (FileAlreadyExistsException x) {} - } - } - - private static void z2zmove(FileSystem src, FileSystem dst, String path) - throws IOException - { - Path srcPath = src.getPath(path); - Path dstPath = dst.getPath(path); - - if (Files.isDirectory(srcPath)) { - if (!Files.exists(dstPath)) - mkdirs(dstPath); - try (DirectoryStream ds = Files.newDirectoryStream(srcPath)) { - for (Path child : ds) { - z2zmove(src, dst, - path + (path.endsWith("/")?"":"/") + child.getFileName()); - } - } - } else { - //System.out.println("moving..." + path); - Path parent = dstPath.getParent(); - if (parent != null && Files.notExists(parent)) - mkdirs(parent); - Files.move(srcPath, dstPath); - } - } - - private static void walk(Path path) throws IOException - { - Files.walkFileTree( - path, - new SimpleFileVisitor() { - private int indent = 0; - private void indent() { - int n = 0; - while (n++ < indent) - System.out.printf(" "); - } - - @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attrs) - { - indent(); - System.out.printf("%s%n", file.getFileName().toString()); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, - BasicFileAttributes attrs) - { - indent(); - System.out.printf("[%s]%n", dir.toString()); - indent += 2; - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, - IOException ioe) - throws IOException - { - indent -= 2; - return FileVisitResult.CONTINUE; - } - }); - } - - private static void mkdirs(Path path) throws IOException { - if (Files.exists(path)) - return; - path = path.toAbsolutePath(); - Path parent = path.getParent(); - if (parent != null) { - if (Files.notExists(parent)) - mkdirs(parent); - } - Files.createDirectory(path); - } - - private static void rmdirs(Path path) throws IOException { - while (path != null && path.getNameCount() != 0) { - Files.delete(path); - path = path.getParent(); - } - } - - // check the content of two paths are equal - private static void checkEqual(Path src, Path dst) throws IOException - { - //System.out.printf("checking <%s> vs <%s>...%n", - // src.toString(), dst.toString()); - - //streams - byte[] bufSrc = new byte[8192]; - byte[] bufDst = new byte[8192]; - try (InputStream isSrc = Files.newInputStream(src); - InputStream isDst = Files.newInputStream(dst)) - { - int nSrc = 0; - while ((nSrc = isSrc.read(bufSrc)) != -1) { - int nDst = 0; - while (nDst < nSrc) { - int n = isDst.read(bufDst, nDst, nSrc - nDst); - if (n == -1) { - System.out.printf("checking <%s> vs <%s>...%n", - src.toString(), dst.toString()); - throw new RuntimeException("CHECK FAILED!"); - } - nDst += n; - } - while (--nSrc >= 0) { - if (bufSrc[nSrc] != bufDst[nSrc]) { - System.out.printf("checking <%s> vs <%s>...%n", - src.toString(), dst.toString()); - throw new RuntimeException("CHECK FAILED!"); - } - nSrc--; - } - } - } - - // channels - try (SeekableByteChannel chSrc = Files.newByteChannel(src); - SeekableByteChannel chDst = Files.newByteChannel(dst)) - { - if (chSrc.size() != chDst.size()) { - System.out.printf("src[%s].size=%d, dst[%s].size=%d%n", - chSrc.toString(), chSrc.size(), - chDst.toString(), chDst.size()); - throw new RuntimeException("CHECK FAILED!"); - } - ByteBuffer bbSrc = ByteBuffer.allocate(8192); - ByteBuffer bbDst = ByteBuffer.allocate(8192); - - int nSrc = 0; - while ((nSrc = chSrc.read(bbSrc)) != -1) { - int nDst = chDst.read(bbDst); - if (nSrc != nDst) { - System.out.printf("checking <%s> vs <%s>...%n", - src.toString(), dst.toString()); - throw new RuntimeException("CHECK FAILED!"); - } - while (--nSrc >= 0) { - if (bbSrc.get(nSrc) != bbDst.get(nSrc)) { - System.out.printf("checking <%s> vs <%s>...%n", - src.toString(), dst.toString()); - throw new RuntimeException("CHECK FAILED!"); - } - nSrc--; - } - bbSrc.flip(); - bbDst.flip(); - } - - // Check if source read position is at the end - if (chSrc.position() != chSrc.size()) { - System.out.printf("src[%s]: size=%d, position=%d%n", - chSrc.toString(), chSrc.size(), chSrc.position()); - throw new RuntimeException("CHECK FAILED!"); - } - - // Check if destination read position is at the end - if (chDst.position() != chDst.size()) { - System.out.printf("dst[%s]: size=%d, position=%d%n", - chDst.toString(), chDst.size(), chDst.position()); - throw new RuntimeException("CHECK FAILED!"); - } - } catch (IOException x) { - x.printStackTrace(); - } - } - - private static void fchCopy(Path src, Path dst) throws IOException - { - Set read = new HashSet<>(); - read.add(READ); - Set openwrite = new HashSet<>(); - openwrite.add(CREATE_NEW); - openwrite.add(WRITE); - - try (FileChannel srcFc = src.getFileSystem() - .provider() - .newFileChannel(src, read); - FileChannel dstFc = dst.getFileSystem() - .provider() - .newFileChannel(dst, openwrite)) - { - ByteBuffer bb = ByteBuffer.allocate(8192); - while (srcFc.read(bb) >= 0) { - bb.flip(); - dstFc.write(bb); - bb.clear(); - } - } - } - - private static void chCopy(Path src, Path dst) throws IOException - { - Set read = new HashSet<>(); - read.add(READ); - Set openwrite = new HashSet<>(); - openwrite.add(CREATE_NEW); - openwrite.add(WRITE); - - try (SeekableByteChannel srcCh = Files.newByteChannel(src, read); - SeekableByteChannel dstCh = Files.newByteChannel(dst, openwrite)) - { - - ByteBuffer bb = ByteBuffer.allocate(8192); - while (srcCh.read(bb) >= 0) { - bb.flip(); - dstCh.write(bb); - bb.clear(); - } - - // Check if source read position is at the end - if (srcCh.position() != srcCh.size()) { - System.out.printf("src[%s]: size=%d, position=%d%n", - srcCh.toString(), srcCh.size(), srcCh.position()); - throw new RuntimeException("CHECK FAILED!"); - } - - // Check if destination write position is at the end - if (dstCh.position() != dstCh.size()) { - System.out.printf("dst[%s]: size=%d, position=%d%n", - dstCh.toString(), dstCh.size(), dstCh.position()); - throw new RuntimeException("CHECK FAILED!"); - } - } - } - - private static void streamCopy(Path src, Path dst) throws IOException - { - byte[] buf = new byte[8192]; - try (InputStream isSrc = Files.newInputStream(src); - OutputStream osDst = Files.newOutputStream(dst)) - { - int n = 0; - while ((n = isSrc.read(buf)) != -1) { - osDst.write(buf, 0, n); - } - } - } - - static void channel(FileSystem fs, Path path) - throws Exception - { - System.out.println("test ByteChannel..."); - Set read = new HashSet<>(); - read.add(READ); - int n = 0; - ByteBuffer bb = null; - ByteBuffer bb2 = null; - int N = 120; - - try (SeekableByteChannel sbc = Files.newByteChannel(path)) { - System.out.printf(" sbc[0]: pos=%d, size=%d%n", sbc.position(), sbc.size()); - if (sbc.position() != 0) { - throw new RuntimeException("CHECK FAILED!"); - } - - bb = ByteBuffer.allocate((int)sbc.size()); - n = sbc.read(bb); - System.out.printf(" sbc[1]: read=%d, pos=%d, size=%d%n", - n, sbc.position(), sbc.size()); - if (sbc.position() != sbc.size()) { - throw new RuntimeException("CHECK FAILED!"); - } - bb2 = ByteBuffer.allocate((int)sbc.size()); - } - - // sbc.position(pos) is not supported in current version - // try the FileChannel - try (SeekableByteChannel sbc = fs.provider().newFileChannel(path, read)) { - sbc.position(N); - System.out.printf(" sbc[2]: pos=%d, size=%d%n", - sbc.position(), sbc.size()); - if (sbc.position() != N) { - throw new RuntimeException("CHECK FAILED!"); - } - bb2.limit(100); - n = sbc.read(bb2); - System.out.printf(" sbc[3]: read=%d, pos=%d, size=%d%n", - n, sbc.position(), sbc.size()); - if (n < 0 || sbc.position() != (N + n)) { - throw new RuntimeException("CHECK FAILED!"); - } - System.out.printf(" sbc[4]: bb[%d]=%d, bb1[0]=%d%n", - N, bb.get(N) & 0xff, bb2.get(0) & 0xff); - } - } - - // create parents if does not exist - static Path getPathWithParents(FileSystem fs, String name) - throws Exception - { - Path path = fs.getPath(name); - Path parent = path.getParent(); - if (parent != null && Files.notExists(parent)) - mkdirs(parent); - return path; - } -} diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/demo/zipfs/basic.sh --- a/jdk/test/demo/zipfs/basic.sh Tue Apr 15 15:28:01 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -# -# Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# -# @test -# @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596 -# 7157656 8002390 7012868 7012856 8015728 -# @summary Test ZipFileSystem demo -# @build Basic PathOps ZipFSTester -# @run shell basic.sh - -if [ -z "${TESTJAVA}" ]; then - echo "Test must be run with jtreg" - exit 0 -fi - -ZIPFS="${TESTJAVA}/demo/nio/zipfs/zipfs.jar" -if [ ! -r "${ZIPFS}" ]; then - echo "${ZIPFS} not found" - exit 0 -fi - -OS=`uname -s` -case "$OS" in - Windows_* | CYGWIN* ) - CLASSPATH="${TESTCLASSES};${ZIPFS}" - ;; - * ) - CLASSPATH="${TESTCLASSES}:${ZIPFS}" - ;; -esac -export CLASSPATH - -failures=0 - -go() { - echo "" - ${TESTJAVA}/bin/java ${TESTVMOPTS} $1 $2 $3 2>&1 - if [ $? != 0 ]; then failures=`expr $failures + 1`; fi -} - -# Run the tests - -go Basic "${ZIPFS}" -go PathOps "${ZIPFS}" -go ZipFSTester "${ZIPFS}" - -# -# Results -# - -if [ $failures -gt 0 ]; -then echo "$failures tests failed"; -else echo "All tests passed"; -fi -exit $failures diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/java/awt/Toolkit/LoadAWTCrashTest/LoadAWTCrashTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Toolkit/LoadAWTCrashTest/LoadAWTCrashTest.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 8031477 + @summary Crash while awt starting + @author Petr Pchelko + @run main/othervm LoadAWTCrashTest +*/ + +public class LoadAWTCrashTest { + public static void main(String[] args) { + System.loadLibrary("awt"); + // If the bug is present JVM would crash or deadlock + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/java/awt/font/TextLayout/TestAATMorxFont.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/font/TextLayout/TestAATMorxFont.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* @test + * @summary verify rendering of MORX fonts on OS X. + * @bug 8031462 + */ + +import javax.swing.*; +import javax.swing.border.LineBorder; +import java.awt.*; +import java.awt.event.ActionEvent; + +public class TestAATMorxFont extends JComponent { + public static void main(String[] args) { + String osName = System.getProperty("os.name"); + System.out.println("OS is " + osName); + osName = osName.toLowerCase(); + if (!osName.startsWith("mac")) { + return; + } + SwingUtilities.invokeLater(new Runnable() { + public void run() { + JFrame frame = new JFrame("Test Morx"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + TestAATMorxFont panel = new TestAATMorxFont(); + frame.add(panel); + frame.pack(); + frame.setVisible(true); + } + }); + } + + public Dimension getPreferredSize() { + return new Dimension(1200, 400); + } + + public void paintComponent(Graphics g) { + Graphics2D g2d = (Graphics2D)g; + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + int y = 50; + g.setFont(new Font("Gujarati MT", Font.PLAIN, 40)); + System.out.println(g.getFont()); + g.drawString("\u0A95\u0ACD \u0A95\u0A95\u0A95 \u0A95\u0ACD\u0A95\u0ACD\u0A95", 20, y); + y += 50; + g.setFont(new Font("Tamil Sangam MN", Font.PLAIN, 40)); + System.out.println(g.getFont()); + g.drawString("\u0b95\u0bCD \u0b95\u0b95\u0b95 \u0b95\u0bCD\u0b95\u0bCD\u0b95", 20, y); + y += 50; + g.setFont(new Font("Telugu Sangam MN", Font.PLAIN, 40)); + System.out.println(g.getFont()); + g.drawString("\u0c15\u0c4D \u0c15\u0c15\u0c15 \u0c15\u0c4D\u0c15\u0c4D\u0c15", 20, y); + y += 50; + g.setFont(new Font("Devanagari Sangam MN", Font.PLAIN, 40)); + System.out.println(g.getFont()); + g.drawString("\u0915\u0940 \u0915\u0947 \u0915\u0942", 20, y); + y += 50; + g.drawString("\u0907\u0930\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915", 20, y); + y += 50; + g.drawString("\u0930\u093F\u0935\u094D\u092F\u0942 \u0915\u0947 \u092C\u093E\u0926 \u0935\u093F\u0915\u093E\u0938 \u0913\u0932\u0902\u092A\u093F\u0915 \u0938\u0947 \u092C\u093E\u0939\u0930 (\u0926\u0947\u0935\u0928\u093E\u0917\u0930\u0940) (\u0939\u093F\u0928\u094D\u0926\u0940) \u0907\u0930\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915\u094D\u0915", 20, y); + + } +} + diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/java/net/URLPermission/nstest/lookup.sh --- a/jdk/test/java/net/URLPermission/nstest/lookup.sh Tue Apr 15 15:28:01 2014 -0700 +++ b/jdk/test/java/net/URLPermission/nstest/lookup.sh Wed Apr 16 10:53:10 2014 -0700 @@ -26,6 +26,7 @@ # @library /lib/testlibrary # @compile -XDignore.symbol.file=true SimpleNameService.java # LookupTest.java SimpleNameServiceDescriptor.java +# @build jdk.testlibrary.Utils # @run shell/timeout=50 lookup.sh # diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/java/security/Provider/NewInstance.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/security/Provider/NewInstance.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8039853 + * @summary Provider.Service.newInstance() does not work with current + JDK JGSS Mechanisms + */ + +import java.security.*; +import java.util.*; + +public class NewInstance { + + public static void main(String[] args) throws Exception { + for (Provider p : Security.getProviders()) { + System.out.println("---------"); + System.out.println(p.getName() + ":" + p.getInfo()); + if (p.getName().equals("SunPCSC")) { + System.out.println("A smartcard might not be installed. Skip test."); + continue; + } + Set set = p.getServices(); + Iterator i = set.iterator(); + + while (i.hasNext()) { + Provider.Service s = i.next(); + System.out.println(s.getType() + "." + s.getAlgorithm()); + try { + s.newInstance(null); + } catch (NoSuchAlgorithmException e) { + System.out.println(" check"); + Throwable t = e.getCause(); + if (!(t instanceof InvalidAlgorithmParameterException)) { + throw e; + } + } + } + } + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/javax/imageio/plugins/jpeg/TruncatedImageWarningTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/imageio/plugins/jpeg/TruncatedImageWarningTest.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8032370 + * + * @summary Test verifies that Image I/O jpeg reader correctly handles + * and warns of a truncated image stream. + * + * @run main TruncatedImageWarningTest + */ + +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.event.IIOReadWarningListener; +import javax.imageio.stream.ImageInputStream; + +public class TruncatedImageWarningTest implements IIOReadWarningListener { + + private static String fileName = "truncated.jpg"; + boolean receivedWarning = false; + + public static void main(String[] args) throws IOException { + + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String filePath = dir+sep+fileName; + System.out.println("Test file: " + filePath); + File f = new File(filePath); + ImageInputStream in = ImageIO.createImageInputStream(f); + ImageReader reader = ImageIO.getImageReaders(in).next(); + TruncatedImageWarningTest twt = new TruncatedImageWarningTest(); + reader.addIIOReadWarningListener(twt); + reader.setInput(in); + reader.read(0); + if (!twt.receivedWarning) { + throw new RuntimeException("No expected warning"); + } + } + + public void warningOccurred(ImageReader source, String warning) { + System.out.println("Expected warning: " + warning); + receivedWarning = true; + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/javax/imageio/plugins/jpeg/truncated.jpg Binary file jdk/test/javax/imageio/plugins/jpeg/truncated.jpg has changed diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/javax/swing/JTable/8032874/bug8032874.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JTable/8032874/bug8032874.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8032874 + * @summary Test whether ArrayIndexOutOfBoundsException is thrown or not, + * once selected row is removed from JTable with Sorter and Filter + * @author Dmitry Markov + * @run main bug8032874 + */ + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableRowSorter; + +import sun.awt.SunToolkit; + +public class bug8032874 { + private static final int ROW_COUNT = 5; + private static JTable table; + private static TestTableModel tableModel; + + public static void main(String args[]) throws Exception { + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + createAndShowUI(); + } + }); + toolkit.realSync(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + table.getRowSorter().toggleSortOrder(0); + table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); + table.setRowSelectionInterval(1, 2); + } + }); + toolkit.realSync(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + for (int i = 0; i < ROW_COUNT; i++) { + tableModel.remove(0); + table.getRowSorter().toggleSortOrder(0); + } + } + }); + } + + public static void createAndShowUI() { + try { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + } catch (Exception e) { + throw new RuntimeException(e); + } + + JFrame frame = new JFrame("bug8032874"); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + + tableModel = new TestTableModel(); + table = new JTable(tableModel); + table.setSurrendersFocusOnKeystroke(true); + + final TableRowSorter rowSorter = new TableRowSorter(tableModel); + rowSorter.setRowFilter(new RowFilter() { + @Override + public boolean include(Entry entry) { + return entry.getIdentifier() % 2 == 0; + } + }); + table.setRowSorter(rowSorter); + + JScrollPane jScrollPane = new JScrollPane(table); + panel.add(jScrollPane); + + frame.setContentPane(panel); + frame.setSize(new Dimension(800, 600)); + frame.setVisible(true); + } + + private static class TestTableModel extends AbstractTableModel { + private final List data; + + public TestTableModel() { + data = new ArrayList(); + + for (int i = 0; i < ROW_COUNT; i++) { + data.add(i); + } + } + + @Override + public int getRowCount() { + return data.size(); + } + + @Override + public int getColumnCount() { + return 1; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return data.get(rowIndex); + } + + public void remove(int row) { + data.remove(row); + fireTableRowsDeleted(row, row); + } + } +} + diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/jdk/nio/zipfs/Basic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/nio/zipfs/Basic.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.FileSystemProvider; +import java.util.*; +import java.net.URI; +import java.io.IOException; + +/** + * + * @test + * @bug 8038500 + * @summary Basic test for zip provider + */ + +public class Basic { + public static void main(String[] args) throws Exception { + Path zipfile = Paths.get(System.getProperty("test.jdk"), + "jre/lib/ext/zipfs.jar"); + // Test: zip should should be returned in provider list + boolean found = false; + + for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { + if (provider.getScheme().equalsIgnoreCase("jar")) { + found = true; + break; + } + } + if (!found) + throw new RuntimeException("'jar' provider not installed"); + + // Test: FileSystems#newFileSystem(Path) + Map env = new HashMap(); + FileSystems.newFileSystem(zipfile, null).close(); + + // Test: FileSystems#newFileSystem(URI) + URI uri = new URI("jar", zipfile.toUri().toString(), null); + FileSystem fs = FileSystems.newFileSystem(uri, env, null); + + // Test: exercise toUri method + String expected = uri.toString() + "!/foo"; + String actual = fs.getPath("/foo").toUri().toString(); + if (!actual.equals(expected)) { + throw new RuntimeException("toUri returned '" + actual + + "', expected '" + expected + "'"); + } + + // Test: exercise directory iterator and retrieval of basic attributes + Files.walkFileTree(fs.getPath("/"), new FileTreePrinter()); + + // Test: DirectoryStream + found = false; + try (DirectoryStream stream = Files.newDirectoryStream(fs.getPath("/"))) { + for (Path entry: stream) { + found = entry.toString().equals("/META-INF/"); + if (found) break; + } + } + + if (!found) + throw new RuntimeException("Expected file not found"); + + // Test: copy file from zip file to current (scratch) directory + Path source = fs.getPath("/META-INF/services/java.nio.file.spi.FileSystemProvider"); + if (Files.exists(source)) { + Path target = Paths.get(source.getFileName().toString()); + Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING); + try { + long s1 = Files.readAttributes(source, BasicFileAttributes.class).size(); + long s2 = Files.readAttributes(target, BasicFileAttributes.class).size(); + if (s2 != s1) + throw new RuntimeException("target size != source size"); + } finally { + Files.delete(target); + } + } + + // Test: FileStore + FileStore store = Files.getFileStore(fs.getPath("/")); + if (!store.supportsFileAttributeView("basic")) + throw new RuntimeException("BasicFileAttributeView should be supported"); + + // Test: ClosedFileSystemException + fs.close(); + if (fs.isOpen()) + throw new RuntimeException("FileSystem should be closed"); + try { + fs.provider().checkAccess(fs.getPath("/missing"), AccessMode.READ); + } catch (ClosedFileSystemException x) { } + } + + // FileVisitor that pretty prints a file tree + static class FileTreePrinter extends SimpleFileVisitor { + private int indent = 0; + + private void indent() { + StringBuilder sb = new StringBuilder(indent); + for (int i=0; i + // rename entry src to dst inside zipfile + + movein, // + // move an external src file into zipfile + // as entry dst + + moveout, // + // move a zipfile entry src out to dst + + copy, // + // copy entry src to dst inside zipfile + + copyin, // + // copy an external src file into zipfile + // as entry dst + + copyin_attrs, // + // copy an external src file into zipfile + // as entry dst, with attributes (timestamp) + + copyout, // + // copy zipfile entry src" out to file dst + + copyout_attrs, // + + zzmove, // + // move entry path/dir from zfsrc to zfdst + + zzcopy, // + // copy path from zipfile zfsrc to zipfile + // zfdst + + attrs, // + // printout the attributes of entry path + + attrsspace, // + // printout the storespace attrs of entry path + + setmtime, // + // set the lastModifiedTime of entry path + + setatime, // + setctime, // + + lsdir, // + // list dir's direct child files/dirs + + mkdir, // + + mkdirs, // + + rmdirs, // + + list, // + // recursively list all entries of dir + // via DirectoryStream + + tlist, // + // list with buildDirTree=true + + vlist, // + // recursively verbose list all entries of + // dir via DirectoryStream + + walk, // + // recursively walk all entries of dir + // via Files.walkFileTree + + twalk, // + // walk with buildDirTree=true + + extract, // + + update, // + + delete, // + + add, // + + create, // + // create a new zipfile if it doesn't exit + // and then add the file(s) into it. + + attrs2, // + // test different ways to print attrs + + prof, + } + + public static void main(String[] args) throws Throwable { + FileSystemProvider provider = getZipFSProvider(); + if (provider == null) { + System.err.println("ZIP filesystem provider is not installed"); + System.exit(1); + } + + Action action = Action.valueOf(args[0]); + Map env = env = new HashMap<>(); + if (action == Action.create) + env.put("create", "true"); + try (FileSystem fs = provider.newFileSystem(Paths.get(args[1]), env)) { + Path path, src, dst; + switch (action) { + case rename: + src = fs.getPath(args[2]); + dst = fs.getPath(args[3]); + Files.move(src, dst); + break; + case moveout: + src = fs.getPath(args[2]); + dst = Paths.get(args[3]); + Files.move(src, dst); + break; + case movein: + src = Paths.get(args[2]); + dst = fs.getPath(args[3]); + Files.move(src, dst); + break; + case copy: + src = fs.getPath(args[2]); + dst = fs.getPath(args[3]); + Files.copy(src, dst); + break; + case copyout: + src = fs.getPath(args[2]); + dst = Paths.get(args[3]); + Files.copy(src, dst); + break; + case copyin: + src = Paths.get(args[2]); + dst = fs.getPath(args[3]); + Files.copy(src, dst); + break; + case copyin_attrs: + src = Paths.get(args[2]); + dst = fs.getPath(args[3]); + Files.copy(src, dst, COPY_ATTRIBUTES); + break; + case copyout_attrs: + src = fs.getPath(args[2]); + dst = Paths.get(args[3]); + Files.copy(src, dst, COPY_ATTRIBUTES); + break; + case zzmove: + try (FileSystem fs2 = provider.newFileSystem(Paths.get(args[2]), env)) { + z2zmove(fs, fs2, args[3]); + } + break; + case zzcopy: + try (FileSystem fs2 = provider.newFileSystem(Paths.get(args[2]), env)) { + z2zcopy(fs, fs2, args[3]); + } + break; + case attrs: + for (int i = 2; i < args.length; i++) { + path = fs.getPath(args[i]); + System.out.println(path); + System.out.println( + Files.readAttributes(path, BasicFileAttributes.class).toString()); + } + break; + case setmtime: + DateFormat df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); + Date newDatetime = df.parse(args[2]); + for (int i = 3; i < args.length; i++) { + path = fs.getPath(args[i]); + Files.setAttribute(path, "lastModifiedTime", + FileTime.fromMillis(newDatetime.getTime())); + System.out.println( + Files.readAttributes(path, BasicFileAttributes.class).toString()); + } + break; + case setctime: + df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); + newDatetime = df.parse(args[2]); + for (int i = 3; i < args.length; i++) { + path = fs.getPath(args[i]); + Files.setAttribute(path, "creationTime", + FileTime.fromMillis(newDatetime.getTime())); + System.out.println( + Files.readAttributes(path, BasicFileAttributes.class).toString()); + } + break; + case setatime: + df = new SimpleDateFormat("MM/dd/yyyy-HH:mm:ss"); + newDatetime = df.parse(args[2]); + for (int i = 3; i < args.length; i++) { + path = fs.getPath(args[i]); + Files.setAttribute(path, "lastAccessTime", + FileTime.fromMillis(newDatetime.getTime())); + System.out.println( + Files.readAttributes(path, BasicFileAttributes.class).toString()); + } + break; + case attrsspace: + path = fs.getPath("/"); + FileStore fstore = Files.getFileStore(path); + System.out.printf("filestore[%s]%n", fstore.name()); + System.out.printf(" totalSpace: %d%n", + (Long)fstore.getAttribute("totalSpace")); + System.out.printf(" usableSpace: %d%n", + (Long)fstore.getAttribute("usableSpace")); + System.out.printf(" unallocSpace: %d%n", + (Long)fstore.getAttribute("unallocatedSpace")); + break; + case list: + case tlist: + if (args.length < 3) + list(fs.getPath("/"), false); + else + list(fs.getPath(args[2]), false); + break; + case vlist: + if (args.length < 3) + list(fs.getPath("/"), true); + else + list(fs.getPath(args[2]), true); + break; + case twalk: + case walk: + walk(fs.getPath((args.length > 2)? args[2] : "/")); + break; + case extract: + if (args.length == 2) { + extract(fs, "/"); + } else { + for (int i = 2; i < args.length; i++) { + extract(fs, args[i]); + } + } + break; + case delete: + for (int i = 2; i < args.length; i++) + Files.delete(fs.getPath(args[i])); + break; + case create: + case add: + case update: + for (int i = 2; i < args.length; i++) { + update(fs, args[i]); + } + break; + case lsdir: + path = fs.getPath(args[2]); + final String fStr = (args.length > 3)?args[3]:""; + try (DirectoryStream ds = Files.newDirectoryStream(path, + new DirectoryStream.Filter() { + @Override + public boolean accept(Path path) { + return path.toString().contains(fStr); + } + })) + { + for (Path p : ds) + System.out.println(p); + } + break; + case mkdir: + Files.createDirectory(fs.getPath(args[2])); + break; + case mkdirs: + mkdirs(fs.getPath(args[2])); + break; + case attrs2: + for (int i = 2; i < args.length; i++) { + path = fs.getPath(args[i]); + System.out.printf("%n%s%n", path); + System.out.println("-------(1)---------"); + System.out.println( + Files.readAttributes(path, BasicFileAttributes.class).toString()); + System.out.println("-------(2)---------"); + Map map = Files.readAttributes(path, "zip:*"); + for (Map.Entry e : map.entrySet()) { + System.out.printf(" %s : %s%n", e.getKey(), e.getValue()); + } + System.out.println("-------(3)---------"); + map = Files.readAttributes(path, "size,lastModifiedTime,isDirectory"); + for (Map.Entry e : map.entrySet()) { + System.out.printf(" %s : %s%n", e.getKey(), e.getValue()); + } + } + break; + case prof: + list(fs.getPath("/"), false); + while (true) { + Thread.sleep(10000); + //list(fs.getPath("/"), true); + System.out.println("sleeping..."); + } + } + } catch (Exception x) { + x.printStackTrace(); + } + } + + private static FileSystemProvider getZipFSProvider() { + for (FileSystemProvider provider : FileSystemProvider.installedProviders()) { + if ("jar".equals(provider.getScheme())) + return provider; + } + return null; + } + + @SuppressWarnings("unused") + /** + * Not used in demo, but included for demonstrational purposes. + */ + private static byte[] getBytes(String name) { + return name.getBytes(); + } + + @SuppressWarnings("unused") + /** + * Not used in demo, but included for demonstrational purposes. + */ + private static String getString(byte[] name) { + return new String(name); + } + + private static void walk(Path path) throws IOException + { + Files.walkFileTree( + path, + new SimpleFileVisitor() { + private int indent = 0; + private void indent() { + int n = 0; + while (n++ < indent) + System.out.printf(" "); + } + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) + { + indent(); + System.out.printf("%s%n", file.getFileName().toString()); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attrs) + { + indent(); + System.out.printf("[%s]%n", dir.toString()); + indent += 2; + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException ioe) + { + indent -= 2; + return FileVisitResult.CONTINUE; + } + }); + } + + private static void update(FileSystem fs, String path) throws Throwable{ + Path src = FileSystems.getDefault().getPath(path); + if (Files.isDirectory(src)) { + try (DirectoryStream ds = Files.newDirectoryStream(src)) { + for (Path child : ds) + update(fs, child.toString()); + } + } else { + Path dst = fs.getPath(path); + Path parent = dst.getParent(); + if (parent != null && Files.notExists(parent)) + mkdirs(parent); + Files.copy(src, dst, REPLACE_EXISTING); + } + } + + private static void extract(FileSystem fs, String path) throws Throwable{ + Path src = fs.getPath(path); + if (Files.isDirectory(src)) { + try (DirectoryStream ds = Files.newDirectoryStream(src)) { + for (Path child : ds) + extract(fs, child.toString()); + } + } else { + if (path.startsWith("/")) + path = path.substring(1); + Path dst = FileSystems.getDefault().getPath(path); + Path parent = dst.getParent(); + if (Files.notExists(parent)) + mkdirs(parent); + Files.copy(src, dst, REPLACE_EXISTING); + } + } + + // use DirectoryStream + private static void z2zcopy(FileSystem src, FileSystem dst, String path) + throws IOException + { + Path srcPath = src.getPath(path); + Path dstPath = dst.getPath(path); + + if (Files.isDirectory(srcPath)) { + if (!Files.exists(dstPath)) { + try { + mkdirs(dstPath); + } catch (FileAlreadyExistsException x) {} + } + try (DirectoryStream ds = Files.newDirectoryStream(srcPath)) { + for (Path child : ds) { + z2zcopy(src, dst, + path + (path.endsWith("/")?"":"/") + child.getFileName()); + } + } + } else { + //System.out.println("copying..." + path); + Files.copy(srcPath, dstPath); + } + } + + // use TreeWalk to move + private static void z2zmove(FileSystem src, FileSystem dst, String path) + throws IOException + { + final Path srcPath = src.getPath(path).toAbsolutePath(); + final Path dstPath = dst.getPath(path).toAbsolutePath(); + + Files.walkFileTree(srcPath, new SimpleFileVisitor() { + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) + { + Path dst = srcPath.relativize(file); + dst = dstPath.resolve(dst); + try { + Path parent = dstPath.getParent(); + if (parent != null && Files.notExists(parent)) + mkdirs(parent); + Files.move(file, dst); + } catch (IOException x) { + x.printStackTrace(); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attrs) + { + Path dst = srcPath.relativize(dir); + dst = dstPath.resolve(dst); + try { + + if (Files.notExists(dst)) + mkdirs(dst); + } catch (IOException x) { + x.printStackTrace(); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException ioe) + throws IOException + { + try { + Files.delete(dir); + } catch (IOException x) { + //x.printStackTrace(); + } + return FileVisitResult.CONTINUE; + } + }); + + } + + private static void mkdirs(Path path) throws IOException { + path = path.toAbsolutePath(); + Path parent = path.getParent(); + if (parent != null) { + if (Files.notExists(parent)) + mkdirs(parent); + } + Files.createDirectory(path); + } + + @SuppressWarnings("unused") + /** + * Not used in demo, but included for demonstrational purposes. + */ + private static void rmdirs(Path path) throws IOException { + while (path != null && path.getNameCount() != 0) { + Files.delete(path); + path = path.getParent(); + } + } + + private static void list(Path path, boolean verbose ) throws IOException { + if (!"/".equals(path.toString())) { + System.out.printf(" %s%n", path.toString()); + if (verbose) + System.out.println(Files.readAttributes(path, BasicFileAttributes.class).toString()); + } + if (Files.notExists(path)) + return; + if (Files.isDirectory(path)) { + try (DirectoryStream ds = Files.newDirectoryStream(path)) { + for (Path child : ds) + list(child, verbose); + } + } + } + + @SuppressWarnings("unused") + /** + * Checks that the content of two paths are equal. + * Not used in demo, but included for demonstrational purposes. + */ + private static void checkEqual(Path src, Path dst) throws IOException + { + //System.out.printf("checking <%s> vs <%s>...%n", + // src.toString(), dst.toString()); + + //streams + byte[] bufSrc = new byte[8192]; + byte[] bufDst = new byte[8192]; + try (InputStream isSrc = Files.newInputStream(src); + InputStream isDst = Files.newInputStream(dst)) + { + int nSrc = 0; + while ((nSrc = isSrc.read(bufSrc)) != -1) { + int nDst = 0; + while (nDst < nSrc) { + int n = isDst.read(bufDst, nDst, nSrc - nDst); + if (n == -1) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + nDst += n; + } + while (--nSrc >= 0) { + if (bufSrc[nSrc] != bufDst[nSrc]) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + nSrc--; + } + } + } + + // channels + + try (SeekableByteChannel chSrc = Files.newByteChannel(src); + SeekableByteChannel chDst = Files.newByteChannel(dst)) + { + if (chSrc.size() != chDst.size()) { + System.out.printf("src[%s].size=%d, dst[%s].size=%d%n", + chSrc.toString(), chSrc.size(), + chDst.toString(), chDst.size()); + throw new RuntimeException("CHECK FAILED!"); + } + ByteBuffer bbSrc = ByteBuffer.allocate(8192); + ByteBuffer bbDst = ByteBuffer.allocate(8192); + + int nSrc = 0; + while ((nSrc = chSrc.read(bbSrc)) != -1) { + int nDst = chDst.read(bbDst); + if (nSrc != nDst) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + while (--nSrc >= 0) { + if (bbSrc.get(nSrc) != bbDst.get(nSrc)) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + nSrc--; + } + bbSrc.flip(); + bbDst.flip(); + } + } catch (IOException x) { + x.printStackTrace(); + } + } + + private static void fchCopy(Path src, Path dst) throws IOException + { + Set read = new HashSet<>(); + read.add(READ); + Set openwrite = new HashSet<>(); + openwrite.add(CREATE_NEW); + openwrite.add(WRITE); + + try (FileChannel srcFc = src.getFileSystem().provider().newFileChannel(src, read); + FileChannel dstFc = dst.getFileSystem().provider().newFileChannel(dst, openwrite)) + { + ByteBuffer bb = ByteBuffer.allocate(8192); + while (srcFc.read(bb) >= 0) { + bb.flip(); + dstFc.write(bb); + bb.clear(); + } + } + } + + private static void chCopy(Path src, Path dst) throws IOException + { + Set read = new HashSet<>(); + read.add(READ); + Set openwrite = new HashSet<>(); + openwrite.add(CREATE_NEW); + openwrite.add(WRITE); + + try (SeekableByteChannel srcCh = Files.newByteChannel(src, read); + SeekableByteChannel dstCh = Files.newByteChannel(dst, openwrite)) + { + ByteBuffer bb = ByteBuffer.allocate(8192); + while (srcCh.read(bb) >= 0) { + bb.flip(); + dstCh.write(bb); + bb.clear(); + } + } + } + + private static void streamCopy(Path src, Path dst) throws IOException + { + byte[] buf = new byte[8192]; + try (InputStream isSrc = Files.newInputStream(src); + OutputStream osDst = Files.newOutputStream(dst)) + { + int n = 0; + while ((n = isSrc.read(buf)) != -1) { + osDst.write(buf, 0, n); + } + } + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/jdk/nio/zipfs/PathOps.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/nio/zipfs/PathOps.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.file.*; +import java.net.*; +import java.util.*; +import java.io.IOException; + +/** + * + * @test + * @bug 8038500 + * @summary Tests path operations for zip provider. + */ + +public class PathOps { + + static final java.io.PrintStream out = System.out; + static FileSystem fs; + + private String input; + private Path path; + private Exception exc; + + private PathOps(String s) { + out.println(); + input = s; + try { + path = fs.getPath(s); + out.format("%s -> %s", s, path); + } catch (Exception x) { + exc = x; + out.format("%s -> %s", s, x); + } + out.println(); + } + + Path path() { + return path; + } + + void fail() { + throw new RuntimeException("PathOps failed"); + } + + void checkPath() { + if (path == null) { + throw new InternalError("path is null"); + } + } + + void check(Object result, String expected) { + out.format("\tExpected: %s\n", expected); + out.format("\tActual: %s\n", result); + if (result == null) { + if (expected == null) return; + } else { + // compare string representations + if (expected != null && result.toString().equals(expected.toString())) + return; + } + fail(); + } + + void check(Object result, boolean expected) { + check(result, Boolean.toString(expected)); + } + + PathOps root(String expected) { + out.println("check root"); + checkPath(); + check(path.getRoot(), expected); + return this; + } + + PathOps parent(String expected) { + out.println("check parent"); + checkPath(); + check(path.getParent(), expected); + return this; + } + + PathOps name(String expected) { + out.println("check name"); + checkPath(); + check(path.getFileName(), expected); + return this; + } + + PathOps element(int index, String expected) { + out.format("check element %d\n", index); + checkPath(); + check(path.getName(index), expected); + return this; + } + + PathOps subpath(int startIndex, int endIndex, String expected) { + out.format("test subpath(%d,%d)\n", startIndex, endIndex); + checkPath(); + check(path.subpath(startIndex, endIndex), expected); + return this; + } + + PathOps starts(String prefix) { + out.format("test startsWith with %s\n", prefix); + checkPath(); + Path s = fs.getPath(prefix); + check(path.startsWith(s), true); + return this; + } + + PathOps notStarts(String prefix) { + out.format("test not startsWith with %s\n", prefix); + checkPath(); + Path s = fs.getPath(prefix); + check(path.startsWith(s), false); + return this; + } + + PathOps ends(String suffix) { + out.format("test endsWith %s\n", suffix); + checkPath(); + Path s = fs.getPath(suffix); + check(path.endsWith(s), true); + return this; + } + + PathOps notEnds(String suffix) { + out.format("test not endsWith %s\n", suffix); + checkPath(); + Path s = fs.getPath(suffix); + check(path.endsWith(s), false); + return this; + } + + PathOps absolute() { + out.println("check path is absolute"); + checkPath(); + check(path.isAbsolute(), true); + return this; + } + + PathOps notAbsolute() { + out.println("check path is not absolute"); + checkPath(); + check(path.isAbsolute(), false); + return this; + } + + PathOps resolve(String other, String expected) { + out.format("test resolve %s\n", other); + checkPath(); + check(path.resolve(other), expected); + return this; + } + + PathOps relativize(String other, String expected) { + out.format("test relativize %s\n", other); + checkPath(); + Path that = fs.getPath(other); + check(path.relativize(that), expected); + return this; + } + + PathOps normalize(String expected) { + out.println("check normalized path"); + checkPath(); + check(path.normalize(), expected); + return this; + } + + PathOps string(String expected) { + out.println("check string representation"); + checkPath(); + check(path, expected); + return this; + } + + PathOps isSameFile(String target) { + try { + out.println("check two paths are same"); + checkPath(); + check(Files.isSameFile(path, test(target).path()), true); + } catch (IOException ioe) { + fail(); + } + return this; + } + + PathOps invalid() { + if (!(exc instanceof InvalidPathException)) { + out.println("InvalidPathException not thrown as expected"); + fail(); + } + return this; + } + + static PathOps test(String s) { + return new PathOps(s); + } + + // -- PathOpss -- + + static void header(String s) { + out.println(); + out.println(); + out.println("-- " + s + " --"); + } + + static void doPathOpTests() { + header("Path operations"); + + // all components + test("/a/b/c") + .root("/") + .parent("/a/b") + .name("c"); + + // root component only + test("/") + .root("/") + .parent(null) + .name(null); + + // no root component + test("a/b") + .root(null) + .parent("a") + .name("b"); + + // name component only + test("foo") + .root(null) + .parent(null) + .name("foo"); + + // startsWith + test("") + .starts("") + .notStarts("/"); + test("/") + .starts("/") + .notStarts("/foo"); + test("/foo") + .starts("/") + .starts("/foo") + .notStarts("/f") + .notStarts(""); + test("/foo/bar") + .starts("/") + .starts("/foo") + .starts("/foo/") + .starts("/foo/bar") + .notStarts("/f") + .notStarts("foo") + .notStarts("foo/bar") + .notStarts(""); + test("foo") + .starts("foo") + .notStarts("f"); + test("foo/bar") + .starts("foo") + .starts("foo/") + .starts("foo/bar") + .notStarts("f") + .notStarts("/foo") + .notStarts("/foo/bar"); + + // endsWith + test("") + .ends("") + .notEnds("/"); + test("/") + .ends("/") + .notEnds("foo") + .notEnds("/foo"); + test("/foo") + .ends("foo") + .ends("/foo") + .notEnds("/"); + test("/foo/bar") + .ends("bar") + .ends("foo/bar") + .ends("foo/bar/") + .ends("/foo/bar") + .notEnds("/bar"); + test("/foo/bar/") + .ends("bar") + .ends("foo/bar") + .ends("foo/bar/") + .ends("/foo/bar") + .notEnds("/bar"); + test("foo") + .ends("foo"); + test("foo/bar") + .ends("bar") + .ends("bar/") + .ends("foo/bar/") + .ends("foo/bar"); + + + // elements + test("a/b/c") + .element(0,"a") + .element(1,"b") + .element(2,"c"); + + // isAbsolute + test("/") + .absolute(); + test("/tmp") + .absolute(); + test("tmp") + .notAbsolute(); + test("") + .notAbsolute(); + + // resolve + test("/tmp") + .resolve("foo", "/tmp/foo") + .resolve("/foo", "/foo"); + test("tmp") + .resolve("foo", "tmp/foo") + .resolve("/foo", "/foo"); + + // relativize + test("/a/b/c") + .relativize("/a/b/c", "") + .relativize("/a/b/c/d/e", "d/e") + .relativize("/a/x", "../../x"); + + // normalize + test("/") + .normalize("/"); + test("foo") + .normalize("foo"); + test("/foo") + .normalize("/foo"); + test(".") + .normalize(""); + test("..") + .normalize(".."); + test("/..") + .normalize("/"); + test("/../..") + .normalize("/"); + test("foo/.") + .normalize("foo"); + test("./foo") + .normalize("foo"); + test("foo/..") + .normalize(""); + test("../foo") + .normalize("../foo"); + test("../../foo") + .normalize("../../foo"); + test("foo/bar/..") + .normalize("foo"); + test("foo/bar/gus/../..") + .normalize("foo"); + test("/foo/bar/gus/../..") + .normalize("/foo"); + test("/./.") + .normalize("/"); + test("/.") + .normalize("/"); + test("/./abc") + .normalize("/abc"); + // invalid + test("foo\u0000bar") + .invalid(); + test("\u0000foo") + .invalid(); + test("bar\u0000") + .invalid(); + test("//foo\u0000bar") + .invalid(); + test("//\u0000foo") + .invalid(); + test("//bar\u0000") + .invalid(); + + // normalization + test("//foo//bar") + .string("/foo/bar") + .root("/") + .parent("/foo") + .name("bar"); + + // isSameFile + test("/fileDoesNotExist") + .isSameFile("/fileDoesNotExist"); + } + + static void npes() { + header("NullPointerException"); + + Path path = fs.getPath("foo"); + + try { + path.resolve((String)null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + try { + path.relativize(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + try { + path.compareTo(null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + try { + path.startsWith((Path)null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + try { + path.endsWith((Path)null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } + + } + + public static void main(String[] args) throws Throwable { + Path zipfile = Paths.get(System.getProperty("test.jdk"), + "jre/lib/ext/zipfs.jar"); + fs = FileSystems.newFileSystem(zipfile, null); + npes(); + doPathOpTests(); + fs.close(); + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/jdk/nio/zipfs/ZFSTests.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/nio/zipfs/ZFSTests.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 7156873 + @summary ZipFileSystem regression tests + */ + + +import java.net.URI; +import java.nio.file.*; +import java.util.Map; +import java.util.HashMap; + +public class ZFSTests { + + public static void main(String[] args) throws Throwable { + test7156873(); + } + + static void test7156873() throws Throwable { + String DIRWITHSPACE = "testdir with spaces"; + Path dir = Paths.get(DIRWITHSPACE); + Path path = Paths.get(DIRWITHSPACE, "file.zip"); + try { + Files.createDirectory(dir); + URI uri = URI.create("jar:" + path.toUri()); + Map env = new HashMap(); + env.put("create", "true"); + try (FileSystem fs = FileSystems.newFileSystem(uri, env)) {} + } finally { + Files.deleteIfExists(path); + Files.deleteIfExists(dir); + } + } +} diff -r 971bf0a51f75 -r 956d11daac9d jdk/test/jdk/nio/zipfs/ZipFSTester.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/jdk/nio/zipfs/ZipFSTester.java Wed Apr 16 10:53:10 2014 -0700 @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import java.nio.file.*; +import java.nio.file.spi.*; +import java.nio.file.attribute.*; +import java.net.*; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.zip.*; + +import static java.nio.file.StandardOpenOption.*; +import static java.nio.file.StandardCopyOption.*; + +/* + * Tests various zipfs operations. + * + * @test + * @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596 + * 7157656 8002390 7012868 7012856 8015728 8038500 + * @summary Test Zip filesystem provider + */ + +public class ZipFSTester { + + public static void main(String[] args) throws Throwable { + try (FileSystem fs = newZipFileSystem( + Paths.get(System.getProperty("test.jdk"), "jre/lib/ext/zipfs.jar"), + new HashMap())) + { + test0(fs); + test1(fs); + test2(fs); // more tests + } + testTime(Paths.get(System.getProperty("test.jdk"), "jre/lib/ext/zipfs.jar")); + } + + static void test0(FileSystem fs) + throws Exception + { + List list = new LinkedList<>(); + try (ZipFile zf = new ZipFile(fs.toString())) { + Enumeration zes = zf.entries(); + while (zes.hasMoreElements()) { + list.add(zes.nextElement().getName()); + } + for (String pname : list) { + Path path = fs.getPath(pname); + if (!Files.exists(path)) + throw new RuntimeException("path existence check failed!"); + while ((path = path.getParent()) != null) { + if (!Files.exists(path)) + throw new RuntimeException("parent existence check failed!"); + } + } + } + } + + static void test1(FileSystem fs0) + throws Exception + { + Random rdm = new Random(); + // clone a fs and test on it + Path tmpfsPath = getTempPath(); + Map env = new HashMap(); + env.put("create", "true"); + try (FileSystem copy = newZipFileSystem(tmpfsPath, env)) { + z2zcopy(fs0, copy, "/", 0); + } + + try (FileSystem fs = newZipFileSystem(tmpfsPath, new HashMap())) { + + FileSystemProvider provider = fs.provider(); + // newFileSystem(path...) should not throw exception + try (FileSystem fsPath = provider.newFileSystem(tmpfsPath, new HashMap())){} + try (FileSystem fsUri = provider.newFileSystem( + new URI("jar", tmpfsPath.toUri().toString(), null), + new HashMap())) + { + throw new RuntimeException("newFileSystem(uri...) does not throw exception"); + } catch (FileSystemAlreadyExistsException fsaee) {} + + // prepare a src + Path src = getTempPath(); + String tmpName = src.toString(); + OutputStream os = Files.newOutputStream(src); + byte[] bits = new byte[12345]; + rdm.nextBytes(bits); + os.write(bits); + os.close(); + + try { + provider.newFileSystem(new File(System.getProperty("test.src", ".")).toPath(), + new HashMap()); + throw new RuntimeException("newFileSystem() opens a directory as zipfs"); + } catch (UnsupportedOperationException uoe) {} + + try { + provider.newFileSystem(src, new HashMap()); + throw new RuntimeException("newFileSystem() opens a non-zip file as zipfs"); + } catch (UnsupportedOperationException uoe) {} + + + // copyin + Path dst = getPathWithParents(fs, tmpName); + Files.copy(src, dst); + checkEqual(src, dst); + + // copy + Path dst2 = getPathWithParents(fs, "/xyz" + rdm.nextInt(100) + + "/efg" + rdm.nextInt(100) + "/foo.class"); + Files.copy(dst, dst2); + //dst.moveTo(dst2); + checkEqual(src, dst2); + + // delete + Files.delete(dst); + if (Files.exists(dst)) + throw new RuntimeException("Failed!"); + + // moveout + Path dst3 = Paths.get(tmpName + "_Tmp"); + Files.move(dst2, dst3); + checkEqual(src, dst3); + if (Files.exists(dst2)) + throw new RuntimeException("Failed!"); + + // copyback + move + Files.copy(dst3, dst); + Path dst4 = getPathWithParents(fs, tmpName + "_Tmp0"); + Files.move(dst, dst4); + checkEqual(src, dst4); + + // delete + Files.delete(dst4); + if (Files.exists(dst4)) + throw new RuntimeException("Failed!"); + Files.delete(dst3); + if (Files.exists(dst3)) + throw new RuntimeException("Failed!"); + + // move (existing entry) + Path dst5 = fs.getPath("META-INF/MANIFEST.MF"); + if (Files.exists(dst5)) { + Path dst6 = fs.getPath("META-INF/MANIFEST.MF_TMP"); + Files.move(dst5, dst6); + walk(fs.getPath("/")); + } + + // newInputStream on dir + Path parent = dst2.getParent(); + try { + Files.newInputStream(parent); + throw new RuntimeException("Failed"); + } catch (FileSystemException e) { + e.printStackTrace(); // expected fse + } + + // rmdirs + try { + rmdirs(parent); + } catch (IOException x) { + x.printStackTrace(); + } + + // newFileChannel() copy in, out and verify via fch + fchCopy(src, dst); // in + checkEqual(src, dst); + Path tmp = Paths.get(tmpName + "_Tmp"); + fchCopy(dst, tmp); // out + checkEqual(src, tmp); + Files.delete(tmp); + + // test channels + channel(fs, dst); + Files.delete(dst); + Files.delete(src); + } finally { + if (Files.exists(tmpfsPath)) + Files.delete(tmpfsPath); + } + } + + static void test2(FileSystem fs) throws Exception { + + Path fs1Path = getTempPath(); + Path fs2Path = getTempPath(); + Path fs3Path = getTempPath(); + + // create a new filesystem, copy everything from fs + Map env = new HashMap(); + env.put("create", "true"); + FileSystem fs0 = newZipFileSystem(fs1Path, env); + + final FileSystem fs2 = newZipFileSystem(fs2Path, env); + final FileSystem fs3 = newZipFileSystem(fs3Path, env); + + System.out.println("copy src: fs -> fs0..."); + z2zcopy(fs, fs0, "/", 0); // copy fs -> fs1 + fs0.close(); // dump to file + + System.out.println("open fs0 as fs1"); + env = new HashMap(); + final FileSystem fs1 = newZipFileSystem(fs1Path, env); + + System.out.println("listing..."); + final ArrayList files = new ArrayList<>(); + final ArrayList dirs = new ArrayList<>(); + list(fs1.getPath("/"), files, dirs); + + Thread t0 = new Thread(new Runnable() { + public void run() { + List list = new ArrayList<>(dirs); + Collections.shuffle(list); + for (String path : list) { + try { + z2zcopy(fs1, fs2, path, 0); + } catch (Exception x) { + x.printStackTrace(); + } + } + } + + }); + + Thread t1 = new Thread(new Runnable() { + public void run() { + List list = new ArrayList<>(dirs); + Collections.shuffle(list); + for (String path : list) { + try { + z2zcopy(fs1, fs2, path, 1); + } catch (Exception x) { + x.printStackTrace(); + } + } + } + + }); + + Thread t2 = new Thread(new Runnable() { + public void run() { + List list = new ArrayList<>(dirs); + Collections.shuffle(list); + for (String path : list) { + try { + z2zcopy(fs1, fs2, path, 2); + } catch (Exception x) { + x.printStackTrace(); + } + } + } + + }); + + Thread t3 = new Thread(new Runnable() { + public void run() { + List list = new ArrayList<>(files); + Collections.shuffle(list); + while (!list.isEmpty()) { + Iterator itr = list.iterator(); + while (itr.hasNext()) { + String path = itr.next(); + try { + if (Files.exists(fs2.getPath(path))) { + z2zmove(fs2, fs3, path); + itr.remove(); + } + } catch (FileAlreadyExistsException x){ + itr.remove(); + } catch (Exception x) { + x.printStackTrace(); + } + } + } + } + + }); + + System.out.println("copying/removing..."); + t0.start(); t1.start(); t2.start(); t3.start(); + t0.join(); t1.join(); t2.join(); t3.join(); + + System.out.println("closing: fs1, fs2"); + fs1.close(); + fs2.close(); + + int failed = 0; + System.out.println("checkEqual: fs vs fs3"); + for (String path : files) { + try { + checkEqual(fs.getPath(path), fs3.getPath(path)); + } catch (IOException x) { + //x.printStackTrace(); + failed++; + } + } + System.out.println("closing: fs3"); + fs3.close(); + + System.out.println("opening: fs3 as fs4"); + FileSystem fs4 = newZipFileSystem(fs3Path, env); + + + ArrayList files2 = new ArrayList<>(); + ArrayList dirs2 = new ArrayList<>(); + list(fs4.getPath("/"), files2, dirs2); + + System.out.println("checkEqual: fs vs fs4"); + for (String path : files2) { + checkEqual(fs.getPath(path), fs4.getPath(path)); + } + System.out.println("walking: fs4"); + walk(fs4.getPath("/")); + System.out.println("closing: fs4"); + fs4.close(); + System.out.printf("failed=%d%n", failed); + + Files.delete(fs1Path); + Files.delete(fs2Path); + Files.delete(fs3Path); + } + + // test file stamp + static void testTime(Path src) throws Exception { + BasicFileAttributes attrs = Files + .getFileAttributeView(src, BasicFileAttributeView.class) + .readAttributes(); + // create a new filesystem, copy this file into it + Map env = new HashMap(); + env.put("create", "true"); + Path fsPath = getTempPath(); + FileSystem fs = newZipFileSystem(fsPath, env); + + System.out.println("test copy with timestamps..."); + // copyin + Path dst = getPathWithParents(fs, "me"); + Files.copy(src, dst, COPY_ATTRIBUTES); + checkEqual(src, dst); + System.out.println("mtime: " + attrs.lastModifiedTime()); + System.out.println("ctime: " + attrs.creationTime()); + System.out.println("atime: " + attrs.lastAccessTime()); + System.out.println(" ==============>"); + BasicFileAttributes dstAttrs = Files + .getFileAttributeView(dst, BasicFileAttributeView.class) + .readAttributes(); + System.out.println("mtime: " + dstAttrs.lastModifiedTime()); + System.out.println("ctime: " + dstAttrs.creationTime()); + System.out.println("atime: " + dstAttrs.lastAccessTime()); + + // 1-second granularity + if (attrs.lastModifiedTime().to(TimeUnit.SECONDS) != + dstAttrs.lastModifiedTime().to(TimeUnit.SECONDS) || + attrs.lastAccessTime().to(TimeUnit.SECONDS) != + dstAttrs.lastAccessTime().to(TimeUnit.SECONDS) || + attrs.creationTime().to(TimeUnit.SECONDS) != + dstAttrs.creationTime().to(TimeUnit.SECONDS)) { + throw new RuntimeException("Timestamp Copy Failed!"); + } + Files.delete(fsPath); + } + + private static FileSystem newZipFileSystem(Path path, Map env) + throws Exception + { + return FileSystems.newFileSystem( + new URI("jar", path.toUri().toString(), null), env, null); + } + + private static Path getTempPath() throws IOException + { + File tmp = File.createTempFile("testzipfs_", "zip"); + tmp.delete(); // we need a clean path, no file + return tmp.toPath(); + } + + private static void list(Path path, List files, List dirs ) + throws IOException + { + if (Files.isDirectory(path)) { + try (DirectoryStream ds = Files.newDirectoryStream(path)) { + for (Path child : ds) + list(child, files, dirs); + } + dirs.add(path.toString()); + } else { + files.add(path.toString()); + } + } + + private static void z2zcopy(FileSystem src, FileSystem dst, String path, + int method) + throws IOException + { + Path srcPath = src.getPath(path); + Path dstPath = dst.getPath(path); + + if (Files.isDirectory(srcPath)) { + if (!Files.exists(dstPath)) { + try { + mkdirs(dstPath); + } catch (FileAlreadyExistsException x) {} + } + try (DirectoryStream ds = Files.newDirectoryStream(srcPath)) { + for (Path child : ds) { + z2zcopy(src, dst, + path + (path.endsWith("/")?"":"/") + child.getFileName(), + method); + } + } + } else { + try { + if (Files.exists(dstPath)) + return; + switch (method) { + case 0: + Files.copy(srcPath, dstPath); + break; + case 1: + chCopy(srcPath, dstPath); + break; + case 2: + //fchCopy(srcPath, dstPath); + streamCopy(srcPath, dstPath); + break; + } + } catch (FileAlreadyExistsException x) {} + } + } + + private static void z2zmove(FileSystem src, FileSystem dst, String path) + throws IOException + { + Path srcPath = src.getPath(path); + Path dstPath = dst.getPath(path); + + if (Files.isDirectory(srcPath)) { + if (!Files.exists(dstPath)) + mkdirs(dstPath); + try (DirectoryStream ds = Files.newDirectoryStream(srcPath)) { + for (Path child : ds) { + z2zmove(src, dst, + path + (path.endsWith("/")?"":"/") + child.getFileName()); + } + } + } else { + //System.out.println("moving..." + path); + Path parent = dstPath.getParent(); + if (parent != null && Files.notExists(parent)) + mkdirs(parent); + Files.move(srcPath, dstPath); + } + } + + private static void walk(Path path) throws IOException + { + Files.walkFileTree( + path, + new SimpleFileVisitor() { + private int indent = 0; + private void indent() { + int n = 0; + while (n++ < indent) + System.out.printf(" "); + } + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) + { + indent(); + System.out.printf("%s%n", file.getFileName().toString()); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, + BasicFileAttributes attrs) + { + indent(); + System.out.printf("[%s]%n", dir.toString()); + indent += 2; + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, + IOException ioe) + throws IOException + { + indent -= 2; + return FileVisitResult.CONTINUE; + } + }); + } + + private static void mkdirs(Path path) throws IOException { + if (Files.exists(path)) + return; + path = path.toAbsolutePath(); + Path parent = path.getParent(); + if (parent != null) { + if (Files.notExists(parent)) + mkdirs(parent); + } + Files.createDirectory(path); + } + + private static void rmdirs(Path path) throws IOException { + while (path != null && path.getNameCount() != 0) { + Files.delete(path); + path = path.getParent(); + } + } + + // check the content of two paths are equal + private static void checkEqual(Path src, Path dst) throws IOException + { + //System.out.printf("checking <%s> vs <%s>...%n", + // src.toString(), dst.toString()); + + //streams + byte[] bufSrc = new byte[8192]; + byte[] bufDst = new byte[8192]; + try (InputStream isSrc = Files.newInputStream(src); + InputStream isDst = Files.newInputStream(dst)) + { + int nSrc = 0; + while ((nSrc = isSrc.read(bufSrc)) != -1) { + int nDst = 0; + while (nDst < nSrc) { + int n = isDst.read(bufDst, nDst, nSrc - nDst); + if (n == -1) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + nDst += n; + } + while (--nSrc >= 0) { + if (bufSrc[nSrc] != bufDst[nSrc]) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + nSrc--; + } + } + } + + // channels + try (SeekableByteChannel chSrc = Files.newByteChannel(src); + SeekableByteChannel chDst = Files.newByteChannel(dst)) + { + if (chSrc.size() != chDst.size()) { + System.out.printf("src[%s].size=%d, dst[%s].size=%d%n", + chSrc.toString(), chSrc.size(), + chDst.toString(), chDst.size()); + throw new RuntimeException("CHECK FAILED!"); + } + ByteBuffer bbSrc = ByteBuffer.allocate(8192); + ByteBuffer bbDst = ByteBuffer.allocate(8192); + + int nSrc = 0; + while ((nSrc = chSrc.read(bbSrc)) != -1) { + int nDst = chDst.read(bbDst); + if (nSrc != nDst) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + while (--nSrc >= 0) { + if (bbSrc.get(nSrc) != bbDst.get(nSrc)) { + System.out.printf("checking <%s> vs <%s>...%n", + src.toString(), dst.toString()); + throw new RuntimeException("CHECK FAILED!"); + } + nSrc--; + } + bbSrc.flip(); + bbDst.flip(); + } + + // Check if source read position is at the end + if (chSrc.position() != chSrc.size()) { + System.out.printf("src[%s]: size=%d, position=%d%n", + chSrc.toString(), chSrc.size(), chSrc.position()); + throw new RuntimeException("CHECK FAILED!"); + } + + // Check if destination read position is at the end + if (chDst.position() != chDst.size()) { + System.out.printf("dst[%s]: size=%d, position=%d%n", + chDst.toString(), chDst.size(), chDst.position()); + throw new RuntimeException("CHECK FAILED!"); + } + } catch (IOException x) { + x.printStackTrace(); + } + } + + private static void fchCopy(Path src, Path dst) throws IOException + { + Set read = new HashSet<>(); + read.add(READ); + Set openwrite = new HashSet<>(); + openwrite.add(CREATE_NEW); + openwrite.add(WRITE); + + try (FileChannel srcFc = src.getFileSystem() + .provider() + .newFileChannel(src, read); + FileChannel dstFc = dst.getFileSystem() + .provider() + .newFileChannel(dst, openwrite)) + { + ByteBuffer bb = ByteBuffer.allocate(8192); + while (srcFc.read(bb) >= 0) { + bb.flip(); + dstFc.write(bb); + bb.clear(); + } + } + } + + private static void chCopy(Path src, Path dst) throws IOException + { + Set read = new HashSet<>(); + read.add(READ); + Set openwrite = new HashSet<>(); + openwrite.add(CREATE_NEW); + openwrite.add(WRITE); + + try (SeekableByteChannel srcCh = Files.newByteChannel(src, read); + SeekableByteChannel dstCh = Files.newByteChannel(dst, openwrite)) + { + + ByteBuffer bb = ByteBuffer.allocate(8192); + while (srcCh.read(bb) >= 0) { + bb.flip(); + dstCh.write(bb); + bb.clear(); + } + + // Check if source read position is at the end + if (srcCh.position() != srcCh.size()) { + System.out.printf("src[%s]: size=%d, position=%d%n", + srcCh.toString(), srcCh.size(), srcCh.position()); + throw new RuntimeException("CHECK FAILED!"); + } + + // Check if destination write position is at the end + if (dstCh.position() != dstCh.size()) { + System.out.printf("dst[%s]: size=%d, position=%d%n", + dstCh.toString(), dstCh.size(), dstCh.position()); + throw new RuntimeException("CHECK FAILED!"); + } + } + } + + private static void streamCopy(Path src, Path dst) throws IOException + { + byte[] buf = new byte[8192]; + try (InputStream isSrc = Files.newInputStream(src); + OutputStream osDst = Files.newOutputStream(dst)) + { + int n = 0; + while ((n = isSrc.read(buf)) != -1) { + osDst.write(buf, 0, n); + } + } + } + + static void channel(FileSystem fs, Path path) + throws Exception + { + System.out.println("test ByteChannel..."); + Set read = new HashSet<>(); + read.add(READ); + int n = 0; + ByteBuffer bb = null; + ByteBuffer bb2 = null; + int N = 120; + + try (SeekableByteChannel sbc = Files.newByteChannel(path)) { + System.out.printf(" sbc[0]: pos=%d, size=%d%n", sbc.position(), sbc.size()); + if (sbc.position() != 0) { + throw new RuntimeException("CHECK FAILED!"); + } + + bb = ByteBuffer.allocate((int)sbc.size()); + n = sbc.read(bb); + System.out.printf(" sbc[1]: read=%d, pos=%d, size=%d%n", + n, sbc.position(), sbc.size()); + if (sbc.position() != sbc.size()) { + throw new RuntimeException("CHECK FAILED!"); + } + bb2 = ByteBuffer.allocate((int)sbc.size()); + } + + // sbc.position(pos) is not supported in current version + // try the FileChannel + try (SeekableByteChannel sbc = fs.provider().newFileChannel(path, read)) { + sbc.position(N); + System.out.printf(" sbc[2]: pos=%d, size=%d%n", + sbc.position(), sbc.size()); + if (sbc.position() != N) { + throw new RuntimeException("CHECK FAILED!"); + } + bb2.limit(100); + n = sbc.read(bb2); + System.out.printf(" sbc[3]: read=%d, pos=%d, size=%d%n", + n, sbc.position(), sbc.size()); + if (n < 0 || sbc.position() != (N + n)) { + throw new RuntimeException("CHECK FAILED!"); + } + System.out.printf(" sbc[4]: bb[%d]=%d, bb1[0]=%d%n", + N, bb.get(N) & 0xff, bb2.get(0) & 0xff); + } + } + + // create parents if does not exist + static Path getPathWithParents(FileSystem fs, String name) + throws Exception + { + Path path = fs.getPath(name); + Path parent = path.getParent(); + if (parent != null && Files.notExists(parent)) + mkdirs(parent); + return path; + } +}