Bugzilla 53010, patch from June 3: improved support for Continue records in drawing blocks
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/gsoc2012@1345858 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4f20669925
commit
d3f4e26985
@ -1508,31 +1508,10 @@ public final class InternalSheet {
|
||||
return loc;
|
||||
}
|
||||
List<RecordBase> 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 ||
|
||||
records.get( loc + 1 ) instanceof TextObjectRecord) )
|
||||
{
|
||||
loc += 2;
|
||||
if (records.get( loc ) instanceof NoteRecord) loc ++;
|
||||
while ( loc + 1 < records.size()
|
||||
&& records.get( loc ) instanceof ContinueRecord
|
||||
&& (records.get( loc + 1 ) instanceof ObjRecord ||
|
||||
records.get( loc + 1 ) instanceof TextObjectRecord) )
|
||||
{
|
||||
loc += 2;
|
||||
if (records.get( loc ) instanceof NoteRecord) loc ++;
|
||||
}
|
||||
}
|
||||
|
||||
int endloc = loc-1;
|
||||
for(int i = 0; i < (endloc - startloc + 1); i++)
|
||||
records.remove(startloc);
|
||||
records.add(startloc, r);
|
||||
EscherAggregate.createAggregate( records, loc, drawingManager );
|
||||
|
||||
return startloc;
|
||||
return loc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,6 @@ package org.apache.poi.hssf.record;
|
||||
import org.apache.poi.util.LittleEndianOutput;
|
||||
/**
|
||||
* DrawingRecord (0x00EC)<p/>
|
||||
*
|
||||
*/
|
||||
public final class DrawingRecord extends StandardRecord {
|
||||
public static final short sid = 0x00EC;
|
||||
@ -46,6 +45,7 @@ public final class DrawingRecord extends StandardRecord {
|
||||
public void serialize(LittleEndianOutput out) {
|
||||
out.write(recordData);
|
||||
}
|
||||
|
||||
protected int getDataSize() {
|
||||
return recordData.length;
|
||||
}
|
||||
@ -55,12 +55,12 @@ public final class DrawingRecord extends StandardRecord {
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
if(contd != null) {
|
||||
byte[] newBuffer = new byte[ recordData.length + contd.length ];
|
||||
System.arraycopy( recordData, 0, newBuffer, 0, recordData.length );
|
||||
System.arraycopy( contd, 0, newBuffer, recordData.length, contd.length);
|
||||
return newBuffer;
|
||||
}
|
||||
// if (continueData.size() != 0) {
|
||||
// byte[] newBuffer = new byte[recordData.length + continueData.size()];
|
||||
// System.arraycopy(recordData, 0, newBuffer, 0, recordData.length);
|
||||
// System.arraycopy(continueData.toByteArray(), 0, newBuffer, recordData.length, continueData.size());
|
||||
// return newBuffer;
|
||||
// }
|
||||
return recordData;
|
||||
}
|
||||
|
||||
@ -77,7 +77,6 @@ public final class DrawingRecord extends StandardRecord {
|
||||
|
||||
public Object clone() {
|
||||
DrawingRecord rec = new DrawingRecord();
|
||||
|
||||
rec.recordData = recordData.clone();
|
||||
if (contd != null) {
|
||||
// TODO - this code probably never executes
|
||||
|
@ -17,11 +17,9 @@
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.poi.ddf.DefaultEscherRecordFactory;
|
||||
import org.apache.poi.ddf.EscherBoolProperty;
|
||||
@ -65,16 +63,43 @@ import org.apache.poi.util.POILogger;
|
||||
* combination of MSODRAWING -> OBJ -> MSODRAWING -> OBJ records
|
||||
* but the escher records are serialized _across_ the MSODRAWING
|
||||
* records.
|
||||
* <p>
|
||||
* <p/>
|
||||
* It gets even worse when you start looking at TXO records.
|
||||
* <p>
|
||||
* <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.
|
||||
* <p/>
|
||||
* At first document contains 4 types of records which belong to drawing layer.
|
||||
* There are can be such sequence of record:
|
||||
* <p/>
|
||||
* DrawingRecord
|
||||
* ContinueRecord
|
||||
* ...
|
||||
* ContinueRecord
|
||||
* ObjRecord | TextObjectRecord
|
||||
* .....
|
||||
* ContinueRecord
|
||||
* ...
|
||||
* ContinueRecord
|
||||
* ObjRecord | TextObjectRecord
|
||||
* NoteRecord
|
||||
* ...
|
||||
* NoteRecord
|
||||
* <p/>
|
||||
* To work with shapes we have to read data from Drawing and Continue records into single array of bytes and
|
||||
* build escher(office art) records tree from this array.
|
||||
* Each shape in drawing layer matches corresponding ObjRecord
|
||||
* Each textbox matches corresponding TextObjectRecord
|
||||
*
|
||||
* ObjRecord contains information about shape. Thus each ObjRecord corresponds EscherContainerRecord(SPGR)
|
||||
*
|
||||
* EscherAggrefate contains also NoteRecords
|
||||
* NoteRecords must be serial
|
||||
*
|
||||
* @author Glen Stampoultzis (glens at apache.org)
|
||||
*/
|
||||
|
||||
public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
public static final short sid = 9876; // not a real sid - dummy value
|
||||
private static POILogger log = POILogFactory.getLogger(EscherAggregate.class);
|
||||
@ -287,8 +312,10 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
|
||||
protected HSSFPatriarch patriarch;
|
||||
|
||||
/** Maps shape container objects to their {@link TextObjectRecord} or {@link ObjRecord} */
|
||||
Map<EscherRecord, Record> shapeToObj = new HashMap<EscherRecord, Record>();
|
||||
/**
|
||||
* Maps shape container objects to their {@link TextObjectRecord} or {@link ObjRecord}
|
||||
*/
|
||||
private final Map<EscherRecord, Record> shapeToObj = new HashMap<EscherRecord, Record>();
|
||||
private DrawingManager2 drawingManager;
|
||||
private short drawingGroupId;
|
||||
|
||||
@ -297,16 +324,14 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
*/
|
||||
private List tailRec = new ArrayList();
|
||||
|
||||
public EscherAggregate( DrawingManager2 drawingManager )
|
||||
{
|
||||
public EscherAggregate(DrawingManager2 drawingManager) {
|
||||
this.drawingManager = drawingManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the current sid.
|
||||
*/
|
||||
public short getSid()
|
||||
{
|
||||
public short getSid() {
|
||||
return sid;
|
||||
}
|
||||
|
||||
@ -314,14 +339,12 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
* Calculates the string representation of this record. This is
|
||||
* simply a dump of all the records.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
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(); )
|
||||
{
|
||||
for (Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); ) {
|
||||
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||||
result.append(escherRecord.toString());
|
||||
}
|
||||
@ -333,8 +356,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
public String toXml(String tab) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(tab).append("<").append(getRecordName()).append(">\n");
|
||||
for ( Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
for (Iterator iterator = getEscherRecords().iterator(); iterator.hasNext(); ) {
|
||||
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||||
builder.append(escherRecord.toXml(tab + "\t"));
|
||||
}
|
||||
@ -342,103 +364,97 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static boolean isDrawingLayerRecord(final short sid) {
|
||||
return sid == DrawingRecord.sid ||
|
||||
sid == ContinueRecord.sid ||
|
||||
sid == ObjRecord.sid ||
|
||||
sid == TextObjectRecord.sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapses the drawing records into an aggregate.
|
||||
* read Drawing and Continue records into single byte array, create Escher tree from byte array, create map <EscherRecord, Record>
|
||||
*/
|
||||
public static EscherAggregate createAggregate( List records, int locFirstDrawingRecord, DrawingManager2 drawingManager )
|
||||
{
|
||||
public static EscherAggregate createAggregate(List records, int locFirstDrawingRecord, DrawingManager2 drawingManager) {
|
||||
// Keep track of any shape records created so we can match them back to the object id's.
|
||||
// Textbox objects are also treated as shape objects.
|
||||
final List<EscherRecord> shapeRecords = new ArrayList<EscherRecord>();
|
||||
EscherRecordFactory recordFactory = new DefaultEscherRecordFactory()
|
||||
{
|
||||
public EscherRecord createRecord( byte[] data, int offset )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
if (r.getRecordId() == EscherClientDataRecord.RECORD_ID || r.getRecordId() == EscherTextboxRecord.RECORD_ID) {
|
||||
shapeRecords.add(r);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
// Calculate the size of the buffer
|
||||
// Create one big buffer
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
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 ) ).getRecordData().length;
|
||||
loc += 2;
|
||||
while ( loc + 1 < records.size()
|
||||
&& sid( records, loc ) == ContinueRecord.sid
|
||||
&& isObjectRecord( records, loc + 1 ) )
|
||||
{
|
||||
dataSize += ( (ContinueRecord) records.get( loc ) ).getData().length;
|
||||
loc += 2;
|
||||
&& (isDrawingLayerRecord(sid(records, loc)))) {
|
||||
try {
|
||||
if (!(sid(records, loc) == DrawingRecord.sid || sid(records, loc) == ContinueRecord.sid)) {
|
||||
loc++;
|
||||
continue;
|
||||
}
|
||||
if (sid(records, loc) == DrawingRecord.sid) {
|
||||
buffer.write(((DrawingRecord) records.get(loc)).getRecordData());
|
||||
} else {
|
||||
buffer.write(((ContinueRecord) records.get(loc)).getData());
|
||||
}
|
||||
|
||||
// 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.getRecordData(), 0, buffer, offset, drawingRecord.getRecordData().length );
|
||||
offset += drawingRecord.getRecordData().length;
|
||||
loc += 2;
|
||||
while ( loc + 1 < records.size()
|
||||
&& sid( records, loc ) == ContinueRecord.sid
|
||||
&& isObjectRecord( records, loc + 1 ) )
|
||||
{
|
||||
ContinueRecord continueRecord = (ContinueRecord) records.get( loc );
|
||||
System.arraycopy( continueRecord.getData(), 0, buffer, offset, continueRecord.getData().length );
|
||||
offset += continueRecord.getData().length;
|
||||
loc += 2;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Couldn't get data from drawing/continue records", e);
|
||||
}
|
||||
loc++;
|
||||
}
|
||||
|
||||
// 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 );
|
||||
while (pos < buffer.size()) {
|
||||
EscherRecord r = recordFactory.createRecord(buffer.toByteArray(), pos);
|
||||
int bytesRead = r.fillFields(buffer.toByteArray(), pos, recordFactory);
|
||||
agg.addEscherRecord(r);
|
||||
pos += bytesRead;
|
||||
}
|
||||
|
||||
// Associate the object records with the shapes
|
||||
loc = locFirstDrawingRecord;
|
||||
loc = locFirstDrawingRecord + 1;
|
||||
int shapeIndex = 0;
|
||||
agg.shapeToObj = new HashMap<EscherRecord, Record>();
|
||||
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;
|
||||
while ( loc + 1 < records.size()
|
||||
&& sid( records, loc ) == ContinueRecord.sid
|
||||
&& isObjectRecord( records, loc + 1 ) )
|
||||
{
|
||||
objRecord = (Record) records.get( loc + 1 );
|
||||
agg.shapeToObj.put( shapeRecords.get( shapeIndex++ ), objRecord );
|
||||
loc += 2;
|
||||
while (loc < records.size()
|
||||
&& (isDrawingLayerRecord(sid(records, loc)))) {
|
||||
if (!isObjectRecord(records, loc)) {
|
||||
loc++;
|
||||
continue;
|
||||
}
|
||||
Record objRecord = (Record) records.get(loc);
|
||||
agg.shapeToObj.put(shapeRecords.get(shapeIndex++), objRecord);
|
||||
loc++;
|
||||
}
|
||||
|
||||
// any NoteRecords that follow the drawing block must be aggregated and and saved in the tailRec collection
|
||||
// TODO remove this logic. 'tail' records should be inserted in the main record stream
|
||||
while (loc < records.size()) {
|
||||
if (sid(records, loc) == NoteRecord.sid) {
|
||||
NoteRecord r = (NoteRecord) records.get(loc);
|
||||
agg.tailRec.add(r);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
loc++;
|
||||
}
|
||||
|
||||
int locLastDrawingRecord = loc;
|
||||
// replace drawing block with the created EscherAggregate
|
||||
records.subList(locFirstDrawingRecord, locLastDrawingRecord).clear();
|
||||
records.add(locFirstDrawingRecord, agg);
|
||||
|
||||
|
||||
return agg;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -449,8 +465,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
* @param data The byte array to serialize to.
|
||||
* @return The number of bytes serialized.
|
||||
*/
|
||||
public int serialize( int offset, byte[] data )
|
||||
{
|
||||
public int serialize(int offset, byte[] data) {
|
||||
convertUserModelToRecords();
|
||||
|
||||
// Determine buffer size
|
||||
@ -463,19 +478,14 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
final List spEndingOffsets = new ArrayList();
|
||||
final List shapes = new ArrayList();
|
||||
int pos = 0;
|
||||
for ( Iterator iterator = records.iterator(); iterator.hasNext(); )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
public void afterRecordSerialize(int offset, short recordId, int size, EscherRecord record) {
|
||||
if (recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID) {
|
||||
spEndingOffsets.add(Integer.valueOf(offset));
|
||||
shapes.add(record);
|
||||
}
|
||||
@ -489,8 +499,8 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
// 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 writtenEscherBytes = 0;
|
||||
for (int i = 1; i < shapes.size(); i++) {
|
||||
int endOffset = ((Integer) spEndingOffsets.get(i)).intValue() - 1;
|
||||
int startOffset;
|
||||
if (i == 1)
|
||||
@ -498,13 +508,33 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
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 );
|
||||
int temp = 0;
|
||||
|
||||
//First record in drawing layer MUST be DrawingRecord
|
||||
if (writtenEscherBytes + drawingData.length > RecordInputStream.MAX_RECORD_DATA_SIZE && i != 1) {
|
||||
for (int j = 0; j < drawingData.length; j += RecordInputStream.MAX_RECORD_DATA_SIZE) {
|
||||
ContinueRecord drawing = new ContinueRecord(Arrays.copyOfRange(drawingData, j, Math.min(j + RecordInputStream.MAX_RECORD_DATA_SIZE, drawingData.length)));
|
||||
temp += drawing.serialize(pos + temp, data);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < drawingData.length; j += RecordInputStream.MAX_RECORD_DATA_SIZE) {
|
||||
if (j == 0) {
|
||||
DrawingRecord drawing = new DrawingRecord();
|
||||
drawing.setData(Arrays.copyOfRange(drawingData, j, Math.min(j + RecordInputStream.MAX_RECORD_DATA_SIZE, drawingData.length)));
|
||||
temp += drawing.serialize(pos + temp, data);
|
||||
} else {
|
||||
ContinueRecord drawing = new ContinueRecord(Arrays.copyOfRange(drawingData, j, Math.min(j + RecordInputStream.MAX_RECORD_DATA_SIZE, drawingData.length)));
|
||||
temp += drawing.serialize(pos + temp, data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pos += temp;
|
||||
writtenEscherBytes += drawingData.length;
|
||||
|
||||
// Write the matching OBJ record
|
||||
Record obj = shapeToObj.get(shapes.get(i));
|
||||
@ -514,8 +544,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
}
|
||||
|
||||
// write records that need to be serialized after all drawing group records
|
||||
for ( int i = 0; i < tailRec.size(); i++ )
|
||||
{
|
||||
for (int i = 0; i < tailRec.size(); i++) {
|
||||
Record rec = (Record) tailRec.get(i);
|
||||
pos += rec.serialize(pos, data);
|
||||
}
|
||||
@ -528,11 +557,11 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
private int getEscherRecordSize(List records) {
|
||||
int size = 0;
|
||||
for (Iterator iterator = records.iterator(); iterator.hasNext(); )
|
||||
size += ((EscherRecord) iterator.next()).getRecordSize();
|
||||
@ -542,39 +571,62 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
public int getRecordSize() {
|
||||
// TODO - convert this to RecordAggregate
|
||||
convertUserModelToRecords();
|
||||
List records = getEscherRecords();
|
||||
// To determine size of aggregate record we have to know size of each DrawingRecord because if DrawingRecord
|
||||
// is split into several continue records we have to add header size to total EscherAggregate size
|
||||
int continueRecordsHeadersSize = 0;
|
||||
// Determine buffer size
|
||||
List<EscherRecord> records = getEscherRecords();
|
||||
int rawEscherSize = getEscherRecordSize(records);
|
||||
byte[] buffer = new byte[rawEscherSize];
|
||||
final List<Integer> spEndingOffsets = new ArrayList<Integer>();
|
||||
int pos = 0;
|
||||
for (EscherRecord e : records) {
|
||||
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(offset);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
spEndingOffsets.add(0, 0);
|
||||
|
||||
for (int i = 1; i < spEndingOffsets.size(); i++) {
|
||||
if (spEndingOffsets.get(i) - spEndingOffsets.get(i - 1) <= RecordInputStream.MAX_RECORD_DATA_SIZE){
|
||||
continue;
|
||||
}
|
||||
continueRecordsHeadersSize += ((spEndingOffsets.get(i) - spEndingOffsets.get(i - 1)) / RecordInputStream.MAX_RECORD_DATA_SIZE)*4;
|
||||
}
|
||||
|
||||
int drawingRecordSize = rawEscherSize + (shapeToObj.size()) * 4;
|
||||
int objRecordSize = 0;
|
||||
for ( Iterator iterator = shapeToObj.values().iterator(); iterator.hasNext(); )
|
||||
{
|
||||
for (Iterator iterator = shapeToObj.values().iterator(); iterator.hasNext(); ) {
|
||||
Record r = (Record) iterator.next();
|
||||
objRecordSize += r.getRecordSize();
|
||||
}
|
||||
int tailRecordSize = 0;
|
||||
for ( Iterator iterator = tailRec.iterator(); iterator.hasNext(); )
|
||||
{
|
||||
for (Iterator iterator = tailRec.iterator(); iterator.hasNext(); ) {
|
||||
Record r = (Record) iterator.next();
|
||||
tailRecordSize += r.getRecordSize();
|
||||
}
|
||||
return drawingRecordSize + objRecordSize + tailRecordSize;
|
||||
return drawingRecordSize + objRecordSize + tailRecordSize +continueRecordsHeadersSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates an escher record to an OBJ record or a TXO record.
|
||||
*/
|
||||
Object associateShapeToObjRecord( EscherRecord r, ObjRecord objRecord )
|
||||
{
|
||||
Object associateShapeToObjRecord(EscherRecord r, ObjRecord objRecord) {
|
||||
return shapeToObj.put(r, objRecord);
|
||||
}
|
||||
|
||||
public HSSFPatriarch getPatriarch()
|
||||
{
|
||||
public HSSFPatriarch getPatriarch() {
|
||||
return patriarch;
|
||||
}
|
||||
|
||||
public void setPatriarch( HSSFPatriarch patriarch )
|
||||
{
|
||||
public void setPatriarch(HSSFPatriarch patriarch) {
|
||||
this.patriarch = patriarch;
|
||||
}
|
||||
|
||||
@ -642,12 +694,10 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
EscherContainerRecord shapeContainer = (EscherContainerRecord) tcc.get(i);
|
||||
|
||||
// Could be a group, or a base object
|
||||
if (shapeContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER)
|
||||
{
|
||||
if (shapeContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
|
||||
// Group
|
||||
final int shapeChildren = shapeContainer.getChildRecords().size();
|
||||
if (shapeChildren > 0)
|
||||
{
|
||||
if (shapeChildren > 0) {
|
||||
HSSFShapeGroup group = new HSSFShapeGroup(parent, new HSSFClientAnchor());
|
||||
addToParentOrContainer(group, container, parent);
|
||||
|
||||
@ -657,20 +707,17 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
if (shapeChildren > 1) {
|
||||
convertRecordsToUserModelRecursive(shapeContainer.getChildRecords(), container, group);
|
||||
}
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
log.log(POILogger.WARN,
|
||||
"Found drawing group without children.");
|
||||
}
|
||||
|
||||
} else if (shapeContainer.getRecordId() == EscherContainerRecord.SP_CONTAINER)
|
||||
{
|
||||
} else if (shapeContainer.getRecordId() == EscherContainerRecord.SP_CONTAINER) {
|
||||
EscherSpRecord spRecord = shapeContainer
|
||||
.getChildById(EscherSpRecord.RECORD_ID);
|
||||
int type = spRecord.getShapeType();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
switch (type) {
|
||||
case ST_TEXTBOX:
|
||||
HSSFTextbox box = new HSSFTextbox(parent,
|
||||
new HSSFClientAnchor());
|
||||
@ -685,12 +732,10 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
shapeContainer, EscherOptRecord.RECORD_ID);
|
||||
EscherSimpleProperty prop = (EscherSimpleProperty) opt.lookup(
|
||||
EscherProperties.BLIP__BLIPTODISPLAY);
|
||||
if (prop == null)
|
||||
{
|
||||
if (prop == null) {
|
||||
log.log(POILogger.WARN,
|
||||
"Picture index for picture shape not found.");
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
int pictureIndex = prop.getPropertyValue();
|
||||
|
||||
EscherClientAnchorRecord anchorRecord = (EscherClientAnchorRecord) getEscherChild(
|
||||
@ -728,8 +773,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
+ type);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
log.log(POILogger.WARN, "Unexpected record id of shape group.");
|
||||
}
|
||||
|
||||
@ -790,8 +834,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
} else {
|
||||
throw new IllegalStateException("Got top level anchor but not processing a group");
|
||||
}
|
||||
}
|
||||
else if(r instanceof EscherClientAnchorRecord) {
|
||||
} else if (r instanceof EscherClientAnchorRecord) {
|
||||
EscherClientAnchorRecord car = (EscherClientAnchorRecord) r;
|
||||
|
||||
if (model instanceof HSSFShape) {
|
||||
@ -803,57 +846,47 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
} else {
|
||||
throw new IllegalStateException("Got top level anchor but not processing a group or shape");
|
||||
}
|
||||
}
|
||||
else if(r instanceof EscherTextboxRecord) {
|
||||
} else if (r instanceof EscherTextboxRecord) {
|
||||
EscherTextboxRecord tbr = (EscherTextboxRecord) r;
|
||||
|
||||
// Also need to find the TextObjectRecord too
|
||||
// TODO
|
||||
}
|
||||
else if(r instanceof EscherSpRecord) {
|
||||
} else if (r instanceof EscherSpRecord) {
|
||||
// Use flags if needed
|
||||
final EscherSpRecord spr = (EscherSpRecord) r;
|
||||
if (model instanceof HSSFShape) {
|
||||
final HSSFShape s = (HSSFShape) model;
|
||||
}
|
||||
}
|
||||
else if(r instanceof EscherOptRecord) {
|
||||
} else if (r instanceof EscherOptRecord) {
|
||||
// Use properties if needed
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//System.err.println(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
public void clear() {
|
||||
clearEscherRecords();
|
||||
shapeToObj.clear();
|
||||
// lastShapeId = 1024;
|
||||
}
|
||||
|
||||
protected String getRecordName()
|
||||
{
|
||||
protected String getRecordName() {
|
||||
return "ESCHERAGGREGATE";
|
||||
}
|
||||
|
||||
// =============== Private methods ========================
|
||||
|
||||
private static boolean isObjectRecord( List records, int loc )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
private void convertUserModelToRecords() {
|
||||
if (patriarch != null) {
|
||||
shapeToObj.clear();
|
||||
tailRec.clear();
|
||||
clearEscherRecords();
|
||||
if ( patriarch.getChildren().size() != 0 )
|
||||
{
|
||||
if (patriarch.getChildren().size() != 0) {
|
||||
convertPatriarch(patriarch);
|
||||
EscherContainerRecord dgContainer = (EscherContainerRecord) getEscherRecord(0);
|
||||
EscherContainerRecord spgrContainer = null;
|
||||
@ -871,26 +904,20 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
}
|
||||
}
|
||||
|
||||
private void convertShapes( HSSFShapeContainer parent, EscherContainerRecord escherParent, Map shapeToObj )
|
||||
{
|
||||
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(); )
|
||||
{
|
||||
for (Iterator iterator = shapes.iterator(); iterator.hasNext(); ) {
|
||||
HSSFShape shape = (HSSFShape) iterator.next();
|
||||
if ( shape instanceof HSSFShapeGroup )
|
||||
{
|
||||
if (shape instanceof HSSFShapeGroup) {
|
||||
convertGroup((HSSFShapeGroup) shape, escherParent, shapeToObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
AbstractShape shapeModel = AbstractShape.createShape(
|
||||
shape,
|
||||
drawingManager.allocateShapeId(drawingGroupId));
|
||||
shapeToObj.put(findClientData(shapeModel.getSpContainer()), shapeModel.getObjRecord());
|
||||
if ( shapeModel instanceof TextboxShape )
|
||||
{
|
||||
if (shapeModel instanceof TextboxShape) {
|
||||
EscherRecord escherTextbox = ((TextboxShape) shapeModel).getEscherTextbox();
|
||||
shapeToObj.put(escherTextbox, ((TextboxShape) shapeModel).getTextObjectRecord());
|
||||
// escherParent.addChildRecord(escherTextbox);
|
||||
@ -909,8 +936,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
|
||||
}
|
||||
|
||||
private void convertGroup( HSSFShapeGroup shape, EscherContainerRecord escherParent, Map shapeToObj )
|
||||
{
|
||||
private void convertGroup(HSSFShapeGroup shape, EscherContainerRecord escherParent, Map shapeToObj) {
|
||||
EscherContainerRecord spgrContainer = new EscherContainerRecord();
|
||||
EscherContainerRecord spContainer = new EscherContainerRecord();
|
||||
EscherSpgrRecord spgr = new EscherSpgrRecord();
|
||||
@ -982,8 +1008,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
|
||||
}
|
||||
|
||||
private EscherRecord findClientData( EscherContainerRecord spContainer )
|
||||
{
|
||||
private EscherRecord findClientData(EscherContainerRecord spContainer) {
|
||||
for (Iterator<EscherRecord> iterator = spContainer.getChildIterator(); iterator.hasNext(); ) {
|
||||
EscherRecord r = iterator.next();
|
||||
if (r.getRecordId() == EscherClientDataRecord.RECORD_ID) {
|
||||
@ -993,8 +1018,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
throw new IllegalArgumentException("Can not find client data record");
|
||||
}
|
||||
|
||||
private void convertPatriarch( HSSFPatriarch patriarch )
|
||||
{
|
||||
private void convertPatriarch(HSSFPatriarch patriarch) {
|
||||
EscherContainerRecord dgContainer = new EscherContainerRecord();
|
||||
EscherDgRecord dg;
|
||||
EscherContainerRecord spgrContainer = new EscherContainerRecord();
|
||||
@ -1034,8 +1058,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
}
|
||||
|
||||
|
||||
private static short sid( List records, int loc )
|
||||
{
|
||||
private static short sid(List records, int loc) {
|
||||
return ((Record) records.get(loc)).getSid();
|
||||
}
|
||||
|
||||
@ -1048,11 +1071,9 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
|
||||
* @return escher record or <code>null</code> if not found.
|
||||
*/
|
||||
private static EscherRecord getEscherChild(EscherContainerRecord owner,
|
||||
int recordId)
|
||||
{
|
||||
int recordId) {
|
||||
for (Iterator iterator = owner.getChildRecords().iterator(); iterator
|
||||
.hasNext();)
|
||||
{
|
||||
.hasNext(); ) {
|
||||
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||||
if (escherRecord.getRecordId() == recordId)
|
||||
return escherRecord;
|
||||
|
@ -341,8 +341,8 @@ public final class RecordFactoryInputStream {
|
||||
return null;
|
||||
}
|
||||
if (_lastRecord instanceof DrawingRecord) {
|
||||
((DrawingRecord) _lastRecord).processContinueRecord(contRec.getData());
|
||||
return null;
|
||||
// ((DrawingRecord) _lastRecord).appendContinueRecord(contRec.getData());
|
||||
return contRec;
|
||||
}
|
||||
if (_lastRecord instanceof UnknownRecord) {
|
||||
//Gracefully handle records that we don't know about,
|
||||
|
@ -17,11 +17,7 @@
|
||||
package org.apache.poi.hssf.model;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.poi.ddf.EscherClientDataRecord;
|
||||
import org.apache.poi.ddf.EscherContainerRecord;
|
||||
import org.apache.poi.ddf.EscherDggRecord;
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
import org.apache.poi.ddf.EscherSpRecord;
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.hssf.record.*;
|
||||
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
||||
@ -30,124 +26,26 @@ import org.apache.poi.hssf.usermodel.HSSFTestHelper;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.util.HexRead;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Yegor Kozlov
|
||||
* @author Evgeniy Berlog
|
||||
*/
|
||||
public class TestDrawingAggregate extends TestCase {
|
||||
/**
|
||||
* Serialize escher aggregate, read back and assert that the drawing data is preserved.
|
||||
*
|
||||
* @param agg the aggregate to test
|
||||
* @return verified aggregate (serialized and read back)
|
||||
*/
|
||||
public static EscherAggregate assertWriteAndReadBack(EscherAggregate agg) {
|
||||
byte[] dgBytes = agg.serialize();
|
||||
|
||||
|
||||
List<Record> dgRecords = RecordFactory.createRecords(new ByteArrayInputStream(dgBytes));
|
||||
|
||||
DrawingManager2 drawingManager = new DrawingManager2(new EscherDggRecord());
|
||||
|
||||
// create a dummy sheet consisting of our test data
|
||||
InternalSheet sheet = InternalSheet.createSheet();
|
||||
List<RecordBase> records = sheet.getRecords();
|
||||
records.clear();
|
||||
records.addAll(dgRecords);
|
||||
records.add(EOFRecord.instance);
|
||||
|
||||
|
||||
sheet.aggregateDrawingRecords(drawingManager, false);
|
||||
assertEquals("drawing was not fully aggregated", 2, records.size());
|
||||
assertTrue("expected EscherAggregate", records.get(0) instanceof EscherAggregate);
|
||||
assertTrue("expected EOFRecord", records.get(1) instanceof EOFRecord);
|
||||
EscherAggregate agg2 = (EscherAggregate) records.get(0);
|
||||
|
||||
assertEquals(agg.getEscherRecords().size(), agg2.getEscherRecords().size());
|
||||
|
||||
// assert that both pre- and after- serialize aggregates have the same xml representation
|
||||
for (int i = 0; i < agg.getEscherRecords().size(); i++) {
|
||||
EscherRecord r1 = agg.getEscherRecords().get(i);
|
||||
EscherRecord r2 = agg2.getEscherRecords().get(i);
|
||||
|
||||
assertEquals(r1.toXml(), r2.toXml());
|
||||
}
|
||||
|
||||
return agg2;
|
||||
}
|
||||
|
||||
/**
|
||||
* assert that mapping of Obj records to escher shape containers is the same in both aggregates
|
||||
*/
|
||||
public static void assertObjectMappingSame(EscherAggregate agg1, EscherAggregate agg2) {
|
||||
|
||||
// map EscherClientDataRecord and EscherTextboxRecord to their parents
|
||||
Map<EscherRecord, EscherContainerRecord> map1 = new LinkedHashMap<EscherRecord, EscherContainerRecord>();
|
||||
for (EscherRecord r : agg1.getEscherRecords()) mapShapeContainers(r, map1);
|
||||
|
||||
Map<EscherRecord, EscherContainerRecord> map2 = new LinkedHashMap<EscherRecord, EscherContainerRecord>();
|
||||
for (EscherRecord r : agg2.getEscherRecords()) mapShapeContainers(r, map2);
|
||||
|
||||
assertEquals("aggregates have different number of shapes", map1.size(), map2.size());
|
||||
|
||||
// for each EscherClientDataRecord get parent SP_CONTAINER and corresponding ObjRecord
|
||||
// verify that ObjRecord to
|
||||
List<EscherRecord> l1 = new ArrayList<EscherRecord>(map1.keySet());
|
||||
List<EscherRecord> l2 = new ArrayList<EscherRecord>(map2.keySet());
|
||||
for (int i = 0; i < l1.size(); i++) {
|
||||
EscherRecord e1 = l1.get(i);
|
||||
EscherRecord e2 = l2.get(i);
|
||||
ObjRecord obj1 = (ObjRecord) HSSFRecordTestHelper.getShapeToObjForTest(agg1).get(e1);
|
||||
ObjRecord obj2 = (ObjRecord) HSSFRecordTestHelper.getShapeToObjForTest(agg2).get(e2);
|
||||
|
||||
CommonObjectDataSubRecord cmo1 = (CommonObjectDataSubRecord) obj1.getSubRecords().get(0);
|
||||
CommonObjectDataSubRecord cmo2 = (CommonObjectDataSubRecord) obj2.getSubRecords().get(0);
|
||||
|
||||
assertEquals(cmo1.getObjectId(), cmo2.getObjectId());
|
||||
assertEquals(obj1.toString(), obj2.toString());
|
||||
|
||||
// test that obj parents have the same shapeId, that is, that shape is the same
|
||||
EscherContainerRecord p1 = map1.get(e1);
|
||||
EscherContainerRecord p2 = map2.get(e2);
|
||||
EscherSpRecord sp1 = (EscherSpRecord) p1.getChildById(EscherSpRecord.RECORD_ID);
|
||||
EscherSpRecord sp2 = (EscherSpRecord) p2.getChildById(EscherSpRecord.RECORD_ID);
|
||||
assertEquals(sp1.getShapeId(), sp2.getShapeId());
|
||||
|
||||
assertEquals("wrong shape2obj mapping", sp1.getShapeId() % 1024, cmo1.getObjectId());
|
||||
assertEquals(p1.toXml(), p2.toXml());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* recursively map EscherClientDataRecords to their parent shape containers:
|
||||
* <p/>
|
||||
* EscherClientDataRecord1 --> EscherContainerRecord1
|
||||
* EscherClientDataRecord2 --> EscherContainerRecord2
|
||||
* ...
|
||||
* <p/>
|
||||
* TODO: YK: this method can be avoided if we have EscherRecord.getParent()
|
||||
*/
|
||||
private static void mapShapeContainers(EscherRecord parent, Map<EscherRecord, EscherContainerRecord> map) {
|
||||
if (parent.isContainerRecord()) {
|
||||
if (parent.getRecordId() == EscherContainerRecord.SP_CONTAINER) {
|
||||
// iterate over shape's children and search for EscherClientDataRecord
|
||||
for (EscherRecord r : parent.getChildRecords()) {
|
||||
if (r.getRecordId() == EscherClientDataRecord.RECORD_ID) {
|
||||
map.put(r, (EscherContainerRecord) parent);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (EscherRecord ch : parent.getChildRecords()) {
|
||||
mapShapeContainers(ch, map);
|
||||
}
|
||||
private static byte[] toByteArray(List<RecordBase> records){
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
for(RecordBase rb : records) {
|
||||
Record r = (Record)rb;
|
||||
try {
|
||||
out.write(r.serialize());
|
||||
} catch (IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -170,7 +68,10 @@ public class TestDrawingAggregate extends TestCase {
|
||||
records.get(18) instanceof RowRecordsAggregate);
|
||||
|
||||
// records to be aggregated
|
||||
List<RecordBase> dgRecords = records.subList(19, 388);
|
||||
List<RecordBase> dgRecords = records.subList(19, 389);
|
||||
// collect drawing records into a byte buffer.
|
||||
byte[] dgBytes = toByteArray(dgRecords);
|
||||
|
||||
for (RecordBase rb : dgRecords) {
|
||||
Record r = (Record) rb;
|
||||
short sid = r.getSid();
|
||||
@ -203,11 +104,162 @@ public class TestDrawingAggregate extends TestCase {
|
||||
assertTrue("records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName(),
|
||||
records.get(20) instanceof WindowTwoRecord);
|
||||
|
||||
EscherAggregate agg2 = assertWriteAndReadBack(agg);
|
||||
|
||||
assertObjectMappingSame(agg, agg2);
|
||||
byte[] dgBytesAfterSave = agg.serialize();
|
||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||
assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to check file with such record sequence
|
||||
* ...
|
||||
* DrawingRecord
|
||||
* ContinueRecord
|
||||
* ObjRecord | TextObjRecord
|
||||
* ...
|
||||
*/
|
||||
public void testSerializeDrawingBigger8k() {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("DrawingContinue.xls");
|
||||
InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
|
||||
HSSFSheet sh = wb.getSheetAt(0);
|
||||
InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
|
||||
|
||||
|
||||
List<RecordBase> records = isheet.getRecords();
|
||||
|
||||
// the sheet's drawing is not aggregated
|
||||
assertEquals("wrong size of sheet records stream", 32, records.size());
|
||||
// the last record before the drawing block
|
||||
assertTrue(
|
||||
"records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
|
||||
records.get(18) instanceof RowRecordsAggregate);
|
||||
|
||||
// records to be aggregated
|
||||
List<RecordBase> dgRecords = records.subList(19, 26);
|
||||
for (RecordBase rb : dgRecords) {
|
||||
Record r = (Record) rb;
|
||||
short sid = r.getSid();
|
||||
// we expect that drawing block consists of either
|
||||
// DrawingRecord or ContinueRecord or ObjRecord or TextObjectRecord
|
||||
assertTrue(
|
||||
sid == DrawingRecord.sid ||
|
||||
sid == ContinueRecord.sid ||
|
||||
sid == ObjRecord.sid ||
|
||||
sid == NoteRecord.sid ||
|
||||
sid == TextObjectRecord.sid);
|
||||
}
|
||||
// collect drawing records into a byte buffer.
|
||||
byte[] dgBytes = toByteArray(dgRecords);
|
||||
|
||||
// the first record after the drawing block
|
||||
assertTrue(
|
||||
"records.get(26) is expected to be Window2",
|
||||
records.get(26) instanceof WindowTwoRecord);
|
||||
|
||||
// aggregate drawing records.
|
||||
// The subrange [19, 38] is expected to be replaced with a EscherAggregate object
|
||||
DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
|
||||
int loc = isheet.aggregateDrawingRecords(drawingManager, false);
|
||||
EscherAggregate agg = (EscherAggregate) records.get(loc);
|
||||
|
||||
assertEquals("wrong size of the aggregated sheet records stream", 26, records.size());
|
||||
assertTrue(
|
||||
"records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
|
||||
records.get(18) instanceof RowRecordsAggregate);
|
||||
assertTrue("records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName(),
|
||||
records.get(19) instanceof EscherAggregate);
|
||||
assertTrue("records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName(),
|
||||
records.get(20) instanceof WindowTwoRecord);
|
||||
|
||||
byte[] dgBytesAfterSave = agg.serialize();
|
||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||
assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void testSerializeDrawingBigger8k_noAggregation() {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("DrawingContinue.xls");
|
||||
|
||||
InternalSheet isheet = HSSFTestHelper.getSheetForTest(wb.getSheetAt(0));
|
||||
List<RecordBase> records = isheet.getRecords();
|
||||
|
||||
HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||
InternalSheet isheet2 = HSSFTestHelper.getSheetForTest( wb2.getSheetAt(0));
|
||||
List<RecordBase> records2 = isheet2.getRecords();
|
||||
|
||||
assertEquals(records.size(), records2.size());
|
||||
for(int i = 0; i < records.size(); i++) {
|
||||
RecordBase r1 = records.get(i);
|
||||
RecordBase r2 = records2.get(i);
|
||||
assertTrue(r1.getClass() == r2.getClass());
|
||||
assertEquals(r1.getRecordSize(), r2.getRecordSize());
|
||||
if(r1 instanceof Record ){
|
||||
assertEquals(((Record)r1).getSid(), ((Record)r2).getSid());
|
||||
assertTrue(Arrays.equals(((Record) r1).serialize(), ((Record) r2).serialize()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void testSerializeDrawingWithComments() throws IOException {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("DrawingAndComments.xls");
|
||||
HSSFSheet sh = wb.getSheetAt(0);
|
||||
InternalWorkbook iworkbook = HSSFTestHelper.getWorkbookForTest(wb);
|
||||
InternalSheet isheet = HSSFTestHelper.getSheetForTest(sh);
|
||||
|
||||
List<RecordBase> records = isheet.getRecords();
|
||||
|
||||
// the sheet's drawing is not aggregated
|
||||
assertEquals("wrong size of sheet records stream", 46, records.size());
|
||||
// the last record before the drawing block
|
||||
assertTrue(
|
||||
"records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
|
||||
records.get(18) instanceof RowRecordsAggregate);
|
||||
|
||||
// records to be aggregated
|
||||
List<RecordBase> dgRecords = records.subList(19, 39);
|
||||
for (RecordBase rb : dgRecords) {
|
||||
Record r = (Record) rb;
|
||||
short sid = r.getSid();
|
||||
// we expect that drawing block consists of either
|
||||
// DrawingRecord or ContinueRecord or ObjRecord or TextObjectRecord
|
||||
assertTrue(
|
||||
sid == DrawingRecord.sid ||
|
||||
sid == ContinueRecord.sid ||
|
||||
sid == ObjRecord.sid ||
|
||||
sid == NoteRecord.sid ||
|
||||
sid == TextObjectRecord.sid);
|
||||
}
|
||||
// collect drawing records into a byte buffer.
|
||||
byte[] dgBytes = toByteArray(dgRecords);
|
||||
|
||||
// the first record after the drawing block
|
||||
assertTrue(
|
||||
"records.get(39) is expected to be Window2",
|
||||
records.get(39) instanceof WindowTwoRecord);
|
||||
|
||||
// aggregate drawing records.
|
||||
// The subrange [19, 38] is expected to be replaced with a EscherAggregate object
|
||||
DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
|
||||
int loc = isheet.aggregateDrawingRecords(drawingManager, false);
|
||||
EscherAggregate agg = (EscherAggregate) records.get(loc);
|
||||
|
||||
assertEquals("wrong size of the aggregated sheet records stream", 27, records.size());
|
||||
assertTrue(
|
||||
"records.get(18) is expected to be RowRecordsAggregate but was " + records.get(18).getClass().getSimpleName(),
|
||||
records.get(18) instanceof RowRecordsAggregate);
|
||||
assertTrue("records.get(19) is expected to be EscherAggregate but was " + records.get(19).getClass().getSimpleName(),
|
||||
records.get(19) instanceof EscherAggregate);
|
||||
assertTrue("records.get(20) is expected to be Window2 but was " + records.get(20).getClass().getSimpleName(),
|
||||
records.get(20) instanceof WindowTwoRecord);
|
||||
|
||||
byte[] dgBytesAfterSave = agg.serialize();
|
||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||
assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||
}
|
||||
|
||||
|
||||
public void testFileWithPictures() {
|
||||
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("ContinueRecordProblem.xls");
|
||||
HSSFSheet sh = wb.getSheetAt(0);
|
||||
@ -225,7 +277,7 @@ public class TestDrawingAggregate extends TestCase {
|
||||
records.get(21) instanceof RowRecordsAggregate);
|
||||
|
||||
// records to be aggregated
|
||||
List<RecordBase> dgRecords = records.subList(22, 299);
|
||||
List<RecordBase> dgRecords = records.subList(22, 300);
|
||||
for (RecordBase rb : dgRecords) {
|
||||
Record r = (Record) rb;
|
||||
short sid = r.getSid();
|
||||
@ -237,6 +289,8 @@ public class TestDrawingAggregate extends TestCase {
|
||||
sid == ObjRecord.sid ||
|
||||
sid == TextObjectRecord.sid);
|
||||
}
|
||||
// collect drawing records into a byte buffer.
|
||||
byte[] dgBytes = toByteArray(dgRecords);
|
||||
|
||||
// the first record after the drawing block
|
||||
assertTrue(
|
||||
@ -244,7 +298,7 @@ public class TestDrawingAggregate extends TestCase {
|
||||
records.get(300) instanceof WindowTwoRecord);
|
||||
|
||||
// aggregate drawing records.
|
||||
// The subrange [19, 388] is expected to be replaced with a EscherAggregate object
|
||||
// The subrange [19, 299] is expected to be replaced with a EscherAggregate object
|
||||
DrawingManager2 drawingManager = iworkbook.findDrawingGroup();
|
||||
int loc = isheet.aggregateDrawingRecords(drawingManager, false);
|
||||
EscherAggregate agg = (EscherAggregate) records.get(loc);
|
||||
@ -258,9 +312,9 @@ public class TestDrawingAggregate extends TestCase {
|
||||
assertTrue("records.get(23) is expected to be Window2 but was " + records.get(23).getClass().getSimpleName(),
|
||||
records.get(23) instanceof WindowTwoRecord);
|
||||
|
||||
EscherAggregate agg2 = assertWriteAndReadBack(agg);
|
||||
|
||||
assertObjectMappingSame(agg, agg2);
|
||||
byte[] dgBytesAfterSave = agg.serialize();
|
||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||
assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||
}
|
||||
|
||||
public void testUnhandledContinue() {
|
||||
@ -972,10 +1026,9 @@ public class TestDrawingAggregate extends TestCase {
|
||||
assertTrue("expected EOFRecord", records.get(1) instanceof EOFRecord);
|
||||
EscherAggregate agg = (EscherAggregate) records.get(0);
|
||||
|
||||
// serialize, read back and assert that the drawing data is preserved
|
||||
EscherAggregate agg2 = assertWriteAndReadBack(agg);
|
||||
|
||||
assertObjectMappingSame(agg, agg2);
|
||||
byte[] dgBytesAfterSave = agg.serialize();
|
||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||
assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||
}
|
||||
|
||||
public void testUnhandledContinue2() {
|
||||
@ -1926,8 +1979,8 @@ public class TestDrawingAggregate extends TestCase {
|
||||
|
||||
EscherAggregate agg = (EscherAggregate) records.get(0);
|
||||
|
||||
EscherAggregate agg2 = assertWriteAndReadBack(agg);
|
||||
|
||||
assertObjectMappingSame(agg, agg2);
|
||||
byte[] dgBytesAfterSave = agg.serialize();
|
||||
assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);
|
||||
assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import org.apache.poi.ddf.EscherRecord;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Evgeniy Berlog
|
||||
* date: 30.05.12
|
||||
*/
|
||||
public class HSSFRecordTestHelper {
|
||||
|
||||
public static Map<EscherRecord, Record> getShapeToObjForTest(EscherAggregate agg){
|
||||
return agg.shapeToObj;
|
||||
}
|
||||
|
||||
}
|
@ -49,17 +49,12 @@ public final class TestDrawingRecord extends TestCase {
|
||||
out.write(cn.serialize());
|
||||
|
||||
List<Record> rec = RecordFactory.createRecords(new ByteArrayInputStream(out.toByteArray()));
|
||||
assertEquals(1, rec.size());
|
||||
assertEquals(2, rec.size());
|
||||
assertTrue(rec.get(0) instanceof DrawingRecord);
|
||||
assertTrue(rec.get(1) instanceof ContinueRecord);
|
||||
|
||||
//DrawingRecord.getData() should return concatenated data1 and data2
|
||||
byte[] tmp = new byte[data1.length + data2.length];
|
||||
System.arraycopy(data1, 0, tmp, 0, data1.length);
|
||||
System.arraycopy(data2, 0, tmp, data1.length, data2.length);
|
||||
|
||||
DrawingRecord dg2 = (DrawingRecord)rec.get(0);
|
||||
assertEquals(data1.length + data2.length, dg2.getData().length);
|
||||
assertTrue(Arrays.equals(tmp, dg2.getData()));
|
||||
assertTrue(Arrays.equals(data1, ((DrawingRecord)rec.get(0)).getData()));
|
||||
assertTrue(Arrays.equals(data2, ((ContinueRecord)rec.get(1)).getData()));
|
||||
|
||||
}
|
||||
|
||||
|
BIN
test-data/spreadsheet/DrawingAndComments.xls
Executable file
BIN
test-data/spreadsheet/DrawingAndComments.xls
Executable file
Binary file not shown.
BIN
test-data/spreadsheet/DrawingContinue.xls
Executable file
BIN
test-data/spreadsheet/DrawingContinue.xls
Executable file
Binary file not shown.
Loading…
Reference in New Issue
Block a user