/*
 *  ====================================================================
 *    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.IOUtils;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.RecordFormatException;
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.
/** * 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 <code>DConRef</code> Structure * <a href="http://msdn.microsoft.com/en-us/library/dd923854(office.12).aspx">[MS-XLS s. * 2.4.86]</a>, and the contained <code>DConFile</code> structure * <a href="http://msdn.microsoft.com/en-us/library/dd950157(office.12).aspx"> * [MS-XLS s. 2.5.69]</a>. This in turn contains a <code>XLUnicodeStringNoCch</code> * <a href="http://msdn.microsoft.com/en-us/library/dd910585(office.12).aspx"> * [MS-XLS s. 2.5.296]</a>. * * <pre> * _______________________________ * | DConRef | *(bytes) +-+-+-+-+-+-+-+-+-+-+...+-+-+-+-+ * | ref |cch| stFile | un| * +-+-+-+-+-+-+-+-+-+-+...+-+-+-+-+ * | * _________|_____________________ * |DConFile / XLUnicodeStringNoCch| * +-+-+-+-+-+-+-+-+-+-+-+...+-+-+-+ * (bits) |h| reserved | rgb | * +-+-+-+-+-+-+-+-+-+-+-+...+-+-+-+ * </pre> * Where * <ul> * <li><code>DConFile.h = 0x00</code> if the characters in<code>rgb</code> are single byte, and * <code>DConFile.h = 0x01</code> if they are double byte.<p> * If they are double byte, then * <ul> * <li> If it exists, the length of <code>DConRef.un = 2</code>. Otherwise it is 1. * <li> The length of <code>DConFile.rgb = (2 * DConRef.cch)</code>. Otherwise it is equal to * <code>DConRef.cch</code>. * </ul> * <li><code>DConRef.rgb</code> starts with <code>0x01</code> if it is an external reference, * and with <code>0x02</code> if it is a self-reference. * </ul> * * At the moment this class is read-only. */
public class DConRefRecord extends StandardRecord { //arbitrarily selected; may need to increase private static final int MAX_RECORD_LENGTH = 100_000;
The id of the record type, sid = 81
/** * The id of the record type, * <code>sid = {@value}</code> */
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]
/** * A RefU structure specifying the range of cells if this record is part of an SXTBL. * <a href="http://msdn.microsoft.com/en-us/library/dd920420(office.12).aspx"> * [MS XLS s.2.5.211]</a> */
private int firstRow, lastRow, firstCol, lastCol;
the number of chars in the link
/** * the number of chars in the link */
private int charCount;
the type of characters (single or double byte)
/** * 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 Also:
/** * The link's path string. This is the <code>rgb</code> field of a * <code>XLUnicodeStringNoCch</code>. Therefore it will contain at least one leading special * character (0x01 or 0x02) and probably other ones.<p> * @see <A href="http://msdn.microsoft.com/en-us/library/dd923491(office.12).aspx"> * DConFile [MS-XLS s. 2.5.77]</A> and * <A href="http://msdn.microsoft.com/en-us/library/dd950157(office.12).aspx"> * VirtualPath [MS-XLS s. 2.5.69]</a> * <p> */
private byte[] path;
unused bits at the end, must be set to 0.
/** * unused bits at the end, must be set to 0. */
private byte[] _unused;
Read constructor.
Params:
  • data – byte array containing a DConRef Record, including the header.
/** * 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 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, MAX_RECORD_LENGTH); 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), MAX_RECORD_LENGTH); }
Read Constructor.
Params:
  • inStream – RecordInputStream containing a DConRefRecord structure.
/** * 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 = IOUtils.safelyAllocate(byteLength, MAX_RECORD_LENGTH); 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; }
Returns:The first column of the range.
/** * @return The first column of the range. */
public int getFirstColumn() { return firstCol; }
Returns:The first row of the range.
/** * @return The first row of the range. */
public int getFirstRow() { return firstRow; }
Returns:The last column of the range.
/** * @return The last column of the range. */
public int getLastColumn() { return lastCol; }
Returns:The last row of the range.
/** * @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(); }
Returns:raw path byte array.
/** * * @return raw path byte array. */
public byte[] getPath() { return Arrays.copyOf(path, path.length); }
Returns:the link's path, with the special characters stripped/replaced. May be null. See MS-XLS 2.5.277 (VirtualPath)
/** * @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.
Returns:true iff this is an external reference.
/** * 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; } }