Browse Source

Added image support for POI. See the quick guide for details. Sponsored through superlink software.


git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353660 13f79535-47bb-0310-9956-ffa450edef68
tags/BEFORE_RICHTEXT
Glen Stampoultzis 19 years ago
parent
commit
585f86a986
46 changed files with 1497 additions and 495 deletions
  1. 6
    6
      build.xml
  2. 43
    13
      src/documentation/content/xdocs/hssf/quick-guide.xml
  3. 1
    0
      src/documentation/content/xdocs/status.xml
  4. 50
    3
      src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawing.java
  5. 11
    1
      src/java/org/apache/poi/ddf/DefaultEscherRecordFactory.java
  6. 52
    11
      src/java/org/apache/poi/ddf/EscherBSERecord.java
  7. 25
    333
      src/java/org/apache/poi/ddf/EscherBlipRecord.java
  8. 435
    0
      src/java/org/apache/poi/ddf/EscherBlipWMFRecord.java
  9. 2
    2
      src/java/org/apache/poi/ddf/EscherBoolProperty.java
  10. 1
    1
      src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
  11. 1
    1
      src/java/org/apache/poi/ddf/EscherClientDataRecord.java
  12. 7
    4
      src/java/org/apache/poi/ddf/EscherDggRecord.java
  13. 1
    1
      src/java/org/apache/poi/ddf/EscherProperty.java
  14. 7
    11
      src/java/org/apache/poi/ddf/EscherPropertyFactory.java
  15. 1
    1
      src/java/org/apache/poi/ddf/EscherRGBProperty.java
  16. 1
    0
      src/java/org/apache/poi/ddf/EscherSimpleProperty.java
  17. 43
    16
      src/java/org/apache/poi/hssf/dev/BiffViewer.java
  18. 4
    1
      src/java/org/apache/poi/hssf/model/AbstractShape.java
  19. 1
    1
      src/java/org/apache/poi/hssf/model/ConvertAnchor.java
  20. 25
    5
      src/java/org/apache/poi/hssf/model/Sheet.java
  21. 74
    14
      src/java/org/apache/poi/hssf/model/Workbook.java
  22. 63
    11
      src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java
  23. 100
    0
      src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java
  24. 8
    0
      src/java/org/apache/poi/hssf/record/DrawingRecord.java
  25. 8
    5
      src/java/org/apache/poi/hssf/record/EscherAggregate.java
  26. 8
    0
      src/java/org/apache/poi/hssf/record/ObjRecord.java
  27. 16
    2
      src/java/org/apache/poi/hssf/record/RecordFactory.java
  28. 4
    3
      src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java
  29. 1
    1
      src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java
  30. 22
    2
      src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java
  31. 17
    0
      src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
  32. 7
    4
      src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
  33. 3
    1
      src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java
  34. 88
    6
      src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
  35. 11
    4
      src/java/org/apache/poi/util/DrawingDump.java
  36. 1
    1
      src/java/org/apache/poi/util/HexDump.java
  37. 2
    1
      src/testcases/org/apache/poi/ddf/TestEscherBSERecord.java
  38. 7
    7
      src/testcases/org/apache/poi/ddf/TestEscherBlipWMFRecord.java
  39. 1
    1
      src/testcases/org/apache/poi/ddf/TestEscherBoolProperty.java
  40. 1
    1
      src/testcases/org/apache/poi/ddf/TestEscherClientDataRecord.java
  41. 1
    1
      src/testcases/org/apache/poi/ddf/TestEscherOptRecord.java
  42. 232
    6
      src/testcases/org/apache/poi/hssf/model/TestSheet.java
  43. 91
    0
      src/testcases/org/apache/poi/hssf/record/TestDrawingGroupRecord.java
  44. 6
    7
      src/testcases/org/apache/poi/hssf/record/TestEscherAggregate.java
  45. 4
    2
      src/testcases/org/apache/poi/util/TestHexDump.java
  46. 4
    4
      src/testcases/org/apache/poi/util/TestLittleEndian.java

+ 6
- 6
build.xml View File

@@ -256,10 +256,10 @@
<copy todir="${main.output.dir}">
<fileset dir="${main.resource1.dir}"/>
</copy>
<javac srcdir="${main.src}" destdir="${main.output.dir}" debug="on">
<javac srcdir="${main.src}" destdir="${main.output.dir}" debug="on" fork="yes" includeAntRuntime="no" failonerror="true">
<classpath refid="main.classpath"/>
</javac>
<javac srcdir="${main.src.test}" destdir="${main.output.test.dir}" debug="on">
<javac srcdir="${main.src.test}" destdir="${main.output.test.dir}" debug="on" fork="yes" includeAntRuntime="no" failonerror="true">
<classpath>
<path refid="main.classpath"/>
<pathelement location="${main.output.dir}"/>
@@ -269,10 +269,10 @@
</target>

<target name="compile-scratchpad" depends="init">
<javac srcdir="${scratchpad.src}" destdir="${scratchpad.output.dir}" debug="on">
<javac srcdir="${scratchpad.src}" destdir="${scratchpad.output.dir}" debug="on" fork="yes" includeAntRuntime="no" failonerror="true">
<classpath refid="scratchpad.classpath"/>
</javac>
<javac srcdir="${scratchpad.src.test}" destdir="${scratchpad.output.test.dir}" debug="on">
<javac srcdir="${scratchpad.src.test}" destdir="${scratchpad.output.test.dir}" debug="on" fork="yes" includeAntRuntime="no" failonerror="true">
<classpath>
<path refid="scratchpad.classpath"/>
<pathelement location="${scratchpad.output.dir}"/>
@@ -282,10 +282,10 @@
</target>

<target name="compile-contrib" depends="init">
<javac srcdir="${contrib.src}" destdir="${contrib.output.dir}" debug="on">
<javac srcdir="${contrib.src}" destdir="${contrib.output.dir}" debug="on" fork="yes" includeAntRuntime="no" failonerror="true">
<classpath refid="contrib.classpath"/>
</javac>
<javac srcdir="${contrib.src.test}" destdir="${contrib.output.test.dir}" debug="on">
<javac srcdir="${contrib.src.test}" destdir="${contrib.output.test.dir}" debug="on" fork="yes" includeAntRuntime="no" failonerror="true">
<classpath>
<path refid="contrib.classpath"/>
<pathelement location="${contrib.output.dir}"/>

+ 43
- 13
src/documentation/content/xdocs/hssf/quick-guide.xml View File

@@ -31,20 +31,21 @@
<li><link href="#CustomColors">Custom colors</link></li>
<li><link href="#ReadWriteWorkbook">Reading and writing</link></li>
<li><link href="#NewLinesInCells">Use newlines in cells.</link></li>
<li><link href="#DataFormats">Create user defined data formats.</link></li>
<li><link href="#DataFormats">Create user defined data formats</link></li>
<li><link href="#FitTo">Fit Sheet to One Page</link></li>
<li><link href="#PrintArea2">Set print area for a sheet.</link></li>
<li><link href="#FooterPageNumbers">Set page numbers on the footer of a sheet.</link></li>
<li><link href="#ShiftRows">Shift rows.</link></li>
<li><link href="#SelectSheet">Set a sheet as selected.</link></li>
<li><link href="#Zoom">Set the zoom magnification for a sheet.</link></li>
<li><link href="#Splits">Create split and freeze panes.</link></li>
<li><link href="#Repeating">Repeating rows and columns.</link></li>
<li><link href="#HeaderFooter">Headers and Footers.</link></li>
<li><link href="#DrawingShapes">Drawing Shapes.</link></li>
<li><link href="#StylingShapes">Styling Shapes.</link></li>
<li><link href="#Graphics2d">Shapes and Graphics2d.</link></li>
<li><link href="#Outlining">Outlining.</link></li>
<li><link href="#PrintArea2">Set print area for a sheet</link></li>
<li><link href="#FooterPageNumbers">Set page numbers on the footer of a sheet</link></li>
<li><link href="#ShiftRows">Shift rows</link></li>
<li><link href="#SelectSheet">Set a sheet as selected</link></li>
<li><link href="#Zoom">Set the zoom magnification for a sheet</link></li>
<li><link href="#Splits">Create split and freeze panes</link></li>
<li><link href="#Repeating">Repeating rows and columns</link></li>
<li><link href="#HeaderFooter">Headers and Footers</link></li>
<li><link href="#DrawingShapes">Drawing Shapes</link></li>
<li><link href="#StylingShapes">Styling Shapes</link></li>
<li><link href="#Graphics2d">Shapes and Graphics2d</link></li>
<li><link href="#Outlining">Outlining</link></li>
<li><link href="#Images">Images</link></li>
</ul>
</section>
<section><title>Features</title>
@@ -940,5 +941,34 @@
</section>
</section>
</section>
<anchor id="Images"/>
<section>
<title>Images</title>
<p>
Images are part of the drawing support. To add an image just
call <code>createPicture()</code> on the drawing patriarch.
At the time of writing the following types are supported:
</p>
<ul>
<li>PNG</li>
<li>JPG</li>
<li>DIB</li>
</ul>
<p>
It is not currently possible to read existing images and it
should be noted that any existing drawings may be erased
once you add a image to a sheet.
</p>
<source>
// Create the drawing patriarch. This is the top level container for
// all shapes. This will clear out any existing shapes for that sheet.
HSSFPatriarch patriarch = sheet5.createDrawingPatriarch();

HSSFClientAnchor anchor;
anchor = new HSSFClientAnchor(0,0,0,255,(short)2,2,(short)4,7);
anchor.setAnchorType( 2 );
patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4.png", wb ));
</source>
</section>
</body>
</document>

+ 1
- 0
src/documentation/content/xdocs/status.xml View File

@@ -14,6 +14,7 @@

<release version="unreleased" date="???">
<action dev="POI-DEVELOPERS" type="fix" context="All">Bugzilla Bug 29976 [PATCH] HSSF hyperlink formula size problem</action>
<action dev="POI-DEVELOPERS" type="add" context="All">Image writing support</action>
</release>
<release version="2.5.1-FINAL" date="29 Feburary 2004">

+ 50
- 3
src/examples/src/org/apache/poi/hssf/usermodel/examples/OfficeDrawing.java View File

@@ -19,9 +19,7 @@ package org.apache.poi.hssf.usermodel.examples;

import org.apache.poi.hssf.usermodel.*;

import java.io.IOException;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.*;

/**
* Demonstrates how to use the office drawing capabilities of POI.
@@ -39,12 +37,14 @@ public class OfficeDrawing
HSSFSheet sheet2 = wb.createSheet("second sheet");
HSSFSheet sheet3 = wb.createSheet("third sheet");
HSSFSheet sheet4 = wb.createSheet("fourth sheet");
HSSFSheet sheet5 = wb.createSheet("fifth sheet");

// Draw stuff in them
drawSheet1( sheet1 );
drawSheet2( sheet2 );
drawSheet3( sheet3 );
drawSheet4( sheet4, wb );
drawSheet5( sheet5, wb );

// Write the file out.
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
@@ -143,6 +143,53 @@ public class OfficeDrawing
textbox3.setNoFill(true); // make it transparent
}

private static void drawSheet5( HSSFSheet sheet5, HSSFWorkbook wb ) throws IOException
{

// Create the drawing patriarch. This is the top level container for
// all shapes. This will clear out any existing shapes for that sheet.
HSSFPatriarch patriarch = sheet5.createDrawingPatriarch();

HSSFClientAnchor anchor;
anchor = new HSSFClientAnchor(0,0,0,255,(short)2,2,(short)4,7);
anchor.setAnchorType( 2 );
patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4.png", wb ));

anchor = new HSSFClientAnchor(0,0,0,255,(short)4,2,(short)5,7);
anchor.setAnchorType( 2 );
patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4edited.png", wb ));

anchor = new HSSFClientAnchor(0,0,1023,255,(short)6,2,(short)8,7);
anchor.setAnchorType( 2 );
HSSFPicture picture = patriarch.createPicture(anchor, loadPicture( "src/resources/logos/logoKarmokar4s.png", wb ));
picture.setLineStyle( picture.LINESTYLE_DASHDOTGEL );

}

private static int loadPicture( String path, HSSFWorkbook wb ) throws IOException
{
int pictureIndex;
FileInputStream fis = null;
ByteArrayOutputStream bos = null;
try
{
fis = new FileInputStream( path);
bos = new ByteArrayOutputStream( );
int c;
while ( (c = fis.read()) != -1)
bos.write( c );
pictureIndex = wb.addPicture( bos.toByteArray(), HSSFWorkbook.PICTURE_TYPE_PNG );
}
finally
{
if (fis != null)
fis.close();
if (bos != null)
bos.close();
}
return pictureIndex;
}

private static void drawOval( HSSFPatriarch patriarch )
{
// Create an oval and style to taste.

+ 11
- 1
src/java/org/apache/poi/ddf/DefaultEscherRecordFactory.java View File

@@ -66,7 +66,17 @@ public class DefaultEscherRecordFactory
}
else if ( header.getRecordId() >= EscherBlipRecord.RECORD_ID_START && header.getRecordId() <= EscherBlipRecord.RECORD_ID_END )
{
EscherBlipRecord r = new EscherBlipRecord();
EscherBlipRecord r;
if (header.getRecordId() == EscherBitmapBlip.RECORD_ID_DIB ||
header.getRecordId() == EscherBitmapBlip.RECORD_ID_JPEG ||
header.getRecordId() == EscherBitmapBlip.RECORD_ID_PNG)
{
r = new EscherBitmapBlip();
}
else
{
r = new EscherBlipRecord();
}
r.setRecordId( header.getRecordId() );
r.setOptions( header.getOptions() );
return r;

+ 52
- 11
src/java/org/apache/poi/ddf/EscherBSERecord.java View File

@@ -17,15 +17,15 @@
package org.apache.poi.ddf;

import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;

/**
* The BSE record is related closely to the <code>EscherBlipRecord</code> and stores
* extra information about the blip.
* extra information about the blip. A blip record is actually stored inside
* the BSE record even though the BSE record isn't actually a container record.
*
* @author Glen Stampoultzis
* @see EscherBlipRecord
@@ -56,6 +56,7 @@ public class EscherBSERecord
private byte field_9_name;
private byte field_10_unused2;
private byte field_11_unused3;
private EscherBlipRecord field_12_blipRecord;

private byte[] remainingData;

@@ -85,9 +86,28 @@ public class EscherBSERecord
field_10_unused2 = data[pos + 34];
field_11_unused3 = data[pos + 35];
bytesRemaining -= 36;
int bytesRead = 0;
if (bytesRemaining > 0)
{
field_12_blipRecord = (EscherBlipRecord) recordFactory.createRecord( data, pos + 36 );
bytesRead = field_12_blipRecord.fillFields( data, pos + 36, recordFactory );
}
pos += 36 + bytesRead;
bytesRemaining -= bytesRead;
// if (field_1_blipTypeWin32 == BT_PNG)
// {
// byte[] uid = new byte[16];
// System.arraycopy( data, pos + 36, uid, 0, 16 );
// byte[] puid = new byte[16];
// System.arraycopy( data, pos + 52, puid, 0, 16 );
// byte tag = data[pos+68];
// System.out.println( HexDump.dump( data, 0, 0 ) );
// byte[] pngBytes = EscherBlipRecord.decompress( data, pos+69, bytesRemaining);
// }

remainingData = new byte[bytesRemaining];
System.arraycopy( data, pos + 36, remainingData, 0, bytesRemaining );
return bytesRemaining + 8 + 36;
System.arraycopy( data, pos, remainingData, 0, bytesRemaining );
return bytesRemaining + 8 + 36 + (field_12_blipRecord == null ? 0 : field_12_blipRecord.getRecordSize()) ;

}

@@ -104,9 +124,14 @@ public class EscherBSERecord
{
listener.beforeRecordSerialize( offset, getRecordId(), this );

if (remainingData == null)
remainingData = new byte[0];

LittleEndian.putShort( data, offset, getOptions() );
LittleEndian.putShort( data, offset + 2, getRecordId() );
int remainingBytes = remainingData.length + 36;
if (remainingData == null) remainingData = new byte[0];
int blipSize = field_12_blipRecord == null ? 0 : field_12_blipRecord.getRecordSize();
int remainingBytes = remainingData.length + 36 + blipSize;
LittleEndian.putInt( data, offset + 4, remainingBytes );

data[offset + 8] = field_1_blipTypeWin32;
@@ -121,8 +146,15 @@ public class EscherBSERecord
data[offset + 41] = field_9_name;
data[offset + 42] = field_10_unused2;
data[offset + 43] = field_11_unused3;
System.arraycopy( remainingData, 0, data, offset + 44, remainingData.length );
int pos = offset + 8 + 36 + remainingData.length;
int bytesWritten = 0;
if (field_12_blipRecord != null)
{
bytesWritten = field_12_blipRecord.serialize( offset + 44, data, new NullEscherSerializationListener() );
}
if (remainingData == null)
remainingData = new byte[0];
System.arraycopy( remainingData, 0, data, offset + 44 + bytesWritten, remainingData.length );
int pos = offset + 8 + 36 + remainingData.length + bytesWritten;

listener.afterRecordSerialize(pos, getRecordId(), pos - offset, this);
return pos - offset;
@@ -135,7 +167,7 @@ public class EscherBSERecord
*/
public int getRecordSize()
{
return 8 + 1 + 1 + 16 + 2 + 4 + 4 + 4 + 1 + 1 + 1 + 1 + remainingData.length;
return 8 + 1 + 1 + 16 + 2 + 4 + 4 + 4 + 1 + 1 + 1 + 1 + field_12_blipRecord.getRecordSize() + (remainingData == null ? 0 : remainingData.length);
}

/**
@@ -312,6 +344,16 @@ public class EscherBSERecord
this.field_11_unused3 = unused3;
}

public EscherBlipRecord getBlipRecord()
{
return field_12_blipRecord;
}

public void setBlipRecord( EscherBlipRecord field_12_blipRecord )
{
this.field_12_blipRecord = field_12_blipRecord;
}

/**
* Any remaining data in this record.
*/
@@ -360,9 +402,8 @@ public class EscherBSERecord
" Name: " + field_9_name + nl +
" Unused2: " + field_10_unused2 + nl +
" Unused3: " + field_11_unused3 + nl +
" blipRecord: " + field_12_blipRecord + nl +
" Extra Data:" + nl + extraData;


}

/**

+ 25
- 333
src/java/org/apache/poi/ddf/EscherBlipRecord.java View File

@@ -17,24 +17,14 @@
package org.apache.poi.ddf;

import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.HexDump;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.zip.InflaterInputStream;
import java.util.zip.DeflaterOutputStream;

/**
* The blip record is used to hold details about large binary objects that occur in escher such
* as JPEG, GIF, PICT and WMF files. The contents of the stream is usually compressed. Inflate
* can be used to decompress the data.
*
* @author Glen Stampoultzis
* @see java.util.zip.Inflater
* @version $Id$
*/
public class EscherBlipRecord
extends EscherRecord
@@ -42,21 +32,14 @@ public class EscherBlipRecord
public static final short RECORD_ID_START = (short) 0xF018;
public static final short RECORD_ID_END = (short) 0xF117;
public static final String RECORD_DESCRIPTION = "msofbtBlip";

private static final int HEADER_SIZE = 8;

private byte[] field_1_secondaryUID;
private int field_2_cacheOfSize;
private int field_3_boundaryTop;
private int field_4_boundaryLeft;
private int field_5_boundaryWidth;
private int field_6_boundaryHeight;
private int field_7_width;
private int field_8_height;
private int field_9_cacheOfSavedSize;
private byte field_10_compressionFlag;
private byte field_11_filter;
private byte[] field_12_data;
protected byte[] field_pictureData;

public EscherBlipRecord()
{
}

/**
* This method deserializes the record from a byte array.
@@ -66,44 +49,27 @@ public class EscherBlipRecord
* @param recordFactory May be null since this is not a container record.
* @return The number of bytes read from the byte array.
*/
public int fillFields( byte[] data, int offset,
EscherRecordFactory recordFactory
)
public int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory )
{
int bytesAfterHeader = readHeader( data, offset );
int pos = offset + HEADER_SIZE;

int size = 0;
field_1_secondaryUID = new byte[16];
System.arraycopy( data, pos + size, field_1_secondaryUID, 0, 16 ); size += 16;
field_2_cacheOfSize = LittleEndian.getInt( data, pos + size );size+=4;
field_3_boundaryTop = LittleEndian.getInt( data, pos + size );size+=4;
field_4_boundaryLeft = LittleEndian.getInt( data, pos + size );size+=4;
field_5_boundaryWidth = LittleEndian.getInt( data, pos + size );size+=4;
field_6_boundaryHeight = LittleEndian.getInt( data, pos + size );size+=4;
field_7_width = LittleEndian.getInt( data, pos + size );size+=4;
field_8_height = LittleEndian.getInt( data, pos + size );size+=4;
field_9_cacheOfSavedSize = LittleEndian.getInt( data, pos + size );size+=4;
field_10_compressionFlag = data[pos + size]; size++;
field_11_filter = data[pos + size]; size++;
field_pictureData = new byte[bytesAfterHeader];
System.arraycopy(data, pos, field_pictureData, 0, bytesAfterHeader);

int bytesRemaining = bytesAfterHeader - size;
field_12_data = new byte[bytesRemaining];
System.arraycopy(data, pos + size, field_12_data, 0, bytesRemaining);

return bytesRemaining + HEADER_SIZE + bytesAfterHeader;
return bytesAfterHeader + 8;
}


/**
* This method serializes this escher record into a byte array.
*
* @param offset The offset into <code>data</code> to start writing the record data to.
* @param data The byte array to serialize to.
* @param listener A listener to retrieve start and end callbacks. Use a <code>NullEscherSerailizationListener</code> to ignore these events.
* @return The number of bytes written.
* Serializes the record to an existing byte array.
*
* @see NullEscherSerializationListener
* @param offset the offset within the byte array
* @param data the data array to serialize to
* @param listener a listener for begin and end serialization events. This
* is useful because the serialization is
* hierarchical/recursive and sometimes you need to be able
* break into that.
* @return the number of bytes written.
*/
public int serialize( int offset, byte[] data, EscherSerializationListener listener )
{
@@ -111,25 +77,11 @@ public class EscherBlipRecord

LittleEndian.putShort( data, offset, getOptions() );
LittleEndian.putShort( data, offset + 2, getRecordId() );
int remainingBytes = field_12_data.length + 36;
LittleEndian.putInt( data, offset + 4, remainingBytes );

int pos = offset + HEADER_SIZE;
System.arraycopy(field_1_secondaryUID, 0, data, pos, 16 ); pos += 16;
LittleEndian.putInt( data, pos, field_2_cacheOfSize); pos += 4;
LittleEndian.putInt( data, pos, field_3_boundaryTop); pos += 4;
LittleEndian.putInt( data, pos, field_4_boundaryLeft); pos += 4;
LittleEndian.putInt( data, pos, field_5_boundaryWidth); pos += 4;
LittleEndian.putInt( data, pos, field_6_boundaryHeight); pos += 4;
LittleEndian.putInt( data, pos, field_7_width); pos += 4;
LittleEndian.putInt( data, pos, field_8_height); pos += 4;
LittleEndian.putInt( data, pos, field_9_cacheOfSavedSize); pos += 4;
data[pos++] = field_10_compressionFlag;
data[pos++] = field_11_filter;
System.arraycopy(field_12_data, 0, data, pos, field_12_data.length); pos += field_12_data.length;
System.arraycopy( field_pictureData, 0, data, offset + 4, field_pictureData.length );

listener.afterRecordSerialize(pos, getRecordId(), pos - offset, this);
return pos - offset;
listener.afterRecordSerialize(offset + 4 + field_pictureData.length, getRecordId(), field_pictureData.length + 4, this);
return field_pictureData.length + 4;
}

/**
@@ -139,7 +91,7 @@ public class EscherBlipRecord
*/
public int getRecordSize()
{
return 58 + field_12_data.length;
return field_pictureData.length + 4;
}

/**
@@ -150,203 +102,6 @@ public class EscherBlipRecord
return "Blip";
}

/**
* Retrieve the secondary UID
*/
public byte[] getSecondaryUID()
{
return field_1_secondaryUID;
}

/**
* Set the secondary UID
*/
public void setSecondaryUID( byte[] field_1_secondaryUID )
{
this.field_1_secondaryUID = field_1_secondaryUID;
}

/**
* Retrieve the cache of the metafile size
*/
public int getCacheOfSize()
{
return field_2_cacheOfSize;
}

/**
* Set the cache of the metafile size
*/
public void setCacheOfSize( int field_2_cacheOfSize )
{
this.field_2_cacheOfSize = field_2_cacheOfSize;
}

/**
* Retrieve the top boundary of the metafile drawing commands
*/
public int getBoundaryTop()
{
return field_3_boundaryTop;
}

/**
* Set the top boundary of the metafile drawing commands
*/
public void setBoundaryTop( int field_3_boundaryTop )
{
this.field_3_boundaryTop = field_3_boundaryTop;
}

/**
* Retrieve the left boundary of the metafile drawing commands
*/
public int getBoundaryLeft()
{
return field_4_boundaryLeft;
}

/**
* Set the left boundary of the metafile drawing commands
*/
public void setBoundaryLeft( int field_4_boundaryLeft )
{
this.field_4_boundaryLeft = field_4_boundaryLeft;
}

/**
* Retrieve the boundary width of the metafile drawing commands
*/
public int getBoundaryWidth()
{
return field_5_boundaryWidth;
}

/**
* Set the boundary width of the metafile drawing commands
*/
public void setBoundaryWidth( int field_5_boundaryWidth )
{
this.field_5_boundaryWidth = field_5_boundaryWidth;
}

/**
* Retrieve the boundary height of the metafile drawing commands
*/
public int getBoundaryHeight()
{
return field_6_boundaryHeight;
}

/**
* Set the boundary height of the metafile drawing commands
*/
public void setBoundaryHeight( int field_6_boundaryHeight )
{
this.field_6_boundaryHeight = field_6_boundaryHeight;
}

/**
* Retrieve the width of the metafile in EMU's (English Metric Units).
*/
public int getWidth()
{
return field_7_width;
}

/**
* Set the width of the metafile in EMU's (English Metric Units).
*/
public void setWidth( int width )
{
this.field_7_width = width;
}

/**
* Retrieve the height of the metafile in EMU's (English Metric Units).
*/
public int getHeight()
{
return field_8_height;
}

/**
* Set the height of the metafile in EMU's (English Metric Units).
*/
public void setHeight( int height )
{
this.field_8_height = height;
}

/**
* Retrieve the cache of the saved size
*/
public int getCacheOfSavedSize()
{
return field_9_cacheOfSavedSize;
}

/**
* Set the cache of the saved size
*/
public void setCacheOfSavedSize( int field_9_cacheOfSavedSize )
{
this.field_9_cacheOfSavedSize = field_9_cacheOfSavedSize;
}

/**
* Is the contents of the blip compressed?
*/
public byte getCompressionFlag()
{
return field_10_compressionFlag;
}

/**
* Set whether the contents of the blip is compressed
*/
public void setCompressionFlag( byte field_10_compressionFlag )
{
this.field_10_compressionFlag = field_10_compressionFlag;
}

/**
* Filter should always be 0
*/
public byte getFilter()
{
return field_11_filter;
}

/**
* Filter should always be 0
*/
public void setFilter( byte field_11_filter )
{
this.field_11_filter = field_11_filter;
}

/**
* The BLIP data
*/
public byte[] getData()
{
return field_12_data;
}

/**
* The BLIP data
*/
public void setData( byte[] field_12_data )
{
this.field_12_data = field_12_data;
}

/**
* The string representation of this record.
*
* @return A string
*/
public String toString()
{
String nl = System.getProperty( "line.separator" );
@@ -355,7 +110,7 @@ public class EscherBlipRecord
ByteArrayOutputStream b = new ByteArrayOutputStream();
try
{
HexDump.dump( this.field_12_data, 0, b, 0 );
HexDump.dump( this.field_pictureData, 0, b, 0 );
extraData = b.toString();
}
catch ( Exception e )
@@ -365,70 +120,7 @@ public class EscherBlipRecord
return getClass().getName() + ":" + nl +
" RecordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
" Options: 0x" + HexDump.toHex( getOptions() ) + nl +
" Secondary UID: " + HexDump.toHex( field_1_secondaryUID ) + nl +
" CacheOfSize: " + field_2_cacheOfSize + nl +
" BoundaryTop: " + field_3_boundaryTop + nl +
" BoundaryLeft: " + field_4_boundaryLeft + nl +
" BoundaryWidth: " + field_5_boundaryWidth + nl +
" BoundaryHeight: " + field_6_boundaryHeight + nl +
" X: " + field_7_width + nl +
" Y: " + field_8_height + nl +
" CacheOfSavedSize: " + field_9_cacheOfSavedSize + nl +
" CompressionFlag: " + field_10_compressionFlag + nl +
" Filter: " + field_11_filter + nl +
" Data:" + nl + extraData;
}

/**
* Compress the contents of the provided array
*
* @param data An uncompressed byte array
* @see DeflaterOutputStream#write(int b)
*/
public static byte[] compress( byte[] data )
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream( out );
try
{
for ( int i = 0; i < data.length; i++ )
deflaterOutputStream.write( data[i] );
}
catch ( IOException e )
{
throw new RecordFormatException( e.toString() );
}
" Extra Data:" + nl + extraData;

return out.toByteArray();
}

/**
* Decompresses a byte array.
*
* @param data The compressed byte array
* @param pos The starting position into the byte array
* @param length The number of compressed bytes to decompress
* @return An uncompressed byte array
* @see InflaterInputStream#read
*/
public static byte[] decompress( byte[] data, int pos, int length )
{
byte[] compressedData = new byte[length];
System.arraycopy( data, pos + 50, compressedData, 0, length );
InputStream compressedInputStream = new ByteArrayInputStream( compressedData );
InflaterInputStream inflaterInputStream = new InflaterInputStream( compressedInputStream );
ByteArrayOutputStream out = new ByteArrayOutputStream();
int c;
try
{
while ( ( c = inflaterInputStream.read() ) != -1 )
out.write( c );
}
catch ( IOException e )
{
throw new RecordFormatException( e.toString() );
}
return out.toByteArray();
}

}

+ 435
- 0
src/java/org/apache/poi/ddf/EscherBlipWMFRecord.java View File

@@ -0,0 +1,435 @@

/* ====================================================================
Copyright 2002-2004 Apache Software Foundation

Licensed 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.ddf;

import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.zip.InflaterInputStream;
import java.util.zip.DeflaterOutputStream;

/**
* The blip record is used to hold details about large binary objects that occur in escher such
* as JPEG, GIF, PICT and WMF files. The contents of the stream is usually compressed. Inflate
* can be used to decompress the data.
*
* @author Glen Stampoultzis
* @see java.util.zip.Inflater
*/
public class EscherBlipWMFRecord
extends EscherBlipRecord
{
// public static final short RECORD_ID_START = (short) 0xF018;
// public static final short RECORD_ID_END = (short) 0xF117;
public static final String RECORD_DESCRIPTION = "msofbtBlip";
private static final int HEADER_SIZE = 8;

private byte[] field_1_secondaryUID;
private int field_2_cacheOfSize;
private int field_3_boundaryTop;
private int field_4_boundaryLeft;
private int field_5_boundaryWidth;
private int field_6_boundaryHeight;
private int field_7_width;
private int field_8_height;
private int field_9_cacheOfSavedSize;
private byte field_10_compressionFlag;
private byte field_11_filter;
private byte[] field_12_data;


/**
* This method deserializes the record from a byte array.
*
* @param data The byte array containing the escher record information
* @param offset The starting offset into <code>data</code>.
* @param recordFactory May be null since this is not a container record.
* @return The number of bytes read from the byte array.
*/
public int fillFields( byte[] data, int offset,
EscherRecordFactory recordFactory
)
{
int bytesAfterHeader = readHeader( data, offset );
int pos = offset + HEADER_SIZE;

int size = 0;
field_1_secondaryUID = new byte[16];
System.arraycopy( data, pos + size, field_1_secondaryUID, 0, 16 ); size += 16;
field_2_cacheOfSize = LittleEndian.getInt( data, pos + size );size+=4;
field_3_boundaryTop = LittleEndian.getInt( data, pos + size );size+=4;
field_4_boundaryLeft = LittleEndian.getInt( data, pos + size );size+=4;
field_5_boundaryWidth = LittleEndian.getInt( data, pos + size );size+=4;
field_6_boundaryHeight = LittleEndian.getInt( data, pos + size );size+=4;
field_7_width = LittleEndian.getInt( data, pos + size );size+=4;
field_8_height = LittleEndian.getInt( data, pos + size );size+=4;
field_9_cacheOfSavedSize = LittleEndian.getInt( data, pos + size );size+=4;
field_10_compressionFlag = data[pos + size]; size++;
field_11_filter = data[pos + size]; size++;

int bytesRemaining = bytesAfterHeader - size;
field_12_data = new byte[bytesRemaining];
System.arraycopy(data, pos + size, field_12_data, 0, bytesRemaining);
size += bytesRemaining;

return HEADER_SIZE + size;
}


/**
* This method serializes this escher record into a byte array.
*
* @param offset The offset into <code>data</code> to start writing the record data to.
* @param data The byte array to serialize to.
* @param listener A listener to retrieve start and end callbacks. Use a <code>NullEscherSerailizationListener</code> to ignore these events.
* @return The number of bytes written.
*
* @see NullEscherSerializationListener
*/
public int serialize( int offset, byte[] data, EscherSerializationListener listener )
{
listener.beforeRecordSerialize(offset, getRecordId(), this);

LittleEndian.putShort( data, offset, getOptions() );
LittleEndian.putShort( data, offset + 2, getRecordId() );
int remainingBytes = field_12_data.length + 36;
LittleEndian.putInt( data, offset + 4, remainingBytes );

int pos = offset + HEADER_SIZE;
System.arraycopy(field_1_secondaryUID, 0, data, pos, 16 ); pos += 16;
LittleEndian.putInt( data, pos, field_2_cacheOfSize); pos += 4;
LittleEndian.putInt( data, pos, field_3_boundaryTop); pos += 4;
LittleEndian.putInt( data, pos, field_4_boundaryLeft); pos += 4;
LittleEndian.putInt( data, pos, field_5_boundaryWidth); pos += 4;
LittleEndian.putInt( data, pos, field_6_boundaryHeight); pos += 4;
LittleEndian.putInt( data, pos, field_7_width); pos += 4;
LittleEndian.putInt( data, pos, field_8_height); pos += 4;
LittleEndian.putInt( data, pos, field_9_cacheOfSavedSize); pos += 4;
data[pos++] = field_10_compressionFlag;
data[pos++] = field_11_filter;
System.arraycopy(field_12_data, 0, data, pos, field_12_data.length); pos += field_12_data.length;

listener.afterRecordSerialize(pos, getRecordId(), pos - offset, this);
return pos - offset;
}

/**
* Returns the number of bytes that are required to serialize this record.
*
* @return Number of bytes
*/
public int getRecordSize()
{
return 58 + field_12_data.length;
}

/**
* The short name for this record
*/
public String getRecordName()
{
return "Blip";
}

/**
* Retrieve the secondary UID
*/
public byte[] getSecondaryUID()
{
return field_1_secondaryUID;
}

/**
* Set the secondary UID
*/
public void setSecondaryUID( byte[] field_1_secondaryUID )
{
this.field_1_secondaryUID = field_1_secondaryUID;
}

/**
* Retrieve the cache of the metafile size
*/
public int getCacheOfSize()
{
return field_2_cacheOfSize;
}

/**
* Set the cache of the metafile size
*/
public void setCacheOfSize( int field_2_cacheOfSize )
{
this.field_2_cacheOfSize = field_2_cacheOfSize;
}

/**
* Retrieve the top boundary of the metafile drawing commands
*/
public int getBoundaryTop()
{
return field_3_boundaryTop;
}

/**
* Set the top boundary of the metafile drawing commands
*/
public void setBoundaryTop( int field_3_boundaryTop )
{
this.field_3_boundaryTop = field_3_boundaryTop;
}

/**
* Retrieve the left boundary of the metafile drawing commands
*/
public int getBoundaryLeft()
{
return field_4_boundaryLeft;
}

/**
* Set the left boundary of the metafile drawing commands
*/
public void setBoundaryLeft( int field_4_boundaryLeft )
{
this.field_4_boundaryLeft = field_4_boundaryLeft;
}

/**
* Retrieve the boundary width of the metafile drawing commands
*/
public int getBoundaryWidth()
{
return field_5_boundaryWidth;
}

/**
* Set the boundary width of the metafile drawing commands
*/
public void setBoundaryWidth( int field_5_boundaryWidth )
{
this.field_5_boundaryWidth = field_5_boundaryWidth;
}

/**
* Retrieve the boundary height of the metafile drawing commands
*/
public int getBoundaryHeight()
{
return field_6_boundaryHeight;
}

/**
* Set the boundary height of the metafile drawing commands
*/
public void setBoundaryHeight( int field_6_boundaryHeight )
{
this.field_6_boundaryHeight = field_6_boundaryHeight;
}

/**
* Retrieve the width of the metafile in EMU's (English Metric Units).
*/
public int getWidth()
{
return field_7_width;
}

/**
* Set the width of the metafile in EMU's (English Metric Units).
*/
public void setWidth( int width )
{
this.field_7_width = width;
}

/**
* Retrieve the height of the metafile in EMU's (English Metric Units).
*/
public int getHeight()
{
return field_8_height;
}

/**
* Set the height of the metafile in EMU's (English Metric Units).
*/
public void setHeight( int height )
{
this.field_8_height = height;
}

/**
* Retrieve the cache of the saved size
*/
public int getCacheOfSavedSize()
{
return field_9_cacheOfSavedSize;
}

/**
* Set the cache of the saved size
*/
public void setCacheOfSavedSize( int field_9_cacheOfSavedSize )
{
this.field_9_cacheOfSavedSize = field_9_cacheOfSavedSize;
}

/**
* Is the contents of the blip compressed?
*/
public byte getCompressionFlag()
{
return field_10_compressionFlag;
}

/**
* Set whether the contents of the blip is compressed
*/
public void setCompressionFlag( byte field_10_compressionFlag )
{
this.field_10_compressionFlag = field_10_compressionFlag;
}

/**
* Filter should always be 0
*/
public byte getFilter()
{
return field_11_filter;
}

/**
* Filter should always be 0
*/
public void setFilter( byte field_11_filter )
{
this.field_11_filter = field_11_filter;
}

/**
* The BLIP data
*/
public byte[] getData()
{
return field_12_data;
}

/**
* The BLIP data
*/
public void setData( byte[] field_12_data )
{
this.field_12_data = field_12_data;
}

/**
* The string representation of this record.
*
* @return A string
*/
public String toString()
{
String nl = System.getProperty( "line.separator" );

String extraData;
ByteArrayOutputStream b = new ByteArrayOutputStream();
try
{
HexDump.dump( this.field_12_data, 0, b, 0 );
extraData = b.toString();
}
catch ( Exception e )
{
extraData = e.toString();
}
return getClass().getName() + ":" + nl +
" RecordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
" Options: 0x" + HexDump.toHex( getOptions() ) + nl +
" Secondary UID: " + HexDump.toHex( field_1_secondaryUID ) + nl +
" CacheOfSize: " + field_2_cacheOfSize + nl +
" BoundaryTop: " + field_3_boundaryTop + nl +
" BoundaryLeft: " + field_4_boundaryLeft + nl +
" BoundaryWidth: " + field_5_boundaryWidth + nl +
" BoundaryHeight: " + field_6_boundaryHeight + nl +
" X: " + field_7_width + nl +
" Y: " + field_8_height + nl +
" CacheOfSavedSize: " + field_9_cacheOfSavedSize + nl +
" CompressionFlag: " + field_10_compressionFlag + nl +
" Filter: " + field_11_filter + nl +
" Data:" + nl + extraData;
}

/**
* Compress the contents of the provided array
*
* @param data An uncompressed byte array
* @see DeflaterOutputStream#write(int b)
*/
public static byte[] compress( byte[] data )
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream( out );
try
{
for ( int i = 0; i < data.length; i++ )
deflaterOutputStream.write( data[i] );
}
catch ( IOException e )
{
throw new RecordFormatException( e.toString() );
}

return out.toByteArray();
}

/**
* Decompresses a byte array.
*
* @param data The compressed byte array
* @param pos The starting position into the byte array
* @param length The number of compressed bytes to decompress
* @return An uncompressed byte array
* @see InflaterInputStream#read
*/
public static byte[] decompress( byte[] data, int pos, int length )
{
byte[] compressedData = new byte[length];
System.arraycopy( data, pos + 50, compressedData, 0, length );
InputStream compressedInputStream = new ByteArrayInputStream( compressedData );
InflaterInputStream inflaterInputStream = new InflaterInputStream( compressedInputStream );
ByteArrayOutputStream out = new ByteArrayOutputStream();
int c;
try
{
while ( ( c = inflaterInputStream.read() ) != -1 )
out.write( c );
}
catch ( IOException e )
{
throw new RecordFormatException( e.toString() );
}
return out.toByteArray();
}

}

+ 2
- 2
src/java/org/apache/poi/ddf/EscherBoolProperty.java View File

@@ -32,12 +32,12 @@ public class EscherBoolProperty
/**
* Create an instance of an escher boolean property.
*
* @param propertyNumber The property number
* @param propertyNumber The property number (or id)
* @param value The 32 bit value of this bool property
*/
public EscherBoolProperty( short propertyNumber, int value )
{
super( propertyNumber, false, false, value );
super(propertyNumber, value);
}

/**

+ 1
- 1
src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java View File

@@ -154,7 +154,7 @@ public class EscherClientAnchorRecord
}
catch ( Exception e )
{
extraData = "error";
extraData = "error\n";
}
return getClass().getName() + ":" + nl +
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +

+ 1
- 1
src/java/org/apache/poi/ddf/EscherClientDataRecord.java View File

@@ -119,7 +119,7 @@ public class EscherClientDataRecord
}
catch ( Exception e )
{
extraData = "error";
extraData = "error\n";
}
return getClass().getName() + ":" + nl +
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +

+ 7
- 4
src/java/org/apache/poi/ddf/EscherDggRecord.java View File

@@ -17,11 +17,10 @@
package org.apache.poi.ddf;

import org.apache.poi.hssf.record.RecordFormatException;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hssf.record.RecordFormatException;

import java.lang.reflect.Array;
import java.util.*;

/**
@@ -83,8 +82,8 @@ public class EscherDggRecord
int field_2_numIdClusters = LittleEndian.getInt( data, pos + size );size+=4;
field_3_numShapesSaved = LittleEndian.getInt( data, pos + size );size+=4;
field_4_drawingsSaved = LittleEndian.getInt( data, pos + size );size+=4;
field_5_fileIdClusters = new FileIdCluster[field_2_numIdClusters-1];
for (int i = 0; i < field_2_numIdClusters-1; i++)
field_5_fileIdClusters = new FileIdCluster[(bytesRemaining-size) / 8]; // Can't rely on field_2_numIdClusters
for (int i = 0; i < field_5_fileIdClusters.length; i++)
{
field_5_fileIdClusters[i] = new FileIdCluster(LittleEndian.getInt( data, pos + size ), LittleEndian.getInt( data, pos + size + 4 ));
size += 8;
@@ -114,6 +113,7 @@ public class EscherDggRecord
LittleEndian.putShort( data, pos, getRecordId() ); pos += 2;
int remainingBytes = getRecordSize() - 8;
LittleEndian.putInt( data, pos, remainingBytes ); pos += 4;

LittleEndian.putInt( data, pos, field_1_shapeIdMax ); pos += 4;
LittleEndian.putInt( data, pos, getNumIdClusters() ); pos += 4;
LittleEndian.putInt( data, pos, field_3_numShapesSaved ); pos += 4;
@@ -200,6 +200,9 @@ public class EscherDggRecord
this.field_1_shapeIdMax = field_1_shapeIdMax;
}

/**
* Number of id clusters + 1
*/
public int getNumIdClusters()
{
return field_5_fileIdClusters.length + 1;

+ 1
- 1
src/java/org/apache/poi/ddf/EscherProperty.java View File

@@ -26,7 +26,7 @@ package org.apache.poi.ddf;
*/
abstract public class EscherProperty
{
private short id;
protected short id;

/**
* The id is distinct from the actual property number. The id includes the property number the blip id

+ 7
- 11
src/java/org/apache/poi/ddf/EscherPropertyFactory.java View File

@@ -18,11 +18,10 @@
package org.apache.poi.ddf;

import org.apache.poi.util.LittleEndian;
import org.apache.poi.hssf.record.RecordFormatException;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
* Generates a property given a reference into the byte array storing that property.
@@ -43,7 +42,7 @@ public class EscherPropertyFactory
List results = new ArrayList();

int pos = offset;
int complexBytes = 0;
// while ( bytesRemaining >= 6 )
for (int i = 0; i < numProperties; i++)
{
@@ -54,21 +53,18 @@ public class EscherPropertyFactory
short propNumber = (short) ( propId & (short) 0x3FFF );
boolean isComplex = ( propId & (short) 0x8000 ) != 0;
boolean isBlipId = ( propId & (short) 0x4000 ) != 0;
if ( isComplex )
complexBytes = propData;
else
complexBytes = 0;

byte propertyType = EscherProperties.getPropertyType( (short) propNumber );
if ( propertyType == EscherPropertyMetaData.TYPE_BOOLEAN )
results.add( new EscherBoolProperty( propNumber, propData ) );
results.add( new EscherBoolProperty( propId, propData ) );
else if ( propertyType == EscherPropertyMetaData.TYPE_RGB )
results.add( new EscherRGBProperty( propNumber, propData ) );
results.add( new EscherRGBProperty( propId, propData ) );
else if ( propertyType == EscherPropertyMetaData.TYPE_SHAPEPATH )
results.add( new EscherShapePathProperty( propNumber, propData ) );
results.add( new EscherShapePathProperty( propId, propData ) );
else
{
if ( !isComplex )
results.add( new EscherSimpleProperty( propNumber, propData ) );
results.add( new EscherSimpleProperty( propId, propData ) );
else
{
if ( propertyType == EscherPropertyMetaData.TYPE_ARRAY)

+ 1
- 1
src/java/org/apache/poi/ddf/EscherRGBProperty.java View File

@@ -28,7 +28,7 @@ public class EscherRGBProperty

public EscherRGBProperty( short propertyNumber, int rgbColor )
{
super( propertyNumber, false, false, rgbColor );
super( propertyNumber, rgbColor );
}

public int getRgbColor()

+ 1
- 0
src/java/org/apache/poi/ddf/EscherSimpleProperty.java View File

@@ -111,6 +111,7 @@ public class EscherSimpleProperty extends EscherProperty
public String toString()
{
return "propNum: " + getPropertyNumber()
+ ", RAW: 0x" + HexDump.toHex( getId() )
+ ", propName: " + EscherProperties.getPropertyName( getPropertyNumber() )
+ ", complex: " + isComplex()
+ ", blipId: " + isBlipId()

+ 43
- 16
src/java/org/apache/poi/hssf/dev/BiffViewer.java View File

@@ -112,6 +112,23 @@ public class BiffViewer {
in.read(data);
loc += recsize;
Record record = createRecord(rectype, recsize, data );
// if (record.getSid() == DrawingGroupRecord.sid)
// {
// if (activeRecord.getRecord().getSid() == DrawingGroupRecord.sid)
// {
// DrawingGroupRecord dg = (DrawingGroupRecord) activeRecord.getRecord();
// System.out.println( "Joined" );
// dg.join( (AbstractEscherHolderRecord) record );
// }
// else
// {
// records.add(record);
// if (activeRecord != null)
// activeRecord.dump();
// activeRecord = new RecordDetails(rectype, recsize, startloc, data, record);
// }
// }
// else
if (record.getSid() != ContinueRecord.sid)
{
records.add(record);
@@ -178,7 +195,6 @@ public class BiffViewer {
}
}


private static void dumpUnknownRecord(byte[] data) throws IOException {
// record hex dump it!
System.out.println(
@@ -630,29 +646,40 @@ public class BiffViewer {
*/
public static void main(String[] args) {
try {
BiffViewer viewer = new BiffViewer(args);
System.setProperty("poi.deserialize.escher", "true");

if ((args.length > 1) && args[1].equals("on")) {
viewer.setDump(true);
if (args.length == 0)
{
System.out.println( "Biff viewer needs a filename" );
}
if ((args.length > 1) && args[1].equals("bfd")) {
POIFSFileSystem fs =
new POIFSFileSystem(new FileInputStream(args[0]));
InputStream stream =
fs.createDocumentInputStream("Workbook");
int size = stream.available();
byte[] data = new byte[size];

stream.read(data);
HexDump.dump(data, 0, System.out, 0);
} else {
viewer.run();
else
{
BiffViewer viewer = new BiffViewer(args);
if ((args.length > 1) && args[1].equals("on")) {
viewer.setDump(true);
}
if ((args.length > 1) && args[1].equals("bfd")) {
POIFSFileSystem fs =
new POIFSFileSystem(new FileInputStream(args[0]));
InputStream stream =
fs.createDocumentInputStream("Workbook");
int size = stream.available();
byte[] data = new byte[size];

stream.read(data);
HexDump.dump(data, 0, System.out, 0);
} else {
viewer.run();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* This record supports dumping of completed continue records.
*/
static class RecordDetails
{
short rectype, recsize;

+ 4
- 1
src/java/org/apache/poi/hssf/model/AbstractShape.java View File

@@ -34,7 +34,7 @@ public abstract class AbstractShape
*/
public static AbstractShape createShape( HSSFShape hssfShape, int shapeId )
{
AbstractShape shape = null;
AbstractShape shape;
if (hssfShape instanceof HSSFTextbox)
{
shape = new TextboxShape( (HSSFTextbox)hssfShape, shapeId );
@@ -48,6 +48,9 @@ public abstract class AbstractShape
HSSFSimpleShape simpleShape = (HSSFSimpleShape) hssfShape;
switch ( simpleShape.getShapeType() )
{
case HSSFSimpleShape.OBJECT_TYPE_PICTURE:
shape = new PictureShape( simpleShape, shapeId );
break;
case HSSFSimpleShape.OBJECT_TYPE_LINE:
shape = new LineShape( simpleShape, shapeId );
break;

+ 1
- 1
src/java/org/apache/poi/hssf/model/ConvertAnchor.java View File

@@ -37,7 +37,7 @@ public class ConvertAnchor
EscherClientAnchorRecord anchor = new EscherClientAnchorRecord();
anchor.setRecordId( EscherClientAnchorRecord.RECORD_ID );
anchor.setOptions( (short) 0x0000 );
anchor.setFlag( (short) 0 );
anchor.setFlag( (short) a.getAnchorType() );
anchor.setCol1( (short) Math.min(a.getCol1(), a.getCol2()) );
anchor.setDx1( (short) Math.min(a.getDx1(), a.getDx2()) );
anchor.setRow1( (short) Math.min(a.getRow1(), a.getRow2()) );

+ 25
- 5
src/java/org/apache/poi/hssf/model/Sheet.java View File

@@ -19,17 +19,17 @@
package org.apache.poi.hssf.model;

import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.FormulaRecordAggregate;
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.List; // normally I don't do this, buy we literally mean ALL

/**
* Low level model implementation of a Sheet (one workbook contains many sheets)
@@ -768,6 +768,26 @@ public class Sheet implements Model
}
}

//// uncomment to test record sizes ////
// System.out.println( record.getClass().getName() );
// byte[] data2 = new byte[record.getRecordSize()];
// record.serialize(0, data2 ); // rec.length;
// if (LittleEndian.getUShort(data2, 2) != record.getRecordSize() - 4
// && record instanceof RowRecordsAggregate == false
// && record instanceof ValueRecordsAggregate == false
// && record instanceof EscherAggregate == false)
// {
// throw new RuntimeException("Blah!!! Size off by " + ( LittleEndian.getUShort(data2, 2) - record.getRecordSize() - 4) + " records.");
// }

//asd: int len = record.serialize(pos + offset, data );

///// DEBUG BEGIN /////
//asd: if (len != record.getRecordSize())
//asd: throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize() + ". Record object is " + record.getClass());
///// DEBUG END /////

//asd: pos += len; // rec.length;

}
if (log.check( POILogger.DEBUG ))
@@ -2023,9 +2043,9 @@ public class Sheet implements Model
{
int retval = 0;

for (int k = 0; k < records.size(); k++)
for ( int k = 0; k < records.size(); k++ )
{
retval += (( Record ) records.get(k)).getRecordSize();
retval += ( (Record) records.get( k ) ).getRecordSize();
}
//Add space for the IndexRecord
if (rows != null) {
@@ -2430,7 +2450,7 @@ public class Sheet implements Model
return margins;
}

public int aggregateDrawingRecords(DrawingManager drawingManager)
public int aggregateDrawingRecords(DrawingManager2 drawingManager)
{
int loc = findFirstRecordLocBySid(DrawingRecord.sid);
boolean noDrawingRecordsFound = loc == -1;

+ 74
- 14
src/java/org/apache/poi/hssf/model/Workbook.java View File

@@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.io.UnsupportedEncodingException;

/**
* Low level model implementation of a Workbook. Provides creational methods
@@ -99,7 +98,8 @@ public class Workbook implements Model
protected int numfonts = 0; // hold the number of font records
private short maxformatid = -1; // holds the max format id
private boolean uses1904datewindowing = false; // whether 1904 date windowing is being used
private DrawingManager drawingManager;
private DrawingManager2 drawingManager;
private List escherBSERecords = new ArrayList(); // EscherBSERecord

private static POILogger log = POILogFactory.getLogger(Workbook.class);

@@ -748,7 +748,12 @@ public class Workbook implements Model
{
record = sst.createExtSSTRecord(sstPos + offset);
}
pos += record.serialize( pos + offset, data ); // rec.length;
int len = record.serialize( pos + offset, data );
///// DEBUG BEGIN /////
// if (len != record.getRecordSize())
// throw new IllegalStateException("Record size does not match serialized bytes. Serialized size = " + len + " but getRecordSize() returns " + record.getRecordSize());
///// DEBUG END /////
pos += len; // rec.length;
}
}
if (log.check( POILogger.DEBUG ))
@@ -2104,13 +2109,12 @@ public class Workbook implements Model
}

/**
* Creates a drawing group record. If it already exists then it's left
* alone.
* Creates a drawing group record. If it already exists then it's modified.
*/
public void createDrawingGroup()
{
int dggLoc = findFirstRecordLocBySid(EscherContainerRecord.DGG_CONTAINER);
if (dggLoc == -1)
if (drawingManager == null)
{
EscherContainerRecord dggContainer = new EscherContainerRecord();
EscherDggRecord dgg = new EscherDggRecord();
@@ -2125,11 +2129,23 @@ public class Workbook implements Model
dgg.setNumShapesSaved(0);
dgg.setDrawingsSaved(0);
dgg.setFileIdClusters(new EscherDggRecord.FileIdCluster[] {} );
drawingManager = new DrawingManager(dgg);
drawingManager = new DrawingManager2(dgg);
EscherContainerRecord bstoreContainer = null;
if (escherBSERecords.size() > 0)
{
bstoreContainer = new EscherContainerRecord();
bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER );
bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) );
for ( Iterator iterator = escherBSERecords.iterator(); iterator.hasNext(); )
{
EscherRecord escherRecord = (EscherRecord) iterator.next();
bstoreContainer.addChildRecord( escherRecord );
}
}
opt.setRecordId((short) 0xF00B);
opt.setOptions((short) 0x0033);
opt.addEscherProperty( new EscherBoolProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 524296) );
opt.addEscherProperty( new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, 134217737) );
opt.addEscherProperty( new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, 0x08000041) );
opt.addEscherProperty( new EscherRGBProperty(EscherProperties.LINESTYLE__COLOR, 134217792) );
splitMenuColors.setRecordId((short) 0xF11E);
splitMenuColors.setOptions((short) 0x0040);
@@ -2139,17 +2155,61 @@ public class Workbook implements Model
splitMenuColors.setColor4(0x100000F7);

dggContainer.addChildRecord(dgg);
if (bstoreContainer != null)
dggContainer.addChildRecord( bstoreContainer );
dggContainer.addChildRecord(opt);
dggContainer.addChildRecord(splitMenuColors);

DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
drawingGroup.addEscherRecord(dggContainer);
int loc = findFirstRecordLocBySid(CountryRecord.sid);
getRecords().add(loc+1, drawingGroup);
int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
if (dgLoc == -1)
{
DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
drawingGroup.addEscherRecord(dggContainer);
int loc = findFirstRecordLocBySid(CountryRecord.sid);

getRecords().add(loc+1, drawingGroup);
}
else
{
DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
drawingGroup.addEscherRecord(dggContainer);
getRecords().set(dgLoc, drawingGroup);
}

}

}

public int addBSERecord(EscherBSERecord e)
{
createDrawingGroup();

// maybe we don't need that as an instance variable anymore
escherBSERecords.add( e );

int dgLoc = findFirstRecordLocBySid(DrawingGroupRecord.sid);
DrawingGroupRecord drawingGroup = (DrawingGroupRecord) getRecords().get( dgLoc );

EscherContainerRecord dggContainer = (EscherContainerRecord) drawingGroup.getEscherRecord( 0 );
EscherContainerRecord bstoreContainer;
if (dggContainer.getChild( 1 ).getRecordId() == EscherContainerRecord.BSTORE_CONTAINER )
{
bstoreContainer = (EscherContainerRecord) dggContainer.getChild( 1 );
}
else
{
bstoreContainer = new EscherContainerRecord();
bstoreContainer.setRecordId( EscherContainerRecord.BSTORE_CONTAINER );
dggContainer.getChildRecords().add( 1, bstoreContainer );
}
bstoreContainer.setOptions( (short) ( (escherBSERecords.size() << 4) | 0xF ) );

bstoreContainer.addChildRecord( e );

return escherBSERecords.size();
}

public DrawingManager getDrawingManager()
public DrawingManager2 getDrawingManager()
{
return drawingManager;
}

+ 63
- 11
src/java/org/apache/poi/hssf/record/AbstractEscherHolderRecord.java View File

@@ -88,7 +88,7 @@ public abstract class AbstractEscherHolderRecord
{
if (id != getSid())
{
throw new RecordFormatException("Not a Bar record");
throw new RecordFormatException("Not an escher record");
}
}

@@ -102,15 +102,20 @@ public abstract class AbstractEscherHolderRecord
}
else
{
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
int pos = offset;
while ( pos < offset + size )
{
EscherRecord r = recordFactory.createRecord(data, pos);
int bytesRead = r.fillFields(data, pos, recordFactory );
escherRecords.add(r);
pos += bytesRead;
}
convertToEscherRecords( offset, size, data );
}
}

private void convertToEscherRecords( int offset, int size, byte[] data )
{
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
int pos = offset;
while ( pos < offset + size )
{
EscherRecord r = recordFactory.createRecord(data, pos);
int bytesRead = r.fillFields(data, pos, recordFactory );
escherRecords.add(r);
pos += bytesRead;
}
}

@@ -120,6 +125,8 @@ public abstract class AbstractEscherHolderRecord

final String nl = System.getProperty("line.separator");
buffer.append('[' + getRecordName() + ']' + nl);
if (escherRecords.size() == 0)
buffer.append("No Escher Records Decoded" + nl);
for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
{
EscherRecord r = (EscherRecord) iterator.next();
@@ -138,10 +145,16 @@ public abstract class AbstractEscherHolderRecord
LittleEndian.putShort( data, 2 + offset, (short) ( getRecordSize() - 4 ) );
if ( escherRecords.size() == 0 && rawData != null )
{
System.arraycopy( rawData, 0, data, offset + 4, rawData.length );
LittleEndian.putShort(data, 0 + offset, getSid());
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));
System.arraycopy( rawData, 0, data, 4 + offset, rawData.length);
return rawData.length + 4;
}
else
{
LittleEndian.putShort(data, 0 + offset, getSid());
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));

int pos = offset + 4;
for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
{
@@ -255,6 +268,45 @@ public abstract class AbstractEscherHolderRecord
return (EscherRecord) escherRecords.get(index);
}

/**
* Big drawing group records are split but it's easier to deal with them
* as a whole group so we need to join them together.
*/
public void join( AbstractEscherHolderRecord record )
{
int length = this.rawData.length + record.getRawData().length;
byte[] data = new byte[length];
System.arraycopy( rawData, 0, data, 0, rawData.length );
System.arraycopy( record.getRawData(), 0, data, rawData.length, record.getRawData().length );
rawData = data;
}

public void processContinueRecord( byte[] record )
{
int length = this.rawData.length + record.length;
byte[] data = new byte[length];
System.arraycopy( rawData, 0, data, 0, rawData.length );
System.arraycopy( record, 0, data, rawData.length, record.length );
rawData = data;
}

public byte[] getRawData()
{
return rawData;
}

public void setRawData( byte[] rawData )
{
this.rawData = rawData;
}

/**
* Convert raw data to escher records.
*/
public void decode()
{
convertToEscherRecords(0, rawData.length, rawData );
}

} // END OF CLASS


+ 100
- 0
src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java View File

@@ -16,10 +16,22 @@

package org.apache.poi.hssf.record;

import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.ddf.NullEscherSerializationListener;
import org.apache.poi.util.ArrayUtil;
import org.apache.poi.util.LittleEndian;

import java.util.Iterator;
import java.util.List;


public class DrawingGroupRecord extends AbstractEscherHolderRecord
{
public static final short sid = 0xEB;

static final int MAX_RECORD_SIZE = 8228;
private static final int MAX_DATA_SIZE = MAX_RECORD_SIZE - 4;

public DrawingGroupRecord()
{
}
@@ -43,4 +55,92 @@ public class DrawingGroupRecord extends AbstractEscherHolderRecord
{
return sid;
}

public int serialize(int offset, byte[] data)
{
byte[] rawData = getRawData();
if (getEscherRecords().size() == 0 && rawData != null)
{
return writeData( offset, data, rawData );
}
else
{
byte[] buffer = new byte[getRawDataSize()];
int pos = 0;
for ( Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); )
{
EscherRecord r = (EscherRecord) iterator.next();
pos += r.serialize(pos, buffer, new NullEscherSerializationListener() );
}

return writeData( offset, data, buffer );
}
}

/**
* Size of record (including 4 byte headers for all sections)
*/
public int getRecordSize()
{
return grossSizeFromDataSize( getRawDataSize() );
}

public int getRawDataSize()
{
List escherRecords = getEscherRecords();
byte[] rawData = getRawData();
if (escherRecords.size() == 0 && rawData != null)
{
return rawData.length;
}
else
{
int size = 0;
for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
{
EscherRecord r = (EscherRecord) iterator.next();
size += r.getRecordSize();
}
return size;
}
}

static int grossSizeFromDataSize(int dataSize)
{
return dataSize + ( (dataSize - 1) / MAX_DATA_SIZE + 1 ) * 4;
}

private int writeData( int offset, byte[] data, byte[] rawData )
{
int writtenActualData = 0;
int writtenRawData = 0;
while (writtenRawData < rawData.length)
{
int segmentLength = Math.min( rawData.length - writtenRawData, MAX_DATA_SIZE);
if (writtenRawData / MAX_DATA_SIZE >= 2)
writeContinueHeader( data, offset, segmentLength );
else
writeHeader( data, offset, segmentLength );
writtenActualData += 4;
offset += 4;
ArrayUtil.arraycopy( rawData, writtenRawData, data, offset, segmentLength );
offset += segmentLength;
writtenRawData += segmentLength;
writtenActualData += segmentLength;
}
return writtenActualData;
}

private void writeHeader( byte[] data, int offset, int sizeExcludingHeader )
{
LittleEndian.putShort(data, 0 + offset, getSid());
LittleEndian.putShort(data, 2 + offset, (short) sizeExcludingHeader);
}

private void writeContinueHeader( byte[] data, int offset, int sizeExcludingHeader )
{
LittleEndian.putShort(data, 0 + offset, ContinueRecord.sid);
LittleEndian.putShort(data, 2 + offset, (short) sizeExcludingHeader);
}

}

+ 8
- 0
src/java/org/apache/poi/hssf/record/DrawingRecord.java View File

@@ -68,6 +68,14 @@ public class DrawingRecord extends Record
recordData = data;
}

public void processContinueRecord( byte[] record )
{
byte[] newBuffer = new byte[ recordData.length + record.length ];
System.arraycopy( recordData, 0, newBuffer, 0, recordData.length );
System.arraycopy( record, 0, newBuffer, recordData.length, record.length);
recordData = newBuffer;
}

public int serialize( int offset, byte[] data )
{
if (recordData == null)

+ 8
- 5
src/java/org/apache/poi/hssf/record/EscherAggregate.java View File

@@ -20,7 +20,7 @@ import org.apache.poi.ddf.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.model.AbstractShape;
import org.apache.poi.hssf.model.TextboxShape;
import org.apache.poi.hssf.model.DrawingManager;
import org.apache.poi.hssf.model.DrawingManager2;
import org.apache.poi.hssf.model.ConvertAnchor;

import java.util.*;
@@ -256,10 +256,10 @@ public class EscherAggregate extends AbstractEscherHolderRecord

/** Maps shape container objects to their OBJ records */
private Map shapeToObj = new HashMap();
private DrawingManager drawingManager;
private DrawingManager2 drawingManager;
private short drawingGroupId;

public EscherAggregate( DrawingManager drawingManager )
public EscherAggregate( DrawingManager2 drawingManager )
{
this.drawingManager = drawingManager;
}
@@ -305,7 +305,7 @@ public class EscherAggregate extends AbstractEscherHolderRecord
/**
* Collapses the drawing records into an aggregate.
*/
public static EscherAggregate createAggregate( List records, int locFirstDrawingRecord, DrawingManager drawingManager )
public static EscherAggregate createAggregate( List records, int locFirstDrawingRecord, DrawingManager2 drawingManager )
{
// Keep track of any shape records created so we can match them back to the object id's.
// Textbox objects are also treated as shape objects.
@@ -571,6 +571,9 @@ public class EscherAggregate extends AbstractEscherHolderRecord
escherParent.addChildRecord( shapeModel.getSpContainer() );
}
}
// drawingManager.newCluster( (short)1 );
// drawingManager.newCluster( (short)2 );

}

private void convertGroup( HSSFShapeGroup shape, EscherContainerRecord escherParent, Map shapeToObj )
@@ -678,7 +681,7 @@ public class EscherAggregate extends AbstractEscherHolderRecord
spContainer1.setRecordId( EscherContainerRecord.SP_CONTAINER );
spContainer1.setOptions( (short) 0x000F );
spgr.setRecordId( EscherSpgrRecord.RECORD_ID );
spgr.setOptions( (short) 0x0001 ); // don't know what the 1 is for.
spgr.setOptions( (short) 0x0001 ); // version
spgr.setRectX1( patriarch.getX1() );
spgr.setRectY1( patriarch.getY1() );
spgr.setRectX2( patriarch.getX2() );

+ 8
- 0
src/java/org/apache/poi/hssf/record/ObjRecord.java View File

@@ -173,6 +173,14 @@ public class ObjRecord
return subrecords.add( o );
}

// made public to satisfy biffviewer

/* protected */
public void processContinueRecord( byte[] record )
{
super.processContinueRecord( record );
}

public Object clone()
{
ObjRecord rec = new ObjRecord();

+ 16
- 2
src/java/org/apache/poi/hssf/record/RecordFactory.java View File

@@ -148,6 +148,7 @@ public class RecordFactory
{
short rectype = 0;

DrawingRecord lastDrawingRecord = new DrawingRecord( );
do
{
rectype = LittleEndian.readShort(in);
@@ -176,7 +177,13 @@ public class RecordFactory

if (record != null)
{
if (rectype == ContinueRecord.sid &&
if (rectype == DrawingGroupRecord.sid
&& last_record instanceof DrawingGroupRecord)
{
DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) last_record;
lastDGRecord.join((AbstractEscherHolderRecord) record);
}
else if (rectype == ContinueRecord.sid &&
! (last_record instanceof ContinueRecord) && // include continuation records after
! (last_record instanceof UnknownRecord) ) // unknown records or previous continuation records
{
@@ -185,11 +192,18 @@ public class RecordFactory
throw new RecordFormatException(
"First record is a ContinueRecord??");
}
last_record.processContinueRecord(data);

// Drawing records have a very strange continue behaviour. There can actually be OBJ records mixed between the continues.
if (last_record instanceof ObjRecord)
lastDrawingRecord.processContinueRecord( data );
else
last_record.processContinueRecord(data);
}
else
{
last_record = record;
if (record instanceof DrawingRecord)
lastDrawingRecord = (DrawingRecord) record;
records.add(record);
}
}

+ 4
- 3
src/java/org/apache/poi/hssf/record/aggregates/ColumnInfoRecordsAggregate.java View File

@@ -14,7 +14,7 @@ import java.util.List;
public class ColumnInfoRecordsAggregate
extends Record
{
int size = 0;
// int size = 0;
List records = null;

public ColumnInfoRecordsAggregate()
@@ -40,6 +40,9 @@ public class ColumnInfoRecordsAggregate

public int getRecordSize()
{
int size = 0;
for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
size += ( (ColumnInfoRecord) iterator.next() ).getRecordSize();
return size;
}

@@ -68,7 +71,6 @@ public class ColumnInfoRecordsAggregate
*/
public void insertColumn( ColumnInfoRecord col )
{
size += col.getRecordSize();
records.add( col );
}

@@ -78,7 +80,6 @@ public class ColumnInfoRecordsAggregate
*/
public void insertColumn( int idx, ColumnInfoRecord col )
{
size += col.getRecordSize();
records.add( idx, col );
}


+ 1
- 1
src/java/org/apache/poi/hssf/record/aggregates/RowRecordsAggregate.java View File

@@ -228,7 +228,7 @@ public class RowRecordsAggregate

/**
* called by the constructor, should set class level fields. Should throw
* runtime exception for bad/icomplete data.
* runtime exception for bad/incomplete data.
*
* @param data raw data
* @param size size of data

+ 22
- 2
src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java View File

@@ -16,8 +16,7 @@

package org.apache.poi.hssf.usermodel;

import org.apache.poi.ddf.EscherClientAnchorRecord;
import org.apache.poi.ddf.EscherRecord;



/**
@@ -33,6 +32,7 @@ public class HSSFClientAnchor
int row1;
short col2;
int row2;
int anchorType;

/**
* Creates a new client anchor and defaults all the anchor positions to 0.
@@ -213,6 +213,26 @@ public class HSSFClientAnchor
return row1 > row2;
}

/**
* Gets the anchor type
* <p>
* 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
*/
public int getAnchorType()
{
return anchorType;
}

/**
* Sets the anchor type
* <p>
* 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
*/
public void setAnchorType( int anchorType )
{
this.anchorType = anchorType;
}

private void checkRange( int value, int minRange, int maxRange, String varName )
{
if (value < minRange || value > maxRange)

+ 17
- 0
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java View File

@@ -77,6 +77,23 @@ public class HSSFPatriarch
return shape;
}

/**
* Creates a picture.
*
* @param anchor the client anchor describes how this group is attached
* to the sheet.
* @return the newly created shape.
*/
public HSSFPicture createPicture(HSSFClientAnchor anchor, int pictureIndex)
{
HSSFPicture shape = new HSSFPicture(null, anchor);
shape.setPictureIndex( pictureIndex );
shape.anchor = anchor;
shapes.add(shape);
return shape;
}


/**
* Creates a polygon
*

+ 7
- 4
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java View File

@@ -1220,19 +1220,22 @@ public class HSSFSheet
* Aggregates the drawing records and dumps the escher record hierarchy
* to the standard output.
*/
public void dumpDrawingRecords()
public void dumpDrawingRecords(boolean fat)
{
sheet.aggregateDrawingRecords(book.getDrawingManager());

EscherAggregate r = (EscherAggregate) getSheet().findFirstRecordBySid(EscherAggregate.sid);
List escherRecords = r.getEscherRecords();
PrintWriter w = new PrintWriter(System.out);
for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
{
EscherRecord escherRecord = (EscherRecord) iterator.next();
PrintWriter w = new PrintWriter(System.out);
escherRecord.display(w, 0);
w.close();
if (fat)
System.out.println(escherRecord.toString());
else
escherRecord.display(w, 0);
}
w.flush();
}

/**

+ 3
- 1
src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java View File

@@ -34,7 +34,7 @@ public class HSSFSimpleShape
// public final static short OBJECT_TYPE_CHART = 5;
// public final static short OBJECT_TYPE_TEXT = 6;
// public final static short OBJECT_TYPE_BUTTON = 7;
// public final static short OBJECT_TYPE_PICTURE = 8;
public final static short OBJECT_TYPE_PICTURE = 8;
// public final static short OBJECT_TYPE_POLYGON = 9;
// public final static short OBJECT_TYPE_CHECKBOX = 11;
// public final static short OBJECT_TYPE_OPTION_BUTTON = 12;
@@ -63,6 +63,7 @@ public class HSSFSimpleShape
* @see #OBJECT_TYPE_LINE
* @see #OBJECT_TYPE_OVAL
* @see #OBJECT_TYPE_RECTANGLE
* @see #OBJECT_TYPE_PICTURE
*/
public int getShapeType() { return shapeType; }

@@ -74,6 +75,7 @@ public class HSSFSimpleShape
* @see #OBJECT_TYPE_LINE
* @see #OBJECT_TYPE_OVAL
* @see #OBJECT_TYPE_RECTANGLE
* @see #OBJECT_TYPE_PICTURE
*/
public void setShapeType( int shapeType ){ this.shapeType = shapeType; }


+ 88
- 6
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java View File

@@ -22,6 +22,9 @@
*/
package org.apache.poi.hssf.usermodel;

import org.apache.poi.ddf.EscherBSERecord;
import org.apache.poi.ddf.EscherBitmapBlip;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hssf.eventmodel.EventRecordFactory;
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.model.Workbook;
@@ -38,6 +41,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -57,7 +61,6 @@ import java.util.Stack;
*/

public class HSSFWorkbook
extends java.lang.Object
{
private static final int DEBUG = POILogger.DEBUG;

@@ -108,13 +111,31 @@ public class HSSFWorkbook
*/
private HSSFDataFormat formatter;


/// NOT YET SUPPORTED:
/** Extended windows meta file */
//public static final int PICTURE_TYPE_EMF = 2;
/** Windows Meta File */
//public static final int PICTURE_TYPE_WMF = 3;
/** Mac PICT format */
//public static final int PICTURE_TYPE_PICT = 4;

/** JPEG format */
public static final int PICTURE_TYPE_JPEG = 5;
/** PNG format */
public static final int PICTURE_TYPE_PNG = 6;
/** Device independant bitmap */
public static final int PICTURE_TYPE_DIB = 7;


private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class);



/**
* Creates new HSSFWorkbook from scratch (start here!)
*
*/

public HSSFWorkbook()
{
this(Workbook.createWorkbook());
@@ -159,8 +180,6 @@ public class HSSFWorkbook

EventRecordFactory factory = new EventRecordFactory();



List records = RecordFactory.createRecords(stream);

workbook = Workbook.createWorkbook(records);
@@ -796,8 +815,9 @@ public class HSSFWorkbook

// byte[] sb = (byte[])sheetbytes.get(k);
// System.arraycopy(sb, 0, retval, pos, sb.length);
pos += ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos,
retval); // sb.length;
int len = ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos,
retval);
pos += len; // sb.length;
}
/* for (int k = pos; k < totalsize; k++)
{
@@ -1067,6 +1087,68 @@ public class HSSFWorkbook
workbook.getRecords().add(loc, r);
}

/**
* Spits out a list of all the drawing records in the workbook.
*/
public void dumpDrawingGroupRecords(boolean fat)
{
DrawingGroupRecord r = (DrawingGroupRecord) workbook.findFirstRecordBySid( DrawingGroupRecord.sid );
r.decode();
List escherRecords = r.getEscherRecords();
PrintWriter w = new PrintWriter(System.out);
for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
{
EscherRecord escherRecord = (EscherRecord) iterator.next();
if (fat)
System.out.println(escherRecord.toString());
else
escherRecord.display(w, 0);
}
w.flush();
}

/**
* Adds a picture to the workbook.
*
* @param pictureData The bytes of the picture
* @param format The format of the picture. One of <code>PICTURE_TYPE_*</code>
*
* @return the index to this picture (1 based).
*/
public int addPicture(byte[] pictureData, int format)
{
byte[] uid = newUID();
EscherBitmapBlip blipRecord = new EscherBitmapBlip();
blipRecord.setRecordId( (short) ( EscherBitmapBlip.RECORD_ID_START + format ) );
if (format == HSSFWorkbook.PICTURE_TYPE_PNG)
blipRecord.setOptions( (short) 0x6E00 ); // MSOBI
else if (format == HSSFWorkbook.PICTURE_TYPE_JPEG)
blipRecord.setOptions( (short) 0x46A0 ); // MSOBI
else if (format == HSSFWorkbook.PICTURE_TYPE_DIB)
blipRecord.setOptions( (short) 0x7A8 ); // MSOBI

blipRecord.setUID( uid );
blipRecord.setMarker( (byte) 0xFF );
blipRecord.setPictureData( pictureData );

EscherBSERecord r = new EscherBSERecord();
r.setRecordId( EscherBSERecord.RECORD_ID );
r.setOptions( (short) ( 0x0002 | ( format << 4 ) ) );
r.setBlipTypeMacOS( (byte) format );
r.setBlipTypeWin32( (byte) format );
r.setUid( uid );
r.setTag( (short) 0xFF );
r.setSize( pictureData.length + 25 );
r.setRef( 1 );
r.setOffset( 0 );
r.setBlipRecord( blipRecord );

return workbook.addBSERecord( r );
}

private byte[] newUID()
{
byte[] bytes = new byte[16];
return bytes;
}
}

+ 11
- 4
src/java/org/apache/poi/util/DrawingDump.java View File

@@ -17,12 +17,11 @@
package org.apache.poi.util;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
@@ -35,7 +34,15 @@ public class DrawingDump
POIFSFileSystem fs =
new POIFSFileSystem(new FileInputStream(args[0]));
HSSFWorkbook wb = new HSSFWorkbook(fs);
HSSFSheet sheet = wb.getSheetAt(0);
sheet.dumpDrawingRecords();
System.out.println( "Drawing group:" );
wb.dumpDrawingGroupRecords(true);

for (int sheetNum = 1; sheetNum <= wb.getNumberOfSheets(); sheetNum++)
{
System.out.println( "Sheet " + sheetNum + ":" );
HSSFSheet sheet = wb.getSheetAt(sheetNum - 1);
sheet.dumpDrawingRecords(true);
}

}
}

+ 1
- 1
src/java/org/apache/poi/util/HexDump.java View File

@@ -75,7 +75,7 @@ public class HexDump
{
if (data.length == 0)
{
stream.write( "No Data".getBytes() );
stream.write( ("No Data" + System.getProperty( "line.separator")).getBytes() );
stream.flush();
return;
}

+ 2
- 1
src/testcases/org/apache/poi/ddf/TestEscherBSERecord.java View File

@@ -98,8 +98,9 @@ public class TestEscherBSERecord extends TestCase
" Name: 5" + nl +
" Unused2: 6" + nl +
" Unused3: 7" + nl +
" blipRecord: null" + nl +
" Extra Data:" + nl +
"No Data", record.toString() );
"No Data" + nl, record.toString() );
}

}

src/testcases/org/apache/poi/ddf/TestEscherBlipRecord.java → src/testcases/org/apache/poi/ddf/TestEscherBlipWMFRecord.java View File

@@ -21,7 +21,7 @@ import junit.framework.TestCase;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.HexRead;

public class TestEscherBlipRecord extends TestCase
public class TestEscherBlipWMFRecord extends TestCase
{
private String dataStr;
private byte[] data;
@@ -37,7 +37,7 @@ public class TestEscherBlipRecord extends TestCase

public void testSerialize() throws Exception
{
EscherBlipRecord r = new EscherBlipRecord();
EscherBlipWMFRecord r = new EscherBlipWMFRecord();
r.setBoundaryLeft(1);
r.setBoundaryHeight(2);
r.setBoundaryTop(3);
@@ -52,7 +52,7 @@ public class TestEscherBlipRecord extends TestCase
(byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, });
r.setWidth(10);
r.setHeight(11);
r.setRecordId(EscherBlipRecord.RECORD_ID_START);
r.setRecordId(EscherBlipWMFRecord.RECORD_ID_START);
r.setOptions((short)5420);
r.setData(new byte[] { (byte)0x01, (byte)0x02 } );

@@ -79,10 +79,10 @@ public class TestEscherBlipRecord extends TestCase

public void testFillFields() throws Exception
{
EscherBlipRecord r = new EscherBlipRecord();
EscherBlipWMFRecord r = new EscherBlipWMFRecord();
r.fillFields( data, 0, new DefaultEscherRecordFactory());

assertEquals( EscherBlipRecord.RECORD_ID_START, r.getRecordId() );
assertEquals( EscherBlipWMFRecord.RECORD_ID_START, r.getRecordId() );
assertEquals( 1, r.getBoundaryLeft() );
assertEquals( 2, r.getBoundaryHeight() );
assertEquals( 3, r.getBoundaryTop() );
@@ -100,12 +100,12 @@ public class TestEscherBlipRecord extends TestCase

public void testToString() throws Exception
{
EscherBlipRecord r = new EscherBlipRecord();
EscherBlipWMFRecord r = new EscherBlipWMFRecord();
r.fillFields( data, 0, new DefaultEscherRecordFactory() );

String nl = System.getProperty("line.separator");

assertEquals( "org.apache.poi.ddf.EscherBlipRecord:" + nl +
assertEquals( "org.apache.poi.ddf.EscherBlipWMFRecord:" + nl +
" RecordId: 0xF018" + nl +
" Options: 0x152C" + nl +
" Secondary UID: [01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, ]" + nl +

+ 1
- 1
src/testcases/org/apache/poi/ddf/TestEscherBoolProperty.java View File

@@ -24,7 +24,7 @@ public class TestEscherBoolProperty extends TestCase
public void testToString() throws Exception
{
EscherBoolProperty p = new EscherBoolProperty((short)1, 1);
assertEquals("propNum: 1, propName: unknown, complex: false, blipId: false, value: 1 (0x00000001)", p.toString());
assertEquals("propNum: 1, RAW: 0x0001, propName: unknown, complex: false, blipId: false, value: 1 (0x00000001)", p.toString());
}

}

+ 1
- 1
src/testcases/org/apache/poi/ddf/TestEscherClientDataRecord.java View File

@@ -58,7 +58,7 @@ public class TestEscherClientDataRecord extends TestCase
" RecordId: 0xF011" + nl +
" Options: 0x0002" + nl +
" Extra Data:" + nl +
"No Data" ;
"No Data" + nl ;
assertEquals( expected, createRecord().toString() );
}


+ 1
- 1
src/testcases/org/apache/poi/ddf/TestEscherOptRecord.java View File

@@ -150,7 +150,7 @@ public class TestEscherOptRecord extends TestCase
" recordId: 0x" + HexDump.toHex(EscherOptRecord.RECORD_ID) + nl +
" numchildren: 0" + nl +
" properties:" + nl +
" propNum: 1, propName: unknown, complex: false, blipId: false, value: 1 (0x00000001)" + nl;
" propNum: 1, RAW: 0x0001, propName: unknown, complex: false, blipId: false, value: 1 (0x00000001)" + nl;
assertEquals( expected, r.toString());
}


+ 232
- 6
src/testcases/org/apache/poi/hssf/model/TestSheet.java View File

@@ -19,16 +19,14 @@
package org.apache.poi.hssf.model;

import junit.framework.TestCase;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.EOFRecord;
import org.apache.poi.hssf.record.DimensionsRecord;
import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.ValueRecordsAggregate;
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
* Unit test for the Sheet class.
@@ -55,4 +53,232 @@ public class TestSheet extends TestCase
assertTrue( sheet.records.get(pos++) instanceof EOFRecord );
}

public void testAddMergedRegion()
{
Sheet sheet = Sheet.createSheet();
int regionsToAdd = 4096;
int startRecords = sheet.getRecords().size();

//simple test that adds a load of regions
for (int n = 0; n < regionsToAdd; n++)
{
int index = sheet.addMergedRegion(0, (short) 0, 1, (short) 1);
assertTrue("Merged region index expected to be " + n + " got " + index, index == n);
}

//test all the regions were indeed added
assertTrue(sheet.getNumMergedRegions() == regionsToAdd);

//test that the regions were spread out over the appropriate number of records
int recordsAdded = sheet.getRecords().size() - startRecords;
int recordsExpected = regionsToAdd/1027;
if ((regionsToAdd % 1027) != 0)
recordsExpected++;
assertTrue("The " + regionsToAdd + " merged regions should have been spread out over " + recordsExpected + " records, not " + recordsAdded, recordsAdded == recordsExpected);
}

public void testRemoveMergedRegion()
{
Sheet sheet = Sheet.createSheet();
int regionsToAdd = 4096;

for (int n = 0; n < regionsToAdd; n++)
sheet.addMergedRegion(0, (short) 0, 1, (short) 1);

int records = sheet.getRecords().size();

//remove a third from the beginning
for (int n = 0; n < regionsToAdd/3; n++)
{
sheet.removeMergedRegion(0);
//assert they have been deleted
assertTrue("Num of regions should be " + (regionsToAdd - n - 1) + " not " + sheet.getNumMergedRegions(), sheet.getNumMergedRegions() == regionsToAdd - n - 1);
}

//assert any record removing was done
int recordsRemoved = (regionsToAdd/3)/1027; //doesn't work for particular values of regionsToAdd
assertTrue("Expected " + recordsRemoved + " record to be removed from the starting " + records + ". Currently there are " + sheet.getRecords().size() + " records", records - sheet.getRecords().size() == recordsRemoved);
}

/**
* Bug: 22922 (Reported by Xuemin Guan)
* <p>
* Remove mergedregion fails when a sheet loses records after an initial CreateSheet
* fills up the records.
*
*/
public void testMovingMergedRegion() {
List records = new ArrayList();

MergeCellsRecord merged = new MergeCellsRecord();
merged.addArea(0, (short)0, 1, (short)2);
records.add(new RowRecord());
records.add(new RowRecord());
records.add(new RowRecord());
records.add(merged);

Sheet sheet = Sheet.createSheet(records, 0);
sheet.records.remove(0);

//stub object to throw off list INDEX operations
sheet.removeMergedRegion(0);
assertEquals("Should be no more merged regions", 0, sheet.getNumMergedRegions());
}

public void testGetMergedRegionAt()
{
//TODO
}

public void testGetNumMergedRegions()
{
//TODO
}

/**
* Makes sure all rows registered for this sheet are aggregated, they were being skipped
*
*/
public void testRowAggregation() {
List records = new ArrayList();
RowRecord row = new RowRecord();
row.setRowNumber(0);
records.add(row);

row = new RowRecord();
row.setRowNumber(1);
records.add(row);

records.add(new StringRecord());

row = new RowRecord();
row.setRowNumber(2);
records.add(row);


Sheet sheet = Sheet.createSheet(records, 0);
assertNotNull("Row [2] was skipped", sheet.getRow(2));

}

/**
* Make sure page break functionality works (in memory)
*
*/
public void testRowPageBreaks(){
short colFrom = 0;
short colTo = 255;

Sheet sheet = Sheet.createSheet();
sheet.setRowBreak(0, colFrom, colTo);

assertTrue("no row break at 0", sheet.isRowBroken(0));
assertEquals("1 row break available", 1, sheet.getNumRowBreaks());

sheet.setRowBreak(0, colFrom, colTo);
sheet.setRowBreak(0, colFrom, colTo);

assertTrue("no row break at 0", sheet.isRowBroken(0));
assertEquals("1 row break available", 1, sheet.getNumRowBreaks());

sheet.setRowBreak(10, colFrom, colTo);
sheet.setRowBreak(11, colFrom, colTo);

assertTrue("no row break at 10", sheet.isRowBroken(10));
assertTrue("no row break at 11", sheet.isRowBroken(11));
assertEquals("3 row break available", 3, sheet.getNumRowBreaks());


boolean is10 = false;
boolean is0 = false;
boolean is11 = false;

Iterator iterator = sheet.getRowBreaks();
while (iterator.hasNext()) {
PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
int main = (int)breakItem.main;
if (main != 0 && main != 10 && main != 11) fail("Invalid page break");
if (main == 0) is0 = true;
if (main == 10) is10= true;
if (main == 11) is11 = true;
}

assertTrue("one of the breaks didnt make it", is0 && is10 && is11);

sheet.removeRowBreak(11);
assertFalse("row should be removed", sheet.isRowBroken(11));

sheet.removeRowBreak(0);
assertFalse("row should be removed", sheet.isRowBroken(0));

sheet.removeRowBreak(10);
assertFalse("row should be removed", sheet.isRowBroken(10));

assertEquals("no more breaks", 0, sheet.getNumRowBreaks());


}

/**
* Make sure column pag breaks works properly (in-memory)
*
*/
public void testColPageBreaks(){
short rowFrom = 0;
short rowTo = (short)65535;

Sheet sheet = Sheet.createSheet();
sheet.setColumnBreak((short)0, rowFrom, rowTo);

assertTrue("no col break at 0", sheet.isColumnBroken((short)0));
assertEquals("1 col break available", 1, sheet.getNumColumnBreaks());

sheet.setColumnBreak((short)0, rowFrom, rowTo);

assertTrue("no col break at 0", sheet.isColumnBroken((short)0));
assertEquals("1 col break available", 1, sheet.getNumColumnBreaks());

sheet.setColumnBreak((short)1, rowFrom, rowTo);
sheet.setColumnBreak((short)10, rowFrom, rowTo);
sheet.setColumnBreak((short)15, rowFrom, rowTo);

assertTrue("no col break at 1", sheet.isColumnBroken((short)1));
assertTrue("no col break at 10", sheet.isColumnBroken((short)10));
assertTrue("no col break at 15", sheet.isColumnBroken((short)15));
assertEquals("4 col break available", 4, sheet.getNumColumnBreaks());

boolean is10 = false;
boolean is0 = false;
boolean is1 = false;
boolean is15 = false;

Iterator iterator = sheet.getColumnBreaks();
while (iterator.hasNext()) {
PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
int main = (int)breakItem.main;
if (main != 0 && main != 1 && main != 10 && main != 15) fail("Invalid page break");
if (main == 0) is0 = true;
if (main == 1) is1 = true;
if (main == 10) is10= true;
if (main == 15) is15 = true;
}

assertTrue("one of the breaks didnt make it", is0 && is1 && is10 && is15);

sheet.removeColumnBreak((short)15);
assertFalse("column break should not be there", sheet.isColumnBroken((short)15));

sheet.removeColumnBreak((short)0);
assertFalse("column break should not be there", sheet.isColumnBroken((short)0));

sheet.removeColumnBreak((short)1);
assertFalse("column break should not be there", sheet.isColumnBroken((short)1));

sheet.removeColumnBreak((short)10);
assertFalse("column break should not be there", sheet.isColumnBroken((short)10));

assertEquals("no more breaks", 0, sheet.getNumColumnBreaks());
}


}

+ 91
- 0
src/testcases/org/apache/poi/hssf/record/TestDrawingGroupRecord.java View File

@@ -23,6 +23,9 @@ import org.apache.poi.util.HexDump;

public class TestDrawingGroupRecord extends TestCase
{
static final int MAX_RECORD_SIZE = 8228;
private static final int MAX_DATA_SIZE = MAX_RECORD_SIZE - 4;

public void testGetRecordSize()
throws Exception
{
@@ -48,5 +51,93 @@ public class TestDrawingGroupRecord extends TestCase
assertEquals(28, size);

assertEquals(24, dggContainer.getRecordSize());


r = new DrawingGroupRecord( );
r.setRawData( new byte[MAX_DATA_SIZE] );
assertEquals( MAX_RECORD_SIZE, r.getRecordSize() );
r.setRawData( new byte[MAX_DATA_SIZE+1] );
assertEquals( MAX_RECORD_SIZE + 5, r.getRecordSize() );
r.setRawData( new byte[MAX_DATA_SIZE*2] );
assertEquals( MAX_RECORD_SIZE * 2, r.getRecordSize() );
r.setRawData( new byte[MAX_DATA_SIZE*2 + 1] );
assertEquals( MAX_RECORD_SIZE * 2 + 5, r.getRecordSize() );
}

public void testSerialize() throws Exception
{
// Check under max record size
DrawingGroupRecord r = new DrawingGroupRecord();
byte[] rawData = new byte[100];
rawData[0] = 100;
rawData[99] = (byte) 200;
r.setRawData( rawData );
byte[] buffer = new byte[r.getRecordSize()];
int size = r.serialize( 0, buffer );
assertEquals( 104, size );
assertEquals("[EB, 00, 64, 00, 64, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, C8, ]", HexDump.toHex(buffer));

// check at max record size
rawData = new byte[MAX_DATA_SIZE];
r.setRawData( rawData );
buffer = new byte[r.getRecordSize()];
size = r.serialize( 0, buffer );
assertEquals( MAX_RECORD_SIZE, size );

// check over max record size
rawData = new byte[MAX_DATA_SIZE+1];
rawData[rawData.length-1] = (byte) 255;
r.setRawData( rawData );
buffer = new byte[r.getRecordSize()];
size = r.serialize( 0, buffer );
assertEquals( MAX_RECORD_SIZE + 5, size );
assertEquals( "[EB, 00, 20, 20, ]", HexDump.toHex(cut(buffer, 0, 4) ));
assertEquals( "[00, EB, 00, 01, 00, FF, ]", HexDump.toHex(cut(buffer, MAX_RECORD_SIZE - 1, MAX_RECORD_SIZE + 5) ));

// check continue record
rawData = new byte[MAX_DATA_SIZE * 2 + 1];
rawData[rawData.length-1] = (byte) 255;
r.setRawData( rawData );
buffer = new byte[r.getRecordSize()];
size = r.serialize( 0, buffer );
assertEquals( MAX_RECORD_SIZE * 2 + 5, size );
assertEquals( MAX_RECORD_SIZE * 2 + 5, r.getRecordSize() );
assertEquals( "[EB, 00, 20, 20, ]", HexDump.toHex(cut(buffer, 0, 4) ));
assertEquals( "[EB, 00, 20, 20, ]", HexDump.toHex(cut(buffer, MAX_RECORD_SIZE, MAX_RECORD_SIZE + 4) ));
assertEquals( "[3C, 00, 01, 00, FF, ]", HexDump.toHex(cut(buffer, MAX_RECORD_SIZE * 2, MAX_RECORD_SIZE * 2 + 5) ));

// check continue record
rawData = new byte[664532];
r.setRawData( rawData );
buffer = new byte[r.getRecordSize()];
size = r.serialize( 0, buffer );
assertEquals( 664856, size );
assertEquals( 664856, r.getRecordSize() );
}

private byte[] cut( byte[] data, int fromInclusive, int toExclusive )
{
int length = toExclusive - fromInclusive;
byte[] result = new byte[length];
System.arraycopy( data, fromInclusive, result, 0, length);
return result;
}

public void testGrossSizeFromDataSize() throws Exception
{
for (int i = 0; i < MAX_RECORD_SIZE * 4; i += 11)
{
System.out.print( "data size = " + i + ", gross size = " + DrawingGroupRecord.grossSizeFromDataSize( i ) );
System.out.println( " Diff: " + (DrawingGroupRecord.grossSizeFromDataSize( i ) - i) );
}

assertEquals( 4, DrawingGroupRecord.grossSizeFromDataSize( 0 ) );
assertEquals( 5, DrawingGroupRecord.grossSizeFromDataSize( 1 ) );
assertEquals( MAX_RECORD_SIZE, DrawingGroupRecord.grossSizeFromDataSize( MAX_DATA_SIZE ) );
assertEquals( MAX_RECORD_SIZE + 5, DrawingGroupRecord.grossSizeFromDataSize( MAX_DATA_SIZE + 1 ) );
assertEquals( MAX_RECORD_SIZE * 2, DrawingGroupRecord.grossSizeFromDataSize( MAX_DATA_SIZE * 2 ) );
assertEquals( MAX_RECORD_SIZE * 2 + 5, DrawingGroupRecord.grossSizeFromDataSize( MAX_DATA_SIZE * 2 + 1 ) );
}


}

+ 6
- 7
src/testcases/org/apache/poi/hssf/record/TestEscherAggregate.java View File

@@ -17,14 +17,13 @@
package org.apache.poi.hssf.record;

import junit.framework.TestCase;
import org.apache.poi.util.HexRead;
import org.apache.poi.util.HexDump;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.ddf.EscherClientDataRecord;
import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.hssf.model.DrawingManager;
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.hssf.model.DrawingManager2;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.HexRead;

import java.util.ArrayList;
import java.util.List;
@@ -82,7 +81,7 @@ public class TestEscherAggregate extends TestCase
records.add( d2 );
records.add( r2 );

DrawingManager drawingManager = new DrawingManager(new EscherDggRecord() );
DrawingManager2 drawingManager = new DrawingManager2(new EscherDggRecord() );
EscherAggregate aggregate = EscherAggregate.createAggregate( records, 0, drawingManager );

assertEquals( 1, aggregate.getEscherRecords().size() );

+ 4
- 2
src/testcases/org/apache/poi/util/TestHexDump.java View File

@@ -23,6 +23,7 @@ import junit.framework.*;
import java.io.*;

/**
* @author Glen Stampoultzis (glens at apache.org)
* @author Marc Johnson (mjohnson at apache dot org)
*/

@@ -281,7 +282,8 @@ public class TestHexDump
// verify proper behaviour with empty byte array
ByteArrayOutputStream os = new ByteArrayOutputStream( );
HexDump.dump( new byte[0], 0, os, 0 );
assertEquals( "No Data", os.toString() );
assertEquals( "No Data" + System.getProperty( "line.separator"), os.toString() );

}

public void testToHex()
@@ -289,7 +291,7 @@ public class TestHexDump
{
assertEquals( "000A", HexDump.toHex((short)0xA));
assertEquals( "0A", HexDump.toHex((byte)0xA));
assertEquals( "0000000A", HexDump.toHex((int)0xA));
assertEquals( "0000000A", HexDump.toHex(0xA));

assertEquals( "FFFF", HexDump.toHex((short)0xFFFF));


+ 4
- 4
src/testcases/org/apache/poi/util/TestLittleEndian.java View File

@@ -18,11 +18,12 @@

package org.apache.poi.util;

import junit.framework.TestCase;
import org.apache.poi.util.LittleEndian.BufferUnderrunException;

import java.io.*;
import junit.framework.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
* Class to test LittleEndian functionality
@@ -39,7 +40,6 @@ public class TestLittleEndian
*
* @param name
*/

public TestLittleEndian(String name)
{
super(name);

Loading…
Cancel
Save