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.

POIFSReader.java 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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.poifs.eventfilesystem;
  16. import java.io.File;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import org.apache.poi.poifs.filesystem.DocumentInputStream;
  20. import org.apache.poi.poifs.filesystem.POIFSDocument;
  21. import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
  22. import org.apache.poi.poifs.filesystem.POIFSFileSystem;
  23. import org.apache.poi.poifs.property.DirectoryProperty;
  24. import org.apache.poi.poifs.property.DocumentProperty;
  25. import org.apache.poi.poifs.property.Property;
  26. import org.apache.poi.poifs.property.PropertyTable;
  27. import org.apache.poi.poifs.property.RootProperty;
  28. import org.apache.poi.util.IOUtils;
  29. /**
  30. * An event-driven reader for POIFS file systems. Users of this class
  31. * first create an instance of it, then use the registerListener
  32. * methods to register POIFSReaderListener instances for specific
  33. * documents. Once all the listeners have been registered, the read()
  34. * method is called, which results in the listeners being notified as
  35. * their documents are read.
  36. */
  37. public class POIFSReader
  38. {
  39. private final POIFSReaderRegistry registry = new POIFSReaderRegistry();
  40. private boolean registryClosed = false;
  41. private boolean notifyEmptyDirectories;
  42. // private NPOIFSFileSystem poifs;
  43. /**
  44. * Read from an InputStream and process the documents we get
  45. *
  46. * @param stream the InputStream from which to read the data
  47. *
  48. * @throws IOException on errors reading, or on invalid data
  49. */
  50. public void read(final InputStream stream) throws IOException {
  51. try (POIFSFileSystem poifs = new POIFSFileSystem(stream)) {
  52. read(poifs);
  53. }
  54. }
  55. /**
  56. * Read from a File and process the documents we get
  57. *
  58. * @param poifsFile the file from which to read the data
  59. *
  60. * @throws IOException on errors reading, or on invalid data
  61. */
  62. public void read(final File poifsFile) throws IOException {
  63. try (POIFSFileSystem poifs = new POIFSFileSystem(poifsFile, true)) {
  64. read(poifs);
  65. }
  66. }
  67. /**
  68. * Read from a {@link POIFSFileSystem} and process the documents we get
  69. *
  70. * @param poifs the POIFSFileSystem from which to read the data
  71. *
  72. * @throws IOException on errors reading, or on invalid data
  73. */
  74. public void read(final POIFSFileSystem poifs) throws IOException {
  75. registryClosed = true;
  76. // get property table from the document
  77. PropertyTable properties = poifs.getPropertyTable();
  78. // process documents
  79. RootProperty root = properties.getRoot();
  80. processProperties(poifs, root, new POIFSDocumentPath());
  81. }
  82. /**
  83. * Register a POIFSReaderListener for all documents
  84. *
  85. * @param listener the listener to be registered
  86. *
  87. * @throws NullPointerException if listener is null
  88. * @throws IllegalStateException if read() has already been
  89. * called
  90. */
  91. public void registerListener(final POIFSReaderListener listener) {
  92. if (listener == null) {
  93. throw new NullPointerException();
  94. }
  95. if (registryClosed) {
  96. throw new IllegalStateException();
  97. }
  98. registry.registerListener(listener);
  99. }
  100. /**
  101. * Register a POIFSReaderListener for a document in the root
  102. * directory
  103. *
  104. * @param listener the listener to be registered
  105. * @param name the document name
  106. *
  107. * @throws NullPointerException if listener is null or name is
  108. * null or empty
  109. * @throws IllegalStateException if read() has already been
  110. * called
  111. */
  112. public void registerListener(final POIFSReaderListener listener, final String name) {
  113. registerListener(listener, null, name);
  114. }
  115. /**
  116. * Register a POIFSReaderListener for a document in the specified
  117. * directory
  118. *
  119. * @param listener the listener to be registered
  120. * @param path the document path; if null, the root directory is
  121. * assumed
  122. * @param name the document name
  123. *
  124. * @throws NullPointerException if listener is null or name is
  125. * null or empty
  126. * @throws IllegalStateException if read() has already been
  127. * called
  128. */
  129. public void registerListener(final POIFSReaderListener listener,
  130. final POIFSDocumentPath path,
  131. final String name) {
  132. if ((listener == null) || (name == null) || (name.length() == 0)) {
  133. throw new NullPointerException();
  134. }
  135. if (registryClosed) {
  136. throw new IllegalStateException();
  137. }
  138. registry.registerListener(listener, (path == null) ? new POIFSDocumentPath() : path, name);
  139. }
  140. /**
  141. * Activates the notification of empty directories.<p>
  142. * If this flag is activated, the {@link POIFSReaderListener listener} receives
  143. * {@link POIFSReaderEvent POIFSReaderEvents} with nulled {@code name} and {@code stream}
  144. *
  145. * @param notifyEmptyDirectories if {@code true}, empty directories will be notified
  146. */
  147. public void setNotifyEmptyDirectories(boolean notifyEmptyDirectories) {
  148. this.notifyEmptyDirectories = notifyEmptyDirectories;
  149. }
  150. /**
  151. * read in files
  152. *
  153. * @param args names of the files
  154. *
  155. * @throws IOException if the files can't be read or have invalid content
  156. */
  157. public static void main(String[] args) throws IOException {
  158. if (args.length == 0) {
  159. System.err.println("at least one argument required: input filename(s)");
  160. System.exit(1);
  161. }
  162. // register for all
  163. for (String arg : args) {
  164. POIFSReader reader = new POIFSReader();
  165. reader.registerListener(POIFSReader::readEntry);
  166. System.out.println("reading " + arg);
  167. reader.read(new File(arg));
  168. }
  169. }
  170. private static void readEntry(POIFSReaderEvent event) {
  171. POIFSDocumentPath path = event.getPath();
  172. StringBuilder sb = new StringBuilder();
  173. try (DocumentInputStream istream = event.getStream()) {
  174. sb.setLength(0);
  175. int pathLength = path.length();
  176. for (int k = 0; k < pathLength; k++) {
  177. sb.append('/').append(path.getComponent(k));
  178. }
  179. byte[] data = IOUtils.toByteArray(istream);
  180. sb.append('/').append(event.getName()).append(": ").append(data.length).append(" bytes read");
  181. System.out.println(sb);
  182. } catch (IOException ignored) {
  183. }
  184. }
  185. private void processProperties(final POIFSFileSystem poifs, DirectoryProperty dir, final POIFSDocumentPath path) {
  186. boolean hasChildren = false;
  187. for (final Property property : dir) {
  188. hasChildren = true;
  189. String name = property.getName();
  190. if (property.isDirectory()) {
  191. POIFSDocumentPath new_path = new POIFSDocumentPath(path,new String[]{name});
  192. processProperties(poifs, (DirectoryProperty) property, new_path);
  193. } else {
  194. POIFSDocument document = null;
  195. for (POIFSReaderListener rl : registry.getListeners(path, name)) {
  196. if (document == null) {
  197. document = new POIFSDocument((DocumentProperty)property, poifs);
  198. }
  199. try (DocumentInputStream dis = new DocumentInputStream(document)) {
  200. POIFSReaderEvent pe = new POIFSReaderEvent(dis, path, name, dir.getStorageClsid());
  201. rl.processPOIFSReaderEvent(pe);
  202. }
  203. }
  204. }
  205. }
  206. if (hasChildren || !notifyEmptyDirectories) {
  207. return;
  208. }
  209. for (POIFSReaderListener rl : registry.getListeners(path, ".")) {
  210. POIFSReaderEvent pe = new POIFSReaderEvent(null, path, null, dir.getStorageClsid());
  211. rl.processPOIFSReaderEvent(pe);
  212. }
  213. }
  214. }