fpspreadsheet: Read/write worksheet hidden state for biff8 and biff5.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5775 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2017-03-01 20:01:14 +00:00
parent 59c6c664f9
commit 4ce25109a8
3 changed files with 116 additions and 89 deletions

View File

@ -100,7 +100,7 @@ type
procedure InternalWriteToStream(AStream: TStream); procedure InternalWriteToStream(AStream: TStream);
{ Record writing methods } { Record writing methods }
procedure WriteBOF(AStream: TStream; ADataType: Word); procedure WriteBOF(AStream: TStream; ADataType: Word);
function WriteBoundsheet(AStream: TStream; ASheetName: string): Int64; function WriteBoundsheet(AStream: TStream; AWorkSheet: TsWorksheet): Int64;
procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet; procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet;
const AName: String; AIndexToREF: Word); override; const AName: String; AIndexToREF: Word); override;
procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet); procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet);
@ -364,9 +364,10 @@ end;
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
procedure TsSpreadBIFF5Reader.ReadBoundsheet(AStream: TStream); procedure TsSpreadBIFF5Reader.ReadBoundsheet(AStream: TStream);
var var
Len: Byte; len: Byte;
s: AnsiString; s: AnsiString;
sheetName: String; sheetState: Byte;
sheetData: TsSheetData;
begin begin
{ Absolute stream position of the BOF record of the sheet represented { Absolute stream position of the BOF record of the sheet represented
by this record } by this record }
@ -374,18 +375,21 @@ begin
AStream.ReadDWord(); AStream.ReadDWord();
{ Visibility } { Visibility }
AStream.ReadByte(); sheetState := AStream.ReadByte();
{ Sheet type } { Sheet type }
AStream.ReadByte(); AStream.ReadByte();
{ Sheet name: Byte string, 8-bit length } { Sheet name: Byte string, 8-bit length }
Len := AStream.ReadByte(); len := AStream.ReadByte();
SetLength(s, len);
AStream.ReadBuffer(s[1], len*SizeOf(AnsiChar));
SetLength(s, Len); { Temporarily store parameters for worksheet in FSheetList }
AStream.ReadBuffer(s[1], Len*SizeOf(AnsiChar)); sheetData := TsSheetData.Create;
sheetName := ConvertEncoding(s, FCodePage, EncodingUTF8); sheetData.Name := ConvertEncoding(s, FCodePage, EncodingUTF8);
FWorksheetNames.Add(sheetName); sheetData.Hidden := sheetState <> 0;
FSheetList.Add(sheetData);
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
@ -494,8 +498,12 @@ var
SectionEOF: Boolean = False; SectionEOF: Boolean = False;
RecordType: Word; RecordType: Word;
CurStreamPos: Int64; CurStreamPos: Int64;
sheetData: TsSheetData;
begin begin
FWorksheet := FWorkbook.AddWorksheet(FWorksheetNames[FCurSheetIndex], true); sheetData := TsSheetData(FSheetList[FCurSheetIndex]);
FWorksheet := FWorkbook.AddWorksheet(sheetData.Name, true);
if sheetData.Hidden then
FWorksheet.Options := FWorksheet.Options + [soHidden];
while (not SectionEOF) do while (not SectionEOF) do
begin begin
@ -1101,7 +1109,7 @@ end;
procedure TsSpreadBIFF5Writer.InternalWriteToStream(AStream: TStream); procedure TsSpreadBIFF5Writer.InternalWriteToStream(AStream: TStream);
var var
CurrentPos: Int64; CurrentPos: Int64;
Boundsheets: array of Int64; sheetPos: array of Int64;
i: Integer; i: Integer;
pane: Byte; pane: Byte;
begin begin
@ -1121,9 +1129,9 @@ begin
WriteStyle(AStream); WriteStyle(AStream);
// A BOUNDSHEET for each worksheet // A BOUNDSHEET for each worksheet
SetLength(Boundsheets, Workbook.GetWorksheetCount); SetLength(sheetPos, Workbook.GetWorksheetCount);
for i := 0 to Workbook.GetWorksheetCount - 1 do for i := 0 to Workbook.GetWorksheetCount - 1 do
Boundsheets[i] := WriteBoundsheet(AStream, Workbook.GetWorksheetByIndex(i).Name); sheetPos[i] := WriteBoundsheet(AStream, Workbook.GetWorksheetByIndex(i));
WriteEOF(AStream); WriteEOF(AStream);
@ -1136,7 +1144,7 @@ begin
{ First goes back and writes the position of the BOF of the { First goes back and writes the position of the BOF of the
sheet on the respective BOUNDSHEET record } sheet on the respective BOUNDSHEET record }
CurrentPos := AStream.Position; CurrentPos := AStream.Position;
AStream.Position := Boundsheets[i]; AStream.Position := sheetPos[i];
AStream.WriteDWord(CurrentPos); AStream.WriteDWord(CurrentPos);
AStream.Position := CurrentPos; AStream.Position := CurrentPos;
@ -1179,7 +1187,7 @@ begin
{ Cleanup } { Cleanup }
SetLength(Boundsheets, 0); SetLength(sheetPos, 0);
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
@ -1281,13 +1289,15 @@ end;
@return The stream position where the absolute stream position @return The stream position where the absolute stream position
of the BOF of this sheet should be written (4 bytes size). of the BOF of this sheet should be written (4 bytes size).
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
function TsSpreadBIFF5Writer.WriteBoundsheet(AStream: TStream; ASheetName: string): Int64; function TsSpreadBIFF5Writer.WriteBoundsheet(AStream: TStream;
AWorkSheet: TsWorksheet): Int64;
var var
Len: Byte; len: Byte;
xlsSheetName: ansistring; xlsSheetName: ansistring;
sheetState: Byte;
begin begin
xlsSheetName := ConvertEncoding(ASheetName, encodingUTF8, FCodePage); xlsSheetName := ConvertEncoding(AWorkSheet.Name, encodingUTF8, FCodePage);
Len := Length(xlsSheetName); len := Length(xlsSheetName);
{ {
LatinSheetName := UTF8ToISO_8859_1(ASheetName); LatinSheetName := UTF8ToISO_8859_1(ASheetName);
Len := Length(LatinSheetName); Len := Length(LatinSheetName);
@ -1301,15 +1311,16 @@ begin
AStream.WriteDWord(WordToLE(0)); AStream.WriteDWord(WordToLE(0));
{ Visibility } { Visibility }
AStream.WriteByte(0); sheetState := IfThen(soHidden in AWorksheet.Options, 1, 0);
AStream.WriteByte(sheetState);
{ Sheet type } { Sheet type }
AStream.WriteByte(0); AStream.WriteByte(0);
{ Sheet name: Byte string, 8-bit length } { Sheet name: Byte string, 8-bit length }
AStream.WriteByte(Len); AStream.WriteByte(len);
// AStream.WriteBuffer(LatinSheetName[1], Len); // AStream.WriteBuffer(LatinSheetName[1], Len);
AStream.WriteBuffer(xlsSheetName[1], Len); AStream.WriteBuffer(xlsSheetName[1], len);
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------

View File

@ -65,7 +65,6 @@ uses
fpsutils; fpsutils;
type type
TBIFF8ExternSheet = packed record TBIFF8ExternSheet = packed record
ExternBookIndex: Word; ExternBookIndex: Word;
FirstSheetIndex: Word; FirstSheetIndex: Word;
@ -139,7 +138,7 @@ type
{ Record writing methods } { Record writing methods }
procedure WriteBOF(AStream: TStream; ADataType: Word); procedure WriteBOF(AStream: TStream; ADataType: Word);
function WriteBoundsheet(AStream: TStream; ASheetName: string): Int64; function WriteBoundsheet(AStream: TStream; AWorksheet: TsWorksheet): Int64;
procedure WriteComment(AStream: TStream; ACell: PCell); override; procedure WriteComment(AStream: TStream; ACell: PCell); override;
procedure WriteComments(AStream: TStream; AWorksheet: TsWorksheet); procedure WriteComments(AStream: TStream; AWorksheet: TsWorksheet);
procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet; procedure WriteDefinedName(AStream: TStream; AWorksheet: TsWorksheet;
@ -454,6 +453,7 @@ type
Text: String; Text: String;
end; end;
{ TsSpreadBIFF8Reader } { TsSpreadBIFF8Reader }
destructor TsSpreadBIFF8Reader.Destroy; destructor TsSpreadBIFF8Reader.Destroy;
@ -830,8 +830,12 @@ var
SectionEOF: Boolean = False; SectionEOF: Boolean = False;
RecordType: Word; RecordType: Word;
CurStreamPos: Int64; CurStreamPos: Int64;
sheetData: TsSheetData;
begin begin
FWorksheet := FWorkbook.AddWorksheet(FWorksheetNames[FCurSheetIndex], true); sheetData := TsSheetData(FSheetList[FCurSheetIndex]);
FWorksheet := FWorkbook.AddWorksheet(sheetData.Name, true);
if sheetData.Hidden then
FWorksheet.Options := FWorksheet.Options + [soHidden];
while (not SectionEOF) do while (not SectionEOF) do
begin begin
@ -912,9 +916,11 @@ end;
procedure TsSpreadBIFF8Reader.ReadBoundsheet(AStream: TStream); procedure TsSpreadBIFF8Reader.ReadBoundsheet(AStream: TStream);
var var
Len: Byte; len: Byte;
WideName: WideString; wideName: WideString;
rtParams: TsRichTextParams; rtParams: TsRichTextParams;
sheetstate: Byte;
sheetdata: TsSheetData;
begin begin
{ Absolute stream position of the BOF record of the sheet represented { Absolute stream position of the BOF record of the sheet represented
by this record } by this record }
@ -922,18 +928,21 @@ begin
AStream.ReadDWord(); AStream.ReadDWord();
{ Visibility } { Visibility }
AStream.ReadByte(); sheetstate := AStream.ReadByte(); // 0=visible, 1=hidden, 2="very" hidden
{ Sheet type } { Sheet type }
AStream.ReadByte(); AStream.ReadByte();
{ Sheet name: 8-bit length } { Sheet name: 8-bit length }
Len := AStream.ReadByte(); len := AStream.ReadByte();
{ Read string with flags } { Read string with flags }
WideName:=ReadWideString(AStream, Len, rtParams); wideName := ReadWideString(AStream, len, rtParams);
FWorksheetNames.Add(UTF8Encode(WideName)); sheetData := TsSheetData.Create;
sheetData.Name := UTF8Encode(wideName);
sheetData.Hidden := sheetState <> 0;
FSheetList.Add(sheetdata);
end; end;
function TsSpreadBIFF8Reader.ReadString(const AStream: TStream; function TsSpreadBIFF8Reader.ReadString(const AStream: TStream;
@ -2093,8 +2102,8 @@ procedure TsSpreadBIFF8Writer.InternalWriteToStream(AStream: TStream);
const const
isBIFF8 = true; isBIFF8 = true;
var var
CurrentPos: Int64; currentPos: Int64;
Boundsheets: array of Int64; sheetPos: array of Int64;
i: Integer; i: Integer;
pane: Byte; pane: Byte;
begin begin
@ -2109,9 +2118,9 @@ begin
WriteStyle(AStream); WriteStyle(AStream);
// A BOUNDSHEET for each worksheet // A BOUNDSHEET for each worksheet
SetLength(Boundsheets, Workbook.GetWorksheetCount); SetLength(sheetPos, Workbook.GetWorksheetCount);
for i := 0 to Workbook.GetWorksheetCount - 1 do for i := 0 to Workbook.GetWorksheetCount - 1 do
Boundsheets[i] := WriteBoundsheet(AStream, Workbook.GetWorksheetByIndex(i).Name); sheetPos[i] := WriteBoundsheet(AStream, Workbook.GetWorksheetByIndex(i));
WriteEXTERNBOOK(AStream); WriteEXTERNBOOK(AStream);
WriteEXTERNSHEET(AStream); WriteEXTERNSHEET(AStream);
@ -2126,10 +2135,10 @@ begin
{ First goes back and writes the position of the BOF of the { First goes back and writes the position of the BOF of the
sheet on the respective BOUNDSHEET record } sheet on the respective BOUNDSHEET record }
CurrentPos := AStream.Position; currentPos := AStream.Position;
AStream.Position := Boundsheets[i]; AStream.Position := sheetPos[i];
AStream.WriteDWord(DWordToLE(DWORD(CurrentPos))); AStream.WriteDWord(DWordToLE(DWORD(CurrentPos)));
AStream.Position := CurrentPos; AStream.Position := currentPos;
WriteBOF(AStream, INT_BOF_SHEET); WriteBOF(AStream, INT_BOF_SHEET);
WriteIndex(AStream); WriteIndex(AStream);
@ -2175,7 +2184,7 @@ begin
end; end;
{ Cleanup } { Cleanup }
SetLength(Boundsheets, 0); SetLength(sheetPos, 0);
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------
@ -2285,13 +2294,15 @@ end;
@return The stream position where the absolute stream position @return The stream position where the absolute stream position
of the BOF of this sheet should be written (4 bytes size). of the BOF of this sheet should be written (4 bytes size).
-------------------------------------------------------------------------------} -------------------------------------------------------------------------------}
function TsSpreadBIFF8Writer.WriteBoundsheet(AStream: TStream; ASheetName: string): Int64; function TsSpreadBIFF8Writer.WriteBoundsheet(AStream: TStream;
AWorksheet: TsWorksheet): Int64;
var var
Len: Byte; len: Byte;
WideSheetName: WideString; wideSheetName: WideString;
sheetState: Byte;
begin begin
WideSheetName:=UTF8Decode(ASheetName); wideSheetName := UTF8Decode(AWorksheet.Name);
Len := Length(WideSheetName); len := Length(wideSheetName);
{ BIFF Record header } { BIFF Record header }
WriteBIFFHeader(AStream, INT_EXCEL_ID_BOUNDSHEET, 8 + Len * Sizeof(WideChar)); WriteBIFFHeader(AStream, INT_EXCEL_ID_BOUNDSHEET, 8 + Len * Sizeof(WideChar));
@ -2302,7 +2313,8 @@ begin
AStream.WriteDWord(DWordToLE(0)); AStream.WriteDWord(DWordToLE(0));
{ Visibility } { Visibility }
AStream.WriteByte(0); sheetState := IfThen(soHidden in AWorksheet.Options, 1, 0);
AStream.WriteByte(sheetState);
{ Sheet type } { Sheet type }
AStream.WriteByte(0); AStream.WriteByte(0);
@ -2311,7 +2323,7 @@ begin
AStream.WriteByte(Len); AStream.WriteByte(Len);
{String flags} {String flags}
AStream.WriteByte(1); AStream.WriteByte(1);
AStream.WriteBuffer(WideStringToLE(WideSheetName)[1], Len * Sizeof(WideChar)); AStream.WriteBuffer(WideStringToLE(wideSheetName)[1], len * SizeOf(WideChar));
end; end;
{@@ ---------------------------------------------------------------------------- {@@ ----------------------------------------------------------------------------

View File

@ -346,6 +346,12 @@ type
function ConvertToExcelError(AValue: TsErrorValue): byte; function ConvertToExcelError(AValue: TsErrorValue): byte;
type type
{ TsSheetData }
TsSheetData = class
Name: String;
Hidden: Boolean;
end;
{ TsBIFFHeader } { TsBIFFHeader }
TsBIFFHeader = packed record TsBIFFHeader = packed record
RecordID: Word; RecordID: Word;
@ -379,10 +385,11 @@ type
FFirstNumFormatIndexInFile: Integer; FFirstNumFormatIndexInFile: Integer;
FPalette: TsPalette; FPalette: TsPalette;
FDefinedNames: TFPList; FDefinedNames: TFPList;
FWorksheetNames: TStrings; FWorksheetData: TFPList;
FCurSheetIndex: Integer; FCurSheetIndex: Integer;
FActivePane: Integer; FActivePane: Integer;
FExternSheets: TStrings; FExternSheets: TStrings;
FSheetList: TFPList;
procedure AddBuiltinNumFormats; override; procedure AddBuiltinNumFormats; override;
procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); virtual; procedure ApplyCellFormatting(ACell: PCell; XFIndex: Word); virtual;
@ -712,7 +719,6 @@ type
TextLen: Word; TextLen: Word;
end; end;
function ConvertExcelDateTimeToDateTime(const AExcelDateNum: Double; function ConvertExcelDateTimeToDateTime(const AExcelDateNum: Double;
ADateMode: TDateMode): TDateTime; ADateMode: TDateMode): TDateTime;
begin begin
@ -936,6 +942,8 @@ constructor TsSpreadBIFFReader.Create(AWorkbook: TsWorkbook);
begin begin
inherited Create(AWorkbook); inherited Create(AWorkbook);
FSheetList := TFPList.Create;
FPalette := TsPalette.Create; FPalette := TsPalette.Create;
PopulatePalette; PopulatePalette;
@ -967,6 +975,9 @@ begin
for j:=0 to FDefinedNames.Count-1 do TObject(FDefinedNames[j]).Free; for j:=0 to FDefinedNames.Count-1 do TObject(FDefinedNames[j]).Free;
FDefinedNames.Free; FDefinedNames.Free;
for j:= 0 to FSheetList.Count-1 do TObject(FSheetList[j]).Free;
FSheetList.Free;
FExternSheets.Free; FExternSheets.Free;
FPalette.Free; FPalette.Free;
@ -2885,55 +2896,48 @@ var
i: Integer; i: Integer;
sheet: TsWorksheet; sheet: TsWorksheet;
begin begin
// Check if the operation succeeded // Check if the operation succeeded
if AStream.Size = 0 then if AStream.Size = 0 then
raise Exception.Create('[TsSpreadBIFFReader.InternalReadFromStream] Reading of OLE document failed'); raise Exception.Create('[TsSpreadBIFFReader.InternalReadFromStream] Reading of OLE document failed');
// Rewind the stream and read from it // Rewind the stream and read from it
AStream.Position := 0; AStream.Position := 0;
{Initializations } {Initializations }
FWorksheetNames := TStringList.Create; FCurSheetIndex := 0;
try BIFFEOF := false;
FCurSheetIndex := 0;
BIFFEOF := false;
{ Read workbook globals } { Read workbook globals }
ReadWorkbookGlobals(AStream); ReadWorkbookGlobals(AStream);
{ Check for the end of the file } { Check for the end of the file }
if AStream.Position >= AStream.Size then if AStream.Position >= AStream.Size then
BIFFEOF := true; BIFFEOF := true;
{ Now read all worksheets } { Now read all worksheets }
while not BIFFEOF do while not BIFFEOF do
begin begin
ReadWorksheet(AStream); ReadWorksheet(AStream);
// Check for the end of the file // Check for the end of the file
if AStream.Position >= AStream.Size then if AStream.Position >= AStream.Size then
BIFFEOF := true; BIFFEOF := true;
// Final preparations // Final preparations
inc(FCurSheetIndex); inc(FCurSheetIndex);
// It can happen in files written by Office97 that the OLE directory is // It can happen in files written by Office97 that the OLE directory is
// at the end of the file. // at the end of the file.
if FCurSheetIndex = FWorksheetNames.Count then if FCurSheetIndex = FSheetList.Count then
BIFFEOF := true; BIFFEOF := true;
end; end;
{ Extract print ranges, repeated rows/cols } { Extract print ranges, repeated rows/cols }
for i:=0 to FWorkbook.GetWorksheetCount-1 do begin for i:=0 to FWorkbook.GetWorksheetCount-1 do begin
sheet := FWorkbook.GetWorksheetByIndex(i); sheet := FWorkbook.GetWorksheetByIndex(i);
FixDefinedNames(sheet); FixDefinedNames(sheet);
ExtractPrintRanges(sheet); ExtractPrintRanges(sheet);
ExtractPrintTitles(sheet); ExtractPrintTitles(sheet);
end; end;
finally
{ Finalization }
FreeAndNil(FWorksheetNames);
end;
end; end;