/src/org/apache/poi/ddf/EscherMetafileBlip.java
Java | 298 lines | 193 code | 38 blank | 67 comment | 20 complexity | 40ae8a8dc728bbce21c8fc56dec8bb5e MD5 | raw file
Possible License(s): Apache-2.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.ddf;
- import org.apache.poi.util.HexDump;
- import org.apache.poi.util.LittleEndian;
- import org.apache.poi.util.POILogFactory;
- import org.apache.poi.util.POILogger;
- //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;
- /**
- * @author Daniel Noll
- */
- public final class EscherMetafileBlip extends EscherBlipRecord {
- private static final POILogger log = POILogFactory.getLogger(EscherMetafileBlip.class);
- 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;
- /**
- * BLIP signatures as defined in the escher spec
- */
- public static final short SIGNATURE_EMF = 0x3D40;
- public static final short SIGNATURE_WMF = 0x2160;
- public static final short SIGNATURE_PICT = 0x5420;
- private static final int HEADER_SIZE = 8;
- private byte[] field_1_UID;
- /**
- * The primary UID is only saved to disk if (blip_instance ^ blip_signature == 1)
- */
- private byte[] field_2_UID;
- 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;
- private byte[] remainingData;
- public int fillFields(byte[] data, int offset, EscherRecordFactory recordFactory) {
- int bytesAfterHeader = readHeader( data, offset );
- int pos = offset + HEADER_SIZE;
- field_1_UID = new byte[16];
- System.arraycopy( data, pos, field_1_UID, 0, 16 ); pos += 16;
- if((getOptions() ^ getSignature()) == 0x10){
- field_2_UID = new byte[16];
- System.arraycopy( data, pos, field_2_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 = new byte[field_5_cbSave];
- System.arraycopy( data, pos, raw_pictureData, 0, field_5_cbSave );
- pos += field_5_cbSave;
- // 0 means DEFLATE compression
- // 0xFE means no compression
- if (field_6_fCompression == 0) {
- field_pictureData = inflatePictureData(raw_pictureData);
- } else {
- field_pictureData = raw_pictureData;
- }
- int remaining = bytesAfterHeader - pos + offset + HEADER_SIZE;
- if(remaining > 0) {
- remainingData = new byte[remaining];
- System.arraycopy( data, pos, remainingData, 0, remaining );
- }
- return bytesAfterHeader + HEADER_SIZE;
- }
- 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() - HEADER_SIZE ); pos += 4;
- System.arraycopy( field_1_UID, 0, data, pos, field_1_UID.length ); pos += field_1_UID.length;
- if ((getOptions() ^ getSignature()) == 0x10) {
- System.arraycopy( field_2_UID, 0, data, pos, field_2_UID.length ); pos += field_2_UID.length;
- }
- 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 ); pos += raw_pictureData.length;
- if(remainingData != null) {
- System.arraycopy( remainingData, 0, data, pos, remainingData.length ); pos += remainingData.length;
- }
- listener.afterRecordSerialize(offset + getRecordSize(), getRecordId(), getRecordSize(), this);
- return getRecordSize();
- }
- /**
- * Decompresses the provided data, returning the inflated result.
- *
- * @param data the deflated picture data.
- * @return the inflated picture data.
- */
- 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.WARN, "Possibly corrupt compression or non-compressed data", e);
- return data;
- }
- }
- public int getRecordSize() {
- int size = 8 + 50 + raw_pictureData.length;
- if(remainingData != null) size += remainingData.length;
- if((getOptions() ^ getSignature()) == 0x10){
- size += field_2_UID.length;
- }
- return size;
- }
- public byte[] getUID() {
- return field_1_UID;
- }
- public void setUID(byte[] uid) {
- field_1_UID = uid;
- }
- public byte[] getPrimaryUID()
- {
- return field_2_UID;
- }
- public void setPrimaryUID(byte[] primaryUID) {
- field_2_UID = primaryUID;
- }
- 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[] getRemainingData() {
- return remainingData;
- }
- // filtering is always 254 according to available docs, so no point giving it a setter method.
- public String toString() {
- String extraData = "";//HexDump.toHex(field_pictureData, 32);
- return getClass().getName() + ":" + '\n' +
- " RecordId: 0x" + HexDump.toHex( getRecordId() ) + '\n' +
- " Version: 0x" + HexDump.toHex( getVersion() ) + '\n' +
- " Instance: 0x" + HexDump.toHex( getInstance() ) + '\n' +
- " UID: 0x" + HexDump.toHex( field_1_UID ) + '\n' +
- (field_2_UID == null ? "" : (" UID2: 0x" + HexDump.toHex( field_2_UID ) + '\n')) +
- " Uncompressed Size: " + HexDump.toHex( field_2_cb ) + '\n' +
- // " Bounds: " + getBounds() + '\n' +
- // " Size in EMU: " + getSizeEMU() + '\n' +
- " Compressed Size: " + HexDump.toHex( field_5_cbSave ) + '\n' +
- " Compression: " + HexDump.toHex( field_6_fCompression ) + '\n' +
- " Filter: " + HexDump.toHex( field_7_fFilter ) + '\n' +
- " Extra Data:" + '\n' + extraData +
- (remainingData == null ? null : ("\n" +
- " Remaining Data: " + HexDump.toHex(remainingData, 32)));
- }
-
- @Override
- public String toXml(String tab) {
- String extraData = "";
- StringBuilder builder = new StringBuilder();
- builder.append(tab).append(formatXmlRecordHeader(getClass().getSimpleName(), HexDump.toHex(getRecordId()), HexDump.toHex(getVersion()), HexDump.toHex(getInstance())))
- .append(tab).append("\t").append("<UID>0x").append(HexDump.toHex( field_1_UID ) + '\n' +
- (field_2_UID == null ? "" : (" UID2: 0x" + HexDump.toHex( field_2_UID ) + '\n'))).append("</UID>\n")
- .append(tab).append("\t").append("<UncompressedSize>0x").append(HexDump.toHex( field_2_cb )).append("</UncompressedSize>\n")
- // .append(tab).append("\t").append("<Bounds>").append(getBounds()).append("</Bounds>\n")
- // .append(tab).append("\t").append("<SizeInEMU>").append(getSizeEMU()).append("</SizeInEMU>\n")
- .append(tab).append("\t").append("<CompressedSize>0x").append(HexDump.toHex( field_5_cbSave )).append("</CompressedSize>\n")
- .append(tab).append("\t").append("<Compression>0x").append(HexDump.toHex( field_6_fCompression )).append("</Compression>\n")
- .append(tab).append("\t").append("<Filter>0x").append(HexDump.toHex( field_7_fFilter )).append("</Filter>\n")
- .append(tab).append("\t").append("<ExtraData>").append(extraData).append("</ExtraData>\n")
- .append(tab).append("\t").append("<RemainingData>0x").append(HexDump.toHex(remainingData, 32)).append("</RemainingData>\n");
- builder.append(tab).append("</").append(getClass().getSimpleName()).append(">\n");
- return builder.toString();
- }
-
- /**
- * Return the blip signature
- *
- * @return the blip signature
- */
- public short getSignature() {
- switch (getRecordId()) {
- case RECORD_ID_EMF: return SIGNATURE_EMF;
- case RECORD_ID_WMF: return SIGNATURE_WMF;
- case RECORD_ID_PICT: return SIGNATURE_PICT;
- }
- log.log(POILogger.WARN, "Unknown metafile: " + getRecordId());
- return 0;
- }
- }