]> source.dussan.org Git - poi.git/commitdiff
Patch to support reading in Shared Formulas
authorDanny Mui <dmui@apache.org>
Thu, 8 May 2003 00:02:03 +0000 (00:02 +0000)
committerDanny Mui <dmui@apache.org>
Thu, 8 May 2003 00:02:03 +0000 (00:02 +0000)
1) Added new Record: SharedFormulaRecord that is basically a storage area
2) Enabled ExpPtg to store and serialize data for repeating formulas
3) Updated the aggregates to store the SharedFormulaRecord appropriately

git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353090 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/dev/BiffViewer.java
src/java/org/apache/poi/hssf/eventmodel/EventRecordFactory.java
src/java/org/apache/poi/hssf/record/RecordFactory.java
src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java [new file with mode: 0755]
src/java/org/apache/poi/hssf/record/aggregates/FormulaRecordAggregate.java
src/java/org/apache/poi/hssf/record/aggregates/ValueRecordsAggregate.java
src/java/org/apache/poi/hssf/record/formula/ExpPtg.java
src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java
src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java [new file with mode: 0755]

index a2ac1a767e509f78dd4dc33606432383a48fd0ee..da65d5920cb78fefccb05e36261fe9fc8f72fa42 100644 (file)
@@ -630,6 +630,9 @@ public class BiffViewer {
             case PaneRecord.sid:
                 retval = new PaneRecord( rectype, size, data );
                 break;
+            case SharedFormulaRecord.sid:
+                retval = new SharedFormulaRecord( rectype, size, data);
+                break;
             default:
                 retval = new UnknownRecord( rectype, size, data );
         }
index 8bec712237bb1f2a520fed4515ea70ba92d7fca5..3b576528808278e67fbddfa50e6904f38c9ac87e 100644 (file)
  */
 package org.apache.poi.hssf.eventmodel;
 
-import java.io.InputStream;
 import java.io.IOException;
-
-import java.util.*;
-
+import java.io.InputStream;
 import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.poi.hssf.record.BOFRecord;
 import org.apache.poi.hssf.record.BackupRecord;
@@ -126,6 +128,7 @@ import org.apache.poi.hssf.record.RowRecord;
 import org.apache.poi.hssf.record.SSTRecord;
 import org.apache.poi.hssf.record.SaveRecalcRecord;
 import org.apache.poi.hssf.record.SelectionRecord;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
 import org.apache.poi.hssf.record.StringRecord;
 import org.apache.poi.hssf.record.StyleRecord;
 import org.apache.poi.hssf.record.TabIdRecord;
@@ -189,7 +192,7 @@ public class EventRecordFactory
                 BoolErrRecord.class, ExternSheetRecord.class, NameRecord.class,
                 LeftMarginRecord.class, RightMarginRecord.class,
                 TopMarginRecord.class, BottomMarginRecord.class,
-                PaletteRecord.class, StringRecord.class
+                PaletteRecord.class, StringRecord.class, SharedFormulaRecord.class
             };
        
     }
index 83bd7c63765e8d168f6c1857540e533ff216d59b..f12f903b06c151e3a4e7bbf1a911c53c1d81dcc1 100644 (file)
@@ -112,7 +112,7 @@ public class RecordFactory
                 FormulaRecord.class, BoolErrRecord.class, ExternSheetRecord.class,
                 NameRecord.class, LeftMarginRecord.class, RightMarginRecord.class,
                 TopMarginRecord.class, BottomMarginRecord.class,
-                PaletteRecord.class, StringRecord.class, RecalcIdRecord.class
+                PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class
             };
         } else {
             records = new Class[]
@@ -143,7 +143,7 @@ public class RecordFactory
                 BoolErrRecord.class, ExternSheetRecord.class, NameRecord.class,
                 LeftMarginRecord.class, RightMarginRecord.class,
                 TopMarginRecord.class, BottomMarginRecord.class,
-                PaletteRecord.class, StringRecord.class, RecalcIdRecord.class
+                PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class
             };
 
         }
diff --git a/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java b/src/java/org/apache/poi/hssf/record/SharedFormulaRecord.java
new file mode 100755 (executable)
index 0000000..eb44823
--- /dev/null
@@ -0,0 +1,191 @@
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ *    "Apache POI" must not be used to endorse or promote products
+ *    derived from this software without prior written permission. For
+ *    written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache POI", nor may "Apache" appear in their name, without
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package org.apache.poi.hssf.record;
+
+import org.apache.poi.util.LittleEndian;
+
+/**
+ * Title:        SharedFormulaRecord
+ * Description:  Primarily used as an excel optimization so that multiple similar formulas
+ *                               are not written out too many times.  We should recognize this record and
+ *               serialize as is since this is used when reading templates.
+ * <p>
+ * Note: the documentation says that the SID is BC where biffviewer reports 4BC.  The hex dump shows
+ * that the two byte sid representation to be 'BC 04' that is consistent with the other high byte
+ * record types.
+ * @author Danny Mui at apache dot org
+ */
+
+public class SharedFormulaRecord
+    extends Record
+{
+        public final static short   sid = 0x4BC;
+    private short  size    = 0;
+    private byte[] thedata = null;
+    int             offset  = 0;
+
+    public SharedFormulaRecord()
+    {
+    }
+
+    /**
+     * construct the sharedformula record, save all the information
+     * @param id    id of the record -not validated, just stored for serialization
+     * @param size  size of the data
+     * @param data  the data
+     */
+
+    public SharedFormulaRecord(short id, short size, byte [] data)
+    {
+         super(id, size, data);
+         
+         this.fillFields(data, size, 0);
+    }
+
+    /**
+     * spit the record out AS IS.  no interperatation or identification
+     */
+
+    public int serialize(int offset, byte [] data)
+    {
+        if (thedata == null)
+        {
+            thedata = new byte[ 0 ];
+        }
+        LittleEndian.putShort(data, 0 + offset, sid);
+        LittleEndian.putShort(data, 2 + offset, ( short ) (thedata.length));
+        if (thedata.length > 0)
+        {
+            System.arraycopy(thedata, 0, data, 4 + offset, thedata.length);
+        }
+        return getRecordSize();
+    }
+
+    public int getRecordSize()
+    {
+        int retval = 4;
+
+        if (thedata != null)
+        {
+            retval += thedata.length;
+        }
+        return retval;
+    }
+
+
+    protected void validateSid(short id)
+    {
+               if (id != this.sid)
+               {
+                       throw new RecordFormatException("Not a valid SharedFormula");
+               }
+        
+    }
+
+    /**
+     * print a sort of string representation ([SHARED FORMULA RECORD] id = x [/SHARED FORMULA RECORD])
+     */
+
+    public String toString()
+    {
+        StringBuffer buffer = new StringBuffer();
+
+        buffer.append("[SHARED FORMULA RECORD:" + Integer.toHexString(sid) + "]\n");
+        buffer.append("    .id        = ").append(Integer.toHexString(sid))
+            .append("\n");
+        buffer.append("[/SHARED FORMULA RECORD]\n");
+        return buffer.toString();
+    }
+
+    public short getSid()
+    {
+        return this.sid;
+    }
+
+        /**
+         * Shared formulas are to treated like unknown records, and as a result d
+         */
+    protected void fillFields(byte [] data, short size, int offset)
+    {
+               thedata = new byte[size];
+               System.arraycopy(data, 0, thedata, 0, size);            
+
+    }
+
+       /**
+        * Mirroring formula records so it is registered in the ValueRecordsAggregate
+        */
+       public boolean isInValueSection()
+       {
+                return true;
+       }
+
+
+        /**
+         * Register it in the ValueRecordsAggregate so it can go into the FormulaRecordAggregate
+         */
+        public boolean isValue() {
+               return true;
+        }
+
+    public Object clone() {
+      SharedFormulaRecord rec = new SharedFormulaRecord();
+      rec.offset = offset;      
+      rec.size = size;
+      rec.thedata = thedata;
+      return rec;
+    }
+}
index 82d168bf862b595f3d7bcf8c4f4b94086f461e4a..7d5b0b048d769b98ce01dc78deb3c8d396ede4dd 100644 (file)
@@ -58,7 +58,7 @@ import org.apache.poi.hssf.record.*;
 
 /**
  * The formula record aggregate is used to join together the formula record and it's
- * (optional) string record.
+ * (optional) string record and (optional) Shared Formula Record (template reads, excel optimization).
  *
  * @author Glen Stampoultzis (glens at apache.org)
  */
@@ -70,6 +70,11 @@ public class FormulaRecordAggregate
 
     private FormulaRecord formulaRecord;
     private StringRecord stringRecord;
+    
+    /**
+     * will only be set through the RecordFactory
+     */
+        private SharedFormulaRecord sharedFormulaRecord;
 
     public FormulaRecordAggregate( FormulaRecord formulaRecord, StringRecord stringRecord )
     {
@@ -105,7 +110,12 @@ public class FormulaRecordAggregate
         {
             pos += stringRecord.serialize(pos, data);
         }
+        if (this.getSharedFormulaRecord() != null) 
+        {
+                       pos += getSharedFormulaRecord().serialize(pos, data);
+        }      
         return pos - offset;
+        
     }
 
     /**
@@ -114,6 +124,7 @@ public class FormulaRecordAggregate
     public int getRecordSize()
     {
         int size = formulaRecord.getRecordSize() + (stringRecord == null ? 0 : stringRecord.getRecordSize());
+        size += (getSharedFormulaRecord() == null) ? 0 : getSharedFormulaRecord().getRecordSize();
         return size;
     }
 
@@ -215,4 +226,19 @@ public class FormulaRecordAggregate
 
 
 
+   /**
+    * @return SharedFormulaRecord
+    */
+   public SharedFormulaRecord getSharedFormulaRecord() {
+      return sharedFormulaRecord;
+   }
+
+   /**
+    * Sets the sharedFormulaRecord, only set from RecordFactory since they are not generated by POI and are an Excel optimization
+    * @param sharedFormulaRecord The sharedFormulaRecord to set
+    */
+   public void setSharedFormulaRecord(SharedFormulaRecord sharedFormulaRecord) {
+      this.sharedFormulaRecord = sharedFormulaRecord;
+   }
+
 }
index fae69130e7c0f748a50d9e44d2917b2b240b9c40..d985ac84f188c302f69e1fe75ffcd1c10d30db2d 100644 (file)
@@ -157,6 +157,11 @@ public class ValueRecordsAggregate
             {
                 lastFormulaAggregate.setStringRecord((StringRecord)rec);
             }
+            else if (rec instanceof SharedFormulaRecord)
+            {
+               //these follow the first formula in a group
+               lastFormulaAggregate.setSharedFormulaRecord((SharedFormulaRecord)rec);
+            }
             else if (rec.isValue())
             {
                 insertCell(( CellValueRecordInterface ) rec);
index 8b182230ea07a3e9f28d4e673f6f69e3ad8ff330..576bce331603b9075d9500be036c1bd12b8fd869 100644 (file)
@@ -66,6 +66,7 @@ import org.apache.poi.hssf.util.SheetReferences;
  *
  * @author  andy
  * @author Jason Height (jheight at chariot dot net dot au)
+ * @author dmui (save existing implementation)
  */
 
 public class ExpPtg
@@ -73,6 +74,7 @@ public class ExpPtg
 {
     private final static int  SIZE = 5;
     public final static short sid  = 0x1;
+        private        byte[] existing = null;
 
     /** Creates new ExpPtg */
 
@@ -84,10 +86,15 @@ public class ExpPtg
 
     public ExpPtg(byte [] array, int offset)
     {
+       existing = new byte[this.getSize()];
+       System.arraycopy(array, offset, existing, 0, this.getSize());
     }
 
     public void writeBytes(byte [] array, int offset)
     {
+       if (existing != null) {
+                       System.arraycopy(existing, 0, array, offset, existing.length);
+       }
     }
 
     public int getSize()
index 0efdd7c719e849065b5d56999e45fa6484292121..2ab793d5e71cf5df196d47c2fc764de4ee2fad4a 100644 (file)
@@ -121,6 +121,30 @@ public class TestFormulaRecord
                
     }
     
+    /**
+     * Tests to see if the shared formula cells properly reserialize the expPtg
+     *
+     */
+    public void testExpFormula() {
+       byte[] formulaByte = new byte[27];
+       
+               for (int i = 0; i < formulaByte.length; i++) formulaByte[i] = (byte)0;
+       
+       formulaByte[4] =(byte)0x0F;
+               formulaByte[14]=(byte)0x08;
+               formulaByte[18]=(byte)0xE0;
+               formulaByte[19]=(byte)0xFD;
+               formulaByte[20]=(byte)0x05;
+               formulaByte[22]=(byte)0x01;
+               FormulaRecord record = new FormulaRecord(FormulaRecord.sid, (short)27, formulaByte);
+               assertEquals("Row", 0, record.getRow());
+               assertEquals("Column", 0, record.getColumn());
+               byte[] output = record.serialize();
+               assertEquals("Output size", 31, output.length); //includes sid+recordlength
+       assertEquals("Offset 22", 1, output[26]);
+    }
+    
+    
     public static void main(String [] ignored_args)
     {
         String filename = System.getProperty("HSSF.testdata.path");
diff --git a/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java b/src/testcases/org/apache/poi/hssf/record/aggregates/TestValueRecordsAggregate.java
new file mode 100755 (executable)
index 0000000..9088f11
--- /dev/null
@@ -0,0 +1,96 @@
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ *    "Apache POI" must not be used to endorse or promote products
+ *    derived from this software without prior written permission. For
+ *    written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache POI", nor may "Apache" appear in their name, without
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+package org.apache.poi.hssf.record.aggregates;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.poi.hssf.record.FormulaRecord;
+import org.apache.poi.hssf.record.Record;
+import org.apache.poi.hssf.record.SharedFormulaRecord;
+
+public class TestValueRecordsAggregate extends junit.framework.TestCase {
+    public TestValueRecordsAggregate(String name) {
+        super (name);
+    }
+    
+    /**
+     * Make sure the shared formula makes it to the FormulaRecordAggregate when being parsed
+     * as part of the value records
+     *
+     */
+    public void testSharedFormula() {
+                       List records = new ArrayList();
+                       records.add(new FormulaRecord());
+                       records.add(new SharedFormulaRecord());
+                       
+                       ValueRecordsAggregate valueRecord = new ValueRecordsAggregate();
+                       valueRecord.construct(0, records); 
+                       Iterator iterator = valueRecord.getIterator();                  
+                       Record record = (Record)iterator.next();
+                       assertNotNull("Row contains a value", record);
+                       assertTrue("First record is a FormulaRecordsAggregate", (record instanceof FormulaRecordAggregate));
+                       FormulaRecordAggregate aggregate = (FormulaRecordAggregate)record;
+                       assertNotNull("SharedFormulaRecord is null", aggregate.getSharedFormulaRecord());
+                               
+    }
+    
+     public static void main(String [] args) {
+        System.out
+        .println("Testing org.apache.poi.hssf.record.aggregates.TestValueRecordAggregate");
+        junit.textui.TestRunner.run(TestValueRecordsAggregate.class);
+    }
+}
\ No newline at end of file