232 lines
7.5 KiB
Java
232 lines
7.5 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.hssf.record;
|
|
|
|
import org.apache.poi.ss.formula.Formula;
|
|
import org.apache.poi.ss.formula.constant.ConstantValueParser;
|
|
import org.apache.poi.ss.formula.ptg.Ptg;
|
|
import org.apache.poi.util.LittleEndianOutput;
|
|
import org.apache.poi.util.StringUtil;
|
|
|
|
/**
|
|
* EXTERNALNAME (0x0023)
|
|
*/
|
|
public final class ExternalNameRecord extends StandardRecord {
|
|
|
|
public final static short sid = 0x0023; // as per BIFF8. (some old versions used 0x223)
|
|
|
|
private static final int OPT_BUILTIN_NAME = 0x0001;
|
|
private static final int OPT_AUTOMATIC_LINK = 0x0002; // m$ doc calls this fWantAdvise
|
|
private static final int OPT_PICTURE_LINK = 0x0004;
|
|
private static final int OPT_STD_DOCUMENT_NAME = 0x0008; //fOle
|
|
private static final int OPT_OLE_LINK = 0x0010; //fOleLink
|
|
// private static final int OPT_CLIP_FORMAT_MASK = 0x7FE0;
|
|
private static final int OPT_ICONIFIED_PICTURE_LINK= 0x8000;
|
|
|
|
|
|
private short field_1_option_flag;
|
|
private short field_2_ixals;
|
|
private short field_3_not_used;
|
|
private String field_4_name;
|
|
private Formula field_5_name_definition;
|
|
|
|
/**
|
|
* 'rgoper' / 'Last received results of the DDE link'
|
|
* (seems to be only applicable to DDE links)<br/>
|
|
* Logically this is a 2-D array, which has been flattened into 1-D array here.
|
|
*/
|
|
private Object[] _ddeValues;
|
|
/**
|
|
* (logical) number of columns in the {@link #_ddeValues} array
|
|
*/
|
|
private int _nColumns;
|
|
/**
|
|
* (logical) number of rows in the {@link #_ddeValues} array
|
|
*/
|
|
private int _nRows;
|
|
|
|
/**
|
|
* @return {@code true} if the name is a built-in name
|
|
*/
|
|
public boolean isBuiltInName() {
|
|
return (field_1_option_flag & OPT_BUILTIN_NAME) != 0;
|
|
}
|
|
/**
|
|
* For OLE and DDE, links can be either 'automatic' or 'manual'
|
|
*
|
|
* @return {@code true} if this is a automatic link
|
|
*/
|
|
public boolean isAutomaticLink() {
|
|
return (field_1_option_flag & OPT_AUTOMATIC_LINK) != 0;
|
|
}
|
|
/**
|
|
* only for OLE and DDE
|
|
*
|
|
* @return {@code true} if this is a picture link
|
|
*/
|
|
public boolean isPicureLink() {
|
|
return (field_1_option_flag & OPT_PICTURE_LINK) != 0;
|
|
}
|
|
/**
|
|
* DDE links only. If <code>true</code>, this denotes the 'StdDocumentName'
|
|
*
|
|
* @return {@code true} if this denotes the 'StdDocumentName'
|
|
*/
|
|
public boolean isStdDocumentNameIdentifier() {
|
|
return (field_1_option_flag & OPT_STD_DOCUMENT_NAME) != 0;
|
|
}
|
|
public boolean isOLELink() {
|
|
return (field_1_option_flag & OPT_OLE_LINK) != 0;
|
|
}
|
|
public boolean isIconifiedPictureLink() {
|
|
return (field_1_option_flag & OPT_ICONIFIED_PICTURE_LINK) != 0;
|
|
}
|
|
/**
|
|
* @return the standard String representation of this name
|
|
*/
|
|
public String getText() {
|
|
return field_4_name;
|
|
}
|
|
|
|
public void setText(String str) {
|
|
field_4_name = str;
|
|
}
|
|
|
|
/**
|
|
* If this is a local name, then this is the (1 based)
|
|
* index of the name of the Sheet this refers to, as
|
|
* defined in the preceding {@link SupBookRecord}.
|
|
* If it isn't a local name, then it must be zero.
|
|
*
|
|
* @return the index of the name of the Sheet this refers to
|
|
*/
|
|
public short getIx() {
|
|
return field_2_ixals;
|
|
}
|
|
|
|
public void setIx(short ix) {
|
|
field_2_ixals = ix;
|
|
}
|
|
|
|
public Ptg[] getParsedExpression() {
|
|
return Formula.getTokens(field_5_name_definition);
|
|
}
|
|
public void setParsedExpression(Ptg[] ptgs) {
|
|
field_5_name_definition = Formula.create(ptgs);
|
|
}
|
|
|
|
|
|
@Override
|
|
protected int getDataSize(){
|
|
int result = 2 + 4; // short and int
|
|
result += StringUtil.getEncodedSize(field_4_name) - 1; //size is byte, not short
|
|
|
|
if(!isOLELink() && !isStdDocumentNameIdentifier()){
|
|
if(isAutomaticLink()){
|
|
if(_ddeValues != null) {
|
|
result += 3; // byte, short
|
|
result += ConstantValueParser.getEncodedSize(_ddeValues);
|
|
}
|
|
} else {
|
|
result += field_5_name_definition.getEncodedSize();
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public void serialize(LittleEndianOutput out) {
|
|
out.writeShort(field_1_option_flag);
|
|
out.writeShort(field_2_ixals);
|
|
out.writeShort(field_3_not_used);
|
|
|
|
out.writeByte(field_4_name.length());
|
|
StringUtil.writeUnicodeStringFlagAndData(out, field_4_name);
|
|
|
|
if(!isOLELink() && !isStdDocumentNameIdentifier()){
|
|
if(isAutomaticLink()){
|
|
if(_ddeValues != null) {
|
|
out.writeByte(_nColumns-1);
|
|
out.writeShort(_nRows-1);
|
|
ConstantValueParser.encode(out, _ddeValues);
|
|
}
|
|
} else {
|
|
field_5_name_definition.serialize(out);
|
|
}
|
|
}
|
|
}
|
|
|
|
public ExternalNameRecord() {
|
|
field_2_ixals = 0;
|
|
}
|
|
|
|
public ExternalNameRecord(RecordInputStream in) {
|
|
field_1_option_flag = in.readShort();
|
|
field_2_ixals = in.readShort();
|
|
field_3_not_used = in.readShort();
|
|
|
|
int numChars = in.readUByte();
|
|
field_4_name = StringUtil.readUnicodeString(in, numChars);
|
|
|
|
// the record body can take different forms.
|
|
// The form is dictated by the values of 3-th and 4-th bits in field_1_option_flag
|
|
if(!isOLELink() && !isStdDocumentNameIdentifier()){
|
|
// another switch: the fWantAdvise bit specifies whether the body describes
|
|
// an external defined name or a DDE data item
|
|
if(isAutomaticLink()){
|
|
if(in.available() > 0) {
|
|
//body specifies DDE data item
|
|
int nColumns = in.readUByte() + 1;
|
|
int nRows = in.readShort() + 1;
|
|
|
|
int totalCount = nRows * nColumns;
|
|
_ddeValues = ConstantValueParser.parse(in, totalCount);
|
|
_nColumns = nColumns;
|
|
_nRows = nRows;
|
|
}
|
|
} else {
|
|
//body specifies an external defined name
|
|
int formulaLen = in.readUShort();
|
|
field_5_name_definition = Formula.read(formulaLen, in);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public short getSid() {
|
|
return sid;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
StringBuffer sb = new StringBuffer();
|
|
sb.append("[EXTERNALNAME]\n");
|
|
sb.append(" .options = ").append(field_1_option_flag).append("\n");
|
|
sb.append(" .ix = ").append(field_2_ixals).append("\n");
|
|
sb.append(" .name = ").append(field_4_name).append("\n");
|
|
if(field_5_name_definition != null) {
|
|
Ptg[] ptgs = field_5_name_definition.getTokens();
|
|
for (Ptg ptg : ptgs) {
|
|
sb.append(ptg.toString()).append(ptg.getRVAType()).append("\n");
|
|
}
|
|
}
|
|
sb.append("[/EXTERNALNAME]\n");
|
|
return sb.toString();
|
|
}
|
|
}
|