fca4623791
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@489730 13f79535-47bb-0310-9956-ffa450edef68
437 lines
14 KiB
Java
437 lines
14 KiB
Java
|
|
/* ====================================================================
|
|
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.hssf.record.RecordFormatException;
|
|
import org.apache.poi.util.HexDump;
|
|
import org.apache.poi.util.LittleEndian;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.InputStream;
|
|
import java.io.IOException;
|
|
import java.util.zip.InflaterInputStream;
|
|
import java.util.zip.DeflaterOutputStream;
|
|
|
|
/**
|
|
* The blip record is used to hold details about large binary objects that occur in escher such
|
|
* as JPEG, GIF, PICT and WMF files. The contents of the stream is usually compressed. Inflate
|
|
* can be used to decompress the data.
|
|
*
|
|
* @author Glen Stampoultzis
|
|
* @see java.util.zip.Inflater
|
|
*/
|
|
public class EscherBlipWMFRecord
|
|
extends EscherBlipRecord
|
|
{
|
|
// public static final short RECORD_ID_START = (short) 0xF018;
|
|
// public static final short RECORD_ID_END = (short) 0xF117;
|
|
public static final String RECORD_DESCRIPTION = "msofbtBlip";
|
|
private static final int HEADER_SIZE = 8;
|
|
|
|
private byte[] field_1_secondaryUID;
|
|
private int field_2_cacheOfSize;
|
|
private int field_3_boundaryTop;
|
|
private int field_4_boundaryLeft;
|
|
private int field_5_boundaryWidth;
|
|
private int field_6_boundaryHeight;
|
|
private int field_7_width;
|
|
private int field_8_height;
|
|
private int field_9_cacheOfSavedSize;
|
|
private byte field_10_compressionFlag;
|
|
private byte field_11_filter;
|
|
private byte[] field_12_data;
|
|
|
|
|
|
/**
|
|
* This method deserializes the record from a byte array.
|
|
*
|
|
* @param data The byte array containing the escher record information
|
|
* @param offset The starting offset into <code>data</code>.
|
|
* @param recordFactory May be null since this is not a container record.
|
|
* @return The number of bytes read from the byte array.
|
|
*/
|
|
public int fillFields( byte[] data, int offset,
|
|
EscherRecordFactory recordFactory
|
|
)
|
|
{
|
|
int bytesAfterHeader = readHeader( data, offset );
|
|
int pos = offset + HEADER_SIZE;
|
|
|
|
int size = 0;
|
|
field_1_secondaryUID = new byte[16];
|
|
System.arraycopy( data, pos + size, field_1_secondaryUID, 0, 16 ); size += 16;
|
|
field_2_cacheOfSize = LittleEndian.getInt( data, pos + size );size+=4;
|
|
field_3_boundaryTop = LittleEndian.getInt( data, pos + size );size+=4;
|
|
field_4_boundaryLeft = LittleEndian.getInt( data, pos + size );size+=4;
|
|
field_5_boundaryWidth = LittleEndian.getInt( data, pos + size );size+=4;
|
|
field_6_boundaryHeight = LittleEndian.getInt( data, pos + size );size+=4;
|
|
field_7_width = LittleEndian.getInt( data, pos + size );size+=4;
|
|
field_8_height = LittleEndian.getInt( data, pos + size );size+=4;
|
|
field_9_cacheOfSavedSize = LittleEndian.getInt( data, pos + size );size+=4;
|
|
field_10_compressionFlag = data[pos + size]; size++;
|
|
field_11_filter = data[pos + size]; size++;
|
|
|
|
int bytesRemaining = bytesAfterHeader - size;
|
|
field_12_data = new byte[bytesRemaining];
|
|
System.arraycopy(data, pos + size, field_12_data, 0, bytesRemaining);
|
|
size += bytesRemaining;
|
|
|
|
return HEADER_SIZE + size;
|
|
}
|
|
|
|
|
|
/**
|
|
* This method serializes this escher record into a byte array.
|
|
*
|
|
* @param offset The offset into <code>data</code> to start writing the record data to.
|
|
* @param data The byte array to serialize to.
|
|
* @param listener A listener to retrieve start and end callbacks. Use a <code>NullEscherSerailizationListener</code> to ignore these events.
|
|
* @return The number of bytes written.
|
|
*
|
|
* @see NullEscherSerializationListener
|
|
*/
|
|
public int serialize( int offset, byte[] data, EscherSerializationListener listener )
|
|
{
|
|
listener.beforeRecordSerialize(offset, getRecordId(), this);
|
|
|
|
LittleEndian.putShort( data, offset, getOptions() );
|
|
LittleEndian.putShort( data, offset + 2, getRecordId() );
|
|
int remainingBytes = field_12_data.length + 36;
|
|
LittleEndian.putInt( data, offset + 4, remainingBytes );
|
|
|
|
int pos = offset + HEADER_SIZE;
|
|
System.arraycopy(field_1_secondaryUID, 0, data, pos, 16 ); pos += 16;
|
|
LittleEndian.putInt( data, pos, field_2_cacheOfSize); pos += 4;
|
|
LittleEndian.putInt( data, pos, field_3_boundaryTop); pos += 4;
|
|
LittleEndian.putInt( data, pos, field_4_boundaryLeft); pos += 4;
|
|
LittleEndian.putInt( data, pos, field_5_boundaryWidth); pos += 4;
|
|
LittleEndian.putInt( data, pos, field_6_boundaryHeight); pos += 4;
|
|
LittleEndian.putInt( data, pos, field_7_width); pos += 4;
|
|
LittleEndian.putInt( data, pos, field_8_height); pos += 4;
|
|
LittleEndian.putInt( data, pos, field_9_cacheOfSavedSize); pos += 4;
|
|
data[pos++] = field_10_compressionFlag;
|
|
data[pos++] = field_11_filter;
|
|
System.arraycopy(field_12_data, 0, data, pos, field_12_data.length); pos += field_12_data.length;
|
|
|
|
listener.afterRecordSerialize(pos, getRecordId(), pos - offset, this);
|
|
return pos - offset;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of bytes that are required to serialize this record.
|
|
*
|
|
* @return Number of bytes
|
|
*/
|
|
public int getRecordSize()
|
|
{
|
|
return 58 + field_12_data.length;
|
|
}
|
|
|
|
/**
|
|
* The short name for this record
|
|
*/
|
|
public String getRecordName()
|
|
{
|
|
return "Blip";
|
|
}
|
|
|
|
/**
|
|
* Retrieve the secondary UID
|
|
*/
|
|
public byte[] getSecondaryUID()
|
|
{
|
|
return field_1_secondaryUID;
|
|
}
|
|
|
|
/**
|
|
* Set the secondary UID
|
|
*/
|
|
public void setSecondaryUID( byte[] field_1_secondaryUID )
|
|
{
|
|
this.field_1_secondaryUID = field_1_secondaryUID;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the cache of the metafile size
|
|
*/
|
|
public int getCacheOfSize()
|
|
{
|
|
return field_2_cacheOfSize;
|
|
}
|
|
|
|
/**
|
|
* Set the cache of the metafile size
|
|
*/
|
|
public void setCacheOfSize( int field_2_cacheOfSize )
|
|
{
|
|
this.field_2_cacheOfSize = field_2_cacheOfSize;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the top boundary of the metafile drawing commands
|
|
*/
|
|
public int getBoundaryTop()
|
|
{
|
|
return field_3_boundaryTop;
|
|
}
|
|
|
|
/**
|
|
* Set the top boundary of the metafile drawing commands
|
|
*/
|
|
public void setBoundaryTop( int field_3_boundaryTop )
|
|
{
|
|
this.field_3_boundaryTop = field_3_boundaryTop;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the left boundary of the metafile drawing commands
|
|
*/
|
|
public int getBoundaryLeft()
|
|
{
|
|
return field_4_boundaryLeft;
|
|
}
|
|
|
|
/**
|
|
* Set the left boundary of the metafile drawing commands
|
|
*/
|
|
public void setBoundaryLeft( int field_4_boundaryLeft )
|
|
{
|
|
this.field_4_boundaryLeft = field_4_boundaryLeft;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the boundary width of the metafile drawing commands
|
|
*/
|
|
public int getBoundaryWidth()
|
|
{
|
|
return field_5_boundaryWidth;
|
|
}
|
|
|
|
/**
|
|
* Set the boundary width of the metafile drawing commands
|
|
*/
|
|
public void setBoundaryWidth( int field_5_boundaryWidth )
|
|
{
|
|
this.field_5_boundaryWidth = field_5_boundaryWidth;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the boundary height of the metafile drawing commands
|
|
*/
|
|
public int getBoundaryHeight()
|
|
{
|
|
return field_6_boundaryHeight;
|
|
}
|
|
|
|
/**
|
|
* Set the boundary height of the metafile drawing commands
|
|
*/
|
|
public void setBoundaryHeight( int field_6_boundaryHeight )
|
|
{
|
|
this.field_6_boundaryHeight = field_6_boundaryHeight;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the width of the metafile in EMU's (English Metric Units).
|
|
*/
|
|
public int getWidth()
|
|
{
|
|
return field_7_width;
|
|
}
|
|
|
|
/**
|
|
* Set the width of the metafile in EMU's (English Metric Units).
|
|
*/
|
|
public void setWidth( int width )
|
|
{
|
|
this.field_7_width = width;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the height of the metafile in EMU's (English Metric Units).
|
|
*/
|
|
public int getHeight()
|
|
{
|
|
return field_8_height;
|
|
}
|
|
|
|
/**
|
|
* Set the height of the metafile in EMU's (English Metric Units).
|
|
*/
|
|
public void setHeight( int height )
|
|
{
|
|
this.field_8_height = height;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the cache of the saved size
|
|
*/
|
|
public int getCacheOfSavedSize()
|
|
{
|
|
return field_9_cacheOfSavedSize;
|
|
}
|
|
|
|
/**
|
|
* Set the cache of the saved size
|
|
*/
|
|
public void setCacheOfSavedSize( int field_9_cacheOfSavedSize )
|
|
{
|
|
this.field_9_cacheOfSavedSize = field_9_cacheOfSavedSize;
|
|
}
|
|
|
|
/**
|
|
* Is the contents of the blip compressed?
|
|
*/
|
|
public byte getCompressionFlag()
|
|
{
|
|
return field_10_compressionFlag;
|
|
}
|
|
|
|
/**
|
|
* Set whether the contents of the blip is compressed
|
|
*/
|
|
public void setCompressionFlag( byte field_10_compressionFlag )
|
|
{
|
|
this.field_10_compressionFlag = field_10_compressionFlag;
|
|
}
|
|
|
|
/**
|
|
* Filter should always be 0
|
|
*/
|
|
public byte getFilter()
|
|
{
|
|
return field_11_filter;
|
|
}
|
|
|
|
/**
|
|
* Filter should always be 0
|
|
*/
|
|
public void setFilter( byte field_11_filter )
|
|
{
|
|
this.field_11_filter = field_11_filter;
|
|
}
|
|
|
|
/**
|
|
* The BLIP data
|
|
*/
|
|
public byte[] getData()
|
|
{
|
|
return field_12_data;
|
|
}
|
|
|
|
/**
|
|
* The BLIP data
|
|
*/
|
|
public void setData( byte[] field_12_data )
|
|
{
|
|
this.field_12_data = field_12_data;
|
|
}
|
|
|
|
/**
|
|
* The string representation of this record.
|
|
*
|
|
* @return A string
|
|
*/
|
|
public String toString()
|
|
{
|
|
String nl = System.getProperty( "line.separator" );
|
|
|
|
String extraData;
|
|
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
|
try
|
|
{
|
|
HexDump.dump( this.field_12_data, 0, b, 0 );
|
|
extraData = b.toString();
|
|
}
|
|
catch ( Exception e )
|
|
{
|
|
extraData = e.toString();
|
|
}
|
|
return getClass().getName() + ":" + nl +
|
|
" RecordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
|
|
" Options: 0x" + HexDump.toHex( getOptions() ) + nl +
|
|
" Secondary UID: " + HexDump.toHex( field_1_secondaryUID ) + nl +
|
|
" CacheOfSize: " + field_2_cacheOfSize + nl +
|
|
" BoundaryTop: " + field_3_boundaryTop + nl +
|
|
" BoundaryLeft: " + field_4_boundaryLeft + nl +
|
|
" BoundaryWidth: " + field_5_boundaryWidth + nl +
|
|
" BoundaryHeight: " + field_6_boundaryHeight + nl +
|
|
" X: " + field_7_width + nl +
|
|
" Y: " + field_8_height + nl +
|
|
" CacheOfSavedSize: " + field_9_cacheOfSavedSize + nl +
|
|
" CompressionFlag: " + field_10_compressionFlag + nl +
|
|
" Filter: " + field_11_filter + nl +
|
|
" Data:" + nl + extraData;
|
|
}
|
|
|
|
/**
|
|
* Compress the contents of the provided array
|
|
*
|
|
* @param data An uncompressed byte array
|
|
* @see DeflaterOutputStream#write(int b)
|
|
*/
|
|
public static byte[] compress( byte[] data )
|
|
{
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
DeflaterOutputStream deflaterOutputStream = new DeflaterOutputStream( out );
|
|
try
|
|
{
|
|
for ( int i = 0; i < data.length; i++ )
|
|
deflaterOutputStream.write( data[i] );
|
|
}
|
|
catch ( IOException e )
|
|
{
|
|
throw new RecordFormatException( e.toString() );
|
|
}
|
|
|
|
return out.toByteArray();
|
|
}
|
|
|
|
/**
|
|
* Decompresses a byte array.
|
|
*
|
|
* @param data The compressed byte array
|
|
* @param pos The starting position into the byte array
|
|
* @param length The number of compressed bytes to decompress
|
|
* @return An uncompressed byte array
|
|
* @see InflaterInputStream#read
|
|
*/
|
|
public static byte[] decompress( byte[] data, int pos, int length )
|
|
{
|
|
byte[] compressedData = new byte[length];
|
|
System.arraycopy( data, pos + 50, compressedData, 0, length );
|
|
InputStream compressedInputStream = new ByteArrayInputStream( compressedData );
|
|
InflaterInputStream inflaterInputStream = new InflaterInputStream( compressedInputStream );
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
int c;
|
|
try
|
|
{
|
|
while ( ( c = inflaterInputStream.read() ) != -1 )
|
|
out.write( c );
|
|
}
|
|
catch ( IOException e )
|
|
{
|
|
throw new RecordFormatException( e.toString() );
|
|
}
|
|
return out.toByteArray();
|
|
}
|
|
|
|
}
|