in poi/src/main/java/org/apache/poi/poifs/macros/VBAMacroReader.java [483:606]
private void processDirStream(Entry dir, ModuleMap modules) throws IOException {
DocumentNode dirDocumentNode = (DocumentNode)dir;
DIR_STATE dirState = DIR_STATE.INFORMATION_RECORD;
try (DocumentInputStream dis = new DocumentInputStream(dirDocumentNode)) {
String streamName = null;
int recordId = 0;
try (RLEDecompressingInputStream in = new RLEDecompressingInputStream(dis)) {
while (true) {
recordId = in.readShort();
if (recordId == -1) {
break;
}
RecordType type = RecordType.lookup(recordId);
if (type.equals(RecordType.EOF) || type.equals(RecordType.DIR_STREAM_TERMINATOR)) {
break;
}
switch (type) {
case PROJECT_VERSION:
trySkip(in, RecordType.PROJECT_VERSION.getConstantLength());
break;
case PROJECT_CODEPAGE:
in.readInt();//record size must == 4
int codepage = in.readShort();
modules.charset = Charset.forName(CodePageUtil.codepageToEncoding(codepage, true));
break;
case MODULE_STREAM_NAME:
ASCIIUnicodeStringPair pair = readStringPair(in, modules.charset, STREAMNAME_RESERVED);
streamName = pair.getAscii();
break;
case PROJECT_DOC_STRING:
readStringPair(in, modules.charset, DOC_STRING_RESERVED);
break;
case PROJECT_HELP_FILE_PATH:
readStringPair(in, modules.charset, HELP_FILE_PATH_RESERVED);
break;
case PROJECT_CONSTANTS:
readStringPair(in, modules.charset, PROJECT_CONSTANTS_RESERVED);
break;
case REFERENCE_NAME:
if (dirState.equals(DIR_STATE.INFORMATION_RECORD)) {
dirState = DIR_STATE.REFERENCES_RECORD;
}
ASCIIUnicodeStringPair stringPair = readStringPair(in,
modules.charset, REFERENCE_NAME_RESERVED, false);
if (stringPair.getPushbackRecordId() == -1) {
break;
}
//Special handling for when there's only an ascii string and a REFERENCED_REGISTERED
//record that follows.
//See https://github.com/decalage2/oletools/blob/master/oletools/olevba.py#L1516
//and https://github.com/decalage2/oletools/pull/135 from (@c1fe)
if (stringPair.getPushbackRecordId() != RecordType.REFERENCE_REGISTERED.id) {
throw new IllegalArgumentException("Unexpected reserved character. "+
"Expected "+Integer.toHexString(REFERENCE_NAME_RESERVED)
+ " or "+Integer.toHexString(RecordType.REFERENCE_REGISTERED.id)+
" not: "+Integer.toHexString(stringPair.getPushbackRecordId()));
}
//fall through!
case REFERENCE_REGISTERED:
//REFERENCE_REGISTERED must come immediately after
//REFERENCE_NAME to allow for fall through in special case of bug 62625
int recLength = in.readInt();
trySkip(in, recLength);
break;
case MODULE_DOC_STRING:
int modDocStringLength = in.readInt();
readString(in, modDocStringLength, modules.charset);
int modDocStringReserved = in.readShort();
if (modDocStringReserved != MODULE_DOCSTRING_RESERVED) {
throw new IOException("Expected x003C after stream name before Unicode stream name, but found: " +
Integer.toHexString(modDocStringReserved));
}
int unicodeModDocStringLength = in.readInt();
readUnicodeString(in, unicodeModDocStringLength);
// do something with this at some point
break;
case MODULE_OFFSET:
int modOffsetSz = in.readInt();
//should be 4
readModuleMetadataFromDirStream(in, streamName, modules);
break;
case PROJECT_MODULES:
dirState = DIR_STATE.MODULES_RECORD;
in.readInt();//size must == 2
in.readShort();//number of modules
break;
case REFERENCE_CONTROL_A:
int szTwiddled = in.readInt();
trySkip(in, szTwiddled);
int nextRecord = in.readShort();
//reference name is optional!
if (nextRecord == RecordType.REFERENCE_NAME.id) {
readStringPair(in, modules.charset, REFERENCE_NAME_RESERVED);
nextRecord = in.readShort();
}
if (nextRecord != 0x30) {
throw new IOException("Expected 0x30 as Reserved3 in a ReferenceControl record");
}
int szExtended = in.readInt();
trySkip(in, szExtended);
break;
case MODULE_TERMINATOR:
int endOfModulesReserved = in.readInt();
//must be 0;
break;
default:
if (type.getConstantLength() > -1) {
trySkip(in, type.getConstantLength());
} else {
int recordLength = in.readInt();
trySkip(in, recordLength);
}
break;
}
}
} catch (final IOException e) {
throw new IOException(
"Error occurred while reading macros at section id "
+ recordId + " (" + HexDump.shortToHex(recordId) + ")", e);
}
}
}