org.apache.poi.hssf.record.DConRefRecord Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of poi Show documentation
Show all versions of poi Show documentation
Apache POI - Java API To Access Microsoft Format Files
/*
* ====================================================================
* 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.hssf.record;
import java.util.Arrays;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil;
/**
* DConRef records specify a range in a workbook (internal or external) that serves as a data source
* for pivot tables or data consolidation.
*
* Represents a DConRef
Structure
* [MS-XLS s.
* 2.4.86], and the contained DConFile
structure
*
* [MS-XLS s. 2.5.69]. This in turn contains a XLUnicodeStringNoCch
*
* [MS-XLS s. 2.5.296].
*
*
* _______________________________
* | DConRef |
*(bytes) +-+-+-+-+-+-+-+-+-+-+...+-+-+-+-+
* | ref |cch| stFile | un|
* +-+-+-+-+-+-+-+-+-+-+...+-+-+-+-+
* |
* _________|_____________________
* |DConFile / XLUnicodeStringNoCch|
* +-+-+-+-+-+-+-+-+-+-+-+...+-+-+-+
* (bits) |h| reserved | rgb |
* +-+-+-+-+-+-+-+-+-+-+-+...+-+-+-+
*
* Where
*
* DConFile.h = 0x00
if the characters inrgb
are single byte, and
* DConFile.h = 0x01
if they are double byte.
* If they are double byte, then
*
* - If it exists, the length of
DConRef.un = 2
. Otherwise it is 1.
* - The length of
DConFile.rgb = (2 * DConRef.cch)
. Otherwise it is equal to
* DConRef.cch
.
*
* DConRef.rgb
starts with 0x01
if it is an external reference,
* and with 0x02
if it is a self-reference.
*
*
* At the moment this class is read-only.
*/
public class DConRefRecord extends StandardRecord
{
/**
* The id of the record type,
* sid = {@value}
*/
public static final short sid = 0x0051;
/**
* A RefU structure specifying the range of cells if this record is part of an SXTBL.
*
* [MS XLS s.2.5.211]
*/
private int firstRow, lastRow, firstCol, lastCol;
/**
* the number of chars in the link
*/
private int charCount;
/**
* the type of characters (single or double byte)
*/
private int charType;
/**
* The link's path string. This is the rgb
field of a
* XLUnicodeStringNoCch
. Therefore it will contain at least one leading special
* character (0x01 or 0x02) and probably other ones.
* @see
* DConFile [MS-XLS s. 2.5.77] and
*
* VirtualPath [MS-XLS s. 2.5.69]
*
*/
private byte[] path;
/**
* unused bits at the end, must be set to 0.
*/
private byte[] _unused;
/**
* Read constructor.
*
* @param data byte array containing a DConRef Record, including the header.
*/
public DConRefRecord(byte[] data)
{
int offset = 0;
if (!(LittleEndian.getShort(data, offset) == DConRefRecord.sid))
throw new RecordFormatException("incompatible sid.");
offset += LittleEndian.SHORT_SIZE;
//length = LittleEndian.getShort(data, offset);
offset += LittleEndian.SHORT_SIZE;
firstRow = LittleEndian.getUShort(data, offset);
offset += LittleEndian.SHORT_SIZE;
lastRow = LittleEndian.getUShort(data, offset);
offset += LittleEndian.SHORT_SIZE;
firstCol = LittleEndian.getUByte(data, offset);
offset += LittleEndian.BYTE_SIZE;
lastCol = LittleEndian.getUByte(data, offset);
offset += LittleEndian.BYTE_SIZE;
charCount = LittleEndian.getUShort(data, offset);
offset += LittleEndian.SHORT_SIZE;
if (charCount < 2)
throw new org.apache.poi.hssf.record.RecordFormatException(
"Character count must be >= 2");
charType = LittleEndian.getUByte(data, offset);
offset += LittleEndian.BYTE_SIZE; //7 bits reserved + 1 bit type
/*
* bytelength is the length of the string in bytes, which depends on whether the string is
* made of single- or double-byte chars. This is given by charType, which equals 0 if
* single-byte, 1 if double-byte.
*/
int byteLength = charCount * ((charType & 1) + 1);
path = LittleEndian.getByteArray(data, offset, byteLength);
offset += byteLength;
/*
* If it's a self reference, the last one or two bytes (depending on char type) are the
* unused field. Not sure If i need to bother with this...
*/
if (path[0] == 0x02)
_unused = LittleEndian.getByteArray(data, offset, (charType + 1));
}
/**
* Read Constructor.
*
* @param inStream RecordInputStream containing a DConRefRecord structure.
*/
public DConRefRecord(RecordInputStream inStream)
{
if (inStream.getSid() != sid)
throw new RecordFormatException("Wrong sid: " + inStream.getSid());
firstRow = inStream.readUShort();
lastRow = inStream.readUShort();
firstCol = inStream.readUByte();
lastCol = inStream.readUByte();
charCount = inStream.readUShort();
charType = inStream.readUByte() & 0x01; //first bit only.
// byteLength depends on whether we are using single- or double-byte chars.
int byteLength = charCount * (charType + 1);
path = new byte[byteLength];
inStream.readFully(path);
if (path[0] == 0x02)
_unused = inStream.readRemainder();
}
/*
* assuming this wants the number of bytes returned by {@link serialize(LittleEndianOutput)},
* that is, (length - 4).
*/
@Override
protected int getDataSize()
{
int sz = 9 + path.length;
if (path[0] == 0x02)
sz += _unused.length;
return sz;
}
@Override
protected void serialize(LittleEndianOutput out)
{
out.writeShort(firstRow);
out.writeShort(lastRow);
out.writeByte(firstCol);
out.writeByte(lastCol);
out.writeShort(charCount);
out.writeByte(charType);
out.write(path);
if (path[0] == 0x02)
out.write(_unused);
}
@Override
public short getSid()
{
return sid;
}
/**
* @return The first column of the range.
*/
public int getFirstColumn()
{
return firstCol;
}
/**
* @return The first row of the range.
*/
public int getFirstRow()
{
return firstRow;
}
/**
* @return The last column of the range.
*/
public int getLastColumn()
{
return lastCol;
}
/**
* @return The last row of the range.
*/
public int getLastRow()
{
return lastRow;
}
@Override
public String toString()
{
StringBuilder b = new StringBuilder();
b.append("[DCONREF]\n");
b.append(" .ref\n");
b.append(" .firstrow = ").append(firstRow).append("\n");
b.append(" .lastrow = ").append(lastRow).append("\n");
b.append(" .firstcol = ").append(firstCol).append("\n");
b.append(" .lastcol = ").append(lastCol).append("\n");
b.append(" .cch = ").append(charCount).append("\n");
b.append(" .stFile\n");
b.append(" .h = ").append(charType).append("\n");
b.append(" .rgb = ").append(getReadablePath()).append("\n");
b.append("[/DCONREF]\n");
return b.toString();
}
/**
*
* @return raw path byte array.
*/
public byte[] getPath()
{
return Arrays.copyOf(path, path.length);
}
/**
* @return the link's path, with the special characters stripped/replaced. May be null.
* See MS-XLS 2.5.277 (VirtualPath)
*/
public String getReadablePath()
{
if (path != null)
{
//all of the path strings start with either 0x02 or 0x01 followed by zero or
//more of 0x01..0x08
int offset = 1;
while (path[offset] < 0x20 && offset < path.length)
{
offset++;
}
String out = new String(Arrays.copyOfRange(path, offset, path.length), StringUtil.UTF8);
//UNC paths have \u0003 chars as path separators.
out = out.replaceAll("\u0003", "/");
return out;
}
return null;
}
/**
* Checks if the data source in this reference record is external to this sheet or internal.
*
* @return true iff this is an external reference.
*/
public boolean isExternalRef()
{
if (path[0] == 0x01)
return true;
return false;
}
}