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;
  }