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 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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.*;
  17. import java.util.*;
  18. import org.apache.poi.poifs.filesystem.DocumentInputStream;
  19. import org.apache.poi.poifs.filesystem.POIFSDocument;
  20. import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
  21. import org.apache.poi.poifs.property.DirectoryProperty;
  22. import org.apache.poi.poifs.property.Property;
  23. import org.apache.poi.poifs.property.PropertyTable;
  24. import org.apache.poi.poifs.storage.BlockAllocationTableReader;
  25. import org.apache.poi.poifs.storage.BlockList;
  26. import org.apache.poi.poifs.storage.HeaderBlock;
  27. import org.apache.poi.poifs.storage.RawDataBlockList;
  28. import org.apache.poi.poifs.storage.SmallBlockTableReader;
  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. * @author Marc Johnson (mjohnson at apache dot org)
  38. */
  39. public class POIFSReader
  40. {
  41. private POIFSReaderRegistry registry;
  42. private boolean registryClosed;
  43. /**
  44. * Create a POIFSReader
  45. */
  46. public POIFSReader()
  47. {
  48. registry = new POIFSReaderRegistry();
  49. registryClosed = false;
  50. }
  51. /**
  52. * Read from an InputStream and process the documents we get
  53. *
  54. * @param stream the InputStream from which to read the data
  55. *
  56. * @exception IOException on errors reading, or on invalid data
  57. */
  58. public void read(final InputStream stream)
  59. throws IOException
  60. {
  61. registryClosed = true;
  62. // read the header block from the stream
  63. HeaderBlock header_block = new HeaderBlock(stream);
  64. // read the rest of the stream into blocks
  65. RawDataBlockList data_blocks = new RawDataBlockList(stream, header_block.getBigBlockSize());
  66. // set up the block allocation table (necessary for the
  67. // data_blocks to be manageable
  68. new BlockAllocationTableReader(header_block.getBigBlockSize(),
  69. header_block.getBATCount(),
  70. header_block.getBATArray(),
  71. header_block.getXBATCount(),
  72. header_block.getXBATIndex(),
  73. data_blocks);
  74. // get property table from the document
  75. PropertyTable properties =
  76. new PropertyTable(header_block, data_blocks);
  77. // process documents
  78. processProperties(SmallBlockTableReader
  79. .getSmallDocumentBlocks(
  80. header_block.getBigBlockSize(),
  81. data_blocks, properties.getRoot(),
  82. header_block.getSBATStart()),
  83. data_blocks, properties.getRoot()
  84. .getChildren(), new POIFSDocumentPath());
  85. }
  86. /**
  87. * Register a POIFSReaderListener for all documents
  88. *
  89. * @param listener the listener to be registered
  90. *
  91. * @exception NullPointerException if listener is null
  92. * @exception IllegalStateException if read() has already been
  93. * called
  94. */
  95. public void registerListener(final POIFSReaderListener listener)
  96. {
  97. if (listener == null)
  98. {
  99. throw new NullPointerException();
  100. }
  101. if (registryClosed)
  102. {
  103. throw new IllegalStateException();
  104. }
  105. registry.registerListener(listener);
  106. }
  107. /**
  108. * Register a POIFSReaderListener for a document in the root
  109. * directory
  110. *
  111. * @param listener the listener to be registered
  112. * @param name the document name
  113. *
  114. * @exception NullPointerException if listener is null or name is
  115. * null or empty
  116. * @exception IllegalStateException if read() has already been
  117. * called
  118. */
  119. public void registerListener(final POIFSReaderListener listener,
  120. final String name)
  121. {
  122. registerListener(listener, null, name);
  123. }
  124. /**
  125. * Register a POIFSReaderListener for a document in the specified
  126. * directory
  127. *
  128. * @param listener the listener to be registered
  129. * @param path the document path; if null, the root directory is
  130. * assumed
  131. * @param name the document name
  132. *
  133. * @exception NullPointerException if listener is null or name is
  134. * null or empty
  135. * @exception IllegalStateException if read() has already been
  136. * called
  137. */
  138. public void registerListener(final POIFSReaderListener listener,
  139. final POIFSDocumentPath path,
  140. final String name)
  141. {
  142. if ((listener == null) || (name == null) || (name.length() == 0))
  143. {
  144. throw new NullPointerException();
  145. }
  146. if (registryClosed)
  147. {
  148. throw new IllegalStateException();
  149. }
  150. registry.registerListener(listener,
  151. (path == null) ? new POIFSDocumentPath()
  152. : path, name);
  153. }
  154. /**
  155. * read in files
  156. *
  157. * @param args names of the files
  158. *
  159. * @exception IOException
  160. */
  161. public static void main(String args[])
  162. throws IOException
  163. {
  164. if (args.length == 0)
  165. {
  166. System.err
  167. .println("at least one argument required: input filename(s)");
  168. System.exit(1);
  169. }
  170. // register for all
  171. for (int j = 0; j < args.length; j++)
  172. {
  173. POIFSReader reader = new POIFSReader();
  174. POIFSReaderListener listener = new SampleListener();
  175. reader.registerListener(listener);
  176. System.out.println("reading " + args[ j ]);
  177. FileInputStream istream = new FileInputStream(args[ j ]);
  178. reader.read(istream);
  179. istream.close();
  180. }
  181. }
  182. private void processProperties(final BlockList small_blocks,
  183. final BlockList big_blocks,
  184. final Iterator properties,
  185. final POIFSDocumentPath path)
  186. throws IOException
  187. {
  188. while (properties.hasNext())
  189. {
  190. Property property = ( Property ) properties.next();
  191. String name = property.getName();
  192. if (property.isDirectory())
  193. {
  194. POIFSDocumentPath new_path = new POIFSDocumentPath(path,
  195. new String[]
  196. {
  197. name
  198. });
  199. processProperties(
  200. small_blocks, big_blocks,
  201. (( DirectoryProperty ) property).getChildren(), new_path);
  202. }
  203. else
  204. {
  205. int startBlock = property.getStartBlock();
  206. Iterator listeners = registry.getListeners(path, name);
  207. if (listeners.hasNext())
  208. {
  209. int size = property.getSize();
  210. POIFSDocument document = null;
  211. if (property.shouldUseSmallBlocks())
  212. {
  213. document =
  214. new POIFSDocument(name, small_blocks
  215. .fetchBlocks(startBlock, -1), size);
  216. }
  217. else
  218. {
  219. document =
  220. new POIFSDocument(name, big_blocks
  221. .fetchBlocks(startBlock, -1), size);
  222. }
  223. while (listeners.hasNext())
  224. {
  225. POIFSReaderListener listener =
  226. ( POIFSReaderListener ) listeners.next();
  227. listener.processPOIFSReaderEvent(
  228. new POIFSReaderEvent(
  229. new DocumentInputStream(document), path,
  230. name));
  231. }
  232. }
  233. else
  234. {
  235. // consume the document's data and discard it
  236. if (property.shouldUseSmallBlocks())
  237. {
  238. small_blocks.fetchBlocks(startBlock, -1);
  239. }
  240. else
  241. {
  242. big_blocks.fetchBlocks(startBlock, -1);
  243. }
  244. }
  245. }
  246. }
  247. }
  248. private static class SampleListener
  249. implements POIFSReaderListener
  250. {
  251. /**
  252. * Constructor SampleListener
  253. */
  254. SampleListener()
  255. {
  256. }
  257. /**
  258. * Method processPOIFSReaderEvent
  259. *
  260. * @param event
  261. */
  262. public void processPOIFSReaderEvent(final POIFSReaderEvent event)
  263. {
  264. DocumentInputStream istream = event.getStream();
  265. POIFSDocumentPath path = event.getPath();
  266. String name = event.getName();
  267. try
  268. {
  269. byte[] data = new byte[ istream.available() ];
  270. istream.read(data);
  271. int pathLength = path.length();
  272. for (int k = 0; k < pathLength; k++)
  273. {
  274. System.out.print("/" + path.getComponent(k));
  275. }
  276. System.out.println("/" + name + ": " + data.length
  277. + " bytes read");
  278. }
  279. catch (IOException ignored)
  280. {
  281. }
  282. }
  283. } // end private class SampleListener
  284. } // end public class POIFSReader