org.docx4j.openpackaging.URIHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of docx4j Show documentation
Show all versions of docx4j Show documentation
docx4j is a library which helps you to work with the Office Open
XML file format as used in docx
documents, pptx presentations, and xlsx spreadsheets.
/*
* Copyright (c) 2006, Wygwam
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
* - Neither the name of Wygwam nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.docx4j.openpackaging;
import java.net.URI;
import java.net.URISyntaxException;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.parts.PartName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper for part and pack URI.
*
* @author Julien Chable, CDubet
* @version 0.3
*/
public final class URIHelper {
private static Logger log = LoggerFactory.getLogger(URIHelper.class);
/**
* 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 PartName PACKAGE_RELATIONSHIPS_ROOT_PART_NAME;
/**
* Core properties part URI.
*/
public static final URI CORE_PROPERTIES_URI;
/**
* Core properties partname.
*/
public static final PartName CORE_PROPERTIES_PART_NAME;
/**
* Root package URI.
*/
public static final URI PACKAGE_ROOT_URI;
/**
* Root package part name.
*/
public static final PartName 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
PartName tmpPACKAGE_ROOT_PART_NAME = null;
PartName tmpPACKAGE_RELATIONSHIPS_ROOT_PART_NAME = null;
PartName 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 PartName(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 true if the URI false.
*/
private static boolean isRelationshipPartURI(URI partUri) {
if (partUri == null)
throw new NullPointerException("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 == URIHelper.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 == URIHelper.FORWARD_SLASH_CHAR) {
try {
return new URI(path.substring(0, num2));
} catch (URISyntaxException e) {
return null;
}
}
}
}
return null;
}
/**
* Combine two URI.
*
* @param prefix
* @param suffix
* @return
*/
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 combined !");
}
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 target part URI against the source 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
* null
.
*/
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 target uri against a source.
*
* @param sourcePartUri
* The source URI.
* @param targetUri
* The target URI.
* @return The resolved URI.
*/
public static URI resolvePartUri(URI sourcePartUri, URI targetUri) {
// log.info("source: " + sourcePartUri);
// log.info("target: " + targetUri);
URI uri;
if (sourcePartUri == null || sourcePartUri.isAbsolute()) {
throw new IllegalArgumentException("sourcePartUri");
}
if (targetUri == null) {
log.error("targetUri was null");
throw new IllegalArgumentException("targetUri");
} else if (targetUri.isAbsolute()) {
log.error("targetUri " + targetUri.toString() + " is absolute!");
throw new IllegalArgumentException("targetUri");
}
uri = sourcePartUri.resolve(targetUri);
// log.info("RESULT: " + uri);
return uri;
}
/**
* 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;
}
public static URI getSourcePartUriFromRelationshipPartUri(
URI relationshipPartUri) {
if (relationshipPartUri == null)
throw new IllegalArgumentException(
"The relationshipPart Uri was null !");
if (!isRelationshipPartURI(relationshipPartUri))
throw new IllegalArgumentException(
"L'URI ne doit pas �tre celle d'une partie de type relation.");
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 null
.
* @throws InvalidFormatException
* Throws if the specified URI is not OPC compliant.
*/
public static PartName createPartName(URI partUri)
throws InvalidFormatException {
if (partUri == null)
throw new IllegalArgumentException("partName");
return new PartName(partUri, true);
}
/**
* Create an OPC compliant part name by throwing an exception if the
* specified name is not valid.
*
* @param partName
* The part name to validate.
* @return The correspondant part name if valid, else null
.
* @throws InvalidFormatException
* Throws if the specified part name is not OPC compliant.
* @see #createPartName(URI)
*/
public static PartName createPartName(String partName)
throws InvalidFormatException {
URI partNameURI;
try {
partNameURI = new URI(partName);
} catch (URISyntaxException e) {
throw new InvalidFormatException(e.getMessage());
}
return createPartName(partNameURI);
}
/**
* 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:
*
* part_name = 1*( "/" segment )
*
* segment = 1*( pchar )
*
*
* (pchar is defined in RFC 3986)
*
* @param partUri
* The URI to validate.
* @return true if the URI is valid to the OPC Specifications, else
* false
*
* @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();
}
// /**
// * 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
// * null
.
// */
// public static URI OLDrelativizeURI(URI sourceURI, URI targetURI) {
// StringBuffer retVal = new StringBuffer();
// String[] segmentsSource = sourceURI.getPath().split("/");
// String[] segmentsTarget = targetURI.getPath().split("/");
//
// // If the source URI is empty
// if (segmentsSource.length == 0) {
// return null;
// }
//
// // If target URI is empty
// if (segmentsTarget.length == 0) {
// if (sourceURI.getPath().startsWith(FORWARD_SLASH_STRING)) {
// try {
// return new URI(sourceURI.getPath().substring(1));
// } catch (Exception e) {
// return null;
// }
// } else
// return sourceURI;
// }
//
// // Relativize the source URI against the target URI.
// for (short i = 0, j = 0; i < segmentsSource.length
// && j < segmentsTarget.length; ++i, ++j) {
// if (segmentsSource[i].equalsIgnoreCase(segmentsTarget[j])) {
// if (i < segmentsSource.length - 1) {
// continue;
// } else {
// // We add the last segment whatever it happens
// retVal.append("/");
// retVal.append(segmentsTarget[i]);
// break;
// }
// } else {
// for (; i < segmentsSource.length; ++i) {
// retVal.append("/");
// retVal.append(segmentsSource[i]);
// }
// break;
// }
// }
// try {
// PartName retPartName = new PartName(
// retVal.toString(), true);
// return new URI(retPartName.getURI().getPath().substring(1));
// } catch (Exception e) {
// return null;
// }
// }
}