[bug-62522] include partName in exception message
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1835276 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
0c3e972a71
commit
75d1771f49
@ -43,433 +43,434 @@ import org.xml.sax.SAXException;
|
||||
*/
|
||||
public abstract class ContentTypeManager {
|
||||
|
||||
/**
|
||||
* Content type part name.
|
||||
*/
|
||||
public static final String CONTENT_TYPES_PART_NAME = "[Content_Types].xml";
|
||||
/**
|
||||
* Content type part name.
|
||||
*/
|
||||
public static final String CONTENT_TYPES_PART_NAME = "[Content_Types].xml";
|
||||
|
||||
/**
|
||||
* Content type namespace
|
||||
*/
|
||||
public static final String TYPES_NAMESPACE_URI = PackageNamespaces.CONTENT_TYPES;
|
||||
/**
|
||||
* Content type namespace
|
||||
*/
|
||||
public static final String TYPES_NAMESPACE_URI = PackageNamespaces.CONTENT_TYPES;
|
||||
|
||||
/* Xml elements in content type part */
|
||||
/* Xml elements in content type part */
|
||||
|
||||
private static final String TYPES_TAG_NAME = "Types";
|
||||
private static final String TYPES_TAG_NAME = "Types";
|
||||
|
||||
private static final String DEFAULT_TAG_NAME = "Default";
|
||||
private static final String DEFAULT_TAG_NAME = "Default";
|
||||
|
||||
private static final String EXTENSION_ATTRIBUTE_NAME = "Extension";
|
||||
private static final String EXTENSION_ATTRIBUTE_NAME = "Extension";
|
||||
|
||||
private static final String CONTENT_TYPE_ATTRIBUTE_NAME = "ContentType";
|
||||
private static final String CONTENT_TYPE_ATTRIBUTE_NAME = "ContentType";
|
||||
|
||||
private static final String OVERRIDE_TAG_NAME = "Override";
|
||||
private static final String OVERRIDE_TAG_NAME = "Override";
|
||||
|
||||
private static final String PART_NAME_ATTRIBUTE_NAME = "PartName";
|
||||
private static final String PART_NAME_ATTRIBUTE_NAME = "PartName";
|
||||
|
||||
/**
|
||||
* Reference to the package using this content type manager.
|
||||
*/
|
||||
protected OPCPackage container;
|
||||
/**
|
||||
* Reference to the package using this content type manager.
|
||||
*/
|
||||
protected OPCPackage container;
|
||||
|
||||
/**
|
||||
* Default content type tree. <Extension, ContentType>
|
||||
*/
|
||||
private TreeMap<String, String> defaultContentType;
|
||||
/**
|
||||
* Default content type tree. <Extension, ContentType>
|
||||
*/
|
||||
private TreeMap<String, String> defaultContentType;
|
||||
|
||||
/**
|
||||
* Override content type tree.
|
||||
*/
|
||||
private TreeMap<PackagePartName, String> overrideContentType;
|
||||
/**
|
||||
* Override content type tree.
|
||||
*/
|
||||
private TreeMap<PackagePartName, String> overrideContentType;
|
||||
|
||||
/**
|
||||
* Constructor. Parses the content of the specified input stream.
|
||||
*
|
||||
* @param in
|
||||
* If different of <i>null</i> then the content types part is
|
||||
* retrieve and parse.
|
||||
* @throws InvalidFormatException
|
||||
* If the content types part content is not valid.
|
||||
*/
|
||||
public ContentTypeManager(InputStream in, OPCPackage pkg)
|
||||
throws InvalidFormatException {
|
||||
this.container = pkg;
|
||||
this.defaultContentType = new TreeMap<>();
|
||||
if (in != null) {
|
||||
try {
|
||||
parseContentTypesFile(in);
|
||||
} catch (InvalidFormatException e) {
|
||||
InvalidFormatException ex = new InvalidFormatException("Can't read content types part !");
|
||||
/**
|
||||
* Constructor. Parses the content of the specified input stream.
|
||||
*
|
||||
* @param in
|
||||
* If different of <i>null</i> then the content types part is
|
||||
* retrieve and parse.
|
||||
* @throws InvalidFormatException
|
||||
* If the content types part content is not valid.
|
||||
*/
|
||||
public ContentTypeManager(InputStream in, OPCPackage pkg)
|
||||
throws InvalidFormatException {
|
||||
this.container = pkg;
|
||||
this.defaultContentType = new TreeMap<>();
|
||||
if (in != null) {
|
||||
try {
|
||||
parseContentTypesFile(in);
|
||||
} catch (InvalidFormatException e) {
|
||||
InvalidFormatException ex = new InvalidFormatException("Can't read content types part !");
|
||||
|
||||
// here it is useful to add the cause to not loose the original stack-trace
|
||||
ex.initCause(e);
|
||||
|
||||
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build association extention-> content type (will be stored in
|
||||
* [Content_Types].xml) for example ContentType="image/png" Extension="png"
|
||||
* <p>
|
||||
* [M2.8]: When adding a new part to a package, the package implementer
|
||||
* shall ensure that a content type for that part is specified in the
|
||||
* Content Types stream; the package implementer shall perform the steps
|
||||
* described in §9.1.2.3:
|
||||
* </p><p>
|
||||
* 1. Get the extension from the part name by taking the substring to the
|
||||
* right of the rightmost occurrence of the dot character (.) from the
|
||||
* rightmost segment.
|
||||
* </p><p>
|
||||
* 2. If a part name has no extension, a corresponding Override element
|
||||
* shall be added to the Content Types stream.
|
||||
* </p><p>
|
||||
* 3. Compare the resulting extension with the values specified for the
|
||||
* Extension attributes of the Default elements in the Content Types stream.
|
||||
* The comparison shall be case-insensitive ASCII.
|
||||
* </p><p>
|
||||
* 4. If there is a Default element with a matching Extension attribute,
|
||||
* then the content type of the new part shall be compared with the value of
|
||||
* the ContentType attribute. The comparison might be case-sensitive and
|
||||
* include every character regardless of the role it plays in the
|
||||
* content-type grammar of RFC 2616, or it might follow the grammar of RFC
|
||||
* 2616.
|
||||
* </p><p>
|
||||
* a. If the content types match, no further action is required.
|
||||
* </p><p>
|
||||
* b. If the content types do not match, a new Override element shall be
|
||||
* added to the Content Types stream. .
|
||||
* </p><p>
|
||||
* 5. If there is no Default element with a matching Extension attribute, a
|
||||
* new Default element or Override element shall be added to the Content
|
||||
* Types stream.
|
||||
* </p>
|
||||
*/
|
||||
public void addContentType(PackagePartName partName, String contentType) {
|
||||
boolean defaultCTExists = this.defaultContentType.containsValue(contentType);
|
||||
String extension = partName.getExtension().toLowerCase(Locale.ROOT);
|
||||
if ((extension.length() == 0)
|
||||
|| (this.defaultContentType.containsKey(extension) && !defaultCTExists))
|
||||
this.addOverrideContentType(partName, contentType);
|
||||
else if (!defaultCTExists)
|
||||
this.addDefaultContentType(extension, contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an override content type for a specific part.
|
||||
*
|
||||
* @param partName
|
||||
* Name of the part.
|
||||
* @param contentType
|
||||
* Content type of the part.
|
||||
*/
|
||||
private void addOverrideContentType(PackagePartName partName,
|
||||
String contentType) {
|
||||
if (overrideContentType == null)
|
||||
overrideContentType = new TreeMap<>();
|
||||
overrideContentType.put(partName, contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a content type associated with the specified extension.
|
||||
*
|
||||
* @param extension
|
||||
* The part name extension to bind to a content type.
|
||||
* @param contentType
|
||||
* The content type associated with the specified extension.
|
||||
*/
|
||||
private void addDefaultContentType(String extension, String contentType) {
|
||||
// Remark : Originally the latest parameter was :
|
||||
// contentType.toLowerCase(). Change due to a request ID 1996748.
|
||||
defaultContentType.put(extension.toLowerCase(Locale.ROOT), contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Build association extention-> content type (will be stored in
|
||||
* [Content_Types].xml) for example ContentType="image/png" Extension="png"
|
||||
* <p>
|
||||
* Delete a content type based on the specified part name. If the specified
|
||||
* part name is register with an override content type, then this content
|
||||
* type is remove, else the content type is remove in the default content
|
||||
* type list if it exists and if no part is associated with it yet.
|
||||
* </p><p>
|
||||
* Check rule M2.4: The package implementer shall require that the Content
|
||||
* Types stream contain one of the following for every part in the package:
|
||||
* One matching Default element One matching Override element Both a
|
||||
* matching Default element and a matching Override element, in which case
|
||||
* the Override element takes precedence.
|
||||
* </p>
|
||||
* @param partName
|
||||
* The part URI associated with the override content type to
|
||||
* delete.
|
||||
* @exception InvalidOperationException
|
||||
* Throws if
|
||||
*/
|
||||
public void removeContentType(PackagePartName partName)
|
||||
throws InvalidOperationException {
|
||||
if (partName == null)
|
||||
throw new IllegalArgumentException("partName");
|
||||
* [M2.8]: When adding a new part to a package, the package implementer
|
||||
* shall ensure that a content type for that part is specified in the
|
||||
* Content Types stream; the package implementer shall perform the steps
|
||||
* described in §9.1.2.3:
|
||||
* </p><p>
|
||||
* 1. Get the extension from the part name by taking the substring to the
|
||||
* right of the rightmost occurrence of the dot character (.) from the
|
||||
* rightmost segment.
|
||||
* </p><p>
|
||||
* 2. If a part name has no extension, a corresponding Override element
|
||||
* shall be added to the Content Types stream.
|
||||
* </p><p>
|
||||
* 3. Compare the resulting extension with the values specified for the
|
||||
* Extension attributes of the Default elements in the Content Types stream.
|
||||
* The comparison shall be case-insensitive ASCII.
|
||||
* </p><p>
|
||||
* 4. If there is a Default element with a matching Extension attribute,
|
||||
* then the content type of the new part shall be compared with the value of
|
||||
* the ContentType attribute. The comparison might be case-sensitive and
|
||||
* include every character regardless of the role it plays in the
|
||||
* content-type grammar of RFC 2616, or it might follow the grammar of RFC
|
||||
* 2616.
|
||||
* </p><p>
|
||||
* a. If the content types match, no further action is required.
|
||||
* </p><p>
|
||||
* b. If the content types do not match, a new Override element shall be
|
||||
* added to the Content Types stream. .
|
||||
* </p><p>
|
||||
* 5. If there is no Default element with a matching Extension attribute, a
|
||||
* new Default element or Override element shall be added to the Content
|
||||
* Types stream.
|
||||
* </p>
|
||||
*/
|
||||
public void addContentType(PackagePartName partName, String contentType) {
|
||||
boolean defaultCTExists = this.defaultContentType.containsValue(contentType);
|
||||
String extension = partName.getExtension().toLowerCase(Locale.ROOT);
|
||||
if ((extension.length() == 0)
|
||||
|| (this.defaultContentType.containsKey(extension) && !defaultCTExists))
|
||||
this.addOverrideContentType(partName, contentType);
|
||||
else if (!defaultCTExists)
|
||||
this.addDefaultContentType(extension, contentType);
|
||||
}
|
||||
|
||||
/* Override content type */
|
||||
if (this.overrideContentType != null
|
||||
&& (this.overrideContentType.get(partName) != null)) {
|
||||
// Remove the override definition for the specified part.
|
||||
this.overrideContentType.remove(partName);
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Add an override content type for a specific part.
|
||||
*
|
||||
* @param partName
|
||||
* Name of the part.
|
||||
* @param contentType
|
||||
* Content type of the part.
|
||||
*/
|
||||
private void addOverrideContentType(PackagePartName partName,
|
||||
String contentType) {
|
||||
if (overrideContentType == null)
|
||||
overrideContentType = new TreeMap<>();
|
||||
overrideContentType.put(partName, contentType);
|
||||
}
|
||||
|
||||
/* Default content type */
|
||||
String extensionToDelete = partName.getExtension();
|
||||
boolean deleteDefaultContentTypeFlag = true;
|
||||
if (this.container != null) {
|
||||
try {
|
||||
for (PackagePart part : this.container.getParts()) {
|
||||
if (!part.getPartName().equals(partName)
|
||||
&& part.getPartName().getExtension()
|
||||
.equalsIgnoreCase(extensionToDelete)) {
|
||||
deleteDefaultContentTypeFlag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new InvalidOperationException(e.getMessage());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Add a content type associated with the specified extension.
|
||||
*
|
||||
* @param extension
|
||||
* The part name extension to bind to a content type.
|
||||
* @param contentType
|
||||
* The content type associated with the specified extension.
|
||||
*/
|
||||
private void addDefaultContentType(String extension, String contentType) {
|
||||
// Remark : Originally the latest parameter was :
|
||||
// contentType.toLowerCase(). Change due to a request ID 1996748.
|
||||
defaultContentType.put(extension.toLowerCase(Locale.ROOT), contentType);
|
||||
}
|
||||
|
||||
// Remove the default content type, no other part use this content type.
|
||||
if (deleteDefaultContentTypeFlag) {
|
||||
this.defaultContentType.remove(extensionToDelete);
|
||||
}
|
||||
/**
|
||||
* <p>
|
||||
* Delete a content type based on the specified part name. If the specified
|
||||
* part name is register with an override content type, then this content
|
||||
* type is remove, else the content type is remove in the default content
|
||||
* type list if it exists and if no part is associated with it yet.
|
||||
* </p><p>
|
||||
* Check rule M2.4: The package implementer shall require that the Content
|
||||
* Types stream contain one of the following for every part in the package:
|
||||
* One matching Default element One matching Override element Both a
|
||||
* matching Default element and a matching Override element, in which case
|
||||
* the Override element takes precedence.
|
||||
* </p>
|
||||
* @param partName
|
||||
* The part URI associated with the override content type to
|
||||
* delete.
|
||||
* @exception InvalidOperationException
|
||||
* Throws if
|
||||
*/
|
||||
public void removeContentType(PackagePartName partName)
|
||||
throws InvalidOperationException {
|
||||
if (partName == null)
|
||||
throw new IllegalArgumentException("partName");
|
||||
|
||||
/*
|
||||
* Check rule 2.4: The package implementer shall require that the
|
||||
* Content Types stream contain one of the following for every part in
|
||||
* the package: One matching Default element One matching Override
|
||||
* element Both a matching Default element and a matching Override
|
||||
* element, in which case the Override element takes precedence.
|
||||
*/
|
||||
if (this.container != null) {
|
||||
try {
|
||||
for (PackagePart part : this.container.getParts()) {
|
||||
if (!part.getPartName().equals(partName)
|
||||
&& this.getContentType(part.getPartName()) == null)
|
||||
throw new InvalidOperationException(
|
||||
"Rule M2.4 is not respected: Nor a default element or override element is associated with the part: "
|
||||
+ part.getPartName().getName());
|
||||
}
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new InvalidOperationException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Override content type */
|
||||
if (this.overrideContentType != null
|
||||
&& (this.overrideContentType.get(partName) != null)) {
|
||||
// Remove the override definition for the specified part.
|
||||
this.overrideContentType.remove(partName);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specified content type is already register.
|
||||
*
|
||||
* @param contentType
|
||||
* The content type to check.
|
||||
* @return <code>true</code> if the specified content type is already
|
||||
* register, then <code>false</code>.
|
||||
*/
|
||||
public boolean isContentTypeRegister(String contentType) {
|
||||
if (contentType == null)
|
||||
throw new IllegalArgumentException("contentType");
|
||||
/* Default content type */
|
||||
String extensionToDelete = partName.getExtension();
|
||||
boolean deleteDefaultContentTypeFlag = true;
|
||||
if (this.container != null) {
|
||||
try {
|
||||
for (PackagePart part : this.container.getParts()) {
|
||||
if (!part.getPartName().equals(partName)
|
||||
&& part.getPartName().getExtension()
|
||||
.equalsIgnoreCase(extensionToDelete)) {
|
||||
deleteDefaultContentTypeFlag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new InvalidOperationException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return (this.defaultContentType.values().contains(contentType) || (this.overrideContentType != null && this.overrideContentType
|
||||
.values().contains(contentType)));
|
||||
}
|
||||
// Remove the default content type, no other part use this content type.
|
||||
if (deleteDefaultContentTypeFlag) {
|
||||
this.defaultContentType.remove(extensionToDelete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content type for the specified part, if any.
|
||||
* <p>
|
||||
* Rule [M2.9]: To get the content type of a part, the package implementer
|
||||
* shall perform the steps described in §9.1.2.4:
|
||||
* </p><p>
|
||||
* 1. Compare the part name with the values specified for the PartName
|
||||
* attribute of the Override elements. The comparison shall be
|
||||
* case-insensitive ASCII.
|
||||
* </p><p>
|
||||
* 2. If there is an Override element with a matching PartName attribute,
|
||||
* return the value of its ContentType attribute. No further action is
|
||||
* required.
|
||||
* </p><p>
|
||||
* 3. If there is no Override element with a matching PartName attribute,
|
||||
* then a. Get the extension from the part name by taking the substring to
|
||||
* the right of the rightmost occurrence of the dot character (.) from the
|
||||
* rightmost segment. b. Check the Default elements of the Content Types
|
||||
* stream, comparing the extension with the value of the Extension
|
||||
* attribute. The comparison shall be case-insensitive ASCII.
|
||||
* </p><p>
|
||||
* 4. If there is a Default element with a matching Extension attribute,
|
||||
* return the value of its ContentType attribute. No further action is
|
||||
* required.
|
||||
* </p><p>
|
||||
* 5. If neither Override nor Default elements with matching attributes are
|
||||
* found for the specified part name, the implementation shall not map this
|
||||
* part name to a part.
|
||||
* </p>
|
||||
* @param partName
|
||||
* The URI part to check.
|
||||
* @return The content type associated with the URI (in case of an override
|
||||
* content type) or the extension (in case of default content type),
|
||||
* else <code>null</code>.
|
||||
*
|
||||
* @exception OpenXML4JRuntimeException
|
||||
* Throws if the content type manager is not able to find the
|
||||
* content from an existing part.
|
||||
*/
|
||||
public String getContentType(PackagePartName partName) {
|
||||
if (partName == null)
|
||||
throw new IllegalArgumentException("partName");
|
||||
/*
|
||||
* Check rule 2.4: The package implementer shall require that the
|
||||
* Content Types stream contain one of the following for every part in
|
||||
* the package: One matching Default element One matching Override
|
||||
* element Both a matching Default element and a matching Override
|
||||
* element, in which case the Override element takes precedence.
|
||||
*/
|
||||
if (this.container != null) {
|
||||
try {
|
||||
for (PackagePart part : this.container.getParts()) {
|
||||
if (!part.getPartName().equals(partName)
|
||||
&& this.getContentType(part.getPartName()) == null)
|
||||
throw new InvalidOperationException(
|
||||
"Rule M2.4 is not respected: Nor a default element or override element is associated with the part: "
|
||||
+ part.getPartName().getName());
|
||||
}
|
||||
} catch (InvalidFormatException e) {
|
||||
throw new InvalidOperationException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((this.overrideContentType != null)
|
||||
&& this.overrideContentType.containsKey(partName))
|
||||
return this.overrideContentType.get(partName);
|
||||
/**
|
||||
* Check if the specified content type is already register.
|
||||
*
|
||||
* @param contentType
|
||||
* The content type to check.
|
||||
* @return <code>true</code> if the specified content type is already
|
||||
* register, then <code>false</code>.
|
||||
*/
|
||||
public boolean isContentTypeRegister(String contentType) {
|
||||
if (contentType == null)
|
||||
throw new IllegalArgumentException("contentType");
|
||||
|
||||
String extension = partName.getExtension().toLowerCase(Locale.ROOT);
|
||||
if (this.defaultContentType.containsKey(extension))
|
||||
return this.defaultContentType.get(extension);
|
||||
return (this.defaultContentType.values().contains(contentType) || (this.overrideContentType != null && this.overrideContentType
|
||||
.values().contains(contentType)));
|
||||
}
|
||||
|
||||
/*
|
||||
* [M2.4] : The package implementer shall require that the Content Types
|
||||
* stream contain one of the following for every part in the package:
|
||||
* One matching Default element, One matching Override element, Both a
|
||||
* matching Default element and a matching Override element, in which
|
||||
* case the Override element takes precedence.
|
||||
*/
|
||||
if (this.container != null && this.container.getPart(partName) != null) {
|
||||
throw new OpenXML4JRuntimeException(
|
||||
"Rule M2.4 exception : this error should NEVER happen! If you can provide the triggering file, then please raise a bug at https://bz.apache.org/bugzilla/enter_bug.cgi?product=POI and attach the file that triggers it, thanks!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Get the content type for the specified part, if any.
|
||||
* <p>
|
||||
* Rule [M2.9]: To get the content type of a part, the package implementer
|
||||
* shall perform the steps described in §9.1.2.4:
|
||||
* </p><p>
|
||||
* 1. Compare the part name with the values specified for the PartName
|
||||
* attribute of the Override elements. The comparison shall be
|
||||
* case-insensitive ASCII.
|
||||
* </p><p>
|
||||
* 2. If there is an Override element with a matching PartName attribute,
|
||||
* return the value of its ContentType attribute. No further action is
|
||||
* required.
|
||||
* </p><p>
|
||||
* 3. If there is no Override element with a matching PartName attribute,
|
||||
* then a. Get the extension from the part name by taking the substring to
|
||||
* the right of the rightmost occurrence of the dot character (.) from the
|
||||
* rightmost segment. b. Check the Default elements of the Content Types
|
||||
* stream, comparing the extension with the value of the Extension
|
||||
* attribute. The comparison shall be case-insensitive ASCII.
|
||||
* </p><p>
|
||||
* 4. If there is a Default element with a matching Extension attribute,
|
||||
* return the value of its ContentType attribute. No further action is
|
||||
* required.
|
||||
* </p><p>
|
||||
* 5. If neither Override nor Default elements with matching attributes are
|
||||
* found for the specified part name, the implementation shall not map this
|
||||
* part name to a part.
|
||||
* </p>
|
||||
* @param partName
|
||||
* The URI part to check.
|
||||
* @return The content type associated with the URI (in case of an override
|
||||
* content type) or the extension (in case of default content type),
|
||||
* else <code>null</code>.
|
||||
*
|
||||
* @exception OpenXML4JRuntimeException
|
||||
* Throws if the content type manager is not able to find the
|
||||
* content from an existing part.
|
||||
*/
|
||||
public String getContentType(PackagePartName partName) {
|
||||
if (partName == null)
|
||||
throw new IllegalArgumentException("partName");
|
||||
|
||||
/**
|
||||
* Clear all content types.
|
||||
*/
|
||||
public void clearAll() {
|
||||
this.defaultContentType.clear();
|
||||
if (this.overrideContentType != null)
|
||||
this.overrideContentType.clear();
|
||||
}
|
||||
if ((this.overrideContentType != null)
|
||||
&& this.overrideContentType.containsKey(partName))
|
||||
return this.overrideContentType.get(partName);
|
||||
|
||||
/**
|
||||
* Clear all override content types.
|
||||
*
|
||||
*/
|
||||
public void clearOverrideContentTypes() {
|
||||
if (this.overrideContentType != null)
|
||||
this.overrideContentType.clear();
|
||||
}
|
||||
String extension = partName.getExtension().toLowerCase(Locale.ROOT);
|
||||
if (this.defaultContentType.containsKey(extension))
|
||||
return this.defaultContentType.get(extension);
|
||||
|
||||
/**
|
||||
* Parse the content types part.
|
||||
*
|
||||
* @throws InvalidFormatException
|
||||
* Throws if the content type doesn't exist or the XML format is
|
||||
* invalid.
|
||||
*/
|
||||
private void parseContentTypesFile(InputStream in)
|
||||
throws InvalidFormatException {
|
||||
try {
|
||||
Document xmlContentTypetDoc = DocumentHelper.readDocument(in);
|
||||
/*
|
||||
* [M2.4] : The package implementer shall require that the Content Types
|
||||
* stream contain one of the following for every part in the package:
|
||||
* One matching Default element, One matching Override element, Both a
|
||||
* matching Default element and a matching Override element, in which
|
||||
* case the Override element takes precedence.
|
||||
*/
|
||||
if (this.container != null && this.container.getPart(partName) != null) {
|
||||
throw new OpenXML4JRuntimeException(
|
||||
"Rule M2.4 exception : Part \'" + partName +
|
||||
"\' not found - this error should NEVER happen! If you can provide the triggering file, then please raise a bug at https://bz.apache.org/bugzilla/enter_bug.cgi?product=POI and attach the file that triggers it, thanks!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Default content types
|
||||
NodeList defaultTypes = xmlContentTypetDoc.getDocumentElement().getElementsByTagNameNS(TYPES_NAMESPACE_URI, DEFAULT_TAG_NAME);
|
||||
int defaultTypeCount = defaultTypes.getLength();
|
||||
for (int i = 0; i < defaultTypeCount; i++) {
|
||||
/**
|
||||
* Clear all content types.
|
||||
*/
|
||||
public void clearAll() {
|
||||
this.defaultContentType.clear();
|
||||
if (this.overrideContentType != null)
|
||||
this.overrideContentType.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all override content types.
|
||||
*
|
||||
*/
|
||||
public void clearOverrideContentTypes() {
|
||||
if (this.overrideContentType != null)
|
||||
this.overrideContentType.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the content types part.
|
||||
*
|
||||
* @throws InvalidFormatException
|
||||
* Throws if the content type doesn't exist or the XML format is
|
||||
* invalid.
|
||||
*/
|
||||
private void parseContentTypesFile(InputStream in)
|
||||
throws InvalidFormatException {
|
||||
try {
|
||||
Document xmlContentTypetDoc = DocumentHelper.readDocument(in);
|
||||
|
||||
// Default content types
|
||||
NodeList defaultTypes = xmlContentTypetDoc.getDocumentElement().getElementsByTagNameNS(TYPES_NAMESPACE_URI, DEFAULT_TAG_NAME);
|
||||
int defaultTypeCount = defaultTypes.getLength();
|
||||
for (int i = 0; i < defaultTypeCount; i++) {
|
||||
Element element = (Element) defaultTypes.item(i);
|
||||
String extension = element.getAttribute(EXTENSION_ATTRIBUTE_NAME);
|
||||
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
|
||||
addDefaultContentType(extension, contentType);
|
||||
}
|
||||
String extension = element.getAttribute(EXTENSION_ATTRIBUTE_NAME);
|
||||
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
|
||||
addDefaultContentType(extension, contentType);
|
||||
}
|
||||
|
||||
// Overriden content types
|
||||
// Overriden content types
|
||||
NodeList overrideTypes = xmlContentTypetDoc.getDocumentElement().getElementsByTagNameNS(TYPES_NAMESPACE_URI, OVERRIDE_TAG_NAME);
|
||||
int overrideTypeCount = overrideTypes.getLength();
|
||||
for (int i = 0; i < overrideTypeCount; i++) {
|
||||
Element element = (Element) overrideTypes.item(i);
|
||||
URI uri = new URI(element.getAttribute(PART_NAME_ATTRIBUTE_NAME));
|
||||
PackagePartName partName = PackagingURIHelper.createPartName(uri);
|
||||
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
|
||||
addOverrideContentType(partName, contentType);
|
||||
}
|
||||
} catch (URISyntaxException | IOException | SAXException e) {
|
||||
throw new InvalidFormatException(e.getMessage());
|
||||
Element element = (Element) overrideTypes.item(i);
|
||||
URI uri = new URI(element.getAttribute(PART_NAME_ATTRIBUTE_NAME));
|
||||
PackagePartName partName = PackagingURIHelper.createPartName(uri);
|
||||
String contentType = element.getAttribute(CONTENT_TYPE_ATTRIBUTE_NAME);
|
||||
addOverrideContentType(partName, contentType);
|
||||
}
|
||||
} catch (URISyntaxException | IOException | SAXException e) {
|
||||
throw new InvalidFormatException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the contents type part.
|
||||
*
|
||||
* @param outStream
|
||||
* The output stream use to save the XML content of the content
|
||||
* types part.
|
||||
* @return <b>true</b> if the operation success, else <b>false</b>.
|
||||
*/
|
||||
public boolean save(OutputStream outStream) {
|
||||
Document xmlOutDoc = DocumentHelper.createDocument();
|
||||
/**
|
||||
* Save the contents type part.
|
||||
*
|
||||
* @param outStream
|
||||
* The output stream use to save the XML content of the content
|
||||
* types part.
|
||||
* @return <b>true</b> if the operation success, else <b>false</b>.
|
||||
*/
|
||||
public boolean save(OutputStream outStream) {
|
||||
Document xmlOutDoc = DocumentHelper.createDocument();
|
||||
|
||||
// Building namespace
|
||||
Element typesElem = xmlOutDoc.createElementNS(TYPES_NAMESPACE_URI, TYPES_TAG_NAME);
|
||||
// Building namespace
|
||||
Element typesElem = xmlOutDoc.createElementNS(TYPES_NAMESPACE_URI, TYPES_TAG_NAME);
|
||||
xmlOutDoc.appendChild(typesElem);
|
||||
|
||||
// Adding default types
|
||||
for (Entry<String, String> entry : defaultContentType.entrySet()) {
|
||||
appendDefaultType(typesElem, entry);
|
||||
}
|
||||
// Adding default types
|
||||
for (Entry<String, String> entry : defaultContentType.entrySet()) {
|
||||
appendDefaultType(typesElem, entry);
|
||||
}
|
||||
|
||||
// Adding specific types if any exist
|
||||
if (overrideContentType != null) {
|
||||
for (Entry<PackagePartName, String> entry : overrideContentType
|
||||
.entrySet()) {
|
||||
appendSpecificTypes(typesElem, entry);
|
||||
}
|
||||
}
|
||||
xmlOutDoc.normalize();
|
||||
// Adding specific types if any exist
|
||||
if (overrideContentType != null) {
|
||||
for (Entry<PackagePartName, String> entry : overrideContentType
|
||||
.entrySet()) {
|
||||
appendSpecificTypes(typesElem, entry);
|
||||
}
|
||||
}
|
||||
xmlOutDoc.normalize();
|
||||
|
||||
// Save content in the specified output stream
|
||||
return this.saveImpl(xmlOutDoc, outStream);
|
||||
}
|
||||
// Save content in the specified output stream
|
||||
return this.saveImpl(xmlOutDoc, outStream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to append specific type XML elements, use by the save() method.
|
||||
*
|
||||
* @param root
|
||||
* XML parent element use to append this override type element.
|
||||
* @param entry
|
||||
* The values to append.
|
||||
* @see #save(java.io.OutputStream)
|
||||
*/
|
||||
private void appendSpecificTypes(Element root,
|
||||
Entry<PackagePartName, String> entry) {
|
||||
/**
|
||||
* Use to append specific type XML elements, use by the save() method.
|
||||
*
|
||||
* @param root
|
||||
* XML parent element use to append this override type element.
|
||||
* @param entry
|
||||
* The values to append.
|
||||
* @see #save(java.io.OutputStream)
|
||||
*/
|
||||
private void appendSpecificTypes(Element root,
|
||||
Entry<PackagePartName, String> entry) {
|
||||
Element specificType = root.getOwnerDocument().createElementNS(TYPES_NAMESPACE_URI, OVERRIDE_TAG_NAME);
|
||||
specificType.setAttribute(PART_NAME_ATTRIBUTE_NAME, entry.getKey().getName());
|
||||
specificType.setAttribute(CONTENT_TYPE_ATTRIBUTE_NAME, entry.getValue());
|
||||
root.appendChild(specificType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use to append default types XML elements, use by the save() method.
|
||||
*
|
||||
* @param root
|
||||
* XML parent element use to append this default type element.
|
||||
* @param entry
|
||||
* The values to append.
|
||||
* @see #save(java.io.OutputStream)
|
||||
*/
|
||||
private void appendDefaultType(Element root, Entry<String, String> entry) {
|
||||
/**
|
||||
* Use to append default types XML elements, use by the save() method.
|
||||
*
|
||||
* @param root
|
||||
* XML parent element use to append this default type element.
|
||||
* @param entry
|
||||
* The values to append.
|
||||
* @see #save(java.io.OutputStream)
|
||||
*/
|
||||
private void appendDefaultType(Element root, Entry<String, String> entry) {
|
||||
Element defaultType = root.getOwnerDocument().createElementNS(TYPES_NAMESPACE_URI, DEFAULT_TAG_NAME);
|
||||
defaultType.setAttribute(EXTENSION_ATTRIBUTE_NAME, entry.getKey());
|
||||
defaultType.setAttribute(CONTENT_TYPE_ATTRIBUTE_NAME, entry.getValue());
|
||||
root.appendChild(defaultType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific implementation of the save method. Call by the save() method,
|
||||
* call before exiting.
|
||||
*
|
||||
* @param out
|
||||
* The output stream use to write the content type XML.
|
||||
*/
|
||||
public abstract boolean saveImpl(Document content, OutputStream out);
|
||||
/**
|
||||
* Specific implementation of the save method. Call by the save() method,
|
||||
* call before exiting.
|
||||
*
|
||||
* @param out
|
||||
* The output stream use to write the content type XML.
|
||||
*/
|
||||
public abstract boolean saveImpl(Document content, OutputStream out);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user