You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ki...@apache.org on 2017/12/31 00:56:07 UTC

svn commit: r1819708 - in /poi: site/src/documentation/content/xdocs/ trunk/src/ooxml/java/org/apache/poi/ trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/

Author: kiwiwings
Date: Sun Dec 31 00:56:07 2017
New Revision: 1819708

URL: http://svn.apache.org/viewvc?rev=1819708&view=rev
Log:
#61942 - Refactor PackagePartName handling and add getUnusedPartIndex method

Modified:
    poi/site/src/documentation/content/xdocs/status.xml
    poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartCollection.java
    poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java

Modified: poi/site/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/site/src/documentation/content/xdocs/status.xml?rev=1819708&r1=1819707&r2=1819708&view=diff
==============================================================================
--- poi/site/src/documentation/content/xdocs/status.xml (original)
+++ poi/site/src/documentation/content/xdocs/status.xml Sun Dec 31 00:56:07 2017
@@ -68,6 +68,7 @@
         <summary-item>Provide new ooxml-schemas-1.4.jar</summary-item>
       </summary>
       <actions>
+        <action dev="PD" type="add" fixes-bug="61942" module="OPC">Refactor PackagePartName handling and add getUnusedPartIndex method</action>
         <action dev="PD" type="fix" fixes-bug="61941" module="POIFS">Move Ole marker generation to Ole10Native</action>
         <action dev="PD" type="fix" fixes-bug="61940" module="POI Overall">Replace ClassID statics with enum</action>
         <action dev="PD" type="add" fixes-bug="61939" module="OPC">Provide schema for AlternateContent - provide new ooxml-schemas-1.4.jar</action>

Modified: poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java?rev=1819708&r1=1819707&r2=1819708&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java Sun Dec 31 00:56:07 2017
@@ -571,7 +571,7 @@ public class POIXMLDocumentPart {
      *             equivalent part names and package implementers shall neither
      *             create nor recognize packages with equivalent part names.
      */
-    protected final RelationPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory, int idx, boolean noRelation){
+    public final RelationPart createRelationship(POIXMLRelation descriptor, POIXMLFactory factory, int idx, boolean noRelation){
         try {
             PackagePartName ppName = PackagingURIHelper.createPartName(descriptor.getFileName(idx));
             PackageRelationship rel = null;

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java?rev=1819708&r1=1819707&r2=1819708&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/OPCPackage.java Sun Dec 31 00:56:07 2017
@@ -1670,4 +1670,19 @@ public abstract class OPCPackage impleme
         this.isDirty = true;
     }
 
+
+    /**
+     * Get an unused part index based on the namePattern, which doesn't exist yet
+     * and has the lowest positive index
+     *
+     * @param nameTemplate
+     *      The template for new part names containing a {@code '#'} for the index,
+     *      e.g. "/ppt/slides/slide#.xml"
+     * @return the next available part name index
+     * @throws InvalidFormatException if the nameTemplate is null or doesn't contain
+     *      the index char (#) or results in an invalid part name 
+     */
+    public int getUnusedPartIndex(final String nameTemplate) throws InvalidFormatException {
+        return partList.getUnusedPartIndex(nameTemplate);
+    }
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartCollection.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartCollection.java?rev=1819708&r1=1819707&r2=1819708&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartCollection.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartCollection.java Sun Dec 31 00:56:07 2017
@@ -18,28 +18,34 @@
 package org.apache.poi.openxml4j.opc;
 
 import java.io.Serializable;
-import java.util.*;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.function.ToIntFunction;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
 import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
 
 /**
  * A package part collection.
- *
- * @author Julien Chable
- * @version 0.1
  */
 public final class PackagePartCollection implements Serializable {
 
 	private static final long serialVersionUID = 2515031135957635517L;
 
-	/**
-	 * HashSet use to store this collection part names as string for rule
-	 * M1.11 optimized checking.
-	 */
-	private HashSet<String> registerPartNameStr = new HashSet<>();
-
+    /**
+     * HashSet use to store this collection part names as string for rule
+     * M1.11 optimized checking.
+     */
+    private final Set<String> registerPartNameStr = new HashSet<>();
 
-	private final HashMap<PackagePartName, PackagePart> packagePartLookup = new HashMap<>();
+	private final TreeMap<String, PackagePart> packagePartLookup =
+        new TreeMap<>(PackagePartName::compare);
 
 
 	/**
@@ -51,26 +57,32 @@ public final class PackagePartCollection
 	 *                Throws if you try to add a part with a name derived from
 	 *                another part name.
 	 */
-	public PackagePart put(PackagePartName partName, PackagePart part) {
-		String[] segments = partName.getURI().toASCIIString().split(
-				PackagingURIHelper.FORWARD_SLASH_STRING);
-		StringBuilder concatSeg = new StringBuilder();
-		for (String seg : segments) {
-			if (!seg.isEmpty())
-				concatSeg.append(PackagingURIHelper.FORWARD_SLASH_CHAR);
+	public PackagePart put(final PackagePartName partName, final PackagePart part) {
+	    final String ppName = partName.getName();
+        final StringBuilder concatSeg = new StringBuilder();
+        // split at slash, but keep leading slash
+        final String delim = "(?=["+PackagingURIHelper.FORWARD_SLASH_STRING+".])";
+		for (String seg : ppName.split(delim)) {
 			concatSeg.append(seg);
-			if (this.registerPartNameStr.contains(concatSeg.toString())) {
+			if (registerPartNameStr.contains(concatSeg.toString())) {
 				throw new InvalidOperationException(
-						"You can't add a part with a part name derived from another part ! [M1.11]");
+					"You can't add a part with a part name derived from another part ! [M1.11]");
 			}
 		}
-		this.registerPartNameStr.add(partName.getName());
-		return packagePartLookup.put(partName, part);
+		registerPartNameStr.add(ppName);
+		return packagePartLookup.put(ppName, part);
 	}
 
 	public PackagePart remove(PackagePartName key) {
-		this.registerPartNameStr.remove(key.getName());
-		return packagePartLookup.remove(key);
+	    if (key == null) {
+	        return null;
+	    }
+        final String ppName = key.getName();
+	    PackagePart pp = packagePartLookup.remove(ppName);
+	    if (pp != null) {
+	        this.registerPartNameStr.remove(ppName);
+	    }
+		return pp;
 	}
 
 
@@ -79,21 +91,49 @@ public final class PackagePartCollection
 	 * avoids paying the high cost of Natural Ordering per insertion.
 	 */
 	public Collection<PackagePart> sortedValues() {
-		ArrayList<PackagePart> packageParts = new ArrayList<>(packagePartLookup.values());
-		Collections.sort(packageParts);
-		return packageParts;
+	    return Collections.unmodifiableCollection(packagePartLookup.values());
 
 	}
 
 	public boolean containsKey(PackagePartName partName) {
-		return packagePartLookup.containsKey(partName);
+		return partName != null && packagePartLookup.containsKey(partName.getName());
 	}
 
 	public PackagePart get(PackagePartName partName) {
-		return packagePartLookup.get(partName);
+		return partName == null ? null : packagePartLookup.get(partName.getName());
 	}
 
 	public int size() {
 		return packagePartLookup.size();
 	}
+
+
+
+    /**
+     * Get an unused part index based on the namePattern, which doesn't exist yet
+     * and has the lowest positive index
+     *
+     * @param nameTemplate
+     *      The template for new part names containing a {@code '#'} for the index,
+     *      e.g. "/ppt/slides/slide#.xml"
+     * @return the next available part name index
+     * @throws InvalidFormatException if the nameTemplate is null or doesn't contain
+     *      the index char (#) or results in an invalid part name 
+     */
+    public int getUnusedPartIndex(final String nameTemplate) throws InvalidFormatException {
+        if (nameTemplate == null || !nameTemplate.contains("#")) {
+            throw new InvalidFormatException("name template must not be null and contain an index char (#)");
+        }
+
+        final Pattern pattern = Pattern.compile(nameTemplate.replace("#", "([0-9]+)"));
+        
+        final ToIntFunction<String> indexFromName = name -> {
+            Matcher m = pattern.matcher(name);
+            return m.matches() ? Integer.parseInt(m.group(1)) : 0;
+        };
+        
+        return packagePartLookup.keySet().stream()
+            .mapToInt(indexFromName)
+            .collect(BitSet::new, BitSet::set, BitSet::or).nextClearBit(1);
+    }
 }

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java?rev=1819708&r1=1819707&r2=1819708&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagePartName.java Sun Dec 31 00:56:07 2017
@@ -28,8 +28,6 @@ import org.apache.poi.openxml4j.exceptio
 /**
  * An immutable Open Packaging Convention compliant part name.
  *
- * @author Julien Chable
- *
  * @see <a href="http://www.ietf.org/rfc/rfc3986.txt">http://www.ietf.org/rfc/rfc3986.txt</a>
  */
 public final class PackagePartName implements Comparable<PackagePartName> {
@@ -37,32 +35,31 @@ public final class PackagePartName imple
 	/**
 	 * Part name stored as an URI.
 	 */
-	private URI partNameURI;
+	private final URI partNameURI;
 
 	/*
 	 * URI Characters definition (RFC 3986)
 	 */
 
 	/**
-	 * Reserved characters for sub delimitations.
+	 * Reserved characters for sub delimiters.
 	 */
-	private static String[] RFC3986_PCHAR_SUB_DELIMS = { "!", "$", "&", "'",
-			"(", ")", "*", "+", ",", ";", "=" };
+	private static final String RFC3986_PCHAR_SUB_DELIMS = "!$&'()*+,;=";
 
 	/**
 	 * Unreserved character (+ ALPHA & DIGIT).
 	 */
-	private static String[] RFC3986_PCHAR_UNRESERVED_SUP = { "-", ".", "_", "~" };
+	private static final String RFC3986_PCHAR_UNRESERVED_SUP = "-._~";
 
 	/**
 	 * Authorized reserved characters for pChar.
 	 */
-	private static String[] RFC3986_PCHAR_AUTHORIZED_SUP = { ":", "@" };
+	private static final String RFC3986_PCHAR_AUTHORIZED_SUP = ":@";
 
 	/**
 	 * Flag to know if this part name is from a relationship part name.
 	 */
-	private boolean isRelationship;
+	private final boolean isRelationship;
 
 	/**
 	 * Constructor. Makes a ValidPartName object from a java.net.URI
@@ -70,7 +67,7 @@ public final class PackagePartName imple
 	 * @param uri
 	 *            The URI to validate and to transform into ValidPartName.
 	 * @param checkConformance
-	 *            Flag to specify if the contructor have to validate the OPC
+	 *            Flag to specify if the constructor have to validate the OPC
 	 *            conformance. Must be always <code>true</code> except for
 	 *            special URI like '/' which is needed for internal use by
 	 *            OpenXML4J but is not valid.
@@ -99,7 +96,7 @@ public final class PackagePartName imple
 	 * @param partName
 	 *            Part name to valid and to create.
 	 * @param checkConformance
-	 *            Flag to specify if the contructor have to validate the OPC
+	 *            Flag to specify if the constructor have to validate the OPC
 	 *            conformance. Must be always <code>true</code> except for
 	 *            special URI like '/' which is needed for internal use by
 	 *            OpenXML4J but is not valid.
@@ -138,8 +135,9 @@ public final class PackagePartName imple
 	 *         part naming convention else <code>false</code>.
 	 */
 	private boolean isRelationshipPartURI(URI partUri) {
-		if (partUri == null)
-			throw new IllegalArgumentException("partUri");
+		if (partUri == null) {
+            throw new IllegalArgumentException("partUri");
+        }
 
 		return partUri.getPath().matches(
 				"^.*/" + PackagingURIHelper.RELATIONSHIP_PART_SEGMENT_NAME + "/.*\\"
@@ -168,8 +166,9 @@ public final class PackagePartName imple
 	 */
 	private static void throwExceptionIfInvalidPartUri(URI partUri)
 			throws InvalidFormatException {
-		if (partUri == null)
-			throw new IllegalArgumentException("partUri");
+		if (partUri == null) {
+            throw new IllegalArgumentException("partUri");
+        }
 		// Check if the part name URI is empty [M1.1]
 		throwExceptionIfEmptyURI(partUri);
 
@@ -197,15 +196,17 @@ public final class PackagePartName imple
 	 */
 	private static void throwExceptionIfEmptyURI(URI partURI)
 			throws InvalidFormatException {
-		if (partURI == null)
-			throw new IllegalArgumentException("partURI");
+		if (partURI == null) {
+            throw new IllegalArgumentException("partURI");
+        }
 
 		String uriPath = partURI.getPath();
 		if (uriPath.length() == 0
-				|| ((uriPath.length() == 1) && (uriPath.charAt(0) == PackagingURIHelper.FORWARD_SLASH_CHAR)))
-			throw new InvalidFormatException(
+				|| ((uriPath.length() == 1) && (uriPath.charAt(0) == PackagingURIHelper.FORWARD_SLASH_CHAR))) {
+            throw new InvalidFormatException(
 					"A part name shall not be empty [M1.1]: "
 							+ partURI.getPath());
+        }
 	}
 
 	/**
@@ -240,32 +241,31 @@ public final class PackagePartName imple
 		}
 
 		// Split the URI into several part and analyze each
-		String[] segments = partUri.toASCIIString().split("/");
-		if (segments.length <= 1 || !segments[0].isEmpty())
-			throw new InvalidFormatException(
-					"A part name shall not have empty segments [M1.3]: "
-							+ partUri.getPath());
+		String[] segments = partUri.toASCIIString()
+	        .replaceFirst("^"+PackagingURIHelper.FORWARD_SLASH_CHAR,"")
+	        .split(PackagingURIHelper.FORWARD_SLASH_STRING);
+		
+		if (segments.length < 1) {
+            throw new InvalidFormatException(
+				"A part name shall not have empty segments [M1.3]: " + partUri.getPath());
+        }
 
-		for (int i = 1; i < segments.length; ++i) {
-			String seg = segments[i];
+		for (final String seg : segments) {
 			if (seg == null || seg.isEmpty()) {
 				throw new InvalidFormatException(
-						"A part name shall not have empty segments [M1.3]: "
-								+ partUri.getPath());
+					"A part name shall not have empty segments [M1.3]: " + partUri.getPath());
 			}
 
 			if (seg.endsWith(".")) {
 				throw new InvalidFormatException(
-						"A segment shall not end with a dot ('.') character [M1.9]: "
-								+ partUri.getPath());
+					"A segment shall not end with a dot ('.') character [M1.9]: " + partUri.getPath());
 			}
 
 			if (seg.replaceAll("\\\\.", "").isEmpty()) {
 				// Normally will never been invoked with the previous
 				// implementation rule [M1.9]
 				throw new InvalidFormatException(
-						"A segment shall include at least one non-dot character. [M1.10]: "
-								+ partUri.getPath());
+					"A segment shall include at least one non-dot character. [M1.10]: " + partUri.getPath());
 			}
 
 			// Check for rule M1.6, M1.7, M1.8
@@ -288,93 +288,60 @@ public final class PackagePartName imple
 	 */
 	private static void checkPCharCompliance(String segment)
 			throws InvalidFormatException {
-		boolean errorFlag;
 		final int length = segment.length();
 		for (int i = 0; i < length; ++i) {
-			char c = segment.charAt(i);
-			errorFlag = true;
+			final char c = segment.charAt(i);
 
 			/* Check rule M1.6 */
 
-			// Check for digit or letter
-			if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
-					|| (c >= '0' && c <= '9')) {
-				errorFlag = false;
-			} else {
-				// Check "-", ".", "_", "~"
-				for (int j = 0; j < RFC3986_PCHAR_UNRESERVED_SUP.length; ++j) {
-					if (c == RFC3986_PCHAR_UNRESERVED_SUP[j].charAt(0)) {
-						errorFlag = false;
-						break;
-					}
-				}
-
-				// Check ":", "@"
-				for (int j = 0; errorFlag
-						&& j < RFC3986_PCHAR_AUTHORIZED_SUP.length; ++j) {
-					if (c == RFC3986_PCHAR_AUTHORIZED_SUP[j].charAt(0)) {
-						errorFlag = false;
-					}
-				}
-
-				// Check "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
-				for (int j = 0; errorFlag
-						&& j < RFC3986_PCHAR_SUB_DELIMS.length; ++j) {
-					if (c == RFC3986_PCHAR_SUB_DELIMS[j].charAt(0)) {
-						errorFlag = false;
-					}
-				}
+			if (
+    			// Check for digit or letter
+		        isDigitOrLetter(c) ||
+                // Check "-", ".", "_", "~"
+                RFC3986_PCHAR_UNRESERVED_SUP.indexOf(c) > -1 ||
+                // Check ":", "@"
+                RFC3986_PCHAR_AUTHORIZED_SUP.indexOf(c) > -1 ||
+                // Check "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
+                RFC3986_PCHAR_SUB_DELIMS.indexOf(c) > -1
+            ) {
+			    continue;
 			}
+			
 
-			if (errorFlag && c == '%') {
-				// We certainly found an encoded character, check for length
-				// now ( '%' HEXDIGIT HEXDIGIT)
-				if (((length - i) < 2)) {
-					throw new InvalidFormatException("The segment " + segment
-							+ " contain invalid encoded character !");
-				}
-
-				// If not percent encoded character error occur then reset the
-				// flag -> the character is valid
-				errorFlag = false;
-
-				// Decode the encoded character
-				char decodedChar = (char) Integer.parseInt(segment.substring(
-						i + 1, i + 3), 16);
-				i += 2;
-
-				/* Check rule M1.7 */
-				if (decodedChar == '/' || decodedChar == '\\')
-					throw new InvalidFormatException(
-							"A segment shall not contain percent-encoded forward slash ('/'), or backward slash ('\') characters. [M1.7]");
-
-				/* Check rule M1.8 */
-
-				// Check for unreserved character like define in RFC3986
-				if ((decodedChar >= 'A' && decodedChar <= 'Z')
-						|| (decodedChar >= 'a' && decodedChar <= 'z')
-						|| (decodedChar >= '0' && decodedChar <= '9'))
-					errorFlag = true;
-
-				// Check for unreserved character "-", ".", "_", "~"
-				for (int j = 0; !errorFlag
-						&& j < RFC3986_PCHAR_UNRESERVED_SUP.length; ++j) {
-					if (c == RFC3986_PCHAR_UNRESERVED_SUP[j].charAt(0)) {
-						errorFlag = true;
-						break;
-					}
-				}
-				if (errorFlag)
-					throw new InvalidFormatException(
-							"A segment shall not contain percent-encoded unreserved characters. [M1.8]");
+			if (c != '%') {
+	            throw new InvalidFormatException(
+                    "A segment shall not hold any characters other than pchar characters. [M1.6]");
+			}			    
+			    
+			// We certainly found an encoded character, check for length
+			// now ( '%' HEXDIGIT HEXDIGIT)
+			if ((length - i) < 2 || !isHexDigit(segment.charAt(i+1)) || !isHexDigit(segment.charAt(i+2))) {
+				throw new InvalidFormatException("The segment " + segment + " contain invalid encoded character !");
 			}
 
-			if (errorFlag)
+			// Decode the encoded character
+			final char decodedChar = (char) Integer.parseInt(segment.substring(i + 1, i + 3), 16);
+			i += 2;
+
+			/* Check rule M1.7 */
+			if (decodedChar == '/' || decodedChar == '\\') {
 				throw new InvalidFormatException(
-						"A segment shall not hold any characters other than pchar characters. [M1.6]");
+					"A segment shall not contain percent-encoded forward slash ('/'), or backward slash ('\') characters. [M1.7]");
+			}
+
+			/* Check rule M1.8 */
+			if (
+			     // Check for unreserved character like define in RFC3986
+		        isDigitOrLetter(decodedChar) ||
+		        // Check for unreserved character "-", ".", "_", "~"
+		        RFC3986_PCHAR_UNRESERVED_SUP.indexOf(decodedChar) > -1
+	        ) {
+                throw new InvalidFormatException(
+                    "A segment shall not contain percent-encoded unreserved characters. [M1.8]");
+			}
 		}
 	}
-
+    
 	/**
 	 * Throws an exception if the specified part name doesn't start with a
 	 * forward slash character '/'. [M1.4]
@@ -389,10 +356,11 @@ public final class PackagePartName imple
 			URI partUri) throws InvalidFormatException {
 		String uriPath = partUri.getPath();
 		if (uriPath.length() > 0
-				&& uriPath.charAt(0) != PackagingURIHelper.FORWARD_SLASH_CHAR)
-			throw new InvalidFormatException(
+				&& uriPath.charAt(0) != PackagingURIHelper.FORWARD_SLASH_CHAR) {
+            throw new InvalidFormatException(
 					"A part name shall start with a forward slash ('/') character [M1.4]: "
 							+ partUri.getPath());
+        }
 	}
 
 	/**
@@ -409,10 +377,11 @@ public final class PackagePartName imple
 			URI partUri) throws InvalidFormatException {
 		String uriPath = partUri.getPath();
 		if (uriPath.length() > 0
-				&& uriPath.charAt(uriPath.length() - 1) == PackagingURIHelper.FORWARD_SLASH_CHAR)
-			throw new InvalidFormatException(
+				&& uriPath.charAt(uriPath.length() - 1) == PackagingURIHelper.FORWARD_SLASH_CHAR) {
+            throw new InvalidFormatException(
 					"A part name shall not have a forward slash as the last character [M1.5]: "
 							+ partUri.getPath());
+        }
 	}
 
 	/**
@@ -423,11 +392,10 @@ public final class PackagePartName imple
 	 * @throws InvalidFormatException
 	 *             Throws if the specified URI is absolute.
 	 */
-	private static void throwExceptionIfAbsoluteUri(URI partUri)
-			throws InvalidFormatException {
-		if (partUri.isAbsolute())
-			throw new InvalidFormatException("Absolute URI forbidden: "
-					+ partUri);
+	private static void throwExceptionIfAbsoluteUri(URI partUri) throws InvalidFormatException {
+		if (partUri.isAbsolute()) {
+            throw new InvalidFormatException("Absolute URI forbidden: " + partUri);
+        }
 	}
 
 	/**
@@ -438,12 +406,11 @@ public final class PackagePartName imple
 	 * part names and package implementers shall neither create nor recognize
 	 * packages with equivalent part names. [M1.12]
 	 */
-        @Override
-        public int compareTo(PackagePartName other)
-        {
-            // compare with natural sort order
-            return compare(this, other);
-        }
+    @Override
+    public int compareTo(PackagePartName other) {
+        // compare with natural sort order
+        return compare(this, other);
+    }
 
 
 	/**
@@ -456,8 +423,9 @@ public final class PackagePartName imple
 		String fragment = this.partNameURI.getPath();
 		if (fragment.length() > 0) {
 			int i = fragment.lastIndexOf(".");
-			if (i > -1)
-				return fragment.substring(i + 1);
+			if (i > -1) {
+                return fragment.substring(i + 1);
+            }
 		}
 		return "";
 	}
@@ -468,7 +436,7 @@ public final class PackagePartName imple
 	 * @return The name of this part name.
 	 */
 	public String getName() {
-		return this.partNameURI.toASCIIString();
+		return getURI().toASCIIString();
 	}
 
 	/**
@@ -479,20 +447,13 @@ public final class PackagePartName imple
 	 */
 	@Override
 	public boolean equals(Object other) {
-            if (other instanceof PackagePartName) {
-                // String.equals() is compatible with our compareTo(), but cheaper
-                return this.partNameURI.toASCIIString().toLowerCase(Locale.ROOT).equals
-                (
-                    ((PackagePartName) other).partNameURI.toASCIIString().toLowerCase(Locale.ROOT)
-                );
-            } else {
-                return false;
-            }
-        }
+        return (other instanceof PackagePartName) &&
+            compare(this.getName(), ((PackagePartName)other).getName()) == 0;
+    }
 
 	@Override
 	public int hashCode() {
-		return this.partNameURI.toASCIIString().toLowerCase(Locale.ROOT).hashCode();
+		return getName().toLowerCase(Locale.ROOT).hashCode();
 	}
 
 	@Override
@@ -529,24 +490,10 @@ public final class PackagePartName imple
      * part names and package implementers shall neither create nor recognize
      * packages with equivalent part names. [M1.12]
      */
-    public static int compare(PackagePartName obj1, PackagePartName obj2)
-    {
-        // NOTE could also throw a NullPointerException() if desired
-        if (obj1 == null)
-        {
-            // (null) == (null), (null) < (non-null)
-            return (obj2 == null ? 0 : -1);
-        }
-        else if (obj2 == null)
-        {
-            // (non-null) > (null)
-            return 1;
-        }
-
-        return compare
-        (
-            obj1.getURI().toASCIIString().toLowerCase(Locale.ROOT),
-            obj2.getURI().toASCIIString().toLowerCase(Locale.ROOT)
+    public static int compare(PackagePartName obj1, PackagePartName obj2) {
+        return compare (
+            obj1 == null ? null : obj1.getName(),
+            obj2 == null ? null : obj2.getName()
         );
     }
 
@@ -560,49 +507,48 @@ public final class PackagePartName imple
      * numerical portion), but sorts "File10.png" before "file2.png"
      * (lexigraphical sort)
      */
-    public static int compare(String str1, String str2)
+    public static int compare(final String str1, final String str2)
     {
-        if (str1 == null)
-        {
+        if (str1 == null) {
             // (null) == (null), (null) < (non-null)
             return (str2 == null ? 0 : -1);
-        }
-        else if (str2 == null)
-        {
+        } else if (str2 == null) {
             // (non-null) > (null)
             return 1;
         }
+        
+        if (str1.equalsIgnoreCase(str2)) {
+            return 0;
+        }
+        final String name1 = str1.toLowerCase(Locale.ROOT);
+        final String name2 = str2.toLowerCase(Locale.ROOT);
 
-        int len1 = str1.length();
-        int len2 = str2.length();
-        for (int idx1 = 0, idx2 = 0; idx1 < len1 && idx2 < len2; /*nil*/)
-        {
-            char c1 = str1.charAt(idx1++);
-            char c2 = str2.charAt(idx2++);
-
-            if (Character.isDigit(c1) && Character.isDigit(c2))
-            {
-                int beg1 = idx1 - 1;  // undo previous increment
-                while (idx1 < len1 && Character.isDigit(str1.charAt(idx1)))
-                {
-                    ++idx1;
+        final int len1 = name1.length();
+        final int len2 = name2.length();
+        for (int idx1 = 0, idx2 = 0; idx1 < len1 && idx2 < len2; /*nil*/) {
+            final char c1 = name1.charAt(idx1++);
+            final char c2 = name2.charAt(idx2++);
+
+            if (Character.isDigit(c1) && Character.isDigit(c2)) {
+                final int beg1 = idx1 - 1;  // undo previous increment
+                while (idx1 < len1 && Character.isDigit(name1.charAt(idx1))) {
+                    idx1++;
                 }
 
-                int beg2 = idx2 - 1;  // undo previous increment
-                while (idx2 < len2 && Character.isDigit(str2.charAt(idx2)))
-                {
-                    ++idx2;
+                final int beg2 = idx2 - 1;  // undo previous increment
+                while (idx2 < len2 && Character.isDigit(name2.charAt(idx2))) {
+                    idx2++;
                 }
 
                 // note: BigInteger for extra safety
-                int cmp = new BigInteger(str1.substring(beg1, idx1)).compareTo
-                (
-                    new BigInteger(str2.substring(beg2, idx2))
-                );
-                if (cmp != 0) return cmp;
+                final BigInteger b1 = new BigInteger(name1.substring(beg1, idx1));
+                final BigInteger b2 = new BigInteger(name2.substring(beg2, idx2));
+                final int cmp = b1.compareTo(b2);
+                if (cmp != 0) {
+                    return cmp;
+                }
             }
-            else if (c1 != c2)
-            {
+            else if (c1 != c2) {
                 return (c1 - c2);
             }
         }
@@ -610,6 +556,11 @@ public final class PackagePartName imple
         return (len1 - len2);
     }
 
+    private static boolean isDigitOrLetter(char c) {
+        return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+    }
+    
+    private static boolean isHexDigit(char c) {
+        return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+    }
 }
-
-/* ************************************************************************** */



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org