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