package org.apache.poi.ddf;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.InflaterInputStream;
import org.apache.poi.util.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
public final class EscherPictBlip extends EscherBlipRecord {
private static final POILogger log = POILogFactory.getLogger(EscherPictBlip.class);
private static final int MAX_RECORD_LENGTH = 100_000;
public static final short RECORD_ID_EMF = (short) 0xF018 + 2;
public static final short RECORD_ID_WMF = (short) 0xF018 + 3;
public static final short RECORD_ID_PICT = (short) 0xF018 + 4;
private static final int = 8;
private final byte[] field_1_UID = new byte[16];
private int field_2_cb;
private int field_3_rcBounds_x1;
private int field_3_rcBounds_y1;
private int field_3_rcBounds_x2;
private int field_3_rcBounds_y2;
private int field_4_ptSize_w;
private int field_4_ptSize_h;
private int field_5_cbSave;
private byte field_6_fCompression;
private byte field_7_fFilter;
private byte[] raw_pictureData;
@Override
public int fillFields(byte[] data, int offset, EscherRecordFactory recordFactory) {
int bytesAfterHeader = readHeader(data, offset);
int pos = offset + HEADER_SIZE;
System.arraycopy( data, pos, field_1_UID, 0, 16 ); pos += 16;
field_2_cb = LittleEndian.getInt( data, pos ); pos += 4;
field_3_rcBounds_x1 = LittleEndian.getInt( data, pos ); pos += 4;
field_3_rcBounds_y1 = LittleEndian.getInt( data, pos ); pos += 4;
field_3_rcBounds_x2 = LittleEndian.getInt( data, pos ); pos += 4;
field_3_rcBounds_y2 = LittleEndian.getInt( data, pos ); pos += 4;
field_4_ptSize_w = LittleEndian.getInt( data, pos ); pos += 4;
field_4_ptSize_h = LittleEndian.getInt( data, pos ); pos += 4;
field_5_cbSave = LittleEndian.getInt( data, pos ); pos += 4;
field_6_fCompression = data[pos]; pos++;
field_7_fFilter = data[pos]; pos++;
raw_pictureData = IOUtils.safelyAllocate(field_5_cbSave, MAX_RECORD_LENGTH);
System.arraycopy( data, pos, raw_pictureData, 0, field_5_cbSave );
if (field_6_fCompression == 0)
{
super.setPictureData(inflatePictureData(raw_pictureData));
}
else
{
super.setPictureData(raw_pictureData);
}
return bytesAfterHeader + HEADER_SIZE;
}
@Override
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, 0, getRecordSize() - HEADER_SIZE ); pos += 4;
System.arraycopy( field_1_UID, 0, data, pos, 16 ); pos += 16;
LittleEndian.putInt( data, pos, field_2_cb ); pos += 4;
LittleEndian.putInt( data, pos, field_3_rcBounds_x1 ); pos += 4;
LittleEndian.putInt( data, pos, field_3_rcBounds_y1 ); pos += 4;
LittleEndian.putInt( data, pos, field_3_rcBounds_x2 ); pos += 4;
LittleEndian.putInt( data, pos, field_3_rcBounds_y2 ); pos += 4;
LittleEndian.putInt( data, pos, field_4_ptSize_w ); pos += 4;
LittleEndian.putInt( data, pos, field_4_ptSize_h ); pos += 4;
LittleEndian.putInt( data, pos, field_5_cbSave ); pos += 4;
data[pos] = field_6_fCompression; pos++;
data[pos] = field_7_fFilter; pos++;
System.arraycopy( raw_pictureData, 0, data, pos, raw_pictureData.length );
listener.afterRecordSerialize(offset + getRecordSize(), getRecordId(), getRecordSize(), this);
return HEADER_SIZE + 16 + 1 + raw_pictureData.length;
}
private static byte[] inflatePictureData(byte[] data) {
try {
InflaterInputStream in = new InflaterInputStream(new ByteArrayInputStream(data));
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int readBytes;
while ((readBytes = in.read(buf)) > 0) {
out.write(buf, 0, readBytes);
}
return out.toByteArray();
} catch (IOException e) {
log.log(POILogger.INFO, "Possibly corrupt compression or non-compressed data", e);
return data;
}
}
@Override
public int getRecordSize() {
return 8 + 50 + raw_pictureData.length;
}
public byte[] getUID() {
return field_1_UID;
}
public void setUID(byte[] uid) {
if (uid == null || uid.length != 16) {
throw new IllegalArgumentException("uid must be byte[16]");
}
System.arraycopy(uid, 0, field_1_UID, 0, field_1_UID.length);
}
public int getUncompressedSize() {
return field_2_cb;
}
public void setUncompressedSize(int uncompressedSize) {
field_2_cb = uncompressedSize;
}
public Rectangle getBounds() {
return new Rectangle(field_3_rcBounds_x1,
field_3_rcBounds_y1,
field_3_rcBounds_x2 - field_3_rcBounds_x1,
field_3_rcBounds_y2 - field_3_rcBounds_y1);
}
public void setBounds(Rectangle bounds) {
field_3_rcBounds_x1 = bounds.x;
field_3_rcBounds_y1 = bounds.y;
field_3_rcBounds_x2 = bounds.x + bounds.width;
field_3_rcBounds_y2 = bounds.y + bounds.height;
}
public Dimension getSizeEMU() {
return new Dimension(field_4_ptSize_w, field_4_ptSize_h);
}
public void setSizeEMU(Dimension sizeEMU) {
field_4_ptSize_w = sizeEMU.width;
field_4_ptSize_h = sizeEMU.height;
}
public int getCompressedSize() {
return field_5_cbSave;
}
public void setCompressedSize(int compressedSize) {
field_5_cbSave = compressedSize;
}
public boolean isCompressed() {
return (field_6_fCompression == 0);
}
public void setCompressed(boolean compressed) {
field_6_fCompression = compressed ? 0 : (byte)0xFE;
}
public byte getFilter() {
return field_7_fFilter;
}
public void setFilter(byte filter) {
field_7_fFilter = filter;
}
@Override
protected Object[][] getAttributeMap() {
return new Object[][]{
{ "UID", field_1_UID },
{ "Uncompressed Size", field_2_cb },
{ "Bounds", getBounds().toString() },
{ "Size in EMU", getSizeEMU().toString() },
{ "Compressed Size", field_5_cbSave },
{ "Compression", field_6_fCompression },
{ "Filter", field_7_fFilter },
{ "Extra Data", getPicturedata() },
};
}
}