mirror of https://github.com/apache/poi.git
bug 52949: add VBAMacroReader unit tests for H/XSLF, H/XWPF, and HGDF; OLE directories as case-insensitive
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1738513 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e3ad497b79
commit
e869575af9
|
@ -17,6 +17,9 @@
|
|||
|
||||
package org.apache.poi.poifs.macros;
|
||||
|
||||
import static org.apache.poi.util.StringUtil.startsWithIgnoreCase;
|
||||
import static org.apache.poi.util.StringUtil.endsWithIgnoreCase;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
|
@ -45,7 +48,7 @@ import org.apache.poi.util.RLEDecompressingInputStream;
|
|||
* and returns them.
|
||||
*/
|
||||
public class VBAMacroReader implements Closeable {
|
||||
protected static final String VBA_PROJECT_OOXML = "xl/vbaProject.bin";
|
||||
protected static final String VBA_PROJECT_OOXML = "vbaProject.bin";
|
||||
protected static final String VBA_PROJECT_POIFS = "VBA";
|
||||
|
||||
private NPOIFSFileSystem fs;
|
||||
|
@ -76,7 +79,7 @@ public class VBAMacroReader implements Closeable {
|
|||
ZipInputStream zis = new ZipInputStream(zipFile);
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = zis.getNextEntry()) != null) {
|
||||
if (VBA_PROJECT_OOXML.equals(zipEntry.getName())) {
|
||||
if (endsWithIgnoreCase(zipEntry.getName(), VBA_PROJECT_OOXML)) {
|
||||
try {
|
||||
// Make a NPOIFS from the contents, and close the stream
|
||||
this.fs = new NPOIFSFileSystem(zis);
|
||||
|
@ -125,8 +128,17 @@ public class VBAMacroReader implements Closeable {
|
|||
Charset charset = Charset.forName("Cp1252"); // default charset
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively traverses directory structure rooted at <tt>dir</tt>.
|
||||
* For each macro module that is found, the module's name and code are
|
||||
* added to <tt>modules<tt>.
|
||||
*
|
||||
* @param dir
|
||||
* @param modules
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void findMacros(DirectoryNode dir, ModuleMap modules) throws IOException {
|
||||
if (VBA_PROJECT_POIFS.equals(dir.getName())) {
|
||||
if (VBA_PROJECT_POIFS.equalsIgnoreCase(dir.getName())) {
|
||||
// VBA project directory, process
|
||||
readMacros(dir, modules);
|
||||
} else {
|
||||
|
@ -138,6 +150,22 @@ public class VBAMacroReader implements Closeable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read <tt>length</tt> bytes of MBCS (multi-byte character set) characters from the stream
|
||||
*
|
||||
* @param stream the inputstream to read from
|
||||
* @param length number of bytes to read from stream
|
||||
* @param charset the character set encoding of the bytes in the stream
|
||||
* @return a java String in the supplied character set
|
||||
* @throws IOException
|
||||
*/
|
||||
private static String readString(InputStream stream, int length, Charset charset) throws IOException {
|
||||
byte[] buffer = new byte[length];
|
||||
int count = stream.read(buffer);
|
||||
return new String(buffer, 0, count, charset);
|
||||
}
|
||||
|
||||
protected void readMacros(DirectoryNode macroDir, ModuleMap modules) throws IOException {
|
||||
for (Entry entry : macroDir) {
|
||||
if (! (entry instanceof DocumentNode)) { continue; }
|
||||
|
@ -145,7 +173,7 @@ public class VBAMacroReader implements Closeable {
|
|||
String name = entry.getName();
|
||||
DocumentNode document = (DocumentNode)entry;
|
||||
DocumentInputStream dis = new DocumentInputStream(document);
|
||||
if ("dir".equals(name)) {
|
||||
if ("dir".equalsIgnoreCase(name)) {
|
||||
// process DIR
|
||||
RLEDecompressingInputStream in = new RLEDecompressingInputStream(dis);
|
||||
String streamName = null;
|
||||
|
@ -164,9 +192,7 @@ public class VBAMacroReader implements Closeable {
|
|||
modules.charset = Charset.forName("Cp" + codepage);
|
||||
break;
|
||||
case 0x001A: // STREAMNAME
|
||||
byte[] streamNameBuf = new byte[len];
|
||||
int count = in.read(streamNameBuf);
|
||||
streamName = new String(streamNameBuf, 0, count, modules.charset);
|
||||
streamName = readString(in, len, modules.charset);
|
||||
break;
|
||||
case 0x0031: // MODULEOFFSET
|
||||
int moduleOffset = in.readInt();
|
||||
|
@ -191,7 +217,8 @@ public class VBAMacroReader implements Closeable {
|
|||
}
|
||||
}
|
||||
in.close();
|
||||
} else if (!name.startsWith("__SRP") && !name.startsWith("_VBA_PROJECT")) {
|
||||
} else if (!startsWithIgnoreCase(name, "__SRP")
|
||||
&& !startsWithIgnoreCase(name, "_VBA_PROJECT")) {
|
||||
// process module, skip __SRP and _VBA_PROJECT since these do not contain macros
|
||||
Module module = modules.get(name);
|
||||
final InputStream in;
|
||||
|
|
|
@ -289,7 +289,23 @@ public class StringUtil {
|
|||
public static boolean isUnicodeString(final String value) {
|
||||
return !value.equals(new String(value.getBytes(ISO_8859_1), ISO_8859_1));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests if the string starts with the specified prefix, ignoring case consideration.
|
||||
*/
|
||||
public static boolean startsWithIgnoreCase(String haystack, String prefix) {
|
||||
return haystack.regionMatches(true, 0, prefix, 0, prefix.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the string ends with the specified suffix, ignoring case consideration.
|
||||
*/
|
||||
public static boolean endsWithIgnoreCase(String haystack, String suffix) {
|
||||
int length = suffix.length();
|
||||
int start = haystack.length() - length;
|
||||
return haystack.regionMatches(true, start, suffix, 0, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* An Iterator over an array of Strings.
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.security.AccessController;
|
|||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.util.SuppressForbidden;
|
||||
|
||||
|
@ -75,6 +76,17 @@ public class POITestCase {
|
|||
fail("Unable to find " + needle + " in " + haystack);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param map haystack
|
||||
* @param key needle
|
||||
*/
|
||||
public static <T> void assertContains(Map<T, ?> map, T key) {
|
||||
if (map.containsKey(key)) {
|
||||
return;
|
||||
}
|
||||
fail("Unable to find " + key + " in " + map);
|
||||
}
|
||||
|
||||
/** Utility method to get the value of a private/protected field.
|
||||
* Only use this method in test cases!!!
|
||||
*/
|
||||
|
|
|
@ -20,37 +20,58 @@ package org.apache.poi.poifs.macros;
|
|||
import static org.apache.poi.POITestCase.assertContains;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.hssf.HSSFTestDataSamples;
|
||||
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestVBAMacroReader {
|
||||
private final String testMacroContents;
|
||||
private final String testMacroNoSub;
|
||||
public TestVBAMacroReader() throws Exception {
|
||||
File macro = HSSFTestDataSamples.getSampleFile("SimpleMacro.vba");
|
||||
testMacroContents = new String(
|
||||
IOUtils.toByteArray(new FileInputStream(macro)),
|
||||
StringUtil.UTF8
|
||||
);
|
||||
|
||||
private static final Map<POIDataSamples, String> expectedMacroContents;
|
||||
protected static String readVBA(POIDataSamples poiDataSamples) {
|
||||
File macro = poiDataSamples.getFile("SimpleMacro.vba");
|
||||
byte[] bytes;
|
||||
try {
|
||||
bytes = IOUtils.toByteArray(new FileInputStream(macro));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String testMacroContents = new String(bytes, StringUtil.UTF8);
|
||||
|
||||
if (! testMacroContents.startsWith("Sub ")) {
|
||||
throw new IllegalArgumentException("Not a macro");
|
||||
}
|
||||
testMacroNoSub = testMacroContents.substring(testMacroContents.indexOf("()")+3);
|
||||
String testMacroNoSub = testMacroContents.substring(testMacroContents.indexOf("()")+3);
|
||||
return testMacroNoSub;
|
||||
}
|
||||
static {
|
||||
final Map<POIDataSamples, String> _expectedMacroContents = new HashMap<POIDataSamples, String>();
|
||||
final POIDataSamples[] dataSamples = {
|
||||
POIDataSamples.getSpreadSheetInstance(),
|
||||
POIDataSamples.getSlideShowInstance(),
|
||||
POIDataSamples.getDocumentInstance(),
|
||||
POIDataSamples.getDiagramInstance()
|
||||
};
|
||||
for (POIDataSamples sample : dataSamples) {
|
||||
_expectedMacroContents.put(sample, readVBA(sample));
|
||||
}
|
||||
expectedMacroContents = Collections.unmodifiableMap(_expectedMacroContents);
|
||||
}
|
||||
|
||||
//////////////////////////////// From Stream /////////////////////////////
|
||||
@Test
|
||||
public void HSSFfromStream() throws Exception {
|
||||
fromStream(POIDataSamples.getSpreadSheetInstance(), "SimpleMacro.xls");
|
||||
|
@ -59,7 +80,30 @@ public class TestVBAMacroReader {
|
|||
public void XSSFfromStream() throws Exception {
|
||||
fromStream(POIDataSamples.getSpreadSheetInstance(), "SimpleMacro.xlsm");
|
||||
}
|
||||
@Ignore("Found 0 macros")
|
||||
@Test
|
||||
public void HSLFfromStream() throws Exception {
|
||||
fromStream(POIDataSamples.getSlideShowInstance(), "SimpleMacro.ppt");
|
||||
}
|
||||
@Test
|
||||
public void XSLFfromStream() throws Exception {
|
||||
fromStream(POIDataSamples.getSlideShowInstance(), "SimpleMacro.pptm");
|
||||
}
|
||||
@Test
|
||||
public void HWPFfromStream() throws Exception {
|
||||
fromStream(POIDataSamples.getDocumentInstance(), "SimpleMacro.doc");
|
||||
}
|
||||
@Test
|
||||
public void XWPFfromStream() throws Exception {
|
||||
fromStream(POIDataSamples.getDocumentInstance(), "SimpleMacro.docm");
|
||||
}
|
||||
@Ignore("Found 0 macros")
|
||||
@Test
|
||||
public void HDGFfromStream() throws Exception {
|
||||
fromStream(POIDataSamples.getDiagramInstance(), "SimpleMacro.vsd");
|
||||
}
|
||||
|
||||
//////////////////////////////// From File /////////////////////////////
|
||||
@Test
|
||||
public void HSSFfromFile() throws Exception {
|
||||
fromFile(POIDataSamples.getSpreadSheetInstance(), "SimpleMacro.xls");
|
||||
|
@ -68,28 +112,65 @@ public class TestVBAMacroReader {
|
|||
public void XSSFfromFile() throws Exception {
|
||||
fromFile(POIDataSamples.getSpreadSheetInstance(), "SimpleMacro.xlsm");
|
||||
}
|
||||
@Ignore("Found 0 macros")
|
||||
@Test
|
||||
public void HSLFfromFile() throws Exception {
|
||||
fromFile(POIDataSamples.getSlideShowInstance(), "SimpleMacro.ppt");
|
||||
}
|
||||
@Test
|
||||
public void XSLFfromFile() throws Exception {
|
||||
fromFile(POIDataSamples.getSlideShowInstance(), "SimpleMacro.pptm");
|
||||
}
|
||||
@Test
|
||||
public void HWPFfromFile() throws Exception {
|
||||
fromFile(POIDataSamples.getDocumentInstance(), "SimpleMacro.doc");
|
||||
}
|
||||
@Test
|
||||
public void XWPFfromFile() throws Exception {
|
||||
fromFile(POIDataSamples.getDocumentInstance(), "SimpleMacro.docm");
|
||||
}
|
||||
@Ignore("Found 0 macros")
|
||||
@Test
|
||||
public void HDGFfromFile() throws Exception {
|
||||
fromFile(POIDataSamples.getDiagramInstance(), "SimpleMacro.vsd");
|
||||
}
|
||||
|
||||
//////////////////////////////// From NPOIFS /////////////////////////////
|
||||
@Test
|
||||
public void HSSFfromNPOIFS() throws Exception {
|
||||
fromNPOIFS(POIDataSamples.getSpreadSheetInstance(), "SimpleMacro.xls");
|
||||
}
|
||||
@Ignore("Found 0 macros")
|
||||
@Test
|
||||
public void HSLFfromNPOIFS() throws Exception {
|
||||
fromNPOIFS(POIDataSamples.getSlideShowInstance(), "SimpleMacro.ppt");
|
||||
}
|
||||
@Test
|
||||
public void HWPFfromNPOIFS() throws Exception {
|
||||
fromNPOIFS(POIDataSamples.getDocumentInstance(), "SimpleMacro.doc");
|
||||
}
|
||||
@Ignore("Found 0 macros")
|
||||
@Test
|
||||
public void HDGFfromNPOIFS() throws Exception {
|
||||
fromNPOIFS(POIDataSamples.getDiagramInstance(), "SimpleMacro.vsd");
|
||||
}
|
||||
|
||||
protected void fromFile(POIDataSamples poiDataSamples, String filename) throws IOException {
|
||||
File f = poiDataSamples.getFile(filename);
|
||||
protected void fromFile(POIDataSamples dataSamples, String filename) throws IOException {
|
||||
File f = dataSamples.getFile(filename);
|
||||
VBAMacroReader r = new VBAMacroReader(f);
|
||||
try {
|
||||
assertMacroContents(r);
|
||||
assertMacroContents(dataSamples, r);
|
||||
} finally {
|
||||
r.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void fromStream(POIDataSamples poiDataSamples, String filename) throws IOException {
|
||||
InputStream fis = poiDataSamples.openResourceAsStream(filename);
|
||||
protected void fromStream(POIDataSamples dataSamples, String filename) throws IOException {
|
||||
InputStream fis = dataSamples.openResourceAsStream(filename);
|
||||
try {
|
||||
VBAMacroReader r = new VBAMacroReader(fis);
|
||||
try {
|
||||
assertMacroContents(r);
|
||||
assertMacroContents(dataSamples, r);
|
||||
} finally {
|
||||
r.close();
|
||||
}
|
||||
|
@ -98,13 +179,13 @@ public class TestVBAMacroReader {
|
|||
}
|
||||
}
|
||||
|
||||
protected void fromNPOIFS(POIDataSamples poiDataSamples, String filename) throws IOException {
|
||||
File f = poiDataSamples.getFile(filename);
|
||||
protected void fromNPOIFS(POIDataSamples dataSamples, String filename) throws IOException {
|
||||
File f = dataSamples.getFile(filename);
|
||||
NPOIFSFileSystem fs = new NPOIFSFileSystem(f);
|
||||
try {
|
||||
VBAMacroReader r = new VBAMacroReader(fs);
|
||||
try {
|
||||
assertMacroContents(r);
|
||||
assertMacroContents(dataSamples, r);
|
||||
} finally {
|
||||
r.close();
|
||||
}
|
||||
|
@ -113,10 +194,12 @@ public class TestVBAMacroReader {
|
|||
}
|
||||
}
|
||||
|
||||
protected void assertMacroContents(VBAMacroReader r) throws IOException {
|
||||
protected void assertMacroContents(POIDataSamples samples, VBAMacroReader r) throws IOException {
|
||||
assertNotNull(r);
|
||||
Map<String,String> contents = r.readMacros();
|
||||
|
||||
assertFalse(contents.isEmpty());
|
||||
assertNotNull(contents);
|
||||
assertFalse("Found 0 macros", contents.isEmpty());
|
||||
/*
|
||||
assertEquals(5, contents.size());
|
||||
|
||||
// Check the ones without scripts
|
||||
|
@ -132,13 +215,17 @@ public class TestVBAMacroReader {
|
|||
assertContains(content, "Attribute VB_GlobalNameSpace = False");
|
||||
assertContains(content, "Attribute VB_Exposed = True");
|
||||
}
|
||||
*/
|
||||
|
||||
// Check the script one
|
||||
assertContains(contents, "Module1");
|
||||
String content = contents.get("Module1");
|
||||
assertNotNull(content);
|
||||
assertContains(content, "Attribute VB_Name = \"Module1\"");
|
||||
assertContains(content, "Attribute TestMacro.VB_Description = \"This is a test macro\"");
|
||||
//assertContains(content, "Attribute TestMacro.VB_Description = \"This is a test macro\"");
|
||||
|
||||
// And the macro itself
|
||||
String testMacroNoSub = expectedMacroContents.get(samples);
|
||||
assertContains(content, testMacroNoSub);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
|
@ -165,5 +165,24 @@ public class TestStringUtil {
|
|||
fail();
|
||||
} catch(ArrayIndexOutOfBoundsException e) {}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void startsWithIgnoreCase() {
|
||||
assertTrue("same string", StringUtil.startsWithIgnoreCase("Apache POI", "Apache POI"));
|
||||
assertTrue("longer string", StringUtil.startsWithIgnoreCase("Apache POI project", "Apache POI"));
|
||||
assertTrue("different case", StringUtil.startsWithIgnoreCase("APACHE POI", "Apache POI"));
|
||||
assertFalse("leading whitespace should not be ignored", StringUtil.startsWithIgnoreCase(" Apache POI project", "Apache POI"));
|
||||
assertFalse("shorter string", StringUtil.startsWithIgnoreCase("Apache", "Apache POI"));;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void endsWithIgnoreCase() {
|
||||
assertTrue("same string", StringUtil.endsWithIgnoreCase("Apache POI", "Apache POI"));
|
||||
assertTrue("longer string", StringUtil.endsWithIgnoreCase("Project Apache POI", "Apache POI"));
|
||||
assertTrue("different case", StringUtil.endsWithIgnoreCase("APACHE POI", "Apache POI"));
|
||||
assertFalse("trailing whitespace should not be ignored", StringUtil.endsWithIgnoreCase("Apache POI project ", "Apache POI"));
|
||||
assertFalse("shorter string", StringUtil.endsWithIgnoreCase("Apache", "Apache POI"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue