Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

ZipPartMarshaller.java 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.openxml4j.opc.internal.marshallers;
  16. import java.io.IOException;
  17. import java.io.InputStream;
  18. import java.io.OutputStream;
  19. import java.net.URI;
  20. import java.util.Objects;
  21. import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
  22. import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
  23. import org.apache.logging.log4j.LogManager;
  24. import org.apache.logging.log4j.Logger;
  25. import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
  26. import org.apache.poi.openxml4j.opc.PackageNamespaces;
  27. import org.apache.poi.openxml4j.opc.PackagePart;
  28. import org.apache.poi.openxml4j.opc.PackagePartName;
  29. import org.apache.poi.openxml4j.opc.PackageRelationship;
  30. import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
  31. import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
  32. import org.apache.poi.openxml4j.opc.PackagingURIHelper;
  33. import org.apache.poi.openxml4j.opc.StreamHelper;
  34. import org.apache.poi.openxml4j.opc.TargetMode;
  35. import org.apache.poi.openxml4j.opc.internal.PartMarshaller;
  36. import org.apache.poi.openxml4j.opc.internal.ZipHelper;
  37. import org.apache.poi.ooxml.util.DocumentHelper;
  38. import org.apache.poi.util.IOUtils;
  39. import org.apache.poi.xssf.usermodel.XSSFRelation;
  40. import org.w3c.dom.Document;
  41. import org.w3c.dom.Element;
  42. /**
  43. * Zip part marshaller. This marshaller is use to save any part in a zip stream.
  44. */
  45. public final class ZipPartMarshaller implements PartMarshaller {
  46. private static final Logger LOG = LogManager.getLogger(ZipPartMarshaller.class);
  47. /**
  48. * Save the specified part to the given stream.
  49. *
  50. * @param part The {@link PackagePart} to save
  51. * @param os The stream to write the data to
  52. * @return true if saving was successful or there was nothing to save,
  53. * false if an error occurred.
  54. * In case of errors, logging via Log4j 2 is used to provide more information.
  55. * @throws OpenXML4JException
  56. * Throws if the stream cannot be written to or an internal exception is thrown.
  57. */
  58. @Override
  59. public boolean marshall(PackagePart part, OutputStream os)
  60. throws OpenXML4JException {
  61. if (!(os instanceof ZipArchiveOutputStream)) {
  62. LOG.atError().log("Unexpected class {}", os.getClass().getName());
  63. throw new OpenXML4JException("ZipOutputStream expected !");
  64. // Normally should happen only in development phase, so just throw
  65. // exception
  66. }
  67. // check if there is anything to save for some parts. We don't do this for all parts as some code
  68. // might depend on empty parts being saved, e.g. some unit tests verify this currently.
  69. if(part.getSize() == 0 && part.getPartName().getName().equals(XSSFRelation.SHARED_STRINGS.getDefaultFileName())) {
  70. return true;
  71. }
  72. ZipArchiveOutputStream zos = (ZipArchiveOutputStream) os;
  73. ZipArchiveEntry partEntry = new ZipArchiveEntry(ZipHelper
  74. .getZipItemNameFromOPCName(part.getPartName().getURI()
  75. .getPath()));
  76. try {
  77. // Create next zip entry
  78. zos.putArchiveEntry(partEntry);
  79. // Saving data in the ZIP file
  80. try (final InputStream ins = part.getInputStream()) {
  81. IOUtils.copy(ins, zos);
  82. } finally {
  83. zos.closeArchiveEntry();
  84. }
  85. } catch (IOException ioe) {
  86. LOG.atError().withThrowable(ioe).log("Cannot write: {}: in ZIP", part.getPartName());
  87. return false;
  88. }
  89. // Saving relationship part
  90. if (part.hasRelationships()) {
  91. PackagePartName relationshipPartName = PackagingURIHelper
  92. .getRelationshipPartName(part.getPartName());
  93. marshallRelationshipPart(part.getRelationships(),
  94. relationshipPartName, zos);
  95. }
  96. return true;
  97. }
  98. /**
  99. * Save relationships into the part.
  100. *
  101. * @param rels
  102. * The relationships collection to marshall.
  103. * @param relPartName
  104. * Part name of the relationship part to marshall.
  105. * @param zos
  106. * Zip output stream in which to save the XML content of the
  107. * relationships serialization.
  108. * @return true if saving was successful,
  109. * false if an error occurred.
  110. * In case of errors, logging via Log4j 2 is used to provide more information.
  111. */
  112. public static boolean marshallRelationshipPart(
  113. PackageRelationshipCollection rels, PackagePartName relPartName,
  114. ZipArchiveOutputStream zos) {
  115. // Building xml
  116. Document xmlOutDoc = DocumentHelper.createDocument();
  117. // make something like <Relationships
  118. // xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  119. Element root = xmlOutDoc.createElementNS(PackageNamespaces.RELATIONSHIPS, PackageRelationship.RELATIONSHIPS_TAG_NAME);
  120. xmlOutDoc.appendChild(root);
  121. // <Relationship
  122. // TargetMode="External"
  123. // Id="rIdx"
  124. // Target="http://www.custom.com/images/pic1.jpg"
  125. // Type="http://www.custom.com/external-resource"/>
  126. URI sourcePartURI = PackagingURIHelper
  127. .getSourcePartUriFromRelationshipPartUri(relPartName.getURI());
  128. for (PackageRelationship rel : rels) {
  129. // the relationship element
  130. Element relElem = xmlOutDoc.createElementNS(PackageNamespaces.RELATIONSHIPS, PackageRelationship.RELATIONSHIP_TAG_NAME);
  131. root.appendChild(relElem);
  132. // the relationship ID
  133. relElem.setAttribute(PackageRelationship.ID_ATTRIBUTE_NAME, rel.getId());
  134. // the relationship Type
  135. relElem.setAttribute(PackageRelationship.TYPE_ATTRIBUTE_NAME, rel.getRelationshipType());
  136. // the relationship Target
  137. String targetValue;
  138. URI uri = rel.getTargetURI();
  139. if (Objects.equals(rel.getRelationshipType(), PackageRelationshipTypes.HYPERLINK_PART)) {
  140. // Save the target as-is - we don't need to validate it,
  141. targetValue = uri.toString();
  142. if (rel.getTargetMode() == TargetMode.EXTERNAL) {
  143. // add TargetMode attribute (as it is external link external)
  144. relElem.setAttribute(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME, "External");
  145. }
  146. } else if (rel.getTargetMode() == TargetMode.EXTERNAL) {
  147. // Save the target as-is - we don't need to validate it,
  148. // alter it etc
  149. targetValue = uri.toString();
  150. // add TargetMode attribute (as it is external link external)
  151. relElem.setAttribute(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME, "External");
  152. } else {
  153. URI targetURI = rel.getTargetURI();
  154. targetValue = PackagingURIHelper.relativizeURI(
  155. sourcePartURI, targetURI, true).toString();
  156. }
  157. relElem.setAttribute(PackageRelationship.TARGET_ATTRIBUTE_NAME, targetValue);
  158. }
  159. xmlOutDoc.normalize();
  160. // String schemaFilename = Configuration.getPathForXmlSchema()+
  161. // File.separator + "opc-relationships.xsd";
  162. // Save part in zip
  163. ZipArchiveEntry ctEntry = new ZipArchiveEntry(ZipHelper.getZipURIFromOPCName(
  164. relPartName.getURI().toASCIIString()).getPath());
  165. try {
  166. zos.putArchiveEntry(ctEntry);
  167. try {
  168. return StreamHelper.saveXmlInStream(xmlOutDoc, zos);
  169. } finally {
  170. zos.closeArchiveEntry();
  171. }
  172. } catch (IOException e) {
  173. LOG.atError().withThrowable(e).log("Cannot create zip entry {}", relPartName);
  174. return false;
  175. }
  176. }
  177. }