Ported the drawing stuff from the rel_2_branch. Given the effort this took I'm really really wanting to move to subversion.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353542 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
89101ac1da
commit
d335e740b6
25
build.xml
25
build.xml
@ -135,10 +135,27 @@ Main targets:
|
|||||||
</echo>
|
</echo>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
<target name="with.clover" if="clover.present">
|
||||||
|
<taskdef resource="clovertasks"/>
|
||||||
|
<clover-setup initString="mycoverage.db"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="clover.html" depends="with.clover" if="clover.present">
|
||||||
|
<echo>Generating clover report</echo>
|
||||||
|
<clover-report>
|
||||||
|
<current outfile="build/tmp/site/build/site/clover_html">
|
||||||
|
<format type="html"/>
|
||||||
|
</current>
|
||||||
|
</clover-report>
|
||||||
|
</target>
|
||||||
|
|
||||||
<target name="init" depends="check-jars,fetch-jars">
|
<target name="init" depends="check-jars,fetch-jars">
|
||||||
|
|
||||||
<tstamp/>
|
<tstamp/>
|
||||||
|
|
||||||
|
<available resource="clovertasks" property="clover.present"/>
|
||||||
|
<antcall target="with.clover"/>
|
||||||
|
|
||||||
<mkdir dir="build"/>
|
<mkdir dir="build"/>
|
||||||
<mkdir dir="${main.output.dir}"/>
|
<mkdir dir="${main.output.dir}"/>
|
||||||
<mkdir dir="${contrib.output.dir}"/>
|
<mkdir dir="${contrib.output.dir}"/>
|
||||||
@ -253,7 +270,7 @@ Main targets:
|
|||||||
<pathelement location="${junit.jar1.dir}"/>
|
<pathelement location="${junit.jar1.dir}"/>
|
||||||
</path>
|
</path>
|
||||||
<target name="test-main" depends="compile-main,-test-main-check" unless="main.test.notRequired">
|
<target name="test-main" depends="compile-main,-test-main-check" unless="main.test.notRequired">
|
||||||
<junit printsummary="yes" showoutput="true" filtertrace="no" fork="no"
|
<junit printsummary="no" showoutput="true" fork="no"
|
||||||
haltonfailure="${halt.on.test.failure}" failureproperty="main.test.failed">
|
haltonfailure="${halt.on.test.failure}" failureproperty="main.test.failed">
|
||||||
<classpath refid="test.classpath"/>
|
<classpath refid="test.classpath"/>
|
||||||
<sysproperty key="HSSF.testdata.path" file="${main.src.test}/org/apache/poi/hssf/data"/>
|
<sysproperty key="HSSF.testdata.path" file="${main.src.test}/org/apache/poi/hssf/data"/>
|
||||||
@ -312,7 +329,7 @@ Main targets:
|
|||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="test-scratchpad" depends="compile-scratchpad,-test-scratchpad-check" unless="scratchpad.test.notRequired">
|
<target name="test-scratchpad" depends="compile-scratchpad,-test-scratchpad-check" unless="scratchpad.test.notRequired">
|
||||||
<junit printsummary="yes" fork="no" haltonfailure="${halt.on.test.failure}" failureproperty="scratchpad.test.failed">
|
<junit printsummary="no" fork="no" haltonfailure="${halt.on.test.failure}" failureproperty="scratchpad.test.failed">
|
||||||
<classpath>
|
<classpath>
|
||||||
<path refid="scratchpad.classpath"/>
|
<path refid="scratchpad.classpath"/>
|
||||||
<pathelement location="${main.output.dir}"/>
|
<pathelement location="${main.output.dir}"/>
|
||||||
@ -521,6 +538,7 @@ FORREST_HOME environment variable!</echo>
|
|||||||
<group title="Utils" packages="org.apache.poi.util*"/>
|
<group title="Utils" packages="org.apache.poi.util*"/>
|
||||||
</javadoc>
|
</javadoc>
|
||||||
|
|
||||||
|
<antcall target="clover.html"/>
|
||||||
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
@ -560,6 +578,9 @@ FORREST_HOME environment variable!</echo>
|
|||||||
<group title="Record Generator" packages="org.apache.poi.record*"/>
|
<group title="Record Generator" packages="org.apache.poi.record*"/>
|
||||||
<group title="Utils" packages="org.apache.poi.util*"/>
|
<group title="Utils" packages="org.apache.poi.util*"/>
|
||||||
</javadoc>
|
</javadoc>
|
||||||
|
|
||||||
|
<antcall target="clover.html"/>
|
||||||
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
package org.apache.poi.contrib.metrics;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class FontMetricsDumper
|
||||||
|
{
|
||||||
|
public static void main( String[] args ) throws IOException
|
||||||
|
{
|
||||||
|
|
||||||
|
Properties props = new Properties();
|
||||||
|
|
||||||
|
Font[] allFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
|
||||||
|
for ( int i = 0; i < allFonts.length; i++ )
|
||||||
|
{
|
||||||
|
String fontName = allFonts[i].getFontName();
|
||||||
|
|
||||||
|
Font font = new Font(fontName, Font.BOLD, 10);
|
||||||
|
FontMetrics fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(font);
|
||||||
|
int fontHeight = fontMetrics.getHeight();
|
||||||
|
|
||||||
|
props.setProperty("font." + fontName + ".height", fontHeight+"");
|
||||||
|
StringBuffer characters = new StringBuffer();
|
||||||
|
for (char c = 'a'; c <= 'z'; c++)
|
||||||
|
{
|
||||||
|
characters.append( c + ", " );
|
||||||
|
}
|
||||||
|
for (char c = 'A'; c <= 'Z'; c++)
|
||||||
|
{
|
||||||
|
characters.append( c + ", " );
|
||||||
|
}
|
||||||
|
for (char c = '0'; c <= '9'; c++)
|
||||||
|
{
|
||||||
|
characters.append( c + ", " );
|
||||||
|
}
|
||||||
|
StringBuffer widths = new StringBuffer();
|
||||||
|
for (char c = 'a'; c <= 'z'; c++)
|
||||||
|
{
|
||||||
|
widths.append( fontMetrics.getWidths()[c] + ", " );
|
||||||
|
}
|
||||||
|
for (char c = 'A'; c <= 'Z'; c++)
|
||||||
|
{
|
||||||
|
widths.append( fontMetrics.getWidths()[c] + ", " );
|
||||||
|
}
|
||||||
|
for (char c = '0'; c <= '9'; c++)
|
||||||
|
{
|
||||||
|
widths.append( fontMetrics.getWidths()[c] + ", " );
|
||||||
|
}
|
||||||
|
props.setProperty("font." + fontName + ".characters", characters.toString());
|
||||||
|
props.setProperty("font." + fontName + ".widths", widths.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOutputStream fileOut = new FileOutputStream("font_metrics.properties");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
props.store(fileOut, "Font Metrics");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fileOut.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -40,6 +40,9 @@
|
|||||||
<li><link href="#Splits">Create split and freeze panes.</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="#Repeating">Repeating rows and columns.</link></li>
|
||||||
<li><link href="#HeaderFooter">Headers and Footers.</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>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section><title>Features</title>
|
<section><title>Features</title>
|
||||||
@ -692,6 +695,212 @@
|
|||||||
fileOut.close();
|
fileOut.close();
|
||||||
</source>
|
</source>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<anchor id="DrawingShapes"/>
|
||||||
|
<section><title>Drawing Shapes</title>
|
||||||
|
<p>
|
||||||
|
POI supports drawing shapes using the Microsoft Office
|
||||||
|
drawing tools. Shapes on a sheet are organized in a
|
||||||
|
hiearchy of groups and and shapes. The top-most shape
|
||||||
|
is the patriarch. This is not visisble on the sheet
|
||||||
|
at all. To start drawing you need to call <code>createPatriarch</code>
|
||||||
|
on the <code>HSSFSheet</code> class. This has the
|
||||||
|
effect erasing any other shape information stored
|
||||||
|
in that sheet. By default POI will leave shape
|
||||||
|
records alone in the sheet unless you make a call to
|
||||||
|
this method.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
To create a shape you have to go through the following
|
||||||
|
steps:
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li>Create the patriarch.</li>
|
||||||
|
<li>Create an anchor to position the shape on the sheet.</li>
|
||||||
|
<li>Ask the patriarch to create the shape.</li>
|
||||||
|
<li>Set the shape type (line, oval, rectangle etc...)</li>
|
||||||
|
<li>Set any other style details converning the shape. (eg:
|
||||||
|
line thickness, etc...)</li>
|
||||||
|
</ol>
|
||||||
|
<source>
|
||||||
|
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
|
||||||
|
a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 1, 0, (short) 1, 0 );
|
||||||
|
HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
|
||||||
|
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
</source>
|
||||||
|
<p>
|
||||||
|
Text boxes are created using a different call:
|
||||||
|
</p>
|
||||||
|
<source>
|
||||||
|
HSSFTextbox textbox1 = patriarch.createTextbox(
|
||||||
|
new HSSFClientAnchor(0,0,0,0,(short)1,1,(short)2,2));
|
||||||
|
textbox1.setString(new HSSFRichTextString("This is a test") );
|
||||||
|
</source>
|
||||||
|
<p>
|
||||||
|
It's possible to use different fonts to style parts of
|
||||||
|
the text in the textbox. Here's how:
|
||||||
|
</p>
|
||||||
|
<source>
|
||||||
|
HSSFFont font = wb.createFont();
|
||||||
|
font.setItalic(true);
|
||||||
|
font.setUnderline(HSSFFont.U_DOUBLE);
|
||||||
|
HSSFRichTextString string = new HSSFRichTextString("Woo!!!");
|
||||||
|
string.applyFont(2,5,font);
|
||||||
|
textbox.setString(string );
|
||||||
|
</source>
|
||||||
|
<p>
|
||||||
|
Just as can be done manually using Excel, it is possible
|
||||||
|
to group shapes together. This is done by calling
|
||||||
|
<code>createGroup()</code> and then creating the shapes
|
||||||
|
using those groups.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
It's also possible to create groups within groups.
|
||||||
|
</p>
|
||||||
|
<warning>Any group you create should contain at least two
|
||||||
|
other shapes or subgroups.</warning>
|
||||||
|
<p>
|
||||||
|
Here's how to create a shape group:
|
||||||
|
</p>
|
||||||
|
<source>
|
||||||
|
// Create a shape group.
|
||||||
|
HSSFShapeGroup group = patriarch.createGroup(
|
||||||
|
new HSSFClientAnchor(0,0,900,200,(short)2,2,(short)2,2));
|
||||||
|
|
||||||
|
// Create a couple of lines in the group.
|
||||||
|
HSSFSimpleShape shape1 = group.createShape(new HSSFChildAnchor(3,3,500,500));
|
||||||
|
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
( (HSSFChildAnchor) shape1.getAnchor() ).setAnchor((short)3,3,500,500);
|
||||||
|
HSSFSimpleShape shape2 = group.createShape(new HSSFChildAnchor((short)1,200,400,600));
|
||||||
|
shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
</source>
|
||||||
|
<p>
|
||||||
|
If you're being observant you'll noticed that the shapes
|
||||||
|
that are added to the group use a new type of anchor:
|
||||||
|
the <code>HSSFChildAnchor</code>. What happens is that
|
||||||
|
the created group has it's own coordinate space for
|
||||||
|
shapes that are placed into it. POI defaults this to
|
||||||
|
(0,0,1023,255) but you are able to change it as desired.
|
||||||
|
Here's how:
|
||||||
|
</p>
|
||||||
|
<source>
|
||||||
|
myGroup.setCoordinates(10,10,20,20); // top-left, bottom-right
|
||||||
|
</source>
|
||||||
|
<p>
|
||||||
|
If you create a group within a group it's also going
|
||||||
|
to have it's own coordinate space.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<anchor id="StylingShapes"/>
|
||||||
|
<section><title>Styling Shapes</title>
|
||||||
|
<p>
|
||||||
|
By default shapes can look a little plain. It's possible
|
||||||
|
to apply different styles to the shapes however. The
|
||||||
|
sorts of things that can currently be done are:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Change the fill color.</li>
|
||||||
|
<li>Make a shape with no fill color.</li>
|
||||||
|
<li>Change the thickness of the lines.</li>
|
||||||
|
<li>Change the style of the lines. Eg: dashed, dotted.</li>
|
||||||
|
<li>Change the line color.</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Here's an examples of how this is done:
|
||||||
|
</p>
|
||||||
|
<source>
|
||||||
|
HSSFSimpleShape s = patriarch.createSimpleShape(a);
|
||||||
|
s.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
|
||||||
|
s.setLineStyleColor(10,10,10);
|
||||||
|
s.setFillColor(90,10,200);
|
||||||
|
s.setLineWidth(HSSFShape.LINEWIDTH_ONE_PT * 3);
|
||||||
|
s.setLineStyle(HSSFShape.LINESTYLE_DOTSYS);
|
||||||
|
</source>
|
||||||
|
</section>
|
||||||
|
<anchor id="Graphics2d"/>
|
||||||
|
<section><title>Shapes and Graphics2d</title>
|
||||||
|
<p>
|
||||||
|
While the native POI shape drawing commands are the
|
||||||
|
recommended way to draw shapes in a shape it's sometimes
|
||||||
|
desirable to use a standard API for compatibility with
|
||||||
|
external libraries. With this in mind we created some
|
||||||
|
wrappers for <code>Graphics</code> and <code>Graphics2d</code>.
|
||||||
|
</p>
|
||||||
|
<warning>
|
||||||
|
It's important to not however before continuing that
|
||||||
|
<code>Graphics2d</code> is a poor match to the capabilities
|
||||||
|
of the Microsoft Office drawing commands. The older
|
||||||
|
<code>Graphics</code> class offers a closer match but is
|
||||||
|
still a square peg in a round hole.
|
||||||
|
</warning>
|
||||||
|
<p>
|
||||||
|
All Graphics commands are issued into an <code>HSSFShapeGroup</code>.
|
||||||
|
Here's how it's done:
|
||||||
|
</p>
|
||||||
|
<source>
|
||||||
|
a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 1, 0, (short) 1, 0 );
|
||||||
|
group = patriarch.createGroup( a );
|
||||||
|
group.setCoordinates( 0, 0, 80 * 4 , 12 * 23 );
|
||||||
|
float verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / (float)Math.abs(group.getY2() - group.getY1());
|
||||||
|
g = new EscherGraphics( group, wb, Color.black, verticalPointsPerPixel );
|
||||||
|
g2d = new EscherGraphics2d( g );
|
||||||
|
drawChemicalStructure( g2d );
|
||||||
|
</source>
|
||||||
|
<p>
|
||||||
|
The first thing we do is create the group and set it's coordinates
|
||||||
|
to match what we plan to draw. Next we calculate a reasonable
|
||||||
|
fontSizeMultipler then create the EscherGraphics object.
|
||||||
|
Since what we really want is a <code>Graphics2d</code>
|
||||||
|
object we create an EscherGraphics2d object and pass in
|
||||||
|
the graphics object we created. Finally we call a routine
|
||||||
|
that draws into the EscherGraphics2d object.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The vertical points per pixel deserves some more explanation.
|
||||||
|
One of the difficulties in converting Graphics calls
|
||||||
|
into escher drawing calls is that Excel does not have
|
||||||
|
the concept of absolute pixel positions. It measures
|
||||||
|
it's cell widths in 'characters' and the cell heights in points.
|
||||||
|
Unfortunately it's not defined exactly what type of character it's
|
||||||
|
measuring. Presumably this is due to the fact that the Excel will be
|
||||||
|
using different fonts on different platforms or even within the same
|
||||||
|
platform.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Because of this constraint we've had to implement the concept of a
|
||||||
|
verticalPointsPerPixel. This the amount the font should be scaled by when
|
||||||
|
you issue commands such as drawString(). To calculate this value
|
||||||
|
use the follow formula:
|
||||||
|
</p>
|
||||||
|
<source>
|
||||||
|
multipler = groupHeightInPoints / heightOfGroup
|
||||||
|
</source>
|
||||||
|
<p>
|
||||||
|
The height of the group is calculated fairly simply by calculating the
|
||||||
|
difference between the y coordinates of the bounding box of the shape. The
|
||||||
|
height of the group can be calculated by using a convenience called
|
||||||
|
<code>HSSFClientAnchor.getAnchorHeightInPoints()</code>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Many of the functions supported by the graphics classes
|
||||||
|
are not complete. Here's some of the functions that are known
|
||||||
|
to work.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>fillRect()</li>
|
||||||
|
<li>fillOval()</li>
|
||||||
|
<li>drawString()</li>
|
||||||
|
<li>drawOval()</li>
|
||||||
|
<li>drawLine()</li>
|
||||||
|
<li>clearRect()</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Functions that are not supported will return and log a message
|
||||||
|
using the POI logging infrastructure (disabled by default).
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</body>
|
</body>
|
||||||
|
@ -0,0 +1,255 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demonstrates how to use the office drawing capabilities of POI.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class OfficeDrawing
|
||||||
|
{
|
||||||
|
public static void main(String[] args)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
// Create the workbook and sheets.
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
HSSFSheet sheet1 = wb.createSheet("new sheet");
|
||||||
|
HSSFSheet sheet2 = wb.createSheet("second sheet");
|
||||||
|
HSSFSheet sheet3 = wb.createSheet("third sheet");
|
||||||
|
HSSFSheet sheet4 = wb.createSheet("fourth sheet");
|
||||||
|
|
||||||
|
// Draw stuff in them
|
||||||
|
drawSheet1( sheet1 );
|
||||||
|
drawSheet2( sheet2 );
|
||||||
|
drawSheet3( sheet3 );
|
||||||
|
drawSheet4( sheet4, wb );
|
||||||
|
|
||||||
|
// Write the file out.
|
||||||
|
FileOutputStream fileOut = new FileOutputStream("workbook.xls");
|
||||||
|
wb.write(fileOut);
|
||||||
|
fileOut.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawSheet1( HSSFSheet sheet1 )
|
||||||
|
{
|
||||||
|
// Create a row and size one of the cells reasonably large.
|
||||||
|
HSSFRow row = sheet1.createRow(2);
|
||||||
|
row.setHeight((short) 2800);
|
||||||
|
sheet1.setColumnWidth((short) 2, (short) 9000);
|
||||||
|
|
||||||
|
// Create the drawing patriarch. This is the top level container for
|
||||||
|
// all shapes.
|
||||||
|
HSSFPatriarch patriarch = sheet1.createDrawingPatriarch();
|
||||||
|
|
||||||
|
// Draw some lines and an oval.
|
||||||
|
drawLinesToCenter( patriarch );
|
||||||
|
drawManyLines( patriarch );
|
||||||
|
drawOval( patriarch );
|
||||||
|
drawPolygon( patriarch );
|
||||||
|
|
||||||
|
// Draw a rectangle.
|
||||||
|
HSSFSimpleShape rect = patriarch.createSimpleShape( new HSSFClientAnchor(100, 100, 900, 200, (short)0, 0, (short)0, 0) );
|
||||||
|
rect.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawSheet2( HSSFSheet sheet2 )
|
||||||
|
{
|
||||||
|
// Create a row and size one of the cells reasonably large.
|
||||||
|
HSSFRow row = sheet2.createRow(2);
|
||||||
|
row.setHeightInPoints(240);
|
||||||
|
sheet2.setColumnWidth((short) 2, (short) 9000);
|
||||||
|
|
||||||
|
// 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 = sheet2.createDrawingPatriarch();
|
||||||
|
|
||||||
|
// Draw a grid in one of the cells.
|
||||||
|
drawGrid( patriarch );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawSheet3( HSSFSheet sheet3 )
|
||||||
|
{
|
||||||
|
// Create a row and size one of the cells reasonably large
|
||||||
|
HSSFRow row = sheet3.createRow(2);
|
||||||
|
row.setHeightInPoints(140);
|
||||||
|
sheet3.setColumnWidth((short) 2, (short) 9000);
|
||||||
|
|
||||||
|
// 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 = sheet3.createDrawingPatriarch();
|
||||||
|
|
||||||
|
// Create a shape group.
|
||||||
|
HSSFShapeGroup group = patriarch.createGroup(
|
||||||
|
new HSSFClientAnchor(0,0,900,200,(short)2,2,(short)2,2));
|
||||||
|
|
||||||
|
// Create a couple of lines in the group.
|
||||||
|
HSSFSimpleShape shape1 = group.createShape(new HSSFChildAnchor(3,3,500,500));
|
||||||
|
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
( (HSSFChildAnchor) shape1.getAnchor() ).setAnchor((short)3,3,500,500);
|
||||||
|
HSSFSimpleShape shape2 = group.createShape(new HSSFChildAnchor((short)1,200,400,600));
|
||||||
|
shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawSheet4( HSSFSheet sheet4, HSSFWorkbook wb )
|
||||||
|
{
|
||||||
|
// 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 = sheet4.createDrawingPatriarch();
|
||||||
|
|
||||||
|
// Create a couple of textboxes
|
||||||
|
HSSFTextbox textbox1 = patriarch.createTextbox(
|
||||||
|
new HSSFClientAnchor(0,0,0,0,(short)1,1,(short)2,2));
|
||||||
|
textbox1.setString(new HSSFRichTextString("This is a test") );
|
||||||
|
HSSFTextbox textbox2 = patriarch.createTextbox(
|
||||||
|
new HSSFClientAnchor(0,0,900,100,(short)3,3,(short)3,4));
|
||||||
|
textbox2.setString(new HSSFRichTextString("Woo") );
|
||||||
|
textbox2.setFillColor(200,0,0);
|
||||||
|
textbox2.setLineStyle(HSSFSimpleShape.LINESTYLE_DOTGEL);
|
||||||
|
|
||||||
|
// Create third one with some fancy font styling.
|
||||||
|
HSSFTextbox textbox3 = patriarch.createTextbox(
|
||||||
|
new HSSFClientAnchor(0,0,900,100,(short)4,4,(short)5,4+1));
|
||||||
|
HSSFFont font = wb.createFont();
|
||||||
|
font.setItalic(true);
|
||||||
|
font.setUnderline(HSSFFont.U_DOUBLE);
|
||||||
|
HSSFRichTextString string = new HSSFRichTextString("Woo!!!");
|
||||||
|
string.applyFont(2,5,font);
|
||||||
|
textbox3.setString(string );
|
||||||
|
textbox3.setFillColor(0x08000030);
|
||||||
|
textbox3.setLineStyle(HSSFSimpleShape.LINESTYLE_NONE); // no line around the textbox.
|
||||||
|
textbox3.setNoFill(true); // make it transparent
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawOval( HSSFPatriarch patriarch )
|
||||||
|
{
|
||||||
|
// Create an oval and style to taste.
|
||||||
|
HSSFClientAnchor a = new HSSFClientAnchor();
|
||||||
|
a.setAnchor((short)2, 2, 20, 20, (short) 2, 2, 190, 80);
|
||||||
|
HSSFSimpleShape s = patriarch.createSimpleShape(a);
|
||||||
|
s.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
|
||||||
|
s.setLineStyleColor(10,10,10);
|
||||||
|
s.setFillColor(90,10,200);
|
||||||
|
s.setLineWidth(HSSFShape.LINEWIDTH_ONE_PT * 3);
|
||||||
|
s.setLineStyle(HSSFShape.LINESTYLE_DOTSYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawPolygon( HSSFPatriarch patriarch )
|
||||||
|
{
|
||||||
|
// HSSFClientAnchor a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 2, 2, (short) 3, 3 );
|
||||||
|
// HSSFPolygon p = patriarch.createPolygon(a);
|
||||||
|
// p.setPolygonDrawArea(100,100);
|
||||||
|
// p.setPoints( new int[]{30, 90, 50}, new int[]{88, 5, 44} );
|
||||||
|
|
||||||
|
|
||||||
|
HSSFClientAnchor a = new HSSFClientAnchor();
|
||||||
|
a.setAnchor( (short) 2, 2, 0, 0, (short) 3, 3, 1023, 255 );
|
||||||
|
HSSFShapeGroup g = patriarch.createGroup( a );
|
||||||
|
g.setCoordinates(0,0,200,200);
|
||||||
|
HSSFPolygon p1 = g.createPolygon( new HSSFChildAnchor( 0, 0, 200, 200 ) );
|
||||||
|
p1.setPolygonDrawArea( 100, 100 );
|
||||||
|
p1.setPoints( new int[]{0, 90, 50}, new int[]{5, 5, 44} );
|
||||||
|
p1.setFillColor( 0, 255, 0 );
|
||||||
|
HSSFPolygon p2 = g.createPolygon( new HSSFChildAnchor( 20, 20, 200, 200 ) );
|
||||||
|
p2.setPolygonDrawArea( 200, 200 );
|
||||||
|
p2.setPoints( new int[]{120, 20, 150}, new int[]{105, 30, 195} );
|
||||||
|
p2.setFillColor( 255, 0, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawManyLines( HSSFPatriarch patriarch )
|
||||||
|
{
|
||||||
|
// Draw bunch of lines
|
||||||
|
int x1 = 100;
|
||||||
|
int y1 = 100;
|
||||||
|
int x2 = 800;
|
||||||
|
int y2 = 200;
|
||||||
|
int color = 0;
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
HSSFClientAnchor a2 = new HSSFClientAnchor();
|
||||||
|
a2.setAnchor((short) 2, 2, x1, y1, (short) 2, 2, x2, y2);
|
||||||
|
HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
|
||||||
|
shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
shape2.setLineStyleColor(color);
|
||||||
|
y1 -= 10;
|
||||||
|
y2 -= 10;
|
||||||
|
color += 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawGrid( HSSFPatriarch patriarch )
|
||||||
|
{
|
||||||
|
// This draws a grid of lines. Since the coordinates space fixed at
|
||||||
|
// 1024 by 256 we use a ratio to get a reasonably square grids.
|
||||||
|
|
||||||
|
double xRatio = 3.22;
|
||||||
|
double yRatio = 0.6711;
|
||||||
|
|
||||||
|
int x1 = 000;
|
||||||
|
int y1 = 000;
|
||||||
|
int x2 = 000;
|
||||||
|
int y2 = 200;
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
HSSFClientAnchor a2 = new HSSFClientAnchor();
|
||||||
|
a2.setAnchor((short) 2, 2, (int) ( x1 * xRatio ), (int) ( y1 * yRatio ),
|
||||||
|
(short) 2, 2, (int) ( x2 * xRatio ), (int) ( y2 * yRatio ));
|
||||||
|
HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
|
||||||
|
shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
|
||||||
|
x1 += 10;
|
||||||
|
x2 += 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
x1 = 000;
|
||||||
|
y1 = 000;
|
||||||
|
x2 = 200;
|
||||||
|
y2 = 000;
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
HSSFClientAnchor a2 = new HSSFClientAnchor();
|
||||||
|
a2.setAnchor((short) 2, 2, (int) ( x1 * xRatio ), (int) ( y1 * yRatio ),
|
||||||
|
(short) 2, 2, (int) ( x2 * xRatio ), (int) ( y2 * yRatio ));
|
||||||
|
HSSFSimpleShape shape2 = patriarch.createSimpleShape(a2);
|
||||||
|
shape2.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
|
||||||
|
y1 += 10;
|
||||||
|
y2 += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawLinesToCenter( HSSFPatriarch patriarch )
|
||||||
|
{
|
||||||
|
// Draw some lines from and to the corners
|
||||||
|
{
|
||||||
|
HSSFClientAnchor a1 = new HSSFClientAnchor();
|
||||||
|
a1.setAnchor( (short)2, 2, 0, 0, (short) 2, 2, 512, 128);
|
||||||
|
HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
|
||||||
|
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
HSSFClientAnchor a1 = new HSSFClientAnchor();
|
||||||
|
a1.setAnchor( (short)2, 2, 512, 128, (short) 2, 2, 1024, 0);
|
||||||
|
HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
|
||||||
|
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
HSSFClientAnchor a1 = new HSSFClientAnchor();
|
||||||
|
a1.setAnchor( (short)1, 1, 0, 0, (short) 1, 1, 512, 100);
|
||||||
|
HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
|
||||||
|
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
HSSFClientAnchor a1 = new HSSFClientAnchor();
|
||||||
|
a1.setAnchor( (short)1, 1, 512, 100, (short) 1, 1, 1024, 0);
|
||||||
|
HSSFSimpleShape shape1 = patriarch.createSimpleShape(a1);
|
||||||
|
shape1.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel.examples;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.usermodel.*;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demonstrates the use of the EscherGraphics2d library.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class OfficeDrawingWithGraphics
|
||||||
|
{
|
||||||
|
public static void main( String[] args ) throws IOException
|
||||||
|
{
|
||||||
|
// Create a workbook with one sheet and size the first three somewhat
|
||||||
|
// larger so we can fit the chemical structure diagram in.
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
HSSFSheet sheet = wb.createSheet( "my drawing" );
|
||||||
|
sheet.setColumnWidth((short)1, (short)(256 * 27));
|
||||||
|
HSSFRow row1 = sheet.createRow(0);
|
||||||
|
row1.setHeightInPoints(10 * 15);
|
||||||
|
HSSFRow row2 = sheet.createRow(1);
|
||||||
|
row2.setHeightInPoints(5 * 15);
|
||||||
|
HSSFRow row3 = sheet.createRow(2);
|
||||||
|
row3.setHeightInPoints(10 * 15);
|
||||||
|
|
||||||
|
// Add some cells so we can test that the anchoring works when we
|
||||||
|
// sort them.
|
||||||
|
row1.createCell((short)0).setCellValue("C");
|
||||||
|
row2.createCell((short)0).setCellValue("A");
|
||||||
|
row3.createCell((short)0).setCellValue("B");
|
||||||
|
|
||||||
|
// Create the top level drawing patriarch.
|
||||||
|
HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
|
||||||
|
|
||||||
|
HSSFClientAnchor a;
|
||||||
|
HSSFShapeGroup group;
|
||||||
|
EscherGraphics g;
|
||||||
|
EscherGraphics2d g2d;
|
||||||
|
// Anchor entirely within one cell.
|
||||||
|
a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 1, 0, (short) 1, 0 );
|
||||||
|
group = patriarch.createGroup( a );
|
||||||
|
group.setCoordinates( 0, 0, 320, 276 );
|
||||||
|
float verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / (float)Math.abs(group.getY2() - group.getY1());
|
||||||
|
g = new EscherGraphics( group, wb, Color.black, verticalPointsPerPixel );
|
||||||
|
g2d = new EscherGraphics2d( g );
|
||||||
|
drawStar( g2d );
|
||||||
|
|
||||||
|
a = new HSSFClientAnchor( 0, 0, 1023, 255, (short) 1, 1, (short) 1, 1 );
|
||||||
|
group = patriarch.createGroup( a );
|
||||||
|
group.setCoordinates( 0, 0, 640, 276 );
|
||||||
|
verticalPointsPerPixel = a.getAnchorHeightInPoints(sheet) / (float)Math.abs(group.getY2() - group.getY1());
|
||||||
|
// verticalPixelsPerPoint = (float)Math.abs(group.getY2() - group.getY1()) / a.getAnchorHeightInPoints(sheet);
|
||||||
|
g = new EscherGraphics( group, wb, Color.black, verticalPointsPerPixel );
|
||||||
|
g2d = new EscherGraphics2d( g );
|
||||||
|
drawStar( g2d );
|
||||||
|
|
||||||
|
FileOutputStream out = new FileOutputStream("workbook.xls");
|
||||||
|
wb.write(out);
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void drawStar( EscherGraphics2d g2d )
|
||||||
|
{
|
||||||
|
g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
|
||||||
|
for (double i = 0; i < Math.PI; i += 0.1)
|
||||||
|
{
|
||||||
|
g2d.setColor( new Color((int)(i * 5343062d) ) );
|
||||||
|
int x1 = (int) ( Math.cos(i) * 160.0 ) + 160;
|
||||||
|
int y1 = (int) ( Math.sin(i) * 138.0 ) + 138;
|
||||||
|
int x2 = (int) ( -Math.cos(i) * 160.0 ) + 160;
|
||||||
|
int y2 = (int) ( -Math.sin(i) * 138.0 ) + 138;
|
||||||
|
g2d.drawLine(x1,y1,x2,y2);
|
||||||
|
}
|
||||||
|
g2d.setFont(new Font("SansSerif",Font.BOLD | Font.ITALIC, 20));
|
||||||
|
g2d.drawString("EscherGraphics2d",70,100);
|
||||||
|
g2d.setColor(Color.yellow);
|
||||||
|
g2d.fillOval( 160-20,138-20,40,40);
|
||||||
|
g2d.setColor(Color.black);
|
||||||
|
g2d.fillPolygon(new int[] {-10+160,0+160,10+160,0+160}, new int[] {0+138,10+138,0+138,-10+138}, 4);
|
||||||
|
g2d.drawPolygon(new int[] {-160+160,0+160,160+160,0+160}, new int[] {0+138,138+138,0+138,-138+138}, 4);
|
||||||
|
}
|
||||||
|
}
|
114
src/java/org/apache/poi/ddf/DefaultEscherRecordFactory.java
Normal file
114
src/java/org/apache/poi/ddf/DefaultEscherRecordFactory.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates escher records when provided the byte array containing those records.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherRecordFactory
|
||||||
|
*/
|
||||||
|
public class DefaultEscherRecordFactory
|
||||||
|
implements EscherRecordFactory
|
||||||
|
{
|
||||||
|
private static Class[] escherRecordClasses = {
|
||||||
|
EscherBSERecord.class, EscherOptRecord.class, EscherClientAnchorRecord.class, EscherDgRecord.class,
|
||||||
|
EscherSpgrRecord.class, EscherSpRecord.class, EscherClientDataRecord.class, EscherDggRecord.class,
|
||||||
|
EscherSplitMenuColorsRecord.class, EscherChildAnchorRecord.class, EscherTextboxRecord.class
|
||||||
|
};
|
||||||
|
private static Map recordsMap = recordsToMap( escherRecordClasses );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of the escher record factory
|
||||||
|
*/
|
||||||
|
public DefaultEscherRecordFactory()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an escher record including the any children contained under that record.
|
||||||
|
* An exception is thrown if the record could not be generated.
|
||||||
|
*
|
||||||
|
* @param data The byte array containing the records
|
||||||
|
* @param offset The starting offset into the byte array
|
||||||
|
* @return The generated escher record
|
||||||
|
*/
|
||||||
|
public EscherRecord createRecord( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
EscherRecord.EscherRecordHeader header = EscherRecord.EscherRecordHeader.readHeader( data, offset );
|
||||||
|
if ( ( header.getOptions() & (short) 0x000F ) == (short) 0x000F )
|
||||||
|
{
|
||||||
|
EscherContainerRecord r = new EscherContainerRecord();
|
||||||
|
r.setRecordId( header.getRecordId() );
|
||||||
|
r.setOptions( header.getOptions() );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else if ( header.getRecordId() >= EscherBlipRecord.RECORD_ID_START && header.getRecordId() <= EscherBlipRecord.RECORD_ID_END )
|
||||||
|
{
|
||||||
|
EscherBlipRecord r = new EscherBlipRecord();
|
||||||
|
r.setRecordId( header.getRecordId() );
|
||||||
|
r.setOptions( header.getOptions() );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Constructor recordConstructor = (Constructor) recordsMap.get( new Short( header.getRecordId() ) );
|
||||||
|
EscherRecord escherRecord = null;
|
||||||
|
if ( recordConstructor != null )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
escherRecord = (EscherRecord) recordConstructor.newInstance( new Object[]{} );
|
||||||
|
escherRecord.setRecordId( header.getRecordId() );
|
||||||
|
escherRecord.setOptions( header.getOptions() );
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
escherRecord = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return escherRecord == null ? new UnknownEscherRecord() : escherRecord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts from a list of classes into a map that contains the record id as the key and
|
||||||
|
* the Constructor in the value part of the map. It does this by using reflection to look up
|
||||||
|
* the RECORD_ID field then using reflection again to find a reference to the constructor.
|
||||||
|
*
|
||||||
|
* @param records The records to convert
|
||||||
|
* @return The map containing the id/constructor pairs.
|
||||||
|
*/
|
||||||
|
private static Map recordsToMap( Class[] records )
|
||||||
|
{
|
||||||
|
Map result = new HashMap();
|
||||||
|
Constructor constructor;
|
||||||
|
|
||||||
|
for ( int i = 0; i < records.length; i++ )
|
||||||
|
{
|
||||||
|
Class record = null;
|
||||||
|
short sid = 0;
|
||||||
|
|
||||||
|
record = records[i];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sid = record.getField( "RECORD_ID" ).getShort( null );
|
||||||
|
constructor = record.getConstructor( new Class[]
|
||||||
|
{
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
catch ( Exception illegalArgumentException )
|
||||||
|
{
|
||||||
|
throw new RecordFormatException(
|
||||||
|
"Unable to determine record types" );
|
||||||
|
}
|
||||||
|
result.put( new Short( sid ), constructor );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
162
src/java/org/apache/poi/ddf/EscherArrayProperty.java
Normal file
162
src/java/org/apache/poi/ddf/EscherArrayProperty.java
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher array properties are the most wierd construction ever invented
|
||||||
|
* with all sorts of special cases. I'm hopeful I've got them all.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at superlinksoftware.com)
|
||||||
|
*/
|
||||||
|
public class EscherArrayProperty
|
||||||
|
extends EscherComplexProperty
|
||||||
|
{
|
||||||
|
private static final int FIXED_SIZE = 3 * 2;
|
||||||
|
|
||||||
|
public EscherArrayProperty( short id, byte[] complexData )
|
||||||
|
{
|
||||||
|
super( id, checkComplexData(complexData) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherArrayProperty( short propertyNumber, boolean isBlipId, byte[] complexData )
|
||||||
|
{
|
||||||
|
super( propertyNumber, isBlipId, checkComplexData(complexData) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] checkComplexData( byte[] complexData )
|
||||||
|
{
|
||||||
|
if (complexData == null || complexData.length == 0)
|
||||||
|
complexData = new byte[6];
|
||||||
|
|
||||||
|
return complexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfElementsInArray()
|
||||||
|
{
|
||||||
|
return LittleEndian.getUShort( complexData, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumberOfElementsInArray( int numberOfElements )
|
||||||
|
{
|
||||||
|
int expectedArraySize = numberOfElements * getActualSizeOfElements(getSizeOfElements()) + FIXED_SIZE;
|
||||||
|
if ( expectedArraySize != complexData.length )
|
||||||
|
{
|
||||||
|
byte[] newArray = new byte[expectedArraySize];
|
||||||
|
System.arraycopy( complexData, 0, newArray, 0, complexData.length );
|
||||||
|
complexData = newArray;
|
||||||
|
}
|
||||||
|
LittleEndian.putShort( complexData, 0, (short) numberOfElements );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfElementsInMemory()
|
||||||
|
{
|
||||||
|
return LittleEndian.getUShort( complexData, 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumberOfElementsInMemory( int numberOfElements )
|
||||||
|
{
|
||||||
|
int expectedArraySize = numberOfElements * getActualSizeOfElements(getSizeOfElements()) + FIXED_SIZE;
|
||||||
|
if ( expectedArraySize != complexData.length )
|
||||||
|
{
|
||||||
|
byte[] newArray = new byte[expectedArraySize];
|
||||||
|
System.arraycopy( complexData, 0, newArray, 0, expectedArraySize );
|
||||||
|
complexData = newArray;
|
||||||
|
}
|
||||||
|
LittleEndian.putShort( complexData, 2, (short) numberOfElements );
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSizeOfElements()
|
||||||
|
{
|
||||||
|
return LittleEndian.getShort( complexData, 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSizeOfElements( int sizeOfElements )
|
||||||
|
{
|
||||||
|
LittleEndian.putShort( complexData, 4, (short) sizeOfElements );
|
||||||
|
|
||||||
|
int expectedArraySize = getNumberOfElementsInArray() * getActualSizeOfElements(getSizeOfElements()) + FIXED_SIZE;
|
||||||
|
if ( expectedArraySize != complexData.length )
|
||||||
|
{
|
||||||
|
// Keep just the first 6 bytes. The rest is no good to us anyway.
|
||||||
|
byte[] newArray = new byte[expectedArraySize];
|
||||||
|
System.arraycopy( complexData, 0, newArray, 0, 6 );
|
||||||
|
complexData = newArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getElement( int index )
|
||||||
|
{
|
||||||
|
int actualSize = getActualSizeOfElements(getSizeOfElements());
|
||||||
|
byte[] result = new byte[actualSize];
|
||||||
|
System.arraycopy(complexData, FIXED_SIZE + index * actualSize, result, 0, result.length );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setElement( int index, byte[] element )
|
||||||
|
{
|
||||||
|
int actualSize = getActualSizeOfElements(getSizeOfElements());
|
||||||
|
System.arraycopy( element, 0, complexData, FIXED_SIZE + index * actualSize, actualSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
StringBuffer results = new StringBuffer();
|
||||||
|
results.append(" {EscherArrayProperty:" + nl);
|
||||||
|
results.append(" Num Elements: " + getNumberOfElementsInArray() + nl);
|
||||||
|
results.append(" Num Elements In Memory: " + getNumberOfElementsInMemory() + nl);
|
||||||
|
results.append(" Size of elements: " + getSizeOfElements() + nl);
|
||||||
|
for (int i = 0; i < getNumberOfElementsInArray(); i++)
|
||||||
|
{
|
||||||
|
results.append(" Element " + i + ": " + HexDump.toHex(getElement(i)) + nl);
|
||||||
|
}
|
||||||
|
results.append("}" + nl);
|
||||||
|
|
||||||
|
return "propNum: " + getPropertyNumber()
|
||||||
|
+ ", propName: " + EscherProperties.getPropertyName( getPropertyNumber() )
|
||||||
|
+ ", complex: " + isComplex()
|
||||||
|
+ ", blipId: " + isBlipId()
|
||||||
|
+ ", data: " + nl + results.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have this method because the way in which arrays in escher works
|
||||||
|
* is screwed for seemly arbitary reasons. While most properties are
|
||||||
|
* fairly consistent and have a predictable array size, escher arrays
|
||||||
|
* have special cases.
|
||||||
|
*
|
||||||
|
* @param data The data array containing the escher array information
|
||||||
|
* @param offset The offset into the array to start reading from.
|
||||||
|
* @return the number of bytes used by this complex property.
|
||||||
|
*/
|
||||||
|
public int setArrayData( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
short numElements = LittleEndian.getShort(data, offset);
|
||||||
|
short numReserved = LittleEndian.getShort(data, offset + 2);
|
||||||
|
short sizeOfElements = LittleEndian.getShort(data, offset + 4);
|
||||||
|
|
||||||
|
int arraySize = getActualSizeOfElements(sizeOfElements) * numElements;
|
||||||
|
if (arraySize == complexData.length)
|
||||||
|
complexData = new byte[arraySize + 6]; // Calculation missing the header for some reason
|
||||||
|
System.arraycopy(data, offset, complexData, 0, complexData.length );
|
||||||
|
return complexData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sometimes the element size is stored as a negative number. We
|
||||||
|
* negate it and shift it to get the real value.
|
||||||
|
*/
|
||||||
|
public static int getActualSizeOfElements(short sizeOfElements)
|
||||||
|
{
|
||||||
|
if (sizeOfElements < 0)
|
||||||
|
return (short) ( ( -sizeOfElements ) >> 2 );
|
||||||
|
else
|
||||||
|
return sizeOfElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
383
src/java/org/apache/poi/ddf/EscherBSERecord.java
Normal file
383
src/java/org/apache/poi/ddf/EscherBSERecord.java
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherBlipRecord
|
||||||
|
*/
|
||||||
|
public class EscherBSERecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF007;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtBSE";
|
||||||
|
|
||||||
|
public static final byte BT_ERROR = 0;
|
||||||
|
public static final byte BT_UNKNOWN = 1;
|
||||||
|
public static final byte BT_EMF = 2;
|
||||||
|
public static final byte BT_WMF = 3;
|
||||||
|
public static final byte BT_PICT = 4;
|
||||||
|
public static final byte BT_JPEG = 5;
|
||||||
|
public static final byte BT_PNG = 6;
|
||||||
|
public static final byte BT_DIB = 7;
|
||||||
|
|
||||||
|
private byte field_1_blipTypeWin32;
|
||||||
|
private byte field_2_blipTypeMacOS;
|
||||||
|
private byte[] field_3_uid; // 16 bytes
|
||||||
|
private short field_4_tag;
|
||||||
|
private int field_5_size;
|
||||||
|
private int field_6_ref;
|
||||||
|
private int field_7_offset;
|
||||||
|
private byte field_8_usage;
|
||||||
|
private byte field_9_name;
|
||||||
|
private byte field_10_unused2;
|
||||||
|
private byte field_11_unused3;
|
||||||
|
|
||||||
|
private byte[] remainingData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
field_1_blipTypeWin32 = data[pos];
|
||||||
|
field_2_blipTypeMacOS = data[pos + 1];
|
||||||
|
System.arraycopy( data, pos + 2, field_3_uid = new byte[16], 0, 16 );
|
||||||
|
field_4_tag = LittleEndian.getShort( data, pos + 18 );
|
||||||
|
field_5_size = LittleEndian.getInt( data, pos + 20 );
|
||||||
|
field_6_ref = LittleEndian.getInt( data, pos + 24 );
|
||||||
|
field_7_offset = LittleEndian.getInt( data, pos + 28 );
|
||||||
|
field_8_usage = data[pos + 32];
|
||||||
|
field_9_name = data[pos + 33];
|
||||||
|
field_10_unused2 = data[pos + 34];
|
||||||
|
field_11_unused3 = data[pos + 35];
|
||||||
|
bytesRemaining -= 36;
|
||||||
|
remainingData = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, pos + 36, remainingData, 0, bytesRemaining );
|
||||||
|
return bytesRemaining + 8 + 36;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = remainingData.length + 36;
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
||||||
|
|
||||||
|
data[offset + 8] = field_1_blipTypeWin32;
|
||||||
|
data[offset + 9] = field_2_blipTypeMacOS;
|
||||||
|
for ( int i = 0; i < 16; i++ )
|
||||||
|
data[offset + 10 + i] = field_3_uid[i];
|
||||||
|
LittleEndian.putShort( data, offset + 26, field_4_tag );
|
||||||
|
LittleEndian.putInt( data, offset + 28, field_5_size );
|
||||||
|
LittleEndian.putInt( data, offset + 32, field_6_ref );
|
||||||
|
LittleEndian.putInt( data, offset + 36, field_7_offset );
|
||||||
|
data[offset + 40] = field_8_usage;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 8 + 1 + 1 + 16 + 2 + 4 + 4 + 4 + 1 + 1 + 1 + 1 + remainingData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "BSE";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The expected blip type under windows (failure to match this blip type will result in
|
||||||
|
* Excel converting to this format).
|
||||||
|
*/
|
||||||
|
public byte getBlipTypeWin32()
|
||||||
|
{
|
||||||
|
return field_1_blipTypeWin32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected win32 blip type
|
||||||
|
*/
|
||||||
|
public void setBlipTypeWin32( byte blipTypeWin32 )
|
||||||
|
{
|
||||||
|
this.field_1_blipTypeWin32 = blipTypeWin32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The expected blip type under MacOS (failure to match this blip type will result in
|
||||||
|
* Excel converting to this format).
|
||||||
|
*/
|
||||||
|
public byte getBlipTypeMacOS()
|
||||||
|
{
|
||||||
|
return field_2_blipTypeMacOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the expected MacOS blip type
|
||||||
|
*/
|
||||||
|
public void setBlipTypeMacOS( byte blipTypeMacOS )
|
||||||
|
{
|
||||||
|
this.field_2_blipTypeMacOS = blipTypeMacOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16 byte MD4 checksum.
|
||||||
|
*/
|
||||||
|
public byte[] getUid()
|
||||||
|
{
|
||||||
|
return field_3_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16 byte MD4 checksum.
|
||||||
|
*/
|
||||||
|
public void setUid( byte[] uid )
|
||||||
|
{
|
||||||
|
this.field_3_uid = uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unused
|
||||||
|
*/
|
||||||
|
public short getTag()
|
||||||
|
{
|
||||||
|
return field_4_tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unused
|
||||||
|
*/
|
||||||
|
public void setTag( short tag )
|
||||||
|
{
|
||||||
|
this.field_4_tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blip size in stream.
|
||||||
|
*/
|
||||||
|
public int getSize()
|
||||||
|
{
|
||||||
|
return field_5_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blip size in stream.
|
||||||
|
*/
|
||||||
|
public void setSize( int size )
|
||||||
|
{
|
||||||
|
this.field_5_size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference count of this blip.
|
||||||
|
*/
|
||||||
|
public int getRef()
|
||||||
|
{
|
||||||
|
return field_6_ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference count of this blip.
|
||||||
|
*/
|
||||||
|
public void setRef( int ref )
|
||||||
|
{
|
||||||
|
this.field_6_ref = ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File offset in the delay stream.
|
||||||
|
*/
|
||||||
|
public int getOffset()
|
||||||
|
{
|
||||||
|
return field_7_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File offset in the delay stream.
|
||||||
|
*/
|
||||||
|
public void setOffset( int offset )
|
||||||
|
{
|
||||||
|
this.field_7_offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the way this blip is used.
|
||||||
|
*/
|
||||||
|
public byte getUsage()
|
||||||
|
{
|
||||||
|
return field_8_usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the way this blip is used.
|
||||||
|
*/
|
||||||
|
public void setUsage( byte usage )
|
||||||
|
{
|
||||||
|
this.field_8_usage = usage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length in characters of the blip name.
|
||||||
|
*/
|
||||||
|
public byte getName()
|
||||||
|
{
|
||||||
|
return field_9_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The length in characters of the blip name.
|
||||||
|
*/
|
||||||
|
public void setName( byte name )
|
||||||
|
{
|
||||||
|
this.field_9_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getUnused2()
|
||||||
|
{
|
||||||
|
return field_10_unused2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnused2( byte unused2 )
|
||||||
|
{
|
||||||
|
this.field_10_unused2 = unused2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getUnused3()
|
||||||
|
{
|
||||||
|
return field_11_unused3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnused3( byte unused3 )
|
||||||
|
{
|
||||||
|
this.field_11_unused3 = unused3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any remaining data in this record.
|
||||||
|
*/
|
||||||
|
public byte[] getRemainingData()
|
||||||
|
{
|
||||||
|
return remainingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any remaining data in this record.
|
||||||
|
*/
|
||||||
|
public void setRemainingData( byte[] remainingData )
|
||||||
|
{
|
||||||
|
this.remainingData = remainingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the string representation of this object
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
String extraData;
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HexDump.dump( this.remainingData, 0, b, 0 );
|
||||||
|
extraData = b.toString();
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
extraData = e.toString();
|
||||||
|
}
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex( RECORD_ID ) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" BlipTypeWin32: " + field_1_blipTypeWin32 + nl +
|
||||||
|
" BlipTypeMacOS: " + field_2_blipTypeMacOS + nl +
|
||||||
|
" SUID: " + HexDump.toHex(field_3_uid) + nl +
|
||||||
|
" Tag: " + field_4_tag + nl +
|
||||||
|
" Size: " + field_5_size + nl +
|
||||||
|
" Ref: " + field_6_ref + nl +
|
||||||
|
" Offset: " + field_7_offset + nl +
|
||||||
|
" Usage: " + field_8_usage + nl +
|
||||||
|
" Name: " + field_9_name + nl +
|
||||||
|
" Unused2: " + field_10_unused2 + nl +
|
||||||
|
" Unused3: " + field_11_unused3 + nl +
|
||||||
|
" Extra Data:" + nl + extraData;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the string representation given a blip id.
|
||||||
|
*/
|
||||||
|
public String getBlipType( byte b )
|
||||||
|
{
|
||||||
|
switch ( b )
|
||||||
|
{
|
||||||
|
case BT_ERROR:
|
||||||
|
return " ERROR";
|
||||||
|
case BT_UNKNOWN:
|
||||||
|
return " UNKNOWN";
|
||||||
|
case BT_EMF:
|
||||||
|
return " EMF";
|
||||||
|
case BT_WMF:
|
||||||
|
return " WMF";
|
||||||
|
case BT_PICT:
|
||||||
|
return " PICT";
|
||||||
|
case BT_JPEG:
|
||||||
|
return " JPEG";
|
||||||
|
case BT_PNG:
|
||||||
|
return " PNG";
|
||||||
|
case BT_DIB:
|
||||||
|
return " DIB";
|
||||||
|
default:
|
||||||
|
if ( b < 32 )
|
||||||
|
return " NotKnown";
|
||||||
|
else
|
||||||
|
return " Client";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
417
src/java/org/apache/poi/ddf/EscherBlipRecord.java
Normal file
417
src/java/org/apache/poi/ddf/EscherBlipRecord.java
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
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 EscherBlipRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
return bytesRemaining + HEADER_SIZE + bytesAfterHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
src/java/org/apache/poi/ddf/EscherBoolProperty.java
Normal file
50
src/java/org/apache/poi/ddf/EscherBoolProperty.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a boolean property. The actual utility of this property is in doubt because many
|
||||||
|
* of the properties marked as boolean seem to actually contain special values. In other words
|
||||||
|
* they're not true booleans.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherSimpleProperty
|
||||||
|
* @see EscherProperty
|
||||||
|
*/
|
||||||
|
public class EscherBoolProperty
|
||||||
|
extends EscherSimpleProperty
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create an instance of an escher boolean property.
|
||||||
|
*
|
||||||
|
* @param propertyNumber The property number
|
||||||
|
* @param value The 32 bit value of this bool property
|
||||||
|
*/
|
||||||
|
public EscherBoolProperty( short propertyNumber, int value )
|
||||||
|
{
|
||||||
|
super( propertyNumber, false, false, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this boolean property is true
|
||||||
|
*/
|
||||||
|
public boolean isTrue()
|
||||||
|
{
|
||||||
|
return propertyValue != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this boolean property is false
|
||||||
|
*/
|
||||||
|
public boolean isFalse()
|
||||||
|
{
|
||||||
|
return propertyValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public String toString()
|
||||||
|
// {
|
||||||
|
// return "propNum: " + getPropertyNumber()
|
||||||
|
// + ", complex: " + isComplex()
|
||||||
|
// + ", blipId: " + isBlipId()
|
||||||
|
// + ", value: " + (getValue() != 0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
176
src/java/org/apache/poi/ddf/EscherChildAnchorRecord.java
Normal file
176
src/java/org/apache/poi/ddf/EscherChildAnchorRecord.java
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The escher child achor record is used to specify the position of a shape under an
|
||||||
|
* existing group. The first level of shape records use a EscherClientAnchor record instead.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherChildAnchorRecord
|
||||||
|
*/
|
||||||
|
public class EscherChildAnchorRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF00F;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtChildAnchor";
|
||||||
|
|
||||||
|
private int field_1_dx1;
|
||||||
|
private int field_2_dy1;
|
||||||
|
private int field_3_dx2;
|
||||||
|
private int field_4_dy2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
int size = 0;
|
||||||
|
field_1_dx1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_2_dy1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_3_dx2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_4_dy2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
return 8 + 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 );
|
||||||
|
int pos = offset;
|
||||||
|
LittleEndian.putShort( data, pos, getOptions() ); pos += 2;
|
||||||
|
LittleEndian.putShort( data, pos, getRecordId() ); pos += 2;
|
||||||
|
LittleEndian.putInt( data, pos, getRecordSize()-8 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_1_dx1 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_2_dy1 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_3_dx2 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_4_dy2 ); pos += 4;
|
||||||
|
|
||||||
|
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 8 + 4 * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The record id for the EscherChildAnchorRecord.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "ChildAnchor";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string representation of this record
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" X1: " + field_1_dx1 + nl +
|
||||||
|
" Y1: " + field_2_dy1 + nl +
|
||||||
|
" X2: " + field_3_dx2 + nl +
|
||||||
|
" Y2: " + field_4_dy2 + nl ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves offset within the parent coordinate space for the top left point.
|
||||||
|
*/
|
||||||
|
public int getDx1()
|
||||||
|
{
|
||||||
|
return field_1_dx1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets offset within the parent coordinate space for the top left point.
|
||||||
|
*/
|
||||||
|
public void setDx1( int field_1_dx1 )
|
||||||
|
{
|
||||||
|
this.field_1_dx1 = field_1_dx1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets offset within the parent coordinate space for the top left point.
|
||||||
|
*/
|
||||||
|
public int getDy1()
|
||||||
|
{
|
||||||
|
return field_2_dy1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets offset within the parent coordinate space for the top left point.
|
||||||
|
*/
|
||||||
|
public void setDy1( int field_2_dy1 )
|
||||||
|
{
|
||||||
|
this.field_2_dy1 = field_2_dy1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves offset within the parent coordinate space for the bottom right point.
|
||||||
|
*/
|
||||||
|
public int getDx2()
|
||||||
|
{
|
||||||
|
return field_3_dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets offset within the parent coordinate space for the bottom right point.
|
||||||
|
*/
|
||||||
|
public void setDx2( int field_3_dx2 )
|
||||||
|
{
|
||||||
|
this.field_3_dx2 = field_3_dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the offset within the parent coordinate space for the bottom right point.
|
||||||
|
*/
|
||||||
|
public int getDy2()
|
||||||
|
{
|
||||||
|
return field_4_dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the offset within the parent coordinate space for the bottom right point.
|
||||||
|
*/
|
||||||
|
public void setDy2( int field_4_dy2 )
|
||||||
|
{
|
||||||
|
this.field_4_dy2 = field_4_dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
317
src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
Normal file
317
src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The escher client anchor specifies which rows and cells the shape is bound to as well as
|
||||||
|
* the offsets within those cells. Each cell is 1024 units wide by 256 units long regardless
|
||||||
|
* of the actual size of the cell. The EscherClientAnchorRecord only applies to the top-most
|
||||||
|
* shapes. Shapes contained in groups are bound using the EscherChildAnchorRecords.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
* @see EscherChildAnchorRecord
|
||||||
|
*/
|
||||||
|
public class EscherClientAnchorRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF010;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtClientAnchor";
|
||||||
|
|
||||||
|
private short field_1_flag;
|
||||||
|
private short field_2_col1;
|
||||||
|
private short field_3_dx1;
|
||||||
|
private short field_4_row1;
|
||||||
|
private short field_5_dy1;
|
||||||
|
private short field_6_col2;
|
||||||
|
private short field_7_dx2;
|
||||||
|
private short field_8_row2;
|
||||||
|
private short field_9_dy2;
|
||||||
|
private byte[] remainingData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
int size = 0;
|
||||||
|
field_1_flag = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_2_col1 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_3_dx1 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_4_row1 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_5_dy1 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_6_col2 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_7_dx2 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_8_row2 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
field_9_dy2 = LittleEndian.getShort( data, pos + size ); size += 2;
|
||||||
|
bytesRemaining -= size;
|
||||||
|
remainingData = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
|
||||||
|
return 8 + size + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
|
||||||
|
if (remainingData == null) remainingData = new byte[0];
|
||||||
|
LittleEndian.putShort( data, offset, getOptions() );
|
||||||
|
LittleEndian.putShort( data, offset + 2, getRecordId() );
|
||||||
|
int remainingBytes = remainingData.length + 18;
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
||||||
|
LittleEndian.putShort( data, offset + 8, field_1_flag );
|
||||||
|
LittleEndian.putShort( data, offset + 10, field_2_col1 );
|
||||||
|
LittleEndian.putShort( data, offset + 12, field_3_dx1 );
|
||||||
|
LittleEndian.putShort( data, offset + 14, field_4_row1 );
|
||||||
|
LittleEndian.putShort( data, offset + 16, field_5_dy1 );
|
||||||
|
LittleEndian.putShort( data, offset + 18, field_6_col2 );
|
||||||
|
LittleEndian.putShort( data, offset + 20, field_7_dx2 );
|
||||||
|
LittleEndian.putShort( data, offset + 22, field_8_row2 );
|
||||||
|
LittleEndian.putShort( data, offset + 24, field_9_dy2 );
|
||||||
|
System.arraycopy( remainingData, 0, data, offset + 26, remainingData.length );
|
||||||
|
int pos = offset + 8 + 18 + remainingData.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 8 + 18 + (remainingData == null ? 0 : remainingData.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The record id for this record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "ClientAnchor";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation for this record.
|
||||||
|
*
|
||||||
|
* @return A string
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String extraData;
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
extraData = b.toString();
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
extraData = "error";
|
||||||
|
}
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" Flag: " + field_1_flag + nl +
|
||||||
|
" Col1: " + field_2_col1 + nl +
|
||||||
|
" DX1: " + field_3_dx1 + nl +
|
||||||
|
" Row1: " + field_4_row1 + nl +
|
||||||
|
" DY1: " + field_5_dy1 + nl +
|
||||||
|
" Col2: " + field_6_col2 + nl +
|
||||||
|
" DX2: " + field_7_dx2 + nl +
|
||||||
|
" Row2: " + field_8_row2 + nl +
|
||||||
|
" DY2: " + field_9_dy2 + nl +
|
||||||
|
" Extra Data:" + nl + extraData;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
|
||||||
|
*/
|
||||||
|
public short getFlag()
|
||||||
|
{
|
||||||
|
return field_1_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
|
||||||
|
*/
|
||||||
|
public void setFlag( short field_1_flag )
|
||||||
|
{
|
||||||
|
this.field_1_flag = field_1_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The column number for the top-left position. 0 based.
|
||||||
|
*/
|
||||||
|
public short getCol1()
|
||||||
|
{
|
||||||
|
return field_2_col1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The column number for the top-left position. 0 based.
|
||||||
|
*/
|
||||||
|
public void setCol1( short field_2_col1 )
|
||||||
|
{
|
||||||
|
this.field_2_col1 = field_2_col1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x offset within the top-left cell. Range is from 0 to 1023.
|
||||||
|
*/
|
||||||
|
public short getDx1()
|
||||||
|
{
|
||||||
|
return field_3_dx1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x offset within the top-left cell. Range is from 0 to 1023.
|
||||||
|
*/
|
||||||
|
public void setDx1( short field_3_dx1 )
|
||||||
|
{
|
||||||
|
this.field_3_dx1 = field_3_dx1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The row number for the top-left corner of the shape.
|
||||||
|
*/
|
||||||
|
public short getRow1()
|
||||||
|
{
|
||||||
|
return field_4_row1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The row number for the top-left corner of the shape.
|
||||||
|
*/
|
||||||
|
public void setRow1( short field_4_row1 )
|
||||||
|
{
|
||||||
|
this.field_4_row1 = field_4_row1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y offset within the top-left corner of the current shape.
|
||||||
|
*/
|
||||||
|
public short getDy1()
|
||||||
|
{
|
||||||
|
return field_5_dy1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y offset within the top-left corner of the current shape.
|
||||||
|
*/
|
||||||
|
public void setDy1( short field_5_dy1 )
|
||||||
|
{
|
||||||
|
this.field_5_dy1 = field_5_dy1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The column of the bottom right corner of this shape.
|
||||||
|
*/
|
||||||
|
public short getCol2()
|
||||||
|
{
|
||||||
|
return field_6_col2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The column of the bottom right corner of this shape.
|
||||||
|
*/
|
||||||
|
public void setCol2( short field_6_col2 )
|
||||||
|
{
|
||||||
|
this.field_6_col2 = field_6_col2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x offset withing the cell for the bottom-right corner of this shape.
|
||||||
|
*/
|
||||||
|
public short getDx2()
|
||||||
|
{
|
||||||
|
return field_7_dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The x offset withing the cell for the bottom-right corner of this shape.
|
||||||
|
*/
|
||||||
|
public void setDx2( short field_7_dx2 )
|
||||||
|
{
|
||||||
|
this.field_7_dx2 = field_7_dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The row number for the bottom-right corner of the current shape.
|
||||||
|
*/
|
||||||
|
public short getRow2()
|
||||||
|
{
|
||||||
|
return field_8_row2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The row number for the bottom-right corner of the current shape.
|
||||||
|
*/
|
||||||
|
public void setRow2( short field_8_row2 )
|
||||||
|
{
|
||||||
|
this.field_8_row2 = field_8_row2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y offset withing the cell for the bottom-right corner of this shape.
|
||||||
|
*/
|
||||||
|
public short getDy2()
|
||||||
|
{
|
||||||
|
return field_9_dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The y offset withing the cell for the bottom-right corner of this shape.
|
||||||
|
*/
|
||||||
|
public void setDy2( short field_9_dy2 )
|
||||||
|
{
|
||||||
|
this.field_9_dy2 = field_9_dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any remaining data in the record
|
||||||
|
*/
|
||||||
|
public byte[] getRemainingData()
|
||||||
|
{
|
||||||
|
return remainingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any remaining data in the record
|
||||||
|
*/
|
||||||
|
public void setRemainingData( byte[] remainingData )
|
||||||
|
{
|
||||||
|
this.remainingData = remainingData;
|
||||||
|
}
|
||||||
|
}
|
130
src/java/org/apache/poi/ddf/EscherClientDataRecord.java
Normal file
130
src/java/org/apache/poi/ddf/EscherClientDataRecord.java
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The EscherClientDataRecord is used to store client specific data about the position of a
|
||||||
|
* shape within a container.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherClientDataRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF011;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtClientData";
|
||||||
|
|
||||||
|
private byte[] remainingData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
remainingData = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, pos, remainingData, 0, bytesRemaining );
|
||||||
|
return 8 + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
|
||||||
|
if (remainingData == null) remainingData = new byte[0];
|
||||||
|
LittleEndian.putShort( data, offset, getOptions() );
|
||||||
|
LittleEndian.putShort( data, offset + 2, getRecordId() );
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingData.length );
|
||||||
|
System.arraycopy( remainingData, 0, data, offset + 8, remainingData.length );
|
||||||
|
int pos = offset + 8 + remainingData.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 8 + (remainingData == null ? 0 : remainingData.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the identifier of this record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "ClientData";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation of this record.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String extraData;
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
extraData = b.toString();
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
extraData = "error";
|
||||||
|
}
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" Extra Data:" + nl +
|
||||||
|
extraData;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any data recording this record.
|
||||||
|
*/
|
||||||
|
public byte[] getRemainingData()
|
||||||
|
{
|
||||||
|
return remainingData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any data recording this record.
|
||||||
|
*/
|
||||||
|
public void setRemainingData( byte[] remainingData )
|
||||||
|
{
|
||||||
|
this.remainingData = remainingData;
|
||||||
|
}
|
||||||
|
}
|
152
src/java/org/apache/poi/ddf/EscherComplexProperty.java
Normal file
152
src/java/org/apache/poi/ddf/EscherComplexProperty.java
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A complex property differs from a simple property in that the data can not fit inside a 32 bit
|
||||||
|
* integer. See the specification for more detailed information regarding exactly what is
|
||||||
|
* stored here.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherComplexProperty
|
||||||
|
extends EscherProperty
|
||||||
|
{
|
||||||
|
byte[] complexData = new byte[0];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a complex property using the property id and a byte array containing the complex
|
||||||
|
* data value.
|
||||||
|
*
|
||||||
|
* @param id The id consists of the property number, a flag indicating whether this is a blip id and a flag
|
||||||
|
* indicating that this is a complex property.
|
||||||
|
* @param complexData The value of this property.
|
||||||
|
*/
|
||||||
|
public EscherComplexProperty( short id, byte[] complexData )
|
||||||
|
{
|
||||||
|
super( id );
|
||||||
|
this.complexData = complexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a complex property using the property number, a flag to indicate whether this is a
|
||||||
|
* blip reference and the complex property data.
|
||||||
|
*
|
||||||
|
* @param propertyNumber The property number
|
||||||
|
* @param isBlipId Whether this is a blip id. Should be false.
|
||||||
|
* @param complexData The value of this complex property.
|
||||||
|
*/
|
||||||
|
public EscherComplexProperty( short propertyNumber, boolean isBlipId, byte[] complexData )
|
||||||
|
{
|
||||||
|
super( propertyNumber, true, isBlipId );
|
||||||
|
this.complexData = complexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the simple part of this property. ie the first 6 bytes.
|
||||||
|
*/
|
||||||
|
public int serializeSimplePart( byte[] data, int pos )
|
||||||
|
{
|
||||||
|
LittleEndian.putShort(data, pos, getId());
|
||||||
|
LittleEndian.putInt(data, pos + 2, complexData.length);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the complex part of this property
|
||||||
|
*
|
||||||
|
* @param data The data array to serialize to
|
||||||
|
* @param pos The offset within data to start serializing to.
|
||||||
|
* @return The number of bytes serialized.
|
||||||
|
*/
|
||||||
|
public int serializeComplexPart( byte[] data, int pos )
|
||||||
|
{
|
||||||
|
System.arraycopy(complexData, 0, data, pos, complexData.length);
|
||||||
|
return complexData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the complex data value.
|
||||||
|
*/
|
||||||
|
public byte[] getComplexData()
|
||||||
|
{
|
||||||
|
return complexData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether this property is equal to another property.
|
||||||
|
*
|
||||||
|
* @param o The object to compare to.
|
||||||
|
* @return True if the objects are equal.
|
||||||
|
*/
|
||||||
|
public boolean equals( Object o )
|
||||||
|
{
|
||||||
|
if ( this == o ) return true;
|
||||||
|
if ( !( o instanceof EscherComplexProperty ) ) return false;
|
||||||
|
|
||||||
|
final EscherComplexProperty escherComplexProperty = (EscherComplexProperty) o;
|
||||||
|
|
||||||
|
if ( !Arrays.equals( complexData, escherComplexProperty.complexData ) ) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caclulates the number of bytes required to serialize this property.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getPropertySize()
|
||||||
|
{
|
||||||
|
return 6 + complexData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a hashcode for this property.
|
||||||
|
*/
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return getId() * 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the string representation for this property.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String dataStr;
|
||||||
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HexDump.dump( this.complexData, 0, b, 0 );
|
||||||
|
dataStr = b.toString();
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
dataStr = e.toString();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
b.close();
|
||||||
|
}
|
||||||
|
catch ( IOException e )
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "propNum: " + getPropertyNumber()
|
||||||
|
+ ", propName: " + EscherProperties.getPropertyName( getPropertyNumber() )
|
||||||
|
+ ", complex: " + isComplex()
|
||||||
|
+ ", blipId: " + isBlipId()
|
||||||
|
+ ", data: " + System.getProperty("line.separator") + dataStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
168
src/java/org/apache/poi/ddf/EscherContainerRecord.java
Normal file
168
src/java/org/apache/poi/ddf/EscherContainerRecord.java
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher container records store other escher records as children.
|
||||||
|
* The container records themselves never store any information beyond
|
||||||
|
* the standard header used by all escher records. This one record is
|
||||||
|
* used to represent many different types of records.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherContainerRecord extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short DGG_CONTAINER = (short)0xF000;
|
||||||
|
public static final short BSTORE_CONTAINER = (short)0xF001;
|
||||||
|
public static final short DG_CONTAINER = (short)0xF002;
|
||||||
|
public static final short SPGR_CONTAINER = (short)0xF003;
|
||||||
|
public static final short SP_CONTAINER = (short)0xF004;
|
||||||
|
public static final short SOLVER_CONTAINER = (short)0xF005;
|
||||||
|
|
||||||
|
private List childRecords = new ArrayList();
|
||||||
|
|
||||||
|
public int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory )
|
||||||
|
{
|
||||||
|
int bytesRemaining = readHeader( data, offset );
|
||||||
|
int bytesWritten = 8;
|
||||||
|
offset += 8;
|
||||||
|
while ( bytesRemaining > 0 && offset < data.length )
|
||||||
|
{
|
||||||
|
EscherRecord child = recordFactory.createRecord(data, offset);
|
||||||
|
int childBytesWritten = child.fillFields( data, offset, recordFactory );
|
||||||
|
bytesWritten += childBytesWritten;
|
||||||
|
offset += childBytesWritten;
|
||||||
|
bytesRemaining -= childBytesWritten;
|
||||||
|
getChildRecords().add( child );
|
||||||
|
if (offset >= data.length && bytesRemaining > 0)
|
||||||
|
{
|
||||||
|
System.out.println("WARNING: " + bytesRemaining + " bytes remaining but no space left");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = 0;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
remainingBytes += r.getRecordSize();
|
||||||
|
}
|
||||||
|
LittleEndian.putInt(data, offset+4, remainingBytes);
|
||||||
|
int pos = offset+8;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
pos += r.serialize(pos, data, listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
|
||||||
|
return pos - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
int childRecordsSize = 0;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
childRecordsSize += r.getRecordSize();
|
||||||
|
}
|
||||||
|
return 8 + childRecordsSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List getChildRecords()
|
||||||
|
{
|
||||||
|
return childRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildRecords( List childRecords )
|
||||||
|
{
|
||||||
|
this.childRecords = childRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
switch ((short)getRecordId())
|
||||||
|
{
|
||||||
|
case DGG_CONTAINER:
|
||||||
|
return "DggContainer";
|
||||||
|
case BSTORE_CONTAINER:
|
||||||
|
return "BStoreContainer";
|
||||||
|
case DG_CONTAINER:
|
||||||
|
return "DgContainer";
|
||||||
|
case SPGR_CONTAINER:
|
||||||
|
return "SpgrContainer";
|
||||||
|
case SP_CONTAINER:
|
||||||
|
return "SpContainer";
|
||||||
|
case SOLVER_CONTAINER:
|
||||||
|
return "SolverContainer";
|
||||||
|
default:
|
||||||
|
return "Container 0x" + HexDump.toHex(getRecordId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display( PrintWriter w, int indent )
|
||||||
|
{
|
||||||
|
super.display( w, indent );
|
||||||
|
for ( Iterator iterator = childRecords.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||||||
|
escherRecord.display( w, indent + 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChildRecord( EscherRecord record )
|
||||||
|
{
|
||||||
|
this.childRecords.add( record );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
StringBuffer children = new StringBuffer();
|
||||||
|
if ( getChildRecords().size() > 0 )
|
||||||
|
{
|
||||||
|
children.append( " children: " + nl );
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord record = (EscherRecord) iterator.next();
|
||||||
|
children.append( record.toString() );
|
||||||
|
// children.append( nl );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getClass().getName() + " (" + getRecordName() + "):" + nl +
|
||||||
|
" isContainer: " + isContainerRecord() + nl +
|
||||||
|
" options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||||
|
" numchildren: " + getChildRecords().size() + nl +
|
||||||
|
children.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherSpRecord getChildById( short recordId )
|
||||||
|
{
|
||||||
|
for ( Iterator iterator = childRecords.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||||||
|
if (escherRecord.getRecordId() == recordId)
|
||||||
|
return (EscherSpRecord) escherRecord;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
163
src/java/org/apache/poi/ddf/EscherDgRecord.java
Normal file
163
src/java/org/apache/poi/ddf/EscherDgRecord.java
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This record simply holds the number of shapes in the drawing group and the
|
||||||
|
* last shape id used for this drawing group.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherDgRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF008;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtDg";
|
||||||
|
|
||||||
|
private int field_1_numShapes;
|
||||||
|
private int field_2_lastMSOSPID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
int size = 0;
|
||||||
|
field_1_numShapes = LittleEndian.getInt( data, pos + size ); size += 4;
|
||||||
|
field_2_lastMSOSPID = LittleEndian.getInt( data, pos + size ); size += 4;
|
||||||
|
// bytesRemaining -= size;
|
||||||
|
// remainingData = new byte[bytesRemaining];
|
||||||
|
// System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() );
|
||||||
|
LittleEndian.putInt( data, offset + 4, 8 );
|
||||||
|
LittleEndian.putInt( data, offset + 8, field_1_numShapes );
|
||||||
|
LittleEndian.putInt( data, offset + 12, field_2_lastMSOSPID );
|
||||||
|
// System.arraycopy( remainingData, 0, data, offset + 26, remainingData.length );
|
||||||
|
// int pos = offset + 8 + 18 + remainingData.length;
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( offset + 16, getRecordId(), getRecordSize(), this );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Dg";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation of this record.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
// String extraData;
|
||||||
|
// ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
// extraData = b.toString();
|
||||||
|
// }
|
||||||
|
// catch ( Exception e )
|
||||||
|
// {
|
||||||
|
// extraData = "error";
|
||||||
|
// }
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" NumShapes: " + field_1_numShapes + nl +
|
||||||
|
" LastMSOSPID: " + field_2_lastMSOSPID + nl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of shapes in this drawing group.
|
||||||
|
*/
|
||||||
|
public int getNumShapes()
|
||||||
|
{
|
||||||
|
return field_1_numShapes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of shapes in this drawing group.
|
||||||
|
*/
|
||||||
|
public void setNumShapes( int field_1_numShapes )
|
||||||
|
{
|
||||||
|
this.field_1_numShapes = field_1_numShapes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last shape id used in this drawing group.
|
||||||
|
*/
|
||||||
|
public int getLastMSOSPID()
|
||||||
|
{
|
||||||
|
return field_2_lastMSOSPID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last shape id used in this drawing group.
|
||||||
|
*/
|
||||||
|
public void setLastMSOSPID( int field_2_lastMSOSPID )
|
||||||
|
{
|
||||||
|
this.field_2_lastMSOSPID = field_2_lastMSOSPID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the drawing group id for this record. This is encoded in the
|
||||||
|
* instance part of the option record.
|
||||||
|
*
|
||||||
|
* @return a drawing group id.
|
||||||
|
*/
|
||||||
|
public short getDrawingGroupId()
|
||||||
|
{
|
||||||
|
return (short) ( getOptions() >> 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incrementShapeCount()
|
||||||
|
{
|
||||||
|
this.field_1_numShapes++;
|
||||||
|
}
|
||||||
|
}
|
241
src/java/org/apache/poi/ddf/EscherDggRecord.java
Normal file
241
src/java/org/apache/poi/ddf/EscherDggRecord.java
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
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.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This record defines the drawing groups used for a particular sheet.
|
||||||
|
*/
|
||||||
|
public class EscherDggRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF006;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtDgg";
|
||||||
|
|
||||||
|
private int field_1_shapeIdMax;
|
||||||
|
// private int field_2_numIdClusters; // for some reason the number of clusters is actually the real number + 1
|
||||||
|
private int field_3_numShapesSaved;
|
||||||
|
private int field_4_drawingsSaved;
|
||||||
|
private FileIdCluster[] field_5_fileIdClusters;
|
||||||
|
|
||||||
|
public static class FileIdCluster
|
||||||
|
{
|
||||||
|
public FileIdCluster( int drawingGroupId, int numShapeIdsUsed )
|
||||||
|
{
|
||||||
|
this.field_1_drawingGroupId = drawingGroupId;
|
||||||
|
this.field_2_numShapeIdsUsed = numShapeIdsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int field_1_drawingGroupId;
|
||||||
|
private int field_2_numShapeIdsUsed;
|
||||||
|
|
||||||
|
public int getDrawingGroupId()
|
||||||
|
{
|
||||||
|
return field_1_drawingGroupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumShapeIdsUsed()
|
||||||
|
{
|
||||||
|
return field_2_numShapeIdsUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incrementShapeId( )
|
||||||
|
{
|
||||||
|
this.field_2_numShapeIdsUsed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
int size = 0;
|
||||||
|
field_1_shapeIdMax = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
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[i] = new FileIdCluster(LittleEndian.getInt( data, pos + size ), LittleEndian.getInt( data, pos + size + 4 ));
|
||||||
|
size += 8;
|
||||||
|
}
|
||||||
|
bytesRemaining -= size;
|
||||||
|
if (bytesRemaining != 0)
|
||||||
|
throw new RecordFormatException("Expecting no remaining data but got " + bytesRemaining + " byte(s).");
|
||||||
|
return 8 + size + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 );
|
||||||
|
|
||||||
|
int pos = offset;
|
||||||
|
LittleEndian.putShort( data, pos, getOptions() ); pos += 2;
|
||||||
|
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;
|
||||||
|
LittleEndian.putInt( data, pos, field_4_drawingsSaved ); pos += 4;
|
||||||
|
for ( int i = 0; i < field_5_fileIdClusters.length; i++ )
|
||||||
|
{
|
||||||
|
LittleEndian.putInt( data, pos, field_5_fileIdClusters[i].field_1_drawingGroupId ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_5_fileIdClusters[i].field_2_numShapeIdsUsed ); pos += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), getRecordSize(), this );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 16 + (8 * field_5_fileIdClusters.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Dgg";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
// String extraData;
|
||||||
|
// ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
// extraData = b.toString();
|
||||||
|
// }
|
||||||
|
// catch ( Exception e )
|
||||||
|
// {
|
||||||
|
// extraData = "error";
|
||||||
|
// }
|
||||||
|
StringBuffer field_5_string = new StringBuffer();
|
||||||
|
for ( int i = 0; i < field_5_fileIdClusters.length; i++ )
|
||||||
|
{
|
||||||
|
field_5_string.append(" DrawingGroupId").append(i+1).append(": ");
|
||||||
|
field_5_string.append(field_5_fileIdClusters[i].field_1_drawingGroupId);
|
||||||
|
field_5_string.append(nl);
|
||||||
|
field_5_string.append(" NumShapeIdsUsed").append(i+1).append(": ");
|
||||||
|
field_5_string.append(field_5_fileIdClusters[i].field_2_numShapeIdsUsed);
|
||||||
|
field_5_string.append(nl);
|
||||||
|
}
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" ShapeIdMax: " + field_1_shapeIdMax + nl +
|
||||||
|
" NumIdClusters: " + getNumIdClusters() + nl +
|
||||||
|
" NumShapesSaved: " + field_3_numShapesSaved + nl +
|
||||||
|
" DrawingsSaved: " + field_4_drawingsSaved + nl +
|
||||||
|
"" + field_5_string.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getShapeIdMax()
|
||||||
|
{
|
||||||
|
return field_1_shapeIdMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum is actually the next available. shape id.
|
||||||
|
*/
|
||||||
|
public void setShapeIdMax( int field_1_shapeIdMax )
|
||||||
|
{
|
||||||
|
this.field_1_shapeIdMax = field_1_shapeIdMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumIdClusters()
|
||||||
|
{
|
||||||
|
return field_5_fileIdClusters.length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumShapesSaved()
|
||||||
|
{
|
||||||
|
return field_3_numShapesSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumShapesSaved( int field_3_numShapesSaved )
|
||||||
|
{
|
||||||
|
this.field_3_numShapesSaved = field_3_numShapesSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDrawingsSaved()
|
||||||
|
{
|
||||||
|
return field_4_drawingsSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDrawingsSaved( int field_4_drawingsSaved )
|
||||||
|
{
|
||||||
|
this.field_4_drawingsSaved = field_4_drawingsSaved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileIdCluster[] getFileIdClusters()
|
||||||
|
{
|
||||||
|
return field_5_fileIdClusters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileIdClusters( FileIdCluster[] field_5_fileIdClusters )
|
||||||
|
{
|
||||||
|
this.field_5_fileIdClusters = field_5_fileIdClusters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCluster( int dgId, int numShapedUsed )
|
||||||
|
{
|
||||||
|
List clusters = new ArrayList(Arrays.asList(field_5_fileIdClusters));
|
||||||
|
clusters.add(new FileIdCluster(dgId, numShapedUsed));
|
||||||
|
Collections.sort(clusters, new Comparator()
|
||||||
|
{
|
||||||
|
public int compare( Object o1, Object o2 )
|
||||||
|
{
|
||||||
|
FileIdCluster f1 = (FileIdCluster) o1;
|
||||||
|
FileIdCluster f2 = (FileIdCluster) o2;
|
||||||
|
if (f1.getDrawingGroupId() == f2.getDrawingGroupId())
|
||||||
|
return 0;
|
||||||
|
if (f1.getDrawingGroupId() < f2.getDrawingGroupId())
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
field_5_fileIdClusters = (FileIdCluster[]) clusters.toArray( new FileIdCluster[clusters.size()] );
|
||||||
|
}
|
||||||
|
}
|
990
src/java/org/apache/poi/ddf/EscherDump.java
Normal file
990
src/java/org/apache/poi/ddf/EscherDump.java
Normal file
@ -0,0 +1,990 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to dump the contents of escher records to a PrintStream.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherDump
|
||||||
|
{
|
||||||
|
|
||||||
|
public EscherDump()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the escher stream from a byte array and dumps the results to
|
||||||
|
* a print stream.
|
||||||
|
*
|
||||||
|
* @param data The data array containing the escher records.
|
||||||
|
* @param offset The starting offset within the data array.
|
||||||
|
* @param size The number of bytes to read.
|
||||||
|
* @param out The output stream to write the results to.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void dump( byte[] data, int offset, int size, PrintStream out ) throws IOException, LittleEndian.BufferUnderrunException
|
||||||
|
{
|
||||||
|
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory();
|
||||||
|
int pos = offset;
|
||||||
|
while ( pos < offset + size )
|
||||||
|
{
|
||||||
|
EscherRecord r = recordFactory.createRecord(data, pos);
|
||||||
|
int bytesRead = r.fillFields(data, pos, recordFactory );
|
||||||
|
System.out.println( r.toString() );
|
||||||
|
pos += bytesRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This version of dump is a translation from the open office escher dump routine.
|
||||||
|
*
|
||||||
|
* @param maxLength The number of bytes to read
|
||||||
|
* @param in An input stream to read from.
|
||||||
|
* @param out An output stream to write to.
|
||||||
|
*/
|
||||||
|
public void dumpOld( long maxLength, InputStream in, PrintStream out ) throws IOException, LittleEndian.BufferUnderrunException
|
||||||
|
{
|
||||||
|
long remainingBytes = maxLength;
|
||||||
|
short options; // 4 bits for the version and 12 bits for the instance
|
||||||
|
short recordId;
|
||||||
|
int recordBytesRemaining; // including enclosing records
|
||||||
|
StringBuffer stringBuf = new StringBuffer();
|
||||||
|
short nDumpSize;
|
||||||
|
String recordName;
|
||||||
|
|
||||||
|
boolean atEOF = false;
|
||||||
|
|
||||||
|
while ( !atEOF && ( remainingBytes > 0 ) )
|
||||||
|
{
|
||||||
|
stringBuf = new StringBuffer();
|
||||||
|
options = LittleEndian.readShort( in );
|
||||||
|
recordId = LittleEndian.readShort( in );
|
||||||
|
recordBytesRemaining = LittleEndian.readInt( in );
|
||||||
|
|
||||||
|
remainingBytes -= 2 + 2 + 4;
|
||||||
|
|
||||||
|
switch ( recordId )
|
||||||
|
{
|
||||||
|
case (short) 0xF000:
|
||||||
|
recordName = "MsofbtDggContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF006:
|
||||||
|
recordName = "MsofbtDgg";
|
||||||
|
break;
|
||||||
|
case (short) 0xF016:
|
||||||
|
recordName = "MsofbtCLSID";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00B:
|
||||||
|
recordName = "MsofbtOPT";
|
||||||
|
break;
|
||||||
|
case (short) 0xF11A:
|
||||||
|
recordName = "MsofbtColorMRU";
|
||||||
|
break;
|
||||||
|
case (short) 0xF11E:
|
||||||
|
recordName = "MsofbtSplitMenuColors";
|
||||||
|
break;
|
||||||
|
case (short) 0xF001:
|
||||||
|
recordName = "MsofbtBstoreContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF007:
|
||||||
|
recordName = "MsofbtBSE";
|
||||||
|
break;
|
||||||
|
case (short) 0xF002:
|
||||||
|
recordName = "MsofbtDgContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF008:
|
||||||
|
recordName = "MsofbtDg";
|
||||||
|
break;
|
||||||
|
case (short) 0xF118:
|
||||||
|
recordName = "MsofbtRegroupItem";
|
||||||
|
break;
|
||||||
|
case (short) 0xF120:
|
||||||
|
recordName = "MsofbtColorScheme";
|
||||||
|
break;
|
||||||
|
case (short) 0xF003:
|
||||||
|
recordName = "MsofbtSpgrContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF004:
|
||||||
|
recordName = "MsofbtSpContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF009:
|
||||||
|
recordName = "MsofbtSpgr";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00A:
|
||||||
|
recordName = "MsofbtSp";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00C:
|
||||||
|
recordName = "MsofbtTextbox";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00D:
|
||||||
|
recordName = "MsofbtClientTextbox";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00E:
|
||||||
|
recordName = "MsofbtAnchor";
|
||||||
|
break;
|
||||||
|
case (short) 0xF00F:
|
||||||
|
recordName = "MsofbtChildAnchor";
|
||||||
|
break;
|
||||||
|
case (short) 0xF010:
|
||||||
|
recordName = "MsofbtClientAnchor";
|
||||||
|
break;
|
||||||
|
case (short) 0xF011:
|
||||||
|
recordName = "MsofbtClientData";
|
||||||
|
break;
|
||||||
|
case (short) 0xF11F:
|
||||||
|
recordName = "MsofbtOleObject";
|
||||||
|
break;
|
||||||
|
case (short) 0xF11D:
|
||||||
|
recordName = "MsofbtDeletedPspl";
|
||||||
|
break;
|
||||||
|
case (short) 0xF005:
|
||||||
|
recordName = "MsofbtSolverContainer";
|
||||||
|
break;
|
||||||
|
case (short) 0xF012:
|
||||||
|
recordName = "MsofbtConnectorRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF013:
|
||||||
|
recordName = "MsofbtAlignRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF014:
|
||||||
|
recordName = "MsofbtArcRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF015:
|
||||||
|
recordName = "MsofbtClientRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF017:
|
||||||
|
recordName = "MsofbtCalloutRule";
|
||||||
|
break;
|
||||||
|
case (short) 0xF119:
|
||||||
|
recordName = "MsofbtSelection";
|
||||||
|
break;
|
||||||
|
case (short) 0xF122:
|
||||||
|
recordName = "MsofbtUDefProp";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ( recordId >= (short) 0xF018 && recordId <= (short) 0xF117 )
|
||||||
|
recordName = "MsofbtBLIP";
|
||||||
|
else if ( ( options & (short) 0x000F ) == (short) 0x000F )
|
||||||
|
recordName = "UNKNOWN container";
|
||||||
|
else
|
||||||
|
recordName = "UNKNOWN ID";
|
||||||
|
}
|
||||||
|
|
||||||
|
stringBuf.append( " " );
|
||||||
|
stringBuf.append( HexDump.toHex( recordId ) );
|
||||||
|
stringBuf.append( " " ).append( recordName ).append( " [" );
|
||||||
|
stringBuf.append( HexDump.toHex( options ) );
|
||||||
|
stringBuf.append( ',' );
|
||||||
|
stringBuf.append( HexDump.toHex( recordBytesRemaining ) );
|
||||||
|
stringBuf.append( "] instance: " );
|
||||||
|
stringBuf.append( HexDump.toHex( ( (short) ( options >> 4 ) ) ) );
|
||||||
|
out.println( stringBuf.toString() );
|
||||||
|
|
||||||
|
|
||||||
|
if ( recordId == (short) 0xF007 && 36 <= remainingBytes && 36 <= recordBytesRemaining )
|
||||||
|
{ // BSE, FBSE
|
||||||
|
// ULONG nP = pIn->GetRecPos();
|
||||||
|
|
||||||
|
byte n8;
|
||||||
|
// short n16;
|
||||||
|
// int n32;
|
||||||
|
|
||||||
|
stringBuf = new StringBuffer( " btWin32: " );
|
||||||
|
n8 = (byte) in.read();
|
||||||
|
stringBuf.append( HexDump.toHex( n8 ) );
|
||||||
|
stringBuf.append( getBlipType( n8 ) );
|
||||||
|
stringBuf.append( " btMacOS: " );
|
||||||
|
n8 = (byte) in.read();
|
||||||
|
stringBuf.append( HexDump.toHex( n8 ) );
|
||||||
|
stringBuf.append( getBlipType( n8 ) );
|
||||||
|
out.println( stringBuf.toString() );
|
||||||
|
|
||||||
|
out.println( " rgbUid:" );
|
||||||
|
HexDump.dump( in, out, 0, 16 );
|
||||||
|
|
||||||
|
out.print( " tag: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " size: " );
|
||||||
|
outHex( 4, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " cRef: " );
|
||||||
|
outHex( 4, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " offs: " );
|
||||||
|
outHex( 4, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " usage: " );
|
||||||
|
outHex( 1, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " cbName: " );
|
||||||
|
outHex( 1, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " unused2: " );
|
||||||
|
outHex( 1, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " unused3: " );
|
||||||
|
outHex( 1, in, out );
|
||||||
|
out.println();
|
||||||
|
|
||||||
|
// subtract the number of bytes we've read
|
||||||
|
remainingBytes -= 36;
|
||||||
|
//n -= pIn->GetRecPos() - nP;
|
||||||
|
recordBytesRemaining = 0; // loop to MsofbtBLIP
|
||||||
|
}
|
||||||
|
else if ( recordId == (short) 0xF010 && 0x12 <= remainingBytes && 0x12 <= recordBytesRemaining )
|
||||||
|
{ // ClientAnchor
|
||||||
|
//ULONG nP = pIn->GetRecPos();
|
||||||
|
// short n16;
|
||||||
|
|
||||||
|
out.print( " Flag: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " Col1: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " dX1: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " Row1: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " dY1: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.println();
|
||||||
|
out.print( " Col2: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " dX2: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " Row2: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.print( " dY2: " );
|
||||||
|
outHex( 2, in, out );
|
||||||
|
out.println();
|
||||||
|
|
||||||
|
remainingBytes -= 18;
|
||||||
|
recordBytesRemaining -= 18;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ( recordId == (short) 0xF00B || recordId == (short) 0xF122 )
|
||||||
|
{ // OPT
|
||||||
|
int nComplex = 0;
|
||||||
|
out.println( " PROPID VALUE" );
|
||||||
|
while ( recordBytesRemaining >= 6 + nComplex && remainingBytes >= 6 + nComplex )
|
||||||
|
{
|
||||||
|
short n16;
|
||||||
|
int n32;
|
||||||
|
n16 = LittleEndian.readShort( in );
|
||||||
|
n32 = LittleEndian.readInt( in );
|
||||||
|
|
||||||
|
recordBytesRemaining -= 6;
|
||||||
|
remainingBytes -= 6;
|
||||||
|
out.print( " " );
|
||||||
|
out.print( HexDump.toHex( n16 ) );
|
||||||
|
out.print( " (" );
|
||||||
|
int propertyId = n16 & (short) 0x3FFF;
|
||||||
|
out.print( " " + propertyId );
|
||||||
|
if ( ( n16 & (short) 0x8000 ) == 0 )
|
||||||
|
{
|
||||||
|
if ( ( n16 & (short) 0x4000 ) != 0 )
|
||||||
|
out.print( ", fBlipID" );
|
||||||
|
out.print( ") " );
|
||||||
|
|
||||||
|
out.print( HexDump.toHex( n32 ) );
|
||||||
|
|
||||||
|
if ( ( n16 & (short) 0x4000 ) == 0 )
|
||||||
|
{
|
||||||
|
out.print( " (" );
|
||||||
|
out.print( dec1616( n32 ) );
|
||||||
|
out.print( ')' );
|
||||||
|
out.print( " {" + propName( (short)propertyId ) + "}" );
|
||||||
|
}
|
||||||
|
out.println();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out.print( ", fComplex) " );
|
||||||
|
out.print( HexDump.toHex( n32 ) );
|
||||||
|
out.print( " - Complex prop len" );
|
||||||
|
out.println( " {" + propName( (short)propertyId ) + "}" );
|
||||||
|
|
||||||
|
nComplex += n32;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// complex property data
|
||||||
|
while ( ( nComplex & remainingBytes ) > 0 )
|
||||||
|
{
|
||||||
|
nDumpSize = ( nComplex > (int) remainingBytes ) ? (short) remainingBytes : (short) nComplex;
|
||||||
|
HexDump.dump( in, out, 0, nDumpSize );
|
||||||
|
nComplex -= nDumpSize;
|
||||||
|
recordBytesRemaining -= nDumpSize;
|
||||||
|
remainingBytes -= nDumpSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( recordId == (short) 0xF012 )
|
||||||
|
{
|
||||||
|
out.print( " Connector rule: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " ShapeID A: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " ShapeID B: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " ShapeID connector: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " Connect pt A: " );
|
||||||
|
out.print( LittleEndian.readInt( in ) );
|
||||||
|
out.print( " Connect pt B: " );
|
||||||
|
out.println( LittleEndian.readInt( in ) );
|
||||||
|
|
||||||
|
recordBytesRemaining -= 24;
|
||||||
|
remainingBytes -= 24;
|
||||||
|
}
|
||||||
|
else if ( recordId >= (short) 0xF018 && recordId < (short) 0xF117 )
|
||||||
|
{
|
||||||
|
out.println( " Secondary UID: " );
|
||||||
|
HexDump.dump( in, out, 0, 16 );
|
||||||
|
out.println( " Cache of size: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Boundary top: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Boundary left: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Boundary width: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Boundary height: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " X: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Y: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Cache of saved size: " + HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
out.println( " Compression Flag: " + HexDump.toHex( (byte) in.read() ) );
|
||||||
|
out.println( " Filter: " + HexDump.toHex( (byte) in.read() ) );
|
||||||
|
out.println( " Data (after decompression): " );
|
||||||
|
|
||||||
|
recordBytesRemaining -= 34 + 16;
|
||||||
|
remainingBytes -= 34 + 16;
|
||||||
|
|
||||||
|
nDumpSize = ( recordBytesRemaining > (int) remainingBytes ) ? (short) remainingBytes : (short) recordBytesRemaining;
|
||||||
|
|
||||||
|
|
||||||
|
byte[] buf = new byte[nDumpSize];
|
||||||
|
int read = in.read( buf );
|
||||||
|
while ( read != -1 && read < nDumpSize )
|
||||||
|
read += in.read( buf, read, buf.length );
|
||||||
|
ByteArrayInputStream bin = new ByteArrayInputStream( buf );
|
||||||
|
|
||||||
|
InputStream in1 = new InflaterInputStream( bin );
|
||||||
|
int bytesToDump = -1;
|
||||||
|
HexDump.dump( in1, out, 0, bytesToDump );
|
||||||
|
|
||||||
|
recordBytesRemaining -= nDumpSize;
|
||||||
|
remainingBytes -= nDumpSize;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isContainer = ( options & (short) 0x000F ) == (short) 0x000F;
|
||||||
|
if ( isContainer && remainingBytes >= 0 )
|
||||||
|
{ // Container
|
||||||
|
if ( recordBytesRemaining <= (int) remainingBytes )
|
||||||
|
out.println( " completed within" );
|
||||||
|
else
|
||||||
|
out.println( " continued elsewhere" );
|
||||||
|
}
|
||||||
|
else if ( remainingBytes >= 0 )
|
||||||
|
// -> 0x0000 ... 0x0FFF
|
||||||
|
{
|
||||||
|
nDumpSize = ( recordBytesRemaining > (int) remainingBytes ) ? (short) remainingBytes : (short) recordBytesRemaining;
|
||||||
|
|
||||||
|
if ( nDumpSize != 0 )
|
||||||
|
{
|
||||||
|
HexDump.dump( in, out, 0, nDumpSize );
|
||||||
|
remainingBytes -= nDumpSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out.println( " >> OVERRUN <<" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a property name given a property id. This is used only by the
|
||||||
|
* old escher dump routine.
|
||||||
|
*
|
||||||
|
* @param propertyId The property number for the name
|
||||||
|
* @return A descriptive name.
|
||||||
|
*/
|
||||||
|
private String propName( short propertyId )
|
||||||
|
{
|
||||||
|
class PropName {
|
||||||
|
public PropName( int id, String name )
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int id;
|
||||||
|
String name;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PropName[] props = new PropName[] {
|
||||||
|
new PropName(4, "transform.rotation"),
|
||||||
|
new PropName(119, "protection.lockrotation"),
|
||||||
|
new PropName(120, "protection.lockaspectratio"),
|
||||||
|
new PropName(121, "protection.lockposition"),
|
||||||
|
new PropName(122, "protection.lockagainstselect"),
|
||||||
|
new PropName(123, "protection.lockcropping"),
|
||||||
|
new PropName(124, "protection.lockvertices"),
|
||||||
|
new PropName(125, "protection.locktext"),
|
||||||
|
new PropName(126, "protection.lockadjusthandles"),
|
||||||
|
new PropName(127, "protection.lockagainstgrouping"),
|
||||||
|
new PropName(128, "text.textid"),
|
||||||
|
new PropName(129, "text.textleft"),
|
||||||
|
new PropName(130, "text.texttop"),
|
||||||
|
new PropName(131, "text.textright"),
|
||||||
|
new PropName(132, "text.textbottom"),
|
||||||
|
new PropName(133, "text.wraptext"),
|
||||||
|
new PropName(134, "text.scaletext"),
|
||||||
|
new PropName(135, "text.anchortext"),
|
||||||
|
new PropName(136, "text.textflow"),
|
||||||
|
new PropName(137, "text.fontrotation"),
|
||||||
|
new PropName(138, "text.idofnextshape"),
|
||||||
|
new PropName(139, "text.bidir"),
|
||||||
|
new PropName(187, "text.singleclickselects"),
|
||||||
|
new PropName(188, "text.usehostmargins"),
|
||||||
|
new PropName(189, "text.rotatetextwithshape"),
|
||||||
|
new PropName(190, "text.sizeshapetofittext"),
|
||||||
|
new PropName(191, "text.sizetexttofitshape"),
|
||||||
|
new PropName(192, "geotext.unicode"),
|
||||||
|
new PropName(193, "geotext.rtftext"),
|
||||||
|
new PropName(194, "geotext.alignmentoncurve"),
|
||||||
|
new PropName(195, "geotext.defaultpointsize"),
|
||||||
|
new PropName(196, "geotext.textspacing"),
|
||||||
|
new PropName(197, "geotext.fontfamilyname"),
|
||||||
|
new PropName(240, "geotext.reverseroworder"),
|
||||||
|
new PropName(241, "geotext.hastexteffect"),
|
||||||
|
new PropName(242, "geotext.rotatecharacters"),
|
||||||
|
new PropName(243, "geotext.kerncharacters"),
|
||||||
|
new PropName(244, "geotext.tightortrack"),
|
||||||
|
new PropName(245, "geotext.stretchtofitshape"),
|
||||||
|
new PropName(246, "geotext.charboundingbox"),
|
||||||
|
new PropName(247, "geotext.scaletextonpath"),
|
||||||
|
new PropName(248, "geotext.stretchcharheight"),
|
||||||
|
new PropName(249, "geotext.nomeasurealongpath"),
|
||||||
|
new PropName(250, "geotext.boldfont"),
|
||||||
|
new PropName(251, "geotext.italicfont"),
|
||||||
|
new PropName(252, "geotext.underlinefont"),
|
||||||
|
new PropName(253, "geotext.shadowfont"),
|
||||||
|
new PropName(254, "geotext.smallcapsfont"),
|
||||||
|
new PropName(255, "geotext.strikethroughfont"),
|
||||||
|
new PropName(256, "blip.cropfromtop"),
|
||||||
|
new PropName(257, "blip.cropfrombottom"),
|
||||||
|
new PropName(258, "blip.cropfromleft"),
|
||||||
|
new PropName(259, "blip.cropfromright"),
|
||||||
|
new PropName(260, "blip.bliptodisplay"),
|
||||||
|
new PropName(261, "blip.blipfilename"),
|
||||||
|
new PropName(262, "blip.blipflags"),
|
||||||
|
new PropName(263, "blip.transparentcolor"),
|
||||||
|
new PropName(264, "blip.contrastsetting"),
|
||||||
|
new PropName(265, "blip.brightnesssetting"),
|
||||||
|
new PropName(266, "blip.gamma"),
|
||||||
|
new PropName(267, "blip.pictureid"),
|
||||||
|
new PropName(268, "blip.doublemod"),
|
||||||
|
new PropName(269, "blip.picturefillmod"),
|
||||||
|
new PropName(270, "blip.pictureline"),
|
||||||
|
new PropName(271, "blip.printblip"),
|
||||||
|
new PropName(272, "blip.printblipfilename"),
|
||||||
|
new PropName(273, "blip.printflags"),
|
||||||
|
new PropName(316, "blip.nohittestpicture"),
|
||||||
|
new PropName(317, "blip.picturegray"),
|
||||||
|
new PropName(318, "blip.picturebilevel"),
|
||||||
|
new PropName(319, "blip.pictureactive"),
|
||||||
|
new PropName(320, "geometry.left"),
|
||||||
|
new PropName(321, "geometry.top"),
|
||||||
|
new PropName(322, "geometry.right"),
|
||||||
|
new PropName(323, "geometry.bottom"),
|
||||||
|
new PropName(324, "geometry.shapepath"),
|
||||||
|
new PropName(325, "geometry.vertices"),
|
||||||
|
new PropName(326, "geometry.segmentinfo"),
|
||||||
|
new PropName(327, "geometry.adjustvalue"),
|
||||||
|
new PropName(328, "geometry.adjust2value"),
|
||||||
|
new PropName(329, "geometry.adjust3value"),
|
||||||
|
new PropName(330, "geometry.adjust4value"),
|
||||||
|
new PropName(331, "geometry.adjust5value"),
|
||||||
|
new PropName(332, "geometry.adjust6value"),
|
||||||
|
new PropName(333, "geometry.adjust7value"),
|
||||||
|
new PropName(334, "geometry.adjust8value"),
|
||||||
|
new PropName(335, "geometry.adjust9value"),
|
||||||
|
new PropName(336, "geometry.adjust10value"),
|
||||||
|
new PropName(378, "geometry.shadowOK"),
|
||||||
|
new PropName(379, "geometry.3dok"),
|
||||||
|
new PropName(380, "geometry.lineok"),
|
||||||
|
new PropName(381, "geometry.geotextok"),
|
||||||
|
new PropName(382, "geometry.fillshadeshapeok"),
|
||||||
|
new PropName(383, "geometry.fillok"),
|
||||||
|
new PropName(384, "fill.filltype"),
|
||||||
|
new PropName(385, "fill.fillcolor"),
|
||||||
|
new PropName(386, "fill.fillopacity"),
|
||||||
|
new PropName(387, "fill.fillbackcolor"),
|
||||||
|
new PropName(388, "fill.backopacity"),
|
||||||
|
new PropName(389, "fill.crmod"),
|
||||||
|
new PropName(390, "fill.patterntexture"),
|
||||||
|
new PropName(391, "fill.blipfilename"),
|
||||||
|
new PropName(392, "fill.blipflags"),
|
||||||
|
new PropName(393, "fill.width"),
|
||||||
|
new PropName(394, "fill.height"),
|
||||||
|
new PropName(395, "fill.angle"),
|
||||||
|
new PropName(396, "fill.focus"),
|
||||||
|
new PropName(397, "fill.toleft"),
|
||||||
|
new PropName(398, "fill.totop"),
|
||||||
|
new PropName(399, "fill.toright"),
|
||||||
|
new PropName(400, "fill.tobottom"),
|
||||||
|
new PropName(401, "fill.rectleft"),
|
||||||
|
new PropName(402, "fill.recttop"),
|
||||||
|
new PropName(403, "fill.rectright"),
|
||||||
|
new PropName(404, "fill.rectbottom"),
|
||||||
|
new PropName(405, "fill.dztype"),
|
||||||
|
new PropName(406, "fill.shadepreset"),
|
||||||
|
new PropName(407, "fill.shadecolors"),
|
||||||
|
new PropName(408, "fill.originx"),
|
||||||
|
new PropName(409, "fill.originy"),
|
||||||
|
new PropName(410, "fill.shapeoriginx"),
|
||||||
|
new PropName(411, "fill.shapeoriginy"),
|
||||||
|
new PropName(412, "fill.shadetype"),
|
||||||
|
new PropName(443, "fill.filled"),
|
||||||
|
new PropName(444, "fill.hittestfill"),
|
||||||
|
new PropName(445, "fill.shape"),
|
||||||
|
new PropName(446, "fill.userect"),
|
||||||
|
new PropName(447, "fill.nofillhittest"),
|
||||||
|
new PropName(448, "linestyle.color"),
|
||||||
|
new PropName(449, "linestyle.opacity"),
|
||||||
|
new PropName(450, "linestyle.backcolor"),
|
||||||
|
new PropName(451, "linestyle.crmod"),
|
||||||
|
new PropName(452, "linestyle.linetype"),
|
||||||
|
new PropName(453, "linestyle.fillblip"),
|
||||||
|
new PropName(454, "linestyle.fillblipname"),
|
||||||
|
new PropName(455, "linestyle.fillblipflags"),
|
||||||
|
new PropName(456, "linestyle.fillwidth"),
|
||||||
|
new PropName(457, "linestyle.fillheight"),
|
||||||
|
new PropName(458, "linestyle.filldztype"),
|
||||||
|
new PropName(459, "linestyle.linewidth"),
|
||||||
|
new PropName(460, "linestyle.linemiterlimit"),
|
||||||
|
new PropName(461, "linestyle.linestyle"),
|
||||||
|
new PropName(462, "linestyle.linedashing"),
|
||||||
|
new PropName(463, "linestyle.linedashstyle"),
|
||||||
|
new PropName(464, "linestyle.linestartarrowhead"),
|
||||||
|
new PropName(465, "linestyle.lineendarrowhead"),
|
||||||
|
new PropName(466, "linestyle.linestartarrowwidth"),
|
||||||
|
new PropName(467, "linestyle.lineestartarrowlength"),
|
||||||
|
new PropName(468, "linestyle.lineendarrowwidth"),
|
||||||
|
new PropName(469, "linestyle.lineendarrowlength"),
|
||||||
|
new PropName(470, "linestyle.linejoinstyle"),
|
||||||
|
new PropName(471, "linestyle.lineendcapstyle"),
|
||||||
|
new PropName(507, "linestyle.arrowheadsok"),
|
||||||
|
new PropName(508, "linestyle.anyline"),
|
||||||
|
new PropName(509, "linestyle.hitlinetest"),
|
||||||
|
new PropName(510, "linestyle.linefillshape"),
|
||||||
|
new PropName(511, "linestyle.nolinedrawdash"),
|
||||||
|
new PropName(512, "shadowstyle.type"),
|
||||||
|
new PropName(513, "shadowstyle.color"),
|
||||||
|
new PropName(514, "shadowstyle.highlight"),
|
||||||
|
new PropName(515, "shadowstyle.crmod"),
|
||||||
|
new PropName(516, "shadowstyle.opacity"),
|
||||||
|
new PropName(517, "shadowstyle.offsetx"),
|
||||||
|
new PropName(518, "shadowstyle.offsety"),
|
||||||
|
new PropName(519, "shadowstyle.secondoffsetx"),
|
||||||
|
new PropName(520, "shadowstyle.secondoffsety"),
|
||||||
|
new PropName(521, "shadowstyle.scalextox"),
|
||||||
|
new PropName(522, "shadowstyle.scaleytox"),
|
||||||
|
new PropName(523, "shadowstyle.scalextoy"),
|
||||||
|
new PropName(524, "shadowstyle.scaleytoy"),
|
||||||
|
new PropName(525, "shadowstyle.perspectivex"),
|
||||||
|
new PropName(526, "shadowstyle.perspectivey"),
|
||||||
|
new PropName(527, "shadowstyle.weight"),
|
||||||
|
new PropName(528, "shadowstyle.originx"),
|
||||||
|
new PropName(529, "shadowstyle.originy"),
|
||||||
|
new PropName(574, "shadowstyle.shadow"),
|
||||||
|
new PropName(575, "shadowstyle.shadowobsured"),
|
||||||
|
new PropName(576, "perspective.type"),
|
||||||
|
new PropName(577, "perspective.offsetx"),
|
||||||
|
new PropName(578, "perspective.offsety"),
|
||||||
|
new PropName(579, "perspective.scalextox"),
|
||||||
|
new PropName(580, "perspective.scaleytox"),
|
||||||
|
new PropName(581, "perspective.scalextoy"),
|
||||||
|
new PropName(582, "perspective.scaleytox"),
|
||||||
|
new PropName(583, "perspective.perspectivex"),
|
||||||
|
new PropName(584, "perspective.perspectivey"),
|
||||||
|
new PropName(585, "perspective.weight"),
|
||||||
|
new PropName(586, "perspective.originx"),
|
||||||
|
new PropName(587, "perspective.originy"),
|
||||||
|
new PropName(639, "perspective.perspectiveon"),
|
||||||
|
new PropName(640, "3d.specularamount"),
|
||||||
|
new PropName(661, "3d.diffuseamount"),
|
||||||
|
new PropName(662, "3d.shininess"),
|
||||||
|
new PropName(663, "3d.edgethickness"),
|
||||||
|
new PropName(664, "3d.extrudeforward"),
|
||||||
|
new PropName(665, "3d.extrudebackward"),
|
||||||
|
new PropName(666, "3d.extrudeplane"),
|
||||||
|
new PropName(667, "3d.extrusioncolor"),
|
||||||
|
new PropName(648, "3d.crmod"),
|
||||||
|
new PropName(700, "3d.3deffect"),
|
||||||
|
new PropName(701, "3d.metallic"),
|
||||||
|
new PropName(702, "3d.useextrusioncolor"),
|
||||||
|
new PropName(703, "3d.lightface"),
|
||||||
|
new PropName(704, "3dstyle.yrotationangle"),
|
||||||
|
new PropName(705, "3dstyle.xrotationangle"),
|
||||||
|
new PropName(706, "3dstyle.rotationaxisx"),
|
||||||
|
new PropName(707, "3dstyle.rotationaxisy"),
|
||||||
|
new PropName(708, "3dstyle.rotationaxisz"),
|
||||||
|
new PropName(709, "3dstyle.rotationangle"),
|
||||||
|
new PropName(710, "3dstyle.rotationcenterx"),
|
||||||
|
new PropName(711, "3dstyle.rotationcentery"),
|
||||||
|
new PropName(712, "3dstyle.rotationcenterz"),
|
||||||
|
new PropName(713, "3dstyle.rendermode"),
|
||||||
|
new PropName(714, "3dstyle.tolerance"),
|
||||||
|
new PropName(715, "3dstyle.xviewpoint"),
|
||||||
|
new PropName(716, "3dstyle.yviewpoint"),
|
||||||
|
new PropName(717, "3dstyle.zviewpoint"),
|
||||||
|
new PropName(718, "3dstyle.originx"),
|
||||||
|
new PropName(719, "3dstyle.originy"),
|
||||||
|
new PropName(720, "3dstyle.skewangle"),
|
||||||
|
new PropName(721, "3dstyle.skewamount"),
|
||||||
|
new PropName(722, "3dstyle.ambientintensity"),
|
||||||
|
new PropName(723, "3dstyle.keyx"),
|
||||||
|
new PropName(724, "3dstyle.keyy"),
|
||||||
|
new PropName(725, "3dstyle.keyz"),
|
||||||
|
new PropName(726, "3dstyle.keyintensity"),
|
||||||
|
new PropName(727, "3dstyle.fillx"),
|
||||||
|
new PropName(728, "3dstyle.filly"),
|
||||||
|
new PropName(729, "3dstyle.fillz"),
|
||||||
|
new PropName(730, "3dstyle.fillintensity"),
|
||||||
|
new PropName(763, "3dstyle.constrainrotation"),
|
||||||
|
new PropName(764, "3dstyle.rotationcenterauto"),
|
||||||
|
new PropName(765, "3dstyle.parallel"),
|
||||||
|
new PropName(766, "3dstyle.keyharsh"),
|
||||||
|
new PropName(767, "3dstyle.fillharsh"),
|
||||||
|
new PropName(769, "shape.master"),
|
||||||
|
new PropName(771, "shape.connectorstyle"),
|
||||||
|
new PropName(772, "shape.blackandwhitesettings"),
|
||||||
|
new PropName(773, "shape.wmodepurebw"),
|
||||||
|
new PropName(774, "shape.wmodebw"),
|
||||||
|
new PropName(826, "shape.oleicon"),
|
||||||
|
new PropName(827, "shape.preferrelativeresize"),
|
||||||
|
new PropName(828, "shape.lockshapetype"),
|
||||||
|
new PropName(830, "shape.deleteattachedobject"),
|
||||||
|
new PropName(831, "shape.backgroundshape"),
|
||||||
|
new PropName(832, "callout.callouttype"),
|
||||||
|
new PropName(833, "callout.xycalloutgap"),
|
||||||
|
new PropName(834, "callout.calloutangle"),
|
||||||
|
new PropName(835, "callout.calloutdroptype"),
|
||||||
|
new PropName(836, "callout.calloutdropspecified"),
|
||||||
|
new PropName(837, "callout.calloutlengthspecified"),
|
||||||
|
new PropName(889, "callout.iscallout"),
|
||||||
|
new PropName(890, "callout.calloutaccentbar"),
|
||||||
|
new PropName(891, "callout.callouttextborder"),
|
||||||
|
new PropName(892, "callout.calloutminusx"),
|
||||||
|
new PropName(893, "callout.calloutminusy"),
|
||||||
|
new PropName(894, "callout.dropauto"),
|
||||||
|
new PropName(895, "callout.lengthspecified"),
|
||||||
|
new PropName(896, "groupshape.shapename"),
|
||||||
|
new PropName(897, "groupshape.description"),
|
||||||
|
new PropName(898, "groupshape.hyperlink"),
|
||||||
|
new PropName(899, "groupshape.wrappolygonvertices"),
|
||||||
|
new PropName(900, "groupshape.wrapdistleft"),
|
||||||
|
new PropName(901, "groupshape.wrapdisttop"),
|
||||||
|
new PropName(902, "groupshape.wrapdistright"),
|
||||||
|
new PropName(903, "groupshape.wrapdistbottom"),
|
||||||
|
new PropName(904, "groupshape.regroupid"),
|
||||||
|
new PropName(953, "groupshape.editedwrap"),
|
||||||
|
new PropName(954, "groupshape.behinddocument"),
|
||||||
|
new PropName(955, "groupshape.ondblclicknotify"),
|
||||||
|
new PropName(956, "groupshape.isbutton"),
|
||||||
|
new PropName(957, "groupshape.1dadjustment"),
|
||||||
|
new PropName(958, "groupshape.hidden"),
|
||||||
|
new PropName(959, "groupshape.print"),
|
||||||
|
};
|
||||||
|
|
||||||
|
for ( int i = 0; i < props.length; i++ )
|
||||||
|
{
|
||||||
|
if (props[i].id == propertyId)
|
||||||
|
{
|
||||||
|
return props[i].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unknown property";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the blip description given a blip id.
|
||||||
|
*
|
||||||
|
* @param b blip id
|
||||||
|
* @return A description.
|
||||||
|
*/
|
||||||
|
private String getBlipType( byte b )
|
||||||
|
{
|
||||||
|
switch ( b )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return " ERROR";
|
||||||
|
case 1:
|
||||||
|
return " UNKNOWN";
|
||||||
|
case 2:
|
||||||
|
return " EMF";
|
||||||
|
case 3:
|
||||||
|
return " WMF";
|
||||||
|
case 4:
|
||||||
|
return " PICT";
|
||||||
|
case 5:
|
||||||
|
return " JPEG";
|
||||||
|
case 6:
|
||||||
|
return " PNG";
|
||||||
|
case 7:
|
||||||
|
return " DIB";
|
||||||
|
default:
|
||||||
|
if ( b < 32 )
|
||||||
|
return " NotKnown";
|
||||||
|
else
|
||||||
|
return " Client";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Straight conversion from OO. Converts a type of float.
|
||||||
|
*/
|
||||||
|
private String dec1616( int n32 )
|
||||||
|
{
|
||||||
|
String result = "";
|
||||||
|
result += (short) ( n32 >> 16 );
|
||||||
|
result += '.';
|
||||||
|
result += (short) ( n32 & (short) 0xFFFF );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps out a hex value by reading from a input stream.
|
||||||
|
*
|
||||||
|
* @param bytes How many bytes this hex value consists of.
|
||||||
|
* @param in The stream to read the hex value from.
|
||||||
|
* @param out The stream to write the nicely formatted hex value to.
|
||||||
|
*/
|
||||||
|
private void outHex( int bytes, InputStream in, PrintStream out ) throws IOException, LittleEndian.BufferUnderrunException
|
||||||
|
{
|
||||||
|
switch ( bytes )
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
out.print( HexDump.toHex( (byte) in.read() ) );
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
out.print( HexDump.toHex( LittleEndian.readShort( in ) ) );
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
out.print( HexDump.toHex( LittleEndian.readInt( in ) ) );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IOException( "Unable to output variable of that width" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple test stub.
|
||||||
|
*/
|
||||||
|
public static void main( String[] args ) throws IOException
|
||||||
|
{
|
||||||
|
String dump =
|
||||||
|
"0F 00 00 F0 89 07 00 00 00 00 06 F0 18 00 00 00 " +
|
||||||
|
"05 04 00 00 02 00 00 00 05 00 00 00 01 00 00 00 " +
|
||||||
|
"01 00 00 00 05 00 00 00 4F 00 01 F0 2F 07 00 00 " +
|
||||||
|
"42 00 07 F0 B7 01 00 00 03 04 3F 14 AE 6B 0F 65 " +
|
||||||
|
"B0 48 BF 5E 94 63 80 E8 91 73 FF 00 93 01 00 00 " +
|
||||||
|
"01 00 00 00 00 00 00 00 00 00 FF FF 20 54 1C F0 " +
|
||||||
|
"8B 01 00 00 3F 14 AE 6B 0F 65 B0 48 BF 5E 94 63 " +
|
||||||
|
"80 E8 91 73 92 0E 00 00 00 00 00 00 00 00 00 00 " +
|
||||||
|
"D1 07 00 00 DD 05 00 00 4A AD 6F 00 8A C5 53 00 " +
|
||||||
|
"59 01 00 00 00 FE 78 9C E3 9B C4 00 04 AC 77 D9 " +
|
||||||
|
"2F 32 08 32 FD E7 61 F8 FF 0F C8 FD 05 C5 30 19 " +
|
||||||
|
"10 90 63 90 FA 0F 06 0C 8C 0C 5C 70 19 43 30 EB " +
|
||||||
|
"0E FB 05 86 85 0C DB 18 58 80 72 8C 70 16 0B 83 " +
|
||||||
|
"05 56 51 29 88 C9 60 D9 69 0C 6C 20 26 23 03 C8 " +
|
||||||
|
"74 B0 A8 0E 03 07 FB 45 56 C7 A2 CC C4 1C 06 66 " +
|
||||||
|
"A0 0D 2C 40 39 5E 86 4C 06 3D A0 4E 10 D0 60 D9 " +
|
||||||
|
"C8 58 CC E8 CF B0 80 61 3A 8A 7E 0D C6 23 AC 4F " +
|
||||||
|
"E0 E2 98 B6 12 2B 06 73 9D 12 E3 52 56 59 F6 08 " +
|
||||||
|
"8A CC 52 66 A3 50 FF 96 2B 94 E9 DF 4C A1 FE 2D " +
|
||||||
|
"3A 03 AB 9F 81 C2 F0 A3 54 BF 0F 85 EE A7 54 FF " +
|
||||||
|
"40 FB 7F A0 E3 9F D2 F4 4F 71 FE 19 58 FF 2B 31 " +
|
||||||
|
"7F 67 36 3B 25 4F 99 1B 4E 53 A6 5F 89 25 95 E9 " +
|
||||||
|
"C4 00 C7 83 12 F3 1F 26 35 4A D3 D2 47 0E 0A C3 " +
|
||||||
|
"41 8E C9 8A 52 37 DC 15 A1 D0 0D BC 4C 06 0C 2B " +
|
||||||
|
"28 2C 13 28 D4 EF 43 61 5A A0 58 3F 85 71 E0 4B " +
|
||||||
|
"69 9E 64 65 FE 39 C0 E5 22 30 1D 30 27 0E 74 3A " +
|
||||||
|
"18 60 FD 4A CC B1 2C 13 7D 07 36 2D 2A 31 85 B2 " +
|
||||||
|
"6A 0D 74 1D 1D 22 4D 99 FE 60 0A F5 9B EC 1C 58 " +
|
||||||
|
"FD 67 06 56 3F 38 0D 84 3C A5 30 0E 28 D3 AF C4 " +
|
||||||
|
"A4 CA FA 44 7A 0D 65 6E 60 7F 4D A1 1B 24 58 F7 " +
|
||||||
|
"49 AF A5 CC 0D CC DF 19 FE 03 00 F0 B1 25 4D 42 " +
|
||||||
|
"00 07 F0 E1 01 00 00 03 04 39 50 BE 98 B0 6F 57 " +
|
||||||
|
"24 31 70 5D 23 2F 9F 10 66 FF 00 BD 01 00 00 01 " +
|
||||||
|
"00 00 00 00 00 00 00 00 00 FF FF 20 54 1C F0 B5 " +
|
||||||
|
"01 00 00 39 50 BE 98 B0 6F 57 24 31 70 5D 23 2F " +
|
||||||
|
"9F 10 66 DA 03 00 00 00 00 00 00 00 00 00 00 D1 " +
|
||||||
|
"07 00 00 DD 05 00 00 4A AD 6F 00 8A C5 53 00 83 " +
|
||||||
|
"01 00 00 00 FE 78 9C A5 52 BF 4B 42 51 14 3E F7 " +
|
||||||
|
"DC 77 7A 16 45 48 8B 3C 48 A8 16 15 0D 6C 88 D0 " +
|
||||||
|
"04 C3 40 A3 32 1C 84 96 08 21 04 A1 C5 5C A2 35 " +
|
||||||
|
"82 C0 35 6A AB 1C 6A 6B A8 24 5A 83 68 08 84 84 " +
|
||||||
|
"96 A2 86 A0 7F C2 86 5E E7 5E F5 41 E4 10 BC 03 " +
|
||||||
|
"1F E7 FB F1 CE B9 F7 F1 9E 7C 05 2E 7A 37 9B E0 " +
|
||||||
|
"45 7B 10 EC 6F 96 5F 1D 74 13 55 7E B0 6C 5D 20 " +
|
||||||
|
"60 C0 49 A2 9A BD 99 4F 50 83 1B 30 38 13 0E 33 " +
|
||||||
|
"60 A6 A7 6B B5 37 EB F4 10 FA 14 15 A0 B6 6B 37 " +
|
||||||
|
"0C 1E B3 49 73 5B A5 C2 26 48 3E C1 E0 6C 08 4A " +
|
||||||
|
"30 C9 93 AA 02 B8 20 13 62 05 4E E1 E8 D7 7C C0 " +
|
||||||
|
"B8 14 95 5E BE B8 A7 CF 1E BE 55 2C 56 B9 78 DF " +
|
||||||
|
"08 7E 88 4C 27 FF 7B DB FF 7A DD B7 1A 17 67 34 " +
|
||||||
|
"6A AE BA DA 35 D1 E7 72 BE FE EC 6E FE DA E5 7C " +
|
||||||
|
"3D EC 7A DE 03 FD 50 06 0B 23 F2 0E F3 B2 A5 11 " +
|
||||||
|
"91 0D 4C B5 B5 F3 BF 94 C1 8F 24 F7 D9 6F 60 94 " +
|
||||||
|
"3B C9 9A F3 1C 6B E7 BB F0 2E 49 B2 25 2B C6 B1 " +
|
||||||
|
"EE 69 EE 15 63 4F 71 7D CE 85 CC C8 35 B9 C3 28 " +
|
||||||
|
"28 CE D0 5C 67 79 F2 4A A2 14 23 A4 38 43 73 9D " +
|
||||||
|
"2D 69 2F C1 08 31 9F C5 5C 9B EB 7B C5 69 19 B3 " +
|
||||||
|
"B4 81 F3 DC E3 B4 8E 8B CC B3 94 53 5A E7 41 2A " +
|
||||||
|
"63 9A AA 38 C5 3D 48 BB EC 57 59 6F 2B AD 73 1F " +
|
||||||
|
"1D 60 92 AE 70 8C BB 8F CE 31 C1 3C 49 27 4A EB " +
|
||||||
|
"DC A4 5B 8C D1 0B 0E 73 37 E9 11 A7 99 C7 E8 41 " +
|
||||||
|
"69 B0 7F 00 96 F2 A7 E8 42 00 07 F0 B4 01 00 00 " +
|
||||||
|
"03 04 1A BA F9 D6 A9 B9 3A 03 08 61 E9 90 FF 7B " +
|
||||||
|
"9E E6 FF 00 90 01 00 00 01 00 00 00 00 00 00 00 " +
|
||||||
|
"00 00 FF FF 20 54 1C F0 88 01 00 00 1A BA F9 D6 " +
|
||||||
|
"A9 B9 3A 03 08 61 E9 90 FF 7B 9E E6 12 0E 00 00 " +
|
||||||
|
"00 00 00 00 00 00 00 00 D1 07 00 00 DD 05 00 00 " +
|
||||||
|
"4A AD 6F 00 8A C5 53 00 56 01 00 00 00 FE 78 9C " +
|
||||||
|
"E3 13 62 00 02 D6 BB EC 17 19 04 99 FE F3 30 FC " +
|
||||||
|
"FF 07 E4 FE 82 62 98 0C 08 C8 31 48 FD 07 03 06 " +
|
||||||
|
"46 06 2E B8 8C 21 98 75 87 FD 02 C3 42 86 6D 0C " +
|
||||||
|
"2C 40 39 46 38 8B 85 C1 02 AB A8 14 C4 64 B0 EC " +
|
||||||
|
"34 06 36 10 93 91 01 64 3A 58 54 87 81 83 FD 22 " +
|
||||||
|
"AB 63 51 66 62 0E 03 33 D0 06 16 A0 1C 2F 43 26 " +
|
||||||
|
"83 1E 50 27 08 68 B0 6C 64 2C 66 F4 67 58 C0 30 " +
|
||||||
|
"1D 45 BF 06 E3 11 D6 27 70 71 4C 5B 89 15 83 B9 " +
|
||||||
|
"4E 89 71 29 AB 2C 7B 04 45 66 29 B3 51 A8 7F CB " +
|
||||||
|
"15 CA F4 6F A6 50 FF 16 9D 81 D5 CF 40 61 F8 51 " +
|
||||||
|
"AA DF 87 42 F7 53 AA 7F A0 FD 3F D0 F1 4F 69 FA " +
|
||||||
|
"A7 38 FF 0C AC FF 95 98 BF 33 9B 9D 92 A7 CC 0D " +
|
||||||
|
"A7 29 D3 AF C4 92 CA 74 62 80 E3 41 89 F9 0F 93 " +
|
||||||
|
"1A A5 69 E9 23 07 85 E1 20 C7 64 45 A9 1B EE 8A " +
|
||||||
|
"50 E8 06 5E 26 03 86 15 14 96 09 14 EA F7 A1 30 " +
|
||||||
|
"2D 50 AC 9F C2 38 F0 A5 34 4F B2 32 FF 1C E0 72 " +
|
||||||
|
"11 98 0E 98 13 07 38 1D 28 31 C7 B2 4C F4 1D D8 " +
|
||||||
|
"B4 A0 C4 14 CA AA 35 D0 75 64 88 34 65 FA 83 29 " +
|
||||||
|
"D4 6F B2 73 60 F5 9F A1 54 FF 0E CA D3 40 C8 53 " +
|
||||||
|
"0A E3 E0 09 85 6E 50 65 7D 22 BD 86 32 37 B0 BF " +
|
||||||
|
"A6 D0 0D 12 AC FB A4 D7 52 E6 06 E6 EF 0C FF 01 " +
|
||||||
|
"97 1D 12 C7 42 00 07 F0 C3 01 00 00 03 04 BA 4C " +
|
||||||
|
"B6 23 BA 8B 27 BE C8 55 59 86 24 9F 89 D4 FF 00 " +
|
||||||
|
"9F 01 00 00 01 00 00 00 00 00 00 00 00 00 FF FF " +
|
||||||
|
"20 54 1C F0 97 01 00 00 BA 4C B6 23 BA 8B 27 BE " +
|
||||||
|
"C8 55 59 86 24 9F 89 D4 AE 0E 00 00 00 00 00 00 " +
|
||||||
|
"00 00 00 00 D1 07 00 00 DD 05 00 00 4A AD 6F 00 " +
|
||||||
|
"8A C5 53 00 65 01 00 00 00 FE 78 9C E3 5B C7 00 " +
|
||||||
|
"04 AC 77 D9 2F 32 08 32 FD E7 61 F8 FF 0F C8 FD " +
|
||||||
|
"05 C5 30 19 10 90 63 90 FA 0F 06 0C 8C 0C 5C 70 " +
|
||||||
|
"19 43 30 EB 0E FB 05 86 85 0C DB 18 58 80 72 8C " +
|
||||||
|
"70 16 0B 83 05 56 51 29 88 C9 60 D9 69 0C 6C 20 " +
|
||||||
|
"26 23 03 C8 74 B0 A8 0E 03 07 FB 45 56 C7 A2 CC " +
|
||||||
|
"C4 1C 06 66 A0 0D 2C 40 39 5E 86 4C 06 3D A0 4E " +
|
||||||
|
"10 D0 60 99 C6 B8 98 D1 9F 61 01 C3 74 14 FD 1A " +
|
||||||
|
"8C 2B D8 84 B1 88 4B A5 A5 75 03 01 50 DF 59 46 " +
|
||||||
|
"77 46 0F A8 3C A6 AB 88 15 83 B9 5E 89 B1 8B D5 " +
|
||||||
|
"97 2D 82 22 B3 94 29 D5 BF E5 CA C0 EA DF AC 43 " +
|
||||||
|
"A1 FD 14 EA 67 A0 30 FC 28 D5 EF 43 A1 FB 7D 87 " +
|
||||||
|
"B8 FF 07 3A FE 07 3A FD 53 EA 7E 0A C3 4F 89 F9 " +
|
||||||
|
"0E 73 EA 69 79 CA DC 70 8A 32 FD 4A 2C 5E 4C DF " +
|
||||||
|
"87 7A 3C BC E0 A5 30 1E 3E 31 C5 33 AC A0 30 2F " +
|
||||||
|
"52 A8 DF 87 C2 30 A4 54 3F A5 65 19 85 65 A9 12 " +
|
||||||
|
"D3 2B 16 0D 8A CB 13 4A F3 E3 27 E6 09 03 9D 0E " +
|
||||||
|
"06 58 BF 12 B3 13 CB C1 01 4E 8B 4A 4C 56 AC 91 " +
|
||||||
|
"03 5D 37 86 48 53 A6 3F 98 42 FD 26 3B 07 56 FF " +
|
||||||
|
"99 1D 14 EA A7 CC 7E 70 1A 08 79 42 61 1C 3C A5 " +
|
||||||
|
"D0 0D 9C 6C C2 32 6B 29 73 03 DB 6B CA DC C0 F8 " +
|
||||||
|
"97 F5 AD CC 1A CA DC C0 F4 83 32 37 B0 A4 30 CE " +
|
||||||
|
"FC C7 48 99 1B FE 33 32 FC 07 00 6C CC 2E 23 33 " +
|
||||||
|
"00 0B F0 12 00 00 00 BF 00 08 00 08 00 81 01 09 " +
|
||||||
|
"00 00 08 C0 01 40 00 00 08 40 00 1E F1 10 00 00 " +
|
||||||
|
"00 0D 00 00 08 0C 00 00 08 17 00 00 08 F7 00 00 " +
|
||||||
|
"10 ";
|
||||||
|
|
||||||
|
// Decode the stream to bytes
|
||||||
|
byte[] bytes = HexRead.readData( new ByteArrayInputStream( dump.getBytes() ), -1 );
|
||||||
|
// Create a new instance of the escher dumper
|
||||||
|
EscherDump dumper = new EscherDump();
|
||||||
|
// Dump the contents of scher to screen.
|
||||||
|
// dumper.dumpOld( bytes.length, new ByteArrayInputStream( bytes ), System.out );
|
||||||
|
dumper.dump(bytes, 0, bytes.length, System.out);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump( int recordSize, byte[] data, PrintStream out ) throws IOException, LittleEndian.BufferUnderrunException
|
||||||
|
{
|
||||||
|
// ByteArrayInputStream is = new ByteArrayInputStream( data );
|
||||||
|
// dump( recordSize, is, out );
|
||||||
|
dump( data, 0, recordSize, System.out );
|
||||||
|
}
|
||||||
|
}
|
174
src/java/org/apache/poi/ddf/EscherOptRecord.java
Normal file
174
src/java/org/apache/poi/ddf/EscherOptRecord.java
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The opt record is used to store property values for a shape. It is the key to determining
|
||||||
|
* the attributes of a shape. Properties can be of two types: simple or complex. Simple types
|
||||||
|
* are fixed length. Complex properties are variable length.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherOptRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF00B;
|
||||||
|
public static final String RECORD_DESCRIPTION = "msofbtOPT";
|
||||||
|
|
||||||
|
private List properties = new ArrayList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
|
||||||
|
EscherPropertyFactory f = new EscherPropertyFactory();
|
||||||
|
properties = f.createProperties( data, pos, getInstance() );
|
||||||
|
return bytesRemaining + 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.
|
||||||
|
* @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() );
|
||||||
|
LittleEndian.putInt( data, offset + 4, getPropertiesSize() );
|
||||||
|
int pos = offset + 8;
|
||||||
|
for ( Iterator iterator = properties.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherProperty escherProperty = (EscherProperty) iterator.next();
|
||||||
|
pos += escherProperty.serializeSimplePart( data, pos );
|
||||||
|
}
|
||||||
|
for ( Iterator iterator = properties.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherProperty escherProperty = (EscherProperty) iterator.next();
|
||||||
|
pos += escherProperty.serializeComplexPart( data, pos );
|
||||||
|
}
|
||||||
|
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 8 + getPropertiesSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically recalculate the correct option
|
||||||
|
*/
|
||||||
|
public short getOptions()
|
||||||
|
{
|
||||||
|
setOptions( (short) ( ( properties.size() << 4 ) | 0x3 ) );
|
||||||
|
return super.getOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Opt";
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPropertiesSize()
|
||||||
|
{
|
||||||
|
int totalSize = 0;
|
||||||
|
for ( Iterator iterator = properties.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherProperty escherProperty = (EscherProperty) iterator.next();
|
||||||
|
totalSize += escherProperty.getPropertySize();
|
||||||
|
}
|
||||||
|
return totalSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the string representation of this record.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
StringBuffer propertiesBuf = new StringBuffer();
|
||||||
|
for ( Iterator iterator = properties.iterator(); iterator.hasNext(); )
|
||||||
|
propertiesBuf.append( " "
|
||||||
|
+ iterator.next().toString()
|
||||||
|
+ nl );
|
||||||
|
|
||||||
|
return "org.apache.poi.ddf.EscherOptRecord:" + nl +
|
||||||
|
" isContainer: " + isContainerRecord() + nl +
|
||||||
|
" options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||||
|
" numchildren: " + getChildRecords().size() + nl +
|
||||||
|
" properties:" + nl +
|
||||||
|
propertiesBuf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of properties stored by this record.
|
||||||
|
*/
|
||||||
|
public List getEscherProperties()
|
||||||
|
{
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of properties stored by this record.
|
||||||
|
*/
|
||||||
|
public EscherProperty getEscherProperty( int index )
|
||||||
|
{
|
||||||
|
return (EscherProperty) properties.get( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a property to this record.
|
||||||
|
*/
|
||||||
|
public void addEscherProperty( EscherProperty prop )
|
||||||
|
{
|
||||||
|
properties.add( prop );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records should be sorted by property number before being stored.
|
||||||
|
*/
|
||||||
|
public void sortProperties()
|
||||||
|
{
|
||||||
|
Collections.sort( properties, new Comparator()
|
||||||
|
{
|
||||||
|
public int compare( Object o1, Object o2 )
|
||||||
|
{
|
||||||
|
EscherProperty p1 = (EscherProperty) o1;
|
||||||
|
EscherProperty p2 = (EscherProperty) o2;
|
||||||
|
return new Short( p1.getPropertyNumber() ).compareTo( new Short( p2.getPropertyNumber() ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
607
src/java/org/apache/poi/ddf/EscherProperties.java
Normal file
607
src/java/org/apache/poi/ddf/EscherProperties.java
Normal file
@ -0,0 +1,607 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a list of all known escher properties including the description and
|
||||||
|
* type.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherProperties
|
||||||
|
{
|
||||||
|
|
||||||
|
// Property constants
|
||||||
|
public static final short TRANSFORM__ROTATION = 4;
|
||||||
|
public static final short PROTECTION__LOCKROTATION = 119;
|
||||||
|
public static final short PROTECTION__LOCKASPECTRATIO = 120;
|
||||||
|
public static final short PROTECTION__LOCKPOSITION = 121;
|
||||||
|
public static final short PROTECTION__LOCKAGAINSTSELECT = 122;
|
||||||
|
public static final short PROTECTION__LOCKCROPPING = 123;
|
||||||
|
public static final short PROTECTION__LOCKVERTICES = 124;
|
||||||
|
public static final short PROTECTION__LOCKTEXT = 125;
|
||||||
|
public static final short PROTECTION__LOCKADJUSTHANDLES = 126;
|
||||||
|
public static final short PROTECTION__LOCKAGAINSTGROUPING = 127;
|
||||||
|
public static final short TEXT__TEXTID = 128;
|
||||||
|
public static final short TEXT__TEXTLEFT = 129;
|
||||||
|
public static final short TEXT__TEXTTOP = 130;
|
||||||
|
public static final short TEXT__TEXTRIGHT = 131;
|
||||||
|
public static final short TEXT__TEXTBOTTOM = 132;
|
||||||
|
public static final short TEXT__WRAPTEXT = 133;
|
||||||
|
public static final short TEXT__SCALETEXT = 134;
|
||||||
|
public static final short TEXT__ANCHORTEXT = 135;
|
||||||
|
public static final short TEXT__TEXTFLOW = 136;
|
||||||
|
public static final short TEXT__FONTROTATION = 137;
|
||||||
|
public static final short TEXT__IDOFNEXTSHAPE = 138;
|
||||||
|
public static final short TEXT__BIDIR = 139;
|
||||||
|
public static final short TEXT__SINGLECLICKSELECTS = 187;
|
||||||
|
public static final short TEXT__USEHOSTMARGINS = 188;
|
||||||
|
public static final short TEXT__ROTATETEXTWITHSHAPE = 189;
|
||||||
|
public static final short TEXT__SIZESHAPETOFITTEXT = 190;
|
||||||
|
public static final short TEXT__SIZE_TEXT_TO_FIT_SHAPE = 191 ;
|
||||||
|
public static final short GEOTEXT__UNICODE = 192;
|
||||||
|
public static final short GEOTEXT__RTFTEXT = 193;
|
||||||
|
public static final short GEOTEXT__ALIGNMENTONCURVE = 194;
|
||||||
|
public static final short GEOTEXT__DEFAULTPOINTSIZE = 195;
|
||||||
|
public static final short GEOTEXT__TEXTSPACING = 196;
|
||||||
|
public static final short GEOTEXT__FONTFAMILYNAME = 197;
|
||||||
|
public static final short GEOTEXT__REVERSEROWORDER = 240;
|
||||||
|
public static final short GEOTEXT__HASTEXTEFFECT = 241;
|
||||||
|
public static final short GEOTEXT__ROTATECHARACTERS = 242;
|
||||||
|
public static final short GEOTEXT__KERNCHARACTERS = 243;
|
||||||
|
public static final short GEOTEXT__TIGHTORTRACK = 244;
|
||||||
|
public static final short GEOTEXT__STRETCHTOFITSHAPE = 245;
|
||||||
|
public static final short GEOTEXT__CHARBOUNDINGBOX = 246;
|
||||||
|
public static final short GEOTEXT__SCALETEXTONPATH = 247;
|
||||||
|
public static final short GEOTEXT__STRETCHCHARHEIGHT = 248;
|
||||||
|
public static final short GEOTEXT__NOMEASUREALONGPATH = 249;
|
||||||
|
public static final short GEOTEXT__BOLDFONT = 250;
|
||||||
|
public static final short GEOTEXT__ITALICFONT = 251;
|
||||||
|
public static final short GEOTEXT__UNDERLINEFONT = 252;
|
||||||
|
public static final short GEOTEXT__SHADOWFONT = 253;
|
||||||
|
public static final short GEOTEXT__SMALLCAPSFONT = 254;
|
||||||
|
public static final short GEOTEXT__STRIKETHROUGHFONT = 255;
|
||||||
|
public static final short BLIP__CROPFROMTOP = 256;
|
||||||
|
public static final short BLIP__CROPFROMBOTTOM = 257;
|
||||||
|
public static final short BLIP__CROPFROMLEFT = 258;
|
||||||
|
public static final short BLIP__CROPFROMRIGHT = 259;
|
||||||
|
public static final short BLIP__BLIPTODISPLAY = 260;
|
||||||
|
public static final short BLIP__BLIPFILENAME = 261;
|
||||||
|
public static final short BLIP__BLIPFLAGS = 262;
|
||||||
|
public static final short BLIP__TRANSPARENTCOLOR = 263;
|
||||||
|
public static final short BLIP__CONTRASTSETTING = 264;
|
||||||
|
public static final short BLIP__BRIGHTNESSSETTING = 265;
|
||||||
|
public static final short BLIP__GAMMA = 266;
|
||||||
|
public static final short BLIP__PICTUREID = 267;
|
||||||
|
public static final short BLIP__DOUBLEMOD = 268;
|
||||||
|
public static final short BLIP__PICTUREFILLMOD = 269;
|
||||||
|
public static final short BLIP__PICTURELINE = 270;
|
||||||
|
public static final short BLIP__PRINTBLIP = 271;
|
||||||
|
public static final short BLIP__PRINTBLIPFILENAME = 272;
|
||||||
|
public static final short BLIP__PRINTFLAGS = 273;
|
||||||
|
public static final short BLIP__NOHITTESTPICTURE = 316;
|
||||||
|
public static final short BLIP__PICTUREGRAY = 317;
|
||||||
|
public static final short BLIP__PICTUREBILEVEL = 318;
|
||||||
|
public static final short BLIP__PICTUREACTIVE = 319;
|
||||||
|
public static final short GEOMETRY__LEFT = 320;
|
||||||
|
public static final short GEOMETRY__TOP = 321;
|
||||||
|
public static final short GEOMETRY__RIGHT = 322;
|
||||||
|
public static final short GEOMETRY__BOTTOM = 323;
|
||||||
|
public static final short GEOMETRY__SHAPEPATH = 324;
|
||||||
|
public static final short GEOMETRY__VERTICES = 325;
|
||||||
|
public static final short GEOMETRY__SEGMENTINFO = 326;
|
||||||
|
public static final short GEOMETRY__ADJUSTVALUE = 327;
|
||||||
|
public static final short GEOMETRY__ADJUST2VALUE = 328;
|
||||||
|
public static final short GEOMETRY__ADJUST3VALUE = 329;
|
||||||
|
public static final short GEOMETRY__ADJUST4VALUE = 330;
|
||||||
|
public static final short GEOMETRY__ADJUST5VALUE = 331;
|
||||||
|
public static final short GEOMETRY__ADJUST6VALUE = 332;
|
||||||
|
public static final short GEOMETRY__ADJUST7VALUE = 333;
|
||||||
|
public static final short GEOMETRY__ADJUST8VALUE = 334;
|
||||||
|
public static final short GEOMETRY__ADJUST9VALUE = 335;
|
||||||
|
public static final short GEOMETRY__ADJUST10VALUE = 336;
|
||||||
|
public static final short GEOMETRY__SHADOWok = 378;
|
||||||
|
public static final short GEOMETRY__3DOK = 379;
|
||||||
|
public static final short GEOMETRY__LINEOK = 380;
|
||||||
|
public static final short GEOMETRY__GEOTEXTOK = 381;
|
||||||
|
public static final short GEOMETRY__FILLSHADESHAPEOK = 382;
|
||||||
|
public static final short GEOMETRY__FILLOK = 383;
|
||||||
|
public static final short FILL__FILLTYPE = 384;
|
||||||
|
public static final short FILL__FILLCOLOR = 385 ;
|
||||||
|
public static final short FILL__FILLOPACITY = 386;
|
||||||
|
public static final short FILL__FILLBACKCOLOR = 387;
|
||||||
|
public static final short FILL__BACKOPACITY = 388;
|
||||||
|
public static final short FILL__CRMOD = 389;
|
||||||
|
public static final short FILL__PATTERNTEXTURE = 390;
|
||||||
|
public static final short FILL__BLIPFILENAME = 391;
|
||||||
|
public static final short FILL__BLIPFLAGS = 392;
|
||||||
|
public static final short FILL__WIDTH = 393;
|
||||||
|
public static final short FILL__HEIGHT = 394;
|
||||||
|
public static final short FILL__ANGLE = 395;
|
||||||
|
public static final short FILL__FOCUS = 396;
|
||||||
|
public static final short FILL__TOLEFT = 397;
|
||||||
|
public static final short FILL__TOTOP = 398;
|
||||||
|
public static final short FILL__TORIGHT = 399;
|
||||||
|
public static final short FILL__TOBOTTOM = 400;
|
||||||
|
public static final short FILL__RECTLEFT = 401;
|
||||||
|
public static final short FILL__RECTTOP = 402;
|
||||||
|
public static final short FILL__RECTRIGHT = 403;
|
||||||
|
public static final short FILL__RECTBOTTOM = 404;
|
||||||
|
public static final short FILL__DZTYPE = 405;
|
||||||
|
public static final short FILL__SHADEPRESET = 406;
|
||||||
|
public static final short FILL__SHADECOLORS = 407;
|
||||||
|
public static final short FILL__ORIGINX = 408;
|
||||||
|
public static final short FILL__ORIGINY = 409;
|
||||||
|
public static final short FILL__SHAPEORIGINX = 410;
|
||||||
|
public static final short FILL__SHAPEORIGINY = 411;
|
||||||
|
public static final short FILL__SHADETYPE = 412;
|
||||||
|
public static final short FILL__FILLED = 443;
|
||||||
|
public static final short FILL__HITTESTFILL = 444;
|
||||||
|
public static final short FILL__SHAPE = 445;
|
||||||
|
public static final short FILL__USERECT = 446;
|
||||||
|
public static final short FILL__NOFILLHITTEST = 447;
|
||||||
|
public static final short LINESTYLE__COLOR = 448 ;
|
||||||
|
public static final short LINESTYLE__OPACITY = 449;
|
||||||
|
public static final short LINESTYLE__BACKCOLOR = 450;
|
||||||
|
public static final short LINESTYLE__CRMOD = 451;
|
||||||
|
public static final short LINESTYLE__LINETYPE = 452;
|
||||||
|
public static final short LINESTYLE__FILLBLIP = 453;
|
||||||
|
public static final short LINESTYLE__FILLBLIPNAME = 454;
|
||||||
|
public static final short LINESTYLE__FILLBLIPFLAGS = 455;
|
||||||
|
public static final short LINESTYLE__FILLWIDTH = 456;
|
||||||
|
public static final short LINESTYLE__FILLHEIGHT = 457;
|
||||||
|
public static final short LINESTYLE__FILLDZTYPE = 458;
|
||||||
|
public static final short LINESTYLE__LINEWIDTH = 459;
|
||||||
|
public static final short LINESTYLE__LINEMITERLIMIT = 460;
|
||||||
|
public static final short LINESTYLE__LINESTYLE = 461;
|
||||||
|
public static final short LINESTYLE__LINEDASHING = 462;
|
||||||
|
public static final short LINESTYLE__LINEDASHSTYLE = 463;
|
||||||
|
public static final short LINESTYLE__LINESTARTARROWHEAD = 464;
|
||||||
|
public static final short LINESTYLE__LINEENDARROWHEAD = 465;
|
||||||
|
public static final short LINESTYLE__LINESTARTARROWWIDTH = 466;
|
||||||
|
public static final short LINESTYLE__LINEESTARTARROWLENGTH = 467;
|
||||||
|
public static final short LINESTYLE__LINEENDARROWWIDTH = 468;
|
||||||
|
public static final short LINESTYLE__LINEENDARROWLENGTH = 469;
|
||||||
|
public static final short LINESTYLE__LINEJOINSTYLE = 470;
|
||||||
|
public static final short LINESTYLE__LINEENDCAPSTYLE = 471;
|
||||||
|
public static final short LINESTYLE__ARROWHEADSOK = 507;
|
||||||
|
public static final short LINESTYLE__ANYLINE = 508;
|
||||||
|
public static final short LINESTYLE__HITLINETEST = 509;
|
||||||
|
public static final short LINESTYLE__LINEFILLSHAPE = 510;
|
||||||
|
public static final short LINESTYLE__NOLINEDRAWDASH = 511;
|
||||||
|
public static final short SHADOWSTYLE__TYPE = 512;
|
||||||
|
public static final short SHADOWSTYLE__COLOR = 513;
|
||||||
|
public static final short SHADOWSTYLE__HIGHLIGHT = 514;
|
||||||
|
public static final short SHADOWSTYLE__CRMOD = 515;
|
||||||
|
public static final short SHADOWSTYLE__OPACITY = 516;
|
||||||
|
public static final short SHADOWSTYLE__OFFSETX = 517;
|
||||||
|
public static final short SHADOWSTYLE__OFFSETY = 518;
|
||||||
|
public static final short SHADOWSTYLE__SECONDOFFSETX = 519;
|
||||||
|
public static final short SHADOWSTYLE__SECONDOFFSETY = 520;
|
||||||
|
public static final short SHADOWSTYLE__SCALEXTOX = 521;
|
||||||
|
public static final short SHADOWSTYLE__SCALEYTOX = 522;
|
||||||
|
public static final short SHADOWSTYLE__SCALEXTOY = 523;
|
||||||
|
public static final short SHADOWSTYLE__SCALEYTOY = 524;
|
||||||
|
public static final short SHADOWSTYLE__PERSPECTIVEX = 525;
|
||||||
|
public static final short SHADOWSTYLE__PERSPECTIVEY = 526;
|
||||||
|
public static final short SHADOWSTYLE__WEIGHT = 527;
|
||||||
|
public static final short SHADOWSTYLE__ORIGINX = 528;
|
||||||
|
public static final short SHADOWSTYLE__ORIGINY = 529;
|
||||||
|
public static final short SHADOWSTYLE__SHADOW = 574;
|
||||||
|
public static final short SHADOWSTYLE__SHADOWOBSURED = 575;
|
||||||
|
public static final short PERSPECTIVE__TYPE = 576;
|
||||||
|
public static final short PERSPECTIVE__OFFSETX = 577;
|
||||||
|
public static final short PERSPECTIVE__OFFSETY = 578;
|
||||||
|
public static final short PERSPECTIVE__SCALEXTOX = 579;
|
||||||
|
public static final short PERSPECTIVE__SCALEYTOX = 580;
|
||||||
|
public static final short PERSPECTIVE__SCALEXTOY = 581;
|
||||||
|
public static final short PERSPECTIVE__SCALEYTOY = 582;
|
||||||
|
public static final short PERSPECTIVE__PERSPECTIVEX = 583;
|
||||||
|
public static final short PERSPECTIVE__PERSPECTIVEY = 584;
|
||||||
|
public static final short PERSPECTIVE__WEIGHT = 585;
|
||||||
|
public static final short PERSPECTIVE__ORIGINX = 586;
|
||||||
|
public static final short PERSPECTIVE__ORIGINY = 587;
|
||||||
|
public static final short PERSPECTIVE__PERSPECTIVEON = 639;
|
||||||
|
public static final short THREED__SPECULARAMOUNT = 640;
|
||||||
|
public static final short THREED__DIFFUSEAMOUNT = 661;
|
||||||
|
public static final short THREED__SHININESS = 662;
|
||||||
|
public static final short THREED__EDGETHICKNESS = 663;
|
||||||
|
public static final short THREED__EXTRUDEFORWARD = 664;
|
||||||
|
public static final short THREED__EXTRUDEBACKWARD = 665;
|
||||||
|
public static final short THREED__EXTRUDEPLANE = 666;
|
||||||
|
public static final short THREED__EXTRUSIONCOLOR = 667;
|
||||||
|
public static final short THREED__CRMOD = 648;
|
||||||
|
public static final short THREED__3DEFFECT = 700;
|
||||||
|
public static final short THREED__METALLIC = 701;
|
||||||
|
public static final short THREED__USEEXTRUSIONCOLOR = 702;
|
||||||
|
public static final short THREED__LIGHTFACE = 703;
|
||||||
|
public static final short THREEDSTYLE__YROTATIONANGLE = 704;
|
||||||
|
public static final short THREEDSTYLE__XROTATIONANGLE = 705;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONAXISX = 706;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONAXISY = 707;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONAXISZ = 708;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONANGLE = 709;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONCENTERX = 710;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONCENTERY = 711;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONCENTERZ = 712;
|
||||||
|
public static final short THREEDSTYLE__RENDERMODE = 713;
|
||||||
|
public static final short THREEDSTYLE__TOLERANCE = 714;
|
||||||
|
public static final short THREEDSTYLE__XVIEWPOINT = 715;
|
||||||
|
public static final short THREEDSTYLE__YVIEWPOINT = 716;
|
||||||
|
public static final short THREEDSTYLE__ZVIEWPOINT = 717;
|
||||||
|
public static final short THREEDSTYLE__ORIGINX = 718;
|
||||||
|
public static final short THREEDSTYLE__ORIGINY = 719;
|
||||||
|
public static final short THREEDSTYLE__SKEWANGLE = 720;
|
||||||
|
public static final short THREEDSTYLE__SKEWAMOUNT = 721;
|
||||||
|
public static final short THREEDSTYLE__AMBIENTINTENSITY = 722;
|
||||||
|
public static final short THREEDSTYLE__KEYX = 723;
|
||||||
|
public static final short THREEDSTYLE__KEYY = 724;
|
||||||
|
public static final short THREEDSTYLE__KEYZ = 725;
|
||||||
|
public static final short THREEDSTYLE__KEYINTENSITY = 726;
|
||||||
|
public static final short THREEDSTYLE__FILLX = 727;
|
||||||
|
public static final short THREEDSTYLE__FILLY = 728;
|
||||||
|
public static final short THREEDSTYLE__FILLZ = 729;
|
||||||
|
public static final short THREEDSTYLE__FILLINTENSITY = 730;
|
||||||
|
public static final short THREEDSTYLE__CONSTRAINROTATION = 763;
|
||||||
|
public static final short THREEDSTYLE__ROTATIONCENTERAUTO = 764;
|
||||||
|
public static final short THREEDSTYLE__PARALLEL = 765;
|
||||||
|
public static final short THREEDSTYLE__KEYHARSH = 766;
|
||||||
|
public static final short THREEDSTYLE__FILLHARSH = 767;
|
||||||
|
public static final short SHAPE__MASTER = 769;
|
||||||
|
public static final short SHAPE__CONNECTORSTYLE = 771;
|
||||||
|
public static final short SHAPE__BLACKANDWHITESETTINGS = 772;
|
||||||
|
public static final short SHAPE__WMODEPUREBW = 773;
|
||||||
|
public static final short SHAPE__WMODEBW = 774;
|
||||||
|
public static final short SHAPE__OLEICON = 826;
|
||||||
|
public static final short SHAPE__PREFERRELATIVERESIZE = 827;
|
||||||
|
public static final short SHAPE__LOCKSHAPETYPE = 828;
|
||||||
|
public static final short SHAPE__DELETEATTACHEDOBJECT = 830;
|
||||||
|
public static final short SHAPE__BACKGROUNDSHAPE = 831;
|
||||||
|
public static final short CALLOUT__CALLOUTTYPE = 832;
|
||||||
|
public static final short CALLOUT__XYCALLOUTGAP = 833;
|
||||||
|
public static final short CALLOUT__CALLOUTANGLE = 834;
|
||||||
|
public static final short CALLOUT__CALLOUTDROPTYPE = 835;
|
||||||
|
public static final short CALLOUT__CALLOUTDROPSPECIFIED = 836;
|
||||||
|
public static final short CALLOUT__CALLOUTLENGTHSPECIFIED = 837;
|
||||||
|
public static final short CALLOUT__ISCALLOUT = 889;
|
||||||
|
public static final short CALLOUT__CALLOUTACCENTBAR = 890;
|
||||||
|
public static final short CALLOUT__CALLOUTTEXTBORDER = 891;
|
||||||
|
public static final short CALLOUT__CALLOUTMINUSX = 892;
|
||||||
|
public static final short CALLOUT__CALLOUTMINUSY = 893;
|
||||||
|
public static final short CALLOUT__DROPAUTO = 894;
|
||||||
|
public static final short CALLOUT__LENGTHSPECIFIED = 895;
|
||||||
|
public static final short GROUPSHAPE__SHAPENAME = 896;
|
||||||
|
public static final short GROUPSHAPE__DESCRIPTION = 897;
|
||||||
|
public static final short GROUPSHAPE__HYPERLINK = 898;
|
||||||
|
public static final short GROUPSHAPE__WRAPPOLYGONVERTICES = 899;
|
||||||
|
public static final short GROUPSHAPE__WRAPDISTLEFT = 900;
|
||||||
|
public static final short GROUPSHAPE__WRAPDISTTOP = 901;
|
||||||
|
public static final short GROUPSHAPE__WRAPDISTRIGHT = 902;
|
||||||
|
public static final short GROUPSHAPE__WRAPDISTBOTTOM = 903;
|
||||||
|
public static final short GROUPSHAPE__REGROUPID = 904;
|
||||||
|
public static final short GROUPSHAPE__EDITEDWRAP = 953;
|
||||||
|
public static final short GROUPSHAPE__BEHINDDOCUMENT = 954;
|
||||||
|
public static final short GROUPSHAPE__ONDBLCLICKNOTIFY = 955;
|
||||||
|
public static final short GROUPSHAPE__ISBUTTON = 956;
|
||||||
|
public static final short GROUPSHAPE__1DADJUSTMENT = 957;
|
||||||
|
public static final short GROUPSHAPE__HIDDEN = 958;
|
||||||
|
public static final short GROUPSHAPE__PRINT = 959;
|
||||||
|
|
||||||
|
|
||||||
|
private static Map properties;
|
||||||
|
|
||||||
|
private static void initProps()
|
||||||
|
{
|
||||||
|
if ( properties == null )
|
||||||
|
{
|
||||||
|
properties = new HashMap();
|
||||||
|
addProp( TRANSFORM__ROTATION, data( "transform.rotation" ) );
|
||||||
|
addProp( PROTECTION__LOCKROTATION , data( "protection.lockrotation" ) );
|
||||||
|
addProp( PROTECTION__LOCKASPECTRATIO , data( "protection.lockaspectratio" ) );
|
||||||
|
addProp( PROTECTION__LOCKPOSITION , data( "protection.lockposition" ) );
|
||||||
|
addProp( PROTECTION__LOCKAGAINSTSELECT , data( "protection.lockagainstselect" ) );
|
||||||
|
addProp( PROTECTION__LOCKCROPPING , data( "protection.lockcropping" ) );
|
||||||
|
addProp( PROTECTION__LOCKVERTICES , data( "protection.lockvertices" ) );
|
||||||
|
addProp( PROTECTION__LOCKTEXT , data( "protection.locktext" ) );
|
||||||
|
addProp( PROTECTION__LOCKADJUSTHANDLES , data( "protection.lockadjusthandles" ) );
|
||||||
|
addProp( PROTECTION__LOCKAGAINSTGROUPING , data( "protection.lockagainstgrouping", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( TEXT__TEXTID , data( "text.textid" ) );
|
||||||
|
addProp( TEXT__TEXTLEFT , data( "text.textleft" ) );
|
||||||
|
addProp( TEXT__TEXTTOP , data( "text.texttop" ) );
|
||||||
|
addProp( TEXT__TEXTRIGHT , data( "text.textright" ) );
|
||||||
|
addProp( TEXT__TEXTBOTTOM , data( "text.textbottom" ) );
|
||||||
|
addProp( TEXT__WRAPTEXT , data( "text.wraptext" ) );
|
||||||
|
addProp( TEXT__SCALETEXT , data( "text.scaletext" ) );
|
||||||
|
addProp( TEXT__ANCHORTEXT , data( "text.anchortext" ) );
|
||||||
|
addProp( TEXT__TEXTFLOW , data( "text.textflow" ) );
|
||||||
|
addProp( TEXT__FONTROTATION , data( "text.fontrotation" ) );
|
||||||
|
addProp( TEXT__IDOFNEXTSHAPE , data( "text.idofnextshape" ) );
|
||||||
|
addProp( TEXT__BIDIR , data( "text.bidir" ) );
|
||||||
|
addProp( TEXT__SINGLECLICKSELECTS , data( "text.singleclickselects" ) );
|
||||||
|
addProp( TEXT__USEHOSTMARGINS , data( "text.usehostmargins" ) );
|
||||||
|
addProp( TEXT__ROTATETEXTWITHSHAPE , data( "text.rotatetextwithshape" ) );
|
||||||
|
addProp( TEXT__SIZESHAPETOFITTEXT , data( "text.sizeshapetofittext" ) );
|
||||||
|
addProp( TEXT__SIZE_TEXT_TO_FIT_SHAPE, data( "text.sizetexttofitshape", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( GEOTEXT__UNICODE , data( "geotext.unicode" ) );
|
||||||
|
addProp( GEOTEXT__RTFTEXT , data( "geotext.rtftext" ) );
|
||||||
|
addProp( GEOTEXT__ALIGNMENTONCURVE , data( "geotext.alignmentoncurve" ) );
|
||||||
|
addProp( GEOTEXT__DEFAULTPOINTSIZE , data( "geotext.defaultpointsize" ) );
|
||||||
|
addProp( GEOTEXT__TEXTSPACING , data( "geotext.textspacing" ) );
|
||||||
|
addProp( GEOTEXT__FONTFAMILYNAME , data( "geotext.fontfamilyname" ) );
|
||||||
|
addProp( GEOTEXT__REVERSEROWORDER , data( "geotext.reverseroworder" ) );
|
||||||
|
addProp( GEOTEXT__HASTEXTEFFECT , data( "geotext.hastexteffect" ) );
|
||||||
|
addProp( GEOTEXT__ROTATECHARACTERS , data( "geotext.rotatecharacters" ) );
|
||||||
|
addProp( GEOTEXT__KERNCHARACTERS , data( "geotext.kerncharacters" ) );
|
||||||
|
addProp( GEOTEXT__TIGHTORTRACK , data( "geotext.tightortrack" ) );
|
||||||
|
addProp( GEOTEXT__STRETCHTOFITSHAPE , data( "geotext.stretchtofitshape" ) );
|
||||||
|
addProp( GEOTEXT__CHARBOUNDINGBOX , data( "geotext.charboundingbox" ) );
|
||||||
|
addProp( GEOTEXT__SCALETEXTONPATH , data( "geotext.scaletextonpath" ) );
|
||||||
|
addProp( GEOTEXT__STRETCHCHARHEIGHT , data( "geotext.stretchcharheight" ) );
|
||||||
|
addProp( GEOTEXT__NOMEASUREALONGPATH , data( "geotext.nomeasurealongpath" ) );
|
||||||
|
addProp( GEOTEXT__BOLDFONT , data( "geotext.boldfont" ) );
|
||||||
|
addProp( GEOTEXT__ITALICFONT , data( "geotext.italicfont" ) );
|
||||||
|
addProp( GEOTEXT__UNDERLINEFONT , data( "geotext.underlinefont" ) );
|
||||||
|
addProp( GEOTEXT__SHADOWFONT , data( "geotext.shadowfont" ) );
|
||||||
|
addProp( GEOTEXT__SMALLCAPSFONT , data( "geotext.smallcapsfont" ) );
|
||||||
|
addProp( GEOTEXT__STRIKETHROUGHFONT , data( "geotext.strikethroughfont" ) );
|
||||||
|
addProp( BLIP__CROPFROMTOP , data( "blip.cropfromtop" ) );
|
||||||
|
addProp( BLIP__CROPFROMBOTTOM , data( "blip.cropfrombottom" ) );
|
||||||
|
addProp( BLIP__CROPFROMLEFT , data( "blip.cropfromleft" ) );
|
||||||
|
addProp( BLIP__CROPFROMRIGHT , data( "blip.cropfromright" ) );
|
||||||
|
addProp( BLIP__BLIPTODISPLAY , data( "blip.bliptodisplay" ) );
|
||||||
|
addProp( BLIP__BLIPFILENAME , data( "blip.blipfilename" ) );
|
||||||
|
addProp( BLIP__BLIPFLAGS , data( "blip.blipflags" ) );
|
||||||
|
addProp( BLIP__TRANSPARENTCOLOR , data( "blip.transparentcolor" ) );
|
||||||
|
addProp( BLIP__CONTRASTSETTING , data( "blip.contrastsetting" ) );
|
||||||
|
addProp( BLIP__BRIGHTNESSSETTING , data( "blip.brightnesssetting" ) );
|
||||||
|
addProp( BLIP__GAMMA , data( "blip.gamma" ) );
|
||||||
|
addProp( BLIP__PICTUREID , data( "blip.pictureid" ) );
|
||||||
|
addProp( BLIP__DOUBLEMOD , data( "blip.doublemod" ) );
|
||||||
|
addProp( BLIP__PICTUREFILLMOD , data( "blip.picturefillmod" ) );
|
||||||
|
addProp( BLIP__PICTURELINE , data( "blip.pictureline" ) );
|
||||||
|
addProp( BLIP__PRINTBLIP , data( "blip.printblip" ) );
|
||||||
|
addProp( BLIP__PRINTBLIPFILENAME , data( "blip.printblipfilename" ) );
|
||||||
|
addProp( BLIP__PRINTFLAGS , data( "blip.printflags" ) );
|
||||||
|
addProp( BLIP__NOHITTESTPICTURE , data( "blip.nohittestpicture" ) );
|
||||||
|
addProp( BLIP__PICTUREGRAY , data( "blip.picturegray" ) );
|
||||||
|
addProp( BLIP__PICTUREBILEVEL , data( "blip.picturebilevel" ) );
|
||||||
|
addProp( BLIP__PICTUREACTIVE , data( "blip.pictureactive" ) );
|
||||||
|
addProp( GEOMETRY__LEFT , data( "geometry.left" ) );
|
||||||
|
addProp( GEOMETRY__TOP , data( "geometry.top" ) );
|
||||||
|
addProp( GEOMETRY__RIGHT , data( "geometry.right" ) );
|
||||||
|
addProp( GEOMETRY__BOTTOM , data( "geometry.bottom" ) );
|
||||||
|
addProp( GEOMETRY__SHAPEPATH , data( "geometry.shapepath", EscherPropertyMetaData.TYPE_SHAPEPATH ) );
|
||||||
|
addProp( GEOMETRY__VERTICES , data( "geometry.vertices" , EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( GEOMETRY__SEGMENTINFO , data( "geometry.segmentinfo", EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( GEOMETRY__ADJUSTVALUE , data( "geometry.adjustvalue" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST2VALUE , data( "geometry.adjust2value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST3VALUE , data( "geometry.adjust3value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST4VALUE , data( "geometry.adjust4value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST5VALUE , data( "geometry.adjust5value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST6VALUE , data( "geometry.adjust6value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST7VALUE , data( "geometry.adjust7value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST8VALUE , data( "geometry.adjust8value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST9VALUE , data( "geometry.adjust9value" ) );
|
||||||
|
addProp( GEOMETRY__ADJUST10VALUE , data( "geometry.adjust10value" ) );
|
||||||
|
addProp( GEOMETRY__SHADOWok , data( "geometry.shadowOK" ) );
|
||||||
|
addProp( GEOMETRY__3DOK , data( "geometry.3dok" ) );
|
||||||
|
addProp( GEOMETRY__LINEOK , data( "geometry.lineok" ) );
|
||||||
|
addProp( GEOMETRY__GEOTEXTOK , data( "geometry.geotextok" ) );
|
||||||
|
addProp( GEOMETRY__FILLSHADESHAPEOK , data( "geometry.fillshadeshapeok" ) );
|
||||||
|
addProp( GEOMETRY__FILLOK , data( "geometry.fillok", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( FILL__FILLTYPE , data( "fill.filltype" ) );
|
||||||
|
addProp( FILL__FILLCOLOR, data( "fill.fillcolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( FILL__FILLOPACITY , data( "fill.fillopacity" ) );
|
||||||
|
addProp( FILL__FILLBACKCOLOR , data( "fill.fillbackcolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( FILL__BACKOPACITY , data( "fill.backopacity" ) );
|
||||||
|
addProp( FILL__CRMOD , data( "fill.crmod" ) );
|
||||||
|
addProp( FILL__PATTERNTEXTURE , data( "fill.patterntexture" ) );
|
||||||
|
addProp( FILL__BLIPFILENAME , data( "fill.blipfilename" ) );
|
||||||
|
addProp( FILL__BLIPFLAGS, data( "fill.blipflags" ) );
|
||||||
|
addProp( FILL__WIDTH , data( "fill.width" ) );
|
||||||
|
addProp( FILL__HEIGHT , data( "fill.height" ) );
|
||||||
|
addProp( FILL__ANGLE , data( "fill.angle" ) );
|
||||||
|
addProp( FILL__FOCUS , data( "fill.focus" ) );
|
||||||
|
addProp( FILL__TOLEFT , data( "fill.toleft" ) );
|
||||||
|
addProp( FILL__TOTOP , data( "fill.totop" ) );
|
||||||
|
addProp( FILL__TORIGHT , data( "fill.toright" ) );
|
||||||
|
addProp( FILL__TOBOTTOM , data( "fill.tobottom" ) );
|
||||||
|
addProp( FILL__RECTLEFT , data( "fill.rectleft" ) );
|
||||||
|
addProp( FILL__RECTTOP , data( "fill.recttop" ) );
|
||||||
|
addProp( FILL__RECTRIGHT , data( "fill.rectright" ) );
|
||||||
|
addProp( FILL__RECTBOTTOM , data( "fill.rectbottom" ) );
|
||||||
|
addProp( FILL__DZTYPE , data( "fill.dztype" ) );
|
||||||
|
addProp( FILL__SHADEPRESET , data( "fill.shadepreset" ) );
|
||||||
|
addProp( FILL__SHADECOLORS , data( "fill.shadecolors", EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( FILL__ORIGINX , data( "fill.originx" ) );
|
||||||
|
addProp( FILL__ORIGINY , data( "fill.originy" ) );
|
||||||
|
addProp( FILL__SHAPEORIGINX , data( "fill.shapeoriginx" ) );
|
||||||
|
addProp( FILL__SHAPEORIGINY , data( "fill.shapeoriginy" ) );
|
||||||
|
addProp( FILL__SHADETYPE , data( "fill.shadetype" ) );
|
||||||
|
addProp( FILL__FILLED , data( "fill.filled" ) );
|
||||||
|
addProp( FILL__HITTESTFILL , data( "fill.hittestfill" ) );
|
||||||
|
addProp( FILL__SHAPE , data( "fill.shape" ) );
|
||||||
|
addProp( FILL__USERECT , data( "fill.userect" ) );
|
||||||
|
addProp( FILL__NOFILLHITTEST , data( "fill.nofillhittest", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( LINESTYLE__COLOR, data( "linestyle.color", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( LINESTYLE__OPACITY , data( "linestyle.opacity" ) );
|
||||||
|
addProp( LINESTYLE__BACKCOLOR , data( "linestyle.backcolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( LINESTYLE__CRMOD , data( "linestyle.crmod" ) );
|
||||||
|
addProp( LINESTYLE__LINETYPE , data( "linestyle.linetype" ) );
|
||||||
|
addProp( LINESTYLE__FILLBLIP , data( "linestyle.fillblip" ) );
|
||||||
|
addProp( LINESTYLE__FILLBLIPNAME , data( "linestyle.fillblipname" ) );
|
||||||
|
addProp( LINESTYLE__FILLBLIPFLAGS , data( "linestyle.fillblipflags" ) );
|
||||||
|
addProp( LINESTYLE__FILLWIDTH , data( "linestyle.fillwidth" ) );
|
||||||
|
addProp( LINESTYLE__FILLHEIGHT , data( "linestyle.fillheight" ) );
|
||||||
|
addProp( LINESTYLE__FILLDZTYPE , data( "linestyle.filldztype" ) );
|
||||||
|
addProp( LINESTYLE__LINEWIDTH , data( "linestyle.linewidth" ) );
|
||||||
|
addProp( LINESTYLE__LINEMITERLIMIT , data( "linestyle.linemiterlimit" ) );
|
||||||
|
addProp( LINESTYLE__LINESTYLE , data( "linestyle.linestyle" ) );
|
||||||
|
addProp( LINESTYLE__LINEDASHING , data( "linestyle.linedashing" ) );
|
||||||
|
addProp( LINESTYLE__LINEDASHSTYLE , data( "linestyle.linedashstyle", EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( LINESTYLE__LINESTARTARROWHEAD , data( "linestyle.linestartarrowhead" ) );
|
||||||
|
addProp( LINESTYLE__LINEENDARROWHEAD , data( "linestyle.lineendarrowhead" ) );
|
||||||
|
addProp( LINESTYLE__LINESTARTARROWWIDTH , data( "linestyle.linestartarrowwidth" ) );
|
||||||
|
addProp( LINESTYLE__LINEESTARTARROWLENGTH , data( "linestyle.lineestartarrowlength" ) );
|
||||||
|
addProp( LINESTYLE__LINEENDARROWWIDTH , data( "linestyle.lineendarrowwidth" ) );
|
||||||
|
addProp( LINESTYLE__LINEENDARROWLENGTH , data( "linestyle.lineendarrowlength" ) );
|
||||||
|
addProp( LINESTYLE__LINEJOINSTYLE , data( "linestyle.linejoinstyle" ) );
|
||||||
|
addProp( LINESTYLE__LINEENDCAPSTYLE , data( "linestyle.lineendcapstyle" ) );
|
||||||
|
addProp( LINESTYLE__ARROWHEADSOK , data( "linestyle.arrowheadsok" ) );
|
||||||
|
addProp( LINESTYLE__ANYLINE , data( "linestyle.anyline" ) );
|
||||||
|
addProp( LINESTYLE__HITLINETEST , data( "linestyle.hitlinetest" ) );
|
||||||
|
addProp( LINESTYLE__LINEFILLSHAPE , data( "linestyle.linefillshape" ) );
|
||||||
|
addProp( LINESTYLE__NOLINEDRAWDASH , data( "linestyle.nolinedrawdash", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
addProp( SHADOWSTYLE__TYPE , data( "shadowstyle.type" ) );
|
||||||
|
addProp( SHADOWSTYLE__COLOR , data( "shadowstyle.color", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( SHADOWSTYLE__HIGHLIGHT , data( "shadowstyle.highlight" ) );
|
||||||
|
addProp( SHADOWSTYLE__CRMOD , data( "shadowstyle.crmod" ) );
|
||||||
|
addProp( SHADOWSTYLE__OPACITY , data( "shadowstyle.opacity" ) );
|
||||||
|
addProp( SHADOWSTYLE__OFFSETX , data( "shadowstyle.offsetx" ) );
|
||||||
|
addProp( SHADOWSTYLE__OFFSETY , data( "shadowstyle.offsety" ) );
|
||||||
|
addProp( SHADOWSTYLE__SECONDOFFSETX , data( "shadowstyle.secondoffsetx" ) );
|
||||||
|
addProp( SHADOWSTYLE__SECONDOFFSETY , data( "shadowstyle.secondoffsety" ) );
|
||||||
|
addProp( SHADOWSTYLE__SCALEXTOX , data( "shadowstyle.scalextox" ) );
|
||||||
|
addProp( SHADOWSTYLE__SCALEYTOX , data( "shadowstyle.scaleytox" ) );
|
||||||
|
addProp( SHADOWSTYLE__SCALEXTOY , data( "shadowstyle.scalextoy" ) );
|
||||||
|
addProp( SHADOWSTYLE__SCALEYTOY , data( "shadowstyle.scaleytoy" ) );
|
||||||
|
addProp( SHADOWSTYLE__PERSPECTIVEX , data( "shadowstyle.perspectivex" ) );
|
||||||
|
addProp( SHADOWSTYLE__PERSPECTIVEY , data( "shadowstyle.perspectivey" ) );
|
||||||
|
addProp( SHADOWSTYLE__WEIGHT , data( "shadowstyle.weight" ) );
|
||||||
|
addProp( SHADOWSTYLE__ORIGINX , data( "shadowstyle.originx" ) );
|
||||||
|
addProp( SHADOWSTYLE__ORIGINY , data( "shadowstyle.originy" ) );
|
||||||
|
addProp( SHADOWSTYLE__SHADOW , data( "shadowstyle.shadow" ) );
|
||||||
|
addProp( SHADOWSTYLE__SHADOWOBSURED , data( "shadowstyle.shadowobsured" ) );
|
||||||
|
addProp( PERSPECTIVE__TYPE , data( "perspective.type" ) );
|
||||||
|
addProp( PERSPECTIVE__OFFSETX , data( "perspective.offsetx" ) );
|
||||||
|
addProp( PERSPECTIVE__OFFSETY , data( "perspective.offsety" ) );
|
||||||
|
addProp( PERSPECTIVE__SCALEXTOX , data( "perspective.scalextox" ) );
|
||||||
|
addProp( PERSPECTIVE__SCALEYTOX , data( "perspective.scaleytox" ) );
|
||||||
|
addProp( PERSPECTIVE__SCALEXTOY , data( "perspective.scalextoy" ) );
|
||||||
|
addProp( PERSPECTIVE__SCALEYTOY , data( "perspective.scaleytoy" ) );
|
||||||
|
addProp( PERSPECTIVE__PERSPECTIVEX , data( "perspective.perspectivex" ) );
|
||||||
|
addProp( PERSPECTIVE__PERSPECTIVEY , data( "perspective.perspectivey" ) );
|
||||||
|
addProp( PERSPECTIVE__WEIGHT , data( "perspective.weight" ) );
|
||||||
|
addProp( PERSPECTIVE__ORIGINX , data( "perspective.originx" ) );
|
||||||
|
addProp( PERSPECTIVE__ORIGINY , data( "perspective.originy" ) );
|
||||||
|
addProp( PERSPECTIVE__PERSPECTIVEON , data( "perspective.perspectiveon" ) );
|
||||||
|
addProp( THREED__SPECULARAMOUNT , data( "3d.specularamount" ) );
|
||||||
|
addProp( THREED__DIFFUSEAMOUNT , data( "3d.diffuseamount" ) );
|
||||||
|
addProp( THREED__SHININESS , data( "3d.shininess" ) );
|
||||||
|
addProp( THREED__EDGETHICKNESS , data( "3d.edgethickness" ) );
|
||||||
|
addProp( THREED__EXTRUDEFORWARD , data( "3d.extrudeforward" ) );
|
||||||
|
addProp( THREED__EXTRUDEBACKWARD , data( "3d.extrudebackward" ) );
|
||||||
|
addProp( THREED__EXTRUDEPLANE , data( "3d.extrudeplane" ) );
|
||||||
|
addProp( THREED__EXTRUSIONCOLOR , data( "3d.extrusioncolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( THREED__CRMOD , data( "3d.crmod" ) );
|
||||||
|
addProp( THREED__3DEFFECT , data( "3d.3deffect" ) );
|
||||||
|
addProp( THREED__METALLIC , data( "3d.metallic" ) );
|
||||||
|
addProp( THREED__USEEXTRUSIONCOLOR , data( "3d.useextrusioncolor", EscherPropertyMetaData.TYPE_RGB ) );
|
||||||
|
addProp( THREED__LIGHTFACE , data( "3d.lightface" ) );
|
||||||
|
addProp( THREEDSTYLE__YROTATIONANGLE , data( "3dstyle.yrotationangle" ) );
|
||||||
|
addProp( THREEDSTYLE__XROTATIONANGLE , data( "3dstyle.xrotationangle" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONAXISX , data( "3dstyle.rotationaxisx" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONAXISY , data( "3dstyle.rotationaxisy" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONAXISZ , data( "3dstyle.rotationaxisz" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONANGLE , data( "3dstyle.rotationangle" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONCENTERX , data( "3dstyle.rotationcenterx" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONCENTERY , data( "3dstyle.rotationcentery" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONCENTERZ , data( "3dstyle.rotationcenterz" ) );
|
||||||
|
addProp( THREEDSTYLE__RENDERMODE , data( "3dstyle.rendermode" ) );
|
||||||
|
addProp( THREEDSTYLE__TOLERANCE , data( "3dstyle.tolerance" ) );
|
||||||
|
addProp( THREEDSTYLE__XVIEWPOINT , data( "3dstyle.xviewpoint" ) );
|
||||||
|
addProp( THREEDSTYLE__YVIEWPOINT , data( "3dstyle.yviewpoint" ) );
|
||||||
|
addProp( THREEDSTYLE__ZVIEWPOINT , data( "3dstyle.zviewpoint" ) );
|
||||||
|
addProp( THREEDSTYLE__ORIGINX , data( "3dstyle.originx" ) );
|
||||||
|
addProp( THREEDSTYLE__ORIGINY , data( "3dstyle.originy" ) );
|
||||||
|
addProp( THREEDSTYLE__SKEWANGLE , data( "3dstyle.skewangle" ) );
|
||||||
|
addProp( THREEDSTYLE__SKEWAMOUNT , data( "3dstyle.skewamount" ) );
|
||||||
|
addProp( THREEDSTYLE__AMBIENTINTENSITY , data( "3dstyle.ambientintensity" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYX , data( "3dstyle.keyx" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYY , data( "3dstyle.keyy" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYZ , data( "3dstyle.keyz" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYINTENSITY , data( "3dstyle.keyintensity" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLX , data( "3dstyle.fillx" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLY , data( "3dstyle.filly" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLZ , data( "3dstyle.fillz" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLINTENSITY , data( "3dstyle.fillintensity" ) );
|
||||||
|
addProp( THREEDSTYLE__CONSTRAINROTATION , data( "3dstyle.constrainrotation" ) );
|
||||||
|
addProp( THREEDSTYLE__ROTATIONCENTERAUTO , data( "3dstyle.rotationcenterauto" ) );
|
||||||
|
addProp( THREEDSTYLE__PARALLEL , data( "3dstyle.parallel" ) );
|
||||||
|
addProp( THREEDSTYLE__KEYHARSH , data( "3dstyle.keyharsh" ) );
|
||||||
|
addProp( THREEDSTYLE__FILLHARSH , data( "3dstyle.fillharsh" ) );
|
||||||
|
addProp( SHAPE__MASTER , data( "shape.master" ) );
|
||||||
|
addProp( SHAPE__CONNECTORSTYLE , data( "shape.connectorstyle" ) );
|
||||||
|
addProp( SHAPE__BLACKANDWHITESETTINGS , data( "shape.blackandwhitesettings" ) );
|
||||||
|
addProp( SHAPE__WMODEPUREBW , data( "shape.wmodepurebw" ) );
|
||||||
|
addProp( SHAPE__WMODEBW , data( "shape.wmodebw" ) );
|
||||||
|
addProp( SHAPE__OLEICON , data( "shape.oleicon" ) );
|
||||||
|
addProp( SHAPE__PREFERRELATIVERESIZE , data( "shape.preferrelativeresize" ) );
|
||||||
|
addProp( SHAPE__LOCKSHAPETYPE , data( "shape.lockshapetype" ) );
|
||||||
|
addProp( SHAPE__DELETEATTACHEDOBJECT , data( "shape.deleteattachedobject" ) );
|
||||||
|
addProp( SHAPE__BACKGROUNDSHAPE , data( "shape.backgroundshape" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTTYPE , data( "callout.callouttype" ) );
|
||||||
|
addProp( CALLOUT__XYCALLOUTGAP , data( "callout.xycalloutgap" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTANGLE , data( "callout.calloutangle" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTDROPTYPE , data( "callout.calloutdroptype" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTDROPSPECIFIED , data( "callout.calloutdropspecified" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTLENGTHSPECIFIED , data( "callout.calloutlengthspecified" ) );
|
||||||
|
addProp( CALLOUT__ISCALLOUT , data( "callout.iscallout" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTACCENTBAR , data( "callout.calloutaccentbar" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTTEXTBORDER , data( "callout.callouttextborder" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTMINUSX , data( "callout.calloutminusx" ) );
|
||||||
|
addProp( CALLOUT__CALLOUTMINUSY , data( "callout.calloutminusy" ) );
|
||||||
|
addProp( CALLOUT__DROPAUTO , data( "callout.dropauto" ) );
|
||||||
|
addProp( CALLOUT__LENGTHSPECIFIED , data( "callout.lengthspecified" ) );
|
||||||
|
addProp( GROUPSHAPE__SHAPENAME , data( "groupshape.shapename" ) );
|
||||||
|
addProp( GROUPSHAPE__DESCRIPTION , data( "groupshape.description" ) );
|
||||||
|
addProp( GROUPSHAPE__HYPERLINK , data( "groupshape.hyperlink" ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPPOLYGONVERTICES , data( "groupshape.wrappolygonvertices", EscherPropertyMetaData.TYPE_ARRAY ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPDISTLEFT , data( "groupshape.wrapdistleft" ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPDISTTOP , data( "groupshape.wrapdisttop" ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPDISTRIGHT , data( "groupshape.wrapdistright" ) );
|
||||||
|
addProp( GROUPSHAPE__WRAPDISTBOTTOM , data( "groupshape.wrapdistbottom" ) );
|
||||||
|
addProp( GROUPSHAPE__REGROUPID , data( "groupshape.regroupid" ) );
|
||||||
|
addProp( GROUPSHAPE__EDITEDWRAP , data( "groupshape.editedwrap" ) );
|
||||||
|
addProp( GROUPSHAPE__BEHINDDOCUMENT , data( "groupshape.behinddocument" ) );
|
||||||
|
addProp( GROUPSHAPE__ONDBLCLICKNOTIFY , data( "groupshape.ondblclicknotify" ) );
|
||||||
|
addProp( GROUPSHAPE__ISBUTTON , data( "groupshape.isbutton" ) );
|
||||||
|
addProp( GROUPSHAPE__1DADJUSTMENT , data( "groupshape.1dadjustment" ) );
|
||||||
|
addProp( GROUPSHAPE__HIDDEN , data( "groupshape.hidden" ) );
|
||||||
|
addProp( GROUPSHAPE__PRINT , data( "groupshape.print", EscherPropertyMetaData.TYPE_BOOLEAN ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void addProp( int s, EscherPropertyMetaData data )
|
||||||
|
{
|
||||||
|
properties.put( new Short( (short) s ), data );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EscherPropertyMetaData data( String propName, byte type )
|
||||||
|
{
|
||||||
|
return new EscherPropertyMetaData( propName, type );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EscherPropertyMetaData data( String propName )
|
||||||
|
{
|
||||||
|
return new EscherPropertyMetaData( propName );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPropertyName( short propertyId )
|
||||||
|
{
|
||||||
|
initProps();
|
||||||
|
EscherPropertyMetaData o = (EscherPropertyMetaData) properties.get( new Short( propertyId ) );
|
||||||
|
return o == null ? "unknown" : o.getDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte getPropertyType( short propertyId )
|
||||||
|
{
|
||||||
|
initProps();
|
||||||
|
EscherPropertyMetaData escherPropertyMetaData = (EscherPropertyMetaData) properties.get( new Short( propertyId ) );
|
||||||
|
return escherPropertyMetaData == null ? 0 : escherPropertyMetaData.getType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
78
src/java/org/apache/poi/ddf/EscherProperty.java
Normal file
78
src/java/org/apache/poi/ddf/EscherProperty.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the abstract base class for all escher properties.
|
||||||
|
*
|
||||||
|
* @see EscherOptRecord
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
abstract public class EscherProperty
|
||||||
|
{
|
||||||
|
private short id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id is distinct from the actual property number. The id includes the property number the blip id
|
||||||
|
* flag and an indicator whether the property is complex or not.
|
||||||
|
*/
|
||||||
|
public EscherProperty( short id )
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new escher property. The three parameters are combined to form a property
|
||||||
|
* id.
|
||||||
|
*/
|
||||||
|
public EscherProperty( short propertyNumber, boolean isComplex, boolean isBlipId )
|
||||||
|
{
|
||||||
|
this.id = (short)(propertyNumber +
|
||||||
|
(isComplex ? 0x8000 : 0x0) +
|
||||||
|
(isBlipId ? 0x4000 : 0x0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getPropertyNumber()
|
||||||
|
{
|
||||||
|
return (short) ( id & (short) 0x3FFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isComplex()
|
||||||
|
{
|
||||||
|
return ( id & (short) 0x8000 ) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBlipId()
|
||||||
|
{
|
||||||
|
return ( id & (short) 0x4000 ) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return EscherProperties.getPropertyName(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Most properties are just 6 bytes in length. Override this if we're
|
||||||
|
* dealing with complex properties.
|
||||||
|
*/
|
||||||
|
public int getPropertySize()
|
||||||
|
{
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher properties consist of a simple fixed length part and a complex variable length part.
|
||||||
|
* The fixed length part is serialized first.
|
||||||
|
*/
|
||||||
|
abstract public int serializeSimplePart( byte[] data, int pos );
|
||||||
|
/**
|
||||||
|
* Escher properties consist of a simple fixed length part and a complex variable length part.
|
||||||
|
* The fixed length part is serialized first.
|
||||||
|
*/
|
||||||
|
abstract public int serializeComplexPart( byte[] data, int pos );
|
||||||
|
}
|
91
src/java/org/apache/poi/ddf/EscherPropertyFactory.java
Normal file
91
src/java/org/apache/poi/ddf/EscherPropertyFactory.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a property given a reference into the byte array storing that property.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
public class EscherPropertyFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create new properties from a byte array.
|
||||||
|
*
|
||||||
|
* @param data The byte array containing the property
|
||||||
|
* @param offset The starting offset into the byte array
|
||||||
|
* @return The new properties
|
||||||
|
*/
|
||||||
|
public List createProperties( byte[] data, int offset, short numProperties )
|
||||||
|
{
|
||||||
|
List results = new ArrayList();
|
||||||
|
|
||||||
|
int pos = offset;
|
||||||
|
int complexBytes = 0;
|
||||||
|
// while ( bytesRemaining >= 6 )
|
||||||
|
for (int i = 0; i < numProperties; i++)
|
||||||
|
{
|
||||||
|
short propId;
|
||||||
|
int propData;
|
||||||
|
propId = LittleEndian.getShort( data, pos );
|
||||||
|
propData = LittleEndian.getInt( data, pos + 2 );
|
||||||
|
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 ) );
|
||||||
|
else if ( propertyType == EscherPropertyMetaData.TYPE_RGB )
|
||||||
|
results.add( new EscherRGBProperty( propNumber, propData ) );
|
||||||
|
else if ( propertyType == EscherPropertyMetaData.TYPE_SHAPEPATH )
|
||||||
|
results.add( new EscherShapePathProperty( propNumber, propData ) );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( !isComplex )
|
||||||
|
results.add( new EscherSimpleProperty( propNumber, propData ) );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( propertyType == EscherPropertyMetaData.TYPE_ARRAY)
|
||||||
|
results.add( new EscherArrayProperty( propId, new byte[propData]) );
|
||||||
|
else
|
||||||
|
results.add( new EscherComplexProperty( propId, new byte[propData]) );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos += 6;
|
||||||
|
// bytesRemaining -= 6 + complexBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get complex data
|
||||||
|
for ( Iterator iterator = results.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherProperty p = (EscherProperty) iterator.next();
|
||||||
|
if (p instanceof EscherComplexProperty)
|
||||||
|
{
|
||||||
|
if (p instanceof EscherArrayProperty)
|
||||||
|
{
|
||||||
|
pos += ((EscherArrayProperty)p).setArrayData(data, pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte[] complexData = ((EscherComplexProperty)p).getComplexData();
|
||||||
|
System.arraycopy(data, pos, complexData, 0, complexData.length);
|
||||||
|
pos += complexData.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
51
src/java/org/apache/poi/ddf/EscherPropertyMetaData.java
Normal file
51
src/java/org/apache/poi/ddf/EscherPropertyMetaData.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class stores the type and description of an escher property.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherPropertyMetaData
|
||||||
|
{
|
||||||
|
// Escher property types.
|
||||||
|
public final static byte TYPE_UNKNOWN = (byte) 0;
|
||||||
|
public final static byte TYPE_BOOLEAN = (byte) 1;
|
||||||
|
public final static byte TYPE_RGB = (byte) 2;
|
||||||
|
public final static byte TYPE_SHAPEPATH = (byte) 3;
|
||||||
|
public final static byte TYPE_SIMPLE = (byte)4;
|
||||||
|
public final static byte TYPE_ARRAY = (byte)5;;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
private byte type;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param description The description of the escher property.
|
||||||
|
*/
|
||||||
|
public EscherPropertyMetaData( String description )
|
||||||
|
{
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param description The description of the escher property.
|
||||||
|
* @param type The type of the property.
|
||||||
|
*/
|
||||||
|
public EscherPropertyMetaData( String description, byte type )
|
||||||
|
{
|
||||||
|
this.description = description;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription()
|
||||||
|
{
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getType()
|
||||||
|
{
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
37
src/java/org/apache/poi/ddf/EscherRGBProperty.java
Normal file
37
src/java/org/apache/poi/ddf/EscherRGBProperty.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A color property.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherRGBProperty
|
||||||
|
extends EscherSimpleProperty
|
||||||
|
{
|
||||||
|
|
||||||
|
public EscherRGBProperty( short propertyNumber, int rgbColor )
|
||||||
|
{
|
||||||
|
super( propertyNumber, false, false, rgbColor );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRgbColor()
|
||||||
|
{
|
||||||
|
return propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getRed()
|
||||||
|
{
|
||||||
|
return (byte) ( propertyValue & 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getGreen()
|
||||||
|
{
|
||||||
|
return (byte) ( (propertyValue >> 8) & 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getBlue()
|
||||||
|
{
|
||||||
|
return (byte) ( (propertyValue >> 16) & 0xFF );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
273
src/java/org/apache/poi/ddf/EscherRecord.java
Normal file
273
src/java/org/apache/poi/ddf/EscherRecord.java
Normal file
@ -0,0 +1,273 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base abstract record from which all escher records are defined. Subclasses will need
|
||||||
|
* to define methods for serialization/deserialization and for determining the record size.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis
|
||||||
|
*/
|
||||||
|
abstract public class EscherRecord
|
||||||
|
{
|
||||||
|
private short options;
|
||||||
|
private short recordId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance
|
||||||
|
*/
|
||||||
|
public EscherRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegates to fillFields(byte[], int, EscherRecordFactory)
|
||||||
|
*
|
||||||
|
* @see #fillFields(byte[], int, org.apache.poi.ddf.EscherRecordFactory)
|
||||||
|
*/
|
||||||
|
protected int fillFields( byte[] data, EscherRecordFactory f )
|
||||||
|
{
|
||||||
|
return fillFields( data, 0, f );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The contract of this method is to deserialize an escher record including
|
||||||
|
* it's children.
|
||||||
|
*
|
||||||
|
* @param data The byte array containing the serialized escher
|
||||||
|
* records.
|
||||||
|
* @param offset The offset into the byte array.
|
||||||
|
* @param recordFactory A factory for creating new escher records.
|
||||||
|
* @return The number of bytes written.
|
||||||
|
*/
|
||||||
|
public abstract int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the 8 byte header information and populates the <code>options</code>
|
||||||
|
* and <code>recordId</code> records.
|
||||||
|
*
|
||||||
|
* @param data the byte array to read from
|
||||||
|
* @param offset the offset to start reading from
|
||||||
|
* @return the number of bytes remaining in this record. This
|
||||||
|
* may include the children if this is a container.
|
||||||
|
*/
|
||||||
|
protected int readHeader( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
EscherRecordHeader header = EscherRecordHeader.readHeader(data, offset);
|
||||||
|
options = header.getOptions();
|
||||||
|
recordId = header.getRecordId();
|
||||||
|
return header.getRemainingBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether this is a container record by inspecting the option
|
||||||
|
* field.
|
||||||
|
* @return true is this is a container field.
|
||||||
|
*/
|
||||||
|
public boolean isContainerRecord()
|
||||||
|
{
|
||||||
|
return (options & (short)0x000f) == (short)0x000f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The options field for this record. All records have one.
|
||||||
|
*/
|
||||||
|
public short getOptions()
|
||||||
|
{
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the options this this record. Container records should have the
|
||||||
|
* last nibble set to 0xF.
|
||||||
|
*/
|
||||||
|
public void setOptions( short options )
|
||||||
|
{
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes to a new byte array. This is done by delegating to
|
||||||
|
* serialize(int, byte[]);
|
||||||
|
*
|
||||||
|
* @return the serialized record.
|
||||||
|
* @see #serialize(int, byte[])
|
||||||
|
*/
|
||||||
|
public byte[] serialize()
|
||||||
|
{
|
||||||
|
byte[] retval = new byte[getRecordSize()];
|
||||||
|
|
||||||
|
serialize( 0, retval );
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes to an existing byte array without serialization listener.
|
||||||
|
* This is done by delegating to serialize(int, byte[], EscherSerializationListener).
|
||||||
|
*
|
||||||
|
* @param offset the offset within the data byte array.
|
||||||
|
* @param data the data array to serialize to.
|
||||||
|
* @return The number of bytes written.
|
||||||
|
*
|
||||||
|
* @see #serialize(int, byte[], org.apache.poi.ddf.EscherSerializationListener)
|
||||||
|
*/
|
||||||
|
public int serialize( int offset, byte[] data)
|
||||||
|
{
|
||||||
|
return serialize( offset, data, new NullEscherSerializationListener() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the record to an existing byte array.
|
||||||
|
*
|
||||||
|
* @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 abstract int serialize( int offset, byte[] data, EscherSerializationListener listener );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses should effeciently return the number of bytes required to
|
||||||
|
* serialize the record.
|
||||||
|
*
|
||||||
|
* @return number of bytes
|
||||||
|
*/
|
||||||
|
abstract public int getRecordSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current record id.
|
||||||
|
*
|
||||||
|
* @return The 16 bit record id.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the record id for this record.
|
||||||
|
*/
|
||||||
|
public void setRecordId( short recordId )
|
||||||
|
{
|
||||||
|
this.recordId = recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the children of this record. By default this will
|
||||||
|
* be an empty list. EscherCotainerRecord is the only record
|
||||||
|
* that may contain children.
|
||||||
|
*
|
||||||
|
* @see EscherContainerRecord
|
||||||
|
*/
|
||||||
|
public List getChildRecords() { return Collections.EMPTY_LIST; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the child records for this record. By default this will throw
|
||||||
|
* an exception as only EscherContainerRecords may have children.
|
||||||
|
*
|
||||||
|
* @param childRecords Not used in base implementation.
|
||||||
|
*/
|
||||||
|
public void setChildRecords( List childRecords ) { throw new IllegalArgumentException("This record does not support child records."); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher records may need to be clonable in the future.
|
||||||
|
*/
|
||||||
|
public Object clone()
|
||||||
|
{
|
||||||
|
throw new RuntimeException( "The class " + getClass().getName() + " needs to define a clone method" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the indexed child record.
|
||||||
|
*/
|
||||||
|
public EscherRecord getChild( int index )
|
||||||
|
{
|
||||||
|
return (EscherRecord) getChildRecords().get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The display methods allows escher variables to print the record names
|
||||||
|
* according to their hierarchy.
|
||||||
|
*
|
||||||
|
* @param w The print writer to output to.
|
||||||
|
* @param indent The current indent level.
|
||||||
|
*/
|
||||||
|
public void display(PrintWriter w, int indent)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < indent * 4; i++) w.print(' ');
|
||||||
|
w.println(getRecordName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses should return the short name for this escher record.
|
||||||
|
*/
|
||||||
|
public abstract String getRecordName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the instance part of the option record.
|
||||||
|
*
|
||||||
|
* @return The instance part of the record
|
||||||
|
*/
|
||||||
|
public short getInstance()
|
||||||
|
{
|
||||||
|
return (short) ( options >> 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class reads the standard escher header.
|
||||||
|
*/
|
||||||
|
static class EscherRecordHeader
|
||||||
|
{
|
||||||
|
private short options;
|
||||||
|
private short recordId;
|
||||||
|
private int remainingBytes;
|
||||||
|
|
||||||
|
private EscherRecordHeader()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EscherRecordHeader readHeader( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
EscherRecordHeader header = new EscherRecordHeader();
|
||||||
|
header.options = LittleEndian.getShort(data, offset);
|
||||||
|
header.recordId = LittleEndian.getShort(data, offset + 2);
|
||||||
|
header.remainingBytes = LittleEndian.getInt( data, offset + 4 );
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public short getOptions()
|
||||||
|
{
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return recordId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRemainingBytes()
|
||||||
|
{
|
||||||
|
return remainingBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "EscherRecordHeader{" +
|
||||||
|
"options=" + options +
|
||||||
|
", recordId=" + recordId +
|
||||||
|
", remainingBytes=" + remainingBytes +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
src/java/org/apache/poi/ddf/EscherRecordFactory.java
Normal file
16
src/java/org/apache/poi/ddf/EscherRecordFactory.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The escher record factory interface allows for the creation of escher
|
||||||
|
* records from a pointer into a data array.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public interface EscherRecordFactory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new escher record from the data provided. Does not attempt
|
||||||
|
* to fill the contents of the record however.
|
||||||
|
*/
|
||||||
|
EscherRecord createRecord( byte[] data, int offset );
|
||||||
|
}
|
27
src/java/org/apache/poi/ddf/EscherSerializationListener.java
Normal file
27
src/java/org/apache/poi/ddf/EscherSerializationListener.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for listening to escher serialization events.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public interface EscherSerializationListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Fired before a given escher record is serialized.
|
||||||
|
*
|
||||||
|
* @param offset The position in the data array at which the record will be serialized.
|
||||||
|
* @param recordId The id of the record about to be serialized.
|
||||||
|
*/
|
||||||
|
void beforeRecordSerialize(int offset, short recordId, EscherRecord record);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fired after a record has been serialized.
|
||||||
|
*
|
||||||
|
* @param offset The position of the end of the serialized record + 1
|
||||||
|
* @param recordId The id of the record about to be serialized
|
||||||
|
* @param size The number of bytes written for this record. If it is a container
|
||||||
|
* record then this will include the size of any included records.
|
||||||
|
*/
|
||||||
|
void afterRecordSerialize(int offset, short recordId, int size, EscherRecord record);
|
||||||
|
}
|
25
src/java/org/apache/poi/ddf/EscherShapePathProperty.java
Normal file
25
src/java/org/apache/poi/ddf/EscherShapePathProperty.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the constants for the various possible shape paths.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherShapePathProperty
|
||||||
|
extends EscherSimpleProperty
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final int LINE_OF_STRAIGHT_SEGMENTS = 0;
|
||||||
|
public static final int CLOSED_POLYGON = 1;
|
||||||
|
public static final int CURVES = 2;
|
||||||
|
public static final int CLOSED_CURVES = 3;
|
||||||
|
public static final int COMPLEX = 4;
|
||||||
|
|
||||||
|
public EscherShapePathProperty( short propertyNumber, int shapePath )
|
||||||
|
{
|
||||||
|
super( propertyNumber, false, false, shapePath );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
103
src/java/org/apache/poi/ddf/EscherSimpleProperty.java
Normal file
103
src/java/org/apache/poi/ddf/EscherSimpleProperty.java
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple property is of fixed length and as a property number in addition
|
||||||
|
* to a 32-bit value. Properties that can't be stored in only 32-bits are
|
||||||
|
* stored as EscherComplexProperty objects.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherSimpleProperty extends EscherProperty
|
||||||
|
{
|
||||||
|
protected int propertyValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id is distinct from the actual property number. The id includes the property number the blip id
|
||||||
|
* flag and an indicator whether the property is complex or not.
|
||||||
|
*/
|
||||||
|
public EscherSimpleProperty( short id, int propertyValue )
|
||||||
|
{
|
||||||
|
super( id );
|
||||||
|
this.propertyValue = propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new escher property. The three parameters are combined to form a property
|
||||||
|
* id.
|
||||||
|
*/
|
||||||
|
public EscherSimpleProperty( short propertyNumber, boolean isComplex, boolean isBlipId, int propertyValue )
|
||||||
|
{
|
||||||
|
super( propertyNumber, isComplex, isBlipId );
|
||||||
|
this.propertyValue = propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the simple part of the escher record.
|
||||||
|
*
|
||||||
|
* @return the number of bytes serialized.
|
||||||
|
*/
|
||||||
|
public int serializeSimplePart( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
LittleEndian.putShort(data, offset, getId());
|
||||||
|
LittleEndian.putInt(data, offset + 2, propertyValue);
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escher properties consist of a simple fixed length part and a complex variable length part.
|
||||||
|
* The fixed length part is serialized first.
|
||||||
|
*/
|
||||||
|
public int serializeComplexPart( byte[] data, int pos )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Return the 32 bit value of this property.
|
||||||
|
*/
|
||||||
|
public int getPropertyValue()
|
||||||
|
{
|
||||||
|
return propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if one escher property is equal to another.
|
||||||
|
*/
|
||||||
|
public boolean equals( Object o )
|
||||||
|
{
|
||||||
|
if ( this == o ) return true;
|
||||||
|
if ( !( o instanceof EscherSimpleProperty ) ) return false;
|
||||||
|
|
||||||
|
final EscherSimpleProperty escherSimpleProperty = (EscherSimpleProperty) o;
|
||||||
|
|
||||||
|
if ( propertyValue != escherSimpleProperty.propertyValue ) return false;
|
||||||
|
if ( getId() != escherSimpleProperty.getId() ) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a hashcode so that this object can be stored in collections that
|
||||||
|
* require the use of such things.
|
||||||
|
*/
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return propertyValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the string representation of this property.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "propNum: " + getPropertyNumber()
|
||||||
|
+ ", propName: " + EscherProperties.getPropertyName( getPropertyNumber() )
|
||||||
|
+ ", complex: " + isComplex()
|
||||||
|
+ ", blipId: " + isBlipId()
|
||||||
|
+ ", value: " + propertyValue + " (0x" + HexDump.toHex(propertyValue) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
201
src/java/org/apache/poi/ddf/EscherSpRecord.java
Normal file
201
src/java/org/apache/poi/ddf/EscherSpRecord.java
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Together the the EscherOptRecord this record defines some of the basic
|
||||||
|
* properties of a shape.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherSpRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF00A;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtSp";
|
||||||
|
|
||||||
|
public static final int FLAG_GROUP = 0x0001;
|
||||||
|
public static final int FLAG_CHILD = 0x0002;
|
||||||
|
public static final int FLAG_PATRIARCH = 0x0004;
|
||||||
|
public static final int FLAG_DELETED = 0x0008;
|
||||||
|
public static final int FLAG_OLESHAPE = 0x0010;
|
||||||
|
public static final int FLAG_HAVEMASTER = 0x0020;
|
||||||
|
public static final int FLAG_FLIPHORIZ = 0x0040;
|
||||||
|
public static final int FLAG_FLIPVERT = 0x0080;
|
||||||
|
public static final int FLAG_CONNECTOR = 0x0100;
|
||||||
|
public static final int FLAG_HAVEANCHOR = 0x0200;
|
||||||
|
public static final int FLAG_BACKGROUND = 0x0400;
|
||||||
|
public static final int FLAG_HASSHAPETYPE = 0x0800;
|
||||||
|
|
||||||
|
private int field_1_shapeId;
|
||||||
|
private int field_2_flags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
int size = 0;
|
||||||
|
field_1_shapeId = LittleEndian.getInt( data, pos + size ); size += 4;
|
||||||
|
field_2_flags = LittleEndian.getInt( data, pos + size ); size += 4;
|
||||||
|
// bytesRemaining -= size;
|
||||||
|
// remainingData = new byte[bytesRemaining];
|
||||||
|
// System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = 8;
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
||||||
|
LittleEndian.putInt( data, offset + 8, field_1_shapeId );
|
||||||
|
LittleEndian.putInt( data, offset + 12, field_2_flags );
|
||||||
|
// System.arraycopy( remainingData, 0, data, offset + 26, remainingData.length );
|
||||||
|
// int pos = offset + 8 + 18 + remainingData.length;
|
||||||
|
listener.afterRecordSerialize( offset + getRecordSize(), getRecordId(), getRecordSize(), this );
|
||||||
|
return 8 + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the 16 bit identifier for this record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Sp";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the string representing this shape.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" ShapeId: " + field_1_shapeId + nl +
|
||||||
|
" Flags: " + decodeFlags(field_2_flags) + " (0x" + HexDump.toHex(field_2_flags) + ")" + nl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the shape flags into a more descriptive name.
|
||||||
|
*/
|
||||||
|
private String decodeFlags( int flags )
|
||||||
|
{
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
result.append( ( flags & FLAG_GROUP ) != 0 ? "|GROUP" : "" );
|
||||||
|
result.append( ( flags & FLAG_CHILD ) != 0 ? "|CHILD" : "" );
|
||||||
|
result.append( ( flags & FLAG_PATRIARCH ) != 0 ? "|PATRIARCH" : "" );
|
||||||
|
result.append( ( flags & FLAG_DELETED ) != 0 ? "|DELETED" : "" );
|
||||||
|
result.append( ( flags & FLAG_OLESHAPE ) != 0 ? "|OLESHAPE" : "" );
|
||||||
|
result.append( ( flags & FLAG_HAVEMASTER ) != 0 ? "|HAVEMASTER" : "" );
|
||||||
|
result.append( ( flags & FLAG_FLIPHORIZ ) != 0 ? "|FLIPHORIZ" : "" );
|
||||||
|
result.append( ( flags & FLAG_FLIPVERT ) != 0 ? "|FLIPVERT" : "" );
|
||||||
|
result.append( ( flags & FLAG_CONNECTOR ) != 0 ? "|CONNECTOR" : "" );
|
||||||
|
result.append( ( flags & FLAG_HAVEANCHOR ) != 0 ? "|HAVEANCHOR" : "" );
|
||||||
|
result.append( ( flags & FLAG_BACKGROUND ) != 0 ? "|BACKGROUND" : "" );
|
||||||
|
result.append( ( flags & FLAG_HASSHAPETYPE ) != 0 ? "|HASSHAPETYPE" : "" );
|
||||||
|
|
||||||
|
result.deleteCharAt(0);
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A number that identifies this shape
|
||||||
|
*/
|
||||||
|
public int getShapeId()
|
||||||
|
{
|
||||||
|
return field_1_shapeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a number that identifies this shape.
|
||||||
|
*/
|
||||||
|
public void setShapeId( int field_1_shapeId )
|
||||||
|
{
|
||||||
|
this.field_1_shapeId = field_1_shapeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flags that apply to this shape.
|
||||||
|
*
|
||||||
|
* @see #FLAG_GROUP
|
||||||
|
* @see #FLAG_CHILD
|
||||||
|
* @see #FLAG_PATRIARCH
|
||||||
|
* @see #FLAG_DELETED
|
||||||
|
* @see #FLAG_OLESHAPE
|
||||||
|
* @see #FLAG_HAVEMASTER
|
||||||
|
* @see #FLAG_FLIPHORIZ
|
||||||
|
* @see #FLAG_FLIPVERT
|
||||||
|
* @see #FLAG_CONNECTOR
|
||||||
|
* @see #FLAG_HAVEANCHOR
|
||||||
|
* @see #FLAG_BACKGROUND
|
||||||
|
* @see #FLAG_HASSHAPETYPE
|
||||||
|
*/
|
||||||
|
public int getFlags()
|
||||||
|
{
|
||||||
|
return field_2_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The flags that apply to this shape.
|
||||||
|
*
|
||||||
|
* @see #FLAG_GROUP
|
||||||
|
* @see #FLAG_CHILD
|
||||||
|
* @see #FLAG_PATRIARCH
|
||||||
|
* @see #FLAG_DELETED
|
||||||
|
* @see #FLAG_OLESHAPE
|
||||||
|
* @see #FLAG_HAVEMASTER
|
||||||
|
* @see #FLAG_FLIPHORIZ
|
||||||
|
* @see #FLAG_FLIPVERT
|
||||||
|
* @see #FLAG_CONNECTOR
|
||||||
|
* @see #FLAG_HAVEANCHOR
|
||||||
|
* @see #FLAG_BACKGROUND
|
||||||
|
* @see #FLAG_HASSHAPETYPE
|
||||||
|
*/
|
||||||
|
public void setFlags( int field_2_flags )
|
||||||
|
{
|
||||||
|
this.field_2_flags = field_2_flags;
|
||||||
|
}
|
||||||
|
}
|
192
src/java/org/apache/poi/ddf/EscherSpgrRecord.java
Normal file
192
src/java/org/apache/poi/ddf/EscherSpgrRecord.java
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The spgr record defines information about a shape group. Groups in escher
|
||||||
|
* are simply another form of shape that you can't physically see.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherSpgrRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF009;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtSpgr";
|
||||||
|
|
||||||
|
private int field_1_rectX1;
|
||||||
|
private int field_2_rectY1;
|
||||||
|
private int field_3_rectX2;
|
||||||
|
private int field_4_rectY2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
int size = 0;
|
||||||
|
field_1_rectX1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_2_rectY1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_3_rectX2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_4_rectY2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
bytesRemaining -= size;
|
||||||
|
if (bytesRemaining != 0) throw new RecordFormatException("Expected no remaining bytes but got " + bytesRemaining);
|
||||||
|
// remainingData = new byte[bytesRemaining];
|
||||||
|
// System.arraycopy( data, pos + size, remainingData, 0, bytesRemaining );
|
||||||
|
return 8 + size + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = 16;
|
||||||
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
||||||
|
LittleEndian.putInt( data, offset + 8, field_1_rectX1 );
|
||||||
|
LittleEndian.putInt( data, offset + 12, field_2_rectY1 );
|
||||||
|
LittleEndian.putInt( data, offset + 16, field_3_rectX2 );
|
||||||
|
LittleEndian.putInt( data, offset + 20, field_4_rectY2 );
|
||||||
|
// System.arraycopy( remainingData, 0, data, offset + 26, remainingData.length );
|
||||||
|
// int pos = offset + 8 + 18 + remainingData.length;
|
||||||
|
listener.afterRecordSerialize( offset + getRecordSize(), getRecordId(), offset + getRecordSize(), this );
|
||||||
|
return 8 + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The 16 bit identifier of this shape group record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Spgr";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the string representation of this record.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
// String extraData;
|
||||||
|
// ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
// extraData = b.toString();
|
||||||
|
// }
|
||||||
|
// catch ( Exception e )
|
||||||
|
// {
|
||||||
|
// extraData = "error";
|
||||||
|
// }
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" RectX: " + field_1_rectX1 + nl +
|
||||||
|
" RectY: " + field_2_rectY1 + nl +
|
||||||
|
" RectWidth: " + field_3_rectX2 + nl +
|
||||||
|
" RectHeight: " + field_4_rectY2 + nl;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting top-left coordinate of child records.
|
||||||
|
*/
|
||||||
|
public int getRectX1()
|
||||||
|
{
|
||||||
|
return field_1_rectX1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting top-left coordinate of child records.
|
||||||
|
*/
|
||||||
|
public void setRectX1( int x1 )
|
||||||
|
{
|
||||||
|
this.field_1_rectX1 = x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting top-left coordinate of child records.
|
||||||
|
*/
|
||||||
|
public int getRectY1()
|
||||||
|
{
|
||||||
|
return field_2_rectY1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting top-left coordinate of child records.
|
||||||
|
*/
|
||||||
|
public void setRectY1( int y1 )
|
||||||
|
{
|
||||||
|
this.field_2_rectY1 = y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting bottom-right coordinate of child records.
|
||||||
|
*/
|
||||||
|
public int getRectX2()
|
||||||
|
{
|
||||||
|
return field_3_rectX2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting bottom-right coordinate of child records.
|
||||||
|
*/
|
||||||
|
public void setRectX2( int x2 )
|
||||||
|
{
|
||||||
|
this.field_3_rectX2 = x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting bottom-right coordinate of child records.
|
||||||
|
*/
|
||||||
|
public int getRectY2()
|
||||||
|
{
|
||||||
|
return field_4_rectY2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The starting bottom-right coordinate of child records.
|
||||||
|
*/
|
||||||
|
public void setRectY2( int field_4_rectY2 )
|
||||||
|
{
|
||||||
|
this.field_4_rectY2 = field_4_rectY2;
|
||||||
|
}
|
||||||
|
}
|
171
src/java/org/apache/poi/ddf/EscherSplitMenuColorsRecord.java
Normal file
171
src/java/org/apache/poi/ddf/EscherSplitMenuColorsRecord.java
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of the most recently used colours for the drawings contained in
|
||||||
|
* this document.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherSplitMenuColorsRecord
|
||||||
|
extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short) 0xF11E;
|
||||||
|
public static final String RECORD_DESCRIPTION = "MsofbtSplitMenuColors";
|
||||||
|
|
||||||
|
private int field_1_color1;
|
||||||
|
private int field_2_color2;
|
||||||
|
private int field_3_color3;
|
||||||
|
private int field_4_color4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
int pos = offset + 8;
|
||||||
|
int size = 0;
|
||||||
|
field_1_color1 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_2_color2 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_3_color3 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
field_4_color4 = LittleEndian.getInt( data, pos + size );size+=4;
|
||||||
|
bytesRemaining -= size;
|
||||||
|
if (bytesRemaining != 0)
|
||||||
|
throw new RecordFormatException("Expecting no remaining data but got " + bytesRemaining + " byte(s).");
|
||||||
|
return 8 + size + bytesRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 )
|
||||||
|
{
|
||||||
|
// int field_2_numIdClusters = field_5_fileIdClusters.length + 1;
|
||||||
|
listener.beforeRecordSerialize( offset, getRecordId(), this );
|
||||||
|
|
||||||
|
int pos = offset;
|
||||||
|
LittleEndian.putShort( data, pos, getOptions() ); pos += 2;
|
||||||
|
LittleEndian.putShort( data, pos, getRecordId() ); pos += 2;
|
||||||
|
int remainingBytes = getRecordSize() - 8;
|
||||||
|
|
||||||
|
LittleEndian.putInt( data, pos, remainingBytes ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_1_color1 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_2_color2 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_3_color3 ); pos += 4;
|
||||||
|
LittleEndian.putInt( data, pos, field_4_color4 ); pos += 4;
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + 4 * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the 16 bit identifer for this record.
|
||||||
|
*/
|
||||||
|
public short getRecordId()
|
||||||
|
{
|
||||||
|
return RECORD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "SplitMenuColors";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a string representation of this record.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
// String extraData;
|
||||||
|
// ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// HexDump.dump(this.remainingData, 0, b, 0);
|
||||||
|
// extraData = b.toString();
|
||||||
|
// }
|
||||||
|
// catch ( Exception e )
|
||||||
|
// {
|
||||||
|
// extraData = "error";
|
||||||
|
// }
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" RecordId: 0x" + HexDump.toHex(RECORD_ID) + nl +
|
||||||
|
" Options: 0x" + HexDump.toHex(getOptions()) + nl +
|
||||||
|
" Color1: 0x" + HexDump.toHex(field_1_color1) + nl +
|
||||||
|
" Color2: 0x" + HexDump.toHex(field_2_color2) + nl +
|
||||||
|
" Color3: 0x" + HexDump.toHex(field_3_color3) + nl +
|
||||||
|
" Color4: 0x" + HexDump.toHex(field_4_color4) + nl +
|
||||||
|
"";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor1()
|
||||||
|
{
|
||||||
|
return field_1_color1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor1( int field_1_color1 )
|
||||||
|
{
|
||||||
|
this.field_1_color1 = field_1_color1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor2()
|
||||||
|
{
|
||||||
|
return field_2_color2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor2( int field_2_color2 )
|
||||||
|
{
|
||||||
|
this.field_2_color2 = field_2_color2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor3()
|
||||||
|
{
|
||||||
|
return field_3_color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor3( int field_3_color3 )
|
||||||
|
{
|
||||||
|
this.field_3_color3 = field_3_color3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor4()
|
||||||
|
{
|
||||||
|
return field_4_color4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor4( int field_4_color4 )
|
||||||
|
{
|
||||||
|
this.field_4_color4 = field_4_color4;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
215
src/java/org/apache/poi/ddf/EscherTextboxRecord.java
Normal file
215
src/java/org/apache/poi/ddf/EscherTextboxRecord.java
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supports text boxes
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherTextboxRecord extends EscherRecord
|
||||||
|
{
|
||||||
|
public static final short RECORD_ID = (short)0xF00D;
|
||||||
|
public static final String RECORD_DESCRIPTION = "msofbtClientTextbox";
|
||||||
|
|
||||||
|
private static final byte[] NO_BYTES = new byte[0];
|
||||||
|
|
||||||
|
/** The data for this record not including the the 8 byte header */
|
||||||
|
private byte[] thedata = NO_BYTES;
|
||||||
|
|
||||||
|
public EscherTextboxRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
if ( isContainerRecord() )
|
||||||
|
{
|
||||||
|
int bytesWritten = 0;
|
||||||
|
thedata = new byte[0];
|
||||||
|
offset += 8;
|
||||||
|
bytesWritten += 8;
|
||||||
|
while ( bytesRemaining > 0 )
|
||||||
|
{
|
||||||
|
EscherRecord child = recordFactory.createRecord( data, offset );
|
||||||
|
int childBytesWritten = child.fillFields( data, offset, recordFactory );
|
||||||
|
bytesWritten += childBytesWritten;
|
||||||
|
offset += childBytesWritten;
|
||||||
|
bytesRemaining -= childBytesWritten;
|
||||||
|
getChildRecords().add( child );
|
||||||
|
}
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thedata = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, offset + 8, thedata, 0, bytesRemaining );
|
||||||
|
return bytesRemaining + 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes this record and any contained records to the supplied byte
|
||||||
|
* array.
|
||||||
|
*
|
||||||
|
* @return the number of bytes written.
|
||||||
|
*/
|
||||||
|
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 = thedata.length;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
remainingBytes += r.getRecordSize();
|
||||||
|
}
|
||||||
|
LittleEndian.putInt(data, offset+4, remainingBytes);
|
||||||
|
System.arraycopy(thedata, 0, data, offset+8, thedata.length);
|
||||||
|
int pos = offset+8+thedata.length;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
pos += r.serialize(pos, data, listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
|
||||||
|
int size = pos - offset;
|
||||||
|
if (size != getRecordSize())
|
||||||
|
throw new RecordFormatException(size + " bytes written but getRecordSize() reports " + getRecordSize());
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns any extra data associated with this record. In practice excel
|
||||||
|
* does not seem to put anything here.
|
||||||
|
*/
|
||||||
|
public byte[] getData()
|
||||||
|
{
|
||||||
|
return thedata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + thedata.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone()
|
||||||
|
{
|
||||||
|
// shallow clone
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "ClientTextbox";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
String theDumpHex = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (thedata.length != 0)
|
||||||
|
{
|
||||||
|
theDumpHex = " Extra Data:" + nl;
|
||||||
|
theDumpHex += HexDump.dump(thedata, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
theDumpHex = "Error!!";
|
||||||
|
}
|
||||||
|
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" isContainer: " + isContainerRecord() + nl +
|
||||||
|
" options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||||
|
" numchildren: " + getChildRecords().size() + nl +
|
||||||
|
theDumpHex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignores all serialization events.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class NullEscherSerializationListener implements EscherSerializationListener
|
||||||
|
{
|
||||||
|
public void beforeRecordSerialize( int offset, short recordId, EscherRecord record )
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterRecordSerialize( int offset, short recordId, int size, EscherRecord record )
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
87
src/java/org/apache/poi/ddf/TestEscherBSERecord.java
Normal file
87
src/java/org/apache/poi/ddf/TestEscherBSERecord.java
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class TestEscherBSERecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String data = "01 00 00 00 24 00 00 00 05 05 01 02 03 04 " +
|
||||||
|
" 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00 01 00 00 00 " +
|
||||||
|
" 00 00 02 00 00 00 03 00 00 00 04 05 06 07";
|
||||||
|
EscherBSERecord r = new EscherBSERecord();
|
||||||
|
int bytesWritten = r.fillFields( HexRead.readFromString( data ), 0, new DefaultEscherRecordFactory() );
|
||||||
|
assertEquals( 44, bytesWritten );
|
||||||
|
assertEquals( (short) 0x0001, r.getOptions() );
|
||||||
|
assertEquals( EscherBSERecord.BT_JPEG, r.getBlipTypeWin32() );
|
||||||
|
assertEquals( EscherBSERecord.BT_JPEG, r.getBlipTypeMacOS() );
|
||||||
|
assertEquals( "[01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 00, ]", HexDump.toHex( r.getUid() ) );
|
||||||
|
assertEquals( (short) 1, r.getTag() );
|
||||||
|
assertEquals( 2, r.getRef() );
|
||||||
|
assertEquals( 3, r.getOffset() );
|
||||||
|
assertEquals( (byte) 4, r.getUsage() );
|
||||||
|
assertEquals( (byte) 5, r.getName() );
|
||||||
|
assertEquals( (byte) 6, r.getUnused2() );
|
||||||
|
assertEquals( (byte) 7, r.getUnused3() );
|
||||||
|
assertEquals( 0, r.getRemainingData().length );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherBSERecord r = createRecord();
|
||||||
|
|
||||||
|
byte[] data = new byte[8 + 36];
|
||||||
|
int bytesWritten = r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 44, bytesWritten );
|
||||||
|
assertEquals( "[01, 00, 00, 00, 24, 00, 00, 00, 05, 05, 01, 02, 03, 04, " +
|
||||||
|
"05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 00, 01, 00, 00, 00, " +
|
||||||
|
"00, 00, 02, 00, 00, 00, 03, 00, 00, 00, 04, 05, 06, 07, ]",
|
||||||
|
HexDump.toHex( data ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherBSERecord createRecord() throws IOException
|
||||||
|
{
|
||||||
|
EscherBSERecord r = new EscherBSERecord();
|
||||||
|
r.setOptions( (short) 0x0001 );
|
||||||
|
r.setBlipTypeWin32( EscherBSERecord.BT_JPEG );
|
||||||
|
r.setBlipTypeMacOS( EscherBSERecord.BT_JPEG );
|
||||||
|
r.setUid( HexRead.readFromString( "01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 00" ) );
|
||||||
|
r.setTag( (short) 1 );
|
||||||
|
r.setRef( 2 );
|
||||||
|
r.setOffset( 3 );
|
||||||
|
r.setUsage( (byte) 4 );
|
||||||
|
r.setName( (byte) 5 );
|
||||||
|
r.setUnused2( (byte) 6 );
|
||||||
|
r.setUnused3( (byte) 7 );
|
||||||
|
r.setRemainingData( new byte[0] );
|
||||||
|
return r;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
EscherBSERecord record = createRecord();
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
assertEquals( "org.apache.poi.ddf.EscherBSERecord:" + nl +
|
||||||
|
" RecordId: 0xF007" + nl +
|
||||||
|
" Options: 0x0001" + nl +
|
||||||
|
" BlipTypeWin32: 5" + nl +
|
||||||
|
" BlipTypeMacOS: 5" + nl +
|
||||||
|
" SUID: [01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 00, ]" + nl +
|
||||||
|
" Tag: 1" + nl +
|
||||||
|
" Size: 0" + nl +
|
||||||
|
" Ref: 2" + nl +
|
||||||
|
" Offset: 3" + nl +
|
||||||
|
" Usage: 4" + nl +
|
||||||
|
" Name: 5" + nl +
|
||||||
|
" Unused2: 6" + nl +
|
||||||
|
" Unused3: 7" + nl +
|
||||||
|
" Extra Data:" + nl, record.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
110
src/java/org/apache/poi/ddf/TestEscherBlipRecord.java
Normal file
110
src/java/org/apache/poi/ddf/TestEscherBlipRecord.java
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
public class TestEscherBlipRecord extends TestCase
|
||||||
|
{
|
||||||
|
private String dataStr;
|
||||||
|
private byte[] data;
|
||||||
|
|
||||||
|
protected void setUp() throws Exception
|
||||||
|
{
|
||||||
|
dataStr = "2C 15 18 F0 34 00 00 00 01 01 01 01 01 01 01 01 " +
|
||||||
|
"01 01 01 01 01 01 01 01 06 00 00 00 03 00 00 00 " +
|
||||||
|
"01 00 00 00 04 00 00 00 02 00 00 00 0A 00 00 00 " +
|
||||||
|
"0B 00 00 00 05 00 00 00 08 07 01 02";
|
||||||
|
data = HexRead.readFromString(dataStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherBlipRecord r = new EscherBlipRecord();
|
||||||
|
r.setBoundaryLeft(1);
|
||||||
|
r.setBoundaryHeight(2);
|
||||||
|
r.setBoundaryTop(3);
|
||||||
|
r.setBoundaryWidth(4);
|
||||||
|
r.setCacheOfSavedSize(5);
|
||||||
|
r.setCacheOfSize(6);
|
||||||
|
r.setFilter((byte)7);
|
||||||
|
r.setCompressionFlag((byte)8);
|
||||||
|
r.setSecondaryUID(new byte[] { (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01,
|
||||||
|
(byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01,
|
||||||
|
(byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01,
|
||||||
|
(byte)0x01, (byte)0x01, (byte)0x01, (byte)0x01, });
|
||||||
|
r.setWidth(10);
|
||||||
|
r.setHeight(11);
|
||||||
|
r.setRecordId(EscherBlipRecord.RECORD_ID_START);
|
||||||
|
r.setOptions((short)5420);
|
||||||
|
r.setData(new byte[] { (byte)0x01, (byte)0x02 } );
|
||||||
|
|
||||||
|
byte[] buf = new byte[r.getRecordSize()];
|
||||||
|
r.serialize(0, buf, new NullEscherSerializationListener() );
|
||||||
|
|
||||||
|
assertEquals("[2C, 15, 18, F0, 26, 00, 00, 00, " +
|
||||||
|
"01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, " +
|
||||||
|
"06, 00, 00, 00, " + // field_2_cacheOfSize
|
||||||
|
"03, 00, 00, 00, " + // field_3_boundaryTop
|
||||||
|
"01, 00, 00, 00, " + // field_4_boundaryLeft
|
||||||
|
"04, 00, 00, 00, " + // field_5_boundaryWidth
|
||||||
|
"02, 00, 00, 00, " + // field_6_boundaryHeight
|
||||||
|
"0A, 00, 00, 00, " + // field_7_x
|
||||||
|
"0B, 00, 00, 00, " + // field_8_y
|
||||||
|
"05, 00, 00, 00, " + // field_9_cacheOfSavedSize
|
||||||
|
"08, " + // field_10_compressionFlag
|
||||||
|
"07, " + // field_11_filter
|
||||||
|
"01, 02, ]", // field_12_data
|
||||||
|
HexDump.toHex(buf));
|
||||||
|
assertEquals(60, r.getRecordSize() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
EscherBlipRecord r = new EscherBlipRecord();
|
||||||
|
r.fillFields( data, 0, new DefaultEscherRecordFactory());
|
||||||
|
|
||||||
|
assertEquals( EscherBlipRecord.RECORD_ID_START, r.getRecordId() );
|
||||||
|
assertEquals( 1, r.getBoundaryLeft() );
|
||||||
|
assertEquals( 2, r.getBoundaryHeight() );
|
||||||
|
assertEquals( 3, r.getBoundaryTop() );
|
||||||
|
assertEquals( 4, r.getBoundaryWidth() );
|
||||||
|
assertEquals( 5, r.getCacheOfSavedSize() );
|
||||||
|
assertEquals( 6, r.getCacheOfSize() );
|
||||||
|
assertEquals( 7, r.getFilter() );
|
||||||
|
assertEquals( 8, r.getCompressionFlag() );
|
||||||
|
assertEquals( "[01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, 01, ]", HexDump.toHex(r.getSecondaryUID() ) );
|
||||||
|
assertEquals( 10, r.getWidth() );
|
||||||
|
assertEquals( 11, r.getHeight() );
|
||||||
|
assertEquals( (short)5420, r.getOptions() );
|
||||||
|
assertEquals( "[01, 02, ]", HexDump.toHex( r.getData() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
EscherBlipRecord r = new EscherBlipRecord();
|
||||||
|
r.fillFields( data, 0, new DefaultEscherRecordFactory() );
|
||||||
|
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
assertEquals( "org.apache.poi.ddf.EscherBlipRecord:" + 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 +
|
||||||
|
" CacheOfSize: 6" + nl +
|
||||||
|
" BoundaryTop: 3" + nl +
|
||||||
|
" BoundaryLeft: 1" + nl +
|
||||||
|
" BoundaryWidth: 4" + nl +
|
||||||
|
" BoundaryHeight: 2" + nl +
|
||||||
|
" X: 10" + nl +
|
||||||
|
" Y: 11" + nl +
|
||||||
|
" CacheOfSavedSize: 5" + nl +
|
||||||
|
" CompressionFlag: 8" + nl +
|
||||||
|
" Filter: 7" + nl +
|
||||||
|
" Data:" + nl +
|
||||||
|
"00000000 01 02 .." + nl
|
||||||
|
, r.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
src/java/org/apache/poi/ddf/TestEscherBoolProperty.java
Normal file
13
src/java/org/apache/poi/ddf/TestEscherBoolProperty.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
73
src/java/org/apache/poi/ddf/TestEscherChildAnchorRecord.java
Normal file
73
src/java/org/apache/poi/ddf/TestEscherChildAnchorRecord.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
public class TestEscherChildAnchorRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherChildAnchorRecord r = createRecord();
|
||||||
|
|
||||||
|
byte[] data = new byte[8 + 16];
|
||||||
|
int bytesWritten = r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 24, bytesWritten );
|
||||||
|
assertEquals( "[01, 00, " +
|
||||||
|
"0F, F0, " +
|
||||||
|
"10, 00, 00, 00, " +
|
||||||
|
"01, 00, 00, 00, " +
|
||||||
|
"02, 00, 00, 00, " +
|
||||||
|
"03, 00, 00, 00, " +
|
||||||
|
"04, 00, 00, 00, ]", HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String hexData = "01 00 " +
|
||||||
|
"0F F0 " +
|
||||||
|
"10 00 00 00 " +
|
||||||
|
"01 00 00 00 " +
|
||||||
|
"02 00 00 00 " +
|
||||||
|
"03 00 00 00 " +
|
||||||
|
"04 00 00 00 ";
|
||||||
|
|
||||||
|
byte[] data = HexRead.readFromString( hexData );
|
||||||
|
EscherChildAnchorRecord r = new EscherChildAnchorRecord();
|
||||||
|
int bytesWritten = r.fillFields( data, new DefaultEscherRecordFactory() );
|
||||||
|
|
||||||
|
assertEquals( 24, bytesWritten );
|
||||||
|
assertEquals( 1, r.getDx1() );
|
||||||
|
assertEquals( 2, r.getDy1() );
|
||||||
|
assertEquals( 3, r.getDx2() );
|
||||||
|
assertEquals( 4, r.getDy2() );
|
||||||
|
assertEquals( (short) 0x0001, r.getOptions() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
String expected = "org.apache.poi.ddf.EscherChildAnchorRecord:" + nl +
|
||||||
|
" RecordId: 0xF00F" + nl +
|
||||||
|
" Options: 0x0001" + nl +
|
||||||
|
" X1: 1" + nl +
|
||||||
|
" Y1: 2" + nl +
|
||||||
|
" X2: 3" + nl +
|
||||||
|
" Y2: 4" + nl;
|
||||||
|
assertEquals( expected, createRecord().toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherChildAnchorRecord createRecord()
|
||||||
|
{
|
||||||
|
EscherChildAnchorRecord r = new EscherChildAnchorRecord();
|
||||||
|
r.setRecordId( EscherChildAnchorRecord.RECORD_ID );
|
||||||
|
r.setOptions( (short) 0x0001 );
|
||||||
|
r.setDx1( 1 );
|
||||||
|
r.setDy1( 2 );
|
||||||
|
r.setDx2( 3 );
|
||||||
|
r.setDy2( 4 );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
public class TestEscherClientAnchorRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherClientAnchorRecord r = createRecord();
|
||||||
|
|
||||||
|
byte[] data = new byte[8 + 18 + 2];
|
||||||
|
int bytesWritten = r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 28, bytesWritten );
|
||||||
|
assertEquals( "[01, 00, " +
|
||||||
|
"10, F0, " +
|
||||||
|
"14, 00, 00, 00, " +
|
||||||
|
"4D, 00, 37, 00, 21, 00, 58, 00, " +
|
||||||
|
"0B, 00, 2C, 00, 16, 00, 63, 00, " +
|
||||||
|
"42, 00, " +
|
||||||
|
"FF, DD, ]", HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String hexData = "01 00 " +
|
||||||
|
"10 F0 " +
|
||||||
|
"14 00 00 00 " +
|
||||||
|
"4D 00 37 00 21 00 58 00 " +
|
||||||
|
"0B 00 2C 00 16 00 63 00 " +
|
||||||
|
"42 00 " +
|
||||||
|
"FF DD";
|
||||||
|
byte[] data = HexRead.readFromString( hexData );
|
||||||
|
EscherClientAnchorRecord r = new EscherClientAnchorRecord();
|
||||||
|
int bytesWritten = r.fillFields( data, new DefaultEscherRecordFactory() );
|
||||||
|
|
||||||
|
assertEquals( 28, bytesWritten );
|
||||||
|
assertEquals( (short) 55, r.getCol1() );
|
||||||
|
assertEquals( (short) 44, r.getCol2() );
|
||||||
|
assertEquals( (short) 33, r.getDx1() );
|
||||||
|
assertEquals( (short) 22, r.getDx2() );
|
||||||
|
assertEquals( (short) 11, r.getDy1() );
|
||||||
|
assertEquals( (short) 66, r.getDy2() );
|
||||||
|
assertEquals( (short) 77, r.getFlag() );
|
||||||
|
assertEquals( (short) 88, r.getRow1() );
|
||||||
|
assertEquals( (short) 99, r.getRow2() );
|
||||||
|
assertEquals( (short) 0x0001, r.getOptions() );
|
||||||
|
assertEquals( (byte) 0xFF, r.getRemainingData()[0] );
|
||||||
|
assertEquals( (byte) 0xDD, r.getRemainingData()[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String expected = "org.apache.poi.ddf.EscherClientAnchorRecord:" + nl +
|
||||||
|
" RecordId: 0xF010" + nl +
|
||||||
|
" Options: 0x0001" + nl +
|
||||||
|
" Flag: 77" + nl +
|
||||||
|
" Col1: 55" + nl +
|
||||||
|
" DX1: 33" + nl +
|
||||||
|
" Row1: 88" + nl +
|
||||||
|
" DY1: 11" + nl +
|
||||||
|
" Col2: 44" + nl +
|
||||||
|
" DX2: 22" + nl +
|
||||||
|
" Row2: 99" + nl +
|
||||||
|
" DY2: 66" + nl +
|
||||||
|
" Extra Data:" + nl +
|
||||||
|
"00000000 FF DD .." + nl;
|
||||||
|
assertEquals( expected, createRecord().toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherClientAnchorRecord createRecord()
|
||||||
|
{
|
||||||
|
EscherClientAnchorRecord r = new EscherClientAnchorRecord();
|
||||||
|
r.setCol1( (short) 55 );
|
||||||
|
r.setCol2( (short) 44 );
|
||||||
|
r.setDx1( (short) 33 );
|
||||||
|
r.setDx2( (short) 22 );
|
||||||
|
r.setDy1( (short) 11 );
|
||||||
|
r.setDy2( (short) 66 );
|
||||||
|
r.setFlag( (short) 77 );
|
||||||
|
r.setRow1( (short) 88 );
|
||||||
|
r.setRow2( (short) 99 );
|
||||||
|
r.setOptions( (short) 0x0001 );
|
||||||
|
r.setRemainingData( new byte[]{(byte) 0xFF, (byte) 0xDD} );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
57
src/java/org/apache/poi/ddf/TestEscherClientDataRecord.java
Normal file
57
src/java/org/apache/poi/ddf/TestEscherClientDataRecord.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
public class TestEscherClientDataRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherClientDataRecord r = createRecord();
|
||||||
|
|
||||||
|
byte[] data = new byte[8];
|
||||||
|
int bytesWritten = r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 8, bytesWritten );
|
||||||
|
assertEquals( "[02, 00, " +
|
||||||
|
"11, F0, " +
|
||||||
|
"00, 00, 00, 00, ]",
|
||||||
|
HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String hexData = "02 00 " +
|
||||||
|
"11 F0 " +
|
||||||
|
"00 00 00 00 ";
|
||||||
|
byte[] data = HexRead.readFromString( hexData );
|
||||||
|
EscherClientDataRecord r = new EscherClientDataRecord();
|
||||||
|
int bytesWritten = r.fillFields( data, new DefaultEscherRecordFactory() );
|
||||||
|
|
||||||
|
assertEquals( 8, bytesWritten );
|
||||||
|
assertEquals( (short)0xF011, r.getRecordId() );
|
||||||
|
assertEquals( "[]", HexDump.toHex(r.getRemainingData()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String expected = "org.apache.poi.ddf.EscherClientDataRecord:" + nl +
|
||||||
|
" RecordId: 0xF011" + nl +
|
||||||
|
" Options: 0x0002" + nl +
|
||||||
|
" Extra Data:" + nl +
|
||||||
|
"" ;
|
||||||
|
assertEquals( expected, createRecord().toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherClientDataRecord createRecord()
|
||||||
|
{
|
||||||
|
EscherClientDataRecord r = new EscherClientDataRecord();
|
||||||
|
r.setOptions( (short) 0x0002 );
|
||||||
|
r.setRecordId( EscherClientDataRecord.RECORD_ID );
|
||||||
|
r.setRemainingData( new byte[] {} );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
98
src/java/org/apache/poi/ddf/TestEscherContainerRecord.java
Normal file
98
src/java/org/apache/poi/ddf/TestEscherContainerRecord.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
public class TestEscherContainerRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
EscherRecordFactory f = new DefaultEscherRecordFactory();
|
||||||
|
byte[] data = HexRead.readFromString( "0F 02 11 F1 00 00 00 00" );
|
||||||
|
EscherRecord r = f.createRecord( data, 0 );
|
||||||
|
r.fillFields( data, 0, f );
|
||||||
|
assertTrue( r instanceof EscherContainerRecord );
|
||||||
|
assertEquals( (short) 0x020F, r.getOptions() );
|
||||||
|
assertEquals( (short) 0xF111, r.getRecordId() );
|
||||||
|
|
||||||
|
data = HexRead.readFromString( "0F 02 11 F1 08 00 00 00" +
|
||||||
|
" 02 00 22 F2 00 00 00 00" );
|
||||||
|
r = f.createRecord( data, 0 );
|
||||||
|
r.fillFields( data, 0, f );
|
||||||
|
EscherRecord c = r.getChild( 0 );
|
||||||
|
assertFalse( c instanceof EscherContainerRecord );
|
||||||
|
assertEquals( (short) 0x0002, c.getOptions() );
|
||||||
|
assertEquals( (short) 0xF222, c.getRecordId() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
UnknownEscherRecord r = new UnknownEscherRecord();
|
||||||
|
r.setOptions( (short) 0x123F );
|
||||||
|
r.setRecordId( (short) 0xF112 );
|
||||||
|
byte[] data = new byte[8];
|
||||||
|
r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
|
||||||
|
assertEquals( "[3F, 12, 12, F1, 00, 00, 00, 00, ]", HexDump.toHex( data ) );
|
||||||
|
|
||||||
|
EscherRecord childRecord = new UnknownEscherRecord();
|
||||||
|
childRecord.setOptions( (short) 0x9999 );
|
||||||
|
childRecord.setRecordId( (short) 0xFF01 );
|
||||||
|
r.addChildRecord( childRecord );
|
||||||
|
data = new byte[16];
|
||||||
|
r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
|
||||||
|
assertEquals( "[3F, 12, 12, F1, 08, 00, 00, 00, 99, 99, 01, FF, 00, 00, 00, 00, ]", HexDump.toHex( data ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
EscherContainerRecord r = new EscherContainerRecord();
|
||||||
|
r.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
|
r.setOptions( (short) 0x000F );
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
assertEquals( "org.apache.poi.ddf.EscherContainerRecord (SpContainer):" + nl +
|
||||||
|
" isContainer: true" + nl +
|
||||||
|
" options: 0x000F" + nl +
|
||||||
|
" recordId: 0xF004" + nl +
|
||||||
|
" numchildren: 0" + nl
|
||||||
|
, r.toString() );
|
||||||
|
|
||||||
|
EscherOptRecord r2 = new EscherOptRecord();
|
||||||
|
r2.setOptions( (short) 0x9876 );
|
||||||
|
r2.setRecordId( EscherOptRecord.RECORD_ID );
|
||||||
|
|
||||||
|
r.addChildRecord( r2 );
|
||||||
|
String expected = "org.apache.poi.ddf.EscherContainerRecord (SpContainer):" + nl +
|
||||||
|
" isContainer: true" + nl +
|
||||||
|
" options: 0x000F" + nl +
|
||||||
|
" recordId: 0xF004" + nl +
|
||||||
|
" numchildren: 1" + nl +
|
||||||
|
" children: " + nl +
|
||||||
|
"org.apache.poi.ddf.EscherOptRecord:" + nl +
|
||||||
|
" isContainer: false" + nl +
|
||||||
|
" options: 0x0003" + nl +
|
||||||
|
" recordId: 0xF00B" + nl +
|
||||||
|
" numchildren: 0" + nl +
|
||||||
|
" properties:" + nl;
|
||||||
|
assertEquals( expected, r.toString() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetRecordSize() throws Exception
|
||||||
|
{
|
||||||
|
EscherContainerRecord r = new EscherContainerRecord();
|
||||||
|
r.addChildRecord(new EscherRecord()
|
||||||
|
{
|
||||||
|
public int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory ) { return 0; }
|
||||||
|
public int serialize( int offset, byte[] data, EscherSerializationListener listener ) { return 0; }
|
||||||
|
public int getRecordSize() { return 10; }
|
||||||
|
public String getRecordName() { return ""; }
|
||||||
|
} );
|
||||||
|
|
||||||
|
assertEquals(18, r.getRecordSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
62
src/java/org/apache/poi/ddf/TestEscherDgRecord.java
Normal file
62
src/java/org/apache/poi/ddf/TestEscherDgRecord.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
public class TestEscherDgRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherDgRecord r = createRecord();
|
||||||
|
|
||||||
|
byte[] data = new byte[16];
|
||||||
|
int bytesWritten = r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 16, bytesWritten );
|
||||||
|
assertEquals( "[10, 00, " +
|
||||||
|
"08, F0, " +
|
||||||
|
"08, 00, 00, 00, " +
|
||||||
|
"02, 00, 00, 00, " + // num shapes in drawing
|
||||||
|
"01, 04, 00, 00, ]", // The last MSOSPID given to an SP in this DG
|
||||||
|
HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String hexData = "10 00 " +
|
||||||
|
"08 F0 " +
|
||||||
|
"08 00 00 00 " +
|
||||||
|
"02 00 00 00 " +
|
||||||
|
"01 04 00 00 ";
|
||||||
|
byte[] data = HexRead.readFromString( hexData );
|
||||||
|
EscherDgRecord r = new EscherDgRecord();
|
||||||
|
int bytesWritten = r.fillFields( data, new DefaultEscherRecordFactory() );
|
||||||
|
|
||||||
|
assertEquals( 16, bytesWritten );
|
||||||
|
assertEquals( 2, r.getNumShapes() );
|
||||||
|
assertEquals( 1025, r.getLastMSOSPID() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String expected = "org.apache.poi.ddf.EscherDgRecord:" + nl +
|
||||||
|
" RecordId: 0xF008" + nl +
|
||||||
|
" Options: 0x0010" + nl +
|
||||||
|
" NumShapes: 2" + nl +
|
||||||
|
" LastMSOSPID: 1025" + nl;
|
||||||
|
assertEquals( expected, createRecord().toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherDgRecord createRecord()
|
||||||
|
{
|
||||||
|
EscherDgRecord r = new EscherDgRecord();
|
||||||
|
r.setOptions( (short) 0x0010 );
|
||||||
|
r.setRecordId( EscherDgRecord.RECORD_ID );
|
||||||
|
r.setNumShapes(2);
|
||||||
|
r.setLastMSOSPID(1025);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
89
src/java/org/apache/poi/ddf/TestEscherDggRecord.java
Normal file
89
src/java/org/apache/poi/ddf/TestEscherDggRecord.java
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
public class TestEscherDggRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherDggRecord r = createRecord();
|
||||||
|
|
||||||
|
byte[] data = new byte[32];
|
||||||
|
int bytesWritten = r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 32, bytesWritten );
|
||||||
|
assertEquals( "[00, 00, " +
|
||||||
|
"06, F0, " +
|
||||||
|
"18, 00, 00, 00, " +
|
||||||
|
"02, 04, 00, 00, " +
|
||||||
|
"02, 00, 00, 00, " +
|
||||||
|
"02, 00, 00, 00, " +
|
||||||
|
"01, 00, 00, 00, " +
|
||||||
|
"01, 00, 00, 00, 02, 00, 00, 00, ]",
|
||||||
|
HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String hexData = "00 00 " +
|
||||||
|
"06 F0 " +
|
||||||
|
"18 00 00 00 " +
|
||||||
|
"02 04 00 00 " +
|
||||||
|
"02 00 00 00 " +
|
||||||
|
"02 00 00 00 " +
|
||||||
|
"01 00 00 00 " +
|
||||||
|
"01 00 00 00 02 00 00 00";
|
||||||
|
byte[] data = HexRead.readFromString( hexData );
|
||||||
|
EscherDggRecord r = new EscherDggRecord();
|
||||||
|
int bytesWritten = r.fillFields( data, new DefaultEscherRecordFactory() );
|
||||||
|
|
||||||
|
assertEquals( 32, bytesWritten );
|
||||||
|
assertEquals( 0x402, r.getShapeIdMax() );
|
||||||
|
assertEquals( 0x02, r.getNumIdClusters() );
|
||||||
|
assertEquals( 0x02, r.getNumShapesSaved() );
|
||||||
|
assertEquals( 0x01, r.getDrawingsSaved() );
|
||||||
|
assertEquals( 1, r.getFileIdClusters().length );
|
||||||
|
assertEquals( 0x01, r.getFileIdClusters()[0].getDrawingGroupId());
|
||||||
|
assertEquals( 0x02, r.getFileIdClusters()[0].getNumShapeIdsUsed());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String expected = "org.apache.poi.ddf.EscherDggRecord:" + nl +
|
||||||
|
" RecordId: 0xF006" + nl +
|
||||||
|
" Options: 0x0000" + nl +
|
||||||
|
" ShapeIdMax: 1026" + nl +
|
||||||
|
" NumIdClusters: 2" + nl +
|
||||||
|
" NumShapesSaved: 2" + nl +
|
||||||
|
" DrawingsSaved: 1" + nl +
|
||||||
|
" DrawingGroupId1: 1" + nl +
|
||||||
|
" NumShapeIdsUsed1: 2" + nl;
|
||||||
|
assertEquals( expected, createRecord().toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherDggRecord createRecord()
|
||||||
|
{
|
||||||
|
EscherDggRecord r = new EscherDggRecord();
|
||||||
|
r.setOptions( (short) 0x0000 );
|
||||||
|
r.setRecordId( EscherDggRecord.RECORD_ID );
|
||||||
|
r.setShapeIdMax( 0x402 );
|
||||||
|
r.setNumShapesSaved( 0x02 );
|
||||||
|
r.setDrawingsSaved( 0x01 );
|
||||||
|
r.setFileIdClusters(new EscherDggRecord.FileIdCluster[] {
|
||||||
|
new EscherDggRecord.FileIdCluster( 1, 2 )
|
||||||
|
});
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetRecordSize() throws Exception
|
||||||
|
{
|
||||||
|
EscherDggRecord r = new EscherDggRecord();
|
||||||
|
r.setFileIdClusters(new EscherDggRecord.FileIdCluster[] { new EscherDggRecord.FileIdCluster(0,0) } );
|
||||||
|
assertEquals(32,r.getRecordSize());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
140
src/java/org/apache/poi/ddf/TestEscherOptRecord.java
Normal file
140
src/java/org/apache/poi/ddf/TestEscherOptRecord.java
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class TestEscherOptRecord extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
checkFillFieldsSimple();
|
||||||
|
checkFillFieldsComplex();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkFillFieldsComplex() throws IOException
|
||||||
|
{
|
||||||
|
String dataStr = "33 00 " +
|
||||||
|
"0B F0 " +
|
||||||
|
"14 00 00 00 " +
|
||||||
|
"BF 00 01 00 00 00 " +
|
||||||
|
"01 80 02 00 00 00 " +
|
||||||
|
"BF 00 01 00 00 00 " +
|
||||||
|
"01 02";
|
||||||
|
|
||||||
|
EscherOptRecord r = new EscherOptRecord();
|
||||||
|
r.fillFields( HexRead.readFromString( dataStr ), new DefaultEscherRecordFactory() );
|
||||||
|
assertEquals( (short) 0x0033, r.getOptions() );
|
||||||
|
assertEquals( (short) 0xF00B, r.getRecordId() );
|
||||||
|
assertEquals( 3, r.getEscherProperties().size() );
|
||||||
|
EscherBoolProperty prop1 = new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1 );
|
||||||
|
EscherComplexProperty prop2 = new EscherComplexProperty( (short) 1, false, new byte[] { 0x01, 0x02 } );
|
||||||
|
EscherBoolProperty prop3 = new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1 );
|
||||||
|
assertEquals( prop1, r.getEscherProperty( 0 ) );
|
||||||
|
assertEquals( prop2, r.getEscherProperty( 1 ) );
|
||||||
|
assertEquals( prop3, r.getEscherProperty( 2 ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkFillFieldsSimple()
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
String dataStr = "33 00 " + // options
|
||||||
|
"0B F0 " + // recordid
|
||||||
|
"12 00 00 00 " + // remaining bytes
|
||||||
|
"BF 00 08 00 08 00 " +
|
||||||
|
"81 01 09 00 00 08 " +
|
||||||
|
"C0 01 40 00 00 08";
|
||||||
|
|
||||||
|
EscherOptRecord r = new EscherOptRecord();
|
||||||
|
r.fillFields( HexRead.readFromString( dataStr ), new DefaultEscherRecordFactory() );
|
||||||
|
assertEquals( (short) 0x0033, r.getOptions() );
|
||||||
|
assertEquals( (short) 0xF00B, r.getRecordId() );
|
||||||
|
assertEquals( 3, r.getEscherProperties().size() );
|
||||||
|
EscherBoolProperty prop1 = new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 524296 );
|
||||||
|
EscherRGBProperty prop2 = new EscherRGBProperty( EscherProperties.FILL__FILLCOLOR, 0x08000009 );
|
||||||
|
EscherRGBProperty prop3 = new EscherRGBProperty( EscherProperties.LINESTYLE__COLOR, 0x08000040 );
|
||||||
|
assertEquals( prop1, r.getEscherProperty( 0 ) );
|
||||||
|
assertEquals( prop2, r.getEscherProperty( 1 ) );
|
||||||
|
assertEquals( prop3, r.getEscherProperty( 2 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
checkSerializeSimple();
|
||||||
|
checkSerializeComplex();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkSerializeComplex()
|
||||||
|
{
|
||||||
|
//Complex escher record
|
||||||
|
EscherOptRecord r = new EscherOptRecord();
|
||||||
|
r.setOptions( (short) 0x0033 );
|
||||||
|
r.setRecordId( (short) 0xF00B );
|
||||||
|
EscherBoolProperty prop1 = new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1 );
|
||||||
|
EscherComplexProperty prop2 = new EscherComplexProperty( (short) 1, false, new byte[] { 0x01, 0x02 } );
|
||||||
|
EscherBoolProperty prop3 = new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1 );
|
||||||
|
r.addEscherProperty( prop1 );
|
||||||
|
r.addEscherProperty( prop2 );
|
||||||
|
r.addEscherProperty( prop3 );
|
||||||
|
|
||||||
|
byte[] data = new byte[28];
|
||||||
|
int bytesWritten = r.serialize(0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 28, bytesWritten );
|
||||||
|
String dataStr = "[33, 00, " +
|
||||||
|
"0B, F0, " +
|
||||||
|
"14, 00, 00, 00, " +
|
||||||
|
"BF, 00, 01, 00, 00, 00, " +
|
||||||
|
"01, 80, 02, 00, 00, 00, " +
|
||||||
|
"BF, 00, 01, 00, 00, 00, " +
|
||||||
|
"01, 02, ]";
|
||||||
|
assertEquals( dataStr, HexDump.toHex(data) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkSerializeSimple()
|
||||||
|
{
|
||||||
|
EscherOptRecord r = new EscherOptRecord();
|
||||||
|
r.setOptions( (short) 0x0033 );
|
||||||
|
r.setRecordId( (short) 0xF00B );
|
||||||
|
EscherBoolProperty prop1 = new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 1 );
|
||||||
|
EscherRGBProperty prop2 = new EscherRGBProperty( EscherProperties.FILL__FILLCOLOR, 0x08000009 );
|
||||||
|
EscherRGBProperty prop3 = new EscherRGBProperty( EscherProperties.LINESTYLE__COLOR, 0x08000040 );
|
||||||
|
r.addEscherProperty( prop1 );
|
||||||
|
r.addEscherProperty( prop2 );
|
||||||
|
r.addEscherProperty( prop3 );
|
||||||
|
|
||||||
|
byte[] data = new byte[26];
|
||||||
|
int bytesWritten = r.serialize(0, data, new NullEscherSerializationListener() );
|
||||||
|
String dataStr = "[33, 00, " +
|
||||||
|
"0B, F0, " +
|
||||||
|
"12, 00, 00, 00, " +
|
||||||
|
"BF, 00, 01, 00, 00, 00, " +
|
||||||
|
"81, 01, 09, 00, 00, 08, " +
|
||||||
|
"C0, 01, 40, 00, 00, 08, ]";
|
||||||
|
assertEquals( dataStr, HexDump.toHex(data) );
|
||||||
|
assertEquals( 26, bytesWritten );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
EscherOptRecord r = new EscherOptRecord();
|
||||||
|
r.setOptions((short)0x000F);
|
||||||
|
r.setRecordId(EscherOptRecord.RECORD_ID);
|
||||||
|
EscherProperty prop1 = new EscherBoolProperty((short)1, 1);
|
||||||
|
r.addEscherProperty(prop1);
|
||||||
|
String expected = "org.apache.poi.ddf.EscherOptRecord:" + nl +
|
||||||
|
" isContainer: true" + nl +
|
||||||
|
" options: 0x0013" + nl +
|
||||||
|
" 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;
|
||||||
|
assertEquals( expected, r.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
src/java/org/apache/poi/ddf/TestEscherPropertyFactory.java
Normal file
42
src/java/org/apache/poi/ddf/TestEscherPropertyFactory.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Glen Stampoultzis (glens @ superlinksoftware.com)
|
||||||
|
*/
|
||||||
|
public class TestEscherPropertyFactory extends TestCase
|
||||||
|
{
|
||||||
|
public void testCreateProperties() throws Exception
|
||||||
|
{
|
||||||
|
String dataStr = "41 C1 " + // propid, complex ind
|
||||||
|
"03 00 00 00 " + // size of complex property
|
||||||
|
"01 00 " + // propid, complex ind
|
||||||
|
"00 00 00 00 " + // value
|
||||||
|
"41 C1 " + // propid, complex ind
|
||||||
|
"03 00 00 00 " + // size of complex property
|
||||||
|
"01 02 03 " +
|
||||||
|
"01 02 03 "
|
||||||
|
;
|
||||||
|
byte[] data = HexRead.readFromString( dataStr );
|
||||||
|
EscherPropertyFactory f = new EscherPropertyFactory();
|
||||||
|
List props = f.createProperties( data, 0, (short)3 );
|
||||||
|
EscherComplexProperty p1 = (EscherComplexProperty) props.get( 0 );
|
||||||
|
assertEquals( (short)0xC141, p1.getId() );
|
||||||
|
assertEquals( "[01, 02, 03, ]", HexDump.toHex( p1.getComplexData() ) );
|
||||||
|
|
||||||
|
EscherComplexProperty p3 = (EscherComplexProperty) props.get( 2 );
|
||||||
|
assertEquals( (short)0xC141, p3.getId() );
|
||||||
|
assertEquals( "[01, 02, 03, ]", HexDump.toHex( p3.getComplexData() ) );
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
62
src/java/org/apache/poi/ddf/TestEscherSpRecord.java
Normal file
62
src/java/org/apache/poi/ddf/TestEscherSpRecord.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
public class TestEscherSpRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherSpRecord r = createRecord();
|
||||||
|
|
||||||
|
byte[] data = new byte[16];
|
||||||
|
int bytesWritten = r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 16, bytesWritten );
|
||||||
|
assertEquals( "[02, 00, " +
|
||||||
|
"0A, F0, " +
|
||||||
|
"08, 00, 00, 00, " +
|
||||||
|
"00, 04, 00, 00, " +
|
||||||
|
"05, 00, 00, 00, ]",
|
||||||
|
HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String hexData = "02 00 " +
|
||||||
|
"0A F0 " +
|
||||||
|
"08 00 00 00 " +
|
||||||
|
"00 04 00 00 " +
|
||||||
|
"05 00 00 00 ";
|
||||||
|
byte[] data = HexRead.readFromString( hexData );
|
||||||
|
EscherSpRecord r = new EscherSpRecord();
|
||||||
|
int bytesWritten = r.fillFields( data, new DefaultEscherRecordFactory() );
|
||||||
|
|
||||||
|
assertEquals( 16, bytesWritten );
|
||||||
|
assertEquals( 0x0400, r.getShapeId() );
|
||||||
|
assertEquals( 0x05, r.getFlags() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String expected = "org.apache.poi.ddf.EscherSpRecord:" + nl +
|
||||||
|
" RecordId: 0xF00A" + nl +
|
||||||
|
" Options: 0x0002" + nl +
|
||||||
|
" ShapeId: 1024" + nl +
|
||||||
|
" Flags: GROUP|PATRIARCH (0x00000005)" + nl;
|
||||||
|
assertEquals( expected, createRecord().toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherSpRecord createRecord()
|
||||||
|
{
|
||||||
|
EscherSpRecord r = new EscherSpRecord();
|
||||||
|
r.setOptions( (short) 0x0002 );
|
||||||
|
r.setRecordId( EscherSpRecord.RECORD_ID );
|
||||||
|
r.setShapeId(0x0400);
|
||||||
|
r.setFlags(0x05);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
73
src/java/org/apache/poi/ddf/TestEscherSpgrRecord.java
Normal file
73
src/java/org/apache/poi/ddf/TestEscherSpgrRecord.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
public class TestEscherSpgrRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherSpgrRecord r = createRecord();
|
||||||
|
|
||||||
|
byte[] data = new byte[24];
|
||||||
|
int bytesWritten = r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 24, bytesWritten );
|
||||||
|
assertEquals( "[10, 00, " +
|
||||||
|
"09, F0, " +
|
||||||
|
"10, 00, 00, 00, " +
|
||||||
|
"01, 00, 00, 00, " + // x
|
||||||
|
"02, 00, 00, 00, " + // y
|
||||||
|
"03, 00, 00, 00, " + // width
|
||||||
|
"04, 00, 00, 00, ]", // height
|
||||||
|
HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String hexData = "10 00 " +
|
||||||
|
"09 F0 " +
|
||||||
|
"10 00 00 00 " +
|
||||||
|
"01 00 00 00 " +
|
||||||
|
"02 00 00 00 " +
|
||||||
|
"03 00 00 00 " +
|
||||||
|
"04 00 00 00 ";
|
||||||
|
byte[] data = HexRead.readFromString( hexData );
|
||||||
|
EscherSpgrRecord r = new EscherSpgrRecord();
|
||||||
|
int bytesWritten = r.fillFields( data, new DefaultEscherRecordFactory() );
|
||||||
|
|
||||||
|
assertEquals( 24, bytesWritten );
|
||||||
|
assertEquals( 1, r.getRectX1() );
|
||||||
|
assertEquals( 2, r.getRectY1() );
|
||||||
|
assertEquals( 3, r.getRectX2() );
|
||||||
|
assertEquals( 4, r.getRectY2() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String expected = "org.apache.poi.ddf.EscherSpgrRecord:" + nl +
|
||||||
|
" RecordId: 0xF009" + nl +
|
||||||
|
" Options: 0x0010" + nl +
|
||||||
|
" RectX: 1" + nl +
|
||||||
|
" RectY: 2" + nl +
|
||||||
|
" RectWidth: 3" + nl +
|
||||||
|
" RectHeight: 4" + nl;
|
||||||
|
;
|
||||||
|
assertEquals( expected, createRecord().toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherSpgrRecord createRecord()
|
||||||
|
{
|
||||||
|
EscherSpgrRecord r = new EscherSpgrRecord();
|
||||||
|
r.setOptions( (short) 0x0010 );
|
||||||
|
r.setRecordId( EscherSpgrRecord.RECORD_ID );
|
||||||
|
r.setRectX1(1);
|
||||||
|
r.setRectY1(2);
|
||||||
|
r.setRectX2(3);
|
||||||
|
r.setRectY2(4);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
|
||||||
|
public class TestEscherSplitMenuColorsRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
EscherSplitMenuColorsRecord r = createRecord();
|
||||||
|
|
||||||
|
byte[] data = new byte[24];
|
||||||
|
int bytesWritten = r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
assertEquals( 24, bytesWritten );
|
||||||
|
assertEquals( "[40, 00, " +
|
||||||
|
"1E, F1, " +
|
||||||
|
"10, 00, 00, 00, " +
|
||||||
|
"02, 04, 00, 00, " +
|
||||||
|
"02, 00, 00, 00, " +
|
||||||
|
"02, 00, 00, 00, " +
|
||||||
|
"01, 00, 00, 00, ]",
|
||||||
|
HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String hexData = "40 00 " +
|
||||||
|
"1E F1 " +
|
||||||
|
"10 00 00 00 " +
|
||||||
|
"02 04 00 00 " +
|
||||||
|
"02 00 00 00 " +
|
||||||
|
"02 00 00 00 " +
|
||||||
|
"01 00 00 00 ";
|
||||||
|
byte[] data = HexRead.readFromString( hexData );
|
||||||
|
EscherSplitMenuColorsRecord r = new EscherSplitMenuColorsRecord();
|
||||||
|
int bytesWritten = r.fillFields( data, new DefaultEscherRecordFactory() );
|
||||||
|
|
||||||
|
assertEquals( 24, bytesWritten );
|
||||||
|
assertEquals( 0x0402, r.getColor1() );
|
||||||
|
assertEquals( 0x02, r.getColor2() );
|
||||||
|
assertEquals( 0x02, r.getColor3() );
|
||||||
|
assertEquals( 0x01, r.getColor4() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
String expected = "org.apache.poi.ddf.EscherSplitMenuColorsRecord:" + nl +
|
||||||
|
" RecordId: 0xF11E" + nl +
|
||||||
|
" Options: 0x0040" + nl +
|
||||||
|
" Color1: 0x00000402" + nl +
|
||||||
|
" Color2: 0x00000002" + nl +
|
||||||
|
" Color3: 0x00000002" + nl +
|
||||||
|
" Color4: 0x00000001" + nl +
|
||||||
|
"";
|
||||||
|
assertEquals( expected, createRecord().toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherSplitMenuColorsRecord createRecord()
|
||||||
|
{
|
||||||
|
EscherSplitMenuColorsRecord r = new EscherSplitMenuColorsRecord();
|
||||||
|
r.setOptions( (short) 0x0040 );
|
||||||
|
r.setRecordId( EscherSplitMenuColorsRecord.RECORD_ID );
|
||||||
|
r.setColor1( 0x402 );
|
||||||
|
r.setColor2( 0x2 );
|
||||||
|
r.setColor3( 0x2 );
|
||||||
|
r.setColor4( 0x1 );
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
106
src/java/org/apache/poi/ddf/TestUnknownEscherRecord.java
Normal file
106
src/java/org/apache/poi/ddf/TestUnknownEscherRecord.java
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.util.HexRead;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
public class TestUnknownEscherRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testFillFields() throws Exception
|
||||||
|
{
|
||||||
|
String testData =
|
||||||
|
"0F 02 " + // options
|
||||||
|
"11 F1 " + // record id
|
||||||
|
"00 00 00 00"; // remaining bytes
|
||||||
|
|
||||||
|
UnknownEscherRecord r = new UnknownEscherRecord();
|
||||||
|
EscherRecordFactory factory = new DefaultEscherRecordFactory();
|
||||||
|
r.fillFields( HexRead.readFromString( testData ), factory );
|
||||||
|
|
||||||
|
assertEquals( 0x020F, r.getOptions() );
|
||||||
|
assertEquals( (short) 0xF111, r.getRecordId() );
|
||||||
|
assertTrue( r.isContainerRecord() );
|
||||||
|
assertEquals( 8, r.getRecordSize() );
|
||||||
|
assertEquals( 0, r.getChildRecords().size() );
|
||||||
|
assertEquals( 0, r.getData().length );
|
||||||
|
|
||||||
|
testData =
|
||||||
|
"00 02 " + // options
|
||||||
|
"11 F1 " + // record id
|
||||||
|
"04 00 00 00 " + // remaining bytes
|
||||||
|
"01 02 03 04";
|
||||||
|
|
||||||
|
r = new UnknownEscherRecord();
|
||||||
|
r.fillFields( HexRead.readFromString( testData ), factory );
|
||||||
|
|
||||||
|
assertEquals( 0x0200, r.getOptions() );
|
||||||
|
assertEquals( (short) 0xF111, r.getRecordId() );
|
||||||
|
assertEquals( 12, r.getRecordSize() );
|
||||||
|
assertFalse( r.isContainerRecord() );
|
||||||
|
assertEquals( 0, r.getChildRecords().size() );
|
||||||
|
assertEquals( 4, r.getData().length );
|
||||||
|
assertEquals( 1, r.getData()[0] );
|
||||||
|
assertEquals( 2, r.getData()[1] );
|
||||||
|
assertEquals( 3, r.getData()[2] );
|
||||||
|
assertEquals( 4, r.getData()[3] );
|
||||||
|
|
||||||
|
testData =
|
||||||
|
"0F 02 " + // options
|
||||||
|
"11 F1 " + // record id
|
||||||
|
"08 00 00 00 " + // remaining bytes
|
||||||
|
"00 02 " + // options
|
||||||
|
"FF FF " + // record id
|
||||||
|
"00 00 00 00"; // remaining bytes
|
||||||
|
|
||||||
|
r = new UnknownEscherRecord();
|
||||||
|
r.fillFields( HexRead.readFromString( testData ), factory );
|
||||||
|
|
||||||
|
assertEquals( 0x020F, r.getOptions() );
|
||||||
|
assertEquals( (short) 0xF111, r.getRecordId() );
|
||||||
|
assertEquals( 8, r.getRecordSize() );
|
||||||
|
assertTrue( r.isContainerRecord() );
|
||||||
|
assertEquals( 1, r.getChildRecords().size() );
|
||||||
|
assertEquals( (short) 0xFFFF, r.getChild( 0 ).getRecordId() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
UnknownEscherRecord r = new UnknownEscherRecord();
|
||||||
|
r.setOptions( (short) 0x1234 );
|
||||||
|
r.setRecordId( (short) 0xF112 );
|
||||||
|
byte[] data = new byte[8];
|
||||||
|
r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
|
||||||
|
assertEquals( "[34, 12, 12, F1, 00, 00, 00, 00, ]", HexDump.toHex( data ) );
|
||||||
|
|
||||||
|
EscherRecord childRecord = new UnknownEscherRecord();
|
||||||
|
childRecord.setOptions( (short) 0x9999 );
|
||||||
|
childRecord.setRecordId( (short) 0xFF01 );
|
||||||
|
r.addChildRecord( childRecord );
|
||||||
|
r.setOptions( (short) 0x123F );
|
||||||
|
data = new byte[16];
|
||||||
|
r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
|
||||||
|
assertEquals( "[3F, 12, 12, F1, 08, 00, 00, 00, 99, 99, 01, FF, 00, 00, 00, 00, ]", HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testToString() throws Exception
|
||||||
|
{
|
||||||
|
UnknownEscherRecord r = new UnknownEscherRecord();
|
||||||
|
r.setOptions( (short) 0x1234 );
|
||||||
|
r.setRecordId( (short) 0xF112 );
|
||||||
|
byte[] data = new byte[8];
|
||||||
|
r.serialize( 0, data, new NullEscherSerializationListener() );
|
||||||
|
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
assertEquals( "org.apache.poi.ddf.UnknownEscherRecord:" + nl +
|
||||||
|
" isContainer: false" + nl +
|
||||||
|
" options: 0x1234" + nl +
|
||||||
|
" recordId: 0xF112" + nl +
|
||||||
|
" numchildren: 0" + nl
|
||||||
|
, r.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
234
src/java/org/apache/poi/ddf/UnknownEscherRecord.java
Normal file
234
src/java/org/apache/poi/ddf/UnknownEscherRecord.java
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
package org.apache.poi.ddf;
|
||||||
|
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This record is used whenever a escher record is encountered that
|
||||||
|
* we do not explicitly support.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class UnknownEscherRecord extends EscherRecord
|
||||||
|
{
|
||||||
|
private static final byte[] NO_BYTES = new byte[0];
|
||||||
|
|
||||||
|
/** The data for this record not including the the 8 byte header */
|
||||||
|
private byte[] thedata = NO_BYTES;
|
||||||
|
private List childRecords = new ArrayList();
|
||||||
|
|
||||||
|
public UnknownEscherRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 bytesRemaining = readHeader( data, offset );
|
||||||
|
if ( isContainerRecord() )
|
||||||
|
{
|
||||||
|
int bytesWritten = 0;
|
||||||
|
thedata = new byte[0];
|
||||||
|
offset += 8;
|
||||||
|
bytesWritten += 8;
|
||||||
|
while ( bytesRemaining > 0 )
|
||||||
|
{
|
||||||
|
EscherRecord child = recordFactory.createRecord( data, offset );
|
||||||
|
int childBytesWritten = child.fillFields( data, offset, recordFactory );
|
||||||
|
bytesWritten += childBytesWritten;
|
||||||
|
offset += childBytesWritten;
|
||||||
|
bytesRemaining -= childBytesWritten;
|
||||||
|
getChildRecords().add( child );
|
||||||
|
}
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thedata = new byte[bytesRemaining];
|
||||||
|
System.arraycopy( data, offset + 8, thedata, 0, bytesRemaining );
|
||||||
|
return bytesRemaining + 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes this record and any contained records to the supplied byte
|
||||||
|
* array.
|
||||||
|
*
|
||||||
|
* @return the number of bytes written.
|
||||||
|
*/
|
||||||
|
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 = thedata.length;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
remainingBytes += r.getRecordSize();
|
||||||
|
}
|
||||||
|
LittleEndian.putInt(data, offset+4, remainingBytes);
|
||||||
|
System.arraycopy(thedata, 0, data, offset+8, thedata.length);
|
||||||
|
int pos = offset+8+thedata.length;
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
pos += r.serialize(pos, data, listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.afterRecordSerialize( pos, getRecordId(), pos - offset, this );
|
||||||
|
return pos - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData()
|
||||||
|
{
|
||||||
|
return thedata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are required to serialize this record.
|
||||||
|
*
|
||||||
|
* @return Number of bytes
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 8 + thedata.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List getChildRecords()
|
||||||
|
{
|
||||||
|
return childRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildRecords( List childRecords )
|
||||||
|
{
|
||||||
|
this.childRecords = childRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone()
|
||||||
|
{
|
||||||
|
// shallow clone
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The short name for this record
|
||||||
|
*/
|
||||||
|
public String getRecordName()
|
||||||
|
{
|
||||||
|
return "Unknown 0x" + HexDump.toHex(getRecordId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separator" );
|
||||||
|
|
||||||
|
StringBuffer children = new StringBuffer();
|
||||||
|
if ( getChildRecords().size() > 0 )
|
||||||
|
{
|
||||||
|
children.append( " children: " + nl );
|
||||||
|
for ( Iterator iterator = getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord record = (EscherRecord) iterator.next();
|
||||||
|
children.append( record.toString() );
|
||||||
|
children.append( nl );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String theDumpHex = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (thedata.length != 0)
|
||||||
|
{
|
||||||
|
theDumpHex = " Extra Data:" + nl;
|
||||||
|
theDumpHex += HexDump.dump(thedata, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( Exception e )
|
||||||
|
{
|
||||||
|
theDumpHex = "Error!!";
|
||||||
|
}
|
||||||
|
|
||||||
|
return getClass().getName() + ":" + nl +
|
||||||
|
" isContainer: " + isContainerRecord() + nl +
|
||||||
|
" options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
||||||
|
" recordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
||||||
|
" numchildren: " + getChildRecords().size() + nl +
|
||||||
|
theDumpHex +
|
||||||
|
children.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChildRecord( EscherRecord childRecord )
|
||||||
|
{
|
||||||
|
getChildRecords().add( childRecord );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
11
src/java/org/apache/poi/ddf/package.html
Normal file
11
src/java/org/apache/poi/ddf/package.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<p>This package contains classes for decoding the Microsoft Office
|
||||||
|
Drawing format otherwise known as escher henceforth known in POI
|
||||||
|
as the Dreadful Drawing Format.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -88,15 +88,6 @@ public class RecordGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of the Method
|
|
||||||
*
|
|
||||||
*@param defintionsDir Description of the Parameter
|
|
||||||
*@param recordStyleDir Description of the Parameter
|
|
||||||
*@param destSrcPathDir Description of the Parameter
|
|
||||||
*@param testSrcPathDir Description of the Parameter
|
|
||||||
*@exception Exception Description of the Exception
|
|
||||||
*/
|
|
||||||
private static void generateRecords(String defintionsDir, String recordStyleDir, String destSrcPathDir, String testSrcPathDir)
|
private static void generateRecords(String defintionsDir, String recordStyleDir, String destSrcPathDir, String testSrcPathDir)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
File definitionsFile = new File(defintionsDir);
|
File definitionsFile = new File(defintionsDir);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* ====================================================================
|
* ====================================================================
|
||||||
* The Apache Software License, Version 1.1
|
* The Apache Software License, Version 1.1
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
* Copyright (c) 2004 The Apache Software Foundation. All rights
|
||||||
* reserved.
|
* reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -107,7 +107,7 @@ public class BiffViewer {
|
|||||||
new POIFSFileSystem(new FileInputStream(filename));
|
new POIFSFileSystem(new FileInputStream(filename));
|
||||||
InputStream stream =
|
InputStream stream =
|
||||||
fs.createDocumentInputStream("Workbook");
|
fs.createDocumentInputStream("Workbook");
|
||||||
Record[] records = createRecords(stream, dump);
|
createRecords(stream, dump);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -128,17 +128,20 @@ public class BiffViewer {
|
|||||||
public static Record[] createRecords(InputStream in, boolean dump)
|
public static Record[] createRecords(InputStream in, boolean dump)
|
||||||
throws RecordFormatException {
|
throws RecordFormatException {
|
||||||
ArrayList records = new ArrayList();
|
ArrayList records = new ArrayList();
|
||||||
Record last_record = null;
|
//Record last_record = null;
|
||||||
int loc = 0;
|
int loc = 0;
|
||||||
|
|
||||||
|
RecordDetails activeRecord = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// long offset = 0;
|
// long offset = 0;
|
||||||
short rectype = 0;
|
short rectype = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
rectype = LittleEndian.readShort(in);
|
rectype = LittleEndian.readShort(in);
|
||||||
System.out.println("============================================");
|
int startloc = loc;
|
||||||
System.out.println("Offset 0x" + Integer.toHexString(loc) + " (" + loc + ")");
|
// System.out.println("============================================");
|
||||||
|
// System.out.println("Offset 0x" + Integer.toHexString(loc) + " (" + loc + ")");
|
||||||
loc += 2;
|
loc += 2;
|
||||||
if (rectype != 0) {
|
if (rectype != 0) {
|
||||||
short recsize = LittleEndian.readShort(in);
|
short recsize = LittleEndian.readShort(in);
|
||||||
@ -147,36 +150,27 @@ public class BiffViewer {
|
|||||||
byte[] data = new byte[(int) recsize];
|
byte[] data = new byte[(int) recsize];
|
||||||
|
|
||||||
in.read(data);
|
in.read(data);
|
||||||
if ((rectype == WSBoolRecord.sid) && (recsize == 0)) {
|
|
||||||
System.out.println(loc);
|
|
||||||
}
|
|
||||||
loc += recsize;
|
loc += recsize;
|
||||||
// offset += 4 + recsize;
|
Record record = createRecord(rectype, recsize, data );
|
||||||
if (dump) {
|
if (record.getSid() != ContinueRecord.sid)
|
||||||
dump(rectype, recsize, data);
|
{
|
||||||
}
|
|
||||||
Record[] recs = createRecord(rectype, recsize,
|
|
||||||
data);
|
|
||||||
// handle MulRK records
|
|
||||||
|
|
||||||
Record record = recs[0];
|
|
||||||
|
|
||||||
if ((record instanceof UnknownRecord)
|
|
||||||
&& !dump) {
|
|
||||||
// if we didn't already dump
|
|
||||||
// just cause dump was on and we're hit an unknow
|
|
||||||
dumpUnknownRecord(data);
|
|
||||||
}
|
|
||||||
if (record != null) {
|
|
||||||
if (rectype == ContinueRecord.sid) {
|
|
||||||
dumpContinueRecord(last_record, dump, data);
|
|
||||||
} else {
|
|
||||||
last_record = record;
|
|
||||||
records.add(record);
|
records.add(record);
|
||||||
|
if (activeRecord != null)
|
||||||
|
activeRecord.dump();
|
||||||
|
activeRecord = new RecordDetails(rectype, recsize, startloc, data, record);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
activeRecord.getRecord().processContinueRecord(data);
|
||||||
|
}
|
||||||
|
if (dump) {
|
||||||
|
dumpRaw(rectype, recsize, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (rectype != 0);
|
} while (rectype != 0);
|
||||||
|
|
||||||
|
activeRecord.dump();
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RecordFormatException("Error reading bytes");
|
throw new RecordFormatException("Error reading bytes");
|
||||||
}
|
}
|
||||||
@ -186,15 +180,14 @@ public class BiffViewer {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void dumpNormal(Record record, int startloc, short rectype, short recsize)
|
||||||
|
{
|
||||||
|
System.out.println("Offset 0x" + Integer.toHexString(startloc) + " (" + startloc + ")");
|
||||||
|
System.out.println( "recordid = 0x" + Integer.toHexString( rectype ) + ", size = " + recsize );
|
||||||
|
System.out.println( record.toString() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of the Method
|
|
||||||
*
|
|
||||||
*@param last_record Description of the Parameter
|
|
||||||
*@param dump Description of the Parameter
|
|
||||||
*@param data Description of the Parameter
|
|
||||||
*@exception IOException Description of the Exception
|
|
||||||
*/
|
|
||||||
private static void dumpContinueRecord(Record last_record, boolean dump, byte[] data) throws IOException {
|
private static void dumpContinueRecord(Record last_record, boolean dump, byte[] data) throws IOException {
|
||||||
if (last_record == null) {
|
if (last_record == null) {
|
||||||
throw new RecordFormatException(
|
throw new RecordFormatException(
|
||||||
@ -226,12 +219,6 @@ public class BiffViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of the Method
|
|
||||||
*
|
|
||||||
*@param data Description of the Parameter
|
|
||||||
*@exception IOException Description of the Exception
|
|
||||||
*/
|
|
||||||
private static void dumpUnknownRecord(byte[] data) throws IOException {
|
private static void dumpUnknownRecord(byte[] data) throws IOException {
|
||||||
// record hex dump it!
|
// record hex dump it!
|
||||||
System.out.println(
|
System.out.println(
|
||||||
@ -247,10 +234,11 @@ public class BiffViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void dump( short rectype, short recsize, byte[] data ) throws IOException
|
private static void dumpRaw( short rectype, short recsize, byte[] data ) throws IOException
|
||||||
{
|
{
|
||||||
// System.out
|
// System.out
|
||||||
// .println("fixing to recordize the following");
|
// .println("fixing to recordize the following");
|
||||||
|
System.out.println("============================================");
|
||||||
System.out.print( "rectype = 0x"
|
System.out.print( "rectype = 0x"
|
||||||
+ Integer.toHexString( rectype ) );
|
+ Integer.toHexString( rectype ) );
|
||||||
System.out.println( ", recsize = 0x"
|
System.out.println( ", recsize = 0x"
|
||||||
@ -275,13 +263,9 @@ public class BiffViewer {
|
|||||||
* Essentially a duplicate of RecordFactory. Kept seperate as not to screw
|
* Essentially a duplicate of RecordFactory. Kept seperate as not to screw
|
||||||
* up non-debug operations.
|
* up non-debug operations.
|
||||||
*
|
*
|
||||||
*@param rectype Description of the Parameter
|
|
||||||
*@param size Description of the Parameter
|
|
||||||
*@param data Description of the Parameter
|
|
||||||
*@return Description of the Return Value
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private static Record[] createRecord( short rectype, short size,
|
private static Record createRecord( short rectype, short size,
|
||||||
byte[] data )
|
byte[] data )
|
||||||
{
|
{
|
||||||
Record retval = null;
|
Record retval = null;
|
||||||
@ -429,6 +413,15 @@ public class BiffViewer {
|
|||||||
case GridsetRecord.sid:
|
case GridsetRecord.sid:
|
||||||
retval = new GridsetRecord( rectype, size, data );
|
retval = new GridsetRecord( rectype, size, data );
|
||||||
break;
|
break;
|
||||||
|
case DrawingGroupRecord.sid:
|
||||||
|
retval = new DrawingGroupRecord( rectype, size, data );
|
||||||
|
break;
|
||||||
|
case DrawingRecordForBiffViewer.sid:
|
||||||
|
retval = new DrawingRecordForBiffViewer( rectype, size, data );
|
||||||
|
break;
|
||||||
|
case DrawingSelectionRecord.sid:
|
||||||
|
retval = new DrawingSelectionRecord( rectype, size, data );
|
||||||
|
break;
|
||||||
case GutsRecord.sid:
|
case GutsRecord.sid:
|
||||||
retval = new GutsRecord( rectype, size, data );
|
retval = new GutsRecord( rectype, size, data );
|
||||||
break;
|
break;
|
||||||
@ -633,17 +626,22 @@ public class BiffViewer {
|
|||||||
case SharedFormulaRecord.sid:
|
case SharedFormulaRecord.sid:
|
||||||
retval = new SharedFormulaRecord( rectype, size, data);
|
retval = new SharedFormulaRecord( rectype, size, data);
|
||||||
break;
|
break;
|
||||||
|
case ObjRecord.sid:
|
||||||
|
retval = new ObjRecord( rectype, size, data);
|
||||||
|
break;
|
||||||
|
case TextObjectRecord.sid:
|
||||||
|
retval = new TextObjectRecord( rectype, size, data);
|
||||||
|
break;
|
||||||
|
case HorizontalPageBreakRecord.sid:
|
||||||
|
retval = new HorizontalPageBreakRecord( rectype, size, data);
|
||||||
|
break;
|
||||||
|
case VerticalPageBreakRecord.sid:
|
||||||
|
retval = new VerticalPageBreakRecord( rectype, size, data);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
retval = new UnknownRecord( rectype, size, data );
|
retval = new UnknownRecord( rectype, size, data );
|
||||||
}
|
}
|
||||||
if ( realretval == null )
|
return retval;
|
||||||
{
|
|
||||||
realretval = new Record[1];
|
|
||||||
realretval[0] = retval;
|
|
||||||
System.out.println( "recordid = 0x" + Integer.toHexString( rectype ) + ", size =" + size );
|
|
||||||
System.out.println( realretval[0].toString() );
|
|
||||||
}
|
|
||||||
return realretval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -674,6 +672,7 @@ public class BiffViewer {
|
|||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
try {
|
try {
|
||||||
|
System.setProperty("poi.deserialize.escher", "true");
|
||||||
BiffViewer viewer = new BiffViewer(args);
|
BiffViewer viewer = new BiffViewer(args);
|
||||||
|
|
||||||
if ((args.length > 1) && args[1].equals("on")) {
|
if ((args.length > 1) && args[1].equals("on")) {
|
||||||
@ -696,4 +695,50 @@ public class BiffViewer {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class RecordDetails
|
||||||
|
{
|
||||||
|
short rectype, recsize;
|
||||||
|
int startloc;
|
||||||
|
byte[] data;
|
||||||
|
Record record;
|
||||||
|
|
||||||
|
public RecordDetails( short rectype, short recsize, int startloc, byte[] data, Record record )
|
||||||
|
{
|
||||||
|
this.rectype = rectype;
|
||||||
|
this.recsize = recsize;
|
||||||
|
this.startloc = startloc;
|
||||||
|
this.data = data;
|
||||||
|
this.record = record;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRectype()
|
||||||
|
{
|
||||||
|
return rectype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRecsize()
|
||||||
|
{
|
||||||
|
return recsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData()
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Record getRecord()
|
||||||
|
{
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dump() throws IOException
|
||||||
|
{
|
||||||
|
if (record instanceof UnknownRecord)
|
||||||
|
dumpUnknownRecord(data);
|
||||||
|
else
|
||||||
|
dumpNormal(record, startloc, rectype, recsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
126
src/java/org/apache/poi/hssf/model/AbstractShape.java
Normal file
126
src/java/org/apache/poi/hssf/model/AbstractShape.java
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.*;
|
||||||
|
import org.apache.poi.hssf.record.ObjRecord;
|
||||||
|
import org.apache.poi.hssf.usermodel.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract shape is the lowlevel model for a shape.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public abstract class AbstractShape
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new shape object used to create the escher records.
|
||||||
|
*
|
||||||
|
* @param hssfShape The simple shape this is based on.
|
||||||
|
*/
|
||||||
|
public static AbstractShape createShape( HSSFShape hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
AbstractShape shape = null;
|
||||||
|
if (hssfShape instanceof HSSFTextbox)
|
||||||
|
{
|
||||||
|
shape = new TextboxShape( (HSSFTextbox)hssfShape, shapeId );
|
||||||
|
}
|
||||||
|
else if (hssfShape instanceof HSSFPolygon)
|
||||||
|
{
|
||||||
|
shape = new PolygonShape( (HSSFPolygon) hssfShape, shapeId );
|
||||||
|
}
|
||||||
|
else if (hssfShape instanceof HSSFSimpleShape)
|
||||||
|
{
|
||||||
|
HSSFSimpleShape simpleShape = (HSSFSimpleShape) hssfShape;
|
||||||
|
switch ( simpleShape.getShapeType() )
|
||||||
|
{
|
||||||
|
case HSSFSimpleShape.OBJECT_TYPE_LINE:
|
||||||
|
shape = new LineShape( simpleShape, shapeId );
|
||||||
|
break;
|
||||||
|
case HSSFSimpleShape.OBJECT_TYPE_OVAL:
|
||||||
|
case HSSFSimpleShape.OBJECT_TYPE_RECTANGLE:
|
||||||
|
shape = new SimpleFilledShape( simpleShape, shapeId );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Do not know how to handle this type of shape");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Unknown shape type");
|
||||||
|
}
|
||||||
|
EscherSpRecord sp = shape.getSpContainer().getChildById(EscherSpRecord.RECORD_ID);
|
||||||
|
if (hssfShape.getParent() != null)
|
||||||
|
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_CHILD);
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractShape()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The shape container and it's children that can represent this
|
||||||
|
* shape.
|
||||||
|
*/
|
||||||
|
public abstract EscherContainerRecord getSpContainer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The object record that is associated with this shape.
|
||||||
|
*/
|
||||||
|
public abstract ObjRecord getObjRecord();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an escher anchor record from a HSSFAnchor.
|
||||||
|
*
|
||||||
|
* @param userAnchor The high level anchor to convert.
|
||||||
|
* @return An escher anchor record.
|
||||||
|
*/
|
||||||
|
protected EscherRecord createAnchor( HSSFAnchor userAnchor )
|
||||||
|
{
|
||||||
|
return ConvertAnchor.createAnchor(userAnchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add standard properties to the opt record. These properties effect
|
||||||
|
* all records.
|
||||||
|
*
|
||||||
|
* @param shape The user model shape.
|
||||||
|
* @param opt The opt record to add the properties to.
|
||||||
|
* @return The number of options added.
|
||||||
|
*/
|
||||||
|
protected int addStandardOptions( HSSFShape shape, EscherOptRecord opt )
|
||||||
|
{
|
||||||
|
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x080000 ) );
|
||||||
|
// opt.addEscherProperty( new EscherBoolProperty( EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x080008 ) );
|
||||||
|
if ( shape.isNoFill() )
|
||||||
|
{
|
||||||
|
// Wonderful... none of the spec's give any clue as to what these constants mean.
|
||||||
|
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.FILL__NOFILLHITTEST, 0x00110000 ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.FILL__NOFILLHITTEST, 0x00010000 ) );
|
||||||
|
}
|
||||||
|
opt.addEscherProperty( new EscherRGBProperty( EscherProperties.FILL__FILLCOLOR, shape.getFillColor() ) );
|
||||||
|
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.GROUPSHAPE__PRINT, 0x080000 ) );
|
||||||
|
opt.addEscherProperty( new EscherRGBProperty( EscherProperties.LINESTYLE__COLOR, shape.getLineStyleColor() ) );
|
||||||
|
int options = 5;
|
||||||
|
if (shape.getLineWidth() != HSSFShape.LINEWIDTH_DEFAULT)
|
||||||
|
{
|
||||||
|
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.LINESTYLE__LINEWIDTH, shape.getLineWidth()));
|
||||||
|
options++;
|
||||||
|
}
|
||||||
|
if (shape.getLineStyle() != HSSFShape.LINESTYLE_SOLID)
|
||||||
|
{
|
||||||
|
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.LINESTYLE__LINEDASHING, shape.getLineStyle()));
|
||||||
|
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.LINESTYLE__LINEENDCAPSTYLE, 0));
|
||||||
|
if (shape.getLineStyle() == HSSFShape.LINESTYLE_NONE)
|
||||||
|
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x00080000));
|
||||||
|
else
|
||||||
|
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x00080008));
|
||||||
|
options += 3;
|
||||||
|
}
|
||||||
|
opt.sortProperties();
|
||||||
|
return options; // # options added
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
src/java/org/apache/poi/hssf/model/ConvertAnchor.java
Normal file
50
src/java/org/apache/poi/hssf/model/ConvertAnchor.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
|
import org.apache.poi.ddf.EscherClientAnchorRecord;
|
||||||
|
import org.apache.poi.ddf.EscherChildAnchorRecord;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFAnchor;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFChildAnchor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
public class ConvertAnchor
|
||||||
|
{
|
||||||
|
public static EscherRecord createAnchor( HSSFAnchor userAnchor )
|
||||||
|
{
|
||||||
|
if (userAnchor instanceof HSSFClientAnchor)
|
||||||
|
{
|
||||||
|
HSSFClientAnchor a = (HSSFClientAnchor) userAnchor;
|
||||||
|
|
||||||
|
EscherClientAnchorRecord anchor = new EscherClientAnchorRecord();
|
||||||
|
anchor.setRecordId( EscherClientAnchorRecord.RECORD_ID );
|
||||||
|
anchor.setOptions( (short) 0x0000 );
|
||||||
|
anchor.setFlag( (short) 0 );
|
||||||
|
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()) );
|
||||||
|
anchor.setDy1( (short) Math.min(a.getDy1(), a.getDy2()) );
|
||||||
|
|
||||||
|
anchor.setCol2( (short) Math.max(a.getCol1(), a.getCol2()) );
|
||||||
|
anchor.setDx2( (short) Math.max(a.getDx1(), a.getDx2()) );
|
||||||
|
anchor.setRow2( (short) Math.max(a.getRow1(), a.getRow2()) );
|
||||||
|
anchor.setDy2( (short) Math.max(a.getDy1(), a.getDy2() ) );
|
||||||
|
return anchor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HSSFChildAnchor a = (HSSFChildAnchor) userAnchor;
|
||||||
|
EscherChildAnchorRecord anchor = new EscherChildAnchorRecord();
|
||||||
|
anchor.setRecordId( EscherChildAnchorRecord.RECORD_ID );
|
||||||
|
anchor.setOptions( (short) 0x0000 );
|
||||||
|
anchor.setDx1( (short) Math.min(a.getDx1(), a.getDx2()) );
|
||||||
|
anchor.setDy1( (short) Math.min(a.getDy1(), a.getDy2()) );
|
||||||
|
anchor.setDx2( (short) Math.max(a.getDx2(), a.getDx1()) );
|
||||||
|
anchor.setDy2( (short) Math.max(a.getDy2(), a.getDy1()) );
|
||||||
|
return anchor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
136
src/java/org/apache/poi/hssf/model/DrawingManager.java
Normal file
136
src/java/org/apache/poi/hssf/model/DrawingManager.java
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherDggRecord;
|
||||||
|
import org.apache.poi.ddf.EscherDgRecord;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides utilities to manage drawing groups.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class DrawingManager
|
||||||
|
{
|
||||||
|
EscherDggRecord dgg;
|
||||||
|
Map dgMap = new HashMap(); // key = Short(drawingId), value=EscherDgRecord
|
||||||
|
|
||||||
|
public DrawingManager( EscherDggRecord dgg )
|
||||||
|
{
|
||||||
|
this.dgg = dgg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherDgRecord createDgRecord()
|
||||||
|
{
|
||||||
|
EscherDgRecord dg = new EscherDgRecord();
|
||||||
|
dg.setRecordId( EscherDgRecord.RECORD_ID );
|
||||||
|
short dgId = findNewDrawingGroupId();
|
||||||
|
dg.setOptions( (short) ( dgId << 4 ) );
|
||||||
|
dg.setNumShapes( 0 );
|
||||||
|
dg.setLastMSOSPID( -1 );
|
||||||
|
dgg.addCluster( dgId, 0 );
|
||||||
|
dgg.setDrawingsSaved( dgg.getDrawingsSaved() + 1 );
|
||||||
|
dgMap.put( new Short( dgId ), dg );
|
||||||
|
return dg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates new shape id for the new drawing group id.
|
||||||
|
*
|
||||||
|
* @return a new shape id.
|
||||||
|
*/
|
||||||
|
public int allocateShapeId(short drawingGroupId)
|
||||||
|
{
|
||||||
|
// Get the last shape id for this drawing group.
|
||||||
|
EscherDgRecord dg = (EscherDgRecord) dgMap.get(new Short(drawingGroupId));
|
||||||
|
int lastShapeId = dg.getLastMSOSPID();
|
||||||
|
|
||||||
|
|
||||||
|
// Have we run out of shapes for this cluster?
|
||||||
|
int newShapeId = 0;
|
||||||
|
if (lastShapeId % 1024 == 1023)
|
||||||
|
{
|
||||||
|
// Yes:
|
||||||
|
// Find the starting shape id of the next free cluster
|
||||||
|
newShapeId = findFreeSPIDBlock();
|
||||||
|
// Create a new cluster in the dgg record.
|
||||||
|
dgg.addCluster(drawingGroupId, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No:
|
||||||
|
// Find the cluster for this drawing group with free space.
|
||||||
|
for (int i = 0; i < dgg.getFileIdClusters().length; i++)
|
||||||
|
{
|
||||||
|
EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
|
||||||
|
if (c.getDrawingGroupId() == drawingGroupId)
|
||||||
|
{
|
||||||
|
if (c.getNumShapeIdsUsed() != 1024)
|
||||||
|
{
|
||||||
|
// Increment the number of shapes used for this cluster.
|
||||||
|
c.incrementShapeId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the last shape id = -1 then we know to find a free block;
|
||||||
|
if (dg.getLastMSOSPID() == -1)
|
||||||
|
{
|
||||||
|
newShapeId = findFreeSPIDBlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The new shape id to be the last shapeid of this cluster + 1
|
||||||
|
newShapeId = dg.getLastMSOSPID() + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Increment the total number of shapes used in the dgg.
|
||||||
|
dgg.setNumShapesSaved(dgg.getNumShapesSaved() + 1);
|
||||||
|
// Is the new shape id >= max shape id for dgg?
|
||||||
|
if (newShapeId >= dgg.getShapeIdMax())
|
||||||
|
{
|
||||||
|
// Yes:
|
||||||
|
// Set the max shape id = new shape id + 1
|
||||||
|
dgg.setShapeIdMax(newShapeId + 1);
|
||||||
|
}
|
||||||
|
// Set last shape id for this drawing group.
|
||||||
|
dg.setLastMSOSPID(newShapeId);
|
||||||
|
// Increased the number of shapes used for this drawing group.
|
||||||
|
dg.incrementShapeCount();
|
||||||
|
|
||||||
|
|
||||||
|
return newShapeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////// Non-public methods /////////////
|
||||||
|
short findNewDrawingGroupId()
|
||||||
|
{
|
||||||
|
short dgId = 1;
|
||||||
|
while ( drawingGroupExists( dgId ) )
|
||||||
|
dgId++;
|
||||||
|
return dgId;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean drawingGroupExists( short dgId )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < dgg.getFileIdClusters().length; i++ )
|
||||||
|
{
|
||||||
|
if ( dgg.getFileIdClusters()[i].getDrawingGroupId() == dgId )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int findFreeSPIDBlock()
|
||||||
|
{
|
||||||
|
int max = dgg.getShapeIdMax();
|
||||||
|
int next = ( ( max / 1024 ) + 1 ) * 1024;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherDggRecord getDgg()
|
||||||
|
{
|
||||||
|
return dgg;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
105
src/java/org/apache/poi/hssf/model/LineShape.java
Normal file
105
src/java/org/apache/poi/hssf/model/LineShape.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.*;
|
||||||
|
import org.apache.poi.hssf.record.*;
|
||||||
|
import org.apache.poi.hssf.usermodel.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a line shape and creates all the line specific low level records.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class LineShape
|
||||||
|
extends AbstractShape
|
||||||
|
{
|
||||||
|
private EscherContainerRecord spContainer;
|
||||||
|
private ObjRecord objRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the line shape from the highlevel user shape. All low level
|
||||||
|
* records are created at this point.
|
||||||
|
*
|
||||||
|
* @param hssfShape The user model shape.
|
||||||
|
* @param shapeId The identifier to use for this shape.
|
||||||
|
*/
|
||||||
|
LineShape( HSSFSimpleShape hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
spContainer = createSpContainer(hssfShape, shapeId);
|
||||||
|
objRecord = createObjRecord(hssfShape, shapeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the lowerlevel escher records for this shape.
|
||||||
|
*/
|
||||||
|
private EscherContainerRecord createSpContainer(HSSFSimpleShape hssfShape, int shapeId)
|
||||||
|
{
|
||||||
|
HSSFShape shape = hssfShape;
|
||||||
|
|
||||||
|
EscherContainerRecord spContainer = new EscherContainerRecord();
|
||||||
|
EscherSpRecord sp = new EscherSpRecord();
|
||||||
|
EscherOptRecord opt = new EscherOptRecord();
|
||||||
|
EscherRecord anchor = new EscherClientAnchorRecord();
|
||||||
|
EscherClientDataRecord clientData = new EscherClientDataRecord();
|
||||||
|
|
||||||
|
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
|
spContainer.setOptions( (short) 0x000F );
|
||||||
|
sp.setRecordId( EscherSpRecord.RECORD_ID );
|
||||||
|
sp.setOptions( (short) ( (EscherAggregate.ST_LINE << 4) | 0x2 ) );
|
||||||
|
|
||||||
|
sp.setShapeId( shapeId );
|
||||||
|
sp.setFlags( EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
|
||||||
|
opt.setRecordId( EscherOptRecord.RECORD_ID );
|
||||||
|
opt.addEscherProperty( new EscherShapePathProperty( EscherProperties.GEOMETRY__SHAPEPATH, EscherShapePathProperty.COMPLEX ) );
|
||||||
|
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.LINESTYLE__NOLINEDRAWDASH, 1048592 ) );
|
||||||
|
addStandardOptions(shape, opt);
|
||||||
|
HSSFAnchor userAnchor = shape.getAnchor();
|
||||||
|
if (userAnchor.isHorizontallyFlipped())
|
||||||
|
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPHORIZ);
|
||||||
|
if (userAnchor.isVerticallyFlipped())
|
||||||
|
sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPVERT);
|
||||||
|
anchor = createAnchor(userAnchor);
|
||||||
|
clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
|
||||||
|
clientData.setOptions( (short) 0x0000 );
|
||||||
|
|
||||||
|
spContainer.addChildRecord(sp);
|
||||||
|
spContainer.addChildRecord(opt);
|
||||||
|
spContainer.addChildRecord(anchor);
|
||||||
|
spContainer.addChildRecord(clientData);
|
||||||
|
|
||||||
|
return spContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the low level OBJ record for this shape.
|
||||||
|
*/
|
||||||
|
private ObjRecord createObjRecord(HSSFShape hssfShape, int shapeId)
|
||||||
|
{
|
||||||
|
HSSFShape shape = hssfShape;
|
||||||
|
|
||||||
|
ObjRecord obj = new ObjRecord();
|
||||||
|
CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
|
||||||
|
c.setObjectType((short) ((HSSFSimpleShape)shape).getShapeType());
|
||||||
|
c.setObjectId((short) ( shapeId ));
|
||||||
|
c.setLocked(true);
|
||||||
|
c.setPrintable(true);
|
||||||
|
c.setAutofill(true);
|
||||||
|
c.setAutoline(true);
|
||||||
|
EndSubRecord e = new EndSubRecord();
|
||||||
|
|
||||||
|
obj.addSubRecord(c);
|
||||||
|
obj.addSubRecord(e);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherContainerRecord getSpContainer()
|
||||||
|
{
|
||||||
|
return spContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjRecord getObjRecord()
|
||||||
|
{
|
||||||
|
return objRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
143
src/java/org/apache/poi/hssf/model/PolygonShape.java
Normal file
143
src/java/org/apache/poi/hssf/model/PolygonShape.java
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.*;
|
||||||
|
import org.apache.poi.hssf.record.ObjRecord;
|
||||||
|
import org.apache.poi.hssf.record.EscherAggregate;
|
||||||
|
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
|
||||||
|
import org.apache.poi.hssf.record.EndSubRecord;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFShape;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFPolygon;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
public class PolygonShape
|
||||||
|
extends AbstractShape
|
||||||
|
{
|
||||||
|
public final static short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 30;
|
||||||
|
|
||||||
|
private EscherContainerRecord spContainer;
|
||||||
|
private ObjRecord objRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the low evel records for an polygon.
|
||||||
|
*
|
||||||
|
* @param hssfShape The highlevel shape.
|
||||||
|
* @param shapeId The shape id to use for this shape.
|
||||||
|
*/
|
||||||
|
PolygonShape( HSSFPolygon hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
spContainer = createSpContainer( hssfShape, shapeId );
|
||||||
|
objRecord = createObjRecord( hssfShape, shapeId );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the shape records for this shape.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private EscherContainerRecord createSpContainer( HSSFPolygon hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
HSSFShape shape = hssfShape;
|
||||||
|
|
||||||
|
EscherContainerRecord spContainer = new EscherContainerRecord();
|
||||||
|
EscherSpRecord sp = new EscherSpRecord();
|
||||||
|
EscherOptRecord opt = new EscherOptRecord();
|
||||||
|
EscherClientDataRecord clientData = new EscherClientDataRecord();
|
||||||
|
|
||||||
|
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
|
spContainer.setOptions( (short) 0x000F );
|
||||||
|
sp.setRecordId( EscherSpRecord.RECORD_ID );
|
||||||
|
sp.setOptions( (short) ( ( EscherAggregate.ST_DONUT << 4 ) | 0x2 ) );
|
||||||
|
sp.setShapeId( shapeId );
|
||||||
|
if (hssfShape.getParent() == null)
|
||||||
|
sp.setFlags( EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
|
||||||
|
else
|
||||||
|
sp.setFlags( EscherSpRecord.FLAG_CHILD | EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
|
||||||
|
opt.setRecordId( EscherOptRecord.RECORD_ID );
|
||||||
|
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.TRANSFORM__ROTATION, false, false, 0));
|
||||||
|
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__RIGHT, false, false, hssfShape.getDrawAreaWidth()));
|
||||||
|
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__BOTTOM, false, false, hssfShape.getDrawAreaHeight()));
|
||||||
|
opt.addEscherProperty(new EscherShapePathProperty(EscherProperties.GEOMETRY__SHAPEPATH, EscherShapePathProperty.COMPLEX));
|
||||||
|
EscherArrayProperty verticesProp = new EscherArrayProperty(EscherProperties.GEOMETRY__VERTICES, false, new byte[0] );
|
||||||
|
verticesProp.setNumberOfElementsInArray(hssfShape.getXPoints().length+1);
|
||||||
|
verticesProp.setNumberOfElementsInMemory(hssfShape.getXPoints().length+1);
|
||||||
|
verticesProp.setSizeOfElements(0xFFF0);
|
||||||
|
for (int i = 0; i < hssfShape.getXPoints().length; i++)
|
||||||
|
{
|
||||||
|
byte[] data = new byte[4];
|
||||||
|
LittleEndian.putShort(data, 0, (short)hssfShape.getXPoints()[i]);
|
||||||
|
LittleEndian.putShort(data, 2, (short)hssfShape.getYPoints()[i]);
|
||||||
|
verticesProp.setElement(i, data);
|
||||||
|
}
|
||||||
|
int point = hssfShape.getXPoints().length;
|
||||||
|
byte[] data = new byte[4];
|
||||||
|
LittleEndian.putShort(data, 0, (short)hssfShape.getXPoints()[0]);
|
||||||
|
LittleEndian.putShort(data, 2, (short)hssfShape.getYPoints()[0]);
|
||||||
|
verticesProp.setElement(point, data);
|
||||||
|
opt.addEscherProperty(verticesProp);
|
||||||
|
EscherArrayProperty segmentsProp = new EscherArrayProperty(EscherProperties.GEOMETRY__SEGMENTINFO, false, null );
|
||||||
|
segmentsProp.setSizeOfElements(0x0002);
|
||||||
|
segmentsProp.setNumberOfElementsInArray(hssfShape.getXPoints().length * 2 + 4);
|
||||||
|
segmentsProp.setNumberOfElementsInMemory(hssfShape.getXPoints().length * 2 + 4);
|
||||||
|
segmentsProp.setElement(0, new byte[] { (byte)0x00, (byte)0x40 } );
|
||||||
|
segmentsProp.setElement(1, new byte[] { (byte)0x00, (byte)0xAC } );
|
||||||
|
for (int i = 0; i < hssfShape.getXPoints().length; i++)
|
||||||
|
{
|
||||||
|
segmentsProp.setElement(2 + i * 2, new byte[] { (byte)0x01, (byte)0x00 } );
|
||||||
|
segmentsProp.setElement(3 + i * 2, new byte[] { (byte)0x00, (byte)0xAC } );
|
||||||
|
}
|
||||||
|
segmentsProp.setElement(segmentsProp.getNumberOfElementsInArray() - 2, new byte[] { (byte)0x01, (byte)0x60 } );
|
||||||
|
segmentsProp.setElement(segmentsProp.getNumberOfElementsInArray() - 1, new byte[] { (byte)0x00, (byte)0x80 } );
|
||||||
|
opt.addEscherProperty(segmentsProp);
|
||||||
|
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__FILLOK, false, false, 0x00010001));
|
||||||
|
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__LINESTARTARROWHEAD, false, false, 0x0));
|
||||||
|
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__LINEENDARROWHEAD, false, false, 0x0));
|
||||||
|
opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__LINEENDCAPSTYLE, false, false, 0x0));
|
||||||
|
|
||||||
|
addStandardOptions(shape, opt);
|
||||||
|
|
||||||
|
EscherRecord anchor = createAnchor( shape.getAnchor() );
|
||||||
|
clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
|
||||||
|
clientData.setOptions( (short) 0x0000 );
|
||||||
|
|
||||||
|
spContainer.addChildRecord( sp );
|
||||||
|
spContainer.addChildRecord( opt );
|
||||||
|
spContainer.addChildRecord( anchor );
|
||||||
|
spContainer.addChildRecord( clientData );
|
||||||
|
|
||||||
|
return spContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the low level OBJ record for this shape.
|
||||||
|
*/
|
||||||
|
private ObjRecord createObjRecord( HSSFShape hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
HSSFShape shape = hssfShape;
|
||||||
|
|
||||||
|
ObjRecord obj = new ObjRecord();
|
||||||
|
CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
|
||||||
|
c.setObjectType( OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING );
|
||||||
|
c.setObjectId( (short) ( shapeId ) );
|
||||||
|
c.setLocked( true );
|
||||||
|
c.setPrintable( true );
|
||||||
|
c.setAutofill( true );
|
||||||
|
c.setAutoline( true );
|
||||||
|
EndSubRecord e = new EndSubRecord();
|
||||||
|
|
||||||
|
obj.addSubRecord( c );
|
||||||
|
obj.addSubRecord( e );
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherContainerRecord getSpContainer()
|
||||||
|
{
|
||||||
|
return spContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjRecord getObjRecord()
|
||||||
|
{
|
||||||
|
return objRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -122,6 +122,8 @@ public class Sheet implements Model
|
|||||||
private Iterator rowRecIterator = null;
|
private Iterator rowRecIterator = null;
|
||||||
protected int eofLoc = 0;
|
protected int eofLoc = 0;
|
||||||
protected ProtectRecord protect = null;
|
protected ProtectRecord protect = null;
|
||||||
|
protected PageBreakRecord rowBreaks = null;
|
||||||
|
protected PageBreakRecord colBreaks = null;
|
||||||
|
|
||||||
public static final byte PANE_LOWER_RIGHT = (byte)0;
|
public static final byte PANE_LOWER_RIGHT = (byte)0;
|
||||||
public static final byte PANE_UPPER_RIGHT = (byte)1;
|
public static final byte PANE_UPPER_RIGHT = (byte)1;
|
||||||
@ -155,7 +157,7 @@ public class Sheet implements Model
|
|||||||
*/
|
*/
|
||||||
public static Sheet createSheet(List recs, int sheetnum, int offset)
|
public static Sheet createSheet(List recs, int sheetnum, int offset)
|
||||||
{
|
{
|
||||||
log.logFormatted(log.DEBUG,
|
log.logFormatted(POILogger.DEBUG,
|
||||||
"Sheet createSheet (existing file) with %",
|
"Sheet createSheet (existing file) with %",
|
||||||
new Integer(recs.size()));
|
new Integer(recs.size()));
|
||||||
Sheet retval = new Sheet();
|
Sheet retval = new Sheet();
|
||||||
@ -170,18 +172,18 @@ public class Sheet implements Model
|
|||||||
|
|
||||||
if (rec.getSid() == LabelRecord.sid)
|
if (rec.getSid() == LabelRecord.sid)
|
||||||
{
|
{
|
||||||
log.log(log.DEBUG, "Hit label record.");
|
log.log(POILogger.DEBUG, "Hit label record.");
|
||||||
retval.containsLabels = true;
|
retval.containsLabels = true;
|
||||||
}
|
}
|
||||||
else if (rec.getSid() == BOFRecord.sid)
|
else if (rec.getSid() == BOFRecord.sid)
|
||||||
{
|
{
|
||||||
bofEofNestingLevel++;
|
bofEofNestingLevel++;
|
||||||
log.log(log.DEBUG, "Hit BOF record. Nesting increased to " + bofEofNestingLevel);
|
log.log(POILogger.DEBUG, "Hit BOF record. Nesting increased to " + bofEofNestingLevel);
|
||||||
}
|
}
|
||||||
else if (rec.getSid() == EOFRecord.sid)
|
else if (rec.getSid() == EOFRecord.sid)
|
||||||
{
|
{
|
||||||
--bofEofNestingLevel;
|
--bofEofNestingLevel;
|
||||||
log.log(log.DEBUG, "Hit EOF record. Nesting decreased to " + bofEofNestingLevel);
|
log.log(POILogger.DEBUG, "Hit EOF record. Nesting decreased to " + bofEofNestingLevel);
|
||||||
if (bofEofNestingLevel == 0) {
|
if (bofEofNestingLevel == 0) {
|
||||||
records.add(rec);
|
records.add(rec);
|
||||||
retval.eofLoc = k;
|
retval.eofLoc = k;
|
||||||
@ -296,6 +298,14 @@ public class Sheet implements Model
|
|||||||
{
|
{
|
||||||
rec = null;
|
rec = null;
|
||||||
}
|
}
|
||||||
|
else if (rec.getSid() == PageBreakRecord.HORIZONTAL_SID)
|
||||||
|
{
|
||||||
|
retval.rowBreaks = (PageBreakRecord)rec;
|
||||||
|
}
|
||||||
|
else if (rec.getSid() == PageBreakRecord.VERTICAL_SID)
|
||||||
|
{
|
||||||
|
retval.colBreaks = (PageBreakRecord)rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (rec != null)
|
if (rec != null)
|
||||||
@ -312,7 +322,7 @@ public class Sheet implements Model
|
|||||||
{
|
{
|
||||||
retval.cells = new ValueRecordsAggregate();
|
retval.cells = new ValueRecordsAggregate();
|
||||||
}
|
}
|
||||||
log.log(log.DEBUG, "sheet createSheet (existing file) exited");
|
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +381,7 @@ public class Sheet implements Model
|
|||||||
|
|
||||||
public static Sheet createSheet(List records, int sheetnum)
|
public static Sheet createSheet(List records, int sheetnum)
|
||||||
{
|
{
|
||||||
log.log(log.DEBUG,
|
log.log(POILogger.DEBUG,
|
||||||
"Sheet createSheet (exisiting file) assumed offset 0");
|
"Sheet createSheet (exisiting file) assumed offset 0");
|
||||||
return createSheet(records, sheetnum, 0);
|
return createSheet(records, sheetnum, 0);
|
||||||
}
|
}
|
||||||
@ -386,7 +396,7 @@ public class Sheet implements Model
|
|||||||
|
|
||||||
public static Sheet createSheet()
|
public static Sheet createSheet()
|
||||||
{
|
{
|
||||||
log.log(log.DEBUG, "Sheet createsheet from scratch called");
|
log.log(POILogger.DEBUG, "Sheet createsheet from scratch called");
|
||||||
Sheet retval = new Sheet();
|
Sheet retval = new Sheet();
|
||||||
ArrayList records = new ArrayList(30);
|
ArrayList records = new ArrayList(30);
|
||||||
|
|
||||||
@ -409,6 +419,10 @@ public class Sheet implements Model
|
|||||||
(DefaultRowHeightRecord) retval.createDefaultRowHeight();
|
(DefaultRowHeightRecord) retval.createDefaultRowHeight();
|
||||||
records.add( retval.defaultrowheight );
|
records.add( retval.defaultrowheight );
|
||||||
records.add( retval.createWSBool() );
|
records.add( retval.createWSBool() );
|
||||||
|
retval.rowBreaks = new PageBreakRecord(PageBreakRecord.HORIZONTAL_SID);
|
||||||
|
records.add(retval.rowBreaks);
|
||||||
|
retval.colBreaks = new PageBreakRecord(PageBreakRecord.VERTICAL_SID);
|
||||||
|
records.add(retval.colBreaks);
|
||||||
retval.header = (HeaderRecord) retval.createHeader();
|
retval.header = (HeaderRecord) retval.createHeader();
|
||||||
records.add( retval.header );
|
records.add( retval.header );
|
||||||
retval.footer = (FooterRecord) retval.createFooter();
|
retval.footer = (FooterRecord) retval.createFooter();
|
||||||
@ -421,7 +435,7 @@ public class Sheet implements Model
|
|||||||
(DefaultColWidthRecord) retval.createDefaultColWidth();
|
(DefaultColWidthRecord) retval.createDefaultColWidth();
|
||||||
records.add( retval.defaultcolwidth);
|
records.add( retval.defaultcolwidth);
|
||||||
retval.dims = ( DimensionsRecord ) retval.createDimensions();
|
retval.dims = ( DimensionsRecord ) retval.createDimensions();
|
||||||
retval.dimsloc = 19;
|
retval.dimsloc = records.size()-1;
|
||||||
records.add(retval.dims);
|
records.add(retval.dims);
|
||||||
records.add(retval.windowTwo = retval.createWindowTwo());
|
records.add(retval.windowTwo = retval.createWindowTwo());
|
||||||
retval.setLoc(records.size() - 1);
|
retval.setLoc(records.size() - 1);
|
||||||
@ -432,7 +446,7 @@ public class Sheet implements Model
|
|||||||
records.add(retval.protect);
|
records.add(retval.protect);
|
||||||
records.add(retval.createEOF());
|
records.add(retval.createEOF());
|
||||||
retval.records = records;
|
retval.records = records;
|
||||||
log.log(log.DEBUG, "Sheet createsheet from scratch exit");
|
log.log(POILogger.DEBUG, "Sheet createsheet from scratch exit");
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,7 +590,7 @@ public class Sheet implements Model
|
|||||||
|
|
||||||
public void convertLabelRecords(Workbook wb)
|
public void convertLabelRecords(Workbook wb)
|
||||||
{
|
{
|
||||||
log.log(log.DEBUG, "convertLabelRecords called");
|
log.log(POILogger.DEBUG, "convertLabelRecords called");
|
||||||
if (containsLabels)
|
if (containsLabels)
|
||||||
{
|
{
|
||||||
for (int k = 0; k < records.size(); k++)
|
for (int k = 0; k < records.size(); k++)
|
||||||
@ -600,7 +614,7 @@ public class Sheet implements Model
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.log(log.DEBUG, "convertLabelRecords exit");
|
log.log(POILogger.DEBUG, "convertLabelRecords exit");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -614,8 +628,8 @@ public class Sheet implements Model
|
|||||||
{
|
{
|
||||||
checkCells();
|
checkCells();
|
||||||
checkRows();
|
checkRows();
|
||||||
log.log(log.DEBUG, "Sheet.getNumRecords");
|
log.log(POILogger.DEBUG, "Sheet.getNumRecords");
|
||||||
log.logFormatted(log.DEBUG, "returning % + % + % - 2 = %", new int[]
|
log.logFormatted(POILogger.DEBUG, "returning % + % + % - 2 = %", new int[]
|
||||||
{
|
{
|
||||||
records.size(), cells.getPhysicalNumberOfCells(),
|
records.size(), cells.getPhysicalNumberOfCells(),
|
||||||
rows.getPhysicalNumberOfRows(),
|
rows.getPhysicalNumberOfRows(),
|
||||||
@ -638,8 +652,8 @@ public class Sheet implements Model
|
|||||||
public void setDimensions(int firstrow, short firstcol, int lastrow,
|
public void setDimensions(int firstrow, short firstcol, int lastrow,
|
||||||
short lastcol)
|
short lastcol)
|
||||||
{
|
{
|
||||||
log.log(log.DEBUG, "Sheet.setDimensions");
|
log.log(POILogger.DEBUG, "Sheet.setDimensions");
|
||||||
log.log(log.DEBUG,
|
log.log(POILogger.DEBUG,
|
||||||
(new StringBuffer("firstrow")).append(firstrow)
|
(new StringBuffer("firstrow")).append(firstrow)
|
||||||
.append("firstcol").append(firstcol).append("lastrow")
|
.append("firstcol").append(firstcol).append("lastrow")
|
||||||
.append(lastrow).append("lastcol").append(lastcol)
|
.append(lastrow).append("lastcol").append(lastcol)
|
||||||
@ -2560,4 +2574,192 @@ public class Sheet implements Model
|
|||||||
{
|
{
|
||||||
return protect;
|
return protect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int aggregateDrawingRecords(DrawingManager drawingManager)
|
||||||
|
{
|
||||||
|
int loc = findFirstRecordLocBySid(DrawingRecord.sid);
|
||||||
|
boolean noDrawingRecordsFound = loc == -1;
|
||||||
|
if (noDrawingRecordsFound)
|
||||||
|
{
|
||||||
|
EscherAggregate aggregate = new EscherAggregate( drawingManager );
|
||||||
|
loc = findFirstRecordLocBySid(EscherAggregate.sid);
|
||||||
|
if (loc == -1)
|
||||||
|
{
|
||||||
|
loc = findFirstRecordLocBySid( WindowTwoRecord.sid );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
getRecords().remove(loc);
|
||||||
|
}
|
||||||
|
getRecords().add( loc, aggregate );
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List records = getRecords();
|
||||||
|
EscherAggregate r = EscherAggregate.createAggregate( records, loc, drawingManager );
|
||||||
|
int startloc = loc;
|
||||||
|
while ( loc + 1 < records.size()
|
||||||
|
&& records.get( loc ) instanceof DrawingRecord
|
||||||
|
&& records.get( loc + 1 ) instanceof ObjRecord )
|
||||||
|
{
|
||||||
|
loc += 2;
|
||||||
|
}
|
||||||
|
int endloc = loc-1;
|
||||||
|
for(int i = 0; i < (endloc - startloc + 1); i++)
|
||||||
|
records.remove(startloc);
|
||||||
|
records.add(startloc, r);
|
||||||
|
|
||||||
|
return startloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform any work necessary before the sheet is about to be serialized.
|
||||||
|
* For instance the escher aggregates size needs to be calculated before
|
||||||
|
* serialization so that the dgg record (which occurs first) can be written.
|
||||||
|
*/
|
||||||
|
public void preSerialize()
|
||||||
|
{
|
||||||
|
for ( Iterator iterator = getRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
Record r = (Record) iterator.next();
|
||||||
|
if (r instanceof EscherAggregate)
|
||||||
|
r.getRecordSize(); // Trigger flatterning of user model and corresponding update of dgg record.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shifts all the page breaks in the range "count" number of rows/columns
|
||||||
|
* @param breaks The page record to be shifted
|
||||||
|
* @param start Starting "main" value to shift breaks
|
||||||
|
* @param stop Ending "main" value to shift breaks
|
||||||
|
* @param count number of units (rows/columns) to shift by
|
||||||
|
*/
|
||||||
|
public void shiftBreaks(PageBreakRecord breaks, short start, short stop, int count) {
|
||||||
|
|
||||||
|
if(rowBreaks == null)
|
||||||
|
return;
|
||||||
|
Iterator iterator = breaks.getBreaksIterator();
|
||||||
|
List shiftedBreak = new ArrayList();
|
||||||
|
while(iterator.hasNext())
|
||||||
|
{
|
||||||
|
PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
|
||||||
|
short breakLocation = breakItem.main;
|
||||||
|
boolean inStart = (breakLocation >= start);
|
||||||
|
boolean inEnd = (breakLocation <= stop);
|
||||||
|
if(inStart && inEnd)
|
||||||
|
shiftedBreak.add(breakItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator = shiftedBreak.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
PageBreakRecord.Break breakItem = (PageBreakRecord.Break)iterator.next();
|
||||||
|
breaks.removeBreak(breakItem.main);
|
||||||
|
breaks.addBreak((short)(breakItem.main+count), breakItem.subFrom, breakItem.subTo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a page break at the indicated row
|
||||||
|
* @param row
|
||||||
|
*/
|
||||||
|
public void setRowBreak(int row, short fromCol, short toCol) {
|
||||||
|
rowBreaks.addBreak((short)row, fromCol, toCol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a page break at the indicated row
|
||||||
|
* @param row
|
||||||
|
*/
|
||||||
|
public void removeRowBreak(int row) {
|
||||||
|
rowBreaks.removeBreak((short)row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries if the specified row has a page break
|
||||||
|
* @param row
|
||||||
|
* @return true if the specified row has a page break
|
||||||
|
*/
|
||||||
|
public boolean isRowBroken(int row) {
|
||||||
|
return rowBreaks.getBreak((short)row) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a page break at the indicated column
|
||||||
|
* @param row
|
||||||
|
*/
|
||||||
|
public void setColumnBreak(short column, short fromRow, short toRow) {
|
||||||
|
colBreaks.addBreak(column, fromRow, toRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a page break at the indicated column
|
||||||
|
* @param row
|
||||||
|
*/
|
||||||
|
public void removeColumnBreak(short column) {
|
||||||
|
colBreaks.removeBreak(column);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queries if the specified column has a page break
|
||||||
|
* @param row
|
||||||
|
* @return true if the specified column has a page break
|
||||||
|
*/
|
||||||
|
public boolean isColumnBroken(short column) {
|
||||||
|
return colBreaks.getBreak(column) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shifts the horizontal page breaks for the indicated count
|
||||||
|
* @param startingRow
|
||||||
|
* @param endingRow
|
||||||
|
* @param count
|
||||||
|
*/
|
||||||
|
public void shiftRowBreaks(int startingRow, int endingRow, int count) {
|
||||||
|
shiftBreaks(rowBreaks, (short)startingRow, (short)endingRow, (short)count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shifts the vertical page breaks for the indicated count
|
||||||
|
* @param startingCol
|
||||||
|
* @param endingCol
|
||||||
|
* @param count
|
||||||
|
*/
|
||||||
|
public void shiftColumnBreaks(short startingCol, short endingCol, short count) {
|
||||||
|
shiftBreaks(colBreaks, startingCol, endingCol, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the row page breaks
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Iterator getRowBreaks() {
|
||||||
|
return rowBreaks.getBreaksIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of row page breaks
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getNumRowBreaks(){
|
||||||
|
return (int)rowBreaks.getNumBreaks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the column page breaks
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Iterator getColumnBreaks(){
|
||||||
|
return colBreaks.getBreaksIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of column page breaks
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getNumColumnBreaks(){
|
||||||
|
return (int)colBreaks.getNumBreaks();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
111
src/java/org/apache/poi/hssf/model/SimpleFilledShape.java
Normal file
111
src/java/org/apache/poi/hssf/model/SimpleFilledShape.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.*;
|
||||||
|
import org.apache.poi.hssf.record.ObjRecord;
|
||||||
|
import org.apache.poi.hssf.record.EscherAggregate;
|
||||||
|
import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
|
||||||
|
import org.apache.poi.hssf.record.EndSubRecord;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFShape;
|
||||||
|
|
||||||
|
public class SimpleFilledShape
|
||||||
|
extends AbstractShape
|
||||||
|
{
|
||||||
|
private EscherContainerRecord spContainer;
|
||||||
|
private ObjRecord objRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the low evel records for an oval.
|
||||||
|
*
|
||||||
|
* @param hssfShape The highlevel shape.
|
||||||
|
* @param shapeId The shape id to use for this shape.
|
||||||
|
*/
|
||||||
|
SimpleFilledShape( HSSFSimpleShape hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
spContainer = createSpContainer( hssfShape, shapeId );
|
||||||
|
objRecord = createObjRecord( hssfShape, shapeId );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the shape records for this shape.
|
||||||
|
*
|
||||||
|
* @param hssfShape
|
||||||
|
* @param shapeId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private EscherContainerRecord createSpContainer( HSSFSimpleShape hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
HSSFShape shape = hssfShape;
|
||||||
|
|
||||||
|
EscherContainerRecord spContainer = new EscherContainerRecord();
|
||||||
|
EscherSpRecord sp = new EscherSpRecord();
|
||||||
|
EscherOptRecord opt = new EscherOptRecord();
|
||||||
|
EscherClientDataRecord clientData = new EscherClientDataRecord();
|
||||||
|
|
||||||
|
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
|
spContainer.setOptions( (short) 0x000F );
|
||||||
|
sp.setRecordId( EscherSpRecord.RECORD_ID );
|
||||||
|
short shapeType = objTypeToShapeType( hssfShape.getShapeType() );
|
||||||
|
sp.setOptions( (short) ( ( shapeType << 4 ) | 0x2 ) );
|
||||||
|
sp.setShapeId( shapeId );
|
||||||
|
sp.setFlags( EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
|
||||||
|
opt.setRecordId( EscherOptRecord.RECORD_ID );
|
||||||
|
addStandardOptions(shape, opt);
|
||||||
|
EscherRecord anchor = createAnchor( shape.getAnchor() );
|
||||||
|
clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
|
||||||
|
clientData.setOptions( (short) 0x0000 );
|
||||||
|
|
||||||
|
spContainer.addChildRecord( sp );
|
||||||
|
spContainer.addChildRecord( opt );
|
||||||
|
spContainer.addChildRecord( anchor );
|
||||||
|
spContainer.addChildRecord( clientData );
|
||||||
|
|
||||||
|
return spContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private short objTypeToShapeType( int objType )
|
||||||
|
{
|
||||||
|
short shapeType;
|
||||||
|
if (objType == HSSFSimpleShape.OBJECT_TYPE_OVAL)
|
||||||
|
shapeType = EscherAggregate.ST_ELLIPSE;
|
||||||
|
else if (objType == HSSFSimpleShape.OBJECT_TYPE_RECTANGLE)
|
||||||
|
shapeType = EscherAggregate.ST_RECTANGLE;
|
||||||
|
else
|
||||||
|
throw new IllegalArgumentException("Unable to handle an object of this type");
|
||||||
|
return shapeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the low level OBJ record for this shape.
|
||||||
|
*/
|
||||||
|
private ObjRecord createObjRecord( HSSFShape hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
HSSFShape shape = hssfShape;
|
||||||
|
|
||||||
|
ObjRecord obj = new ObjRecord();
|
||||||
|
CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
|
||||||
|
c.setObjectType( (short) ( (HSSFSimpleShape) shape ).getShapeType() );
|
||||||
|
c.setObjectId( (short) ( shapeId ) );
|
||||||
|
c.setLocked( true );
|
||||||
|
c.setPrintable( true );
|
||||||
|
c.setAutofill( true );
|
||||||
|
c.setAutoline( true );
|
||||||
|
EndSubRecord e = new EndSubRecord();
|
||||||
|
|
||||||
|
obj.addSubRecord( c );
|
||||||
|
obj.addSubRecord( e );
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherContainerRecord getSpContainer()
|
||||||
|
{
|
||||||
|
return spContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjRecord getObjRecord()
|
||||||
|
{
|
||||||
|
return objRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
src/java/org/apache/poi/hssf/model/TestDrawingManager.java
Normal file
81
src/java/org/apache/poi/hssf/model/TestDrawingManager.java
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.ddf.EscherDggRecord;
|
||||||
|
import org.apache.poi.ddf.EscherDgRecord;
|
||||||
|
|
||||||
|
public class TestDrawingManager extends TestCase
|
||||||
|
{
|
||||||
|
public void testFindFreeSPIDBlock() throws Exception
|
||||||
|
{
|
||||||
|
EscherDggRecord dgg = new EscherDggRecord();
|
||||||
|
DrawingManager dm = new DrawingManager( dgg );
|
||||||
|
dgg.setShapeIdMax( 1024 );
|
||||||
|
assertEquals( 2048, dm.findFreeSPIDBlock() );
|
||||||
|
dgg.setShapeIdMax( 1025 );
|
||||||
|
assertEquals( 2048, dm.findFreeSPIDBlock() );
|
||||||
|
dgg.setShapeIdMax( 2047 );
|
||||||
|
assertEquals( 2048, dm.findFreeSPIDBlock() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFindNewDrawingGroupId() throws Exception
|
||||||
|
{
|
||||||
|
EscherDggRecord dgg = new EscherDggRecord();
|
||||||
|
dgg.setDrawingsSaved( 1 );
|
||||||
|
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{
|
||||||
|
new EscherDggRecord.FileIdCluster( 2, 10 )} );
|
||||||
|
DrawingManager dm = new DrawingManager( dgg );
|
||||||
|
assertEquals( 1, dm.findNewDrawingGroupId() );
|
||||||
|
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{
|
||||||
|
new EscherDggRecord.FileIdCluster( 1, 10 ),
|
||||||
|
new EscherDggRecord.FileIdCluster( 2, 10 )} );
|
||||||
|
assertEquals( 3, dm.findNewDrawingGroupId() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDrawingGroupExists() throws Exception
|
||||||
|
{
|
||||||
|
EscherDggRecord dgg = new EscherDggRecord();
|
||||||
|
dgg.setDrawingsSaved( 1 );
|
||||||
|
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{
|
||||||
|
new EscherDggRecord.FileIdCluster( 2, 10 )} );
|
||||||
|
DrawingManager dm = new DrawingManager( dgg );
|
||||||
|
assertFalse( dm.drawingGroupExists( (short) 1 ) );
|
||||||
|
assertTrue( dm.drawingGroupExists( (short) 2 ) );
|
||||||
|
assertFalse( dm.drawingGroupExists( (short) 3 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateDgRecord() throws Exception
|
||||||
|
{
|
||||||
|
EscherDggRecord dgg = new EscherDggRecord();
|
||||||
|
dgg.setDrawingsSaved( 0 );
|
||||||
|
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{} );
|
||||||
|
DrawingManager dm = new DrawingManager( dgg );
|
||||||
|
|
||||||
|
EscherDgRecord dgRecord = dm.createDgRecord();
|
||||||
|
assertEquals( -1, dgRecord.getLastMSOSPID() );
|
||||||
|
assertEquals( 0, dgRecord.getNumShapes() );
|
||||||
|
assertEquals( 1, dm.getDgg().getDrawingsSaved() );
|
||||||
|
assertEquals( 1, dm.getDgg().getFileIdClusters().length );
|
||||||
|
assertEquals( 1, dm.getDgg().getFileIdClusters()[0].getDrawingGroupId() );
|
||||||
|
assertEquals( 0, dm.getDgg().getFileIdClusters()[0].getNumShapeIdsUsed() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllocateShapeId() throws Exception
|
||||||
|
{
|
||||||
|
EscherDggRecord dgg = new EscherDggRecord();
|
||||||
|
dgg.setDrawingsSaved( 0 );
|
||||||
|
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{} );
|
||||||
|
DrawingManager dm = new DrawingManager( dgg );
|
||||||
|
|
||||||
|
EscherDgRecord dg = dm.createDgRecord();
|
||||||
|
int shapeId = dm.allocateShapeId( dg.getDrawingGroupId() );
|
||||||
|
assertEquals( 1024, shapeId );
|
||||||
|
assertEquals( 1025, dgg.getShapeIdMax() );
|
||||||
|
assertEquals( 1, dgg.getDrawingsSaved() );
|
||||||
|
assertEquals( 1, dgg.getFileIdClusters()[0].getDrawingGroupId() );
|
||||||
|
assertEquals( 1, dgg.getFileIdClusters()[0].getNumShapeIdsUsed() );
|
||||||
|
assertEquals( 1024, dg.getLastMSOSPID() );
|
||||||
|
assertEquals( 1, dg.getNumShapes() );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
151
src/java/org/apache/poi/hssf/model/TextboxShape.java
Normal file
151
src/java/org/apache/poi/hssf/model/TextboxShape.java
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package org.apache.poi.hssf.model;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.*;
|
||||||
|
import org.apache.poi.hssf.record.*;
|
||||||
|
import org.apache.poi.hssf.usermodel.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an textbox shape and converts between the highlevel records
|
||||||
|
* and lowlevel records for an oval.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class TextboxShape
|
||||||
|
extends AbstractShape
|
||||||
|
{
|
||||||
|
private EscherContainerRecord spContainer;
|
||||||
|
private TextObjectRecord textObjectRecord;
|
||||||
|
private ObjRecord objRecord;
|
||||||
|
private EscherTextboxRecord escherTextbox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the low evel records for an textbox.
|
||||||
|
*
|
||||||
|
* @param hssfShape The highlevel shape.
|
||||||
|
* @param shapeId The shape id to use for this shape.
|
||||||
|
*/
|
||||||
|
TextboxShape( HSSFTextbox hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
spContainer = createSpContainer( hssfShape, shapeId );
|
||||||
|
objRecord = createObjRecord( hssfShape, shapeId );
|
||||||
|
textObjectRecord = createTextObjectRecord( hssfShape, shapeId );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the low level OBJ record for this shape.
|
||||||
|
*/
|
||||||
|
private ObjRecord createObjRecord( HSSFTextbox hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
HSSFShape shape = hssfShape;
|
||||||
|
|
||||||
|
ObjRecord obj = new ObjRecord();
|
||||||
|
CommonObjectDataSubRecord c = new CommonObjectDataSubRecord();
|
||||||
|
c.setObjectType( (short) ( (HSSFSimpleShape) shape ).getShapeType() );
|
||||||
|
c.setObjectId( (short) ( shapeId ) );
|
||||||
|
c.setLocked( true );
|
||||||
|
c.setPrintable( true );
|
||||||
|
c.setAutofill( true );
|
||||||
|
c.setAutoline( true );
|
||||||
|
EndSubRecord e = new EndSubRecord();
|
||||||
|
|
||||||
|
obj.addSubRecord( c );
|
||||||
|
obj.addSubRecord( e );
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the escher shape records for this shape.
|
||||||
|
*
|
||||||
|
* @param hssfShape
|
||||||
|
* @param shapeId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private EscherContainerRecord createSpContainer( HSSFTextbox hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
HSSFTextbox shape = hssfShape;
|
||||||
|
|
||||||
|
EscherContainerRecord spContainer = new EscherContainerRecord();
|
||||||
|
EscherSpRecord sp = new EscherSpRecord();
|
||||||
|
EscherOptRecord opt = new EscherOptRecord();
|
||||||
|
EscherRecord anchor = new EscherClientAnchorRecord();
|
||||||
|
EscherClientDataRecord clientData = new EscherClientDataRecord();
|
||||||
|
escherTextbox = new EscherTextboxRecord();
|
||||||
|
|
||||||
|
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
|
spContainer.setOptions( (short) 0x000F );
|
||||||
|
sp.setRecordId( EscherSpRecord.RECORD_ID );
|
||||||
|
sp.setOptions( (short) ( ( EscherAggregate.ST_TEXTBOX << 4 ) | 0x2 ) );
|
||||||
|
|
||||||
|
sp.setShapeId( shapeId );
|
||||||
|
sp.setFlags( EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE );
|
||||||
|
opt.setRecordId( EscherOptRecord.RECORD_ID );
|
||||||
|
// opt.addEscherProperty( new EscherBoolProperty( EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144 ) );
|
||||||
|
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTID, 0 ) );
|
||||||
|
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTLEFT, shape.getMarginLeft() ) );
|
||||||
|
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTRIGHT, shape.getMarginRight() ) );
|
||||||
|
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTBOTTOM, shape.getMarginBottom() ) );
|
||||||
|
opt.addEscherProperty( new EscherSimpleProperty( EscherProperties.TEXT__TEXTTOP, shape.getMarginTop() ) );
|
||||||
|
addStandardOptions( shape, opt );
|
||||||
|
HSSFAnchor userAnchor = shape.getAnchor();
|
||||||
|
// if (userAnchor.isHorizontallyFlipped())
|
||||||
|
// sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPHORIZ);
|
||||||
|
// if (userAnchor.isVerticallyFlipped())
|
||||||
|
// sp.setFlags(sp.getFlags() | EscherSpRecord.FLAG_FLIPVERT);
|
||||||
|
anchor = createAnchor( userAnchor );
|
||||||
|
clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
|
||||||
|
clientData.setOptions( (short) 0x0000 );
|
||||||
|
escherTextbox.setRecordId( EscherTextboxRecord.RECORD_ID );
|
||||||
|
escherTextbox.setOptions( (short) 0x0000 );
|
||||||
|
|
||||||
|
spContainer.addChildRecord( sp );
|
||||||
|
spContainer.addChildRecord( opt );
|
||||||
|
spContainer.addChildRecord( anchor );
|
||||||
|
spContainer.addChildRecord( clientData );
|
||||||
|
spContainer.addChildRecord( escherTextbox );
|
||||||
|
|
||||||
|
return spContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Textboxes also have an extra TXO record associated with them that most
|
||||||
|
* other shapes dont have.
|
||||||
|
*/
|
||||||
|
private TextObjectRecord createTextObjectRecord( HSSFTextbox hssfShape, int shapeId )
|
||||||
|
{
|
||||||
|
HSSFTextbox shape = hssfShape;
|
||||||
|
|
||||||
|
TextObjectRecord obj = new TextObjectRecord();
|
||||||
|
obj.setHorizontalTextAlignment( TextObjectRecord.HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED );
|
||||||
|
obj.setVerticalTextAlignment( TextObjectRecord.VERTICAL_TEXT_ALIGNMENT_TOP );
|
||||||
|
obj.setTextLocked( true );
|
||||||
|
obj.setTextOrientation( TextObjectRecord.TEXT_ORIENTATION_NONE );
|
||||||
|
int frLength = ( shape.getString().numFormattingRuns() + 1 ) * 8;
|
||||||
|
obj.setFormattingRunLength( (short) frLength );
|
||||||
|
obj.setTextLength( (short) shape.getString().length() );
|
||||||
|
obj.setStr( shape.getString() );
|
||||||
|
obj.setReserved7( 0 );
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherContainerRecord getSpContainer()
|
||||||
|
{
|
||||||
|
return spContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjRecord getObjRecord()
|
||||||
|
{
|
||||||
|
return objRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextObjectRecord getTextObjectRecord()
|
||||||
|
{
|
||||||
|
return textObjectRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EscherRecord getEscherTextbox()
|
||||||
|
{
|
||||||
|
return escherTextbox;
|
||||||
|
}
|
||||||
|
}
|
@ -60,6 +60,7 @@ import org.apache.poi.hssf.util.HSSFColor;
|
|||||||
import org.apache.poi.hssf.util.SheetReferences;
|
import org.apache.poi.hssf.util.SheetReferences;
|
||||||
import org.apache.poi.util.POILogFactory;
|
import org.apache.poi.util.POILogFactory;
|
||||||
import org.apache.poi.util.POILogger;
|
import org.apache.poi.util.POILogger;
|
||||||
|
import org.apache.poi.ddf.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -133,6 +134,7 @@ public class Workbook implements Model {
|
|||||||
protected int numfonts = 0; // hold the number of font records
|
protected int numfonts = 0; // hold the number of font records
|
||||||
private short maxformatid = -1; // holds the max format id
|
private short maxformatid = -1; // holds the max format id
|
||||||
private boolean uses1904datewindowing = false; // whether 1904 date windowing is being used
|
private boolean uses1904datewindowing = false; // whether 1904 date windowing is being used
|
||||||
|
private DrawingManager drawingManager;
|
||||||
|
|
||||||
private static POILogger log = POILogFactory.getLogger(Workbook.class);
|
private static POILogger log = POILogFactory.getLogger(Workbook.class);
|
||||||
|
|
||||||
@ -2090,6 +2092,56 @@ public class Workbook implements Model {
|
|||||||
return palette;
|
return palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a drawing group record. If it already exists then it's left
|
||||||
|
* alone.
|
||||||
|
*/
|
||||||
|
public void createDrawingGroup()
|
||||||
|
{
|
||||||
|
int dggLoc = findFirstRecordLocBySid(EscherContainerRecord.DGG_CONTAINER);
|
||||||
|
if (dggLoc == -1)
|
||||||
|
{
|
||||||
|
EscherContainerRecord dggContainer = new EscherContainerRecord();
|
||||||
|
EscherDggRecord dgg = new EscherDggRecord();
|
||||||
|
EscherOptRecord opt = new EscherOptRecord();
|
||||||
|
EscherSplitMenuColorsRecord splitMenuColors = new EscherSplitMenuColorsRecord();
|
||||||
|
|
||||||
|
dggContainer.setRecordId((short) 0xF000);
|
||||||
|
dggContainer.setOptions((short) 0x000F);
|
||||||
|
dgg.setRecordId(EscherDggRecord.RECORD_ID);
|
||||||
|
dgg.setOptions((short)0x0000);
|
||||||
|
dgg.setShapeIdMax(1024);
|
||||||
|
dgg.setNumShapesSaved(0);
|
||||||
|
dgg.setDrawingsSaved(0);
|
||||||
|
dgg.setFileIdClusters(new EscherDggRecord.FileIdCluster[] {} );
|
||||||
|
drawingManager = new DrawingManager(dgg);
|
||||||
|
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.LINESTYLE__COLOR, 134217792) );
|
||||||
|
splitMenuColors.setRecordId((short) 0xF11E);
|
||||||
|
splitMenuColors.setOptions((short) 0x0040);
|
||||||
|
splitMenuColors.setColor1(0x0800000D);
|
||||||
|
splitMenuColors.setColor2(0x0800000C);
|
||||||
|
splitMenuColors.setColor3(0x08000017);
|
||||||
|
splitMenuColors.setColor4(0x100000F7);
|
||||||
|
|
||||||
|
dggContainer.addChildRecord(dgg);
|
||||||
|
dggContainer.addChildRecord(opt);
|
||||||
|
dggContainer.addChildRecord(splitMenuColors);
|
||||||
|
|
||||||
|
DrawingGroupRecord drawingGroup = new DrawingGroupRecord();
|
||||||
|
drawingGroup.addEscherRecord(dggContainer);
|
||||||
|
int loc = findFirstRecordLocBySid(CountryRecord.sid);
|
||||||
|
getRecords().add(loc+1, drawingGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawingManager getDrawingManager()
|
||||||
|
{
|
||||||
|
return drawingManager;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,266 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.DefaultEscherRecordFactory;
|
||||||
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
|
import org.apache.poi.ddf.EscherRecordFactory;
|
||||||
|
import org.apache.poi.ddf.NullEscherSerializationListener;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The escher container record is used to hold escher records. It is abstract and
|
||||||
|
* must be subclassed for maximum benefit.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public abstract class AbstractEscherHolderRecord
|
||||||
|
extends Record
|
||||||
|
{
|
||||||
|
private static final boolean DESERIALISE = System.getProperty("poi.deserialize.escher") != null;
|
||||||
|
|
||||||
|
private List escherRecords;
|
||||||
|
private byte[] rawData;
|
||||||
|
|
||||||
|
|
||||||
|
public AbstractEscherHolderRecord()
|
||||||
|
{
|
||||||
|
escherRecords = new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Bar record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x1017 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public AbstractEscherHolderRecord(short id, short size, byte [] data)
|
||||||
|
{
|
||||||
|
super(id, size, data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Bar record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x1017 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
* @param offset of the record's data
|
||||||
|
*/
|
||||||
|
|
||||||
|
public AbstractEscherHolderRecord(short id, short size, byte [] data, int offset)
|
||||||
|
{
|
||||||
|
super(id, size, data, offset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the sid matches the expected side for this record
|
||||||
|
*
|
||||||
|
* @param id the expected sid.
|
||||||
|
*/
|
||||||
|
protected void validateSid(short id)
|
||||||
|
{
|
||||||
|
if (id != getSid())
|
||||||
|
{
|
||||||
|
throw new RecordFormatException("Not a Bar record");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillFields(byte [] data, short size, int offset)
|
||||||
|
{
|
||||||
|
escherRecords = new ArrayList();
|
||||||
|
if (! DESERIALISE )
|
||||||
|
{
|
||||||
|
rawData = new byte[size];
|
||||||
|
System.arraycopy(data, offset, rawData, 0, size);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
final String nl = System.getProperty("line.separator");
|
||||||
|
buffer.append("[" + getRecordName() + "]" + nl);
|
||||||
|
for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
buffer.append(r.toString());
|
||||||
|
}
|
||||||
|
buffer.append("[/" + getRecordName() + "]" + nl);
|
||||||
|
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getRecordName();
|
||||||
|
|
||||||
|
public int serialize(int offset, byte[] data)
|
||||||
|
{
|
||||||
|
if (escherRecords.size() == 0 && rawData != null)
|
||||||
|
{
|
||||||
|
System.arraycopy( rawData, 0, data, offset, rawData.length);
|
||||||
|
return rawData.length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collapseShapeInformation();
|
||||||
|
|
||||||
|
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(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
pos += r.serialize(pos, data, new NullEscherSerializationListener() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of record (including 4 byte header)
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
if (escherRecords.size() == 0 && rawData != null)
|
||||||
|
{
|
||||||
|
return rawData.length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
collapseShapeInformation();
|
||||||
|
|
||||||
|
int size = 4;
|
||||||
|
for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
size += r.getRecordSize();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collapseShapeInformation()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract short getSid();
|
||||||
|
|
||||||
|
public Object clone()
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Not implemented yet.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEscherRecord(int index, EscherRecord element)
|
||||||
|
{
|
||||||
|
escherRecords.add( index, element );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addEscherRecord(EscherRecord element)
|
||||||
|
{
|
||||||
|
return escherRecords.add( element );
|
||||||
|
}
|
||||||
|
|
||||||
|
public List getEscherRecords()
|
||||||
|
{
|
||||||
|
return escherRecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearEscherRecords()
|
||||||
|
{
|
||||||
|
escherRecords.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public EscherRecord getEscherRecord(int index)
|
||||||
|
{
|
||||||
|
return (EscherRecord) escherRecords.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // END OF CLASS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,498 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.poi.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The common object data record is used to store all common preferences for an excel object.
|
||||||
|
* NOTE: This source is automatically generated please do not modify this file. Either subclass or
|
||||||
|
* remove the record in src/records/definitions.
|
||||||
|
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class CommonObjectDataSubRecord
|
||||||
|
extends SubRecord
|
||||||
|
{
|
||||||
|
public final static short sid = 0x15;
|
||||||
|
private short field_1_objectType;
|
||||||
|
public final static short OBJECT_TYPE_GROUP = 0;
|
||||||
|
public final static short OBJECT_TYPE_LINE = 1;
|
||||||
|
public final static short OBJECT_TYPE_RECTANGLE = 2;
|
||||||
|
public final static short OBJECT_TYPE_OVAL = 3;
|
||||||
|
public final static short OBJECT_TYPE_ARC = 4;
|
||||||
|
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_POLYGON = 9;
|
||||||
|
public final static short OBJECT_TYPE_RESERVED1 = 10;
|
||||||
|
public final static short OBJECT_TYPE_CHECKBOX = 11;
|
||||||
|
public final static short OBJECT_TYPE_OPTION_BUTTON = 12;
|
||||||
|
public final static short OBJECT_TYPE_EDIT_BOX = 13;
|
||||||
|
public final static short OBJECT_TYPE_LABEL = 14;
|
||||||
|
public final static short OBJECT_TYPE_DIALOG_BOX = 15;
|
||||||
|
public final static short OBJECT_TYPE_SPINNER = 16;
|
||||||
|
public final static short OBJECT_TYPE_SCROLL_BAR = 17;
|
||||||
|
public final static short OBJECT_TYPE_LIST_BOX = 18;
|
||||||
|
public final static short OBJECT_TYPE_GROUP_BOX = 19;
|
||||||
|
public final static short OBJECT_TYPE_COMBO_BOX = 20;
|
||||||
|
public final static short OBJECT_TYPE_RESERVED2 = 21;
|
||||||
|
public final static short OBJECT_TYPE_RESERVED3 = 22;
|
||||||
|
public final static short OBJECT_TYPE_RESERVED4 = 23;
|
||||||
|
public final static short OBJECT_TYPE_RESERVED5 = 24;
|
||||||
|
public final static short OBJECT_TYPE_COMMENT = 25;
|
||||||
|
public final static short OBJECT_TYPE_RESERVED6 = 26;
|
||||||
|
public final static short OBJECT_TYPE_RESERVED7 = 27;
|
||||||
|
public final static short OBJECT_TYPE_RESERVED8 = 28;
|
||||||
|
public final static short OBJECT_TYPE_RESERVED9 = 29;
|
||||||
|
public final static short OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 30;
|
||||||
|
private short field_2_objectId;
|
||||||
|
private short field_3_option;
|
||||||
|
private BitField locked = new BitField(0x1);
|
||||||
|
private BitField printable = new BitField(0x10);
|
||||||
|
private BitField autofill = new BitField(0x2000);
|
||||||
|
private BitField autoline = new BitField(0x4000);
|
||||||
|
private int field_4_reserved1;
|
||||||
|
private int field_5_reserved2;
|
||||||
|
private int field_6_reserved3;
|
||||||
|
|
||||||
|
|
||||||
|
public CommonObjectDataSubRecord()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a CommonObjectData record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x15 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public CommonObjectDataSubRecord(short id, short size, byte [] data)
|
||||||
|
{
|
||||||
|
super(id, size, data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a CommonObjectData record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x15 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
* @param offset of the record's data
|
||||||
|
*/
|
||||||
|
|
||||||
|
public CommonObjectDataSubRecord(short id, short size, byte [] data, int offset)
|
||||||
|
{
|
||||||
|
super(id, size, data, offset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the sid matches the expected side for this record
|
||||||
|
*
|
||||||
|
* @param id the expected sid.
|
||||||
|
*/
|
||||||
|
protected void validateSid(short id)
|
||||||
|
{
|
||||||
|
if (id != sid)
|
||||||
|
{
|
||||||
|
throw new RecordFormatException("Not a CommonObjectData record");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillFields(byte [] data, short size, int offset)
|
||||||
|
{
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
field_1_objectType = LittleEndian.getShort(data, pos + 0x0 + offset);
|
||||||
|
field_2_objectId = LittleEndian.getShort(data, pos + 0x2 + offset);
|
||||||
|
field_3_option = LittleEndian.getShort(data, pos + 0x4 + offset);
|
||||||
|
field_4_reserved1 = LittleEndian.getInt(data, pos + 0x6 + offset);
|
||||||
|
field_5_reserved2 = LittleEndian.getInt(data, pos + 0xa + offset);
|
||||||
|
field_6_reserved3 = LittleEndian.getInt(data, pos + 0xe + offset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
buffer.append("[ftCmo]\n");
|
||||||
|
buffer.append(" .objectType = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getObjectType ()))
|
||||||
|
.append(" (").append( getObjectType() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .objectId = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getObjectId ()))
|
||||||
|
.append(" (").append( getObjectId() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .option = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getOption ()))
|
||||||
|
.append(" (").append( getOption() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .locked = ").append(isLocked()).append('\n');
|
||||||
|
buffer.append(" .printable = ").append(isPrintable()).append('\n');
|
||||||
|
buffer.append(" .autofill = ").append(isAutofill()).append('\n');
|
||||||
|
buffer.append(" .autoline = ").append(isAutoline()).append('\n');
|
||||||
|
buffer.append(" .reserved1 = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getReserved1 ()))
|
||||||
|
.append(" (").append( getReserved1() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .reserved2 = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getReserved2 ()))
|
||||||
|
.append(" (").append( getReserved2() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .reserved3 = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getReserved3 ()))
|
||||||
|
.append(" (").append( getReserved3() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
|
||||||
|
buffer.append("[/ftCmo]\n");
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int serialize(int offset, byte[] data)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
|
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));
|
||||||
|
|
||||||
|
LittleEndian.putShort(data, 4 + offset + pos, field_1_objectType);
|
||||||
|
LittleEndian.putShort(data, 6 + offset + pos, field_2_objectId);
|
||||||
|
LittleEndian.putShort(data, 8 + offset + pos, field_3_option);
|
||||||
|
LittleEndian.putInt(data, 10 + offset + pos, field_4_reserved1);
|
||||||
|
LittleEndian.putInt(data, 14 + offset + pos, field_5_reserved2);
|
||||||
|
LittleEndian.putInt(data, 18 + offset + pos, field_6_reserved3);
|
||||||
|
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of record (exluding 4 byte header)
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 4 + 2 + 2 + 2 + 4 + 4 + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return this.sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone() {
|
||||||
|
CommonObjectDataSubRecord rec = new CommonObjectDataSubRecord();
|
||||||
|
|
||||||
|
rec.field_1_objectType = field_1_objectType;
|
||||||
|
rec.field_2_objectId = field_2_objectId;
|
||||||
|
rec.field_3_option = field_3_option;
|
||||||
|
rec.field_4_reserved1 = field_4_reserved1;
|
||||||
|
rec.field_5_reserved2 = field_5_reserved2;
|
||||||
|
rec.field_6_reserved3 = field_6_reserved3;
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the object type field for the CommonObjectData record.
|
||||||
|
*
|
||||||
|
* @return One of
|
||||||
|
* OBJECT_TYPE_GROUP
|
||||||
|
* OBJECT_TYPE_LINE
|
||||||
|
* OBJECT_TYPE_RECTANGLE
|
||||||
|
* OBJECT_TYPE_OVAL
|
||||||
|
* OBJECT_TYPE_ARC
|
||||||
|
* OBJECT_TYPE_CHART
|
||||||
|
* OBJECT_TYPE_TEXT
|
||||||
|
* OBJECT_TYPE_BUTTON
|
||||||
|
* OBJECT_TYPE_PICTURE
|
||||||
|
* OBJECT_TYPE_POLYGON
|
||||||
|
* OBJECT_TYPE_RESERVED1
|
||||||
|
* OBJECT_TYPE_CHECKBOX
|
||||||
|
* OBJECT_TYPE_OPTION_BUTTON
|
||||||
|
* OBJECT_TYPE_EDIT_BOX
|
||||||
|
* OBJECT_TYPE_LABEL
|
||||||
|
* OBJECT_TYPE_DIALOG_BOX
|
||||||
|
* OBJECT_TYPE_SPINNER
|
||||||
|
* OBJECT_TYPE_SCROLL_BAR
|
||||||
|
* OBJECT_TYPE_LIST_BOX
|
||||||
|
* OBJECT_TYPE_GROUP_BOX
|
||||||
|
* OBJECT_TYPE_COMBO_BOX
|
||||||
|
* OBJECT_TYPE_RESERVED2
|
||||||
|
* OBJECT_TYPE_RESERVED3
|
||||||
|
* OBJECT_TYPE_RESERVED4
|
||||||
|
* OBJECT_TYPE_RESERVED5
|
||||||
|
* OBJECT_TYPE_COMMENT
|
||||||
|
* OBJECT_TYPE_RESERVED6
|
||||||
|
* OBJECT_TYPE_RESERVED7
|
||||||
|
* OBJECT_TYPE_RESERVED8
|
||||||
|
* OBJECT_TYPE_RESERVED9
|
||||||
|
* OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING
|
||||||
|
*/
|
||||||
|
public short getObjectType()
|
||||||
|
{
|
||||||
|
return field_1_objectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the object type field for the CommonObjectData record.
|
||||||
|
*
|
||||||
|
* @param field_1_objectType
|
||||||
|
* One of
|
||||||
|
* OBJECT_TYPE_GROUP
|
||||||
|
* OBJECT_TYPE_LINE
|
||||||
|
* OBJECT_TYPE_RECTANGLE
|
||||||
|
* OBJECT_TYPE_OVAL
|
||||||
|
* OBJECT_TYPE_ARC
|
||||||
|
* OBJECT_TYPE_CHART
|
||||||
|
* OBJECT_TYPE_TEXT
|
||||||
|
* OBJECT_TYPE_BUTTON
|
||||||
|
* OBJECT_TYPE_PICTURE
|
||||||
|
* OBJECT_TYPE_POLYGON
|
||||||
|
* OBJECT_TYPE_RESERVED1
|
||||||
|
* OBJECT_TYPE_CHECKBOX
|
||||||
|
* OBJECT_TYPE_OPTION_BUTTON
|
||||||
|
* OBJECT_TYPE_EDIT_BOX
|
||||||
|
* OBJECT_TYPE_LABEL
|
||||||
|
* OBJECT_TYPE_DIALOG_BOX
|
||||||
|
* OBJECT_TYPE_SPINNER
|
||||||
|
* OBJECT_TYPE_SCROLL_BAR
|
||||||
|
* OBJECT_TYPE_LIST_BOX
|
||||||
|
* OBJECT_TYPE_GROUP_BOX
|
||||||
|
* OBJECT_TYPE_COMBO_BOX
|
||||||
|
* OBJECT_TYPE_RESERVED2
|
||||||
|
* OBJECT_TYPE_RESERVED3
|
||||||
|
* OBJECT_TYPE_RESERVED4
|
||||||
|
* OBJECT_TYPE_RESERVED5
|
||||||
|
* OBJECT_TYPE_COMMENT
|
||||||
|
* OBJECT_TYPE_RESERVED6
|
||||||
|
* OBJECT_TYPE_RESERVED7
|
||||||
|
* OBJECT_TYPE_RESERVED8
|
||||||
|
* OBJECT_TYPE_RESERVED9
|
||||||
|
* OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING
|
||||||
|
*/
|
||||||
|
public void setObjectType(short field_1_objectType)
|
||||||
|
{
|
||||||
|
this.field_1_objectType = field_1_objectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the object id field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public short getObjectId()
|
||||||
|
{
|
||||||
|
return field_2_objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the object id field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public void setObjectId(short field_2_objectId)
|
||||||
|
{
|
||||||
|
this.field_2_objectId = field_2_objectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the option field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public short getOption()
|
||||||
|
{
|
||||||
|
return field_3_option;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the option field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public void setOption(short field_3_option)
|
||||||
|
{
|
||||||
|
this.field_3_option = field_3_option;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the reserved1 field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public int getReserved1()
|
||||||
|
{
|
||||||
|
return field_4_reserved1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reserved1 field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public void setReserved1(int field_4_reserved1)
|
||||||
|
{
|
||||||
|
this.field_4_reserved1 = field_4_reserved1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the reserved2 field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public int getReserved2()
|
||||||
|
{
|
||||||
|
return field_5_reserved2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reserved2 field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public void setReserved2(int field_5_reserved2)
|
||||||
|
{
|
||||||
|
this.field_5_reserved2 = field_5_reserved2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the reserved3 field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public int getReserved3()
|
||||||
|
{
|
||||||
|
return field_6_reserved3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reserved3 field for the CommonObjectData record.
|
||||||
|
*/
|
||||||
|
public void setReserved3(int field_6_reserved3)
|
||||||
|
{
|
||||||
|
this.field_6_reserved3 = field_6_reserved3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the locked field value.
|
||||||
|
* true if object is locked when sheet has been protected
|
||||||
|
*/
|
||||||
|
public void setLocked(boolean value)
|
||||||
|
{
|
||||||
|
field_3_option = locked.setShortBoolean(field_3_option, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true if object is locked when sheet has been protected
|
||||||
|
* @return the locked field value.
|
||||||
|
*/
|
||||||
|
public boolean isLocked()
|
||||||
|
{
|
||||||
|
return locked.isSet(field_3_option);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the printable field value.
|
||||||
|
* object appears when printed
|
||||||
|
*/
|
||||||
|
public void setPrintable(boolean value)
|
||||||
|
{
|
||||||
|
field_3_option = printable.setShortBoolean(field_3_option, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* object appears when printed
|
||||||
|
* @return the printable field value.
|
||||||
|
*/
|
||||||
|
public boolean isPrintable()
|
||||||
|
{
|
||||||
|
return printable.isSet(field_3_option);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the autofill field value.
|
||||||
|
* whether object uses an automatic fill style
|
||||||
|
*/
|
||||||
|
public void setAutofill(boolean value)
|
||||||
|
{
|
||||||
|
field_3_option = autofill.setShortBoolean(field_3_option, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether object uses an automatic fill style
|
||||||
|
* @return the autofill field value.
|
||||||
|
*/
|
||||||
|
public boolean isAutofill()
|
||||||
|
{
|
||||||
|
return autofill.isSet(field_3_option);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the autoline field value.
|
||||||
|
* whether object uses an automatic line style
|
||||||
|
*/
|
||||||
|
public void setAutoline(boolean value)
|
||||||
|
{
|
||||||
|
field_3_option = autoline.setShortBoolean(field_3_option, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* whether object uses an automatic line style
|
||||||
|
* @return the autoline field value.
|
||||||
|
*/
|
||||||
|
public boolean isAutoline()
|
||||||
|
{
|
||||||
|
return autoline.isSet(field_3_option);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // END OF CLASS
|
||||||
|
|
||||||
|
|
30
src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java
Normal file
30
src/java/org/apache/poi/hssf/record/DrawingGroupRecord.java
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
public class DrawingGroupRecord extends AbstractEscherHolderRecord
|
||||||
|
{
|
||||||
|
public static final short sid = 0xEB;
|
||||||
|
|
||||||
|
public DrawingGroupRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawingGroupRecord( short id, short size, byte[] data )
|
||||||
|
{
|
||||||
|
super( id, size, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawingGroupRecord( short id, short size, byte[] data, int offset )
|
||||||
|
{
|
||||||
|
super( id, size, data, offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getRecordName()
|
||||||
|
{
|
||||||
|
return "MSODRAWINGGROUP";
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
}
|
97
src/java/org/apache/poi/hssf/record/DrawingRecord.java
Normal file
97
src/java/org/apache/poi/hssf/record/DrawingRecord.java
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
public class DrawingRecord extends Record
|
||||||
|
{
|
||||||
|
public static final short sid = 0xEC;
|
||||||
|
|
||||||
|
private byte[] recordData;
|
||||||
|
|
||||||
|
public DrawingRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawingRecord( short id, short size, byte[] data )
|
||||||
|
{
|
||||||
|
super( id, size, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawingRecord( short id, short size, byte[] data, int offset )
|
||||||
|
{
|
||||||
|
super( id, size, data, offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the sid matches the expected side for this record
|
||||||
|
*
|
||||||
|
* @param id the expected sid.
|
||||||
|
*/
|
||||||
|
protected void validateSid(short id)
|
||||||
|
{
|
||||||
|
if (id != sid)
|
||||||
|
{
|
||||||
|
throw new RecordFormatException("Not a MSODRAWING record");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillFields( byte[] data, short size, int offset )
|
||||||
|
{
|
||||||
|
if (offset == 0 && size == data.length)
|
||||||
|
{
|
||||||
|
recordData = data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
recordData = new byte[size];
|
||||||
|
System.arraycopy(data, offset, recordData, 0, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillFields( byte[] data, short size )
|
||||||
|
{
|
||||||
|
recordData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int serialize( int offset, byte[] data )
|
||||||
|
{
|
||||||
|
if (recordData == null)
|
||||||
|
{
|
||||||
|
recordData = new byte[ 0 ];
|
||||||
|
}
|
||||||
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
|
LittleEndian.putShort(data, 2 + offset, ( short ) (recordData.length));
|
||||||
|
if (recordData.length > 0)
|
||||||
|
{
|
||||||
|
System.arraycopy(recordData, 0, data, 4 + offset, recordData.length);
|
||||||
|
}
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
int retval = 4;
|
||||||
|
|
||||||
|
if (recordData != null)
|
||||||
|
{
|
||||||
|
retval += recordData.length;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData()
|
||||||
|
{
|
||||||
|
return recordData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData( byte[] thedata )
|
||||||
|
{
|
||||||
|
this.recordData = thedata;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is purely for the biff viewer. During normal operations we don't want
|
||||||
|
* to be seeing this.
|
||||||
|
*/
|
||||||
|
public class DrawingRecordForBiffViewer
|
||||||
|
extends AbstractEscherHolderRecord
|
||||||
|
{
|
||||||
|
public static final short sid = 0xEC;
|
||||||
|
|
||||||
|
public DrawingRecordForBiffViewer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawingRecordForBiffViewer( short id, short size, byte[] data )
|
||||||
|
{
|
||||||
|
super( id, size, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawingRecordForBiffViewer( short id, short size, byte[] data, int offset )
|
||||||
|
{
|
||||||
|
super( id, size, data, offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getRecordName()
|
||||||
|
{
|
||||||
|
return "MSODRAWING";
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
public class DrawingSelectionRecord extends AbstractEscherHolderRecord
|
||||||
|
{
|
||||||
|
public static final short sid = 0xED;
|
||||||
|
|
||||||
|
public DrawingSelectionRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawingSelectionRecord( short id, short size, byte[] data )
|
||||||
|
{
|
||||||
|
super( id, size, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawingSelectionRecord( short id, short size, byte[] data, int offset )
|
||||||
|
{
|
||||||
|
super( id, size, data, offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getRecordName()
|
||||||
|
{
|
||||||
|
return "MSODRAWINGSELECTION";
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
}
|
176
src/java/org/apache/poi/hssf/record/EndSubRecord.java
Normal file
176
src/java/org/apache/poi/hssf/record/EndSubRecord.java
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.poi.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The end data record is used to denote the end of the subrecords.
|
||||||
|
* NOTE: This source is automatically generated please do not modify this file. Either subclass or
|
||||||
|
* remove the record in src/records/definitions.
|
||||||
|
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EndSubRecord
|
||||||
|
extends SubRecord
|
||||||
|
{
|
||||||
|
public final static short sid = 0x00;
|
||||||
|
|
||||||
|
|
||||||
|
public EndSubRecord()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a End record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x00 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public EndSubRecord(short id, short size, byte [] data)
|
||||||
|
{
|
||||||
|
super(id, size, data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a End record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x00 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
* @param offset of the record's data
|
||||||
|
*/
|
||||||
|
|
||||||
|
public EndSubRecord(short id, short size, byte [] data, int offset)
|
||||||
|
{
|
||||||
|
super(id, size, data, offset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the sid matches the expected side for this record
|
||||||
|
*
|
||||||
|
* @param id the expected sid.
|
||||||
|
*/
|
||||||
|
protected void validateSid(short id)
|
||||||
|
{
|
||||||
|
if (id != sid)
|
||||||
|
{
|
||||||
|
throw new RecordFormatException("Not a End record");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillFields(byte [] data, short size, int offset)
|
||||||
|
{
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
buffer.append("[ftEnd]\n");
|
||||||
|
|
||||||
|
buffer.append("[/ftEnd]\n");
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int serialize(int offset, byte[] data)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
|
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));
|
||||||
|
|
||||||
|
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of record (exluding 4 byte header)
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 4 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return this.sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone() {
|
||||||
|
EndSubRecord rec = new EndSubRecord();
|
||||||
|
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // END OF CLASS
|
||||||
|
|
||||||
|
|
696
src/java/org/apache/poi/hssf/record/EscherAggregate.java
Normal file
696
src/java/org/apache/poi/hssf/record/EscherAggregate.java
Normal file
@ -0,0 +1,696 @@
|
|||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
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.ConvertAnchor;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to aggregate the MSODRAWING and OBJ record
|
||||||
|
* combinations. This is necessary due to the bizare way in which
|
||||||
|
* these records are serialized. What happens is that you get a
|
||||||
|
* combination of MSODRAWING -> OBJ -> MSODRAWING -> OBJ records
|
||||||
|
* but the escher records are serialized _across_ the MSODRAWING
|
||||||
|
* records.
|
||||||
|
* <p>
|
||||||
|
* It gets even worse when you start looking at TXO records.
|
||||||
|
* <p>
|
||||||
|
* So what we do with this class is aggregate lazily. That is
|
||||||
|
* we don't aggregate the MSODRAWING -> OBJ records unless we
|
||||||
|
* need to modify them.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherAggregate extends AbstractEscherHolderRecord
|
||||||
|
{
|
||||||
|
public static final short sid = 9876;
|
||||||
|
|
||||||
|
public static final short ST_MIN = (short) 0;
|
||||||
|
public static final short ST_NOT_PRIMATIVE = ST_MIN;
|
||||||
|
public static final short ST_RECTANGLE = (short) 1;
|
||||||
|
public static final short ST_ROUNDRECTANGLE = (short) 2;
|
||||||
|
public static final short ST_ELLIPSE = (short) 3;
|
||||||
|
public static final short ST_DIAMOND = (short) 4;
|
||||||
|
public static final short ST_ISOCELESTRIANGLE = (short) 5;
|
||||||
|
public static final short ST_RIGHTTRIANGLE = (short) 6;
|
||||||
|
public static final short ST_PARALLELOGRAM = (short) 7;
|
||||||
|
public static final short ST_TRAPEZOID = (short) 8;
|
||||||
|
public static final short ST_HEXAGON = (short) 9;
|
||||||
|
public static final short ST_OCTAGON = (short) 10;
|
||||||
|
public static final short ST_PLUS = (short) 11;
|
||||||
|
public static final short ST_STAR = (short) 12;
|
||||||
|
public static final short ST_ARROW = (short) 13;
|
||||||
|
public static final short ST_THICKARROW = (short) 14;
|
||||||
|
public static final short ST_HOMEPLATE = (short) 15;
|
||||||
|
public static final short ST_CUBE = (short) 16;
|
||||||
|
public static final short ST_BALLOON = (short) 17;
|
||||||
|
public static final short ST_SEAL = (short) 18;
|
||||||
|
public static final short ST_ARC = (short) 19;
|
||||||
|
public static final short ST_LINE = (short) 20;
|
||||||
|
public static final short ST_PLAQUE = (short) 21;
|
||||||
|
public static final short ST_CAN = (short) 22;
|
||||||
|
public static final short ST_DONUT = (short) 23;
|
||||||
|
public static final short ST_TEXTSIMPLE = (short) 24;
|
||||||
|
public static final short ST_TEXTOCTAGON = (short) 25;
|
||||||
|
public static final short ST_TEXTHEXAGON = (short) 26;
|
||||||
|
public static final short ST_TEXTCURVE = (short) 27;
|
||||||
|
public static final short ST_TEXTWAVE = (short) 28;
|
||||||
|
public static final short ST_TEXTRING = (short) 29;
|
||||||
|
public static final short ST_TEXTONCURVE = (short) 30;
|
||||||
|
public static final short ST_TEXTONRING = (short) 31;
|
||||||
|
public static final short ST_STRAIGHTCONNECTOR1 = (short) 32;
|
||||||
|
public static final short ST_BENTCONNECTOR2 = (short) 33;
|
||||||
|
public static final short ST_BENTCONNECTOR3 = (short) 34;
|
||||||
|
public static final short ST_BENTCONNECTOR4 = (short) 35;
|
||||||
|
public static final short ST_BENTCONNECTOR5 = (short) 36;
|
||||||
|
public static final short ST_CURVEDCONNECTOR2 = (short) 37;
|
||||||
|
public static final short ST_CURVEDCONNECTOR3 = (short) 38;
|
||||||
|
public static final short ST_CURVEDCONNECTOR4 = (short) 39;
|
||||||
|
public static final short ST_CURVEDCONNECTOR5 = (short) 40;
|
||||||
|
public static final short ST_CALLOUT1 = (short) 41;
|
||||||
|
public static final short ST_CALLOUT2 = (short) 42;
|
||||||
|
public static final short ST_CALLOUT3 = (short) 43;
|
||||||
|
public static final short ST_ACCENTCALLOUT1 = (short) 44;
|
||||||
|
public static final short ST_ACCENTCALLOUT2 = (short) 45;
|
||||||
|
public static final short ST_ACCENTCALLOUT3 = (short) 46;
|
||||||
|
public static final short ST_BORDERCALLOUT1 = (short) 47;
|
||||||
|
public static final short ST_BORDERCALLOUT2 = (short) 48;
|
||||||
|
public static final short ST_BORDERCALLOUT3 = (short) 49;
|
||||||
|
public static final short ST_ACCENTBORDERCALLOUT1 = (short) 50;
|
||||||
|
public static final short ST_ACCENTBORDERCALLOUT2 = (short) 51;
|
||||||
|
public static final short ST_ACCENTBORDERCALLOUT3 = (short) 52;
|
||||||
|
public static final short ST_RIBBON = (short) 53;
|
||||||
|
public static final short ST_RIBBON2 = (short) 54;
|
||||||
|
public static final short ST_CHEVRON = (short) 55;
|
||||||
|
public static final short ST_PENTAGON = (short) 56;
|
||||||
|
public static final short ST_NOSMOKING = (short) 57;
|
||||||
|
public static final short ST_SEAL8 = (short) 58;
|
||||||
|
public static final short ST_SEAL16 = (short) 59;
|
||||||
|
public static final short ST_SEAL32 = (short) 60;
|
||||||
|
public static final short ST_WEDGERECTCALLOUT = (short) 61;
|
||||||
|
public static final short ST_WEDGERRECTCALLOUT = (short) 62;
|
||||||
|
public static final short ST_WEDGEELLIPSECALLOUT = (short) 63;
|
||||||
|
public static final short ST_WAVE = (short) 64;
|
||||||
|
public static final short ST_FOLDEDCORNER = (short) 65;
|
||||||
|
public static final short ST_LEFTARROW = (short) 66;
|
||||||
|
public static final short ST_DOWNARROW = (short) 67;
|
||||||
|
public static final short ST_UPARROW = (short) 68;
|
||||||
|
public static final short ST_LEFTRIGHTARROW = (short) 69;
|
||||||
|
public static final short ST_UPDOWNARROW = (short) 70;
|
||||||
|
public static final short ST_IRREGULARSEAL1 = (short) 71;
|
||||||
|
public static final short ST_IRREGULARSEAL2 = (short) 72;
|
||||||
|
public static final short ST_LIGHTNINGBOLT = (short) 73;
|
||||||
|
public static final short ST_HEART = (short) 74;
|
||||||
|
public static final short ST_PICTUREFRAME = (short) 75;
|
||||||
|
public static final short ST_QUADARROW = (short) 76;
|
||||||
|
public static final short ST_LEFTARROWCALLOUT = (short) 77;
|
||||||
|
public static final short ST_RIGHTARROWCALLOUT = (short) 78;
|
||||||
|
public static final short ST_UPARROWCALLOUT = (short) 79;
|
||||||
|
public static final short ST_DOWNARROWCALLOUT = (short) 80;
|
||||||
|
public static final short ST_LEFTRIGHTARROWCALLOUT = (short) 81;
|
||||||
|
public static final short ST_UPDOWNARROWCALLOUT = (short) 82;
|
||||||
|
public static final short ST_QUADARROWCALLOUT = (short) 83;
|
||||||
|
public static final short ST_BEVEL = (short) 84;
|
||||||
|
public static final short ST_LEFTBRACKET = (short) 85;
|
||||||
|
public static final short ST_RIGHTBRACKET = (short) 86;
|
||||||
|
public static final short ST_LEFTBRACE = (short) 87;
|
||||||
|
public static final short ST_RIGHTBRACE = (short) 88;
|
||||||
|
public static final short ST_LEFTUPARROW = (short) 89;
|
||||||
|
public static final short ST_BENTUPARROW = (short) 90;
|
||||||
|
public static final short ST_BENTARROW = (short) 91;
|
||||||
|
public static final short ST_SEAL24 = (short) 92;
|
||||||
|
public static final short ST_STRIPEDRIGHTARROW = (short) 93;
|
||||||
|
public static final short ST_NOTCHEDRIGHTARROW = (short) 94;
|
||||||
|
public static final short ST_BLOCKARC = (short) 95;
|
||||||
|
public static final short ST_SMILEYFACE = (short) 96;
|
||||||
|
public static final short ST_VERTICALSCROLL = (short) 97;
|
||||||
|
public static final short ST_HORIZONTALSCROLL = (short) 98;
|
||||||
|
public static final short ST_CIRCULARARROW = (short) 99;
|
||||||
|
public static final short ST_NOTCHEDCIRCULARARROW = (short) 100;
|
||||||
|
public static final short ST_UTURNARROW = (short) 101;
|
||||||
|
public static final short ST_CURVEDRIGHTARROW = (short) 102;
|
||||||
|
public static final short ST_CURVEDLEFTARROW = (short) 103;
|
||||||
|
public static final short ST_CURVEDUPARROW = (short) 104;
|
||||||
|
public static final short ST_CURVEDDOWNARROW = (short) 105;
|
||||||
|
public static final short ST_CLOUDCALLOUT = (short) 106;
|
||||||
|
public static final short ST_ELLIPSERIBBON = (short) 107;
|
||||||
|
public static final short ST_ELLIPSERIBBON2 = (short) 108;
|
||||||
|
public static final short ST_FLOWCHARTPROCESS = (short) 109;
|
||||||
|
public static final short ST_FLOWCHARTDECISION = (short) 110;
|
||||||
|
public static final short ST_FLOWCHARTINPUTOUTPUT = (short) 111;
|
||||||
|
public static final short ST_FLOWCHARTPREDEFINEDPROCESS = (short) 112;
|
||||||
|
public static final short ST_FLOWCHARTINTERNALSTORAGE = (short) 113;
|
||||||
|
public static final short ST_FLOWCHARTDOCUMENT = (short) 114;
|
||||||
|
public static final short ST_FLOWCHARTMULTIDOCUMENT = (short) 115;
|
||||||
|
public static final short ST_FLOWCHARTTERMINATOR = (short) 116;
|
||||||
|
public static final short ST_FLOWCHARTPREPARATION = (short) 117;
|
||||||
|
public static final short ST_FLOWCHARTMANUALINPUT = (short) 118;
|
||||||
|
public static final short ST_FLOWCHARTMANUALOPERATION = (short) 119;
|
||||||
|
public static final short ST_FLOWCHARTCONNECTOR = (short) 120;
|
||||||
|
public static final short ST_FLOWCHARTPUNCHEDCARD = (short) 121;
|
||||||
|
public static final short ST_FLOWCHARTPUNCHEDTAPE = (short) 122;
|
||||||
|
public static final short ST_FLOWCHARTSUMMINGJUNCTION = (short) 123;
|
||||||
|
public static final short ST_FLOWCHARTOR = (short) 124;
|
||||||
|
public static final short ST_FLOWCHARTCOLLATE = (short) 125;
|
||||||
|
public static final short ST_FLOWCHARTSORT = (short) 126;
|
||||||
|
public static final short ST_FLOWCHARTEXTRACT = (short) 127;
|
||||||
|
public static final short ST_FLOWCHARTMERGE = (short) 128;
|
||||||
|
public static final short ST_FLOWCHARTOFFLINESTORAGE = (short) 129;
|
||||||
|
public static final short ST_FLOWCHARTONLINESTORAGE = (short) 130;
|
||||||
|
public static final short ST_FLOWCHARTMAGNETICTAPE = (short) 131;
|
||||||
|
public static final short ST_FLOWCHARTMAGNETICDISK = (short) 132;
|
||||||
|
public static final short ST_FLOWCHARTMAGNETICDRUM = (short) 133;
|
||||||
|
public static final short ST_FLOWCHARTDISPLAY = (short) 134;
|
||||||
|
public static final short ST_FLOWCHARTDELAY = (short) 135;
|
||||||
|
public static final short ST_TEXTPLAINTEXT = (short) 136;
|
||||||
|
public static final short ST_TEXTSTOP = (short) 137;
|
||||||
|
public static final short ST_TEXTTRIANGLE = (short) 138;
|
||||||
|
public static final short ST_TEXTTRIANGLEINVERTED = (short) 139;
|
||||||
|
public static final short ST_TEXTCHEVRON = (short) 140;
|
||||||
|
public static final short ST_TEXTCHEVRONINVERTED = (short) 141;
|
||||||
|
public static final short ST_TEXTRINGINSIDE = (short) 142;
|
||||||
|
public static final short ST_TEXTRINGOUTSIDE = (short) 143;
|
||||||
|
public static final short ST_TEXTARCHUPCURVE = (short) 144;
|
||||||
|
public static final short ST_TEXTARCHDOWNCURVE = (short) 145;
|
||||||
|
public static final short ST_TEXTCIRCLECURVE = (short) 146;
|
||||||
|
public static final short ST_TEXTBUTTONCURVE = (short) 147;
|
||||||
|
public static final short ST_TEXTARCHUPPOUR = (short) 148;
|
||||||
|
public static final short ST_TEXTARCHDOWNPOUR = (short) 149;
|
||||||
|
public static final short ST_TEXTCIRCLEPOUR = (short) 150;
|
||||||
|
public static final short ST_TEXTBUTTONPOUR = (short) 151;
|
||||||
|
public static final short ST_TEXTCURVEUP = (short) 152;
|
||||||
|
public static final short ST_TEXTCURVEDOWN = (short) 153;
|
||||||
|
public static final short ST_TEXTCASCADEUP = (short) 154;
|
||||||
|
public static final short ST_TEXTCASCADEDOWN = (short) 155;
|
||||||
|
public static final short ST_TEXTWAVE1 = (short) 156;
|
||||||
|
public static final short ST_TEXTWAVE2 = (short) 157;
|
||||||
|
public static final short ST_TEXTWAVE3 = (short) 158;
|
||||||
|
public static final short ST_TEXTWAVE4 = (short) 159;
|
||||||
|
public static final short ST_TEXTINFLATE = (short) 160;
|
||||||
|
public static final short ST_TEXTDEFLATE = (short) 161;
|
||||||
|
public static final short ST_TEXTINFLATEBOTTOM = (short) 162;
|
||||||
|
public static final short ST_TEXTDEFLATEBOTTOM = (short) 163;
|
||||||
|
public static final short ST_TEXTINFLATETOP = (short) 164;
|
||||||
|
public static final short ST_TEXTDEFLATETOP = (short) 165;
|
||||||
|
public static final short ST_TEXTDEFLATEINFLATE = (short) 166;
|
||||||
|
public static final short ST_TEXTDEFLATEINFLATEDEFLATE = (short) 167;
|
||||||
|
public static final short ST_TEXTFADERIGHT = (short) 168;
|
||||||
|
public static final short ST_TEXTFADELEFT = (short) 169;
|
||||||
|
public static final short ST_TEXTFADEUP = (short) 170;
|
||||||
|
public static final short ST_TEXTFADEDOWN = (short) 171;
|
||||||
|
public static final short ST_TEXTSLANTUP = (short) 172;
|
||||||
|
public static final short ST_TEXTSLANTDOWN = (short) 173;
|
||||||
|
public static final short ST_TEXTCANUP = (short) 174;
|
||||||
|
public static final short ST_TEXTCANDOWN = (short) 175;
|
||||||
|
public static final short ST_FLOWCHARTALTERNATEPROCESS = (short) 176;
|
||||||
|
public static final short ST_FLOWCHARTOFFPAGECONNECTOR = (short) 177;
|
||||||
|
public static final short ST_CALLOUT90 = (short) 178;
|
||||||
|
public static final short ST_ACCENTCALLOUT90 = (short) 179;
|
||||||
|
public static final short ST_BORDERCALLOUT90 = (short) 180;
|
||||||
|
public static final short ST_ACCENTBORDERCALLOUT90 = (short) 181;
|
||||||
|
public static final short ST_LEFTRIGHTUPARROW = (short) 182;
|
||||||
|
public static final short ST_SUN = (short) 183;
|
||||||
|
public static final short ST_MOON = (short) 184;
|
||||||
|
public static final short ST_BRACKETPAIR = (short) 185;
|
||||||
|
public static final short ST_BRACEPAIR = (short) 186;
|
||||||
|
public static final short ST_SEAL4 = (short) 187;
|
||||||
|
public static final short ST_DOUBLEWAVE = (short) 188;
|
||||||
|
public static final short ST_ACTIONBUTTONBLANK = (short) 189;
|
||||||
|
public static final short ST_ACTIONBUTTONHOME = (short) 190;
|
||||||
|
public static final short ST_ACTIONBUTTONHELP = (short) 191;
|
||||||
|
public static final short ST_ACTIONBUTTONINFORMATION = (short) 192;
|
||||||
|
public static final short ST_ACTIONBUTTONFORWARDNEXT = (short) 193;
|
||||||
|
public static final short ST_ACTIONBUTTONBACKPREVIOUS = (short) 194;
|
||||||
|
public static final short ST_ACTIONBUTTONEND = (short) 195;
|
||||||
|
public static final short ST_ACTIONBUTTONBEGINNING = (short) 196;
|
||||||
|
public static final short ST_ACTIONBUTTONRETURN = (short) 197;
|
||||||
|
public static final short ST_ACTIONBUTTONDOCUMENT = (short) 198;
|
||||||
|
public static final short ST_ACTIONBUTTONSOUND = (short) 199;
|
||||||
|
public static final short ST_ACTIONBUTTONMOVIE = (short) 200;
|
||||||
|
public static final short ST_HOSTCONTROL = (short) 201;
|
||||||
|
public static final short ST_TEXTBOX = (short) 202;
|
||||||
|
public static final short ST_NIL = (short) 0x0FFF;
|
||||||
|
|
||||||
|
protected HSSFPatriarch patriarch;
|
||||||
|
|
||||||
|
/** Maps shape container objects to their OBJ records */
|
||||||
|
private Map shapeToObj = new HashMap();
|
||||||
|
private DrawingManager drawingManager;
|
||||||
|
private short drawingGroupId;
|
||||||
|
|
||||||
|
public EscherAggregate( DrawingManager drawingManager )
|
||||||
|
{
|
||||||
|
this.drawingManager = drawingManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the current sid.
|
||||||
|
*/
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unused since this is an aggregate record. Use createAggregate().
|
||||||
|
*
|
||||||
|
* @see #createAggregate
|
||||||
|
*/
|
||||||
|
protected void fillFields( byte[] data, short size, int offset )
|
||||||
|
{
|
||||||
|
throw new IllegalStateException( "Should not reach here" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the string representation of this record. This is
|
||||||
|
* simply a dump of all the records.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
String nl = System.getProperty( "line.separtor" );
|
||||||
|
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
result.append( '[' ).append( getRecordName() ).append( ']' + nl );
|
||||||
|
for ( Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||||||
|
result.append( escherRecord.toString() );
|
||||||
|
}
|
||||||
|
result.append( "[/" ).append( getRecordName() ).append( ']' + nl );
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collapses the drawing records into an aggregate.
|
||||||
|
*/
|
||||||
|
public static EscherAggregate createAggregate( List records, int locFirstDrawingRecord, DrawingManager 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.
|
||||||
|
final List shapeRecords = new ArrayList();
|
||||||
|
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory()
|
||||||
|
{
|
||||||
|
public EscherRecord createRecord( byte[] data, int offset )
|
||||||
|
{
|
||||||
|
EscherRecord r = super.createRecord( data, offset );
|
||||||
|
if ( r.getRecordId() == EscherClientDataRecord.RECORD_ID || r.getRecordId() == EscherTextboxRecord.RECORD_ID )
|
||||||
|
{
|
||||||
|
shapeRecords.add( r );
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate the size of the buffer
|
||||||
|
EscherAggregate agg = new EscherAggregate(drawingManager);
|
||||||
|
int loc = locFirstDrawingRecord;
|
||||||
|
int dataSize = 0;
|
||||||
|
while ( loc + 1 < records.size()
|
||||||
|
&& sid( records, loc ) == DrawingRecord.sid
|
||||||
|
&& isObjectRecord( records, loc + 1 ) )
|
||||||
|
{
|
||||||
|
dataSize += ( (DrawingRecord) records.get( loc ) ).getData().length;
|
||||||
|
loc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create one big buffer
|
||||||
|
byte buffer[] = new byte[dataSize];
|
||||||
|
int offset = 0;
|
||||||
|
loc = locFirstDrawingRecord;
|
||||||
|
while ( loc + 1 < records.size()
|
||||||
|
&& sid( records, loc ) == DrawingRecord.sid
|
||||||
|
&& isObjectRecord( records, loc + 1 ) )
|
||||||
|
{
|
||||||
|
DrawingRecord drawingRecord = (DrawingRecord) records.get( loc );
|
||||||
|
System.arraycopy( drawingRecord.getData(), 0, buffer, offset, drawingRecord.getData().length );
|
||||||
|
offset += drawingRecord.getData().length;
|
||||||
|
loc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the shapes
|
||||||
|
// agg.escherRecords = new ArrayList();
|
||||||
|
int pos = 0;
|
||||||
|
while ( pos < dataSize )
|
||||||
|
{
|
||||||
|
EscherRecord r = recordFactory.createRecord( buffer, pos );
|
||||||
|
int bytesRead = r.fillFields( buffer, pos, recordFactory );
|
||||||
|
agg.addEscherRecord( r );
|
||||||
|
pos += bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Associate the object records with the shapes
|
||||||
|
loc = locFirstDrawingRecord;
|
||||||
|
int shapeIndex = 0;
|
||||||
|
agg.shapeToObj = new HashMap();
|
||||||
|
while ( loc + 1 < records.size()
|
||||||
|
&& sid( records, loc ) == DrawingRecord.sid
|
||||||
|
&& isObjectRecord( records, loc + 1 ) )
|
||||||
|
{
|
||||||
|
Record objRecord = (Record) records.get( loc + 1 );
|
||||||
|
agg.shapeToObj.put( shapeRecords.get( shapeIndex++ ), objRecord );
|
||||||
|
loc += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return agg;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes this aggregate to a byte array. Since this is an aggregate
|
||||||
|
* record it will effectively serialize the aggregated records.
|
||||||
|
*
|
||||||
|
* @param offset The offset into the start of the array.
|
||||||
|
* @param data The byte array to serialize to.
|
||||||
|
* @return The number of bytes serialized.
|
||||||
|
*/
|
||||||
|
public int serialize( int offset, byte[] data )
|
||||||
|
{
|
||||||
|
convertUserModelToRecords();
|
||||||
|
|
||||||
|
// Determine buffer size
|
||||||
|
List records = getEscherRecords();
|
||||||
|
int size = getEscherRecordSize( records );
|
||||||
|
byte[] buffer = new byte[size];
|
||||||
|
|
||||||
|
|
||||||
|
// Serialize escher records into one big data structure and keep note of ending offsets.
|
||||||
|
final List spEndingOffsets = new ArrayList();
|
||||||
|
final List shapes = new ArrayList();
|
||||||
|
int pos = 0;
|
||||||
|
for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord e = (EscherRecord) iterator.next();
|
||||||
|
pos += e.serialize( pos, buffer, new EscherSerializationListener()
|
||||||
|
{
|
||||||
|
public void beforeRecordSerialize( int offset, short recordId, EscherRecord record )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterRecordSerialize( int offset, short recordId, int size, EscherRecord record )
|
||||||
|
{
|
||||||
|
if ( recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID )
|
||||||
|
{
|
||||||
|
spEndingOffsets.add( new Integer( offset ) );
|
||||||
|
shapes.add( record );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
// todo: fix this
|
||||||
|
shapes.add( 0, null );
|
||||||
|
spEndingOffsets.add( 0, null );
|
||||||
|
|
||||||
|
// Split escher records into separate MSODRAWING and OBJ, TXO records. (We don't break on
|
||||||
|
// the first one because it's the patriach).
|
||||||
|
pos = offset;
|
||||||
|
for ( int i = 1; i < shapes.size(); i++ )
|
||||||
|
{
|
||||||
|
int endOffset = ( (Integer) spEndingOffsets.get( i ) ).intValue() - 1;
|
||||||
|
int startOffset;
|
||||||
|
if ( i == 1 )
|
||||||
|
startOffset = 0;
|
||||||
|
else
|
||||||
|
startOffset = ( (Integer) spEndingOffsets.get( i - 1 ) ).intValue();
|
||||||
|
|
||||||
|
// Create and write a new MSODRAWING record
|
||||||
|
DrawingRecord drawing = new DrawingRecord();
|
||||||
|
byte[] drawingData = new byte[endOffset - startOffset + 1];
|
||||||
|
System.arraycopy( buffer, startOffset, drawingData, 0, drawingData.length );
|
||||||
|
drawing.setData( drawingData );
|
||||||
|
int temp = drawing.serialize( pos, data );
|
||||||
|
pos += temp;
|
||||||
|
|
||||||
|
// Write the matching OBJ record
|
||||||
|
Record obj = (Record) shapeToObj.get( shapes.get( i ) );
|
||||||
|
temp = obj.serialize( pos, data );
|
||||||
|
pos += temp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytesWritten = pos - offset;
|
||||||
|
if ( bytesWritten != getRecordSize() )
|
||||||
|
throw new RecordFormatException( bytesWritten + " bytes written but getRecordSize() reports " + getRecordSize() );
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many bytes do the raw escher records contain.
|
||||||
|
* @param records List of escher records
|
||||||
|
* @return the number of bytes
|
||||||
|
*/
|
||||||
|
private int getEscherRecordSize( List records )
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
|
||||||
|
size += ( (EscherRecord) iterator.next() ).getRecordSize();
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of bytes required to serialize this record.
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
convertUserModelToRecords();
|
||||||
|
List records = getEscherRecords();
|
||||||
|
int rawEscherSize = getEscherRecordSize( records );
|
||||||
|
int drawingRecordSize = rawEscherSize + ( shapeToObj.size() ) * 4;
|
||||||
|
int objRecordSize = 0;
|
||||||
|
for ( Iterator iterator = shapeToObj.values().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
Record r = (Record) iterator.next();
|
||||||
|
objRecordSize += r.getRecordSize();
|
||||||
|
}
|
||||||
|
return drawingRecordSize + objRecordSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associates an escher record to an OBJ record or a TXO record.
|
||||||
|
*/
|
||||||
|
public Object assoicateShapeToObjRecord( EscherRecord r, Record objRecord )
|
||||||
|
{
|
||||||
|
return shapeToObj.put( r, objRecord );
|
||||||
|
}
|
||||||
|
|
||||||
|
public HSSFPatriarch getPatriarch()
|
||||||
|
{
|
||||||
|
return patriarch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPatriarch( HSSFPatriarch patriarch )
|
||||||
|
{
|
||||||
|
this.patriarch = patriarch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
clearEscherRecords();
|
||||||
|
shapeToObj.clear();
|
||||||
|
// lastShapeId = 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getRecordName()
|
||||||
|
{
|
||||||
|
return "ESCHERAGGREGATE";
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============== Private methods ========================
|
||||||
|
|
||||||
|
private static boolean isObjectRecord( List records, int loc )
|
||||||
|
{
|
||||||
|
return sid( records, loc ) == ObjRecord.sid || sid( records, loc ) == TextObjectRecord.sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertUserModelToRecords()
|
||||||
|
{
|
||||||
|
if ( patriarch != null )
|
||||||
|
{
|
||||||
|
shapeToObj.clear();
|
||||||
|
clearEscherRecords();
|
||||||
|
if ( patriarch.getChildren().size() != 0 )
|
||||||
|
{
|
||||||
|
convertPatriarch( patriarch );
|
||||||
|
EscherContainerRecord dgContainer = (EscherContainerRecord) getEscherRecord( 0 );
|
||||||
|
EscherContainerRecord spgrContainer = null;
|
||||||
|
for ( int i = 0; i < dgContainer.getChildRecords().size(); i++ )
|
||||||
|
if ( dgContainer.getChild( i ).getRecordId() == EscherContainerRecord.SPGR_CONTAINER )
|
||||||
|
spgrContainer = (EscherContainerRecord) dgContainer.getChild( i );
|
||||||
|
convertShapes( patriarch, spgrContainer, shapeToObj );
|
||||||
|
|
||||||
|
patriarch = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertShapes( HSSFShapeContainer parent, EscherContainerRecord escherParent, Map shapeToObj )
|
||||||
|
{
|
||||||
|
if ( escherParent == null ) throw new IllegalArgumentException( "Parent record required" );
|
||||||
|
|
||||||
|
List shapes = parent.getChildren();
|
||||||
|
for ( Iterator iterator = shapes.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
HSSFShape shape = (HSSFShape) iterator.next();
|
||||||
|
if ( shape instanceof HSSFShapeGroup )
|
||||||
|
{
|
||||||
|
convertGroup( (HSSFShapeGroup) shape, escherParent, shapeToObj );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AbstractShape shapeModel = AbstractShape.createShape(
|
||||||
|
shape,
|
||||||
|
drawingManager.allocateShapeId(drawingGroupId) );
|
||||||
|
shapeToObj.put( findClientData( shapeModel.getSpContainer() ), shapeModel.getObjRecord() );
|
||||||
|
if ( shapeModel instanceof TextboxShape )
|
||||||
|
{
|
||||||
|
EscherRecord escherTextbox = ( (TextboxShape) shapeModel ).getEscherTextbox();
|
||||||
|
shapeToObj.put( escherTextbox, ( (TextboxShape) shapeModel ).getTextObjectRecord() );
|
||||||
|
// escherParent.addChildRecord(escherTextbox);
|
||||||
|
}
|
||||||
|
escherParent.addChildRecord( shapeModel.getSpContainer() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertGroup( HSSFShapeGroup shape, EscherContainerRecord escherParent, Map shapeToObj )
|
||||||
|
{
|
||||||
|
EscherContainerRecord spgrContainer = new EscherContainerRecord();
|
||||||
|
EscherContainerRecord spContainer = new EscherContainerRecord();
|
||||||
|
EscherSpgrRecord spgr = new EscherSpgrRecord();
|
||||||
|
EscherSpRecord sp = new EscherSpRecord();
|
||||||
|
EscherOptRecord opt = new EscherOptRecord();
|
||||||
|
EscherRecord anchor;
|
||||||
|
EscherClientDataRecord clientData = new EscherClientDataRecord();
|
||||||
|
|
||||||
|
spgrContainer.setRecordId( EscherContainerRecord.SPGR_CONTAINER );
|
||||||
|
spgrContainer.setOptions( (short) 0x000F );
|
||||||
|
spContainer.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
|
spContainer.setOptions( (short) 0x000F );
|
||||||
|
spgr.setRecordId( EscherSpgrRecord.RECORD_ID );
|
||||||
|
spgr.setOptions( (short) 0x0001 );
|
||||||
|
spgr.setRectX1( shape.getX1() );
|
||||||
|
spgr.setRectY1( shape.getY1() );
|
||||||
|
spgr.setRectX2( shape.getX2() );
|
||||||
|
spgr.setRectY2( shape.getY2() );
|
||||||
|
sp.setRecordId( EscherSpRecord.RECORD_ID );
|
||||||
|
sp.setOptions( (short) 0x0002 );
|
||||||
|
int shapeId = drawingManager.allocateShapeId(drawingGroupId);
|
||||||
|
sp.setShapeId( shapeId );
|
||||||
|
if (shape.getAnchor() instanceof HSSFClientAnchor)
|
||||||
|
sp.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR );
|
||||||
|
else
|
||||||
|
sp.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_CHILD );
|
||||||
|
opt.setRecordId( EscherOptRecord.RECORD_ID );
|
||||||
|
opt.setOptions( (short) 0x0023 );
|
||||||
|
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x00040004 ) );
|
||||||
|
opt.addEscherProperty( new EscherBoolProperty( EscherProperties.GROUPSHAPE__PRINT, 0x00080000 ) );
|
||||||
|
|
||||||
|
anchor = ConvertAnchor.createAnchor( shape.getAnchor() );
|
||||||
|
// clientAnchor.setCol1( ( (HSSFClientAnchor) shape.getAnchor() ).getCol1() );
|
||||||
|
// clientAnchor.setRow1( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow1() );
|
||||||
|
// clientAnchor.setDx1( (short) shape.getAnchor().getDx1() );
|
||||||
|
// clientAnchor.setDy1( (short) shape.getAnchor().getDy1() );
|
||||||
|
// clientAnchor.setCol2( ( (HSSFClientAnchor) shape.getAnchor() ).getCol2() );
|
||||||
|
// clientAnchor.setRow2( (short) ( (HSSFClientAnchor) shape.getAnchor() ).getRow2() );
|
||||||
|
// clientAnchor.setDx2( (short) shape.getAnchor().getDx2() );
|
||||||
|
// clientAnchor.setDy2( (short) shape.getAnchor().getDy2() );
|
||||||
|
clientData.setRecordId( EscherClientDataRecord.RECORD_ID );
|
||||||
|
clientData.setOptions( (short) 0x0000 );
|
||||||
|
|
||||||
|
spgrContainer.addChildRecord( spContainer );
|
||||||
|
spContainer.addChildRecord( spgr );
|
||||||
|
spContainer.addChildRecord( sp );
|
||||||
|
spContainer.addChildRecord( opt );
|
||||||
|
spContainer.addChildRecord( anchor );
|
||||||
|
spContainer.addChildRecord( clientData );
|
||||||
|
|
||||||
|
ObjRecord obj = new ObjRecord();
|
||||||
|
CommonObjectDataSubRecord cmo = new CommonObjectDataSubRecord();
|
||||||
|
cmo.setObjectType( CommonObjectDataSubRecord.OBJECT_TYPE_GROUP );
|
||||||
|
cmo.setObjectId( (short) ( shapeId ) );
|
||||||
|
cmo.setLocked( true );
|
||||||
|
cmo.setPrintable( true );
|
||||||
|
cmo.setAutofill( true );
|
||||||
|
cmo.setAutoline( true );
|
||||||
|
GroupMarkerSubRecord gmo = new GroupMarkerSubRecord();
|
||||||
|
EndSubRecord end = new EndSubRecord();
|
||||||
|
obj.addSubRecord( cmo );
|
||||||
|
obj.addSubRecord( gmo );
|
||||||
|
obj.addSubRecord( end );
|
||||||
|
shapeToObj.put( clientData, obj );
|
||||||
|
|
||||||
|
escherParent.addChildRecord( spgrContainer );
|
||||||
|
|
||||||
|
convertShapes( shape, spgrContainer, shapeToObj );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherRecord findClientData( EscherContainerRecord spContainer )
|
||||||
|
{
|
||||||
|
for ( Iterator iterator = spContainer.getChildRecords().iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
EscherRecord r = (EscherRecord) iterator.next();
|
||||||
|
if ( r.getRecordId() == EscherClientDataRecord.RECORD_ID )
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException( "Can not find client data record" );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void convertPatriarch( HSSFPatriarch patriarch )
|
||||||
|
{
|
||||||
|
EscherContainerRecord dgContainer = new EscherContainerRecord();
|
||||||
|
EscherDgRecord dg;
|
||||||
|
EscherContainerRecord spgrContainer = new EscherContainerRecord();
|
||||||
|
EscherContainerRecord spContainer1 = new EscherContainerRecord();
|
||||||
|
EscherSpgrRecord spgr = new EscherSpgrRecord();
|
||||||
|
EscherSpRecord sp1 = new EscherSpRecord();
|
||||||
|
|
||||||
|
dgContainer.setRecordId( EscherContainerRecord.DG_CONTAINER );
|
||||||
|
dgContainer.setOptions( (short) 0x000F );
|
||||||
|
dg = drawingManager.createDgRecord();
|
||||||
|
drawingGroupId = dg.getDrawingGroupId();
|
||||||
|
// dg.setOptions( (short) ( drawingId << 4 ) );
|
||||||
|
// dg.setNumShapes( getNumberOfShapes( patriarch ) );
|
||||||
|
// dg.setLastMSOSPID( 0 ); // populated after all shape id's are assigned.
|
||||||
|
spgrContainer.setRecordId( EscherContainerRecord.SPGR_CONTAINER );
|
||||||
|
spgrContainer.setOptions( (short) 0x000F );
|
||||||
|
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.setRectX1( patriarch.getX1() );
|
||||||
|
spgr.setRectY1( patriarch.getY1() );
|
||||||
|
spgr.setRectX2( patriarch.getX2() );
|
||||||
|
spgr.setRectY2( patriarch.getY2() );
|
||||||
|
sp1.setRecordId( EscherSpRecord.RECORD_ID );
|
||||||
|
sp1.setOptions( (short) 0x0002 );
|
||||||
|
sp1.setShapeId( drawingManager.allocateShapeId(dg.getDrawingGroupId()) );
|
||||||
|
sp1.setFlags( EscherSpRecord.FLAG_GROUP | EscherSpRecord.FLAG_PATRIARCH );
|
||||||
|
|
||||||
|
dgContainer.addChildRecord( dg );
|
||||||
|
dgContainer.addChildRecord( spgrContainer );
|
||||||
|
spgrContainer.addChildRecord( spContainer1 );
|
||||||
|
spContainer1.addChildRecord( spgr );
|
||||||
|
spContainer1.addChildRecord( sp1 );
|
||||||
|
|
||||||
|
addEscherRecord( dgContainer );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieve the number of shapes (including the patriarch). */
|
||||||
|
// private int getNumberOfShapes( HSSFPatriarch patriarch )
|
||||||
|
// {
|
||||||
|
// return patriarch.countOfAllChildren();
|
||||||
|
// }
|
||||||
|
|
||||||
|
private static short sid( List records, int loc )
|
||||||
|
{
|
||||||
|
return ( (Record) records.get( loc ) ).getSid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
176
src/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java
Normal file
176
src/java/org/apache/poi/hssf/record/GroupMarkerSubRecord.java
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.poi.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The group marker record is used as a position holder for groups.
|
||||||
|
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class GroupMarkerSubRecord
|
||||||
|
extends SubRecord
|
||||||
|
{
|
||||||
|
public final static short sid = 0x06;
|
||||||
|
|
||||||
|
private byte[] reserved = new byte[0]; // would really love to know what goes in here.
|
||||||
|
|
||||||
|
public GroupMarkerSubRecord()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a group marker record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x00 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public GroupMarkerSubRecord(short id, short size, byte [] data)
|
||||||
|
{
|
||||||
|
super(id, size, data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a group marker record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x00 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
* @param offset of the record's data
|
||||||
|
*/
|
||||||
|
|
||||||
|
public GroupMarkerSubRecord(short id, short size, byte [] data, int offset)
|
||||||
|
{
|
||||||
|
super(id, size, data, offset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the sid matches the expected side for this record
|
||||||
|
*
|
||||||
|
* @param id the expected sid.
|
||||||
|
*/
|
||||||
|
protected void validateSid(short id)
|
||||||
|
{
|
||||||
|
if (id != sid)
|
||||||
|
{
|
||||||
|
throw new RecordFormatException("Not a Group Marker record");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillFields(byte [] data, short size, int offset)
|
||||||
|
{
|
||||||
|
// int pos = 0;
|
||||||
|
reserved = new byte[size];
|
||||||
|
System.arraycopy(data, offset, reserved, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
String nl = System.getProperty("line.separator");
|
||||||
|
buffer.append("[ftGmo]" + nl);
|
||||||
|
buffer.append(" reserved = ").append(HexDump.toHex(reserved)).append(nl);
|
||||||
|
buffer.append("[/ftGmo]" + nl);
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int serialize(int offset, byte[] data)
|
||||||
|
{
|
||||||
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
|
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));
|
||||||
|
System.arraycopy(reserved, 0, data, offset + 4, getRecordSize() - 4);
|
||||||
|
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of record (exluding 4 byte header)
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 4 + reserved.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone() {
|
||||||
|
GroupMarkerSubRecord rec = new GroupMarkerSubRecord();
|
||||||
|
rec.reserved = new byte[reserved.length];
|
||||||
|
for ( int i = 0; i < reserved.length; i++ )
|
||||||
|
rec.reserved[i] = reserved[i];
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // END OF CLASS
|
||||||
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HorizontalPageBreak record that stores page breaks at rows
|
||||||
|
* <p>
|
||||||
|
* This class is just used so that SID compares work properly in the RecordFactory
|
||||||
|
* @see PageBreakRecord
|
||||||
|
* @author Danny Mui (dmui at apache dot org)
|
||||||
|
*/
|
||||||
|
public class HorizontalPageBreakRecord extends PageBreakRecord {
|
||||||
|
|
||||||
|
public static final short sid = PageBreakRecord.HORIZONTAL_SID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public HorizontalPageBreakRecord() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sid
|
||||||
|
*/
|
||||||
|
public HorizontalPageBreakRecord(short sid) {
|
||||||
|
super(sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @param size
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
public HorizontalPageBreakRecord(short id, short size, byte[] data) {
|
||||||
|
super(id, size, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @param size
|
||||||
|
* @param data
|
||||||
|
* @param offset
|
||||||
|
*/
|
||||||
|
public HorizontalPageBreakRecord(short id, short size, byte[] data, int offset) {
|
||||||
|
super(id, size, data, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.poi.hssf.record.Record#getSid()
|
||||||
|
*/
|
||||||
|
public short getSid() {
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
227
src/java/org/apache/poi/hssf/record/ObjRecord.java
Normal file
227
src/java/org/apache/poi/hssf/record/ObjRecord.java
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.poi.util.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The obj record is used to hold various graphic objects and controls.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class ObjRecord
|
||||||
|
extends Record
|
||||||
|
{
|
||||||
|
public final static short sid = 0x5D;
|
||||||
|
private List subrecords;
|
||||||
|
|
||||||
|
//00000000 15 00 12 00 01 00 01 00 11 60 00 00 00 00 00 0D .........`......
|
||||||
|
//00000010 26 01 00 00 00 00 00 00 00 00 &.........
|
||||||
|
|
||||||
|
|
||||||
|
public ObjRecord()
|
||||||
|
{
|
||||||
|
subrecords = new ArrayList(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a OBJ record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x5D or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public ObjRecord(short id, short size, byte [] data)
|
||||||
|
{
|
||||||
|
super(id, size, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a obj record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x5D or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
* @param offset of the record's data
|
||||||
|
*/
|
||||||
|
public ObjRecord(short id, short size, byte[] data, int offset)
|
||||||
|
{
|
||||||
|
super(id, size, data, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the sid matches the expected side for this record
|
||||||
|
*
|
||||||
|
* @param id the expected sid.
|
||||||
|
*/
|
||||||
|
protected void validateSid(short id)
|
||||||
|
{
|
||||||
|
if (id != sid)
|
||||||
|
{
|
||||||
|
throw new RecordFormatException("Not an OBJ record");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillFields(byte [] data, short size, int offset)
|
||||||
|
{
|
||||||
|
subrecords = new ArrayList();
|
||||||
|
int pos = offset;
|
||||||
|
while (pos - offset < size)
|
||||||
|
{
|
||||||
|
short subRecordSid = LittleEndian.getShort(data, pos);
|
||||||
|
short subRecordSize = LittleEndian.getShort(data, pos + 2);
|
||||||
|
Record subRecord = SubRecord.createSubRecord(subRecordSid, subRecordSize, data, pos + 4);
|
||||||
|
subrecords.add(subRecord);
|
||||||
|
pos += 4 + subRecordSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
buffer.append("[OBJ]\n");
|
||||||
|
for ( Iterator iterator = subrecords.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
Record record = (Record) iterator.next();
|
||||||
|
buffer.append("SUBRECORD: " + record.toString());
|
||||||
|
}
|
||||||
|
buffer.append("[/OBJ]\n");
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int serialize(int offset, byte[] data)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
|
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));
|
||||||
|
|
||||||
|
pos = offset + 4;
|
||||||
|
for ( Iterator iterator = subrecords.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
Record record = (Record) iterator.next();
|
||||||
|
pos += record.serialize(pos, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of record (excluding 4 byte header)
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
int size = 0;
|
||||||
|
for ( Iterator iterator = subrecords.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
Record record = (Record) iterator.next();
|
||||||
|
size += record.getRecordSize();
|
||||||
|
}
|
||||||
|
return 4 + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List getSubRecords()
|
||||||
|
{
|
||||||
|
return subrecords;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearSubRecords()
|
||||||
|
{
|
||||||
|
subrecords.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSubRecord(int index, Object element)
|
||||||
|
{
|
||||||
|
subrecords.add( index, element );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addSubRecord(Object o)
|
||||||
|
{
|
||||||
|
return subrecords.add( o );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone()
|
||||||
|
{
|
||||||
|
ObjRecord rec = new ObjRecord();
|
||||||
|
rec.subrecords = new ArrayList();
|
||||||
|
|
||||||
|
for ( Iterator iterator = subrecords.iterator(); iterator.hasNext(); )
|
||||||
|
subrecords.add(( (Record) iterator.next() ).clone());
|
||||||
|
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // END OF CLASS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
304
src/java/org/apache/poi/hssf/record/PageBreakRecord.java
Normal file
304
src/java/org/apache/poi/hssf/record/PageBreakRecord.java
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record that contains the functionality page breaks (horizontal and vertical)
|
||||||
|
* <p>
|
||||||
|
* The other two classes just specifically set the SIDS for record creation
|
||||||
|
* @see HorizontalPageBreakRecord
|
||||||
|
* @see VerticalPageBreakREcord
|
||||||
|
*
|
||||||
|
* REFERENCE: Microsoft Excel SDK page 322 and 420
|
||||||
|
* @author Danny Mui (dmui at apache dot org)
|
||||||
|
*/
|
||||||
|
public class PageBreakRecord extends Record {
|
||||||
|
public static final short HORIZONTAL_SID = (short)0x1B;
|
||||||
|
public static final short VERTICAL_SID = (short)0x1A;
|
||||||
|
public short sid;
|
||||||
|
private short numBreaks;
|
||||||
|
private List breaks;
|
||||||
|
private Map BreakMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since both records store 2byte integers (short), no point in
|
||||||
|
* differentiating it in the records.
|
||||||
|
* <p>
|
||||||
|
* The subs (rows or columns, don't seem to be able to set but excel sets
|
||||||
|
* them automatically)
|
||||||
|
*/
|
||||||
|
public class Break
|
||||||
|
{
|
||||||
|
|
||||||
|
public short main;
|
||||||
|
public short subFrom;
|
||||||
|
public short subTo;
|
||||||
|
|
||||||
|
public Break(short main, short subFrom, short subTo)
|
||||||
|
{
|
||||||
|
this.main = main;
|
||||||
|
this.subFrom = subFrom;
|
||||||
|
this.subTo = subTo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageBreakRecord()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param sid
|
||||||
|
*/
|
||||||
|
public PageBreakRecord(short sid) {
|
||||||
|
super();
|
||||||
|
this.sid = sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageBreakRecord(short id, short size, byte data[])
|
||||||
|
{
|
||||||
|
super(id, size, data);
|
||||||
|
this.sid = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageBreakRecord(short id, short size, byte data[], int offset)
|
||||||
|
{
|
||||||
|
super(id, size, data, offset);
|
||||||
|
this.sid = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillFields(byte data[], short size, int offset)
|
||||||
|
{
|
||||||
|
short loadedBreaks = LittleEndian.getShort(data, 0 + offset);
|
||||||
|
setNumBreaks(loadedBreaks);
|
||||||
|
int pos = 2;
|
||||||
|
for(int k = 0; k < loadedBreaks; k++)
|
||||||
|
{
|
||||||
|
addBreak((short)(LittleEndian.getShort(data, pos + offset) - 1), LittleEndian.getShort(data, pos + 2 + offset), LittleEndian.getShort(data, pos + 4 + offset));
|
||||||
|
pos += 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int serialize(int offset, byte data[])
|
||||||
|
{
|
||||||
|
int recordsize = getRecordSize();
|
||||||
|
int pos = 6;
|
||||||
|
LittleEndian.putShort(data, offset + 0, getSid());
|
||||||
|
LittleEndian.putShort(data, offset + 2, (short)(recordsize - 4));
|
||||||
|
LittleEndian.putShort(data, offset + 4, getNumBreaks());
|
||||||
|
for(Iterator iterator = getBreaksIterator(); iterator.hasNext();)
|
||||||
|
{
|
||||||
|
Break Break = (Break)iterator.next();
|
||||||
|
LittleEndian.putShort(data, offset + pos, (short)(Break.main + 1));
|
||||||
|
pos += 2;
|
||||||
|
LittleEndian.putShort(data, offset + pos, Break.subFrom);
|
||||||
|
pos += 2;
|
||||||
|
LittleEndian.putShort(data, offset + pos, Break.subTo);
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return recordsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void validateSid(short id)
|
||||||
|
{
|
||||||
|
if(id != HORIZONTAL_SID && id != VERTICAL_SID)
|
||||||
|
throw new RecordFormatException("NOT A HorizontalPageBreak or VerticalPageBreak RECORD!! " + id);
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getNumBreaks()
|
||||||
|
{
|
||||||
|
return breaks != null ? (short)breaks.size() : numBreaks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumBreaks(short numBreaks)
|
||||||
|
{
|
||||||
|
this.numBreaks = numBreaks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator getBreaksIterator()
|
||||||
|
{
|
||||||
|
if(breaks == null)
|
||||||
|
return Collections.EMPTY_LIST.iterator();
|
||||||
|
else
|
||||||
|
return breaks.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer retval = new StringBuffer();
|
||||||
|
|
||||||
|
if (getSid() != HORIZONTAL_SID && getSid()!= VERTICAL_SID)
|
||||||
|
return "[INVALIDPAGEBREAK]\n .sid ="+getSid()+"[INVALIDPAGEBREAK]";
|
||||||
|
|
||||||
|
String label;
|
||||||
|
String mainLabel;
|
||||||
|
String subLabel;
|
||||||
|
|
||||||
|
if (getSid() == HORIZONTAL_SID) {
|
||||||
|
label = "HORIZONTALPAGEBREAK";
|
||||||
|
mainLabel = "row";
|
||||||
|
subLabel = "col";
|
||||||
|
} else {
|
||||||
|
label = "VERTICALPAGEBREAK";
|
||||||
|
mainLabel = "column";
|
||||||
|
subLabel = "row";
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.append("["+label+"]").append("\n");
|
||||||
|
retval.append(" .sid =").append(getSid()).append("\n");
|
||||||
|
retval.append(" .numbreaks =").append(getNumBreaks()).append("\n");
|
||||||
|
Iterator iterator = getBreaksIterator();
|
||||||
|
for(int k = 0; k < getNumBreaks(); k++)
|
||||||
|
{
|
||||||
|
Break region = (Break)iterator.next();
|
||||||
|
|
||||||
|
retval.append(" .").append(mainLabel).append(" (zero-based) =").append(region.main).append("\n");
|
||||||
|
retval.append(" .").append(subLabel).append("From =").append(region.subFrom).append("\n");
|
||||||
|
retval.append(" .").append(subLabel).append("To =").append(region.subTo).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
retval.append("["+label+"]").append("\n");
|
||||||
|
return retval.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the page break at the specified parameters
|
||||||
|
* @param main Depending on sid, will determine row or column to put page break (zero-based)
|
||||||
|
* @param subFrom No user-interface to set (defaults to minumum, 0)
|
||||||
|
* @param subTo No user-interface to set
|
||||||
|
*/
|
||||||
|
public void addBreak(short main, short subFrom, short subTo)
|
||||||
|
{
|
||||||
|
if(breaks == null)
|
||||||
|
{
|
||||||
|
breaks = new ArrayList(getNumBreaks() + 10);
|
||||||
|
BreakMap = new HashMap();
|
||||||
|
}
|
||||||
|
Integer key = new Integer(main);
|
||||||
|
Break region = (Break)BreakMap.get(key);
|
||||||
|
if(region != null)
|
||||||
|
{
|
||||||
|
region.main = main;
|
||||||
|
region.subFrom = subFrom;
|
||||||
|
region.subTo = subTo;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
region = new Break(main, subFrom, subTo);
|
||||||
|
breaks.add(region);
|
||||||
|
}
|
||||||
|
BreakMap.put(key, region);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the break indicated by the parameter
|
||||||
|
* @param main (zero-based)
|
||||||
|
*/
|
||||||
|
public void removeBreak(short main)
|
||||||
|
{
|
||||||
|
Integer rowKey = new Integer(main);
|
||||||
|
Break region = (Break)BreakMap.get(rowKey);
|
||||||
|
breaks.remove(region);
|
||||||
|
BreakMap.remove(rowKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 6 + getNumBreaks() * 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the region at the row/column indicated
|
||||||
|
* @param main
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Break getBreak(short main)
|
||||||
|
{
|
||||||
|
Integer rowKey = new Integer(main);
|
||||||
|
return (Break)BreakMap.get(rowKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clones the page break record
|
||||||
|
* @see java.lang.Object#clone()
|
||||||
|
*/
|
||||||
|
public Object clone() {
|
||||||
|
PageBreakRecord record = new PageBreakRecord(getSid());
|
||||||
|
Iterator iterator = getBreaksIterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Break original = (Break)iterator.next();
|
||||||
|
record.addBreak(original.main, original.subFrom, original.subTo);
|
||||||
|
}
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -112,7 +112,10 @@ public class RecordFactory
|
|||||||
FormulaRecord.class, BoolErrRecord.class, ExternSheetRecord.class,
|
FormulaRecord.class, BoolErrRecord.class, ExternSheetRecord.class,
|
||||||
NameRecord.class, LeftMarginRecord.class, RightMarginRecord.class,
|
NameRecord.class, LeftMarginRecord.class, RightMarginRecord.class,
|
||||||
TopMarginRecord.class, BottomMarginRecord.class,
|
TopMarginRecord.class, BottomMarginRecord.class,
|
||||||
PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class
|
PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class,
|
||||||
|
DrawingRecord.class, DrawingGroupRecord.class, DrawingSelectionRecord.class,
|
||||||
|
ObjRecord.class, TextObjectRecord.class,
|
||||||
|
HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
records = new Class[]
|
records = new Class[]
|
||||||
@ -143,7 +146,10 @@ public class RecordFactory
|
|||||||
BoolErrRecord.class, ExternSheetRecord.class, NameRecord.class,
|
BoolErrRecord.class, ExternSheetRecord.class, NameRecord.class,
|
||||||
LeftMarginRecord.class, RightMarginRecord.class,
|
LeftMarginRecord.class, RightMarginRecord.class,
|
||||||
TopMarginRecord.class, BottomMarginRecord.class,
|
TopMarginRecord.class, BottomMarginRecord.class,
|
||||||
PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class
|
PaletteRecord.class, StringRecord.class, RecalcIdRecord.class, SharedFormulaRecord.class,
|
||||||
|
DrawingRecord.class, DrawingGroupRecord.class, DrawingSelectionRecord.class,
|
||||||
|
ObjRecord.class, TextObjectRecord.class,
|
||||||
|
HorizontalPageBreakRecord.class, VerticalPageBreakRecord.class
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
98
src/java/org/apache/poi/hssf/record/SubRecord.java
Normal file
98
src/java/org/apache/poi/hssf/record/SubRecord.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subrecords are part of the OBJ class.
|
||||||
|
*/
|
||||||
|
abstract public class SubRecord
|
||||||
|
extends Record
|
||||||
|
{
|
||||||
|
public SubRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubRecord( short id, short size, byte[] data )
|
||||||
|
{
|
||||||
|
super( id, size, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubRecord( short id, short size, byte[] data, int offset )
|
||||||
|
{
|
||||||
|
super( id, size, data, offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Record createSubRecord( short subRecordSid, short size, byte[] data, int offset )
|
||||||
|
{
|
||||||
|
Record r = null;
|
||||||
|
|
||||||
|
switch ( subRecordSid )
|
||||||
|
{
|
||||||
|
case CommonObjectDataSubRecord.sid:
|
||||||
|
r = new CommonObjectDataSubRecord( subRecordSid, size, data, offset );
|
||||||
|
break;
|
||||||
|
case GroupMarkerSubRecord.sid:
|
||||||
|
r = new GroupMarkerSubRecord( subRecordSid, size, data, offset );
|
||||||
|
break;
|
||||||
|
case EndSubRecord.sid:
|
||||||
|
r = new EndSubRecord( subRecordSid, size, data, offset );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
r = new UnknownRecord( subRecordSid, size, data, offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,127 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the serialization and deserialization of the CommonObjectDataSubRecord
|
||||||
|
* class works correctly. Test data taken directly from a real
|
||||||
|
* Excel file.
|
||||||
|
*
|
||||||
|
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class TestCommonObjectDataSubRecord
|
||||||
|
extends TestCase
|
||||||
|
{
|
||||||
|
byte[] data = new byte[] {
|
||||||
|
(byte)0x12,(byte)0x00,(byte)0x01,(byte)0x00,
|
||||||
|
(byte)0x01,(byte)0x00,(byte)0x11,(byte)0x60,
|
||||||
|
(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
|
||||||
|
(byte)0x00,(byte)0x0D,(byte)0x26,(byte)0x01,
|
||||||
|
(byte)0x00,(byte)0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
public TestCommonObjectDataSubRecord(String name)
|
||||||
|
{
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLoad()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
CommonObjectDataSubRecord record = new CommonObjectDataSubRecord((short)0x15, (short)data.length, data);
|
||||||
|
|
||||||
|
|
||||||
|
assertEquals( CommonObjectDataSubRecord.OBJECT_TYPE_LIST_BOX, record.getObjectType());
|
||||||
|
assertEquals( (short)1, record.getObjectId());
|
||||||
|
assertEquals( (short)1, record.getOption());
|
||||||
|
assertEquals( true , record.isLocked() );
|
||||||
|
assertEquals( false, record.isPrintable() );
|
||||||
|
assertEquals( false, record.isAutofill() );
|
||||||
|
assertEquals( false, record.isAutoline() );
|
||||||
|
assertEquals( (int)24593, record.getReserved1());
|
||||||
|
assertEquals( (int)218103808, record.getReserved2());
|
||||||
|
assertEquals( (int)294, record.getReserved3());
|
||||||
|
assertEquals( 22 , record.getRecordSize() );
|
||||||
|
|
||||||
|
record.validateSid((short)0x15);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStore()
|
||||||
|
{
|
||||||
|
CommonObjectDataSubRecord record = new CommonObjectDataSubRecord();
|
||||||
|
|
||||||
|
record.setObjectType( CommonObjectDataSubRecord.OBJECT_TYPE_LIST_BOX );
|
||||||
|
record.setObjectId( (short) 1);
|
||||||
|
record.setOption( (short) 1);
|
||||||
|
record.setLocked( true );
|
||||||
|
record.setPrintable( false );
|
||||||
|
record.setAutofill( false );
|
||||||
|
record.setAutoline( false );
|
||||||
|
record.setReserved1( (int) 24593);
|
||||||
|
record.setReserved2( (int) 218103808);
|
||||||
|
record.setReserved3( (int) 294);
|
||||||
|
|
||||||
|
byte [] recordBytes = record.serialize();
|
||||||
|
assertEquals(recordBytes.length - 4, data.length);
|
||||||
|
for (int i = 0; i < data.length; i++)
|
||||||
|
assertEquals("At offset " + i, data[i], recordBytes[i+4]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
|
import org.apache.poi.ddf.EscherSpRecord;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
|
public class TestDrawingGroupRecord extends TestCase
|
||||||
|
{
|
||||||
|
public void testGetRecordSize()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
DrawingGroupRecord r = new DrawingGroupRecord();
|
||||||
|
assertEquals(4, r.getRecordSize());
|
||||||
|
|
||||||
|
EscherSpRecord sp = new EscherSpRecord();
|
||||||
|
sp.setRecordId(EscherSpRecord.RECORD_ID);
|
||||||
|
sp.setOptions((short) 0x1111);
|
||||||
|
sp.setFlags(-1);
|
||||||
|
sp.setShapeId(-1);
|
||||||
|
EscherContainerRecord dggContainer = new EscherContainerRecord();
|
||||||
|
dggContainer.setOptions((short) 0x000F);
|
||||||
|
dggContainer.setRecordId((short) 0xF000);
|
||||||
|
dggContainer.addChildRecord(sp);
|
||||||
|
|
||||||
|
r.addEscherRecord(dggContainer);
|
||||||
|
assertEquals(28, r.getRecordSize());
|
||||||
|
|
||||||
|
byte[] data = new byte[28];
|
||||||
|
int size = r.serialize(0, data);
|
||||||
|
assertEquals("[EB, 00, 18, 00, 0F, 00, 00, F0, 10, 00, 00, 00, 11, 11, 0A, F0, 08, 00, 00, 00, FF, FF, FF, FF, FF, FF, FF, FF, ]", HexDump.toHex(data));
|
||||||
|
assertEquals(28, size);
|
||||||
|
|
||||||
|
assertEquals(24, dggContainer.getRecordSize());
|
||||||
|
}
|
||||||
|
}
|
102
src/java/org/apache/poi/hssf/record/TestEndSubRecord.java
Normal file
102
src/java/org/apache/poi/hssf/record/TestEndSubRecord.java
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the serialization and deserialization of the EndSubRecord
|
||||||
|
* class works correctly. Test data taken directly from a real
|
||||||
|
* Excel file.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class TestEndSubRecord
|
||||||
|
extends TestCase
|
||||||
|
{
|
||||||
|
byte[] data = new byte[] {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public TestEndSubRecord(String name)
|
||||||
|
{
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLoad()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
EndSubRecord record = new EndSubRecord((short)0x00, (short)data.length, data);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
assertEquals( 4, record.getRecordSize() );
|
||||||
|
|
||||||
|
record.validateSid((short)0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStore()
|
||||||
|
{
|
||||||
|
EndSubRecord record = new EndSubRecord();
|
||||||
|
|
||||||
|
byte [] recordBytes = record.serialize();
|
||||||
|
assertEquals(recordBytes.length - 4, data.length);
|
||||||
|
for (int i = 0; i < data.length; i++)
|
||||||
|
assertEquals("At offset " + i, data[i], recordBytes[i+4]);
|
||||||
|
}
|
||||||
|
}
|
124
src/java/org/apache/poi/hssf/record/TestEscherAggregate.java
Normal file
124
src/java/org/apache/poi/hssf/record/TestEscherAggregate.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
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.EscherDggRecord;
|
||||||
|
import org.apache.poi.hssf.model.DrawingManager;
|
||||||
|
import org.apache.poi.hssf.model.Sheet;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the EscherAggregate class.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class TestEscherAggregate extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Tests that the create aggregate method correctly rejoins escher records together.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void testCreateAggregate() throws Exception
|
||||||
|
{
|
||||||
|
String msoDrawingRecord1 =
|
||||||
|
"0F 00 02 F0 20 01 00 00 10 00 08 F0 08 00 00 00 \n" +
|
||||||
|
"03 00 00 00 02 04 00 00 0F 00 03 F0 08 01 00 00 \n" +
|
||||||
|
"0F 00 04 F0 28 00 00 00 01 00 09 F0 10 00 00 00 \n" +
|
||||||
|
"00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \n" +
|
||||||
|
"02 00 0A F0 08 00 00 00 00 04 00 00 05 00 00 00 \n" +
|
||||||
|
"0F 00 04 F0 64 00 00 00 42 01 0A F0 08 00 00 00 \n" +
|
||||||
|
"01 04 00 00 00 0A 00 00 73 00 0B F0 2A 00 00 00 \n" +
|
||||||
|
"BF 00 08 00 08 00 44 01 04 00 00 00 7F 01 00 00 \n" +
|
||||||
|
"01 00 BF 01 00 00 11 00 C0 01 40 00 00 08 FF 01 \n" +
|
||||||
|
"10 00 10 00 BF 03 00 00 08 00 00 00 10 F0 12 00 \n" +
|
||||||
|
"00 00 00 00 01 00 54 00 05 00 45 00 01 00 88 03 \n" +
|
||||||
|
"05 00 94 00 00 00 11 F0 00 00 00 00";
|
||||||
|
|
||||||
|
String msoDrawingRecord2 =
|
||||||
|
"0F 00 04 F0 64 00 00 00 42 01 0A F0 08 00 00 00 " +
|
||||||
|
"02 04 00 00 80 0A 00 00 73 00 0B F0 2A 00 00 00 " +
|
||||||
|
"BF 00 08 00 08 00 44 01 04 00 00 00 7F 01 00 00 " +
|
||||||
|
"01 00 BF 01 00 00 11 00 C0 01 40 00 00 08 FF 01 " +
|
||||||
|
"10 00 10 00 BF 03 00 00 08 00 00 00 10 F0 12 00 " +
|
||||||
|
"00 00 00 00 01 00 8D 03 05 00 E4 00 03 00 4D 03 " +
|
||||||
|
"0B 00 0C 00 00 00 11 F0 00 00 00 00";
|
||||||
|
|
||||||
|
DrawingRecord d1 = new DrawingRecord();
|
||||||
|
d1.setData( HexRead.readFromString( msoDrawingRecord1 ) );
|
||||||
|
|
||||||
|
ObjRecord r1 = new ObjRecord();
|
||||||
|
|
||||||
|
DrawingRecord d2 = new DrawingRecord();
|
||||||
|
d2.setData( HexRead.readFromString( msoDrawingRecord2 ) );
|
||||||
|
|
||||||
|
ObjRecord r2 = new ObjRecord();
|
||||||
|
|
||||||
|
List records = new ArrayList();
|
||||||
|
records.add( d1 );
|
||||||
|
records.add( r1 );
|
||||||
|
records.add( d2 );
|
||||||
|
records.add( r2 );
|
||||||
|
|
||||||
|
DrawingManager drawingManager = new DrawingManager(new EscherDggRecord() );
|
||||||
|
EscherAggregate aggregate = EscherAggregate.createAggregate( records, 0, drawingManager );
|
||||||
|
|
||||||
|
assertEquals( 1, aggregate.getEscherRecords().size() );
|
||||||
|
assertEquals( (short) 0xF002, aggregate.getEscherRecord( 0 ).getRecordId() );
|
||||||
|
assertEquals( 2, aggregate.getEscherRecord( 0 ).getChildRecords().size() );
|
||||||
|
|
||||||
|
// System.out.println( "aggregate = " + aggregate );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSerialize() throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
EscherContainerRecord container1 = new EscherContainerRecord();
|
||||||
|
EscherContainerRecord spContainer1 = new EscherContainerRecord();
|
||||||
|
EscherContainerRecord spContainer2 = new EscherContainerRecord();
|
||||||
|
EscherContainerRecord spContainer3 = new EscherContainerRecord();
|
||||||
|
EscherSpRecord sp1 = new EscherSpRecord();
|
||||||
|
EscherSpRecord sp2 = new EscherSpRecord();
|
||||||
|
EscherSpRecord sp3 = new EscherSpRecord();
|
||||||
|
EscherClientDataRecord d2 = new EscherClientDataRecord();
|
||||||
|
EscherClientDataRecord d3 = new EscherClientDataRecord();
|
||||||
|
|
||||||
|
container1.setOptions( (short) 0x000F );
|
||||||
|
spContainer1.setOptions( (short) 0x000F );
|
||||||
|
spContainer1.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
|
spContainer2.setOptions( (short) 0x000F );
|
||||||
|
spContainer2.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
|
spContainer3.setOptions( (short) 0x000F );
|
||||||
|
spContainer3.setRecordId( EscherContainerRecord.SP_CONTAINER );
|
||||||
|
d2.setRecordId( EscherClientDataRecord.RECORD_ID );
|
||||||
|
d2.setRemainingData( new byte[0] );
|
||||||
|
d3.setRecordId( EscherClientDataRecord.RECORD_ID );
|
||||||
|
d3.setRemainingData( new byte[0] );
|
||||||
|
container1.addChildRecord( spContainer1 );
|
||||||
|
container1.addChildRecord( spContainer2 );
|
||||||
|
container1.addChildRecord( spContainer3 );
|
||||||
|
spContainer1.addChildRecord( sp1 );
|
||||||
|
spContainer2.addChildRecord( sp2 );
|
||||||
|
spContainer3.addChildRecord( sp3 );
|
||||||
|
spContainer2.addChildRecord( d2 );
|
||||||
|
spContainer3.addChildRecord( d3 );
|
||||||
|
|
||||||
|
EscherAggregate aggregate = new EscherAggregate(null);
|
||||||
|
aggregate.addEscherRecord( container1 );
|
||||||
|
aggregate.assoicateShapeToObjRecord( d2, new ObjRecord() );
|
||||||
|
aggregate.assoicateShapeToObjRecord( d3, new ObjRecord() );
|
||||||
|
|
||||||
|
byte[] data = new byte[112];
|
||||||
|
int bytesWritten = aggregate.serialize( 0, data );
|
||||||
|
assertEquals( 112, bytesWritten );
|
||||||
|
assertEquals( "[EC, 00, 40, 00, 0F, 00, 00, 00, 58, 00, 00, 00, 0F, 00, 04, F0, 10, 00, 00, 00, 00, 00, 0A, F0, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0F, 00, 04, F0, 18, 00, 00, 00, 00, 00, 0A, F0, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 11, F0, 00, 00, 00, 00, 5D, 00, 00, 00, EC, 00, 20, 00, 0F, 00, 04, F0, 18, 00, 00, 00, 00, 00, 0A, F0, 08, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 11, F0, 00, 00, 00, 00, 5D, 00, 00, 00, ]",
|
||||||
|
HexDump.toHex( data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the serialization and deserialization of the TextObjectBaseRecord
|
||||||
|
* class works correctly. Test data taken directly from a real
|
||||||
|
* Excel file.
|
||||||
|
*
|
||||||
|
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class TestTextObjectBaseRecord
|
||||||
|
extends TestCase
|
||||||
|
{
|
||||||
|
byte[] data = new byte[] {
|
||||||
|
0x44, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
public TestTextObjectBaseRecord(String name)
|
||||||
|
{
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testLoad()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
TextObjectBaseRecord record = new TextObjectBaseRecord((short)0x1B6, (short)data.length, data);
|
||||||
|
|
||||||
|
|
||||||
|
// assertEquals( (short), record.getOptions());
|
||||||
|
assertEquals( false, record.isReserved1() );
|
||||||
|
assertEquals( TextObjectBaseRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED, record.getHorizontalTextAlignment() );
|
||||||
|
assertEquals( TextObjectBaseRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY, record.getVerticalTextAlignment() );
|
||||||
|
assertEquals( 0, record.getReserved2() );
|
||||||
|
assertEquals( true, record.isTextLocked() );
|
||||||
|
assertEquals( 0, record.getReserved3() );
|
||||||
|
assertEquals( TextObjectBaseRecord.TEXT_ORIENTATION_ROT_RIGHT, record.getTextOrientation());
|
||||||
|
assertEquals( 0, record.getReserved4());
|
||||||
|
assertEquals( 0, record.getReserved5());
|
||||||
|
assertEquals( 0, record.getReserved6());
|
||||||
|
assertEquals( 2, record.getTextLength());
|
||||||
|
assertEquals( 2, record.getFormattingRunLength());
|
||||||
|
assertEquals( 0, record.getReserved7());
|
||||||
|
|
||||||
|
|
||||||
|
assertEquals( 22, record.getRecordSize() );
|
||||||
|
|
||||||
|
record.validateSid((short)0x1B6);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStore()
|
||||||
|
{
|
||||||
|
TextObjectBaseRecord record = new TextObjectBaseRecord();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// record.setOptions( (short) 0x0000);
|
||||||
|
record.setReserved1( false );
|
||||||
|
record.setHorizontalTextAlignment( TextObjectBaseRecord.HORIZONTAL_TEXT_ALIGNMENT_CENTERED );
|
||||||
|
record.setVerticalTextAlignment( TextObjectBaseRecord.VERTICAL_TEXT_ALIGNMENT_JUSTIFY );
|
||||||
|
record.setReserved2( (short)0 );
|
||||||
|
record.setTextLocked( true );
|
||||||
|
record.setReserved3( (short)0 );
|
||||||
|
record.setTextOrientation( TextObjectBaseRecord.TEXT_ORIENTATION_ROT_RIGHT );
|
||||||
|
record.setReserved4( (short)0 );
|
||||||
|
record.setReserved5( (short)0 );
|
||||||
|
record.setReserved6( (short)0 );
|
||||||
|
record.setTextLength( (short)2 );
|
||||||
|
record.setFormattingRunLength( (short)2 );
|
||||||
|
record.setReserved7( 0 );
|
||||||
|
|
||||||
|
byte [] recordBytes = record.serialize();
|
||||||
|
assertEquals(recordBytes.length - 4, data.length);
|
||||||
|
for (int i = 0; i < data.length; i++)
|
||||||
|
assertEquals("At offset " + i, data[i], recordBytes[i+4]);
|
||||||
|
}
|
||||||
|
}
|
519
src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java
Normal file
519
src/java/org/apache/poi/hssf/record/TextObjectBaseRecord.java
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.poi.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TXO record is used to define the properties of a text box. It is followed
|
||||||
|
by two continue records unless there is no actual text. The first continue record contains
|
||||||
|
the text data and the next continue record contains the formatting runs.
|
||||||
|
* NOTE: This source is automatically generated please do not modify this file. Either subclass or
|
||||||
|
* remove the record in src/records/definitions.
|
||||||
|
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class TextObjectBaseRecord
|
||||||
|
extends Record
|
||||||
|
{
|
||||||
|
public final static short sid = 0x1B6;
|
||||||
|
private short field_1_options;
|
||||||
|
private BitField reserved1 = new BitField(0x1);
|
||||||
|
private BitField HorizontalTextAlignment = new BitField(0x000E);
|
||||||
|
public final static short HORIZONTAL_TEXT_ALIGNMENT_LEFT_ALIGNED = 1;
|
||||||
|
public final static short HORIZONTAL_TEXT_ALIGNMENT_CENTERED = 2;
|
||||||
|
public final static short HORIZONTAL_TEXT_ALIGNMENT_RIGHT_ALIGNED = 3;
|
||||||
|
public final static short HORIZONTAL_TEXT_ALIGNMENT_JUSTIFIED = 4;
|
||||||
|
private BitField VerticalTextAlignment = new BitField(0x0070);
|
||||||
|
public final static short VERTICAL_TEXT_ALIGNMENT_TOP = 1;
|
||||||
|
public final static short VERTICAL_TEXT_ALIGNMENT_CENTER = 2;
|
||||||
|
public final static short VERTICAL_TEXT_ALIGNMENT_BOTTOM = 3;
|
||||||
|
public final static short VERTICAL_TEXT_ALIGNMENT_JUSTIFY = 4;
|
||||||
|
private BitField reserved2 = new BitField(0x0180);
|
||||||
|
private BitField textLocked = new BitField(0x200);
|
||||||
|
private BitField reserved3 = new BitField(0xFC00);
|
||||||
|
private short field_2_textOrientation;
|
||||||
|
public final static short TEXT_ORIENTATION_NONE = 0;
|
||||||
|
public final static short TEXT_ORIENTATION_TOP_TO_BOTTOM = 1;
|
||||||
|
public final static short TEXT_ORIENTATION_ROT_RIGHT = 2;
|
||||||
|
public final static short TEXT_ORIENTATION_ROT_LEFT = 3;
|
||||||
|
private short field_3_reserved4;
|
||||||
|
private short field_4_reserved5;
|
||||||
|
private short field_5_reserved6;
|
||||||
|
private short field_6_textLength;
|
||||||
|
private short field_7_formattingRunLength;
|
||||||
|
private int field_8_reserved7;
|
||||||
|
|
||||||
|
|
||||||
|
public TextObjectBaseRecord()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a TextObjectBase record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x1B6 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public TextObjectBaseRecord(short id, short size, byte [] data)
|
||||||
|
{
|
||||||
|
super(id, size, data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a TextObjectBase record and sets its fields appropriately.
|
||||||
|
*
|
||||||
|
* @param id id must be 0x1B6 or an exception
|
||||||
|
* will be throw upon validation
|
||||||
|
* @param size size the size of the data area of the record
|
||||||
|
* @param data data of the record (should not contain sid/len)
|
||||||
|
* @param offset of the record's data
|
||||||
|
*/
|
||||||
|
|
||||||
|
public TextObjectBaseRecord(short id, short size, byte [] data, int offset)
|
||||||
|
{
|
||||||
|
super(id, size, data, offset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the sid matches the expected side for this record
|
||||||
|
*
|
||||||
|
* @param id the expected sid.
|
||||||
|
*/
|
||||||
|
protected void validateSid(short id)
|
||||||
|
{
|
||||||
|
if (id != sid)
|
||||||
|
{
|
||||||
|
throw new RecordFormatException("Not a TextObjectBase record");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fillFields(byte [] data, short size, int offset)
|
||||||
|
{
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
field_1_options = LittleEndian.getShort(data, pos + 0x0 + offset);
|
||||||
|
field_2_textOrientation = LittleEndian.getShort(data, pos + 0x2 + offset);
|
||||||
|
field_3_reserved4 = LittleEndian.getShort(data, pos + 0x4 + offset);
|
||||||
|
field_4_reserved5 = LittleEndian.getShort(data, pos + 0x6 + offset);
|
||||||
|
field_5_reserved6 = LittleEndian.getShort(data, pos + 0x8 + offset);
|
||||||
|
field_6_textLength = LittleEndian.getShort(data, pos + 0xa + offset);
|
||||||
|
field_7_formattingRunLength = LittleEndian.getShort(data, pos + 0xc + offset);
|
||||||
|
field_8_reserved7 = LittleEndian.getInt(data, pos + 0xe + offset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
buffer.append("[TXO]\n");
|
||||||
|
buffer.append(" .options = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getOptions ()))
|
||||||
|
.append(" (").append( getOptions() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .reserved1 = ").append(isReserved1()).append('\n');
|
||||||
|
buffer.append(" .HorizontalTextAlignment = ").append(getHorizontalTextAlignment()).append('\n');
|
||||||
|
buffer.append(" .VerticalTextAlignment = ").append(getVerticalTextAlignment()).append('\n');
|
||||||
|
buffer.append(" .reserved2 = ").append(getReserved2()).append('\n');
|
||||||
|
buffer.append(" .textLocked = ").append(isTextLocked()).append('\n');
|
||||||
|
buffer.append(" .reserved3 = ").append(getReserved3()).append('\n');
|
||||||
|
buffer.append(" .textOrientation = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getTextOrientation ()))
|
||||||
|
.append(" (").append( getTextOrientation() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .reserved4 = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getReserved4 ()))
|
||||||
|
.append(" (").append( getReserved4() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .reserved5 = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getReserved5 ()))
|
||||||
|
.append(" (").append( getReserved5() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .reserved6 = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getReserved6 ()))
|
||||||
|
.append(" (").append( getReserved6() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .textLength = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getTextLength ()))
|
||||||
|
.append(" (").append( getTextLength() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .formattingRunLength = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getFormattingRunLength ()))
|
||||||
|
.append(" (").append( getFormattingRunLength() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
buffer.append(" .reserved7 = ")
|
||||||
|
.append("0x").append(HexDump.toHex( getReserved7 ()))
|
||||||
|
.append(" (").append( getReserved7() ).append(" )");
|
||||||
|
buffer.append(System.getProperty("line.separator"));
|
||||||
|
|
||||||
|
buffer.append("[/TXO]\n");
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int serialize(int offset, byte[] data)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
LittleEndian.putShort(data, 0 + offset, sid);
|
||||||
|
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize() - 4));
|
||||||
|
|
||||||
|
LittleEndian.putShort(data, 4 + offset + pos, field_1_options);
|
||||||
|
LittleEndian.putShort(data, 6 + offset + pos, field_2_textOrientation);
|
||||||
|
LittleEndian.putShort(data, 8 + offset + pos, field_3_reserved4);
|
||||||
|
LittleEndian.putShort(data, 10 + offset + pos, field_4_reserved5);
|
||||||
|
LittleEndian.putShort(data, 12 + offset + pos, field_5_reserved6);
|
||||||
|
LittleEndian.putShort(data, 14 + offset + pos, field_6_textLength);
|
||||||
|
LittleEndian.putShort(data, 16 + offset + pos, field_7_formattingRunLength);
|
||||||
|
LittleEndian.putInt(data, 18 + offset + pos, field_8_reserved7);
|
||||||
|
|
||||||
|
return getRecordSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of record (exluding 4 byte header)
|
||||||
|
*/
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
return 4 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSid()
|
||||||
|
{
|
||||||
|
return this.sid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object clone() {
|
||||||
|
TextObjectBaseRecord rec = new TextObjectBaseRecord();
|
||||||
|
|
||||||
|
rec.field_1_options = field_1_options;
|
||||||
|
rec.field_2_textOrientation = field_2_textOrientation;
|
||||||
|
rec.field_3_reserved4 = field_3_reserved4;
|
||||||
|
rec.field_4_reserved5 = field_4_reserved5;
|
||||||
|
rec.field_5_reserved6 = field_5_reserved6;
|
||||||
|
rec.field_6_textLength = field_6_textLength;
|
||||||
|
rec.field_7_formattingRunLength = field_7_formattingRunLength;
|
||||||
|
rec.field_8_reserved7 = field_8_reserved7;
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the options field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public short getOptions()
|
||||||
|
{
|
||||||
|
return field_1_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the options field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public void setOptions(short field_1_options)
|
||||||
|
{
|
||||||
|
this.field_1_options = field_1_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text orientation field for the TextObjectBase record.
|
||||||
|
*
|
||||||
|
* @return One of
|
||||||
|
* TEXT_ORIENTATION_NONE
|
||||||
|
* TEXT_ORIENTATION_TOP_TO_BOTTOM
|
||||||
|
* TEXT_ORIENTATION_ROT_RIGHT
|
||||||
|
* TEXT_ORIENTATION_ROT_LEFT
|
||||||
|
*/
|
||||||
|
public short getTextOrientation()
|
||||||
|
{
|
||||||
|
return field_2_textOrientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the text orientation field for the TextObjectBase record.
|
||||||
|
*
|
||||||
|
* @param field_2_textOrientation
|
||||||
|
* One of
|
||||||
|
* TEXT_ORIENTATION_NONE
|
||||||
|
* TEXT_ORIENTATION_TOP_TO_BOTTOM
|
||||||
|
* TEXT_ORIENTATION_ROT_RIGHT
|
||||||
|
* TEXT_ORIENTATION_ROT_LEFT
|
||||||
|
*/
|
||||||
|
public void setTextOrientation(short field_2_textOrientation)
|
||||||
|
{
|
||||||
|
this.field_2_textOrientation = field_2_textOrientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the reserved4 field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public short getReserved4()
|
||||||
|
{
|
||||||
|
return field_3_reserved4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reserved4 field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public void setReserved4(short field_3_reserved4)
|
||||||
|
{
|
||||||
|
this.field_3_reserved4 = field_3_reserved4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the reserved5 field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public short getReserved5()
|
||||||
|
{
|
||||||
|
return field_4_reserved5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reserved5 field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public void setReserved5(short field_4_reserved5)
|
||||||
|
{
|
||||||
|
this.field_4_reserved5 = field_4_reserved5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the reserved6 field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public short getReserved6()
|
||||||
|
{
|
||||||
|
return field_5_reserved6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reserved6 field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public void setReserved6(short field_5_reserved6)
|
||||||
|
{
|
||||||
|
this.field_5_reserved6 = field_5_reserved6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the text length field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public short getTextLength()
|
||||||
|
{
|
||||||
|
return field_6_textLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the text length field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public void setTextLength(short field_6_textLength)
|
||||||
|
{
|
||||||
|
this.field_6_textLength = field_6_textLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the formatting run length field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public short getFormattingRunLength()
|
||||||
|
{
|
||||||
|
return field_7_formattingRunLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the formatting run length field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public void setFormattingRunLength(short field_7_formattingRunLength)
|
||||||
|
{
|
||||||
|
this.field_7_formattingRunLength = field_7_formattingRunLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the reserved7 field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public int getReserved7()
|
||||||
|
{
|
||||||
|
return field_8_reserved7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reserved7 field for the TextObjectBase record.
|
||||||
|
*/
|
||||||
|
public void setReserved7(int field_8_reserved7)
|
||||||
|
{
|
||||||
|
this.field_8_reserved7 = field_8_reserved7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reserved1 field value.
|
||||||
|
* reserved field
|
||||||
|
*/
|
||||||
|
public void setReserved1(boolean value)
|
||||||
|
{
|
||||||
|
field_1_options = reserved1.setShortBoolean(field_1_options, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reserved field
|
||||||
|
* @return the reserved1 field value.
|
||||||
|
*/
|
||||||
|
public boolean isReserved1()
|
||||||
|
{
|
||||||
|
return reserved1.isSet(field_1_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Horizontal text alignment field value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setHorizontalTextAlignment(short value)
|
||||||
|
{
|
||||||
|
field_1_options = HorizontalTextAlignment.setShortValue(field_1_options, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the Horizontal text alignment field value.
|
||||||
|
*/
|
||||||
|
public short getHorizontalTextAlignment()
|
||||||
|
{
|
||||||
|
return HorizontalTextAlignment.getShortValue(field_1_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Vertical text alignment field value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setVerticalTextAlignment(short value)
|
||||||
|
{
|
||||||
|
field_1_options = VerticalTextAlignment.setShortValue(field_1_options, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the Vertical text alignment field value.
|
||||||
|
*/
|
||||||
|
public short getVerticalTextAlignment()
|
||||||
|
{
|
||||||
|
return VerticalTextAlignment.getShortValue(field_1_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reserved2 field value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setReserved2(short value)
|
||||||
|
{
|
||||||
|
field_1_options = reserved2.setShortValue(field_1_options, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the reserved2 field value.
|
||||||
|
*/
|
||||||
|
public short getReserved2()
|
||||||
|
{
|
||||||
|
return reserved2.getShortValue(field_1_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text locked field value.
|
||||||
|
* Text has been locked
|
||||||
|
*/
|
||||||
|
public void setTextLocked(boolean value)
|
||||||
|
{
|
||||||
|
field_1_options = textLocked.setShortBoolean(field_1_options, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text has been locked
|
||||||
|
* @return the text locked field value.
|
||||||
|
*/
|
||||||
|
public boolean isTextLocked()
|
||||||
|
{
|
||||||
|
return textLocked.isSet(field_1_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reserved3 field value.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setReserved3(short value)
|
||||||
|
{
|
||||||
|
field_1_options = reserved3.setShortValue(field_1_options, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the reserved3 field value.
|
||||||
|
*/
|
||||||
|
public short getReserved3()
|
||||||
|
{
|
||||||
|
return reserved3.getShortValue(field_1_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // END OF CLASS
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
216
src/java/org/apache/poi/hssf/record/TextObjectRecord.java
Normal file
216
src/java/org/apache/poi/hssf/record/TextObjectRecord.java
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
||||||
|
import org.apache.poi.util.StringUtil;
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
public class TextObjectRecord
|
||||||
|
extends TextObjectBaseRecord
|
||||||
|
{
|
||||||
|
HSSFRichTextString str = new HSSFRichTextString( "" );
|
||||||
|
int continueRecordCount = 0; // how many times has continue record been called?
|
||||||
|
|
||||||
|
public TextObjectRecord()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextObjectRecord( short id, short size, byte[] data )
|
||||||
|
{
|
||||||
|
super( id, size, data );
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextObjectRecord( short id, short size, byte[] data, int offset )
|
||||||
|
{
|
||||||
|
super( id, size, data, offset );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRecordSize()
|
||||||
|
{
|
||||||
|
int continue1Size = 0;
|
||||||
|
int continue2Size = 0;
|
||||||
|
if (str.length() != 0)
|
||||||
|
{
|
||||||
|
continue1Size = str.length() * 2 + 1 + 4;
|
||||||
|
continue2Size = (str.numFormattingRuns() + 1) * 8 + 4;
|
||||||
|
}
|
||||||
|
return super.getRecordSize() + continue1Size + continue2Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int serialize( int offset, byte[] data )
|
||||||
|
{
|
||||||
|
// Temporarily blank out str so that record size is calculated without the continue records.
|
||||||
|
HSSFRichTextString temp = str;
|
||||||
|
str = new HSSFRichTextString("");
|
||||||
|
int bytesWritten1 = super.serialize( offset, data );
|
||||||
|
str = temp;
|
||||||
|
|
||||||
|
int pos = offset + bytesWritten1;
|
||||||
|
if ( str.toString().equals( "" ) == false )
|
||||||
|
{
|
||||||
|
ContinueRecord c1 = createContinue1();
|
||||||
|
ContinueRecord c2 = createContinue2();
|
||||||
|
int bytesWritten2 = c1.serialize( pos, data );
|
||||||
|
pos += bytesWritten2;
|
||||||
|
int bytesWritten3 = c2.serialize( pos, data );
|
||||||
|
pos += bytesWritten3;
|
||||||
|
|
||||||
|
int size = bytesWritten1 + bytesWritten2 + bytesWritten3;
|
||||||
|
if ( size != getRecordSize() )
|
||||||
|
throw new RecordFormatException(size + " bytes written but getRecordSize() reports " + getRecordSize());
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
if ( bytesWritten1 != getRecordSize() )
|
||||||
|
throw new RecordFormatException(bytesWritten1 + " bytes written but getRecordSize() reports " + getRecordSize());
|
||||||
|
return bytesWritten1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContinueRecord createContinue1()
|
||||||
|
{
|
||||||
|
ContinueRecord c1 = new ContinueRecord();
|
||||||
|
byte[] c1Data = new byte[str.length() * 2 + 1];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
c1Data[0] = 1;
|
||||||
|
System.arraycopy( str.toString().getBytes( "UTF-16LE" ), 0, c1Data, 1, str.length() * 2 );
|
||||||
|
}
|
||||||
|
catch ( UnsupportedEncodingException e )
|
||||||
|
{
|
||||||
|
throw new RuntimeException( e.getMessage() );
|
||||||
|
}
|
||||||
|
c1.setData( c1Data );
|
||||||
|
return c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContinueRecord createContinue2()
|
||||||
|
{
|
||||||
|
ContinueRecord c2 = new ContinueRecord();
|
||||||
|
byte[] c2Data = new byte[str.numFormattingRuns() * 8 + 8];
|
||||||
|
int pos = 0;
|
||||||
|
for ( int i = 0; i < str.numFormattingRuns(); i++ )
|
||||||
|
{
|
||||||
|
LittleEndian.putShort( c2Data, pos, (short) str.getIndexOfFormattingRun( i ) );
|
||||||
|
pos += 2;
|
||||||
|
LittleEndian.putShort( c2Data, pos, str.getFontOfFormattingRun( i ) == str.NO_FONT ? 0 : str.getFontOfFormattingRun( i ) );
|
||||||
|
pos += 2;
|
||||||
|
pos += 4; // skip reserved
|
||||||
|
}
|
||||||
|
LittleEndian.putShort( c2Data, pos, (short) str.length() );
|
||||||
|
pos += 2;
|
||||||
|
LittleEndian.putShort( c2Data, pos, (short) 0 );
|
||||||
|
pos += 2;
|
||||||
|
pos += 4; // skip reserved
|
||||||
|
|
||||||
|
c2.setData( c2Data );
|
||||||
|
|
||||||
|
return c2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processContinueRecord( byte[] data )
|
||||||
|
{
|
||||||
|
if ( continueRecordCount == 0 )
|
||||||
|
processRawString( data );
|
||||||
|
else
|
||||||
|
processFontRuns( data );
|
||||||
|
continueRecordCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processFontRuns( byte[] data )
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
short index = LittleEndian.getShort( data, pos );
|
||||||
|
pos += 2;
|
||||||
|
short iFont = LittleEndian.getShort( data, pos );
|
||||||
|
pos += 2;
|
||||||
|
pos += 4; // skip reserved.
|
||||||
|
|
||||||
|
if ( index >= str.length() )
|
||||||
|
break;
|
||||||
|
str.applyFont( index, str.length(), iFont );
|
||||||
|
}
|
||||||
|
while ( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processRawString( byte[] data )
|
||||||
|
{
|
||||||
|
String s;
|
||||||
|
int pos = 0;
|
||||||
|
byte compressByte = data[pos++];
|
||||||
|
boolean isCompressed = compressByte == 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if ( isCompressed )
|
||||||
|
{
|
||||||
|
s = new String( data, pos, getTextLength(), StringUtil.getPreferredEncoding() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s = new String( data, pos, getTextLength() * 2, "UTF-16LE" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch ( UnsupportedEncodingException e )
|
||||||
|
{
|
||||||
|
throw new RuntimeException( e.getMessage() );
|
||||||
|
}
|
||||||
|
str = new HSSFRichTextString( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public HSSFRichTextString getStr()
|
||||||
|
{
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStr( HSSFRichTextString str )
|
||||||
|
{
|
||||||
|
this.str = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
|
buffer.append( "[TXO]\n" );
|
||||||
|
buffer.append( " .options = " )
|
||||||
|
.append( "0x" ).append( HexDump.toHex( getOptions() ) )
|
||||||
|
.append( " (" ).append( getOptions() ).append( " )" );
|
||||||
|
buffer.append( System.getProperty( "line.separator" ) );
|
||||||
|
buffer.append( " .reserved1 = " ).append( isReserved1() ).append( '\n' );
|
||||||
|
buffer.append( " .HorizontalTextAlignment = " ).append( getHorizontalTextAlignment() ).append( '\n' );
|
||||||
|
buffer.append( " .VerticalTextAlignment = " ).append( getVerticalTextAlignment() ).append( '\n' );
|
||||||
|
buffer.append( " .reserved2 = " ).append( getReserved2() ).append( '\n' );
|
||||||
|
buffer.append( " .textLocked = " ).append( isTextLocked() ).append( '\n' );
|
||||||
|
buffer.append( " .reserved3 = " ).append( getReserved3() ).append( '\n' );
|
||||||
|
buffer.append( " .textOrientation = " )
|
||||||
|
.append( "0x" ).append( HexDump.toHex( getTextOrientation() ) )
|
||||||
|
.append( " (" ).append( getTextOrientation() ).append( " )" );
|
||||||
|
buffer.append( System.getProperty( "line.separator" ) );
|
||||||
|
buffer.append( " .reserved4 = " )
|
||||||
|
.append( "0x" ).append( HexDump.toHex( getReserved4() ) )
|
||||||
|
.append( " (" ).append( getReserved4() ).append( " )" );
|
||||||
|
buffer.append( System.getProperty( "line.separator" ) );
|
||||||
|
buffer.append( " .reserved5 = " )
|
||||||
|
.append( "0x" ).append( HexDump.toHex( getReserved5() ) )
|
||||||
|
.append( " (" ).append( getReserved5() ).append( " )" );
|
||||||
|
buffer.append( System.getProperty( "line.separator" ) );
|
||||||
|
buffer.append( " .reserved6 = " )
|
||||||
|
.append( "0x" ).append( HexDump.toHex( getReserved6() ) )
|
||||||
|
.append( " (" ).append( getReserved6() ).append( " )" );
|
||||||
|
buffer.append( System.getProperty( "line.separator" ) );
|
||||||
|
buffer.append( " .textLength = " )
|
||||||
|
.append( "0x" ).append( HexDump.toHex( getTextLength() ) )
|
||||||
|
.append( " (" ).append( getTextLength() ).append( " )" );
|
||||||
|
buffer.append( System.getProperty( "line.separator" ) );
|
||||||
|
buffer.append( " .reserved7 = " )
|
||||||
|
.append( "0x" ).append( HexDump.toHex( getReserved7() ) )
|
||||||
|
.append( " (" ).append( getReserved7() ).append( " )" );
|
||||||
|
buffer.append( System.getProperty( "line.separator" ) );
|
||||||
|
|
||||||
|
buffer.append( " .string = " ).append(str).append('\n');
|
||||||
|
|
||||||
|
buffer.append( "[/TXO]\n" );
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -95,6 +95,13 @@ public class UnknownRecord
|
|||||||
this.thedata = data;
|
this.thedata = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UnknownRecord( short id, short size, byte[] data, int offset )
|
||||||
|
{
|
||||||
|
sid = id;
|
||||||
|
thedata = new byte[size];
|
||||||
|
System.arraycopy(data, offset, thedata, 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spit the record out AS IS. no interperatation or identification
|
* spit the record out AS IS. no interperatation or identification
|
||||||
*/
|
*/
|
||||||
|
107
src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.java
Normal file
107
src/java/org/apache/poi/hssf/record/VerticalPageBreakRecord.java
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
* The Apache Software License, Version 1.1
|
||||||
|
*
|
||||||
|
* Copyright (c) 2004 The Apache Software Foundation. All rights
|
||||||
|
* reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* 3. The end-user documentation included with the redistribution,
|
||||||
|
* if any, must include the following acknowledgment:
|
||||||
|
* "This product includes software developed by the
|
||||||
|
* Apache Software Foundation (http://www.apache.org/)."
|
||||||
|
* Alternately, this acknowledgment may appear in the software itself,
|
||||||
|
* if and wherever such third-party acknowledgments normally appear.
|
||||||
|
*
|
||||||
|
* 4. The names "Apache" and "Apache Software Foundation" and
|
||||||
|
* "Apache POI" must not be used to endorse or promote products
|
||||||
|
* derived from this software without prior written permission. For
|
||||||
|
* written permission, please contact apache@apache.org.
|
||||||
|
*
|
||||||
|
* 5. Products derived from this software may not be called "Apache",
|
||||||
|
* "Apache POI", nor may "Apache" appear in their name, without
|
||||||
|
* prior written permission of the Apache Software Foundation.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||||
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||||
|
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
* ====================================================================
|
||||||
|
*
|
||||||
|
* This software consists of voluntary contributions made by many
|
||||||
|
* individuals on behalf of the Apache Software Foundation. For more
|
||||||
|
* information on the Apache Software Foundation, please see
|
||||||
|
* <http://www.apache.org/>.
|
||||||
|
*/
|
||||||
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VerticalPageBreak record that stores page breaks at columns
|
||||||
|
* <p>
|
||||||
|
* This class is just used so that SID compares work properly in the RecordFactory
|
||||||
|
* @see PageBreakRecord
|
||||||
|
* @author Danny Mui (dmui at apache dot org)
|
||||||
|
*/
|
||||||
|
public class VerticalPageBreakRecord extends PageBreakRecord {
|
||||||
|
|
||||||
|
public static final short sid = PageBreakRecord.VERTICAL_SID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public VerticalPageBreakRecord() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param sid
|
||||||
|
*/
|
||||||
|
public VerticalPageBreakRecord(short sid) {
|
||||||
|
super(sid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @param size
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
public VerticalPageBreakRecord(short id, short size, byte[] data) {
|
||||||
|
super(id, size, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id
|
||||||
|
* @param size
|
||||||
|
* @param data
|
||||||
|
* @param offset
|
||||||
|
*/
|
||||||
|
public VerticalPageBreakRecord(short id, short size, byte[] data, int offset) {
|
||||||
|
super(id, size, data, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.poi.hssf.record.Record#getSid()
|
||||||
|
*/
|
||||||
|
public short getSid() {
|
||||||
|
return PageBreakRecord.VERTICAL_SID;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
773
src/java/org/apache/poi/hssf/usermodel/DummyGraphics2d.java
Normal file
773
src/java/org/apache/poi/hssf/usermodel/DummyGraphics2d.java
Normal file
@ -0,0 +1,773 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.BufferedImageOp;
|
||||||
|
import java.awt.image.ImageObserver;
|
||||||
|
import java.awt.image.RenderedImage;
|
||||||
|
import java.awt.image.renderable.RenderableImage;
|
||||||
|
import java.awt.font.GlyphVector;
|
||||||
|
import java.awt.font.FontRenderContext;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.text.AttributedCharacterIterator;
|
||||||
|
|
||||||
|
public class DummyGraphics2d
|
||||||
|
extends Graphics2D
|
||||||
|
{
|
||||||
|
BufferedImage img;
|
||||||
|
private Graphics2D g2D;
|
||||||
|
|
||||||
|
public DummyGraphics2d()
|
||||||
|
{
|
||||||
|
img = new BufferedImage(1000, 1000, 2);
|
||||||
|
g2D = (Graphics2D)img.getGraphics();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRenderingHints(Map hints)
|
||||||
|
{
|
||||||
|
System.out.println( "addRenderingHinds(Map):" );
|
||||||
|
System.out.println( " hints = " + hints );
|
||||||
|
g2D.addRenderingHints( hints );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clip(Shape s)
|
||||||
|
{
|
||||||
|
System.out.println( "clip(Shape):" );
|
||||||
|
System.out.println( " s = " + s );
|
||||||
|
g2D.clip( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(Shape s)
|
||||||
|
{
|
||||||
|
System.out.println( "draw(Shape):" );
|
||||||
|
System.out.println( "s = " + s );
|
||||||
|
g2D.draw( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawGlyphVector(GlyphVector g, float x, float y)
|
||||||
|
{
|
||||||
|
System.out.println( "drawGlyphVector(GlyphVector, float, float):" );
|
||||||
|
System.out.println( "g = " + g );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.drawGlyphVector( g, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawImage(BufferedImage img,
|
||||||
|
BufferedImageOp op,
|
||||||
|
int x,
|
||||||
|
int y)
|
||||||
|
{
|
||||||
|
System.out.println( "drawImage(BufferedImage, BufferedImageOp, x, y):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "op = " + op );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.drawImage( img, op, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img,
|
||||||
|
AffineTransform xform,
|
||||||
|
ImageObserver obs)
|
||||||
|
{
|
||||||
|
System.out.println( "drawImage(Image,AfflineTransform,ImageObserver):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "xform = " + xform );
|
||||||
|
System.out.println( "obs = " + obs );
|
||||||
|
return g2D.drawImage( img, xform, obs );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRenderableImage(RenderableImage img,
|
||||||
|
AffineTransform xform)
|
||||||
|
{
|
||||||
|
System.out.println( "drawRenderableImage(RenderableImage, AfflineTransform):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "xform = " + xform );
|
||||||
|
g2D.drawRenderableImage( img, xform );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRenderedImage(RenderedImage img,
|
||||||
|
AffineTransform xform)
|
||||||
|
{
|
||||||
|
System.out.println( "drawRenderedImage(RenderedImage, AffineTransform):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "xform = " + xform );
|
||||||
|
g2D.drawRenderedImage( img, xform );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawString(AttributedCharacterIterator iterator,
|
||||||
|
float x, float y)
|
||||||
|
{
|
||||||
|
System.out.println( "drawString(AttributedCharacterIterator):" );
|
||||||
|
System.out.println( "iterator = " + iterator );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.drawString( iterator, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void drawString(AttributedCharacterIterator iterator,
|
||||||
|
// int x, int y)
|
||||||
|
// {
|
||||||
|
// g2D.drawString( iterator, x, y );
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void drawString(String s, float x, float y)
|
||||||
|
{
|
||||||
|
System.out.println( "drawString(s,x,y):" );
|
||||||
|
System.out.println( "s = " + s );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.drawString( s, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void drawString(String str, int x, int y)
|
||||||
|
// {
|
||||||
|
// g2D.drawString( str, x, y );
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void fill(Shape s)
|
||||||
|
{
|
||||||
|
System.out.println( "fill(Shape):" );
|
||||||
|
System.out.println( "s = " + s );
|
||||||
|
g2D.fill( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void fill3DRect(int x, int y, int width, int height,
|
||||||
|
// boolean raised) {
|
||||||
|
// g2D.fill3DRect( x, y, width, height, raised );
|
||||||
|
// }
|
||||||
|
|
||||||
|
public Color getBackground()
|
||||||
|
{
|
||||||
|
System.out.println( "getBackground():" );
|
||||||
|
return g2D.getBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Composite getComposite()
|
||||||
|
{
|
||||||
|
System.out.println( "getComposite():" );
|
||||||
|
return g2D.getComposite();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphicsConfiguration getDeviceConfiguration()
|
||||||
|
{
|
||||||
|
System.out.println( "getDeviceConfiguration():" );
|
||||||
|
return g2D.getDeviceConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FontRenderContext getFontRenderContext()
|
||||||
|
{
|
||||||
|
System.out.println( "getFontRenderContext():" );
|
||||||
|
return g2D.getFontRenderContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Paint getPaint()
|
||||||
|
{
|
||||||
|
System.out.println( "getPaint():" );
|
||||||
|
return g2D.getPaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getRenderingHint(RenderingHints.Key hintKey)
|
||||||
|
{
|
||||||
|
System.out.println( "getRenderingHint(RenderingHints.Key):" );
|
||||||
|
System.out.println( "hintKey = " + hintKey );
|
||||||
|
return g2D.getRenderingHint( hintKey );
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderingHints getRenderingHints()
|
||||||
|
{
|
||||||
|
System.out.println( "getRenderingHints():" );
|
||||||
|
return g2D.getRenderingHints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stroke getStroke()
|
||||||
|
{
|
||||||
|
System.out.println( "getStroke():" );
|
||||||
|
return g2D.getStroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AffineTransform getTransform()
|
||||||
|
{
|
||||||
|
System.out.println( "getTransform():" );
|
||||||
|
return g2D.getTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hit(Rectangle rect,
|
||||||
|
Shape s,
|
||||||
|
boolean onStroke)
|
||||||
|
{
|
||||||
|
System.out.println( "hit(Rectangle, Shape, onStroke):" );
|
||||||
|
System.out.println( "rect = " + rect );
|
||||||
|
System.out.println( "s = " + s );
|
||||||
|
System.out.println( "onStroke = " + onStroke );
|
||||||
|
return g2D.hit( rect, s, onStroke );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rotate(double theta)
|
||||||
|
{
|
||||||
|
System.out.println( "rotate(theta):" );
|
||||||
|
System.out.println( "theta = " + theta );
|
||||||
|
g2D.rotate( theta );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rotate(double theta, double x, double y)
|
||||||
|
{
|
||||||
|
System.out.println( "rotate(double,double,double):" );
|
||||||
|
System.out.println( "theta = " + theta );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.rotate( theta, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scale(double sx, double sy)
|
||||||
|
{
|
||||||
|
System.out.println( "scale(double,double):" );
|
||||||
|
System.out.println( "sx = " + sx );
|
||||||
|
System.out.println( "sy" );
|
||||||
|
g2D.scale( sx, sy );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackground(Color color)
|
||||||
|
{
|
||||||
|
System.out.println( "setBackground(Color):" );
|
||||||
|
System.out.println( "color = " + color );
|
||||||
|
g2D.setBackground( color );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComposite(Composite comp)
|
||||||
|
{
|
||||||
|
System.out.println( "setComposite(Composite):" );
|
||||||
|
System.out.println( "comp = " + comp );
|
||||||
|
g2D.setComposite( comp );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaint( Paint paint )
|
||||||
|
{
|
||||||
|
System.out.println( "setPain(Paint):" );
|
||||||
|
System.out.println( "paint = " + paint );
|
||||||
|
g2D.setPaint( paint );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
|
||||||
|
{
|
||||||
|
System.out.println( "setRenderingHint(RenderingHints.Key, Object):" );
|
||||||
|
System.out.println( "hintKey = " + hintKey );
|
||||||
|
System.out.println( "hintValue = " + hintValue );
|
||||||
|
g2D.setRenderingHint( hintKey, hintValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRenderingHints(Map hints)
|
||||||
|
{
|
||||||
|
System.out.println( "setRenderingHints(Map):" );
|
||||||
|
System.out.println( "hints = " + hints );
|
||||||
|
g2D.setRenderingHints( hints );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStroke(Stroke s)
|
||||||
|
{
|
||||||
|
System.out.println( "setStroke(Stoke):" );
|
||||||
|
System.out.println( "s = " + s );
|
||||||
|
g2D.setStroke( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransform(AffineTransform Tx)
|
||||||
|
{
|
||||||
|
System.out.println( "setTransform():" );
|
||||||
|
System.out.println( "Tx = " + Tx );
|
||||||
|
g2D.setTransform( Tx );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shear(double shx, double shy)
|
||||||
|
{
|
||||||
|
System.out.println( "shear(shx, dhy):" );
|
||||||
|
System.out.println( "shx = " + shx );
|
||||||
|
System.out.println( "shy = " + shy );
|
||||||
|
g2D.shear( shx, shy );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void transform(AffineTransform Tx)
|
||||||
|
{
|
||||||
|
System.out.println( "transform(AffineTransform):" );
|
||||||
|
System.out.println( "Tx = " + Tx );
|
||||||
|
g2D.transform( Tx );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void translate(double tx, double ty)
|
||||||
|
{
|
||||||
|
System.out.println( "translate(double, double):" );
|
||||||
|
System.out.println( "tx = " + tx );
|
||||||
|
System.out.println( "ty = " + ty );
|
||||||
|
g2D.translate( tx, ty );
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void translate(int x, int y)
|
||||||
|
// {
|
||||||
|
// g2D.translate( x, y );
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void clearRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
System.out.println( "clearRect(int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
g2D.clearRect( x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clipRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
System.out.println( "clipRect(int, int, int, int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
g2D.clipRect( x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyArea(int x, int y, int width, int height,
|
||||||
|
int dx, int dy)
|
||||||
|
{
|
||||||
|
System.out.println( "copyArea(int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
g2D.copyArea( x, y, width, height, dx, dy );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Graphics create()
|
||||||
|
{
|
||||||
|
System.out.println( "create():" );
|
||||||
|
return g2D.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Graphics create(int x, int y, int width, int height) {
|
||||||
|
System.out.println( "create(int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
return g2D.create( x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose()
|
||||||
|
{
|
||||||
|
System.out.println( "dispose():" );
|
||||||
|
g2D.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw3DRect(int x, int y, int width, int height,
|
||||||
|
boolean raised) {
|
||||||
|
System.out.println( "draw3DRect(int,int,int,int,boolean):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
System.out.println( "raised = " + raised );
|
||||||
|
g2D.draw3DRect( x, y, width, height, raised );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawArc(int x, int y, int width, int height,
|
||||||
|
int startAngle, int arcAngle)
|
||||||
|
{
|
||||||
|
System.out.println( "drawArc(int,int,int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
System.out.println( "startAngle = " + startAngle );
|
||||||
|
System.out.println( "arcAngle = " + arcAngle );
|
||||||
|
g2D.drawArc( x, y, width, height, startAngle, arcAngle );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawBytes(byte data[], int offset, int length, int x, int y) {
|
||||||
|
System.out.println( "drawBytes(byte[],int,int,int,int):" );
|
||||||
|
System.out.println( "data = " + data );
|
||||||
|
System.out.println( "offset = " + offset );
|
||||||
|
System.out.println( "length = " + length );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.drawBytes( data, offset, length, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawChars(char data[], int offset, int length, int x, int y) {
|
||||||
|
System.out.println( "drawChars(data,int,int,int,int):" );
|
||||||
|
System.out.println( "data = " + data );
|
||||||
|
System.out.println( "offset = " + offset );
|
||||||
|
System.out.println( "length = " + length );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.drawChars( data, offset, length, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img,
|
||||||
|
int dx1, int dy1, int dx2, int dy2,
|
||||||
|
int sx1, int sy1, int sx2, int sy2,
|
||||||
|
ImageObserver observer)
|
||||||
|
{
|
||||||
|
System.out.println( "drawImage(Image,int,int,int,int,int,int,int,int,ImageObserver):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "dx1 = " + dx1 );
|
||||||
|
System.out.println( "dy1 = " + dy1 );
|
||||||
|
System.out.println( "dx2 = " + dx2 );
|
||||||
|
System.out.println( "dy2 = " + dy2 );
|
||||||
|
System.out.println( "sx1 = " + sx1 );
|
||||||
|
System.out.println( "sy1 = " + sy1 );
|
||||||
|
System.out.println( "sx2 = " + sx2 );
|
||||||
|
System.out.println( "sy2 = " + sy2 );
|
||||||
|
System.out.println( "observer = " + observer );
|
||||||
|
return g2D.drawImage( img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img,
|
||||||
|
int dx1, int dy1, int dx2, int dy2,
|
||||||
|
int sx1, int sy1, int sx2, int sy2,
|
||||||
|
Color bgcolor,
|
||||||
|
ImageObserver observer)
|
||||||
|
{
|
||||||
|
System.out.println( "drawImage(Image,int,int,int,int,int,int,int,int,Color,ImageObserver):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "dx1 = " + dx1 );
|
||||||
|
System.out.println( "dy1 = " + dy1 );
|
||||||
|
System.out.println( "dx2 = " + dx2 );
|
||||||
|
System.out.println( "dy2 = " + dy2 );
|
||||||
|
System.out.println( "sx1 = " + sx1 );
|
||||||
|
System.out.println( "sy1 = " + sy1 );
|
||||||
|
System.out.println( "sx2 = " + sx2 );
|
||||||
|
System.out.println( "sy2 = " + sy2 );
|
||||||
|
System.out.println( "bgcolor = " + bgcolor );
|
||||||
|
System.out.println( "observer = " + observer );
|
||||||
|
return g2D.drawImage( img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img, int x, int y,
|
||||||
|
Color bgcolor,
|
||||||
|
ImageObserver observer)
|
||||||
|
{
|
||||||
|
System.out.println( "drawImage(Image,int,int,Color,ImageObserver):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "bgcolor = " + bgcolor );
|
||||||
|
System.out.println( "observer = " + observer );
|
||||||
|
return g2D.drawImage( img, x, y, bgcolor, observer );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img, int x, int y,
|
||||||
|
ImageObserver observer)
|
||||||
|
{
|
||||||
|
System.out.println( "drawImage(Image,int,int,observer):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "observer = " + observer );
|
||||||
|
return g2D.drawImage( img, x, y, observer );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img, int x, int y,
|
||||||
|
int width, int height,
|
||||||
|
Color bgcolor,
|
||||||
|
ImageObserver observer)
|
||||||
|
{
|
||||||
|
System.out.println( "drawImage(Image,int,int,int,int,Color,ImageObserver):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
System.out.println( "bgcolor = " + bgcolor );
|
||||||
|
System.out.println( "observer = " + observer );
|
||||||
|
return g2D.drawImage( img, x, y, width, height, bgcolor, observer );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img, int x, int y,
|
||||||
|
int width, int height,
|
||||||
|
ImageObserver observer)
|
||||||
|
{
|
||||||
|
System.out.println( "drawImage(Image,int,int,width,height,observer):" );
|
||||||
|
System.out.println( "img = " + img );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
System.out.println( "observer = " + observer );
|
||||||
|
return g2D.drawImage( img, x, y, width, height, observer );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawLine(int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
System.out.println( "drawLine(int,int,int,int):" );
|
||||||
|
System.out.println( "x1 = " + x1 );
|
||||||
|
System.out.println( "y1 = " + y1 );
|
||||||
|
System.out.println( "x2 = " + x2 );
|
||||||
|
System.out.println( "y2 = " + y2 );
|
||||||
|
g2D.drawLine( x1, y1, x2, y2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawOval(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
System.out.println( "drawOval(int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
g2D.drawOval( x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPolygon(Polygon p) {
|
||||||
|
System.out.println( "drawPolygon(Polygon):" );
|
||||||
|
System.out.println( "p = " + p );
|
||||||
|
g2D.drawPolygon( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPolygon(int xPoints[], int yPoints[],
|
||||||
|
int nPoints)
|
||||||
|
{
|
||||||
|
System.out.println( "drawPolygon(int[],int[],int):" );
|
||||||
|
System.out.println( "xPoints = " + xPoints );
|
||||||
|
System.out.println( "yPoints = " + yPoints );
|
||||||
|
System.out.println( "nPoints = " + nPoints );
|
||||||
|
g2D.drawPolygon( xPoints, yPoints, nPoints );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPolyline(int xPoints[], int yPoints[],
|
||||||
|
int nPoints)
|
||||||
|
{
|
||||||
|
System.out.println( "drawPolyline(int[],int[],int):" );
|
||||||
|
System.out.println( "xPoints = " + xPoints );
|
||||||
|
System.out.println( "yPoints = " + yPoints );
|
||||||
|
System.out.println( "nPoints = " + nPoints );
|
||||||
|
g2D.drawPolyline( xPoints, yPoints, nPoints );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRect(int x, int y, int width, int height) {
|
||||||
|
System.out.println( "drawRect(int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
g2D.drawRect( x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRoundRect(int x, int y, int width, int height,
|
||||||
|
int arcWidth, int arcHeight)
|
||||||
|
{
|
||||||
|
System.out.println( "drawRoundRect(int,int,int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
System.out.println( "arcWidth = " + arcWidth );
|
||||||
|
System.out.println( "arcHeight = " + arcHeight );
|
||||||
|
g2D.drawRoundRect( x, y, width, height, arcWidth, arcHeight );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawString(AttributedCharacterIterator iterator,
|
||||||
|
int x, int y)
|
||||||
|
{
|
||||||
|
System.out.println( "drawString(AttributedCharacterIterator,int,int):" );
|
||||||
|
System.out.println( "iterator = " + iterator );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.drawString( iterator, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawString(String str, int x, int y)
|
||||||
|
{
|
||||||
|
System.out.println( "drawString(str,int,int):" );
|
||||||
|
System.out.println( "str = " + str );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.drawString( str, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fill3DRect(int x, int y, int width, int height,
|
||||||
|
boolean raised) {
|
||||||
|
System.out.println( "fill3DRect(int,int,int,int,boolean):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
System.out.println( "raised = " + raised );
|
||||||
|
g2D.fill3DRect( x, y, width, height, raised );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillArc(int x, int y, int width, int height,
|
||||||
|
int startAngle, int arcAngle)
|
||||||
|
{
|
||||||
|
System.out.println( "fillArc(int,int,int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
System.out.println( "startAngle = " + startAngle );
|
||||||
|
System.out.println( "arcAngle = " + arcAngle );
|
||||||
|
g2D.fillArc( x, y, width, height, startAngle, arcAngle );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillOval(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
System.out.println( "fillOval(int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
g2D.fillOval( x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillPolygon(Polygon p) {
|
||||||
|
System.out.println( "fillPolygon(Polygon):" );
|
||||||
|
System.out.println( "p = " + p );
|
||||||
|
g2D.fillPolygon( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillPolygon(int xPoints[], int yPoints[],
|
||||||
|
int nPoints)
|
||||||
|
{
|
||||||
|
System.out.println( "fillPolygon(int[],int[],int):" );
|
||||||
|
System.out.println( "xPoints = " + xPoints );
|
||||||
|
System.out.println( "yPoints = " + yPoints );
|
||||||
|
System.out.println( "nPoints = " + nPoints );
|
||||||
|
g2D.fillPolygon( xPoints, yPoints, nPoints );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
System.out.println( "fillRect(int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
g2D.fillRect( x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillRoundRect(int x, int y, int width, int height,
|
||||||
|
int arcWidth, int arcHeight)
|
||||||
|
{
|
||||||
|
System.out.println( "fillRoundRect(int,int,int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
g2D.fillRoundRect( x, y, width, height, arcWidth, arcHeight );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finalize() {
|
||||||
|
System.out.println( "finalize():" );
|
||||||
|
g2D.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Shape getClip()
|
||||||
|
{
|
||||||
|
System.out.println( "getClip():" );
|
||||||
|
return g2D.getClip();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getClipBounds()
|
||||||
|
{
|
||||||
|
System.out.println( "getClipBounds():" );
|
||||||
|
return g2D.getClipBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getClipBounds(Rectangle r) {
|
||||||
|
System.out.println( "getClipBounds(Rectangle):" );
|
||||||
|
System.out.println( "r = " + r );
|
||||||
|
return g2D.getClipBounds( r );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getClipRect() {
|
||||||
|
System.out.println( "getClipRect():" );
|
||||||
|
return g2D.getClipRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor()
|
||||||
|
{
|
||||||
|
System.out.println( "getColor():" );
|
||||||
|
return g2D.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Font getFont()
|
||||||
|
{
|
||||||
|
System.out.println( "getFont():" );
|
||||||
|
return g2D.getFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FontMetrics getFontMetrics() {
|
||||||
|
System.out.println( "getFontMetrics():" );
|
||||||
|
return g2D.getFontMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FontMetrics getFontMetrics(Font f)
|
||||||
|
{
|
||||||
|
System.out.println( "getFontMetrics():" );
|
||||||
|
return g2D.getFontMetrics( f );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hitClip(int x, int y, int width, int height) {
|
||||||
|
System.out.println( "hitClip(int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
return g2D.hitClip( x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClip(Shape clip)
|
||||||
|
{
|
||||||
|
System.out.println( "setClip(Shape):" );
|
||||||
|
System.out.println( "clip = " + clip );
|
||||||
|
g2D.setClip( clip );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClip(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
System.out.println( "setClip(int,int,int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
System.out.println( "width = " + width );
|
||||||
|
System.out.println( "height = " + height );
|
||||||
|
g2D.setClip( x, y, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(Color c)
|
||||||
|
{
|
||||||
|
System.out.println( "setColor():" );
|
||||||
|
System.out.println( "c = " + c );
|
||||||
|
g2D.setColor( c );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFont(Font font)
|
||||||
|
{
|
||||||
|
System.out.println( "setFont(Font):" );
|
||||||
|
System.out.println( "font = " + font );
|
||||||
|
g2D.setFont( font );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaintMode()
|
||||||
|
{
|
||||||
|
System.out.println( "setPaintMode():" );
|
||||||
|
g2D.setPaintMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXORMode(Color c1)
|
||||||
|
{
|
||||||
|
System.out.println( "setXORMode(Color):" );
|
||||||
|
System.out.println( "c1 = " + c1 );
|
||||||
|
g2D.setXORMode( c1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
System.out.println( "toString():" );
|
||||||
|
return g2D.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void translate(int x, int y)
|
||||||
|
{
|
||||||
|
System.out.println( "translate(int,int):" );
|
||||||
|
System.out.println( "x = " + x );
|
||||||
|
System.out.println( "y = " + y );
|
||||||
|
g2D.translate( x, y );
|
||||||
|
}
|
||||||
|
}
|
450
src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java
Normal file
450
src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.util.POILogFactory;
|
||||||
|
import org.apache.poi.util.POILogger;
|
||||||
|
import org.apache.poi.hssf.util.HSSFColor;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.ImageObserver;
|
||||||
|
import java.text.AttributedCharacterIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates Graphics calls into escher calls. The translation is lossy so
|
||||||
|
* many features are not supported and some just aren't implemented yet. If
|
||||||
|
* in doubt test the specific calls you wish to make. Graphics calls are
|
||||||
|
* always performed into an EscherGroup so one will need to be created.
|
||||||
|
* <p>
|
||||||
|
* <b>Important:</b>
|
||||||
|
* <blockquote>
|
||||||
|
* One important concept worth considering is that of font size. One of the
|
||||||
|
* difficulties in converting Graphics calls into escher drawing calls is that
|
||||||
|
* Excel does not have the concept of absolute pixel positions. It measures
|
||||||
|
* it's cell widths in 'characters' and the cell heights in points.
|
||||||
|
* Unfortunately it's not defined exactly what a type of character it's
|
||||||
|
* measuring. Presumably this is due to the fact that the Excel will be
|
||||||
|
* using different fonts on different platforms or even within the same
|
||||||
|
* platform.
|
||||||
|
* <p>
|
||||||
|
* Because of this constraint we've had to calculate the
|
||||||
|
* verticalPointsPerPixel. This the amount the font should be scaled by when
|
||||||
|
* you issue commands such as drawString(). A good way to calculate this
|
||||||
|
* is to use the follow formula:
|
||||||
|
* <p>
|
||||||
|
* <pre>
|
||||||
|
* multipler = groupHeightInPoints / heightOfGroup
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* The height of the group is calculated fairly simply by calculating the
|
||||||
|
* difference between the y coordinates of the bounding box of the shape. The
|
||||||
|
* height of the group can be calculated by using a convenience called
|
||||||
|
* <code>HSSFClientAnchor.getAnchorHeightInPoints()</code>.
|
||||||
|
* </blockquote>
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherGraphics
|
||||||
|
extends Graphics
|
||||||
|
{
|
||||||
|
private HSSFShapeGroup escherGroup;
|
||||||
|
private HSSFWorkbook workbook;
|
||||||
|
private float verticalPointsPerPixel = 1.0f;
|
||||||
|
private float verticalPixelsPerPoint;
|
||||||
|
private Color foreground;
|
||||||
|
private Color background = Color.white;
|
||||||
|
private Font font;
|
||||||
|
private static POILogger logger = POILogFactory.getLogger(EscherGraphics.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an escher graphics object.
|
||||||
|
*
|
||||||
|
* @param escherGroup The escher group to write the graphics calls into.
|
||||||
|
* @param workbook The workbook we are using.
|
||||||
|
* @param forecolor The foreground color to use as default.
|
||||||
|
* @param verticalPointsPerPixel The font multiplier. (See class description for information on how this works.).
|
||||||
|
*/
|
||||||
|
public EscherGraphics(HSSFShapeGroup escherGroup, HSSFWorkbook workbook, Color forecolor, float verticalPointsPerPixel )
|
||||||
|
{
|
||||||
|
this.escherGroup = escherGroup;
|
||||||
|
this.workbook = workbook;
|
||||||
|
this.verticalPointsPerPixel = verticalPointsPerPixel;
|
||||||
|
this.verticalPixelsPerPoint = 1 / verticalPointsPerPixel;
|
||||||
|
this.font = new Font("Arial", 0, 10);
|
||||||
|
this.foreground = forecolor;
|
||||||
|
// background = backcolor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an escher graphics object.
|
||||||
|
*
|
||||||
|
* @param escherGroup The escher group to write the graphics calls into.
|
||||||
|
* @param workbook The workbook we are using.
|
||||||
|
* @param foreground The foreground color to use as default.
|
||||||
|
* @param verticalPointsPerPixel The font multiplier. (See class description for information on how this works.).
|
||||||
|
* @param font The font to use.
|
||||||
|
*/
|
||||||
|
EscherGraphics( HSSFShapeGroup escherGroup, HSSFWorkbook workbook, Color foreground, Font font, float verticalPointsPerPixel )
|
||||||
|
{
|
||||||
|
this.escherGroup = escherGroup;
|
||||||
|
this.workbook = workbook;
|
||||||
|
this.foreground = foreground;
|
||||||
|
// this.background = background;
|
||||||
|
this.font = font;
|
||||||
|
this.verticalPointsPerPixel = verticalPointsPerPixel;
|
||||||
|
this.verticalPixelsPerPoint = 1 / verticalPointsPerPixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an escher graphics object.
|
||||||
|
*
|
||||||
|
* @param escherGroup The escher group to write the graphics calls into.
|
||||||
|
* @param workbook The workbook we are using.
|
||||||
|
* @param forecolor The default foreground color.
|
||||||
|
*/
|
||||||
|
// public EscherGraphics( HSSFShapeGroup escherGroup, HSSFWorkbook workbook, Color forecolor)
|
||||||
|
// {
|
||||||
|
// this(escherGroup, workbook, forecolor, 1.0f);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
public void clearRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
Color color = foreground;
|
||||||
|
setColor(background);
|
||||||
|
fillRect(x,y,width,height);
|
||||||
|
setColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clipRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"clipRect not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyArea(int x, int y, int width, int height, int dx, int dy)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"copyArea not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Graphics create()
|
||||||
|
{
|
||||||
|
EscherGraphics g = new EscherGraphics(escherGroup, workbook,
|
||||||
|
foreground, font, verticalPointsPerPixel );
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawArc(int x, int y, int width, int height,
|
||||||
|
int startAngle, int arcAngle)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawArc not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img,
|
||||||
|
int dx1, int dy1, int dx2, int dy2,
|
||||||
|
int sx1, int sy1, int sx2, int sy2,
|
||||||
|
Color bgcolor,
|
||||||
|
ImageObserver observer)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawImage not supported");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img,
|
||||||
|
int dx1, int dy1, int dx2, int dy2,
|
||||||
|
int sx1, int sy1, int sx2, int sy2,
|
||||||
|
ImageObserver observer)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawImage not supported");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image image, int i, int j, int k, int l, Color color, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
return drawImage(image, i, j, i + k, j + l, 0, 0, image.getWidth(imageobserver), image.getHeight(imageobserver), color, imageobserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image image, int i, int j, int k, int l, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
return drawImage(image, i, j, i + k, j + l, 0, 0, image.getWidth(imageobserver), image.getHeight(imageobserver), imageobserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image image, int i, int j, Color color, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
return drawImage(image, i, j, image.getWidth(imageobserver), image.getHeight(imageobserver), color, imageobserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image image, int i, int j, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
return drawImage(image, i, j, image.getWidth(imageobserver), image.getHeight(imageobserver), imageobserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawLine(int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
HSSFSimpleShape shape = escherGroup.createShape(new HSSFChildAnchor(x1, y1, x2, y2) );
|
||||||
|
shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
|
||||||
|
shape.setLineWidth(0);
|
||||||
|
shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawOval(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
HSSFSimpleShape shape = escherGroup.createShape(new HSSFChildAnchor(x,y,x+width,y+height) );
|
||||||
|
shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
|
||||||
|
shape.setLineWidth(0);
|
||||||
|
shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
|
||||||
|
shape.setNoFill(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPolygon(int xPoints[], int yPoints[],
|
||||||
|
int nPoints)
|
||||||
|
{
|
||||||
|
int right = findBiggest(xPoints);
|
||||||
|
int bottom = findBiggest(yPoints);
|
||||||
|
int left = findSmallest(xPoints);
|
||||||
|
int top = findSmallest(yPoints);
|
||||||
|
HSSFPolygon shape = escherGroup.createPolygon(new HSSFChildAnchor(left,top,right,bottom) );
|
||||||
|
shape.setPolygonDrawArea(right - left, bottom - top);
|
||||||
|
shape.setPoints(addToAll(xPoints, -left), addToAll(yPoints, -top));
|
||||||
|
shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
|
||||||
|
shape.setLineWidth(0);
|
||||||
|
shape.setNoFill(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] addToAll( int[] values, int amount )
|
||||||
|
{
|
||||||
|
int[] result = new int[values.length];
|
||||||
|
for ( int i = 0; i < values.length; i++ )
|
||||||
|
result[i] = values[i] + amount;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPolyline(int xPoints[], int yPoints[],
|
||||||
|
int nPoints)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawPolyline not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawRect not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRoundRect(int x, int y, int width, int height,
|
||||||
|
int arcWidth, int arcHeight)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawRoundRect not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawString(String str, int x, int y)
|
||||||
|
{
|
||||||
|
if (str == null || str.equals(""))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Font excelFont = font;
|
||||||
|
if ( font.getName().equals( "SansSerif" ) )
|
||||||
|
{
|
||||||
|
excelFont = new Font( "Arial", font.getStyle(), (int) ( font.getSize() / verticalPixelsPerPoint ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
excelFont = new Font( font.getName(), font.getStyle(), (int) ( font.getSize() / verticalPixelsPerPoint ));
|
||||||
|
}
|
||||||
|
FontDetails d = StaticFontMetrics.getFontDetails( excelFont );
|
||||||
|
int width = (int) ( (d.getStringWidth( str ) * 2.5) + 12 );
|
||||||
|
int height = (int) ( ( font.getSize() * 2.0 * verticalPixelsPerPoint ) + 6 );
|
||||||
|
y -= ( font.getSize() * verticalPixelsPerPoint ); // we want to draw the shape from the top-left
|
||||||
|
HSSFTextbox textbox = escherGroup.createTextbox( new HSSFChildAnchor( x, y, x + width, y + height ) );
|
||||||
|
textbox.setNoFill( true );
|
||||||
|
textbox.setLineStyle( HSSFShape.LINESTYLE_NONE );
|
||||||
|
HSSFRichTextString s = new HSSFRichTextString( str );
|
||||||
|
HSSFFont hssfFont = matchFont( excelFont );
|
||||||
|
s.applyFont( hssfFont );
|
||||||
|
textbox.setString( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
private HSSFFont matchFont( Font font )
|
||||||
|
{
|
||||||
|
HSSFColor hssfColor = workbook.getCustomPalette()
|
||||||
|
.findColor((byte)foreground.getRed(), (byte)foreground.getGreen(), (byte)foreground.getBlue());
|
||||||
|
if (hssfColor == null)
|
||||||
|
hssfColor = workbook.getCustomPalette().findSimilarColor((byte)foreground.getRed(), (byte)foreground.getGreen(), (byte)foreground.getBlue());
|
||||||
|
boolean bold = (font.getStyle() & Font.BOLD) != 0;
|
||||||
|
boolean italic = (font.getStyle() & Font.ITALIC) != 0;
|
||||||
|
HSSFFont hssfFont = workbook.findFont(bold ? HSSFFont.BOLDWEIGHT_BOLD : 0,
|
||||||
|
hssfColor.getIndex(),
|
||||||
|
(short)(font.getSize() * 20),
|
||||||
|
font.getName(),
|
||||||
|
italic,
|
||||||
|
false,
|
||||||
|
(short)0,
|
||||||
|
(byte)0);
|
||||||
|
if (hssfFont == null)
|
||||||
|
{
|
||||||
|
hssfFont = workbook.createFont();
|
||||||
|
hssfFont.setBoldweight(bold ? HSSFFont.BOLDWEIGHT_BOLD : 0);
|
||||||
|
hssfFont.setColor(hssfColor.getIndex());
|
||||||
|
hssfFont.setFontHeight((short)(font.getSize() * 20));
|
||||||
|
hssfFont.setFontName(font.getName());
|
||||||
|
hssfFont.setItalic(italic);
|
||||||
|
hssfFont.setStrikeout(false);
|
||||||
|
hssfFont.setTypeOffset((short) 0);
|
||||||
|
hssfFont.setUnderline((byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hssfFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void drawString(AttributedCharacterIterator iterator,
|
||||||
|
int x, int y)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawString not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillArc(int x, int y, int width, int height,
|
||||||
|
int startAngle, int arcAngle)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"fillArc not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillOval(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
HSSFSimpleShape shape = escherGroup.createShape(new HSSFChildAnchor( x, y, x + width, y + height ) );
|
||||||
|
shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
|
||||||
|
shape.setLineStyle(HSSFShape.LINESTYLE_NONE);
|
||||||
|
shape.setFillColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
|
||||||
|
shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillPolygon(int xPoints[], int yPoints[],
|
||||||
|
int nPoints)
|
||||||
|
{
|
||||||
|
int right = findBiggest(xPoints);
|
||||||
|
int bottom = findBiggest(yPoints);
|
||||||
|
int left = findSmallest(xPoints);
|
||||||
|
int top = findSmallest(yPoints);
|
||||||
|
HSSFPolygon shape = escherGroup.createPolygon(new HSSFChildAnchor(left,top,right,bottom) );
|
||||||
|
shape.setPolygonDrawArea(right - left, bottom - top);
|
||||||
|
shape.setPoints(addToAll(xPoints, -left), addToAll(yPoints, -top));
|
||||||
|
shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
|
||||||
|
shape.setFillColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findBiggest( int[] values )
|
||||||
|
{
|
||||||
|
int result = Integer.MIN_VALUE;
|
||||||
|
for ( int i = 0; i < values.length; i++ )
|
||||||
|
{
|
||||||
|
if (values[i] > result)
|
||||||
|
result = values[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int findSmallest( int[] values )
|
||||||
|
{
|
||||||
|
int result = Integer.MAX_VALUE;
|
||||||
|
for ( int i = 0; i < values.length; i++ )
|
||||||
|
{
|
||||||
|
if (values[i] < result)
|
||||||
|
result = values[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
HSSFSimpleShape shape = escherGroup.createShape(new HSSFChildAnchor( x, y, x + width, y + height ) );
|
||||||
|
shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);
|
||||||
|
shape.setLineStyle(HSSFShape.LINESTYLE_NONE);
|
||||||
|
shape.setFillColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
|
||||||
|
shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillRoundRect(int x, int y, int width, int height,
|
||||||
|
int arcWidth, int arcHeight)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"fillRoundRect not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Shape getClip()
|
||||||
|
{
|
||||||
|
return getClipBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getClipBounds()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getClipRect()
|
||||||
|
{
|
||||||
|
return getClipBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor()
|
||||||
|
{
|
||||||
|
return foreground;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Font getFont()
|
||||||
|
{
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FontMetrics getFontMetrics(Font f)
|
||||||
|
{
|
||||||
|
return Toolkit.getDefaultToolkit().getFontMetrics(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClip(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
setClip(((Shape) (new Rectangle(x,y,width,height))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClip(Shape shape)
|
||||||
|
{
|
||||||
|
// ignore... not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(Color color)
|
||||||
|
{
|
||||||
|
foreground = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFont(Font f)
|
||||||
|
{
|
||||||
|
font = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaintMode()
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"setPaintMode not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXORMode(Color color)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"setXORMode not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void translate(int x, int y)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"translate not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getBackground()
|
||||||
|
{
|
||||||
|
return background;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackground( Color background )
|
||||||
|
{
|
||||||
|
this.background = background;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
567
src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java
Normal file
567
src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java
Normal file
@ -0,0 +1,567 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.util.POILogFactory;
|
||||||
|
import org.apache.poi.util.POILogger;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.font.FontRenderContext;
|
||||||
|
import java.awt.font.GlyphVector;
|
||||||
|
import java.awt.font.TextLayout;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.awt.geom.Area;
|
||||||
|
import java.awt.geom.GeneralPath;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.BufferedImageOp;
|
||||||
|
import java.awt.image.ImageObserver;
|
||||||
|
import java.awt.image.RenderedImage;
|
||||||
|
import java.awt.image.renderable.RenderableImage;
|
||||||
|
import java.text.AttributedCharacterIterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates Graphics2d calls into escher calls. The translation is lossy so
|
||||||
|
* many features are not supported and some just aren't implemented yet. If
|
||||||
|
* in doubt test the specific calls you wish to make. Graphics calls are
|
||||||
|
* always drawn into an EscherGroup so one will need to be created.
|
||||||
|
* <p>
|
||||||
|
* <b>Important:</b>
|
||||||
|
* <blockquote>
|
||||||
|
* One important concept worth considering is that of font size. One of the
|
||||||
|
* difficulties in converting Graphics calls into escher drawing calls is that
|
||||||
|
* Excel does not have the concept of absolute pixel positions. It measures
|
||||||
|
* it's cell widths in 'characters' and the cell heights in points.
|
||||||
|
* Unfortunately it's not defined exactly what a type of character it's
|
||||||
|
* measuring. Presumably this is due to the fact that the Excel will be
|
||||||
|
* using different fonts on different platforms or even within the same
|
||||||
|
* platform.
|
||||||
|
* <p>
|
||||||
|
* Because of this constraint you have to calculate the verticalPointsPerPixel.
|
||||||
|
* This the amount the font should be scaled by when
|
||||||
|
* you issue commands such as drawString(). A good way to calculate this
|
||||||
|
* is to use the follow formula:
|
||||||
|
* <p>
|
||||||
|
* <pre>
|
||||||
|
* multipler = groupHeightInPoints / heightOfGroup
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* The height of the group is calculated fairly simply by calculating the
|
||||||
|
* difference between the y coordinates of the bounding box of the shape. The
|
||||||
|
* height of the group can be calculated by using a convenience called
|
||||||
|
* <code>HSSFClientAnchor.getAnchorHeightInPoints()</code>.
|
||||||
|
* </blockquote>
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class EscherGraphics2d extends Graphics2D
|
||||||
|
{
|
||||||
|
private EscherGraphics escherGraphics;
|
||||||
|
private BufferedImage img;
|
||||||
|
private AffineTransform trans;
|
||||||
|
private Stroke stroke;
|
||||||
|
private Paint paint;
|
||||||
|
private Shape deviceclip;
|
||||||
|
private POILogger logger = POILogFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs one escher graphics object from an escher graphics object.
|
||||||
|
*
|
||||||
|
* @param escherGraphics the original EscherGraphics2d object to copy
|
||||||
|
*/
|
||||||
|
public EscherGraphics2d(EscherGraphics escherGraphics)
|
||||||
|
{
|
||||||
|
this.escherGraphics = escherGraphics;
|
||||||
|
setImg( new BufferedImage(1, 1, 2) );
|
||||||
|
setColor(Color.black);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRenderingHints(Map map)
|
||||||
|
{
|
||||||
|
getG2D().addRenderingHints(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearRect(int i, int j, int k, int l)
|
||||||
|
{
|
||||||
|
Paint paint1 = getPaint();
|
||||||
|
setColor(getBackground());
|
||||||
|
fillRect(i, j, k, l);
|
||||||
|
setPaint(paint1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clip(Shape shape)
|
||||||
|
{
|
||||||
|
if(getDeviceclip() != null)
|
||||||
|
{
|
||||||
|
Area area = new Area(getClip());
|
||||||
|
if(shape != null)
|
||||||
|
area.intersect(new Area(shape));
|
||||||
|
shape = area;
|
||||||
|
}
|
||||||
|
setClip(shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clipRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
clip(new Rectangle(x,y,width,height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyArea(int x, int y, int width, int height,
|
||||||
|
int dx, int dy)
|
||||||
|
{
|
||||||
|
getG2D().copyArea(x,y,width,height,dx,dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Graphics create()
|
||||||
|
{
|
||||||
|
EscherGraphics2d g2d = new EscherGraphics2d(escherGraphics);
|
||||||
|
return g2d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose()
|
||||||
|
{
|
||||||
|
getEscherGraphics().dispose();
|
||||||
|
getG2D().dispose();
|
||||||
|
getImg().flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(Shape shape)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"copyArea not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawArc(int x, int y, int width, int height,
|
||||||
|
int startAngle, int arcAngle)
|
||||||
|
{
|
||||||
|
draw(new java.awt.geom.Arc2D.Float(x, y, width, height, startAngle, arcAngle, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawGlyphVector(GlyphVector g, float x, float y)
|
||||||
|
{
|
||||||
|
fill(g.getOutline(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
|
||||||
|
int sx2, int sy2, Color bgColor, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawImage() not supported");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
|
||||||
|
int sx2, int sy2, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawImage() not supported");
|
||||||
|
return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, imageobserver);
|
||||||
|
}
|
||||||
|
public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, Color bgColor, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"drawImage() not supported");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image img, int x, int y,
|
||||||
|
int width, int height,
|
||||||
|
ImageObserver observer)
|
||||||
|
{
|
||||||
|
return drawImage(img, x,y,width,height, null, observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image image, int x, int y, Color bgColor, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
return drawImage(image, x, y, image.getWidth(imageobserver), image.getHeight(imageobserver), bgColor, imageobserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image image, int x, int y, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
return drawImage(image, x, y, image.getWidth(imageobserver), image.getHeight(imageobserver), imageobserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean drawImage(Image image, AffineTransform affinetransform, ImageObserver imageobserver)
|
||||||
|
{
|
||||||
|
AffineTransform affinetransform1 = (AffineTransform)getTrans().clone();
|
||||||
|
getTrans().concatenate(affinetransform);
|
||||||
|
drawImage(image, 0, 0, imageobserver);
|
||||||
|
setTrans( affinetransform1 );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawImage(BufferedImage bufferedimage, BufferedImageOp op, int x, int y)
|
||||||
|
{
|
||||||
|
BufferedImage img = op.filter(bufferedimage, null);
|
||||||
|
drawImage(((Image) (img)), new AffineTransform(1.0F, 0.0F, 0.0F, 1.0F, x, y), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawLine(int x1, int y1, int x2, int y2)
|
||||||
|
{
|
||||||
|
getEscherGraphics().drawLine(x1,y1,x2,y2);
|
||||||
|
// draw(new GeneralPath(new java.awt.geom.Line2D.Float(x1, y1, x2, y2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawOval(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
getEscherGraphics().drawOval(x,y,width,height);
|
||||||
|
// draw(new java.awt.geom.Ellipse2D.Float(x, y, width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPolygon(int xPoints[], int yPoints[],
|
||||||
|
int nPoints)
|
||||||
|
{
|
||||||
|
getEscherGraphics().drawPolygon(xPoints, yPoints, nPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawPolyline(int xPoints[], int yPoints[], int nPoints)
|
||||||
|
{
|
||||||
|
if(nPoints > 0)
|
||||||
|
{
|
||||||
|
GeneralPath generalpath = new GeneralPath();
|
||||||
|
generalpath.moveTo(xPoints[0], yPoints[0]);
|
||||||
|
for(int j = 1; j < nPoints; j++)
|
||||||
|
generalpath.lineTo(xPoints[j], yPoints[j]);
|
||||||
|
|
||||||
|
draw(generalpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
escherGraphics.drawRect(x,y,width,height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRenderableImage(RenderableImage renderableimage, AffineTransform affinetransform)
|
||||||
|
{
|
||||||
|
drawRenderedImage(renderableimage.createDefaultRendering(), affinetransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRenderedImage(RenderedImage renderedimage, AffineTransform affinetransform)
|
||||||
|
{
|
||||||
|
BufferedImage bufferedimage = new BufferedImage(renderedimage.getColorModel(), renderedimage.getData().createCompatibleWritableRaster(), false, null);
|
||||||
|
bufferedimage.setData(renderedimage.getData());
|
||||||
|
drawImage(bufferedimage, affinetransform, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRoundRect(int i, int j, int k, int l, int i1, int j1)
|
||||||
|
{
|
||||||
|
draw(new java.awt.geom.RoundRectangle2D.Float(i, j, k, l, i1, j1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawString(String string, float x, float y)
|
||||||
|
{
|
||||||
|
getEscherGraphics().drawString(string, (int)x, (int)y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawString(String string, int x, int y)
|
||||||
|
{
|
||||||
|
getEscherGraphics().drawString(string, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawString(AttributedCharacterIterator attributedcharacteriterator, float x, float y)
|
||||||
|
{
|
||||||
|
TextLayout textlayout = new TextLayout(attributedcharacteriterator, getFontRenderContext());
|
||||||
|
Paint paint1 = getPaint();
|
||||||
|
setColor(getColor());
|
||||||
|
fill(textlayout.getOutline(AffineTransform.getTranslateInstance(x, y)));
|
||||||
|
setPaint(paint1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawString(AttributedCharacterIterator attributedcharacteriterator, int x, int y)
|
||||||
|
{
|
||||||
|
drawString(attributedcharacteriterator, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fill(Shape shape)
|
||||||
|
{
|
||||||
|
logger.log(POILogger.WARN,"fill(Shape) not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillArc(int i, int j, int k, int l, int i1, int j1)
|
||||||
|
{
|
||||||
|
fill(new java.awt.geom.Arc2D.Float(i, j, k, l, i1, j1, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillOval(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
escherGraphics.fillOval(x,y,width,height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills a closed polygon defined by
|
||||||
|
* arrays of <i>x</i> and <i>y</i> coordinates.
|
||||||
|
* <p>
|
||||||
|
* This method draws the polygon defined by <code>nPoint</code> line
|
||||||
|
* segments, where the first <code>nPoint - 1</code>
|
||||||
|
* line segments are line segments from
|
||||||
|
* <code>(xPoints[i - 1], yPoints[i - 1])</code>
|
||||||
|
* to <code>(xPoints[i], yPoints[i])</code>, for
|
||||||
|
* 1 ≤ <i>i</i> ≤ <code>nPoints</code>.
|
||||||
|
* The figure is automatically closed by drawing a line connecting
|
||||||
|
* the final point to the first point, if those points are different.
|
||||||
|
* <p>
|
||||||
|
* The area inside the polygon is defined using an
|
||||||
|
* even-odd fill rule, also known as the alternating rule.
|
||||||
|
* @param xPoints a an array of <code>x</code> coordinates.
|
||||||
|
* @param yPoints a an array of <code>y</code> coordinates.
|
||||||
|
* @param nPoints a the total number of points.
|
||||||
|
* @see java.awt.Graphics#drawPolygon(int[], int[], int)
|
||||||
|
*/
|
||||||
|
public void fillPolygon(int xPoints[], int yPoints[], int nPoints)
|
||||||
|
{
|
||||||
|
escherGraphics.fillPolygon(xPoints, yPoints, nPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillRect(int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
getEscherGraphics().fillRect(x,y,width,height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillRoundRect(int x, int y, int width, int height,
|
||||||
|
int arcWidth, int arcHeight)
|
||||||
|
{
|
||||||
|
fill(new java.awt.geom.RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getBackground()
|
||||||
|
{
|
||||||
|
return getEscherGraphics().getBackground();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Shape getClip()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return getTrans().createInverse().createTransformedShape(getDeviceclip());
|
||||||
|
}
|
||||||
|
catch(Exception _ex)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getClipBounds()
|
||||||
|
{
|
||||||
|
if(getDeviceclip() != null)
|
||||||
|
return getClip().getBounds();
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor()
|
||||||
|
{
|
||||||
|
return escherGraphics.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Composite getComposite()
|
||||||
|
{
|
||||||
|
return getG2D().getComposite();
|
||||||
|
}
|
||||||
|
|
||||||
|
public GraphicsConfiguration getDeviceConfiguration()
|
||||||
|
{
|
||||||
|
return getG2D().getDeviceConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Font getFont()
|
||||||
|
{
|
||||||
|
return getEscherGraphics().getFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FontMetrics getFontMetrics(Font font)
|
||||||
|
{
|
||||||
|
return getEscherGraphics().getFontMetrics(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FontRenderContext getFontRenderContext()
|
||||||
|
{
|
||||||
|
getG2D().setTransform(getTrans());
|
||||||
|
return getG2D().getFontRenderContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Paint getPaint()
|
||||||
|
{
|
||||||
|
return paint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getRenderingHint(java.awt.RenderingHints.Key key)
|
||||||
|
{
|
||||||
|
return getG2D().getRenderingHint(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderingHints getRenderingHints()
|
||||||
|
{
|
||||||
|
return getG2D().getRenderingHints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stroke getStroke()
|
||||||
|
{
|
||||||
|
return stroke;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AffineTransform getTransform()
|
||||||
|
{
|
||||||
|
return (AffineTransform)getTrans().clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hit(Rectangle rectangle, Shape shape, boolean flag)
|
||||||
|
{
|
||||||
|
getG2D().setTransform(getTrans());
|
||||||
|
getG2D().setStroke(getStroke());
|
||||||
|
getG2D().setClip(getClip());
|
||||||
|
return getG2D().hit(rectangle, shape, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rotate(double d)
|
||||||
|
{
|
||||||
|
getTrans().rotate(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rotate(double d, double d1, double d2)
|
||||||
|
{
|
||||||
|
getTrans().rotate(d, d1, d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scale(double d, double d1)
|
||||||
|
{
|
||||||
|
getTrans().scale(d, d1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackground(Color c)
|
||||||
|
{
|
||||||
|
getEscherGraphics().setBackground(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClip(int i, int j, int k, int l)
|
||||||
|
{
|
||||||
|
setClip(((Shape) (new Rectangle(i, j, k, l))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClip(Shape shape)
|
||||||
|
{
|
||||||
|
setDeviceclip( getTrans().createTransformedShape(shape) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(Color c)
|
||||||
|
{
|
||||||
|
escherGraphics.setColor(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComposite(Composite composite)
|
||||||
|
{
|
||||||
|
getG2D().setComposite(composite);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFont(Font font)
|
||||||
|
{
|
||||||
|
getEscherGraphics().setFont(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaint(Paint paint1)
|
||||||
|
{
|
||||||
|
if(paint1 != null)
|
||||||
|
{
|
||||||
|
paint = paint1;
|
||||||
|
if(paint1 instanceof Color)
|
||||||
|
setColor( (Color)paint1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPaintMode()
|
||||||
|
{
|
||||||
|
getEscherGraphics().setPaintMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRenderingHint(java.awt.RenderingHints.Key key, Object obj)
|
||||||
|
{
|
||||||
|
getG2D().setRenderingHint(key, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRenderingHints(Map map)
|
||||||
|
{
|
||||||
|
getG2D().setRenderingHints(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStroke(Stroke s)
|
||||||
|
{
|
||||||
|
stroke = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransform(AffineTransform affinetransform)
|
||||||
|
{
|
||||||
|
setTrans( (AffineTransform)affinetransform.clone() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXORMode(Color color1)
|
||||||
|
{
|
||||||
|
getEscherGraphics().setXORMode(color1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shear(double d, double d1)
|
||||||
|
{
|
||||||
|
getTrans().shear(d, d1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void transform(AffineTransform affinetransform)
|
||||||
|
{
|
||||||
|
getTrans().concatenate(affinetransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image transformImage(Image image, Rectangle rectangle, Rectangle rectangle1, ImageObserver imageobserver, Color color1)
|
||||||
|
// {
|
||||||
|
// logger.log(POILogger.WARN,"transformImage() not supported");
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Image transformImage(Image image, int ai[], Rectangle rectangle, ImageObserver imageobserver, Color color1)
|
||||||
|
// {
|
||||||
|
// logger.log(POILogger.WARN,"transformImage() not supported");
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void translate(double d, double d1)
|
||||||
|
{
|
||||||
|
getTrans().translate(d, d1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void translate(int i, int j)
|
||||||
|
{
|
||||||
|
getTrans().translate(i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EscherGraphics getEscherGraphics()
|
||||||
|
{
|
||||||
|
return escherGraphics;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage getImg()
|
||||||
|
{
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setImg( BufferedImage img )
|
||||||
|
{
|
||||||
|
this.img = img;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Graphics2D getG2D()
|
||||||
|
{
|
||||||
|
return (Graphics2D) img.getGraphics();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AffineTransform getTrans()
|
||||||
|
{
|
||||||
|
return trans;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTrans( AffineTransform trans )
|
||||||
|
{
|
||||||
|
this.trans = trans;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Shape getDeviceclip()
|
||||||
|
{
|
||||||
|
return deviceclip;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDeviceclip( Shape deviceclip )
|
||||||
|
{
|
||||||
|
this.deviceclip = deviceclip;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
143
src/java/org/apache/poi/hssf/usermodel/FontDetails.java
Normal file
143
src/java/org/apache/poi/hssf/usermodel/FontDetails.java
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores width and height details about a font.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class FontDetails
|
||||||
|
{
|
||||||
|
private String fontName;
|
||||||
|
private int height;
|
||||||
|
private Map charWidths = new HashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct the font details with the given name and height.
|
||||||
|
*
|
||||||
|
* @param fontName The font name.
|
||||||
|
* @param height The height of the font.
|
||||||
|
*/
|
||||||
|
public FontDetails( String fontName, int height )
|
||||||
|
{
|
||||||
|
this.fontName = fontName;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFontName()
|
||||||
|
{
|
||||||
|
return fontName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight()
|
||||||
|
{
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChar( char c, int width )
|
||||||
|
{
|
||||||
|
charWidths.put(new Character(c), new Integer(width));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the width of the specified character. If the metrics for
|
||||||
|
* a particular character are not available it defaults to returning the
|
||||||
|
* width for the 'W' character.
|
||||||
|
*/
|
||||||
|
public int getCharWidth( char c )
|
||||||
|
{
|
||||||
|
Integer widthInteger = (Integer)(charWidths.get(new Character(c)));
|
||||||
|
if (widthInteger == null && c != 'W')
|
||||||
|
return getCharWidth('W');
|
||||||
|
else
|
||||||
|
return widthInteger.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChars( char[] characters, int[] widths )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < characters.length; i++ )
|
||||||
|
{
|
||||||
|
charWidths.put( new Character(characters[i]), new Integer(widths[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of <code>FontDetails</code> by loading them from the
|
||||||
|
* provided property object.
|
||||||
|
* @param fontName the font name
|
||||||
|
* @param fontMetricsProps the property object holding the details of this
|
||||||
|
* particular font.
|
||||||
|
* @return a new FontDetails instance.
|
||||||
|
*/
|
||||||
|
public static FontDetails create( String fontName, Properties fontMetricsProps )
|
||||||
|
{
|
||||||
|
String heightStr = fontMetricsProps.getProperty( "font." + fontName + ".height");
|
||||||
|
String widthsStr = fontMetricsProps.getProperty( "font." + fontName + ".widths");
|
||||||
|
String charactersStr = fontMetricsProps.getProperty( "font." + fontName + ".characters");
|
||||||
|
int height = Integer.parseInt(heightStr);
|
||||||
|
FontDetails d = new FontDetails(fontName, height);
|
||||||
|
String[] charactersStrArray = split(charactersStr, ",", -1);
|
||||||
|
String[] widthsStrArray = split(widthsStr, ",", -1);
|
||||||
|
if (charactersStrArray.length != widthsStrArray.length)
|
||||||
|
throw new RuntimeException("Number of characters does not number of widths for font " + fontName);
|
||||||
|
for ( int i = 0; i < widthsStrArray.length; i++ )
|
||||||
|
{
|
||||||
|
if (charactersStrArray[i].length() != 0)
|
||||||
|
d.addChar(charactersStrArray[i].charAt(0), Integer.parseInt(widthsStrArray[i]));
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the width of all characters in a string.
|
||||||
|
*
|
||||||
|
* @param str The string to measure.
|
||||||
|
* @return The width of the string for a 10 point font.
|
||||||
|
*/
|
||||||
|
public int getStringWidth(String str)
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
for (int i = 0; i < str.length(); i++)
|
||||||
|
{
|
||||||
|
width += getCharWidth(str.charAt(i));
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split the given string into an array of strings using the given
|
||||||
|
* delimiter.
|
||||||
|
*/
|
||||||
|
private static String[] split(String text, String separator, int max)
|
||||||
|
{
|
||||||
|
StringTokenizer tok = new StringTokenizer(text, separator);
|
||||||
|
int listSize = tok.countTokens();
|
||||||
|
if(max != -1 && listSize > max)
|
||||||
|
listSize = max;
|
||||||
|
String list[] = new String[listSize];
|
||||||
|
for(int i = 0; tok.hasMoreTokens(); i++)
|
||||||
|
{
|
||||||
|
if(max != -1 && i == listSize - 1)
|
||||||
|
{
|
||||||
|
StringBuffer buf = new StringBuffer((text.length() * (listSize - i)) / listSize);
|
||||||
|
while(tok.hasMoreTokens())
|
||||||
|
{
|
||||||
|
buf.append(tok.nextToken());
|
||||||
|
if(tok.hasMoreTokens())
|
||||||
|
buf.append(separator);
|
||||||
|
}
|
||||||
|
list[i] = buf.toString().trim();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list[i] = tok.nextToken().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
40
src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.java
Normal file
40
src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An anchor is what specifics the position of a shape within a client object
|
||||||
|
* or within another containing shape.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public abstract class HSSFAnchor
|
||||||
|
{
|
||||||
|
int dx1;
|
||||||
|
int dy1;
|
||||||
|
int dx2;
|
||||||
|
int dy2;
|
||||||
|
|
||||||
|
public HSSFAnchor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public HSSFAnchor( int dx1, int dy1, int dx2, int dy2 )
|
||||||
|
{
|
||||||
|
this.dx1 = dx1;
|
||||||
|
this.dy1 = dy1;
|
||||||
|
this.dx2 = dx2;
|
||||||
|
this.dy2 = dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDx1(){ return dx1; }
|
||||||
|
public void setDx1( int dx1 ){ this.dx1 = dx1; }
|
||||||
|
public int getDy1(){ return dy1; }
|
||||||
|
public void setDy1( int dy1 ){ this.dy1 = dy1; }
|
||||||
|
public int getDy2(){ return dy2; }
|
||||||
|
public void setDy2( int dy2 ){ this.dy2 = dy2; }
|
||||||
|
public int getDx2(){ return dx2; }
|
||||||
|
public void setDx2( int dx2 ){ this.dx2 = dx2; }
|
||||||
|
|
||||||
|
public abstract boolean isHorizontallyFlipped();
|
||||||
|
public abstract boolean isVerticallyFlipped();
|
||||||
|
}
|
37
src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java
Normal file
37
src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
|
import org.apache.poi.ddf.EscherClientAnchorRecord;
|
||||||
|
import org.apache.poi.ddf.EscherChildAnchorRecord;
|
||||||
|
|
||||||
|
public class HSSFChildAnchor
|
||||||
|
extends HSSFAnchor
|
||||||
|
{
|
||||||
|
public HSSFChildAnchor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public HSSFChildAnchor( int dx1, int dy1, int dx2, int dy2 )
|
||||||
|
{
|
||||||
|
super( dx1, dy1, dx2, dy2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnchor(int dx1, int dy1, int dx2, int dy2)
|
||||||
|
{
|
||||||
|
this.dx1 = dx1;
|
||||||
|
this.dy1 = dy1;
|
||||||
|
this.dx2 = dx2;
|
||||||
|
this.dy2 = dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHorizontallyFlipped()
|
||||||
|
{
|
||||||
|
return dx1 > dx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVerticallyFlipped()
|
||||||
|
{
|
||||||
|
return dy1 > dy2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
207
src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java
Normal file
207
src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import org.apache.poi.ddf.EscherClientAnchorRecord;
|
||||||
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A client anchor is attached to an excel worksheet. It anchors against a
|
||||||
|
* top-left and buttom-right cell.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class HSSFClientAnchor
|
||||||
|
extends HSSFAnchor
|
||||||
|
{
|
||||||
|
short col1;
|
||||||
|
int row1;
|
||||||
|
short col2;
|
||||||
|
int row2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new client anchor and defaults all the anchor positions to 0.
|
||||||
|
*/
|
||||||
|
public HSSFClientAnchor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new client anchor and sets the top-left and bottom-right
|
||||||
|
* coordinates of the anchor.
|
||||||
|
*
|
||||||
|
* @param dx1 the x coordinate within the first cell.
|
||||||
|
* @param dy1 the y coordinate within the first cell.
|
||||||
|
* @param dx2 the x coordinate within the second cell.
|
||||||
|
* @param dy2 the y coordinate within the second cell.
|
||||||
|
* @param col1 the column (0 based) of the first cell.
|
||||||
|
* @param row1 the row (0 based) of the first cell.
|
||||||
|
* @param col2 the column (0 based) of the second cell.
|
||||||
|
* @param row2 the row (0 based) of the second cell.
|
||||||
|
*/
|
||||||
|
public HSSFClientAnchor( int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2 )
|
||||||
|
{
|
||||||
|
super( dx1, dy1, dx2, dy2 );
|
||||||
|
|
||||||
|
checkRange(dx1, 0, 1023, "dx1");
|
||||||
|
checkRange(dx2, 0, 1023, "dx2");
|
||||||
|
checkRange(dy1, 0, 255, "dy1");
|
||||||
|
checkRange(dy2, 0, 255, "dy2");
|
||||||
|
checkRange(col1, 0, 255, "col1");
|
||||||
|
checkRange(col2, 0, 255, "col2");
|
||||||
|
checkRange(row1, 0, 255 * 256, "row1");
|
||||||
|
checkRange(row2, 0, 255 * 256, "row2");
|
||||||
|
|
||||||
|
this.col1 = col1;
|
||||||
|
this.row1 = row1;
|
||||||
|
this.col2 = col2;
|
||||||
|
this.row2 = row2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the height of a client anchor in points.
|
||||||
|
*
|
||||||
|
* @param sheet the sheet the anchor will be attached to
|
||||||
|
* @return the shape height.
|
||||||
|
*/
|
||||||
|
public float getAnchorHeightInPoints(HSSFSheet sheet )
|
||||||
|
{
|
||||||
|
int y1 = Math.min( getDy1(), getDy2() );
|
||||||
|
int y2 = Math.max( getDy1(), getDy2() );
|
||||||
|
int row1 = Math.min( getRow1(), getRow2() );
|
||||||
|
int row2 = Math.max( getRow1(), getRow2() );
|
||||||
|
|
||||||
|
float points = 0;
|
||||||
|
if (row1 == row2)
|
||||||
|
{
|
||||||
|
points = ((y2 - y1) / 256.0f) * getRowHeightInPoints(sheet, row2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
points += ((256.0f - y1) / 256.0f) * getRowHeightInPoints(sheet, row1);
|
||||||
|
for (int i = row1 + 1; i < row2; i++)
|
||||||
|
{
|
||||||
|
points += getRowHeightInPoints(sheet, i);
|
||||||
|
}
|
||||||
|
points += (y2 / 256.0f) * getRowHeightInPoints(sheet, row2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getRowHeightInPoints(HSSFSheet sheet, int rowNum)
|
||||||
|
{
|
||||||
|
HSSFRow row = sheet.getRow(rowNum);
|
||||||
|
if (row == null)
|
||||||
|
return sheet.getDefaultRowHeightInPoints();
|
||||||
|
else
|
||||||
|
return row.getHeightInPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getCol1()
|
||||||
|
{
|
||||||
|
return col1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCol1( short col1 )
|
||||||
|
{
|
||||||
|
checkRange(col1, 0, 255, "col1");
|
||||||
|
this.col1 = col1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getCol2()
|
||||||
|
{
|
||||||
|
return col2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCol2( short col2 )
|
||||||
|
{
|
||||||
|
checkRange(col2, 0, 255, "col2");
|
||||||
|
this.col2 = col2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRow1()
|
||||||
|
{
|
||||||
|
return row1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRow1( int row1 )
|
||||||
|
{
|
||||||
|
checkRange(row1, 0, 256 * 256, "row1");
|
||||||
|
this.row1 = row1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRow2()
|
||||||
|
{
|
||||||
|
return row2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRow2( int row2 )
|
||||||
|
{
|
||||||
|
checkRange(row2, 0, 256 * 256, "row2");
|
||||||
|
this.row2 = row2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dets the top-left and bottom-right
|
||||||
|
* coordinates of the anchor.
|
||||||
|
*
|
||||||
|
* @param x1 the x coordinate within the first cell.
|
||||||
|
* @param y1 the y coordinate within the first cell.
|
||||||
|
* @param x2 the x coordinate within the second cell.
|
||||||
|
* @param y2 the y coordinate within the second cell.
|
||||||
|
* @param col1 the column (0 based) of the first cell.
|
||||||
|
* @param row1 the row (0 based) of the first cell.
|
||||||
|
* @param col2 the column (0 based) of the second cell.
|
||||||
|
* @param row2 the row (0 based) of the second cell.
|
||||||
|
*/
|
||||||
|
public void setAnchor( short col1, int row1, int x1, int y1, short col2, int row2, int x2, int y2 )
|
||||||
|
{
|
||||||
|
checkRange(dx1, 0, 1023, "dx1");
|
||||||
|
checkRange(dx2, 0, 1023, "dx2");
|
||||||
|
checkRange(dy1, 0, 255, "dy1");
|
||||||
|
checkRange(dy2, 0, 255, "dy2");
|
||||||
|
checkRange(col1, 0, 255, "col1");
|
||||||
|
checkRange(col2, 0, 255, "col2");
|
||||||
|
checkRange(row1, 0, 255 * 256, "row1");
|
||||||
|
checkRange(row2, 0, 255 * 256, "row2");
|
||||||
|
|
||||||
|
this.col1 = col1;
|
||||||
|
this.row1 = row1;
|
||||||
|
this.dx1 = x1;
|
||||||
|
this.dy1 = y1;
|
||||||
|
this.col2 = col2;
|
||||||
|
this.row2 = row2;
|
||||||
|
this.dx2 = x2;
|
||||||
|
this.dy2 = y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the anchor goes from right to left.
|
||||||
|
*/
|
||||||
|
public boolean isHorizontallyFlipped()
|
||||||
|
{
|
||||||
|
if (col1 == col2)
|
||||||
|
return dx1 > dx2;
|
||||||
|
else
|
||||||
|
return col1 > col2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the anchor goes from bottom to top.
|
||||||
|
*/
|
||||||
|
public boolean isVerticallyFlipped()
|
||||||
|
{
|
||||||
|
if (row1 == row2)
|
||||||
|
return dy1 > dy2;
|
||||||
|
else
|
||||||
|
return row1 > row2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkRange( int value, int minRange, int maxRange, String varName )
|
||||||
|
{
|
||||||
|
if (value < minRange || value > maxRange)
|
||||||
|
throw new IllegalArgumentException(varName + " must be between " + minRange + " and " + maxRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -386,4 +386,12 @@ public class HSSFFont
|
|||||||
{
|
{
|
||||||
return font.getUnderline();
|
return font.getUnderline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "org.apache.poi.hssf.usermodel.HSSFFont{" +
|
||||||
|
font +
|
||||||
|
"}";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,59 @@ public class HSSFPalette
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the closest matching color in the custom palette. The
|
||||||
|
* method for finding the distance between the colors is fairly
|
||||||
|
* primative.
|
||||||
|
*
|
||||||
|
* @param red The red component of the color to match.
|
||||||
|
* @param green The green component of the color to match.
|
||||||
|
* @param blue The blue component of the color to match.
|
||||||
|
* @return The closest color or null if there are no custom
|
||||||
|
* colors currently defined.
|
||||||
|
*/
|
||||||
|
public HSSFColor findSimilarColor(byte red, byte green, byte blue)
|
||||||
|
{
|
||||||
|
HSSFColor result = null;
|
||||||
|
int minColorDistance = Integer.MAX_VALUE;
|
||||||
|
byte[] b = palette.getColor(PaletteRecord.FIRST_COLOR_INDEX);
|
||||||
|
for (short i = (short) PaletteRecord.FIRST_COLOR_INDEX; b != null;
|
||||||
|
b = palette.getColor(++i))
|
||||||
|
{
|
||||||
|
int colorDistance = red - b[0] + green - b[1] + blue - b[2];
|
||||||
|
if (colorDistance < minColorDistance)
|
||||||
|
{
|
||||||
|
result = getColor(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new color into an empty color slot.
|
||||||
|
* @param red The red component
|
||||||
|
* @param green The green component
|
||||||
|
* @param blue The blue component
|
||||||
|
*
|
||||||
|
* @return The new custom color.
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if there are more more free color indexes.
|
||||||
|
*/
|
||||||
|
public HSSFColor addColor( byte red, byte green, byte blue )
|
||||||
|
{
|
||||||
|
byte[] b = palette.getColor(PaletteRecord.FIRST_COLOR_INDEX);
|
||||||
|
short i;
|
||||||
|
for (i = (short) PaletteRecord.FIRST_COLOR_INDEX; i < PaletteRecord.STANDARD_PALETTE_SIZE + PaletteRecord.FIRST_COLOR_INDEX; b = palette.getColor(++i))
|
||||||
|
{
|
||||||
|
if (b == null)
|
||||||
|
{
|
||||||
|
setColorAtIndex( i, red, green, blue );
|
||||||
|
return getColor(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Could not find free color index");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the color at the given offset
|
* Sets the color at the given offset
|
||||||
*
|
*
|
||||||
|
159
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
Normal file
159
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The patriarch is the toplevel container for shapes in a sheet. It does
|
||||||
|
* little other than act as a container for other shapes and groups.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class HSSFPatriarch
|
||||||
|
implements HSSFShapeContainer
|
||||||
|
{
|
||||||
|
List shapes = new ArrayList();
|
||||||
|
HSSFSheet sheet;
|
||||||
|
int x1 = 0;
|
||||||
|
int y1 = 0 ;
|
||||||
|
int x2 = 1023;
|
||||||
|
int y2 = 255;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the patriarch.
|
||||||
|
*
|
||||||
|
* @param sheet the sheet this patriarch is stored in.
|
||||||
|
*/
|
||||||
|
HSSFPatriarch(HSSFSheet sheet)
|
||||||
|
{
|
||||||
|
this.sheet = sheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new group record stored under this patriarch.
|
||||||
|
*
|
||||||
|
* @param anchor the client anchor describes how this group is attached
|
||||||
|
* to the sheet.
|
||||||
|
* @return the newly created group.
|
||||||
|
*/
|
||||||
|
public HSSFShapeGroup createGroup(HSSFClientAnchor anchor)
|
||||||
|
{
|
||||||
|
HSSFShapeGroup group = new HSSFShapeGroup(null, anchor);
|
||||||
|
group.anchor = anchor;
|
||||||
|
shapes.add(group);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a simple shape. This includes such shapes as lines, rectangles,
|
||||||
|
* and ovals.
|
||||||
|
*
|
||||||
|
* @param anchor the client anchor describes how this group is attached
|
||||||
|
* to the sheet.
|
||||||
|
* @return the newly created shape.
|
||||||
|
*/
|
||||||
|
public HSSFSimpleShape createSimpleShape(HSSFClientAnchor anchor)
|
||||||
|
{
|
||||||
|
HSSFSimpleShape shape = new HSSFSimpleShape(null, anchor);
|
||||||
|
shape.anchor = anchor;
|
||||||
|
shapes.add(shape);
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a polygon
|
||||||
|
*
|
||||||
|
* @param anchor the client anchor describes how this group is attached
|
||||||
|
* to the sheet.
|
||||||
|
* @return the newly created shape.
|
||||||
|
*/
|
||||||
|
public HSSFPolygon createPolygon(HSSFClientAnchor anchor)
|
||||||
|
{
|
||||||
|
HSSFPolygon shape = new HSSFPolygon(null, anchor);
|
||||||
|
shape.anchor = anchor;
|
||||||
|
shapes.add(shape);
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a textbox under the patriarch.
|
||||||
|
*
|
||||||
|
* @param anchor the client anchor describes how this group is attached
|
||||||
|
* to the sheet.
|
||||||
|
* @return the newly created textbox.
|
||||||
|
*/
|
||||||
|
public HSSFTextbox createTextbox(HSSFClientAnchor anchor)
|
||||||
|
{
|
||||||
|
HSSFTextbox shape = new HSSFTextbox(null, anchor);
|
||||||
|
shape.anchor = anchor;
|
||||||
|
shapes.add(shape);
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all shapes contained by the patriarch.
|
||||||
|
*/
|
||||||
|
public List getChildren()
|
||||||
|
{
|
||||||
|
return shapes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total count of all children and their children's children.
|
||||||
|
*/
|
||||||
|
public int countOfAllChildren()
|
||||||
|
{
|
||||||
|
int count = shapes.size();
|
||||||
|
for ( Iterator iterator = shapes.iterator(); iterator.hasNext(); )
|
||||||
|
{
|
||||||
|
HSSFShape shape = (HSSFShape) iterator.next();
|
||||||
|
count += shape.countOfAllChildren();
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the coordinate space of this group. All children are contrained
|
||||||
|
* to these coordinates.
|
||||||
|
*/
|
||||||
|
public void setCoordinates( int x1, int y1, int x2, int y2 )
|
||||||
|
{
|
||||||
|
this.x1 = x1;
|
||||||
|
this.y1 = y1;
|
||||||
|
this.x2 = x2;
|
||||||
|
this.y2 = y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The top left x coordinate of this group.
|
||||||
|
*/
|
||||||
|
public int getX1()
|
||||||
|
{
|
||||||
|
return x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The top left y coordinate of this group.
|
||||||
|
*/
|
||||||
|
public int getY1()
|
||||||
|
{
|
||||||
|
return y1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bottom right x coordinate of this group.
|
||||||
|
*/
|
||||||
|
public int getX2()
|
||||||
|
{
|
||||||
|
return x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bottom right y coordinate of this group.
|
||||||
|
*/
|
||||||
|
public int getY2()
|
||||||
|
{
|
||||||
|
return y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
66
src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java
Normal file
66
src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Glen Stampoultzis (glens at superlinksoftware.com)
|
||||||
|
*/
|
||||||
|
public class HSSFPolygon
|
||||||
|
extends HSSFShape
|
||||||
|
{
|
||||||
|
int[] xPoints;
|
||||||
|
int[] yPoints;
|
||||||
|
int drawAreaWidth = 100;
|
||||||
|
int drawAreaHeight = 100;
|
||||||
|
|
||||||
|
HSSFPolygon( HSSFShape parent, HSSFAnchor anchor )
|
||||||
|
{
|
||||||
|
super( parent, anchor );
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getXPoints()
|
||||||
|
{
|
||||||
|
return xPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getYPoints()
|
||||||
|
{
|
||||||
|
return yPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPoints(int[] xPoints, int[] yPoints)
|
||||||
|
{
|
||||||
|
this.xPoints = cloneArray(xPoints);
|
||||||
|
this.yPoints = cloneArray(yPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] cloneArray( int[] a )
|
||||||
|
{
|
||||||
|
int[] result = new int[a.length];
|
||||||
|
for ( int i = 0; i < a.length; i++ )
|
||||||
|
result[i] = a[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the width and height of the points in the polygon
|
||||||
|
* @param width
|
||||||
|
* @param height
|
||||||
|
*/
|
||||||
|
public void setPolygonDrawArea( int width, int height )
|
||||||
|
{
|
||||||
|
this.drawAreaWidth = width;
|
||||||
|
this.drawAreaHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDrawAreaWidth()
|
||||||
|
{
|
||||||
|
return drawAreaWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDrawAreaHeight()
|
||||||
|
{
|
||||||
|
return drawAreaHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
179
src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java
Normal file
179
src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rich text unicode string. These strings can have fonts applied to
|
||||||
|
* arbitary parts of the string.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public class HSSFRichTextString
|
||||||
|
implements Comparable
|
||||||
|
{
|
||||||
|
/** Place holder for indicating that NO_FONT has been applied here */
|
||||||
|
public static final short NO_FONT = -1;
|
||||||
|
|
||||||
|
String string;
|
||||||
|
SortedMap formattingRuns = new TreeMap();
|
||||||
|
|
||||||
|
public HSSFRichTextString()
|
||||||
|
{
|
||||||
|
this("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public HSSFRichTextString( String string )
|
||||||
|
{
|
||||||
|
this.string = string;
|
||||||
|
this.formattingRuns.put(new Integer(0), new Short(NO_FONT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a font to the specified characters of a string.
|
||||||
|
*
|
||||||
|
* @param startIndex The start index to apply the font to (inclusive)
|
||||||
|
* @param endIndex The end index to apply the font to (exclusive)
|
||||||
|
* @param fontIndex The font to use.
|
||||||
|
*/
|
||||||
|
public void applyFont(int startIndex, int endIndex, short fontIndex)
|
||||||
|
{
|
||||||
|
if (startIndex > endIndex)
|
||||||
|
throw new IllegalArgumentException("Start index must be less than end index.");
|
||||||
|
if (startIndex < 0 || endIndex > length())
|
||||||
|
throw new IllegalArgumentException("Start and end index not in range.");
|
||||||
|
if (startIndex == endIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Integer from = new Integer(startIndex);
|
||||||
|
Integer to = new Integer(endIndex);
|
||||||
|
short fontAtIndex = NO_FONT;
|
||||||
|
if (endIndex != length())
|
||||||
|
fontAtIndex = getFontAtIndex(endIndex);
|
||||||
|
formattingRuns.subMap(from, to).clear();
|
||||||
|
formattingRuns.put(from, new Short(fontIndex));
|
||||||
|
if (endIndex != length())
|
||||||
|
{
|
||||||
|
if (fontIndex != fontAtIndex)
|
||||||
|
formattingRuns.put(to, new Short(fontAtIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a font to the specified characters of a string.
|
||||||
|
*
|
||||||
|
* @param startIndex The start index to apply the font to (inclusive)
|
||||||
|
* @param endIndex The end index to apply to font to (exclusive)
|
||||||
|
* @param font The index of the font to use.
|
||||||
|
*/
|
||||||
|
public void applyFont(int startIndex, int endIndex, HSSFFont font)
|
||||||
|
{
|
||||||
|
applyFont(startIndex, endIndex, font.getIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the font of the entire string.
|
||||||
|
* @param font The font to use.
|
||||||
|
*/
|
||||||
|
public void applyFont(HSSFFont font)
|
||||||
|
{
|
||||||
|
applyFont(0, string.length(), font);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the plain string representation.
|
||||||
|
*/
|
||||||
|
public String getString()
|
||||||
|
{
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of characters in the font.
|
||||||
|
*/
|
||||||
|
public int length()
|
||||||
|
{
|
||||||
|
return string.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the font in use at a particular index.
|
||||||
|
*
|
||||||
|
* @param index The index.
|
||||||
|
* @return The font that's currently being applied at that
|
||||||
|
* index or null if no font is being applied or the
|
||||||
|
* index is out of range.
|
||||||
|
*/
|
||||||
|
public short getFontAtIndex( int index )
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= string.length())
|
||||||
|
throw new ArrayIndexOutOfBoundsException("Font index " + index + " out of bounds of string");
|
||||||
|
Integer key = new Integer(index + 1);
|
||||||
|
SortedMap head = formattingRuns.headMap(key);
|
||||||
|
if (head.isEmpty())
|
||||||
|
throw new IllegalStateException("Should not reach here. No font found.");
|
||||||
|
else
|
||||||
|
return ((Short) head.get(head.lastKey())).shortValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The number of formatting runs used. There will always be at
|
||||||
|
* least one of font NO_FONT.
|
||||||
|
*
|
||||||
|
* @see #NO_FONT
|
||||||
|
*/
|
||||||
|
public int numFormattingRuns()
|
||||||
|
{
|
||||||
|
return formattingRuns.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index within the string to which the specified formatting run applies.
|
||||||
|
* @param index the index of the formatting run
|
||||||
|
* @return the index within the string.
|
||||||
|
*/
|
||||||
|
public int getIndexOfFormattingRun(int index)
|
||||||
|
{
|
||||||
|
Map.Entry[] runs = (Map.Entry[]) formattingRuns.entrySet().toArray(new Map.Entry[formattingRuns.size()] );
|
||||||
|
return ((Integer)runs[index].getKey()).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the font used in a particular formatting run.
|
||||||
|
*
|
||||||
|
* @param index the index of the formatting run
|
||||||
|
* @return the font number used.
|
||||||
|
*/
|
||||||
|
public short getFontOfFormattingRun(int index)
|
||||||
|
{
|
||||||
|
Map.Entry[] runs = (Map.Entry[]) formattingRuns.entrySet().toArray(new Map.Entry[formattingRuns.size()] );
|
||||||
|
return ((Short)(runs[index].getValue())).shortValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares one rich text string to another.
|
||||||
|
*/
|
||||||
|
public int compareTo( Object o )
|
||||||
|
{
|
||||||
|
return 0; // todo
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the plain text representation of this string.
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the specified font to the entire string.
|
||||||
|
*
|
||||||
|
* @param fontIndex the font to apply.
|
||||||
|
*/
|
||||||
|
public void applyFont( short fontIndex )
|
||||||
|
{
|
||||||
|
applyFont(0, string.length(), fontIndex);
|
||||||
|
}
|
||||||
|
}
|
195
src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
Normal file
195
src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract shape.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public abstract class HSSFShape
|
||||||
|
{
|
||||||
|
public static final int LINEWIDTH_ONE_PT = 12700;
|
||||||
|
public static final int LINEWIDTH_DEFAULT = 9525;
|
||||||
|
|
||||||
|
public static final int LINESTYLE_SOLID = 0; // Solid (continuous) pen
|
||||||
|
public static final int LINESTYLE_DASHSYS = 1; // PS_DASH system dash style
|
||||||
|
public static final int LINESTYLE_DOTSYS = 2; // PS_DOT system dash style
|
||||||
|
public static final int LINESTYLE_DASHDOTSYS = 3; // PS_DASHDOT system dash style
|
||||||
|
public static final int LINESTYLE_DASHDOTDOTSYS = 4; // PS_DASHDOTDOT system dash style
|
||||||
|
public static final int LINESTYLE_DOTGEL = 5; // square dot style
|
||||||
|
public static final int LINESTYLE_DASHGEL = 6; // dash style
|
||||||
|
public static final int LINESTYLE_LONGDASHGEL = 7; // long dash style
|
||||||
|
public static final int LINESTYLE_DASHDOTGEL = 8; // dash short dash
|
||||||
|
public static final int LINESTYLE_LONGDASHDOTGEL = 9; // long dash short dash
|
||||||
|
public static final int LINESTYLE_LONGDASHDOTDOTGEL = 10; // long dash short dash short dash
|
||||||
|
public static final int LINESTYLE_NONE = -1;
|
||||||
|
|
||||||
|
HSSFShape parent;
|
||||||
|
HSSFAnchor anchor;
|
||||||
|
int lineStyleColor = 0x08000040;
|
||||||
|
int fillColor = 0x08000009;
|
||||||
|
int lineWidth = LINEWIDTH_DEFAULT; // 12700 = 1pt
|
||||||
|
int lineStyle = LINESTYLE_SOLID;
|
||||||
|
boolean noFill = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new shape with the specified parent and anchor.
|
||||||
|
*/
|
||||||
|
HSSFShape( HSSFShape parent, HSSFAnchor anchor )
|
||||||
|
{
|
||||||
|
this.parent = parent;
|
||||||
|
this.anchor = anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parent shape.
|
||||||
|
*/
|
||||||
|
public HSSFShape getParent()
|
||||||
|
{
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the anchor that is used by this shape.
|
||||||
|
*/
|
||||||
|
public HSSFAnchor getAnchor()
|
||||||
|
{
|
||||||
|
return anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a particular anchor. A top-level shape must have an anchor of
|
||||||
|
* HSSFClientAnchor. A child anchor must have an anchor of HSSFChildAnchor
|
||||||
|
*
|
||||||
|
* @param anchor the anchor to use.
|
||||||
|
* @throws IllegalArgumentException when the wrong anchor is used for
|
||||||
|
* this particular shape.
|
||||||
|
*
|
||||||
|
* @see HSSFChildAnchor
|
||||||
|
* @see HSSFClientAnchor
|
||||||
|
*/
|
||||||
|
public void setAnchor( HSSFAnchor anchor )
|
||||||
|
{
|
||||||
|
if ( parent == null )
|
||||||
|
{
|
||||||
|
if ( anchor instanceof HSSFChildAnchor )
|
||||||
|
throw new IllegalArgumentException( "Must use client anchors for shapes directly attached to sheet." );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( anchor instanceof HSSFClientAnchor )
|
||||||
|
throw new IllegalArgumentException( "Must use child anchors for shapes attached to groups." );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.anchor = anchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color applied to the lines of this shape.
|
||||||
|
*/
|
||||||
|
public int getLineStyleColor()
|
||||||
|
{
|
||||||
|
return lineStyleColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color applied to the lines of this shape.
|
||||||
|
*/
|
||||||
|
public void setLineStyleColor( int lineStyleColor )
|
||||||
|
{
|
||||||
|
this.lineStyleColor = lineStyleColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color applied to the lines of this shape.
|
||||||
|
*/
|
||||||
|
public void setLineStyleColor( int red, int green, int blue )
|
||||||
|
{
|
||||||
|
this.lineStyleColor = ((blue) << 16) | ((green) << 8) | red;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color used to fill this shape.
|
||||||
|
*/
|
||||||
|
public int getFillColor()
|
||||||
|
{
|
||||||
|
return fillColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color used to fill this shape.
|
||||||
|
*/
|
||||||
|
public void setFillColor( int fillColor )
|
||||||
|
{
|
||||||
|
this.fillColor = fillColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color used to fill this shape.
|
||||||
|
*/
|
||||||
|
public void setFillColor( int red, int green, int blue )
|
||||||
|
{
|
||||||
|
this.fillColor = ((blue) << 16) | ((green) << 8) | red;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return returns with width of the line in EMUs. 12700 = 1 pt.
|
||||||
|
*/
|
||||||
|
public int getLineWidth()
|
||||||
|
{
|
||||||
|
return lineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the width of the line. 12700 = 1 pt.
|
||||||
|
*
|
||||||
|
* @param lineWidth width in EMU's. 12700EMU's = 1 pt
|
||||||
|
*
|
||||||
|
* @see HSSFShape#LINEWIDTH_ONE_PT
|
||||||
|
*/
|
||||||
|
public void setLineWidth( int lineWidth )
|
||||||
|
{
|
||||||
|
this.lineWidth = lineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return One of the constants in LINESTYLE_*
|
||||||
|
*/
|
||||||
|
public int getLineStyle()
|
||||||
|
{
|
||||||
|
return lineStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the line style.
|
||||||
|
*
|
||||||
|
* @param lineStyle One of the constants in LINESTYLE_*
|
||||||
|
*/
|
||||||
|
public void setLineStyle( int lineStyle )
|
||||||
|
{
|
||||||
|
this.lineStyle = lineStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this shape is not filled with a color.
|
||||||
|
*/
|
||||||
|
public boolean isNoFill()
|
||||||
|
{
|
||||||
|
return noFill;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this shape is filled or transparent.
|
||||||
|
*/
|
||||||
|
public void setNoFill( boolean noFill )
|
||||||
|
{
|
||||||
|
this.noFill = noFill;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count of all children and their childrens children.
|
||||||
|
*/
|
||||||
|
public int countOfAllChildren()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package org.apache.poi.hssf.usermodel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that indicates whether a class can contain children.
|
||||||
|
*
|
||||||
|
* @author Glen Stampoultzis (glens at apache.org)
|
||||||
|
*/
|
||||||
|
public interface HSSFShapeContainer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return Any children contained by this shape.
|
||||||
|
*/
|
||||||
|
List getChildren();
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user