]> source.dussan.org Git - poi.git/commitdiff
Merged revisions 707486,707519,707525,707534,707541-707542,707551,707585,707729,70777...
authorJosh Micich <josh@apache.org>
Sun, 26 Oct 2008 07:18:17 +0000 (07:18 +0000)
committerJosh Micich <josh@apache.org>
Sun, 26 Oct 2008 07:18:17 +0000 (07:18 +0000)
https://svn.apache.org/repos/asf/poi/trunk

........
  r707486 | josh | 2008-10-23 15:28:05 -0700 (Thu, 23 Oct 2008) | 1 line

  Converted Ptgs to use LittleEndianOutput
........
  r707519 | josh | 2008-10-23 17:58:49 -0700 (Thu, 23 Oct 2008) | 1 line

  Fix for unicode string bug in StyleRecord.  Improvements to WriteAccessRecord.
........
  r707525 | josh | 2008-10-23 19:08:47 -0700 (Thu, 23 Oct 2008) | 1 line

  Further conversion of Ptg classes to use LittleEndian input/output interfaces
........
  r707534 | josh | 2008-10-23 20:47:42 -0700 (Thu, 23 Oct 2008) | 1 line

  added LittleEndianByteArrayInputStream
........
  r707541 | josh | 2008-10-23 21:30:38 -0700 (Thu, 23 Oct 2008) | 1 line

  Removed String methods from LittleEndianInput
........
  r707542 | josh | 2008-10-23 21:40:37 -0700 (Thu, 23 Oct 2008) | 1 line

  removing unused code
........
  r707551 | josh | 2008-10-23 22:46:29 -0700 (Thu, 23 Oct 2008) | 1 line

  Simplification and code clean-up
........
  r707585 | josh | 2008-10-24 01:58:00 -0700 (Fri, 24 Oct 2008) | 1 line

  General clean-up in LittleEndian util class. (Some optimization, some obsolete code removal)
........
  r707729 | josh | 2008-10-24 12:25:11 -0700 (Fri, 24 Oct 2008) | 1 line

  Fixed test suite name
........
  r707778 | josh | 2008-10-24 16:13:44 -0700 (Fri, 24 Oct 2008) | 1 line

  Optimisation of RecordInputStream - removed intermediate 8K byte buffer.  Expected performance gain was not realised immediately, so LittleEndianInput stuff has been pushed down into DocumentInputStream to help.
........
  r707780 | josh | 2008-10-24 16:19:26 -0700 (Fri, 24 Oct 2008) | 1 line

  should have been submitted with c707778
........
  r707802 | josh | 2008-10-24 18:02:37 -0700 (Fri, 24 Oct 2008) | 1 line

  Further simplification to RecordInputStream.  Mostly regarding Strings, ContinueRecords and LittleEndianInput
........

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@707945 13f79535-47bb-0310-9956-ffa450edef68

89 files changed:
src/contrib/src/org/apache/poi/contrib/poibrowser/TreeReaderListener.java
src/java/org/apache/poi/hssf/model/Workbook.java
src/java/org/apache/poi/hssf/record/CRNRecord.java
src/java/org/apache/poi/hssf/record/EmbeddedObjectRefSubRecord.java
src/java/org/apache/poi/hssf/record/LinkedDataFormulaField.java
src/java/org/apache/poi/hssf/record/RecordInputStream.java
src/java/org/apache/poi/hssf/record/StyleRecord.java
src/java/org/apache/poi/hssf/record/SubRecord.java
src/java/org/apache/poi/hssf/record/SupBookRecord.java
src/java/org/apache/poi/hssf/record/TextObjectRecord.java
src/java/org/apache/poi/hssf/record/UnicodeString.java
src/java/org/apache/poi/hssf/record/WriteAccessRecord.java
src/java/org/apache/poi/hssf/record/constant/ConstantValueParser.java
src/java/org/apache/poi/hssf/record/formula/AbstractFunctionPtg.java
src/java/org/apache/poi/hssf/record/formula/Area2DPtgBase.java
src/java/org/apache/poi/hssf/record/formula/Area3DPtg.java
src/java/org/apache/poi/hssf/record/formula/AreaErrPtg.java
src/java/org/apache/poi/hssf/record/formula/AreaNPtg.java
src/java/org/apache/poi/hssf/record/formula/AreaPtg.java
src/java/org/apache/poi/hssf/record/formula/AreaPtgBase.java
src/java/org/apache/poi/hssf/record/formula/ArrayPtg.java
src/java/org/apache/poi/hssf/record/formula/AttrPtg.java
src/java/org/apache/poi/hssf/record/formula/BoolPtg.java
src/java/org/apache/poi/hssf/record/formula/DeletedArea3DPtg.java
src/java/org/apache/poi/hssf/record/formula/DeletedRef3DPtg.java
src/java/org/apache/poi/hssf/record/formula/ErrPtg.java
src/java/org/apache/poi/hssf/record/formula/ExpPtg.java
src/java/org/apache/poi/hssf/record/formula/FuncPtg.java
src/java/org/apache/poi/hssf/record/formula/FuncVarPtg.java
src/java/org/apache/poi/hssf/record/formula/IntPtg.java
src/java/org/apache/poi/hssf/record/formula/IntersectionPtg.java
src/java/org/apache/poi/hssf/record/formula/MemAreaPtg.java
src/java/org/apache/poi/hssf/record/formula/MemErrPtg.java
src/java/org/apache/poi/hssf/record/formula/MemFuncPtg.java
src/java/org/apache/poi/hssf/record/formula/MissingArgPtg.java
src/java/org/apache/poi/hssf/record/formula/NamePtg.java
src/java/org/apache/poi/hssf/record/formula/NameXPtg.java
src/java/org/apache/poi/hssf/record/formula/NumberPtg.java
src/java/org/apache/poi/hssf/record/formula/ParenthesisPtg.java
src/java/org/apache/poi/hssf/record/formula/Ptg.java
src/java/org/apache/poi/hssf/record/formula/RangePtg.java
src/java/org/apache/poi/hssf/record/formula/Ref2DPtgBase.java
src/java/org/apache/poi/hssf/record/formula/Ref3DPtg.java
src/java/org/apache/poi/hssf/record/formula/RefErrorPtg.java
src/java/org/apache/poi/hssf/record/formula/RefNPtg.java
src/java/org/apache/poi/hssf/record/formula/RefPtg.java
src/java/org/apache/poi/hssf/record/formula/RefPtgBase.java
src/java/org/apache/poi/hssf/record/formula/StringPtg.java
src/java/org/apache/poi/hssf/record/formula/TblPtg.java
src/java/org/apache/poi/hssf/record/formula/UnionPtg.java
src/java/org/apache/poi/hssf/record/formula/UnknownPtg.java
src/java/org/apache/poi/hssf/record/formula/ValueOperatorPtg.java
src/java/org/apache/poi/hssf/usermodel/HSSFCellStyle.java
src/java/org/apache/poi/poifs/filesystem/DocumentInputStream.java
src/java/org/apache/poi/poifs/filesystem/POIFSDocument.java
src/java/org/apache/poi/poifs/storage/DataInputBlock.java [new file with mode: 0644]
src/java/org/apache/poi/poifs/storage/DocumentBlock.java
src/java/org/apache/poi/poifs/storage/SmallDocumentBlock.java
src/java/org/apache/poi/util/DoubleList.java [deleted file]
src/java/org/apache/poi/util/DoubleList2d.java [deleted file]
src/java/org/apache/poi/util/LittleEndian.java
src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java [new file with mode: 0644]
src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java [new file with mode: 0644]
src/java/org/apache/poi/util/LittleEndianInput.java
src/java/org/apache/poi/util/LittleEndianInputStream.java
src/java/org/apache/poi/util/StringUtil.java
src/testcases/org/apache/poi/hssf/record/AllRecordTests.java
src/testcases/org/apache/poi/hssf/record/TestCommonObjectDataSubRecord.java
src/testcases/org/apache/poi/hssf/record/TestEmbeddedObjectRefSubRecord.java
src/testcases/org/apache/poi/hssf/record/TestFormulaRecord.java
src/testcases/org/apache/poi/hssf/record/TestHyperlinkRecord.java
src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java
src/testcases/org/apache/poi/hssf/record/TestStyleRecord.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/record/TestTextObjectBaseRecord.java
src/testcases/org/apache/poi/hssf/record/TestTextObjectRecord.java
src/testcases/org/apache/poi/hssf/record/TestcaseRecordInputStream.java
src/testcases/org/apache/poi/hssf/record/constant/TestConstantValueParser.java
src/testcases/org/apache/poi/hssf/record/formula/TestArrayPtg.java
src/testcases/org/apache/poi/hssf/record/formula/TestAttrPtg.java
src/testcases/org/apache/poi/hssf/record/formula/TestFuncPtg.java
src/testcases/org/apache/poi/hssf/record/formula/TestReferencePtg.java
src/testcases/org/apache/poi/poifs/filesystem/TestDocumentInputStream.java
src/testcases/org/apache/poi/poifs/storage/AllPOIFSStorageTests.java
src/testcases/org/apache/poi/poifs/storage/TestDocumentBlock.java
src/testcases/org/apache/poi/poifs/storage/TestSmallDocumentBlock.java
src/testcases/org/apache/poi/util/AllPOIUtilTests.java
src/testcases/org/apache/poi/util/TestDoubleList2d.java [deleted file]
src/testcases/org/apache/poi/util/TestLittleEndian.java
src/testcases/org/apache/poi/util/TestStringUtil.java

index a98ec3906ca33dbe2cac2dac12bfda98ded16876..df9e996fbe9fdeb3aadad780d674385c794e7126 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.contrib.poibrowser;
 
-import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -160,17 +157,7 @@ public class TreeReaderListener implements POIFSReaderListener
             throw new RuntimeException(t.getMessage());
         }
 
-        try
-        {
-            is.close();
-        }
-        catch (IOException ex)
-        {
-            System.err.println
-                ("Unexpected exception while closing " +
-                event.getName() + " in " + event.getPath().toString());
-            ex.printStackTrace(System.err);
-        }
+        is.close();
 
         final MutableTreeNode parentNode = getNode(d.path, filename, rootNode);
         final MutableTreeNode nameNode = new DefaultMutableTreeNode(d.name);
index 54639adb182e114b8225cb0039e09cc8c2efb78c..222f0a6ab6193c54e8b71850cf4a5165a2022b6a 100644 (file)
@@ -788,7 +788,7 @@ public final class Workbook implements Model {
             if(r instanceof ExtendedFormatRecord) {
             } else if(r instanceof StyleRecord) {
                 StyleRecord sr = (StyleRecord)r;
-                if(sr.getIndex() == xfIndex) {
+                if(sr.getXFIndex() == xfIndex) {
                     return sr;
                 }
             } else {
@@ -806,7 +806,7 @@ public final class Workbook implements Model {
         // Style records always follow after 
         //  the ExtendedFormat records
         StyleRecord newSR = new StyleRecord();
-        newSR.setIndex((short)xfIndex);
+        newSR.setXFIndex(xfIndex);
         
         // Find the spot
         int addAt = -1;
@@ -1782,45 +1782,44 @@ public final class Workbook implements Model {
      * @see org.apache.poi.hssf.record.StyleRecord
      * @see org.apache.poi.hssf.record.Record
      */
-
     protected Record createStyle(int id) {   // we'll need multiple editions
         StyleRecord retval = new StyleRecord();
 
         switch (id) {
 
             case 0 :
-                retval.setIndex(( short ) 0xffff8010);
-                retval.setBuiltin(( byte ) 3);
+                retval.setXFIndex(0x010);
+                retval.setBuiltinStyle(3);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 1 :
-                retval.setIndex(( short ) 0xffff8011);
-                retval.setBuiltin(( byte ) 6);
+                retval.setXFIndex(0x011);
+                retval.setBuiltinStyle(6);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 2 :
-                retval.setIndex(( short ) 0xffff8012);
-                retval.setBuiltin(( byte ) 4);
+                retval.setXFIndex(0x012);
+                retval.setBuiltinStyle(4);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 3 :
-                retval.setIndex(( short ) 0xffff8013);
-                retval.setBuiltin(( byte ) 7);
+                retval.setXFIndex(0x013);
+                retval.setBuiltinStyle(7);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 4 :
-                retval.setIndex(( short ) 0xffff8000);
-                retval.setBuiltin(( byte ) 0);
+                retval.setXFIndex(0x000);
+                retval.setBuiltinStyle(0);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
 
             case 5 :
-                retval.setIndex(( short ) 0xffff8014);
-                retval.setBuiltin(( byte ) 5);
+                retval.setXFIndex(0x014);
+                retval.setBuiltinStyle(5);
                 retval.setOutlineStyleLevel(( byte ) 0xffffffff);
                 break;
         }
index 417f2a559a3250c749facea04750cb82f51bffec..050076cca27e362635e5f2df7ee492a6bad79ee7 100755 (executable)
 package org.apache.poi.hssf.record;
 
 import org.apache.poi.hssf.record.constant.ConstantValueParser;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
- * Title:       CRN  <P>
- * Description: This record stores the contents of an external cell or cell range <P>
- * REFERENCE:  5.23<P>
+ * Title:       CRN(0x005A) <p/>
+ * Description: This record stores the contents of an external cell or cell range <p/>
+ * REFERENCE:   OOO 5.23<p/>
  *
  * @author josh micich
  */
 public final class CRNRecord extends Record {
-       public final static short sid = 0x5A;
+       public final static short sid = 0x005A;
 
        private int      field_1_last_column_index;
        private int      field_2_first_column_index;
@@ -45,8 +46,8 @@ public final class CRNRecord extends Record {
 
 
        public CRNRecord(RecordInputStream in) {
-               field_1_last_column_index = in.readByte() & 0x00FF;
-               field_2_first_column_index = in.readByte() & 0x00FF;
+               field_1_last_column_index = in.readUByte();
+               field_2_first_column_index = in.readUByte();
                field_3_row_index = in.readShort();
                int nValues = field_1_last_column_index - field_2_first_column_index + 1;
                field_4_constant_values = ConstantValueParser.parse(in, nValues);
@@ -68,13 +69,15 @@ public final class CRNRecord extends Record {
 
        public int serialize(int offset, byte [] data) {
                int dataSize = getDataSize();
-               LittleEndian.putShort(data, 0 + offset, sid);
-               LittleEndian.putShort(data, 2 + offset, (short) dataSize);
-               LittleEndian.putByte(data, 4 + offset, field_1_last_column_index);
-               LittleEndian.putByte(data, 5 + offset, field_2_first_column_index);
-               LittleEndian.putShort(data, 6 + offset, (short) field_3_row_index);
-               ConstantValueParser.encode(data, 8 + offset, field_4_constant_values);
-               return getRecordSize();
+               int recSize = 4 + dataSize;
+               LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
+               out.writeShort(sid);
+               out.writeShort(dataSize);
+               out.writeByte(field_1_last_column_index);
+               out.writeByte(field_2_first_column_index);
+               out.writeShort(field_3_row_index);
+               ConstantValueParser.encode(out, field_4_constant_values);
+               return recSize;
        }
 
        public int getRecordSize() {
index db0dbf67713b1e681f9b86ad17952655f1b3b2f2..f033149ee871e40862c756f7915a44278ea2eddf 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.poi.hssf.record.formula.RefPtg;
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianInputStream;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.StringUtil;
 
@@ -111,10 +112,10 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord {
                                field_3_unicode_flag = ( in.readByte() & 0x01 ) != 0;
                                remaining -= LittleEndian.BYTE_SIZE;
                                if (field_3_unicode_flag) {
-                                       field_4_ole_classname = in.readUnicodeLEString(nChars);
+                                       field_4_ole_classname = StringUtil.readUnicodeLE(in, nChars);
                                        stringByteCount = nChars * 2;
                                } else {
-                                       field_4_ole_classname = in.readCompressedUnicode(nChars);
+                                       field_4_ole_classname = StringUtil.readCompressedUnicode(in, nChars);
                                        stringByteCount = nChars;
                                }
                        } else {
@@ -156,12 +157,7 @@ public final class EmbeddedObjectRefSubRecord extends SubRecord {
        }
 
        private static Ptg readRefPtg(byte[] formulaRawBytes) {
-               byte[] data = new byte[formulaRawBytes.length + 4];
-               LittleEndian.putUShort(data, 0, -5555);
-               LittleEndian.putUShort(data, 2, formulaRawBytes.length);
-               System.arraycopy(formulaRawBytes, 0, data, 4, formulaRawBytes.length);
-               RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
-               in.nextRecord();
+               LittleEndianInput in = new LittleEndianInputStream(new ByteArrayInputStream(formulaRawBytes));
                byte ptgSid = in.readByte();
                switch(ptgSid) {
                        case AreaPtg.sid:   return new AreaPtg(in);
index 4a607c9e37d10feb53884013a82d11869cf11c5f..36aeb7b47ce524671946520299a8558b0acc504d 100644 (file)
@@ -51,7 +51,7 @@ public final class LinkedDataFormulaField {
                     .append( "=" )
                     .append(ptg.toString() )
                     .append( "\n" )
-                    .append(ptg.toDebugString() )
+                    .append(ptg.toString())
                     .append( "\n" );
         }
     }
index cec9ddb1910dc62ac5c7fbaa768ae3ba7f66b58d..f9dd2c76c7d770694d87786c0ff78ad31211d4e0 100755 (executable)
 
 package org.apache.poi.hssf.record;
 
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.LittleEndianInput;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInputStream;
 
 /**
  * Title:  Record Input Stream<P>
@@ -34,115 +34,147 @@ public final class RecordInputStream extends InputStream implements LittleEndian
        /** Maximum size of a single record (minus the 4 byte header) without a continue*/
        public final static short MAX_RECORD_DATA_SIZE = 8224;
        private static final int INVALID_SID_VALUE = -1;
+       /**
+        * When {@link #_currentDataLength} has this value, it means that the previous BIFF record is
+        * finished, the next sid has been properly read, but the data size field has not been read yet.
+        */
+       private static final int DATA_LEN_NEEDS_TO_BE_READ = -1;
+       private static final byte[] EMPTY_BYTE_ARRAY = { };
+
+       /** {@link LittleEndianInput} facet of the wrapped {@link InputStream} */
+       private final LittleEndianInput _le;
+       /** the record identifier of the BIFF record currently being read */
+       private int _currentSid;
+       /** 
+        * Length of the data section of the current BIFF record (always 4 less than the total record size).
+        * When uninitialised, this field is set to {@link #DATA_LEN_NEEDS_TO_BE_READ}.
+        */
+       private int _currentDataLength;
+       /** 
+        * The BIFF record identifier for the next record is read when just as the current record
+        * is finished.
+        * This field is only really valid during the time that ({@link #_currentDataLength} == 
+        * {@link #DATA_LEN_NEEDS_TO_BE_READ}).  At most other times its value is not really the 
+        * 'sid of the next record'.  Wwhile mid-record, this field coincidentally holds the sid 
+        * of the current record.
+        */
+       private int _nextSid;
+       /** 
+        * index within the data section of the current BIFF record
+        */
+       private int _currentDataOffset;
+
+       public RecordInputStream(InputStream in) throws RecordFormatException {
+               if (in instanceof LittleEndianInput) {
+                       // accessing directly is an optimisation
+                       _le = (LittleEndianInput) in;
+               } else {
+                       // less optimal, but should work OK just the same. Often occurs in junit tests.
+                       _le = new LittleEndianInputStream(in);
+               }
+               _nextSid = readNextSid();
+       }
+       
+       /**
+        * @returns the number of bytes available in the current BIFF record
+        * @see #remaining()
+        */
+       public int available() {
+               return remaining();
+       }
 
-       private InputStream in;
-       private short currentSid;
-       private short currentLength = -1;
-       private short nextSid;
-
-       private final byte[] data = new byte[MAX_RECORD_DATA_SIZE];
-       private short recordOffset;
-       private long pos;
-
-  private boolean autoContinue = true;
-
-  public RecordInputStream(InputStream in) throws RecordFormatException {
-    this.in = in;
-    try {
-      nextSid = LittleEndian.readShort(in);
-      //Don't increment the pos just yet (technically we are at the start of
-      //the record stream until nextRecord is called).
-    } catch (IOException ex) {
-      throw new RecordFormatException("Error reading bytes", ex);
-    }
-  }
-
-       /** This method will read a byte from the current record*/
        public int read() {
                checkRecordPosition(LittleEndian.BYTE_SIZE);
-
-               byte result = data[recordOffset];
-               recordOffset += LittleEndian.BYTE_SIZE;
-               pos += LittleEndian.BYTE_SIZE;
-               return result;
+               _currentDataOffset += LittleEndian.BYTE_SIZE;
+               return _le.readUByte();
+       }
+       public int read(byte[] b, int off, int len) {
+               int limit = Math.min(len, remaining());
+               if (limit == 0) {
+                       return 0;
+               }
+               readFully(b, off,limit);
+               return limit;
        }
 
-  public short getSid() {
-    return currentSid;
-  }
-
-  public short getLength() {
-    return currentLength;
-  }
-
-  public short getRecordOffset() {
-    return recordOffset;
-  }
-
-  public long getPos() {
-    return pos;
-  }
-
-  public boolean hasNextRecord() {
-    return nextSid != INVALID_SID_VALUE;
-  }
+       public short getSid() {
+               return (short) _currentSid;
+       }
 
-  /** Moves to the next record in the stream.
-   *
-   * <i>Note: The auto continue flag is reset to true</i>
-   */
-  public void nextRecord() throws RecordFormatException {
-    if ((currentLength != -1) && (currentLength != recordOffset)) {
-      System.out.println("WARN. Unread "+remaining()+" bytes of record 0x"+Integer.toHexString(currentSid));
-    }
-    currentSid = nextSid;
-    pos += LittleEndian.SHORT_SIZE;
-    autoContinue = true;
-    try {
-      recordOffset = 0;
-      currentLength = LittleEndian.readShort(in);
-      if (currentLength > MAX_RECORD_DATA_SIZE)
-        throw new RecordFormatException("The content of an excel record cannot exceed "+MAX_RECORD_DATA_SIZE+" bytes");
-      pos += LittleEndian.SHORT_SIZE;
-      in.read(data, 0, currentLength);
-
-      //Read the Sid of the next record
-      if (in.available() < EOFRecord.ENCODED_SIZE) {
-          if (in.available() > 0) {
-              // some scrap left over?
-              // ex45582-22397.xls has one extra byte after the last record
-              // Excel reads that file OK
-          }
-          nextSid = INVALID_SID_VALUE;
-      } else {
-          nextSid = LittleEndian.readShort(in);
-          if (nextSid == INVALID_SID_VALUE) {
-              throw new RecordFormatException("Found sid " + nextSid + " after record with sid 0x"
-                      + Integer.toHexString(currentSid).toUpperCase());
-          }
-      }
-    } catch (IOException ex) {
-      throw new RecordFormatException("Error reading bytes", ex);
-    }
-  }
+       /**
+        * Note - this method is expected to be called only when completed reading the current BIFF record.
+        * Calling this before reaching the end of the current record will cause all remaining data to be
+        * discarded
+        */
+       public boolean hasNextRecord() {
+               if (_currentDataLength != -1 && _currentDataLength != _currentDataOffset) {
+                       System.out.println("WARN. Unread "+remaining()+" bytes of record 0x"+Integer.toHexString(_currentSid));
+                       // discard unread data
+                       while (_currentDataOffset < _currentDataLength) {
+                               readByte();
+                       }
+               }
+               if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
+                       _nextSid = readNextSid();
+               }
+               return _nextSid != INVALID_SID_VALUE;
+       }
 
-  public void setAutoContinue(boolean enable) {
-    this.autoContinue = enable;
-  }
+       /**
+        * 
+        * @return the sid of the next record or {@link #INVALID_SID_VALUE} if at end of stream
+        */
+       private int readNextSid() {
+               int nAvailable  = _le.available();
+               if (nAvailable < EOFRecord.ENCODED_SIZE) {
+                       if (nAvailable > 0) {
+                               // some scrap left over?
+                               // ex45582-22397.xls has one extra byte after the last record
+                               // Excel reads that file OK
+                       }
+                       return INVALID_SID_VALUE;
+               }
+               int result = _le.readUShort();
+               if (result == INVALID_SID_VALUE) {
+                       throw new RecordFormatException("Found invalid sid (" + result + ")");
+               }
+               _currentDataLength = DATA_LEN_NEEDS_TO_BE_READ;
+               return result;
+       }
 
-  public boolean getAutoContinue() {
-    return autoContinue;
-  }
+       /** Moves to the next record in the stream.
+        *
+        * <i>Note: The auto continue flag is reset to true</i>
+        */
+       public void nextRecord() throws RecordFormatException {
+               if (_nextSid == INVALID_SID_VALUE) {
+                       throw new IllegalStateException("EOF - next record not available");
+               }
+               if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ) {
+                       throw new IllegalStateException("Cannot call nextRecord() without checking hasNextRecord() first");
+               }
+               _currentSid = _nextSid;
+               _currentDataOffset = 0;
+               _currentDataLength = _le.readUShort();
+               if (_currentDataLength > MAX_RECORD_DATA_SIZE) {
+                       throw new RecordFormatException("The content of an excel record cannot exceed "
+                                       + MAX_RECORD_DATA_SIZE + " bytes");
+               }
+       }
 
        private void checkRecordPosition(int requiredByteCount) {
 
-               if (remaining() < requiredByteCount) {
-                       if (isContinueNext() && autoContinue) {
-                               nextRecord();
-                       } else {
-                          throw new ArrayIndexOutOfBoundsException();
-                       }
+               int nAvailable = remaining();
+               if (nAvailable >= requiredByteCount) {
+                       // all OK
+                       return;
                }
+               if (nAvailable == 0 && isContinueNext()) {
+                       nextRecord();
+                       return;
+               }
+               throw new RecordFormatException("Not enough data (" + nAvailable 
+                               + ") to read requested (" + requiredByteCount +") bytes");
        }
 
        /**
@@ -150,11 +182,8 @@ public final class RecordInputStream extends InputStream implements LittleEndian
         */
        public byte readByte() {
                checkRecordPosition(LittleEndian.BYTE_SIZE);
-
-               byte result = data[recordOffset];
-               recordOffset += LittleEndian.BYTE_SIZE;
-               pos += LittleEndian.BYTE_SIZE;
-               return result;
+               _currentDataOffset += LittleEndian.BYTE_SIZE;
+               return _le.readByte();
        }
 
        /**
@@ -162,29 +191,20 @@ public final class RecordInputStream extends InputStream implements LittleEndian
         */
        public short readShort() {
                checkRecordPosition(LittleEndian.SHORT_SIZE);
-
-               short result = LittleEndian.getShort(data, recordOffset);
-               recordOffset += LittleEndian.SHORT_SIZE;
-               pos += LittleEndian.SHORT_SIZE;
-               return result;
+               _currentDataOffset += LittleEndian.SHORT_SIZE;
+               return _le.readShort();
        }
 
        public int readInt() {
                checkRecordPosition(LittleEndian.INT_SIZE);
-
-               int result = LittleEndian.getInt(data, recordOffset);
-               recordOffset += LittleEndian.INT_SIZE;
-               pos += LittleEndian.INT_SIZE;
-               return result;
+               _currentDataOffset += LittleEndian.INT_SIZE;
+               return _le.readInt();
        }
 
        public long readLong() {
                checkRecordPosition(LittleEndian.LONG_SIZE);
-
-               long result = LittleEndian.getLong(data, recordOffset);
-               recordOffset += LittleEndian.LONG_SIZE;
-               pos += LittleEndian.LONG_SIZE;
-               return result;
+               _currentDataOffset += LittleEndian.LONG_SIZE;
+               return _le.readLong();
        }
 
        /**
@@ -200,22 +220,18 @@ public final class RecordInputStream extends InputStream implements LittleEndian
         */
        public int readUShort() {
                checkRecordPosition(LittleEndian.SHORT_SIZE);
-
-               int result = LittleEndian.getUShort(data, recordOffset);
-               recordOffset += LittleEndian.SHORT_SIZE;
-               pos += LittleEndian.SHORT_SIZE;
-               return result;
+               _currentDataOffset += LittleEndian.SHORT_SIZE;
+               return _le.readUShort();
        }
 
        public double readDouble() {
                checkRecordPosition(LittleEndian.DOUBLE_SIZE);
-               long valueLongBits = LittleEndian.getLong(data, recordOffset);
+               _currentDataOffset += LittleEndian.DOUBLE_SIZE;
+               long valueLongBits = _le.readLong();
                double result = Double.longBitsToDouble(valueLongBits);
                if (Double.isNaN(result)) {
                        throw new RuntimeException("Did not expect to read NaN"); // (Because Excel typically doesn't write NaN
                }
-               recordOffset += LittleEndian.DOUBLE_SIZE;
-               pos += LittleEndian.DOUBLE_SIZE;
                return result;
        }
        public void readFully(byte[] buf) {
@@ -224,9 +240,8 @@ public final class RecordInputStream extends InputStream implements LittleEndian
 
        public void readFully(byte[] buf, int off, int len) {
                checkRecordPosition(len);
-               System.arraycopy(data, recordOffset, buf, off, len);
-               recordOffset+=len;
-               pos+=len;
+               _le.readFully(buf, off, len);
+               _currentDataOffset+=len;
        }
 
        public String readString() {
@@ -315,18 +330,19 @@ public final class RecordInputStream extends InputStream implements LittleEndian
     return new UnicodeString(this);
   }
 
-  /** Returns the remaining bytes for the current record.
-   *
-   * @return The remaining bytes of the current record.
-   */
-  public byte[] readRemainder() {
-    int size = remaining();
-    byte[] result = new byte[size];
-    System.arraycopy(data, recordOffset, result, 0, size);
-    recordOffset += size;
-    pos += size;
-    return result;
-  }
+       /** Returns the remaining bytes for the current record.
+        *
+         * @return The remaining bytes of the current record.
+         */
+       public byte[] readRemainder() {
+               int size = remaining();
+               if (size ==0) {
+                       return EMPTY_BYTE_ARRAY;
+               }
+               byte[] result = new byte[size];
+               readFully(result);
+               return result;
+       }
 
   /** Reads all byte data for the current record, including any
    *  that overlaps into any following continue records.
@@ -350,19 +366,34 @@ public final class RecordInputStream extends InputStream implements LittleEndian
     return out.toByteArray();
   }
 
-  /** The remaining number of bytes in the <i>current</i> record.
-   *
-   * @return The number of bytes remaining in the current record
-   */
-  public int remaining() {
-    return (currentLength - recordOffset);
-  }
+       /** The remaining number of bytes in the <i>current</i> record.
+        *
+        * @return The number of bytes remaining in the current record
+        */
+       public int remaining() {
+               if (_currentDataLength == DATA_LEN_NEEDS_TO_BE_READ) {
+                       // already read sid of next record. so current one is finished
+                       return 0;
+               }
+               return _currentDataLength - _currentDataOffset;
+       }
 
-  /** Returns true iif a Continue record is next in the excel stream
-   *
-   * @return True when a ContinueRecord is next.
-   */
-  public boolean isContinueNext() {
-    return (nextSid == ContinueRecord.sid);
-  }
+       /**
+        *
+        * @return <code>true</code> when a {@link ContinueRecord} is next.
+        */
+       private boolean isContinueNext() {
+               if (_currentDataLength != DATA_LEN_NEEDS_TO_BE_READ && _currentDataOffset != _currentDataLength) {
+                       throw new IllegalStateException("Should never be called before end of current record");
+               }
+               if (!hasNextRecord()) {
+                       return false;
+               }
+               // At what point are records continued?
+               //  - Often from within the char data of long strings (caller is within readStringCommon()).
+               //  - From UnicodeString construction (many different points - call via checkRecordPosition)
+               //  - During TextObjectRecord construction (just before the text, perhaps within the text, 
+               //    and before the formatting run data)
+               return _nextSid == ContinueRecord.sid;
+       }
 }
index 5b746e8d4b7dba7f0e4d0f7d181c3e2c6d136555..ad740e9b2e43ac2840920c515506925ce7f75795 100644 (file)
@@ -19,332 +19,181 @@ package org.apache.poi.hssf.record;
 
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.StringUtil;
 
 /**
- * Title:        Style Record<P>
+ * Title:        Style Record (0x0293)<p/>
  * Description:  Describes a builtin to the gui or user defined style<P>
  * REFERENCE:  PG 390 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
  * @author Andrew C. Oliver (acoliver at apache dot org)
  * @author aviks : string fixes for UserDefined Style
- * @version 2.0-pre
  */
 public final class StyleRecord extends Record {
-    public final static short sid = 0x0293;
-
-    private static final BitField fHighByte = BitFieldFactory.getInstance(0x01);
-
-    public final static short STYLE_USER_DEFINED = 0;
-    public final static short STYLE_BUILT_IN     = 1;
-
-    // shared by both user defined and builtin styles
-    private short             field_1_xf_index;   // TODO: bitfield candidate
-
-    // only for built in styles
-    private byte              field_2_builtin_style;
-    private byte              field_3_outline_style_level;
-
-    // only for user defined styles
-    private short              field_2_name_length; //OO doc says 16 bit length, so we believe
-    private byte               field_3_string_options;
-    private String             field_4_name;
-
-    public StyleRecord()
-    {
-    }
-
-    public StyleRecord(RecordInputStream in)
-    {
-        field_1_xf_index = in.readShort();
-        if (getType() == STYLE_BUILT_IN)
-        {
-            field_2_builtin_style       = in.readByte();
-            field_3_outline_style_level = in.readByte();
-        }
-        else if (getType() == STYLE_USER_DEFINED)
-        {
-            field_2_name_length = in.readShort();
-            
-            // Some files from Crystal Reports lack
-            //  the remaining fields, which is naughty
-            if(in.remaining() > 0) {
-                   field_3_string_options = in.readByte();
-                   
-                   byte[] string = in.readRemainder();
-                   if (fHighByte.isSet(field_3_string_options)) {
-                       field_4_name= StringUtil.getFromUnicodeBE(string, 0, field_2_name_length);
-                   } else {
-                       field_4_name=StringUtil.getFromCompressedUnicode(string, 0, field_2_name_length);
-                   }
-            }
-        }
-
-        // todo sanity check exception to make sure we're one or the other
-    }
-
-    /**
-     * set the entire index field (including the type) (see bit setters that reference this method)
-     *  @param index  bitmask
-     */
-
-    public void setIndex(short index)
-    {
-        field_1_xf_index = index;
-    }
-
-    // bitfields for field 1
-
-    /**
-     * set the type of the style (builtin or user-defined)
-     * @see #STYLE_USER_DEFINED
-     * @see #STYLE_BUILT_IN
-     * @param type of style (userdefined/builtin)
-     * @see #setIndex(short)
-     */
-
-    public void setType(short type)
-    {
-        field_1_xf_index = setField(field_1_xf_index, type, 0x8000, 15);
-    }
-
-    /**
-     * set the actual index of the style extended format record
-     * @see #setIndex(short)
-     * @param index of the xf record
-     */
-
-    public void setXFIndex(short index)
-    {
-        field_1_xf_index = setField(field_1_xf_index, index, 0x1FFF, 0);
-    }
-
-    // end bitfields
-    // only for user defined records
-
-    /**
-     * if this is a user defined record set the length of the style name
-     * @param length of the style's name
-     * @see #setName(String)
-     */
-
-    public void setNameLength(byte length)
-    {
-        field_2_name_length = length;
-    }
-
-    /**
-     * set the style's name
-     * @param name of the style
-     * @see #setNameLength(byte)
-     */
-
-    public void setName(String name)
-    {
-        field_4_name = name;
-        
-        // Fix up the length
-        field_2_name_length = (short)name.length();
-        //TODO set name string options
-    }
-
-    // end user defined
-    // only for buildin records
-
-    /**
-     * if this is a builtin style set teh number of the built in style
-     * @param  builtin style number (0-7)
-     *
-     */
-
-    public void setBuiltin(byte builtin)
-    {
-        field_2_builtin_style = builtin;
-    }
-
-    /**
-     * set the row or column level of the style (if builtin 1||2)
-     */
-
-    public void setOutlineStyleLevel(byte level)
-    {
-        field_3_outline_style_level = level;
-    }
-
-    // end builtin records
-    // field 1
-
-    /**
-     * get the entire index field (including the type) (see bit getters that reference this method)
-     *  @return bitmask
-     */
-
-    public short getIndex()
-    {
-        return field_1_xf_index;
-    }
-
-    // bitfields for field 1
-
-    /**
-     * get the type of the style (builtin or user-defined)
-     * @see #STYLE_USER_DEFINED
-     * @see #STYLE_BUILT_IN
-     * @return type of style (userdefined/builtin)
-     * @see #getIndex()
-     */
-
-    public short getType()
-    {
-        return ( short ) ((field_1_xf_index & 0x8000) >> 15);
-    }
-
-    /**
-     * get the actual index of the style extended format record
-     * @see #getIndex()
-     * @return index of the xf record
-     */
-
-    public short getXFIndex()
-    {
-        return ( short ) (field_1_xf_index & 0x1FFF);
-    }
-
-    // end bitfields
-    // only for user defined records
-
-    /**
-     * if this is a user defined record get the length of the style name
-     * @return length of the style's name
-     * @see #getName()
-     */
-
-    public short getNameLength()
-    {
-        return field_2_name_length;
-    }
-
-    /**
-     * get the style's name
-     * @return name of the style
-     * @see #getNameLength()
-     */
-
-    public String getName()
-    {
-        return field_4_name;
-    }
-
-    // end user defined
-    // only for buildin records
-
-    /**
-     * if this is a builtin style get the number of the built in style
-     * @return  builtin style number (0-7)
-     *
-     */
-
-    public byte getBuiltin()
-    {
-        return field_2_builtin_style;
-    }
-
-    /**
-     * get the row or column level of the style (if builtin 1||2)
-     */
-
-    public byte getOutlineStyleLevel()
-    {
-        return field_3_outline_style_level;
-    }
-
-    // end builtin records
-    public String toString()
-    {
-        StringBuffer buffer = new StringBuffer();
-
-        buffer.append("[STYLE]\n");
-        buffer.append("    .xf_index_raw    = ")
-            .append(Integer.toHexString(getIndex())).append("\n");
-        buffer.append("        .type        = ")
-            .append(Integer.toHexString(getType())).append("\n");
-        buffer.append("        .xf_index    = ")
-            .append(Integer.toHexString(getXFIndex())).append("\n");
-        if (getType() == STYLE_BUILT_IN)
-        {
-            buffer.append("    .builtin_style   = ")
-                .append(Integer.toHexString(getBuiltin())).append("\n");
-            buffer.append("    .outline_level   = ")
-                .append(Integer.toHexString(getOutlineStyleLevel()))
-                .append("\n");
-        }
-        else if (getType() == STYLE_USER_DEFINED)
-        {
-            buffer.append("    .name_length     = ")
-                .append(Integer.toHexString(getNameLength())).append("\n");
-            buffer.append("    .name            = ").append(getName())
-                .append("\n");
-        }
-        buffer.append("[/STYLE]\n");
-        return buffer.toString();
-    }
-
-    private short setField(int fieldValue, int new_value, int mask,
-                           int shiftLeft)
-    {
-        return ( short ) ((fieldValue & ~mask)
-                          | ((new_value << shiftLeft) & mask));
-    }
-
-    public int serialize(int offset, byte [] data)
-    {
-        LittleEndian.putShort(data, 0 + offset, sid);
-        if (getType() == STYLE_BUILT_IN)
-        {
-            LittleEndian.putShort(data, 2 + offset,
-                                  (( short ) 0x04));   // 4 bytes (8 total)
-        }
-        else
-        {
-            LittleEndian.putShort(data, 2 + offset,
-                                  (( short ) (getRecordSize()-4)));
-        }
-        LittleEndian.putShort(data, 4 + offset, getIndex());
-        if (getType() == STYLE_BUILT_IN)
-        {
-            data[ 6 + offset ] = getBuiltin();
-            data[ 7 + offset ] = getOutlineStyleLevel();
-        }
-        else
-        {
-            LittleEndian.putShort(data, 6 + offset , getNameLength());
-            data[8+offset]=this.field_3_string_options;
-            StringUtil.putCompressedUnicode(getName(), data, 9 + offset);
-        }
-        return getRecordSize();
-    }
-
-    public int getRecordSize()
-    {
-        int retval;
-
-        if (getType() == STYLE_BUILT_IN)
-        {
-            retval = 8;
-        }
-        else
-        {
-             if (fHighByte.isSet(field_3_string_options))  {
-                 retval= 9+2*getNameLength();
-             }else {
-                retval = 9 + getNameLength();
-             }
-        }
-        return retval;
-    }
-
-    public short getSid()
-    {
-        return sid;
-    }
+       public final static short sid = 0x0293;
+
+       private static final BitField is16BitUnicodeFlag = BitFieldFactory.getInstance(0x01);
+
+       private static final BitField styleIndexMask = BitFieldFactory.getInstance(0x0FFF);
+       private static final BitField isBuiltinFlag  = BitFieldFactory.getInstance(0x8000);
+
+       /** shared by both user defined and built-in styles */
+       private int field_1_xf_index;
+
+       // only for built in styles
+       private int field_2_builtin_style;
+       private int field_3_outline_style_level;
+
+       // only for user defined styles
+       private int field_3_string_options;
+       private String field_4_name;
+
+       /**
+        * creates a new style record, initially set to 'built-in'
+        */
+       public StyleRecord() {
+               field_1_xf_index = isBuiltinFlag.set(field_1_xf_index);
+       }
+
+       public StyleRecord(RecordInputStream in) {
+               field_1_xf_index = in.readShort();
+               if (isBuiltin()) {
+                       field_2_builtin_style      = in.readByte();
+                       field_3_outline_style_level = in.readByte();
+               } else {
+                       int field_2_name_length = in.readShort();
+                       
+                       if(in.remaining() < 1) {
+                               // Some files from Crystal Reports lack the is16BitUnicode byte
+                               //  the remaining fields, which is naughty
+                               if (field_2_name_length != 0) {
+                                       throw new RecordFormatException("Ran out of data reading style record");
+                               }
+                               // guess this is OK if the string length is zero
+                               field_4_name = "";
+                       } else {
+                               
+                               int is16BitUnicode = in.readByte();
+                               if (is16BitUnicodeFlag.isSet(is16BitUnicode)) {
+                                       field_4_name = StringUtil.readUnicodeLE(in, field_2_name_length);
+                               } else {
+                                       field_4_name = StringUtil.readCompressedUnicode(in, field_2_name_length);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * set the actual index of the style extended format record
+        * @param xfIndex of the xf record
+        */
+       public void setXFIndex(int xfIndex) {
+               field_1_xf_index = styleIndexMask.setValue(field_1_xf_index, xfIndex);
+       }
+
+       /**
+        * get the actual index of the style extended format record
+        * @see #getIndex()
+        * @return index of the xf record
+        */
+       public int getXFIndex() {
+               return styleIndexMask.getValue(field_1_xf_index);
+       }
+
+       /**
+        * set the style's name
+        * @param name of the style
+        */
+       public void setName(String name) {
+               field_4_name = name;
+               field_3_string_options = StringUtil.hasMultibyte(name) ? 0x01 : 0x00;
+               field_1_xf_index = isBuiltinFlag.clear(field_1_xf_index);
+       }
+
+       /**
+        * if this is a builtin style set the number of the built in style
+        * @param  builtinStyleId style number (0-7)
+        *
+        */
+       public void setBuiltinStyle(int builtinStyleId) {
+               field_1_xf_index = isBuiltinFlag.set(field_1_xf_index);
+               field_2_builtin_style = builtinStyleId;
+       }
+
+       /**
+        * set the row or column level of the style (if builtin 1||2)
+        */
+       public void setOutlineStyleLevel(int level) {
+               field_3_outline_style_level = level & 0x00FF;
+       }
+
+       public boolean isBuiltin(){
+               return isBuiltinFlag.isSet(field_1_xf_index);
+       }
+
+       /**
+        * get the style's name
+        * @return name of the style
+        */
+       public String getName() {
+               return field_4_name;
+       }
+
+       public String toString() {
+               StringBuffer sb = new StringBuffer();
+
+               sb.append("[STYLE]\n");
+               sb.append("    .xf_index_raw =").append(HexDump.shortToHex(field_1_xf_index)).append("\n");
+               sb.append("        .type     =").append(isBuiltin() ? "built-in" : "user-defined").append("\n");
+               sb.append("        .xf_index =").append(HexDump.shortToHex(getXFIndex())).append("\n");
+               if (isBuiltin()){
+                       sb.append("    .builtin_style=").append(HexDump.byteToHex(field_2_builtin_style)).append("\n");
+                       sb.append("    .outline_level=").append(HexDump.byteToHex(field_3_outline_style_level)).append("\n");
+               } else {
+                        sb.append("    .name        =").append(getName()).append("\n");
+               }
+               sb.append("[/STYLE]\n");
+               return sb.toString();
+       }
+
+       
+       private int getDataSize() {
+               if (isBuiltin()) {
+                       return 4; // short, byte, byte
+               }
+               int size = 2 + 3; // short
+               if (is16BitUnicodeFlag.isSet(field_3_string_options))  {
+                       size += 2 * field_4_name.length();
+               } else {
+                       size += field_4_name.length();
+               }
+               return size;
+       }
+
+       public int serialize(int offset, byte [] data) {
+               int dataSize = getDataSize();
+               LittleEndian.putShort(data, 0 + offset, sid);
+               LittleEndian.putUShort(data, 2 + offset, dataSize);
+               
+               LittleEndian.putUShort(data, 4 + offset, field_1_xf_index);
+               if (isBuiltin()) {
+                       LittleEndian.putByte(data, 6 + offset, field_2_builtin_style);
+                       LittleEndian.putByte(data, 7 + offset, field_3_outline_style_level);
+               } else {
+                       LittleEndian.putUShort(data, 6 + offset, field_4_name.length());
+                       LittleEndian.putByte(data, 8 + offset, field_3_string_options);
+                       StringUtil.putCompressedUnicode(getName(), data, 9 + offset);
+               }
+               return 4+dataSize;
+       }
+
+       public int getRecordSize() {
+               return 4 + getDataSize();
+       }
+
+       public short getSid()
+       {
+               return sid;
+       }
 }
index a5263b1ba92afe7b4c8856e6378327708d4a91ce..78bcb4eee2e697540cd4eb5c4d1b55895ad518b1 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.poi.hssf.record.formula.Ref3DPtg;
 import org.apache.poi.hssf.record.formula.RefPtg;
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayInputStream;
 import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.LittleEndianOutputStream;
@@ -209,17 +210,12 @@ public abstract class SubRecord {
                        out.writeShort(_unknownShort13);
                }
                private static Ptg readRefPtg(byte[] formulaRawBytes) {
-                       byte[] data = new byte[formulaRawBytes.length + 4];
-                       LittleEndian.putUShort(data, 0, -5555);
-                       LittleEndian.putUShort(data, 2, formulaRawBytes.length);
-                       System.arraycopy(formulaRawBytes, 0, data, 4, formulaRawBytes.length);
-                       RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
-                       in.nextRecord();
-                       byte ptgSid = in.readByte();
+                       LittleEndianInput in = new LittleEndianByteArrayInputStream(formulaRawBytes);
+                       byte ptgSid = in.readByte();
                        switch(ptgSid) {
                                case AreaPtg.sid:   return new AreaPtg(in);
                                case Area3DPtg.sid: return new Area3DPtg(in);
-                               case RefPtg.sid:        return new RefPtg(in);
+                               case RefPtg.sid:    return new RefPtg(in);
                                case Ref3DPtg.sid:  return new Ref3DPtg(in);
                        }
                        return null;
index 30e337e2d53a8e13c0b0d42873040732b4d67401..78d77c5cbf6ea84e85eccdcc89db661e4f59a929 100644 (file)
@@ -84,9 +84,11 @@ public final class SupBookRecord extends Record {
      * @param offset of the record's data (provided a big array of the file)
      */
     public SupBookRecord(RecordInputStream in) {
+       int recLen = in.remaining();
+       
         field_1_number_of_sheets = in.readShort();
         
-        if(in.getLength() > SMALL_RECORD_SIZE) {
+        if(recLen > SMALL_RECORD_SIZE) {
             // 5.38.1 External References
             _isAddInFunctions = false;
 
index 6529dc93f8664902f403558b6d4b0a2956f9cc99..4bb065e91e23a2f6eeee58b9d074e060bed8dbf7 100644 (file)
@@ -25,6 +25,8 @@ import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.HexDump;
 import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * The TXO record (0x01B6) is used to define the properties of a text box. It is
@@ -129,13 +131,7 @@ public final class TextObjectRecord extends Record {
                _text = new HSSFRichTextString(text);
 
                if (field_7_formattingDataLength > 0) {
-                       if (in.isContinueNext() && in.remaining() == 0) {
-                               in.nextRecord();
-                               processFontRuns(in, _text, field_7_formattingDataLength);
-                       } else {
-                               throw new RecordFormatException(
-                                               "Expected Continue Record to hold font runs for TextObjectRecord");
-                       }
+                       processFontRuns(in, _text, field_7_formattingDataLength);
                }
        }
 
@@ -154,10 +150,6 @@ public final class TextObjectRecord extends Record {
                        throw new RecordFormatException("Bad format run data length " + formattingRunDataLength
                                        + ")");
                }
-               if (in.remaining() != formattingRunDataLength) {
-                       throw new RecordFormatException("Expected " + formattingRunDataLength
-                                       + " bytes but got " + in.remaining());
-               }
                int nRuns = formattingRunDataLength / FORMAT_RUN_ENCODED_SIZE;
                for (int i = 0; i < nRuns; i++) {
                        short index = in.readShort();
@@ -190,36 +182,31 @@ public final class TextObjectRecord extends Record {
 
        private int serializeTXORecord(int offset, byte[] data) {
                int dataSize = getDataSize();
+               int recSize = dataSize+4;
+               LittleEndianOutput out = new LittleEndianByteArrayOutputStream(data, offset, recSize);
                
-               LittleEndian.putUShort(data, 0 + offset, TextObjectRecord.sid);
-               LittleEndian.putUShort(data, 2 + offset, dataSize);
-
+               out.writeShort(TextObjectRecord.sid);
+               out.writeShort(dataSize);
                
-               LittleEndian.putUShort(data, 4 + offset, field_1_options);
-               LittleEndian.putUShort(data, 6 + offset, field_2_textOrientation);
-               LittleEndian.putUShort(data, 8 + offset, field_3_reserved4);
-               LittleEndian.putUShort(data, 10 + offset, field_4_reserved5);
-               LittleEndian.putUShort(data, 12 + offset, field_5_reserved6);
-               LittleEndian.putUShort(data, 14 + offset, _text.length());
-               LittleEndian.putUShort(data, 16 + offset, getFormattingDataLength());
-               LittleEndian.putInt(data, 18 + offset, field_8_reserved7);
+               out.writeShort(field_1_options);
+               out.writeShort(field_2_textOrientation);
+               out.writeShort(field_3_reserved4);
+               out.writeShort(field_4_reserved5);
+               out.writeShort(field_5_reserved6);
+               out.writeShort(_text.length());
+               out.writeShort(getFormattingDataLength());
+               out.writeInt(field_8_reserved7);
                
                if (_linkRefPtg != null) {
-                       int pos = offset+22;
                        int formulaSize = _linkRefPtg.getSize();
-                       LittleEndian.putUShort(data, pos, formulaSize);
-                       pos += LittleEndian.SHORT_SIZE;
-                       LittleEndian.putInt(data, pos, _unknownPreFormulaInt);
-                       pos += LittleEndian.INT_SIZE;
-                       _linkRefPtg.writeBytes(data, pos);
-                       pos += formulaSize;
+                       out.writeShort(formulaSize);
+                       out.writeInt(_unknownPreFormulaInt);
+                       _linkRefPtg.write(out);
                        if (_unknownPostFormulaByte != null) {
-                               LittleEndian.putByte(data, pos, _unknownPostFormulaByte.byteValue());
-                               pos += LittleEndian.BYTE_SIZE;
+                               out.writeByte(_unknownPostFormulaByte.byteValue());
                        }
                }
-               
-               return 4 + dataSize;
+               return recSize;
        }
 
        private int serializeTrailingRecords(int offset, byte[] data) {
index 4258d0a6d5164e2cc4000c3ef579e520a128181c..0494aa98abeb8d17bcce69af01ca6406faeec97b 100644 (file)
@@ -36,13 +36,8 @@ import java.util.Collections;
  * @author  Andrew C. Oliver
  * @author Marc Johnson (mjohnson at apache dot org)
  * @author Glen Stampoultzis (glens at apache.org)
- * @version 2.0-pre
  */
-
-public class UnicodeString
-    implements Comparable
-{
-    public final static short sid = 0xFFF;
+public final class UnicodeString implements Comparable {
     private short             field_1_charCount;     // = 0;
     private byte              field_2_optionflags;   // = 0;
     private String            field_3_string;        // = null;
@@ -53,8 +48,8 @@ public class UnicodeString
     private  static final BitField   richText  = BitFieldFactory.getInstance(0x8);
 
     public static class FormatRun implements Comparable {
-      private short character;
-      private short fontIndex;
+      short character;
+      short fontIndex;
 
       public FormatRun(short character, short fontIndex) {
         this.character = character;
@@ -102,15 +97,6 @@ public class UnicodeString
       setString(str);
     }
 
-    /**
-     * construct a unicode string record and fill its fields, ID is ignored
-     * @param in the RecordInputstream to read the record from
-     */
-
-    public UnicodeString(RecordInputStream in)
-    {
-      fillFields(in); // TODO - inline
-    }
 
 
     public int hashCode()
@@ -142,9 +128,9 @@ public class UnicodeString
                 && field_3_string.equals(other.field_3_string));
         if (!eq) return false;
 
-        //Ok string appears to be equal but now lets compare formatting runs
+        //OK string appears to be equal but now lets compare formatting runs
         if ((field_4_format_runs == null) && (other.field_4_format_runs == null))
-          //Strings are equal, and there are not formtting runs.
+          //Strings are equal, and there are not formatting runs.
           return true;
         if (((field_4_format_runs == null) && (other.field_4_format_runs != null)) ||
              (field_4_format_runs != null) && (other.field_4_format_runs == null))
@@ -186,10 +172,10 @@ public class UnicodeString
     }
 
     /**
+     * construct a unicode string record and fill its fields, ID is ignored
      * @param in the RecordInputstream to read the record from
      */
-    protected void fillFields(RecordInputStream in)
-        {
+    public UnicodeString(RecordInputStream in) {
         field_1_charCount   = in.readShort();
         field_2_optionflags = in.readByte();
 
@@ -206,35 +192,13 @@ public class UnicodeString
             extensionLength = in.readInt();
         }
 
-        //Now need to get the string data.
-        //Turn off autocontinuation so that we can catch the continue boundary
-        in.setAutoContinue(false);
-        StringBuffer tmpString = new StringBuffer(field_1_charCount);
-        int stringCharCount = field_1_charCount;
         boolean isCompressed = ((field_2_optionflags & 1) == 0);
-        while (stringCharCount != 0) {
-          if (in.remaining() == 0) {
-            if (in.isContinueNext()) {
-              in.nextRecord();
-              //Check if we are now reading, compressed or uncompressed unicode.
-              byte optionflags = in.readByte();
-              isCompressed = ((optionflags & 1) == 0);
-            } else
-              throw new RecordFormatException("Expected continue record.");
-          }
-          if (isCompressed) {
-            char ch = (char)in.readUByte(); // avoid sex
-            tmpString.append(ch);
-          } else {
-            char ch = (char) in.readShort();
-            tmpString.append(ch);
-          }
-          stringCharCount --;
+        if (isCompressed) {
+               field_3_string = in.readCompressedUnicode(field_1_charCount);
+        } else {
+               field_3_string = in.readUnicodeLEString(field_1_charCount);
         }
-        field_3_string = tmpString.toString();
-        //Turn back on autocontinuation
-        in.setAutoContinue(true);
-
 
         if (isRichText() && (runCount > 0)) {
           field_4_format_runs = new ArrayList(runCount);
@@ -305,13 +269,8 @@ public class UnicodeString
     }
 
     /**
-     * get the actual string this contains as a java String object
-     *
-     *
-     * @return String
-     *
+     * @return the actual string this contains as a java String object
      */
-
     public String getString()
     {
         return field_3_string;
@@ -341,7 +300,7 @@ public class UnicodeString
             }
         }
         if (useUTF16)
-          //Set the uncomressed bit
+          //Set the uncompressed bit
           field_2_optionflags = highByte.setByte(field_2_optionflags);
         else field_2_optionflags = highByte.clearByte(field_2_optionflags);
     }
@@ -392,7 +351,7 @@ public class UnicodeString
 
       //Make sure that we now say that we are a rich string
       field_2_optionflags = richText.setByte(field_2_optionflags);
-        }
+    }
 
     public Iterator formatIterator() {
       if (field_4_format_runs != null)
@@ -497,8 +456,8 @@ public class UnicodeString
 
         LittleEndian.putShort(data, offset, ContinueRecord.sid);
         offset+=2;
-        //Record the location of the last continue legnth position, but dont write
-        //anything there yet (since we dont know what it will be!)
+        //Record the location of the last continue length position, but don't write
+        //anything there yet (since we don't know what it will be!)
         stats.lastLengthPos = offset;
         offset += 2;
 
@@ -506,7 +465,7 @@ public class UnicodeString
         stats.remainingSize = SSTRecord.MAX_RECORD_SIZE-4;
       }
       return offset;
-        }
+    }
 
     public int serialize(UnicodeRecordStats stats, final int offset, byte [] data)
     {
@@ -514,7 +473,6 @@ public class UnicodeString
 
       //Basic string overhead
       pos = writeContinueIfRequired(stats, 3, pos, data);
-        // byte[] retval = new byte[ 3 + (getString().length() * charsize)];
       LittleEndian.putShort(data, pos, getCharCount());
       pos += 2;
       data[ pos ] = getOptionFlags();
@@ -568,39 +526,39 @@ public class UnicodeString
       //Check to see if the offset occurs mid string, if so then we need to add
       //the byte to start with that represents the first byte of the continue record.
       if (strSize > stats.remainingSize) {
-        //Ok the offset occurs half way through the string, that means that
+        //OK the offset occurs half way through the string, that means that
         //we need an extra byte after the continue record ie we didnt finish
         //writing out the string the 1st time through
 
         //But hang on, how many continue records did we span? What if this is
         //a REALLY long string. We need to work this all out.
-        int ammountThatCantFit = strSize;
+        int amountThatCantFit = strSize;
         int strPos = 0;
-        while (ammountThatCantFit > 0) {
-          int ammountWritten = Math.min(stats.remainingSize, ammountThatCantFit);
-          //Make sure that the ammount that cant fit takes into account
+        while (amountThatCantFit > 0) {
+          int amountWritten = Math.min(stats.remainingSize, amountThatCantFit);
+          //Make sure that the amount that can't fit takes into account
           //whether we are writing double byte unicode
           if (isUncompressedUnicode()) {
             //We have the '-1' here because whether this is the first record or
             //subsequent continue records, there is always the case that the
-            //number of bytes in a string on doube byte boundaries is actually odd.
-            if ( ( (ammountWritten ) % 2) == 1)
-              ammountWritten--;
+            //number of bytes in a string on double byte boundaries is actually odd.
+            if ( ( (amountWritten ) % 2) == 1)
+              amountWritten--;
           }
-          System.arraycopy(strBytes, strPos, data, pos, ammountWritten);
-          pos += ammountWritten;
-          strPos += ammountWritten;
-          stats.recordSize += ammountWritten;
-          stats.remainingSize -= ammountWritten;
+          System.arraycopy(strBytes, strPos, data, pos, amountWritten);
+          pos += amountWritten;
+          strPos += amountWritten;
+          stats.recordSize += amountWritten;
+          stats.remainingSize -= amountWritten;
 
           //Ok lets subtract what we can write
-          ammountThatCantFit -= ammountWritten;
+          amountThatCantFit -= amountWritten;
 
           //Each iteration of this while loop is another continue record, unless
           //everything  now fits.
-          if (ammountThatCantFit > 0) {
+          if (amountThatCantFit > 0) {
             //We know that a continue WILL be requied, but use this common method
-            pos = writeContinueIfRequired(stats, ammountThatCantFit, pos, data);
+            pos = writeContinueIfRequired(stats, amountThatCantFit, pos, data);
 
             //The first byte after a continue mid string is the extra byte to
             //indicate if this run is compressed or not.
@@ -686,7 +644,7 @@ public class UnicodeString
         return highByte.isSet(getOptionFlags());
     }
 
-    /** Returns the size of this record, given the ammount of record space
+    /** Returns the size of this record, given the amount of record space
      * remaining, it will also include the size of writing a continue record.
      */
 
@@ -833,13 +791,6 @@ public class UnicodeString
       }
     }
 
-
-
-    public short getSid()
-    {
-        return sid;
-    }
-
     public int compareTo(Object obj)
     {
         UnicodeString str = ( UnicodeString ) obj;
@@ -877,7 +828,7 @@ public class UnicodeString
         }
 
         //Well the format runs are equal as well!, better check the ExtRst data
-        //Which by the way we dont know how to decode!
+        //Which by the way we don't know how to decode!
         if ((field_5_ext_rst == null) && (str.field_5_ext_rst == null))
           return 0;
         if ((field_5_ext_rst == null) && (str.field_5_ext_rst != null))
index d73687f1866a07f441cf4c72bdd3a3c7656c7da3..6b005c7f4403f8fb509ced1ce351c7445771297b 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
+import java.util.Arrays;
+
 import org.apache.poi.util.LittleEndian;
 import org.apache.poi.util.StringUtil;
 
 /**
- * Title:        Write Access Record<P>
- * Description:  Stores the username of that who owns the spreadsheet generator
- *               (on unix the user's login, on Windoze its the name you typed when
- *                you installed the thing)<P>
- * REFERENCE:  PG 424 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
+ * Title: Write Access Record (0x005C)<p/>
+ * 
+ * Description: Stores the username of that who owns the spreadsheet generator (on unix the user's 
+ * login, on Windoze its the name you typed when you installed the thing)
+ * <p/>
+ * REFERENCE: PG 424 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)
+ * <p/>
+ * 
  * @author Andrew C. Oliver (acoliver at apache dot org)
- * @version 2.0-pre
  */
-
-public class WriteAccessRecord
-    extends Record
-{
-    public final static short sid = 0x5c;
-    private String            field_1_username;
-
-    public WriteAccessRecord()
-    {
-    }
-
-    public WriteAccessRecord(RecordInputStream in)
-    {
-        byte[] data = in.readRemainder();
-        //The string is always 112 characters (padded with spaces), therefore
-        //this record can not be continued.
-
-        //What a wierd record, it is not really a unicode string because the
-        //header doesnt provide a correct size indication.???
-        //But the header is present, so we need to skip over it.
-        //Odd, Odd, Odd ;-)
-        field_1_username = StringUtil.getFromCompressedUnicode(data, 3, data.length - 3);
-    }
-
-    /**
-     * set the username for the user that created the report.  HSSF uses the logged in user.
-     * @param username of the user who  is logged in (probably "tomcat" or "apache")
-     */
-
-    public void setUsername(String username)
-    {
-        field_1_username = username;
-    }
-
-    /**
-     * get the username for the user that created the report.  HSSF uses the logged in user.  On
-     * natively created M$ Excel sheet this would be the name you typed in when you installed it
-     * in most cases.
-     * @return username of the user who  is logged in (probably "tomcat" or "apache")
-     */
-
-    public String getUsername()
-    {
-        return field_1_username;
-    }
-
-    public String toString()
-    {
-        StringBuffer buffer = new StringBuffer();
-
-        buffer.append("[WRITEACCESS]\n");
-        buffer.append("    .name            = ")
-            .append(field_1_username.toString()).append("\n");
-        buffer.append("[/WRITEACCESS]\n");
-        return buffer.toString();
-    }
-
-    public int serialize(int offset, byte [] data)
-    {
-        String       username = getUsername();
-        StringBuffer temp     = new StringBuffer(0x70 - (0x3));
-
-        temp.append(username);
-        while (temp.length() < 0x70 - 0x3)
-        {
-            temp.append(
-                " ");   // (70 = fixed lenght -3 = the overhead bits of unicode string)
-        }
-        username = temp.toString();
-        UnicodeString str = new UnicodeString(username);
-        str.setOptionFlags(( byte ) 0x0);
-
-        LittleEndian.putShort(data, 0 + offset, sid);
-        LittleEndian.putShort(data, 2 + offset, (short)112);   // 112 bytes (115 total)
-        UnicodeString.UnicodeRecordStats stats = new UnicodeString.UnicodeRecordStats();
-        stats.recordSize += 4;
-        stats.remainingSize-= 4;
-        str.serialize(stats, 4 + offset, data);
-
-        return getRecordSize();
-    }
-
-    public int getRecordSize()
-    {
-        return 116;
-    }
-
-    public short getSid()
-    {
-        return sid;
-    }
+public final class WriteAccessRecord extends Record {
+       private static final byte PAD_CHAR = (byte) ' ';
+       public final static short sid = 0x005C;
+       private static final int DATA_SIZE = 112;
+       private String field_1_username;
+       /** this record is always padded to a constant length */
+       private byte[] padding;
+
+       public WriteAccessRecord() {
+               setUsername("");
+               padding = new byte[DATA_SIZE - 3];
+       }
+
+       public WriteAccessRecord(RecordInputStream in) {
+               if (in.remaining() > DATA_SIZE) {
+                       throw new RecordFormatException("Expected data size (" + DATA_SIZE + ") but got ("
+                                       + in.remaining() + ")");
+               }
+               // The string is always 112 characters (padded with spaces), therefore
+               // this record can not be continued.
+
+               int nChars = in.readUShort();
+               int is16BitFlag = in.readUByte();
+               int expectedPadSize = DATA_SIZE - 3;
+               if ((is16BitFlag & 0x01) == 0x00) {
+                       field_1_username = StringUtil.readCompressedUnicode(in, nChars);
+                       expectedPadSize -= nChars;
+               } else {
+                       field_1_username = StringUtil.readUnicodeLE(in, nChars);
+                       expectedPadSize -= nChars * 2;
+               }
+               padding = new byte[expectedPadSize];
+               int padSize = in.remaining();
+               in.readFully(padding, 0, padSize);
+               if (padSize < expectedPadSize) {
+                       // this occurs in a couple of test examples: "42564.xls",
+                       // "bug_42794.xls"
+                       Arrays.fill(padding, padSize, expectedPadSize, PAD_CHAR);
+               }
+       }
+
+       /**
+        * set the username for the user that created the report. HSSF uses the
+        * logged in user.
+        * 
+        * @param username of the user who is logged in (probably "tomcat" or "apache")
+        */
+       public void setUsername(String username) {
+               boolean is16bit = StringUtil.hasMultibyte(username);
+               int encodedByteCount = 3 + username.length() * (is16bit ? 2 : 1);
+               int paddingSize = DATA_SIZE - encodedByteCount;
+               if (paddingSize < 0) {
+                       throw new IllegalArgumentException("Name is too long: " + username);
+               }
+               padding = new byte[paddingSize];
+               Arrays.fill(padding, PAD_CHAR);
+
+               field_1_username = username;
+       }
+
+       /**
+        * get the username for the user that created the report. HSSF uses the
+        * logged in user. On natively created M$ Excel sheet this would be the name
+        * you typed in when you installed it in most cases.
+        * 
+        * @return username of the user who is logged in (probably "tomcat" or "apache")
+        */
+       public String getUsername() {
+               return field_1_username;
+       }
+
+       public String toString() {
+               StringBuffer buffer = new StringBuffer();
+
+               buffer.append("[WRITEACCESS]\n");
+               buffer.append("    .name            = ").append(field_1_username.toString()).append("\n");
+               buffer.append("[/WRITEACCESS]\n");
+               return buffer.toString();
+       }
+
+       public int serialize(int offset, byte[] data) {
+               String username = getUsername();
+               boolean is16bit = StringUtil.hasMultibyte(username);
+
+               LittleEndian.putUShort(data, 0 + offset, sid);
+               LittleEndian.putUShort(data, 2 + offset, DATA_SIZE);
+               LittleEndian.putUShort(data, 4 + offset, username.length());
+               LittleEndian.putByte(data, 6 + offset, is16bit ? 0x01 : 0x00);
+               int pos = offset + 7;
+               if (is16bit) {
+                       StringUtil.putUnicodeLE(username, data, pos);
+                       pos += username.length() * 2;
+               } else {
+                       StringUtil.putCompressedUnicode(username, data, pos);
+                       pos += username.length();
+               }
+               System.arraycopy(padding, 0, data, pos, padding.length);
+               return 4 + DATA_SIZE;
+       }
+
+       public int getRecordSize() {
+               return 4 + DATA_SIZE;
+       }
+
+       public short getSid() {
+               return sid;
+       }
 }
index 12f26bfdee5fdbd44df17eaca84923114eef2729..8304eb0ee33a3f5db87dcb285ef8a4553b928b5e 100755 (executable)
 
 package org.apache.poi.hssf.record.constant;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.record.UnicodeString;
 import org.apache.poi.hssf.record.UnicodeString.UnicodeRecordStats;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
+import org.apache.poi.util.StringUtil;
 
 /**
  * To support Constant Values (2.5.7) as required by the CRN record.
@@ -47,7 +48,7 @@ public final class ConstantValueParser {
                // no instances of this class
        }
 
-       public static Object[] parse(RecordInputStream in, int nValues) {
+       public static Object[] parse(LittleEndianInput in, int nValues) {
                Object[] result = new Object[nValues];
                for (int i = 0; i < result.length; i++) {
                        result[i] = readAConstantValue(in);
@@ -55,7 +56,7 @@ public final class ConstantValueParser {
                return result;
        }
 
-       private static Object readAConstantValue(RecordInputStream in) {
+       private static Object readAConstantValue(LittleEndianInput in) {
                byte grbit = in.readByte();
                switch(grbit) {
                        case TYPE_EMPTY:
@@ -64,7 +65,7 @@ public final class ConstantValueParser {
                        case TYPE_NUMBER:
                                return new Double(in.readDouble());
                        case TYPE_STRING:
-                               return in.readUnicodeString();
+                               return new UnicodeString(StringUtil.readUnicodeString(in));
                        case TYPE_BOOLEAN:
                                return readBoolean(in);
                        case TYPE_ERROR_CODE:
@@ -77,7 +78,7 @@ public final class ConstantValueParser {
                throw new RuntimeException("Unknown grbit value (" + grbit + ")");
        }
 
-       private static Object readBoolean(RecordInputStream in) {
+       private static Object readBoolean(LittleEndianInput in) {
                byte val = (byte)in.readLong(); // 7 bytes 'not used'
                switch(val) {
                        case FALSE_ENCODING:
@@ -116,46 +117,43 @@ public final class ConstantValueParser {
                return urs.recordSize;
        }
 
-       public static void encode(byte[] data, int offset, Object[] values) {
-               int currentOffset = offset;
+       public static void encode(LittleEndianOutput out, Object[] values) {
                for (int i = 0; i < values.length; i++) {
-                       currentOffset += encodeSingleValue(data, currentOffset, values[i]);
+                       encodeSingleValue(out, values[i]);
                }
        }
 
-       private static int encodeSingleValue(byte[] data, int offset, Object value) {
+       private static void encodeSingleValue(LittleEndianOutput out, Object value) {
                if (value == EMPTY_REPRESENTATION) {
-                       LittleEndian.putByte(data, offset, TYPE_EMPTY);
-                       LittleEndian.putLong(data, offset+1, 0L);
-                       return 9;
+                       out.writeByte(TYPE_EMPTY);
+                       out.writeLong(0L);
+                       return;
                }
                if (value instanceof Boolean) {
                        Boolean bVal = ((Boolean)value);
-                       LittleEndian.putByte(data, offset, TYPE_BOOLEAN);
+                       out.writeByte(TYPE_BOOLEAN);
                        long longVal = bVal.booleanValue() ? 1L : 0L;
-                       LittleEndian.putLong(data, offset+1, longVal);
-                       return 9;
+                       out.writeLong(longVal);
+                       return;
                }
                if (value instanceof Double) {
                        Double dVal = (Double) value;
-                       LittleEndian.putByte(data, offset, TYPE_NUMBER);
-                       LittleEndian.putDouble(data, offset+1, dVal.doubleValue());
-                       return 9;
+                       out.writeByte(TYPE_NUMBER);
+                       out.writeDouble(dVal.doubleValue());
+                       return;
                }
                if (value instanceof UnicodeString) {
                        UnicodeString usVal = (UnicodeString) value;
-                       LittleEndian.putByte(data, offset, TYPE_STRING);
-                       UnicodeRecordStats urs = new UnicodeRecordStats();
-                       usVal.serialize(urs, offset +1, data);
-                       return 1 + urs.recordSize;
+                       out.writeByte(TYPE_STRING);
+                       StringUtil.writeUnicodeString(out, usVal.getString());
+                       return;
                }
                if (value instanceof ErrorConstant) {
                        ErrorConstant ecVal = (ErrorConstant) value;
-                       LittleEndian.putByte(data, offset, TYPE_ERROR_CODE);
-                       LittleEndian.putUShort(data, offset+1, ecVal.getErrorCode());
-                       LittleEndian.putUShort(data, offset+3, 0);
-                       LittleEndian.putInt(data, offset+5, 0);
-                       return 9;
+                       out.writeByte(TYPE_ERROR_CODE);
+                       long longVal = ecVal.getErrorCode();
+                       out.writeLong(longVal);
+                       return;
                }
 
                throw new IllegalStateException("Unexpected value type (" + value.getClass().getName() + "'");
index 037ebb83ae176083ba807b63770483aeb992512d..8e1f9ffe939051d59576867d7fbeb84d411009c4 100644 (file)
@@ -98,7 +98,6 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
         buf.append(")");
     }
 
-    public abstract void writeBytes(byte[] array, int offset);
     public abstract int getSize();
 
 
index f16a20077966d8ed7cea6521f73be1631ccead17..7802fcd13f5b7ac568f9c0622821ecd681f05a23 100644 (file)
 \r
 package org.apache.poi.hssf.record.formula;\r
 \r
-import org.apache.poi.hssf.record.RecordInputStream;\r
-import org.apache.poi.util.LittleEndian;\r
+import org.apache.poi.util.LittleEndianInput;\r
+import org.apache.poi.util.LittleEndianOutput;\r
 \r
 /**\r
- * Common superclass of 2-D area refs \r
+ * Common superclass of 2-D area refs\r
  */\r
 public abstract class Area2DPtgBase extends AreaPtgBase {\r
-       private final static int  SIZE = 9;\r
+       private final static int SIZE = 9;\r
 \r
        protected Area2DPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {\r
                super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);\r
        }\r
-       protected Area2DPtgBase(RecordInputStream in) {\r
+\r
+       protected Area2DPtgBase(LittleEndianInput in)  {\r
                readCoordinates(in);\r
        }\r
+\r
        protected abstract byte getSid();\r
 \r
-       public final void writeBytes(byte [] array, int offset) {\r
-               LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());\r
-               writeCoordinates(array, offset+1);       \r
+       public final void write(LittleEndianOutput out) {\r
+               out.writeByte(getSid() + getPtgClass());\r
+               writeCoordinates(out);\r
        }\r
+\r
        public Area2DPtgBase(String arearef) {\r
-       super(arearef);\r
+               super(arearef);\r
        }\r
+\r
        public final int getSize() {\r
                return SIZE;\r
        }\r
+\r
        public final String toFormulaString() {\r
-       return formatReferenceAsString();\r
+               return formatReferenceAsString();\r
+       }\r
+\r
+       public final String toString() {\r
+               StringBuffer sb = new StringBuffer();\r
+               sb.append(getClass().getName());\r
+               sb.append(" [");\r
+               sb.append(formatReferenceAsString());\r
+               sb.append("]");\r
+               return sb.toString();\r
        }\r
-    public final String toString() {\r
-        StringBuffer sb = new StringBuffer();\r
-        sb.append(getClass().getName());\r
-        sb.append(" [");\r
-        sb.append(formatReferenceAsString());\r
-        sb.append("]");\r
-        return sb.toString();\r
-    }\r
 }\r
index 58cdc5b275bfc21aff88643fe9cc5d23bf8aee52..675ee45551aa09d14bda860250ae396e8824b059 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.ss.formula.ExternSheetReferenceToken;
 import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
 import org.apache.poi.ss.formula.WorkbookDependentFormula;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * Title:        Area 3D Ptg - 3D reference (Sheet + Area)<P>
@@ -44,7 +44,7 @@ public final class Area3DPtg extends AreaPtgBase implements WorkbookDependentFor
                setExternSheetIndex( externIdx );
        }
 
-       public Area3DPtg(RecordInputStream in) {
+       public Area3DPtg(LittleEndianInput in)  {
                field_1_index_extern_sheet = in.readShort();
                readCoordinates(in);
        }
@@ -67,10 +67,10 @@ public final class Area3DPtg extends AreaPtgBase implements WorkbookDependentFor
                return sb.toString();
        }
 
-       public void writeBytes(byte[] array, int offset) {
-               LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
-               LittleEndian.putUShort(array, 1 + offset, field_1_index_extern_sheet);
-               writeCoordinates(array, offset+3);
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeShort(field_1_index_extern_sheet);
+               writeCoordinates(out);
        }
 
        public int getSize() {
index bfe247897dc7047ba8f28c2d96e6eec1bc93bbcb..dfbfb7ab32b49ce3c551f05e11cdd08bc0fdfb29 100644 (file)
@@ -17,9 +17,9 @@
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * AreaErr - handles deleted cell area references.
@@ -36,16 +36,16 @@ public final class AreaErrPtg extends OperandPtg {
                unused2 = 0;
        }
 
-       public AreaErrPtg(RecordInputStream in) {
+       public AreaErrPtg(LittleEndianInput in)  {
                // 8 bytes unused:
                unused1 = in.readInt();
                unused2 = in.readInt();
        }
 
-       public void writeBytes(byte[] array, int offset) {
-               LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
-               LittleEndian.putInt(array, offset + 1, unused1);
-               LittleEndian.putInt(array, offset + 5, unused2);
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeInt(unused1);
+               out.writeInt(unused2);
        }
 
        public String toFormulaString() {
index fc391b801d03829393b37c5d782431ce6b621244..f8b761f315eb05072c8762764cbbb60aa78b6942 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianInput;
 
 /**
  * Specifies a rectangular area of cells A1:A4 for instance.
@@ -26,7 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
 public final class AreaNPtg extends Area2DPtgBase {
        public final static short sid = 0x2D;
 
-       public AreaNPtg(RecordInputStream in) {
+       public AreaNPtg(LittleEndianInput in)  {
                super(in);
        }
 
index 77e9fa0b5e67759cfa1a1b85de0748d27306f2bd..1da9b784c85e4a846227722b3d08712d6615ab96 100755 (executable)
@@ -17,7 +17,7 @@
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianInput;
 
 /**
  * Specifies a rectangular area of cells A1:A4 for instance.
@@ -29,7 +29,7 @@ public final class AreaPtg extends Area2DPtgBase {
        public AreaPtg(int firstRow, int lastRow, int firstColumn, int lastColumn, boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
                super(firstRow, lastRow, firstColumn, lastColumn, firstRowRelative, lastRowRelative, firstColRelative, lastColRelative);
        }
-       public AreaPtg(RecordInputStream in) {
+       public AreaPtg(LittleEndianInput in)  {
                super(in);
        }
        public AreaPtg(String arearef) {
index a97ecd4f0388fd58dfaf55c53291f355c85d8103..d6f2b44aaf1fd25228d9a54cc866ef312be794f2 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.ss.util.AreaReference;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * Specifies a rectangular area of cells A1:A4 for instance.
@@ -46,7 +46,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
        private int             field_3_first_column;
        /** zero based, unsigned 8 bit */
        private int             field_4_last_column;
-       
+
        private final static BitField   rowRelative = BitFieldFactory.getInstance(0x8000);
        private final static BitField   colRelative = BitFieldFactory.getInstance(0x4000);
        private final static BitField   columnMask      = BitFieldFactory.getInstance(0x3FFF);
@@ -54,7 +54,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
        protected AreaPtgBase() {
                // do nothing
        }
-       
+
        protected AreaPtgBase(String arearef) {
                AreaReference ar = new AreaReference(arearef);
                CellReference firstCell = ar.getFirstCell();
@@ -66,17 +66,17 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
                setFirstColRelative(!firstCell.isColAbsolute());
                setLastColRelative(!lastCell.isColAbsolute());
                setFirstRowRelative(!firstCell.isRowAbsolute());
-               setLastRowRelative(!lastCell.isRowAbsolute());        
+               setLastRowRelative(!lastCell.isRowAbsolute());
        }
-       
+
        protected AreaPtgBase(int firstRow, int lastRow, int firstColumn, int lastColumn,
                        boolean firstRowRelative, boolean lastRowRelative, boolean firstColRelative, boolean lastColRelative) {
-               
+
                checkColumnBounds(firstColumn);
                checkColumnBounds(lastColumn);
                checkRowBounds(firstRow);
                checkRowBounds(lastRow);
-               
+
                if (lastRow > firstRow) {
                        setFirstRow(firstRow);
                        setLastRow(lastRow);
@@ -88,7 +88,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
                        setFirstRowRelative(lastRowRelative);
                        setLastRowRelative(firstRowRelative);
                }
-                       
+
                if (lastColumn > firstColumn) {
                        setFirstColumn(firstColumn);
                        setLastColumn(lastColumn);
@@ -100,7 +100,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
                        setFirstColRelative(lastColRelative);
                        setLastColRelative(firstColRelative);
                }
-       }    
+       }
 
        private static void checkColumnBounds(int colIx) {
                if((colIx & 0x0FF) != colIx) {
@@ -113,17 +113,17 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
                }
        }
 
-       protected final void readCoordinates(RecordInputStream in) {
+       protected final void readCoordinates(LittleEndianInput in)  {
                field_1_first_row = in.readUShort();
                field_2_last_row = in.readUShort();
                field_3_first_column = in.readUShort();
                field_4_last_column = in.readUShort();
        }
-       protected final void writeCoordinates(byte[] array, int offset) {
-               LittleEndian.putUShort(array, offset + 0, field_1_first_row);
-               LittleEndian.putUShort(array, offset + 2, field_2_last_row);
-               LittleEndian.putUShort(array, offset + 4, field_3_first_column);
-               LittleEndian.putUShort(array, offset + 6, field_4_last_column);        
+       protected final void writeCoordinates(LittleEndianOutput out) {
+               out.writeShort(field_1_first_row);
+               out.writeShort(field_2_last_row);
+               out.writeShort(field_3_first_column);
+               out.writeShort(field_4_last_column);
        }
 
        /**
@@ -150,7 +150,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
        }
 
        /**
-        * @param rowIx last row number in the area 
+        * @param rowIx last row number in the area
         */
        public final void setLastRow(int rowIx) {
                checkRowBounds(rowIx);
@@ -177,7 +177,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
        public final boolean isFirstRowRelative() {
                return rowRelative.isSet(field_3_first_column);
        }
-       
+
        /**
         * sets the first row to relative or not
         * @param rel is relative or not.
@@ -192,9 +192,9 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
        public final boolean isFirstColRelative() {
                return colRelative.isSet(field_3_first_column);
        }
-       
+
        /**
-        * set whether the first column is relative 
+        * set whether the first column is relative
         */
        public final void setFirstColRelative(boolean rel) {
                field_3_first_column=colRelative.setBoolean(field_3_first_column,rel);
@@ -235,7 +235,7 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
        public final boolean isLastRowRelative() {
                return rowRelative.isSet(field_4_last_column);
        }
-       
+
        /**
         * set whether the last row is relative or not
         * @param rel <code>true</code> if the last row relative, else
@@ -251,14 +251,14 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
        public final boolean isLastColRelative() {
                return colRelative.isSet(field_4_last_column);
        }
-       
+
        /**
         * set whether the last column should be relative or not
         */
        public final void setLastColRelative(boolean rel) {
                field_4_last_column=colRelative.setBoolean(field_4_last_column,rel);
        }
-       
+
        /**
         * set the last column in the area
         */
@@ -276,13 +276,13 @@ public abstract class AreaPtgBase extends OperandPtg implements AreaI {
        protected final String formatReferenceAsString() {
                CellReference topLeft = new CellReference(getFirstRow(),getFirstColumn(),!isFirstRowRelative(),!isFirstColRelative());
                CellReference botRight = new CellReference(getLastRow(),getLastColumn(),!isLastRowRelative(),!isLastColRelative());
-               
+
                if(AreaReference.isWholeColumnReference(topLeft, botRight)) {
                        return (new AreaReference(topLeft, botRight)).formatAsString();
                }
-               return topLeft.formatAsString() + ":" + botRight.formatAsString(); 
+               return topLeft.formatAsString() + ":" + botRight.formatAsString();
        }
-       
+
        public String toFormulaString() {
                return formatReferenceAsString();
        }
index 1b025872d4622a3b3a66e46bfc8d2c107553322c..3fcc23eda0345b53cd64663784e89364327be682 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.record.UnicodeString;
 import org.apache.poi.hssf.record.constant.ConstantValueParser;
 import org.apache.poi.hssf.record.constant.ErrorConstant;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * ArrayPtg - handles arrays
@@ -54,7 +54,7 @@ public final class ArrayPtg extends Ptg {
        private short token_2_rows;
        private Object[] token_3_arrayValues;
 
-       public ArrayPtg(RecordInputStream in) {
+       public ArrayPtg(LittleEndianInput in) {
                field_1_reserved = new byte[RESERVED_FIELD_LEN];
                // TODO - add readFully method to RecordInputStream
                for(int i=0; i< RESERVED_FIELD_LEN; i++) {
@@ -108,7 +108,7 @@ public final class ArrayPtg extends Ptg {
         * AFTER the last Ptg in the expression.
         * See page 304-305 of Excel97-2007BinaryFileFormat(xls)Specification.pdf
         */
-       public void readTokenValues(RecordInputStream in) {
+       public void readTokenValues(LittleEndianInput in) {
                int nColumns = in.readUByte();
                short nRows = in.readShort();
                //The token_1_columns and token_2_rows do not follow the documentation.
@@ -132,7 +132,7 @@ public final class ArrayPtg extends Ptg {
                if (token_3_arrayValues == null) {
                        sb.append("  #values#uninitialised#\n");
                } else {
-                       sb.append("  ").append(formatAsString());
+                       sb.append("  ").append(toFormulaString());
                }
                return sb.toString();
        }
@@ -153,17 +153,16 @@ public final class ArrayPtg extends Ptg {
                return rowIx * token_1_columns + colIx;
        }
 
-       public void writeBytes(byte[] data, int offset) {
-               
-               LittleEndian.putByte(data, offset + 0, sid + getPtgClass());
-               System.arraycopy(field_1_reserved, 0, data, offset+1, RESERVED_FIELD_LEN);
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.write(field_1_reserved);
        }
 
-       public int writeTokenValueBytes(byte[] data, int offset) {
+       public int writeTokenValueBytes(LittleEndianOutput out) {
 
-               LittleEndian.putByte(data,  offset + 0, token_1_columns-1);
-               LittleEndian.putUShort(data, offset + 1, token_2_rows-1);
-               ConstantValueParser.encode(data, offset + 3, token_3_arrayValues);
+               out.writeByte(token_1_columns-1);
+               out.writeShort(token_2_rows-1);
+               ConstantValueParser.encode(out, token_3_arrayValues);
                return 3 + ConstantValueParser.getEncodedSize(token_3_arrayValues);
        }
 
@@ -183,7 +182,7 @@ public final class ArrayPtg extends Ptg {
                        + ConstantValueParser.getEncodedSize(token_3_arrayValues);
        }
 
-       public String formatAsString() { // TODO - fold into toFormulaString
+       public String toFormulaString() {
                StringBuffer b = new StringBuffer();
                b.append("{");
                for (int y=0;y<getRowCount();y++) {
@@ -201,9 +200,6 @@ public final class ArrayPtg extends Ptg {
                b.append("}");
                return b.toString();
        }
-       public String toFormulaString() {
-               return formatAsString();
-       }
        
        private static String getConstantText(Object o) {
 
index ea0afcc377913d6ef309653d2c143b7de7d586b6..7a256bf2f7bf9dc6ba852f681a09a2f8a2e2906b 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
 import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * "Special Attributes"
@@ -78,7 +79,7 @@ public final class AttrPtg extends ControlPtg {
         _chooseFuncOffset = -1;
     }
 
-    public AttrPtg(RecordInputStream in)
+    public AttrPtg(LittleEndianInput in) 
     {
         field_1_options = in.readByte();
         field_2_data    = in.readShort();
@@ -213,19 +214,16 @@ public final class AttrPtg extends ControlPtg {
         return sb.toString();
     }
 
-    public void writeBytes(byte [] array, int offset)
-    {
-        LittleEndian.putByte(array, offset+0, sid);
-        LittleEndian.putByte(array, offset+1, field_1_options);
-        LittleEndian.putShort(array,offset+2, field_2_data);
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
+        out.writeByte(field_1_options);
+        out.writeShort(field_2_data);
         int[] jt = _jumpTable;
         if (jt != null) {
-            int joff = offset+4;
             for (int i = 0; i < jt.length; i++) {
-                LittleEndian.putUShort(array, joff, jt[i]);
-                joff+=2;
+                out.writeShort(jt[i]);
             }
-            LittleEndian.putUShort(array, joff, _chooseFuncOffset);
+            out.writeShort(_chooseFuncOffset);
         }
     }
 
index f975b0419ee4ac86e2a2af696664cc580ae9b7ce..88604ac50d96475ab136e0bae16fd6d519f00cf1 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
- * Boolean (boolean)
- * Stores a (java) boolean value in a formula.
+ * Boolean (boolean) Stores a (java) boolean value in a formula.
+ * 
  * @author Paul Krause (pkrause at soundbite dot com)
  * @author Andrew C. Oliver (acoliver at apache dot org)
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public final class BoolPtg extends ScalarConstantPtg {
-    public final static int  SIZE = 2;
-    public final static byte sid  = 0x1d;
-    private final boolean _value;
-
-    public BoolPtg(RecordInputStream in) {
-        _value = (in.readByte() == 1);
-    }
-
-    public BoolPtg(String formulaToken) {
-        _value = (formulaToken.equalsIgnoreCase("TRUE"));
-    }
-
-    public boolean getValue() {
-        return _value;
-    }
-
-    public void writeBytes(byte [] array, int offset) {
-        array[ offset + 0 ] = sid;
-        array[ offset + 1 ] = (byte) (_value ? 1 : 0);
-    }
-
-    public int getSize() {
-        return SIZE;
-    }
-
-    public String toFormulaString() {
-        return _value ? "TRUE" : "FALSE";
-    }
+       public final static int SIZE = 2;
+       public final static byte sid = 0x1D;
+       private final boolean _value;
+
+       public BoolPtg(LittleEndianInput in)  {
+               _value = (in.readByte() == 1);
+       }
+
+       public BoolPtg(String formulaToken) {
+               _value = (formulaToken.equalsIgnoreCase("TRUE"));
+       }
+
+       public boolean getValue() {
+               return _value;
+       }
+
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeByte(_value ? 1 : 0);
+       }
+
+       public int getSize() {
+               return SIZE;
+       }
+
+       public String toFormulaString() {
+               return _value ? "TRUE" : "FALSE";
+       }
 }
index a45cfcd69ea040e6fdff97a723afe2f02cec22dd..0cf412d859d785fa624243aa712b5b22d24617fa 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
-import org.apache.poi.ss.formula.WorkbookDependentFormula;
 import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.ss.formula.WorkbookDependentFormula;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * Title:        Deleted Area 3D Ptg - 3D referecnce (Sheet + Area)<P>
@@ -42,7 +42,7 @@ public final class DeletedArea3DPtg extends OperandPtg implements WorkbookDepend
                unused2 = 0;
        }
        
-       public DeletedArea3DPtg(RecordInputStream in) {
+       public DeletedArea3DPtg(LittleEndianInput in)  {
                field_1_index_extern_sheet = in.readUShort();
                unused1 = in.readInt();
                unused2 = in.readInt();
@@ -60,10 +60,10 @@ public final class DeletedArea3DPtg extends OperandPtg implements WorkbookDepend
        public int getSize() {
                return 11;
        }
-       public void writeBytes(byte[] data, int offset) {
-               LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
-               LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
-               LittleEndian.putInt(data, 3 + offset, unused1);
-               LittleEndian.putInt(data, 7 + offset, unused2);
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeShort(field_1_index_extern_sheet);
+               out.writeInt(unused1);
+               out.writeInt(unused2);
        }
 }
index 4dbf09b7ff1f46797e29b0d6842ab87c720611b1..dcc07ab6d9df4ce481e3cfb3f37bf86311a0f3bd 100644 (file)
 package org.apache.poi.hssf.record.formula;
 
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
-import org.apache.poi.ss.formula.WorkbookDependentFormula;
 import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.ss.formula.WorkbookDependentFormula;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * Title:        Deleted Reference 3D Ptg <P>
@@ -37,7 +37,7 @@ public final class DeletedRef3DPtg extends OperandPtg implements WorkbookDepende
        private final int unused1;
 
        /** Creates new DeletedRef3DPtg */
-       public DeletedRef3DPtg(RecordInputStream in) {
+       public DeletedRef3DPtg(LittleEndianInput in)  {
                field_1_index_extern_sheet = in.readUShort();
                unused1 = in.readInt();
        }
@@ -60,9 +60,9 @@ public final class DeletedRef3DPtg extends OperandPtg implements WorkbookDepende
        public int getSize() {
                return 7;
        }
-       public void writeBytes(byte[] data, int offset) {
-               LittleEndian.putByte(data, 0 + offset, sid + getPtgClass());
-               LittleEndian.putUShort(data, 1 + offset, field_1_index_extern_sheet);
-               LittleEndian.putInt(data, 3 + offset, unused1);
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeShort(field_1_index_extern_sheet);
+               out.writeInt(unused1);
        }
 }
index 65d40dc51ed2a7880991b835bca2bc290c0c47e9..361e4b5cf9b2f79ce1066d5ef6c10157ccbed98c 100644 (file)
@@ -17,8 +17,9 @@
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * @author Daniel Noll (daniel at nuix dot com dot au)
@@ -57,14 +58,13 @@ public final class ErrPtg extends ScalarConstantPtg {
         field_1_error_code = errorCode;
     }
 
-    public static ErrPtg read(RecordInputStream in) {
+    public static ErrPtg read(LittleEndianInput in)  {
         return valueOf(in.readByte());
     }
 
-    public void writeBytes(byte [] array, int offset)
-    {
-        array[offset] = (byte) (sid + getPtgClass());
-        array[offset + 1] = (byte)field_1_error_code;
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
+        out.writeByte(field_1_error_code);
     }
 
     public String toFormulaString() {
index 5c48aeb6b0805605c288d3dbeea3135d71b85231..665fa97c837913373b854aae3d3bd969f98b78cf 100644 (file)
@@ -18,8 +18,8 @@
 package org.apache.poi.hssf.record.formula;
 
 import org.apache.poi.hssf.record.RecordFormatException;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  *
@@ -33,42 +33,41 @@ public final class ExpPtg extends ControlPtg {
     private final short            field_1_first_row;
     private final short            field_2_first_col;
 
-    public ExpPtg(RecordInputStream in)
+    public ExpPtg(LittleEndianInput in) 
     {
       field_1_first_row = in.readShort();
       field_2_first_col = in.readShort();
     }
-    
-    public void writeBytes(byte [] array, int offset)
-    {
-      array[offset+0]= (byte) (sid);
-      LittleEndian.putShort(array,offset+1,field_1_first_row);
-      LittleEndian.putShort(array,offset+3,field_2_first_col);
+
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
+        out.writeShort(field_1_first_row);
+        out.writeShort(field_2_first_col);
     }
 
     public int getSize()
     {
         return SIZE;
     }
-    
+
     public short getRow() {
       return field_1_first_row;
     }
 
     public short getColumn() {
       return field_2_first_col;
-    }    
+    }
 
     public String toFormulaString()
     {
         throw new RecordFormatException("Coding Error: Expected ExpPtg to be converted from Shared to Non-Shared Formula by ValueRecordsAggregate, but it wasn't");
     }
-    
+
     public String toString()
     {
         StringBuffer buffer = new StringBuffer("[Array Formula or Shared Formula]\n");
         buffer.append("row = ").append(getRow()).append("\n");
         buffer.append("col = ").append(getColumn()).append("\n");
         return buffer.toString();
-    }    
+    }
 }
index c0034b24fb29a4b62bba2e7fb2b652cd017f0ba3..133072203bf65b66b8d32a02bc0c32088d6dfd00 100644 (file)
 ==================================================================== */
 
 package org.apache.poi.hssf.record.formula;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
 import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * @author aviks
@@ -35,7 +35,7 @@ public final class FuncPtg extends AbstractFunctionPtg {
     /**Creates new function pointer from a byte array
      * usually called while reading an excel file.
      */
-    public FuncPtg(RecordInputStream in) {
+    public FuncPtg(LittleEndianInput in) {
         //field_1_num_args = data[ offset + 0 ];
         field_2_fnc_index  = in.readShort();
 
@@ -55,9 +55,9 @@ public final class FuncPtg extends AbstractFunctionPtg {
         paramClass = fm.getParameterClassCodes();
     }
 
-    public void writeBytes(byte[] array, int offset) {
-        array[offset+0]= (byte) (sid + getPtgClass());
-        LittleEndian.putShort(array,offset+1,field_2_fnc_index);
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
+        out.writeShort(field_2_fnc_index);
     }
 
     public int getNumberOfOperands() {
index fd3546250a9029cee0f909e16033cf7e5321f64f..1deb630d50b38fedc36956d51b612be583d58566 100644 (file)
 ==================================================================== */
 
 package org.apache.poi.hssf.record.formula;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
 import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  *
@@ -33,7 +33,7 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
     /**Creates new function pointer from a byte array
      * usually called while reading an excel file.
      */
-    public FuncVarPtg(RecordInputStream in) {
+    public FuncVarPtg(LittleEndianInput in)  {
         field_1_num_args = in.readByte();
         field_2_fnc_index  = in.readShort();
         FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(field_2_fnc_index);
@@ -64,10 +64,10 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
         }
     }
 
-     public void writeBytes(byte[] array, int offset) {
-        array[offset+0]=(byte) (sid + getPtgClass());
-        array[offset+1]=field_1_num_args;
-        LittleEndian.putShort(array,offset+2,field_2_fnc_index);
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
+        out.writeByte(field_1_num_args);
+        out.writeShort(field_2_fnc_index);
     }
 
      public int getNumberOfOperands() {
index ea3fc80bd6f523d9cf39efa5f278ddd9b9350d10..bb5d36f0075e2f6c17cd22fa897be6a7ebcbe619 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
- * Integer (unsigned short integer)
- * Stores an unsigned short value (java int) in a formula
- * @author  Andrew C. Oliver (acoliver at apache dot org)
+ * Integer (unsigned short integer) Stores an unsigned short value (java int) in
+ * a formula
+ * 
+ * @author Andrew C. Oliver (acoliver at apache dot org)
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public final class IntPtg extends ScalarConstantPtg {
-    // 16 bit unsigned integer
-    private static final int MIN_VALUE = 0x0000;
-    private static final int MAX_VALUE = 0xFFFF;
-    
-    /**
-     * Excel represents integers 0..65535 with the tInt token. 
-     * @return <code>true</code> if the specified value is within the range of values 
-     * <tt>IntPtg</tt> can represent. 
-     */
-    public static boolean isInRange(int i) {
-        return i>=MIN_VALUE && i <=MAX_VALUE;
-    }
+       // 16 bit unsigned integer
+       private static final int MIN_VALUE = 0x0000;
+       private static final int MAX_VALUE = 0xFFFF;
 
-    public final static int  SIZE = 3;
-    public final static byte sid  = 0x1e;
-    private final int field_1_value;
-  
-    public IntPtg(RecordInputStream in) {
-        this(in.readUShort());
-    }
+       /**
+        * Excel represents integers 0..65535 with the tInt token.
+        * 
+        * @return <code>true</code> if the specified value is within the range of values 
+        * <tt>IntPtg</tt> can represent.
+        */
+       public static boolean isInRange(int i) {
+               return i >= MIN_VALUE && i <= MAX_VALUE;
+       }
 
-    public IntPtg(int value) {
-        if(!isInRange(value)) {
-            throw new IllegalArgumentException("value is out of range: " + value);
-        }
-        field_1_value = value;
-    }
+       public final static int SIZE = 3;
+       public final static byte sid = 0x1e;
+       private final int field_1_value;
 
-    public int getValue() {
-        return field_1_value;
-    }
+       public IntPtg(LittleEndianInput in)  {
+               this(in.readUShort());
+       }
 
-    public void writeBytes(byte [] array, int offset) {
-        array[ offset + 0 ] = sid;
-        LittleEndian.putUShort(array, offset + 1, getValue());
-    }
+       public IntPtg(int value) {
+               if (!isInRange(value)) {
+                       throw new IllegalArgumentException("value is out of range: " + value);
+               }
+               field_1_value = value;
+       }
 
-    public int getSize() {
-        return SIZE;
-    }
+       public int getValue() {
+               return field_1_value;
+       }
 
-    public String toFormulaString() {
-        return String.valueOf(getValue());
-    }
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeShort(getValue());
+       }
+
+       public int getSize() {
+               return SIZE;
+       }
+
+       public String toFormulaString() {
+               return String.valueOf(getValue());
+       }
 }
index f96c5ecb1a181c722712e6024bd068a7294f283e..0e6771de35862a19b843554497f8b14814385232 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * @author Daniel Noll (daniel at nuix dot com dot au)
  */
 public final class IntersectionPtg extends OperationPtg {
-    public final static byte sid  = 0x0f;
+       public final static byte sid = 0x0f;
 
-    public static final OperationPtg instance = new IntersectionPtg();
+       public static final OperationPtg instance = new IntersectionPtg();
 
-    private IntersectionPtg() {
-       // enforce singleton
-    }
+       private IntersectionPtg() {
+               // enforce singleton
+       }
 
-    public final boolean isBaseToken() {
-        return true;
-    }
+       public final boolean isBaseToken() {
+               return true;
+       }
 
-    public int getSize()
-    {
-        return 1;
-    }
+       public int getSize() {
+               return 1;
+       }
 
-    public void writeBytes( byte[] array, int offset )
-    {
-        array[ offset + 0 ] = sid;
-    }
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+       }
 
-    /** Implementation of method from Ptg */
-    public String toFormulaString()
-    {
-        return " ";
-    }
+       public String toFormulaString() {
+               return " ";
+       }
 
+       public String toFormulaString(String[] operands) {
+               StringBuffer buffer = new StringBuffer();
 
-    /** implementation of method from OperationsPtg*/
-    public String toFormulaString(String[] operands)
-    {
-         StringBuffer buffer = new StringBuffer();
-
-         buffer.append(operands[ 0 ]);
-         buffer.append(" ");
-         buffer.append(operands[ 1 ]);
-         return buffer.toString();
-     }
-
-    public int getNumberOfOperands()
-    {
-        return 2;
-    }
+               buffer.append(operands[0]);
+               buffer.append(" ");
+               buffer.append(operands[1]);
+               return buffer.toString();
+       }
 
+       public int getNumberOfOperands() {
+               return 2;
+       }
 }
index 951fd7c43647ad6c21cbe2ad672e570fcf756d5a..58a836e28f7cd67d5b0a57276db8696591766a3c 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * @author Daniel Noll (daniel at nuix dot com dot au)
  */
 public class MemAreaPtg extends OperandPtg {
-    public final static short sid  = 0x26;
-    private final static int  SIZE = 7;
-    private int               field_1_reserved;
-    private short             field_2_subex_len;
-
-    /** Creates new MemAreaPtg */
-
-    public MemAreaPtg()
-    {
-    }
-
-    public MemAreaPtg(RecordInputStream in)
-    {
-        field_1_reserved  = in.readInt();
-        field_2_subex_len = in.readShort();
-    }
-
-    public void setReserved(int res)
-    {
-        field_1_reserved = res;
-    }
-
-    public int getReserved()
-    {
-        return field_1_reserved;
-    }
-
-    public void setSubexpressionLength(short subexlen)
-    {
-        field_2_subex_len = subexlen;
-    }
-
-    public short getSubexpressionLength()
-    {
-        return field_2_subex_len;
-    }
-
-    public void writeBytes(byte [] array, int offset)
-    {
-        array[offset] = (byte) (sid + getPtgClass());
-        LittleEndian.putInt(array, offset + 1, field_1_reserved);
-        LittleEndian.putShort(array, offset + 5, field_2_subex_len);
-    }
-
-    public int getSize()
-    {
-        return SIZE;
-    }
-
-    public String toFormulaString()
-    {
-        return ""; // TODO: Not sure how to format this. -- DN
-    }
-
-    public byte getDefaultOperandClass() {
-       return Ptg.CLASS_VALUE;
-    }
+       public final static short sid = 0x26;
+       private final static int SIZE = 7;
+       private final int field_1_reserved;
+       private final int field_2_subex_len;
+
+       /** Creates new MemAreaPtg */
+
+       public MemAreaPtg(int subexLen) {
+               field_1_reserved = 0;
+               field_2_subex_len = subexLen;
+       }
+
+       public MemAreaPtg(LittleEndianInput in)  {
+               field_1_reserved = in.readInt();
+               field_2_subex_len = in.readShort();
+       }
+
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeInt(field_1_reserved);
+               out.writeShort(field_2_subex_len);
+       }
+
+       public int getSize() {
+               return SIZE;
+       }
+
+       public String toFormulaString() {
+               return ""; // TODO: Not sure how to format this. -- DN
+       }
+
+       public byte getDefaultOperandClass() {
+               return Ptg.CLASS_VALUE;
+       }
 }
index d3de53fe1327ecf4d592e15c69ca3519db127187..91027b0ab0098998bf408c09c277332da88f0b8e 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
- *
- * @author  andy
+ * 
+ * @author andy
  * @author Jason Height (jheight at chariot dot net dot au)
  * @author Daniel Noll (daniel at nuix dot com dot au)
  */
-
-public final class MemErrPtg extends MemAreaPtg {
-    public final static short sid  = 0x27;
-
-    /** Creates new MemErrPtg */
-
-    public MemErrPtg()
-    {
-    }
-
-    public MemErrPtg(RecordInputStream in) {
-        super(in);
-    }
-
-    public void writeBytes(byte [] array, int offset) {
-        super.writeBytes(array, offset);
-        array[offset] = (byte) (sid + getPtgClass());
-    }
-
-    public String toFormulaString()
-    {
-        return "ERR#";
-    }
+public final class MemErrPtg extends OperandPtg {
+       public final static short sid = 0x27;
+       private final static int SIZE = 7;
+       private int field_1_reserved;
+       private short field_2_subex_len;
+
+       public MemErrPtg(LittleEndianInput in)  {
+               field_1_reserved = in.readInt();
+               field_2_subex_len = in.readShort();
+       }
+
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeInt(field_1_reserved);
+               out.writeShort(field_2_subex_len);
+       }
+
+       public int getSize() {
+               return SIZE;
+       }
+
+       public String toFormulaString() {
+               return "ERR#";
+       }
+
+       public byte getDefaultOperandClass() {
+               return Ptg.CLASS_VALUE;
+       }
 }
index 991f1742c01266265a8428aebd20615aa3eca4f3..3ee893bdd795abacf6df841682556d9e5cac6676 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * @author Glen Stampoultzis (glens at apache.org)
  */
 public final class MemFuncPtg extends OperandPtg {
 
-    public final static byte sid = 0x29;
-    private final int field_1_len_ref_subexpression;
+       public final static byte sid = 0x29;
+       private final int field_1_len_ref_subexpression;
 
-    /**Creates new function pointer from a byte array
-     * usually called while reading an excel file.
-     */
-    public MemFuncPtg(RecordInputStream in) {
-        this(in.readUShort());
-    }
+       /**
+        * Creates new function pointer from a byte array usually called while
+        * reading an excel file.
+        */
+       public MemFuncPtg(LittleEndianInput in)  {
+               this(in.readUShort());
+       }
 
-    public MemFuncPtg(int subExprLen) {
-       field_1_len_ref_subexpression = subExprLen;
+       public MemFuncPtg(int subExprLen) {
+               field_1_len_ref_subexpression = subExprLen;
        }
 
-       public int getSize()
-    {
-        return 3;
-    }
+       public int getSize() {
+               return 3;
+       }
 
-    public void writeBytes( byte[] array, int offset )
-    {
-        array[offset + 0] =  sid ;
-        LittleEndian.putUShort( array, offset + 1, field_1_len_ref_subexpression );
-    }
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeShort(field_1_len_ref_subexpression);
+       }
 
-    public String toFormulaString()
-    {
-        return "";
-    }
+       public String toFormulaString() {
+               return "";
+       }
 
-    public byte getDefaultOperandClass()
-    {
-        return Ptg.CLASS_REF;
-    }
+       public byte getDefaultOperandClass() {
+               return Ptg.CLASS_REF;
+       }
 
-    public int getNumberOfOperands()
-    {
-        return field_1_len_ref_subexpression;
-    }
+       public int getNumberOfOperands() {
+               return field_1_len_ref_subexpression;
+       }
 
-    public int getLenRefSubexpression()
-    {
-        return field_1_len_ref_subexpression;
-    }
+       public int getLenRefSubexpression() {
+               return field_1_len_ref_subexpression;
+       }
 }
\ No newline at end of file
index 075105f50c9a11dba07c0f4d3901a081cb32af13..99b7708a4b8859733719ff317b03f1139145ddfd 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
+import org.apache.poi.util.LittleEndianOutput;
+
 /**
  * Missing Function Arguments
- *
+ * 
  * Avik Sengupta &lt;avik at apache.org&gt;
+ * 
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public final class MissingArgPtg extends ScalarConstantPtg {
-   
-    private final static int SIZE = 1;
-    public final static byte sid  = 0x16;
-   
-    public static final Ptg instance = new MissingArgPtg();
-
-    private MissingArgPtg() {
-       // enforce singleton
-    }
-     
-    public void writeBytes(byte [] array, int offset) {
-        array[ offset + 0 ] = sid;
-    }
-
-    public int getSize() {
-        return SIZE;
-    }
-   
-    public String toFormulaString() {
-        return " ";
-    }
+
+       private final static int SIZE = 1;
+       public final static byte sid = 0x16;
+
+       public static final Ptg instance = new MissingArgPtg();
+
+       private MissingArgPtg() {
+               // enforce singleton
+       }
+
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+       }
+
+       public int getSize() {
+               return SIZE;
+       }
+
+       public String toFormulaString() {
+               return " ";
+       }
 }
index 59670f87580c1ac1adcf75fbc9432a440e6db26a..e5cd0fc9dea5faaa3792b29f02a8a2cb95ef080a 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.ss.formula.WorkbookDependentFormula;
 import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.ss.formula.WorkbookDependentFormula;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
- *
- * @author  andy
+ * 
+ * @author andy
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public final class NamePtg extends OperandPtg implements WorkbookDependentFormula {
-    public final static short sid  = 0x23;
-    private final static int  SIZE = 5;
-    /** one-based index to defined name record */
-    private int  field_1_label_index;
-    private short             field_2_zero;   // reserved must be 0
+       public final static short sid = 0x23;
+       private final static int SIZE = 5;
+       /** one-based index to defined name record */
+       private int field_1_label_index;
+       private short field_2_zero; // reserved must be 0
 
-    /**
-     * @param nameIndex zero-based index to name within workbook
-     */
-    public NamePtg(int nameIndex) {
-        field_1_label_index = 1+nameIndex; // convert to 1-based
-    }
+       /**
+        * @param nameIndex zero-based index to name within workbook
+        */
+       public NamePtg(int nameIndex) {
+               field_1_label_index = 1 + nameIndex; // convert to 1-based
+       }
 
-    /** Creates new NamePtg */
+       /** Creates new NamePtg */
 
-    public NamePtg(RecordInputStream in) {
-        field_1_label_index = in.readShort();
-        field_2_zero        = in.readShort();
-    }
-    
-    /**
-     * @return zero based index to a defined name record in the LinkTable
-     */
-    public int getIndex() {
-        return field_1_label_index-1; // convert to zero based
-    }
+       public NamePtg(LittleEndianInput in)  {
+               field_1_label_index = in.readShort();
+               field_2_zero = in.readShort();
+       }
 
-    public void writeBytes(byte [] array, int offset) {
-       LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
-               LittleEndian.putUShort(array, offset + 1, field_1_label_index);
-               LittleEndian.putUShort(array, offset + 3, field_2_zero);
-    }
+       /**
+        * @return zero based index to a defined name record in the LinkTable
+        */
+       public int getIndex() {
+               return field_1_label_index - 1; // convert to zero based
+       }
 
-    public int getSize() {
-        return SIZE;
-    }
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeShort(field_1_label_index);
+               out.writeShort(field_2_zero);
+       }
+
+       public int getSize() {
+               return SIZE;
+       }
+
+       public String toFormulaString(FormulaRenderingWorkbook book) {
+               return book.getNameText(this);
+       }
 
-    public String toFormulaString(FormulaRenderingWorkbook book)
-    {
-       return book.getNameText(this);
-    }
        public String toFormulaString() {
                throw new RuntimeException("3D references need a workbook to determine formula text");
        }
-    
-    public byte getDefaultOperandClass() {
+
+       public byte getDefaultOperandClass() {
                return Ptg.CLASS_REF;
        }
 }
index 7f1614347f322fa9a7c1428370fca90dd1032b63..de08763c7341a05972a0a5582073bc6d08ed2965 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.ss.formula.WorkbookDependentFormula;
 import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.ss.formula.WorkbookDependentFormula;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * 
@@ -51,15 +51,15 @@ public final class NameXPtg extends OperandPtg implements WorkbookDependentFormu
                this(sheetRefIndex, nameIndex + 1, 0);
        }
 
-       public NameXPtg(RecordInputStream in) {
+       public NameXPtg(LittleEndianInput in)  {
                this(in.readUShort(), in.readUShort(), in.readUShort());
        }
 
-       public void writeBytes(byte[] array, int offset) {
-               LittleEndian.putByte(array, offset + 0, sid + getPtgClass());
-               LittleEndian.putUShort(array, offset + 1, _sheetRefIndex);
-               LittleEndian.putUShort(array, offset + 3, _nameNumber);
-               LittleEndian.putUShort(array, offset + 5, _reserved);
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeShort(_sheetRefIndex);
+               out.writeShort(_nameNumber);
+               out.writeShort(_reserved);
        }
 
        public int getSize() {
index cddb674475dc46d499e344396a1012232c3eec02..5bd8b08453ac2f0e34d8471e28915c3dc19c3994 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
- * Number
- * Stores a floating point value in a formula
- * value stored in a 8 byte field using IEEE notation
- * @author  Avik Sengupta
+ * Number Stores a floating point value in a formula value stored in a 8 byte
+ * field using IEEE notation
+ * 
+ * @author Avik Sengupta
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public final class NumberPtg extends ScalarConstantPtg {
-    public final static int  SIZE = 9;
-    public final static byte sid  = 0x1f;
-    private final double field_1_value;
-        
-    /** Create a NumberPtg from a byte array read from disk */
-    public NumberPtg(RecordInputStream in) {
-        this(in.readDouble());
-    }
-    
-    /** Create a NumberPtg from a string representation of  the number
-     *  Number format is not checked, it is expected to be validated in the parser
-     *   that calls this method. 
-     *  @param value : String representation of a floating point number
-     */
-    public NumberPtg(String value) {
-        this(Double.parseDouble(value));
-    }
-    
-    public NumberPtg(double value) {
-        field_1_value = value;
-    }
-    
-    public double getValue() {
-        return field_1_value;
-    }
+       public final static int SIZE = 9;
+       public final static byte sid = 0x1f;
+       private final double field_1_value;
 
-    public void writeBytes(byte [] array, int offset) {
-        array[ offset + 0 ] = sid;
-        LittleEndian.putDouble(array, offset + 1, getValue());
-    }
+       public NumberPtg(LittleEndianInput in)  {
+               this(in.readDouble());
+       }
 
-    public int getSize() {
-        return SIZE;
-    }
+       /**
+        * Create a NumberPtg from a string representation of the number Number
+        * format is not checked, it is expected to be validated in the parser that
+        * calls this method.
+        * 
+        * @param value String representation of a floating point number
+        */
+       public NumberPtg(String value) {
+               this(Double.parseDouble(value));
+       }
 
-    public String toFormulaString() {
-        // TODO - java's rendering of double values is not quite same as excel's
-        // Maybe use HSSFDataFormatter?
-        return String.valueOf(field_1_value);
-    }
+       public NumberPtg(double value) {
+               field_1_value = value;
+       }
+
+       public double getValue() {
+               return field_1_value;
+       }
+
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+               out.writeDouble(getValue());
+       }
+
+       public int getSize() {
+               return SIZE;
+       }
+
+       public String toFormulaString() {
+               // TODO - java's rendering of double values is not quite same as excel's
+               return String.valueOf(field_1_value);
+       }
 }
index 5365b939d82aa7d7f79f230896c9f94b9ebd17d1..1b94c90383abf953771645a2c10b6582098f959d 100644 (file)
    limitations under the License.
 ==================================================================== */
 
-
 package org.apache.poi.hssf.record.formula;
 
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
- * While formula tokens are stored in RPN order and thus do not need parenthesis for 
- * precedence reasons, Parenthesis tokens ARE written to ensure that user entered
- * parenthesis are displayed as-is on reading back
- *
- * Avik Sengupta &lt;lists@aviksengupta.com&gt;
- * Andrew C. Oliver (acoliver at apache dot org)
+ * While formula tokens are stored in RPN order and thus do not need parenthesis
+ * for precedence reasons, Parenthesis tokens ARE written to ensure that user
+ * entered parenthesis are displayed as-is on reading back
+ * 
+ * Avik Sengupta &lt;lists@aviksengupta.com&gt; Andrew C. Oliver (acoliver at
+ * apache dot org)
+ * 
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public final class ParenthesisPtg extends ControlPtg {
-   
-    private final static int SIZE = 1;
-    public final static byte sid  = 0x15;
-   
-    public static final ControlPtg instance = new ParenthesisPtg();
-    private ParenthesisPtg() {
-       // enforce singleton
-    }
-    
-    public void writeBytes(byte [] array, int offset)
-    {
-        array[ offset + 0 ] = sid;
-    }
-
-    public int getSize()
-    {
-        return SIZE;
-    }
-
-    public String toFormulaString()
-    {
-        return "()";
-    }
-
-          
-    public String toFormulaString(String[] operands) {
-        return "("+operands[0]+")";
-    }  
+
+       private final static int SIZE = 1;
+       public final static byte sid = 0x15;
+
+       public static final ControlPtg instance = new ParenthesisPtg();
+
+       private ParenthesisPtg() {
+               // enforce singleton
+       }
+
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+       }
+
+       public int getSize() {
+               return SIZE;
+       }
+
+       public String toFormulaString() {
+               return "()";
+       }
+
+       public String toFormulaString(String[] operands) {
+               return "(" + operands[0] + ")";
+       }
 }
index a264481d4347f0fe880600a6a390612720c99b25..771cccf5824f57443c0ab398b3536cb776c8dfc4 100644 (file)
@@ -20,8 +20,8 @@ package org.apache.poi.hssf.record.formula;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.HexDump;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
 import org.apache.poi.util.LittleEndianOutput;
 
 /**
@@ -48,12 +48,12 @@ public abstract class Ptg implements Cloneable {
         * Reads <tt>size</tt> bytes of the input stream, to create an array of <tt>Ptg</tt>s.
         * Extra data (beyond <tt>size</tt>) may be read if and <tt>ArrayPtg</tt>s are present.
         */
-       public static Ptg[] readTokens(int size, RecordInputStream in) {
+       public static Ptg[] readTokens(int size, LittleEndianInput in) {
                List temp = new ArrayList(4 + size / 2);
                int pos = 0;
                List arrayPtgs = null;
                while (pos < size) {
-                       Ptg ptg = Ptg.createPtg( in );
+                       Ptg ptg = Ptg.createPtg(in);
                        if (ptg instanceof ArrayPtg) {
                                if (arrayPtgs == null) {
                                        arrayPtgs = new ArrayList(5);
@@ -77,7 +77,7 @@ public abstract class Ptg implements Cloneable {
                return toPtgArray(temp);
        }
 
-       public static Ptg createPtg(RecordInputStream in) {
+       public static Ptg createPtg(LittleEndianInput in) {
                byte id = in.readByte();
                
                if (id < 0x20) {
@@ -97,7 +97,7 @@ public abstract class Ptg implements Cloneable {
                return retval;
        }
 
-       private static Ptg createClassifiedPtg(byte id, RecordInputStream in) {
+       private static Ptg createClassifiedPtg(byte id, LittleEndianInput in) {
                
                int baseId = id & 0x1F | 0x20;
                
@@ -126,9 +126,9 @@ public abstract class Ptg implements Cloneable {
                                   Integer.toHexString(id) + " (" + ( int ) id + ")");
        }
 
-       private static Ptg createBasePtg(byte id, RecordInputStream in) {
+       private static Ptg createBasePtg(byte id, LittleEndianInput in) {
                switch(id) {
-                       case 0x00:                return new UnknownPtg(); // TODO - not a real Ptg
+                       case 0x00:                return new UnknownPtg(id); // TODO - not a real Ptg
                        case ExpPtg.sid:          return new ExpPtg(in);          // 0x01
                        case TblPtg.sid:          return new TblPtg(in);          // 0x02
                        case AddPtg.sid:          return AddPtg.instance;         // 0x03
@@ -228,32 +228,30 @@ public abstract class Ptg implements Cloneable {
         * @return number of bytes written
         */
        public static int serializePtgs(Ptg[] ptgs, byte[] array, int offset) {
-               int pos = 0;
-               int size = ptgs.length;
+               int nTokens = ptgs.length;
+               
+               LittleEndianByteArrayOutputStream out = new LittleEndianByteArrayOutputStream(array, offset);
 
                List arrayPtgs = null;
 
-               for (int k = 0; k < size; k++) {
+               for (int k = 0; k < nTokens; k++) {
                        Ptg ptg = ptgs[k];
 
-                       ptg.writeBytes(array, pos + offset);
+                       ptg.write(out);
                        if (ptg instanceof ArrayPtg) {
                                if (arrayPtgs == null) {
                                        arrayPtgs = new ArrayList(5);
                                }
                                arrayPtgs.add(ptg);
-                               pos += ArrayPtg.PLAIN_TOKEN_SIZE;
-                       } else {
-                               pos += ptg.getSize();
                        }
                }
                if (arrayPtgs != null) {
                        for (int i=0;i<arrayPtgs.size();i++) {
                                ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
-                               pos += p.writeTokenValueBytes(array, pos + offset);
+                               p.writeTokenValueBytes(out);
                        }
                }
-               return pos;
+               return out.getWriteIndex() - offset;
        }
 
        /**
@@ -266,38 +264,12 @@ public abstract class Ptg implements Cloneable {
         */
 //    public abstract int getDataSize();
 
-       public final byte[] getBytes()
-       {
-               int    size  = getSize();
-               byte[] bytes = new byte[ size ];
-
-               writeBytes(bytes, 0);
-               return bytes;
-       }
-       /** write this Ptg to a byte array*/
-       public abstract void writeBytes(byte [] array, int offset);
-
-       public void write(LittleEndianOutput out) {
-               out.write(getBytes()); // TODO - optimise - just a hack for the moment
-       }
+       public abstract void write(LittleEndianOutput out);
        
        /**
         * return a string representation of this token alone
         */
        public abstract String toFormulaString();
-       /**
-        * dump a debug representation (hexdump) to a string
-        */
-       public final String toDebugString() {
-               byte[] ba = new byte[getSize()];
-               writeBytes(ba,0);
-               try {
-                       return HexDump.dump(ba,0,0);
-               } catch (Exception e) {
-                       e.printStackTrace();
-               }
-               return null;
-       }
 
        /** Overridden toString method to ensure object hash is not printed.
         * This helps get rid of gratuitous diffs when comparing two dumps
index 658e2f47b412e875597726462782442a3aa8e122..c2507244da899be473e265e417233104e1795947 100644 (file)
@@ -17,6 +17,8 @@
 
 package org.apache.poi.hssf.record.formula;
 
+import org.apache.poi.util.LittleEndianOutput;
+
 
 /**
  * @author Daniel Noll (daniel at nuix dot com dot au)
@@ -40,9 +42,8 @@ public final class RangePtg  extends OperationPtg {
         return SIZE;
     }
 
-    public void writeBytes( byte[] array, int offset )
-    {
-        array[ offset + 0 ] = sid;
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
     }
 
     public String toFormulaString()
index 545ff0bfc4b728f214c7b3f37a2bc4bde0d1212c..3e52bc2081b4a2d0411e918b9bc65932e5db3c02 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * @author Josh Micich
  */
 abstract class Ref2DPtgBase extends RefPtgBase {
-    private final static int SIZE = 5;
+       private final static int SIZE = 5;
 
-    /**
-     * Takes in a String representation of a cell reference and fills out the
-     * numeric fields.
-     */
-    protected Ref2DPtgBase(String cellref) {
-       super(cellref);
-    }
+       /**
+        * Takes in a String representation of a cell reference and fills out the
+        * numeric fields.
+        */
+       protected Ref2DPtgBase(String cellref) {
+               super(cellref);
+       }
 
-    protected Ref2DPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
-      setRow(row);
-      setColumn(column);
-      setRowRelative(isRowRelative);
-      setColRelative(isColumnRelative);
-    }
+       protected Ref2DPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
+               setRow(row);
+               setColumn(column);
+               setRowRelative(isRowRelative);
+               setColRelative(isColumnRelative);
+       }
 
-    protected Ref2DPtgBase(RecordInputStream in) {
-        readCoordinates(in);
-    }
-    public final void writeBytes(byte [] array, int offset) {
-       LittleEndian.putByte(array, offset+0, getSid() + getPtgClass());
-       writeCoordinates(array, offset+1);
-    }
-    public final String toFormulaString() {
-       return formatReferenceAsString();
-    }
+       protected Ref2DPtgBase(LittleEndianInput in)  {
+               readCoordinates(in);
+       }
+
+       public void write(LittleEndianOutput out) {
+               out.writeByte(getSid() + getPtgClass());
+               writeCoordinates(out);
+       }
+
+       public final String toFormulaString() {
+               return formatReferenceAsString();
+       }
 
        protected abstract byte getSid();
-    public final int getSize() {
-        return SIZE;
-    }
-    public final String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append(getClass().getName());
-        sb.append(" [");
-        sb.append(formatReferenceAsString());
-        sb.append("]");
-        return sb.toString();
-    }
+
+       public final int getSize() {
+               return SIZE;
+       }
+
+       public final String toString() {
+               StringBuffer sb = new StringBuffer();
+               sb.append(getClass().getName());
+               sb.append(" [");
+               sb.append(formatReferenceAsString());
+               sb.append("]");
+               return sb.toString();
+       }
 }
index 053057925f2af5c7eeebc8ffb5f5219ca51b5fd6..acb96e4e4f7ea7aa85ca4aacba86411330276ae4 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.ss.formula.ExternSheetReferenceToken;
 import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
 import org.apache.poi.ss.formula.WorkbookDependentFormula;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * Title:        Reference 3D Ptg <P>
@@ -41,7 +41,7 @@ public final class Ref3DPtg extends RefPtgBase implements WorkbookDependentFormu
     /** Creates new AreaPtg */
     public Ref3DPtg() {}
 
-    public Ref3DPtg(RecordInputStream in) {
+    public Ref3DPtg(LittleEndianInput in)  {
         field_1_index_extern_sheet = in.readShort();
         readCoordinates(in);
     }
@@ -66,10 +66,10 @@ public final class Ref3DPtg extends RefPtgBase implements WorkbookDependentFormu
         return sb.toString();
     }
 
-    public void writeBytes(byte [] array, int offset) {
-        LittleEndian.putByte(array, 0 + offset, sid + getPtgClass());
-        LittleEndian.putUShort(array, 1 + offset, getExternSheetIndex());
-        writeCoordinates(array, offset + 3);
+       public void write(LittleEndianOutput out) {
+               out.writeByte(sid + getPtgClass());
+        out.writeShort(getExternSheetIndex());
+        writeCoordinates(out);
     }
 
     public int getSize() {
index 699f6344a3865c296fa445eed0bfbca1664c406c..4cbd501053f1de5996930aabb001238514b3719c 100755 (executable)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * RefError - handles deleted cell reference
@@ -35,7 +34,7 @@ public final class RefErrorPtg extends OperandPtg {
     public RefErrorPtg() {
         field_1_reserved = 0;
     }
-    public RefErrorPtg(RecordInputStream in) {
+    public RefErrorPtg(LittleEndianInput in)  {
         field_1_reserved = in.readInt();
     }
 
@@ -43,9 +42,9 @@ public final class RefErrorPtg extends OperandPtg {
         return getClass().getName();
     }
 
-    public void writeBytes(byte [] array, int offset) {
-        LittleEndian.putByte(array, offset+0, sid + getPtgClass());
-        LittleEndian.putInt(array,offset+1,field_1_reserved);
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
+        out.writeInt(field_1_reserved);
     }
 
     public int getSize()
index 07114265d0c1a3858d5a66addd0537feb0b0d7da..3a8148c46cc5c450e1c124574413bc00644d7d53 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianInput;
 
 /**
  * RefNPtg
@@ -26,7 +26,7 @@ import org.apache.poi.hssf.record.RecordInputStream;
 public final class RefNPtg extends Ref2DPtgBase {
        public final static byte sid = 0x2C;
 
-       public RefNPtg(RecordInputStream in) {
+       public RefNPtg(LittleEndianInput in)  {
                super(in);
        }
 
index 94a1b3301c314c225d24bcc4217551893e599c4b..69508fd7d21b1365b098422ccd3d3260d01ae953 100644 (file)
@@ -17,7 +17,7 @@
 \r
 package org.apache.poi.hssf.record.formula;\r
 \r
-import org.apache.poi.hssf.record.RecordInputStream;\r
+import org.apache.poi.util.LittleEndianInput;\r
 \r
 /**\r
  * ReferencePtg - handles references (such as A1, A2, IA4)\r
@@ -39,7 +39,7 @@ public final class RefPtg extends Ref2DPtgBase {
                super(row, column, isRowRelative, isColumnRelative);\r
        }\r
 \r
-       public RefPtg(RecordInputStream in) {\r
+       public RefPtg(LittleEndianInput in)  {\r
                super(in);\r
        }\r
 \r
index f04ec0ac8ff05d04b6d498d8c6c5dc24f20b64fc..8357e158c511a1d2d5b5b5ce41e8e6b8ee010a1e 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.util.CellReference;
 import org.apache.poi.util.BitField;
 import org.apache.poi.util.BitFieldFactory;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * ReferencePtgBase - handles references (such as A1, A2, IA4)
- * @author  Andrew C. Oliver (acoliver@apache.org)
+ * 
+ * @author Andrew C. Oliver (acoliver@apache.org)
  * @author Jason Height (jheight at chariot dot net dot au)
  */
 public abstract class RefPtgBase extends OperandPtg {
 
-    private final static int MAX_ROW_NUMBER = 65536;
-
-   /** The row index - zero based unsigned 16 bit value */
-    private int            field_1_row;
-    /** Field 2
-     * - lower 8 bits is the zero based unsigned byte column index
-     * - bit 16 - isRowRelative
-     * - bit 15 - isColumnRelative
-     */
-    private int            field_2_col;
-    private static final BitField         rowRelative = BitFieldFactory.getInstance(0x8000);
-    private static final BitField         colRelative = BitFieldFactory.getInstance(0x4000);
-    private static final BitField         column      = BitFieldFactory.getInstance(0x00FF);
-
-    protected RefPtgBase() {
-      //Required for clone methods
-    }
-
-    /**
-     * Takes in a String representation of a cell reference and fills out the
-     * numeric fields.
-     */
-    protected RefPtgBase(String cellref) {
-        CellReference c= new CellReference(cellref);
-        setRow(c.getRow());
-        setColumn(c.getCol());
-        setColRelative(!c.isColAbsolute());
-        setRowRelative(!c.isRowAbsolute());
-    }
-
-    protected RefPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
-      setRow(row);
-      setColumn(column);
-      setRowRelative(isRowRelative);
-      setColRelative(isColumnRelative);
-    }
-
-    protected final void readCoordinates(RecordInputStream in) {
-        field_1_row = in.readUShort();
-        field_2_col = in.readUShort();
-    }
-    protected final void writeCoordinates(byte[] array, int offset) {
-        LittleEndian.putUShort(array, offset + 0, field_1_row);
-        LittleEndian.putUShort(array, offset + 2, field_2_col);
-    }
-
-    public final void setRow(int row) {
-        if(row < 0 || row >= MAX_ROW_NUMBER) {
-           throw new IllegalArgumentException("The row number, when specified as an integer, must be between 0 and " + MAX_ROW_NUMBER);
-        }
-        field_1_row = row;
-    }
-
-    /**
-     * @return the row number as an int, between 0 and 65535
-     */
-    public final int getRow(){
-        return field_1_row;
-    }
-
-    public final boolean isRowRelative() {
-        return rowRelative.isSet(field_2_col);
-    }
-
-    public final void setRowRelative(boolean rel) {
-        field_2_col=rowRelative.setBoolean(field_2_col,rel);
-    }
-
-    public final boolean isColRelative() {
-        return colRelative.isSet(field_2_col);
-    }
-
-    public final void setColRelative(boolean rel) {
-        field_2_col=colRelative.setBoolean(field_2_col,rel);
-    }
-
-    public final void setColumn(int col) {
-        if(col < 0 || col >= 0x100) {
-            throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
-        }
-       field_2_col = column.setValue(field_2_col, col);
-    }
-
-    public final int getColumn() {
-       return column.getValue(field_2_col);
-    }
-    protected final String formatReferenceAsString() {
-        // Only make cell references as needed. Memory is an issue
-        CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(), !isColRelative());
-        return cr.formatAsString();
-    }
-
-    public final byte getDefaultOperandClass() {
-        return Ptg.CLASS_REF;
-    }
+       private final static int MAX_ROW_NUMBER = 65536;
+
+       /** The row index - zero based unsigned 16 bit value */
+       private int field_1_row;
+       /**
+        * Field 2 - lower 8 bits is the zero based unsigned byte column index - bit
+        * 16 - isRowRelative - bit 15 - isColumnRelative
+        */
+       private int field_2_col;
+       private static final BitField rowRelative = BitFieldFactory.getInstance(0x8000);
+       private static final BitField colRelative = BitFieldFactory.getInstance(0x4000);
+       private static final BitField column = BitFieldFactory.getInstance(0x00FF);
+
+       protected RefPtgBase() {
+               // Required for clone methods
+       }
+
+       /**
+        * Takes in a String representation of a cell reference and fills out the
+        * numeric fields.
+        */
+       protected RefPtgBase(String cellref) {
+               CellReference c = new CellReference(cellref);
+               setRow(c.getRow());
+               setColumn(c.getCol());
+               setColRelative(!c.isColAbsolute());
+               setRowRelative(!c.isRowAbsolute());
+       }
+
+       protected RefPtgBase(int row, int column, boolean isRowRelative, boolean isColumnRelative) {
+               setRow(row);
+               setColumn(column);
+               setRowRelative(isRowRelative);
+               setColRelative(isColumnRelative);
+       }
+
+       protected final void readCoordinates(LittleEndianInput in)  {
+               field_1_row = in.readUShort();
+               field_2_col = in.readUShort();
+       }
+
+       protected final void writeCoordinates(LittleEndianOutput out) {
+               out.writeShort(field_1_row);
+               out.writeShort(field_2_col);
+       }
+
+       public final void setRow(int rowIndex) {
+               if (rowIndex < 0 || rowIndex >= MAX_ROW_NUMBER) {
+                       throw new IllegalArgumentException("rowIndex must be between 0 and " + MAX_ROW_NUMBER);
+               }
+               field_1_row = rowIndex;
+       }
+
+       /**
+        * @return the row number as an int, between 0 and 65535
+        */
+       public final int getRow() {
+               return field_1_row;
+       }
+
+       public final boolean isRowRelative() {
+               return rowRelative.isSet(field_2_col);
+       }
+
+       public final void setRowRelative(boolean rel) {
+               field_2_col = rowRelative.setBoolean(field_2_col, rel);
+       }
+
+       public final boolean isColRelative() {
+               return colRelative.isSet(field_2_col);
+       }
+
+       public final void setColRelative(boolean rel) {
+               field_2_col = colRelative.setBoolean(field_2_col, rel);
+       }
+
+       public final void setColumn(int col) {
+               if (col < 0 || col >= 0x100) {
+                       throw new IllegalArgumentException("Specified colIx (" + col + ") is out of range");
+               }
+               field_2_col = column.setValue(field_2_col, col);
+       }
+
+       public final int getColumn() {
+               return column.getValue(field_2_col);
+       }
+
+       protected final String formatReferenceAsString() {
+               // Only make cell references as needed. Memory is an issue
+               CellReference cr = new CellReference(getRow(), getColumn(), !isRowRelative(), !isColRelative());
+               return cr.formatAsString();
+       }
+
+       public final byte getDefaultOperandClass() {
+               return Ptg.CLASS_REF;
+       }
 }
index 2f34e2e360d48b3f90702066aa3190d72d0add85..be6a20d6e4952c38d3e21b23e4a782f06fe7c889 100644 (file)
@@ -17,9 +17,8 @@
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.BitField;
-import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 import org.apache.poi.util.StringUtil;
 
 /**
@@ -31,29 +30,26 @@ import org.apache.poi.util.StringUtil;
  * @author Bernard Chesnoy
  */
 public final class StringPtg extends ScalarConstantPtg {
-    public final static int SIZE = 9;
-    public final static byte sid = 0x17;
-    private static final BitField fHighByte = BitFieldFactory.getInstance(0x01);
-    /** the character (")used in formulas to delimit string literals */
+     public final static byte sid = 0x17;
+    /** the character (") used in formulas to delimit string literals */
     private static final char FORMULA_DELIMITER = '"';
 
+    private final boolean _is16bitUnicode;
     /**
      * NOTE: OO doc says 16bit length, but BiffViewer says 8 Book says something
      * totally different, so don't look there!
      */
-    private final int field_1_length;
-    private final byte field_2_options;
     private final String field_3_string;
 
     /** Create a StringPtg from a stream */
-    public StringPtg(RecordInputStream in) {
-        field_1_length = in.readUByte();
-        field_2_options = in.readByte();
-        if (fHighByte.isSet(field_2_options)) {
-            field_3_string = in.readUnicodeLEString(field_1_length);
-        } else {
-            field_3_string = in.readCompressedUnicode(field_1_length);
-        }
+    public StringPtg(LittleEndianInput in)  {
+       int nChars = in.readUByte(); // Note - nChars is 8-bit
+       _is16bitUnicode = (in.readByte() & 0x01) != 0;
+       if (_is16bitUnicode) {
+               field_3_string = StringUtil.readUnicodeLE(in, nChars);
+       } else {
+               field_3_string = StringUtil.readCompressedUnicode(in, nChars);
+       }
     }
 
     /**
@@ -69,32 +65,27 @@ public final class StringPtg extends ScalarConstantPtg {
             throw new IllegalArgumentException(
                     "String literals in formulas can't be bigger than 255 characters ASCII");
         }
-        field_2_options = (byte) fHighByte.setBoolean(0, StringUtil.hasMultibyte(value));
+        _is16bitUnicode = StringUtil.hasMultibyte(value);
         field_3_string = value;
-        field_1_length = value.length(); // for the moment, we support only ASCII strings in formulas we create
     }
 
     public String getValue() {
         return field_3_string;
     }
 
-    public void writeBytes(byte[] array, int offset) {
-        array[offset + 0] = sid;
-        array[offset + 1] = (byte) field_1_length;
-        array[offset + 2] = field_2_options;
-        if (fHighByte.isSet(field_2_options)) {
-            StringUtil.putUnicodeLE(getValue(), array, offset + 3);
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
+        out.writeByte(field_3_string.length()); // Note - nChars is 8-bit
+        out.writeByte(_is16bitUnicode ? 0x01 : 0x00);
+        if (_is16bitUnicode) {
+               StringUtil.putUnicodeLE(field_3_string, out);
         } else {
-            StringUtil.putCompressedUnicode(getValue(), array, offset + 3);
+               StringUtil.putCompressedUnicode(field_3_string, out);
         }
     }
 
     public int getSize() {
-        if (fHighByte.isSet(field_2_options)) {
-            return 2 * field_1_length + 3;
-        } else {
-            return field_1_length + 3;
-        }
+       return 3 +  field_3_string.length() * (_is16bitUnicode ? 2 : 1);
     }
 
     public String toFormulaString() {
index 0b17e268e254e5a732e6872ff8cf2ffa12ab79f8..280bd9c010bbf8ec3e3a68d8eefc9fb8f03b58e9 100644 (file)
@@ -18,8 +18,8 @@
 package org.apache.poi.hssf.record.formula;
 
 import org.apache.poi.hssf.record.RecordFormatException;
-import org.apache.poi.hssf.record.RecordInputStream;
-import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  * This ptg indicates a data table.
@@ -43,15 +43,15 @@ public final class TblPtg extends ControlPtg {
     /** The column number of the upper left corner */
     private final int field_2_first_col;
 
-    public TblPtg(RecordInputStream in) {
+    public TblPtg(LittleEndianInput in)  {
       field_1_first_row = in.readUShort();
       field_2_first_col = in.readUShort();
     }
 
-    public void writeBytes(byte [] array, int offset) {
-      LittleEndian.putByte(array, offset+0, sid);
-      LittleEndian.putUShort(array, offset+1, field_1_first_row);
-      LittleEndian.putUShort(array, offset+3, field_2_first_col);
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
+        out.writeShort(field_1_first_row);
+        out.writeShort(field_2_first_col);
     }
 
     public int getSize() {
index fdd82ce54927fb5bc0e52c053b6648f84b07c726..2c80ab6fe69349569ae8057b96ff685b110e70e2 100644 (file)
@@ -17,6 +17,8 @@
 
 package org.apache.poi.hssf.record.formula;
 
+import org.apache.poi.util.LittleEndianOutput;
+
 
 /**
  * @author Glen Stampoultzis (glens at apache.org)
@@ -39,9 +41,8 @@ public final class UnionPtg extends OperationPtg {
         return 1;
     }
 
-    public void writeBytes( byte[] array, int offset )
-    {
-        array[ offset + 0 ] = sid;
+    public void write(LittleEndianOutput out) {
+        out.writeByte(sid + getPtgClass());
     }
 
     public String toFormulaString()
index d073878707f61bb3ddc7b143a5b85e728df1c10b..d441a0098d56169c7fb468d18dc64c7cd97e03c0 100644 (file)
@@ -16,7 +16,7 @@
 ==================================================================== */
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.record.RecordInputStream;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
  *
@@ -25,22 +25,17 @@ import org.apache.poi.hssf.record.RecordInputStream;
  */
 public class UnknownPtg extends Ptg {
     private short size = 1;
+    private final int _sid;
 
-    /** Creates new UnknownPtg */
-
-    public UnknownPtg()
-    {
-    }
-
-    public UnknownPtg(RecordInputStream in) {
-        // doesn't need anything
+    public UnknownPtg(int sid) {
+        _sid = sid;
     }
 
     public boolean isBaseToken() {
-       return true;
+        return true;
     }
-    public void writeBytes(byte [] array, int offset)
-    {
+    public void write(LittleEndianOutput out) {
+        out.writeByte(_sid);
     }
 
     public int getSize()
@@ -55,8 +50,6 @@ public class UnknownPtg extends Ptg {
     public byte getDefaultOperandClass() {return Ptg.CLASS_VALUE;}
 
     public Object clone() {
-      return new UnknownPtg();
+      return this;
     }
-
-    
 }
index 7bb632b59598a543b8a4c1d77674a40b3e07a357..4f9d4be30507536280c6f5c8412efc769e6cb541 100644 (file)
 
 package org.apache.poi.hssf.record.formula;
 
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.LittleEndianOutput;
 
 /**
- * Common superclass of all value operators.
- * Subclasses include all unary and binary operators except for the reference operators (IntersectionPtg, RangePtg, UnionPtg) 
+ * Common superclass of all value operators. Subclasses include all unary and
+ * binary operators except for the reference operators (IntersectionPtg,
+ * RangePtg, UnionPtg)
  * 
  * @author Josh Micich
  */
 public abstract class ValueOperatorPtg extends OperationPtg {
 
        /**
-        * All Operator <tt>Ptg</tt>s are base tokens (i.e. are not RVA classified)  
+        * All Operator <tt>Ptg</tt>s are base tokens (i.e. are not RVA classified)
         */
        public final boolean isBaseToken() {
                return true;
@@ -38,8 +39,8 @@ public abstract class ValueOperatorPtg extends OperationPtg {
                return Ptg.CLASS_VALUE;
        }
 
-       public final void writeBytes(byte[] array, int offset) {
-               array[offset + 0] = getSid();
+       public void write(LittleEndianOutput out) {
+               out.writeByte(getSid());
        }
 
        protected abstract byte getSid();
@@ -47,8 +48,9 @@ public abstract class ValueOperatorPtg extends OperationPtg {
        public final int getSize() {
                return 1;
        }
-    public final String toFormulaString() {
-       // TODO - prune this method out of the hierarchy
-       throw new RuntimeException("toFormulaString(String[] operands) should be used for subclasses of OperationPtgs");
+
+       public final String toFormulaString() {
+               // TODO - prune this method out of the hierarchy
+               throw new RuntimeException("toFormulaString(String[] operands) should be used for subclasses of OperationPtgs");
        }
 }
index 84525881a733e3a2ed7c738b3ecf55fba69425fa..5baf8219ccbdd5bafff16554518a10983c64b53b 100644 (file)
@@ -975,7 +975,7 @@ public class HSSFCellStyle implements CellStyle
        if(sr == null) {
                return null;
        }
-       if(sr.getType() == StyleRecord.STYLE_BUILT_IN) {
+       if(sr.isBuiltin()) {
                return null;
        }
        return sr.getName();
@@ -990,7 +990,7 @@ public class HSSFCellStyle implements CellStyle
        if(sr == null) {
                sr = workbook.createStyleRecord(index);
        }
-       if(sr.getType() == StyleRecord.STYLE_BUILT_IN) {
+       if(sr.isBuiltin()) {
                throw new IllegalArgumentException("Unable to set user specified style names for built in styles!");
        }
        sr.setName(styleName);
index 786a8d24e2271a60feb49febb0efa2d1c23b86c7..ecd110a3292a85a38e4b79a3208dbf065ff76e18 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.filesystem;
 
-import java.io.*;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.poifs.storage.DataInputBlock;
+import org.apache.poi.util.LittleEndianInput;
 
 /**
  * This class provides methods to read a DocumentEntry managed by a
- * Filesystem instance.
+ * {@link POIFSFileSystem} instance.
  *
  * @author Marc Johnson (mjohnson at apache dot org)
  */
-
-public class DocumentInputStream
-    extends InputStream
-{
-
-    // current offset into the Document
-    private int              _current_offset;
-
-    // current marked offset into the Document (used by mark and
-    // reset)
-    private int              _marked_offset;
-
-    // the Document's size
-    private int              _document_size;
-
-    // have we been closed?
-    private boolean          _closed;
-
-    // the actual Document
-    private POIFSDocument    _document;
-
-    // buffer used to read one byte at a time
-    private byte[]           _tiny_buffer;
-
-    // returned by read operations if we're at end of document
-    static private final int EOD = -1;
-
-    /**
-     * Create an InputStream from the specified DocumentEntry
-     *
-     * @param document the DocumentEntry to be read
-     *
-     * @exception IOException if the DocumentEntry cannot be opened
-     *            (like, maybe it has been deleted?)
-     */
-
-    public DocumentInputStream(final DocumentEntry document)
-        throws IOException
-    {
-        _current_offset = 0;
-        _marked_offset  = 0;
-        _document_size  = document.getSize();
-        _closed         = false;
-        _tiny_buffer    = null;
-        if (document instanceof DocumentNode)
-        {
-            _document = (( DocumentNode ) document).getDocument();
-        }
-        else
-        {
-            throw new IOException("Cannot open internal document storage");
-        }
-    }
-
-    /**
-     * Create an InputStream from the specified Document
-     *
-     * @param document the Document to be read
-     *
-     * @exception IOException if the DocumentEntry cannot be opened
-     *            (like, maybe it has been deleted?)
-     */
-
-    public DocumentInputStream(final POIFSDocument document)
-        throws IOException
-    {
-        _current_offset = 0;
-        _marked_offset  = 0;
-        _document_size  = document.getSize();
-        _closed         = false;
-        _tiny_buffer    = null;
-        _document       = document;
-    }
-
-    /**
-     * Returns the number of bytes that can be read (or skipped over)
-     * from this input stream without blocking by the next caller of a
-     * method for this input stream. The next caller might be the same
-     * thread or or another thread.
-     *
-     * @return the number of bytes that can be read from this input
-     *         stream without blocking.
-     *
-     * @exception IOException on error (such as the stream has been
-     *            closed)
-     */
-
-    public int available()
-        throws IOException
-    {
-        dieIfClosed();
-        return _document_size - _current_offset;
-    }
-
-    /**
-     * Closes this input stream and releases any system resources
-     * associated with the stream.
-     *
-     * @exception IOException
-     */
-
-    public void close()
-        throws IOException
-    {
-        _closed = true;
-    }
-
-    /**
-     * Marks the current position in this input stream. A subsequent
-     * call to the reset method repositions this stream at the last
-     * marked position so that subsequent reads re-read the same
-     * bytes.
-     * <p>
-     * The readlimit arguments tells this input stream to allow that
-     * many bytes to be read before the mark position gets
-     * invalidated. This implementation, however, does not care.
-     * <p>
-     * The general contract of mark is that, if the method
-     * markSupported returns true, the stream somehow remembers all
-     * the bytes read after the call to mark and stands ready to
-     * supply those same bytes again if and whenever the method reset
-     * is called. However, the stream is not required to remember any
-     * data at all if more than readlimit bytes are read from the
-     * stream before reset is called. But this stream will.
-     *
-     * @param ignoredReadlimit the maximum limit of bytes that can be
-     *                         read before the mark position becomes
-     *                         invalid. Ignored by this
-     *                         implementation.
-     */
-
-    public void mark(int ignoredReadlimit)
-    {
-        _marked_offset = _current_offset;
-    }
-
-    /**
-     * Tests if this input stream supports the mark and reset methods.
-     *
-     * @return true
-     */
-
-    public boolean markSupported()
-    {
-        return true;
-    }
-
-    /**
-     * Reads the next byte of data from the input stream. The value
-     * byte is returned as an int in the range 0 to 255. If no byte is
-     * available because the end of the stream has been reached, the
-     * value -1 is returned. The definition of this method in
-     * java.io.InputStream allows this method to block, but it won't.
-     *
-     * @return the next byte of data, or -1 if the end of the stream
-     *         is reached.
-     *
-     * @exception IOException
-     */
-
-    public int read()
-        throws IOException
-    {
-        dieIfClosed();
-        if (atEOD())
-        {
-            return EOD;
-        }
-        if (_tiny_buffer == null)
-        {
-            _tiny_buffer = new byte[ 1 ];
-        }
-        _document.read(_tiny_buffer, _current_offset++);
-        return ((int)_tiny_buffer[ 0 ]) & 0x000000FF;
-    }
-
-    /**
-     * Reads some number of bytes from the input stream and stores
-     * them into the buffer array b. The number of bytes actually read
-     * is returned as an integer. The definition of this method in
-     * java.io.InputStream allows this method to block, but it won't.
-     * <p>
-     * If b is null, a NullPointerException is thrown. If the length
-     * of b is zero, then no bytes are read and 0 is returned;
-     * otherwise, there is an attempt to read at least one byte. If no
-     * byte is available because the stream is at end of file, the
-     * value -1 is returned; otherwise, at least one byte is read and
-     * stored into b.
-     * <p>
-     * The first byte read is stored into element b[0], the next one
-     * into b[1], and so on. The number of bytes read is, at most,
-     * equal to the length of b. Let k be the number of bytes actually
-     * read; these bytes will be stored in elements b[0] through
-     * b[k-1], leaving elements b[k] through b[b.length-1] unaffected.
-     * <p>
-     * If the first byte cannot be read for any reason other than end
-     * of file, then an IOException is thrown. In particular, an
-     * IOException is thrown if the input stream has been closed.
-     * <p>
-     * The read(b) method for class InputStream has the same effect as:
-     * <p>
-     * <code>read(b, 0, b.length)</code>
-     *
-     * @param b the buffer into which the data is read.
-     *
-     * @return the total number of bytes read into the buffer, or -1
-     *         if there is no more data because the end of the stream
-     *         has been reached.
-     *
-     * @exception IOException
-     * @exception NullPointerException
-     */
-
-    public int read(final byte [] b)
-        throws IOException, NullPointerException
-    {
-        return read(b, 0, b.length);
-    }
-
-    /**
-     * Reads up to len bytes of data from the input stream into an
-     * array of bytes. An attempt is made to read as many as len
-     * bytes, but a smaller number may be read, possibly zero. The
-     * number of bytes actually read is returned as an integer.
-     * <p>
-     * The definition of this method in java.io.InputStream allows it
-     * to block, but it won't.
-     * <p>
-     * If b is null, a NullPointerException is thrown.
-     * <p>
-     * If off is negative, or len is negative, or off+len is greater
-     * than the length of the array b, then an
-     * IndexOutOfBoundsException is thrown.
-     * <p>
-     * If len is zero, then no bytes are read and 0 is returned;
-     * otherwise, there is an attempt to read at least one byte. If no
-     * byte is available because the stream is at end of file, the
-     * value -1 is returned; otherwise, at least one byte is read and
-     * stored into b.
-     * <p>
-     * The first byte read is stored into element b[off], the next one
-     * into b[off+1], and so on. The number of bytes read is, at most,
-     * equal to len. Let k be the number of bytes actually read; these
-     * bytes will be stored in elements b[off] through b[off+k-1],
-     * leaving elements b[off+k] through b[off+len-1] unaffected.
-     * <p>
-     * In every case, elements b[0] through b[off] and elements
-     * b[off+len] through b[b.length-1] are unaffected.
-     * <p>
-     * If the first byte cannot be read for any reason other than end
-     * of file, then an IOException is thrown. In particular, an
-     * IOException is thrown if the input stream has been closed.
-     *
-     * @param b the buffer into which the data is read.
-     * @param off the start offset in array b at which the data is
-     *            written.
-     * @param len the maximum number of bytes to read.
-     *
-     * @return the total number of bytes read into the buffer, or -1
-     *         if there is no more data because the end of the stream
-     *         has been reached.
-     *
-     * @exception IOException
-     * @exception NullPointerException
-     * @exception IndexOutOfBoundsException
-     */
-
-    public int read(final byte [] b, final int off, final int len)
-        throws IOException, NullPointerException, IndexOutOfBoundsException
-    {
-        dieIfClosed();
-        if (b == null)
-        {
-            throw new NullPointerException("buffer is null");
-        }
-        if ((off < 0) || (len < 0) || (b.length < (off + len)))
-        {
-            throw new IndexOutOfBoundsException(
-                "can't read past buffer boundaries");
-        }
-        if (len == 0)
-        {
-            return 0;
-        }
-        if (atEOD())
-        {
-            return EOD;
-        }
-        int limit = Math.min(available(), len);
-
-        if ((off == 0) && (limit == b.length))
-        {
-            _document.read(b, _current_offset);
-        }
-        else
-        {
-            byte[] buffer = new byte[ limit ];
-
-            _document.read(buffer, _current_offset);
-            System.arraycopy(buffer, 0, b, off, limit);
-        }
-        _current_offset += limit;
-        return limit;
-    }
-
-    /**
-     * Repositions this stream to the position at the time the mark
-     * method was last called on this input stream.
-     * <p>
-     * The general contract of reset is:
-     * <p>
-     * <ul>
-     *    <li>
-     *        If the method markSupported returns true, then:
-     *        <ul>
-     *            <li>
-     *                If the method mark has not been called since the
-     *                stream was created, or the number of bytes read
-     *                from the stream since mark was last called is
-     *                larger than the argument to mark at that last
-     *                call, then an IOException might be thrown.
-     *            </li>
-     *            <li>
-     *                If such an IOException is not thrown, then the
-     *                stream is reset to a state such that all the
-     *                bytes read since the most recent call to mark
-     *                (or since the start of the file, if mark has not
-     *                been called) will be resupplied to subsequent
-     *                callers of the read method, followed by any
-     *                bytes that otherwise would have been the next
-     *                input data as of the time of the call to reset.
-     *             </li>
-     *         </ul>
-     *     </li>
-     *     <li>
-     *         If the method markSupported returns false, then:
-     *         <ul>
-     *             <li>
-     *                 The call to reset may throw an IOException.
-     *             </li>
-     *             <li>
-     *                 If an IOException is not thrown, then the
-     *                 stream is reset to a fixed state that depends
-     *                 on the particular type of the input and how it
-     *                 was created. The bytes that will be supplied to
-     *                 subsequent callers of the read method depend on
-     *                 the particular type of the input stream.
-     *             </li>
-     *         </ul>
-     *     </li>
-     * </ul>
-     * <p>
-     * All well and good ... this class's markSupported method returns
-     * true and this method does not care whether you've called mark
-     * at all, or whether you've exceeded the number of bytes
-     * specified in the last call to mark. We're basically walking a
-     * byte array ... mark and reset to your heart's content.
-     */
-
-    public void reset()
-    {
-        _current_offset = _marked_offset;
-    }
-
-    /**
-     * Skips over and discards n bytes of data from this input
-     * stream. The skip method may, for a variety of reasons, end up
-     * skipping over some smaller number of bytes, possibly 0. This
-     * may result from any of a number of conditions; reaching end of
-     * file before n bytes have been skipped is only one
-     * possibility. The actual number of bytes skipped is returned. If
-     * n is negative, no bytes are skipped.
-     *
-     * @param n the number of bytes to be skipped.
-     *
-     * @return the actual number of bytes skipped.
-     *
-     * @exception IOException
-     */
-
-    public long skip(final long n)
-        throws IOException
-    {
-        dieIfClosed();
-        if (n < 0)
-        {
-            return 0;
-        }
-        int new_offset = _current_offset + ( int ) n;
-
-        if (new_offset < _current_offset)
-        {
-
-            // wrap around in converting a VERY large long to an int
-            new_offset = _document_size;
-        }
-        else if (new_offset > _document_size)
-        {
-            new_offset = _document_size;
-        }
-        long rval = new_offset - _current_offset;
-
-        _current_offset = new_offset;
-        return rval;
-    }
-
-    private void dieIfClosed()
-        throws IOException
-    {
-        if (_closed)
-        {
-            throw new IOException(
-                "cannot perform requested operation on a closed stream");
-        }
-    }
-
-    private boolean atEOD()
-    {
-        return _current_offset == _document_size;
-    }
-}   // end public class DocumentInputStream
-
+public final class DocumentInputStream extends InputStream implements LittleEndianInput {
+       /** returned by read operations if we're at end of document */
+       private static final int EOF = -1;
+
+       private static final int SIZE_SHORT = 2;
+       private static final int SIZE_INT = 4;
+       private static final int SIZE_LONG = 8;
+
+       /** current offset into the Document */
+       private int _current_offset;
+
+       /** current marked offset into the Document (used by mark and reset) */
+       private int _marked_offset;
+
+       /** the Document's size */
+       private int _document_size;
+
+       /** have we been closed? */
+       private boolean _closed;
+
+       /** the actual Document */
+       private POIFSDocument _document;
+
+       /** the data block containing the current stream pointer */
+       private DataInputBlock _currentBlock;
+
+       /**
+        * Create an InputStream from the specified DocumentEntry
+        * 
+        * @param document the DocumentEntry to be read
+        * 
+        * @exception IOException if the DocumentEntry cannot be opened (like, maybe it has
+        *                been deleted?)
+        */
+       public DocumentInputStream(DocumentEntry document) throws IOException {
+               if (!(document instanceof DocumentNode)) {
+                       throw new IOException("Cannot open internal document storage");
+               }
+               _current_offset = 0;
+               _marked_offset = 0;
+               _document_size = document.getSize();
+               _closed = false;
+               _document = ((DocumentNode) document).getDocument();
+               _currentBlock = getDataInputBlock(0);
+       }
+
+       /**
+        * Create an InputStream from the specified Document
+        * 
+        * @param document the Document to be read
+        */
+       public DocumentInputStream(POIFSDocument document) {
+               _current_offset = 0;
+               _marked_offset = 0;
+               _document_size = document.getSize();
+               _closed = false;
+               _document = document;
+               _currentBlock = getDataInputBlock(0);
+       }
+
+       public int available() {
+               if (_closed) {
+                       throw new IllegalStateException("cannot perform requested operation on a closed stream");
+               }
+               return _document_size - _current_offset;
+       }
+
+       public void close() {
+               _closed = true;
+       }
+
+       public void mark(int ignoredReadlimit) {
+               _marked_offset = _current_offset;
+       }
+
+       /**
+        * Tests if this input stream supports the mark and reset methods.
+        * 
+        * @return <code>true</code> always
+        */
+       public boolean markSupported() {
+               return true;
+       }
+
+       private DataInputBlock getDataInputBlock(int offset) {
+               return _document.getDataInputBlock(offset);
+       }
+
+       public int read() throws IOException {
+               dieIfClosed();
+               if (atEOD()) {
+                       return EOF;
+               }
+               int result = _currentBlock.readUByte();
+               _current_offset++;
+               if (_currentBlock.available() < 1) {
+                       _currentBlock = getDataInputBlock(_current_offset);
+               }
+               return result;
+       }
+
+       public int read(byte[] b) throws IOException {
+               return read(b, 0, b.length);
+       }
+
+       public int read(byte[] b, int off, int len) throws IOException {
+               dieIfClosed();
+               if (b == null) {
+                       throw new IllegalArgumentException("buffer must not be null");
+               }
+               if (off < 0 || len < 0 || b.length < off + len) {
+                       throw new IndexOutOfBoundsException("can't read past buffer boundaries");
+               }
+               if (len == 0) {
+                       return 0;
+               }
+               if (atEOD()) {
+                       return EOF;
+               }
+               int limit = Math.min(available(), len);
+               readFully(b, off, limit);
+               return limit;
+       }
+
+       /**
+        * Repositions this stream to the position at the time the mark() method was
+        * last called on this input stream. If mark() has not been called this
+        * method repositions the stream to its beginning.
+        */
+       public void reset() {
+               _current_offset = _marked_offset;
+               _currentBlock = getDataInputBlock(_current_offset);
+       }
+
+       public long skip(long n) throws IOException {
+               dieIfClosed();
+               if (n < 0) {
+                       return 0;
+               }
+               int new_offset = _current_offset + (int) n;
+
+               if (new_offset < _current_offset) {
+
+                       // wrap around in converting a VERY large long to an int
+                       new_offset = _document_size;
+               } else if (new_offset > _document_size) {
+                       new_offset = _document_size;
+               }
+               long rval = new_offset - _current_offset;
+
+               _current_offset = new_offset;
+               _currentBlock = getDataInputBlock(_current_offset);
+               return rval;
+       }
+
+       private void dieIfClosed() throws IOException {
+               if (_closed) {
+                       throw new IOException("cannot perform requested operation on a closed stream");
+               }
+       }
+
+       private boolean atEOD() {
+               return _current_offset == _document_size;
+       }
+
+       private void checkAvaliable(int requestedSize) {
+               if (_closed) {
+                       throw new IllegalStateException("cannot perform requested operation on a closed stream");
+               }
+               if (requestedSize > _document_size - _current_offset) {
+                       throw new RuntimeException("Buffer underrun - requested " + requestedSize
+                                       + " bytes but " + (_document_size - _current_offset) + " was available");
+               }
+       }
+
+       public byte readByte() {
+               return (byte) readUByte();
+       }
+
+       public double readDouble() {
+               return Double.longBitsToDouble(readLong());
+       }
+
+       public void readFully(byte[] buf) {
+               readFully(buf, 0, buf.length);
+       }
+
+       public short readShort() {
+               return (short) readUShort();
+       }
+
+       public void readFully(byte[] buf, int off, int len) {
+               checkAvaliable(len);
+               int blockAvailable = _currentBlock.available();
+               if (blockAvailable > len) {
+                       _currentBlock.readFully(buf, off, len);
+                       _current_offset += len;
+                       return;
+               }
+               // else read big amount in chunks
+               int remaining = len;
+               int writePos = off;
+               while (remaining > 0) {
+                       boolean blockIsExpiring = remaining >= blockAvailable;
+                       int reqSize;
+                       if (blockIsExpiring) {
+                               reqSize = blockAvailable;
+                       } else {
+                               reqSize = remaining;
+                       }
+                       _currentBlock.readFully(buf, writePos, reqSize);
+                       remaining -= reqSize;
+                       writePos += reqSize;
+                       _current_offset += reqSize;
+                       if (blockIsExpiring) {
+                               if (_current_offset == _document_size) {
+                                       if (remaining > 0) {
+                                               throw new IllegalStateException(
+                                                               "reached end of document stream unexpectedly");
+                                       }
+                                       _currentBlock = null;
+                                       break;
+                               }
+                               _currentBlock = getDataInputBlock(_current_offset);
+                               blockAvailable = _currentBlock.available();
+                       }
+               }
+       }
+
+       public long readLong() {
+               checkAvaliable(SIZE_LONG);
+               int blockAvailable = _currentBlock.available();
+               long result;
+               if (blockAvailable > SIZE_LONG) {
+                       result = _currentBlock.readLongLE();
+               } else {
+                       DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
+                       if (blockAvailable == SIZE_LONG) {
+                               result = _currentBlock.readLongLE();
+                       } else {
+                               result = nextBlock.readLongLE(_currentBlock, blockAvailable);
+                       }
+                       _currentBlock = nextBlock;
+               }
+               _current_offset += SIZE_LONG;
+               return result;
+       }
+
+       public int readInt() {
+               checkAvaliable(SIZE_INT);
+               int blockAvailable = _currentBlock.available();
+               int result;
+               if (blockAvailable > SIZE_INT) {
+                       result = _currentBlock.readIntLE();
+               } else {
+                       DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
+                       if (blockAvailable == SIZE_INT) {
+                               result = _currentBlock.readIntLE();
+                       } else {
+                               result = nextBlock.readIntLE(_currentBlock, blockAvailable);
+                       }
+                       _currentBlock = nextBlock;
+               }
+               _current_offset += SIZE_INT;
+               return result;
+       }
+
+       public int readUShort() {
+               checkAvaliable(SIZE_SHORT);
+               int blockAvailable = _currentBlock.available();
+               int result;
+               if (blockAvailable > SIZE_SHORT) {
+                       result = _currentBlock.readUShortLE();
+               } else {
+                       DataInputBlock nextBlock = getDataInputBlock(_current_offset + blockAvailable);
+                       if (blockAvailable == SIZE_SHORT) {
+                               result = _currentBlock.readUShortLE();
+                       } else {
+                               result = nextBlock.readUShortLE(_currentBlock);
+                       }
+                       _currentBlock = nextBlock;
+               }
+               _current_offset += SIZE_SHORT;
+               return result;
+       }
+
+       public int readUByte() {
+               checkAvaliable(1);
+               int result = _currentBlock.readUByte();
+               _current_offset++;
+               if (_currentBlock.available() < 1) {
+                       _currentBlock = getDataInputBlock(_current_offset);
+               }
+               return result;
+       }
+}
index c313baf4894d0d5f933dc4cb2c20fa2b73dc3496..b7830355561df68886ee1d5568af26c5e2f23ed1 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.filesystem;
 
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
 
 import org.apache.poi.poifs.common.POIFSConstants;
 import org.apache.poi.poifs.dev.POIFSViewable;
 import org.apache.poi.poifs.property.DocumentProperty;
 import org.apache.poi.poifs.property.Property;
 import org.apache.poi.poifs.storage.BlockWritable;
-import org.apache.poi.poifs.storage.ListManagedBlock;
+import org.apache.poi.poifs.storage.DataInputBlock;
 import org.apache.poi.poifs.storage.DocumentBlock;
+import org.apache.poi.poifs.storage.ListManagedBlock;
 import org.apache.poi.poifs.storage.RawDataBlock;
 import org.apache.poi.poifs.storage.SmallDocumentBlock;
 import org.apache.poi.util.HexDump;
@@ -39,595 +43,488 @@ import org.apache.poi.util.HexDump;
  *
  * @author Marc Johnson (mjohnson at apache dot org)
  */
-
-public class POIFSDocument
-    implements BATManaged, BlockWritable, POIFSViewable
-{
-    private DocumentProperty _property;
-    private int              _size;
-
-    // one of these stores will be valid
-    private SmallBlockStore  _small_store;
-    private BigBlockStore    _big_store;
-
-    /**
-     * Constructor from large blocks
-     *
-     * @param name the name of the POIFSDocument
-     * @param blocks the big blocks making up the POIFSDocument
-     * @param length the actual length of the POIFSDocument
-     *
-     * @exception IOException
-     */
-
-    public POIFSDocument(final String name, final RawDataBlock [] blocks,
-                         final int length)
-        throws IOException
-    {
-        _size        = length;
-        _big_store   = new BigBlockStore(blocks);
-        _property    = new DocumentProperty(name, _size);
-        _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
-        _property.setDocument(this);
-    }
-
-    /**
-     * Constructor from small blocks
-     *
-     * @param name the name of the POIFSDocument
-     * @param blocks the small blocks making up the POIFSDocument
-     * @param length the actual length of the POIFSDocument
-     */
-
-    public POIFSDocument(final String name,
-                         final SmallDocumentBlock [] blocks, final int length)
-    {
-        _size = length;
-        try
-        {
-            _big_store = new BigBlockStore(new RawDataBlock[ 0 ]);
-        }
-        catch (IOException ignored)
-        {
-
-            // can't happen with that constructor
-        }
-        _property    = new DocumentProperty(name, _size);
-        _small_store = new SmallBlockStore(blocks);
-        _property.setDocument(this);
-    }
-
-    /**
-     * Constructor from small blocks
-     *
-     * @param name the name of the POIFSDocument
-     * @param blocks the small blocks making up the POIFSDocument
-     * @param length the actual length of the POIFSDocument
-     *
-     * @exception IOException
-     */
-
-    public POIFSDocument(final String name, final ListManagedBlock [] blocks,
-                         final int length)
-        throws IOException
-    {
-        _size     = length;
-        _property = new DocumentProperty(name, _size);
-        _property.setDocument(this);
-        if (Property.isSmall(_size))
-        {
-            _big_store   = new BigBlockStore(new RawDataBlock[ 0 ]);
-            _small_store = new SmallBlockStore(blocks);
-        }
-        else
-        {
-            _big_store   = new BigBlockStore(blocks);
-            _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
-        }
-    }
-
-    /**
-     * Constructor
-     *
-     * @param name the name of the POIFSDocument
-     * @param stream the InputStream we read data from
-     *
-     * @exception IOException thrown on read errors
-     */
-
-    public POIFSDocument(final String name, final InputStream stream)
-        throws IOException
-    {
-        List blocks = new ArrayList();
-
-        _size = 0;
-        while (true)
-        {
-            DocumentBlock block     = new DocumentBlock(stream);
-            int           blockSize = block.size();
-
-            if (blockSize > 0)
-            {
-                blocks.add(block);
-                _size += blockSize;
-            }
-            if (block.partiallyRead())
-            {
-                break;
-            }
-        }
-        DocumentBlock[] bigBlocks =
-            ( DocumentBlock [] ) blocks.toArray(new DocumentBlock[ 0 ]);
-
-        _big_store = new BigBlockStore(bigBlocks);
-        _property  = new DocumentProperty(name, _size);
-        _property.setDocument(this);
-        if (_property.shouldUseSmallBlocks())
-        {
-            _small_store =
-                new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks,
-                    _size));
-            _big_store   = new BigBlockStore(new DocumentBlock[ 0 ]);
-        }
-        else
-        {
-            _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
-        }
-    }
-
-    /**
-     * Constructor
-     *
-     * @param name the name of the POIFSDocument
-     * @param size the length of the POIFSDocument
-     * @param path the path of the POIFSDocument
-     * @param writer the writer who will eventually write the document
-     *               contents
-     *
-     * @exception IOException thrown on read errors
-     */
-
-    public POIFSDocument(final String name, final int size,
-                         final POIFSDocumentPath path,
-                         final POIFSWriterListener writer)
-        throws IOException
-    {
-        _size     = size;
-        _property = new DocumentProperty(name, _size);
-        _property.setDocument(this);
-        if (_property.shouldUseSmallBlocks())
-        {
-            _small_store = new SmallBlockStore(path, name, size, writer);
-            _big_store   = new BigBlockStore(new Object[ 0 ]);
-        }
-        else
-        {
-            _small_store = new SmallBlockStore(new BlockWritable[ 0 ]);
-            _big_store   = new BigBlockStore(path, name, size, writer);
-        }
-    }
-
-    /**
-     * return the array of SmallDocumentBlocks used
-     *
-     * @return array of SmallDocumentBlocks; may be empty, cannot be null
-     */
-
-    public BlockWritable [] getSmallBlocks()
-    {
-        return _small_store.getBlocks();
-    }
-
-    /**
-     * @return size of the document
-     */
-
-    public int getSize()
-    {
-        return _size;
-    }
-
-    /**
-     * read data from the internal stores
-     *
-     * @param buffer the buffer to write to
-     * @param offset the offset into our storage to read from
-     */
-
-    void read(final byte [] buffer, final int offset)
-    {
-        if (_property.shouldUseSmallBlocks())
-        {
-            SmallDocumentBlock.read(_small_store.getBlocks(), buffer, offset);
-        }
-        else
-        {
-            DocumentBlock.read(_big_store.getBlocks(), buffer, offset);
-        }
-    }
-
-    /**
-     * Get the DocumentProperty
-     *
-     * @return the instance's DocumentProperty
-     */
-
-    DocumentProperty getDocumentProperty()
-    {
-        return _property;
-    }
-
-    /* ********** START implementation of BlockWritable ********** */
-
-    /**
-     * Write the storage to an OutputStream
-     *
-     * @param stream the OutputStream to which the stored data should
-     *               be written
-     *
-     * @exception IOException on problems writing to the specified
-     *            stream
-     */
-
-    public void writeBlocks(final OutputStream stream)
-        throws IOException
-    {
-        _big_store.writeBlocks(stream);
-    }
-
-    /* **********  END  implementation of BlockWritable ********** */
-    /* ********** START implementation of BATManaged ********** */
-
-    /**
-     * Return the number of BigBlock's this instance uses
-     *
-     * @return count of BigBlock instances
-     */
-
-    public int countBlocks()
-    {
-        return _big_store.countBlocks();
-    }
-
-    /**
-     * Set the start block for this instance
-     *
-     * @param index index into the array of blocks making up the
-     *        filesystem
-     */
-
-    public void setStartBlock(final int index)
-    {
-        _property.setStartBlock(index);
-    }
-
-    /* **********  END  implementation of BATManaged ********** */
-    /* ********** START begin implementation of POIFSViewable ********** */
-
-    /**
-     * Get an array of objects, some of which may implement
-     * POIFSViewable
-     *
-     * @return an array of Object; may not be null, but may be empty
-     */
-
-    public Object [] getViewableArray()
-    {
-        Object[] results = new Object[ 1 ];
-        String   result;
-
-        try
-        {
-            ByteArrayOutputStream output = new ByteArrayOutputStream();
-            BlockWritable[]       blocks = null;
-
-            if (_big_store.isValid())
-            {
-                blocks = _big_store.getBlocks();
-            }
-            else if (_small_store.isValid())
-            {
-                blocks = _small_store.getBlocks();
-            }
-            if (blocks != null)
-            {
-                for (int k = 0; k < blocks.length; k++)
-                {
-                    blocks[ k ].writeBlocks(output);
-                }
-                byte[] data = output.toByteArray();
-
-                if (data.length > _property.getSize())
-                {
-                    byte[] tmp = new byte[ _property.getSize() ];
-
-                    System.arraycopy(data, 0, tmp, 0, tmp.length);
-                    data = tmp;
-                }
-                output = new ByteArrayOutputStream();
-                HexDump.dump(data, 0, output, 0);
-                result = output.toString();
-            }
-            else
-            {
-                result = "<NO DATA>";
-            }
-        }
-        catch (IOException e)
-        {
-            result = e.getMessage();
-        }
-        results[ 0 ] = result;
-        return results;
-    }
-
-    /**
-     * Get an Iterator of objects, some of which may implement
-     * POIFSViewable
-     *
-     * @return an Iterator; may not be null, but may have an empty
-     * back end store
-     */
-
-    public Iterator getViewableIterator()
-    {
-        return Collections.EMPTY_LIST.iterator();
-    }
-
-    /**
-     * Give viewers a hint as to whether to call getViewableArray or
-     * getViewableIterator
-     *
-     * @return true if a viewer should call getViewableArray, false if
-     *         a viewer should call getViewableIterator
-     */
-
-    public boolean preferArray()
-    {
-        return true;
-    }
-
-    /**
-     * Provides a short description of the object, to be used when a
-     * POIFSViewable object has not provided its contents.
-     *
-     * @return short description
-     */
-
-    public String getShortDescription()
-    {
-        StringBuffer buffer = new StringBuffer();
-
-        buffer.append("Document: \"").append(_property.getName())
-            .append("\"");
-        buffer.append(" size = ").append(getSize());
-        return buffer.toString();
-    }
-
-    /* **********  END  begin implementation of POIFSViewable ********** */
-    private class SmallBlockStore
-    {
-        private SmallDocumentBlock[] smallBlocks;
-        private POIFSDocumentPath    path;
-        private String               name;
-        private int                  size;
-        private POIFSWriterListener  writer;
-
-        /**
-         * Constructor
-         *
-         * @param blocks blocks to construct the store from
-         */
-
-        SmallBlockStore(final Object [] blocks)
-        {
-            smallBlocks = new SmallDocumentBlock[ blocks.length ];
-            for (int j = 0; j < blocks.length; j++)
-            {
-                smallBlocks[ j ] = ( SmallDocumentBlock ) blocks[ j ];
-            }
-            this.path   = null;
-            this.name   = null;
-            this.size   = -1;
-            this.writer = null;
-        }
-
-        /**
-         * Constructor for a small block store that will be written
-         * later
-         *
-         * @param path path of the document
-         * @param name name of the document
-         * @param size length of the document
-         * @param writer the object that will eventually write the document
-         */
-
-        SmallBlockStore(final POIFSDocumentPath path, final String name,
-                        final int size, final POIFSWriterListener writer)
-        {
-            smallBlocks = new SmallDocumentBlock[ 0 ];
-            this.path   = path;
-            this.name   = name;
-            this.size   = size;
-            this.writer = writer;
-        }
-
-        /**
-         * @return true if this store is a valid source of data
-         */
-
-        boolean isValid()
-        {
-            return ((smallBlocks.length > 0) || (writer != null));
-        }
-
-        /**
-         * @return the SmallDocumentBlocks
-         */
-
-        BlockWritable [] getBlocks()
-        {
-            if (isValid() && (writer != null))
-            {
-                ByteArrayOutputStream stream  =
-                    new ByteArrayOutputStream(size);
-                DocumentOutputStream  dstream =
-                    new DocumentOutputStream(stream, size);
-
-                writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
-                        path, name, size));
-                smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(),
-                                                         size);
-            }
-            return smallBlocks;
-        }
-    }   // end private class SmallBlockStore
-
-    private class BigBlockStore
-    {
-        private DocumentBlock[]     bigBlocks;
-        private POIFSDocumentPath   path;
-        private String              name;
-        private int                 size;
-        private POIFSWriterListener writer;
-
-        /**
-         * Constructor
-         *
-         * @param blocks the blocks making up the store
-         *
-         * @exception IOException on I/O error
-         */
-
-        BigBlockStore(final Object [] blocks)
-            throws IOException
-        {
-            bigBlocks = new DocumentBlock[ blocks.length ];
-            for (int j = 0; j < blocks.length; j++)
-            {
-                if (blocks[ j ] instanceof DocumentBlock)
-                {
-                    bigBlocks[ j ] = ( DocumentBlock ) blocks[ j ];
-                }
-                else
-                {
-                    bigBlocks[ j ] =
-                        new DocumentBlock(( RawDataBlock ) blocks[ j ]);
-                }
-            }
-            this.path   = null;
-            this.name   = null;
-            this.size   = -1;
-            this.writer = null;
-        }
-
-        /**
-         * Constructor for a big block store that will be written
-         * later
-         *
-         * @param path path of the document
-         * @param name name of the document
-         * @param size length of the document
-         * @param writer the object that will eventually write the
-         *               document
-         */
-
-        BigBlockStore(final POIFSDocumentPath path, final String name,
-                      final int size, final POIFSWriterListener writer)
-        {
-            bigBlocks   = new DocumentBlock[ 0 ];
-            this.path   = path;
-            this.name   = name;
-            this.size   = size;
-            this.writer = writer;
-        }
-
-        /**
-         * @return true if this store is a valid source of data
-         */
-
-        boolean isValid()
-        {
-            return ((bigBlocks.length > 0) || (writer != null));
-        }
-
-        /**
-         * @return the DocumentBlocks
-         */
-
-        DocumentBlock [] getBlocks()
-        {
-            if (isValid() && (writer != null))
-            {
-                ByteArrayOutputStream stream  =
-                    new ByteArrayOutputStream(size);
-                DocumentOutputStream  dstream =
-                    new DocumentOutputStream(stream, size);
-
-                writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream,
-                        path, name, size));
-                bigBlocks = DocumentBlock.convert(stream.toByteArray(), size);
-            }
-            return bigBlocks;
-        }
-
-        /**
-         * write the blocks to a stream
-         *
-         * @param stream the stream to which the data is to be written
-         *
-         * @exception IOException on error
-         */
-
-        void writeBlocks(OutputStream stream)
-            throws IOException
-        {
-            if (isValid())
-            {
-                if (writer != null)
-                {
-                    DocumentOutputStream dstream =
-                        new DocumentOutputStream(stream, size);
-
-                    writer.processPOIFSWriterEvent(
-                        new POIFSWriterEvent(dstream, path, name, size));
-                    dstream.writeFiller(countBlocks()
-                                        * POIFSConstants
-                                            .BIG_BLOCK_SIZE, DocumentBlock
-                                            .getFillByte());
-                }
-                else
-                {
-                    for (int k = 0; k < bigBlocks.length; k++)
-                    {
-                        bigBlocks[ k ].writeBlocks(stream);
-                    }
-                }
-            }
-        }
-
-        /**
-         * @return number of big blocks making up this document
-         */
-
-        int countBlocks()
-        {
-            int rval = 0;
-
-            if (isValid())
-            {
-                if (writer != null)
-                {
-                    rval = (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
-                           / POIFSConstants.BIG_BLOCK_SIZE;
-                }
-                else
-                {
-                    rval = bigBlocks.length;
-                }
-            }
-            return rval;
-        }
-    }   // end private class BigBlockStore
-}       // end class POIFSDocument
-
+public final class POIFSDocument implements BATManaged, BlockWritable, POIFSViewable  {
+       private static final DocumentBlock[] EMPTY_BIG_BLOCK_ARRAY = { };
+       private static final SmallDocumentBlock[] EMPTY_SMALL_BLOCK_ARRAY = { };
+       private DocumentProperty _property;
+       private int _size;
+
+       // one of these stores will be valid
+       private SmallBlockStore  _small_store;
+       private BigBlockStore   _big_store;
+
+       /**
+        * Constructor from large blocks
+        *
+        * @param name the name of the POIFSDocument
+        * @param blocks the big blocks making up the POIFSDocument
+        * @param length the actual length of the POIFSDocument
+        */
+       public POIFSDocument(String name, RawDataBlock[] blocks, int length) throws IOException {
+               _size = length;
+               _big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
+               _property = new DocumentProperty(name, _size);
+               _small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+               _property.setDocument(this);
+       }
+
+       // TODO - awkward typing going on here
+       private static DocumentBlock[] convertRawBlocksToBigBlocks(ListManagedBlock[] blocks) throws IOException {
+               DocumentBlock[] result = new DocumentBlock[blocks.length];
+               for (int i = 0; i < result.length; i++) {
+                       result[i] = new DocumentBlock((RawDataBlock)blocks[i]); 
+               }
+               return result;
+       }
+       private static SmallDocumentBlock[] convertRawBlocksToSmallBlocks(ListManagedBlock[] blocks) {
+               if (blocks instanceof SmallDocumentBlock[]) {
+                       return (SmallDocumentBlock[]) blocks;
+               }
+               SmallDocumentBlock[] result = new SmallDocumentBlock[blocks.length];
+               System.arraycopy(blocks, 0, result, 0, blocks.length);
+               return result;
+       }
+
+       /**
+        * Constructor from small blocks
+        *
+        * @param name the name of the POIFSDocument
+        * @param blocks the small blocks making up the POIFSDocument
+        * @param length the actual length of the POIFSDocument
+        */
+       public POIFSDocument(String name, SmallDocumentBlock[] blocks, int length) {
+               _size = length;
+               _big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
+               _property = new DocumentProperty(name, _size);
+               _small_store = new SmallBlockStore(blocks);
+               _property.setDocument(this);
+       }
+
+       /**
+        * Constructor from small blocks
+        *
+        * @param name the name of the POIFSDocument
+        * @param blocks the small blocks making up the POIFSDocument
+        * @param length the actual length of the POIFSDocument
+        */
+       public POIFSDocument(String name, ListManagedBlock[] blocks, int length) throws IOException {
+               _size = length;
+               _property = new DocumentProperty(name, _size);
+               _property.setDocument(this);
+               if (Property.isSmall(_size)) {
+                       _big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
+                       _small_store = new SmallBlockStore(convertRawBlocksToSmallBlocks(blocks));
+               } else {
+                       _big_store = new BigBlockStore(convertRawBlocksToBigBlocks(blocks));
+                       _small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+               }
+       }
+
+       /**
+        * Constructor
+        *
+        * @param name the name of the POIFSDocument
+        * @param stream the InputStream we read data from
+        */
+       public POIFSDocument(String name, InputStream stream) throws IOException {
+               List blocks = new ArrayList();
+
+               _size = 0;
+               while (true) {
+                       DocumentBlock block = new DocumentBlock(stream);
+                       int blockSize = block.size();
+
+                       if (blockSize > 0) {
+                               blocks.add(block);
+                               _size += blockSize;
+                       }
+                       if (block.partiallyRead()) {
+                               break;
+                       }
+               }
+               DocumentBlock[] bigBlocks = (DocumentBlock[]) blocks.toArray(new DocumentBlock[blocks.size()]);
+
+               _big_store = new BigBlockStore(bigBlocks);
+               _property = new DocumentProperty(name, _size);
+               _property.setDocument(this);
+               if (_property.shouldUseSmallBlocks()) {
+                       _small_store = new SmallBlockStore(SmallDocumentBlock.convert(bigBlocks, _size));
+                       _big_store = new BigBlockStore(new DocumentBlock[0]);
+               } else {
+                       _small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+               }
+       }
+
+       /**
+        * Constructor
+        *
+        * @param name the name of the POIFSDocument
+        * @param size the length of the POIFSDocument
+        * @param path the path of the POIFSDocument
+        * @param writer the writer who will eventually write the document contents
+        */
+       public POIFSDocument(String name, int size, POIFSDocumentPath path, POIFSWriterListener writer) {
+               _size = size;
+               _property = new DocumentProperty(name, _size);
+               _property.setDocument(this);
+               if (_property.shouldUseSmallBlocks()) {
+                       _small_store = new SmallBlockStore(path, name, size, writer);
+                       _big_store = new BigBlockStore(EMPTY_BIG_BLOCK_ARRAY);
+               } else {
+                       _small_store = new SmallBlockStore(EMPTY_SMALL_BLOCK_ARRAY);
+                       _big_store = new BigBlockStore(path, name, size, writer);
+               }
+       }
+
+       /**
+        * @return array of SmallDocumentBlocks; may be empty, cannot be null
+        */
+       public BlockWritable[] getSmallBlocks() {
+               return _small_store.getBlocks();
+       }
+
+       /**
+        * @return size of the document
+        */
+       public int getSize() {
+               return _size;
+       }
+
+       /**
+        * read data from the internal stores
+        *
+        * @param buffer the buffer to write to
+        * @param offset the offset into our storage to read from
+        * This method is currently (Oct 2008) only used by test code. Perhaps it can be deleted
+        */
+       void read(byte[] buffer, int offset) {
+               int len = buffer.length;
+
+               DataInputBlock currentBlock = getDataInputBlock(offset);
+               
+               int blockAvailable = currentBlock.available();
+               if (blockAvailable > len) {
+                       currentBlock.readFully(buffer, 0, len);
+                       return;
+               }
+               // else read big amount in chunks
+               int remaining = len;
+               int writePos = 0;
+               int currentOffset = offset;
+               while (remaining > 0) {
+                       boolean blockIsExpiring = remaining >= blockAvailable;
+                       int reqSize;
+                       if (blockIsExpiring) {
+                               reqSize = blockAvailable;
+                       } else {
+                               reqSize = remaining;
+                       }
+                       currentBlock.readFully(buffer, writePos, reqSize);
+                       remaining-=reqSize;
+                       writePos+=reqSize;
+                       currentOffset += reqSize;
+                       if (blockIsExpiring) {
+                               if (currentOffset == _size) {
+                                       if (remaining > 0) {
+                                               throw new IllegalStateException("reached end of document stream unexpectedly");
+                                       }
+                                       currentBlock = null;
+                                       break;
+                               }
+                               currentBlock = getDataInputBlock(currentOffset);
+                               blockAvailable = currentBlock.available();
+                       }
+               }
+       }
+
+       /**
+        * @return <code>null</code> if <tt>offset</tt> points to the end of the document stream
+        */
+       DataInputBlock getDataInputBlock(int offset) {
+               if (offset >= _size) {
+                       if (offset > _size) {
+                               throw new RuntimeException("Request for Offset " + offset + " doc size is " + _size);
+                       }
+                       return null;
+               }
+               if (_property.shouldUseSmallBlocks()) {
+                       return SmallDocumentBlock.getDataInputBlock(_small_store.getBlocks(), offset);
+               } else {
+                       return DocumentBlock.getDataInputBlock(_big_store.getBlocks(), offset);
+               }
+       }
+
+       /**
+        * @return the instance's DocumentProperty
+        */
+
+       DocumentProperty getDocumentProperty() {
+               return _property;
+       }
+
+       /* ********** START implementation of BlockWritable ********** */
+
+       /**
+        * Write the storage to an OutputStream
+        *
+        * @param stream the OutputStream to which the stored data should be written
+        */
+       public void writeBlocks(OutputStream stream) throws IOException {
+               _big_store.writeBlocks(stream);
+       }
+
+       /* **********  END  implementation of BlockWritable ********** */
+       /* ********** START implementation of BATManaged ********** */
+
+       /**
+        * Return the number of BigBlock's this instance uses
+        *
+        * @return count of BigBlock instances
+        */
+       public int countBlocks() {
+               return _big_store.countBlocks();
+       }
+
+       /**
+        * Set the start block for this instance
+        *
+        * @param index index into the array of blocks making up the filesystem
+        */
+       public void setStartBlock(int index) {
+               _property.setStartBlock(index);
+       }
+
+       /* **********  END  implementation of BATManaged ********** */
+       /* ********** START begin implementation of POIFSViewable ********** */
+
+       /**
+        * Get an array of objects, some of which may implement POIFSViewable
+        *
+        * @return an array of Object; may not be null, but may be empty
+        */
+       public Object[] getViewableArray() {
+               Object[] results = new Object[1];
+               String result;
+
+               try {
+                       ByteArrayOutputStream output = new ByteArrayOutputStream();
+                       BlockWritable[] blocks = null;
+
+                       if (_big_store.isValid()) {
+                               blocks = _big_store.getBlocks();
+                       } else if (_small_store.isValid()) {
+                               blocks = _small_store.getBlocks();
+                       }
+                       if (blocks != null) {
+                               for (int k = 0; k < blocks.length; k++) {
+                                       blocks[k].writeBlocks(output);
+                               }
+                               byte[] data = output.toByteArray();
+
+                               if (data.length > _property.getSize()) {
+                                       byte[] tmp = new byte[_property.getSize()];
+
+                                       System.arraycopy(data, 0, tmp, 0, tmp.length);
+                                       data = tmp;
+                               }
+                               output = new ByteArrayOutputStream();
+                               HexDump.dump(data, 0, output, 0);
+                               result = output.toString();
+                       } else {
+                               result = "<NO DATA>";
+                       }
+               } catch (IOException e) {
+                       result = e.getMessage();
+               }
+               results[0] = result;
+               return results;
+       }
+
+       /**
+        * Get an Iterator of objects, some of which may implement POIFSViewable
+        *
+        * @return an Iterator; may not be null, but may have an empty back end
+        *               store
+        */
+       public Iterator getViewableIterator() {
+               return Collections.EMPTY_LIST.iterator();
+       }
+
+       /**
+        * Give viewers a hint as to whether to call getViewableArray or
+        * getViewableIterator
+        *
+        * @return <code>true</code> if a viewer should call getViewableArray,
+        *               <code>false</code> if a viewer should call getViewableIterator
+        */
+       public boolean preferArray() {
+               return true;
+       }
+
+       /**
+        * Provides a short description of the object, to be used when a
+        * POIFSViewable object has not provided its contents.
+        *
+        * @return short description
+        */
+       public String getShortDescription() {
+               StringBuffer buffer = new StringBuffer();
+
+               buffer.append("Document: \"").append(_property.getName()).append("\"");
+               buffer.append(" size = ").append(getSize());
+               return buffer.toString();
+       }
+
+       /* **********  END  begin implementation of POIFSViewable ********** */
+       private static final class SmallBlockStore {
+               private SmallDocumentBlock[] smallBlocks;
+               private final POIFSDocumentPath path;
+               private final String name;
+               private final int size;
+               private final POIFSWriterListener writer;
+
+               /**
+                * Constructor
+                *
+                * @param blocks blocks to construct the store from
+                */
+               SmallBlockStore(SmallDocumentBlock[] blocks) {
+                       smallBlocks = (SmallDocumentBlock[]) blocks.clone();
+                       this.path = null;
+                       this.name = null;
+                       this.size = -1;
+                       this.writer = null;
+               }
+
+               /**
+                * Constructor for a small block store that will be written later
+                *
+                * @param path path of the document
+                * @param name name of the document
+                * @param size length of the document
+                * @param writer the object that will eventually write the document
+                */
+               SmallBlockStore(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
+                       smallBlocks = new SmallDocumentBlock[0];
+                       this.path = path;
+                       this.name = name;
+                       this.size = size;
+                       this.writer = writer;
+               }
+
+               /**
+                * @return <code>true</code> if this store is a valid source of data
+                */
+               boolean isValid() {
+                       return smallBlocks.length > 0 || writer != null;
+               }
+
+               /**
+                * @return the SmallDocumentBlocks
+                */
+               SmallDocumentBlock[] getBlocks() {
+                       if (isValid() && writer != null) {
+                               ByteArrayOutputStream stream = new ByteArrayOutputStream(size);
+                               DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
+
+                               writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
+                               smallBlocks = SmallDocumentBlock.convert(stream.toByteArray(), size);
+                       }
+                       return smallBlocks;
+               }
+       } // end private class SmallBlockStore
+
+       private static final class BigBlockStore {
+               private DocumentBlock[] bigBlocks;
+               private final POIFSDocumentPath path;
+               private final String name;
+               private final int size;
+               private final POIFSWriterListener writer;
+
+               /**
+                * Constructor
+                *
+                * @param blocks the blocks making up the store
+                */
+               BigBlockStore(DocumentBlock[] blocks) {
+                       bigBlocks = (DocumentBlock[]) blocks.clone();
+                       this.path = null;
+                       this.name = null;
+                       this.size = -1;
+                       this.writer = null;
+               }
+
+               /**
+                * Constructor for a big block store that will be written later
+                *
+                * @param path path of the document
+                * @param name name of the document
+                * @param size length of the document
+                * @param writer the object that will eventually write the document
+                */
+               BigBlockStore(POIFSDocumentPath path, String name, int size, POIFSWriterListener writer) {
+                       bigBlocks = new DocumentBlock[0];
+                       this.path = path;
+                       this.name = name;
+                       this.size = size;
+                       this.writer = writer;
+               }
+
+               /**
+                * @return <code>true</code> if this store is a valid source of data
+                */
+               boolean isValid() {
+                       return bigBlocks.length > 0 || writer != null;
+               }
+
+               /**
+                * @return the DocumentBlocks
+                */
+               DocumentBlock[] getBlocks() {
+                       if (isValid() && writer != null) {
+                               ByteArrayOutputStream stream = new ByteArrayOutputStream(size);
+                               DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
+
+                               writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
+                               bigBlocks = DocumentBlock.convert(stream.toByteArray(), size);
+                       }
+                       return bigBlocks;
+               }
+
+               /**
+                * write the blocks to a stream
+                *
+                * @param stream the stream to which the data is to be written
+                */
+               void writeBlocks(OutputStream stream) throws IOException {
+                       if (isValid()) {
+                               if (writer != null) {
+                                       DocumentOutputStream dstream = new DocumentOutputStream(stream, size);
+
+                                       writer.processPOIFSWriterEvent(new POIFSWriterEvent(dstream, path, name, size));
+                                       dstream.writeFiller(countBlocks() * POIFSConstants.BIG_BLOCK_SIZE,
+                                                       DocumentBlock.getFillByte());
+                               } else {
+                                       for (int k = 0; k < bigBlocks.length; k++) {
+                                               bigBlocks[k].writeBlocks(stream);
+                                       }
+                               }
+                       }
+               }
+
+               /**
+                * @return number of big blocks making up this document
+                */
+               int countBlocks() {
+
+                       if (isValid()) {
+                               if (writer == null) {
+                                       return bigBlocks.length;
+                               }
+                               return (size + POIFSConstants.BIG_BLOCK_SIZE - 1)
+                                                       / POIFSConstants.BIG_BLOCK_SIZE;
+                       }
+                       return 0;
+               }
+       } // end private class BigBlockStore
+}
diff --git a/src/java/org/apache/poi/poifs/storage/DataInputBlock.java b/src/java/org/apache/poi/poifs/storage/DataInputBlock.java
new file mode 100644 (file)
index 0000000..a571a4f
--- /dev/null
@@ -0,0 +1,186 @@
+/* ====================================================================
+   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.poifs.storage;
+
+/**
+ * Wraps a <tt>byte</tt> array and provides simple data input access.
+ * Internally, this class maintains a buffer read index, so that for the most part, primitive
+ * data can be read in a data-input-stream-like manner.<p/>
+ *
+ * Note - the calling class should call the {@link #available()} method to detect end-of-buffer
+ * and move to the next data block when the current is exhausted.
+ * For optimisation reasons, no error handling is performed in this class.  Thus, mistakes in
+ * calling code ran may raise ugly exceptions here, like {@link ArrayIndexOutOfBoundsException},
+ * etc .<p/>
+ *
+ * The multi-byte primitive input methods ({@link #readUShortLE()}, {@link #readIntLE()} and
+ * {@link #readLongLE()}) have corresponding 'spanning read' methods which (when required) perform
+ * a read across the block boundary.  These spanning read methods take the previous
+ * {@link DataInputBlock} as a parameter.
+ * Reads of larger amounts of data (into <tt>byte</tt> array buffers) must be managed by the caller
+ * since these could conceivably involve more than two blocks.
+ *
+ * @author Josh Micich
+ */
+public final class DataInputBlock {
+
+       /**
+        * Possibly any size (usually 512K or 64K).  Assumed to be at least 8 bytes for all blocks
+        * before the end of the stream.  The last block in the stream can be any size except zero. 
+        */
+       private final byte[] _buf;
+       private int _readIndex;
+       private int _maxIndex;
+
+       DataInputBlock(byte[] data, int startOffset) {
+               _buf = data;
+               _readIndex = startOffset;
+               _maxIndex = _buf.length;
+       }
+       public int available() {
+               return _maxIndex-_readIndex;
+       }
+
+       public int readUByte() {
+               return _buf[_readIndex++] & 0xFF;
+       }
+
+       /**
+        * Reads a <tt>short</tt> which was encoded in <em>little endian</em> format.
+        */
+       public int readUShortLE() {
+               int i = _readIndex;
+               
+               int b0 = _buf[i++] & 0xFF;
+               int b1 = _buf[i++] & 0xFF;
+               _readIndex = i;
+               return (b1 << 8) + (b0 << 0);
+       }
+
+       /**
+        * Reads a <tt>short</tt> which spans the end of <tt>prevBlock</tt> and the start of this block.
+        */
+       public int readUShortLE(DataInputBlock prevBlock) {
+               // simple case - will always be one byte in each block
+               int i = prevBlock._buf.length-1;
+               
+               int b0 = prevBlock._buf[i++] & 0xFF;
+               int b1 = _buf[_readIndex++] & 0xFF;
+               return (b1 << 8) + (b0 << 0);
+       }
+
+       /**
+        * Reads an <tt>int</tt> which was encoded in <em>little endian</em> format.
+        */
+       public int readIntLE() {
+               int i = _readIndex;
+               
+               int b0 = _buf[i++] & 0xFF;
+               int b1 = _buf[i++] & 0xFF;
+               int b2 = _buf[i++] & 0xFF;
+               int b3 = _buf[i++] & 0xFF;
+               _readIndex = i;
+               return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
+       }
+
+       /**
+        * Reads an <tt>int</tt> which spans the end of <tt>prevBlock</tt> and the start of this block.
+        */
+       public int readIntLE(DataInputBlock prevBlock, int prevBlockAvailable) {
+               byte[] buf = new byte[4];
+               
+               readSpanning(prevBlock, prevBlockAvailable, buf);
+               int b0 = buf[0] & 0xFF;
+               int b1 = buf[1] & 0xFF;
+               int b2 = buf[2] & 0xFF;
+               int b3 = buf[3] & 0xFF;
+               return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
+       }
+
+       /**
+        * Reads a <tt>long</tt> which was encoded in <em>little endian</em> format.
+        */
+       public long readLongLE() {
+               int i = _readIndex;
+               
+               int b0 = _buf[i++] & 0xFF;
+               int b1 = _buf[i++] & 0xFF;
+               int b2 = _buf[i++] & 0xFF;
+               int b3 = _buf[i++] & 0xFF;
+               int b4 = _buf[i++] & 0xFF;
+               int b5 = _buf[i++] & 0xFF;
+               int b6 = _buf[i++] & 0xFF;
+               int b7 = _buf[i++] & 0xFF;
+               _readIndex = i;
+               return (((long)b7 << 56) +
+                               ((long)b6 << 48) +
+                               ((long)b5 << 40) +
+                               ((long)b4 << 32) +
+                               ((long)b3 << 24) +
+                               (b2 << 16) +
+                               (b1 <<  8) +
+                               (b0 <<  0));
+       }
+
+       /**
+        * Reads a <tt>long</tt> which spans the end of <tt>prevBlock</tt> and the start of this block.
+        */
+       public long readLongLE(DataInputBlock prevBlock, int prevBlockAvailable) {
+               byte[] buf = new byte[8];
+               
+               readSpanning(prevBlock, prevBlockAvailable, buf);
+               
+               int b0 = buf[0] & 0xFF;
+               int b1 = buf[1] & 0xFF;
+               int b2 = buf[2] & 0xFF;
+               int b3 = buf[3] & 0xFF;
+               int b4 = buf[4] & 0xFF;
+               int b5 = buf[5] & 0xFF;
+               int b6 = buf[6] & 0xFF;
+               int b7 = buf[7] & 0xFF;
+               return (((long)b7 << 56) +
+                               ((long)b6 << 48) +
+                               ((long)b5 << 40) +
+                               ((long)b4 << 32) +
+                               ((long)b3 << 24) +
+                               (b2 << 16) +
+                               (b1 <<  8) +
+                               (b0 <<  0));
+       }
+
+       /**
+        * Reads a small amount of data from across the boundary between two blocks.  
+        * The {@link #_readIndex} of this (the second) block is updated accordingly.
+        * Note- this method (and other code) assumes that the second {@link DataInputBlock}
+        * always is big enough to complete the read without being exhausted.
+        */
+       private void readSpanning(DataInputBlock prevBlock, int prevBlockAvailable, byte[] buf) {
+               System.arraycopy(prevBlock._buf, prevBlock._readIndex, buf, 0, prevBlockAvailable);
+               int secondReadLen = buf.length-prevBlockAvailable;
+               System.arraycopy(_buf, 0, buf, prevBlockAvailable, secondReadLen);
+               _readIndex = secondReadLen;
+       }
+
+       /**
+        * Reads <tt>len</tt> bytes from this block into the supplied buffer.
+        */
+       public void readFully(byte[] buf, int off, int len) {
+               System.arraycopy(_buf, _readIndex, buf, off, len);
+               _readIndex += len;
+       }
+}
index ddaf5b3da01d666e2b6ddd232debab0c4925d1a7..7c1f028eda35fdf0d350ac40181f6f0d05723b93 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.storage;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-
 import java.util.Arrays;
 
 import org.apache.poi.poifs.common.POIFSConstants;
 import org.apache.poi.util.IOUtils;
-import org.apache.poi.util.IntegerField;
-import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.LittleEndianConsts;
 
 /**
  * A block of document data.
  *
  * @author Marc Johnson (mjohnson at apache dot org)
  */
+public final class DocumentBlock extends BigBlock {
+    private static final int BLOCK_SHIFT = 9;
+    private static final int BLOCK_SIZE = 1 << BLOCK_SHIFT;
+    private static final int BLOCK_MASK = BLOCK_SIZE-1;
 
-public class DocumentBlock
-    extends BigBlock
-{
     private static final byte _default_value = ( byte ) 0xFF;
     private byte[]            _data;
     private int               _bytes_read;
@@ -161,45 +156,10 @@ public class DocumentBlock
         return rval;
     }
 
-    /**
-     * read data from an array of DocumentBlocks
-     *
-     * @param blocks the blocks to read from
-     * @param buffer the buffer to write the data into
-     * @param offset the offset into the array of blocks to read from
-     */
-
-    public static void read(final DocumentBlock [] blocks,
-                            final byte [] buffer, final int offset)
-    {
-        int firstBlockIndex  = offset / POIFSConstants.BIG_BLOCK_SIZE;
-        int firstBlockOffset = offset % POIFSConstants.BIG_BLOCK_SIZE;
-        int lastBlockIndex   = (offset + buffer.length - 1)
-                               / POIFSConstants.BIG_BLOCK_SIZE;
-
-        if (firstBlockIndex == lastBlockIndex)
-        {
-            System.arraycopy(blocks[ firstBlockIndex ]._data,
-                             firstBlockOffset, buffer, 0, buffer.length);
-        }
-        else
-        {
-            int buffer_offset = 0;
-
-            System.arraycopy(blocks[ firstBlockIndex ]._data,
-                             firstBlockOffset, buffer, buffer_offset,
-                             POIFSConstants.BIG_BLOCK_SIZE
-                             - firstBlockOffset);
-            buffer_offset += POIFSConstants.BIG_BLOCK_SIZE - firstBlockOffset;
-            for (int j = firstBlockIndex + 1; j < lastBlockIndex; j++)
-            {
-                System.arraycopy(blocks[ j ]._data, 0, buffer, buffer_offset,
-                                 POIFSConstants.BIG_BLOCK_SIZE);
-                buffer_offset += POIFSConstants.BIG_BLOCK_SIZE;
-            }
-            System.arraycopy(blocks[ lastBlockIndex ]._data, 0, buffer,
-                             buffer_offset, buffer.length - buffer_offset);
-        }
+    public static DataInputBlock getDataInputBlock(DocumentBlock[] blocks, int offset) {
+        int firstBlockIndex = offset >> BLOCK_SHIFT;
+        int firstBlockOffset= offset & BLOCK_MASK;
+        return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset);
     }
 
     /* ********** START extension of BigBlock ********** */
index dabf280e70c99a2872b90ac79e9d542cf895de1e..5ae4f1ff03814221f15a9f856321c302c9af5169 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.storage;
 
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 import org.apache.poi.poifs.common.POIFSConstants;
 
@@ -31,13 +32,14 @@ import org.apache.poi.poifs.common.POIFSConstants;
  *
  * @author  Marc Johnson (mjohnson at apache dot org)
  */
+public final class SmallDocumentBlock implements BlockWritable, ListManagedBlock {
+    private static final int BLOCK_SHIFT = 6;
 
-public class SmallDocumentBlock
-    implements BlockWritable, ListManagedBlock
-{
     private byte[]            _data;
     private static final byte _default_fill         = ( byte ) 0xff;
-    private static final int  _block_size           = 64;
+    private static final int  _block_size           = 1 << BLOCK_SHIFT;
+    private static final int BLOCK_MASK = _block_size-1;
+
     private static final int  _blocks_per_big_block =
         POIFSConstants.BIG_BLOCK_SIZE / _block_size;
 
@@ -178,46 +180,10 @@ public class SmallDocumentBlock
         return sdbs;
     }
 
-    /**
-     * read data from an array of SmallDocumentBlocks
-     *
-     * @param blocks the blocks to read from
-     * @param buffer the buffer to write the data into
-     * @param offset the offset into the array of blocks to read from
-     */
-
-    public static void read(final BlockWritable [] blocks,
-                            final byte [] buffer, final int offset)
-    {
-        int firstBlockIndex  = offset / _block_size;
-        int firstBlockOffset = offset % _block_size;
-        int lastBlockIndex   = (offset + buffer.length - 1) / _block_size;
-
-        if (firstBlockIndex == lastBlockIndex)
-        {
-            System.arraycopy(
-                (( SmallDocumentBlock ) blocks[ firstBlockIndex ])._data,
-                firstBlockOffset, buffer, 0, buffer.length);
-        }
-        else
-        {
-            int buffer_offset = 0;
-
-            System.arraycopy(
-                (( SmallDocumentBlock ) blocks[ firstBlockIndex ])._data,
-                firstBlockOffset, buffer, buffer_offset,
-                _block_size - firstBlockOffset);
-            buffer_offset += _block_size - firstBlockOffset;
-            for (int j = firstBlockIndex + 1; j < lastBlockIndex; j++)
-            {
-                System.arraycopy((( SmallDocumentBlock ) blocks[ j ])._data,
-                                 0, buffer, buffer_offset, _block_size);
-                buffer_offset += _block_size;
-            }
-            System.arraycopy(
-                (( SmallDocumentBlock ) blocks[ lastBlockIndex ])._data, 0,
-                buffer, buffer_offset, buffer.length - buffer_offset);
-        }
+    public static DataInputBlock getDataInputBlock(SmallDocumentBlock[] blocks, int offset) {
+        int firstBlockIndex = offset >> BLOCK_SHIFT;
+        int firstBlockOffset= offset & BLOCK_MASK;
+        return new DataInputBlock(blocks[firstBlockIndex]._data, firstBlockOffset);
     }
 
     /**
diff --git a/src/java/org/apache/poi/util/DoubleList.java b/src/java/org/apache/poi/util/DoubleList.java
deleted file mode 100644 (file)
index d2c669c..0000000
+++ /dev/null
@@ -1,642 +0,0 @@
-
-/* ====================================================================
-   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.util;
-
-import java.util.*;
-
-/**
- * A List of double's; as full an implementation of the java.util.List
- * interface as possible, with an eye toward minimal creation of
- * objects
- *
- * the mimicry of List is as follows:
- * <ul>
- * <li> if possible, operations designated 'optional' in the List
- *      interface are attempted
- * <li> wherever the List interface refers to an Object, substitute
- *      double
- * <li> wherever the List interface refers to a Collection or List,
- *      substitute DoubleList
- * </ul>
- *
- * the mimicry is not perfect, however:
- * <ul>
- * <li> operations involving Iterators or ListIterators are not
- *      supported
- * <li> remove(Object) becomes removeValue to distinguish it from
- *      remove(int index)
- * <li> subList is not supported
- * </ul>
- *
- * @author Marc Johnson
- */
-
-public class DoubleList
-{
-    private double[]            _array;
-    private int              _limit;
-    private static final int _default_size = 128;
-
-    /**
-     * create an DoubleList of default size
-     */
-
-    public DoubleList()
-    {
-        this(_default_size);
-    }
-
-    /**
-     * create a copy of an existing DoubleList
-     *
-     * @param list the existing DoubleList
-     */
-
-    public DoubleList(final DoubleList list)
-    {
-        this(list._array.length);
-        System.arraycopy(list._array, 0, _array, 0, _array.length);
-        _limit = list._limit;
-    }
-
-    /**
-     * create an DoubleList with a predefined initial size
-     *
-     * @param initialCapacity the size for the internal array
-     */
-
-    public DoubleList(final int initialCapacity)
-    {
-        _array = new double[ initialCapacity ];
-        _limit = 0;
-    }
-
-    /**
-     * add the specfied value at the specified index
-     *
-     * @param index the index where the new value is to be added
-     * @param value the new value
-     *
-     * @exception IndexOutOfBoundsException if the index is out of
-     *            range (index < 0 || index > size()).
-     */
-
-    public void add(final int index, final double value)
-    {
-        if (index > _limit)
-        {
-            throw new IndexOutOfBoundsException();
-        }
-        else if (index == _limit)
-        {
-            add(value);
-        }
-        else
-        {
-
-            // index < limit -- insert into the middle
-            if (_limit == _array.length)
-            {
-                growArray(_limit * 2);
-            }
-            System.arraycopy(_array, index, _array, index + 1,
-                             _limit - index);
-            _array[ index ] = value;
-            _limit++;
-        }
-    }
-
-    /**
-     * Appends the specified element to the end of this list
-     *
-     * @param value element to be appended to this list.
-     *
-     * @return true (as per the general contract of the Collection.add
-     *         method).
-     */
-
-    public boolean add(final double value)
-    {
-        if (_limit == _array.length)
-        {
-            growArray(_limit * 2);
-        }
-        _array[ _limit++ ] = value;
-        return true;
-    }
-
-    /**
-     * Appends all of the elements in the specified collection to the
-     * end of this list, in the order that they are returned by the
-     * specified collection's iterator.  The behavior of this
-     * operation is unspecified if the specified collection is
-     * modified while the operation is in progress.  (Note that this
-     * will occur if the specified collection is this list, and it's
-     * nonempty.)
-     *
-     * @param c collection whose elements are to be added to this
-     *          list.
-     *
-     * @return true if this list changed as a result of the call.
-     */
-
-    public boolean addAll(final DoubleList c)
-    {
-        if (c._limit != 0)
-        {
-            if ((_limit + c._limit) > _array.length)
-            {
-                growArray(_limit + c._limit);
-            }
-            System.arraycopy(c._array, 0, _array, _limit, c._limit);
-            _limit += c._limit;
-        }
-        return true;
-    }
-
-    /**
-     * Inserts all of the elements in the specified collection into
-     * this list at the specified position.  Shifts the element
-     * currently at that position (if any) and any subsequent elements
-     * to the right (increases their indices).  The new elements will
-     * appear in this list in the order that they are returned by the
-     * specified collection's iterator.  The behavior of this
-     * operation is unspecified if the specified collection is
-     * modified while the operation is in progress.  (Note that this
-     * will occur if the specified collection is this list, and it's
-     * nonempty.)
-     *
-     * @param index index at which to insert first element from the
-     *              specified collection.
-     * @param c elements to be inserted into this list.
-     *
-     * @return true if this list changed as a result of the call.
-     *
-     * @exception IndexOutOfBoundsException if the index is out of
-     *            range (index < 0 || index > size())
-     */
-
-    public boolean addAll(final int index, final DoubleList c)
-    {
-        if (index > _limit)
-        {
-            throw new IndexOutOfBoundsException();
-        }
-        if (c._limit != 0)
-        {
-            if ((_limit + c._limit) > _array.length)
-            {
-                growArray(_limit + c._limit);
-            }
-
-            // make a hole
-            System.arraycopy(_array, index, _array, index + c._limit,
-                             _limit - index);
-
-            // fill it in
-            System.arraycopy(c._array, 0, _array, index, c._limit);
-            _limit += c._limit;
-        }
-        return true;
-    }
-
-    /**
-     * Removes all of the elements from this list.  This list will be
-     * empty after this call returns (unless it throws an exception).
-     */
-
-    public void clear()
-    {
-        _limit = 0;
-    }
-
-    /**
-     * Returns true if this list contains the specified element.  More
-     * formally, returns true if and only if this list contains at
-     * least one element e such that o == e
-     *
-     * @param o element whose presence in this list is to be tested.
-     *
-     * @return true if this list contains the specified element.
-     */
-
-    public boolean contains(final double o)
-    {
-        boolean rval = false;
-
-        for (int j = 0; !rval && (j < _limit); j++)
-        {
-            if (_array[ j ] == o)
-            {
-                rval = true;
-            }
-        }
-        return rval;
-    }
-
-    /**
-     * Returns true if this list contains all of the elements of the
-     * specified collection.
-     *
-     * @param c collection to be checked for containment in this list.
-     *
-     * @return true if this list contains all of the elements of the
-     *         specified collection.
-     */
-
-    public boolean containsAll(final DoubleList c)
-    {
-        boolean rval = true;
-
-        if (this != c)
-        {
-            for (int j = 0; rval && (j < c._limit); j++)
-            {
-                if (!contains(c._array[ j ]))
-                {
-                    rval = false;
-                }
-            }
-        }
-        return rval;
-    }
-
-    /**
-     * Compares the specified object with this list for equality.
-     * Returns true if and only if the specified object is also a
-     * list, both lists have the same size, and all corresponding
-     * pairs of elements in the two lists are equal.  (Two elements e1
-     * and e2 are equal if e1 == e2.)  In other words, two lists are
-     * defined to be equal if they contain the same elements in the
-     * same order.  This definition ensures that the equals method
-     * works properly across different implementations of the List
-     * interface.
-     *
-     * @param o the object to be compared for equality with this list.
-     *
-     * @return true if the specified object is equal to this list.
-     */
-
-    public boolean equals(final Object o)
-    {
-        boolean rval = this == o;
-
-        if (!rval && (o != null) && (o.getClass() == this.getClass()))
-        {
-            DoubleList other = ( DoubleList ) o;
-
-            if (other._limit == _limit)
-            {
-
-                // assume match
-                rval = true;
-                for (int j = 0; rval && (j < _limit); j++)
-                {
-                    rval = _array[ j ] == other._array[ j ];
-                }
-            }
-        }
-        return rval;
-    }
-
-    /**
-     * Returns the element at the specified position in this list.
-     *
-     * @param index index of element to return.
-     *
-     * @return the element at the specified position in this list.
-     *
-     * @exception IndexOutOfBoundsException if the index is out of
-     *            range (index < 0 || index >= size()).
-     */
-
-    public double get(final int index)
-    {
-        if (index >= _limit)
-        {
-            throw new IndexOutOfBoundsException();
-        }
-        return _array[ index ];
-    }
-
-    /**
-     * THIS MOST LIKELY DOES NOT WORK
-     * Returns the hash code value for this list.  The hash code of a
-     * list is defined to be the result of the following calculation:
-     *
-     * <code>
-     * hashCode = 1;
-     * Iterator i = list.iterator();
-     * while (i.hasNext()) {
-     *      Object obj = i.next();
-     *      hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
-     * }
-     * </code>
-     *
-     * This ensures that list1.equals(list2) implies that
-     * list1.hashCode()==list2.hashCode() for any two lists, list1 and
-     * list2, as required by the general contract of Object.hashCode.
-     *
-     * @return the hash code value for this list.
-     */
-
-    public int hashCode()
-    {
-        int hash = 0;
-
-        for (int j = 0; j < _limit; j++)
-        {
-            hash = (31 * hash) + ((int) _array[ j ]);
-        }
-        return hash;
-    }
-
-    /**
-     * Returns the index in this list of the first occurrence of the
-     * specified element, or -1 if this list does not contain this
-     * element.  More formally, returns the lowest index i such that
-     * (o == get(i)), or -1 if there is no such index.
-     *
-     * @param o element to search for.
-     *
-     * @return the index in this list of the first occurrence of the
-     *         specified element, or -1 if this list does not contain
-     *         this element.
-     */
-
-    public int indexOf(final double o)
-    {
-        int rval = 0;
-
-        for (; rval < _limit; rval++)
-        {
-            if (o == _array[ rval ])
-            {
-                break;
-            }
-        }
-        if (rval == _limit)
-        {
-            rval = -1;   // didn't find it
-        }
-        return rval;
-    }
-
-    /**
-     * Returns true if this list contains no elements.
-     *
-     * @return true if this list contains no elements.
-     */
-
-    public boolean isEmpty()
-    {
-        return _limit == 0;
-    }
-
-    /**
-     * Returns the index in this list of the last occurrence of the
-     * specified element, or -1 if this list does not contain this
-     * element.  More formally, returns the highest index i such that
-     * (o == get(i)), or -1 if there is no such index.
-     *
-     * @param o element to search for.
-     *
-     * @return the index in this list of the last occurrence of the
-     *         specified element, or -1 if this list does not contain
-     *         this element.
-     */
-
-    public int lastIndexOf(final double o)
-    {
-        int rval = _limit - 1;
-
-        for (; rval >= 0; rval--)
-        {
-            if (o == _array[ rval ])
-            {
-                break;
-            }
-        }
-        return rval;
-    }
-
-    /**
-     * Removes the element at the specified position in this list.
-     * Shifts any subsequent elements to the left (subtracts one from
-     * their indices).  Returns the element that was removed from the
-     * list.
-     *
-     * @param index the index of the element to removed.
-     *
-     * @return the element previously at the specified position.
-     *
-     * @exception IndexOutOfBoundsException if the index is out of
-     *            range (index < 0 || index >= size()).
-     */
-
-    public double remove(final int index)
-    {
-        if (index >= _limit)
-        {
-            throw new IndexOutOfBoundsException();
-        }
-        double rval = _array[ index ];
-
-        System.arraycopy(_array, index + 1, _array, index, _limit - index);
-        _limit--;
-        return rval;
-    }
-
-    /**
-     * Removes the first occurrence in this list of the specified
-     * element (optional operation).  If this list does not contain
-     * the element, it is unchanged.  More formally, removes the
-     * element with the lowest index i such that (o.equals(get(i)))
-     * (if such an element exists).
-     *
-     * @param o element to be removed from this list, if present.
-     *
-     * @return true if this list contained the specified element.
-     */
-
-    public boolean removeValue(final double o)
-    {
-        boolean rval = false;
-
-        for (int j = 0; !rval && (j < _limit); j++)
-        {
-            if (o == _array[ j ])
-            {
-                System.arraycopy(_array, j + 1, _array, j, _limit - j);
-                _limit--;
-                rval = true;
-            }
-        }
-        return rval;
-    }
-
-    /**
-     * Removes from this list all the elements that are contained in
-     * the specified collection
-     *
-     * @param c collection that defines which elements will be removed
-     *          from this list.
-     *
-     * @return true if this list changed as a result of the call.
-     */
-
-    public boolean removeAll(final DoubleList c)
-    {
-        boolean rval = false;
-
-        for (int j = 0; j < c._limit; j++)
-        {
-            if (removeValue(c._array[ j ]))
-            {
-                rval = true;
-            }
-        }
-        return rval;
-    }
-
-    /**
-     * Retains only the elements in this list that are contained in
-     * the specified collection.  In other words, removes from this
-     * list all the elements that are not contained in the specified
-     * collection.
-     *
-     * @param c collection that defines which elements this set will
-     *          retain.
-     *
-     * @return true if this list changed as a result of the call.
-     */
-
-    public boolean retainAll(final DoubleList c)
-    {
-        boolean rval = false;
-
-        for (int j = 0; j < _limit; )
-        {
-            if (!c.contains(_array[ j ]))
-            {
-                remove(j);
-                rval = true;
-            }
-            else
-            {
-                j++;
-            }
-        }
-        return rval;
-    }
-
-    /**
-     * Replaces the element at the specified position in this list
-     * with the specified element
-     *
-     * @param index index of element to replace.
-     * @param element element to be stored at the specified position.
-     *
-     * @return the element previously at the specified position.
-     *
-     * @exception IndexOutOfBoundsException if the index is out of
-     *            range (index < 0 || index >= size()).
-     */
-
-    public double set(final int index, final double element)
-    {
-        if (index >= _limit)
-        {
-            throw new IndexOutOfBoundsException();
-        }
-        double rval = _array[ index ];
-
-        _array[ index ] = element;
-        return rval;
-    }
-
-    /**
-     * Returns the number of elements in this list. If this list
-     * contains more than Doubleeger.MAX_VALUE elements, returns
-     * Doubleeger.MAX_VALUE.
-     *
-     * @return the number of elements in this DoubleList
-     */
-
-    public int size()
-    {
-        return _limit;
-    }
-
-    /**
-     * Returns an array containing all of the elements in this list in
-     * proper sequence.  Obeys the general contract of the
-     * Collection.toArray method.
-     *
-     * @return an array containing all of the elements in this list in
-     *         proper sequence.
-     */
-
-    public double [] toArray()
-    {
-        double[] rval = new double[ _limit ];
-
-        System.arraycopy(_array, 0, rval, 0, _limit);
-        return rval;
-    }
-
-    /**
-     * Returns an array containing all of the elements in this list in
-     * proper sequence.  Obeys the general contract of the
-     * Collection.toArray(Object[]) method.
-     *
-     * @param a the array into which the elements of this list are to
-     *          be stored, if it is big enough; otherwise, a new array
-     *          is allocated for this purpose.
-     *
-     * @return an array containing the elements of this list.
-     */
-
-    public double [] toArray(final double [] a)
-    {
-        double[] rval;
-
-        if (a.length == _limit)
-        {
-            System.arraycopy(_array, 0, a, 0, _limit);
-            rval = a;
-        }
-        else
-        {
-            rval = toArray();
-        }
-        return rval;
-    }
-
-    private void growArray(final int new_size)
-    {
-        int   size      = (new_size == _array.length) ? new_size + 1
-                                                      : new_size;
-        double[] new_array = new double[ size ];
-
-        System.arraycopy(_array, 0, new_array, 0, _limit);
-        _array = new_array;
-    }
-}   // end public class DoubleList
diff --git a/src/java/org/apache/poi/util/DoubleList2d.java b/src/java/org/apache/poi/util/DoubleList2d.java
deleted file mode 100644 (file)
index 45a44fd..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-* 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.util;
-
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * Provides an interface for interacting with 2d arrays of doubles.  This
- * implementation will return 0 for items not yet allocated and automatically
- * increase the array size for set operations.  You never get an index out of
- * bounds.
- *
- * @author Glen Stampoultzis (glens at apache.org)
- * @version $Id$
- */
-public class DoubleList2d
-{
-    // Implemented using a List of DoubleList's.
-    List rows = new ArrayList();
-
-    public double get(int col, int row)
-    {
-        if (row >= rows.size())
-        {
-            return 0;
-        }
-        else
-        {
-            DoubleList cols = (DoubleList) rows.get(row);
-            if (col >= cols.size())
-                return 0;
-            else
-                return cols.get( col );
-        }
-    }
-
-    public void set(int col, int row, double value)
-    {
-        resizeRows(row);
-        resizeCols(row,col);
-        DoubleList cols = (DoubleList) rows.get( row );
-        cols.set( col, value );
-    }
-
-    private void resizeRows( int row )
-    {
-        while (rows.size() <= row)
-            rows.add( new DoubleList() );
-    }
-
-    private void resizeCols( int row, int col )
-    {
-        DoubleList cols = (DoubleList) rows.get( row );
-        while (cols.size() <= col)
-            cols.add(0);
-    }
-
-
-}
index 373710b47a6609ed49243186fe789ee66225b108..69a68c8b31c2f5fab552a1412c1afa438ed80853 100644 (file)
@@ -28,13 +28,12 @@ import java.io.InputStream;
  *@author     Marc Johnson (mjohnson at apache dot org)
  *@author     Andrew Oliver (acoliver at apache dot org)
  */
-public final class LittleEndian implements LittleEndianConsts {
+public class LittleEndian implements LittleEndianConsts {
 
     private LittleEndian() {
-       // no instances of this class
+        // no instances of this class
     }
 
-
     /**
      *  get a short value from a byte array
      *
@@ -42,9 +41,10 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@return         the short (16-bit) value
      */
-
-    public static short getShort(final byte[] data, final int offset) {
-        return (short) getNumber(data, offset, SHORT_SIZE);
+    public static short getShort(byte[] data, int offset) {
+        int b0 = data[offset] & 0xFF;
+        int b1 = data[offset+1] & 0xFF;
+        return (short) ((b1 << 8) + (b0 << 0));
     }
 
 
@@ -55,73 +55,32 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@return         the unsigned short (16-bit) value in an integer
      */
-    public static int getUShort(final byte[] data, final int offset) {
-        short num = (short) getNumber(data, offset, SHORT_SIZE);
-        int retNum;
-        if (num < 0) {
-            retNum = (Short.MAX_VALUE + 1) * 2 + num;
-        } else {
-            retNum = num;
-        }
-        return retNum;
-    }
-
-
-    /**
-     *  get a short array from a byte array.
-     *
-     *@param  data    Description of the Parameter
-     *@param  offset  Description of the Parameter
-     *@param  size    Description of the Parameter
-     *@return         The simpleShortArray value
-     */
-    public static short[] getSimpleShortArray(final byte[] data, final int offset, final int size) {
-        short[] results = new short[size];
-        for (int i = 0; i < size; i++) {
-            results[i] = getShort(data, offset + 2 + (i * 2));
-        }
-        return results;
-    }
-
-
-    /**
-     *  get a short array from a byte array. The short array is assumed to start
-     *  with a word describing the length of the array.
-     *
-     *@param  data    Description of the Parameter
-     *@param  offset  Description of the Parameter
-     *@return         The shortArray value
-     */
-    public static short[] getShortArray(final byte[] data, final int offset) {
-        int size = (int) getNumber(data, offset, SHORT_SIZE);
-        short[] results = getSimpleShortArray(data, offset, size);
-        return results;
+    public static int getUShort(byte[] data, int offset) {
+        int b0 = data[offset] & 0xFF;
+        int b1 = data[offset+1] & 0xFF;
+        return (b1 << 8) + (b0 << 0);
     }
 
-
     /**
      *  get a short value from the beginning of a byte array
      *
      *@param  data  the byte array
      *@return       the short (16-bit) value
      */
-
-    public static short getShort(final byte[] data) {
+    public static short getShort(byte[] data) {
         return getShort(data, 0);
     }
 
-
     /**
      *  get an unsigned short value from the beginning of a byte array
      *
      *@param  data  the byte array
      *@return       the unsigned short (16-bit) value in an int
      */
-    public static int getUShort(final byte[] data) {
+    public static int getUShort(byte[] data) {
         return getUShort(data, 0);
     }
 
-
     /**
      *  get an int value from a byte array
      *
@@ -129,9 +88,13 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@return         the int (32-bit) value
      */
-
-    public static int getInt(final byte[] data, final int offset) {
-        return (int) getNumber(data, offset, INT_SIZE);
+    public static int getInt(byte[] data, int offset) {
+        int i=offset;
+        int b0 = data[i++] & 0xFF;
+        int b1 = data[i++] & 0xFF;
+        int b2 = data[i++] & 0xFF;
+        int b3 = data[i++] & 0xFF;
+        return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
     }
 
 
@@ -139,10 +102,9 @@ public final class LittleEndian implements LittleEndianConsts {
      *  get an int value from the beginning of a byte array
      *
      *@param  data  the byte array
-     *@return       the int (32-bit) value
+     *@return the int (32-bit) value
      */
-
-    public static int getInt(final byte[] data) {
+    public static int getInt(byte[] data) {
         return getInt(data, 0);
     }
 
@@ -154,15 +116,9 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@return         the unsigned int (32-bit) value in a long
      */
-    public static long getUInt(final byte[] data, final int offset) {
-        int num = (int) getNumber(data, offset, INT_SIZE);
-        long retNum;
-        if (num < 0) {
-            retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
-        } else {
-            retNum = num;
-        }
-        return retNum;
+    public static long getUInt(byte[] data, int offset) {
+        long retNum = getInt(data, offset);
+        return retNum & 0x00FFFFFFFF;
     }
 
     /**
@@ -171,8 +127,8 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  data    the byte array
      *@return         the unsigned int (32-bit) value in a long
      */
-    public static long getUInt(final byte[] data) {
-       return getUInt(data,0);
+    public static long getUInt(byte[] data) {
+        return getUInt(data,0);
     }
 
     /**
@@ -182,24 +138,16 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@return         the long (64-bit) value
      */
-
-    public static long getLong(final byte[] data, final int offset) {
-        return getNumber(data, offset, LONG_SIZE);
-    }
-
-
-    /**
-     *  get a long value from the beginning of a byte array
-     *
-     *@param  data  the byte array
-     *@return       the long (64-bit) value
-     */
-
-    public static long getLong(final byte[] data) {
-        return getLong(data, 0);
+    public static long getLong(byte[] data, int offset) {
+        long result = 0;
+               
+               for (int j = offset + LONG_SIZE - 1; j >= offset; j--) {
+                   result <<= 8;
+                   result |= 0xff & data[j];
+               }
+               return result;
     }
 
-
     /**
      *  get a double value from a byte array, reads it in little endian format
      *  then converts the resulting revolting IEEE 754 (curse them) floating
@@ -209,24 +157,10 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@return         the double (64-bit) value
      */
-
-    public static double getDouble(final byte[] data, final int offset) {
-        return Double.longBitsToDouble(getNumber(data, offset, DOUBLE_SIZE));
-    }
-
-
-    /**
-     *  get a double value from the beginning of a byte array
-     *
-     *@param  data  the byte array
-     *@return       the double (64-bit) value
-     */
-
-    public static double getDouble(final byte[] data) {
-        return getDouble(data, 0);
+    public static double getDouble(byte[] data, int offset) {
+        return Double.longBitsToDouble(getLong(data, offset));
     }
 
-
     /**
      *  put a short value into a byte array
      *
@@ -234,9 +168,10 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@param  value   the short (16-bit) value
      */
-    public static void putShort(final byte[] data, final int offset,
-            final short value) {
-        putNumber(data, offset, value, SHORT_SIZE);
+    public static void putShort(byte[] data, int offset, short value) {
+        int i = offset;
+        data[i++] = (byte)((value >>>  0) & 0xFF);
+        data[i++] = (byte)((value >>>  8) & 0xFF);
     }
 
     /**
@@ -247,7 +182,7 @@ public final class LittleEndian implements LittleEndianConsts {
      * Added for consistency with other put~() methods
      */
     public static void putByte(byte[] data, int offset, int value) {
-        putNumber(data, offset, value, LittleEndianConsts.BYTE_SIZE);
+        data[offset] = (byte) value;
     }
 
     /**
@@ -259,10 +194,10 @@ public final class LittleEndian implements LittleEndianConsts {
      *
      * @exception ArrayIndexOutOfBoundsException may be thrown
      */
-    public static void putUShort(final byte[] data, final int offset,
-                                final int value)
-    {
-        putNumber(data, offset, value, SHORT_SIZE);
+    public static void putUShort(byte[] data, int offset, int value) {
+        int i = offset;
+        data[i++] = (byte)((value >>>  0) & 0xFF);
+        data[i++] = (byte)((value >>>  8) & 0xFF);
     }
 
     /**
@@ -271,8 +206,7 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  data   the byte array
      *@param  value  the short (16-bit) value
      */
-
-    public static void putShort(final byte[] data, final short value) {
+    public static void putShort(byte[] data, short value) {
         putShort(data, 0, value);
     }
 
@@ -284,10 +218,12 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@param  value   the int (32-bit) value
      */
-
-    public static void putInt(final byte[] data, final int offset,
-            final int value) {
-        putNumber(data, offset, value, INT_SIZE);
+    public static void putInt(byte[] data, int offset, int value) {
+        int i = offset;
+        data[i++] = (byte)((value >>>  0) & 0xFF);
+        data[i++] = (byte)((value >>>  8) & 0xFF);
+        data[i++] = (byte)((value >>> 16) & 0xFF);
+        data[i++] = (byte)((value >>> 24) & 0xFF);
     }
 
 
@@ -297,8 +233,7 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  data   the byte array
      *@param  value  the int (32-bit) value
      */
-
-    public static void putInt(final byte[] data, final int value) {
+    public static void putInt(byte[] data, int value) {
         putInt(data, 0, value);
     }
 
@@ -310,22 +245,14 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@param  value   the long (64-bit) value
      */
-
-    public static void putLong(final byte[] data, final int offset,
-            final long value) {
-        putNumber(data, offset, value, LONG_SIZE);
-    }
-
-
-    /**
-     *  put a long value into beginning of a byte array
-     *
-     *@param  data   the byte array
-     *@param  value  the long (64-bit) value
-     */
-
-    public static void putLong(final byte[] data, final long value) {
-        putLong(data, 0, value);
+    public static void putLong(byte[] data, int offset, long value) {
+        int limit = LONG_SIZE + offset;
+        long v = value;
+        
+        for (int j = offset; j < limit; j++) {
+            data[j] = (byte) (v & 0xFF);
+            v >>= 8;
+        }
     }
 
 
@@ -336,26 +263,13 @@ public final class LittleEndian implements LittleEndianConsts {
      *@param  offset  a starting offset into the byte array
      *@param  value   the double (64-bit) value
      */
-
-    public static void putDouble(final byte[] data, final int offset,
-            final double value) {
+    public static void putDouble(byte[] data, int offset, double value) {
         // Excel likes NaN to be a specific value.
-        if (Double.isNaN(value))
-            putNumber(data, offset, -276939487313920L, DOUBLE_SIZE);
-        else
-            putNumber(data, offset, Double.doubleToLongBits(value), DOUBLE_SIZE);
-    }
-
-
-    /**
-     *  put a double value into beginning of a byte array
-     *
-     *@param  data   the byte array
-     *@param  value  the double (64-bit) value
-     */
-
-    public static void putDouble(final byte[] data, final double value) {
-        putDouble(data, 0, value);
+        if (Double.isNaN(value)) {
+            putLong(data, offset, -276939487313920L);
+        } else {
+            putLong(data, offset, Double.doubleToLongBits(value));
+        }
     }
 
 
@@ -364,7 +278,6 @@ public final class LittleEndian implements LittleEndianConsts {
      *
      *@author     Marc Johnson (mjohnson at apache dot org)
      */
-
     public static final class BufferUnderrunException extends IOException {
 
         BufferUnderrunException() {
@@ -376,79 +289,72 @@ public final class LittleEndian implements LittleEndianConsts {
     /**
      *  get a short value from an InputStream
      *
-     *@param  stream                       the InputStream from which the short
-     *      is to be read
+     *@param  stream the InputStream from which the short is to be read
      *@return                              the short (16-bit) value
      *@exception  IOException              will be propagated back to the caller
-     *@exception  BufferUnderrunException  if the stream cannot provide enough
-     *      bytes
+     *@exception  BufferUnderrunException  if the stream cannot provide enough bytes
      */
     public static short readShort(InputStream stream) throws IOException, BufferUnderrunException {
 
-               return (short) readUShort(stream);
-       }
+        return (short) readUShort(stream);
+    }
 
-       public static int readUShort(InputStream stream) throws IOException, BufferUnderrunException {
+    public static int readUShort(InputStream stream) throws IOException, BufferUnderrunException {
 
-               int ch1 = stream.read();
-               int ch2 = stream.read();
-               if ((ch1 | ch2) < 0) {
-                       throw new BufferUnderrunException();
-               }
-               return ((ch2 << 8) + (ch1 << 0));
-       }
+        int ch1 = stream.read();
+        int ch2 = stream.read();
+        if ((ch1 | ch2) < 0) {
+            throw new BufferUnderrunException();
+        }
+        return (ch2 << 8) + (ch1 << 0);
+    }
     
 
     /**
      *  get an int value from an InputStream
      *
-     *@param  stream                       the InputStream from which the int is
-     *      to be read
-     *@return                              the int (32-bit) value
-     *@exception  IOException              will be propagated back to the caller
-     *@exception  BufferUnderrunException  if the stream cannot provide enough
-     *      bytes
+     *@param  stream the InputStream from which the int is to be read
+     * @return                              the int (32-bit) value
+     * @exception  IOException              will be propagated back to the caller
+     * @exception  BufferUnderrunException  if the stream cannot provide enough bytes
      */
-    public static int readInt(final InputStream stream)
+    public static int readInt(InputStream stream)
              throws IOException, BufferUnderrunException {
-               int ch1 = stream.read();
-               int ch2 = stream.read();
-               int ch3 = stream.read();
-               int ch4 = stream.read();
-               if ((ch1 | ch2 | ch3 | ch4) < 0) {
-                       throw new BufferUnderrunException();
-               }
-               return ((ch4 << 24) + (ch3<<16) + (ch2 << 8) + (ch1 << 0));
+        int ch1 = stream.read();
+        int ch2 = stream.read();
+        int ch3 = stream.read();
+        int ch4 = stream.read();
+        if ((ch1 | ch2 | ch3 | ch4) < 0) {
+            throw new BufferUnderrunException();
+        }
+        return (ch4 << 24) + (ch3<<16) + (ch2 << 8) + (ch1 << 0);
     }
 
 
     /**
      *  get a long value from an InputStream
      *
-     *@param  stream                       the InputStream from which the long
-     *      is to be read
-     *@return                              the long (64-bit) value
-     *@exception  IOException              will be propagated back to the caller
-     *@exception  BufferUnderrunException  if the stream cannot provide enough
-     *      bytes
+     * @param  stream the InputStream from which the long is to be read
+     * @return                              the long (64-bit) value
+     * @exception  IOException              will be propagated back to the caller
+     * @exception  BufferUnderrunException  if the stream cannot provide enough bytes
      */
-
-    public static long readLong(final InputStream stream)
+    public static long readLong(InputStream stream)
              throws IOException, BufferUnderrunException {
-               int ch1 = stream.read();
-               int ch2 = stream.read();
-               int ch3 = stream.read();
-               int ch4 = stream.read();
-               int ch5 = stream.read();
-               int ch6 = stream.read();
-               int ch7 = stream.read();
-               int ch8 = stream.read();
-               if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
-                       throw new BufferUnderrunException();
-               }
-               
-               return 
-                       ((long)ch8 << 56) +
+        int ch1 = stream.read();
+        int ch2 = stream.read();
+        int ch3 = stream.read();
+        int ch4 = stream.read();
+        int ch5 = stream.read();
+        int ch6 = stream.read();
+        int ch7 = stream.read();
+        int ch8 = stream.read();
+        if ((ch1 | ch2 | ch3 | ch4 | ch5 | ch6 | ch7 | ch8) < 0) {
+            throw new BufferUnderrunException();
+        }
+        
+        return 
+            ((long)ch8 << 56) +
             ((long)ch7 << 48) +
             ((long)ch6 << 40) +
             ((long)ch5 << 32) +
@@ -458,114 +364,44 @@ public final class LittleEndian implements LittleEndianConsts {
                   (ch1 <<  0);
     }
 
-    /**
-     *  Gets the number attribute of the LittleEndian class
-     *
-     *@param  data    Description of the Parameter
-     *@param  offset  Description of the Parameter
-     *@param  size    Description of the Parameter
-     *@return         The number value
-     */
-    private static long getNumber(final byte[] data, final int offset,
-            final int size) {
-        long result = 0;
-
-        for (int j = offset + size - 1; j >= offset; j--) {
-            result <<= 8;
-            result |= 0xff & data[j];
-        }
-        return result;
-    }
-
-
-    /**
-     *  Description of the Method
-     *
-     *@param  data    Description of the Parameter
-     *@param  offset  Description of the Parameter
-     *@param  value   Description of the Parameter
-     *@param  size    Description of the Parameter
-     */
-    private static void putNumber(final byte[] data, final int offset,
-            final long value, final int size) {
-        int limit = size + offset;
-        long v = value;
-
-        for (int j = offset; j < limit; j++) {
-            data[j] = (byte) (v & 0xFF);
-            v >>= 8;
-        }
-    }
-
-
     /**
      *  Convert an 'unsigned' byte to an integer. ie, don't carry across the
      *  sign.
      *
-     *@param  b  Description of the Parameter
-     *@return    Description of the Return Value
+     * @param  b  Description of the Parameter
+     * @return    Description of the Return Value
      */
     public static int ubyteToInt(byte b) {
-        return ((b & 0x80) == 0 ? (int) b : (b & (byte) 0x7f) + 0x80);
+        return b & 0xFF;
     }
 
 
     /**
      *  get the unsigned value of a byte.
      *
-     *@param  data    the byte array.
-     *@param  offset  a starting offset into the byte array.
-     *@return         the unsigned value of the byte as a 32 bit integer
+     * @param  data    the byte array.
+     * @param  offset  a starting offset into the byte array.
+     * @return         the unsigned value of the byte as a 32 bit integer
      */
-    public static int getUnsignedByte(final byte[] data, final int offset) {
-        return (int) getNumber(data, offset, BYTE_SIZE);
-    }
-
-
-    /**
-     *  get the unsigned value of a byte.
-     *
-     *@param  data  the byte array
-     *@return       the unsigned value of the byte as a 32 bit integer
-     */
-    public static int getUnsignedByte(final byte[] data) {
-        return getUnsignedByte(data, 0);
+    public static int getUnsignedByte(byte[] data, int offset) {
+        return data[offset] & 0xFF;
     }
 
 
     /**
      *  Copy a portion of a byte array
      *
-     *@param  data                        the original byte array
-     *@param  offset                      Where to start copying from.
-     *@param  size                        Number of bytes to copy.
-     *@return                             The byteArray value
-     *@throws  IndexOutOfBoundsException  - if copying would cause access of
+     * @param  data                        the original byte array
+     * @param  offset                      Where to start copying from.
+     * @param  size                        Number of bytes to copy.
+     * @return                             The byteArray value
+     * @throws  IndexOutOfBoundsException  - if copying would cause access of
      *      data outside array bounds.
      */
-    public static byte[] getByteArray(final byte[] data, int offset, int size) {
+    public static byte[] getByteArray(byte[] data, int offset, int size) {
         byte[] copy = new byte[size];
         System.arraycopy(data, offset, copy, 0, size);
 
         return copy;
     }
-
-    /**
-     * <p>Gets an unsigned int value (8 bytes) from a byte array.</p>
-     * 
-     * @param data the byte array
-     * @param offset a starting offset into the byte array
-     * @return the unsigned int (32-bit) value in a long
-     */
-    public static long getULong(final byte[] data, final int offset)
-    {
-        int num = (int) getNumber(data, offset, LONG_SIZE);
-        long retNum;
-        if (num < 0)
-            retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
-        else
-            retNum = num;
-        return retNum;
-    }
-
 }
diff --git a/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java b/src/java/org/apache/poi/util/LittleEndianByteArrayInputStream.java
new file mode 100644 (file)
index 0000000..984db5f
--- /dev/null
@@ -0,0 +1,120 @@
+/* ====================================================================
+   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.util;
+
+/**
+ * Adapts a plain byte array to {@link LittleEndianInput} 
+ * 
+ * 
+ * @author Josh Micich
+ */
+public final class LittleEndianByteArrayInputStream implements LittleEndianInput {
+       private final byte[] _buf;
+       private final int _endIndex;
+       private int _readIndex;
+
+       public LittleEndianByteArrayInputStream(byte[] buf, int startOffset, int maxReadLen) {
+               _buf = buf;
+               _readIndex = startOffset;
+               _endIndex = startOffset + maxReadLen;
+       }
+       public LittleEndianByteArrayInputStream(byte[] buf, int startOffset) {
+               this(buf, startOffset, buf.length - startOffset);
+       }
+       public LittleEndianByteArrayInputStream(byte[] buf) {
+               this(buf, 0, buf.length);
+       }
+
+       public int available() {
+               return _endIndex - _readIndex;
+       }
+       private void checkPosition(int i) {
+               if (i > _endIndex - _readIndex) {
+                       throw new RuntimeException("Buffer overrun");
+               }
+       }
+
+       public int getReadIndex() {
+               return _readIndex;
+       }
+       public byte readByte() {
+               checkPosition(1);
+               return _buf[_readIndex++];
+       }
+
+       public int readInt() {
+               checkPosition(4);
+               int i = _readIndex;
+               
+               int b0 = _buf[i++] & 0xFF;
+               int b1 = _buf[i++] & 0xFF;
+               int b2 = _buf[i++] & 0xFF;
+               int b3 = _buf[i++] & 0xFF;
+               _readIndex = i;
+               return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
+       }
+       public long readLong() {
+               checkPosition(8);
+               int i = _readIndex;
+               
+               int b0 = _buf[i++] & 0xFF;
+               int b1 = _buf[i++] & 0xFF;
+               int b2 = _buf[i++] & 0xFF;
+               int b3 = _buf[i++] & 0xFF;
+               int b4 = _buf[i++] & 0xFF;
+               int b5 = _buf[i++] & 0xFF;
+               int b6 = _buf[i++] & 0xFF;
+               int b7 = _buf[i++] & 0xFF;
+               _readIndex = i;
+               return (((long)b7 << 56) +
+                               ((long)b6 << 48) +
+                               ((long)b5 << 40) +
+                               ((long)b4 << 32) +
+                               ((long)b3 << 24) +
+                               (b2 << 16) +
+                               (b1 <<  8) +
+                               (b0 <<  0));
+       }
+       public short readShort() {
+               return (short)readUShort();
+       }
+       public int readUByte() {
+               checkPosition(1);
+               return _buf[_readIndex++] & 0xFF;
+       }
+       public int readUShort() {
+               checkPosition(2);
+               int i = _readIndex;
+               
+               int b0 = _buf[i++] & 0xFF;
+               int b1 = _buf[i++] & 0xFF;
+               _readIndex = i;
+               return (b1 << 8) + (b0 << 0);
+       }
+       public void readFully(byte[] buf, int off, int len) {
+               checkPosition(len);
+               System.arraycopy(_buf, _readIndex, _buf, off, len);
+               _readIndex+=len;
+       }
+       public void readFully(byte[] buf) {
+               readFully(buf, 0, buf.length);
+       }
+       public double readDouble() {
+               return Double.longBitsToDouble(readLong());
+       }
+}
diff --git a/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java b/src/java/org/apache/poi/util/LittleEndianByteArrayOutputStream.java
new file mode 100644 (file)
index 0000000..b77407c
--- /dev/null
@@ -0,0 +1,87 @@
+/* ====================================================================
+   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.util;
+
+
+/**
+ * Adapts a plain byte array to {@link LittleEndianOutput} 
+ * 
+ * 
+ * @author Josh Micich
+ */
+public final class LittleEndianByteArrayOutputStream implements LittleEndianOutput {
+       private final byte[] _buf;
+       private final int _endIndex;
+       private int _writeIndex;
+
+       public LittleEndianByteArrayOutputStream(byte[] buf, int startOffset, int maxWriteLen) {
+               _buf = buf;
+               _writeIndex = startOffset;
+               _endIndex = startOffset + maxWriteLen;
+       }
+       public LittleEndianByteArrayOutputStream(byte[] buf, int startOffset) {
+               this(buf, startOffset, buf.length - startOffset);
+       }
+
+       private void checkPosition(int i) {
+               if (i > _endIndex - _writeIndex) {
+                       throw new RuntimeException("Buffer overrun");
+               }
+       }
+
+       public void writeByte(int v) {
+               checkPosition(1);
+               _buf[_writeIndex++] = (byte)v;
+       }
+
+       public void writeDouble(double v) {
+               writeLong(Double.doubleToLongBits(v));
+       }
+
+       public void writeInt(int v) {
+               checkPosition(4);
+               int i = _writeIndex;
+               _buf[i++] = (byte)((v >>>  0) & 0xFF);
+               _buf[i++] = (byte)((v >>>  8) & 0xFF);
+               _buf[i++] = (byte)((v >>> 16) & 0xFF);
+               _buf[i++] = (byte)((v >>> 24) & 0xFF);
+               _writeIndex = i;
+       }
+
+       public void writeLong(long v) {
+               writeInt((int)(v >>  0));
+               writeInt((int)(v >> 32));
+       }
+
+       public void writeShort(int v) {
+               checkPosition(2);
+               int i = _writeIndex;
+               _buf[i++] = (byte)((v >>>  0) & 0xFF);
+               _buf[i++] = (byte)((v >>>  8) & 0xFF);
+               _writeIndex = i;
+       }
+       public void write(byte[] b) {
+               int len = b.length;
+               checkPosition(len);
+               System.arraycopy(b, 0, _buf, _writeIndex, len);
+               _writeIndex += len;
+       }
+       public int getWriteIndex() {
+               return _writeIndex;
+       }
+}
index 433999dfc3fe5f42d0a5d1027d39b1c51e0fc746..dafa7eadacd8c734b4a01b25603871beaaa06cbf 100644 (file)
@@ -21,6 +21,7 @@ package org.apache.poi.util;
  * @author Josh Micich\r
  */\r
 public interface LittleEndianInput {\r
+       int available();\r
        byte readByte();\r
        int readUByte();\r
        short readShort();\r
@@ -30,6 +31,4 @@ public interface LittleEndianInput {
        double readDouble();\r
        void readFully(byte[] buf);\r
        void readFully(byte[] buf, int off, int len);\r
-       String readUnicodeLEString(int nChars);\r
-       String readCompressedUnicode(int nChars);\r
 }\r
index 035230491baccd8d2f56a3ebfb99235960c59707..622ee23cd432d3bd5183c61b2a512150e867fb3c 100644 (file)
@@ -22,6 +22,10 @@ import java.io.IOException;
 import java.io.InputStream;\r
 \r
 /**\r
+ * Wraps an {@link InputStream} providing {@link LittleEndianInput}<p/>\r
+ * \r
+ * This class does not buffer any input, so the stream read position maintained \r
+ * by this class is consistent with that of the inner stream.\r
  * \r
  * @author Josh Micich\r
  */\r
@@ -29,7 +33,13 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
        public LittleEndianInputStream(InputStream is) {\r
                super(is);\r
        }\r
-\r
+       public int available() {\r
+               try {\r
+                       return super.available();\r
+               } catch (IOException e) {\r
+                       throw new RuntimeException(e);\r
+               }\r
+       }\r
        public byte readByte() {\r
                return (byte)readUByte();\r
        }\r
@@ -131,34 +141,4 @@ public class LittleEndianInputStream extends FilterInputStream implements Little
                        buf[i] = (byte) ch;\r
                }\r
        }\r
-       public String readCompressedUnicode(int nChars) {\r
-               char[] buf = new char[nChars];\r
-               for (int i = 0; i < buf.length; i++) {\r
-                       int ch;\r
-                       try {\r
-                               ch = in.read();\r
-                       } catch (IOException e) {\r
-                               throw new RuntimeException(e);\r
-                       }\r
-                       checkEOF(ch);\r
-                       buf[i] = (char) ch;\r
-                       \r
-               }\r
-               return new String(buf);\r
-       }\r
-       public String readUnicodeLEString(int nChars) {\r
-               char[] buf = new char[nChars];\r
-               for (int i = 0; i < buf.length; i++) {\r
-                       int ch;\r
-                       try {\r
-                               ch = in.read();\r
-                       } catch (IOException e) {\r
-                               throw new RuntimeException(e);\r
-                       }\r
-                       checkEOF(ch);\r
-                       buf[i] = (char) ch;\r
-                       \r
-               }\r
-               return new String(buf);\r
-       }\r
 }\r
index bb98de3d055fb1f7ad7ca25bae77e022cc11e3d9..8a57d2340b83ad476c868ff0b2b549d8df306161 100644 (file)
@@ -20,9 +20,14 @@ package org.apache.poi.util;
 import java.io.UnsupportedEncodingException;
 import java.text.FieldPosition;
 import java.text.NumberFormat;
+
+import org.apache.poi.hssf.record.RecordInputStream;
 /**
- *  Title: String Utility Description: Collection of string handling utilities
- *
+ *  Title: String Utility Description: Collection of string handling utilities<p/>
+ *  
+ * Note - none of the methods in this class deals with {@link ContinueRecord}s.  For such
+ * functionality, consider using {@link RecordInputStream
+} *
  *
  *@author     Andrew C. Oliver
  *@author     Sergei Kozello (sergeikozello at mail.ru)
@@ -84,64 +89,11 @@ public class StringUtil {
         * @param  string  the byte array to be converted
         * @return         the converted string
         */
-       public static String getFromUnicodeLE(final byte[] string) {
+       public static String getFromUnicodeLE(byte[] string) {
                if(string.length == 0) { return ""; }
                return getFromUnicodeLE(string, 0, string.length / 2);
        }
 
-       /**
-        *  Given a byte array of 16-bit unicode characters in big endian
-        *  format (most important byte first), return a Java String representation
-        *  of it.
-        *
-        * { 0x00, 0x16 } -0x16
-        *
-        * @param  string                              the byte array to be converted
-        * @param  offset                              the initial offset into the
-        *      byte array. it is assumed that string[ offset ] and string[ offset +
-        *      1 ] contain the first 16-bit unicode character
-     * @param len the length of the final string
-        * @return                                     the converted string
-        * @exception  ArrayIndexOutOfBoundsException  if offset is out of bounds for
-        *      the byte array (i.e., is negative or is greater than or equal to
-        *      string.length)
-        * @exception  IllegalArgumentException        if len is too large (i.e.,
-        *      there is not enough data in string to create a String of that
-        *      length)
-        */
-       public static String getFromUnicodeBE(
-               final byte[] string,
-               final int offset,
-               final int len)
-               throws ArrayIndexOutOfBoundsException, IllegalArgumentException {
-               if ((offset < 0) || (offset >= string.length)) {
-                       throw new ArrayIndexOutOfBoundsException("Illegal offset");
-               }
-               if ((len < 0) || (((string.length - offset) / 2) < len)) {
-                       throw new IllegalArgumentException("Illegal length");
-               }
-               try {
-                       return new String(string, offset, len * 2, "UTF-16BE");
-               } catch (UnsupportedEncodingException e) {
-                       throw new RuntimeException(e);
-               }
-       }
-
-       /**
-        *  Given a byte array of 16-bit unicode characters in big endian
-        *  format (most important byte first), return a Java String representation
-        *  of it.
-        *
-        * { 0x00, 0x16 } -0x16
-        *
-        * @param  string  the byte array to be converted
-        * @return         the converted string
-        */
-       public static String getFromUnicodeBE(final byte[] string) {
-               if(string.length == 0) { return ""; }
-               return getFromUnicodeBE(string, 0, string.length / 2);
-       }
-
        /**
         * Read 8 bit data (in ISO-8859-1 codepage) into a (unicode) Java
         * String and return.
@@ -163,6 +115,52 @@ public class StringUtil {
                        throw new RuntimeException(e);
                }
        }
+       public static String readCompressedUnicode(LittleEndianInput in, int nChars) {
+               char[] buf = new char[nChars];
+               for (int i = 0; i < buf.length; i++) {
+                       buf[i] = (char) in.readUByte();
+               }
+               return new String(buf);
+       }
+       /**
+        * InputStream <tt>in</tt> is expected to contain:
+        * <ol>
+        * <li>ushort nChars</li>
+        * <li>byte is16BitFlag</li>
+        * <li>byte[]/char[] characterData</li>
+        * </ol>
+        * For this encoding, the is16BitFlag is always present even if nChars==0.
+        */
+       public static String readUnicodeString(LittleEndianInput in) {
+               
+               int nChars = in.readUShort();
+               byte flag = in.readByte();
+               if ((flag & 0x01) == 0) {
+                       return readCompressedUnicode(in, nChars);
+               }
+               return readUnicodeLE(in, nChars);
+       }
+       /**
+        * OutputStream <tt>out</tt> will get:
+        * <ol>
+        * <li>ushort nChars</li>
+        * <li>byte is16BitFlag</li>
+        * <li>byte[]/char[] characterData</li>
+        * </ol>
+        * For this encoding, the is16BitFlag is always present even if nChars==0.
+        */
+       public static void writeUnicodeString(LittleEndianOutput out, String value) {
+               
+               int nChars = value.length();
+               out.writeShort(nChars);
+               boolean is16Bit = hasMultibyte(value);
+               out.writeByte(is16Bit ? 0x01 : 0x00);
+               if (is16Bit) {
+                       putUnicodeLE(value, out);
+               } else {
+                       putCompressedUnicode(value, out);
+               }
+       }
 
        /**
         * Takes a unicode (java) string, and returns it as 8 bit data (in ISO-8859-1
@@ -220,6 +218,14 @@ public class StringUtil {
                }
                out.write(bytes);
        }
+       
+       public static String readUnicodeLE(LittleEndianInput in, int nChars) {
+               char[] buf = new char[nChars];
+               for (int i = 0; i < buf.length; i++) {
+                       buf[i] = (char) in.readUShort();
+               }
+               return new String(buf);
+       }
 
        /**
         *  Apply printf() like formatting to a string.
index 5fb6f4aa03a7ed7ff5e820a2c9b8d98e5e981667..edf62a9ad1ec7f27351b54d802925c012358698b 100755 (executable)
@@ -100,6 +100,7 @@ public final class AllRecordTests {
                result.addTestSuite(TestSheetPropertiesRecord.class);
                result.addTestSuite(TestSharedFormulaRecord.class);
                result.addTestSuite(TestStringRecord.class);
+               result.addTestSuite(TestStyleRecord.class);
                result.addTestSuite(TestSubRecord.class);
                result.addTestSuite(TestSupBookRecord.class);
                result.addTestSuite(TestTableRecord.class);
index 53a49fda0d71a34db19d6573cfa409e033f0e17c..8e6e7ce5610d6b723011c4cdf1f3dada79ffddea 100644 (file)
@@ -37,7 +37,7 @@ public final class TestCommonObjectDataSubRecord extends TestCase {
        };
 
        public void testLoad() {
-               CommonObjectDataSubRecord record = new CommonObjectDataSubRecord(TestcaseRecordInputStream.createWithFakeSid(data), data.length);
+               CommonObjectDataSubRecord record = new CommonObjectDataSubRecord(TestcaseRecordInputStream.createLittleEndian(data), data.length);
 
                assertEquals( CommonObjectDataSubRecord.OBJECT_TYPE_LIST_BOX, record.getObjectType());
                assertEquals((short) 1, record.getObjectId());
index deaf779bbb968305893694e630b685883a5b88eb..02875117ec0c64f57737f6ee70090f14c79349bc 100644 (file)
    See the License for the specific language governing permissions and\r
    limitations under the License.\r
 ==================================================================== */\r
+\r
 package org.apache.poi.hssf.record;\r
 \r
-import java.io.ByteArrayInputStream;\r
 import java.util.Arrays;\r
 \r
+import junit.framework.AssertionFailedError;\r
 import junit.framework.TestCase;\r
 \r
 import org.apache.poi.util.HexRead;\r
@@ -37,33 +38,43 @@ public final class TestEmbeddedObjectRefSubRecord extends TestCase {
        public void testStore() {\r
 \r
                byte[] src = hr(data1);\r
-               src = TestcaseRecordInputStream.mergeDataAndSid(EmbeddedObjectRefSubRecord.sid, (short)src.length, src);\r
+//             src = TestcaseRecordInputStream.mergeDataAndSid(EmbeddedObjectRefSubRecord.sid, (short)src.length, src);\r
 \r
-               RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(src));\r
-               in.nextRecord();\r
+               RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, src);\r
 \r
-               EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length-4);\r
+               EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord(in, src.length);\r
 \r
                byte[] ser = record1.serialize();\r
 \r
-               RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));\r
-               in2.nextRecord();\r
+               RecordInputStream in2 = TestcaseRecordInputStream.create(ser);\r
                EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);\r
 \r
-               assertTrue(Arrays.equals(src, ser));\r
+               confirmData(src, ser);\r
                assertEquals(record1.getOLEClassName(), record2.getOLEClassName());\r
 \r
                byte[] ser2 = record1.serialize();\r
                assertTrue(Arrays.equals(ser, ser2));\r
        }\r
 \r
+       /**\r
+        * @param expectedData does not include sid & size\r
+        * @param actualFullRecordData includes sid & size\r
+        */\r
+       private static void confirmData(byte[] expectedData, byte[] actualFullRecordData) {\r
+               assertEquals(expectedData.length, actualFullRecordData.length-4);\r
+               for (int i = 0; i < expectedData.length; i++) {\r
+                       if(expectedData[i] != actualFullRecordData[i+4]) {\r
+                               throw new AssertionFailedError("Difference at offset (" + i + ")");\r
+                       }\r
+               }\r
+       }\r
+\r
        public void testCreate() {\r
 \r
                EmbeddedObjectRefSubRecord record1 = new EmbeddedObjectRefSubRecord();\r
 \r
                byte[] ser = record1.serialize();\r
-               RecordInputStream in2 = new RecordInputStream(new ByteArrayInputStream(ser));\r
-               in2.nextRecord();\r
+               RecordInputStream in2 = TestcaseRecordInputStream.create(ser);\r
                EmbeddedObjectRefSubRecord record2 = new EmbeddedObjectRefSubRecord(in2, ser.length-4);\r
 \r
                assertEquals(record1.getOLEClassName(), record2.getOLEClassName());\r
@@ -78,21 +89,17 @@ public final class TestEmbeddedObjectRefSubRecord extends TestCase {
         * taken from ftPictFmla sub-record in attachment 22645 (offset 0x40AB).\r
         */\r
        private static final byte[] data45912 = hr(\r
-               "09 00 14 00 " +\r
                "12 00 0B 00 F8 02 88 04 3B 00 " +\r
                "00 00 00 01 00 00 00 01 " +\r
                "00 00");\r
 \r
        public void testCameraTool_bug45912() {\r
                byte[] data = data45912;\r
-               RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));\r
-               in.nextRecord();\r
+               RecordInputStream in = TestcaseRecordInputStream.create(EmbeddedObjectRefSubRecord.sid, data);\r
 \r
-               EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length-4);\r
+               EmbeddedObjectRefSubRecord rec = new EmbeddedObjectRefSubRecord(in, data.length);\r
                byte[] ser2 = rec.serialize();\r
-               assertTrue(Arrays.equals(data, ser2));\r
-\r
-\r
+               confirmData(data, ser2);\r
        }\r
 \r
        private static byte[] hr(String string) {\r
index 703664443ccb29eb26d22bb4bd3608bd47d1e790..cf8fe0bd2fd328100af52dd3664a83dd81be6825 100644 (file)
@@ -119,7 +119,6 @@ public final class TestFormulaRecord extends TestCase {
        public void testWithConcat() {
                // =CHOOSE(2,A2,A3,A4)
                byte[] data = {
-                               6, 0, 68, 0,
                                1, 0, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 57,
                                64, 0, 0, 12, 0, 12, -4, 46, 0,
                                30, 2, 0,       // Int - 2
@@ -134,8 +133,7 @@ public final class TestFormulaRecord extends TestCase {
                                25, 8, 3, 0,  // Attr
                                66, 4, 100, 0 // CHOOSE
                };
-               RecordInputStream inp = new RecordInputStream( new ByteArrayInputStream(data));
-               inp.nextRecord();
+               RecordInputStream inp = TestcaseRecordInputStream.create(FormatRecord.sid, data);
 
                FormulaRecord fr = new FormulaRecord(inp);
 
index 1919a4b038f11343033b63b5f60410e3f97779d7..ce0e6e20309c8fe5849d4f02af674fe1f7215f61 100644 (file)
@@ -239,8 +239,7 @@ public final class TestHyperlinkRecord extends TestCase {
         RecordInputStream is = TestcaseRecordInputStream.create(HyperlinkRecord.sid, data);
         HyperlinkRecord link = new HyperlinkRecord(is);
         byte[] bytes1 = link.serialize();
-        is = new RecordInputStream(new ByteArrayInputStream(bytes1));
-        is.nextRecord();
+        is = TestcaseRecordInputStream.create(bytes1);
         link = new HyperlinkRecord(is);
         byte[] bytes2 = link.serialize();
         assertEquals(bytes1.length, bytes2.length);
index 8a52211a6a540fc00a420315c1e6585cb43f22a2..7dea16b3084f55970af374e49f9ead4f5cf87685 100644 (file)
@@ -23,6 +23,7 @@ import junit.framework.TestCase;
 
 import org.apache.poi.hssf.record.formula.Ptg;
 import org.apache.poi.hssf.record.formula.RefPtg;
+import org.apache.poi.util.LittleEndianInput;
 
 /**
  * @author Josh Micich
@@ -59,7 +60,7 @@ public final class TestSharedFormulaRecord extends TestCase {
         */
        public void testConvertSharedFormulasOperandClasses_bug45123() {
                
-               RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
+               LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SHARED_FORMULA_WITH_REF_ARRAYS_DATA);
                int encodedLen = in.readUShort();
                Ptg[] sharedFormula = Ptg.readTokens(encodedLen, in);
                
diff --git a/src/testcases/org/apache/poi/hssf/record/TestStyleRecord.java b/src/testcases/org/apache/poi/hssf/record/TestStyleRecord.java
new file mode 100644 (file)
index 0000000..bfe11dd
--- /dev/null
@@ -0,0 +1,33 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.hssf.record;\r
+\r
+import junit.framework.TestCase;\r
+/**\r
+ * \r
+ */\r
+public final class TestStyleRecord extends TestCase {\r
+    public void testUnicodeReadName() {\r
+       byte[] data = {\r
+                       17, 0, 9, 0, 1, 56, 94, -60, -119, 95, 0, 83, 0, 104, 0, 101, 0, 101, 0, 116, 0, 49, 0, 92, 40, //92, 36                        \r
+       };\r
+       RecordInputStream in = TestcaseRecordInputStream.create(StyleRecord.sid, data);\r
+       StyleRecord sr = new StyleRecord(in);\r
+       assertEquals("\u5E38\u89C4_Sheet1", sr.getName()); // "<Conventional>_Sheet1"\r
+    }\r
+}\r
index b8f9e86468169cc47b7ef4b53e5b2dba05dcbab5..9b53cdd339d029ed9514cdce9fab2e009e09326b 100644 (file)
@@ -55,11 +55,9 @@ public final class TestTextObjectBaseRecord extends TestCase {
     
 
     public void testLoad() {
-        RecordInputStream in = new RecordInputStream(new ByteArrayInputStream(data));
-        in.nextRecord();
+        RecordInputStream in = TestcaseRecordInputStream.create(data);
         TextObjectRecord record = new TextObjectRecord(in);
 
-
         assertEquals(TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment());
         assertEquals(TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment());
         assertEquals(true, record.isTextLocked());
index b7d45e28b0ef6df0ec798e4370495c4365ffc991..19ec07c8108fd2f4d975b7c1287065156ee6e2c8 100644 (file)
@@ -52,8 +52,7 @@ public final class TestTextObjectRecord extends TestCase {
 \r
     public void testRead() {\r
 \r
-        RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));\r
-        is.nextRecord();\r
+        RecordInputStream is =TestcaseRecordInputStream.create(simpleData);\r
         TextObjectRecord record = new TextObjectRecord(is);\r
 \r
         assertEquals(TextObjectRecord.sid, record.getSid());\r
@@ -79,8 +78,7 @@ public final class TestTextObjectRecord extends TestCase {
         assertTrue(Arrays.equals(simpleData, ser));\r
 \r
         //read again\r
-        RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(simpleData));\r
-        is.nextRecord();\r
+        RecordInputStream is = TestcaseRecordInputStream.create(simpleData);\r
         record = new TextObjectRecord(is);\r
     }\r
 \r
@@ -101,8 +99,7 @@ public final class TestTextObjectRecord extends TestCase {
         assertEquals(22, ser.length); // just the TXO record\r
         \r
         //read again\r
-        RecordInputStream is = new RecordInputStream(new ByteArrayInputStream(ser));\r
-        is.nextRecord();\r
+        RecordInputStream is = TestcaseRecordInputStream.create(ser);\r
         record = new TextObjectRecord(is);\r
         assertEquals(0, record.getStr().length());\r
     }\r
index e16eb2022e75e602c795b2294b218b39e2ed00c6..1bbc9d7a94f0e7f4809ee05fc53a5e490b756cfc 100755 (executable)
@@ -23,6 +23,8 @@ import java.io.InputStream;
 import junit.framework.Assert;
 
 import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.LittleEndianByteArrayInputStream;
+import org.apache.poi.util.LittleEndianInput;
 
 /**
  * A Record Input Stream derivative that makes access to byte arrays used in the
@@ -40,8 +42,8 @@ public final class TestcaseRecordInputStream {
        /**
         * Prepends a mock record identifier to the supplied data and opens a record input stream 
         */
-       public static RecordInputStream createWithFakeSid(byte[] data) {
-               return create(-5555, data);
+       public static LittleEndianInput createLittleEndian(byte[] data) {
+               return new LittleEndianByteArrayInputStream(data);
                
        }
        public static RecordInputStream create(int sid, byte[] data) {
index 17a0901040317b1041852379748e30a42e266054..a72d0e1aed76acb03980d97d0d97de8f304dec10 100644 (file)
@@ -21,11 +21,12 @@ import java.util.Arrays;
 
 import junit.framework.TestCase;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.record.TestcaseRecordInputStream;
 import org.apache.poi.hssf.record.UnicodeString;
 import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
 import org.apache.poi.util.HexRead;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
 /**
  * 
  * @author Josh Micich
@@ -52,14 +53,15 @@ public final class TestConstantValueParser extends TestCase {
        public void testEncode() {
                int size = ConstantValueParser.getEncodedSize(SAMPLE_VALUES);
                byte[] data = new byte[size];
-               ConstantValueParser.encode(data, 0, SAMPLE_VALUES);
+               
+               ConstantValueParser.encode(new LittleEndianByteArrayOutputStream(data, 0), SAMPLE_VALUES);
                
                if (!Arrays.equals(data, SAMPLE_ENCODING)) {
                        fail("Encoding differs");
                }
        }
        public void testDecode() {
-               RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(SAMPLE_ENCODING);
+               LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(SAMPLE_ENCODING);
                
                Object[] values = ConstantValueParser.parse(in, 4);
                for (int i = 0; i < values.length; i++) {
index 8d2fe631d25cb5b62ae000d7453e6d5a9dc9ffe3..94a16b382909506fd6581f7af35a482be106d119 100644 (file)
@@ -24,6 +24,8 @@ import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.record.TestcaseRecordInputStream;
 import org.apache.poi.hssf.record.UnicodeString;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.LittleEndianByteArrayOutputStream;
+import org.apache.poi.util.LittleEndianInput;
 
 import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
@@ -54,9 +56,9 @@ public final class TestArrayPtg extends TestCase {
         */
        public void testReadWriteTokenValueBytes() {
                
-               ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA));
+               ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createLittleEndian(ENCODED_PTG_DATA));
                
-               ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA));
+               ptg.readTokenValues(TestcaseRecordInputStream.createLittleEndian(ENCODED_CONSTANT_DATA));
                assertEquals(3, ptg.getColumnCount());
                assertEquals(2, ptg.getRowCount());
                Object[][] values = ptg.getTokenArrayValues();
@@ -70,7 +72,7 @@ public final class TestArrayPtg extends TestCase {
                assertEquals(new UnicodeString("FG"), values[1][2]);
                
                byte[] outBuf = new byte[ENCODED_CONSTANT_DATA.length];
-               ptg.writeTokenValueBytes(outBuf, 0);
+               ptg.writeTokenValueBytes(new LittleEndianByteArrayOutputStream(outBuf, 0));
                
                if(outBuf[0] == 4) {
                        throw new AssertionFailedError("Identified bug 42564b");
@@ -82,8 +84,8 @@ public final class TestArrayPtg extends TestCase {
         * Excel stores array elements column by column.  This test makes sure POI does the same.
         */
        public void testElementOrdering() {
-               ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA));
-               ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA));
+               ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createLittleEndian(ENCODED_PTG_DATA));
+               ptg.readTokenValues(TestcaseRecordInputStream.createLittleEndian(ENCODED_CONSTANT_DATA));
                assertEquals(3, ptg.getColumnCount());
                assertEquals(2, ptg.getRowCount());
                
@@ -113,9 +115,9 @@ public final class TestArrayPtg extends TestCase {
        }
 
        public void testToFormulaString() {
-               ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createWithFakeSid(ENCODED_PTG_DATA));
+               ArrayPtg ptg = new ArrayPtg(TestcaseRecordInputStream.createLittleEndian(ENCODED_PTG_DATA));
                
-               ptg.readTokenValues(TestcaseRecordInputStream.createWithFakeSid(ENCODED_CONSTANT_DATA));
+               ptg.readTokenValues(TestcaseRecordInputStream.createLittleEndian(ENCODED_CONSTANT_DATA));
                
                String actualFormula;
                try {
@@ -146,7 +148,7 @@ public final class TestArrayPtg extends TestCase {
                // Force encoded operand class for tArray 
                fullData[0] = (byte) (ArrayPtg.sid + operandClass);
                
-               RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(fullData);
+               LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(fullData);
                
                Ptg[] ptgs = Ptg.readTokens(ENCODED_PTG_DATA.length, in);
                assertEquals(1, ptgs.length);
index d9342d61c00eccd7ea8330ad4cb3cb4f2467b134..7edb3f4fc55afe868dfd404c0ea59d698ce7ccb4 100644 (file)
@@ -21,9 +21,9 @@ import java.util.Arrays;
 
 import junit.framework.AssertionFailedError;
 
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.record.TestcaseRecordInputStream;
 import org.apache.poi.util.HexRead;
+import org.apache.poi.util.LittleEndianInput;
 
 /**
  * Tests for {@link AttrPtg}.
@@ -37,7 +37,7 @@ public final class TestAttrPtg extends AbstractPtgTestCase {
         */
        public void testReserializeAttrChoose() {
                byte[] data = HexRead.readFromString("19, 04, 03, 00, 08, 00, 11, 00, 1A, 00, 23, 00");
-               RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(data);
+               LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(data);
                Ptg[] ptgs = Ptg.readTokens(data.length, in);
                byte[] data2 = new byte[data.length];
                try {
index 827bea8332dc41d8af9f20794d6edecf9a7cab12..bbf8c4cfb23893f33b1756bde412f3c4e77a3743 100644 (file)
@@ -34,7 +34,7 @@ public final class TestFuncPtg extends TestCase {
             0,
         };
 
-        FuncPtg ptg = new FuncPtg(TestcaseRecordInputStream.createWithFakeSid(fakeData) );
+        FuncPtg ptg = new FuncPtg(TestcaseRecordInputStream.createLittleEndian(fakeData) );
         assertEquals( "Len formula index is not 32(20H)", 0x20, ptg.getFunctionIndex() );
         assertEquals( "Number of operands in the len formula", 1, ptg.getNumberOfOperands() );
         assertEquals( "Function Name", "LEN", ptg.getName() );
index 6be329ed5ae57b7d9ac014f3eb56ac6d9e3f78e0..dc8fd6b9b6eca4cd01ae61c7c567c0df4bff92da 100644 (file)
@@ -23,10 +23,10 @@ import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 
 import org.apache.poi.hssf.HSSFTestDataSamples;
-import org.apache.poi.hssf.record.RecordInputStream;
 import org.apache.poi.hssf.record.TestcaseRecordInputStream;
 import org.apache.poi.hssf.usermodel.HSSFSheet;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.util.LittleEndianInput;
 
 /**
  * Tests for {@link RefPtg}.
@@ -94,7 +94,7 @@ public final class TestReferencePtg extends TestCase {
        0x2C, 33, 44, 55, 66,
     };
     public void testReadWrite_tRefN_bug45091() {
-        RecordInputStream in = TestcaseRecordInputStream.createWithFakeSid(tRefN_data);
+       LittleEndianInput in = TestcaseRecordInputStream.createLittleEndian(tRefN_data);
         Ptg[] ptgs = Ptg.readTokens(tRefN_data.length, in);
         byte[] outData = new byte[5];
         Ptg.serializePtgs(ptgs, outData, 0);
index b42f7ef71a09ee3214cd0f2e3edc7ac6ab61ecc7..751826e3fb02c27509e569de784d0824bd000b4a 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.filesystem;
 
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Arrays;
 
-import junit.framework.*;
+import junit.framework.TestCase;
 
 import org.apache.poi.poifs.property.DirectoryProperty;
-import org.apache.poi.poifs.property.DocumentProperty;
 import org.apache.poi.poifs.storage.RawDataBlock;
 
 /**
@@ -35,22 +32,9 @@ import org.apache.poi.poifs.storage.RawDataBlock;
  * @author Marc Johnson
  */
 
-public class TestDocumentInputStream
-    extends TestCase
-{
+public final class TestDocumentInputStream extends TestCase {
 
-    /**
-     * Constructor TestDocumentInputStream
-     *
-     * @param name
-     *
-     * @exception IOException
-     */
-
-    public TestDocumentInputStream(String name)
-        throws IOException
-    {
-        super(name);
+       protected void setUp() throws Exception {
         int blocks = (_workbook_size + 511) / 512;
 
         _workbook_data = new byte[ 512 * blocks ];
@@ -86,13 +70,8 @@ public class TestDocumentInputStream
 
     /**
      * test constructor
-     *
-     * @exception IOException
      */
-
-    public void testConstructor()
-        throws IOException
-    {
+    public void testConstructor() throws IOException {
         DocumentInputStream stream = new DocumentInputStream(_workbook);
 
         assertEquals(_workbook_size, stream.available());
@@ -100,13 +79,8 @@ public class TestDocumentInputStream
 
     /**
      * test available() behavior
-     *
-     * @exception IOException
      */
-
-    public void testAvailable()
-        throws IOException
-    {
+    public void testAvailable() throws IOException {
         DocumentInputStream stream = new DocumentInputStream(_workbook);
 
         assertEquals(_workbook_size, stream.available());
@@ -115,9 +89,7 @@ public class TestDocumentInputStream
         {
             stream.available();
             fail("Should have caught IOException");
-        }
-        catch (IOException ignored)
-        {
+        } catch (IllegalStateException ignored) {
 
             // as expected
         }
@@ -125,13 +97,8 @@ public class TestDocumentInputStream
 
     /**
      * test mark/reset/markSupported.
-     *
-     * @exception IOException
      */
-
-    public void testMarkFunctions()
-        throws IOException
-    {
+    public void testMarkFunctions() throws IOException {
         DocumentInputStream stream = new DocumentInputStream(_workbook);
         byte[]              buffer = new byte[ _workbook_size / 5 ];
 
@@ -169,13 +136,8 @@ public class TestDocumentInputStream
 
     /**
      * test simple read method
-     *
-     * @exception IOException
      */
-
-    public void testReadSingleByte()
-        throws IOException
-    {
+    public void testReadSingleByte() throws IOException {
         DocumentInputStream stream    = new DocumentInputStream(_workbook);
         int                 remaining = _workbook_size;
 
@@ -205,13 +167,8 @@ public class TestDocumentInputStream
 
     /**
      * Test buffered read
-     *
-     * @exception IOException
      */
-
-    public void testBufferRead()
-        throws IOException
-    {
+    public void testBufferRead() throws IOException {
         DocumentInputStream stream = new DocumentInputStream(_workbook);
 
         try
@@ -275,23 +232,14 @@ public class TestDocumentInputStream
 
     /**
      * Test complex buffered read
-     *
-     * @exception IOException
      */
-
-    public void testComplexBufferRead()
-        throws IOException
-    {
+    public void testComplexBufferRead() throws IOException {
         DocumentInputStream stream = new DocumentInputStream(_workbook);
 
-        try
-        {
+        try {
             stream.read(null, 0, 1);
             fail("Should have caught NullPointerException");
-        }
-        catch (NullPointerException ignored)
-        {
-
+        } catch (IllegalArgumentException ignored) {
             // as expected
         }
 
@@ -391,13 +339,8 @@ public class TestDocumentInputStream
 
     /**
      * test skip
-     *
-     * @exception IOException
      */
-
-    public void testSkip()
-        throws IOException
-    {
+    public void testSkip() throws IOException {
         DocumentInputStream stream = new DocumentInputStream(_workbook);
 
         assertEquals(_workbook_size, stream.available());
@@ -422,17 +365,4 @@ public class TestDocumentInputStream
                      stream.skip(2 + ( long ) Integer.MAX_VALUE));
         assertEquals(0, stream.available());
     }
-
-    /**
-     * main method to run the unit tests
-     *
-     * @param ignored_args
-     */
-
-    public static void main(String [] ignored_args)
-    {
-        System.out.println(
-            "Testing org.apache.poi.poifs.filesystem.DocumentInputStream");
-        junit.textui.TestRunner.run(TestDocumentInputStream.class);
-    }
 }
index 8c15d389e351691279c3a94db5431c3a8af27ebd..b589922587c1dcd9c08cd010301291a402d3bc9d 100755 (executable)
@@ -26,22 +26,22 @@ import junit.framework.TestSuite;
  */
 public final class AllPOIFSStorageTests {
 
-    public static Test suite() {
-        TestSuite result = new TestSuite("Tests for org.apache.poi.poifs.storage");
-        result.addTestSuite(TestBATBlock.class);
-        result.addTestSuite(TestBlockAllocationTableReader.class);
-        result.addTestSuite(TestBlockAllocationTableWriter.class);
-        result.addTestSuite(TestBlockListImpl.class);
-        result.addTestSuite(TestDocumentBlock.class);
-        result.addTestSuite(TestHeaderBlockReader.class);
-        result.addTestSuite(TestHeaderBlockWriter.class);
-        result.addTestSuite(TestPropertyBlock.class);
-        result.addTestSuite(TestRawDataBlock.class);
-        result.addTestSuite(TestRawDataBlockList.class);
-        result.addTestSuite(TestSmallBlockTableReader.class);
-        result.addTestSuite(TestSmallBlockTableWriter.class);
-        result.addTestSuite(TestSmallDocumentBlock.class);
-        result.addTestSuite(TestSmallDocumentBlockList.class);
-        return result;
-    }
+       public static Test suite() {
+               TestSuite result = new TestSuite(AllPOIFSStorageTests.class.getName());
+               result.addTestSuite(TestBATBlock.class);
+               result.addTestSuite(TestBlockAllocationTableReader.class);
+               result.addTestSuite(TestBlockAllocationTableWriter.class);
+               result.addTestSuite(TestBlockListImpl.class);
+               result.addTestSuite(TestDocumentBlock.class);
+               result.addTestSuite(TestHeaderBlockReader.class);
+               result.addTestSuite(TestHeaderBlockWriter.class);
+               result.addTestSuite(TestPropertyBlock.class);
+               result.addTestSuite(TestRawDataBlock.class);
+               result.addTestSuite(TestRawDataBlockList.class);
+               result.addTestSuite(TestSmallBlockTableReader.class);
+               result.addTestSuite(TestSmallBlockTableWriter.class);
+               result.addTestSuite(TestSmallDocumentBlock.class);
+               result.addTestSuite(TestSmallDocumentBlockList.class);
+               return result;
+       }
 }
index bb0ca8cd6ce45e0992e42bfbef4ef1a254721c0e..3c15e2deae219b3b9d8a2dcb85a59e3d44894f95 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.storage;
 
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 
-import junit.framework.*;
+import junit.framework.TestCase;
 
 /**
  * Class to test DocumentBlock functionality
  *
  * @author Marc Johnson
  */
-
-public class TestDocumentBlock
-    extends TestCase
-{
+public final class TestDocumentBlock extends TestCase {
     static final private byte[] _testdata;
 
     static
@@ -44,25 +39,10 @@ public class TestDocumentBlock
             _testdata[ j ] = ( byte ) j;
         }
     }
-    ;
-
-    /**
-     * Constructor TestDocumentBlock
-     *
-     * @param name
-     */
-
-    public TestDocumentBlock(String name)
-    {
-        super(name);
-    }
 
     /**
      * Test the writing DocumentBlock constructor.
-     *
-     * @exception IOException
      */
-
     public void testConstructor()
         throws IOException
     {
@@ -88,46 +68,10 @@ public class TestDocumentBlock
         assertEquals(_testdata.length, size);
     }
 
-    /**
-     * test static read method
-     *
-     * @exception IOException
-     */
-
-    public void testRead()
-        throws IOException
-    {
-        DocumentBlock[]      blocks = new DocumentBlock[ 4 ];
-        ByteArrayInputStream input  = new ByteArrayInputStream(_testdata);
-
-        for (int j = 0; j < 4; j++)
-        {
-            blocks[ j ] = new DocumentBlock(input);
-        }
-        for (int j = 1; j <= 2000; j += 17)
-        {
-            byte[] buffer = new byte[ j ];
-            int    offset = 0;
-
-            for (int k = 0; k < (2000 / j); k++)
-            {
-                DocumentBlock.read(blocks, buffer, offset);
-                for (int n = 0; n < buffer.length; n++)
-                {
-                    assertEquals("checking byte " + (k * j) + n,
-                                 _testdata[ (k * j) + n ], buffer[ n ]);
-                }
-                offset += j;
-            }
-        }
-    }
 
     /**
      * Test 'reading' constructor
-     *
-     * @exception IOException
      */
-
     public void testReadingConstructor()
         throws IOException
     {
@@ -164,17 +108,4 @@ public class TestDocumentBlock
             assertEquals(( byte ) 0xFF, copy[ j ]);
         }
     }
-
-    /**
-     * main method to run the unit tests
-     *
-     * @param ignored_args
-     */
-
-    public static void main(String [] ignored_args)
-    {
-        System.out
-            .println("Testing org.apache.poi.poifs.storage.DocumentBlock");
-        junit.textui.TestRunner.run(TestDocumentBlock.class);
-    }
 }
index 05e51974f8f3a0513990ad2c4eb5ac21015635ee..dfbfbb4e514906b2ec863226f480d7ac3d5174c2 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.poifs.storage;
 
-import java.io.*;
-
-import java.util.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
-import junit.framework.*;
+import junit.framework.TestCase;
 
 /**
  * Class to test SmallDocumentBlock functionality
  *
  * @author Marc Johnson
  */
-
-public class TestSmallDocumentBlock
-    extends TestCase
-{
+public final class TestSmallDocumentBlock extends TestCase {
     static final private byte[] _testdata;
     static final private int    _testdata_size = 2999;
 
@@ -45,25 +43,10 @@ public class TestSmallDocumentBlock
             _testdata[ j ] = ( byte ) j;
         }
     }
-    ;
-
-    /**
-     * constructor
-     *
-     * @param name
-     */
-
-    public TestSmallDocumentBlock(String name)
-    {
-        super(name);
-    }
 
     /**
      * Test conversion from DocumentBlocks
-     *
-     * @exception IOException
      */
-
     public void testConvert1()
         throws IOException
     {
@@ -113,12 +96,7 @@ public class TestSmallDocumentBlock
 
     /**
      * Test conversion from byte array
-     *
-     * @exception IOException;
-     *
-     * @exception IOException
      */
-
     public void testConvert2()
         throws IOException
     {
@@ -154,57 +132,9 @@ public class TestSmallDocumentBlock
         }
     }
 
-    /**
-     * Test read method
-     *
-     * @exception IOException
-     */
-
-    public void testRead()
-        throws IOException
-    {
-        ByteArrayInputStream stream    = new ByteArrayInputStream(_testdata);
-        List                 documents = new ArrayList();
-
-        while (true)
-        {
-            DocumentBlock block = new DocumentBlock(stream);
-
-            documents.add(block);
-            if (block.partiallyRead())
-            {
-                break;
-            }
-        }
-        SmallDocumentBlock[] blocks =
-            SmallDocumentBlock
-                .convert(( BlockWritable [] ) documents
-                    .toArray(new DocumentBlock[ 0 ]), _testdata_size);
-
-        for (int j = 1; j <= _testdata_size; j += 38)
-        {
-            byte[] buffer = new byte[ j ];
-            int    offset = 0;
-
-            for (int k = 0; k < (_testdata_size / j); k++)
-            {
-                SmallDocumentBlock.read(blocks, buffer, offset);
-                for (int n = 0; n < buffer.length; n++)
-                {
-                    assertEquals("checking byte " + (k * j) + n,
-                                 _testdata[ (k * j) + n ], buffer[ n ]);
-                }
-                offset += j;
-            }
-        }
-    }
-
     /**
      * test fill
-     *
-     * @exception IOException
      */
-
     public void testFill()
         throws IOException
     {
@@ -294,17 +224,4 @@ public class TestSmallDocumentBlock
             }
         }
     }
-
-    /**
-     * main method to run the unit tests
-     *
-     * @param ignored_args
-     */
-
-    public static void main(String [] ignored_args)
-    {
-        System.out.println(
-            "Testing org.apache.poi.poifs.storage.SmallDocumentBlock");
-        junit.textui.TestRunner.run(TestSmallDocumentBlock.class);
-    }
 }
index bb6d3820479dd8c5cddc6d4cbca0d87177db56e7..6364c8c3545ac1c6d11bdad820b641a0df118508 100755 (executable)
@@ -27,12 +27,11 @@ import junit.framework.TestSuite;
 public final class AllPOIUtilTests {
 
     public static Test suite() {
-        TestSuite result = new TestSuite("Tests for org.apache.poi.util");
+        TestSuite result = new TestSuite(AllPOIUtilTests.class.getName());
         result.addTestSuite(TestArrayUtil.class);
         result.addTestSuite(TestBinaryTree.class);
         result.addTestSuite(TestBitField.class);
         result.addTestSuite(TestByteField.class);
-        result.addTestSuite(TestDoubleList2d.class);
         result.addTestSuite(TestHexDump.class);
         result.addTestSuite(TestIntegerField.class);
         result.addTestSuite(TestIntList.class);
diff --git a/src/testcases/org/apache/poi/util/TestDoubleList2d.java b/src/testcases/org/apache/poi/util/TestDoubleList2d.java
deleted file mode 100644 (file)
index b85e7eb..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-* 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.util;
-
-import junit.framework.TestCase;
-
-/**
- * @version $Id$
- */
-public class TestDoubleList2d
-        extends TestCase
-{
-    public void testAccess()
-            throws Exception
-    {
-        DoubleList2d array = new DoubleList2d();
-        assertEquals( 0, array.get( 0, 0 ), 0.00001 );
-        assertEquals( 0, array.get( 1, 1 ), 0.00001 );
-        assertEquals( 0, array.get( 100, 100 ), 0.00001 );
-        array.set( 100, 100, 999 );
-        assertEquals( 999, array.get( 100, 100 ), 0.00001 );
-        assertEquals( 0, array.get( 0, 0 ), 0.00001 );
-        array.set( 0, 0, 999 );
-        assertEquals( 999, array.get( 0, 0 ), 0.00001 );
-
-        try
-        {
-            array.get( -1, -1 );
-            fail();
-        }
-        catch ( ArrayIndexOutOfBoundsException e )
-        {
-            // pass
-        }
-    }
-}
index 0ffcd189daceaf7794c70ec8ca82329a2d1d0532..bba8a653e36dd701ee7d34b380b28203b5a8704e 100644 (file)
@@ -97,13 +97,13 @@ public final class TestLittleEndian extends TestCase {
      * test the getDouble() method
      */
     public void testGetDouble() {
-        assertEquals(_doubles[0], LittleEndian.getDouble(_double_array), 0.000001 );
+        assertEquals(_doubles[0], LittleEndian.getDouble(_double_array, 0), 0.000001 );
         assertEquals(_doubles[1], LittleEndian.getDouble( _double_array, LittleEndian.DOUBLE_SIZE), 0.000001);
-        assertTrue(Double.isNaN(LittleEndian.getDouble(_nan_double_array)));
+        assertTrue(Double.isNaN(LittleEndian.getDouble(_nan_double_array, 0)));
 
-        double nan = LittleEndian.getDouble(_nan_double_array);
+        double nan = LittleEndian.getDouble(_nan_double_array, 0);
         byte[] data = new byte[8];
-        LittleEndian.putDouble(data, nan);
+        LittleEndian.putDouble(data, 0, nan);
         for ( int i = 0; i < data.length; i++ ) {
             assertEquals(data[i], _nan_double_array[i]);
         }
@@ -144,7 +144,7 @@ public final class TestLittleEndian extends TestCase {
             (byte) 0x02,
         };
 
-        assertEquals(0xFFFFFFFFFFFFFF01L, LittleEndian.getLong(testdata));
+        assertEquals(0xFFFFFFFFFFFFFF01L, LittleEndian.getLong(testdata, 0));
         assertEquals(0x02FFFFFFFFFFFFFFL, LittleEndian.getLong(testdata, 1));
     }
 
@@ -194,7 +194,7 @@ public final class TestLittleEndian extends TestCase {
     public void testPutDouble() {
         byte[] received = new byte[ LittleEndian.DOUBLE_SIZE + 1 ];
 
-        LittleEndian.putDouble(received, _doubles[0]);
+        LittleEndian.putDouble(received, 0, _doubles[0]);
         assertTrue(compareByteArrays(received, _double_array, 0, LittleEndian.DOUBLE_SIZE));
         LittleEndian.putDouble(received, 1, _doubles[1]);
         byte[] expected = new byte[ LittleEndian.DOUBLE_SIZE + 1 ];
@@ -224,7 +224,7 @@ public final class TestLittleEndian extends TestCase {
 
         long testdata0 = 0xFFFFFFFFFFFFFF01L;
         long testdata1 = 0x02FFFFFFFFFFFFFFL;
-        LittleEndian.putLong(received, testdata0);
+        LittleEndian.putLong(received, 0, testdata0);
         assertTrue(compareByteArrays(received, expected, 0, LittleEndian.LONG_SIZE));
         LittleEndian.putLong(received, 1, testdata1);
         assertTrue(compareByteArrays(received, expected, 1, LittleEndian.LONG_SIZE));
index b22439cd09526ac13e1aa7ae288142c398367b09..f1b5cfd954a79d2201725b855efb2a1841ea3310 100644 (file)
@@ -42,43 +42,7 @@ public class TestStringUtil
         super( name );
     }
 
-    /**
-     * test simple form of getFromUnicode
-     */
-    public void testSimpleGetFromUnicode()
-    {
-        byte[] test_data = new byte[32];
-        int index = 0;
-
-        for ( int k = 0; k < 16; k++ )
-        {
-            test_data[index++] = (byte) 0;
-            test_data[index++] = (byte) ( 'a' + k );
-        }
-
-        assertEquals( "abcdefghijklmnop",
-                StringUtil.getFromUnicodeBE( test_data ) );
-    }
-
-    /**
-     * test simple form of getFromUnicode with symbols with code below and more 127
-     */
-    public void testGetFromUnicodeSymbolsWithCodesMoreThan127()
-    {
-        byte[] test_data = new byte[]{0x04, 0x22,
-                                      0x04, 0x35,
-                                      0x04, 0x41,
-                                      0x04, 0x42,
-                                      0x00, 0x20,
-                                      0x00, 0x74,
-                                      0x00, 0x65,
-                                      0x00, 0x73,
-                                      0x00, 0x74,
-        };
 
-        assertEquals( "\u0422\u0435\u0441\u0442 test",
-                StringUtil.getFromUnicodeBE( test_data ) );
-    }
 
     /**
      * test getFromUnicodeHigh for symbols with code below and more 127
@@ -101,62 +65,7 @@ public class TestStringUtil
                 StringUtil.getFromUnicodeLE( test_data ) );
     }
 
-    /**
-     * Test more complex form of getFromUnicode
-     */
-    public void testComplexGetFromUnicode()
-    {
-        byte[] test_data = new byte[32];
-        int index = 0;
-        for ( int k = 0; k < 16; k++ )
-        {
-            test_data[index++] = (byte) 0;
-            test_data[index++] = (byte) ( 'a' + k );
-        }
-        assertEquals( "abcdefghijklmno",
-                StringUtil.getFromUnicodeBE( test_data, 0, 15 ) );
-        assertEquals( "bcdefghijklmnop",
-                StringUtil.getFromUnicodeBE( test_data, 2, 15 ) );
-        try
-        {
-            StringUtil.getFromUnicodeBE( test_data, -1, 16 );
-            fail( "Should have caught ArrayIndexOutOfBoundsException" );
-        }
-        catch ( ArrayIndexOutOfBoundsException ignored )
-        {
-            // as expected
-        }
 
-        try
-        {
-            StringUtil.getFromUnicodeBE( test_data, 32, 16 );
-            fail( "Should have caught ArrayIndexOutOfBoundsException" );
-        }
-        catch ( ArrayIndexOutOfBoundsException ignored )
-        {
-            // as expected
-        }
-
-        try
-        {
-            StringUtil.getFromUnicodeBE( test_data, 1, 16 );
-            fail( "Should have caught IllegalArgumentException" );
-        }
-        catch ( IllegalArgumentException ignored )
-        {
-            // as expected
-        }
-
-        try
-        {
-            StringUtil.getFromUnicodeBE( test_data, 1, -1 );
-            fail( "Should have caught IllegalArgumentException" );
-        }
-        catch ( IllegalArgumentException ignored )
-        {
-            // as expected
-        }
-    }
 
     /**
      * Test putCompressedUnicode