You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by jo...@apache.org on 2009/05/20 10:02:37 UTC

svn commit: r776607 [2/7] - in /poi/trunk/src/ooxml/java/org/apache/poi: ./ openxml4j/exceptions/ openxml4j/opc/ openxml4j/opc/internal/ openxml4j/opc/internal/marshallers/ openxml4j/opc/internal/signature/ openxml4j/opc/internal/unmarshallers/ openxml...

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=776607&r1=776606&r2=776607&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 Wed May 20 08:02:35 2009
@@ -1,509 +1,506 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.openxml4j.opc;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
-
-/**
- * An immutable Open Packaging Convention compliant part name.
- * 
- * @author Julien Chable
- * @version 0.1
- * 
- * @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> {
-
-	/**
-	 * Part name stored as an URI.
-	 */
-	private URI partNameURI;
-
-	/*
-	 * URI Characters definition (RFC 3986)
-	 */
-
-	/**
-	 * Reserved characters for sub delimitations.
-	 */
-	private static String[] RFC3986_PCHAR_SUB_DELIMS = { "!", "$", "&", "'",
-			"(", ")", "*", "+", ",", ";", "=" };
-
-	/**
-	 * Unreserved character (+ ALPHA & DIGIT).
-	 */
-	private static String[] RFC3986_PCHAR_UNRESERVED_SUP = { "-", ".", "_", "~" };
-
-	/**
-	 * Authorized reserved characters for pChar.
-	 */
-	private static String[] RFC3986_PCHAR_AUTHORIZED_SUP = { ":", "@" };
-
-	/**
-	 * Flag to know if this part name is from a relationship part name.
-	 */
-	private boolean isRelationship;
-
-	/**
-	 * Constructor. Makes a ValidPartName object from a java.net.URI
-	 * 
-	 * @param uri
-	 *            The URI to validate and to transform into ValidPartName.
-	 * @param checkConformance
-	 *            Flag to specify if the contructor 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.
-	 * @throws InvalidFormatException
-	 *             Throw if the specified part name is not conform to Open
-	 *             Packaging Convention specifications.
-	 * @see java.net.URI
-	 */
-	PackagePartName(URI uri, boolean checkConformance)
-			throws InvalidFormatException {
-		if (checkConformance) {
-			throwExceptionIfInvalidPartUri(uri);
-		} else {
-			if (!PackagingURIHelper.PACKAGE_ROOT_URI.equals(uri)) {
-				throw new OpenXML4JRuntimeException(
-						"OCP conformance must be check for ALL part name except special cases : ['/']");
-			}
-		}
-		this.partNameURI = uri;
-		this.isRelationship = isRelationshipPartURI(this.partNameURI);
-	}
-
-	/**
-	 * Constructor. Makes a ValidPartName object from a String part name.
-	 * 
-	 * @param partName
-	 *            Part name to valid and to create.
-	 * @param checkConformance
-	 *            Flag to specify if the contructor 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.
-	 * @throws InvalidFormatException
-	 *             Throw if the specified part name is not conform to Open
-	 *             Packaging Convention specifications.
-	 */
-	PackagePartName(String partName, boolean checkConformance)
-			throws InvalidFormatException {
-		URI partURI;
-		try {
-			partURI = new URI(partName);
-		} catch (URISyntaxException e) {
-			throw new IllegalArgumentException(
-					"partName argmument is not a valid OPC part name !");
-		}
-
-		if (checkConformance) {
-			throwExceptionIfInvalidPartUri(partURI);
-		} else {
-			if (!PackagingURIHelper.PACKAGE_ROOT_URI.equals(partURI)) {
-				throw new OpenXML4JRuntimeException(
-						"OCP conformance must be check for ALL part name except special cases : ['/']");
-			}
-		}
-		this.partNameURI = partURI;
-		this.isRelationship = isRelationshipPartURI(this.partNameURI);
-	}
-
-	/**
-	 * Check if the specified part name is a relationship part name.
-	 * 
-	 * @param partUri
-	 *            The URI to check.
-	 * @return <code>true</code> if this part name respect the relationship
-	 *         part naming convention else <code>false</code>.
-	 */
-	private boolean isRelationshipPartURI(URI partUri) {
-		if (partUri == null)
-			throw new IllegalArgumentException("partUri");
-
-		return partUri.getPath().matches(
-				"^.*/" + PackagingURIHelper.RELATIONSHIP_PART_SEGMENT_NAME + "/.*\\"
-						+ PackagingURIHelper.RELATIONSHIP_PART_EXTENSION_NAME
-						+ "$");
-	}
-
-	/**
-	 * Know if this part name is a relationship part name.
-	 * 
-	 * @return <code>true</code> if this part name respect the relationship
-	 *         part naming convention else <code>false</code>.
-	 */
-	public boolean isRelationshipPartURI() {
-		return this.isRelationship;
-	}
-
-	/**
-	 * Throws an exception (of any kind) if the specified part name does not
-	 * follow the Open Packaging Convention specifications naming rules.
-	 * 
-	 * @param partUri
-	 *            The part name to check.
-	 * @throws Exception
-	 *             Throws if the part name is invalid.
-	 */
-	private static void throwExceptionIfInvalidPartUri(URI partUri)
-			throws InvalidFormatException {
-		if (partUri == null)
-			throw new IllegalArgumentException("partUri");
-		// Check if the part name URI is empty [M1.1]
-		throwExceptionIfEmptyURI(partUri);
-
-		// Check if the part name URI is absolute
-		throwExceptionIfAbsoluteUri(partUri);
-
-		// Check if the part name URI starts with a forward slash [M1.4]
-		throwExceptionIfPartNameNotStartsWithForwardSlashChar(partUri);
-
-		// Check if the part name URI ends with a forward slash [M1.5]
-		throwExceptionIfPartNameEndsWithForwardSlashChar(partUri);
-
-		// Check if the part name does not have empty segments. [M1.3]
-		// Check if a segment ends with a dot ('.') character. [M1.9]
-		throwExceptionIfPartNameHaveInvalidSegments(partUri);
-	}
-
-	/**
-	 * Throws an exception if the specified URI is empty. [M1.1]
-	 * 
-	 * @param partURI
-	 *            Part URI to check.
-	 * @throws InvalidFormatException
-	 *             If the specified URI is empty.
-	 */
-	private static void throwExceptionIfEmptyURI(URI partURI)
-			throws InvalidFormatException {
-		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(
-					"A part name shall not be empty [M1.1]: "
-							+ partURI.getPath());
-	}
-
-	/**
-	 * Throws an exception if the part name has empty segments. [M1.3]
-	 * 
-	 * Throws an exception if a segment any characters other than pchar
-	 * characters. [M1.6]
-	 * 
-	 * Throws an exception if a segment contain percent-encoded forward slash
-	 * ('/'), or backward slash ('\') characters. [M1.7]
-	 * 
-	 * Throws an exception if a segment contain percent-encoded unreserved
-	 * characters. [M1.8]
-	 * 
-	 * Throws an exception if the specified part name's segments end with a dot
-	 * ('.') character. [M1.9]
-	 * 
-	 * Throws an exception if a segment doesn't include at least one non-dot
-	 * character. [M1.10]
-	 * 
-	 * @param partUri
-	 *            The part name to check.
-	 * @throws InvalidFormatException
-	 *             if the specified URI contain an empty segments or if one the
-	 *             segments contained in the part name, ends with a dot ('.')
-	 *             character.
-	 */
-	private static void throwExceptionIfPartNameHaveInvalidSegments(URI partUri)
-			throws InvalidFormatException {
-		if (partUri == null || "".equals(partUri)) {
-			throw new IllegalArgumentException("partUri");
-		}
-
-		// Split the URI into several part and analyze each
-		String[] segments = partUri.toASCIIString().split("/");
-		if (segments.length <= 1 || !segments[0].equals(""))
-			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];
-			if (seg == null || "".equals(seg)) {
-				throw new InvalidFormatException(
-						"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());
-			}
-
-			if ("".equals(seg.replaceAll("\\\\.", ""))) {
-				// 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());
-			}
-
-			/*
-			 * Check for rule M1.6, M1.7, M1.8
-			 */
-			checkPCharCompliance(seg);
-		}
-	}
-
-	/**
-	 * Throws an exception if a segment any characters other than pchar
-	 * characters. [M1.6]
-	 * 
-	 * Throws an exception if a segment contain percent-encoded forward slash
-	 * ('/'), or backward slash ('\') characters. [M1.7]
-	 * 
-	 * Throws an exception if a segment contain percent-encoded unreserved
-	 * characters. [M1.8]
-	 * 
-	 * @param segment
-	 *            The segment to check
-	 */
-	private static void checkPCharCompliance(String segment)
-			throws InvalidFormatException {
-		boolean errorFlag;
-		for (int i = 0; i < segment.length(); ++i) {
-			char c = segment.charAt(i);
-			errorFlag = true;
-
-			/* 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 (errorFlag && c == '%') {
-				// We certainly found an encoded character, check for length
-				// now ( '%' HEXDIGIT HEXDIGIT)
-				if (((segment.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 (errorFlag)
-				throw new InvalidFormatException(
-						"A segment shall not hold any characters other than pchar characters. [M1.6]");
-		}
-	}
-
-	/**
-	 * Throws an exception if the specified part name doesn't start with a
-	 * forward slash character '/'. [M1.4]
-	 * 
-	 * @param partUri
-	 *            The part name to check.
-	 * @throws InvalidFormatException
-	 *             If the specified part name doesn't start with a forward slash
-	 *             character '/'.
-	 */
-	private static void throwExceptionIfPartNameNotStartsWithForwardSlashChar(
-			URI partUri) throws InvalidFormatException {
-		String uriPath = partUri.getPath();
-		if (uriPath.length() > 0
-				&& uriPath.charAt(0) != PackagingURIHelper.FORWARD_SLASH_CHAR)
-			throw new InvalidFormatException(
-					"A part name shall start with a forward slash ('/') character [M1.4]: "
-							+ partUri.getPath());
-	}
-
-	/**
-	 * Throws an exception if the specified part name ends with a forwar slash
-	 * character '/'. [M1.5]
-	 * 
-	 * @param partUri
-	 *            The part name to check.
-	 * @throws InvalidFormatException
-	 *             If the specified part name ends with a forwar slash character
-	 *             '/'.
-	 */
-	private static void throwExceptionIfPartNameEndsWithForwardSlashChar(
-			URI partUri) throws InvalidFormatException {
-		String uriPath = partUri.getPath();
-		if (uriPath.length() > 0
-				&& 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());
-	}
-
-	/**
-	 * Throws an exception if the specified URI is absolute.
-	 * 
-	 * @param partUri
-	 *            The URI to check.
-	 * @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);
-	}
-
-	/**
-	 * Compare two part name following the rule M1.12 :
-	 * 
-	 * Part name equivalence is determined by comparing part names as
-	 * case-insensitive ASCII strings. Packages shall not contain equivalent
-	 * part names and package implementers shall neither create nor recognize
-	 * packages with equivalent part names. [M1.12]
-	 */
-	public int compareTo(PackagePartName otherPartName) {
-		if (otherPartName == null)
-			return -1;
-		return this.partNameURI.toASCIIString().toLowerCase().compareTo(
-				otherPartName.partNameURI.toASCIIString().toLowerCase());
-	}
-
-	/**
-	 * Retrieves the extension of the part name if any. If there is no extension
-	 * returns an empty String. Example : '/document/content.xml' => 'xml'
-	 * 
-	 * @return The extension of the part name.
-	 */
-	public String getExtension() {
-		String fragment = this.partNameURI.getPath();
-		if (fragment.length() > 0) {
-			int i = fragment.lastIndexOf(".");
-			if (i > -1)
-				return fragment.substring(i + 1);
-		}
-		return "";
-	}
-
-	/**
-	 * Get this part name.
-	 * 
-	 * @return The name of this part name.
-	 */
-	public String getName() {
-		return this.partNameURI.toASCIIString();
-	}
-
-	/**
-	 * Part name equivalence is determined by comparing part names as
-	 * case-insensitive ASCII strings. Packages shall not contain equivalent
-	 * part names and package implementers shall neither create nor recognize
-	 * packages with equivalent part names. [M1.12]
-	 */
-	@Override
-	public boolean equals(Object otherPartName) {
-		if (otherPartName == null
-				|| !(otherPartName instanceof PackagePartName))
-			return false;
-		return this.partNameURI.toASCIIString().toLowerCase().equals(
-				((PackagePartName) otherPartName).partNameURI.toASCIIString()
-						.toLowerCase());
-	}
-
-	@Override
-	public int hashCode() {
-		return this.partNameURI.toASCIIString().toLowerCase().hashCode();
-	}
-
-	@Override
-	public String toString() {
-		return getName();
-	}
-
-	/* Getters and setters */
-
-	/**
-	 * Part name property getter.
-	 * 
-	 * @return This part name URI.
-	 */
-	public URI getURI() {
-		return this.partNameURI;
-	}
-}
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
+
+/**
+ * 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> {
+
+	/**
+	 * Part name stored as an URI.
+	 */
+	private URI partNameURI;
+
+	/*
+	 * URI Characters definition (RFC 3986)
+	 */
+
+	/**
+	 * Reserved characters for sub delimitations.
+	 */
+	private static String[] RFC3986_PCHAR_SUB_DELIMS = { "!", "$", "&", "'",
+			"(", ")", "*", "+", ",", ";", "=" };
+
+	/**
+	 * Unreserved character (+ ALPHA & DIGIT).
+	 */
+	private static String[] RFC3986_PCHAR_UNRESERVED_SUP = { "-", ".", "_", "~" };
+
+	/**
+	 * Authorized reserved characters for pChar.
+	 */
+	private static String[] RFC3986_PCHAR_AUTHORIZED_SUP = { ":", "@" };
+
+	/**
+	 * Flag to know if this part name is from a relationship part name.
+	 */
+	private boolean isRelationship;
+
+	/**
+	 * Constructor. Makes a ValidPartName object from a java.net.URI
+	 *
+	 * @param uri
+	 *            The URI to validate and to transform into ValidPartName.
+	 * @param checkConformance
+	 *            Flag to specify if the contructor 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.
+	 * @throws InvalidFormatException
+	 *             Throw if the specified part name is not conform to Open
+	 *             Packaging Convention specifications.
+	 * @see java.net.URI
+	 */
+	PackagePartName(URI uri, boolean checkConformance)
+			throws InvalidFormatException {
+		if (checkConformance) {
+			throwExceptionIfInvalidPartUri(uri);
+		} else {
+			if (!PackagingURIHelper.PACKAGE_ROOT_URI.equals(uri)) {
+				throw new OpenXML4JRuntimeException(
+						"OCP conformance must be check for ALL part name except special cases : ['/']");
+			}
+		}
+		this.partNameURI = uri;
+		this.isRelationship = isRelationshipPartURI(this.partNameURI);
+	}
+
+	/**
+	 * Constructor. Makes a ValidPartName object from a String part name.
+	 *
+	 * @param partName
+	 *            Part name to valid and to create.
+	 * @param checkConformance
+	 *            Flag to specify if the contructor 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.
+	 * @throws InvalidFormatException
+	 *             Throw if the specified part name is not conform to Open
+	 *             Packaging Convention specifications.
+	 */
+	PackagePartName(String partName, boolean checkConformance)
+			throws InvalidFormatException {
+		URI partURI;
+		try {
+			partURI = new URI(partName);
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException(
+					"partName argmument is not a valid OPC part name !");
+		}
+
+		if (checkConformance) {
+			throwExceptionIfInvalidPartUri(partURI);
+		} else {
+			if (!PackagingURIHelper.PACKAGE_ROOT_URI.equals(partURI)) {
+				throw new OpenXML4JRuntimeException(
+						"OCP conformance must be check for ALL part name except special cases : ['/']");
+			}
+		}
+		this.partNameURI = partURI;
+		this.isRelationship = isRelationshipPartURI(this.partNameURI);
+	}
+
+	/**
+	 * Check if the specified part name is a relationship part name.
+	 *
+	 * @param partUri
+	 *            The URI to check.
+	 * @return <code>true</code> if this part name respect the relationship
+	 *         part naming convention else <code>false</code>.
+	 */
+	private boolean isRelationshipPartURI(URI partUri) {
+		if (partUri == null)
+			throw new IllegalArgumentException("partUri");
+
+		return partUri.getPath().matches(
+				"^.*/" + PackagingURIHelper.RELATIONSHIP_PART_SEGMENT_NAME + "/.*\\"
+						+ PackagingURIHelper.RELATIONSHIP_PART_EXTENSION_NAME
+						+ "$");
+	}
+
+	/**
+	 * Know if this part name is a relationship part name.
+	 *
+	 * @return <code>true</code> if this part name respect the relationship
+	 *         part naming convention else <code>false</code>.
+	 */
+	public boolean isRelationshipPartURI() {
+		return this.isRelationship;
+	}
+
+	/**
+	 * Throws an exception (of any kind) if the specified part name does not
+	 * follow the Open Packaging Convention specifications naming rules.
+	 *
+	 * @param partUri
+	 *            The part name to check.
+	 * @throws Exception
+	 *             Throws if the part name is invalid.
+	 */
+	private static void throwExceptionIfInvalidPartUri(URI partUri)
+			throws InvalidFormatException {
+		if (partUri == null)
+			throw new IllegalArgumentException("partUri");
+		// Check if the part name URI is empty [M1.1]
+		throwExceptionIfEmptyURI(partUri);
+
+		// Check if the part name URI is absolute
+		throwExceptionIfAbsoluteUri(partUri);
+
+		// Check if the part name URI starts with a forward slash [M1.4]
+		throwExceptionIfPartNameNotStartsWithForwardSlashChar(partUri);
+
+		// Check if the part name URI ends with a forward slash [M1.5]
+		throwExceptionIfPartNameEndsWithForwardSlashChar(partUri);
+
+		// Check if the part name does not have empty segments. [M1.3]
+		// Check if a segment ends with a dot ('.') character. [M1.9]
+		throwExceptionIfPartNameHaveInvalidSegments(partUri);
+	}
+
+	/**
+	 * Throws an exception if the specified URI is empty. [M1.1]
+	 *
+	 * @param partURI
+	 *            Part URI to check.
+	 * @throws InvalidFormatException
+	 *             If the specified URI is empty.
+	 */
+	private static void throwExceptionIfEmptyURI(URI partURI)
+			throws InvalidFormatException {
+		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(
+					"A part name shall not be empty [M1.1]: "
+							+ partURI.getPath());
+	}
+
+	/**
+	 * Throws an exception if the part name has empty segments. [M1.3]
+	 *
+	 * Throws an exception if a segment any characters other than pchar
+	 * characters. [M1.6]
+	 *
+	 * Throws an exception if a segment contain percent-encoded forward slash
+	 * ('/'), or backward slash ('\') characters. [M1.7]
+	 *
+	 * Throws an exception if a segment contain percent-encoded unreserved
+	 * characters. [M1.8]
+	 *
+	 * Throws an exception if the specified part name's segments end with a dot
+	 * ('.') character. [M1.9]
+	 *
+	 * Throws an exception if a segment doesn't include at least one non-dot
+	 * character. [M1.10]
+	 *
+	 * @param partUri
+	 *            The part name to check.
+	 * @throws InvalidFormatException
+	 *             if the specified URI contain an empty segments or if one the
+	 *             segments contained in the part name, ends with a dot ('.')
+	 *             character.
+	 */
+	private static void throwExceptionIfPartNameHaveInvalidSegments(URI partUri)
+			throws InvalidFormatException {
+		if (partUri == null || "".equals(partUri)) {
+			throw new IllegalArgumentException("partUri");
+		}
+
+		// Split the URI into several part and analyze each
+		String[] segments = partUri.toASCIIString().split("/");
+		if (segments.length <= 1 || !segments[0].equals(""))
+			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];
+			if (seg == null || "".equals(seg)) {
+				throw new InvalidFormatException(
+						"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());
+			}
+
+			if ("".equals(seg.replaceAll("\\\\.", ""))) {
+				// 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());
+			}
+
+			// Check for rule M1.6, M1.7, M1.8
+			checkPCharCompliance(seg);
+		}
+	}
+
+	/**
+	 * Throws an exception if a segment any characters other than pchar
+	 * characters. [M1.6]
+	 *
+	 * Throws an exception if a segment contain percent-encoded forward slash
+	 * ('/'), or backward slash ('\') characters. [M1.7]
+	 *
+	 * Throws an exception if a segment contain percent-encoded unreserved
+	 * characters. [M1.8]
+	 *
+	 * @param segment
+	 *            The segment to check
+	 */
+	private static void checkPCharCompliance(String segment)
+			throws InvalidFormatException {
+		boolean errorFlag;
+		for (int i = 0; i < segment.length(); ++i) {
+			char c = segment.charAt(i);
+			errorFlag = true;
+
+			/* 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 (errorFlag && c == '%') {
+				// We certainly found an encoded character, check for length
+				// now ( '%' HEXDIGIT HEXDIGIT)
+				if (((segment.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 (errorFlag)
+				throw new InvalidFormatException(
+						"A segment shall not hold any characters other than pchar characters. [M1.6]");
+		}
+	}
+
+	/**
+	 * Throws an exception if the specified part name doesn't start with a
+	 * forward slash character '/'. [M1.4]
+	 *
+	 * @param partUri
+	 *            The part name to check.
+	 * @throws InvalidFormatException
+	 *             If the specified part name doesn't start with a forward slash
+	 *             character '/'.
+	 */
+	private static void throwExceptionIfPartNameNotStartsWithForwardSlashChar(
+			URI partUri) throws InvalidFormatException {
+		String uriPath = partUri.getPath();
+		if (uriPath.length() > 0
+				&& uriPath.charAt(0) != PackagingURIHelper.FORWARD_SLASH_CHAR)
+			throw new InvalidFormatException(
+					"A part name shall start with a forward slash ('/') character [M1.4]: "
+							+ partUri.getPath());
+	}
+
+	/**
+	 * Throws an exception if the specified part name ends with a forwar slash
+	 * character '/'. [M1.5]
+	 *
+	 * @param partUri
+	 *            The part name to check.
+	 * @throws InvalidFormatException
+	 *             If the specified part name ends with a forwar slash character
+	 *             '/'.
+	 */
+	private static void throwExceptionIfPartNameEndsWithForwardSlashChar(
+			URI partUri) throws InvalidFormatException {
+		String uriPath = partUri.getPath();
+		if (uriPath.length() > 0
+				&& 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());
+	}
+
+	/**
+	 * Throws an exception if the specified URI is absolute.
+	 *
+	 * @param partUri
+	 *            The URI to check.
+	 * @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);
+	}
+
+	/**
+	 * Compare two part name following the rule M1.12 :
+	 *
+	 * Part name equivalence is determined by comparing part names as
+	 * case-insensitive ASCII strings. Packages shall not contain equivalent
+	 * part names and package implementers shall neither create nor recognize
+	 * packages with equivalent part names. [M1.12]
+	 */
+	public int compareTo(PackagePartName otherPartName) {
+		if (otherPartName == null)
+			return -1;
+		return this.partNameURI.toASCIIString().toLowerCase().compareTo(
+				otherPartName.partNameURI.toASCIIString().toLowerCase());
+	}
+
+	/**
+	 * Retrieves the extension of the part name if any. If there is no extension
+	 * returns an empty String. Example : '/document/content.xml' => 'xml'
+	 *
+	 * @return The extension of the part name.
+	 */
+	public String getExtension() {
+		String fragment = this.partNameURI.getPath();
+		if (fragment.length() > 0) {
+			int i = fragment.lastIndexOf(".");
+			if (i > -1)
+				return fragment.substring(i + 1);
+		}
+		return "";
+	}
+
+	/**
+	 * Get this part name.
+	 *
+	 * @return The name of this part name.
+	 */
+	public String getName() {
+		return this.partNameURI.toASCIIString();
+	}
+
+	/**
+	 * Part name equivalence is determined by comparing part names as
+	 * case-insensitive ASCII strings. Packages shall not contain equivalent
+	 * part names and package implementers shall neither create nor recognize
+	 * packages with equivalent part names. [M1.12]
+	 */
+	@Override
+	public boolean equals(Object otherPartName) {
+		if (otherPartName == null
+				|| !(otherPartName instanceof PackagePartName))
+			return false;
+		return this.partNameURI.toASCIIString().toLowerCase().equals(
+				((PackagePartName) otherPartName).partNameURI.toASCIIString()
+						.toLowerCase());
+	}
+
+	@Override
+	public int hashCode() {
+		return this.partNameURI.toASCIIString().toLowerCase().hashCode();
+	}
+
+	@Override
+	public String toString() {
+		return getName();
+	}
+
+	/* Getters and setters */
+
+	/**
+	 * Part name property getter.
+	 *
+	 * @return This part name URI.
+	 */
+	public URI getURI() {
+		return this.partNameURI;
+	}
+}

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipTypes.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipTypes.java?rev=776607&r1=776606&r2=776607&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipTypes.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipTypes.java Wed May 20 08:02:35 2009
@@ -1,77 +1,77 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.openxml4j.opc;
-
-/**
- * Relationship types.
- * 
- * @author Julien Chable
- * @version 0.2
- */
-public interface PackageRelationshipTypes {
-
-	/**
-	 * Core properties relationship type.
-	 */
-	String CORE_PROPERTIES = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
-
-	/**
-	 * Digital signature relationship type.
-	 */
-	String DIGITAL_SIGNATURE = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature";
-
-	/**
-	 * Digital signature certificate relationship type.
-	 */
-	String DIGITAL_SIGNATURE_CERTIFICATE = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/certificate";
-
-	/**
-	 * Digital signature origin relationship type.
-	 */
-	String DIGITAL_SIGNATURE_ORIGIN = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin";
-
-	/**
-	 * Thumbnail relationship type.
-	 */
-	String THUMBNAIL = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
-
-	/**
-	 * Extended properties relationship type.
-	 */
-	String EXTENDED_PROPERTIES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
-
-	/**
-	 * Core properties relationship type.
-	 */
-	String CORE_DOCUMENT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
-	
-	/**
-	 * Custom XML relationship type.
-	 */
-	String CUSTOM_XML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
-
-	/**
-	 * Image type.
-	 */
-	String IMAGE_PART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
-
-	/**
-	 * Style type.
-	 */
-	String STYLE_PART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
-}
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+/**
+ * Relationship types.
+ *
+ * @author Julien Chable
+ * @version 0.2
+ */
+public interface PackageRelationshipTypes {
+
+	/**
+	 * Core properties relationship type.
+	 */
+	String CORE_PROPERTIES = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
+
+	/**
+	 * Digital signature relationship type.
+	 */
+	String DIGITAL_SIGNATURE = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature";
+
+	/**
+	 * Digital signature certificate relationship type.
+	 */
+	String DIGITAL_SIGNATURE_CERTIFICATE = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/certificate";
+
+	/**
+	 * Digital signature origin relationship type.
+	 */
+	String DIGITAL_SIGNATURE_ORIGIN = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin";
+
+	/**
+	 * Thumbnail relationship type.
+	 */
+	String THUMBNAIL = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
+
+	/**
+	 * Extended properties relationship type.
+	 */
+	String EXTENDED_PROPERTIES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
+
+	/**
+	 * Core properties relationship type.
+	 */
+	String CORE_DOCUMENT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
+
+	/**
+	 * Custom XML relationship type.
+	 */
+	String CUSTOM_XML = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
+
+	/**
+	 * Image type.
+	 */
+	String IMAGE_PART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
+
+	/**
+	 * Style type.
+	 */
+	String STYLE_PART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
+}

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java?rev=776607&r1=776606&r2=776607&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/PackagingURIHelper.java Wed May 20 08:02:35 2009
@@ -1,622 +1,622 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.openxml4j.opc;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
-
-/**
- * Helper for part and pack URI.
- * 
- * @author Julien Chable, CDubet, Kim Ung
- * @version 0.1
- */
-public final class PackagingURIHelper {
-
-	/**
-	 * Package root URI.
-	 */
-	private static URI packageRootUri;
-
-	/**
-	 * Extension name of a relationship part.
-	 */
-	public static final String RELATIONSHIP_PART_EXTENSION_NAME;
-
-	/**
-	 * Segment name of a relationship part.
-	 */
-	public static final String RELATIONSHIP_PART_SEGMENT_NAME;
-
-	/**
-	 * Segment name of the package properties folder.
-	 */
-	public static final String PACKAGE_PROPERTIES_SEGMENT_NAME;
-
-	/**
-	 * Core package properties art name.
-	 */
-	public static final String PACKAGE_CORE_PROPERTIES_NAME;
-
-	/**
-	 * Forward slash URI separator.
-	 */
-	public static final char FORWARD_SLASH_CHAR;
-
-	/**
-	 * Forward slash URI separator.
-	 */
-	public static final String FORWARD_SLASH_STRING;
-
-	/**
-	 * Package relationships part URI
-	 */
-	public static final URI PACKAGE_RELATIONSHIPS_ROOT_URI;
-
-	/**
-	 * Package relationships part name.
-	 */
-	public static final PackagePartName PACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
-
-	/**
-	 * Core properties part URI.
-	 */
-	public static final URI CORE_PROPERTIES_URI;
-
-	/**
-	 * Core properties partname.
-	 */
-	public static final PackagePartName CORE_PROPERTIES_PART_NAME;
-
-	/**
-	 * Root package URI.
-	 */
-	public static final URI PACKAGE_ROOT_URI;
-
-	/**
-	 * Root package part name.
-	 */
-	public static final PackagePartName PACKAGE_ROOT_PART_NAME;
-
-	/* Static initialization */
-	static {
-		RELATIONSHIP_PART_SEGMENT_NAME = "_rels";
-		RELATIONSHIP_PART_EXTENSION_NAME = ".rels";
-		FORWARD_SLASH_CHAR = '/';
-		FORWARD_SLASH_STRING = "/";
-		PACKAGE_PROPERTIES_SEGMENT_NAME = "docProps";
-		PACKAGE_CORE_PROPERTIES_NAME = "core.xml";
-
-		// Make URI
-		URI uriPACKAGE_ROOT_URI = null;
-		URI uriPACKAGE_RELATIONSHIPS_ROOT_URI = null;
-		URI uriPACKAGE_PROPERTIES_URI = null;
-		try {
-			uriPACKAGE_ROOT_URI = new URI("/");
-			uriPACKAGE_RELATIONSHIPS_ROOT_URI = new URI(FORWARD_SLASH_CHAR
-					+ RELATIONSHIP_PART_SEGMENT_NAME + FORWARD_SLASH_CHAR
-					+ RELATIONSHIP_PART_EXTENSION_NAME);
-			packageRootUri = new URI("/");
-			uriPACKAGE_PROPERTIES_URI = new URI(FORWARD_SLASH_CHAR
-					+ PACKAGE_PROPERTIES_SEGMENT_NAME + FORWARD_SLASH_CHAR
-					+ PACKAGE_CORE_PROPERTIES_NAME);
-		} catch (URISyntaxException e) {
-			// Should never happen in production as all data are fixed
-		}
-		PACKAGE_ROOT_URI = uriPACKAGE_ROOT_URI;
-		PACKAGE_RELATIONSHIPS_ROOT_URI = uriPACKAGE_RELATIONSHIPS_ROOT_URI;
-		CORE_PROPERTIES_URI = uriPACKAGE_PROPERTIES_URI;
-
-		// Make part name from previous URI
-		PackagePartName tmpPACKAGE_ROOT_PART_NAME = null;
-		PackagePartName tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME = null;
-		PackagePartName tmpCORE_PROPERTIES_URI = null;
-		try {
-			tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME = createPartName(PACKAGE_RELATIONSHIPS_ROOT_URI);
-			tmpCORE_PROPERTIES_URI = createPartName(CORE_PROPERTIES_URI);
-			tmpPACKAGE_ROOT_PART_NAME = new PackagePartName(PACKAGE_ROOT_URI,
-					false);
-		} catch (InvalidFormatException e) {
-			// Should never happen in production as all data are fixed
-		}
-		PACKAGE_RELATIONSHIPS_ROOT_PART_NAME = tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
-		CORE_PROPERTIES_PART_NAME = tmpCORE_PROPERTIES_URI;
-		PACKAGE_ROOT_PART_NAME = tmpPACKAGE_ROOT_PART_NAME;
-	}
-
-	/**
-	 * Gets the URI for the package root.
-	 * 
-	 * @return URI of the package root.
-	 */
-	public static URI getPackageRootUri() {
-		return packageRootUri;
-	}
-
-	/**
-	 * Know if the specified URI is a relationship part name.
-	 * 
-	 * @param partUri
-	 *            URI to check.
-	 * @return <i>true</i> if the URI <i>false</i>.
-	 */
-	public static boolean isRelationshipPartURI(URI partUri) {
-		if (partUri == null)
-			throw new IllegalArgumentException("partUri");
-
-		return partUri.getPath().matches(
-				".*" + RELATIONSHIP_PART_SEGMENT_NAME + ".*"
-						+ RELATIONSHIP_PART_EXTENSION_NAME + "$");
-	}
-
-	/**
-	 * Get file name from the specified URI.
-	 */
-	public static String getFilename(URI uri) {
-		if (uri != null) {
-			String path = uri.getPath();
-			int len = path.length();
-			int num2 = len;
-			while (--num2 >= 0) {
-				char ch1 = path.charAt(num2);
-				if (ch1 == PackagingURIHelper.FORWARD_SLASH_CHAR)
-					return path.substring(num2 + 1, len);
-			}
-		}
-		return "";
-	}
-
-	/**
-	 * Get the file name without the trailing extension.
-	 */
-	public static String getFilenameWithoutExtension(URI uri) {
-		String filename = getFilename(uri);
-		int dotIndex = filename.lastIndexOf(".");
-		if (dotIndex == -1)
-			return filename;
-		return filename.substring(0, dotIndex);
-	}
-
-	/**
-	 * Get the directory path from the specified URI.
-	 */
-	public static URI getPath(URI uri) {
-		if (uri != null) {
-			String path = uri.getPath();
-			int len = path.length();
-			int num2 = len;
-			while (--num2 >= 0) {
-				char ch1 = path.charAt(num2);
-				if (ch1 == PackagingURIHelper.FORWARD_SLASH_CHAR) {
-					try {
-						return new URI(path.substring(0, num2));
-					} catch (URISyntaxException e) {
-						return null;
-					}
-				}
-			}
-		}
-		return null;
-	}
-
-	/**
-	 * Combine two URIs.
-	 * 
-	 * @param prefix the prefix URI
-	 * @param suffix the suffix URI
-	 *
-	 * @return the combined URI
-	 */
-	public static URI combine(URI prefix, URI suffix) {
-		URI retUri = null;
-		try {
-			retUri = new URI(combine(prefix.getPath(), suffix.getPath()));
-		} catch (URISyntaxException e) {
-			throw new IllegalArgumentException(
-					"Prefix and suffix can't be combine !");
-		}
-		return retUri;
-	}
-
-	/**
-	 * Combine a string URI with a prefix and a suffix.
-	 */
-	public static String combine(String prefix, String suffix) {
-		if (!prefix.endsWith("" + FORWARD_SLASH_CHAR)
-				&& !suffix.startsWith("" + FORWARD_SLASH_CHAR))
-			return prefix + FORWARD_SLASH_CHAR + suffix;
-		else if ((!prefix.endsWith("" + FORWARD_SLASH_CHAR)
-				&& suffix.startsWith("" + FORWARD_SLASH_CHAR) || (prefix
-				.endsWith("" + FORWARD_SLASH_CHAR) && !suffix.startsWith(""
-				+ FORWARD_SLASH_CHAR))))
-			return prefix + suffix;
-		else
-			return "";
-	}
-
-	/**
-	 * Fully relativize the source part URI against the target part URI.
-	 * 
-	 * @param sourceURI
-	 *            The source part URI.
-	 * @param targetURI
-	 *            The target part URI.
-	 * @return A fully relativize part name URI ('word/media/image1.gif',
-	 *         '/word/document.xml' => 'media/image1.gif') else
-	 *         <code>null</code>.
-	 */
-	public static URI relativizeURI(URI sourceURI, URI targetURI) {
-		StringBuilder retVal = new StringBuilder();
-		String[] segmentsSource = sourceURI.getPath().split("/", -1);
-		String[] segmentsTarget = targetURI.getPath().split("/", -1);
-
-		// If the source URI is empty
-		if (segmentsSource.length == 0) {
-			throw new IllegalArgumentException(
-					"Can't relativize an empty source URI !");
-		}
-
-		// If target URI is empty
-		if (segmentsTarget.length == 0) {
-			throw new IllegalArgumentException(
-					"Can't relativize an empty target URI !");
-		}
-		
-		// If the source is the root, then the relativized
-		//  form must actually be an absolute URI
-		if(sourceURI.toString().equals("/")) {
-			return targetURI;
-		}
-
-
-		// Relativize the source URI against the target URI.
-		// First up, figure out how many steps along we can go
-		// and still have them be the same
-		int segmentsTheSame = 0;
-		for (int i = 0; i < segmentsSource.length && i < segmentsTarget.length; i++) {
-			if (segmentsSource[i].equals(segmentsTarget[i])) {
-				// Match so far, good
-				segmentsTheSame++;
-			} else {
-				break;
-			}
-		}
-
-		// If we didn't have a good match or at least except a first empty element
-		if ((segmentsTheSame == 0 || segmentsTheSame == 1) && 
-				segmentsSource[0].equals("") && segmentsTarget[0].equals("")) {
-			for (int i = 0; i < segmentsSource.length - 2; i++) {
-				retVal.append("../");
-			}
-			for (int i = 0; i < segmentsTarget.length; i++) {
-				if (segmentsTarget[i].equals(""))
-					continue;
-				retVal.append(segmentsTarget[i]);
-				if (i != segmentsTarget.length - 1)
-					retVal.append("/");
-			}
-
-			try {
-				return new URI(retVal.toString());
-			} catch (Exception e) {
-				System.err.println(e);
-				return null;
-			}
-		}
-
-		// Special case for where the two are the same
-		if (segmentsTheSame == segmentsSource.length
-				&& segmentsTheSame == segmentsTarget.length) {
-			retVal.append("");
-		} else {
-			// Matched for so long, but no more
-
-			// Do we need to go up a directory or two from
-			// the source to get here?
-			// (If it's all the way up, then don't bother!)
-			if (segmentsTheSame == 1) {
-				retVal.append("/");
-			} else {
-				for (int j = segmentsTheSame; j < segmentsSource.length - 1; j++) {
-					retVal.append("../");
-				}
-			}
-
-			// Now go from here on down
-			for (int j = segmentsTheSame; j < segmentsTarget.length; j++) {
-				if (retVal.length() > 0
-						&& retVal.charAt(retVal.length() - 1) != '/') {
-					retVal.append("/");
-				}
-				retVal.append(segmentsTarget[j]);
-			}
-		}
-
-		try {
-			return new URI(retVal.toString());
-		} catch (Exception e) {
-			System.err.println(e);
-			return null;
-		}
-	}
-
-	/**
-	 * Resolve a source uri against a target.
-	 * 
-	 * @param sourcePartUri
-	 *            The source URI.
-	 * @param targetUri
-	 *            The target URI.
-	 * @return The resolved URI.
-	 */
-	public static URI resolvePartUri(URI sourcePartUri, URI targetUri) {
-		if (sourcePartUri == null || sourcePartUri.isAbsolute()) {
-			throw new IllegalArgumentException("sourcePartUri invalid - "
-					+ sourcePartUri);
-		}
-
-		if (targetUri == null || targetUri.isAbsolute()) {
-			throw new IllegalArgumentException("targetUri invalid - "
-					+ targetUri);
-		}
-
-		return sourcePartUri.resolve(targetUri);
-	}
-
-	/**
-	 * Get URI from a string path.
-	 */
-	public static URI getURIFromPath(String path) {
-		URI retUri = null;
-		try {
-			retUri = new URI(path);
-		} catch (URISyntaxException e) {
-			throw new IllegalArgumentException("path");
-		}
-		return retUri;
-	}
-
-	/**
-	 * Get the source part URI from a specified relationships part.
-	 * 
-	 * @param relationshipPartUri
-	 *            The relationship part use to retrieve the source part.
-	 * @return The source part URI from the specified relationships part.
-	 */
-	public static URI getSourcePartUriFromRelationshipPartUri(
-			URI relationshipPartUri) {
-		if (relationshipPartUri == null)
-			throw new IllegalArgumentException(
-					"Must not be null");
-
-		if (!isRelationshipPartURI(relationshipPartUri))
-			throw new IllegalArgumentException(
-					"Must be a relationship part");
-
-		if (relationshipPartUri.compareTo(PACKAGE_RELATIONSHIPS_ROOT_URI) == 0)
-			return PACKAGE_ROOT_URI;
-
-		String filename = relationshipPartUri.getPath();
-		String filenameWithoutExtension = getFilenameWithoutExtension(relationshipPartUri);
-		filename = filename
-				.substring(0, ((filename.length() - filenameWithoutExtension
-						.length()) - RELATIONSHIP_PART_EXTENSION_NAME.length()));
-		filename = filename.substring(0, filename.length()
-				- RELATIONSHIP_PART_SEGMENT_NAME.length() - 1);
-		filename = combine(filename, filenameWithoutExtension);
-		return getURIFromPath(filename);
-	}
-
-	/**
-	 * Create an OPC compliant part name by throwing an exception if the URI is
-	 * not valid.
-	 * 
-	 * @param partUri
-	 *            The part name URI to validate.
-	 * @return A valid part name object, else <code>null</code>.
-	 * @throws InvalidFormatException
-	 *             Throws if the specified URI is not OPC compliant.
-	 */
-	public static PackagePartName createPartName(URI partUri)
-			throws InvalidFormatException {
-		if (partUri == null)
-			throw new IllegalArgumentException("partName");
-
-		return new PackagePartName(partUri, true);
-	}
-
-	/**
-	 * Create an OPC compliant part name.
-	 * 
-	 * @param partName
-	 *            The part name to validate.
-	 * @return The correspondant part name if valid, else <code>null</code>.
-	 * @throws InvalidFormatException
-	 *             Throws if the specified part name is not OPC compliant.
-	 * @see #createPartName(URI)
-	 */
-	public static PackagePartName createPartName(String partName)
-			throws InvalidFormatException {
-		URI partNameURI;
-		try {
-			partNameURI = new URI(partName);
-		} catch (URISyntaxException e) {
-			throw new InvalidFormatException(e.getMessage());
-		}
-		return createPartName(partNameURI);
-	}
-
-	/**
-	 * Create an OPC compliant part name by resolving it using a base part.
-	 * 
-	 * @param partName
-	 *            The part name to validate.
-	 * @param relativePart
-	 *            The relative base part.
-	 * @return The correspondant part name if valid, else <code>null</code>.
-	 * @throws InvalidFormatException
-	 *             Throws if the specified part name is not OPC compliant.
-	 * @see #createPartName(URI)
-	 */
-	public static PackagePartName createPartName(String partName,
-			PackagePart relativePart) throws InvalidFormatException {
-		URI newPartNameURI;
-		try {
-			newPartNameURI = resolvePartUri(
-					relativePart.getPartName().getURI(), new URI(partName));
-		} catch (URISyntaxException e) {
-			throw new InvalidFormatException(e.getMessage());
-		}
-		return createPartName(newPartNameURI);
-	}
-
-	/**
-	 * Create an OPC compliant part name by resolving it using a base part.
-	 * 
-	 * @param partName
-	 *            The part name URI to validate.
-	 * @param relativePart
-	 *            The relative base part.
-	 * @return The correspondant part name if valid, else <code>null</code>.
-	 * @throws InvalidFormatException
-	 *             Throws if the specified part name is not OPC compliant.
-	 * @see #createPartName(URI)
-	 */
-	public static PackagePartName createPartName(URI partName,
-			PackagePart relativePart) throws InvalidFormatException {
-		URI newPartNameURI = resolvePartUri(
-				relativePart.getPartName().getURI(), partName);
-		return createPartName(newPartNameURI);
-	}
-
-	/**
-	 * Validate a part URI by returning a boolean.
-	 * ([M1.1],[M1.3],[M1.4],[M1.5],[M1.6])
-	 * 
-	 * (OPC Specifications 8.1.1 Part names) :
-	 * 
-	 * Part Name Syntax
-	 * 
-	 * The part name grammar is defined as follows:
-	 * 
-	 * <i>part_name = 1*( "/" segment )
-	 * 
-	 * segment = 1*( pchar )</i>
-	 * 
-	 * 
-	 * (pchar is defined in RFC 3986)
-	 * 
-	 * @param partUri
-	 *            The URI to validate.
-	 * @return <b>true</b> if the URI is valid to the OPC Specifications, else
-	 *         <b>false</b>
-	 * 
-	 * @see #createPartName(URI)
-	 */
-	public static boolean isValidPartName(URI partUri) {
-		if (partUri == null)
-			throw new IllegalArgumentException("partUri");
-
-		try {
-			createPartName(partUri);
-			return true;
-		} catch (Exception e) {
-			return false;
-		}
-	}
-
-	/**
-	 * Decode a URI by converting all percent encoded character into a String
-	 * character.
-	 * 
-	 * @param uri
-	 *            The URI to decode.
-	 * @return The specified URI in a String with converted percent encoded
-	 *         characters.
-	 */
-	public static String decodeURI(URI uri) {
-		StringBuffer retVal = new StringBuffer();
-		String uriStr = uri.toASCIIString();
-		char c;
-		for (int i = 0; i < uriStr.length(); ++i) {
-			c = uriStr.charAt(i);
-			if (c == '%') {
-				// We certainly found an encoded character, check for length
-				// now ( '%' HEXDIGIT HEXDIGIT)
-				if (((uriStr.length() - i) < 2)) {
-					throw new IllegalArgumentException("The uri " + uriStr
-							+ " contain invalid encoded character !");
-				}
-
-				// Decode the encoded character
-				char decodedChar = (char) Integer.parseInt(uriStr.substring(
-						i + 1, i + 3), 16);
-				retVal.append(decodedChar);
-				i += 2;
-				continue;
-			}
-			retVal.append(c);
-		}
-		return retVal.toString();
-	}
-
-	/**
-	 * Build a part name where the relationship should be stored ((ex
-	 * /word/document.xml -> /word/_rels/document.xml.rels)
-	 * 
-	 * @param partName
-	 *            Source part URI
-	 * @return the full path (as URI) of the relation file
-	 * @throws InvalidOperationException
-	 *             Throws if the specified URI is a relationshp part.
-	 */
-	public static PackagePartName getRelationshipPartName(
-			PackagePartName partName) {
-		if (partName == null)
-			throw new IllegalArgumentException("partName");
-
-		if (PackagingURIHelper.PACKAGE_ROOT_URI.getPath() == partName.getURI()
-				.getPath())
-			return PackagingURIHelper.PACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
-
-		if (partName.isRelationshipPartURI())
-			throw new InvalidOperationException("Can't be a relationship part");
-
-		String fullPath = partName.getURI().getPath();
-		String filename = getFilename(partName.getURI());
-		fullPath = fullPath.substring(0, fullPath.length() - filename.length());
-		fullPath = combine(fullPath,
-				PackagingURIHelper.RELATIONSHIP_PART_SEGMENT_NAME);
-		fullPath = combine(fullPath, filename);
-		fullPath = fullPath
-				+ PackagingURIHelper.RELATIONSHIP_PART_EXTENSION_NAME;
-
-		PackagePartName retPartName;
-		try {
-			retPartName = createPartName(fullPath);
-		} catch (InvalidFormatException e) {
-			// Should never happen in production as all data are fixed but in
-			// case of return null:
-			return null;
-		}
-		return retPartName;
-	}
-}
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
+
+/**
+ * Helper for part and pack URI.
+ *
+ * @author Julien Chable, CDubet, Kim Ung
+ * @version 0.1
+ */
+public final class PackagingURIHelper {
+
+	/**
+	 * Package root URI.
+	 */
+	private static URI packageRootUri;
+
+	/**
+	 * Extension name of a relationship part.
+	 */
+	public static final String RELATIONSHIP_PART_EXTENSION_NAME;
+
+	/**
+	 * Segment name of a relationship part.
+	 */
+	public static final String RELATIONSHIP_PART_SEGMENT_NAME;
+
+	/**
+	 * Segment name of the package properties folder.
+	 */
+	public static final String PACKAGE_PROPERTIES_SEGMENT_NAME;
+
+	/**
+	 * Core package properties art name.
+	 */
+	public static final String PACKAGE_CORE_PROPERTIES_NAME;
+
+	/**
+	 * Forward slash URI separator.
+	 */
+	public static final char FORWARD_SLASH_CHAR;
+
+	/**
+	 * Forward slash URI separator.
+	 */
+	public static final String FORWARD_SLASH_STRING;
+
+	/**
+	 * Package relationships part URI
+	 */
+	public static final URI PACKAGE_RELATIONSHIPS_ROOT_URI;
+
+	/**
+	 * Package relationships part name.
+	 */
+	public static final PackagePartName PACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
+
+	/**
+	 * Core properties part URI.
+	 */
+	public static final URI CORE_PROPERTIES_URI;
+
+	/**
+	 * Core properties partname.
+	 */
+	public static final PackagePartName CORE_PROPERTIES_PART_NAME;
+
+	/**
+	 * Root package URI.
+	 */
+	public static final URI PACKAGE_ROOT_URI;
+
+	/**
+	 * Root package part name.
+	 */
+	public static final PackagePartName PACKAGE_ROOT_PART_NAME;
+
+	/* Static initialization */
+	static {
+		RELATIONSHIP_PART_SEGMENT_NAME = "_rels";
+		RELATIONSHIP_PART_EXTENSION_NAME = ".rels";
+		FORWARD_SLASH_CHAR = '/';
+		FORWARD_SLASH_STRING = "/";
+		PACKAGE_PROPERTIES_SEGMENT_NAME = "docProps";
+		PACKAGE_CORE_PROPERTIES_NAME = "core.xml";
+
+		// Make URI
+		URI uriPACKAGE_ROOT_URI = null;
+		URI uriPACKAGE_RELATIONSHIPS_ROOT_URI = null;
+		URI uriPACKAGE_PROPERTIES_URI = null;
+		try {
+			uriPACKAGE_ROOT_URI = new URI("/");
+			uriPACKAGE_RELATIONSHIPS_ROOT_URI = new URI(FORWARD_SLASH_CHAR
+					+ RELATIONSHIP_PART_SEGMENT_NAME + FORWARD_SLASH_CHAR
+					+ RELATIONSHIP_PART_EXTENSION_NAME);
+			packageRootUri = new URI("/");
+			uriPACKAGE_PROPERTIES_URI = new URI(FORWARD_SLASH_CHAR
+					+ PACKAGE_PROPERTIES_SEGMENT_NAME + FORWARD_SLASH_CHAR
+					+ PACKAGE_CORE_PROPERTIES_NAME);
+		} catch (URISyntaxException e) {
+			// Should never happen in production as all data are fixed
+		}
+		PACKAGE_ROOT_URI = uriPACKAGE_ROOT_URI;
+		PACKAGE_RELATIONSHIPS_ROOT_URI = uriPACKAGE_RELATIONSHIPS_ROOT_URI;
+		CORE_PROPERTIES_URI = uriPACKAGE_PROPERTIES_URI;
+
+		// Make part name from previous URI
+		PackagePartName tmpPACKAGE_ROOT_PART_NAME = null;
+		PackagePartName tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME = null;
+		PackagePartName tmpCORE_PROPERTIES_URI = null;
+		try {
+			tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME = createPartName(PACKAGE_RELATIONSHIPS_ROOT_URI);
+			tmpCORE_PROPERTIES_URI = createPartName(CORE_PROPERTIES_URI);
+			tmpPACKAGE_ROOT_PART_NAME = new PackagePartName(PACKAGE_ROOT_URI,
+					false);
+		} catch (InvalidFormatException e) {
+			// Should never happen in production as all data are fixed
+		}
+		PACKAGE_RELATIONSHIPS_ROOT_PART_NAME = tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
+		CORE_PROPERTIES_PART_NAME = tmpCORE_PROPERTIES_URI;
+		PACKAGE_ROOT_PART_NAME = tmpPACKAGE_ROOT_PART_NAME;
+	}
+
+	/**
+	 * Gets the URI for the package root.
+	 *
+	 * @return URI of the package root.
+	 */
+	public static URI getPackageRootUri() {
+		return packageRootUri;
+	}
+
+	/**
+	 * Know if the specified URI is a relationship part name.
+	 *
+	 * @param partUri
+	 *            URI to check.
+	 * @return <i>true</i> if the URI <i>false</i>.
+	 */
+	public static boolean isRelationshipPartURI(URI partUri) {
+		if (partUri == null)
+			throw new IllegalArgumentException("partUri");
+
+		return partUri.getPath().matches(
+				".*" + RELATIONSHIP_PART_SEGMENT_NAME + ".*"
+						+ RELATIONSHIP_PART_EXTENSION_NAME + "$");
+	}
+
+	/**
+	 * Get file name from the specified URI.
+	 */
+	public static String getFilename(URI uri) {
+		if (uri != null) {
+			String path = uri.getPath();
+			int len = path.length();
+			int num2 = len;
+			while (--num2 >= 0) {
+				char ch1 = path.charAt(num2);
+				if (ch1 == PackagingURIHelper.FORWARD_SLASH_CHAR)
+					return path.substring(num2 + 1, len);
+			}
+		}
+		return "";
+	}
+
+	/**
+	 * Get the file name without the trailing extension.
+	 */
+	public static String getFilenameWithoutExtension(URI uri) {
+		String filename = getFilename(uri);
+		int dotIndex = filename.lastIndexOf(".");
+		if (dotIndex == -1)
+			return filename;
+		return filename.substring(0, dotIndex);
+	}
+
+	/**
+	 * Get the directory path from the specified URI.
+	 */
+	public static URI getPath(URI uri) {
+		if (uri != null) {
+			String path = uri.getPath();
+			int len = path.length();
+			int num2 = len;
+			while (--num2 >= 0) {
+				char ch1 = path.charAt(num2);
+				if (ch1 == PackagingURIHelper.FORWARD_SLASH_CHAR) {
+					try {
+						return new URI(path.substring(0, num2));
+					} catch (URISyntaxException e) {
+						return null;
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Combine two URIs.
+	 *
+	 * @param prefix the prefix URI
+	 * @param suffix the suffix URI
+	 *
+	 * @return the combined URI
+	 */
+	public static URI combine(URI prefix, URI suffix) {
+		URI retUri = null;
+		try {
+			retUri = new URI(combine(prefix.getPath(), suffix.getPath()));
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException(
+					"Prefix and suffix can't be combine !");
+		}
+		return retUri;
+	}
+
+	/**
+	 * Combine a string URI with a prefix and a suffix.
+	 */
+	public static String combine(String prefix, String suffix) {
+		if (!prefix.endsWith("" + FORWARD_SLASH_CHAR)
+				&& !suffix.startsWith("" + FORWARD_SLASH_CHAR))
+			return prefix + FORWARD_SLASH_CHAR + suffix;
+		else if ((!prefix.endsWith("" + FORWARD_SLASH_CHAR)
+				&& suffix.startsWith("" + FORWARD_SLASH_CHAR) || (prefix
+				.endsWith("" + FORWARD_SLASH_CHAR) && !suffix.startsWith(""
+				+ FORWARD_SLASH_CHAR))))
+			return prefix + suffix;
+		else
+			return "";
+	}
+
+	/**
+	 * Fully relativize the source part URI against the target part URI.
+	 *
+	 * @param sourceURI
+	 *            The source part URI.
+	 * @param targetURI
+	 *            The target part URI.
+	 * @return A fully relativize part name URI ('word/media/image1.gif',
+	 *         '/word/document.xml' => 'media/image1.gif') else
+	 *         <code>null</code>.
+	 */
+	public static URI relativizeURI(URI sourceURI, URI targetURI) {
+		StringBuilder retVal = new StringBuilder();
+		String[] segmentsSource = sourceURI.getPath().split("/", -1);
+		String[] segmentsTarget = targetURI.getPath().split("/", -1);
+
+		// If the source URI is empty
+		if (segmentsSource.length == 0) {
+			throw new IllegalArgumentException(
+					"Can't relativize an empty source URI !");
+		}
+
+		// If target URI is empty
+		if (segmentsTarget.length == 0) {
+			throw new IllegalArgumentException(
+					"Can't relativize an empty target URI !");
+		}
+
+		// If the source is the root, then the relativized
+		//  form must actually be an absolute URI
+		if(sourceURI.toString().equals("/")) {
+			return targetURI;
+		}
+
+
+		// Relativize the source URI against the target URI.
+		// First up, figure out how many steps along we can go
+		// and still have them be the same
+		int segmentsTheSame = 0;
+		for (int i = 0; i < segmentsSource.length && i < segmentsTarget.length; i++) {
+			if (segmentsSource[i].equals(segmentsTarget[i])) {
+				// Match so far, good
+				segmentsTheSame++;
+			} else {
+				break;
+			}
+		}
+
+		// If we didn't have a good match or at least except a first empty element
+		if ((segmentsTheSame == 0 || segmentsTheSame == 1) &&
+				segmentsSource[0].equals("") && segmentsTarget[0].equals("")) {
+			for (int i = 0; i < segmentsSource.length - 2; i++) {
+				retVal.append("../");
+			}
+			for (int i = 0; i < segmentsTarget.length; i++) {
+				if (segmentsTarget[i].equals(""))
+					continue;
+				retVal.append(segmentsTarget[i]);
+				if (i != segmentsTarget.length - 1)
+					retVal.append("/");
+			}
+
+			try {
+				return new URI(retVal.toString());
+			} catch (Exception e) {
+				System.err.println(e);
+				return null;
+			}
+		}
+
+		// Special case for where the two are the same
+		if (segmentsTheSame == segmentsSource.length
+				&& segmentsTheSame == segmentsTarget.length) {
+			retVal.append("");
+		} else {
+			// Matched for so long, but no more
+
+			// Do we need to go up a directory or two from
+			// the source to get here?
+			// (If it's all the way up, then don't bother!)
+			if (segmentsTheSame == 1) {
+				retVal.append("/");
+			} else {
+				for (int j = segmentsTheSame; j < segmentsSource.length - 1; j++) {
+					retVal.append("../");
+				}
+			}
+
+			// Now go from here on down
+			for (int j = segmentsTheSame; j < segmentsTarget.length; j++) {
+				if (retVal.length() > 0
+						&& retVal.charAt(retVal.length() - 1) != '/') {
+					retVal.append("/");
+				}
+				retVal.append(segmentsTarget[j]);
+			}
+		}
+
+		try {
+			return new URI(retVal.toString());
+		} catch (Exception e) {
+			System.err.println(e);
+			return null;
+		}
+	}
+
+	/**
+	 * Resolve a source uri against a target.
+	 *
+	 * @param sourcePartUri
+	 *            The source URI.
+	 * @param targetUri
+	 *            The target URI.
+	 * @return The resolved URI.
+	 */
+	public static URI resolvePartUri(URI sourcePartUri, URI targetUri) {
+		if (sourcePartUri == null || sourcePartUri.isAbsolute()) {
+			throw new IllegalArgumentException("sourcePartUri invalid - "
+					+ sourcePartUri);
+		}
+
+		if (targetUri == null || targetUri.isAbsolute()) {
+			throw new IllegalArgumentException("targetUri invalid - "
+					+ targetUri);
+		}
+
+		return sourcePartUri.resolve(targetUri);
+	}
+
+	/**
+	 * Get URI from a string path.
+	 */
+	public static URI getURIFromPath(String path) {
+		URI retUri = null;
+		try {
+			retUri = new URI(path);
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException("path");
+		}
+		return retUri;
+	}
+
+	/**
+	 * Get the source part URI from a specified relationships part.
+	 *
+	 * @param relationshipPartUri
+	 *            The relationship part use to retrieve the source part.
+	 * @return The source part URI from the specified relationships part.
+	 */
+	public static URI getSourcePartUriFromRelationshipPartUri(
+			URI relationshipPartUri) {
+		if (relationshipPartUri == null)
+			throw new IllegalArgumentException(
+					"Must not be null");
+
+		if (!isRelationshipPartURI(relationshipPartUri))
+			throw new IllegalArgumentException(
+					"Must be a relationship part");
+
+		if (relationshipPartUri.compareTo(PACKAGE_RELATIONSHIPS_ROOT_URI) == 0)
+			return PACKAGE_ROOT_URI;
+
+		String filename = relationshipPartUri.getPath();
+		String filenameWithoutExtension = getFilenameWithoutExtension(relationshipPartUri);
+		filename = filename
+				.substring(0, ((filename.length() - filenameWithoutExtension
+						.length()) - RELATIONSHIP_PART_EXTENSION_NAME.length()));
+		filename = filename.substring(0, filename.length()
+				- RELATIONSHIP_PART_SEGMENT_NAME.length() - 1);
+		filename = combine(filename, filenameWithoutExtension);
+		return getURIFromPath(filename);
+	}
+
+	/**
+	 * Create an OPC compliant part name by throwing an exception if the URI is
+	 * not valid.
+	 *
+	 * @param partUri
+	 *            The part name URI to validate.
+	 * @return A valid part name object, else <code>null</code>.
+	 * @throws InvalidFormatException
+	 *             Throws if the specified URI is not OPC compliant.
+	 */
+	public static PackagePartName createPartName(URI partUri)
+			throws InvalidFormatException {
+		if (partUri == null)
+			throw new IllegalArgumentException("partName");
+
+		return new PackagePartName(partUri, true);
+	}
+
+	/**
+	 * Create an OPC compliant part name.
+	 *
+	 * @param partName
+	 *            The part name to validate.
+	 * @return The correspondant part name if valid, else <code>null</code>.
+	 * @throws InvalidFormatException
+	 *             Throws if the specified part name is not OPC compliant.
+	 * @see #createPartName(URI)
+	 */
+	public static PackagePartName createPartName(String partName)
+			throws InvalidFormatException {
+		URI partNameURI;
+		try {
+			partNameURI = new URI(partName);
+		} catch (URISyntaxException e) {
+			throw new InvalidFormatException(e.getMessage());
+		}
+		return createPartName(partNameURI);
+	}
+
+	/**
+	 * Create an OPC compliant part name by resolving it using a base part.
+	 *
+	 * @param partName
+	 *            The part name to validate.
+	 * @param relativePart
+	 *            The relative base part.
+	 * @return The correspondant part name if valid, else <code>null</code>.
+	 * @throws InvalidFormatException
+	 *             Throws if the specified part name is not OPC compliant.
+	 * @see #createPartName(URI)
+	 */
+	public static PackagePartName createPartName(String partName,
+			PackagePart relativePart) throws InvalidFormatException {
+		URI newPartNameURI;
+		try {
+			newPartNameURI = resolvePartUri(
+					relativePart.getPartName().getURI(), new URI(partName));
+		} catch (URISyntaxException e) {
+			throw new InvalidFormatException(e.getMessage());
+		}
+		return createPartName(newPartNameURI);
+	}
+
+	/**
+	 * Create an OPC compliant part name by resolving it using a base part.
+	 *
+	 * @param partName
+	 *            The part name URI to validate.
+	 * @param relativePart
+	 *            The relative base part.
+	 * @return The correspondant part name if valid, else <code>null</code>.
+	 * @throws InvalidFormatException
+	 *             Throws if the specified part name is not OPC compliant.
+	 * @see #createPartName(URI)
+	 */
+	public static PackagePartName createPartName(URI partName,
+			PackagePart relativePart) throws InvalidFormatException {
+		URI newPartNameURI = resolvePartUri(
+				relativePart.getPartName().getURI(), partName);
+		return createPartName(newPartNameURI);
+	}
+
+	/**
+	 * Validate a part URI by returning a boolean.
+	 * ([M1.1],[M1.3],[M1.4],[M1.5],[M1.6])
+	 *
+	 * (OPC Specifications 8.1.1 Part names) :
+	 *
+	 * Part Name Syntax
+	 *
+	 * The part name grammar is defined as follows:
+	 *
+	 * <i>part_name = 1*( "/" segment )
+	 *
+	 * segment = 1*( pchar )</i>
+	 *
+	 *
+	 * (pchar is defined in RFC 3986)
+	 *
+	 * @param partUri
+	 *            The URI to validate.
+	 * @return <b>true</b> if the URI is valid to the OPC Specifications, else
+	 *         <b>false</b>
+	 *
+	 * @see #createPartName(URI)
+	 */
+	public static boolean isValidPartName(URI partUri) {
+		if (partUri == null)
+			throw new IllegalArgumentException("partUri");
+
+		try {
+			createPartName(partUri);
+			return true;
+		} catch (Exception e) {
+			return false;
+		}
+	}
+
+	/**
+	 * Decode a URI by converting all percent encoded character into a String
+	 * character.
+	 *
+	 * @param uri
+	 *            The URI to decode.
+	 * @return The specified URI in a String with converted percent encoded
+	 *         characters.
+	 */
+	public static String decodeURI(URI uri) {
+		StringBuffer retVal = new StringBuffer();
+		String uriStr = uri.toASCIIString();
+		char c;
+		for (int i = 0; i < uriStr.length(); ++i) {
+			c = uriStr.charAt(i);
+			if (c == '%') {
+				// We certainly found an encoded character, check for length
+				// now ( '%' HEXDIGIT HEXDIGIT)
+				if (((uriStr.length() - i) < 2)) {
+					throw new IllegalArgumentException("The uri " + uriStr
+							+ " contain invalid encoded character !");
+				}
+
+				// Decode the encoded character
+				char decodedChar = (char) Integer.parseInt(uriStr.substring(
+						i + 1, i + 3), 16);
+				retVal.append(decodedChar);
+				i += 2;
+				continue;
+			}
+			retVal.append(c);
+		}
+		return retVal.toString();
+	}
+
+	/**
+	 * Build a part name where the relationship should be stored ((ex
+	 * /word/document.xml -> /word/_rels/document.xml.rels)
+	 *
+	 * @param partName
+	 *            Source part URI
+	 * @return the full path (as URI) of the relation file
+	 * @throws InvalidOperationException
+	 *             Throws if the specified URI is a relationshp part.
+	 */
+	public static PackagePartName getRelationshipPartName(
+			PackagePartName partName) {
+		if (partName == null)
+			throw new IllegalArgumentException("partName");
+
+		if (PackagingURIHelper.PACKAGE_ROOT_URI.getPath() == partName.getURI()
+				.getPath())
+			return PackagingURIHelper.PACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
+
+		if (partName.isRelationshipPartURI())
+			throw new InvalidOperationException("Can't be a relationship part");
+
+		String fullPath = partName.getURI().getPath();
+		String filename = getFilename(partName.getURI());
+		fullPath = fullPath.substring(0, fullPath.length() - filename.length());
+		fullPath = combine(fullPath,
+				PackagingURIHelper.RELATIONSHIP_PART_SEGMENT_NAME);
+		fullPath = combine(fullPath, filename);
+		fullPath = fullPath
+				+ PackagingURIHelper.RELATIONSHIP_PART_EXTENSION_NAME;
+
+		PackagePartName retPartName;
+		try {
+			retPartName = createPartName(fullPath);
+		} catch (InvalidFormatException e) {
+			// Should never happen in production as all data are fixed but in
+			// case of return null:
+			return null;
+		}
+		return retPartName;
+	}
+}

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java?rev=776607&r1=776606&r2=776607&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/StreamHelper.java Wed May 20 08:02:35 2009
@@ -1,77 +1,77 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.openxml4j.opc;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.dom4j.Document;
-import org.dom4j.io.OutputFormat;
-import org.dom4j.io.XMLWriter;
-
-public final class StreamHelper {
-
-	private StreamHelper() {
-		// Do nothing
-	}
-
-	/**
-	 * Turning the DOM4j object in the specified output stream.
-	 * 
-	 * @param xmlContent
-	 *            The XML document.
-	 * @param outStream
-	 *            The OutputStream in which the XML document will be written.
-	 * @return <b>true</b> if the xml is successfully written in the stream,
-	 *         else <b>false</b>.
-	 */
-	public static boolean saveXmlInStream(Document xmlContent,
-			OutputStream outStream) {
-		try {
-			OutputFormat outformat = OutputFormat.createPrettyPrint();
-			outformat.setEncoding("UTF-8");
-			XMLWriter writer = new XMLWriter(outStream, outformat);
-			writer.write(xmlContent);
-		} catch (Exception e) {
-			return false;
-		}
-		return true;
-	}
-
-	/**
-	 * Copy the input stream into the output stream.
-	 * 
-	 * @param inStream
-	 *            The source stream.
-	 * @param outStream
-	 *            The destination stream.
-	 * @return <b>true</b> if the operation succeed, else return <b>false</b>.
-	 */
-	public static boolean copyStream(InputStream inStream, OutputStream outStream) {
-		try {
-			byte[] buffer = new byte[1024];
-			int bytesRead;
-			while ((bytesRead = inStream.read(buffer)) >= 0) {
-				outStream.write(buffer, 0, bytesRead);
-			}
-		} catch (Exception e) {
-			return false;
-		}
-		return true;
-	}
-}
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.dom4j.Document;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.XMLWriter;
+
+public final class StreamHelper {
+
+	private StreamHelper() {
+		// Do nothing
+	}
+
+	/**
+	 * Turning the DOM4j object in the specified output stream.
+	 *
+	 * @param xmlContent
+	 *            The XML document.
+	 * @param outStream
+	 *            The OutputStream in which the XML document will be written.
+	 * @return <b>true</b> if the xml is successfully written in the stream,
+	 *         else <b>false</b>.
+	 */
+	public static boolean saveXmlInStream(Document xmlContent,
+			OutputStream outStream) {
+		try {
+			OutputFormat outformat = OutputFormat.createPrettyPrint();
+			outformat.setEncoding("UTF-8");
+			XMLWriter writer = new XMLWriter(outStream, outformat);
+			writer.write(xmlContent);
+		} catch (Exception e) {
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Copy the input stream into the output stream.
+	 *
+	 * @param inStream
+	 *            The source stream.
+	 * @param outStream
+	 *            The destination stream.
+	 * @return <b>true</b> if the operation succeed, else return <b>false</b>.
+	 */
+	public static boolean copyStream(InputStream inStream, OutputStream outStream) {
+		try {
+			byte[] buffer = new byte[1024];
+			int bytesRead;
+			while ((bytesRead = inStream.read(buffer)) >= 0) {
+				outStream.write(buffer, 0, bytesRead);
+			}
+		} catch (Exception e) {
+			return false;
+		}
+		return true;
+	}
+}

Modified: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/TargetMode.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/TargetMode.java?rev=776607&r1=776606&r2=776607&view=diff
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/TargetMode.java (original)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/TargetMode.java Wed May 20 08:02:35 2009
@@ -1,32 +1,32 @@
-/* ====================================================================
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-==================================================================== */
-
-package org.apache.poi.openxml4j.opc;
-
-/**
- * Specifies whether the target of a PackageRelationship is inside or outside a
- * Package.
- * 
- * @author Julien Chable
- * @version 1.0
- */
-public enum TargetMode {
-	/** The relationship references a resource that is external to the package. */
-	INTERNAL,
-	/** The relationship references a part that is inside the package. */
-	EXTERNAL
-}
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.openxml4j.opc;
+
+/**
+ * Specifies whether the target of a PackageRelationship is inside or outside a
+ * Package.
+ *
+ * @author Julien Chable
+ * @version 1.0
+ */
+public enum TargetMode {
+	/** The relationship references a resource that is external to the package. */
+	INTERNAL,
+	/** The relationship references a part that is inside the package. */
+	EXTERNAL
+}



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