You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by jo...@apache.org on 2008/10/05 06:43:48 UTC

svn commit: r701747 - in /poi/trunk/src: java/org/apache/poi/hssf/record/RecordInputStream.java java/org/apache/poi/hssf/record/SeriesListRecord.java java/org/apache/poi/util/LittleEndian.java testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java

Author: josh
Date: Sat Oct  4 21:43:48 2008
New Revision: 701747

URL: http://svn.apache.org/viewvc?rev=701747&view=rev
Log:
Better bounds checking in RecordInputStream. Removed rarely used methods readShortArray and putShortArray

Modified:
    poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java
    poi/trunk/src/java/org/apache/poi/hssf/record/SeriesListRecord.java
    poi/trunk/src/java/org/apache/poi/util/LittleEndian.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java?rev=701747&r1=701746&r2=701747&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/RecordInputStream.java Sat Oct  4 21:43:48 2008
@@ -33,7 +33,7 @@
   /** 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;
-  
+
   private InputStream in;
   protected short currentSid;
   protected short currentLength = -1;
@@ -42,34 +42,34 @@
   protected byte[] data = new byte[MAX_RECORD_DATA_SIZE];
   protected short recordOffset;
   protected long pos;
-  
+
   private boolean autoContinue = true;
 
-  public RecordInputStream(InputStream in) throws RecordFormatException  {
+  public RecordInputStream(InputStream in) throws RecordFormatException {
     this.in = in;
     try {
       nextSid = LittleEndian.readShort(in);
-      //Dont increment the pos just yet (technically we are at the start of
-      //the record stream until nextRecord is called).      
+      //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();
-
-    byte result = data[recordOffset];
-    recordOffset += 1;
-    pos += 1;
-    return result;    
-  }
-  
+
+	/** 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;
+	}
+
   public short getSid() {
     return currentSid;
   }
-  
+
   public short getLength() {
     return currentLength;
   }
@@ -85,12 +85,11 @@
   public boolean hasNextRecord() {
     return nextSid != INVALID_SID_VALUE;
   }
-  
+
   /** 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));
@@ -100,7 +99,7 @@
     autoContinue = true;
     try {
       recordOffset = 0;
-      currentLength = LittleEndian.readShort(in);     
+      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;
@@ -113,138 +112,124 @@
               // ex45582-22397.xls has one extra byte after the last record
               // Excel reads that file OK
           }
-          nextSid = INVALID_SID_VALUE;  
+          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);
     }
   }
-  
+
   public void setAutoContinue(boolean enable) {
-    this.autoContinue = enable;    
+    this.autoContinue = enable;
   }
-  
+
   public boolean getAutoContinue() {
     return autoContinue;
   }
-  
-  protected void checkRecordPosition() {
-    if (remaining() <= 0) {
-      if (isContinueNext() && autoContinue) {
-        nextRecord();
-      }
-      else throw new ArrayIndexOutOfBoundsException();
-    }    
-  }
-  
-  /**
-   * Reads an 8 bit, signed value
-   */
-  public byte readByte() {
-    checkRecordPosition();
-    
-    byte result = data[recordOffset];
-    recordOffset += 1;
-    pos += 1;
-    return result;
-  }
-  
-  /**
-   * Reads a 16 bit, signed value
-   */
-  public short readShort() {
-    checkRecordPosition();
-    
-    short result = LittleEndian.getShort(data, recordOffset);
-    recordOffset += LittleEndian.SHORT_SIZE;
-    pos += LittleEndian.SHORT_SIZE;
-    return result;
-  }
 
-  public int readInt() {
-    checkRecordPosition();
-    
-    int result = LittleEndian.getInt(data, recordOffset);
-    recordOffset += LittleEndian.INT_SIZE;
-    pos += LittleEndian.INT_SIZE;
-    return result;
-  }
+	private void checkRecordPosition(int requiredByteCount) {
 
-  public long readLong() {
-    checkRecordPosition();    
-    
-    long result = LittleEndian.getLong(data, recordOffset);
-    recordOffset += LittleEndian.LONG_SIZE;
-    pos += LittleEndian.LONG_SIZE;
-    return result;
-  }
+		if (remaining() < requiredByteCount) {
+			if (isContinueNext() && autoContinue) {
+				nextRecord();
+			} else {
+			   throw new ArrayIndexOutOfBoundsException();
+			}
+		}
+	}
+
+	/**
+	 * Reads an 8 bit, signed value
+	 */
+	public byte readByte() {
+		checkRecordPosition(LittleEndian.BYTE_SIZE);
+
+		byte result = data[recordOffset];
+		recordOffset += LittleEndian.BYTE_SIZE;
+		pos += LittleEndian.BYTE_SIZE;
+		return result;
+	}
+
+	/**
+	 * Reads a 16 bit, signed value
+	 */
+	public short readShort() {
+		checkRecordPosition(LittleEndian.SHORT_SIZE);
+
+		short result = LittleEndian.getShort(data, recordOffset);
+		recordOffset += LittleEndian.SHORT_SIZE;
+		pos += LittleEndian.SHORT_SIZE;
+		return result;
+	}
+
+	public int readInt() {
+		checkRecordPosition(LittleEndian.INT_SIZE);
+
+		int result = LittleEndian.getInt(data, recordOffset);
+		recordOffset += LittleEndian.INT_SIZE;
+		pos += LittleEndian.INT_SIZE;
+		return result;
+	}
+
+	public long readLong() {
+		checkRecordPosition(LittleEndian.LONG_SIZE);
+
+		long result = LittleEndian.getLong(data, recordOffset);
+		recordOffset += LittleEndian.LONG_SIZE;
+		pos += LittleEndian.LONG_SIZE;
+		return result;
+	}
+
+	/**
+	 * Reads an 8 bit, unsigned value
+	 */
+	public short readUByte() {
+		return (short) (readByte() & 0x00FF);
+	}
+
+	/**
+	 * Reads a 16 bit, unsigned value.
+	 * @return
+	 */
+	public int readUShort() {
+		checkRecordPosition(LittleEndian.SHORT_SIZE);
+
+		int result = LittleEndian.getUShort(data, recordOffset);
+		recordOffset += LittleEndian.SHORT_SIZE;
+		pos += LittleEndian.SHORT_SIZE;
+		return result;
+	}
+
+	public double readDouble() {
+		checkRecordPosition(LittleEndian.DOUBLE_SIZE);
+		long valueLongBits = LittleEndian.getLong(data, recordOffset);
+		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;
+	}
 
   /**
-   * Reads an 8 bit, unsigned value
-   */
-  public short readUByte() {
-      short s = readByte();
-      if(s < 0) {
-          s += 256;
-      }
-      return s;
-  }
-
-  /**
-   * Reads a 16 bit,un- signed value.
-   * @return
-   */
-  public int readUShort() {
-    checkRecordPosition();    
-    
-    int result = LittleEndian.getUShort(data, recordOffset);
-    recordOffset += LittleEndian.SHORT_SIZE;
-    pos += LittleEndian.SHORT_SIZE;
-    return result;
-  }
-
-  public double readDouble() {
-    checkRecordPosition();
-    long valueLongBits = LittleEndian.getLong(data, recordOffset);
-    double result = Double.longBitsToDouble(valueLongBits);
-    if (Double.isNaN(result)) {
-      throw new RuntimeException("Did not expect to read NaN");
-    }
-    recordOffset += LittleEndian.DOUBLE_SIZE;
-    pos += LittleEndian.DOUBLE_SIZE;
-    return result;
-  }
-
-  
-  public short[] readShortArray() {
-    checkRecordPosition();
-    
-    short[] arr = LittleEndian.getShortArray(data, recordOffset);
-    final int size = (2 * (arr.length +1));
-    recordOffset += size;
-    pos += size;
-    
-    return arr;
-  }
-  
-  /**     
-   *  given a byte array of 16-bit unicode characters, compress to 8-bit and     
-   *  return a string     
-   *     
-   * { 0x16, 0x00 } -0x16     
-   *      
+   *  given a byte array of 16-bit unicode characters, compress to 8-bit and
+   *  return a string
+   *
+   * { 0x16, 0x00 } -0x16
+   *
    * @param length the length of the final string
    * @return                                     the converted string
    * @exception  IllegalArgumentException        if len is too large (i.e.,
-   *      there is not enough data in string to create a String of that     
-   *      length)     
-   */  
+   *      there is not enough data in string to create a String of that
+   *      length)
+   */
   public String readUnicodeLEString(int length) {
     if ((length < 0) || (((remaining() / 2) < length) && !isContinueNext())) {
             throw new IllegalArgumentException("Illegal length - asked for " + length + " but only " + (remaining()/2) + " left!");
@@ -258,11 +243,11 @@
         if(compressByte != 1) throw new IllegalArgumentException("compressByte in continue records must be 1 while reading unicode LE string");
       }
       char ch = (char)readShort();
-      buf.append(ch); 
+      buf.append(ch);
     }
     return buf.toString();
   }
-    
+
   public String readCompressedUnicode(int length) {
     if ((length < 0) || ((remaining() < length) && !isContinueNext())) {
             throw new IllegalArgumentException("Illegal length " + length);
@@ -277,23 +262,23 @@
       }
       byte b = readByte();
       char ch = (char)(0x00FF & b); // avoid sex
-      buf.append(ch); 
+      buf.append(ch);
     }
-    return buf.toString();    
+    return buf.toString();
   }
-  
+
   /** Returns an excel style unicode string from the bytes reminaing in the record.
    * <i>Note:</i> Unicode strings differ from <b>normal</b> strings due to the addition of
    * formatting information.
-   * 
+   *
    * @return The unicode string representation of the remaining bytes.
    */
   public UnicodeString readUnicodeString() {
     return new UnicodeString(this);
   }
-  
+
   /** Returns the remaining bytes for the current record.
-   * 
+   *
    * @return The remaining bytes of the current record.
    */
   public byte[] readRemainder() {
@@ -304,39 +289,39 @@
     pos += size;
     return result;
   }
-  
+
   /** Reads all byte data for the current record, including any
    *  that overlaps into any following continue records.
-   * 
+   *
    *  @deprecated Best to write a input stream that wraps this one where there is
    *  special sub record that may overlap continue records.
-   */  
+   */
   public byte[] readAllContinuedRemainder() {
     //Using a ByteArrayOutputStream is just an easy way to get a
     //growable array of the data.
     ByteArrayOutputStream out = new ByteArrayOutputStream(2*MAX_RECORD_DATA_SIZE);
 
     while (isContinueNext()) {
-      byte[] b = readRemainder();      
+      byte[] b = readRemainder();
       out.write(b, 0, b.length);
       nextRecord();
     }
-    byte[] b = readRemainder();      
-    out.write(b, 0, b.length);    
-    
+    byte[] b = readRemainder();
+    out.write(b, 0, b.length);
+
     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);
   }
 
-  /** Returns true iif a Continue record is next in the excel stream 
-   * 
+  /** Returns true iif a Continue record is next in the excel stream
+   *
    * @return True when a ContinueRecord is next.
    */
   public boolean isContinueNext() {

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/SeriesListRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/SeriesListRecord.java?rev=701747&r1=701746&r2=701747&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/SeriesListRecord.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/SeriesListRecord.java Sat Oct  4 21:43:48 2008
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -15,66 +14,66 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 ==================================================================== */
-        
 
 package org.apache.poi.hssf.record;
 
-
-
-import org.apache.poi.util.*;
+import org.apache.poi.util.LittleEndian;
 
 /**
- * The series list record defines the series displayed as an overlay to the main chart record.
- * NOTE: This source is automatically generated please do not modify this file.  Either subclass or
- *       remove the record in src/records/definitions.
-
+ * 
+ * The series list record defines the series displayed as an overlay to the main chart record.<br/>
+ * TODO - does this record (0x1016) really exist.  It doesn't seem to be referenced in either the OOO or MS doc
+ * 
  * @author Glen Stampoultzis (glens at apache.org)
  */
-public class SeriesListRecord
-    extends Record
-{
-    public final static short      sid                             = 0x1016;
+public final class SeriesListRecord extends Record {
+    public final static short sid = 0x1016;
     private  short[]    field_1_seriesNumbers;
 
-
-    public SeriesListRecord()
-    {
-
+    public SeriesListRecord(short[] seriesNumbers) {
+    	field_1_seriesNumbers = seriesNumbers;
     }
 
-    public SeriesListRecord(RecordInputStream in)
-    {
-        field_1_seriesNumbers          = in.readShortArray();
+    public SeriesListRecord(RecordInputStream in) {
+    	int nItems = in.readUShort();
+    	short[] ss = new short[nItems];
+    	for (int i = 0; i < nItems; i++) {
+			ss[i] = in.readShort();
+			
+		}
+        field_1_seriesNumbers = ss;
     }
 
-    public String toString()
-    {
+    public String toString() {
         StringBuffer buffer = new StringBuffer();
 
         buffer.append("[SERIESLIST]\n");
-        buffer.append("    .seriesNumbers        = ")
-            .append(" (").append( getSeriesNumbers() ).append(" )");
-        buffer.append(System.getProperty("line.separator")); 
+        buffer.append("    .seriesNumbers= ").append(" (").append( getSeriesNumbers() ).append(" )");
+        buffer.append("\n"); 
 
         buffer.append("[/SERIESLIST]\n");
         return buffer.toString();
     }
 
-    public int serialize(int offset, byte[] data)
-    {
-        int pos = 0;
+    public int serialize(int offset, byte[] data) {
 
-        LittleEndian.putShort(data, 0 + offset, sid);
-        LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));
+        int nItems = field_1_seriesNumbers.length;
+        int dataSize = 2 + 2 * nItems;
+    	
+        LittleEndian.putUShort(data, 0 + offset, sid);
+        LittleEndian.putUShort(data, 2 + offset, dataSize);
 
-        LittleEndian.putShortArray(data, 4 + offset + pos, field_1_seriesNumbers);
+        LittleEndian.putUShort(data, 4 + offset, nItems);
+        
+        int pos = offset + 6;
+    	for (int i = 0; i < nItems; i++) {
+    		LittleEndian.putUShort(data, pos, field_1_seriesNumbers[i]);
+    		pos += 2;
+    	}
 
-        return getRecordSize();
+        return 4 + dataSize;
     }
 
-    /**
-     * Size of record (exluding 4 byte header)
-     */
     public int getRecordSize()
     {
         return 4  + field_1_seriesNumbers.length * 2 + 2;
@@ -86,34 +85,23 @@
     }
 
     public Object clone() {
-        SeriesListRecord rec = new SeriesListRecord();
-    
-        rec.field_1_seriesNumbers = field_1_seriesNumbers;
-        return rec;
+        return new SeriesListRecord((short[]) field_1_seriesNumbers.clone());
     }
 
-
-
-
     /**
      * Get the series numbers field for the SeriesList record.
      */
-    public short[] getSeriesNumbers()
-    {
+    public short[] getSeriesNumbers() {
         return field_1_seriesNumbers;
     }
 
     /**
      * Set the series numbers field for the SeriesList record.
      */
-    public void setSeriesNumbers(short[] field_1_seriesNumbers)
-    {
+    public void setSeriesNumbers(short[] field_1_seriesNumbers) {
         this.field_1_seriesNumbers = field_1_seriesNumbers;
     }
-
-
-}  // END OF CLASS
-
+}
 
 
 

Modified: poi/trunk/src/java/org/apache/poi/util/LittleEndian.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/util/LittleEndian.java?rev=701747&r1=701746&r2=701747&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/util/LittleEndian.java (original)
+++ poi/trunk/src/java/org/apache/poi/util/LittleEndian.java Sat Oct  4 21:43:48 2008
@@ -251,20 +251,6 @@
     }
 
     /**
-     *  put a array of shorts into a byte array
-     *
-     *@param  data    the byte array
-     *@param  offset  a starting offset into the byte array
-     *@param  value   the short array
-     */
-    public static void putShortArray(final byte[] data, final int offset, final short[] value) {
-        putNumber(data, offset, value.length, SHORT_SIZE);
-        for (int i = 0; i < value.length; i++) {
-            putNumber(data, offset + 2 + (i * 2), value[i], SHORT_SIZE);
-        }
-    }
-
-    /**
      * put an unsigned short value into a byte array
      *
      * @param data the byte array

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java?rev=701747&r1=701746&r2=701747&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/TestSeriesListRecord.java Sat Oct  4 21:43:48 2008
@@ -29,7 +29,7 @@
  * @author Glen Stampoultzis (glens at apache.org)
  */
 public final class TestSeriesListRecord extends TestCase {
-    byte[] data = new byte[] {
+    private static final byte[] data = {
         (byte)0x02,(byte)0x00,(byte)0x01,(byte)0x20,(byte)0xff,(byte)0xf0
     };
 
@@ -43,10 +43,8 @@
         assertEquals( 4 + 6, record.getRecordSize() );
     }
 
-    public void testStore()
-    {
-        SeriesListRecord record = new SeriesListRecord();
-        record.setSeriesNumbers( new short[] { (short)0x2001, (short)0xf0ff } );
+    public void testStore() {
+        SeriesListRecord record = new SeriesListRecord(new short[] { (short)0x2001, (short)0xf0ff } );
 
         byte [] recordBytes = record.serialize();
         assertEquals(recordBytes.length - 4, data.length);



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