mirror of
https://github.com/apache/poi.git
synced 2026-02-27 20:40:08 +08:00
Bug 60405: Add initial support for cetab functions so some macros can be
parsed Add some function-definitions for Excel 4 Macros and missing functions found in regression tests git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1852277 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e59f9c6461
commit
c376d662f9
@ -31,9 +31,11 @@ import java.util.Set;
|
|||||||
import org.apache.poi.EncryptedDocumentException;
|
import org.apache.poi.EncryptedDocumentException;
|
||||||
import org.apache.poi.extractor.POIOLE2TextExtractor;
|
import org.apache.poi.extractor.POIOLE2TextExtractor;
|
||||||
import org.apache.poi.extractor.POITextExtractor;
|
import org.apache.poi.extractor.POITextExtractor;
|
||||||
|
import org.apache.poi.hssf.extractor.EventBasedExcelExtractor;
|
||||||
import org.apache.poi.ooxml.extractor.ExtractorFactory;
|
import org.apache.poi.ooxml.extractor.ExtractorFactory;
|
||||||
import org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor;
|
import org.apache.poi.hpsf.extractor.HPSFPropertiesExtractor;
|
||||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
||||||
|
import org.apache.poi.ss.extractor.ExcelExtractor;
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.apache.xmlbeans.XmlException;
|
import org.apache.xmlbeans.XmlException;
|
||||||
|
|
||||||
@ -83,6 +85,7 @@ public abstract class AbstractFileHandler implements FileHandler {
|
|||||||
long modified = file.lastModified();
|
long modified = file.lastModified();
|
||||||
|
|
||||||
POITextExtractor extractor = null;
|
POITextExtractor extractor = null;
|
||||||
|
String fileAndParentName = file.getParentFile().getName() + "/" + file.getName();
|
||||||
try {
|
try {
|
||||||
extractor = ExtractorFactory.createExtractor(file);
|
extractor = ExtractorFactory.createExtractor(file);
|
||||||
assertNotNull("Should get a POITextExtractor but had none for file " + file, extractor);
|
assertNotNull("Should get a POITextExtractor but had none for file " + file, extractor);
|
||||||
@ -95,7 +98,7 @@ public abstract class AbstractFileHandler implements FileHandler {
|
|||||||
assertNotNull(metadataExtractor.getText());
|
assertNotNull(metadataExtractor.getText());
|
||||||
|
|
||||||
assertFalse("Expected Extraction to fail for file " + file + " and handler " + this + ", but did not fail!",
|
assertFalse("Expected Extraction to fail for file " + file + " and handler " + this + ", but did not fail!",
|
||||||
EXPECTED_EXTRACTOR_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName()));
|
EXPECTED_EXTRACTOR_FAILURES.contains(fileAndParentName));
|
||||||
|
|
||||||
assertEquals("File should not be modified by extractor", length, file.length());
|
assertEquals("File should not be modified by extractor", length, file.length());
|
||||||
assertEquals("File should not be modified by extractor", modified, file.lastModified());
|
assertEquals("File should not be modified by extractor", modified, file.lastModified());
|
||||||
@ -111,8 +114,24 @@ public abstract class AbstractFileHandler implements FileHandler {
|
|||||||
assertNotNull(text);
|
assertNotNull(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test again with including formulas and cell-comments as this caused some bugs
|
||||||
|
if(extractor instanceof ExcelExtractor &&
|
||||||
|
// comment-extraction and formula extraction are not well supported in event based extraction
|
||||||
|
!(extractor instanceof EventBasedExcelExtractor)) {
|
||||||
|
((ExcelExtractor)extractor).setFormulasNotResults(true);
|
||||||
|
|
||||||
|
String text = extractor.getText();
|
||||||
|
assertNotNull(text);
|
||||||
|
// */
|
||||||
|
|
||||||
|
((ExcelExtractor) extractor).setIncludeCellComments(true);
|
||||||
|
|
||||||
|
text = extractor.getText();
|
||||||
|
assertNotNull(text);
|
||||||
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
if(!EXPECTED_EXTRACTOR_FAILURES.contains(file.getParentFile().getName() + "/" + file.getName())) {
|
if(!EXPECTED_EXTRACTOR_FAILURES.contains(fileAndParentName)) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} catch (EncryptedDocumentException e) {
|
} catch (EncryptedDocumentException e) {
|
||||||
|
|||||||
@ -81,8 +81,7 @@ final class FunctionDataBuilder {
|
|||||||
FunctionMetadata[] jumbledArray = new FunctionMetadata[_functionDataByName.size()];
|
FunctionMetadata[] jumbledArray = new FunctionMetadata[_functionDataByName.size()];
|
||||||
_functionDataByName.values().toArray(jumbledArray);
|
_functionDataByName.values().toArray(jumbledArray);
|
||||||
FunctionMetadata[] fdIndexArray = new FunctionMetadata[_maxFunctionIndex+1];
|
FunctionMetadata[] fdIndexArray = new FunctionMetadata[_maxFunctionIndex+1];
|
||||||
for (int i = 0; i < jumbledArray.length; i++) {
|
for (FunctionMetadata fd : jumbledArray) {
|
||||||
FunctionMetadata fd = jumbledArray[i];
|
|
||||||
fdIndexArray[fd.getIndex()] = fd;
|
fdIndexArray[fd.getIndex()] = fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,7 @@ public final class FunctionMetadata {
|
|||||||
* to make that file more version neutral.
|
* to make that file more version neutral.
|
||||||
* @see org.apache.poi.ss.formula.FormulaParser#validateNumArgs(int, FunctionMetadata)
|
* @see org.apache.poi.ss.formula.FormulaParser#validateNumArgs(int, FunctionMetadata)
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("JavadocReference")
|
||||||
private static final short FUNCTION_MAX_PARAMS = 30;
|
private static final short FUNCTION_MAX_PARAMS = 30;
|
||||||
|
|
||||||
private final int _index;
|
private final int _index;
|
||||||
@ -49,27 +50,35 @@ public final class FunctionMetadata {
|
|||||||
_returnClassCode = returnClassCode;
|
_returnClassCode = returnClassCode;
|
||||||
_parameterClassCodes = (parameterClassCodes == null) ? null : parameterClassCodes.clone();
|
_parameterClassCodes = (parameterClassCodes == null) ? null : parameterClassCodes.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getIndex() {
|
public int getIndex() {
|
||||||
return _index;
|
return _index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinParams() {
|
public int getMinParams() {
|
||||||
return _minParams;
|
return _minParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxParams() {
|
public int getMaxParams() {
|
||||||
return _maxParams;
|
return _maxParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasFixedArgsLength() {
|
public boolean hasFixedArgsLength() {
|
||||||
return _minParams == _maxParams;
|
return _minParams == _maxParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getReturnClassCode() {
|
public byte getReturnClassCode() {
|
||||||
return _returnClassCode;
|
return _returnClassCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getParameterClassCodes() {
|
public byte[] getParameterClassCodes() {
|
||||||
return _parameterClassCodes.clone();
|
return _parameterClassCodes.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some varags functions (like VLOOKUP) have a specific limit to the number of arguments that
|
* Some varags functions (like VLOOKUP) have a specific limit to the number of arguments that
|
||||||
* can be passed. Other functions (like SUM) don't have such a limit. For those functions,
|
* can be passed. Other functions (like SUM) don't have such a limit. For those functions,
|
||||||
@ -80,11 +89,8 @@ public final class FunctionMetadata {
|
|||||||
public boolean hasUnlimitedVarags() {
|
public boolean hasUnlimitedVarags() {
|
||||||
return FUNCTION_MAX_PARAMS == _maxParams;
|
return FUNCTION_MAX_PARAMS == _maxParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuffer sb = new StringBuffer(64);
|
return getClass().getName() + " [" + _index + " " + _name + "]";
|
||||||
sb.append(getClass().getName()).append(" [");
|
|
||||||
sb.append(_index).append(" ").append(_name);
|
|
||||||
sb.append("]");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,7 @@ final class FunctionMetadataReader {
|
|||||||
private static final int MAX_RECORD_LENGTH = 100_000;
|
private static final int MAX_RECORD_LENGTH = 100_000;
|
||||||
|
|
||||||
private static final String METADATA_FILE_NAME = "functionMetadata.txt";
|
private static final String METADATA_FILE_NAME = "functionMetadata.txt";
|
||||||
|
private static final String METADATA_FILE_NAME_CETAB = "functionMetadataCetab.txt";
|
||||||
|
|
||||||
/** plain ASCII text metadata file uses three dots for ellipsis */
|
/** plain ASCII text metadata file uses three dots for ellipsis */
|
||||||
private static final String ELLIPSIS = "...";
|
private static final String ELLIPSIS = "...";
|
||||||
@ -52,51 +53,56 @@ final class FunctionMetadataReader {
|
|||||||
private static final String[] DIGIT_ENDING_FUNCTION_NAMES = {
|
private static final String[] DIGIT_ENDING_FUNCTION_NAMES = {
|
||||||
// Digits at the end of a function might be due to a left-over footnote marker.
|
// Digits at the end of a function might be due to a left-over footnote marker.
|
||||||
// except in these cases
|
// except in these cases
|
||||||
"LOG10", "ATAN2", "DAYS360", "SUMXMY2", "SUMX2MY2", "SUMX2PY2",
|
"LOG10", "ATAN2", "DAYS360", "SUMXMY2", "SUMX2MY2", "SUMX2PY2", "A1.R1C1",
|
||||||
};
|
};
|
||||||
private static final Set<String> DIGIT_ENDING_FUNCTION_NAMES_SET = new HashSet<>(Arrays.asList(DIGIT_ENDING_FUNCTION_NAMES));
|
private static final Set<String> DIGIT_ENDING_FUNCTION_NAMES_SET = new HashSet<>(Arrays.asList(DIGIT_ENDING_FUNCTION_NAMES));
|
||||||
|
|
||||||
public static FunctionMetadataRegistry createRegistry() {
|
public static FunctionMetadataRegistry createRegistry() {
|
||||||
try {
|
FunctionDataBuilder fdb = new FunctionDataBuilder(800);
|
||||||
InputStream is = FunctionMetadataReader.class.getResourceAsStream(METADATA_FILE_NAME);
|
readResourceFile(fdb, METADATA_FILE_NAME);
|
||||||
if (is == null) {
|
return fdb.build();
|
||||||
throw new RuntimeException("resource '" + METADATA_FILE_NAME + "' not found");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
try(BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
|
|
||||||
FunctionDataBuilder fdb = new FunctionDataBuilder(400);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
String line = br.readLine();
|
|
||||||
if (line == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (line.length() < 1 || line.charAt(0) == '#') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String trimLine = line.trim();
|
|
||||||
if (trimLine.length() < 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
processLine(fdb, line);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fdb.build();
|
public static FunctionMetadataRegistry createRegistryCetab() {
|
||||||
}
|
FunctionDataBuilder fdb = new FunctionDataBuilder(800);
|
||||||
} finally {
|
readResourceFile(fdb, METADATA_FILE_NAME_CETAB);
|
||||||
is.close();
|
return fdb.build();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
private static void readResourceFile(FunctionDataBuilder fdb, String resourceFile) {
|
||||||
}
|
try (InputStream is = FunctionMetadataReader.class.getResourceAsStream(resourceFile)) {
|
||||||
|
if (is == null) {
|
||||||
|
throw new RuntimeException("resource '" + resourceFile + "' not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
try(BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
String line = br.readLine();
|
||||||
|
if (line == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (line.length() < 1 || line.charAt(0) == '#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String trimLine = line.trim();
|
||||||
|
if (trimLine.length() < 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
processLine(fdb, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void processLine(FunctionDataBuilder fdb, String line) {
|
private static void processLine(FunctionDataBuilder fdb, String line) {
|
||||||
|
|
||||||
String[] parts = TAB_DELIM_PATTERN.split(line, -2);
|
String[] parts = TAB_DELIM_PATTERN.split(line, -2);
|
||||||
if(parts.length != 8) {
|
if(parts.length != 8) {
|
||||||
throw new RuntimeException("Bad line format '" + line + "' - expected 8 data fields");
|
throw new RuntimeException("Bad line format '" + line + "' - expected 8 data fields delimited by tab, " +
|
||||||
|
"but had " + parts.length + ": " + Arrays.toString(parts));
|
||||||
}
|
}
|
||||||
int functionIndex = parseInt(parts[0]);
|
int functionIndex = parseInt(parts[0]);
|
||||||
String functionName = parts[1];
|
String functionName = parts[1];
|
||||||
|
|||||||
@ -37,6 +37,7 @@ public final class FunctionMetadataRegistry {
|
|||||||
public static final short FUNCTION_INDEX_EXTERNAL = 255;
|
public static final short FUNCTION_INDEX_EXTERNAL = 255;
|
||||||
|
|
||||||
private static FunctionMetadataRegistry _instance;
|
private static FunctionMetadataRegistry _instance;
|
||||||
|
private static FunctionMetadataRegistry _instanceCetab;
|
||||||
|
|
||||||
private final FunctionMetadata[] _functionDataByIndex;
|
private final FunctionMetadata[] _functionDataByIndex;
|
||||||
private final Map<String, FunctionMetadata> _functionDataByName;
|
private final Map<String, FunctionMetadata> _functionDataByName;
|
||||||
@ -48,6 +49,13 @@ public final class FunctionMetadataRegistry {
|
|||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static FunctionMetadataRegistry getInstanceCetab() {
|
||||||
|
if (_instanceCetab == null) {
|
||||||
|
_instanceCetab = FunctionMetadataReader.createRegistryCetab();
|
||||||
|
}
|
||||||
|
return _instanceCetab;
|
||||||
|
}
|
||||||
|
|
||||||
/* package */ FunctionMetadataRegistry(FunctionMetadata[] functionDataByIndex, Map<String, FunctionMetadata> functionDataByName) {
|
/* package */ FunctionMetadataRegistry(FunctionMetadata[] functionDataByIndex, Map<String, FunctionMetadata> functionDataByName) {
|
||||||
_functionDataByIndex = (functionDataByIndex == null) ? null : functionDataByIndex.clone();
|
_functionDataByIndex = (functionDataByIndex == null) ? null : functionDataByIndex.clone();
|
||||||
_functionDataByName = functionDataByName;
|
_functionDataByName = functionDataByName;
|
||||||
@ -62,6 +70,10 @@ public final class FunctionMetadataRegistry {
|
|||||||
return getInstance().getFunctionByIndexInternal(index);
|
return getInstance().getFunctionByIndexInternal(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FunctionMetadata getCetabFunctionByIndex(int index) {
|
||||||
|
return getInstanceCetab().getFunctionByIndexInternal(index);
|
||||||
|
}
|
||||||
|
|
||||||
private FunctionMetadata getFunctionByIndexInternal(int index) {
|
private FunctionMetadata getFunctionByIndexInternal(int index) {
|
||||||
return _functionDataByIndex[index];
|
return _functionDataByIndex[index];
|
||||||
}
|
}
|
||||||
@ -74,7 +86,11 @@ public final class FunctionMetadataRegistry {
|
|||||||
public static short lookupIndexByName(String name) {
|
public static short lookupIndexByName(String name) {
|
||||||
FunctionMetadata fd = getInstance().getFunctionByNameInternal(name);
|
FunctionMetadata fd = getInstance().getFunctionByNameInternal(name);
|
||||||
if (fd == null) {
|
if (fd == null) {
|
||||||
return -1;
|
// also try the cetab functions
|
||||||
|
fd = getInstanceCetab().getFunctionByNameInternal(name);
|
||||||
|
if (fd == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (short) fd.getIndex();
|
return (short) fd.getIndex();
|
||||||
}
|
}
|
||||||
@ -83,8 +99,12 @@ public final class FunctionMetadataRegistry {
|
|||||||
return _functionDataByName.get(name);
|
return _functionDataByName.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static FunctionMetadata getFunctionByName(String name) {
|
public static FunctionMetadata getFunctionByName(String name) {
|
||||||
return getInstance().getFunctionByNameInternal(name);
|
FunctionMetadata fm = getInstance().getFunctionByNameInternal(name);
|
||||||
|
if(fm == null) {
|
||||||
|
return getInstanceCetab().getFunctionByNameInternal(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -123,13 +123,22 @@ public abstract class AbstractFunctionPtg extends OperationPtg {
|
|||||||
return ix >= 0;
|
return ix >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final String lookupName(short index) {
|
protected String lookupName(short index) {
|
||||||
|
return lookupName(index, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final String lookupName(short index, boolean isCetab) {
|
||||||
if(index == FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL) {
|
if(index == FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL) {
|
||||||
return "#external#";
|
return "#external#";
|
||||||
}
|
}
|
||||||
FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(index);
|
final FunctionMetadata fm;
|
||||||
|
if(isCetab) {
|
||||||
|
fm = FunctionMetadataRegistry.getCetabFunctionByIndex(index);
|
||||||
|
} else {
|
||||||
|
fm = FunctionMetadataRegistry.getFunctionByIndex(index);
|
||||||
|
}
|
||||||
if(fm == null) {
|
if(fm == null) {
|
||||||
throw new RuntimeException("bad function index (" + index + ")");
|
throw new RuntimeException("bad function index (" + index + ", " + isCetab + ")");
|
||||||
}
|
}
|
||||||
return fm.getName();
|
return fm.getName();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,9 +69,6 @@ public final class ExpPtg extends ControlPtg {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuffer buffer = new StringBuffer("[Array Formula or Shared Formula]\n");
|
return "[Array Formula or Shared Formula]\n" + "row = " + getRow() + "\n" + "col = " + getColumn() + "\n";
|
||||||
buffer.append("row = ").append(getRow()).append("\n");
|
|
||||||
buffer.append("col = ").append(getColumn()).append("\n");
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,8 @@
|
|||||||
package org.apache.poi.ss.formula.ptg;
|
package org.apache.poi.ss.formula.ptg;
|
||||||
import org.apache.poi.ss.formula.function.FunctionMetadata;
|
import org.apache.poi.ss.formula.function.FunctionMetadata;
|
||||||
import org.apache.poi.ss.formula.function.FunctionMetadataRegistry;
|
import org.apache.poi.ss.formula.function.FunctionMetadataRegistry;
|
||||||
|
import org.apache.poi.util.BitField;
|
||||||
|
import org.apache.poi.util.BitFieldFactory;
|
||||||
import org.apache.poi.util.LittleEndianInput;
|
import org.apache.poi.util.LittleEndianInput;
|
||||||
import org.apache.poi.util.LittleEndianOutput;
|
import org.apache.poi.util.LittleEndianOutput;
|
||||||
|
|
||||||
@ -25,24 +27,29 @@ import org.apache.poi.util.LittleEndianOutput;
|
|||||||
* @author Jason Height (jheight at chariot dot net dot au)
|
* @author Jason Height (jheight at chariot dot net dot au)
|
||||||
*/
|
*/
|
||||||
public final class FuncVarPtg extends AbstractFunctionPtg{
|
public final class FuncVarPtg extends AbstractFunctionPtg{
|
||||||
|
|
||||||
public final static byte sid = 0x22;
|
public final static byte sid = 0x22;
|
||||||
private final static int SIZE = 4;
|
private final static int SIZE = 4;
|
||||||
|
|
||||||
|
// See spec at 2.5.198.63 PtgFuncVar
|
||||||
|
private static final BitField ceFunc = BitFieldFactory.getInstance(0xF000);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single instance of this token for 'sum() taking a single argument'
|
* Single instance of this token for 'sum() taking a single argument'
|
||||||
*/
|
*/
|
||||||
public static final OperationPtg SUM = FuncVarPtg.create("SUM", 1);
|
public static final OperationPtg SUM = FuncVarPtg.create("SUM", 1);
|
||||||
|
|
||||||
private FuncVarPtg(int functionIndex, int returnClass, byte[] paramClasses, int numArgs) {
|
private final boolean _isCetab;
|
||||||
|
|
||||||
|
private FuncVarPtg(int functionIndex, int returnClass, byte[] paramClasses, int numArgs, boolean isCetab) {
|
||||||
super(functionIndex, returnClass, paramClasses, numArgs);
|
super(functionIndex, returnClass, paramClasses, numArgs);
|
||||||
|
_isCetab = isCetab;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Creates new function pointer from a byte array
|
/**Creates new function pointer from a byte array
|
||||||
* usually called while reading an excel file.
|
* usually called while reading an excel file.
|
||||||
*/
|
*/
|
||||||
public static FuncVarPtg create(LittleEndianInput in) {
|
public static FuncVarPtg create(LittleEndianInput in) {
|
||||||
return create(in.readByte(), in.readShort());
|
return create(in.readByte(), in.readUShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,12 +60,25 @@ public final class FuncVarPtg extends AbstractFunctionPtg{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static FuncVarPtg create(int numArgs, int functionIndex) {
|
private static FuncVarPtg create(int numArgs, int functionIndex) {
|
||||||
FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByIndex(functionIndex);
|
final FunctionMetadata fm;
|
||||||
if(fm == null) {
|
boolean isCetab = ceFunc.isSet(functionIndex);
|
||||||
// Happens only as a result of a call to FormulaParser.parse(), with a non-built-in function name
|
if(isCetab) {
|
||||||
return new FuncVarPtg(functionIndex, Ptg.CLASS_VALUE, new byte[] {Ptg.CLASS_VALUE}, numArgs);
|
functionIndex = ceFunc.clear(functionIndex);
|
||||||
|
fm = FunctionMetadataRegistry.getCetabFunctionByIndex(functionIndex);
|
||||||
|
} else {
|
||||||
|
fm = FunctionMetadataRegistry.getFunctionByIndex(functionIndex);
|
||||||
}
|
}
|
||||||
return new FuncVarPtg(functionIndex, fm.getReturnClassCode(), fm.getParameterClassCodes(), numArgs);
|
|
||||||
|
if (fm == null) {
|
||||||
|
// Happens only as a result of a call to FormulaParser.parse(), with a non-built-in function name
|
||||||
|
return new FuncVarPtg(functionIndex, Ptg.CLASS_VALUE, new byte[]{Ptg.CLASS_VALUE}, numArgs, isCetab);
|
||||||
|
}
|
||||||
|
return new FuncVarPtg(functionIndex, fm.getReturnClassCode(), fm.getParameterClassCodes(), numArgs, isCetab);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String lookupName(short index) {
|
||||||
|
return lookupName(index, _isCetab);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(LittleEndianOutput out) {
|
public void write(LittleEndianOutput out) {
|
||||||
|
|||||||
@ -74,6 +74,8 @@
|
|||||||
50 TREND 1 3 A R R R x
|
50 TREND 1 3 A R R R x
|
||||||
51 LOGEST 1 2 A R R x
|
51 LOGEST 1 2 A R R x
|
||||||
52 GROWTH 1 3 A R R R x
|
52 GROWTH 1 3 A R R R x
|
||||||
|
53 GOTO 1 1 R R
|
||||||
|
55 RETURN 1 1 V V
|
||||||
56 PV 3 5 V V V V V V
|
56 PV 3 5 V V V V V V
|
||||||
# Built-In Sheet Functions in BIFF2
|
# Built-In Sheet Functions in BIFF2
|
||||||
57 FV 3 5 V V V V V V
|
57 FV 3 5 V V V V V V
|
||||||
@ -98,8 +100,13 @@
|
|||||||
76 ROWS 1 1 V A
|
76 ROWS 1 1 V A
|
||||||
77 COLUMNS 1 1 V A
|
77 COLUMNS 1 1 V A
|
||||||
78 OFFSET 3 5 R R V V V V x
|
78 OFFSET 3 5 R R V V V V x
|
||||||
|
79 ABSREF 2 2 R V R
|
||||||
|
80 RELREF 2 2 R V V
|
||||||
|
81 ARGUMENT 0 3 V V V R
|
||||||
82 SEARCH 2 3 V V V V
|
82 SEARCH 2 3 V V V V
|
||||||
83 TRANSPOSE 1 1 A A
|
83 TRANSPOSE 1 1 A A
|
||||||
|
84 ERROR 0 2 V V R
|
||||||
|
85 STEP 0 0
|
||||||
86 TYPE 1 1 V V
|
86 TYPE 1 1 V V
|
||||||
97 ATAN2 2 2 V V V
|
97 ATAN2 2 2 V V V
|
||||||
98 ASIN 1 1 V V
|
98 ASIN 1 1 V V
|
||||||
@ -109,6 +116,7 @@
|
|||||||
102 VLOOKUP 3 3 V V R R x
|
102 VLOOKUP 3 3 V V R R x
|
||||||
105 ISREF 1 1 V R
|
105 ISREF 1 1 V R
|
||||||
109 LOG 1 2 V V V
|
109 LOG 1 2 V V V
|
||||||
|
110 EXEC 1 4 V V V V V
|
||||||
111 CHAR 1 1 V V
|
111 CHAR 1 1 V V
|
||||||
112 LOWER 1 1 V V
|
112 LOWER 1 1 V V
|
||||||
113 UPPER 1 1 V V
|
113 UPPER 1 1 V V
|
||||||
@ -134,6 +142,7 @@
|
|||||||
143 SYD 4 4 V V V V V
|
143 SYD 4 4 V V V V V
|
||||||
144 DDB 4 5 V V V V V V
|
144 DDB 4 5 V V V V V V
|
||||||
148 INDIRECT 1 2 R V V x
|
148 INDIRECT 1 2 R V V x
|
||||||
|
150 CALL 1 3 V V R R
|
||||||
162 CLEAN 1 1 V V
|
162 CLEAN 1 1 V V
|
||||||
163 MDETERM 1 1 V A
|
163 MDETERM 1 1 V A
|
||||||
164 MINVERSE 1 1 A A
|
164 MINVERSE 1 1 A A
|
||||||
@ -143,6 +152,10 @@
|
|||||||
169 COUNTA 0 30 V R
|
169 COUNTA 0 30 V R
|
||||||
183 PRODUCT 0 30 V R
|
183 PRODUCT 0 30 V R
|
||||||
184 FACT 1 1 V V
|
184 FACT 1 1 V V
|
||||||
|
185 GET.CELL 1 2 V V R
|
||||||
|
186 GET.WORKSPACE 1 1 V V
|
||||||
|
187 GET.WINDOW 1 2 V V V
|
||||||
|
188 GET.DOCUMENT 1 2 V V V
|
||||||
189 DPRODUCT 3 3 V R R R
|
189 DPRODUCT 3 3 V R R R
|
||||||
190 ISNONTEXT 1 1 V V
|
190 ISNONTEXT 1 1 V V
|
||||||
193 STDEVP 1 30 V R
|
193 STDEVP 1 30 V R
|
||||||
@ -174,6 +187,7 @@
|
|||||||
220 DAYS360 2 2 V V V x
|
220 DAYS360 2 2 V V V x
|
||||||
221 TODAY 0 0 V - x
|
221 TODAY 0 0 V - x
|
||||||
222 VDB 5 7 V V V V V V V V
|
222 VDB 5 7 V V V V V V V V
|
||||||
|
225 END.IF 0 0
|
||||||
227 MEDIAN 1 30 V R ...
|
227 MEDIAN 1 30 V R ...
|
||||||
228 SUMPRODUCT 1 30 V A ...
|
228 SUMPRODUCT 1 30 V A ...
|
||||||
229 SINH 1 1 V V
|
229 SINH 1 1 V V
|
||||||
@ -187,11 +201,20 @@
|
|||||||
# New Built-In Sheet Functions in BIFF4
|
# New Built-In Sheet Functions in BIFF4
|
||||||
14 FIXED 1 3 V V V V x
|
14 FIXED 1 3 V V V V x
|
||||||
204 USDOLLAR 1 2 V V V x
|
204 USDOLLAR 1 2 V V V x
|
||||||
|
238 LAST.ERROR 0 0
|
||||||
215 DBCS 1 1 V V x
|
215 DBCS 1 1 V V x
|
||||||
216 RANK 2 3 V V R V
|
216 RANK 2 3 V V R V
|
||||||
247 DB 4 5 V V V V V V
|
247 DB 4 5 V V V V V V
|
||||||
252 FREQUENCY 2 2 A R R
|
252 FREQUENCY 2 2 A R R
|
||||||
|
257 EVALUATE 1 1 V V
|
||||||
261 ERROR.TYPE 1 1 V V
|
261 ERROR.TYPE 1 1 V V
|
||||||
|
262 APP.TITLE 0 1 V V
|
||||||
|
263 WINDOW.TITLE 0 1 V V
|
||||||
|
264 SAVE.TOOLBAR 0 2 V V V
|
||||||
|
265 ENABLE.TOOL 3 3 V V V V
|
||||||
|
266 PRESS.TOOL 3 3 V V V V
|
||||||
|
267 REGISTER.ID 2 3 V V V V
|
||||||
|
268 GET.WORKBOOK 1 2 V V V
|
||||||
269 AVEDEV 1 30 V R ...
|
269 AVEDEV 1 30 V R ...
|
||||||
270 BETADIST 3 5 V V V V V V
|
270 BETADIST 3 5 V V V V V V
|
||||||
271 GAMMALN 1 1 V V
|
271 GAMMALN 1 1 V V
|
||||||
@ -272,13 +295,13 @@
|
|||||||
350 ISPMT 4 4 V V V V V
|
350 ISPMT 4 4 V V V V V
|
||||||
351 DATEDIF 3 3 V V V V
|
351 DATEDIF 3 3 V V V V
|
||||||
352 DATESTRING 1 1 V V
|
352 DATESTRING 1 1 V V
|
||||||
353 NUMBERSTRING 2 2 V V V
|
353 NUMBERSTRING 2 2 V V V
|
||||||
354 ROMAN 1 2 V V V
|
354 ROMAN 1 2 V V V
|
||||||
# New Built-In Sheet Functions in BIFF8
|
# New Built-In Sheet Functions in BIFF8
|
||||||
358 GETPIVOTDATA 2 30 V V R ...
|
358 GETPIVOTDATA 2 30 V V R ...
|
||||||
359 HYPERLINK 1 2 V V V
|
359 HYPERLINK 1 2 V V V
|
||||||
360 PHONETIC 1 1 V R
|
360 PHONETIC 1 1 V R
|
||||||
361 AVERAGEA 1 30 V R ...
|
361 AVERAGEA 1 30 V R ...
|
||||||
362 MAXA 1 30 V R ...
|
362 MAXA 1 30 V R ...
|
||||||
363 MINA 1 30 V R ...
|
363 MINA 1 30 V R ...
|
||||||
364 STDEVPA 1 30 V R ...
|
364 STDEVPA 1 30 V R ...
|
||||||
|
|||||||
@ -0,0 +1,417 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
# Created by (org.apache.poi.ss.formula.function.ExcelCetabFunctionExtractor)
|
||||||
|
# from source file 'org/apache/poi/ss/formula/function/functionMetadataCetab-PDF.txt'
|
||||||
|
#
|
||||||
|
#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )
|
||||||
|
|
||||||
|
#
|
||||||
|
0 BEEP 0 0
|
||||||
|
1 OPEN 0 0
|
||||||
|
2 OPEN.LINKS 0 0
|
||||||
|
3 CLOSE.ALL 0 0
|
||||||
|
4 SAVE 0 0
|
||||||
|
5 SAVE.AS 0 0
|
||||||
|
6 FILE.DELETE 0 0
|
||||||
|
7 PAGE.SETUP 0 0
|
||||||
|
8 PRINT 0 0
|
||||||
|
9 PRINTER.SETUP 0 0
|
||||||
|
10 QUIT 0 0
|
||||||
|
11 NEW.WINDOW 0 0
|
||||||
|
12 ARRANGE.ALL 0 0
|
||||||
|
13 WINDOW.SIZE 0 0
|
||||||
|
14 WINDOW.MOVE 0 0
|
||||||
|
15 FULL 0 0
|
||||||
|
16 CLOSE 0 0
|
||||||
|
17 RUN 0 0
|
||||||
|
22 SET.PRINT.AREA 0 0
|
||||||
|
23 SET.PRINT.TITLES 0 0
|
||||||
|
24 SET.PAGE.BREAK 0 0
|
||||||
|
25 REMOVE.PAGE.BREAK 0 0
|
||||||
|
26 FONT 0 0
|
||||||
|
27 DISPLAY 0 0
|
||||||
|
28 PROTECT.DOCUMENT 0 0
|
||||||
|
29 PRECISION 0 0
|
||||||
|
30 A1.R1C1 0 0
|
||||||
|
31 CALCULATE.NOW 0 0
|
||||||
|
32 CALCULATION 0 0
|
||||||
|
34 DATA.FIND 0 0
|
||||||
|
35 EXTRACT 0 0
|
||||||
|
36 DATA.DELETE 0 0
|
||||||
|
37 SET.DATABASE 0 0
|
||||||
|
38 SET.CRITERIA 0 0
|
||||||
|
39 SORT 0 0
|
||||||
|
40 DATA.SERIES 0 0
|
||||||
|
41 TABLE 0 0
|
||||||
|
42 FORMAT.NUMBER 0 0
|
||||||
|
43 ALIGNMENT 0 0
|
||||||
|
44 STYLE 0 0
|
||||||
|
45 BORDER 0 0
|
||||||
|
46 CELL.PROTECTION 0 0
|
||||||
|
47 COLUMN.WIDTH 0 0
|
||||||
|
48 UNDO 0 0
|
||||||
|
49 CUT 0 0
|
||||||
|
50 COPY 0 0
|
||||||
|
51 PASTE 0 0
|
||||||
|
52 CLEAR 0 0
|
||||||
|
53 PASTE.SPECIAL 0 0
|
||||||
|
54 EDIT.DELETE 0 0
|
||||||
|
55 INSERT 0 0
|
||||||
|
56 FILL.RIGHT 0 0
|
||||||
|
57 FILL.DOWN 0 0
|
||||||
|
61 DEFINE.NAME 0 0
|
||||||
|
62 CREATE.NAMES 0 0
|
||||||
|
63 FORMULA.GOTO 0 0
|
||||||
|
64 FORMULA.FIND 0 0
|
||||||
|
65 SELECT.LAST.CELL 0 0
|
||||||
|
66 SHOW.ACTIVE.CELL 0 0
|
||||||
|
67 GALLERY.AREA 0 0
|
||||||
|
68 GALLERY.BAR 0 0
|
||||||
|
69 GALLERY.COLUMN 0 0
|
||||||
|
70 GALLERY.LINE 0 0
|
||||||
|
71 GALLERY.PIE 0 0
|
||||||
|
72 GALLERY.SCATTER 0 0
|
||||||
|
73 COMBINATION 0 0
|
||||||
|
74 PREFERRED 0 0
|
||||||
|
75 ADD.OVERLAY 0 0
|
||||||
|
76 GRIDLINES 0 0
|
||||||
|
77 SET.PREFERRED 0 0
|
||||||
|
78 AXES 0 0
|
||||||
|
79 LEGEND 0 0
|
||||||
|
80 ATTACH.TEXT 0 0
|
||||||
|
81 ADD.ARROW 0 0
|
||||||
|
82 SELECT.CHART 0 0
|
||||||
|
83 SELECT.PLOT.AREA 0 0
|
||||||
|
84 PATTERNS 0 0
|
||||||
|
85 MAIN.CHART 0 0
|
||||||
|
86 OVERLAY 0 0
|
||||||
|
87 SCALE 0 0
|
||||||
|
88 FORMAT.LEGEND 0 0
|
||||||
|
89 FORMAT.TEXT 0 0
|
||||||
|
90 EDIT.REPEAT 0 0
|
||||||
|
91 PARSE 0 0
|
||||||
|
92 JUSTIFY 0 0
|
||||||
|
93 HIDE 0 0
|
||||||
|
94 UNHIDE 0 0
|
||||||
|
95 WORKSPACE 0 0
|
||||||
|
96 FORMULA 0 0
|
||||||
|
97 FORMULA.FILL 0 0
|
||||||
|
98 FORMULA.ARRAY 0 0
|
||||||
|
99 DATA.FIND.NEXT 0 0
|
||||||
|
100 DATA.FIND.PREV 0 0
|
||||||
|
101 FORMULA.FIND.NEXT 0 0
|
||||||
|
102 FORMULA.FIND.PREV 0 0
|
||||||
|
103 ACTIVATE 0 0
|
||||||
|
104 ACTIVATE.NEXT 0 0
|
||||||
|
105 ACTIVATE.PREV 0 0
|
||||||
|
106 UNLOCKED.NEXT 0 0
|
||||||
|
107 UNLOCKED.PREV 0 0
|
||||||
|
108 COPY.PICTURE 0 0
|
||||||
|
109 SELECT 0 0
|
||||||
|
110 DELETE.NAME 0 0
|
||||||
|
111 DELETE.FORMAT 0 0
|
||||||
|
112 VLINE 0 0
|
||||||
|
113 HLINE 0 0
|
||||||
|
114 VPAGE 0 0
|
||||||
|
115 HPAGE 0 0
|
||||||
|
116 VSCROLL 0 0
|
||||||
|
117 HSCROLL 0 0
|
||||||
|
118 ALERT 0 0
|
||||||
|
119 NEW 0 0
|
||||||
|
120 CANCEL.COPY 0 0
|
||||||
|
121 SHOW.CLIPBOARD 0 0
|
||||||
|
122 MESSAGE 0 0
|
||||||
|
124 PASTE.LINK 0 0
|
||||||
|
125 APP.ACTIVATE 0 0
|
||||||
|
126 DELETE.ARROW 0 0
|
||||||
|
127 ROW.HEIGHT 0 0
|
||||||
|
128 FORMAT.MOVE 0 0
|
||||||
|
129 FORMAT.SIZE 0 0
|
||||||
|
130 FORMULA.REPLACE 0 0
|
||||||
|
131 SEND.KEYS 0 0
|
||||||
|
132 SELECT.SPECIAL 0 0
|
||||||
|
133 APPLY.NAMES 0 0
|
||||||
|
134 REPLACE.FONT 0 0
|
||||||
|
135 FREEZE.PANES 0 0
|
||||||
|
136 SHOW.INFO 0 0
|
||||||
|
137 SPLIT 0 0
|
||||||
|
138 ON.WINDOW 0 0
|
||||||
|
139 ON.DATA 0 0
|
||||||
|
140 DISABLE.INPUT 0 0
|
||||||
|
142 OUTLINE 0 0
|
||||||
|
143 LIST.NAMES 0 0
|
||||||
|
144 FILE.CLOSE 0 0
|
||||||
|
145 SAVE.WORKBOOK 0 0
|
||||||
|
146 DATA.FORM 0 0
|
||||||
|
147 COPY.CHART 0 0
|
||||||
|
148 ON.TIME 0 0
|
||||||
|
149 WAIT 0 0
|
||||||
|
150 FORMAT.FONT 0 0
|
||||||
|
151 FILL.UP 0 0
|
||||||
|
152 FILL.LEFT 0 0
|
||||||
|
153 DELETE.OVERLAY 0 0
|
||||||
|
155 SHORT.MENUS 0 0
|
||||||
|
159 SET.UPDATE.STATUS 0 0
|
||||||
|
161 COLOR.PALETTE 0 0
|
||||||
|
162 DELETE.STYLE 0 0
|
||||||
|
163 WINDOW.RESTORE 0 0
|
||||||
|
164 WINDOW.MAXIMIZE 0 0
|
||||||
|
166 CHANGE.LINK 0 0
|
||||||
|
167 CALCULATE.DOCUMENT 0 0
|
||||||
|
168 ON.KEY 0 0
|
||||||
|
169 APP.RESTORE 0 0
|
||||||
|
170 APP.MOVE 0 0
|
||||||
|
171 APP.SIZE 0 0
|
||||||
|
172 APP.MINIMIZE 0 0
|
||||||
|
173 APP.MAXIMIZE 0 0
|
||||||
|
174 BRING.TO.FRONT 0 0
|
||||||
|
175 SEND.TO.BACK 0 0
|
||||||
|
185 MAIN.CHART.TYPE 0 0
|
||||||
|
186 OVERLAY.CHART.TYPE 0 0
|
||||||
|
187 SELECT.END 0 0
|
||||||
|
188 OPEN.MAIL 0 0
|
||||||
|
189 SEND.MAIL 0 0
|
||||||
|
190 STANDARD.FONT 0 0
|
||||||
|
191 CONSOLIDATE 0 0
|
||||||
|
192 SORT.SPECIAL 0 0
|
||||||
|
193 GALLERY.3D.AREA 0 0
|
||||||
|
194 GALLERY.3D.COLUMN 0 0
|
||||||
|
195 GALLERY.3D.LINE 0 0
|
||||||
|
196 GALLERY.3D.PIE 0 0
|
||||||
|
197 VIEW.3D 0 0
|
||||||
|
198 GOAL.SEEK 0 0
|
||||||
|
199 WORKGROUP 0 0
|
||||||
|
200 FILL.GROUP 0 0
|
||||||
|
201 UPDATE.LINK 0 0
|
||||||
|
202 PROMOTE 0 0
|
||||||
|
203 DEMOTE 0 0
|
||||||
|
204 SHOW.DETAIL 0 0
|
||||||
|
206 UNGROUP 0 0
|
||||||
|
207 OBJECT.PROPERTIES 0 0
|
||||||
|
208 SAVE.NEW.OBJECT 0 0
|
||||||
|
209 SHARE 0 0
|
||||||
|
210 SHARE.NAME 0 0
|
||||||
|
211 DUPLICATE 0 0
|
||||||
|
212 APPLY.STYLE 0 0
|
||||||
|
213 ASSIGN.TO.OBJECT 0 0
|
||||||
|
214 OBJECT.PROTECTION 0 0
|
||||||
|
215 HIDE.OBJECT 0 0
|
||||||
|
216 SET.EXTRACT 0 0
|
||||||
|
217 CREATE.PUBLISHER 0 0
|
||||||
|
218 SUBSCRIBE.TO 0 0
|
||||||
|
219 ATTRIBUTES 0 0
|
||||||
|
220 SHOW.TOOLBAR 0 0
|
||||||
|
222 PRINT.PREVIEW 0 0
|
||||||
|
223 EDIT.COLOR 0 0
|
||||||
|
224 SHOW.LEVELS 0 0
|
||||||
|
225 FORMAT.MAIN 0 0
|
||||||
|
226 FORMAT.OVERLAY 0 0
|
||||||
|
227 ON.RECALC 0 0
|
||||||
|
228 EDIT.SERIES 0 0
|
||||||
|
229 DEFINE.STYLE 0 0
|
||||||
|
240 LINE.PRINT 0 0
|
||||||
|
243 ENTER.DATA 0 0
|
||||||
|
249 GALLERY.RADAR 0 0
|
||||||
|
250 MERGE.STYLES 0 0
|
||||||
|
251 EDITION.OPTIONS 0 0
|
||||||
|
252 PASTE.PICTURE 0 0
|
||||||
|
253 PASTE.PICTURE.LINK 0 0
|
||||||
|
254 SPELLING 0 0
|
||||||
|
256 ZOOM 0 0
|
||||||
|
259 INSERT.OBJECT 0 0
|
||||||
|
260 WINDOW.MINIMIZE 0 0
|
||||||
|
265 SOUND.NOTE 0 0
|
||||||
|
266 SOUND.PLAY 0 0
|
||||||
|
267 FORMAT.SHAPE 0 0
|
||||||
|
268 EXTEND.POLYGON 0 0
|
||||||
|
269 FORMAT.AUTO 0 0
|
||||||
|
272 GALLERY.3D.BAR 0 0
|
||||||
|
273 GALLERY.3D.SURFACE 0 0
|
||||||
|
274 FILL.AUTO 0 0
|
||||||
|
276 CUSTOMIZE.TOOLBAR 0 0
|
||||||
|
277 ADD.TOOL 0 0
|
||||||
|
278 EDIT.OBJECT 0 0
|
||||||
|
279 ON.DOUBLECLICK 0 0
|
||||||
|
280 ON.ENTRY 0 0
|
||||||
|
281 WORKBOOK.ADD 0 0
|
||||||
|
282 WORKBOOK.MOVE 0 0
|
||||||
|
283 WORKBOOK.COPY 0 0
|
||||||
|
284 WORKBOOK.OPTIONS 0 0
|
||||||
|
285 SAVE.WORKSPACE 0 0
|
||||||
|
288 CHART.WIZARD 0 0
|
||||||
|
289 DELETE.TOOL 0 0
|
||||||
|
290 MOVE.TOOL 0 0
|
||||||
|
291 WORKBOOK.SELECT 0 0
|
||||||
|
292 WORKBOOK.ACTIVATE 0 0
|
||||||
|
293 ASSIGN.TO.TOOL 0 0
|
||||||
|
295 COPY.TOOL 0 0
|
||||||
|
296 RESET.TOOL 0 0
|
||||||
|
297 CONSTRAIN.NUMERIC 0 0
|
||||||
|
298 PASTE.TOOL 0 0
|
||||||
|
302 WORKBOOK.NEW 0 0
|
||||||
|
305 SCENARIO.CELLS 0 0
|
||||||
|
306 SCENARIO.DELETE 0 0
|
||||||
|
307 SCENARIO.ADD 0 0
|
||||||
|
308 SCENARIO.EDIT 0 0
|
||||||
|
309 SCENARIO.SHOW 0 0
|
||||||
|
310 SCENARIO.SHOW.NEXT 0 0
|
||||||
|
311 SCENARIO.SUMMARY 0 0
|
||||||
|
312 PIVOT.TABLE.WIZARD 0 0
|
||||||
|
313 PIVOT.FIELD.PROPERTIES 0 0
|
||||||
|
314 PIVOT.FIELD 0 0
|
||||||
|
315 PIVOT.ITEM 0 0
|
||||||
|
316 PIVOT.ADD.FIELDS 0 0
|
||||||
|
318 OPTIONS.CALCULATION 0 0
|
||||||
|
319 OPTIONS.EDIT 0 0
|
||||||
|
320 OPTIONS.VIEW 0 0
|
||||||
|
321 ADDIN.MANAGER 0 0
|
||||||
|
322 MENU.EDITOR 0 0
|
||||||
|
323 ATTACH.TOOLBARS 0 0
|
||||||
|
324 VBAActivate 0 0
|
||||||
|
325 OPTIONS.CHART 0 0
|
||||||
|
328 VBA.INSERT.FILE 0 0
|
||||||
|
330 VBA.PROCEDURE.DEFINITION 0 0
|
||||||
|
336 ROUTING.SLIP 0 0
|
||||||
|
338 ROUTE.DOCUMENT 0 0
|
||||||
|
339 MAIL.LOGON 0 0
|
||||||
|
342 INSERT.PICTURE 0 0
|
||||||
|
343 EDIT.TOOL 0 0
|
||||||
|
344 GALLERY.DOUGHNUT 0 0
|
||||||
|
350 CHART.TREND 0 0
|
||||||
|
352 PIVOT.ITEM.PROPERTIES 0 0
|
||||||
|
354 WORKBOOK.INSERT 0 0
|
||||||
|
355 OPTIONS.TRANSITION 0 0
|
||||||
|
356 OPTIONS.GENERAL 0 0
|
||||||
|
370 FILTER.ADVANCED 0 0
|
||||||
|
373 MAIL.ADD.MAILER 0 0
|
||||||
|
374 MAIL.DELETE.MAILER 0 0
|
||||||
|
375 MAIL.REPLY 0 0
|
||||||
|
376 MAIL.REPLY.ALL 0 0
|
||||||
|
377 MAIL.FORWARD 0 0
|
||||||
|
378 MAIL.NEXT.LETTER 0 0
|
||||||
|
379 DATA.LABEL 0 0
|
||||||
|
380 INSERT.TITLE 0 0
|
||||||
|
381 FONT.PROPERTIES 0 0
|
||||||
|
382 MACRO.OPTIONS 0 0
|
||||||
|
383 WORKBOOK.HIDE 0 0
|
||||||
|
384 WORKBOOK.UNHIDE 0 0
|
||||||
|
385 WORKBOOK.DELETE 0 0
|
||||||
|
386 WORKBOOK.NAME 0 0
|
||||||
|
388 GALLERY.CUSTOM 0 0
|
||||||
|
390 ADD.CHART.AUTOFORMAT 0 0
|
||||||
|
391 DELETE.CHART.AUTOFORMAT 0 0
|
||||||
|
392 CHART.ADD.DATA 0 0
|
||||||
|
393 AUTO.OUTLINE 0 0
|
||||||
|
394 TAB.ORDER 0 0
|
||||||
|
395 SHOW.DIALOG 0 0
|
||||||
|
396 SELECT.ALL 0 0
|
||||||
|
397 UNGROUP.SHEETS 0 0
|
||||||
|
398 SUBTOTAL.CREATE 0 0
|
||||||
|
399 SUBTOTAL.REMOVE 0 0
|
||||||
|
400 RENAME.OBJECT 0 0
|
||||||
|
412 WORKBOOK.SCROLL 0 0
|
||||||
|
413 WORKBOOK.NEXT 0 0
|
||||||
|
414 WORKBOOK.PREV 0 0
|
||||||
|
415 WORKBOOK.TAB.SPLIT 0 0
|
||||||
|
416 FULL.SCREEN 0 0
|
||||||
|
417 WORKBOOK.PROTECT 0 0
|
||||||
|
420 SCROLLBAR.PROPERTIES 0 0
|
||||||
|
421 PIVOT.SHOW.PAGES 0 0
|
||||||
|
422 TEXT.TO.COLUMNS 0 0
|
||||||
|
423 FORMAT.CHARTTYPE 0 0
|
||||||
|
424 LINK.FORMAT 0 0
|
||||||
|
425 TRACER.DISPLAY 0 0
|
||||||
|
430 TRACER.NAVIGATE 0 0
|
||||||
|
431 TRACER.CLEAR 0 0
|
||||||
|
432 TRACER.ERROR 0 0
|
||||||
|
433 PIVOT.FIELD.GROUP 0 0
|
||||||
|
434 PIVOT.FIELD.UNGROUP 0 0
|
||||||
|
435 CHECKBOX.PROPERTIES 0 0
|
||||||
|
436 LABEL.PROPERTIES 0 0
|
||||||
|
437 LISTBOX.PROPERTIES 0 0
|
||||||
|
438 EDITBOX.PROPERTIES 0 0
|
||||||
|
439 PIVOT.REFRESH 0 0
|
||||||
|
440 LINK.COMBO 0 0
|
||||||
|
441 OPEN.TEXT 0 0
|
||||||
|
442 HIDE.DIALOG 0 0
|
||||||
|
443 SET.DIALOG.FOCUS 0 0
|
||||||
|
444 ENABLE.OBJECT 0 0
|
||||||
|
445 PUSHBUTTON.PROPERTIES 0 0
|
||||||
|
446 SET.DIALOG.DEFAULT 0 0
|
||||||
|
447 FILTER 0 0
|
||||||
|
448 FILTER.SHOW.ALL 0 0
|
||||||
|
449 CLEAR.OUTLINE 0 0
|
||||||
|
450 FUNCTION.WIZARD 0 0
|
||||||
|
451 ADD.LIST.ITEM 0 0
|
||||||
|
452 SET.LIST.ITEM 0 0
|
||||||
|
453 REMOVE.LIST.ITEM 0 0
|
||||||
|
454 SELECT.LIST.ITEM 0 0
|
||||||
|
455 SET.CONTROL.VALUE 0 0
|
||||||
|
456 SAVE.COPY.AS 0 0
|
||||||
|
458 OPTIONS.LISTS.ADD 0 0
|
||||||
|
459 OPTIONS.LISTS.DELETE 0 0
|
||||||
|
460 SERIES.AXES 0 0
|
||||||
|
461 SERIES.X 0 0
|
||||||
|
462 SERIES.Y 0 0
|
||||||
|
463 ERRORBAR.X 0 0
|
||||||
|
464 ERRORBAR.Y 0 0
|
||||||
|
465 FORMAT.CHART 0 0
|
||||||
|
466 SERIES.ORDER 0 0
|
||||||
|
467 MAIL.LOGOFF 0 0
|
||||||
|
468 CLEAR.ROUTING.SLIP 0 0
|
||||||
|
469 APP.ACTIVATE.MICROSOFT 0 0
|
||||||
|
470 MAIL.EDIT.MAILER 0 0
|
||||||
|
471 ON.SHEET 0 0
|
||||||
|
472 STANDARD.WIDTH 0 0
|
||||||
|
473 SCENARIO.MERGE 0 0
|
||||||
|
474 SUMMARY.INFO 0 0
|
||||||
|
475 FIND.FILE 0 0
|
||||||
|
476 ACTIVE.CELL.FONT 0 0
|
||||||
|
477 ENABLE.TIPWIZARD 0 0
|
||||||
|
478 VBA.MAKE.ADDIN 0 0
|
||||||
|
480 INSERTDATATABLE 0 0
|
||||||
|
481 WORKGROUP.OPTIONS 0 0
|
||||||
|
482 MAIL.SEND.MAILER 0 0
|
||||||
|
485 AUTOCORRECT 0 0
|
||||||
|
489 POST.DOCUMENT 0 0
|
||||||
|
491 PICKLIST 0 0
|
||||||
|
493 VIEW.SHOW 0 0
|
||||||
|
494 VIEW.DEFINE 0 0
|
||||||
|
495 VIEW.DELETE 0 0
|
||||||
|
509 SHEET.BACKGROUND 0 0
|
||||||
|
510 INSERT.MAP.OBJECT 0 0
|
||||||
|
511 OPTIONS.MENONO 0 0
|
||||||
|
517 MSOCHECKS 0 0
|
||||||
|
518 NORMAL 0 0
|
||||||
|
519 LAYOUT 0 0
|
||||||
|
520 RM.PRINT.AREA 0 0
|
||||||
|
521 CLEAR.PRINT.AREA 0 0
|
||||||
|
522 ADD.PRINT.AREA 0 0
|
||||||
|
523 MOVE.BRK 0 0
|
||||||
|
545 HIDECURR.NOTE 0 0
|
||||||
|
546 HIDEALL.NOTES 0 0
|
||||||
|
547 DELETE.NOTE 0 0
|
||||||
|
548 TRAVERSE.NOTES 0 0
|
||||||
|
549 ACTIVATE.NOTES 0 0
|
||||||
|
620 PROTECT.REVISIONS 0 0
|
||||||
|
621 UNPROTECT.REVISIONS 0 0
|
||||||
|
647 OPTIONS.ME 0 0
|
||||||
|
653 WEB.PUBLISH 0 0
|
||||||
|
667 NEWWEBQUERY 0 0
|
||||||
|
673 PIVOT.TABLE.CHART 0 0
|
||||||
|
753 OPTIONS.SAVE 0 0
|
||||||
|
755 OPTIONS.SPELL 0 0
|
||||||
|
808 HIDEALL.INKANNOTS 0 0
|
||||||
@ -34,7 +34,6 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|||||||
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
import org.apache.poi.poifs.filesystem.DirectoryNode;
|
||||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
import org.apache.poi.util.LocaleUtil;
|
import org.apache.poi.util.LocaleUtil;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,50 +129,42 @@ public final class TestExcelExtractor {
|
|||||||
public void testEventExtractor() throws Exception {
|
public void testEventExtractor() throws Exception {
|
||||||
// First up, a simple file with string
|
// First up, a simple file with string
|
||||||
// based formulas in it
|
// based formulas in it
|
||||||
EventBasedExcelExtractor extractor1 = null;
|
try (EventBasedExcelExtractor extractor1 = new EventBasedExcelExtractor(
|
||||||
try {
|
new POIFSFileSystem(
|
||||||
extractor1 = new EventBasedExcelExtractor(
|
HSSFTestDataSamples.openSampleFileStream("SimpleWithFormula.xls")
|
||||||
new POIFSFileSystem(
|
)
|
||||||
HSSFTestDataSamples.openSampleFileStream("SimpleWithFormula.xls")
|
)) {
|
||||||
)
|
extractor1.setIncludeSheetNames(true);
|
||||||
);
|
|
||||||
extractor1.setIncludeSheetNames(true);
|
String text = extractor1.getText();
|
||||||
|
assertEquals("Sheet1\nreplaceme\nreplaceme\nreplacemereplaceme\nSheet2\nSheet3\n", text);
|
||||||
String text = extractor1.getText();
|
|
||||||
assertEquals("Sheet1\nreplaceme\nreplaceme\nreplacemereplaceme\nSheet2\nSheet3\n", text);
|
extractor1.setIncludeSheetNames(false);
|
||||||
|
extractor1.setFormulasNotResults(true);
|
||||||
extractor1.setIncludeSheetNames(false);
|
|
||||||
extractor1.setFormulasNotResults(true);
|
text = extractor1.getText();
|
||||||
|
assertEquals("replaceme\nreplaceme\nCONCATENATE(A1,A2)\n", text);
|
||||||
text = extractor1.getText();
|
|
||||||
assertEquals("replaceme\nreplaceme\nCONCATENATE(A1,A2)\n", text);
|
|
||||||
} finally {
|
|
||||||
if (extractor1 != null) extractor1.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, a slightly longer file with numeric formulas
|
// Now, a slightly longer file with numeric formulas
|
||||||
EventBasedExcelExtractor extractor2 = null;
|
try (EventBasedExcelExtractor extractor2 = new EventBasedExcelExtractor(
|
||||||
try {
|
new POIFSFileSystem(
|
||||||
extractor2 = new EventBasedExcelExtractor(
|
HSSFTestDataSamples.openSampleFileStream("sumifformula.xls")
|
||||||
new POIFSFileSystem(
|
)
|
||||||
HSSFTestDataSamples.openSampleFileStream("sumifformula.xls")
|
)) {
|
||||||
)
|
|
||||||
);
|
extractor2.setIncludeSheetNames(false);
|
||||||
|
extractor2.setFormulasNotResults(true);
|
||||||
extractor2.setIncludeSheetNames(false);
|
|
||||||
extractor2.setFormulasNotResults(true);
|
String text = extractor2.getText();
|
||||||
|
assertEquals(
|
||||||
String text = extractor2.getText();
|
"1000\t1\tSUMIF(A1:A5,\">4000\",B1:B5)\n" +
|
||||||
assertEquals(
|
"2000\t2\n" +
|
||||||
"1000\t1\tSUMIF(A1:A5,\">4000\",B1:B5)\n" +
|
"3000\t3\n" +
|
||||||
"2000\t2\n" +
|
"4000\t4\n" +
|
||||||
"3000\t3\n" +
|
"5000\t5\n",
|
||||||
"4000\t4\n" +
|
text
|
||||||
"5000\t5\n",
|
);
|
||||||
text
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
if (extractor2 != null) extractor2.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,4 +363,25 @@ public final class TestExcelExtractor {
|
|||||||
assertContains(txt, "NONBUSINESS");
|
assertContains(txt, "NONBUSINESS");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test60405a() throws IOException {
|
||||||
|
//bug 61045. File is govdocs1 626534
|
||||||
|
try (ExcelExtractor extractor = createExtractor("60405.xls")) {
|
||||||
|
String txt = extractor.getText();
|
||||||
|
assertContains(txt, "Macro1");
|
||||||
|
assertContains(txt, "Macro2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test60405b() throws IOException {
|
||||||
|
//bug 61045. File is govdocs1 626534
|
||||||
|
try (ExcelExtractor extractor = createExtractor("60405.xls")) {
|
||||||
|
extractor.setFormulasNotResults(true);
|
||||||
|
String txt = extractor.getText();
|
||||||
|
assertContains(txt, "Macro1");
|
||||||
|
assertContains(txt, "Macro2");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,378 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
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.ss.formula.function;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is not used during normal POI run-time but is used at development time to generate
|
||||||
|
* the file 'functionMetadataCetab.txt'. There are more than 300 built-in functions in Excel in
|
||||||
|
* the Cetab and the intention of this class is to make it easier to maintain the metadata, by extracting
|
||||||
|
* it from a reliable source.
|
||||||
|
*/
|
||||||
|
public final class ExcelCetabFunctionExtractor {
|
||||||
|
|
||||||
|
private static final String SOURCE_DOC_FILE_NAME = "functionMetadataCetab-PDF.txt";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For simplicity, the output file is strictly simple ASCII.
|
||||||
|
* This method detects any unexpected characters.
|
||||||
|
*/
|
||||||
|
/* package */ static boolean isSimpleAscii(char c) {
|
||||||
|
|
||||||
|
if (c>=0x21 && c<=0x7E) {
|
||||||
|
// everything from '!' to '~' (includes letters, digits, punctuation
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// some specific whitespace chars below 0x21:
|
||||||
|
switch(c) {
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static final class FunctionData {
|
||||||
|
// special characters from the ooo document
|
||||||
|
private static final int CHAR_ELLIPSIS_8230 = 8230;
|
||||||
|
private static final int CHAR_NDASH_8211 = 8211;
|
||||||
|
|
||||||
|
private final int _index;
|
||||||
|
private final boolean _hasFootnote;
|
||||||
|
private final String _name;
|
||||||
|
private final int _minParams;
|
||||||
|
private final int _maxParams;
|
||||||
|
private final String _returnClass;
|
||||||
|
private final String _paramClasses;
|
||||||
|
private final boolean _isVolatile;
|
||||||
|
|
||||||
|
public FunctionData(int funcIx, boolean hasFootnote, String funcName, int minParams, int maxParams,
|
||||||
|
String returnClass, String paramClasses, boolean isVolatile) {
|
||||||
|
_index = funcIx;
|
||||||
|
_hasFootnote = hasFootnote;
|
||||||
|
_name = funcName;
|
||||||
|
_minParams = minParams;
|
||||||
|
_maxParams = maxParams;
|
||||||
|
_returnClass = convertSpecialChars(returnClass);
|
||||||
|
_paramClasses = convertSpecialChars(paramClasses);
|
||||||
|
_isVolatile = isVolatile;
|
||||||
|
}
|
||||||
|
private static String convertSpecialChars(String ss) {
|
||||||
|
StringBuilder sb = new StringBuilder(ss.length() + 4);
|
||||||
|
for(int i=0; i<ss.length(); i++) {
|
||||||
|
char c = ss.charAt(i);
|
||||||
|
if (isSimpleAscii(c)) {
|
||||||
|
sb.append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case CHAR_NDASH_8211:
|
||||||
|
sb.append('-');
|
||||||
|
continue;
|
||||||
|
case CHAR_ELLIPSIS_8230:
|
||||||
|
sb.append("...");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new RuntimeException("bad char (" + ((int)c) + ") in string '" + ss + "'");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
public int getIndex() {
|
||||||
|
return _index;
|
||||||
|
}
|
||||||
|
public String getName() {
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
public boolean hasFootnote() {
|
||||||
|
return _hasFootnote;
|
||||||
|
}
|
||||||
|
public String formatAsDataLine() {
|
||||||
|
return _index + "\t" + _name + "\t" + _minParams + "\t"
|
||||||
|
+ _maxParams + "\t" + _returnClass + "\t" + _paramClasses
|
||||||
|
+ "\t" + checkMark(_isVolatile) + "\t" + checkMark(_hasFootnote);
|
||||||
|
}
|
||||||
|
private static String checkMark(boolean b) {
|
||||||
|
return b ? "x" : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class FunctionDataCollector {
|
||||||
|
|
||||||
|
private final Map<Integer, FunctionData> _allFunctionsByIndex;
|
||||||
|
private final Map<String, FunctionData> _allFunctionsByName;
|
||||||
|
private final Set<Integer> _groupFunctionIndexes;
|
||||||
|
private final Set<String> _groupFunctionNames;
|
||||||
|
private final PrintStream _ps;
|
||||||
|
|
||||||
|
public FunctionDataCollector(PrintStream ps) {
|
||||||
|
_ps = ps;
|
||||||
|
_allFunctionsByIndex = new HashMap<>();
|
||||||
|
_allFunctionsByName = new HashMap<>();
|
||||||
|
_groupFunctionIndexes = new HashSet<>();
|
||||||
|
_groupFunctionNames = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFunction(int funcIx, boolean hasFootnote, String funcName, int minParams, int maxParams,
|
||||||
|
String returnClass, String paramClasses, String volatileFlagStr) {
|
||||||
|
boolean isVolatile = volatileFlagStr.length() > 0;
|
||||||
|
|
||||||
|
Integer funcIxKey = Integer.valueOf(funcIx);
|
||||||
|
if(!_groupFunctionIndexes.add(funcIxKey)) {
|
||||||
|
throw new RuntimeException("Duplicate function index (" + funcIx + ")");
|
||||||
|
}
|
||||||
|
if(!_groupFunctionNames.add(funcName)) {
|
||||||
|
throw new RuntimeException("Duplicate function name '" + funcName + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
checkRedefinedFunction(hasFootnote, funcName, funcIxKey);
|
||||||
|
FunctionData fd = new FunctionData(funcIx, hasFootnote, funcName,
|
||||||
|
minParams, maxParams, returnClass, paramClasses, isVolatile);
|
||||||
|
|
||||||
|
_allFunctionsByIndex.put(funcIxKey, fd);
|
||||||
|
_allFunctionsByName.put(funcName, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some extra validation here.
|
||||||
|
* Any function which changes definition will have a footnote in the source document
|
||||||
|
*/
|
||||||
|
private void checkRedefinedFunction(boolean hasNote, String funcName, Integer funcIxKey) {
|
||||||
|
FunctionData fdPrev;
|
||||||
|
// check by index
|
||||||
|
fdPrev = _allFunctionsByIndex.get(funcIxKey);
|
||||||
|
if(fdPrev != null) {
|
||||||
|
if(!fdPrev.hasFootnote() || !hasNote) {
|
||||||
|
throw new RuntimeException("changing function ["
|
||||||
|
+ funcIxKey + "] definition without foot-note");
|
||||||
|
}
|
||||||
|
_allFunctionsByName.remove(fdPrev.getName());
|
||||||
|
}
|
||||||
|
// check by name
|
||||||
|
fdPrev = _allFunctionsByName.get(funcName);
|
||||||
|
if(fdPrev != null) {
|
||||||
|
if(!fdPrev.hasFootnote() || !hasNote) {
|
||||||
|
throw new RuntimeException("changing function '"
|
||||||
|
+ funcName + "' definition without foot-note");
|
||||||
|
}
|
||||||
|
_allFunctionsByIndex.remove(Integer.valueOf(fdPrev.getIndex()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endTableGroup(String headingText) {
|
||||||
|
Integer[] keys = new Integer[_groupFunctionIndexes.size()];
|
||||||
|
_groupFunctionIndexes.toArray(keys);
|
||||||
|
_groupFunctionIndexes.clear();
|
||||||
|
_groupFunctionNames.clear();
|
||||||
|
Arrays.sort(keys);
|
||||||
|
|
||||||
|
_ps.println("# " + headingText);
|
||||||
|
for (Integer key : keys) {
|
||||||
|
FunctionData fd = _allFunctionsByIndex.get(key);
|
||||||
|
_ps.println(fd.formatAsDataLine());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Pattern ID_MATCH = Pattern.compile("0x([\\dA-F]+)");
|
||||||
|
private static final Pattern NAME_MATCH = Pattern.compile("([0-9A-Z.]+)");
|
||||||
|
private static final Pattern ID_NAME_MATCH = Pattern.compile("0x([\\dA-F]+)\\s+([0-9A-Z.]+)");
|
||||||
|
|
||||||
|
private static final Set<String> IGNORED_LINES = new HashSet<>();
|
||||||
|
static {
|
||||||
|
IGNORED_LINES.add("[MS-XLS] — v20141018");
|
||||||
|
IGNORED_LINES.add("Excel Binary File Format (.xls) Structure");
|
||||||
|
IGNORED_LINES.add("Copyright © 2014 Microsoft Corporation.");
|
||||||
|
IGNORED_LINES.add("Release: October 30, 2014Value Meaning");
|
||||||
|
IGNORED_LINES.add("Release: October 30, 2014Value");
|
||||||
|
IGNORED_LINES.add("Meaning");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void extractFunctionData(FunctionDataCollector fdc, InputStream is) throws IOException {
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
|
||||||
|
|
||||||
|
String id = null;
|
||||||
|
String name = null;
|
||||||
|
while (true) {
|
||||||
|
String line = reader.readLine();
|
||||||
|
if(line == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(IGNORED_LINES.contains(line) || line.matches("\\d+ / \\d+")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher idMatcher = ID_MATCH.matcher(line);
|
||||||
|
boolean foundID = idMatcher.matches();
|
||||||
|
Matcher nameMatcher = NAME_MATCH.matcher(line);
|
||||||
|
boolean foundName = nameMatcher.matches();
|
||||||
|
Matcher idAndNameMatcher = ID_NAME_MATCH.matcher(line);
|
||||||
|
boolean foundIDandName = idAndNameMatcher.matches();
|
||||||
|
if(foundID && foundName ||
|
||||||
|
foundName && foundIDandName ||
|
||||||
|
foundID && foundIDandName) {
|
||||||
|
throw new IllegalStateException("Should not find id and name: " +
|
||||||
|
foundID + "/" + foundName + "/" + foundIDandName +
|
||||||
|
", line: " + line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(foundID && id != null) {
|
||||||
|
throw new IllegalStateException("Found ID, but already had one: " + id + ", line: " + line);
|
||||||
|
}
|
||||||
|
if(foundName && name != null) {
|
||||||
|
throw new IllegalStateException("Found name, but already had one: " + name + ", line: " + line);
|
||||||
|
}
|
||||||
|
if(foundIDandName && (name != null || id != null)) {
|
||||||
|
throw new IllegalStateException("Found name and id, but already had one: id: " + id + ", name: " + name + ", line: " + line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(foundID) {
|
||||||
|
id = idMatcher.group(1);
|
||||||
|
} else if (foundName) {
|
||||||
|
name = nameMatcher.group(1);
|
||||||
|
} else if (foundIDandName) {
|
||||||
|
id = idAndNameMatcher.group(1);
|
||||||
|
name = idAndNameMatcher.group(2);
|
||||||
|
// manual override for one function name which contains lowercase characters
|
||||||
|
} else if(line.equals("VBAActivate")) {
|
||||||
|
name = line;
|
||||||
|
} else if (id == null || name == null) {
|
||||||
|
throw new IllegalStateException("Found params, but had empty id or name, id: " + id +
|
||||||
|
", name: " + name + ", line: " + line);
|
||||||
|
} else {
|
||||||
|
System.out.println("Found function " + id + " " + name + " " + line);
|
||||||
|
fdc.addFunction(Integer.parseInt(id, 16), false, name, 0, 0,
|
||||||
|
"", "", "");
|
||||||
|
|
||||||
|
id = null;
|
||||||
|
name = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fdc.endTableGroup("");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* To be sure that no tricky unicode chars make it through to the output file.
|
||||||
|
*/
|
||||||
|
private static final class SimpleAsciiOutputStream extends OutputStream {
|
||||||
|
|
||||||
|
private final OutputStream _os;
|
||||||
|
|
||||||
|
public SimpleAsciiOutputStream(OutputStream os) {
|
||||||
|
_os = os;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
checkByte(b);
|
||||||
|
_os.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkByte(int b) {
|
||||||
|
if (!isSimpleAscii((char)b)) {
|
||||||
|
throw new RuntimeException("Encountered char (" + b + ") which was not simple ascii as expected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
checkByte(b[i + off]);
|
||||||
|
|
||||||
|
}
|
||||||
|
_os.write(b, off, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void processFile(InputStream input, File outFile) throws IOException {
|
||||||
|
try (OutputStream os = new SimpleAsciiOutputStream(new FileOutputStream(outFile));
|
||||||
|
PrintStream ps = new PrintStream(os, true, "UTF-8")) {
|
||||||
|
|
||||||
|
outputLicenseHeader(ps);
|
||||||
|
Class<?> genClass = ExcelCetabFunctionExtractor.class;
|
||||||
|
ps.println("# Created by (" + genClass.getName() + ")");
|
||||||
|
// identify the source file
|
||||||
|
ps.println("# from source file '" + SOURCE_DOC_FILE_NAME + "'");
|
||||||
|
ps.println("#");
|
||||||
|
ps.println("#Columns: (index, name, minParams, maxParams, returnClass, paramClasses, isVolatile, hasFootnote )");
|
||||||
|
ps.println();
|
||||||
|
extractFunctionData(new FunctionDataCollector(ps), input);
|
||||||
|
ps.close();
|
||||||
|
|
||||||
|
String canonicalOutputFileName = outFile.getCanonicalPath();
|
||||||
|
System.out.println("Successfully output to '" + canonicalOutputFileName + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void outputLicenseHeader(PrintStream ps) {
|
||||||
|
String[] lines= {
|
||||||
|
"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.",
|
||||||
|
};
|
||||||
|
for (String line : lines) {
|
||||||
|
ps.print("# ");
|
||||||
|
ps.println(line);
|
||||||
|
}
|
||||||
|
ps.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
if(!new File(SOURCE_DOC_FILE_NAME).exists()) {
|
||||||
|
throw new IllegalStateException("Did not find file " + SOURCE_DOC_FILE_NAME + " in the resources");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream stream = new FileInputStream(SOURCE_DOC_FILE_NAME)) {
|
||||||
|
File outFile = new File("functionMetadataCetab.txt");
|
||||||
|
|
||||||
|
processFile(stream, outFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
test-data/spreadsheet/60405.xls
Normal file
BIN
test-data/spreadsheet/60405.xls
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user