/* ====================================================================
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 escher client anchor specifies which rows and cells the shape is bound to as well as
* the offsets within those cells. Each cell is 1024 units wide by 256 units long regardless
* of the actual size of the cell. The EscherClientAnchorRecord only applies to the top-most
* shapes. Shapes contained in groups are bound using the EscherChildAnchorRecords.
*
* @see EscherChildAnchorRecord
*/
public class
EscherClientAnchorRecord
extends
EscherRecord
{
public static final short
RECORD_ID = (short) 0xF010;
public static final
String RECORD_DESCRIPTION = "MsofbtClientAnchor";
/**
* bit[0] - fMove (1 bit): A bit that specifies whether the shape will be kept intact when the cells are moved.
* bit[1] - fSize (1 bit): A bit that specifies whether the shape will be kept intact when the cells are resized. If fMove is 1, the value MUST be 1.
* bit[2-4] - reserved, MUST be 0 and MUST be ignored
* bit[5-15]- Undefined and MUST be ignored.
*
* it can take values: 0, 2, 3
*/
private short
field_1_flag;
private short
field_2_col1;
private short
field_3_dx1;
private short
field_4_row1;
private short
field_5_dy1;
private short
field_6_col2;
private short
field_7_dx2;
private short
field_8_row2;
private short
field_9_dy2;
private byte[]
remainingData = new byte[0];
private boolean
shortRecord = false;
@
Override
public int
fillFields(byte[]
data, int
offset,
EscherRecordFactory recordFactory) {
int
bytesRemaining =
readHeader(
data,
offset );
int
pos =
offset + 8;
int
size = 0;
// Always find 4 two byte entries. Sometimes find 9
/*if (bytesRemaining == 4) // Word format only 4 bytes
{
// Not sure exactly what the format is quite yet, likely a reference to a PLC
}
else */
if (
bytesRemaining != 4) // Word format only 4 bytes
{
field_1_flag =
LittleEndian.
getShort(
data,
pos +
size );
size += 2;
field_2_col1 =
LittleEndian.
getShort(
data,
pos +
size );
size += 2;
field_3_dx1 =
LittleEndian.
getShort(
data,
pos +
size );
size += 2;
field_4_row1 =
LittleEndian.
getShort(
data,
pos +
size );
size += 2;
if(
bytesRemaining >= 18) {
field_5_dy1 =
LittleEndian.
getShort(
data,
pos +
size );
size += 2;
field_6_col2 =
LittleEndian.
getShort(
data,
pos +
size );
size += 2;
field_7_dx2 =
LittleEndian.
getShort(
data,
pos +
size );
size += 2;
field_8_row2 =
LittleEndian.
getShort(
data,
pos +
size );
size += 2;
field_9_dy2 =
LittleEndian.
getShort(
data,
pos +
size );
size += 2;
shortRecord = false;
} else {
shortRecord = true;
}
}
bytesRemaining -=
size;
remainingData = new byte[
bytesRemaining];
System.
arraycopy(
data,
pos +
size,
remainingData, 0,
bytesRemaining );
return 8 +
size +
bytesRemaining;
}
@
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
remainingBytes =
remainingData.length + (
shortRecord ? 8 : 18);
LittleEndian.
putInt(
data,
offset + 4,
remainingBytes );
LittleEndian.
putShort(
data,
offset + 8,
field_1_flag );
LittleEndian.
putShort(
data,
offset + 10,
field_2_col1 );
LittleEndian.
putShort(
data,
offset + 12,
field_3_dx1 );
LittleEndian.
putShort(
data,
offset + 14,
field_4_row1 );
if(!
shortRecord) {
LittleEndian.
putShort(
data,
offset + 16,
field_5_dy1 );
LittleEndian.
putShort(
data,
offset + 18,
field_6_col2 );
LittleEndian.
putShort(
data,
offset + 20,
field_7_dx2 );
LittleEndian.
putShort(
data,
offset + 22,
field_8_row2 );
LittleEndian.
putShort(
data,
offset + 24,
field_9_dy2 );
}
System.
arraycopy(
remainingData, 0,
data,
offset + (
shortRecord ? 16 : 26),
remainingData.length );
int
pos =
offset + 8 + (
shortRecord ? 8 : 18) +
remainingData.length;
listener.
afterRecordSerialize(
pos,
getRecordId(),
pos -
offset, this );
return
pos -
offset;
}
@
Override
public int
getRecordSize()
{
return 8 + (
shortRecord ? 8 : 18) + (
remainingData == null ? 0 :
remainingData.length);
}
@
Override
public short
getRecordId() {
return
RECORD_ID;
}
@
Override
public
String getRecordName() {
return "ClientAnchor";
}
/**
* 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
*
* @return the move/size flag
*/
public short
getFlag()
{
return
field_1_flag;
}
/**
* 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
*
* @param field_1_flag the move/size flag
*/
public void
setFlag( short
field_1_flag )
{
this.
field_1_flag =
field_1_flag;
}
/**
* The column number for the top-left position. 0 based.
*
* @return the column number of the top-left corner
*/
public short
getCol1()
{
return
field_2_col1;
}
/**
* The column number for the top-left position. 0 based.
*
* @param field_2_col1 the column number of the top-left corner
*/
public void
setCol1( short
field_2_col1 )
{
this.
field_2_col1 =
field_2_col1;
}
/**
* The x offset within the top-left cell. Range is from 0 to 1023.
*
* @return the x offset of the top-left corner
*/
public short
getDx1()
{
return
field_3_dx1;
}
/**
* The x offset within the top-left cell. Range is from 0 to 1023.
*
* @param field_3_dx1 the x offset of the top-left corner
*/
public void
setDx1( short
field_3_dx1 )
{
this.
field_3_dx1 =
field_3_dx1;
}
/**
* The row number for the top-left corner of the shape.
*
* @return the row number of the top-left corner
*/
public short
getRow1()
{
return
field_4_row1;
}
/**
* The row number of the top-left corner of the shape.
*
* @param field_4_row1 the row number of the top-left corner
*/
public void
setRow1( short
field_4_row1 )
{
this.
field_4_row1 =
field_4_row1;
}
/**
* The y offset within the top-left corner of the current shape.
*
* @return the y offset of the top-left corner
*/
public short
getDy1()
{
return
field_5_dy1;
}
/**
* The y offset within the top-left corner of the current shape.
*
* @param field_5_dy1 the y offset of the top-left corner
*/
public void
setDy1( short
field_5_dy1 )
{
shortRecord = false;
this.
field_5_dy1 =
field_5_dy1;
}
/**
* The column of the bottom right corner of this shape.
*
* @return the column of the bottom right corner
*/
public short
getCol2()
{
return
field_6_col2;
}
/**
* The column of the bottom right corner of this shape.
*
* @param field_6_col2 the column of the bottom right corner
*/
public void
setCol2( short
field_6_col2 )
{
shortRecord = false;
this.
field_6_col2 =
field_6_col2;
}
/**
* The x offset withing the cell for the bottom-right corner of this shape.
*
* @return the x offset of the bottom-right corner
*/
public short
getDx2()
{
return
field_7_dx2;
}
/**
* The x offset withing the cell for the bottom-right corner of this shape.
*
* @param field_7_dx2 the x offset of the bottom-right corner
*/
public void
setDx2( short
field_7_dx2 )
{
shortRecord = false;
this.
field_7_dx2 =
field_7_dx2;
}
/**
* The row number for the bottom-right corner of the current shape.
*
* @return the row number for the bottom-right corner
*/
public short
getRow2()
{
return
field_8_row2;
}
/**
* The row number for the bottom-right corner of the current shape.
*
* @param field_8_row2 the row number for the bottom-right corner
*/
public void
setRow2( short
field_8_row2 )
{
shortRecord = false;
this.
field_8_row2 =
field_8_row2;
}
/**
* The y offset withing the cell for the bottom-right corner of this shape.
*
* @return the y offset of the bottom-right corner
*/
public short
getDy2()
{
return
field_9_dy2;
}
/**
* The y offset withing the cell for the bottom-right corner of this shape.
*
* @param field_9_dy2 the y offset of the bottom-right corner
*/
public void
setDy2( short
field_9_dy2 )
{
shortRecord = false;
this.
field_9_dy2 =
field_9_dy2;
}
/**
* Any remaining data in the record
*
* @return the remaining bytes
*/
public byte[]
getRemainingData()
{
return
remainingData;
}
/**
* Any remaining data in the record
*
* @param remainingData the remaining bytes
*/
public void
setRemainingData( byte[]
remainingData ) {
if (
remainingData == null) {
this.
remainingData = new byte[0];
} else {
this.
remainingData =
remainingData.
clone();
}
}
@
Override
protected
Object[][]
getAttributeMap() {
return new
Object[][] {
{ "Flag",
field_1_flag },
{ "Col1",
field_2_col1 },
{ "DX1",
field_3_dx1 },
{ "Row1",
field_4_row1 },
{ "DY1",
field_5_dy1 },
{ "Col2",
field_6_col2 },
{ "DX2",
field_7_dx2 },
{ "Row2",
field_8_row2 },
{ "DY2",
field_9_dy2 },
{ "Extra Data",
remainingData }
};
}
}