/* ====================================================================
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.
LittleEndian;
/**
* The BSE record is related closely to the {@code EscherBlipRecord} and stores
* extra information about the blip. A blip record is actually stored inside
* the BSE record even though the BSE record isn't actually a container record.
*
* @see EscherBlipRecord
*/
public final 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 final byte[]
field_3_uid = new byte[16];
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
EscherBlipRecord field_12_blipRecord;
private byte[]
_remainingData = new byte[0];
public
EscherBSERecord() {
setRecordId(
RECORD_ID);
}
@
Override
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, 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;
int
bytesRead = 0;
if (
bytesRemaining > 0) {
// Some older escher formats skip this last record
field_12_blipRecord = (
EscherBlipRecord)
recordFactory.
createRecord(
data,
pos + 36 );
bytesRead =
field_12_blipRecord.
fillFields(
data,
pos + 36,
recordFactory );
}
pos += 36 +
bytesRead;
bytesRemaining -=
bytesRead;
_remainingData = new byte[
bytesRemaining];
System.
arraycopy(
data,
pos,
_remainingData, 0,
bytesRemaining );
return
bytesRemaining + 8 + 36 + (
field_12_blipRecord == null ? 0 :
field_12_blipRecord.
getRecordSize()) ;
}
@
Override
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
blipSize =
field_12_blipRecord == null ? 0 :
field_12_blipRecord.
getRecordSize();
int
remainingBytes =
_remainingData.length + 36 +
blipSize;
LittleEndian.
putInt(
data,
offset + 4,
remainingBytes );
data[
offset + 8] =
field_1_blipTypeWin32;
data[
offset + 9] =
field_2_blipTypeMacOS;
System.
arraycopy(
field_3_uid, 0,
data,
offset + 10, 16);
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;
int
bytesWritten = 0;
if (
field_12_blipRecord != null) {
bytesWritten =
field_12_blipRecord.
serialize(
offset + 44,
data, new
NullEscherSerializationListener() );
}
System.
arraycopy(
_remainingData, 0,
data,
offset + 44 +
bytesWritten,
_remainingData.length );
int
pos =
offset + 8 + 36 +
_remainingData.length +
bytesWritten;
listener.
afterRecordSerialize(
pos,
getRecordId(),
pos -
offset, this);
return
pos -
offset;
}
@
Override
public int
getRecordSize() {
int
field_12_size = 0;
if(
field_12_blipRecord != null) {
field_12_size =
field_12_blipRecord.
getRecordSize();
}
int
remaining_size = 0;
if(
_remainingData != null) {
remaining_size =
_remainingData.length;
}
return 8 + 1 + 1 + 16 + 2 + 4 + 4 + 4 + 1 + 1 +
1 + 1 +
field_12_size +
remaining_size;
}
@
Override
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).
*
* @return win32 blip type
*/
public byte
getBlipTypeWin32() {
return
field_1_blipTypeWin32;
}
/**
* Set the expected win32 blip type
*
* @param blipTypeWin32 win32 blip type
*/
public void
setBlipTypeWin32(byte
blipTypeWin32) {
field_1_blipTypeWin32 =
blipTypeWin32;
}
/**
* The expected blip type under MacOS (failure to match this blip type will result in
* Excel converting to this format).
*
* @return MacOS blip type
*/
public byte
getBlipTypeMacOS() {
return
field_2_blipTypeMacOS;
}
/**
* Set the expected MacOS blip type
*
* @param blipTypeMacOS MacOS blip type
*/
public void
setBlipTypeMacOS(byte
blipTypeMacOS) {
field_2_blipTypeMacOS =
blipTypeMacOS;
}
/**
* 16 byte MD4 checksum.
*
* @return 16 byte MD4 checksum
*/
public byte[]
getUid() {
return
field_3_uid;
}
/**
* 16 byte MD4 checksum.
*
* @param uid 16 byte MD4 checksum
*/
public void
setUid(byte[]
uid) {
if (
uid == null ||
uid.length != 16) {
throw new
IllegalArgumentException("uid must be byte[16]");
}
System.
arraycopy(
uid, 0,
field_3_uid, 0,
field_3_uid.length);
}
/**
* unused
*
* @return an unknown tag
*/
public short
getTag() {
return
field_4_tag;
}
/**
* unused
*
* @param tag unknown tag
*/
public void
setTag(short
tag) {
field_4_tag =
tag;
}
/**
* Blip size in stream.
*
* @return the blip size
*/
public int
getSize() {
return
field_5_size;
}
/**
* Blip size in stream.
*
* @param size blip size
*/
public void
setSize(int
size) {
field_5_size =
size;
}
/**
* The reference count of this blip.
*
* @return the reference count
*/
public int
getRef() {
return
field_6_ref;
}
/**
* The reference count of this blip.
*
* @param ref the reference count
*/
public void
setRef(int
ref) {
field_6_ref =
ref;
}
/**
* File offset in the delay stream.
*
* @return the file offset
*/
public int
getOffset() {
return
field_7_offset;
}
/**
* File offset in the delay stream.
*
* @param offset the file offset
*/
public void
setOffset(int
offset) {
field_7_offset =
offset;
}
/**
* Defines the way this blip is used.
*
* @return the blip usage
*/
public byte
getUsage() {
return
field_8_usage;
}
/**
* Defines the way this blip is used.
*
* @param usage the blip usae
*/
public void
setUsage(byte
usage) {
field_8_usage =
usage;
}
/**
* The length in characters of the blip name.
*
* @return the blip name length
*/
public byte
getName() {
return
field_9_name;
}
/**
* The length in characters of the blip name.
*
* @param name the blip name length
*/
public void
setName(byte
name) {
field_9_name =
name;
}
public byte
getUnused2() {
return
field_10_unused2;
}
public void
setUnused2(byte
unused2) {
field_10_unused2 =
unused2;
}
public byte
getUnused3() {
return
field_11_unused3;
}
public void
setUnused3(byte
unused3) {
field_11_unused3 =
unused3;
}
public
EscherBlipRecord getBlipRecord() {
return
field_12_blipRecord;
}
public void
setBlipRecord(
EscherBlipRecord blipRecord) {
field_12_blipRecord =
blipRecord;
}
/**
* Any remaining data in this record.
*
* @return the remaining bytes
*/
public byte[]
getRemainingData() {
return
_remainingData;
}
/**
* Any remaining data in this record.
*
* @param remainingData the remaining bytes
*/
public void
setRemainingData(byte[]
remainingData) {
_remainingData = (
remainingData == null) ? new byte[0] :
remainingData.
clone();
}
/**
* Retrieve the string representation given a blip id.
*
* @param b the blip type byte-encoded
*
* @return the blip type as string
*/
public static
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";
}
if (
b < 32 ) {
return " NotKnown";
}
return " Client";
}
@
Override
protected
Object[][]
getAttributeMap() {
return new
Object[][] {
{ "BlipTypeWin32",
field_1_blipTypeWin32 },
{ "BlipTypeMacOS",
field_2_blipTypeMacOS },
{ "SUID",
field_3_uid },
{ "Tag",
field_4_tag },
{ "Size",
field_5_size },
{ "Ref",
field_6_ref },
{ "Offset",
field_7_offset },
{ "Usage",
field_8_usage },
{ "Name",
field_9_name },
{ "Unused2",
field_10_unused2 },
{ "Unused3",
field_11_unused3 },
{ "Blip Record",
field_12_blipRecord },
{ "Extra Data",
_remainingData }
};
}
}