From c1a7ab3860d1879ca252698c51b58cdcd7235615 Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sun, 2 Feb 2014 01:56:02 +0000 Subject: [PATCH] Bug 53282 - Hyperlink with a non-breaking space throws java.lang.IllegalStateException git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1563540 13f79535-47bb-0310-9956-ffa450edef68 --- .../opc/PackageRelationshipCollection.java | 723 +++++++++--------- .../poi/xssf/usermodel/XSSFRelation.java | 414 +++++----- .../poi/xssf/usermodel/TestXSSFBugs.java | 50 +- test-data/spreadsheet/53282b.xlsx | Bin 0 -> 9319 bytes 4 files changed, 607 insertions(+), 580 deletions(-) create mode 100644 test-data/spreadsheet/53282b.xlsx diff --git a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java index e157176eb..7a3d79141 100644 --- a/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java +++ b/src/ooxml/java/org/apache/poi/openxml4j/opc/PackageRelationshipCollection.java @@ -22,14 +22,14 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.TreeMap; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.openxml4j.exceptions.InvalidOperationException; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; -import org.apache.poi.openxml4j.exceptions.InvalidFormatException; -import org.apache.poi.openxml4j.exceptions.InvalidOperationException; -import org.apache.poi.util.POILogger; -import org.apache.poi.util.POILogFactory; /** * Represents a collection of PackageRelationship elements that are owned by a @@ -39,179 +39,179 @@ import org.apache.poi.util.POILogFactory; * @version 0.1 */ public final class PackageRelationshipCollection implements - Iterable { + Iterable { private static POILogger logger = POILogFactory.getLogger(PackageRelationshipCollection.class); - /** - * Package relationships ordered by ID. - */ - private TreeMap relationshipsByID; + /** + * Package relationships ordered by ID. + */ + private TreeMap relationshipsByID; - /** - * Package relationships ordered by type. - */ - private TreeMap relationshipsByType; + /** + * Package relationships ordered by type. + */ + private TreeMap relationshipsByType; - /** - * This relationshipPart. - */ - private PackagePart relationshipPart; + /** + * This relationshipPart. + */ + private PackagePart relationshipPart; - /** - * Source part. - */ - private PackagePart sourcePart; + /** + * Source part. + */ + private PackagePart sourcePart; - /** - * This part name. - */ - private PackagePartName partName; + /** + * This part name. + */ + private PackagePartName partName; - /** - * Reference to the package. - */ - private OPCPackage container; - - /** - * The ID number of the next rID# to generate, or -1 - * if that is still to be determined. - */ - private int nextRelationshipId = -1; + /** + * Reference to the package. + */ + private OPCPackage container; + + /** + * The ID number of the next rID# to generate, or -1 + * if that is still to be determined. + */ + private int nextRelationshipId = -1; - /** - * Constructor. - */ - PackageRelationshipCollection() { - relationshipsByID = new TreeMap(); - relationshipsByType = new TreeMap(); - } + /** + * Constructor. + */ + PackageRelationshipCollection() { + relationshipsByID = new TreeMap(); + relationshipsByType = new TreeMap(); + } - /** - * Copy constructor. - * - * This collection will contain only elements from the specified collection - * for which the type is compatible with the specified relationship type - * filter. - * - * @param coll - * Collection to import. - * @param filter - * Relationship type filter. - */ - public PackageRelationshipCollection(PackageRelationshipCollection coll, - String filter) { - this(); - for (PackageRelationship rel : coll.relationshipsByID.values()) { - if (filter == null || rel.getRelationshipType().equals(filter)) - addRelationship(rel); - } - } + /** + * Copy constructor. + * + * This collection will contain only elements from the specified collection + * for which the type is compatible with the specified relationship type + * filter. + * + * @param coll + * Collection to import. + * @param filter + * Relationship type filter. + */ + public PackageRelationshipCollection(PackageRelationshipCollection coll, + String filter) { + this(); + for (PackageRelationship rel : coll.relationshipsByID.values()) { + if (filter == null || rel.getRelationshipType().equals(filter)) + addRelationship(rel); + } + } - /** - * Constructor. - */ - public PackageRelationshipCollection(OPCPackage container) - throws InvalidFormatException { - this(container, null); - } + /** + * Constructor. + */ + public PackageRelationshipCollection(OPCPackage container) + throws InvalidFormatException { + this(container, null); + } - /** - * Constructor. - * - * @throws InvalidFormatException - * Throws if the format of the content part is invalid. - * - * @throws InvalidOperationException - * Throws if the specified part is a relationship part. - */ - public PackageRelationshipCollection(PackagePart part) - throws InvalidFormatException { - this(part._container, part); - } + /** + * Constructor. + * + * @throws InvalidFormatException + * Throws if the format of the content part is invalid. + * + * @throws InvalidOperationException + * Throws if the specified part is a relationship part. + */ + public PackageRelationshipCollection(PackagePart part) + throws InvalidFormatException { + this(part._container, part); + } - /** - * Constructor. Parse the existing package relationship part if one exists. - * - * @param container - * The parent package. - * @param part - * The part that own this relationships collection. If null - * then this part is considered as the package root. - * @throws InvalidFormatException - * If an error occurs during the parsing of the relatinships - * part fo the specified part. - */ - public PackageRelationshipCollection(OPCPackage container, PackagePart part) - throws InvalidFormatException { - this(); + /** + * Constructor. Parse the existing package relationship part if one exists. + * + * @param container + * The parent package. + * @param part + * The part that own this relationships collection. If null + * then this part is considered as the package root. + * @throws InvalidFormatException + * If an error occurs during the parsing of the relatinships + * part fo the specified part. + */ + public PackageRelationshipCollection(OPCPackage container, PackagePart part) + throws InvalidFormatException { + this(); - if (container == null) - throw new IllegalArgumentException("container"); + if (container == null) + throw new IllegalArgumentException("container"); - // Check if the specified part is not a relationship part - if (part != null && part.isRelationshipPart()) - throw new IllegalArgumentException("part"); + // Check if the specified part is not a relationship part + if (part != null && part.isRelationshipPart()) + throw new IllegalArgumentException("part"); - this.container = container; - this.sourcePart = part; - this.partName = getRelationshipPartName(part); - if ((container.getPackageAccess() != PackageAccess.WRITE) - && container.containPart(this.partName)) { - relationshipPart = container.getPart(this.partName); - parseRelationshipsPart(relationshipPart); - } - } + this.container = container; + this.sourcePart = part; + this.partName = getRelationshipPartName(part); + if ((container.getPackageAccess() != PackageAccess.WRITE) + && container.containPart(this.partName)) { + relationshipPart = container.getPart(this.partName); + parseRelationshipsPart(relationshipPart); + } + } - /** - * Get the relationship part name of the specified part. - * - * @param part - * The part . - * @return The relationship part name of the specified part. Be careful, - * only the correct name is returned, this method does not check if - * the part really exist in a package ! - * @throws InvalidOperationException - * Throws if the specified part is a relationship part. - */ - private static PackagePartName getRelationshipPartName(PackagePart part) - throws InvalidOperationException { - PackagePartName partName; - if (part == null) { - partName = PackagingURIHelper.PACKAGE_ROOT_PART_NAME; - } else { - partName = part.getPartName(); - } - return PackagingURIHelper.getRelationshipPartName(partName); - } + /** + * Get the relationship part name of the specified part. + * + * @param part + * The part . + * @return The relationship part name of the specified part. Be careful, + * only the correct name is returned, this method does not check if + * the part really exist in a package ! + * @throws InvalidOperationException + * Throws if the specified part is a relationship part. + */ + private static PackagePartName getRelationshipPartName(PackagePart part) + throws InvalidOperationException { + PackagePartName partName; + if (part == null) { + partName = PackagingURIHelper.PACKAGE_ROOT_PART_NAME; + } else { + partName = part.getPartName(); + } + return PackagingURIHelper.getRelationshipPartName(partName); + } - /** - * Add the specified relationship to the collection. - * - * @param relPart - * The relationship to add. - */ - public void addRelationship(PackageRelationship relPart) { - relationshipsByID.put(relPart.getId(), relPart); - relationshipsByType.put(relPart.getRelationshipType(), relPart); - } + /** + * Add the specified relationship to the collection. + * + * @param relPart + * The relationship to add. + */ + public void addRelationship(PackageRelationship relPart) { + relationshipsByID.put(relPart.getId(), relPart); + relationshipsByType.put(relPart.getRelationshipType(), relPart); + } - /** - * Add a relationship to the collection. - * - * @param targetUri - * Target URI. - * @param targetMode - * The target mode : INTERNAL or EXTERNAL - * @param relationshipType - * Relationship type. - * @param id - * Relationship ID. - * @return The newly created relationship. - * @see PackageAccess - */ - public PackageRelationship addRelationship(URI targetUri, - TargetMode targetMode, String relationshipType, String id) { + /** + * Add a relationship to the collection. + * + * @param targetUri + * Target URI. + * @param targetMode + * The target mode : INTERNAL or EXTERNAL + * @param relationshipType + * Relationship type. + * @param id + * Relationship ID. + * @return The newly created relationship. + * @see PackageAccess + */ + public PackageRelationship addRelationship(URI targetUri, + TargetMode targetMode, String relationshipType, String id) { if (id == null) { // Generate a unique ID is id parameter is null. if (nextRelationshipId == -1) { @@ -224,229 +224,230 @@ public final class PackageRelationshipCollection implements } while (relationshipsByID.get(id) != null); } - PackageRelationship rel = new PackageRelationship(container, - sourcePart, targetUri, targetMode, relationshipType, id); - relationshipsByID.put(rel.getId(), rel); - relationshipsByType.put(rel.getRelationshipType(), rel); - return rel; - } + PackageRelationship rel = new PackageRelationship(container, + sourcePart, targetUri, targetMode, relationshipType, id); + relationshipsByID.put(rel.getId(), rel); + relationshipsByType.put(rel.getRelationshipType(), rel); + return rel; + } - /** - * Remove a relationship by its ID. - * - * @param id - * The relationship ID to remove. - */ - public void removeRelationship(String id) { - if (relationshipsByID != null && relationshipsByType != null) { - PackageRelationship rel = relationshipsByID.get(id); - if (rel != null) { - relationshipsByID.remove(rel.getId()); - relationshipsByType.values().remove(rel); - } - } - } + /** + * Remove a relationship by its ID. + * + * @param id + * The relationship ID to remove. + */ + public void removeRelationship(String id) { + if (relationshipsByID != null && relationshipsByType != null) { + PackageRelationship rel = relationshipsByID.get(id); + if (rel != null) { + relationshipsByID.remove(rel.getId()); + relationshipsByType.values().remove(rel); + } + } + } - /** - * Remove a relationship by its reference. - * - * @param rel - * The relationship to delete. - */ - public void removeRelationship(PackageRelationship rel) { - if (rel == null) - throw new IllegalArgumentException("rel"); + /** + * Remove a relationship by its reference. + * + * @param rel + * The relationship to delete. + */ + public void removeRelationship(PackageRelationship rel) { + if (rel == null) + throw new IllegalArgumentException("rel"); - relationshipsByID.values().remove(rel); - relationshipsByType.values().remove(rel); - } + relationshipsByID.values().remove(rel); + relationshipsByType.values().remove(rel); + } - /** - * Retrieves a relationship by its index in the collection. - * - * @param index - * Must be a value between [0-relationships_count-1] - */ - public PackageRelationship getRelationship(int index) { - if (index < 0 || index > relationshipsByID.values().size()) - throw new IllegalArgumentException("index"); + /** + * Retrieves a relationship by its index in the collection. + * + * @param index + * Must be a value between [0-relationships_count-1] + */ + public PackageRelationship getRelationship(int index) { + if (index < 0 || index > relationshipsByID.values().size()) + throw new IllegalArgumentException("index"); - PackageRelationship retRel = null; - int i = 0; - for (PackageRelationship rel : relationshipsByID.values()) { - if (index == i++) - return rel; - } - return retRel; - } + PackageRelationship retRel = null; + int i = 0; + for (PackageRelationship rel : relationshipsByID.values()) { + if (index == i++) + return rel; + } + return retRel; + } - /** - * Retrieves a package relationship based on its id. - * - * @param id - * ID of the package relationship to retrieve. - * @return The package relationship identified by the specified id. - */ - public PackageRelationship getRelationshipByID(String id) { - return relationshipsByID.get(id); - } + /** + * Retrieves a package relationship based on its id. + * + * @param id + * ID of the package relationship to retrieve. + * @return The package relationship identified by the specified id. + */ + public PackageRelationship getRelationshipByID(String id) { + return relationshipsByID.get(id); + } - /** - * Get the numbe rof relationships in the collection. - */ - public int size() { - return relationshipsByID.values().size(); - } + /** + * Get the numbe rof relationships in the collection. + */ + public int size() { + return relationshipsByID.values().size(); + } - /** - * Parse the relationship part and add all relationship in this collection. - * - * @param relPart - * The package part to parse. - * @throws InvalidFormatException - * Throws if the relationship part is invalid. - */ - private void parseRelationshipsPart(PackagePart relPart) - throws InvalidFormatException { - try { - SAXReader reader = new SAXReader(); - logger.log(POILogger.DEBUG, "Parsing relationship: " + relPart.getPartName()); - Document xmlRelationshipsDoc = reader - .read(relPart.getInputStream()); + /** + * Parse the relationship part and add all relationship in this collection. + * + * @param relPart + * The package part to parse. + * @throws InvalidFormatException + * Throws if the relationship part is invalid. + */ + private void parseRelationshipsPart(PackagePart relPart) + throws InvalidFormatException { + try { + SAXReader reader = new SAXReader(); + logger.log(POILogger.DEBUG, "Parsing relationship: " + relPart.getPartName()); + Document xmlRelationshipsDoc = reader + .read(relPart.getInputStream()); - // Browse default types - Element root = xmlRelationshipsDoc.getRootElement(); + // Browse default types + Element root = xmlRelationshipsDoc.getRootElement(); - // Check OPC compliance M4.1 rule - boolean fCorePropertiesRelationship = false; + // Check OPC compliance M4.1 rule + boolean fCorePropertiesRelationship = false; - for (Iterator i = root - .elementIterator(PackageRelationship.RELATIONSHIP_TAG_NAME); i - .hasNext();) { - Element element = (Element) i.next(); - // Relationship ID - String id = element.attribute( - PackageRelationship.ID_ATTRIBUTE_NAME).getValue(); - // Relationship type - String type = element.attribute( - PackageRelationship.TYPE_ATTRIBUTE_NAME).getValue(); + @SuppressWarnings("unchecked") + Iterator iter = (Iterator) + root.elementIterator(PackageRelationship.RELATIONSHIP_TAG_NAME); + while (iter.hasNext()) { + Element element = iter.next(); + // Relationship ID + String id = element.attribute( + PackageRelationship.ID_ATTRIBUTE_NAME).getValue(); + // Relationship type + String type = element.attribute( + PackageRelationship.TYPE_ATTRIBUTE_NAME).getValue(); - /* Check OPC Compliance */ - // Check Rule M4.1 - if (type.equals(PackageRelationshipTypes.CORE_PROPERTIES)) - if (!fCorePropertiesRelationship) - fCorePropertiesRelationship = true; - else - throw new InvalidFormatException( - "OPC Compliance error [M4.1]: there is more than one core properties relationship in the package !"); + /* Check OPC Compliance */ + // Check Rule M4.1 + if (type.equals(PackageRelationshipTypes.CORE_PROPERTIES)) + if (!fCorePropertiesRelationship) + fCorePropertiesRelationship = true; + else + throw new InvalidFormatException( + "OPC Compliance error [M4.1]: there is more than one core properties relationship in the package !"); - /* End OPC Compliance */ + /* End OPC Compliance */ - // TargetMode (default value "Internal") - Attribute targetModeAttr = element - .attribute(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME); - TargetMode targetMode = TargetMode.INTERNAL; - if (targetModeAttr != null) { - targetMode = targetModeAttr.getValue().toLowerCase() - .equals("internal") ? TargetMode.INTERNAL - : TargetMode.EXTERNAL; - } - - // Target converted in URI - URI target; - String value = ""; - try { - value = element.attribute( - PackageRelationship.TARGET_ATTRIBUTE_NAME) - .getValue(); + // TargetMode (default value "Internal") + Attribute targetModeAttr = element + .attribute(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME); + TargetMode targetMode = TargetMode.INTERNAL; + if (targetModeAttr != null) { + targetMode = targetModeAttr.getValue().toLowerCase() + .equals("internal") ? TargetMode.INTERNAL + : TargetMode.EXTERNAL; + } + // Target converted in URI + URI target = PackagingURIHelper.toURI("http://invalid.uri"); // dummy url + String value = element.attribute( + PackageRelationship.TARGET_ATTRIBUTE_NAME) + .getValue(); + try { + // when parsing of the given uri fails, we can either + // ignore this relationship, which leads to IllegalStateException + // later on, or use a dummy value and thus enable processing of the + // package target = PackagingURIHelper.toURI(value); + } catch (URISyntaxException e) { + logger.log(POILogger.ERROR, "Cannot convert " + value + + " in a valid relationship URI-> dummy-URI used", e); + } + addRelationship(target, targetMode, type, id); + } + } catch (Exception e) { + logger.log(POILogger.ERROR, e); + throw new InvalidFormatException(e.getMessage()); + } + } - } catch (URISyntaxException e) { - logger.log(POILogger.ERROR, "Cannot convert " + value - + " in a valid relationship URI-> ignored", e); - continue; - } - addRelationship(target, targetMode, type, id); - } - } catch (Exception e) { - logger.log(POILogger.ERROR, e); - throw new InvalidFormatException(e.getMessage()); - } - } + /** + * Retrieves all relations with the specified type. + * + * @param typeFilter + * Relationship type filter. If null then all + * relationships are returned. + * @return All relationships of the type specified by the filter. + */ + public PackageRelationshipCollection getRelationships(String typeFilter) { + PackageRelationshipCollection coll = new PackageRelationshipCollection( + this, typeFilter); + return coll; + } - /** - * Retrieves all relations with the specified type. - * - * @param typeFilter - * Relationship type filter. If null then all - * relationships are returned. - * @return All relationships of the type specified by the filter. - */ - public PackageRelationshipCollection getRelationships(String typeFilter) { - PackageRelationshipCollection coll = new PackageRelationshipCollection( - this, typeFilter); - return coll; - } + /** + * Get this collection's iterator. + */ + public Iterator iterator() { + return relationshipsByID.values().iterator(); + } - /** - * Get this collection's iterator. - */ - public Iterator iterator() { - return relationshipsByID.values().iterator(); - } + /** + * Get an iterator of a collection with all relationship with the specified + * type. + * + * @param typeFilter + * Type filter. + * @return An iterator to a collection containing all relationships with the + * specified type contain in this collection. + */ + public Iterator iterator(String typeFilter) { + ArrayList retArr = new ArrayList(); + for (PackageRelationship rel : relationshipsByID.values()) { + if (rel.getRelationshipType().equals(typeFilter)) + retArr.add(rel); + } + return retArr.iterator(); + } - /** - * Get an iterator of a collection with all relationship with the specified - * type. - * - * @param typeFilter - * Type filter. - * @return An iterator to a collection containing all relationships with the - * specified type contain in this collection. - */ - public Iterator iterator(String typeFilter) { - ArrayList retArr = new ArrayList(); - for (PackageRelationship rel : relationshipsByID.values()) { - if (rel.getRelationshipType().equals(typeFilter)) - retArr.add(rel); - } - return retArr.iterator(); - } + /** + * Clear all relationships. + */ + public void clear() { + relationshipsByID.clear(); + relationshipsByType.clear(); + } - /** - * Clear all relationships. - */ - public void clear() { - relationshipsByID.clear(); - relationshipsByType.clear(); - } + @Override + public String toString() { + String str; + if (relationshipsByID == null) { + str = "relationshipsByID=null"; + } else { + str = relationshipsByID.size() + " relationship(s) = ["; + } + if ((relationshipPart != null) && (relationshipPart._partName != null)) { + str = str + "," + relationshipPart._partName; + } else { + str = str + ",relationshipPart=null"; + } - @Override - public String toString() { - String str; - if (relationshipsByID == null) { - str = "relationshipsByID=null"; - } else { - str = relationshipsByID.size() + " relationship(s) = ["; - } - if ((relationshipPart != null) && (relationshipPart._partName != null)) { - str = str + "," + relationshipPart._partName; - } else { - str = str + ",relationshipPart=null"; - } - - // Source of this relationship - if ((sourcePart != null) && (sourcePart._partName != null)) { - str = str + "," + sourcePart._partName; - } else { - str = str + ",sourcePart=null"; - } - if (partName != null) { - str = str + "," + partName; - } else { - str = str + ",uri=null)"; - } - return str + "]"; - } + // Source of this relationship + if ((sourcePart != null) && (sourcePart._partName != null)) { + str = str + "," + sourcePart._partName; + } else { + str = str + ",sourcePart=null"; + } + if (partName != null) { + str = str + "," + partName; + } else { + str = str + ",uri=null)"; + } + return str + "]"; + } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java index 1f5c5120a..bdb1ea818 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java @@ -30,6 +30,7 @@ import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; +import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; import org.apache.poi.openxml4j.opc.PackagingURIHelper; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -54,252 +55,278 @@ public final class XSSFRelation extends POIXMLRelation { protected static Map _table = new HashMap(); - public static final XSSFRelation WORKBOOK = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/workbook", - "/xl/workbook.xml", - null - ); - public static final XSSFRelation MACROS_WORKBOOK = new XSSFRelation( - "application/vnd.ms-excel.sheet.macroEnabled.main+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", - "/xl/workbook.xml", - null - ); + public static final XSSFRelation WORKBOOK = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/workbook", + "/xl/workbook.xml", + null + ); + public static final XSSFRelation MACROS_WORKBOOK = new XSSFRelation( + "application/vnd.ms-excel.sheet.macroEnabled.main+xml", + PackageRelationshipTypes.CORE_DOCUMENT, + "/xl/workbook.xml", + null + ); public static final XSSFRelation TEMPLATE_WORKBOOK = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", - "/xl/workbook.xml", - null + "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml", + PackageRelationshipTypes.CORE_DOCUMENT, + "/xl/workbook.xml", + null ); + public static final XSSFRelation MACRO_TEMPLATE_WORKBOOK = new XSSFRelation( - "application/vnd.ms-excel.template.macroEnabled.main+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", - "/xl/workbook.xml", - null + "application/vnd.ms-excel.template.macroEnabled.main+xml", + PackageRelationshipTypes.CORE_DOCUMENT, + "/xl/workbook.xml", + null ); + public static final XSSFRelation MACRO_ADDIN_WORKBOOK = new XSSFRelation( - "application/vnd.ms-excel.addin.macroEnabled.main+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument", - "/xl/workbook.xml", - null + "application/vnd.ms-excel.addin.macroEnabled.main+xml", + PackageRelationshipTypes.CORE_DOCUMENT, + "/xl/workbook.xml", + null ); - public static final XSSFRelation WORKSHEET = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", - "/xl/worksheets/sheet#.xml", - XSSFSheet.class - ); - public static final XSSFRelation CHARTSHEET = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet", - "/xl/chartsheets/sheet#.xml", - XSSFChartSheet.class - ); - public static final XSSFRelation SHARED_STRINGS = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings", - "/xl/sharedStrings.xml", - SharedStringsTable.class - ); - public static final XSSFRelation STYLES = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", - "/xl/styles.xml", - StylesTable.class - ); - public static final XSSFRelation DRAWINGS = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.drawing+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing", - "/xl/drawings/drawing#.xml", - XSSFDrawing.class - ); - public static final XSSFRelation VML_DRAWINGS = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.vmlDrawing", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing", - "/xl/drawings/vmlDrawing#.vml", - XSSFVMLDrawing.class - ); - public static final XSSFRelation CHART = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", - "/xl/charts/chart#.xml", - XSSFChart.class - ); - public static final XSSFRelation CUSTOM_XML_MAPPINGS = new XSSFRelation( - "application/xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/xmlMaps", - "/xl/xmlMaps.xml", - MapInfo.class - ); + public static final XSSFRelation WORKSHEET = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", + "/xl/worksheets/sheet#.xml", + XSSFSheet.class + ); - public static final XSSFRelation SINGLE_XML_CELLS = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/tableSingleCells", - "/xl/tables/tableSingleCells#.xml", - SingleXmlCells.class - ); + public static final XSSFRelation CHARTSHEET = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet", + "/xl/chartsheets/sheet#.xml", + XSSFChartSheet.class + ); - public static final XSSFRelation TABLE = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table", - "/xl/tables/table#.xml", - XSSFTable.class - ); + public static final XSSFRelation SHARED_STRINGS = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings", + "/xl/sharedStrings.xml", + SharedStringsTable.class + ); + + public static final XSSFRelation STYLES = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", + PackageRelationshipTypes.STYLE_PART, + "/xl/styles.xml", + StylesTable.class + ); + + public static final XSSFRelation DRAWINGS = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.drawing+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing", + "/xl/drawings/drawing#.xml", + XSSFDrawing.class + ); + + public static final XSSFRelation VML_DRAWINGS = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.vmlDrawing", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing", + "/xl/drawings/vmlDrawing#.vml", + XSSFVMLDrawing.class + ); + + public static final XSSFRelation CHART = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", + "/xl/charts/chart#.xml", + XSSFChart.class + ); + + public static final XSSFRelation CUSTOM_XML_MAPPINGS = new XSSFRelation( + "application/xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/xmlMaps", + "/xl/xmlMaps.xml", + MapInfo.class + ); + + public static final XSSFRelation SINGLE_XML_CELLS = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/tableSingleCells", + "/xl/tables/tableSingleCells#.xml", + SingleXmlCells.class + ); + + public static final XSSFRelation TABLE = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table", + "/xl/tables/table#.xml", + XSSFTable.class + ); public static final XSSFRelation IMAGES = new XSSFRelation( - null, - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - null, - XSSFPictureData.class + null, + PackageRelationshipTypes.IMAGE_PART, + null, + XSSFPictureData.class ); + public static final XSSFRelation IMAGE_EMF = new XSSFRelation( - "image/x-emf", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.emf", - XSSFPictureData.class + "image/x-emf", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.emf", + XSSFPictureData.class ); + public static final XSSFRelation IMAGE_WMF = new XSSFRelation( - "image/x-wmf", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.wmf", - XSSFPictureData.class + "image/x-wmf", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.wmf", + XSSFPictureData.class ); + public static final XSSFRelation IMAGE_PICT = new XSSFRelation( - "image/pict", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.pict", - XSSFPictureData.class + "image/pict", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.pict", + XSSFPictureData.class ); + public static final XSSFRelation IMAGE_JPEG = new XSSFRelation( - "image/jpeg", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.jpeg", - XSSFPictureData.class + "image/jpeg", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.jpeg", + XSSFPictureData.class ); + public static final XSSFRelation IMAGE_PNG = new XSSFRelation( - "image/png", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.png", - XSSFPictureData.class + "image/png", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.png", + XSSFPictureData.class ); + public static final XSSFRelation IMAGE_DIB = new XSSFRelation( - "image/dib", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.dib", - XSSFPictureData.class + "image/dib", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.dib", + XSSFPictureData.class ); public static final XSSFRelation IMAGE_GIF = new XSSFRelation( - "image/gif", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.gif", - XSSFPictureData.class + "image/gif", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.gif", + XSSFPictureData.class ); public static final XSSFRelation IMAGE_TIFF = new XSSFRelation( - "image/tiff", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.tiff", - XSSFPictureData.class + "image/tiff", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.tiff", + XSSFPictureData.class ); + public static final XSSFRelation IMAGE_EPS = new XSSFRelation( - "image/x-eps", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.eps", - XSSFPictureData.class + "image/x-eps", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.eps", + XSSFPictureData.class ); + public static final XSSFRelation IMAGE_BMP = new XSSFRelation( - "image/x-ms-bmp", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.bmp", - XSSFPictureData.class + "image/x-ms-bmp", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.bmp", + XSSFPictureData.class ); + public static final XSSFRelation IMAGE_WPG = new XSSFRelation( - "image/x-wpg", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", - "/xl/media/image#.wpg", - XSSFPictureData.class + "image/x-wpg", + PackageRelationshipTypes.IMAGE_PART, + "/xl/media/image#.wpg", + XSSFPictureData.class ); - public static final XSSFRelation SHEET_COMMENTS = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", - "/xl/comments#.xml", - CommentsTable.class - ); - public static final XSSFRelation SHEET_HYPERLINKS = new XSSFRelation( - null, - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink", - null, - null - ); - public static final XSSFRelation OLEEMBEDDINGS = new XSSFRelation( - null, - POIXMLDocument.OLE_OBJECT_REL_TYPE, - null, - null - ); - public static final XSSFRelation PACKEMBEDDINGS = new XSSFRelation( - null, - POIXMLDocument.PACK_OBJECT_REL_TYPE, - null, - null + public static final XSSFRelation SHEET_COMMENTS = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", + "/xl/comments#.xml", + CommentsTable.class ); - public static final XSSFRelation VBA_MACROS = new XSSFRelation( - "application/vnd.ms-office.vbaProject", - "http://schemas.microsoft.com/office/2006/relationships/vbaProject", - "/xl/vbaProject.bin", - null + public static final XSSFRelation SHEET_HYPERLINKS = new XSSFRelation( + null, + PackageRelationshipTypes.HYPERLINK_PART, + null, + null ); - public static final XSSFRelation ACTIVEX_CONTROLS = new XSSFRelation( - "application/vnd.ms-office.activeX+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control", - "/xl/activeX/activeX#.xml", - null - ); - public static final XSSFRelation ACTIVEX_BINS = new XSSFRelation( - "application/vnd.ms-office.activeX", - "http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary", - "/xl/activeX/activeX#.bin", - null - ); + + public static final XSSFRelation OLEEMBEDDINGS = new XSSFRelation( + null, + POIXMLDocument.OLE_OBJECT_REL_TYPE, + null, + null + ); + + public static final XSSFRelation PACKEMBEDDINGS = new XSSFRelation( + null, + POIXMLDocument.PACK_OBJECT_REL_TYPE, + null, + null + ); + + public static final XSSFRelation VBA_MACROS = new XSSFRelation( + "application/vnd.ms-office.vbaProject", + "http://schemas.microsoft.com/office/2006/relationships/vbaProject", + "/xl/vbaProject.bin", + null + ); + + public static final XSSFRelation ACTIVEX_CONTROLS = new XSSFRelation( + "application/vnd.ms-office.activeX+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/control", + "/xl/activeX/activeX#.xml", + null + ); + + public static final XSSFRelation ACTIVEX_BINS = new XSSFRelation( + "application/vnd.ms-office.activeX", + "http://schemas.microsoft.com/office/2006/relationships/activeXControlBinary", + "/xl/activeX/activeX#.bin", + null + ); + public static final XSSFRelation THEME = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.theme+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", - "/xl/theme/theme#.xml", - ThemesTable.class + "application/vnd.openxmlformats-officedocument.theme+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", + "/xl/theme/theme#.xml", + ThemesTable.class ); + public static final XSSFRelation CALC_CHAIN = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain", - "/xl/calcChain.xml", - CalculationChain.class + "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain", + "/xl/calcChain.xml", + CalculationChain.class ); + public static final XSSFRelation PRINTER_SETTINGS = new XSSFRelation( - "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings", - "/xl/printerSettings/printerSettings#.bin", - null - ); + "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings", + "/xl/printerSettings/printerSettings#.bin", + null + ); - private XSSFRelation(String type, String rel, String defaultName, Class cls) { + private XSSFRelation(String type, String rel, String defaultName, Class cls) { super(type, rel, defaultName, cls); if(cls != null && !_table.containsKey(rel)) _table.put(rel, this); } /** - * Fetches the InputStream to read the contents, based - * of the specified core part, for which we are defined - * as a suitable relationship - */ - public InputStream getContents(PackagePart corePart) throws IOException, InvalidFormatException { + * Fetches the InputStream to read the contents, based + * of the specified core part, for which we are defined + * as a suitable relationship + */ + public InputStream getContents(PackagePart corePart) throws IOException, InvalidFormatException { PackageRelationshipCollection prc = - corePart.getRelationshipsByType(_relation); + corePart.getRelationshipsByType(_relation); Iterator it = prc.iterator(); if(it.hasNext()) { PackageRelationship rel = it.next(); @@ -309,8 +336,7 @@ public final class XSSFRelation extends POIXMLRelation { } log.log(POILogger.WARN, "No part " + _defaultName + " found"); return null; - } - + } /** * Get POIXMLRelation by relation type diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java index faf5825b0..3c24acc7f 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java @@ -26,7 +26,6 @@ import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.InputStream; import java.util.List; import org.apache.poi.EncryptedDocumentException; @@ -1414,30 +1413,31 @@ public final class TestXSSFBugs extends BaseTestBugzillaIssues { * error message when called via WorkbookFactory. * (You need to supply a password explicitly for them) */ + @Test(expected=EncryptedDocumentException.class) + public void bug55692_stream() throws Exception { + // Directly on a Stream + WorkbookFactory.create(POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx")); + } + + @Test(expected=EncryptedDocumentException.class) + public void bug55692_poifs() throws Exception { + // Via a POIFSFileSystem + POIFSFileSystem fsP = new POIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx")); + WorkbookFactory.create(fsP); + } + + @Test(expected=EncryptedDocumentException.class) + public void bug55692_npoifs() throws Exception { + // Via a NPOIFSFileSystem + NPOIFSFileSystem fsNP = new NPOIFSFileSystem(POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx")); + WorkbookFactory.create(fsNP); + } + @Test - public void bug55692() throws Exception { - InputStream inpA = POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx"); - InputStream inpB = POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx"); - InputStream inpC = POIDataSamples.getPOIFSInstance().openResourceAsStream("protect.xlsx"); - - // Directly on a Stream - try { - WorkbookFactory.create(inpA); - fail("Should've raised a EncryptedDocumentException error"); - } catch (EncryptedDocumentException e) {} - - // Via a POIFSFileSystem - POIFSFileSystem fsP = new POIFSFileSystem(inpB); - try { - WorkbookFactory.create(fsP); - fail("Should've raised a EncryptedDocumentException error"); - } catch (EncryptedDocumentException e) {} - - // Via a NPOIFSFileSystem - NPOIFSFileSystem fsNP = new NPOIFSFileSystem(inpC); - try { - WorkbookFactory.create(fsNP); - fail("Should've raised a EncryptedDocumentException error"); - } catch (EncryptedDocumentException e) {} + public void bug53282() { + Workbook wb = XSSFTestDataSamples.openSampleWorkbook("53282b.xlsx"); + Cell c = wb.getSheetAt(0).getRow(1).getCell(0); + assertEquals("#@_#", c.getStringCellValue()); + assertEquals("http://invalid.uri", c.getHyperlink().getAddress()); } } diff --git a/test-data/spreadsheet/53282b.xlsx b/test-data/spreadsheet/53282b.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3ad5ad865a4926b93b0eba3cb6ace35e9d4eda51 GIT binary patch literal 9319 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