You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ye...@apache.org on 2009/07/05 16:10:49 UTC

svn commit: r791251 - in /poi/trunk/src: documentation/content/xdocs/ java/org/apache/poi/hssf/eventusermodel/ java/org/apache/poi/hssf/record/

Author: yegor
Date: Sun Jul  5 14:10:49 2009
New Revision: 791251

URL: http://svn.apache.org/viewvc?rev=791251&view=rev
Log:
refactored HSSFEventFactory to use RecordFactory instead of HSSFRecordStream, see Bugzilla 47448

Added:
    poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java   (with props)
Removed:
    poi/trunk/src/java/org/apache/poi/hssf/eventusermodel/HSSFRecordStream.java
Modified:
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/hssf/eventusermodel/HSSFEventFactory.java
    poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=791251&r1=791250&r2=791251&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Sun Jul  5 14:10:49 2009
@@ -33,6 +33,7 @@
 
     <changes>
         <release version="3.5-beta7" date="2009-??-??">
+           <action dev="POI-DEVELOPERS" type="fix">47448 - Allow HSSFEventFactory to handle non-zero padding at the end of the workbook stream</action>
            <action dev="POI-DEVELOPERS" type="add">47456 - Support for getting OLE object data in PowerPointExtractor</action>
            <action dev="POI-DEVELOPERS" type="fix">47411 - Explicitly set the 1900 date system when creating XSSF workbooks</action>
            <action dev="POI-DEVELOPERS" type="add">47400 - Support fo text extraction of footnotes, endnotes and comments in HWPF</action>

Modified: poi/trunk/src/java/org/apache/poi/hssf/eventusermodel/HSSFEventFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/eventusermodel/HSSFEventFactory.java?rev=791251&r1=791250&r2=791251&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/eventusermodel/HSSFEventFactory.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/eventusermodel/HSSFEventFactory.java Sun Jul  5 14:10:49 2009
@@ -134,7 +134,7 @@
 		Record r = null;
 		
 		// Create a new RecordStream and use that
-		HSSFRecordStream recordStream = new HSSFRecordStream(in);
+		RecordFactoryInputStream recordStream = new RecordFactoryInputStream(in);
 		
 		// Process each record as they come in
 		while(going) {

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java?rev=791251&r1=791250&r2=791251&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactory.java Sun Jul  5 14:10:49 2009
@@ -17,21 +17,14 @@
 
 package org.apache.poi.hssf.record;
 
+import org.apache.poi.hssf.record.chart.*;
+import org.apache.poi.hssf.record.pivottable.*;
+
 import java.io.InputStream;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.poi.hssf.record.chart.*;
-import org.apache.poi.hssf.record.pivottable.*;
+import java.util.*;
 
 /**
  * Title:  Record Factory<P>
@@ -259,7 +252,7 @@
 		return new Record[] { record, };
 	}
 
-	static Record createSingleRecord(RecordInputStream in) {
+	public static Record createSingleRecord(RecordInputStream in) {
 		I_RecordCreator constructor = _recordCreatorsById.get(new Integer(in.getSid()));
 
 		if (constructor == null) {
@@ -273,7 +266,7 @@
 	 * RK record is a slightly smaller alternative to NumberRecord
 	 * POI likes NumberRecord better
 	 */
-	private static NumberRecord convertToNumberRecord(RKRecord rk) {
+	public static NumberRecord convertToNumberRecord(RKRecord rk) {
 		NumberRecord num = new NumberRecord();
 
 		num.setColumn(rk.getColumn());
@@ -286,7 +279,7 @@
 	/**
 	 * Converts a {@link MulRKRecord} into an equivalent array of {@link NumberRecord}s
 	 */
-	private static NumberRecord[] convertRKRecords(MulRKRecord mrk) {
+	public static NumberRecord[] convertRKRecords(MulRKRecord mrk) {
 
 		NumberRecord[] mulRecs = new NumberRecord[mrk.getNumColumns()];
 		for (int k = 0; k < mrk.getNumColumns(); k++) {
@@ -374,109 +367,16 @@
 	 * @exception RecordFormatException on error processing the InputStream
 	 */
 	public static List<Record> createRecords(InputStream in) throws RecordFormatException {
-
 		List<Record> records = new ArrayList<Record>(NUM_RECORDS);
 
-		RecordInputStream recStream = new RecordInputStream(in);
-		DrawingRecord lastDrawingRecord = new DrawingRecord( );
-		Record lastRecord = null;
-		/*
-		 * How to recognise end of stream?
-		 * In the best case, the underlying input stream (in) ends just after the last EOF record
-		 * Usually however, the stream is padded with an arbitrary byte count.  Excel and most apps
-		 * reliably use zeros for padding and if this were always the case, this code could just
-		 * skip all the (zero sized) records with sid==0.  However, bug 46987 shows a file with
-		 * non-zero padding that is read OK by Excel (Excel also fixes the padding).
-		 *
-		 * So to properly detect the workbook end of stream, this code has to identify the last
-		 * EOF record.  This is not so easy because the worbook bof+eof pair do not bracket the
-		 * whole stream.  The worksheets follow the workbook, but it is not easy to tell how many
-		 * sheet sub-streams should be present.  Hence we are looking for an EOF record that is not
-		 * immediately followed by a BOF record.  One extra complication is that bof+eof sub-
-		 * streams can be nested within worksheet streams and it's not clear in these cases what
-		 * record might follow any EOF record.  So we also need to keep track of the bof/eof
-		 * nesting level.
-		 */
-
-		int bofDepth=0;
-		boolean lastRecordWasEOFLevelZero = false;
-		while (recStream.hasNextRecord()) {
-			recStream.nextRecord();
-			if (lastRecordWasEOFLevelZero && recStream.getSid() != BOFRecord.sid) {
-				// Normally InputStream (in) contains only zero padding after this point
-				break;
-			}
-			Record record = createSingleRecord(recStream);
-			lastRecordWasEOFLevelZero = false;
-			if (record instanceof BOFRecord) {
-				bofDepth++;
-				records.add(record);
-				continue;
-			}
-			if (record instanceof EOFRecord) {
-				bofDepth--;
-				records.add(record);
-				if (bofDepth<1) {
-					lastRecordWasEOFLevelZero = true;
-				}
-				continue;
-			}
-
-			if (record instanceof DBCellRecord) {
-				// Not needed by POI.  Regenerated from scratch by POI when spreadsheet is written
-				continue;
-			}
-
-			if (record instanceof RKRecord) {
-				records.add(convertToNumberRecord((RKRecord) record));
-				continue;
-			}
-			if (record instanceof MulRKRecord) {
-				addAll(records, convertRKRecords((MulRKRecord)record));
-				continue;
-			}
+		RecordFactoryInputStream recStream = new RecordFactoryInputStream(new RecordInputStream(in));
+                recStream.setIncludeContinueRecords(true);
 
-			if (record.getSid() == DrawingGroupRecord.sid
-				   && lastRecord instanceof DrawingGroupRecord) {
-				DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) lastRecord;
-				lastDGRecord.join((AbstractEscherHolderRecord) record);
-			} else if (record.getSid() == ContinueRecord.sid) {
-				ContinueRecord contRec = (ContinueRecord)record;
-
-				if (lastRecord instanceof ObjRecord || lastRecord instanceof TextObjectRecord) {
-					// Drawing records have a very strange continue behaviour.
-					//There can actually be OBJ records mixed between the continues.
-					lastDrawingRecord.processContinueRecord(contRec.getData() );
-					//we must remember the position of the continue record.
-					//in the serialization procedure the original structure of records must be preserved
-					records.add(record);
-				} else if (lastRecord instanceof DrawingGroupRecord) {
-					((DrawingGroupRecord)lastRecord).processContinueRecord(contRec.getData());
-				} else if (lastRecord instanceof UnknownRecord) {
-					//Gracefully handle records that we don't know about,
-					//that happen to be continued
-					records.add(record);
-				} else if (lastRecord instanceof EOFRecord) {
-					// This is really odd, but excel still sometimes
-					//  outputs a file like this all the same
-					records.add(record);
-				} else {
-					throw new RecordFormatException("Unhandled Continue Record");
-				}
-			} else {
-				lastRecord = record;
-				if (record instanceof DrawingRecord) {
-					lastDrawingRecord = (DrawingRecord) record;
-				}
-				records.add(record);
-			}
+        Record record;
+		while ((record = recStream.nextRecord())!=null) {
+                        records.add(record);
 		}
-		return records;
-	}
 
-	private static void addAll(List<Record> destList, Record[] srcRecs) {
-		for (int i = 0; i < srcRecs.length; i++) {
-			destList.add(srcRecs[i]);
-		}
+		return records;
 	}
 }

Added: poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java?rev=791251&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java (added)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java Sun Jul  5 14:10:49 2009
@@ -0,0 +1,233 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.hssf.record;
+
+import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
+import org.apache.poi.hssf.eventusermodel.HSSFListener;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A stream based way to get at complete records, with
+ * as low a memory footprint as possible.
+ * This handles reading from a RecordInputStream, turning
+ * the data into full records, processing continue records
+ * etc.
+ * Most users should use {@link HSSFEventFactory} /
+ * {@link HSSFListener} and have new records pushed to
+ * them, but this does allow for a "pull" style of coding.
+ */
+public class RecordFactoryInputStream {
+    private final RecordInputStream recStream;
+
+    /**
+     * Have we returned all the records there are?
+     */
+    private boolean complete = false;
+
+    /**
+     * Sometimes we end up with a bunch of
+     * records. When we do, these should
+     * be returned before the next normal
+     * record processing occurs (i.e. before
+     * we check for continue records and
+     * return rec)
+     */
+    private final LinkedList bonusRecords = new LinkedList();
+
+    /**
+     * The most recent record that we gave to the user
+     */
+    private Record lastRecord = null;
+    /**
+     * The most recent DrawingRecord seen
+     */
+    private DrawingRecord lastDrawingRecord = new DrawingRecord();
+
+    private int bofDepth = 0;
+
+    private boolean lastRecordWasEOFLevelZero = false;
+
+    private boolean includeContinueRecords = false;
+
+    public RecordFactoryInputStream(RecordInputStream inp) {
+        recStream = inp;
+    }
+
+    /**
+     * Returns the next (complete) record from the
+     * stream, or null if there are no more.
+     */
+    public Record nextRecord() {
+        Record r = null;
+
+        // Loop until we get something
+        while (r == null && !complete) {
+            // Are there any bonus records that we need to
+            //  return?
+            r = getBonusRecord();
+
+            // If not, ask for the next real record
+            if (r == null) {
+                r = getNextRecord();
+            }
+        }
+
+        // All done
+        return r;
+    }
+
+    /**
+     * If there are any "bonus" records, that should
+     * be returned before processing new ones,
+     * grabs the next and returns it.
+     * If not, returns null;
+     */
+    private Record getBonusRecord() {
+        if (!bonusRecords.isEmpty()) {
+            return (Record) bonusRecords.removeFirst();
+        }
+        return null;
+    }
+
+    /**
+     * Returns the next available record, or null if
+     * this pass didn't return a record that's
+     * suitable for returning (eg was a continue record).
+     */
+    private Record getNextRecord() {
+        /*
+        * How to recognise end of stream?
+        * In the best case, the underlying input stream (in) ends just after the last EOF record
+        * Usually however, the stream is padded with an arbitrary byte count.  Excel and most apps
+        * reliably use zeros for padding and if this were always the case, this code could just
+        * skip all the (zero sized) records with sid==0.  However, bug 46987 shows a file with
+        * non-zero padding that is read OK by Excel (Excel also fixes the padding).
+        *
+        * So to properly detect the workbook end of stream, this code has to identify the last
+        * EOF record.  This is not so easy because the worbook bof+eof pair do not bracket the
+        * whole stream.  The worksheets follow the workbook, but it is not easy to tell how many
+        * sheet sub-streams should be present.  Hence we are looking for an EOF record that is not
+        * immediately followed by a BOF record.  One extra complication is that bof+eof sub-
+        * streams can be nested within worksheet streams and it's not clear in these cases what
+        * record might follow any EOF record.  So we also need to keep track of the bof/eof
+        * nesting level.
+        */
+
+        if (recStream.hasNextRecord()) {
+            // Grab our next record
+            recStream.nextRecord();
+
+            if (lastRecordWasEOFLevelZero && recStream.getSid() != BOFRecord.sid) {
+                // Normally InputStream (in) contains only zero padding after this point
+                complete = true;
+                return null;
+            }
+
+            Record record = RecordFactory.createSingleRecord(recStream);
+            lastRecordWasEOFLevelZero = false;
+
+            if (record instanceof BOFRecord) {
+                bofDepth++;
+                return record;
+            }
+
+            if (record instanceof EOFRecord) {
+                bofDepth--;
+                if (bofDepth < 1) {
+                    lastRecordWasEOFLevelZero = true;
+                }
+
+                return record;
+            }
+
+            if (record instanceof DBCellRecord) {
+                // Not needed by POI.  Regenerated from scratch by POI when spreadsheet is written
+                return null;
+            }
+
+            if (record instanceof RKRecord) {
+                return RecordFactory.convertToNumberRecord((RKRecord) record);
+            }
+
+            if (record instanceof MulRKRecord) {
+                NumberRecord[] records = RecordFactory.convertRKRecords((MulRKRecord) record);
+
+                List<NumberRecord> list = Arrays.asList(records);
+                bonusRecords.addAll(list.subList(1, list.size()));
+
+                return records[0];
+            }
+
+            if (record.getSid() == DrawingGroupRecord.sid
+                    && lastRecord instanceof DrawingGroupRecord) {
+                DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) lastRecord;
+                lastDGRecord.join((AbstractEscherHolderRecord) record);
+                return null;
+            } else if (record.getSid() == ContinueRecord.sid) {
+                ContinueRecord contRec = (ContinueRecord) record;
+
+                if (lastRecord instanceof ObjRecord || lastRecord instanceof TextObjectRecord) {
+                    // Drawing records have a very strange continue behaviour.
+                    //There can actually be OBJ records mixed between the continues.
+                    lastDrawingRecord.processContinueRecord(contRec.getData());
+                    //we must remember the position of the continue record.
+                    //in the serialization procedure the original structure of records must be preserved
+                    if (includeContinueRecords) {
+                        return record;
+                    } else {
+                        return null;
+                    }
+                } else if (lastRecord instanceof DrawingGroupRecord) {
+                    ((DrawingGroupRecord) lastRecord).processContinueRecord(contRec.getData());
+                    return null;
+                } else if (lastRecord instanceof UnknownRecord) {
+                    //Gracefully handle records that we don't know about,
+                    //that happen to be continued
+                    return record;
+                } else if (lastRecord instanceof EOFRecord) {
+                    // This is really odd, but excel still sometimes
+                    //  outputs a file like this all the same
+                    return record;
+                } else {
+                    throw new RecordFormatException("Unhandled Continue Record");
+                }
+            } else {
+                lastRecord = record;
+                if (record instanceof DrawingRecord) {
+                    lastDrawingRecord = (DrawingRecord) record;
+                }
+
+                return record;
+            }
+
+        } else {
+            // No more records
+            complete = true;
+            return null;
+        }
+    }
+
+    /**
+     * Return or not ContinueRecord in nextRecord
+     */
+    public void setIncludeContinueRecords(boolean includeContinueRecords) {
+        this.includeContinueRecords = includeContinueRecords;
+    }
+}
\ No newline at end of file

Propchange: poi/trunk/src/java/org/apache/poi/hssf/record/RecordFactoryInputStream.java
------------------------------------------------------------------------------
    svn:executable = *



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org