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.

235 lines
7.7 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)
  60. {
  61. try
  62. {
  63. return OPCPackage.Open(path);
  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. * Checks that the supplied Stream (which MUST
  104. * support mark and reSet, or be a PushbackStream)
  105. * has a OOXML (zip) header at the start of it.
  106. * If your Stream does not support mark / reSet,
  107. * then wrap it in a PushBackStream, then be
  108. * sure to always use that, and not the original!
  109. * @param inp An Stream which supports either mark/reSet, or is a PushbackStream
  110. */
  111. [Obsolete("Use the method from DocumentFactoryHelper")]
  112. public static bool HasOOXMLHeader(Stream inp)
  113. {
  114. return DocumentFactoryHelper.HasOOXMLHeader(inp);
  115. }
  116. /**
  117. * Get the document properties. This gives you access to the
  118. * core ooxml properties, and the extended ooxml properties.
  119. */
  120. public POIXMLProperties GetProperties()
  121. {
  122. if (properties == null)
  123. {
  124. try
  125. {
  126. properties = new POIXMLProperties(pkg);
  127. }
  128. catch (Exception e)
  129. {
  130. throw new POIXMLException(e);
  131. }
  132. }
  133. return properties;
  134. }
  135. /**
  136. * Get the document's embedded files.
  137. */
  138. public abstract List<PackagePart> GetAllEmbedds();
  139. protected void Load(POIXMLFactory factory)
  140. {
  141. Dictionary<PackagePart, POIXMLDocumentPart> context = new Dictionary<PackagePart, POIXMLDocumentPart>();
  142. try
  143. {
  144. Read(factory, context);
  145. }
  146. catch (OpenXml4NetException e)
  147. {
  148. throw new POIXMLException(e);
  149. }
  150. OnDocumentRead();
  151. context.Clear();
  152. }
  153. /**
  154. * Closes the underlying {@link OPCPackage} from which this
  155. * document was read, if there is one
  156. */
  157. public void Close()
  158. {
  159. if (pkg != null)
  160. {
  161. if (pkg.GetPackageAccess() == PackageAccess.READ)
  162. {
  163. pkg.Revert();
  164. }
  165. else
  166. {
  167. pkg.Close();
  168. }
  169. pkg = null;
  170. }
  171. }
  172. /**
  173. * Write out this document to an Outputstream.
  174. *
  175. * Note - if the Document was opened from a {@link File} rather
  176. * than an {@link InputStream}, you <b>must</b> write out to
  177. * a different file, overwriting via an OutputStream isn't possible.
  178. *
  179. * If {@code stream} is a {@link java.io.FileOutputStream} on a networked drive
  180. * or has a high cost/latency associated with each written byte,
  181. * consider wrapping the OutputStream in a {@link java.io.BufferedOutputStream}
  182. * to improve write performance.
  183. *
  184. * @param stream - the java Stream you wish to write the file to
  185. *
  186. * @exception IOException if anything can't be written.
  187. */
  188. public void Write(Stream stream)
  189. {
  190. OPCPackage pkg = Package;
  191. if (pkg == null)
  192. {
  193. throw new IOException("Cannot write data, document seems to have been closed already");
  194. }
  195. if (!this.GetProperties().CustomProperties.Contains("Generator"))
  196. this.GetProperties().CustomProperties.AddProperty("Generator", "NPOI");
  197. if (!this.GetProperties().CustomProperties.Contains("Generator Version"))
  198. this.GetProperties().CustomProperties.AddProperty("Generator Version", Assembly.GetExecutingAssembly().GetName().Version.ToString(3));
  199. //force all children to commit their Changes into the underlying OOXML Package
  200. List<PackagePart> context = new List<PackagePart>();
  201. OnSave(context);
  202. context.Clear();
  203. //save extended and custom properties
  204. GetProperties().Commit();
  205. pkg.Save(stream);
  206. }
  207. }
  208. }