You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ZipPartMarshaller.java 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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.zip.ZipEntry;
  21. import java.util.zip.ZipOutputStream;
  22. import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
  23. import org.apache.poi.openxml4j.opc.PackageNamespaces;
  24. import org.apache.poi.openxml4j.opc.PackagePart;
  25. import org.apache.poi.openxml4j.opc.PackagePartName;
  26. import org.apache.poi.openxml4j.opc.PackageRelationship;
  27. import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
  28. import org.apache.poi.openxml4j.opc.PackagingURIHelper;
  29. import org.apache.poi.openxml4j.opc.StreamHelper;
  30. import org.apache.poi.openxml4j.opc.TargetMode;
  31. import org.apache.poi.openxml4j.opc.internal.PartMarshaller;
  32. import org.apache.poi.openxml4j.opc.internal.ZipHelper;
  33. import org.apache.poi.util.DocumentHelper;
  34. import org.apache.poi.util.POILogFactory;
  35. import org.apache.poi.util.POILogger;
  36. import org.apache.poi.xssf.usermodel.XSSFRelation;
  37. import org.w3c.dom.Document;
  38. import org.w3c.dom.Element;
  39. /**
  40. * Zip part marshaller. This marshaller is use to save any part in a zip stream.
  41. *
  42. * @author Julien Chable
  43. */
  44. public final class ZipPartMarshaller implements PartMarshaller {
  45. private static POILogger logger = POILogFactory.getLogger(ZipPartMarshaller.class);
  46. /**
  47. * Save the specified part.
  48. *
  49. * @throws OpenXML4JException
  50. * Throws if an internal exception is thrown.
  51. */
  52. public boolean marshall(PackagePart part, OutputStream os)
  53. throws OpenXML4JException {
  54. if (!(os instanceof ZipOutputStream)) {
  55. logger.log(POILogger.ERROR,"Unexpected class " + os.getClass().getName());
  56. throw new OpenXML4JException("ZipOutputStream expected !");
  57. // Normally should happen only in developement phase, so just throw
  58. // exception
  59. }
  60. // check if there is anything to save for some parts. We don't do this for all parts as some code
  61. // might depend on empty parts being saved, e.g. some unit tests verify this currently.
  62. if(part.getSize() == 0 && part.getPartName().getName().equals(XSSFRelation.SHARED_STRINGS.getDefaultFileName())) {
  63. return true;
  64. }
  65. ZipOutputStream zos = (ZipOutputStream) os;
  66. ZipEntry partEntry = new ZipEntry(ZipHelper
  67. .getZipItemNameFromOPCName(part.getPartName().getURI()
  68. .getPath()));
  69. try {
  70. // Create next zip entry
  71. zos.putNextEntry(partEntry);
  72. // Saving data in the ZIP file
  73. InputStream ins = part.getInputStream();
  74. byte[] buff = new byte[ZipHelper.READ_WRITE_FILE_BUFFER_SIZE];
  75. while (ins.available() > 0) {
  76. int resultRead = ins.read(buff);
  77. if (resultRead == -1) {
  78. // End of file reached
  79. break;
  80. }
  81. zos.write(buff, 0, resultRead);
  82. }
  83. zos.closeEntry();
  84. } catch (IOException ioe) {
  85. logger.log(POILogger.ERROR,"Cannot write: " + part.getPartName() + ": in ZIP",
  86. ioe);
  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. */
  109. public static boolean marshallRelationshipPart(
  110. PackageRelationshipCollection rels, PackagePartName relPartName,
  111. ZipOutputStream zos) {
  112. // Building xml
  113. Document xmlOutDoc = DocumentHelper.createDocument();
  114. // make something like <Relationships
  115. // xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  116. Element root = xmlOutDoc.createElementNS(PackageNamespaces.RELATIONSHIPS, PackageRelationship.RELATIONSHIPS_TAG_NAME);
  117. xmlOutDoc.appendChild(root);
  118. // <Relationship
  119. // TargetMode="External"
  120. // Id="rIdx"
  121. // Target="http://www.custom.com/images/pic1.jpg"
  122. // Type="http://www.custom.com/external-resource"/>
  123. URI sourcePartURI = PackagingURIHelper
  124. .getSourcePartUriFromRelationshipPartUri(relPartName.getURI());
  125. for (PackageRelationship rel : rels) {
  126. // the relationship element
  127. Element relElem = xmlOutDoc.createElementNS(PackageNamespaces.RELATIONSHIPS, PackageRelationship.RELATIONSHIP_TAG_NAME);
  128. root.appendChild(relElem);
  129. // the relationship ID
  130. relElem.setAttribute(PackageRelationship.ID_ATTRIBUTE_NAME, rel.getId());
  131. // the relationship Type
  132. relElem.setAttribute(PackageRelationship.TYPE_ATTRIBUTE_NAME, rel.getRelationshipType());
  133. // the relationship Target
  134. String targetValue;
  135. URI uri = rel.getTargetURI();
  136. if (rel.getTargetMode() == TargetMode.EXTERNAL) {
  137. // Save the target as-is - we don't need to validate it,
  138. // alter it etc
  139. targetValue = uri.toString();
  140. // add TargetMode attribute (as it is external link external)
  141. relElem.setAttribute(PackageRelationship.TARGET_MODE_ATTRIBUTE_NAME, "External");
  142. } else {
  143. URI targetURI = rel.getTargetURI();
  144. targetValue = PackagingURIHelper.relativizeURI(
  145. sourcePartURI, targetURI, true).toString();
  146. }
  147. relElem.setAttribute(PackageRelationship.TARGET_ATTRIBUTE_NAME, targetValue);
  148. }
  149. xmlOutDoc.normalize();
  150. // String schemaFilename = Configuration.getPathForXmlSchema()+
  151. // File.separator + "opc-relationships.xsd";
  152. // Save part in zip
  153. ZipEntry ctEntry = new ZipEntry(ZipHelper.getZipURIFromOPCName(
  154. relPartName.getURI().toASCIIString()).getPath());
  155. try {
  156. zos.putNextEntry(ctEntry);
  157. if (!StreamHelper.saveXmlInStream(xmlOutDoc, zos)) {
  158. return false;
  159. }
  160. zos.closeEntry();
  161. } catch (IOException e) {
  162. logger.log(POILogger.ERROR,"Cannot create zip entry " + relPartName, e);
  163. return false;
  164. }
  165. return true; // success
  166. }
  167. }