bug 59830: attach context to any IOException (likely a result of reaching EOF on input stream)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1751986 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Javen O'Neal 2016-07-09 08:05:43 +00:00
parent 518253650a
commit 76dde0aed5

View File

@ -40,6 +40,7 @@ import org.apache.poi.poifs.filesystem.DocumentNode;
import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.poifs.filesystem.Entry;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.poifs.filesystem.OfficeXmlFileException; import org.apache.poi.poifs.filesystem.OfficeXmlFileException;
import org.apache.poi.util.HexDump;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.RLEDecompressingInputStream; import org.apache.poi.util.RLEDecompressingInputStream;
@ -179,13 +180,31 @@ public class VBAMacroReader implements Closeable {
private static void trySkip(InputStream in, long n) throws IOException { private static void trySkip(InputStream in, long n) throws IOException {
long skippedBytes = in.skip(n); long skippedBytes = in.skip(n);
if (skippedBytes != n) { if (skippedBytes != n) {
throw new IOException( if (skippedBytes < 0) {
"Skipped only " + skippedBytes + " while trying to skip " + n + " bytes. " + throw new IOException(
" This should never happen."); "Tried skipping " + n + " bytes, but no bytes were skipped. "
+ "The end of the stream has been reached or the stream is closed.");
} else {
throw new IOException(
"Tried skipping " + n + " bytes, but only " + skippedBytes + " bytes were skipped. "
+ "This should never happen.");
}
} }
} }
/* // Constants from MS-OVBA: https://msdn.microsoft.com/en-us/library/office/cc313094(v=office.12).aspx
private static final int EOF = -1;
private static final int VERSION_INDEPENDENT_TERMINATOR = 0x0010;
private static final int VERSION_DEPENDENT_TERMINATOR = 0x002B;
private static final int PROJECTVERSION = 0x0009;
private static final int PROJECTCODEPAGE = 0x0003;
private static final int STREAMNAME = 0x001A;
private static final int MODULEOFFSET = 0x0031;
private static final int MODULETYPE_PROCEDURAL = 0x0021;
private static final int MODULETYPE_DOCUMENT_CLASS_OR_DESIGNER = 0x0022;
private static final int PROJECTLCID = 0x0002;
/**
* Reads VBA Project modules from a VBA Project directory located at * Reads VBA Project modules from a VBA Project directory located at
* <tt>macroDir</tt> into <tt>modules</tt>. * <tt>macroDir</tt> into <tt>modules</tt>.
* *
@ -203,50 +222,56 @@ public class VBAMacroReader implements Closeable {
// process DIR // process DIR
RLEDecompressingInputStream in = new RLEDecompressingInputStream(dis); RLEDecompressingInputStream in = new RLEDecompressingInputStream(dis);
String streamName = null; String streamName = null;
while (true) { int recordId = 0;
int id = in.readShort(); try {
if (id == -1 || id == 0x0010) { while (true) {
break; // EOF or TERMINATOR recordId = in.readShort();
} if (EOF == recordId
int len = in.readInt(); || VERSION_INDEPENDENT_TERMINATOR == recordId) {
switch (id) { break;
case 0x0009: // PROJECTVERSION
trySkip(in, 6);
break;
case 0x0003: // PROJECTCODEPAGE
int codepage = in.readShort();
modules.charset = Charset.forName("Cp" + codepage);
break;
case 0x001A: // STREAMNAME
streamName = readString(in, len, modules.charset);
break;
case 0x0031: // MODULEOFFSET
int moduleOffset = in.readInt();
Module module = modules.get(streamName);
if (module != null) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
RLEDecompressingInputStream stream = new RLEDecompressingInputStream(new ByteArrayInputStream(
module.buf, moduleOffset, module.buf.length - moduleOffset));
IOUtils.copy(stream, out);
stream.close();
out.close();
module.buf = out.toByteArray();
} else {
module = new Module();
module.offset = moduleOffset;
modules.put(streamName, module);
} }
break; int recordLength = in.readInt();
default: switch (recordId) {
try { case PROJECTVERSION:
trySkip(in, len); trySkip(in, 6);
} catch (final IOException e) { break;
throw new IOException("Error occurred while reading section id " + id, e); case PROJECTCODEPAGE:
int codepage = in.readShort();
modules.charset = Charset.forName("Cp" + codepage);
break;
case STREAMNAME:
streamName = readString(in, recordLength, modules.charset);
break;
case MODULEOFFSET:
int moduleOffset = in.readInt();
Module module = modules.get(streamName);
if (module != null) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
RLEDecompressingInputStream stream = new RLEDecompressingInputStream(new ByteArrayInputStream(
module.buf, moduleOffset, module.buf.length - moduleOffset));
IOUtils.copy(stream, out);
stream.close();
out.close();
module.buf = out.toByteArray();
} else {
module = new Module();
module.offset = moduleOffset;
modules.put(streamName, module);
}
break;
default:
trySkip(in, recordLength);
break;
} }
break;
} }
} catch (final IOException e) {
throw new IOException(
"Error occurred while reading macros at section id "
+ recordId + " (" + HexDump.shortToHex(recordId) + ")", e);
}
finally {
in.close();
} }
in.close();
} else if (!startsWithIgnoreCase(name, "__SRP") } else if (!startsWithIgnoreCase(name, "__SRP")
&& !startsWithIgnoreCase(name, "_VBA_PROJECT")) { && !startsWithIgnoreCase(name, "_VBA_PROJECT")) {
// process module, skip __SRP and _VBA_PROJECT since these do not contain macros // process module, skip __SRP and _VBA_PROJECT since these do not contain macros