public StreamEncryptionInfo(RecordInputStream rs, List<Record> outputRecs) { Record rec; rs.nextRecord(); int recSize = 4 + rs.remaining(); rec = RecordFactory.createSingleRecord(rs); outputRecs.add(rec); FilePassRecord fpr = null; if (rec instanceof BOFRecord) { _hasBOFRecord = true; // Fetch the next record, and see if it indicates whether // the document is encrypted or not if (rs.hasNextRecord()) { rs.nextRecord(); rec = RecordFactory.createSingleRecord(rs); recSize += rec.getRecordSize(); outputRecs.add(rec); // Encrypted is normally BOF then FILEPASS // May sometimes be BOF, WRITEPROTECT, FILEPASS if (rec instanceof WriteProtectRecord && rs.hasNextRecord()) { rs.nextRecord(); rec = RecordFactory.createSingleRecord(rs); recSize += rec.getRecordSize(); outputRecs.add(rec); } // If it's a FILEPASS, track it specifically but // don't include it in the main stream if (rec instanceof FilePassRecord) { fpr = (FilePassRecord) rec; outputRecs.remove(outputRecs.size() - 1); // TODO - add fpr not added to outputRecs rec = outputRecs.get(0); } else { // workbook not encrypted (typical case) if (rec instanceof EOFRecord) { // A workbook stream is never empty, so crash instead // of trying to keep track of nesting level throw new IllegalStateException("Nothing between BOF and EOF"); } } } } else { // Invalid in a normal workbook stream. // However, some test cases work on sub-sections of // the workbook stream that do not begin with BOF _hasBOFRecord = false; } _initialRecordsSize = recSize; _filePassRec = fpr; _lastRecord = rec; }
public void run() throws IOException { NPOIFSFileSystem fs = new NPOIFSFileSystem(new File(file), true); try { InputStream din = BiffViewer.getPOIFSInputStream(fs); try { RecordInputStream rinp = new RecordInputStream(din); while (rinp.hasNextRecord()) { int sid = rinp.getNextSid(); rinp.nextRecord(); int size = rinp.available(); Class<? extends Record> clz = RecordFactory.getRecordClass(sid); System.out.print(formatSID(sid) + " - " + formatSize(size) + " bytes"); if (clz != null) { System.out.print(" \t"); System.out.print(clz.getName().replace("org.apache.poi.hssf.record.", "")); } System.out.println(); byte[] data = rinp.readRemainder(); if (data.length > 0) { System.out.print(" "); System.out.println(formatData(data)); } } } finally { din.close(); } } finally { fs.close(); } }
/** * Silently swallow unexpected contents in InterfaceEndRecord. Although it violates the spec, * Excel silently converts this data to an {@link InterfaceHdrRecord}. */ public void testUnexpectedBytes_bug47251() { String hex = "" + "09 08 10 00 00 06 05 00 EC 15 CD 07 C1 C0 00 00 06 03 00 00 " + // BOF "E2 00 02 00 B0 04 " + // INTERFACEEND with extra two bytes "0A 00 00 00"; // EOF byte[] data = HexRead.readFromString(hex); List<Record> records = RecordFactory.createRecords(new ByteArrayInputStream(data)); assertEquals(3, records.size()); Record rec1 = records.get(1); assertEquals(InterfaceHdrRecord.class, rec1.getClass()); InterfaceHdrRecord r = (InterfaceHdrRecord) rec1; assertEquals("[E1, 00, 02, 00, B0, 04]", HexDump.toHex(r.serialize())); }
/** * @return the next available record, or <code>null</code> if this pass didn't return a record * that's suitable for returning (eg was a continue record). */ private Record readNextRecord() { Record record = RecordFactory.createSingleRecord(_recStream); _lastRecordWasEOFLevelZero = false; if (record instanceof BOFRecord) { _bofDepth++; return record; } if (record instanceof EOFRecord) { _bofDepth--; if (_bofDepth < 1) { _lastRecordWasEOFLevelZero = true; } return record; } if (record instanceof DBCellRecord) { // Not needed by POI. Regenerated from scratch by POI when spreadsheet is written return null; } if (record instanceof RKRecord) { return RecordFactory.convertToNumberRecord((RKRecord) record); } if (record instanceof MulRKRecord) { Record[] records = RecordFactory.convertRKRecords((MulRKRecord) record); _unreadRecordBuffer = records; _unreadRecordIndex = 1; return records[0]; } if (record.getSid() == DrawingGroupRecord.sid && _lastRecord instanceof DrawingGroupRecord) { DrawingGroupRecord lastDGRecord = (DrawingGroupRecord) _lastRecord; lastDGRecord.join((AbstractEscherHolderRecord) record); return null; } if (record.getSid() == ContinueRecord.sid) { ContinueRecord contRec = (ContinueRecord) record; if (_lastRecord instanceof ObjRecord || _lastRecord instanceof TextObjectRecord) { // Drawing records have a very strange continue behaviour. // There can actually be OBJ records mixed between the continues. _lastDrawingRecord.processContinueRecord(contRec.getData()); // we must remember the position of the continue record. // in the serialization procedure the original structure of records must be preserved if (_shouldIncludeContinueRecords) { return record; } return null; } if (_lastRecord instanceof DrawingGroupRecord) { ((DrawingGroupRecord) _lastRecord).processContinueRecord(contRec.getData()); return null; } if (_lastRecord instanceof DrawingRecord) { // ((DrawingRecord) _lastRecord).appendContinueRecord(contRec.getData()); return contRec; } if (_lastRecord instanceof UnknownRecord) { // Gracefully handle records that we don't know about, // that happen to be continued return record; } if (_lastRecord instanceof EOFRecord) { // This is really odd, but excel still sometimes // outputs a file like this all the same return record; } throw new RecordFormatException( "Unhandled Continue Record followining " + _lastRecord.getClass()); } _lastRecord = record; if (record instanceof DrawingRecord) { _lastDrawingRecord = (DrawingRecord) record; } return record; }