Re-use functionality from HSSFWorkbook in dev-tools to find the

dir-entry-name to make special names like WORKBOOK or BOOK work, handle
a special case in ExternalNameRecord when the flag states that there is
data, but no data remains in the stream, slightly improve error-output
in DirectoryNode, adjust all dev-tools-tests to not report stack-traces
any more for expected failures and try with HSSFWorkbook to decide if it
is an expected failure or now.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1536062 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Dominik Stadler 2013-10-27 08:16:29 +00:00
parent 0342f9602d
commit f82527ecb1
12 changed files with 114 additions and 102 deletions

View File

@ -31,6 +31,7 @@ import org.apache.poi.hssf.record.pivottable.StreamIDRecord;
import org.apache.poi.hssf.record.pivottable.ViewDefinitionRecord; import org.apache.poi.hssf.record.pivottable.ViewDefinitionRecord;
import org.apache.poi.hssf.record.pivottable.ViewFieldsRecord; import org.apache.poi.hssf.record.pivottable.ViewFieldsRecord;
import org.apache.poi.hssf.record.pivottable.ViewSourceRecord; import org.apache.poi.hssf.record.pivottable.ViewSourceRecord;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
import org.apache.poi.util.LittleEndian; import org.apache.poi.util.LittleEndian;
@ -397,8 +398,7 @@ public final class BiffViewer {
ps = System.out; ps = System.out;
} }
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(cmdArgs.getFile())); InputStream is = getPOIFSInputStream(cmdArgs.getFile());
InputStream is = fs.createDocumentInputStream("Workbook");
if (cmdArgs.shouldOutputRawHexOnly()) { if (cmdArgs.shouldOutputRawHexOnly()) {
int size = is.available(); int size = is.available();
@ -419,6 +419,13 @@ public final class BiffViewer {
} }
} }
protected static InputStream getPOIFSInputStream(File file)
throws IOException, FileNotFoundException {
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(file));
String workbookName = HSSFWorkbook.getWorkbookDirEntryName(fs.getRoot());
return fs.createDocumentInputStream(workbookName);
}
protected static void runBiffViewer(PrintStream ps, InputStream is, protected static void runBiffViewer(PrintStream ps, InputStream is,
boolean dumpInterpretedRecords, boolean dumpHex, boolean zeroAlignHexDump, boolean dumpInterpretedRecords, boolean dumpHex, boolean zeroAlignHexDump,
boolean suppressHeader) { boolean suppressHeader) {

View File

@ -17,16 +17,14 @@
package org.apache.poi.hssf.dev; package org.apache.poi.hssf.dev;
import java.io.FileInputStream; import java.io.File;
import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
import org.apache.poi.hssf.record.Record;
/** /**
* *
@ -43,12 +41,8 @@ public class EFBiffViewer
{ {
} }
public void run() public void run() throws IOException {
throws IOException InputStream din = BiffViewer.getPOIFSInputStream(new File(file));
{
FileInputStream fin = new FileInputStream(file);
POIFSFileSystem poifs = new POIFSFileSystem(fin);
InputStream din = poifs.createDocumentInputStream("Workbook");
HSSFRequest req = new HSSFRequest(); HSSFRequest req = new HSSFRequest();
req.addListenerForAllRecords(new HSSFListener() req.addListenerForAllRecords(new HSSFListener()

View File

@ -17,7 +17,7 @@
package org.apache.poi.hssf.dev; package org.apache.poi.hssf.dev;
import java.io.FileInputStream; import java.io.File;
import java.util.List; import java.util.List;
import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.model.HSSFFormulaParser;
@ -25,7 +25,6 @@ import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFactory; import org.apache.poi.hssf.record.RecordFactory;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.formula.ptg.ExpPtg; import org.apache.poi.ss.formula.ptg.ExpPtg;
import org.apache.poi.ss.formula.ptg.FuncPtg; import org.apache.poi.ss.formula.ptg.FuncPtg;
import org.apache.poi.ss.formula.ptg.OperationPtg; import org.apache.poi.ss.formula.ptg.OperationPtg;
@ -60,11 +59,9 @@ public class FormulaViewer
public void run() public void run()
throws Exception throws Exception
{ {
POIFSFileSystem fs =
new POIFSFileSystem(new FileInputStream(file));
List<Record> records = List<Record> records =
RecordFactory RecordFactory
.createRecords(fs.createDocumentInputStream("Workbook")); .createRecords(BiffViewer.getPOIFSInputStream(new File(file)));
for (int k = 0; k < records.size(); k++) for (int k = 0; k < records.size(); k++)
{ {

View File

@ -17,7 +17,7 @@
package org.apache.poi.hssf.dev; package org.apache.poi.hssf.dev;
import java.io.FileInputStream; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -25,7 +25,6 @@ import org.apache.poi.hssf.record.ContinueRecord;
import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFactory; import org.apache.poi.hssf.record.RecordFactory;
import org.apache.poi.hssf.record.RecordInputStream; import org.apache.poi.hssf.record.RecordInputStream;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/** /**
* This is a low-level debugging class, which simply prints * This is a low-level debugging class, which simply prints
@ -50,9 +49,7 @@ public class RecordLister
public void run() public void run()
throws IOException throws IOException
{ {
FileInputStream fin = new FileInputStream(file); InputStream din = BiffViewer.getPOIFSInputStream(new File(file));
POIFSFileSystem poifs = new POIFSFileSystem(fin);
InputStream din = poifs.createDocumentInputStream("Workbook");
RecordInputStream rinp = new RecordInputStream(din); RecordInputStream rinp = new RecordInputStream(din);
while(rinp.hasNextRecord()) { while(rinp.hasNextRecord()) {

View File

@ -17,8 +17,8 @@
package org.apache.poi.hssf.record; package org.apache.poi.hssf.record;
import org.apache.poi.ss.formula.constant.ConstantValueParser;
import org.apache.poi.ss.formula.Formula; 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.ss.formula.ptg.Ptg;
import org.apache.poi.util.LittleEndianOutput; import org.apache.poi.util.LittleEndianOutput;
import org.apache.poi.util.StringUtil; import org.apache.poi.util.StringUtil;
@ -130,8 +130,10 @@ public final class ExternalNameRecord extends StandardRecord {
if(!isOLELink() && !isStdDocumentNameIdentifier()){ if(!isOLELink() && !isStdDocumentNameIdentifier()){
if(isAutomaticLink()){ if(isAutomaticLink()){
result += 3; // byte, short if(_ddeValues != null) {
result += ConstantValueParser.getEncodedSize(_ddeValues); result += 3; // byte, short
result += ConstantValueParser.getEncodedSize(_ddeValues);
}
} else { } else {
result += field_5_name_definition.getEncodedSize(); result += field_5_name_definition.getEncodedSize();
} }
@ -149,9 +151,11 @@ public final class ExternalNameRecord extends StandardRecord {
if(!isOLELink() && !isStdDocumentNameIdentifier()){ if(!isOLELink() && !isStdDocumentNameIdentifier()){
if(isAutomaticLink()){ if(isAutomaticLink()){
out.writeByte(_nColumns-1); if(_ddeValues != null) {
out.writeShort(_nRows-1); out.writeByte(_nColumns-1);
ConstantValueParser.encode(out, _ddeValues); out.writeShort(_nRows-1);
ConstantValueParser.encode(out, _ddeValues);
}
} else { } else {
field_5_name_definition.serialize(out); field_5_name_definition.serialize(out);
} }

View File

@ -48,19 +48,7 @@ import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.model.InternalSheet; import org.apache.poi.hssf.model.InternalSheet;
import org.apache.poi.hssf.model.InternalWorkbook; import org.apache.poi.hssf.model.InternalWorkbook;
import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
import org.apache.poi.hssf.record.AbstractEscherHolderRecord; import org.apache.poi.hssf.record.*;
import org.apache.poi.hssf.record.BackupRecord;
import org.apache.poi.hssf.record.DrawingGroupRecord;
import org.apache.poi.hssf.record.ExtendedFormatRecord;
import org.apache.poi.hssf.record.FontRecord;
import org.apache.poi.hssf.record.LabelRecord;
import org.apache.poi.hssf.record.LabelSSTRecord;
import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.hssf.record.RecalcIdRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFactory;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.UnknownRecord;
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor; import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
import org.apache.poi.hssf.record.common.UnicodeString; import org.apache.poi.hssf.record.common.UnicodeString;
import org.apache.poi.hssf.util.CellReference; import org.apache.poi.hssf.util.CellReference;
@ -222,11 +210,10 @@ public final class HSSFWorkbook extends POIDocument implements org.apache.poi.ss
}; };
private static String getWorkbookDirEntryName(DirectoryNode directory) { public static String getWorkbookDirEntryName(DirectoryNode directory) {
String[] potentialNames = WORKBOOK_DIR_ENTRY_NAMES; for (int i = 0; i < WORKBOOK_DIR_ENTRY_NAMES.length; i++) {
for (int i = 0; i < potentialNames.length; i++) { String wbName = WORKBOOK_DIR_ENTRY_NAMES[i];
String wbName = potentialNames[i];
try { try {
directory.getEntry(wbName); directory.getEntry(wbName);
return wbName; return wbName;

View File

@ -289,13 +289,13 @@ public class DirectoryNode
if (rval) if (rval)
{ {
_entries.remove(entry); _entries.remove(entry);
_byname.remove(entry.getName()); _byname.remove(entry.getName());
if(_ofilesystem != null) { if(_ofilesystem != null) {
_ofilesystem.remove(entry); _ofilesystem.remove(entry);
} else { } else {
_nfilesystem.remove(entry); _nfilesystem.remove(entry);
} }
} }
return rval; return rval;
} }
@ -359,21 +359,16 @@ public class DirectoryNode
* name exists in this DirectoryEntry * name exists in this DirectoryEntry
*/ */
public Entry getEntry(final String name) public Entry getEntry(final String name) throws FileNotFoundException {
throws FileNotFoundException
{
Entry rval = null; Entry rval = null;
if (name != null) if (name != null) {
{
rval = _byname.get(name); rval = _byname.get(name);
} }
if (rval == null) if (rval == null) {
{
// either a null name was given, or there is no such name // either a null name was given, or there is no such name
throw new FileNotFoundException("no such entry: \"" + name throw new FileNotFoundException("no such entry: \"" + name
+ "\""); + "\", had: " + _byname.keySet());
} }
return rval; return rval;
} }
@ -479,6 +474,7 @@ public class DirectoryNode
* @return true if the Entry is a DirectoryEntry, else false * @return true if the Entry is a DirectoryEntry, else false
*/ */
@Override
public boolean isDirectoryEntry() public boolean isDirectoryEntry()
{ {
return true; return true;
@ -495,6 +491,7 @@ public class DirectoryNode
* false * false
*/ */
@Override
protected boolean isDeleteOK() protected boolean isDeleteOK()
{ {
@ -524,7 +521,7 @@ public class DirectoryNode
* @return an Iterator; may not be null, but may have an empty * @return an Iterator; may not be null, but may have an empty
* back end store * back end store
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings({ "unchecked", "rawtypes" })
public Iterator getViewableIterator() public Iterator getViewableIterator()
{ {
List components = new ArrayList(); List components = new ArrayList();

View File

@ -1,14 +1,17 @@
package org.apache.poi.hssf.dev; package org.apache.poi.hssf.dev;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.junit.Test; import org.junit.Test;
/** /**
@ -29,7 +32,7 @@ public abstract class BaseXLSIteratingTest {
System.out.println("Had " + count + " files"); System.out.println("Had " + count + " files");
} }
private int runWithDir(String dir) { private int runWithDir(String dir) throws IOException {
List<String> failed = new ArrayList<String>(); List<String> failed = new ArrayList<String>();
String[] files = new File(dir).list(new FilenameFilter() { String[] files = new File(dir).list(new FilenameFilter() {
@ -46,7 +49,7 @@ public abstract class BaseXLSIteratingTest {
return files.length; return files.length;
} }
private void runWithArrayOfFiles(String[] files, String dir, List<String> failed) { private void runWithArrayOfFiles(String[] files, String dir, List<String> failed) throws IOException {
for(String file : files) { for(String file : files) {
try { try {
runOneFile(dir, file, failed); runOneFile(dir, file, failed);
@ -57,6 +60,15 @@ public abstract class BaseXLSIteratingTest {
} }
e.printStackTrace(); e.printStackTrace();
// try to read it in HSSFWorkbook to quickly fail if we cannot read the file there at all and thus probably can use SILENT_EXCLUDED instead
FileInputStream stream = new FileInputStream(new File(dir, file));
try {
assertNotNull(new HSSFWorkbook(stream));
} finally {
stream.close();
}
if(!EXCLUDED.contains(file)) { if(!EXCLUDED.contains(file)) {
failed.add(file); failed.add(file);
} }

View File

@ -1,45 +1,44 @@
package org.apache.poi.hssf.dev; package org.apache.poi.hssf.dev;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.List; import java.util.List;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class TestBiffViewer extends BaseXLSIteratingTest { public class TestBiffViewer extends BaseXLSIteratingTest {
static { static {
// TODO: is it ok to fail these?
// Look at the output of the test for the detailed stacktrace of the failures... // Look at the output of the test for the detailed stacktrace of the failures...
EXCLUDED.add("WORKBOOK_in_capitals.xls"); //EXCLUDED.add("");
EXCLUDED.add("password.xls");
EXCLUDED.add("NoGutsRecords.xls");
EXCLUDED.add("BOOK_in_capitals.xls");
EXCLUDED.add("XRefCalc.xls");
EXCLUDED.add("50833.xls"); // probably a problem in BiffViewer
EXCLUDED.add("43493.xls");
EXCLUDED.add("51832.xls");
EXCLUDED.add("OddStyleRecord.xls");
// these are likely ok to fail
SILENT_EXCLUDED.add("XRefCalc.xls"); // "Buffer overrun"
SILENT_EXCLUDED.add("50833.xls"); // "Name is too long" when setting username
SILENT_EXCLUDED.add("OddStyleRecord.xls");
SILENT_EXCLUDED.add("NoGutsRecords.xls");
SILENT_EXCLUDED.add("51832.xls"); // password
SILENT_EXCLUDED.add("43493.xls"); // HSSFWorkbook cannot open it as well
SILENT_EXCLUDED.add("password.xls");
SILENT_EXCLUDED.add("46904.xls"); SILENT_EXCLUDED.add("46904.xls");
}; };
@Override @Override
void runOneFile(String dir, String file, List<String> failed) throws IOException { void runOneFile(String dir, String file, List<String> failed) throws IOException {
FileInputStream inStream = new FileInputStream(new File(dir, file)); InputStream is = BiffViewer.getPOIFSInputStream(new File(dir, file));
try { try {
POIFSFileSystem fs = new POIFSFileSystem(inStream); // use a NullOutputStream to not write the bytes anywhere for best runtime
InputStream is = fs.createDocumentInputStream("Workbook"); BiffViewer.runBiffViewer(new PrintStream(NULL_OUTPUT_STREAM), is, true, true, true, false);
try {
// use a NullOutputStream to not write the bytes anywhere for best runtime
BiffViewer.runBiffViewer(new PrintStream(NULL_OUTPUT_STREAM), is, true, true, true, false);
} finally {
is.close();
}
} finally { } finally {
inStream.close(); is.close();
} }
} }
// @Test
// public void testOneFile() throws Exception {
// List<String> failed = new ArrayList<String>();
// runOneFile("test-data/spreadsheet", "WORKBOOK_in_capitals.xls", failed);
//
// assertTrue("Expected to have no failed except the ones excluded, but had: " + failed,
// failed.isEmpty());
// }
} }

View File

@ -7,12 +7,14 @@ import java.util.List;
public class TestEFBiffViewer extends BaseXLSIteratingTest { public class TestEFBiffViewer extends BaseXLSIteratingTest {
static { static {
// TODO: is it ok to fail these?
// Look at the output of the test for the detailed stacktrace of the failures... // Look at the output of the test for the detailed stacktrace of the failures...
EXCLUDED.add("password.xls"); //EXCLUDED.add("");
EXCLUDED.add("XRefCalc.xls");
EXCLUDED.add("43493.xls"); // these are likely ok to fail
EXCLUDED.add("51832.xls"); SILENT_EXCLUDED.add("XRefCalc.xls");
SILENT_EXCLUDED.add("password.xls");
SILENT_EXCLUDED.add("51832.xls"); // password
SILENT_EXCLUDED.add("43493.xls"); // HSSFWorkbook cannot open it as well
}; };
@Override @Override

View File

@ -1,20 +1,25 @@
package org.apache.poi.hssf.dev; package org.apache.poi.hssf.dev;
import static org.junit.Assert.assertTrue;
import java.io.File; import java.io.File;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.junit.Test;
public class TestReSave extends BaseXLSIteratingTest { public class TestReSave extends BaseXLSIteratingTest {
static { static {
// TODO: is it ok to fail these? // TODO: is it ok to fail these?
// Look at the output of the test for the detailed stacktrace of the failures... // Look at the output of the test for the detailed stacktrace of the failures...
EXCLUDED.add("password.xls");
EXCLUDED.add("43493.xls");
EXCLUDED.add("51832.xls");
EXCLUDED.add("49219.xls");
EXCLUDED.add("49931.xls"); EXCLUDED.add("49931.xls");
// these are likely ok to fail
SILENT_EXCLUDED.add("password.xls");
SILENT_EXCLUDED.add("43493.xls"); // HSSFWorkbook cannot open it as well
SILENT_EXCLUDED.add("46904.xls"); SILENT_EXCLUDED.add("46904.xls");
SILENT_EXCLUDED.add("51832.xls"); // password
}; };
@Override @Override
@ -31,6 +36,10 @@ public class TestReSave extends BaseXLSIteratingTest {
try { try {
ReSave.main(new String[] { new File(dir, file).getAbsolutePath() }); ReSave.main(new String[] { new File(dir, file).getAbsolutePath() });
// also try BiffViewer on the saved file
new TestBiffViewer().runOneFile(dir, file.replace(".xls", "-saved.xls"), failed);
try { try {
// had one case where the re-saved could not be re-saved! // had one case where the re-saved could not be re-saved!
ReSave.main(new String[] { new File(dir, file.replace(".xls", "-saved.xls")).getAbsolutePath() }); ReSave.main(new String[] { new File(dir, file.replace(".xls", "-saved.xls")).getAbsolutePath() });
@ -47,4 +56,13 @@ public class TestReSave extends BaseXLSIteratingTest {
System.setOut(save); System.setOut(save);
} }
} }
@Test
public void testOneFile() throws Exception {
List<String> failed = new ArrayList<String>();
runOneFile("test-data/spreadsheet", "49219.xls", failed);
assertTrue("Expected to have no failed except the ones excluded, but had: " + failed,
failed.isEmpty());
}
} }

View File

@ -9,11 +9,9 @@ public class TestRecordLister extends BaseXLSIteratingTest {
static { static {
// TODO: is it ok to fail these? // TODO: is it ok to fail these?
// Look at the output of the test for the detailed stacktrace of the failures... // Look at the output of the test for the detailed stacktrace of the failures...
EXCLUDED.add("WORKBOOK_in_capitals.xls"); //EXCLUDED.add("");
EXCLUDED.add("NoGutsRecords.xls");
EXCLUDED.add("BOOK_in_capitals.xls");
EXCLUDED.add("OddStyleRecord.xls");
// these are likely ok to fail
SILENT_EXCLUDED.add("46904.xls"); SILENT_EXCLUDED.add("46904.xls");
}; };