001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.poifs.eventfilesystem;
019:
020: import java.io.*;
021:
022: import java.util.*;
023:
024: import org.apache.poi.poifs.filesystem.DocumentInputStream;
025: import org.apache.poi.poifs.filesystem.POIFSDocument;
026: import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
027: import org.apache.poi.poifs.property.DirectoryProperty;
028: import org.apache.poi.poifs.property.Property;
029: import org.apache.poi.poifs.property.PropertyTable;
030: import org.apache.poi.poifs.storage.BlockAllocationTableReader;
031: import org.apache.poi.poifs.storage.BlockList;
032: import org.apache.poi.poifs.storage.HeaderBlockReader;
033: import org.apache.poi.poifs.storage.RawDataBlockList;
034: import org.apache.poi.poifs.storage.SmallBlockTableReader;
035:
036: /**
037: * An event-driven reader for POIFS file systems. Users of this class
038: * first create an instance of it, then use the registerListener
039: * methods to register POIFSReaderListener instances for specific
040: * documents. Once all the listeners have been registered, the read()
041: * method is called, which results in the listeners being notified as
042: * their documents are read.
043: *
044: * @author Marc Johnson (mjohnson at apache dot org)
045: */
046:
047: public class POIFSReader {
048: private POIFSReaderRegistry registry;
049: private boolean registryClosed;
050:
051: /**
052: * Create a POIFSReader
053: */
054:
055: public POIFSReader() {
056: registry = new POIFSReaderRegistry();
057: registryClosed = false;
058: }
059:
060: /**
061: * Read from an InputStream and process the documents we get
062: *
063: * @param stream the InputStream from which to read the data
064: *
065: * @exception IOException on errors reading, or on invalid data
066: */
067:
068: public void read(final InputStream stream) throws IOException {
069: registryClosed = true;
070:
071: // read the header block from the stream
072: HeaderBlockReader header_block_reader = new HeaderBlockReader(
073: stream);
074:
075: // read the rest of the stream into blocks
076: RawDataBlockList data_blocks = new RawDataBlockList(stream);
077:
078: // set up the block allocation table (necessary for the
079: // data_blocks to be manageable
080: new BlockAllocationTableReader(header_block_reader
081: .getBATCount(), header_block_reader.getBATArray(),
082: header_block_reader.getXBATCount(), header_block_reader
083: .getXBATIndex(), data_blocks);
084:
085: // get property table from the document
086: PropertyTable properties = new PropertyTable(
087: header_block_reader.getPropertyStart(), data_blocks);
088:
089: // process documents
090: processProperties(SmallBlockTableReader.getSmallDocumentBlocks(
091: data_blocks, properties.getRoot(), header_block_reader
092: .getSBATStart()), data_blocks, properties
093: .getRoot().getChildren(), new POIFSDocumentPath());
094: }
095:
096: /**
097: * Register a POIFSReaderListener for all documents
098: *
099: * @param listener the listener to be registered
100: *
101: * @exception NullPointerException if listener is null
102: * @exception IllegalStateException if read() has already been
103: * called
104: */
105:
106: public void registerListener(final POIFSReaderListener listener) {
107: if (listener == null) {
108: throw new NullPointerException();
109: }
110: if (registryClosed) {
111: throw new IllegalStateException();
112: }
113: registry.registerListener(listener);
114: }
115:
116: /**
117: * Register a POIFSReaderListener for a document in the root
118: * directory
119: *
120: * @param listener the listener to be registered
121: * @param name the document name
122: *
123: * @exception NullPointerException if listener is null or name is
124: * null or empty
125: * @exception IllegalStateException if read() has already been
126: * called
127: */
128:
129: public void registerListener(final POIFSReaderListener listener,
130: final String name) {
131: registerListener(listener, null, name);
132: }
133:
134: /**
135: * Register a POIFSReaderListener for a document in the specified
136: * directory
137: *
138: * @param listener the listener to be registered
139: * @param path the document path; if null, the root directory is
140: * assumed
141: * @param name the document name
142: *
143: * @exception NullPointerException if listener is null or name is
144: * null or empty
145: * @exception IllegalStateException if read() has already been
146: * called
147: */
148:
149: public void registerListener(final POIFSReaderListener listener,
150: final POIFSDocumentPath path, final String name) {
151: if ((listener == null) || (name == null)
152: || (name.length() == 0)) {
153: throw new NullPointerException();
154: }
155: if (registryClosed) {
156: throw new IllegalStateException();
157: }
158: registry.registerListener(listener,
159: (path == null) ? new POIFSDocumentPath() : path, name);
160: }
161:
162: /**
163: * read in files
164: *
165: * @param args names of the files
166: *
167: * @exception IOException
168: */
169:
170: public static void main(String args[]) throws IOException {
171: if (args.length == 0) {
172: System.err
173: .println("at least one argument required: input filename(s)");
174: System.exit(1);
175: }
176:
177: // register for all
178: for (int j = 0; j < args.length; j++) {
179: POIFSReader reader = new POIFSReader();
180: POIFSReaderListener listener = new SampleListener();
181:
182: reader.registerListener(listener);
183: System.out.println("reading " + args[j]);
184: FileInputStream istream = new FileInputStream(args[j]);
185:
186: reader.read(istream);
187: istream.close();
188: }
189: }
190:
191: private void processProperties(final BlockList small_blocks,
192: final BlockList big_blocks, final Iterator properties,
193: final POIFSDocumentPath path) throws IOException {
194: while (properties.hasNext()) {
195: Property property = (Property) properties.next();
196: String name = property.getName();
197:
198: if (property.isDirectory()) {
199: POIFSDocumentPath new_path = new POIFSDocumentPath(
200: path, new String[] { name });
201:
202: processProperties(small_blocks, big_blocks,
203: ((DirectoryProperty) property).getChildren(),
204: new_path);
205: } else {
206: int startBlock = property.getStartBlock();
207: Iterator listeners = registry.getListeners(path, name);
208:
209: if (listeners.hasNext()) {
210: int size = property.getSize();
211: POIFSDocument document = null;
212:
213: if (property.shouldUseSmallBlocks()) {
214: document = new POIFSDocument(name, small_blocks
215: .fetchBlocks(startBlock), size);
216: } else {
217: document = new POIFSDocument(name, big_blocks
218: .fetchBlocks(startBlock), size);
219: }
220: while (listeners.hasNext()) {
221: POIFSReaderListener listener = (POIFSReaderListener) listeners
222: .next();
223:
224: listener
225: .processPOIFSReaderEvent(new POIFSReaderEvent(
226: new DocumentInputStream(
227: document), path, name));
228: }
229: } else {
230:
231: // consume the document's data and discard it
232: if (property.shouldUseSmallBlocks()) {
233: small_blocks.fetchBlocks(startBlock);
234: } else {
235: big_blocks.fetchBlocks(startBlock);
236: }
237: }
238: }
239: }
240: }
241:
242: private static class SampleListener implements POIFSReaderListener {
243:
244: /**
245: * Constructor SampleListener
246: */
247:
248: SampleListener() {
249: }
250:
251: /**
252: * Method processPOIFSReaderEvent
253: *
254: * @param event
255: */
256:
257: public void processPOIFSReaderEvent(final POIFSReaderEvent event) {
258: DocumentInputStream istream = event.getStream();
259: POIFSDocumentPath path = event.getPath();
260: String name = event.getName();
261:
262: try {
263: byte[] data = new byte[istream.available()];
264:
265: istream.read(data);
266: int pathLength = path.length();
267:
268: for (int k = 0; k < pathLength; k++) {
269: System.out.print("/" + path.getComponent(k));
270: }
271: System.out.println("/" + name + ": " + data.length
272: + " bytes read");
273: } catch (IOException ignored) {
274: }
275: }
276: } // end private class SampleListener
277: } // end public class POIFSReader
|