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.hssf.eventusermodel;
019:
020: import java.io.InputStream;
021: import java.io.IOException;
022:
023: import org.apache.poi.hssf.eventusermodel.HSSFUserException;
024: import org.apache.poi.hssf.record.*;
025: import org.apache.poi.poifs.filesystem.POIFSFileSystem;
026:
027: /**
028: * Low level event based HSSF reader. Pass either a DocumentInputStream to
029: * process events along with a request object or pass a POIFS POIFSFileSystem to
030: * processWorkbookEvents along with a request.
031: *
032: * This will cause your file to be processed a record at a time. Each record with
033: * a static id matching one that you have registed in your HSSFRequest will be passed
034: * to your associated HSSFListener.
035: *
036: * @see org.apache.poi.hssf.dev.EFHSSF
037: *
038: * @author Andrew C. Oliver (acoliver at apache dot org)
039: * @author Carey Sublette (careysub@earthling.net)
040: */
041:
042: public class HSSFEventFactory {
043: /** Creates a new instance of HSSFEventFactory */
044:
045: public HSSFEventFactory() {
046: }
047:
048: /**
049: * Processes a file into essentially record events.
050: *
051: * @param req an Instance of HSSFRequest which has your registered listeners
052: * @param fs a POIFS filesystem containing your workbook
053: */
054:
055: public void processWorkbookEvents(HSSFRequest req,
056: POIFSFileSystem fs) throws IOException {
057: InputStream in = fs.createDocumentInputStream("Workbook");
058:
059: processEvents(req, in);
060: }
061:
062: /**
063: * Processes a file into essentially record events.
064: *
065: * @param req an Instance of HSSFRequest which has your registered listeners
066: * @param fs a POIFS filesystem containing your workbook
067: * @return numeric user-specified result code.
068: */
069:
070: public short abortableProcessWorkbookEvents(HSSFRequest req,
071: POIFSFileSystem fs) throws IOException, HSSFUserException {
072: InputStream in = fs.createDocumentInputStream("Workbook");
073: return abortableProcessEvents(req, in);
074: }
075:
076: /**
077: * Processes a DocumentInputStream into essentially Record events.
078: *
079: * If an <code>AbortableHSSFListener</code> causes a halt to processing during this call
080: * the method will return just as with <code>abortableProcessEvents</code>, but no
081: * user code or <code>HSSFUserException</code> will be passed back.
082: *
083: * @see org.apache.poi.poifs.filesystem.POIFSFileSystem#createDocumentInputStream(String)
084: * @param req an Instance of HSSFRequest which has your registered listeners
085: * @param in a DocumentInputStream obtained from POIFS's POIFSFileSystem object
086: */
087:
088: public void processEvents(HSSFRequest req, InputStream in)
089: throws IOException {
090: try {
091: genericProcessEvents(req, new RecordInputStream(in));
092: } catch (HSSFUserException hue) {/*If an HSSFUserException user exception is thrown, ignore it.*/
093: }
094: }
095:
096: /**
097: * Processes a DocumentInputStream into essentially Record events.
098: *
099: * @see org.apache.poi.poifs.filesystem.POIFSFileSystem#createDocumentInputStream(String)
100: * @param req an Instance of HSSFRequest which has your registered listeners
101: * @param in a DocumentInputStream obtained from POIFS's POIFSFileSystem object
102: * @return numeric user-specified result code.
103: */
104:
105: public short abortableProcessEvents(HSSFRequest req, InputStream in)
106: throws IOException, HSSFUserException {
107: return genericProcessEvents(req, new RecordInputStream(in));
108: }
109:
110: /**
111: * Processes a DocumentInputStream into essentially Record events.
112: *
113: * @see org.apache.poi.poifs.filesystem.POIFSFileSystem#createDocumentInputStream(String)
114: * @param req an Instance of HSSFRequest which has your registered listeners
115: * @param in a DocumentInputStream obtained from POIFS's POIFSFileSystem object
116: * @return numeric user-specified result code.
117: */
118:
119: protected short genericProcessEvents(HSSFRequest req,
120: RecordInputStream in) throws IOException, HSSFUserException {
121: short userCode = 0;
122:
123: short sid = 0;
124: process: {
125:
126: Record rec = null;
127: Record lastRec = null;
128: DrawingRecord lastDrawingRecord = new DrawingRecord();
129:
130: while (in.hasNextRecord()) {
131: in.nextRecord();
132: sid = in.getSid();
133: ;
134:
135: //
136: // for some reasons we have to make the workbook to be at least 4096 bytes
137: // but if we have such workbook we fill the end of it with zeros (many zeros)
138: //
139: // it is not good:
140: // if the length( all zero records ) % 4 = 1
141: // e.g.: any zero record would be readed as 4 bytes at once ( 2 - id and 2 - size ).
142: // And the last 1 byte will be readed WRONG ( the id must be 2 bytes )
143: //
144: // So we should better to check if the sid is zero and not to read more data
145: // The zero sid shows us that rest of the stream data is a fake to make workbook
146: // certain size
147: //
148: if (sid == 0)
149: break;
150:
151: if ((rec != null) && (sid != ContinueRecord.sid)) {
152: userCode = req.processRecord(rec);
153: if (userCode != 0)
154: break process;
155: }
156: if (sid != ContinueRecord.sid) {
157: //System.out.println("creating "+sid);
158: Record[] recs = RecordFactory.createRecord(in);
159:
160: if (recs.length > 1) { // we know that the multiple
161: for (int k = 0; k < (recs.length - 1); k++) { // record situations do not
162: userCode = req.processRecord(recs[k]); // contain continue records
163: if (userCode != 0)
164: break process;
165: }
166: }
167: rec = recs[recs.length - 1]; // regardless we'll process
168:
169: // the last record as though
170: // it might be continued
171: // if there is only one
172: // records, it will go here too.
173: } else {
174: // Normally, ContinueRecords are handled internally
175: // However, in a few cases, there is a gap between a record at
176: // its Continue, so we have to handle them specially
177: // This logic is much like in RecordFactory.createRecords()
178: Record[] recs = RecordFactory.createRecord(in);
179: ContinueRecord crec = (ContinueRecord) recs[0];
180: if ((lastRec instanceof ObjRecord)
181: || (lastRec instanceof TextObjectRecord)) {
182: // You can have Obj records between a DrawingRecord
183: // and its continue!
184: lastDrawingRecord.processContinueRecord(crec
185: .getData());
186: // Trigger them on the drawing record, now it's complete
187: rec = lastDrawingRecord;
188: } else if ((lastRec instanceof DrawingGroupRecord)) {
189: ((DrawingGroupRecord) lastRec)
190: .processContinueRecord(crec.getData());
191: // Trigger them on the drawing record, now it's complete
192: rec = lastRec;
193: } else {
194: if (rec instanceof UnknownRecord) {
195: ;//silently skip records we don't know about
196: } else {
197: throw new RecordFormatException(
198: "Records should handle ContinueRecord internally. Should not see this exception");
199: }
200: }
201: }
202:
203: // Update our tracking of the last record
204: lastRec = rec;
205: if (rec instanceof DrawingRecord) {
206: lastDrawingRecord = (DrawingRecord) rec;
207: }
208: }
209: if (rec != null) {
210: userCode = req.processRecord(rec);
211: if (userCode != 0)
212: break process;
213: }
214: }
215:
216: return userCode;
217:
218: // Record[] retval = new Record[ records.size() ];
219: // retval = ( Record [] ) records.toArray(retval);
220: // return null;
221: }
222: }
|