public CustomViewSettingsRecordAggregate(RecordStream rs) { _begin = rs.GetNext(); if (_begin.Sid != UserSViewBegin.sid) { throw new InvalidOperationException("Bad begin record"); } List<RecordBase> temp = new List<RecordBase>(); while (rs.PeekNextSid() != UserSViewEnd.sid) { if (PageSettingsBlock.IsComponentRecord(rs.PeekNextSid())) { if (_psBlock != null) { throw new InvalidOperationException( "Found more than one PageSettingsBlock in custom view Settings sub-stream"); } _psBlock = new PageSettingsBlock(rs); temp.Add(_psBlock); continue; } temp.Add(rs.GetNext()); } _recs = temp; _end = rs.GetNext(); // no need to save EOF in field if (_end.Sid != UserSViewEnd.sid) { throw new InvalidOperationException("Bad custom view Settings end record"); } }
/** * sends the record event to all registered listeners. * @param record the record to be thrown. * @return <c>false</c> to abort. This aborts * out of the event loop should the listener return false */ private bool ProcessRecord(Record record) { if (!IsSidIncluded(record.Sid)) { return true; } return _listener.ProcessRecord(record); }
/** * Process this record ourselves, and then * pass it on to our child listener */ public void ProcessRecord(Record record) { // Handle it ourselves ProcessRecordInternally(record); // Now pass on to our child childListener.ProcessRecord(record); }
/** * Process the record ourselves, but do not * pass it on to the child Listener. * @param record */ public void ProcessRecordInternally(Record record) { if (record is FormatRecord) { FormatRecord fr = (FormatRecord)record; customFormatRecords[fr.IndexCode] = fr; } else if (record is ExtendedFormatRecord) { ExtendedFormatRecord xr = (ExtendedFormatRecord)record; xfRecords.Add(xr); } }
private void CreateFilterModeRecord(HSSFSheet sheet, int insertPos) { //look for the FilterModeRecord Zephyr.Utils.NPOI.HSSF.Record.Record record = sheet.Sheet.FindFirstRecordBySid(FilterModeRecord.sid); // this local variable hides the class one: FilterModeRecord filtermode; //if not found, add a new one if (record == null) { filtermode = new FilterModeRecord(); sheet.Sheet.Records.Insert(insertPos, filtermode); } }
/// <summary> /// Adds the specified pos. /// </summary> /// <param name="pos">The pos.</param> /// <param name="r">The r.</param> public void Add(int pos, Record r) { records.Insert(pos, r); if (Protpos >= pos) Protpos=(protpos + 1); if (Bspos >= pos) Bspos=(bspos + 1); if (Tabpos >= pos) Tabpos=(tabpos + 1); if (Fontpos >= pos) Fontpos=(fontpos + 1); if (Xfpos >= pos) Xfpos=(xfpos + 1); if (Backuppos >= pos) Backuppos=(backuppos + 1); if (Namepos>= pos) Namepos=(namepos + 1); if (Supbookpos >= pos) Supbookpos=(supbookpos + 1); if ((Palettepos!= -1) && (Palettepos>= pos)) Palettepos=(palettepos + 1); if (ExternsheetPos >= pos) ExternsheetPos=ExternsheetPos + 1; }
private void CreateAutoFilterInfoRecord(HSSFSheet sheet, int insertPos, Area3DPtg ptg) { //look for the AutoFilterInfo Record Zephyr.Utils.NPOI.HSSF.Record.Record record = sheet.Sheet.FindFirstRecordBySid(AutoFilterInfoRecord.sid); AutoFilterInfoRecord info; if (record == null) { info = new AutoFilterInfoRecord(); sheet.Sheet.Records.Insert(insertPos, info); } else { info = record as AutoFilterInfoRecord; } info.NumEntries = (short)(ptg.LastColumn - ptg.FirstColumn + 1); }
public void VisitRecord(Record r) { _position += r.RecordSize; _rv.VisitRecord(r); }
public void VisitRecord(Record r) { _totalSize += r.RecordSize; }
/// <summary> /// Called by HSSFEventFactory, passes the Record to each listener associated with /// a record.sid. /// Exception and return value Added 2002-04-19 by Carey Sublette /// </summary> /// <param name="rec">The record.</param> /// <returns>numeric user-specified result code. If zero continue Processing.</returns> public short ProcessRecord(Record rec) { Object obj = records[rec.Sid]; short userCode = 0; if (obj != null) { IList listeners = (IList)obj; for (int k = 0; k < listeners.Count; k++) { Object listenObj = listeners[k]; if (listenObj is AbortableHSSFListener) { AbortableHSSFListener listener = (AbortableHSSFListener)listenObj; userCode = listener.AbortableProcessRecord(rec); if (userCode != 0) break; } else { HSSFListener listener = (HSSFListener)listenObj; listener.ProcessRecord(rec); } } } return userCode; }
/// <summary> /// Process an HSSF Record. Called when a record occurs in an HSSF file. /// </summary> /// <param name="record"></param> public void ProcessRecord(Record record) { int thisRow; int thisColumn; CellValueRecordInterface[] expandedRecords = null; if (record is CellValueRecordInterface) { CellValueRecordInterface valueRec = (CellValueRecordInterface)record; thisRow = valueRec.Row; thisColumn = valueRec.Column; } else { thisRow = -1; thisColumn = -1; switch (record.Sid) { // the BOFRecord can represent either the beginning of a sheet or the workbook case BOFRecord.sid: BOFRecord bof = (BOFRecord)record; if (bof.Type == BOFRecord.TYPE_WORKBOOK || bof.Type == BOFRecord.TYPE_WORKSHEET) { // Reset the row and column counts - new workbook / worksheet ResetCounts(); } break; case RowRecord.sid: RowRecord rowrec = (RowRecord)record; //Console.WriteLine("Row " + rowrec.RowNumber + " found, first column at " // + rowrec.GetFirstCol() + " last column at " + rowrec.GetLastCol()); // If there's a jump in rows, fire off missing row records if (lastRowRow + 1 < rowrec.RowNumber) { for (int i = (lastRowRow + 1); i < rowrec.RowNumber; i++) { MissingRowDummyRecord dr = new MissingRowDummyRecord(i); childListener.ProcessRecord(dr); } } // Record this as the last row we saw lastRowRow = rowrec.RowNumber; break; case SharedFormulaRecord.sid: // SharedFormulaRecord occurs after the first FormulaRecord of the cell range. // There are probably (but not always) more cell records after this // - so don't fire off the LastCellOfRowDummyRecord yet childListener.ProcessRecord(record); return; case MulBlankRecord.sid: // These appear in the middle of the cell records, to // specify that the next bunch are empty but styled // Expand this out into multiple blank cells MulBlankRecord mbr = (MulBlankRecord)record; expandedRecords = RecordFactory.ConvertBlankRecords(mbr); break; case MulRKRecord.sid: // This is multiple consecutive number cells in one record // Exand this out into multiple regular number cells MulRKRecord mrk = (MulRKRecord)record; expandedRecords = RecordFactory.ConvertRKRecords(mrk); break; case NoteRecord.sid: NoteRecord nrec = (NoteRecord)record; thisRow = nrec.Row; thisColumn = nrec.Column; break; default: //Console.WriteLine(record.GetClass()); break; } } // First part of expanded record handling if (expandedRecords != null && expandedRecords.Length > 0) { thisRow = expandedRecords[0].Row; thisColumn = expandedRecords[0].Column; } // If we're on cells, and this cell isn't in the same // row as the last one, then fire the // dummy end-of-row records if (thisRow != lastCellRow && lastCellRow > -1) { for (int i = lastCellRow; i < thisRow; i++) { int cols = -1; if (i == lastCellRow) { cols = lastCellColumn; } childListener.ProcessRecord(new LastCellOfRowDummyRecord(i, cols)); } } // If we've just finished with the cells, then fire the // final dummy end-of-row record if (lastCellRow != -1 && lastCellColumn != -1 && thisRow == -1) { childListener.ProcessRecord(new LastCellOfRowDummyRecord(lastCellRow, lastCellColumn)); lastCellRow = -1; lastCellColumn = -1; } // If we've moved onto a new row, the ensure we re-set // the column counter if (thisRow != lastCellRow) { lastCellColumn = -1; } // If there's a gap in the cells, then fire // the dummy cell records if (lastCellColumn != thisColumn - 1) { for (int i = lastCellColumn + 1; i < thisColumn; i++) { childListener.ProcessRecord(new MissingCellDummyRecord(thisRow, i)); } } // Next part of expanded record handling if (expandedRecords != null && expandedRecords.Length > 0) { thisColumn = expandedRecords[expandedRecords.Length - 1].Column; } // Update cell and row counts as needed if (thisColumn != -1) { lastCellColumn = thisColumn; lastCellRow = thisRow; } // Pass along the record(s) if (expandedRecords != null && expandedRecords.Length > 0) { foreach (CellValueRecordInterface r in expandedRecords) { childListener.ProcessRecord((Record)r); } } else { childListener.ProcessRecord(record); } }
/// <summary> /// Process an HSSF Record. Called when a record occurs in an HSSF file. /// </summary> /// <param name="record"></param> public void ProcessRecord(Record record) { String thisText = null; int thisRow = -1; switch (record.Sid) { case BoundSheetRecord.sid: BoundSheetRecord sr = (BoundSheetRecord)record; sheetNames.Add(sr.Sheetname); break; case BOFRecord.sid: BOFRecord bof = (BOFRecord)record; if (bof.Type == BOFRecord.TYPE_WORKSHEET) { sheetNum++; rowNum = -1; if (includeSheetNames) { if (text.Length > 0) text.Append("\n"); text.Append(sheetNames[sheetNum]); } } break; case SSTRecord.sid: sstRecord = (SSTRecord)record; break; case FormulaRecord.sid: FormulaRecord frec = (FormulaRecord)record; thisRow = frec.Row; if (formulasNotResults) { thisText = HSSFFormulaParser.ToFormulaString((HSSFWorkbook)null, frec.ParsedExpression); } else { if (frec.HasCachedResultString) { // Formula result is a string // This is stored in the next record outputNextStringValue = true; nextRow = frec.Row; } else { thisText = FormatNumberDateCell(frec, frec.Value); } } break; case StringRecord.sid: if (outputNextStringValue) { // String for formula StringRecord srec = (StringRecord)record; thisText = srec.String; thisRow = nextRow; outputNextStringValue = false; } break; case LabelRecord.sid: LabelRecord lrec = (LabelRecord)record; thisRow = lrec.Row; thisText = lrec.Value; break; case LabelSSTRecord.sid: LabelSSTRecord lsrec = (LabelSSTRecord)record; thisRow = lsrec.Row; if (sstRecord == null) { throw new Exception("No SST record found"); } thisText = sstRecord.GetString(lsrec.SSTIndex).ToString(); break; case NoteRecord.sid: NoteRecord nrec = (NoteRecord)record; thisRow = nrec.Row; // TODO: Find object to match nrec.GetShapeId() break; case NumberRecord.sid: NumberRecord numrec = (NumberRecord)record; thisRow = numrec.Row; thisText = FormatNumberDateCell(numrec, numrec.Value); break; default: break; } if (thisText != null) { if (thisRow != rowNum) { rowNum = thisRow; if (text.Length > 0) text.Append("\n"); } else { text.Append("\t"); } text.Append(thisText); } }
/** * Process an HSSF Record. Called when a record occurs in an HSSF file. * Provides two options for halting the Processing of the HSSF file. * * The return value provides a means of non-error termination with a * user-defined result code. A value of zero must be returned to * continue Processing, any other value will halt Processing by * <c>HSSFEventFactory</c> with the code being passed back by * its abortable Process events methods. * * Error termination can be done by throwing the HSSFUserException. * * Note that HSSFEventFactory will not call the inherited Process * * @return result code of zero for continued Processing. * * @throws HSSFUserException User code can throw this to abort * file Processing by HSSFEventFactory and return diagnostic information. */ public abstract short AbortableProcessRecord(Record record);
/// <summary> /// Removes the specified record. /// </summary> /// <param name="record">The record.</param> public void Remove(Record record) { int i = records.IndexOf(record); this.Remove(i); }
private static void AddAll(List<Record> destList, Record[] srcRecs) { for (int i = 0; i < srcRecs.Length; i++) { destList.Add(srcRecs[i]); } }
public void VisitRecord(Record r) { _list.Add(r); _totalSize += r.RecordSize; }
public void VisitRecord(Record r) { if (r.Sid == UserSViewBegin.sid) { byte[] guid1 = ((UserSViewBegin)r).Guid; byte[] guid2 = _hf.Guid; if (Arrays.Equals(guid1, guid2)) { _cv.Append(_hf); _sviewHeaderFooters.Remove(_hf); } } }
private bool ReadARecord(RecordStream rs) { switch (rs.PeekNextSid()) { case HorizontalPageBreakRecord.sid: CheckNotPresent(_rowBreaksRecord); _rowBreaksRecord = (PageBreakRecord)rs.GetNext(); break; case VerticalPageBreakRecord.sid: CheckNotPresent(_columnBreaksRecord); _columnBreaksRecord = (PageBreakRecord)rs.GetNext(); break; case HeaderRecord.sid: CheckNotPresent(header); header = (HeaderRecord)rs.GetNext(); break; case FooterRecord.sid: CheckNotPresent(footer); footer = (FooterRecord)rs.GetNext(); break; case HCenterRecord.sid: CheckNotPresent(_hCenter); _hCenter = (HCenterRecord)rs.GetNext(); break; case VCenterRecord.sid: CheckNotPresent(_vCenter); _vCenter = (VCenterRecord)rs.GetNext(); break; case LeftMarginRecord.sid: CheckNotPresent(_leftMargin); _leftMargin = (LeftMarginRecord)rs.GetNext(); break; case RightMarginRecord.sid: CheckNotPresent(_rightMargin); _rightMargin = (RightMarginRecord)rs.GetNext(); break; case TopMarginRecord.sid: CheckNotPresent(_topMargin); _topMargin = (TopMarginRecord)rs.GetNext(); break; case BottomMarginRecord.sid: CheckNotPresent(_bottomMargin); _bottomMargin = (BottomMarginRecord)rs.GetNext(); break; case UnknownRecord.PLS_004D: // PLS _plsRecords.Add(new PLSAggregate(rs)); break; case PrintSetupRecord.sid: CheckNotPresent(printSetup); printSetup = (PrintSetupRecord)rs.GetNext(); break; case UnknownRecord.BITMAP_00E9: // BITMAP CheckNotPresent(_bitmap); _bitmap = rs.GetNext(); break; case UnknownRecord.PRINTSIZE_0033: CheckNotPresent(_printSize); _printSize = rs.GetNext(); break; case HeaderFooterRecord.sid: HeaderFooterRecord hf = (HeaderFooterRecord)rs.GetNext(); if (hf.IsCurrentSheet) _headerFooter = hf; else _sviewHeaderFooters.Add(hf); break; default: // all other record types are not part of the PageSettingsBlock return false; } return true; }
/** * Handles UnknownRecords which appear within the row/cell records */ private void AddUnknownRecord(Record rec) { // ony a few distinct record IDs are encountered by the existing POI test cases: // 0x1065 // many // 0x01C2 // several // 0x0034 // few // No documentation could be found for these // keep the unknown records for re-serialization _unknownRecords.Add(rec); }
public void VisitRecord(Record r) { int currentOffset = _startOffset + _countBytesWritten; _countBytesWritten += r.Serialize(currentOffset, _data); }
private void CheckNotPresent(Record rec) { if (rec != null) { throw new RecordFormatException("Duplicate WorksheetProtectionBlock record (sid=0x" + StringUtil.ToHexString(rec.Sid) + ")"); } }
/// <summary> /// Returns the next available record, or null if /// this pass didn't return a record that's /// suitable for returning (eg was a continue record). /// </summary> /// <returns></returns> private Record GetNextRecord() { Record toReturn = null; if (in1.HasNextRecord) { // Grab our next record in1.NextRecord(); short sid = in1.Sid; // // for some reasons we have to make the workbook to be at least 4096 bytes // but if we have such workbook we Fill the end of it with zeros (many zeros) // // it Is not good: // if the Length( all zero records ) % 4 = 1 // e.g.: any zero record would be Readed as 4 bytes at once ( 2 - id and 2 - size ). // And the last 1 byte will be Readed WRONG ( the id must be 2 bytes ) // // So we should better to Check if the sid Is zero and not to Read more data // The zero sid shows us that rest of the stream data Is a fake to make workbook // certain size // if (sid == 0) return null; // If we had a last record, and this one // Isn't a continue record, then pass // it on to the listener if ((rec != null) && (sid != ContinueRecord.sid)) { // This last record ought to be returned toReturn = rec; } // If this record Isn't a continue record, // then build it up if (sid != ContinueRecord.sid) { //Console.WriteLine("creating "+sid); Record[] recs = RecordFactory.CreateRecord(in1); // We know that the multiple record situations // don't contain continue records, so just // pass those on to the listener now if (recs.Length > 1) { bonusRecords = new ArrayList(recs.Length - 1); for (int k = 0; k < (recs.Length - 1); k++) { bonusRecords.Add(recs[k]); } } // Regardless of the number we Created, always hold // onto the last record to be Processed on the next // loop, in case it has any continue records rec = recs[recs.Length - 1]; // Don't return it just yet though, as we probably have // a record from the last round to return } else { // Normally, ContinueRecords are handled internally // However, in a few cases, there Is a gap between a record at // its Continue, so we have to handle them specially // This logic Is much like in RecordFactory.CreateRecords() Record[] recs = RecordFactory.CreateRecord(in1); ContinueRecord crec = (ContinueRecord)recs[0]; if ((lastRec is ObjRecord) || (lastRec is TextObjectRecord)) { // You can have Obj records between a DrawingRecord // and its continue! lastDrawingRecord.ProcessContinueRecord(crec.Data); // Trigger them on the drawing record, now it's complete rec = lastDrawingRecord; } else if ((lastRec is DrawingGroupRecord)) { ((DrawingGroupRecord)lastRec).ProcessContinueRecord(crec.Data); // Trigger them on the drawing record, now it's complete rec = lastRec; } else { if (rec is UnknownRecord) { ;//silently skip records we don't know about } else { throw new RecordFormatException("Records should handle ContinueRecord internally. Should not see this exception"); } } } // Update our tracking of the last record lastRec = rec; if (rec is DrawingRecord) { lastDrawingRecord = (DrawingRecord)rec; } } else { // No more records hitEOS = true; } // If we've hit the end-of-stream, then // finish off the last record and be done if (hitEOS) { complete = true; // Return the last record if there was // one, otherwise null if (rec != null) { toReturn = rec; rec = null; } } return toReturn; }
public void VisitRecord(Record r) { _destList.Add(r.Clone()); }
/** * Associates an escher record to an OBJ record or a TXO record. */ public Object AssoicateShapeToObjRecord(EscherRecord r, Record objRecord) { return shapeToObj[r]= objRecord; }
public void VisitRecord(Record r) { _records.Add(r); }
/** * This method, inherited from HSSFListener Is implemented as a stub. * It Is never called by HSSFEventFActory or HSSFRequest. * */ public virtual void ProcessRecord(Record record) { }
/** * @param shouldIncludeContinueRecords caller can pass <c>false</c> if loose * {@link ContinueRecord}s should be skipped (this is sometimes useful in event based * processing). */ public RecordFactoryInputStream(Stream in1, bool shouldIncludeContinueRecords) { RecordInputStream rs = new RecordInputStream(in1); List<Record> records = new List<Record>(); StreamEncryptionInfo sei = new StreamEncryptionInfo(rs, records); if (sei.HasEncryption) { rs = sei.CreateDecryptingStream(in1); } else { // typical case - non-encrypted stream } if (records.Count != 0) { _unreadRecordBuffer = new Record[records.Count]; _unreadRecordBuffer = records.ToArray(); _unreadRecordIndex = 0; } _recStream = rs; _shouldIncludeContinueRecords = shouldIncludeContinueRecords; _lastRecord = sei.LastRecord; /* * How to recognise end of stream? * In the best case, the underlying input stream (in) ends just after the last EOF record * Usually however, the stream is pAdded with an arbitrary byte count. Excel and most apps * reliably use zeros for pAdding and if this were always the case, this code could just * skip all the (zero sized) records with sid==0. However, bug 46987 Shows a file with * non-zero pAdding that is read OK by Excel (Excel also fixes the pAdding). * * So to properly detect the workbook end of stream, this code has to identify the last * EOF record. This is not so easy because the worbook bof+eof pair do not bracket the * whole stream. The worksheets follow the workbook, but it is not easy to tell how many * sheet sub-streams should be present. Hence we are looking for an EOF record that is not * immediately followed by a BOF record. One extra complication is that bof+eof sub- * streams can be nested within worksheet streams and it's not clear in these cases what * record might follow any EOF record. So we also need to keep track of the bof/eof * nesting level. */ _bofDepth = sei.HasBOFRecord ? 1 : 0; _lastRecordWasEOFLevelZero = false; }
private static void VisitIfPresent(Record r, RecordVisitor rv) { if (r != null) { rv.VisitRecord(r); } }
/** * @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 is BOFRecord) { _bofDepth++; return record; } if (record is EOFRecord) { _bofDepth--; if (_bofDepth < 1) { _lastRecordWasEOFLevelZero = true; } return record; } if (record is DBCellRecord) { // Not needed by POI. Regenerated from scratch by POI when spreadsheet is written return null; } if (record is RKRecord) { return RecordFactory.ConvertToNumberRecord((RKRecord)record); } if (record is MulRKRecord) { Record[] records = RecordFactory.ConvertRKRecords((MulRKRecord)record); _unreadRecordBuffer = records; _unreadRecordIndex = 1; return records[0]; } if (record.Sid == DrawingGroupRecord.sid && _lastRecord is DrawingGroupRecord) { DrawingGroupRecord lastDGRecord = (DrawingGroupRecord)_lastRecord; lastDGRecord.Join((AbstractEscherHolderRecord)record); return null; } if (record.Sid == ContinueRecord.sid) { ContinueRecord contRec = (ContinueRecord)record; if (_lastRecord is ObjRecord || _lastRecord is TextObjectRecord) { // Drawing records have a very strange continue behaviour. //There can actually be OBJ records mixed between the continues. _lastDrawingRecord.ProcessContinueRecord(contRec.Data); //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 is DrawingGroupRecord) { ((DrawingGroupRecord)_lastRecord).ProcessContinueRecord(contRec.Data); return null; } if (_lastRecord is DrawingRecord) { ((DrawingRecord)_lastRecord).ProcessContinueRecord(contRec.Data); return null; } if (_lastRecord is UnknownRecord) { //Gracefully handle records that we don't know about, //that happen to be continued return record; } if (_lastRecord is EOFRecord) { // This is really odd, but excel still sometimes // outPuts a file like this all the same return record; } //if (_lastRecord is StringRecord) //{ // ((StringRecord)_lastRecord).ProcessContinueRecord(contRec.Data); // return null; //} throw new RecordFormatException("Unhandled Continue Record"); } _lastRecord = record; if (record is DrawingRecord) { _lastDrawingRecord = (DrawingRecord)record; } return record; }
/// <summary> /// Process the record ourselves, but do not /// pass it on to the child Listener. /// </summary> /// <param name="record">The record.</param> public void ProcessRecordInternally(Record record) { if (record is BoundSheetRecord) { boundSheetRecords.Add(record); } else if (record is ExternSheetRecord) { externSheetRecords.Add(record); } else if (record is SSTRecord) { sstRecord = (SSTRecord)record; } }
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 is BOFRecord) { _hasBOFRecord = true; if (rs.HasNextRecord) { rs.NextRecord(); rec = RecordFactory.CreateSingleRecord(rs); recSize += rec.RecordSize; outputRecs.Add(rec); if (rec is FilePassRecord) { fpr = (FilePassRecord)rec; outputRecs.RemoveAt(outputRecs.Count - 1); // TODO - add fpr not Added to outPutRecs rec = outputRecs[0]; } else { // workbook not encrypted (typical case) if (rec is EOFRecord) { // A workbook stream is never empty, so crash instead // of trying to keep track of nesting level throw new InvalidOperationException("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; }