a .NET library that can read/write Office formats without Microsoft Office installed. No COM+, no interop.
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.

220 lines
7.1 KiB

  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. namespace NPOI
  16. {
  17. using System;
  18. using NPOI.POIFS.Common;
  19. using NPOI.Util;
  20. using NPOI.OpenXml4Net.Exceptions;
  21. using System.IO;
  22. using NPOI.OpenXml4Net.OPC;
  23. using System.Collections.Generic;
  24. using NPOI.OpenXml4Net;
  25. using System.Reflection;
  26. using NPOI.POIFS.FileSystem;
  27. public abstract class POIXMLDocument : POIXMLDocumentPart, ICloseable
  28. {
  29. public static String DOCUMENT_CREATOR = "NPOI";
  30. // OLE embeddings relation name
  31. public static String OLE_OBJECT_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
  32. // Embedded OPC documents relation name
  33. public static String PACK_OBJECT_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
  34. /** The OPC Package */
  35. private OPCPackage pkg;
  36. /**
  37. * The properties of the OPC namespace, opened as needed
  38. */
  39. private POIXMLProperties properties;
  40. protected POIXMLDocument(OPCPackage pkg)
  41. : base(pkg)
  42. {
  43. init(pkg);
  44. }
  45. protected POIXMLDocument(OPCPackage pkg, String coreDocumentRel)
  46. : base(pkg, coreDocumentRel)
  47. {
  48. init(pkg);
  49. }
  50. private void init(OPCPackage pkg)
  51. {
  52. this.pkg = pkg;
  53. }
  54. /**
  55. * Wrapper to open a namespace, returning an IOException
  56. * in the event of a problem.
  57. * Works around shortcomings in java's this() constructor calls
  58. */
  59. public static OPCPackage OpenPackage(String path, bool readOnly = false)
  60. {
  61. try
  62. {
  63. return OPCPackage.Open(path, readOnly ? PackageAccess.READ: PackageAccess.READ_WRITE);
  64. }
  65. catch (InvalidFormatException e)
  66. {
  67. throw new IOException(e.ToString());
  68. }
  69. }
  70. public OPCPackage Package
  71. {
  72. get
  73. {
  74. return this.pkg;
  75. }
  76. }
  77. protected PackagePart CorePart
  78. {
  79. get
  80. {
  81. return GetPackagePart();
  82. }
  83. }
  84. /**
  85. * Retrieves all the PackageParts which are defined as
  86. * relationships of the base document with the
  87. * specified content type.
  88. */
  89. protected PackagePart[] GetRelatedByType(String contentType)
  90. {
  91. PackageRelationshipCollection partsC =
  92. GetPackagePart().GetRelationshipsByType(contentType);
  93. PackagePart[] parts = new PackagePart[partsC.Size];
  94. int count = 0;
  95. foreach (PackageRelationship rel in partsC)
  96. {
  97. parts[count] = GetPackagePart().GetRelatedPart(rel);
  98. count++;
  99. }
  100. return parts;
  101. }
  102. /**
  103. * Get the document properties. This gives you access to the
  104. * core ooxml properties, and the extended ooxml properties.
  105. */
  106. public POIXMLProperties GetProperties()
  107. {
  108. if (properties == null)
  109. {
  110. try
  111. {
  112. properties = new POIXMLProperties(pkg);
  113. }
  114. catch (Exception e)
  115. {
  116. throw new POIXMLException(e);
  117. }
  118. }
  119. return properties;
  120. }
  121. /**
  122. * Get the document's embedded files.
  123. */
  124. public abstract List<PackagePart> GetAllEmbedds();
  125. protected void Load(POIXMLFactory factory)
  126. {
  127. Dictionary<PackagePart, POIXMLDocumentPart> context = new Dictionary<PackagePart, POIXMLDocumentPart>();
  128. try
  129. {
  130. Read(factory, context);
  131. }
  132. catch (OpenXml4NetException e)
  133. {
  134. throw new POIXMLException(e);
  135. }
  136. OnDocumentRead();
  137. context.Clear();
  138. }
  139. /**
  140. * Closes the underlying {@link OPCPackage} from which this
  141. * document was read, if there is one
  142. */
  143. public void Close()
  144. {
  145. if (pkg != null)
  146. {
  147. if (pkg.GetPackageAccess() == PackageAccess.READ)
  148. {
  149. pkg.Revert();
  150. }
  151. else
  152. {
  153. pkg.Close();
  154. }
  155. pkg = null;
  156. }
  157. }
  158. /**
  159. * Write out this document to an Outputstream.
  160. *
  161. * Note - if the Document was opened from a {@link File} rather
  162. * than an {@link InputStream}, you <b>must</b> write out to
  163. * a different file, overwriting via an OutputStream isn't possible.
  164. *
  165. * If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
  166. * or has a high cost/latency associated with each written byte,
  167. * consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
  168. * to improve write performance.
  169. *
  170. * @param stream - the java Stream you wish to write the file to
  171. *
  172. * @exception IOException if anything can't be written.
  173. */
  174. public void Write(Stream stream)
  175. {
  176. OPCPackage pkg = Package;
  177. if (pkg == null)
  178. {
  179. throw new IOException("Cannot write data, document seems to have been closed already");
  180. }
  181. if (!this.GetProperties().CustomProperties.Contains("Generator"))
  182. this.GetProperties().CustomProperties.AddProperty("Generator", "NPOI");
  183. if (!this.GetProperties().CustomProperties.Contains("Generator Version"))
  184. this.GetProperties().CustomProperties.AddProperty("Generator Version", Assembly.GetExecutingAssembly().GetName().Version.ToString(3));
  185. //force all children to commit their Changes into the underlying OOXML Package
  186. List<PackagePart> context = new List<PackagePart>();
  187. OnSave(context);
  188. context.Clear();
  189. //save extended and custom properties
  190. GetProperties().Commit();
  191. pkg.Save(stream);
  192. }
  193. }
  194. }