type, String name, int args) {
- for (Method method : type.getMethods()) {
- if (method.getName().equals(name) && (args == method.getParameterTypes().length)) {
- try {
- return MethodFinder.findAccessibleMethod(method);
+ /**
+ * Internal support for finding a target methodName with a given
+ * parameter list on a given class.
+ */
+ private static Method internalFindMethod(Class start, String methodName,
+ int argCount, Class args[]) {
+ // For overriden methods we need to find the most derived version.
+ // So we start with the given class and walk up the superclass chain.
+
+ Method method = null;
+
+ for (Class cl = start; cl != null; cl = cl.getSuperclass()) {
+ Method methods[] = getPublicDeclaredMethods(cl);
+ for (int i = 0; i < methods.length; i++) {
+ method = methods[i];
+ if (method == null) {
+ continue;
}
- catch (NoSuchMethodException exception) {
- // continue search for a method with the specified count of parameters
+
+ // make sure method signature matches.
+ Class params[] = FeatureDescriptor.getParameterTypes(start, method);
+ if (method.getName().equals(methodName) &&
+ params.length == argCount) {
+ if (args != null) {
+ boolean different = false;
+ if (argCount > 0) {
+ for (int j = 0; j < argCount; j++) {
+ if (params[j] != args[j]) {
+ different = true;
+ continue;
+ }
+ }
+ if (different) {
+ continue;
+ }
+ }
+ }
+ return method;
}
}
}
- return null;
+ method = null;
+
+ // Now check any inherited interfaces. This is necessary both when
+ // the argument class is itself an interface, and when the argument
+ // class is an abstract class.
+ Class ifcs[] = start.getInterfaces();
+ for (int i = 0 ; i < ifcs.length; i++) {
+ // Note: The original implementation had both methods calling
+ // the 3 arg method. This is preserved but perhaps it should
+ // pass the args array instead of null.
+ method = internalFindMethod(ifcs[i], methodName, argCount, null);
+ if (method != null) {
+ break;
+ }
+ }
+ return method;
}
- static Method findInstanceMethod(Class> type, String name, Class>... args) {
- try {
- return MethodFinder.findInstanceMethod(type, name, args);
- }
- catch (NoSuchMethodException exception) {
+ /**
+ * Find a target methodName on a given class.
+ */
+ static Method findMethod(Class cls, String methodName, int argCount) {
+ return findMethod(cls, methodName, argCount, null);
+ }
+
+ /**
+ * Find a target methodName with specific parameter list on a given class.
+ *
+ * Used in the contructors of the EventSetDescriptor,
+ * PropertyDescriptor and the IndexedPropertyDescriptor.
+ *
+ * @param cls The Class object on which to retrieve the method.
+ * @param methodName Name of the method.
+ * @param argCount Number of arguments for the desired method.
+ * @param args Array of argument types for the method.
+ * @return the method or null if not found
+ */
+ static Method findMethod(Class cls, String methodName, int argCount,
+ Class args[]) {
+ if (methodName == null) {
return null;
}
+ return internalFindMethod(cls, methodName, argCount, args);
}
/**
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/java/beans/MethodDescriptor.java
--- a/jdk/src/share/classes/java/beans/MethodDescriptor.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/java/beans/MethodDescriptor.java Wed Oct 13 17:51:41 2010 -0700
@@ -90,13 +90,13 @@
// Find methods for up to 2 params. We are guessing here.
// This block should never execute unless the classloader
// that loaded the argument classes disappears.
- method = Introspector.findMethod(cls, name, i);
+ method = Introspector.findMethod(cls, name, i, null);
if (method != null) {
break;
}
}
} else {
- method = Statement.getMethod(cls, name, params);
+ method = Introspector.findMethod(cls, name, params.length, params);
}
setMethod(method);
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/java/beans/PropertyDescriptor.java
--- a/jdk/src/share/classes/java/beans/PropertyDescriptor.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/java/beans/PropertyDescriptor.java Wed Oct 13 17:51:41 2010 -0700
@@ -112,7 +112,8 @@
// If this class or one of its base classes allow PropertyChangeListener,
// then we assume that any properties we discover are "bound".
// See Introspector.getTargetPropertyInfo() method.
- this.bound = null != Introspector.findInstanceMethod(beanClass, "addPropertyChangeListener", PropertyChangeListener.class);
+ Class[] args = { PropertyChangeListener.class };
+ this.bound = null != Introspector.findMethod(beanClass, "addPropertyChangeListener", args.length, args);
}
/**
@@ -223,10 +224,10 @@
// property type is. For booleans, there can be "is" and "get"
// methods. If an "is" method exists, this is the official
// reader method so look for this one first.
- readMethod = Introspector.findInstanceMethod(cls, readMethodName);
+ readMethod = Introspector.findMethod(cls, readMethodName, 0);
if (readMethod == null) {
readMethodName = Introspector.GET_PREFIX + getBaseName();
- readMethod = Introspector.findInstanceMethod(cls, readMethodName);
+ readMethod = Introspector.findMethod(cls, readMethodName, 0);
}
try {
setReadMethod(readMethod);
@@ -291,7 +292,8 @@
writeMethodName = Introspector.SET_PREFIX + getBaseName();
}
- writeMethod = Introspector.findInstanceMethod(cls, writeMethodName, type);
+ Class[] args = (type == null) ? null : new Class[] { type };
+ writeMethod = Introspector.findMethod(cls, writeMethodName, 1, args);
if (writeMethod != null) {
if (!writeMethod.getReturnType().equals(void.class)) {
writeMethod = null;
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/java/util/Locale.java
--- a/jdk/src/share/classes/java/util/Locale.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/java/util/Locale.java Wed Oct 13 17:51:41 2010 -0700
@@ -569,6 +569,9 @@
* @exception NullPointerException thrown if any argument is null.
*/
public Locale(String language, String country, String variant) {
+ if (language== null || country == null || variant == null) {
+ throw new NullPointerException();
+ }
_baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant);
_extensions = getCompatibilityExtensions(language, "", country, variant);
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/java/util/ResourceBundle.java
--- a/jdk/src/share/classes/java/util/ResourceBundle.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/java/util/ResourceBundle.java Wed Oct 13 17:51:41 2010 -0700
@@ -293,16 +293,6 @@
= new ConcurrentHashMap(INITIAL_CACHE_SIZE);
/**
- * This ConcurrentMap is used to keep multiple threads from loading the
- * same bundle concurrently. The table entries are
- * where CacheKey is the key for the bundle that is under construction
- * and Thread is the thread that is constructing the bundle.
- * This list is manipulated in findBundleInCache and putBundleInCache.
- */
- private static final ConcurrentMap underConstruction
- = new ConcurrentHashMap();
-
- /**
* Queue for reference objects referring to class loaders or bundles.
*/
private static final ReferenceQueue referenceQueue = new ReferenceQueue();
@@ -1381,7 +1371,7 @@
boolean expiredBundle = false;
// First, look up the cache to see if it's in the cache, without
- // declaring beginLoading.
+ // attempting to load bundle.
cacheKey.setLocale(targetLocale);
ResourceBundle bundle = findBundleInCache(cacheKey, control);
if (isValidBundle(bundle)) {
@@ -1408,56 +1398,25 @@
CacheKey constKey = (CacheKey) cacheKey.clone();
try {
- // Try declaring loading. If beginLoading() returns true,
- // then we can proceed. Otherwise, we need to take a look
- // at the cache again to see if someone else has loaded
- // the bundle and put it in the cache while we've been
- // waiting for other loading work to complete.
- while (!beginLoading(constKey)) {
- bundle = findBundleInCache(cacheKey, control);
- if (bundle == null) {
- continue;
+ bundle = loadBundle(cacheKey, formats, control, expiredBundle);
+ if (bundle != null) {
+ if (bundle.parent == null) {
+ bundle.setParent(parent);
}
- if (bundle == NONEXISTENT_BUNDLE) {
- // If the bundle is NONEXISTENT_BUNDLE, the bundle doesn't exist.
- return parent;
- }
- expiredBundle = bundle.expired;
- if (!expiredBundle) {
- if (bundle.parent == parent) {
- return bundle;
- }
- BundleReference bundleRef = cacheList.get(cacheKey);
- if (bundleRef != null && bundleRef.get() == bundle) {
- cacheList.remove(cacheKey, bundleRef);
- }
- }
+ bundle.locale = targetLocale;
+ bundle = putBundleInCache(cacheKey, bundle, control);
+ return bundle;
}
- try {
- bundle = loadBundle(cacheKey, formats, control, expiredBundle);
- if (bundle != null) {
- if (bundle.parent == null) {
- bundle.setParent(parent);
- }
- bundle.locale = targetLocale;
- bundle = putBundleInCache(cacheKey, bundle, control);
- return bundle;
- }
-
- // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
- // instance for the locale.
- putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
- } finally {
- endLoading(constKey);
- }
+ // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
+ // instance for the locale.
+ putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
} finally {
if (constKey.getCause() instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
}
}
- assert underConstruction.get(cacheKey) != Thread.currentThread();
return parent;
}
@@ -1465,7 +1424,6 @@
List formats,
Control control,
boolean reload) {
- assert underConstruction.get(cacheKey) == Thread.currentThread();
// Here we actually load the bundle in the order of formats
// specified by the getFormats() value.
@@ -1498,7 +1456,6 @@
break;
}
}
- assert underConstruction.get(cacheKey) == Thread.currentThread();
return bundle;
}
@@ -1530,57 +1487,6 @@
}
/**
- * Declares the beginning of actual resource bundle loading. This method
- * returns true if the declaration is successful and the current thread has
- * been put in underConstruction. If someone else has already begun
- * loading, this method waits until that loading work is complete and
- * returns false.
- */
- private static final boolean beginLoading(CacheKey constKey) {
- Thread me = Thread.currentThread();
- Thread worker;
- // We need to declare by putting the current Thread (me) to
- // underConstruction that we are working on loading the specified
- // resource bundle. If we are already working the loading, it means
- // that the resource loading requires a recursive call. In that case,
- // we have to proceed. (4300693)
- if (((worker = underConstruction.putIfAbsent(constKey, me)) == null)
- || worker == me) {
- return true;
- }
-
- // If someone else is working on the loading, wait until
- // the Thread finishes the bundle loading.
- synchronized (worker) {
- while (underConstruction.get(constKey) == worker) {
- try {
- worker.wait();
- } catch (InterruptedException e) {
- // record the interruption
- constKey.setCause(e);
- }
- }
- }
- return false;
- }
-
- /**
- * Declares the end of the bundle loading. This method calls notifyAll
- * for those who are waiting for this completion.
- */
- private static final void endLoading(CacheKey constKey) {
- // Remove this Thread from the underConstruction map and wake up
- // those who have been waiting for me to complete this bundle
- // loading.
- Thread me = Thread.currentThread();
- assert (underConstruction.get(constKey) == me);
- underConstruction.remove(constKey);
- synchronized (me) {
- me.notifyAll();
- }
- }
-
- /**
* Throw a MissingResourceException with proper message
*/
private static final void throwMissingResourceException(String baseName,
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/GroupLayout.java
--- a/jdk/src/share/classes/javax/swing/GroupLayout.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/GroupLayout.java Wed Oct 13 17:51:41 2010 -0700
@@ -1464,8 +1464,8 @@
* <= {@code pref} <= {@code max}.
*
* Similarly any methods that take a {@code Component} throw a
- * {@code NullPointerException} if passed {@code null} and any methods
- * that take a {@code Group} throw an {@code IllegalArgumentException} if
+ * {@code IllegalArgumentException} if passed {@code null} and any methods
+ * that take a {@code Group} throw an {@code NullPointerException} if
* passed {@code null}.
*
* @see #createSequentialGroup
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/JComponent.java
--- a/jdk/src/share/classes/javax/swing/JComponent.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/JComponent.java Wed Oct 13 17:51:41 2010 -0700
@@ -4787,6 +4787,17 @@
* @see RepaintManager#addDirtyRegion
*/
public void repaint(long tm, int x, int y, int width, int height) {
+ Container p = this;
+ while ((p = p.getParent()) instanceof JComponent) {
+ JComponent jp = (JComponent) p;
+ if (jp.isPaintingOrigin()) {
+ Rectangle rectangle = SwingUtilities.convertRectangle(
+ this, new Rectangle(x, y, width, height), jp);
+ jp.repaint(tm,
+ rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+ return;
+ }
+ }
RepaintManager.currentManager(this).addDirtyRegion(this, x, y, width, height);
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/JDesktopPane.java
--- a/jdk/src/share/classes/javax/swing/JDesktopPane.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/JDesktopPane.java Wed Oct 13 17:51:41 2010 -0700
@@ -215,7 +215,8 @@
/**
* Sets the DesktopManger
that will handle
- * desktop-specific UI actions.
+ * desktop-specific UI actions. This may be overridden by
+ * {@code LookAndFeel}.
*
* @param d the DesktopManager
to use
*
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/JLayer.java
--- a/jdk/src/share/classes/javax/swing/JLayer.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/JLayer.java Wed Oct 13 17:51:41 2010 -0700
@@ -25,17 +25,17 @@
package javax.swing;
+import sun.awt.AWTAccessor;
+
import javax.swing.plaf.LayerUI;
+import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.ObjectInputStream;
-import java.io.Serializable;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Iterator;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -156,8 +156,6 @@
private LayerUI super V> layerUI;
private JPanel glassPane;
private boolean isPainting;
- private static final DefaultLayerLayout sharedLayoutInstance =
- new DefaultLayerLayout();
private long eventMask;
private static final LayerEventController eventController =
@@ -165,7 +163,7 @@
/**
* Creates a new {@code JLayer} object with a {@code null} view component
- * and {@code null} {@link javax.swing.plaf.LayerUI}.
+ * and default {@link javax.swing.plaf.LayerUI}.
*
* @see #setView
* @see #setUI
@@ -176,14 +174,14 @@
/**
* Creates a new {@code JLayer} object
- * with {@code null} {@link javax.swing.plaf.LayerUI}.
+ * with default {@link javax.swing.plaf.LayerUI}.
*
* @param view the component to be decorated by this {@code JLayer}
*
* @see #setUI
*/
public JLayer(V view) {
- this(view, null);
+ this(view, new LayerUI());
}
/**
@@ -195,7 +193,6 @@
* to be used by this {@code JLayer}
*/
public JLayer(V view, LayerUI ui) {
- setLayout(sharedLayoutInstance);
setGlassPane(createGlassPane());
setView(view);
setUI(ui);
@@ -279,10 +276,15 @@
*/
public void setGlassPane(JPanel glassPane) {
Component oldGlassPane = getGlassPane();
+ boolean isGlassPaneVisible = false;
if (oldGlassPane != null) {
+ isGlassPaneVisible = oldGlassPane.isVisible();
super.remove(oldGlassPane);
}
if (glassPane != null) {
+ AWTAccessor.getComponentAccessor().setMixingCutoutShape(glassPane,
+ new Rectangle());
+ glassPane.setVisible(isGlassPaneVisible);
super.addImpl(glassPane, null, 0);
}
this.glassPane = glassPane;
@@ -303,6 +305,40 @@
}
/**
+ * Sets the layout manager for this container. This method is
+ * overridden to prevent the layout manager from being set.
+ * Note: If {@code mgr} is non-{@code null}, this
+ * method will throw an exception as layout managers are not supported on
+ * a {@code JLayer}.
+ *
+ * @param mgr the specified layout manager
+ * @exception IllegalArgumentException this method is not supported
+ */
+ public void setLayout(LayoutManager mgr) {
+ if (mgr != null) {
+ throw new IllegalArgumentException("JLayer.setLayout() not supported");
+ }
+ }
+
+ /**
+ * A non-{@code null] border, or non-zero insets, isn't supported, to prevent the geometry
+ * of this component from becoming complex enough to inhibit
+ * subclassing of {@code LayerUI} class. To create a {@code JLayer} with a border,
+ * add it to a {@code JPanel} that has a border.
+ * Note: If {@code border} is non-{@code null}, this
+ * method will throw an exception as borders are not supported on
+ * a {@code JLayer}.
+ *
+ * @param border the {@code Border} to set
+ * @exception IllegalArgumentException this method is not supported
+ */
+ public void setBorder(Border border) {
+ if (border != null) {
+ throw new IllegalArgumentException("JLayer.setBorder() not supported");
+ }
+ }
+
+ /**
* This method is not supported by {@code JLayer}
* and always throws {@code UnsupportedOperationException}
*
@@ -341,6 +377,32 @@
}
/**
+ * Always returns {@code true} to cause painting to originate from {@code JLayer},
+ * or one of its ancestors.
+ *
+ * @return true
+ * @see JComponent#isPaintingOrigin()
+ */
+ boolean isPaintingOrigin() {
+ return true;
+ }
+
+ /**
+ * Delegates repainting to {@link javax.swing.plaf.LayerUI#repaint} method.
+ *
+ * @param tm this parameter is not used
+ * @param x the x value of the dirty region
+ * @param y the y value of the dirty region
+ * @param width the width of the dirty region
+ * @param height the height of the dirty region
+ */
+ public void repaint(long tm, int x, int y, int width, int height) {
+ if (getUI() != null) {
+ getUI().repaint(tm, x, y, width, height, this);
+ }
+ }
+
+ /**
* Delegates all painting to the {@link javax.swing.plaf.LayerUI} object.
*
* @param g the {@code Graphics} to render to
@@ -364,14 +426,18 @@
}
/**
- * To enable the correct painting of the {@code glassPane} and view component,
- * the {@code JLayer} overrides the default implementation of
- * this method to return {@code false} when the {@code glassPane} is visible.
+ * The {@code JLayer} overrides the default implementation of
+ * this method (in {@code JComponent}) to return {@code false}.
+ * This ensures
+ * that the drawing machinery will call the {@code JLayer}'s
+ * {@code paint}
+ * implementation rather than messaging the {@code JLayer}'s
+ * children directly.
*
- * @return false if {@code JLayer}'s {@code glassPane} is visible
+ * @return false
*/
public boolean isOptimizedDrawingEnabled() {
- return glassPane == null || !glassPane.isVisible();
+ return false;
}
/**
@@ -461,17 +527,16 @@
/**
* Returns the preferred size of the viewport for a view component.
*
- * If the ui delegate of this layer is not {@code null}, this method delegates its
- * implementation to the {@code LayerUI.getPreferredScrollableViewportSize(JLayer)}
+ * If the view component of this layer implements {@link Scrollable}, this method delegates its
+ * implementation to the view component.
*
* @return the preferred size of the viewport for a view component
*
* @see Scrollable
- * @see LayerUI#getPreferredScrollableViewportSize(JLayer)
*/
public Dimension getPreferredScrollableViewportSize() {
- if (getUI() != null) {
- return getUI().getPreferredScrollableViewportSize(this);
+ if (getView() instanceof Scrollable) {
+ return ((Scrollable)getView()).getPreferredScrollableViewportSize();
}
return getPreferredSize();
}
@@ -481,18 +546,17 @@
* that display logical rows or columns in order to completely expose
* one block of rows or columns, depending on the value of orientation.
*
- * If the ui delegate of this layer is not {@code null}, this method delegates its
- * implementation to the {@code LayerUI.getScrollableBlockIncrement(JLayer,Rectangle,int,int)}
+ * If the view component of this layer implements {@link Scrollable}, this method delegates its
+ * implementation to the view component.
*
* @return the "block" increment for scrolling in the specified direction
*
* @see Scrollable
- * @see LayerUI#getScrollableBlockIncrement(JLayer, Rectangle, int, int)
*/
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation, int direction) {
- if (getUI() != null) {
- return getUI().getScrollableBlockIncrement(this, visibleRect,
+ if (getView() instanceof Scrollable) {
+ return ((Scrollable)getView()).getScrollableBlockIncrement(visibleRect,
orientation, direction);
}
return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
@@ -504,17 +568,16 @@
* determine the height of the layer, unless the preferred height
* of the layer is smaller than the height of the viewport.
*
- * If the ui delegate of this layer is not null, this method delegates its
- * implementation to the {@code LayerUI.getScrollableTracksViewportHeight(JLayer)}
+ * If the view component of this layer implements {@link Scrollable}, this method delegates its
+ * implementation to the view component.
*
* @return whether the layer should track the height of the viewport
*
* @see Scrollable
- * @see LayerUI#getScrollableTracksViewportHeight(JLayer)
*/
public boolean getScrollableTracksViewportHeight() {
- if (getUI() != null) {
- return getUI().getScrollableTracksViewportHeight(this);
+ if (getView() instanceof Scrollable) {
+ return ((Scrollable)getView()).getScrollableTracksViewportHeight();
}
return false;
}
@@ -524,17 +587,16 @@
* determine the width of the layer, unless the preferred width
* of the layer is smaller than the width of the viewport.
*
- * If the ui delegate of this layer is not null, this method delegates its
- * implementation to the {@code LayerUI.getScrollableTracksViewportWidth(JLayer)}
+ * If the view component of this layer implements {@link Scrollable}, this method delegates its
+ * implementation to the view component.
*
* @return whether the layer should track the width of the viewport
*
* @see Scrollable
- * @see LayerUI#getScrollableTracksViewportWidth(JLayer)
*/
public boolean getScrollableTracksViewportWidth() {
- if (getUI() != null) {
- return getUI().getScrollableTracksViewportWidth(this);
+ if (getView() instanceof Scrollable) {
+ return ((Scrollable)getView()).getScrollableTracksViewportWidth();
}
return false;
}
@@ -549,20 +611,19 @@
* Scrolling containers, like {@code JScrollPane}, will use this method
* each time the user requests a unit scroll.
*
- * If the ui delegate of this layer is not {@code null}, this method delegates its
- * implementation to the {@code LayerUI.getScrollableUnitIncrement(JLayer,Rectangle,int,int)}
+ * If the view component of this layer implements {@link Scrollable}, this method delegates its
+ * implementation to the view component.
*
* @return The "unit" increment for scrolling in the specified direction.
* This value should always be positive.
*
* @see Scrollable
- * @see LayerUI#getScrollableUnitIncrement(JLayer, Rectangle, int, int)
*/
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
int direction) {
- if (getUI() != null) {
- return getUI().getScrollableUnitIncrement(
- this, visibleRect, orientation, direction);
+ if (getView() instanceof Scrollable) {
+ return ((Scrollable) getView()).getScrollableUnitIncrement(
+ visibleRect, orientation, direction);
}
return 1;
}
@@ -595,6 +656,16 @@
}
/**
+ * Delegates its functionality to the {@link javax.swing.plaf.LayerUI#doLayout(JLayer)} method,
+ * if {@code LayerUI} is set.
+ */
+ public void doLayout() {
+ if (getUI() != null) {
+ getUI().doLayout(this);
+ }
+ }
+
+ /**
* static AWTEventListener to be shared with all AbstractLayerUIs
*/
private static class LayerEventController implements AWTEventListener {
@@ -625,8 +696,8 @@
JLayer l = (JLayer) component;
LayerUI ui = l.getUI();
if (ui != null &&
- isEventEnabled(l.getLayerEventMask(),
- event.getID())) {
+ isEventEnabled(l.getLayerEventMask(), event.getID()) &&
+ (!(event instanceof InputEvent) || !((InputEvent)event).isConsumed())) {
ui.eventDispatched(event, l);
}
}
@@ -758,82 +829,4 @@
return super.contains(x, y);
}
}
-
- /**
- * The default layout manager for the {@link javax.swing.JLayer}.
- * It places the glassPane on top of the view component
- * and makes it the same size as {@code JLayer},
- * it also makes the view component the same size but minus layer's insets
- */
- private static class DefaultLayerLayout implements LayoutManager, Serializable {
- /**
- * {@inheritDoc}
- */
- public void layoutContainer(Container parent) {
- JLayer layer = (JLayer) parent;
- Component view = layer.getView();
- Component glassPane = layer.getGlassPane();
- if (view != null) {
- Insets insets = layer.getInsets();
- view.setLocation(insets.left, insets.top);
- view.setSize(layer.getWidth() - insets.left - insets.right,
- layer.getHeight() - insets.top - insets.bottom);
- }
- if (glassPane != null) {
- glassPane.setLocation(0, 0);
- glassPane.setSize(layer.getWidth(), layer.getHeight());
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public Dimension minimumLayoutSize(Container parent) {
- JLayer layer = (JLayer) parent;
- Insets insets = layer.getInsets();
- Dimension ret = new Dimension(insets.left + insets.right,
- insets.top + insets.bottom);
- Component view = layer.getView();
- if (view != null) {
- Dimension size = view.getMinimumSize();
- ret.width += size.width;
- ret.height += size.height;
- }
- if (ret.width == 0 || ret.height == 0) {
- ret.width = ret.height = 4;
- }
- return ret;
- }
-
- /**
- * {@inheritDoc}
- */
- public Dimension preferredLayoutSize(Container parent) {
- JLayer layer = (JLayer) parent;
- Insets insets = layer.getInsets();
- Dimension ret = new Dimension(insets.left + insets.right,
- insets.top + insets.bottom);
- Component view = layer.getView();
- if (view != null) {
- Dimension size = view.getPreferredSize();
- if (size.width > 0 && size.height > 0) {
- ret.width += size.width;
- ret.height += size.height;
- }
- }
- return ret;
- }
-
- /**
- * {@inheritDoc}
- */
- public void addLayoutComponent(String name, Component comp) {
- }
-
- /**
- * {@inheritDoc}
- */
- public void removeLayoutComponent(Component comp) {
- }
- }
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/JTable.java
--- a/jdk/src/share/classes/javax/swing/JTable.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/JTable.java Wed Oct 13 17:51:41 2010 -0700
@@ -4574,9 +4574,8 @@
* @see TableColumnModelListener
*/
public void columnMoved(TableColumnModelEvent e) {
- // If I'm currently editing, then I should stop editing
- if (isEditing()) {
- removeEditor();
+ if (isEditing() && !getCellEditor().stopCellEditing()) {
+ getCellEditor().cancelCellEditing();
}
repaint();
}
@@ -4593,8 +4592,8 @@
* @see TableColumnModelListener
*/
public void columnMarginChanged(ChangeEvent e) {
- if (isEditing()) {
- removeEditor();
+ if (isEditing() && !getCellEditor().stopCellEditing()) {
+ getCellEditor().cancelCellEditing();
}
TableColumn resizingColumn = getResizingColumn();
// Need to do this here, before the parent's
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/ToolTipManager.java
--- a/jdk/src/share/classes/javax/swing/ToolTipManager.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/ToolTipManager.java Wed Oct 13 17:51:41 2010 -0700
@@ -459,7 +459,7 @@
if (insideComponent == null) {
// Drag exit
}
- if (window != null && event.getSource() == window) {
+ if (window != null && event.getSource() == window && insideComponent != null) {
// if we get an exit and have a heavy window
// we need to check if it if overlapping the inside component
Container insideComponentWindow = insideComponent.getTopLevelAncestor();
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/plaf/LayerUI.java
--- a/jdk/src/share/classes/javax/swing/plaf/LayerUI.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/plaf/LayerUI.java Wed Oct 13 17:51:41 2010 -0700
@@ -600,104 +600,6 @@
}
/**
- * Returns the preferred size of the viewport for a view component.
- *
- * @param l the {@code JLayer} component where this UI delegate is being installed
- * @return the preferred size of the viewport for a view component
- * @see Scrollable#getPreferredScrollableViewportSize()
- */
- public Dimension getPreferredScrollableViewportSize(JLayer extends V> l) {
- if (l.getView() instanceof Scrollable) {
- return ((Scrollable)l.getView()).getPreferredScrollableViewportSize();
- }
- return l.getPreferredSize();
- }
-
- /**
- * Returns a scroll increment, which is required for components
- * that display logical rows or columns in order to completely expose
- * one block of rows or columns, depending on the value of orientation.
- *
- * @param l the {@code JLayer} component where this UI delegate is being installed
- * @param visibleRect The view area visible within the viewport
- * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
- * @param direction Less than zero to scroll up/left, greater than zero for down/right.
- * @return the "block" increment for scrolling in the specified direction
- * @see Scrollable#getScrollableBlockIncrement(Rectangle, int, int)
- */
- public int getScrollableBlockIncrement(JLayer extends V> l,
- Rectangle visibleRect,
- int orientation, int direction) {
- if (l.getView() instanceof Scrollable) {
- return ((Scrollable)l.getView()).getScrollableBlockIncrement(
- visibleRect,orientation, direction);
- }
- return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
- visibleRect.width;
- }
-
- /**
- * Returns {@code false} to indicate that the height of the viewport does not
- * determine the height of the layer, unless the preferred height
- * of the layer is smaller than the height of the viewport.
- *
- * @param l the {@code JLayer} component where this UI delegate is being installed
- * @return whether the layer should track the height of the viewport
- * @see Scrollable#getScrollableTracksViewportHeight()
- */
- public boolean getScrollableTracksViewportHeight(JLayer extends V> l) {
- if (l.getView() instanceof Scrollable) {
- return ((Scrollable)l.getView()).getScrollableTracksViewportHeight();
- }
- return false;
- }
-
- /**
- * Returns {@code false} to indicate that the width of the viewport does not
- * determine the width of the layer, unless the preferred width
- * of the layer is smaller than the width of the viewport.
- *
- * @param l the {@code JLayer} component where this UI delegate is being installed
- * @return whether the layer should track the width of the viewport
- * @see Scrollable
- * @see LayerUI#getScrollableTracksViewportWidth(JLayer)
- */
- public boolean getScrollableTracksViewportWidth(JLayer extends V> l) {
- if (l.getView() instanceof Scrollable) {
- return ((Scrollable)l.getView()).getScrollableTracksViewportWidth();
- }
- return false;
- }
-
- /**
- * Returns a scroll increment, which is required for components
- * that display logical rows or columns in order to completely expose
- * one new row or column, depending on the value of orientation.
- * Ideally, components should handle a partially exposed row or column
- * by returning the distance required to completely expose the item.
- *
- * Scrolling containers, like JScrollPane, will use this method
- * each time the user requests a unit scroll.
- *
- * @param l the {@code JLayer} component where this UI delegate is being installed
- * @param visibleRect The view area visible within the viewport
- * @param orientation Either SwingConstants.VERTICAL or SwingConstants.HORIZONTAL.
- * @param direction Less than zero to scroll up/left, greater than zero for down/right.
- * @return The "unit" increment for scrolling in the specified direction.
- * This value should always be positive.
- * @see Scrollable#getScrollableUnitIncrement(Rectangle, int, int)
- */
- public int getScrollableUnitIncrement(JLayer extends V> l,
- Rectangle visibleRect,
- int orientation, int direction) {
- if (l.getView() instanceof Scrollable) {
- return ((Scrollable)l.getView()).getScrollableUnitIncrement(
- visibleRect, orientation, direction);
- }
- return 1;
- }
-
- /**
* If the {@code JLayer}'s view component is not {@code null},
* this calls the view's {@code getBaseline()} method.
* Otherwise, the default implementation is called.
@@ -718,7 +620,7 @@
/**
* If the {@code JLayer}'s view component is not {@code null},
- * this calls the view's {@code getBaselineResizeBehavior()} method.
+ * this returns the result of the view's {@code getBaselineResizeBehavior()} method.
* Otherwise, the default implementation is called.
*
* @param c {@code JLayer} to return baseline resize behavior for
@@ -732,4 +634,90 @@
}
return super.getBaselineResizeBehavior(c);
}
+
+ /**
+ * Causes the passed instance of {@code JLayer} to lay out its components.
+ *
+ * @param l the {@code JLayer} component where this UI delegate is being installed
+ */
+ public void doLayout(JLayer extends V> l) {
+ Component view = l.getView();
+ if (view != null) {
+ view.setBounds(0, 0, l.getWidth(), l.getHeight());
+ }
+ Component glassPane = l.getGlassPane();
+ if (glassPane != null) {
+ glassPane.setBounds(0, 0, l.getWidth(), l.getHeight());
+ }
+ }
+
+ /**
+ * If the {@code JLayer}'s view component is not {@code null},
+ * this returns the result of the view's {@code getPreferredSize()} method.
+ * Otherwise, the default implementation is used.
+ *
+ * @param c {@code JLayer} to return preferred size for
+ * @return preferred size for the passed {@code JLayer}
+ */
+ public Dimension getPreferredSize(JComponent c) {
+ JLayer l = (JLayer) c;
+ Component view = l.getView();
+ if (view != null) {
+ return view.getPreferredSize();
+ }
+ return super.getPreferredSize(c);
+ }
+
+ /**
+ * If the {@code JLayer}'s view component is not {@code null},
+ * this returns the result of the view's {@code getMinimalSize()} method.
+ * Otherwise, the default implementation is used.
+ *
+ * @param c {@code JLayer} to return preferred size for
+ * @return minimal size for the passed {@code JLayer}
+ */
+ public Dimension getMinimumSize(JComponent c) {
+ JLayer l = (JLayer) c;
+ Component view = l.getView();
+ if (view != null) {
+ return view.getMinimumSize();
+ }
+ return super.getMinimumSize(c);
+ }
+
+ /**
+ * If the {@code JLayer}'s view component is not {@code null},
+ * this returns the result of the view's {@code getMaximumSize()} method.
+ * Otherwise, the default implementation is used.
+ *
+ * @param c {@code JLayer} to return preferred size for
+ * @return maximun size for the passed {@code JLayer}
+ */
+ public Dimension getMaximumSize(JComponent c) {
+ JLayer l = (JLayer) c;
+ Component view = l.getView();
+ if (view != null) {
+ return view.getMaximumSize();
+ }
+ return super.getMaximumSize(c);
+ }
+
+ /**
+ * Adds the specified region to the dirty region list if the component
+ * is showing. The component will be repainted after all of the
+ * currently pending events have been dispatched.
+ *
+ * This method is to be overridden when the dirty region needs to be changed.
+ *
+ * @param tm this parameter is not used
+ * @param x the x value of the dirty region
+ * @param y the y value of the dirty region
+ * @param width the width of the dirty region
+ * @param height the height of the dirty region
+ * @see java.awt.Component#isShowing
+ * @see RepaintManager#addDirtyRegion
+ */
+ public void repaint(long tm, int x, int y, int width, int height, JLayer extends V> l) {
+ RepaintManager.currentManager(l).addDirtyRegion(l, x, y, width, height);
+ }
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java
--- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicScrollBarUI.java Wed Oct 13 17:51:41 2010 -0700
@@ -1603,6 +1603,7 @@
BoundedRangeModel newModel = (BoundedRangeModel)e.getNewValue();
oldModel.removeChangeListener(modelListener);
newModel.addChangeListener(modelListener);
+ scrollBarValue = scrollbar.getValue();
scrollbar.repaint();
scrollbar.revalidate();
} else if ("orientation" == propertyName) {
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/plaf/metal/MetalComboBoxUI.java
--- a/jdk/src/share/classes/javax/swing/plaf/metal/MetalComboBoxUI.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/plaf/metal/MetalComboBoxUI.java Wed Oct 13 17:51:41 2010 -0700
@@ -144,7 +144,7 @@
*/
public int getBaseline(JComponent c, int width, int height) {
int baseline;
- if (MetalLookAndFeel.usingOcean()) {
+ if (MetalLookAndFeel.usingOcean() && height >= 4) {
height -= 4;
baseline = super.getBaseline(c, width, height);
if (baseline >= 0) {
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java
--- a/jdk/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java Wed Oct 13 17:51:41 2010 -0700
@@ -115,6 +115,9 @@
return new SynthTabbedPaneUI();
}
+ private SynthTabbedPaneUI() {
+ }
+
private boolean scrollableTabLayoutEnabled() {
return (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT);
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/sun/awt/AWTAccessor.java
--- a/jdk/src/share/classes/sun/awt/AWTAccessor.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/sun/awt/AWTAccessor.java Wed Oct 13 17:51:41 2010 -0700
@@ -344,6 +344,11 @@
* Removes the last focus request for the heavyweight from the queue.
*/
void removeLastFocusRequest(Component heavyweight);
+
+ /*
+ * Sets the most recent focus owner in the window.
+ */
+ void setMostRecentFocusOwner(Window window, Component component);
}
/*
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/sun/awt/EmbeddedFrame.java
--- a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java Wed Oct 13 17:51:41 2010 -0700
@@ -70,7 +70,10 @@
// JDK 1.1 compatibility
private static final long serialVersionUID = 2967042741780317130L;
- // Use these in traverseOut method to determine directions
+ /*
+ * The constants define focus traversal directions.
+ * Use them in {@code traverseIn}, {@code traverseOut} methods.
+ */
protected static final boolean FORWARD = true;
protected static final boolean BACKWARD = false;
@@ -284,6 +287,41 @@
}
/**
+ * This method is called by the embedder when we should receive focus as element
+ * of the traversal chain. The method requests focus on:
+ * 1. the first Component of this EmbeddedFrame if user moves focus forward
+ * in the focus traversal cycle.
+ * 2. the last Component of this EmbeddedFrame if user moves focus backward
+ * in the focus traversal cycle.
+ *
+ * The direction parameter specifies which of the two mentioned cases is
+ * happening. Use FORWARD and BACKWARD constants defined in the EmbeddedFrame class
+ * to avoid confusing boolean values.
+ *
+ * A concrete implementation of this method is defined in the platform-dependent
+ * subclasses.
+ *
+ * @param direction FORWARD or BACKWARD
+ * @return true, if the EmbeddedFrame wants to get focus, false otherwise.
+ */
+ public boolean traverseIn(boolean direction) {
+ Component comp = null;
+
+ if (direction == FORWARD) {
+ comp = getFocusTraversalPolicy().getFirstComponent(this);
+ } else {
+ comp = getFocusTraversalPolicy().getLastComponent(this);
+ }
+ if (comp != null) {
+ // comp.requestFocus(); - Leads to a hung.
+
+ AWTAccessor.getKeyboardFocusManagerAccessor().setMostRecentFocusOwner(this, comp);
+ synthesizeWindowActivation(true);
+ }
+ return (null != comp);
+ }
+
+ /**
* This method is called from dispatchKeyEvent in the following two cases:
* 1. The focus is on the first Component of this EmbeddedFrame and we are
* about to transfer the focus backward.
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/classes/sun/util/locale/BaseLocale.java
--- a/jdk/src/share/classes/sun/util/locale/BaseLocale.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/share/classes/sun/util/locale/BaseLocale.java Wed Oct 13 17:51:41 2010 -0700
@@ -64,12 +64,14 @@
public static BaseLocale getInstance(String language, String script, String region, String variant) {
// JDK uses deprecated ISO639.1 language codes for he, yi and id
- if (AsciiUtil.caseIgnoreMatch(language, "he")) {
- language = "iw";
- } else if (AsciiUtil.caseIgnoreMatch(language, "yi")) {
- language = "ji";
- } else if (AsciiUtil.caseIgnoreMatch(language, "id")) {
- language = "in";
+ if (language != null) {
+ if (AsciiUtil.caseIgnoreMatch(language, "he")) {
+ language = "iw";
+ } else if (AsciiUtil.caseIgnoreMatch(language, "yi")) {
+ language = "ji";
+ } else if (AsciiUtil.caseIgnoreMatch(language, "id")) {
+ language = "in";
+ }
}
Key key = new Key(language, script, region, variant);
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/Demo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/Demo.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,664 @@
+/*
+ * 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.
+ */
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.file.*;
+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 [-cp .../zipfs.jar:./] Demo action ZipfileName [...]
+ *
+ * To deploy the provider, either copy the zipfs.jar into JDK/JRE
+ * extensions directory or add
+ * /demo/nio/ZipFileSystem/zipfs.jar
+ * into your class path as showed above.
+ *
+ * @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
+
+ copyout, //
+ // copy zipfile entry src" out to file dst
+
+ 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
+
+ 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
+ }
+
+ public static void main(String[] args) throws Throwable {
+
+ Action action = Action.valueOf(args[0]);;
+ Map env = env = new HashMap();
+ if (action == Action.create)
+ env.put("createNew", true);
+ if (action == Action.tlist || action == Action.twalk)
+ env.put("buildDirTree", true);
+
+ FileSystem fs = FileSystems.newFileSystem(
+ URI.create("zip" + Paths.get(args[1]).toUri().toString().substring(4)),
+ env,
+ null);
+ try {
+ FileSystem fs2;
+ Path path, src, dst;
+ boolean isRename = false;
+ switch (action) {
+ case rename:
+ src = fs.getPath(args[2]);
+ dst = fs.getPath(args[3]);
+ src.moveTo(dst);
+ break;
+ case moveout:
+ src = fs.getPath(args[2]);
+ dst = Paths.get(args[3]);
+ src.moveTo(dst);
+ break;
+ case movein:
+ src = Paths.get(args[2]);
+ dst = fs.getPath(args[3]);
+ src.moveTo(dst);
+ break;
+ case copy:
+ src = fs.getPath(args[2]);
+ dst = fs.getPath(args[3]);
+ src.copyTo(dst);
+ break;
+ case copyout:
+ src = fs.getPath(args[2]);
+ dst = Paths.get(args[3]);
+ src.copyTo(dst);
+ break;
+ case copyin:
+ src = Paths.get(args[2]);
+ dst = fs.getPath(args[3]);
+ src.copyTo(dst);
+ break;
+ case zzmove:
+ fs2 = FileSystems.newFileSystem(
+ URI.create("zip" + Paths.get(args[2]).toUri().toString().substring(4)),
+ env,
+ null);
+ //sf1.getPath(args[3]).moveTo(fs2.getPath(args[3]));
+ z2zmove(fs, fs2, args[3]);
+ fs2.close();
+ break;
+ case zzcopy:
+ fs2 = FileSystems.newFileSystem(
+ URI.create("zip" + Paths.get(args[2]).toUri().toString().substring(4)),
+ env,
+ null);
+ //sf1.getPath(args[3]).copyTo(fs2.getPath(args[3]));
+ z2zcopy(fs, fs2, args[3]);
+ fs2.close();
+ break;
+ case attrs:
+ for (int i = 2; i < args.length; i++) {
+ path = fs.getPath(args[i]);
+ System.out.println(
+ Attributes.readBasicFileAttributes(path).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]);
+ path.setAttribute("lastModifiedTime",
+ FileTime.fromMillis(newDatetime.getTime()));
+ System.out.println(
+ Attributes.readBasicFileAttributes(path).toString());
+ }
+ break;
+ case attrsspace:
+ path = fs.getPath("/");
+ FileStore fstore = path.getFileStore();
+ //System.out.println(fstore.getFileStoreAttributeView(FileStoreSpaceAttributeView.class)
+ // .readAttributes());
+ // or
+ System.out.printf("filestore[%s]%n", fstore.name());
+ System.out.printf(" totalSpace: %d%n",
+ (Long)fstore.getAttribute("space:totalSpace"));
+ System.out.printf(" usableSpace: %d%n",
+ (Long)fstore.getAttribute("space:usableSpace"));
+ System.out.printf(" unallocSpace: %d%n",
+ (Long)fstore.getAttribute("space: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++)
+ fs.getPath(args[i]).delete();
+ 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]:"";
+ DirectoryStream ds = path.newDirectoryStream(
+ new DirectoryStream.Filter() {
+ public boolean accept(Path path) {
+ return path.toString().contains(fStr);
+ }
+ });
+ for (Path p : ds)
+ System.out.println(p);
+ break;
+ case mkdir:
+ fs.getPath(args[2]).createDirectory();
+ 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.println("-------(1)---------");
+ System.out.println(
+ Attributes.readBasicFileAttributes(path).toString());
+ System.out.println("-------(2)---------");
+ Map map = path.readAttributes("zip:*");
+ for (Map.Entry e : map.entrySet()) {
+ System.out.printf(" %s : %s%n", e.getKey(), e.getValue());
+ }
+ System.out.println("-------(3)---------");
+ map = path.readAttributes("size,lastModifiedTime,isDirectory");
+ for (Map.Entry e : map.entrySet()) {
+ System.out.printf(" %s : %s%n", e.getKey(), e.getValue());
+ }
+ }
+ break;
+ }
+ } catch (Exception x) {
+ x.printStackTrace();
+ } finally {
+ if (fs != null)
+ fs.close();
+ }
+ }
+
+ private static byte[] getBytes(String name) {
+ return name.getBytes();
+ }
+
+ 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.getName().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 (Boolean.TRUE.equals(src.getAttribute("isDirectory"))) {
+ DirectoryStream ds = src.newDirectoryStream();
+ for (Path child : ds)
+ update(fs, child.toString());
+ ds.close();
+ } else {
+ Path dst = fs.getPath(path);
+ Path parent = dst.getParent();
+ if (parent != null && parent.notExists())
+ mkdirs(parent);
+ src.copyTo(dst, REPLACE_EXISTING);
+ }
+ }
+
+ private static void extract(FileSystem fs, String path) throws Throwable{
+ Path src = fs.getPath(path);
+ if (Boolean.TRUE.equals(src.getAttribute("isDirectory"))) {
+ DirectoryStream ds = src.newDirectoryStream();
+ for (Path child : ds)
+ extract(fs, child.toString());
+ ds.close();
+ } else {
+ if (path.startsWith("/"))
+ path = path.substring(1);
+ Path dst = FileSystems.getDefault().getPath(path);
+ Path parent = dst.getParent();
+ if (parent.notExists())
+ mkdirs(parent);
+ src.copyTo(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 (Boolean.TRUE.equals(srcPath.getAttribute("isDirectory"))) {
+ if (!dstPath.exists()) {
+ try {
+ mkdirs(dstPath);
+ } catch (FileAlreadyExistsException x) {}
+ }
+ DirectoryStream ds = srcPath.newDirectoryStream();
+ for (Path child : ds) {
+ z2zcopy(src, dst,
+ path + (path.endsWith("/")?"":"/") + child.getName());
+ }
+ ds.close();
+ } else {
+ //System.out.println("copying..." + path);
+ srcPath.copyTo(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 && parent.notExists())
+ mkdirs(parent);
+ file.moveTo(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 (dst.notExists())
+ mkdirs(dst);
+ } catch (IOException x) {
+ x.printStackTrace();
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir,
+ IOException ioe)
+ throws IOException
+ {
+ try {
+ dir.delete();
+ } 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 (parent.notExists())
+ mkdirs(parent);
+ }
+ path.createDirectory();
+ }
+
+ private static void rmdirs(Path path) throws IOException {
+ while (path != null && path.getNameCount() != 0) {
+ path.delete();
+ path = path.getParent();
+ }
+ }
+
+ private static void list(Path path, boolean verbose ) throws IOException {
+ if (verbose)
+ System.out.println(Attributes.readBasicFileAttributes(path).toString());
+ else
+ System.out.printf(" %s%n", path.toString());
+ if (path.notExists())
+ return;
+ if (Attributes.readBasicFileAttributes(path).isDirectory()) {
+ DirectoryStream ds = path.newDirectoryStream();
+ for (Path child : ds)
+ list(child, verbose);
+ ds.close();
+ }
+ }
+
+ // 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
+ InputStream isSrc = src.newInputStream();
+ InputStream isDst = dst.newInputStream();
+ byte[] bufSrc = new byte[8192];
+ byte[] bufDst = new byte[8192];
+
+ try {
+ 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--;
+ }
+ }
+ } finally {
+ isSrc.close();
+ isDst.close();
+ }
+
+ // channels
+ SeekableByteChannel chSrc = src.newByteChannel();
+ SeekableByteChannel chDst = dst.newByteChannel();
+ 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);
+
+ try {
+ 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();
+ } finally {
+ chSrc.close();
+ chDst.close();
+ }
+ }
+
+ 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);
+
+ FileChannel srcFc = src.getFileSystem()
+ .provider()
+ .newFileChannel(src, read);
+ FileChannel dstFc = dst.getFileSystem()
+ .provider()
+ .newFileChannel(dst, openwrite);
+
+ try {
+ ByteBuffer bb = ByteBuffer.allocate(8192);
+ while (srcFc.read(bb) >= 0) {
+ bb.flip();
+ dstFc.write(bb);
+ bb.clear();
+ }
+ } finally {
+ srcFc.close();
+ dstFc.close();
+ }
+ }
+
+ 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);
+
+ SeekableByteChannel srcCh = src.newByteChannel(read);
+ SeekableByteChannel dstCh = dst.newByteChannel(openwrite);
+
+ try {
+ ByteBuffer bb = ByteBuffer.allocate(8192);
+ while (srcCh.read(bb) >= 0) {
+ bb.flip();
+ dstCh.write(bb);
+ bb.clear();
+ }
+ } finally {
+ srcCh.close();
+ dstCh.close();
+ }
+ }
+
+ private static void streamCopy(Path src, Path dst) throws IOException
+ {
+ InputStream isSrc = src.newInputStream();
+ OutputStream osDst = dst.newOutputStream();
+ byte[] buf = new byte[8192];
+ try {
+ int n = 0;
+ while ((n = isSrc.read(buf)) != -1) {
+ osDst.write(buf, 0, n);
+ }
+ } finally {
+ isSrc.close();
+ osDst.close();
+ }
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/META-INF/services/java.nio.file.spi.FileSystemProvider Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,3 @@
+com.sun.nio.zipfs.ZipFileSystemProvider
+com.sun.nio.zipfs.JarFileSystemProvider
+
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/README.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/README.txt Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,29 @@
+ZipFileSystem is a file system provider that treats the contents of a zip or
+JAR file as a java.nio.file.FileSystem.
+
+To deploy the provider you must copy zipfs.jar into your extensions
+directory or else add /demo/nio/ZipFileSystem/zipfs.jar
+to your class path.
+
+The factory methods defined by the java.nio.file.FileSystems class can be
+used to create a FileSystem, eg:
+
+ // use file type detection
+ Map env = Collections.emptyMap();
+ Path jarfile = Path.get("foo.jar");
+ FileSystem fs = FileSystems.newFileSystem(jarfile, env);
+
+-or
+
+ // locate file system by URI
+ Map env = Collections.emptyMap();
+ URI uri = URI.create("zip:///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();
+
+
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/JarFileSystemProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/JarFileSystemProvider.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. 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 Sun Microsystems 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.
+ */
+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
+ }
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipCoder.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipCoder.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+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 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipConstants.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipConstants.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+package com.sun.nio.zipfs;
+
+import java.nio.ByteBuffer;
+
+/**
+ *
+ * @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;
+
+ /*
+ * 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
+
+
+ /*
+ * fields access methods
+ */
+ ///////////////////////////////////////////////////////
+ static final int CH(byte[] b, int n) {
+ return b[n] & 0xff;
+ }
+
+ static final int SH(byte[] b, int n) {
+ return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 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
+
+ //////////////////////////////////////////
+ static final int CH(ByteBuffer b, int pos) {
+ return b.get(pos) & 0xff;
+ }
+ static final int SH(ByteBuffer b, int pos) {
+ return b.getShort(pos) & 0xffff;
+ }
+ static final long LG(ByteBuffer b, int pos) {
+ return b.getInt(pos) & 0xffffffffL;
+ }
+
+ // central directory header (END) fields
+ static final long CENSIG(ByteBuffer b, int pos) { return LG(b, pos + 0); }
+ static final int CENVEM(ByteBuffer b, int pos) { return SH(b, pos + 4); }
+ static final int CENVER(ByteBuffer b, int pos) { return SH(b, pos + 6); }
+ static final int CENFLG(ByteBuffer b, int pos) { return SH(b, pos + 8); }
+ static final int CENHOW(ByteBuffer b, int pos) { return SH(b, pos + 10);}
+ static final long CENTIM(ByteBuffer b, int pos) { return LG(b, pos + 12);}
+ static final long CENCRC(ByteBuffer b, int pos) { return LG(b, pos + 16);}
+ static final long CENSIZ(ByteBuffer b, int pos) { return LG(b, pos + 20);}
+ static final long CENLEN(ByteBuffer b, int pos) { return LG(b, pos + 24);}
+ static final int CENNAM(ByteBuffer b, int pos) { return SH(b, pos + 28);}
+ static final int CENEXT(ByteBuffer b, int pos) { return SH(b, pos + 30);}
+ static final int CENCOM(ByteBuffer b, int pos) { return SH(b, pos + 32);}
+ static final int CENDSK(ByteBuffer b, int pos) { return SH(b, pos + 34);}
+ static final int CENATT(ByteBuffer b, int pos) { return SH(b, pos + 36);}
+ static final long CENATX(ByteBuffer b, int pos) { return LG(b, pos + 38);}
+ static final long CENOFF(ByteBuffer 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 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipDirectoryStream.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipDirectoryStream.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+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;
+import static com.sun.nio.zipfs.ZipUtils.*;
+
+/**
+ *
+ * @author Xueming Shen, Rajendra Gutupalli, Jaya Hangal
+ */
+
+public class ZipDirectoryStream implements DirectoryStream {
+
+ private final ZipFileSystem zipfs;
+ private final byte[] path;
+ private final DirectoryStream.Filter super Path> filter;
+ private volatile boolean isClosed;
+ private volatile Iterator itr;
+
+ ZipDirectoryStream(ZipPath zipPath,
+ DirectoryStream.Filter super java.nio.file.Path> 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 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileAttributeView.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileAttributeView.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+
+package com.sun.nio.zipfs;
+
+import java.nio.file.ReadOnlyFileSystemException;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileTime;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+
+/*
+ * @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);
+ return;
+ } catch (IllegalArgumentException x) {}
+ throw new UnsupportedOperationException("'" + attribute +
+ "' is unknown or read-only attribute");
+ }
+
+ public Object getAttribute(String attribute, boolean domap)
+ throws IOException
+ {
+ ZipFileAttributes zfas = readAttributes();
+ if (!domap) {
+ try {
+ return attribute(AttrID.valueOf(attribute), zfas);
+ } catch (IllegalArgumentException x) {}
+ return null;
+ }
+ LinkedHashMap map = new LinkedHashMap<>();
+ if ("*".equals(attribute)) {
+ for (AttrID id : AttrID.values()) {
+ try {
+ map.put(id.name(), attribute(id, zfas));
+ } catch (IllegalArgumentException x) {}
+ }
+ } else {
+ String[] as = attribute.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 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileAttributes.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileAttributes.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+
+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(dosToJavaTime(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(dosToJavaTime(e.atime));
+ return null;
+ }
+
+ @Override
+ public FileTime lastModifiedTime() {
+ return FileTime.fromMillis(dosToJavaTime(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 byte[] name() {
+ return Arrays.copyOf(e.name, e.name.length);
+ }
+
+ 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();
+ Formatter fm = new Formatter(sb);
+ fm.format("[/%s]%n", new String(e.name)); // TBD encoding
+ fm.format(" creationTime : %s%n", creationTime());
+ 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 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileStore.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileStore.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+package com.sun.nio.zipfs;
+
+import java.io.IOException;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileStoreAttributeView;
+import java.nio.file.attribute.FileStoreSpaceAttributeView;
+import java.nio.file.attribute.FileStoreSpaceAttributes;
+import java.nio.file.attribute.Attributes;
+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 = (ZipFileSystem)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 extends FileAttributeView> 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();
+ if (type == FileStoreSpaceAttributeView.class)
+ return (V) new ZipFileStoreAttributeView(this);
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String attribute) throws IOException {
+ if (attribute.equals("space:totalSpace"))
+ return new ZipFileStoreAttributeView(this).readAttributes().totalSpace();
+ if (attribute.equals("space:usableSpace"))
+ return new ZipFileStoreAttributeView(this).readAttributes().usableSpace();
+ if (attribute.equals("space:unallocatedSpace"))
+ return new ZipFileStoreAttributeView(this).readAttributes().unallocatedSpace();
+ throw new UnsupportedOperationException("does not support the given attribute");
+ }
+
+ private static class ZipFileStoreAttributeView implements FileStoreSpaceAttributeView {
+
+ private final ZipFileStore fileStore;
+
+ public ZipFileStoreAttributeView(ZipFileStore fileStore) {
+ this.fileStore = fileStore;
+ }
+
+ @Override
+ public String name() {
+ return "space";
+ }
+
+ @Override
+ public FileStoreSpaceAttributes readAttributes() throws IOException {
+ final String file = fileStore.name();
+ Path path = FileSystems.getDefault().getPath(file);
+ final long size = Attributes.readBasicFileAttributes(path).size();
+ final FileStore fstore = path.getFileStore();
+ final FileStoreSpaceAttributes fstoreAttrs =
+ Attributes.readFileStoreSpaceAttributes(fstore);
+ return new FileStoreSpaceAttributes() {
+ public long totalSpace() {
+ return size;
+ }
+
+ public long usableSpace() {
+ if (!fstore.isReadOnly())
+ return fstoreAttrs.usableSpace();
+ return 0;
+ }
+
+ public long unallocatedSpace() {
+ if (!fstore.isReadOnly())
+ return fstoreAttrs.unallocatedSpace();
+ return 0;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ Formatter fm = new Formatter(sb);
+ fm.format("FileStoreSpaceAttributes[%s]%n", file);
+ fm.format(" totalSpace: %d%n", totalSpace());
+ fm.format(" usableSpace: %d%n", usableSpace());
+ fm.format(" unallocSpace: %d%n", unallocatedSpace());
+ fm.close();
+ return sb.toString();
+ }
+ };
+ }
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileSystem.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileSystem.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,2257 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+package com.sun.nio.zipfs;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.nio.file.spi.*;
+import java.net.URI;
+import java.util.*;
+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;
+
+ private final Object lock = new Object();
+
+ // 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 buildDirTree; // build a dir tree for directoryStream ops
+ 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
+
+ ZipFileSystem(ZipFileSystemProvider provider,
+ Path zfpath,
+ Map env)
+ throws IOException
+ {
+ // configurable env setup
+ this.buildDirTree = TRUE.equals(env.get("buildDirTree"));
+ this.useTempFile = TRUE.equals(env.get("useTempFile"));
+ this.createNew = TRUE.equals(env.get("createNew"));
+ this.nameEncoding = env.containsKey("nameEncoding") ?
+ (String)env.get("nameEncoding") : "UTF-8";
+ 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 (zfpath.notExists()) {
+ if (createNew) {
+ OutputStream os = zfpath.newOutputStream(CREATE_NEW, WRITE);
+ new END().write(os, 0);
+ os.close();
+ } else {
+ throw new FileSystemNotFoundException(zfpath.toString());
+ }
+ }
+ zfpath.checkAccess(AccessMode.READ); // sm and existence check
+ try {
+ zfpath.checkAccess(AccessMode.WRITE);
+ } catch (AccessDeniedException x) {
+ this.readOnly = true;
+ }
+ this.zc = ZipCoder.get(nameEncoding);
+ this.defaultdir = new ZipPath(this, getBytes(defaultDir));
+ initZipFile();
+ }
+
+ @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 path) {
+ if (path.length() == 0)
+ throw new InvalidPathException(path, "path should not be empty");
+ 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 {
+ synchronized (lock) {
+ if (!isOpen)
+ return;
+ isOpen = false;
+ if (!streams.isEmpty()) {
+ synchronized(streams) {
+ for (InputStream is: streams)
+ is.close();
+ }
+ }
+ sync();
+ ch.close();
+ }
+ synchronized (inflaters) {
+ for (Inflater inf : inflaters)
+ inf.end();
+ }
+ synchronized (deflaters) {
+ for (Deflater def : deflaters)
+ def.end();
+ }
+ for (Path p: tmppaths) {
+ try {
+ p.deleteIfExists();
+ } catch (IOException x) {
+ x.printStackTrace();
+ }
+ }
+ provider.removeFileSystem(zfpath);
+ }
+
+ ZipFileAttributes[] getAllAttributes() throws IOException {
+ ensureOpen();
+ int n = inodes.size();
+ ZipFileAttributes[] zes = new ZipFileAttributes[n];
+ Iterator itr = inodes.values().iterator();
+ int i = 0;
+ while(itr.hasNext()) {
+ zes[i++] = new ZipFileAttributes(Entry.readCEN(cen, itr.next().pos));
+ }
+ return zes;
+ }
+
+ EntryName[] getEntryNames() throws IOException {
+ ensureOpen();
+ return inodes.keySet().toArray(new EntryName[0]);
+ }
+
+ ZipFileAttributes getFileAttributes(byte[] path)
+ throws IOException
+ {
+ synchronized (lock) {
+ Entry e = getEntry0(path);
+ if (e == null) {
+ if (path.length == 0) {
+ e = new Entry(new byte[0]); // root
+ } else if (buildDirTree) {
+ IndexNode inode = getDirs().get(new EntryName(path));
+ if (inode == null)
+ return null;
+ e = new Entry(inode.name);
+ } else {
+ return null;
+ }
+ e.method = METHOD_STORED; // STORED for dir
+ BasicFileAttributes bfas = Attributes.readBasicFileAttributes(zfpath);
+ if (bfas.lastModifiedTime() != null)
+ e.mtime = javaToDosTime(bfas.lastModifiedTime().toMillis());
+ if (bfas.lastAccessTime() != null)
+ e.atime = javaToDosTime(bfas.lastAccessTime().toMillis());
+ if (bfas.creationTime() != null)
+ e.ctime = javaToDosTime(bfas.creationTime().toMillis());
+ }
+ return new ZipFileAttributes(e);
+ }
+ }
+
+ void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime)
+ throws IOException
+ {
+ checkWritable();
+ synchronized (lock) {
+ 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 = javaToDosTime(mtime.toMillis());
+ if (atime != null)
+ e.atime = javaToDosTime(atime.toMillis());
+ if (ctime != null)
+ e.ctime = javaToDosTime(ctime.toMillis());
+ update(e);
+ }
+ }
+
+ boolean exists(byte[] path)
+ throws IOException
+ {
+ return getEntry0(path) != null;
+ }
+
+ boolean isDirectory(byte[] path)
+ throws IOException
+ {
+ synchronized (lock) {
+ if (buildDirTree) {
+ return getDirs().containsKey(new EntryName(path));
+ }
+ Entry e = getEntry0(path);
+ return (e != null && e.isDir()) || path.length == 0;
+ }
+ }
+
+ 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 super Path> filter)
+ throws IOException
+ {
+ synchronized (lock) {
+ if (buildDirTree) {
+ IndexNode inode = getDirs().get(new EntryName(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();
+ }
+
+ if (!isDirectory(path))
+ throw new NotDirectoryException(getString(path));
+ List list = new ArrayList();
+ EntryName[] entries = getEntryNames();
+ path = toDirectoryPath(path);
+ for (EntryName en :entries) {
+ if (!isParentOf(path, en.name)) // is "path" the parent of "name"
+ continue;
+ int off = path.length;
+ while (off < en.name.length) {
+ if (en.name[off] == '/')
+ break;
+ off++;
+ }
+ if (off < (en.name.length - 1))
+ continue;
+ ZipPath zp = toZipPath(en.name);
+ if (filter == null || filter.accept(zp))
+ list.add(zp);
+ }
+ return list.iterator();
+ }
+ }
+
+ void createDirectory(byte[] dir, FileAttribute>... attrs)
+ throws IOException
+ {
+ checkWritable();
+ dir = toDirectoryPath(dir);
+ synchronized (lock) {
+ ensureOpen();
+ // pseudo root dir, or exiting dir
+ if (dir.length == 0 || exists(dir))
+ throw new FileAlreadyExistsException(getString(dir));
+ checkParents(dir);
+
+ Entry e = new Entry(dir, Entry.NEW);
+ e.method = METHOD_STORED; // STORED for dir
+ update(e);
+ }
+ }
+
+ 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
+ synchronized (lock) {
+ 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
+ // don't touch the "nlen and elen" here. writeLOC() always
+ // re-calculate from "name" and "extra" for the correct length,
+ // copyLOCEntry however needs the original lengths to skip the
+ // loc header.
+ // u.nlen = dst.length;
+ if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH)
+ {
+ u.type = eSrc.type; // make it the same type
+ if (!deletesrc) { // if it's not "rename", just take the data
+ if (eSrc.bytes != null)
+ u.bytes = Arrays.copyOf(eSrc.bytes, eSrc.bytes.length);
+ else if (eSrc.file != null) {
+ u.file = getTempPathForEntry(null);
+ eSrc.file.copyTo(u.file, REPLACE_EXISTING);
+ }
+ }
+ }
+ if (!hasCopyAttrs)
+ u.mtime = u.atime= u.ctime = javaToDosTime(System.currentTimeMillis());
+ update(u);
+ if (deletesrc)
+ updateDelete(eSrc);
+ }
+ }
+
+ // 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;
+ }
+ synchronized (lock) {
+ 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));
+ }
+ }
+ }
+
+ // Returns an input stream for reading the contents of the specified
+ // file entry.
+ InputStream newInputStream(byte[] path) throws IOException {
+ synchronized (lock) {
+ 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);
+ }
+ }
+
+ private void checkOptions(Set extends OpenOption> 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 extends OpenOption> options,
+ FileAttribute>... attrs)
+ throws IOException
+ {
+ checkOptions(options);
+ if (options.contains(StandardOpenOption.WRITE) ||
+ options.contains(StandardOpenOption.APPEND)) {
+ checkWritable();
+ 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();
+ }
+ };
+ } else {
+ 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 {
+ return rbc.read(dst);
+ }
+ 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();
+ }
+ };
+ }
+ }
+
+ // 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 extends OpenOption> options,
+ FileAttribute>... attrs)
+ throws IOException
+ {
+ checkOptions(options);
+ final boolean forWrite = (options.contains(StandardOpenOption.WRITE) ||
+ options.contains(StandardOpenOption.APPEND));
+ 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 = javaToDosTime(System.currentTimeMillis());
+ u.size = Attributes.readBasicFileAttributes(u.file).size();
+ update(u);
+ } else {
+ if (!isFCH) // if this is a new fch for reading
+ removeTempPathForEntry(tmpfile);
+ }
+ }
+ };
+ }
+
+ // 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 = new HashSet<>();
+ private Path getTempPathForEntry(byte[] path) throws IOException {
+ Path tmpPath = createTempFileInSameDirectoryAs(zfpath);
+ tmppaths.add(tmpPath);
+
+ if (path != null) {
+ Entry e = getEntry0(path);
+ if (e != null) {
+ InputStream is = newInputStream(path);
+ OutputStream os = tmpPath.newOutputStream(WRITE);
+ try {
+ copyStream(is, os);
+ } finally {
+ is.close();
+ os.close();
+ }
+ }
+ }
+ return tmpPath;
+ }
+
+ private void removeTempPathForEntry(Path path) throws IOException {
+ path.delete();
+ 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 {
+ while ((path = getParent(path)) != null) {
+ if (!inodes.containsKey(new EntryName(path)))
+ throw new NoSuchFileException(getString(path));
+ }
+ }
+
+ 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 null; // top entry
+ return Arrays.copyOf(path, off + 1);
+ }
+
+ // If "starter" is the parent directory of "path"
+ private static boolean isParentOf(byte[] p, byte[] c) {
+ final int plen = p.length;
+ if (plen == 0) // root dir
+ return true;
+ if (plen >= c.length)
+ return false;
+ int n = 0;
+ while (n < plen) {
+ if (p[n] != c[n])
+ return false;
+ n++;
+ }
+ if (p[n - 1] != '/' && (c[n] != '/' || n == c.length - 1))
+ return false;
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ private void initZipFile() throws IOException {
+ ch = zfpath.newByteChannel(READ);
+ initCEN();
+ }
+
+ private volatile boolean isOpen = true;
+ private SeekableByteChannel ch; // channel to the zipfile
+ ByteBuffer cen; // CEN & ENDHDR
+ private END end;
+ private long locpos; // position of first LOC header (usually 0)
+
+ // name -> pos (in cen), package private for ZipInfo
+ LinkedHashMap inodes;
+
+ byte[] getBytes(String name) {
+ return zc.getBytes(name);
+ }
+ 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).
+ private 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 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 occured. 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 long initCEN() throws IOException {
+ end = findEND();
+ if (end.endpos == 0) {
+ inodes = new LinkedHashMap(10);
+ locpos = 0;
+ return 0; // 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
+ cen = ByteBuffer.allocate((int)(end.cenlen + ENDHDR));
+ if (readFullyAt(cen, cenpos) != end.cenlen + ENDHDR) {
+ zerror("read CEN tables failed");
+ }
+ cen.order(ByteOrder.LITTLE_ENDIAN).flip();
+
+ // Iterate through the entries in the central directory
+ inodes = new LinkedHashMap(end.centot + 1);
+ int pos = 0;
+ int limit = cen.remaining() - ENDHDR;
+ int i = 0;
+ byte[] bBuf = new byte[1024];
+ 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 (bad compression method: " + method + ")");
+ if (pos + CENHDR + nlen > limit)
+ zerror("invalid CEN header (bad header size)");
+ if (bBuf.length < nlen)
+ bBuf = new byte[nlen];
+ cen.position(pos + CENHDR);
+ byte[] name = new byte[nlen];
+ cen.get(name);
+ inodes.put(new EntryName(name), new IndexNode(name, pos));
+ // skip ext and comment
+ cen.position(pos += (CENHDR + nlen + elen + clen));
+ i++;
+ }
+ if (cen.remaining() != ENDHDR) {
+ zerror("invalid CEN header (bad header size)");
+ }
+ dirs = null; // clear the dir map
+ return cenpos;
+ }
+
+ 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 File.createTempFile.
+ private static Path createTempFileInSameDirectoryAs(Path path)
+ throws IOException
+ {
+ Path parent = path.toAbsolutePath().getParent();
+ String dir = (parent == null)? "." : parent.toString();
+ return File.createTempFile("zipfstmp", null, new File(dir)).toPath();
+ }
+
+ ////////////////////update & sync //////////////////////////////////////
+
+ private boolean hasUpdate = false;
+ private void updateDelete(Entry e) {
+ EntryName en = new EntryName(e.name);
+ inodes.remove(en);
+ hasUpdate = true;
+ }
+
+ private void update(Entry e) {
+ EntryName en = new EntryName(e.name);
+ inodes.put(en, e);
+ hasUpdate = true;
+ }
+
+ // 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;
+ }
+ if (updateHeader) { // if we need update the loc header
+ locoff += LOCHDR + e.nlen + e.elen; // skip header
+ size += e.csize;
+ written = e.writeLOC(os) + size;
+ } else {
+ size += LOCHDR + e.nlen + e.elen + e.csize;
+ written = 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 {
+ assert Thread.holdsLock(this);
+
+ // check ex-closer
+ if (!exChClosers.isEmpty()) {
+ for (ExChannelCloser ecc : exChClosers) {
+ if (ecc.streams.isEmpty()) {
+ ecc.ch.close();
+ ecc.path.delete();
+ exChClosers.remove(ecc);
+ }
+ }
+ }
+ if (!hasUpdate)
+ return;
+
+ Path tmpFile = createTempFileInSameDirectoryAs(zfpath);
+ OutputStream os = tmpFile.newOutputStream(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 or FILECH
+ 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
+ InputStream is = e.file.newInputStream();
+ 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
+ OutputStream os2 = new EntryOutputStream(e, os);
+ while ((n = is.read(buf)) != -1) {
+ os2.write(buf, 0, n);
+ }
+ os2.close();
+ written += e.csize;
+ if ((e.flag & FLAG_DATADESCR) != 0)
+ written += e.writeEXT(os);
+ }
+ is.close();
+ e.file.delete();
+ 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
+ e = Entry.readCEN(cen, 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);
+ os.close();
+
+ if (!streams.isEmpty()) {
+ // 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);
+ zfpath.moveTo(ecc.path, REPLACE_EXISTING);
+ exChClosers.add(ecc);
+ streams = Collections.synchronizedSet(new HashSet());
+ } else {
+ ch.close();
+ zfpath.delete();
+ }
+ tmpFile.moveTo(zfpath, REPLACE_EXISTING);
+ hasUpdate = false; // clear
+
+ if (isOpen) {
+ ch = zfpath.newByteChannel(READ); // re-fresh "ch" and "cen"
+ initCEN();
+ }
+ //System.out.println("->sync() done!");
+ }
+
+ private Entry getEntry0(byte[] path) throws IOException {
+ assert Thread.holdsLock(this);
+
+ if (path == null)
+ throw new NullPointerException("path");
+ if (path.length == 0)
+ return null;
+ EntryName en = new EntryName(path);
+ IndexNode inode = null;
+ synchronized (lock) {
+ ensureOpen();
+ if ((inode = inodes.get(en)) == null) {
+ if (path[path.length -1] == '/') // already has a slash
+ return null;
+ path = Arrays.copyOf(path, path.length + 1);
+ path[path.length - 1] = '/';
+ en.name(path);
+ if ((inode = inodes.get(en)) == null)
+ return null;
+ }
+ if (inode instanceof Entry)
+ return (Entry)inode;
+ return Entry.readCEN(cen, inode.pos);
+ }
+ }
+
+ // Test if the "name" a parent directory of any entry (dir empty)
+ boolean isAncestor(byte[] name) {
+ for (Map.Entry entry : inodes.entrySet()) {
+ byte[] ename = entry.getKey().name;
+ if (isParentOf(name, ename))
+ return true;
+ }
+ return false;
+ }
+
+ public void deleteFile(byte[] path, boolean failIfNotExists)
+ throws IOException
+ {
+ checkWritable();
+ synchronized(lock) {
+ Entry e = getEntry0(path);
+ if (e == 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 (e.isDir() && isAncestor(path))
+ throw new DirectoryNotEmptyException(getString(path));
+ updateDelete(e);
+ }
+ }
+ }
+
+ 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 {
+
+ ensureOpen();
+ if (e.mtime == -1)
+ e.mtime = javaToDosTime(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 = e.file.newOutputStream(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 = e.file.newInputStream();
+ else
+ throw new ZipException("update entry data is missing");
+ } else if (e.type == Entry.FILECH) {
+ // FILECH result is un-compressed.
+ eis = e.file.newInputStream();
+ // 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;
+ }
+ }
+ // 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) {
+ 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 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 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);
+ }
+ }
+
+ private 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 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 = (Inflater)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 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 = (Deflater)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);
+ }
+ }
+ }
+
+ // wrapper for the byte[] name
+ static class EntryName {
+ byte[] name;
+ int hashcode; // node is hashable/hashed by its name
+
+ public EntryName (byte[] name) {
+ name(name);
+ }
+
+ void name(byte[] name) {
+ this.name = name;
+ this.hashcode = Arrays.hashCode(name);
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof EntryName))
+ return false;
+ return Arrays.equals(name, ((EntryName)other).name);
+ }
+
+ public int hashCode() {
+ return hashcode;
+ }
+ }
+
+ // can simply use Integer instead, if we don't use it to
+ // build a internal node tree.
+ static class IndexNode {
+ byte[] name;
+ int pos = -1; // postion in cen table, -1 menas the
+ // entry does not exists in zip file
+ IndexNode(byte[] name, int pos) {
+ this.name = name;
+ this.pos = pos;
+ }
+
+ 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
+ int nlen;
+ int elen;
+ byte[] extra;
+
+ // loc
+ long startPos;
+ long endPos; // exclusive
+
+ // cen
+ int versionMade;
+ int disk;
+ int attrs;
+ long attrsEx;
+ long locoff;
+
+ int clen;
+ byte[] comment;
+
+ // ZIP64 flag
+ boolean hasZip64;
+
+ Entry() {}
+
+ Entry(byte[] name) {
+ this.name = name;
+ //this.nlen = name.length;
+ this.mtime = javaToDosTime(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 (byte[] name, Path file, int type) {
+ this(name, type);
+ this.file = file;
+ this.method = METHOD_STORED;
+ }
+
+ Entry(Entry e) {
+ this.version = e.version;
+ this.name = e.name; // copyOf?
+ this.nlen = e.nlen;
+ 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 == null)?
+ null:Arrays.copyOf(e.extra, e.extra.length);
+ this.elen = e.elen;
+ this.versionMade = e.versionMade;
+ this.disk = e.disk;
+ this.attrs = e.attrs;
+ this.attrsEx = e.attrsEx;
+ this.locoff = e.locoff;
+ this.clen = e.clen;
+ this.comment = (e.comment == null)?
+ null:Arrays.copyOf(e.comment, e.comment.length);
+ this.startPos = e.startPos;
+ this.endPos = e.endPos;
+ this.hasZip64 = e.hasZip64;;
+ }
+
+ Entry (Entry e, int type) {
+ this(e);
+ this.type = type;
+ }
+
+ boolean isDir() {
+ return name != null &&
+ (name.length == 0 ||
+ name[name.length - 1] == '/');
+ }
+
+ 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(ByteBuffer cen, int pos) throws IOException
+ {
+ return new Entry().cen(cen, pos);
+ }
+
+ private Entry cen(ByteBuffer cen, int pos) throws IOException
+ {
+ 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 = CENTIM(cen, pos);
+ crc = CENCRC(cen, pos);
+ csize = CENSIZ(cen, pos);
+ size = CENLEN(cen, pos);
+ nlen = CENNAM(cen, pos);
+ elen = CENEXT(cen, pos);
+ clen = CENCOM(cen, pos);
+ disk = CENDSK(cen, pos);
+ attrs = CENATT(cen, pos);
+ attrsEx = CENATX(cen, pos);
+ locoff = CENOFF(cen, pos);
+
+ cen.position(pos + CENHDR);
+ name = new byte[nlen];
+ cen.get(name);
+
+ if (elen > 0) {
+ extra = new byte[elen];
+ cen.get(extra);
+ if (csize == ZIP64_MINVAL || size == ZIP64_MINVAL ||
+ locoff == ZIP64_MINVAL) {
+ int off = 0;
+ while (off + 4 < elen) {
+ // extra spec: HeaderID+DataSize+Data
+ int sz = SH(extra, off + 2);
+ if (SH(extra, off) == EXTID_ZIP64) {
+ off += 4;
+ if (size == ZIP64_MINVAL) {
+ // if invalid zip64 extra fields, just skip
+ if (sz < 8 || (off + 8) > elen)
+ break;
+ size = LL(extra, off);
+ sz -= 8;
+ off += 8;
+ }
+ if (csize == ZIP64_MINVAL) {
+ if (sz < 8 || (off + 8) > elen)
+ break;
+ csize = LL(extra, off);
+ sz -= 8;
+ off += 8;
+ }
+ if (locoff == ZIP64_MINVAL) {
+ if (sz < 8 || (off + 8) > elen)
+ break;
+ locoff = LL(extra, off);
+ sz -= 8;
+ off += 8;
+ }
+ break;
+ }
+ off += (sz + 4);
+ }
+ }
+ }
+ if (clen > 0) {
+ comment = new byte[clen];
+ cen.get(comment);
+ }
+ return this;
+ }
+
+ int writeCEN(OutputStream os) throws IOException
+ {
+ int written = CENHDR;
+ int version0 = version();
+
+ long csize0 = csize;
+ long size0 = size;
+ long locoff0 = locoff;
+ int e64len = 0;
+
+ // confirm size/length
+ nlen = (name != null) ? name.length : 0;
+ elen = (extra != null) ? extra.length : 0;
+ clen = (comment != null) ? comment.length : 0;
+
+ boolean hasZip64 = false;
+ if (csize >= ZIP64_MINVAL) {
+ csize0 = ZIP64_MINVAL;
+ e64len += 8; // csize(8)
+ hasZip64 = true;
+ }
+ if (size >= ZIP64_MINVAL) {
+ size0 = ZIP64_MINVAL; // size(8)
+ e64len += 8;
+ hasZip64 = true;
+ }
+ if (locoff >= ZIP64_MINVAL) {
+ locoff0 = ZIP64_MINVAL;
+ e64len += 8; // offset(8)
+ hasZip64 = true;
+ }
+ writeInt(os, CENSIG); // CEN header signature
+ if (hasZip64) {
+ 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
+ writeInt(os, mtime); // last modification time
+ writeInt(os, crc); // crc-32
+ writeInt(os, csize0); // compressed size
+ writeInt(os, size0); // uncompressed size
+ writeShort(os, name.length);
+
+ if (hasZip64) {
+ // + headid(2) + datasize(2)
+ writeShort(os, e64len + 4 + elen);
+ } else {
+ writeShort(os, elen);
+ }
+ 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 (hasZip64) {
+ writeShort(os, EXTID_ZIP64);// Zip64 extra
+ writeShort(os, e64len);
+ if (size0 == ZIP64_MINVAL)
+ writeLong(os, size);
+ if (csize0 == ZIP64_MINVAL)
+ writeLong(os, csize);
+ if (locoff0 == ZIP64_MINVAL)
+ writeLong(os, locoff);
+ }
+ if (extra != null) {
+ writeBytes(os, extra);
+ }
+ if (comment != null) {
+ //TBD: 0, Math.min(commentBytes.length, 0xffff));
+ writeBytes(os, comment);
+ }
+ return CENHDR + nlen + elen + clen + (hasZip64?(e64len + 4):0);
+ }
+
+ ///////////////////// LOC //////////////////////
+ static Entry readLOC(ZipFileSystem zf, long pos)
+ throws IOException
+ {
+ return readLOC(zf, pos, new byte[1024]);
+ }
+
+ static Entry readLOC(ZipFileSystem zf, long pos, byte[] buf)
+ throws IOException
+ {
+ return new Entry().loc(zf, pos, buf);
+ }
+
+ Entry loc(ZipFileSystem zf, long pos, byte[] buf)
+ throws IOException
+ {
+ assert (buf.length >= LOCHDR);
+ if (zf.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 = LOCTIM(buf);
+ crc = LOCCRC(buf);
+ csize = LOCSIZ(buf);
+ size = LOCLEN(buf);
+ nlen = LOCNAM(buf);
+ elen = LOCEXT(buf);
+
+ name = new byte[nlen];
+ if (zf.readFullyAt(name, 0, nlen, pos + LOCHDR) != nlen) {
+ throw new ZipException("loc: name reading failed");
+ }
+ if (elen > 0) {
+ extra = new byte[elen];
+ if (zf.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 = zf.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 {
+ boolean hasZip64 = false;
+ 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);
+ hasZip64 = true;
+ break;
+ }
+ off += (sz + 4);
+ }
+ }
+ pos += (method == METHOD_STORED ? size : csize);
+ }
+ endPos = pos;
+ return this;
+ }
+
+ int writeLOC(OutputStream os)
+ throws IOException
+ {
+ writeInt(os, LOCSIG); // LOC header signature
+
+ int version = version();
+ if ((flag & FLAG_DATADESCR) != 0) {
+ writeShort(os, version()); // version needed to extract
+ writeShort(os, flag); // general purpose bit flag
+ writeShort(os, method); // compression method
+ writeInt(os, mtime); // last modification time
+
+ // 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) {
+ hasZip64 = true;
+ 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
+ writeInt(os, mtime); // last modification time
+ writeInt(os, crc); // crc-32
+ if (hasZip64) {
+ writeInt(os, ZIP64_MINVAL);
+ writeInt(os, ZIP64_MINVAL);
+ //TBD: e.elen += 20; //headid(2) + size(2) + size(8) + csize(8)
+ } else {
+ writeInt(os, csize); // compressed size
+ writeInt(os, size); // uncompressed size
+ }
+ }
+ writeShort(os, name.length);
+ writeShort(os, elen + (hasZip64 ? 20 : 0));
+ writeBytes(os, name);
+ if (hasZip64) {
+ // TBD: should we update extra directory?
+ writeShort(os, EXTID_ZIP64);
+ writeShort(os, 16);
+ writeLong(os, size);
+ writeLong(os, csize);
+ }
+ if (extra != null) {
+ writeBytes(os, extra);
+ }
+ return LOCHDR + name.length + elen + (hasZip64 ? 20 : 0);
+ }
+
+ // 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() {
+ if (extra == null)
+ return;
+ int elen = extra.length;
+ int off = 0;
+ while (off + 4 < elen) {
+ // extra spec: HeaderID+DataSize+Data
+ int sz = SH(extra, off + 2);
+ int tag = SH(extra, off);
+ off += 4;
+ int pos = off;
+ 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;
+ mtime = LL(extra, pos + 4);
+ atime = LL(extra, pos + 12);
+ ctime = LL(extra, pos + 20);
+ break;
+ case EXTID_UNIX:
+ atime = LG(extra, pos);
+ mtime = LG(extra, pos + 4);
+ break;
+ default: // unknow
+ }
+ off += sz;
+ }
+ }
+ }
+
+ 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 HashMap dirs;
+ private IndexNode root;
+ private IndexNode addToDir(EntryName child) {
+ IndexNode cinode = dirs.get(child);
+ if (cinode != null)
+ return cinode;
+
+ byte[] cname = child.name;
+ byte[] pname = getParent(cname);
+ IndexNode pinode;
+
+ if (pname != null)
+ pinode = addToDir(new EntryName(pname));
+ else
+ pinode = root;
+ cinode = inodes.get(child);
+ if (cname[cname.length -1] != '/') { // not a dir
+ cinode.sibling = pinode.child;
+ pinode.child = cinode;
+ return null;
+ }
+ cinode = dirs.get(child);
+ if (cinode == null) // pseudo directry entry
+ cinode = new IndexNode(cname, -1);
+ cinode.sibling = pinode.child;
+ pinode.child = cinode;
+
+ dirs.put(child, cinode);
+ return cinode;
+ }
+
+ private HashMap getDirs()
+ throws IOException
+ {
+ if (hasUpdate)
+ sync();
+ if (dirs != null)
+ return dirs;
+ dirs = new HashMap();
+ byte[] empty = new byte[0];
+ root = new IndexNode(empty, -1);
+ dirs.put(new EntryName(empty), root);
+
+ EntryName[] names = inodes.keySet().toArray(new EntryName[0]);
+ int i = names.length;
+ while (--i >= 0) {
+ addToDir(names[i]);
+ }
+ // for (int i EntryName en : inodes.keySet()) {
+ // addToDir(en);
+ // }
+ return dirs;
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileSystemProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipFileSystemProvider.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+package com.sun.nio.zipfs;
+
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.file.FileRef;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemNotFoundException;
+import java.nio.file.FileSystemAlreadyExistsException;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.ProviderMismatchException;
+import java.nio.file.attribute.FileAttribute;
+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;
+
+/*
+ *
+ * @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 "zip";
+ }
+
+ protected Path uriToPath(URI uri) {
+ String scheme = uri.getScheme();
+ if ((scheme == null) || !scheme.equalsIgnoreCase(getScheme())) {
+ throw new IllegalArgumentException("URI scheme is not '" + getScheme() + "'");
+ }
+ try {
+ return Paths.get(new URI("file", uri.getHost(), uri.getPath(), null))
+ .toAbsolutePath();
+ } catch (URISyntaxException e) {
+ throw new AssertionError(e); //never thrown
+ }
+ }
+
+ @Override
+ public FileSystem newFileSystem(URI uri, Map env)
+ throws IOException
+ {
+ return newFileSystem(uriToPath(uri), env);
+ }
+
+ @Override
+ public FileSystem newFileSystem(FileRef file, Map env)
+ throws IOException
+ {
+ if (!(file instanceof Path))
+ throw new UnsupportedOperationException();
+ Path path = (Path)file;
+ if (!path.toUri().getScheme().equalsIgnoreCase("file")) {
+ throw new UnsupportedOperationException();
+ }
+ return newFileSystem(path, env);
+ }
+
+ private FileSystem newFileSystem(Path path, Map env)
+ throws IOException
+ {
+ synchronized(filesystems) {
+ if (filesystems.containsKey(path))
+ throw new FileSystemAlreadyExistsException();
+ ZipFileSystem zipfs = new ZipFileSystem(this, path, env);
+ filesystems.put(path, zipfs);
+ return zipfs;
+ }
+ }
+
+ @Override
+ public Path getPath(URI uri) {
+ FileSystem fs = getFileSystem(uri);
+ String fragment = uri.getFragment();
+ if (fragment == null) {
+ throw new IllegalArgumentException("URI: "
+ + uri
+ + " does not contain path fragment ex. zip:///c:/foo.zip#/BAR");
+ }
+ return fs.getPath(fragment);
+ }
+
+ @Override
+ public FileChannel newFileChannel(Path path,
+ Set extends OpenOption> options,
+ FileAttribute>... attrs)
+ throws IOException
+ {
+ if (path == null)
+ throw new NullPointerException("path is null");
+ if (path instanceof ZipPath)
+ return ((ZipPath)path).newFileChannel(options, attrs);
+ throw new ProviderMismatchException();
+ }
+
+ @Override
+ public FileSystem getFileSystem(URI uri) {
+ synchronized (filesystems) {
+ ZipFileSystem zipfs = filesystems.get(uriToPath(uri));
+ if (zipfs == null)
+ throw new FileSystemNotFoundException();
+ return zipfs;
+ }
+ }
+
+ void removeFileSystem(Path zfpath) {
+ synchronized (filesystems) {
+ filesystems.remove(zfpath);
+ }
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipInfo.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipInfo.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+package com.sun.nio.zipfs;
+
+import java.io.PrintStream;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import com.sun.nio.zipfs.ZipFileSystem.Entry;
+import static com.sun.nio.zipfs.ZipConstants.*;
+import static com.sun.nio.zipfs.ZipUtils.*;
+
+/**
+ * Print the loc and cen tables of the ZIP file
+ *
+ * @author Xueming Shen
+ */
+
+public class ZipInfo {
+
+ public static void main(String[] args) throws Throwable {
+ if (args.length < 2) {
+ print("Usage: java ZipInfo [cen|loc] zfname");
+ } else {
+ Map env = Collections.emptyMap();
+ ZipFileSystem zfs = (ZipFileSystem)(new ZipFileSystemProvider()
+ .newFileSystem(Paths.get(args[1]), env));
+
+ long pos = 0;
+
+ if ("loc".equals(args[0])) {
+ print("[Local File Header]%n");
+ byte[] buf = new byte[1024];
+ for (int i = 0; i < zfs.getEntryNames().length; i++) {
+ Entry loc = Entry.readLOC(zfs, pos, buf);
+ print("--------loc[%x]--------%n", pos);
+ printLOC(loc);
+ pos = loc.endPos;
+ }
+ } if ("cen".equals(args[0])) {
+ int i = 0;
+ Iterator itr = zfs.inodes.values().iterator();
+ print("[Central Directory Header]%n");
+ while (itr.hasNext()) {
+ Entry cen = Entry.readCEN(zfs.cen, itr.next().pos);
+ print("--------cen[%d]--------%n", i);
+ printCEN(cen);
+ i++;
+ }
+ }
+ zfs.close();
+ }
+ }
+
+ static void print(String fmt, Object... objs) {
+ System.out.printf(fmt, objs);
+ }
+
+ static void printLOC(Entry loc) {
+ print(" [%x, %x]%n", loc.startPos, loc.endPos);
+ print(" Signature : %8x%n", LOCSIG);
+ print(" Version : %4x [%d.%d]%n",
+ loc.version, loc. version/10, loc. version%10);
+ print(" Flag : %4x%n", loc.flag);
+ print(" Method : %4x%n", loc. method);
+ print(" LastMTime : %8x [%tc]%n",
+ loc.mtime, dosToJavaTime(loc.mtime));
+ print(" CRC : %8x%n", loc.crc);
+ print(" CSize : %8x%n", loc.csize);
+ print(" Size : %8x%n", loc.size);
+ print(" NameLength : %4x [%s]%n",
+ loc.nlen, new String(loc.name));
+ print(" ExtraLength : %4x%n", loc.elen);
+ if (loc.hasZip64)
+ print(" *ZIP64*%n");
+ }
+
+ static void printCEN(Entry cen) {
+ print(" Signature : %08x%n", CENSIG);
+ print(" VerMadeby : %4x [%d.%d]%n",
+ cen.versionMade, cen.versionMade/10, cen.versionMade%10);
+ print(" VerExtract : %4x [%d.%d]%n",
+ cen.version, cen.version/10, cen.version%10);
+ print(" Flag : %4x%n", cen.flag);
+ print(" Method : %4x%n", cen.method);
+ print(" LastMTime : %8x [%tc]%n",
+ cen.mtime, dosToJavaTime(cen.mtime));
+ print(" CRC : %8x%n", cen.crc);
+ print(" CSize : %8x%n", cen.csize);
+ print(" Size : %8x%n", cen.size);
+ print(" NameLen : %4x [%s]%n",
+ cen.nlen, new String(cen.name));
+ print(" ExtraLen : %4x%n", cen.elen);
+ print(" CommentLen : %4x%n", cen.clen);
+ print(" DiskStart : %4x%n", cen.disk);
+ print(" Attrs : %4x%n", cen.attrs);
+ print(" AttrsEx : %8x%n", cen.attrsEx);
+ print(" LocOff : %8x%n", cen.locoff);
+ if (cen.hasZip64)
+ print(" *ZIP64*%n");
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipPath.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipPath.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,964 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+package com.sun.nio.zipfs;
+
+import java.io.File;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.*;
+import java.nio.file.DirectoryStream.Filter;
+import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileTime;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import static java.nio.file.StandardOpenOption.*;
+import static java.nio.file.StandardCopyOption.*;
+
+/**
+ *
+ * @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal
+ */
+
+public class ZipPath extends 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 getName() {
+ 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(boolean resolveLinks) throws IOException {
+ ZipPath realPath = new ZipPath(zfs, getResolvedPath());
+ realPath.checkAccess();
+ return realPath;
+ }
+
+ @Override
+ public 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() {
+ String zfPath = zfs.toString();
+ if (File.separatorChar == '\\') // replace all separators by '/'
+ zfPath = "/" + zfPath.replace("\\", "/");
+ try {
+ return new URI("zip", "",
+ zfPath,
+ zfs.getString(toAbsolutePath().path));
+ } 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 null;
+ 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[0] == '/');
+ }
+
+ @Override
+ public ZipPath resolve(Path other) {
+ if (other == null)
+ return this;
+ 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 ZipPath resolve(String other) {
+ return resolve(getFileSystem().getPath(other));
+ }
+
+ @Override
+ public boolean startsWith(Path other) {
+ final ZipPath o = checkPath(other);
+ if (o.isAbsolute() != this.isAbsolute())
+ return false;
+ final int oCount = o.getNameCount();
+ if (getNameCount() < oCount)
+ return false;
+ for (int i = 0; i < oCount; i++) {
+ if (!o.getName(i).equals(getName(i)))
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean endsWith(Path other) {
+ final ZipPath o = checkPath(other);
+ if (o.isAbsolute())
+ return this.isAbsolute() ? this.equals(o) : false;
+ int i = o.getNameCount();
+ int j = this.getNameCount();
+ if (j < i)
+ return false;
+ for (--i, --j; i >= 0; i--, j--) {
+ if (!o.getName(i).equals(this.getName(j)))
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public Path normalize() {
+ byte[] resolved = getResolved();
+ if (resolved == path) // no change
+ return this;
+ if (resolved.length == 0)
+ return null;
+ 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)'.')
+ 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;
+ }
+
+ @Override
+ public Path createSymbolicLink(
+ Path target, FileAttribute>... attrs) throws IOException {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public Path createLink(
+ Path existing) throws IOException {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public Path readSymbolicLink() throws IOException {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
+ @Override
+ public Path createDirectory(FileAttribute>... attrs)
+ throws IOException
+ {
+ zfs.createDirectory(getResolvedPath(), attrs);
+ return this;
+ }
+
+ public final Path createFile(FileAttribute>... attrs)
+ throws IOException
+ {
+ OutputStream os = newOutputStream(CREATE_NEW, WRITE);
+ try {
+ os.close();
+ } catch (IOException x) {}
+ return this;
+ }
+
+ @Override
+ public 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());
+ }
+
+ private static final DirectoryStream.Filter acceptAllFilter =
+ new DirectoryStream.Filter() {
+ @Override public boolean accept(Path entry) { return true; }
+ };
+
+ @Override
+ public final DirectoryStream newDirectoryStream() throws IOException {
+ return newDirectoryStream(acceptAllFilter);
+ }
+
+ @Override
+ public DirectoryStream newDirectoryStream(Filter super Path> filter)
+ throws IOException
+ {
+ return new ZipDirectoryStream(this, filter);
+ }
+
+ @Override
+ public final DirectoryStream newDirectoryStream(String glob)
+ throws IOException
+ {
+ // avoid creating a matcher if all entries are required.
+ if (glob.equals("*"))
+ return newDirectoryStream();
+
+ // create a matcher and return a filter that uses it.
+ final PathMatcher matcher = getFileSystem().getPathMatcher("glob:" + glob);
+ DirectoryStream.Filter filter = new DirectoryStream.Filter() {
+ @Override
+ public boolean accept(Path entry) {
+ return matcher.matches(entry.getName());
+ }
+ };
+ return newDirectoryStream(filter);
+ }
+
+ @Override
+ public final void delete() throws IOException {
+ zfs.deleteFile(getResolvedPath(), true);
+ }
+
+ @Override
+ public final 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;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public V getFileAttributeView(Class type,
+ LinkOption... options)
+ {
+ return (V)ZipFileAttributeView.get(this, type);
+ }
+
+ @Override
+ public 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);
+ }
+
+ private Object getAttributesImpl(String attribute, boolean domap)
+ throws IOException
+ {
+ String view = null;
+ String attr = null;
+ int colonPos = attribute.indexOf(':');
+ if (colonPos == -1) {
+ view = "basic";
+ attr = attribute;
+ } else {
+ view = attribute.substring(0, colonPos++);
+ attr = attribute.substring(colonPos);
+ }
+ ZipFileAttributeView zfv = ZipFileAttributeView.get(this, view);
+ if (zfv == null) {
+ throw new UnsupportedOperationException("view not supported");
+ }
+ return zfv.getAttribute(attr, domap);
+ }
+
+ @Override
+ public Object getAttribute(String attribute, LinkOption... options)
+ throws IOException
+ {
+ return getAttributesImpl(attribute, false);
+ }
+
+ @Override
+ public Map readAttributes(String attribute, LinkOption... options)
+ throws IOException
+ {
+ return (Map)getAttributesImpl(attribute, true);
+ }
+
+ @Override
+ public 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));
+ }
+
+ @Override
+ public boolean isSameFile(Path other) throws IOException {
+ if (other == null ||
+ this.getFileSystem() != other.getFileSystem())
+ return false;
+ this.checkAccess();
+ other.checkAccess();
+ return Arrays.equals(this.getResolvedPath(),
+ ((ZipPath)other).getResolvedPath());
+ }
+
+ 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 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();
+ }
+ };
+ }
+
+ @Override
+ public SeekableByteChannel newByteChannel(Set extends OpenOption> options,
+ FileAttribute>... attrs)
+ throws IOException
+ {
+ return zfs.newByteChannel(getResolvedPath(), options, attrs);
+ }
+
+
+ FileChannel newFileChannel(Set extends OpenOption> options,
+ FileAttribute>... attrs)
+ throws IOException
+ {
+ return zfs.newFileChannel(getResolvedPath(), options, attrs);
+ }
+
+ @Override
+ public SeekableByteChannel newByteChannel(OpenOption... options)
+ throws IOException {
+ Set set = new HashSet(options.length);
+ Collections.addAll(set, options);
+ return newByteChannel(set);
+ }
+
+ @Override
+ public 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());
+
+ }
+
+ @Override
+ public boolean exists() {
+ if (path.length == 1 && path[0] == '/')
+ return true;
+ try {
+ return zfs.exists(getResolvedPath());
+ } catch (IOException x) {}
+ return false;
+ }
+
+ @Override
+ public boolean notExists() {
+ return !exists();
+ }
+
+
+ @Override
+ public OutputStream newOutputStream(OpenOption... options)
+ throws IOException
+ {
+ if (options.length == 0)
+ return zfs.newOutputStream(getResolvedPath(),
+ CREATE_NEW, WRITE);
+ return zfs.newOutputStream(getResolvedPath(), options);
+ }
+
+ @Override
+ public Path moveTo(Path target, CopyOption... options)
+ throws IOException
+ {
+ if (this.zfs.provider() == target.getFileSystem().provider() &&
+ this.zfs.getZipFile().isSameFile(((ZipPath)target).zfs.getZipFile()))
+ {
+ zfs.copyFile(true,
+ getResolvedPath(),
+ ((ZipPath)target).getResolvedPath(),
+ options);
+ } else {
+ copyToTarget(target, options);
+ delete();
+ }
+ return target;
+ }
+
+ @Override
+ public Path copyTo(Path target, CopyOption... options)
+ throws IOException
+ {
+ if (this.zfs.provider() == target.getFileSystem().provider() &&
+ this.zfs.getZipFile().isSameFile(((ZipPath)target).zfs.getZipFile()))
+ {
+ zfs.copyFile(false,
+ getResolvedPath(),
+ ((ZipPath)target).getResolvedPath(),
+ options);
+ } else {
+ copyToTarget(target, options);
+ }
+ return target;
+ }
+
+ private void copyToTarget(Path 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 = false;
+ }
+ // 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 =
+ target.getFileAttributeView(BasicFileAttributeView.class);
+ try {
+ view.setTimes(zfas.lastModifiedTime(), null, null);
+ } catch (IOException x) {
+ // rollback?
+ try {
+ target.delete();
+ } catch (IOException ignore) { }
+ throw x;
+ }
+ }
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipUtils.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/demo/nio/zipfs/com/sun/nio/zipfs/ZipUtils.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2009, 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.
+ */
+
+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;
+
+/**
+ *
+ * @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 >>> 0) & 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 >>> 0) & 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 >>> 0) & 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;
+ }
+
+ 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 43cb79a6b123 -r d954b585d3a1 jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java
--- a/jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java Wed Oct 13 17:51:41 2010 -0700
@@ -64,7 +64,10 @@
accessor.setFile(fd, null);
accessor.setFiles(fd, null, null);
} else {
- accessor.setDirectory(fd, directory);
+ // Fix 6987233: add the trailing slash if it's absent
+ accessor.setDirectory(fd, directory +
+ (directory.endsWith(File.separator) ?
+ "" : File.separator));
accessor.setFile(fd, filenames[0]);
accessor.setFiles(fd, directory, filenames);
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java
--- a/jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11/XBaseWindow.java Wed Oct 13 17:51:41 2010 -0700
@@ -705,12 +705,8 @@
throw new IllegalStateException("Attempt to resize uncreated window");
}
insLog.fine("Setting bounds on " + this + " to (" + x + ", " + y + "), " + width + "x" + height);
- if (width <= 0) {
- width = 1;
- }
- if (height <= 0) {
- height = 1;
- }
+ width = Math.max(MIN_SIZE, width);
+ height = Math.max(MIN_SIZE, height);
XToolkit.awtLock();
try {
XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), getWindow(), x,y,width,height);
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java
--- a/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11/XDecoratedPeer.java Wed Oct 13 17:51:41 2010 -0700
@@ -763,12 +763,8 @@
}
private void checkShellRectSize(Rectangle shellRect) {
- if (shellRect.width < 0) {
- shellRect.width = 1;
- }
- if (shellRect.height < 0) {
- shellRect.height = 1;
- }
+ shellRect.width = Math.max(MIN_SIZE, shellRect.width);
+ shellRect.height = Math.max(MIN_SIZE, shellRect.height);
}
private void checkShellRectPos(Rectangle shellRect) {
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFrame.java
--- a/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFrame.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFrame.java Wed Oct 13 17:51:41 2010 -0700
@@ -28,9 +28,12 @@
import sun.awt.EmbeddedFrame;
import java.awt.*;
import java.awt.AWTKeyStroke;
+import java.util.logging.Logger;
public class XEmbeddedFrame extends EmbeddedFrame {
+ private static final Logger log = Logger.getLogger(XEmbeddedFrame.class.getName());
+
long handle;
public XEmbeddedFrame() {
}
@@ -70,6 +73,21 @@
this(handle, supportsXEmbed, false);
}
+ /*
+ * The method shouldn't be called in case of active XEmbed.
+ */
+ public boolean traverseIn(boolean direction) {
+ XEmbeddedFramePeer peer = (XEmbeddedFramePeer)getPeer();
+ if (peer != null) {
+ if (peer.supportsXEmbed() && peer.isXEmbedActive()) {
+ log.fine("The method shouldn't be called when XEmbed is active!");
+ } else {
+ return super.traverseIn(direction);
+ }
+ }
+ return false;
+ }
+
protected boolean traverseOut(boolean direction) {
XEmbeddedFramePeer xefp = (XEmbeddedFramePeer) getPeer();
if (direction == FORWARD) {
@@ -81,6 +99,20 @@
return true;
}
+ /*
+ * The method shouldn't be called in case of active XEmbed.
+ */
+ public void synthesizeWindowActivation(boolean doActivate) {
+ XEmbeddedFramePeer peer = (XEmbeddedFramePeer)getPeer();
+ if (peer != null) {
+ if (peer.supportsXEmbed() && peer.isXEmbedActive()) {
+ log.fine("The method shouldn't be called when XEmbed is active!");
+ } else {
+ peer.synthesizeFocusInOut(doActivate);
+ }
+ }
+ }
+
public void registerAccelerator(AWTKeyStroke stroke) {
XEmbeddedFramePeer xefp = (XEmbeddedFramePeer) getPeer();
if (xefp != null) {
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java
--- a/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11/XEmbeddedFramePeer.java Wed Oct 13 17:51:41 2010 -0700
@@ -35,6 +35,8 @@
import sun.awt.EmbeddedFrame;
import sun.awt.SunToolkit;
+import static sun.awt.X11.XConstants.*;
+
public class XEmbeddedFramePeer extends XFramePeer {
private static final PlatformLogger xembedLog = PlatformLogger.getLogger("sun.awt.X11.xembed.XEmbeddedFramePeer");
@@ -305,4 +307,20 @@
EmbeddedFrame frame = (EmbeddedFrame)target;
frame.notifyModalBlocked(blocker, blocked);
}
+
+ public void synthesizeFocusInOut(boolean doFocus) {
+ XFocusChangeEvent xev = new XFocusChangeEvent();
+
+ XToolkit.awtLock();
+ try {
+ xev.set_type(doFocus ? FocusIn : FocusOut);
+ xev.set_window(getFocusProxy().getWindow());
+ xev.set_mode(NotifyNormal);
+ XlibWrapper.XSendEvent(XToolkit.getDisplay(), getFocusProxy().getWindow(), false,
+ NoEventMask, xev.pData);
+ } finally {
+ XToolkit.awtUnlock();
+ xev.dispose();
+ }
+ }
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/solaris/classes/sun/awt/X11/XToolkit.java
--- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java Wed Oct 13 17:51:41 2010 -0700
@@ -1482,8 +1482,19 @@
try {
if (numberOfButtons == 0) {
numberOfButtons = getNumberOfButtonsImpl();
+ numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons;
+ //4th and 5th buttons are for wheel and shouldn't be reported as buttons.
+ //If we have more than 3 physical buttons and a wheel, we report N-2 buttons.
+ //If we have 3 physical buttons and a wheel, we report 3 buttons.
+ //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively.
+ if (numberOfButtons >=5) {
+ numberOfButtons -= 2;
+ } else if (numberOfButtons == 4 || numberOfButtons ==5){
+ numberOfButtons = 3;
+ }
}
- return (numberOfButtons > MAX_BUTTONS_SUPPORTED)? MAX_BUTTONS_SUPPORTED : numberOfButtons;
+ //Assume don't have to re-query the number again and again.
+ return numberOfButtons;
} finally {
awtUnlock();
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/solaris/native/sun/awt/awt_InputMethod.c
--- a/jdk/src/solaris/native/sun/awt/awt_InputMethod.c Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/solaris/native/sun/awt/awt_InputMethod.c Wed Oct 13 17:51:41 2010 -0700
@@ -1473,6 +1473,10 @@
static void DestroyXIMCallback(XIM im, XPointer client_data, XPointer call_data) {
/* mark that XIM server was destroyed */
X11im = NULL;
+ JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+ /* free the old pX11IMData and set it to null. this also avoids crashing
+ * the jvm if the XIM server reappears */
+ X11InputMethodData *pX11IMData = getX11InputMethodData(env, currentX11InputMethodInstance);
}
/*
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java
--- a/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/windows/classes/sun/awt/windows/WComponentPeer.java Wed Oct 13 17:51:41 2010 -0700
@@ -556,24 +556,26 @@
Component target = (Component)getTarget();
Window window = SunToolkit.getContainingWindow(target);
- if (window != null && !window.isOpaque()) {
- // Non-opaque windows do not support heavyweight children.
- // Redirect all painting to the Window's Graphics instead.
- // The caller is responsible for calling the
- // WindowPeer.updateWindow() after painting has finished.
- int x = 0, y = 0;
- for (Component c = target; c != window; c = c.getParent()) {
- x += c.getX();
- y += c.getY();
- }
-
+ if (window != null) {
Graphics g =
((WWindowPeer)window.getPeer()).getTranslucentGraphics();
+ // getTranslucentGraphics() returns non-null value for non-opaque windows only
+ if (g != null) {
+ // Non-opaque windows do not support heavyweight children.
+ // Redirect all painting to the Window's Graphics instead.
+ // The caller is responsible for calling the
+ // WindowPeer.updateWindow() after painting has finished.
+ int x = 0, y = 0;
+ for (Component c = target; c != window; c = c.getParent()) {
+ x += c.getX();
+ y += c.getY();
+ }
- g.translate(x, y);
- g.clipRect(0, 0, target.getWidth(), target.getHeight());
+ g.translate(x, y);
+ g.clipRect(0, 0, target.getWidth(), target.getHeight());
- return g;
+ return g;
+ }
}
SurfaceData surfaceData = this.surfaceData;
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java
--- a/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/windows/classes/sun/awt/windows/WEmbeddedFrame.java Wed Oct 13 17:51:41 2010 -0700
@@ -191,9 +191,20 @@
public void activateEmbeddingTopLevel() {
}
- public void synthesizeWindowActivation(boolean doActivate) {
- ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(doActivate);
+ public void synthesizeWindowActivation(final boolean doActivate) {
+ if (!doActivate || EventQueue.isDispatchThread()) {
+ ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(doActivate);
+ } else {
+ // To avoid focus concurrence b/w IE and EmbeddedFrame
+ // activation is postponed by means of posting it to EDT.
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ ((WEmbeddedFramePeer)getPeer()).synthesizeWmActivate(true);
+ }
+ });
+ }
}
+
public void registerAccelerator(AWTKeyStroke stroke) {}
public void unregisterAccelerator(AWTKeyStroke stroke) {}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java
--- a/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/windows/classes/sun/awt/windows/WWindowPeer.java Wed Oct 13 17:51:41 2010 -0700
@@ -595,16 +595,6 @@
}
@Override
- public Graphics getGraphics() {
- synchronized (getStateLock()) {
- if (!isOpaque) {
- return getTranslucentGraphics();
- }
- }
- return super.getGraphics();
- }
-
- @Override
public void setBackground(Color c) {
super.setBackground(c);
synchronized (getStateLock()) {
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/windows/lib/tzmappings
--- a/jdk/src/windows/lib/tzmappings Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/windows/lib/tzmappings Wed Oct 13 17:51:41 2010 -0700
@@ -1,5 +1,4 @@
#
-#
# This file describes mapping information between Windows and Java
# time zones.
# Format: Each line should include a colon separated fields of Windows
@@ -11,7 +10,7 @@
# NOTE
# This table format is not a public interface of any Java
# platforms. No applications should depend on this file in any form.
-#
+#
# This table has been generated by a program and should not be edited
# manually.
#
@@ -84,8 +83,8 @@
Ekaterinburg Standard Time:10,11::Asia/Yekaterinburg:
West Asia:10,11:UZ:Asia/Tashkent:
West Asia Standard Time:10,11:UZ:Asia/Tashkent:
-Central Asia:12,13::Asia/Dhaka:
-Central Asia Standard Time:12,13::Asia/Dhaka:
+Central Asia:12,13::Asia/Almaty:
+Central Asia Standard Time:12,13::Asia/Almaty:
N. Central Asia Standard Time:12,13::Asia/Novosibirsk:
Bangkok:14,15::Asia/Bangkok:
Bangkok Standard Time:14,15::Asia/Bangkok:
@@ -167,22 +166,27 @@
Greenwich Standard Time:88,89::GMT:
Argentina Standard Time:900,900::America/Buenos_Aires:
Azerbaijan Standard Time:901,901:AZ:Asia/Baku:
-Central Brazilian Standard Time:902,902:BR:America/Manaus:
-Central Standard Time (Mexico):903,903::America/Mexico_City:
-Georgian Standard Time:904,904:GE:Asia/Tbilisi:
-Jordan Standard Time:905,905:JO:Asia/Amman:
-Mauritius Standard Time:906,906:MU:Indian/Mauritius:
-Middle East Standard Time:907,907:LB:Asia/Beirut:
-Montevideo Standard Time:908,908:UY:America/Montevideo:
-Morocco Standard Time:909,909:MA:Africa/Casablanca:
-Mountain Standard Time (Mexico):910,910:MX:America/Chihuahua:
-Namibia Standard Time:911,911:NA:Africa/Windhoek:
-Pacific Standard Time (Mexico):912,912:MX:America/Tijuana:
-Pakistan Standard Time:913,913::Asia/Karachi:
-UTC:914,914::UTC:
-Venezuela Standard Time:915,915::America/Caracas:
-Kamchatka Standard Time:916,916:RU:Asia/Kamchatka:
-Paraguay Standard Time:917,917:PY:America/Asuncion:
-Western Brazilian Standard Time:918,918:BR:America/Rio_Branco:
-Ulaanbaatar Standard Time:919,919::Asia/Ulaanbaatar:
-Armenian Standard Time:920,920:AM:Asia/Yerevan:
+Bangladesh Standard Time:902,902::Asia/Dhaka:
+Central Brazilian Standard Time:903,903:BR:America/Manaus:
+Central Standard Time (Mexico):904,904::America/Mexico_City:
+Georgian Standard Time:905,905:GE:Asia/Tbilisi:
+Jordan Standard Time:906,906:JO:Asia/Amman:
+Kamchatka Standard Time:907,907:RU:Asia/Kamchatka:
+Mauritius Standard Time:908,908:MU:Indian/Mauritius:
+Middle East Standard Time:909,909:LB:Asia/Beirut:
+Montevideo Standard Time:910,910:UY:America/Montevideo:
+Morocco Standard Time:911,911:MA:Africa/Casablanca:
+Mountain Standard Time (Mexico):912,912:MX:America/Chihuahua:
+Namibia Standard Time:913,913:NA:Africa/Windhoek:
+Pacific Standard Time (Mexico):914,914:MX:America/Tijuana:
+Pakistan Standard Time:915,915::Asia/Karachi:
+Paraguay Standard Time:916,916:PY:America/Asuncion:
+Syria Standard Time:917,917:SY:Asia/Damascus:
+UTC:918,918::UTC:
+UTC+12:919,919::GMT+1200:
+UTC-02:920,920::GMT-0200:
+UTC-11:921,921::GMT-1100:
+Ulaanbaatar Standard Time:922,922::Asia/Ulaanbaatar:
+Venezuela Standard Time:923,923::America/Caracas:
+Western Brazilian Standard Time:924,924:BR:America/Rio_Branco:
+Armenian Standard Time:925,925:AM:Asia/Yerevan:
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/windows/native/sun/windows/awt_Component.cpp
--- a/jdk/src/windows/native/sun/windows/awt_Component.cpp Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_Component.cpp Wed Oct 13 17:51:41 2010 -0700
@@ -2329,6 +2329,19 @@
MSG msg;
InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y);
+ AwtWindow *toplevel = GetContainer();
+ if (toplevel && !toplevel->IsSimpleWindow()) {
+ /*
+ * The frame should be focused by click in case it is
+ * the active window but not the focused window. See 6886678.
+ */
+ if (toplevel->GetHWnd() == ::GetActiveWindow() &&
+ toplevel->GetHWnd() != AwtComponent::GetFocusedWindow())
+ {
+ toplevel->AwtSetActiveWindow();
+ }
+ }
+
SendMouseEvent(java_awt_event_MouseEvent_MOUSE_PRESSED, now, x, y,
GetJavaModifiers(), clickCount, JNI_FALSE,
GetButton(button), &msg);
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/windows/native/sun/windows/awt_Desktop.cpp
--- a/jdk/src/windows/native/sun/windows/awt_Desktop.cpp Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_Desktop.cpp Wed Oct 13 17:51:41 2010 -0700
@@ -59,15 +59,17 @@
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
- GetLastError(),
+ (int)retval,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR)&buffer,
0,
NULL );
- jstring errmsg = JNU_NewStringPlatform(env, buffer, len);
- LocalFree(buffer);
- return errmsg;
+ if (buffer) {
+ jstring errmsg = JNU_NewStringPlatform(env, buffer);
+ LocalFree(buffer);
+ return errmsg;
+ }
}
return NULL;
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/windows/native/sun/windows/awt_DesktopProperties.cpp
--- a/jdk/src/windows/native/sun/windows/awt_DesktopProperties.cpp Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_DesktopProperties.cpp Wed Oct 13 17:51:41 2010 -0700
@@ -505,7 +505,8 @@
SetIntegerProperty(TEXT("win.drag.width"), cxdrag);
SetIntegerProperty(TEXT("win.drag.height"), cydrag);
SetIntegerProperty(TEXT("DnD.gestureMotionThreshold"), max(cxdrag, cydrag)/2);
- SetIntegerProperty(TEXT("awt.mouse.numButtons"), GetSystemMetrics(SM_CMOUSEBUTTONS));
+ SetIntegerProperty(TEXT("awt.mouse.numButtons"), AwtToolkit::GetNumberOfButtons());
+
SetIntegerProperty(TEXT("awt.multiClickInterval"), GetDoubleClickTime());
// BEGIN cross-platform properties
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/windows/native/sun/windows/awt_Toolkit.cpp
--- a/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp Wed Oct 13 17:51:41 2010 -0700
@@ -133,6 +133,8 @@
static LPCTSTR szAwtToolkitClassName = TEXT("SunAwtToolkit");
+static const int MOUSE_BUTTONS_WINDOWS_SUPPORTED = 5; //three standard buttons + XBUTTON1 + XBUTTON2.
+
UINT AwtToolkit::GetMouseKeyState()
{
static BOOL mbSwapped = ::GetSystemMetrics(SM_SWAPBUTTON);
@@ -2310,5 +2312,9 @@
JNIEXPORT jint JNICALL Java_sun_awt_windows_WToolkit_getNumberOfButtonsImpl
(JNIEnv *, jobject self) {
- return GetSystemMetrics(SM_CMOUSEBUTTONS);
+ return AwtToolkit::GetNumberOfButtons();
}
+
+UINT AwtToolkit::GetNumberOfButtons() {
+ return MOUSE_BUTTONS_WINDOWS_SUPPORTED;
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/src/windows/native/sun/windows/awt_Toolkit.h
--- a/jdk/src/windows/native/sun/windows/awt_Toolkit.h Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.h Wed Oct 13 17:51:41 2010 -0700
@@ -185,6 +185,7 @@
BOOL IsDynamicLayoutActive();
BOOL areExtraMouseButtonsEnabled();
void setExtraMouseButtonsEnabled(BOOL enable);
+ static UINT GetNumberOfButtons();
INLINE BOOL localPump() { return m_localPump; }
INLINE BOOL VerifyComponents() { return FALSE; } // TODO: Use new DebugHelper class to set this flag
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/demo/zipfs/Basic.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/demo/zipfs/Basic.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2009, 2010, 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("zip")) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ throw new RuntimeException("'zip' provider not installed");
+
+ // Test: FileSystems#newFileSystem(FileRef)
+ Map env = new HashMap();
+ FileSystems.newFileSystem(zipfile, env, null).close();
+
+ // Test: FileSystems#newFileSystem(URI)
+ URI uri = URI.create("zip" + zipfile.toUri().toString().substring(4));
+ 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;
+ DirectoryStream stream = fs.getPath("/").newDirectoryStream();
+ try {
+ for (Path entry: stream) {
+ found = entry.toString().equals("/META-INF/");
+ if (found) break;
+ }
+ } finally {
+ stream.close();
+ }
+
+ 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 (source.exists()) {
+ Path target = Paths.get(source.getName().toString());
+ source.copyTo(target, StandardCopyOption.REPLACE_EXISTING);
+ try {
+ long s1 = Attributes.readBasicFileAttributes(source).size();
+ long s2 = Attributes.readBasicFileAttributes(target).size();
+ if (s2 != s1)
+ throw new RuntimeException("target size != source size");
+ } finally {
+ target.delete();
+ }
+ }
+
+ // Test: FileStore
+ FileStore store = fs.getPath("/").getFileStore();
+ 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.getPath("/missing").checkAccess(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.getName(), 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 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("/foo");
+ test("/foo")
+ .starts("/")
+ .starts("/foo")
+ .notStarts("/f");
+ test("/foo/bar")
+ .starts("/")
+ .starts("/foo")
+ .starts("/foo/bar")
+ .notStarts("/f")
+ .notStarts("foo")
+ .notStarts("foo/bar");
+ test("foo")
+ .starts("foo")
+ .notStarts("f");
+ test("foo/bar")
+ .starts("foo")
+ .starts("foo/bar")
+ .notStarts("f")
+ .notStarts("/foo")
+ .notStarts("/foo/bar");
+
+ // endsWith
+ test("/")
+ .ends("/")
+ .notEnds("foo")
+ .notEnds("/foo");
+ test("/foo")
+ .ends("foo")
+ .ends("/foo")
+ .notEnds("/");
+ test("/foo/bar")
+ .ends("bar")
+ .ends("foo/bar")
+ .ends("/foo/bar")
+ .notEnds("/bar");
+ test("foo")
+ .ends("foo");
+ test("foo/bar")
+ .ends("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();
+
+ // 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", null)
+ .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(null);
+ test("..")
+ .normalize("..");
+ test("/..")
+ .normalize("/");
+ test("/../..")
+ .normalize("/");
+ test("foo/.")
+ .normalize("foo");
+ test("./foo")
+ .normalize("foo");
+ test("foo/..")
+ .normalize(null);
+ 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");
+
+ // 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");
+ }
+
+ 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(null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException npe) {
+ }
+
+ try {
+ path.endsWith(null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException npe) {
+ }
+
+ }
+
+ public static void main(String[] args) throws Throwable {
+
+ Path zipfile = Paths.get(args[0]);
+ Map env = new HashMap();
+ fs = FileSystems.newFileSystem(zipfile, env, null);
+ npes();
+ doPathOpTests();
+ fs.close();
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/demo/zipfs/ZipFSTester.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/demo/zipfs/ZipFSTester.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 2010 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.attribute.*;
+import java.net.*;
+import java.util.*;
+
+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 {
+ FileSystem fs = null;
+ try {
+ fs = newZipFileSystem(Paths.get(args[0]), new HashMap());
+ test(fs);
+ test2(fs); // more tests
+ } finally {
+ if (fs != null)
+ fs.close();
+ }
+ }
+
+ static void test(FileSystem fs)
+ throws Exception
+ {
+ Random rdm = new Random();
+
+ // clone a fs and test on it
+ Path tmpfsPath = getTempPath();
+ Map env = new HashMap();
+ env.put("createNew", true);
+ FileSystem fs0 = newZipFileSystem(tmpfsPath, env);
+ z2zcopy(fs, fs0, "/", 0);
+ fs0.close(); // sync to file
+
+ fs = newZipFileSystem(tmpfsPath, new HashMap());
+
+ try {
+ // prepare a src
+ Path src = getTempPath();
+ String tmpName = src.toString();
+ OutputStream os = src.newOutputStream();
+ byte[] bits = new byte[12345];
+ rdm.nextBytes(bits);
+ os.write(bits);
+ os.close();
+
+ // copyin
+ Path dst = getPathWithParents(fs, tmpName);
+ src.copyTo(dst);
+ checkEqual(src, dst);
+
+ // copy
+ Path dst2 = getPathWithParents(fs, "/xyz" + rdm.nextInt(100) +
+ "/efg" + rdm.nextInt(100) + "/foo.class");
+ dst.copyTo(dst2);
+ //dst.moveTo(dst2);
+ checkEqual(src, dst2);
+
+ // delete
+ dst.delete();
+ if (dst.exists())
+ throw new RuntimeException("Failed!");
+
+ // moveout
+ Path dst3 = Paths.get(tmpName + "_Tmp");
+ dst2.moveTo(dst3);
+ checkEqual(src, dst3);
+
+ // delete
+ if (dst2.exists())
+ throw new RuntimeException("Failed!");
+ dst3.delete();
+ if (dst3.exists())
+ throw new RuntimeException("Failed!");
+
+ // newInputStream on dir
+ Path parent = dst2.getParent();
+ try {
+ parent.newInputStream();
+ 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);
+ tmp.delete();
+
+ // test channels
+ channel(fs, dst);
+ dst.delete();
+ src.delete();
+ } finally {
+ if (fs != null)
+ fs.close();
+ if (tmpfsPath.exists())
+ tmpfsPath.delete();
+ }
+ }
+
+ static void test2(FileSystem fs) throws Exception {
+
+ Path fs1Path = getTempPath();
+ Path fs2Path = getTempPath();
+ Path fs3Path = getTempPath();
+
+ if (fs1Path.exists())
+ fs1Path.delete();
+ if (fs2Path.exists())
+ fs2Path.delete();
+ if (fs3Path.exists())
+ fs3Path.delete();
+
+ // create a new filesystem, copy everything from fs
+ Map env = new HashMap();
+ env.put("createNew", 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 (fs2.getPath(path).exists()) {
+ 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);
+
+ fs1Path.delete();
+ fs2Path.delete();
+ fs3Path.delete();
+ }
+
+ private static FileSystem newZipFileSystem(Path path, Map env)
+ throws IOException
+ {
+ return FileSystems.newFileSystem(
+ URI.create("zip" +
+ path.toUri().toString().substring(4)),
+ 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 (Attributes.readBasicFileAttributes(path).isDirectory()) {
+ DirectoryStream ds = path.newDirectoryStream();
+ for (Path child : ds)
+ list(child, files, dirs);
+ ds.close();
+ 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 (Boolean.TRUE.equals(srcPath.getAttribute("isDirectory"))) {
+ if (!dstPath.exists()) {
+ try {
+ mkdirs(dstPath);
+ } catch (FileAlreadyExistsException x) {}
+ }
+ DirectoryStream ds = srcPath.newDirectoryStream();
+ for (Path child : ds) {
+ z2zcopy(src, dst,
+ path + (path.endsWith("/")?"":"/") + child.getName(),
+ method);
+ }
+ ds.close();
+ } else {
+ try {
+ if (dstPath.exists())
+ return;
+ switch (method) {
+ case 0:
+ srcPath.copyTo(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 (Boolean.TRUE.equals(srcPath.getAttribute("isDirectory"))) {
+ if (!dstPath.exists())
+ mkdirs(dstPath);
+ DirectoryStream ds = srcPath.newDirectoryStream();
+ for (Path child : ds) {
+ z2zmove(src, dst,
+ path + (path.endsWith("/")?"":"/") + child.getName());
+ }
+ ds.close();
+ } else {
+ //System.out.println("moving..." + path);
+ Path parent = dstPath.getParent();
+ if (parent != null && parent.notExists())
+ mkdirs(parent);
+ srcPath.moveTo(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.getName().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 {
+ path = path.toAbsolutePath();
+ Path parent = path.getParent();
+ if (parent != null) {
+ if (parent.notExists())
+ mkdirs(parent);
+ }
+ path.createDirectory();
+ }
+
+ private static void rmdirs(Path path) throws IOException {
+ while (path != null && path.getNameCount() != 0) {
+ path.delete();
+ 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
+ InputStream isSrc = src.newInputStream();
+ InputStream isDst = dst.newInputStream();
+ byte[] bufSrc = new byte[8192];
+ byte[] bufDst = new byte[8192];
+
+ try {
+ 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--;
+ }
+ }
+ } finally {
+ isSrc.close();
+ isDst.close();
+ }
+
+ // channels
+ SeekableByteChannel chSrc = src.newByteChannel();
+ SeekableByteChannel chDst = dst.newByteChannel();
+ 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);
+
+ try {
+ 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();
+ } finally {
+ chSrc.close();
+ chDst.close();
+ }
+ }
+
+ 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);
+
+ FileChannel srcFc = src.getFileSystem()
+ .provider()
+ .newFileChannel(src, read);
+ FileChannel dstFc = dst.getFileSystem()
+ .provider()
+ .newFileChannel(dst, openwrite);
+
+ try {
+ ByteBuffer bb = ByteBuffer.allocate(8192);
+ while (srcFc.read(bb) >= 0) {
+ bb.flip();
+ dstFc.write(bb);
+ bb.clear();
+ }
+ } finally {
+ srcFc.close();
+ dstFc.close();
+ }
+ }
+
+ 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);
+
+ SeekableByteChannel srcCh = src.newByteChannel(read);
+ SeekableByteChannel dstCh = dst.newByteChannel(openwrite);
+
+ try {
+ ByteBuffer bb = ByteBuffer.allocate(8192);
+ while (srcCh.read(bb) >= 0) {
+ bb.flip();
+ dstCh.write(bb);
+ bb.clear();
+ }
+ } finally {
+ srcCh.close();
+ dstCh.close();
+ }
+ }
+
+ private static void streamCopy(Path src, Path dst) throws IOException
+ {
+ InputStream isSrc = src.newInputStream();
+ OutputStream osDst = dst.newOutputStream();
+ byte[] buf = new byte[8192];
+ try {
+ int n = 0;
+ while ((n = isSrc.read(buf)) != -1) {
+ osDst.write(buf, 0, n);
+ }
+ } finally {
+ isSrc.close();
+ osDst.close();
+ }
+ }
+
+ static void channel(FileSystem fs, Path path)
+ throws Exception
+ {
+ System.out.println("test ByteChannel...");
+ SeekableByteChannel sbc = path.newByteChannel();
+ Set read = new HashSet<>();
+ read.add(READ);
+ System.out.printf(" sbc[0]: pos=%d, size=%d%n", sbc.position(), sbc.size());
+ ByteBuffer bb = ByteBuffer.allocate((int)sbc.size());
+ int n = sbc.read(bb);
+ System.out.printf(" sbc[1]: read=%d, pos=%d, size=%d%n",
+ n, sbc.position(), sbc.size());
+ ByteBuffer bb2 = ByteBuffer.allocate((int)sbc.size());
+ int N = 120;
+ sbc.close();
+
+ // sbc.position(pos) is not supported in current version
+ // try the FileChannel
+ sbc = fs.provider().newFileChannel(path, read);
+ sbc.position(N);
+ System.out.printf(" sbc[2]: pos=%d, size=%d%n",
+ sbc.position(), sbc.size());
+ bb2.limit(100);
+ n = sbc.read(bb2);
+ System.out.printf(" sbc[3]: read=%d, pos=%d, size=%d%n",
+ n, sbc.position(), sbc.size());
+ System.out.printf(" sbc[4]: bb[%d]=%d, bb1[0]=%d%n",
+ N, bb.get(N) & 0xff, bb2.get(0) & 0xff);
+ sbc.close();
+ }
+
+ // 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 && parent.notExists())
+ mkdirs(parent);
+ return path;
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/demo/zipfs/basic.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/demo/zipfs/basic.sh Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,73 @@
+#
+# Copyright (c) 2009, 2010, 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
+# @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_* )
+ CLASSPATH="${TESTCLASSES};${ZIPFS}"
+ ;;
+ * )
+ CLASSPATH="${TESTCLASSES}:${ZIPFS}"
+ ;;
+esac
+export CLASSPATH
+
+failures=0
+
+go() {
+ echo ""
+ ${TESTJAVA}/bin/java $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 43cb79a6b123 -r d954b585d3a1 jdk/test/java/awt/Focus/FocusOwnerFrameOnClick/FocusOwnerFrameOnClick.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Focus/FocusOwnerFrameOnClick/FocusOwnerFrameOnClick.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1995, 2010, 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.
+ */
+
+/*
+ @test FocusOwnerFrameOnClick.java %W% %E%
+ @bug 6886678
+ @summary Tests that clicking an owner frame switches focus from its owned window.
+ @author Anton Tarasov: area=awt.focus
+ @library ../../regtesthelpers
+ @build Util
+ @run main FocusOwnerFrameOnClick
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+import java.applet.Applet;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.lang.reflect.InvocationTargetException;
+import test.java.awt.regtesthelpers.Util;
+
+public class FocusOwnerFrameOnClick extends Applet {
+ Robot robot;
+ Frame frame = new Frame("Frame");
+ Window window = new Window(frame);
+ Button fButton = new Button("fButton");
+ Button wButton = new Button("wButton");
+
+ AtomicBoolean focused = new AtomicBoolean(false);
+
+ public static void main(String[] args) {
+ FocusOwnerFrameOnClick app = new FocusOwnerFrameOnClick();
+ app.init();
+ app.start();
+ }
+
+ public void init() {
+ robot = Util.createRobot();
+
+ frame.setLayout(new FlowLayout());
+ frame.setSize(200, 200);
+ frame.add(fButton);
+
+ window.setLocation(300, 0);
+ window.add(wButton);
+ window.pack();
+ }
+
+ public void start() {
+ frame.setVisible(true);
+ Util.waitForIdle(robot);
+
+ window.setVisible(true);
+ Util.waitForIdle(robot);
+
+ if (!wButton.hasFocus()) {
+ if (!Util.trackFocusGained(wButton, new Runnable() {
+ public void run() {
+ Util.clickOnComp(wButton, robot);
+ }
+ }, 2000, false))
+ {
+ throw new TestErrorException("wButton didn't gain focus on showing");
+ }
+ }
+
+ Runnable clickAction = new Runnable() {
+ public void run() {
+ Point loc = fButton.getLocationOnScreen();
+ Dimension dim = fButton.getSize();
+
+ robot.mouseMove(loc.x, loc.y + dim.height + 20);
+ robot.delay(50);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.delay(50);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ }
+ };
+
+ if (!Util.trackWindowGainedFocus(frame, clickAction, 2000, true)) {
+ throw new TestFailedException("The frame wasn't focused on click");
+ }
+
+ System.out.println("Test passed.");
+ }
+}
+
+/**
+ * Thrown when the behavior being verified is found wrong.
+ */
+class TestFailedException extends RuntimeException {
+ TestFailedException(String msg) {
+ super("Test failed: " + msg);
+ }
+}
+
+/**
+ * Thrown when an error not related to the behavior being verified is encountered.
+ */
+class TestErrorException extends RuntimeException {
+ TestErrorException(String msg) {
+ super("Unexpected error: " + msg);
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Extra.java
--- a/jdk/test/java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Extra.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/test/java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Extra.java Wed Oct 13 17:51:41 2010 -0700
@@ -21,16 +21,15 @@
static final int SHIFT = 1;
static final int CTRL = 2;
static final int ALT = 3;
- static CheckingModifierAdapter adapterTest1;
- static CheckingModifierAdapter adapterTest2;
- static CheckingModifierAdapter adapterTest3;
- static CheckingModifierAdapter adapterTest4;
+ static CheckingModifierAdapterExtra adapterTest1;
+ static CheckingModifierAdapterExtra adapterTest2;
+ static CheckingModifierAdapterExtra adapterTest3;
+ static CheckingModifierAdapterExtra adapterTest4;
static boolean debug = true; //dump all errors (debug) or throw first(under jtreg) exception
static boolean autorun = false; //use robot or manual run
static int testModifier = NONE;
- static int [] mouseButtons;
static int [] mouseButtonDownMasks;
//an arrays representing a modifiersEx of extra mouse buttons while using ALT/CTRL/SHIFT or none of them
@@ -39,7 +38,6 @@
static int [] modifiersExStandardCTRL;
static int [] modifiersExStandardALT;
- // final static int [] mouseButtons = new int [] {MouseEvent.BUTTON1_MASK, MouseEvent.BUTTON2_MASK, MouseEvent.BUTTON3_MASK};
// BUTTON1, 2, 3 press-release.
final static int modifiersStandard = 0; //InputEvent.BUTTON_DOWN_MASK;
@@ -56,7 +54,7 @@
if (modifiersEx != curStandardExModifiers[index]){
// System.out.println(">>>>>>>>>>>>>>> Pressed. modifiersEx "+modifiersEx +" : "+!= curStandardExModifiers");
- MessageLogger.reportError("Test failed : Pressed. modifiersEx != curStandardExModifiers");
+ MessageLogger.reportError("Test failed : Pressed. modifiersEx != curStandardExModifiers. Got: " + modifiersEx + " , Expected: " + curStandardExModifiers[index]);
}
//check event.paramString() output
@@ -168,7 +166,7 @@
}
if (modifiersEx != curStandardExModifiers[index]){
- MessageLogger.reportError("Test failed : Released. modifiersEx != curStandardExModifiers");
+ MessageLogger.reportError("Test failed : Released. modifiersEx != curStandardExModifiers. Got: " + modifiersEx + " , Expected: " + curStandardExModifiers[index]);
}
//check event.paramString() output
@@ -191,7 +189,7 @@
}
if (modifiersEx != curStandardExModifiers[index]){
- MessageLogger.reportError("Test failed : Clicked. modifiersEx != curStandardExModifiers");
+ MessageLogger.reportError("Test failed : Clicked. modifiersEx != curStandardExModifiers. Got: " + modifiersEx + " , Expected: " + curStandardExModifiers[index]);
}
//check event.paramString() output
@@ -275,11 +273,11 @@
this.addMouseListener(adapterTest1);
robot.delay(1000);
robot.mouseMove(getLocationOnScreen().x + getWidth()/2, getLocationOnScreen().y + getHeight()/2);
- for (int i = 3; i< mouseButtons.length; i++){
- System.out.println("testNONE() => " +mouseButtons[i] );
- robot.mousePress(mouseButtons[i]);
+ for (int i = 3; i< mouseButtonDownMasks.length; i++){
+ System.out.println("testNONE() => " +mouseButtonDownMasks[i] );
+ robot.mousePress(mouseButtonDownMasks[i]);
robot.delay(100);
- robot.mouseRelease(mouseButtons[i]);
+ robot.mouseRelease(mouseButtonDownMasks[i]);
}
robot.delay(1000);
this.removeMouseListener(adapterTest1);
@@ -289,12 +287,12 @@
this.addMouseListener(adapterTest2);
robot.delay(1000);
robot.mouseMove(getLocationOnScreen().x + getWidth()/2, getLocationOnScreen().y + getHeight()/2);
- for (int i = 3; i< mouseButtons.length; i++){
+ for (int i = 3; i< mouseButtonDownMasks.length; i++){
robot.keyPress(KeyEvent.VK_SHIFT);
- System.out.println("testSHIFT() => " +mouseButtons[i] );
- robot.mousePress(mouseButtons[i]);
+ System.out.println("testSHIFT() => " +mouseButtonDownMasks[i] );
+ robot.mousePress(mouseButtonDownMasks[i]);
robot.delay(100);
- robot.mouseRelease(mouseButtons[i]);
+ robot.mouseRelease(mouseButtonDownMasks[i]);
robot.keyRelease(KeyEvent.VK_SHIFT);
}
robot.delay(1000);
@@ -305,12 +303,12 @@
this.addMouseListener(adapterTest3);
robot.delay(1000);
robot.mouseMove(getLocationOnScreen().x + getWidth()/2, getLocationOnScreen().y + getHeight()/2);
- for (int i = 3; i< mouseButtons.length; i++){
+ for (int i = 3; i< mouseButtonDownMasks.length; i++){
robot.keyPress(KeyEvent.VK_CONTROL);
- System.out.println("testCTRL() => " +mouseButtons[i] );
- robot.mousePress(mouseButtons[i]);
+ System.out.println("testCTRL() => " +mouseButtonDownMasks[i] );
+ robot.mousePress(mouseButtonDownMasks[i]);
robot.delay(100);
- robot.mouseRelease(mouseButtons[i]);
+ robot.mouseRelease(mouseButtonDownMasks[i]);
robot.keyRelease(KeyEvent.VK_CONTROL);
}
robot.delay(1000);
@@ -321,12 +319,12 @@
this.addMouseListener(adapterTest4);
robot.delay(1000);
robot.mouseMove(getLocationOnScreen().x + getWidth()/2, getLocationOnScreen().y + getHeight()/2);
- for (int i = 3; i< mouseButtons.length; i++){
+ for (int i = 3; i< mouseButtonDownMasks.length; i++){
robot.keyPress(KeyEvent.VK_ALT);
- System.out.println("testALT() => " +mouseButtons[i] );
- robot.mousePress(mouseButtons[i]);
+ System.out.println("testALT() => " +mouseButtonDownMasks[i] );
+ robot.mousePress(mouseButtonDownMasks[i]);
robot.delay(100);
- robot.mouseRelease(mouseButtons[i]);
+ robot.mouseRelease(mouseButtonDownMasks[i]);
robot.keyRelease(KeyEvent.VK_ALT);
}
robot.delay(1000);
@@ -368,52 +366,52 @@
}
public static void initAdapters(){
- adapterTest1 = new CheckingModifierAdapter(NONE);
- adapterTest2 = new CheckingModifierAdapter(SHIFT);
- adapterTest3 = new CheckingModifierAdapter(CTRL);
- adapterTest4 = new CheckingModifierAdapter(ALT);
+ adapterTest1 = new CheckingModifierAdapterExtra(NONE);
+ adapterTest2 = new CheckingModifierAdapterExtra(SHIFT);
+ adapterTest3 = new CheckingModifierAdapterExtra(CTRL);
+ adapterTest4 = new CheckingModifierAdapterExtra(ALT);
}
public static void initVars(){
- int [] tmp = new int [MouseInfo.getNumberOfButtons()];
- for (int i = 0; i < MouseInfo.getNumberOfButtons(); i++){
- tmp[i] = InputEvent.getMaskForButton(i+1);
- // System.out.println("TEST: "+tmp[i]);
+ //Init the array of the mouse button masks. It will be used for generating mouse events.
+ mouseButtonDownMasks = new int [MouseInfo.getNumberOfButtons()];
+ for (int i = 0; i < mouseButtonDownMasks.length; i++){
+ mouseButtonDownMasks[i] = InputEvent.getMaskForButton(i+1);
+ System.out.println("MouseArray [i] == "+mouseButtonDownMasks[i]);
}
- mouseButtons = Arrays.copyOf(tmp, tmp.length);
-
- for (int i = 0; i < mouseButtons.length; i++){
- System.out.println("MouseArray [i] == "+mouseButtons[i]);
- }
-
- mouseButtonDownMasks = Arrays.copyOf(tmp, tmp.length);
-
// So we need to get the number of extra buttons on the mouse: "MouseInfo.getNumberOfButtons() - 3"
// and multyply on 3 because each button will generate three events : PRESS, RELEASE and CLICK.
- tmp = new int [(MouseInfo.getNumberOfButtons()-3)*3];
+ int [] tmp = new int [(MouseInfo.getNumberOfButtons()-3)*3];
+
+ //Fill array of expected results for the case when mouse buttons are only used (no-modifier keys)
Arrays.fill(tmp, 0);
-
for (int i = 0, j = 3; i < tmp.length; i = i + 3, j++){
tmp[i] = mouseButtonDownMasks[j];
}
modifiersExStandard = Arrays.copyOf(tmp, tmp.length);
+ //Fill array of expected results for the case when mouse buttons are only used with SHIFT modifier key
Arrays.fill(tmp, InputEvent.SHIFT_DOWN_MASK);
- for (int i = 0, j = 3; i < MouseInfo.getNumberOfButtons(); i = i + 3, j++){
- tmp[i] = tmp[j] | mouseButtonDownMasks[j];
+ for (int i = 0, j = 3; i < tmp.length; i = i + 3, j++){
+ System.out.println("modifiersExStandardSHIFT FILLING : " + tmp[i] + " + " + mouseButtonDownMasks[j]);
+ tmp[i] = tmp[i] | mouseButtonDownMasks[j];
}
modifiersExStandardSHIFT = Arrays.copyOf(tmp, tmp.length);
+ //Fill array of expected results for the case when mouse buttons are only used with CTRL modifier key
Arrays.fill(tmp, InputEvent.CTRL_DOWN_MASK);
- for (int i = 0, j = 3; i < MouseInfo.getNumberOfButtons(); i = i + 3, j++){
- tmp[i] = tmp[j] | mouseButtonDownMasks[j];
+ for (int i = 0, j = 3; i < tmp.length; i = i + 3, j++){
+ System.out.println("modifiersExStandardCTRL FILLING : " + tmp[i] + " + " + mouseButtonDownMasks[j]);
+ tmp[i] = tmp[i] | mouseButtonDownMasks[j];
}
modifiersExStandardCTRL = Arrays.copyOf(tmp, tmp.length);
+ //Fill array of expected results for the case when mouse buttons are only used with ALT modifier key
Arrays.fill(tmp, InputEvent.ALT_DOWN_MASK);
- for (int i = 0, j = 3; i < MouseInfo.getNumberOfButtons(); i = i + 3, j++){
- tmp[i] = tmp[j] | mouseButtonDownMasks[j];
+ for (int i = 0, j = 3; i < tmp.length; i = i + 3, j++){
+ System.out.println("modifiersExStandardALT FILLING : " + tmp[i] + " + " + mouseButtonDownMasks[j]);
+ tmp[i] = tmp[i] | mouseButtonDownMasks[j];
}
modifiersExStandardALT = Arrays.copyOf(tmp, tmp.length);
}
@@ -436,9 +434,9 @@
/* A class that invoke appropriate verification
* routine with current modifier.
*/
-class CheckingModifierAdapter extends MouseAdapter{
+class CheckingModifierAdapterExtra extends MouseAdapter{
int modifier;
- public CheckingModifierAdapter(int modifier){
+ public CheckingModifierAdapterExtra(int modifier){
this.modifier = modifier;
}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java
--- a/jdk/test/java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/test/java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java Wed Oct 13 17:51:41 2010 -0700
@@ -90,7 +90,7 @@
int [] buttonMasks = new int[MouseInfo.getNumberOfButtons()]; // = InputEvent.getButtonDownMasks();
for (int i = 0; i < MouseInfo.getNumberOfButtons(); i++){
buttonMasks[i] = InputEvent.getMaskForButton(i+1);
- System.out.println("TEST: "+buttonMasks[i]);
+ System.out.println("TEST: buttonMasks["+ i +"] = " + buttonMasks[i]);
}
for (int i = 0; i < MouseInfo.getNumberOfButtons(); i++){
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/java/awt/image/GetSamplesTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/image/GetSamplesTest.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010, 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 6735275
+ * @summary Test verifies that SampleModel.getSamples() throws an appropriate
+ * exception if coordinates are not in bounds.
+ *
+ * @run main GetSamplesTest
+ */
+
+import java.awt.image.BandedSampleModel;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.MultiPixelPackedSampleModel;
+import java.awt.image.PixelInterleavedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.util.Vector;
+
+public class GetSamplesTest {
+
+ public static int width = 100;
+ public static int height = 100;
+ public static int dataType = DataBuffer.TYPE_BYTE;
+ public static int numBands = 4;
+
+ public static void main(String[] args) {
+ Vector> classes = new Vector>();
+
+ classes.add(ComponentSampleModel.class);
+ classes.add(MultiPixelPackedSampleModel.class);
+ classes.add(SinglePixelPackedSampleModel.class);
+ classes.add(BandedSampleModel.class);
+ classes.add(PixelInterleavedSampleModel.class);
+
+ for (Class extends SampleModel> c : classes) {
+ doTest(c);
+ }
+ }
+ private static void doTest(Class extends SampleModel> c) {
+ System.out.println("Test for: " + c.getName());
+ SampleModel sm = createSampleModel(c);
+
+ DataBuffer db = sm.createDataBuffer();
+
+ int[] iArray = new int[ width * height + numBands];
+ float[] fArray = new float[ width * height + numBands];
+ double[] dArray = new double[ width * height + numBands];
+
+ boolean iOk = false;
+ boolean fOk = false;
+ boolean dOk = false;
+
+ try {
+ sm.getSamples(Integer.MAX_VALUE, 0, 1, 1, 0, iArray, db);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println(e.getMessage());
+ iOk = true;
+ }
+
+ try {
+ sm.getSamples(Integer.MAX_VALUE, 0, 1, 1, 0, fArray, db);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println(e.getMessage());
+ fOk = true;
+ }
+
+ try {
+ sm.getSamples(0, Integer.MAX_VALUE, 1, 1, 0, dArray, db);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println(e.getMessage());
+ dOk = true;
+ }
+ if (!iOk || !fOk || !dOk) {
+ throw new RuntimeException("Test for " + c.getSimpleName() +
+ " failed: iOk=" + iOk + "; fOk=" + fOk + "; dOk=" + dOk);
+ }
+ }
+
+ private static SampleModel createSampleModel(Class extends SampleModel> cls) {
+ SampleModel res = null;
+
+ if (cls == ComponentSampleModel.class) {
+ res = new ComponentSampleModel(dataType, width, height, 4, width * 4, new int[] { 0, 1, 2, 3 } );
+ } else if (cls == MultiPixelPackedSampleModel.class) {
+ res = new MultiPixelPackedSampleModel(dataType, width, height, 4);
+ } else if (cls == SinglePixelPackedSampleModel.class) {
+ res = new SinglePixelPackedSampleModel(dataType, width, height,
+ new int[]{ 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff });
+ } else if (cls == BandedSampleModel.class) {
+ res = new BandedSampleModel(dataType, width, height, numBands);
+ } else if (cls == PixelInterleavedSampleModel.class) {
+ res = new PixelInterleavedSampleModel(dataType, width, height, 4, width * 4, new int[] { 0, 1, 2, 3 });
+ } else {
+ throw new RuntimeException("Unknown class " + cls);
+ }
+ return res;
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/java/beans/Introspector/6976577/Test6976577.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Introspector/6976577/Test6976577.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2010, 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 6976577
+ * @summary Tests public methods in non-public beans
+ * @author Sergey Malenkov
+ */
+
+import test.Accessor;
+
+import java.beans.EventSetDescriptor;
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+
+public class Test6976577 {
+
+ public static void main(String[] args) throws Exception {
+ Class> bt = Accessor.getBeanType();
+ Class> lt = Accessor.getListenerType();
+
+ // test PropertyDescriptor
+ PropertyDescriptor pd = new PropertyDescriptor("boolean", bt);
+ test(pd.getReadMethod());
+ test(pd.getWriteMethod());
+
+ // test IndexedPropertyDescriptor
+ IndexedPropertyDescriptor ipd = new IndexedPropertyDescriptor("indexed", bt);
+ test(ipd.getReadMethod());
+ test(ipd.getWriteMethod());
+ test(ipd.getIndexedReadMethod());
+ test(ipd.getIndexedWriteMethod());
+
+ // test EventSetDescriptor
+ EventSetDescriptor esd = new EventSetDescriptor(bt, "test", lt, "process");
+ test(esd.getAddListenerMethod());
+ test(esd.getRemoveListenerMethod());
+ test(esd.getGetListenerMethod());
+ test(esd.getListenerMethods());
+ }
+
+ private static void test(Method... methods) {
+ for (Method method : methods) {
+ if (method == null) {
+ throw new Error("public method is not found");
+ }
+ }
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/java/beans/Introspector/6976577/test/Accessor.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/beans/Introspector/6976577/test/Accessor.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,81 @@
+package test;
+
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.EventListener;
+import java.util.TooManyListenersException;
+
+public class Accessor {
+
+ public static Class> getBeanType() {
+ return Bean.class;
+ }
+
+ public static Class> getListenerType() {
+ return TestListener.class;
+ }
+}
+
+interface TestEvent {
+}
+
+interface TestListener extends EventListener {
+ void process(TestEvent event);
+}
+
+class Bean {
+
+ private boolean b;
+ private int[] indexed;
+ private TestListener listener;
+ private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+
+ public void addPropertyChangeListener(PropertyChangeListener listener) {
+ this.pcs.addPropertyChangeListener(listener);
+ }
+
+ public void addTestListener(TestListener listener) throws TooManyListenersException {
+ if (listener != null) {
+ if (this.listener != null) {
+ throw new TooManyListenersException();
+ }
+ this.listener = listener;
+ }
+ }
+
+ public void removeTestListener(TestListener listener) {
+ if (this.listener == listener) {
+ this.listener = null;
+ }
+ }
+
+ public TestListener[] getTestListeners() {
+ return (this.listener != null)
+ ? new TestListener[] { this.listener }
+ : new TestListener[0];
+ }
+
+ public boolean isBoolean() {
+ return this.b;
+ }
+
+ public void setBoolean(boolean b) {
+ this.b = b;
+ }
+
+ public int[] getIndexed() {
+ return this.indexed;
+ }
+
+ public void setIndexed(int[] values) {
+ this.indexed = values;
+ }
+
+ public int getIndexed(int index) {
+ return this.indexed[index];
+ }
+
+ public void setIndexed(int index, int value) {
+ this.indexed[index] = value;
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/javax/swing/JComboBox/6632953/bug6632953.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JComboBox/6632953/bug6632953.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010, 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 6632953
+ * @summary MetalComboBoxUI.getBaseline(JComponent, int, int) throws IAE for valid width/height
+ * @author Alexander Potochkin
+ */
+
+import javax.swing.JComboBox;
+import javax.swing.plaf.metal.MetalComboBoxUI;
+
+public class bug6632953 {
+
+ public static void main(String... args) throws Exception {
+ MetalComboBoxUI ui = new MetalComboBoxUI();
+ ui.installUI(new JComboBox());
+ ui.getBaseline(new JComboBox(), 0, 0);
+ ui.getBaseline(new JComboBox(), 1, 1);
+ ui.getBaseline(new JComboBox(), 2, 2);
+ ui.getBaseline(new JComboBox(), 3, 3);
+ ui.getBaseline(new JComboBox(), 4, 4);
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/javax/swing/JScrollBar/6542335/bug6542335.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JScrollBar/6542335/bug6542335.java Wed Oct 13 17:51:41 2010 -0700
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2010, 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 6542335
+ @summary different behavior on knob of scroll bar between 1.4.2 and 5.0
+ @author Alexander Potochkin
+ @run main bug6542335
+*/
+
+import sun.awt.SunToolkit;
+
+import javax.swing.*;
+import javax.swing.plaf.basic.BasicScrollBarUI;
+import java.awt.*;
+import java.awt.event.InputEvent;
+
+public class bug6542335 {
+ private static JScrollBar sb;
+ private static MyScrollBarUI ui;
+
+ public static void main(String[] args) throws Exception {
+ Robot robot = new Robot();
+ robot.setAutoDelay(10);
+
+ SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
+
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ final JFrame frame = new JFrame("bug6542335");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ sb = new JScrollBar(0, 0, 1, 0, 1);
+
+ ui = new MyScrollBarUI();
+ sb.setUI(ui);
+
+ sb.setPreferredSize(new Dimension(200, 17));
+ DefaultBoundedRangeModel rangeModel = new DefaultBoundedRangeModel();
+ rangeModel.setMaximum(100);
+ rangeModel.setMinimum(0);
+ rangeModel.setExtent(50);
+ rangeModel.setValue(50);
+
+ sb.setModel(rangeModel);
+ frame.add(sb);
+
+ frame.setSize(200, 100);
+ frame.setVisible(true);
+ }
+ });
+
+ Rectangle thumbBounds = new Rectangle(ui.getThumbBounds());
+
+ toolkit.realSync();
+ Point l = sb.getLocationOnScreen();
+ robot.mouseMove(l.x + (int) (0.75 * sb.getWidth()), l.y + sb.getHeight()/2);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+ toolkit.realSync();
+
+ if (!thumbBounds.equals(ui.getThumbBounds())) {
+ throw new RuntimeException("Test failed");
+ }
+ }
+
+ static class MyScrollBarUI extends BasicScrollBarUI {
+ public Rectangle getThumbBounds() {
+ return super.getThumbBounds();
+ }
+ }
+}
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/javax/swing/JTable/Test6888156.java
--- a/jdk/test/javax/swing/JTable/Test6888156.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/test/javax/swing/JTable/Test6888156.java Wed Oct 13 17:51:41 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2010, 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
@@ -71,14 +71,14 @@
table = new JTable(model);
}
- public void test(final LookAndFeel laf) throws Exception {
+ public void test(final String laf) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
@Override public void run() {
try {
+ System.out.println(laf);
UIManager.setLookAndFeel(laf);
- } catch (UnsupportedLookAndFeelException e) {
- System.err.println(laf.getDescription() +
- " is unsupported; continuing");
+ } catch (Exception e) {
+ System.err.println(laf + " is unsupported; continuing");
return;
}
SwingUtilities.updateComponentTreeUI(table);
@@ -92,8 +92,10 @@
public static void main(String[] args) throws Exception {
Test6888156 t = new Test6888156();
- t.test(new javax.swing.plaf.nimbus.NimbusLookAndFeel());
- t.test(new com.sun.java.swing.plaf.gtk.GTKLookAndFeel());
+ t.test("javax.swing.plaf.nimbus.NimbusLookAndFeel");
+ t.test("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
+ for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
+ t.test(laf.getClassName());
+ }
}
}
-
diff -r 43cb79a6b123 -r d954b585d3a1 jdk/test/javax/swing/JTextArea/6940863/bug6940863.java
--- a/jdk/test/javax/swing/JTextArea/6940863/bug6940863.java Tue Oct 12 17:05:28 2010 -0700
+++ b/jdk/test/javax/swing/JTextArea/6940863/bug6940863.java Wed Oct 13 17:51:41 2010 -0700
@@ -56,6 +56,7 @@
public static void main(String[] args) throws Exception {
if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) {
System.out.println("The test is suitable only for Windows OS. Skipped");
+ return;
}
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/.hgtags
--- a/langtools/.hgtags Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/.hgtags Wed Oct 13 17:51:41 2010 -0700
@@ -86,3 +86,5 @@
4826378eaade4c6676c452efe954be4ee113cc11 jdk7-b109
32da0f38d2fe96c558492b8707b40da24643d41e jdk7-b110
8bec624274ef8535720cff553374347c2f4f5fb2 jdk7-b111
+fd2579b80b83bf5d4289426016c7d29174ba5dd9 jdk7-b112
+6dbd2d869b0573fa5b799a23cccff47d20c12696 jdk7-b113
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/make/netbeans/langtools/build.xml
--- a/langtools/make/netbeans/langtools/build.xml Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/make/netbeans/langtools/build.xml Wed Oct 13 17:51:41 2010 -0700
@@ -31,44 +31,44 @@
-->
-
-
-
-
-
-
+
+
-
-
-
+
-
+
-
+
-
+
Must set property 'includes'
-
-
-
-
-
+
-
+
Must set property 'run.classname'
-
+
-
-
-
+
@@ -118,7 +118,7 @@
-
+
@@ -127,36 +127,36 @@
-
+
Some tests failed; see report for details.
-
+
-
+
-
+
Must set property 'debug.classname'
-
+
Must set property 'jtreg.tests'
-
+
-
+
Must set property 'class'
@@ -169,16 +169,16 @@
-
+
-
-
-
+
@@ -187,7 +187,7 @@
-
+
@@ -196,26 +196,26 @@
-
+
-
+
-
+
-
-
+
-
@@ -236,7 +236,7 @@
-
+
@@ -251,28 +251,29 @@
-
-
+
-
+
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java
--- a/langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/apt/main/JavaCompiler.java Wed Oct 13 17:51:41 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2010, 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
@@ -99,9 +99,6 @@
private static Context preRegister(Context context) {
Bark.preRegister(context);
- // force the use of the scanner that captures Javadoc comments
- DocCommentScanner.Factory.preRegister(context);
-
if (context.get(JavaFileManager.class) == null)
JavacFileManager.preRegister(context);
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java Wed Oct 13 17:51:41 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, 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
@@ -96,9 +96,6 @@
args.getClass();
context.getClass();
fileObjects.getClass();
-
- // force the use of the scanner that captures Javadoc comments
- com.sun.tools.javac.parser.DocCommentScanner.Factory.preRegister(context);
}
JavacTaskImpl(JavacTool tool,
@@ -337,9 +334,13 @@
ListBuffer elements = new ListBuffer();
for (JCCompilationUnit unit : units) {
- for (JCTree node : unit.defs)
- if (node.getTag() == JCTree.CLASSDEF)
- elements.append(((JCTree.JCClassDecl) node).sym);
+ for (JCTree node : unit.defs) {
+ if (node.getTag() == JCTree.CLASSDEF) {
+ JCClassDecl cdef = (JCClassDecl) node;
+ if (cdef.sym != null) // maybe null if errors in anno processing
+ elements.append(cdef.sym);
+ }
+ }
}
return elements.toList();
}
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java Wed Oct 13 17:51:41 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, 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
@@ -56,7 +56,6 @@
import com.sun.tools.javac.comp.MemberEnter;
import com.sun.tools.javac.comp.Resolve;
import com.sun.tools.javac.model.JavacElements;
-import com.sun.tools.javac.processing.JavacMessager;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.tree.JCTree;
@@ -81,14 +80,15 @@
*/
public class JavacTrees extends Trees {
- private final Resolve resolve;
- private final Enter enter;
- private final Log log;
- private final MemberEnter memberEnter;
- private final Attr attr;
- private final TreeMaker treeMaker;
- private final JavacElements elements;
- private final JavacTaskImpl javacTaskImpl;
+ // in a world of a single context per compilation, these would all be final
+ private Resolve resolve;
+ private Enter enter;
+ private Log log;
+ private MemberEnter memberEnter;
+ private Attr attr;
+ private TreeMaker treeMaker;
+ private JavacElements elements;
+ private JavacTaskImpl javacTaskImpl;
public static JavacTrees instance(JavaCompiler.CompilationTask task) {
if (!(task instanceof JavacTaskImpl))
@@ -111,6 +111,14 @@
private JavacTrees(Context context) {
context.put(JavacTrees.class, this);
+ init(context);
+ }
+
+ public void updateContext(Context context) {
+ init(context);
+ }
+
+ private void init(Context context) {
attr = Attr.instance(context);
enter = Enter.instance(context);
elements = JavacElements.instance(context);
@@ -337,6 +345,7 @@
super(M);
}
+ @Override
public T copy(T t, JCTree leaf) {
T t2 = super.copy(t, leaf);
if (t == leaf)
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/src/share/classes/com/sun/tools/javac/code/Scope.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Scope.java Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Scope.java Wed Oct 13 17:51:41 2010 -0700
@@ -70,6 +70,45 @@
*/
public int nelems = 0;
+ /** A timestamp - useful to quickly check whether a scope has changed or not
+ */
+ public ScopeCounter scopeCounter;
+
+ static ScopeCounter dummyCounter = new ScopeCounter() {
+ @Override
+ public void inc() {
+ //do nothing
+ }
+ };
+
+ public static class ScopeCounter {
+ protected static final Context.Key scopeCounterKey =
+ new Context.Key();
+
+ public static ScopeCounter instance(Context context) {
+ ScopeCounter instance = context.get(scopeCounterKey);
+ if (instance == null)
+ instance = new ScopeCounter(context);
+ return instance;
+ }
+
+ protected ScopeCounter(Context context) {
+ context.put(scopeCounterKey, this);
+ }
+
+ private ScopeCounter() {};
+
+ private long val = 0;
+
+ public void inc() {
+ val++;
+ }
+
+ public long val() {
+ return val;
+ }
+ }
+
/** Every hash bucket is a list of Entry's which ends in sentinel.
*/
private static final Entry sentinel = new Entry(null, null, null, null);
@@ -80,12 +119,12 @@
/** A value for the empty scope.
*/
- public static final Scope emptyScope = new Scope(null, null, new Entry[]{});
+ public static final Scope emptyScope = new Scope(null, null, new Entry[]{}, dummyCounter);
/** Construct a new scope, within scope next, with given owner, using
* given table. The table's length must be an exponent of 2.
*/
- Scope(Scope next, Symbol owner, Entry[] table) {
+ private Scope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) {
this.next = next;
assert emptyScope == null || owner != null;
this.owner = owner;
@@ -94,13 +133,18 @@
this.elems = null;
this.nelems = 0;
this.shared = 0;
+ this.scopeCounter = scopeCounter;
}
/** Construct a new scope, within scope next, with given owner,
* using a fresh table of length INITIAL_SIZE.
*/
public Scope(Symbol owner) {
- this(null, owner, new Entry[INITIAL_SIZE]);
+ this(owner, dummyCounter);
+ }
+
+ protected Scope(Symbol owner, ScopeCounter scopeCounter) {
+ this(null, owner, new Entry[INITIAL_SIZE], scopeCounter);
for (int i = 0; i < INITIAL_SIZE; i++) table[i] = sentinel;
}
@@ -110,7 +154,7 @@
* of fresh tables.
*/
public Scope dup() {
- Scope result = new Scope(this, this.owner, this.table);
+ Scope result = new Scope(this, this.owner, this.table, scopeCounter);
shared++;
// System.out.println("====> duping scope " + this.hashCode() + " owned by " + this.owner + " to " + result.hashCode());
// new Error().printStackTrace(System.out);
@@ -123,7 +167,7 @@
* of fresh tables.
*/
public Scope dup(Symbol newOwner) {
- Scope result = new Scope(this, newOwner, this.table);
+ Scope result = new Scope(this, newOwner, this.table, scopeCounter);
shared++;
// System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode());
// new Error().printStackTrace(System.out);
@@ -135,7 +179,7 @@
* the table of its outer scope.
*/
public Scope dupUnshared() {
- return new Scope(this, this.owner, this.table.clone());
+ return new Scope(this, this.owner, this.table.clone(), scopeCounter);
}
/** Remove all entries of this scope from its table, if shared
@@ -211,6 +255,7 @@
table[hash] = e;
elems = e;
nelems++;
+ scopeCounter.inc();
}
Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) {
@@ -226,6 +271,8 @@
while (e.scope == this && e.sym != sym) e = e.next();
if (e.scope == null) return;
+ scopeCounter.inc();
+
// remove e from table and shadowed list;
Entry te = table[sym.name.hashCode() & hashMask];
if (te == e)
@@ -472,7 +519,7 @@
public static final Entry[] emptyTable = new Entry[0];
public DelegatedScope(Scope outer) {
- super(outer, outer.owner, emptyTable);
+ super(outer, outer.owner, emptyTable, outer.scopeCounter);
delegatee = outer;
}
public Scope dup() {
@@ -498,10 +545,22 @@
}
}
+ /** A class scope, for which a scope counter should be provided */
+ public static class ClassScope extends Scope {
+
+ ClassScope(Scope next, Symbol owner, Entry[] table, ScopeCounter scopeCounter) {
+ super(next, owner, table, scopeCounter);
+ }
+
+ public ClassScope(Symbol owner, ScopeCounter scopeCounter) {
+ super(owner, scopeCounter);
+ }
+ }
+
/** An error scope, for which the owner should be an error symbol. */
public static class ErrorScope extends Scope {
ErrorScope(Scope next, Symbol errSymbol, Entry[] table) {
- super(next, /*owner=*/errSymbol, table);
+ super(next, /*owner=*/errSymbol, table, dummyCounter);
}
public ErrorScope(Symbol errSymbol) {
super(errSymbol);
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/src/share/classes/com/sun/tools/javac/code/Source.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java Wed Oct 13 17:51:41 2010 -0700
@@ -25,11 +25,14 @@
package com.sun.tools.javac.code;
+import java.util.*;
+import javax.lang.model.SourceVersion;
+import static javax.lang.model.SourceVersion.*;
+
import com.sun.tools.javac.util.*;
import com.sun.tools.javac.jvm.Target;
-import javax.lang.model.SourceVersion;
-import static javax.lang.model.SourceVersion.*;
-import java.util.*;
+
+import static com.sun.tools.javac.main.OptionName.*;
/** The source language version accepted.
*
@@ -71,7 +74,7 @@
Source instance = context.get(sourceKey);
if (instance == null) {
Options options = Options.instance(context);
- String sourceString = options.get("-source");
+ String sourceString = options.get(SOURCE);
if (sourceString != null) instance = lookup(sourceString);
if (instance == null) instance = DEFAULT;
context.put(sourceKey, instance);
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Wed Oct 13 17:51:41 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -960,6 +960,8 @@
return ElementKind.ENUM_CONSTANT;
} else if (owner.kind == TYP || owner.kind == ERR) {
return ElementKind.FIELD;
+ } else if (isResourceVariable()) {
+ return ElementKind.RESOURCE_VARIABLE;
} else {
return ElementKind.LOCAL_VARIABLE;
}
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symtab.java Wed Oct 13 17:51:41 2010 -0700
@@ -74,6 +74,7 @@
public final JCNoType voidType = new JCNoType(TypeTags.VOID);
private final Names names;
+ private final Scope.ScopeCounter scopeCounter;
private final ClassReader reader;
private final Target target;
@@ -340,6 +341,7 @@
context.put(symtabKey, this);
names = Names.instance(context);
+ scopeCounter = Scope.ScopeCounter.instance(context);
target = Target.instance(context);
// Create the unknown type
@@ -386,7 +388,7 @@
// Create class to hold all predefined constants and operations.
predefClass = new ClassSymbol(PUBLIC|ACYCLIC, names.empty, rootPackage);
- Scope scope = new Scope(predefClass);
+ Scope scope = new Scope.ClassScope(predefClass, scopeCounter);
predefClass.members_field = scope;
// Enter symbols for basic types.
@@ -476,7 +478,7 @@
proprietarySymbol.completer = null;
proprietarySymbol.flags_field = PUBLIC|ACYCLIC|ANNOTATION|INTERFACE;
proprietarySymbol.erasure_field = proprietaryType;
- proprietarySymbol.members_field = new Scope(proprietarySymbol);
+ proprietarySymbol.members_field = new Scope.ClassScope(proprietarySymbol, scopeCounter);
proprietaryType.typarams_field = List.nil();
proprietaryType.allparams_field = List.nil();
proprietaryType.supertype_field = annotationType;
@@ -488,7 +490,7 @@
ClassType arrayClassType = (ClassType)arrayClass.type;
arrayClassType.supertype_field = objectType;
arrayClassType.interfaces_field = List.of(cloneableType, serializableType);
- arrayClass.members_field = new Scope(arrayClass);
+ arrayClass.members_field = new Scope.ClassScope(arrayClass, scopeCounter);
lengthVar = new VarSymbol(
PUBLIC | FINAL,
names.length,
diff -r 43cb79a6b123 -r d954b585d3a1 langtools/src/share/classes/com/sun/tools/javac/code/Types.java
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Tue Oct 12 17:05:28 2010 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java Wed Oct 13 17:51:41 2010 -0700
@@ -69,6 +69,7 @@
new Context.Key();
final Symtab syms;
+ final Scope.ScopeCounter scopeCounter;
final JavacMessages messages;
final Names names;
final boolean allowBoxing;
@@ -89,6 +90,7 @@
protected Types(Context context) {
context.put(typesKey, this);
syms = Symtab.instance(context);
+ scopeCounter = Scope.ScopeCounter.instance(context);
names = Names.instance(context);
allowBoxing = Source.instance(context).allowBoxing();
reader = ClassReader.instance(context);
@@ -1984,22 +1986,26 @@
final MethodSymbol cachedImpl;
final Filter implFilter;
final boolean checkResult;
+ final Scope.ScopeCounter scopeCounter;
public Entry(MethodSymbol cachedImpl,
Filter scopeFilter,
- boolean checkResult) {
+ boolean checkResult,
+ Scope.ScopeCounter scopeCounter) {
this.cachedImpl = cachedImpl;
this.implFilter = scopeFilter;
this.checkResult = checkResult;
+ this.scopeCounter = scopeCounter;
}
- boolean matches(Filter scopeFilter, boolean checkResult) {
+ boolean matches(Filter scopeFilter, boolean checkResult, Scope.ScopeCounter scopeCounter) {
return this.implFilter == scopeFilter &&
- this.checkResult == checkResult;
+ this.checkResult == checkResult &&
+ this.scopeCounter.val() >= scopeCounter.val();
}
}
- MethodSymbol get(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter implFilter) {
+ MethodSymbol get(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter implFilter, Scope.ScopeCounter scopeCounter) {
SoftReference