fpspreadsheet: Remove reading code for RK and MULTRK records from xlsbiff5 and xlsbiff8, use the xlsbiff8 versions in xlscommon. --> Formatting of RK and MULRK works now for biff5 as well.

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3042 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2014-05-11 16:45:42 +00:00
parent 705a7956ce
commit 75f2a8c0a5
3 changed files with 112 additions and 182 deletions

View File

@@ -80,8 +80,6 @@ type
FWorksheetNames: TStringList; FWorksheetNames: TStringList;
FCurrentWorksheet: Integer; FCurrentWorksheet: Integer;
protected protected
{ Helpers }
function DecodeRKValue(const ARK: DWORD): Double;
{ Record writing methods } { Record writing methods }
procedure ReadBlank(AStream: TStream); override; procedure ReadBlank(AStream: TStream); override;
procedure ReadFont(const AStream: TStream); procedure ReadFont(const AStream: TStream);
@@ -89,12 +87,10 @@ type
procedure ReadFormula(AStream: TStream); override; procedure ReadFormula(AStream: TStream); override;
procedure ReadFormulaExcel(AStream: TStream); procedure ReadFormulaExcel(AStream: TStream);
procedure ReadLabel(AStream: TStream); override; procedure ReadLabel(AStream: TStream); override;
procedure ReadMulRKValues(AStream: TStream);
procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook); procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook);
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook); procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
procedure ReadBoundsheet(AStream: TStream); procedure ReadBoundsheet(AStream: TStream);
procedure ReadRichString(AStream: TStream); procedure ReadRichString(AStream: TStream);
procedure ReadRKValue(AStream: TStream);
procedure ReadXF(AStream: TStream); procedure ReadXF(AStream: TStream);
public public
{ General reading methods } { General reading methods }
@@ -1380,54 +1376,6 @@ begin
ApplyCellFormatting(ARow, ACol, XF); ApplyCellFormatting(ARow, ACol, XF);
end; end;
procedure TsSpreadBIFF5Reader.ReadRKValue(AStream: TStream);
var
L: DWORD;
ARow, ACol: Cardinal;
XF: WORD;
Number: Double;
begin
ReadRowColXF(AStream, ARow, ACol, XF);
{Encoded RK value}
L:=DWordLEtoN(AStream.ReadDWord);
{Check RK codes}
Number:=DecodeRKValue(L);
FWorksheet.WriteNumber(ARow,ACol,Number);
{ Add attributes to cell }
ApplyCellFormatting(ARow, ACol, XF);
end;
procedure TsSpreadBIFF5Reader.ReadMulRKValues(AStream: TStream);
var
ARow, fc,lc,XF: Word;
Pending: integer;
RK: DWORD;
Number: Double;
begin
ARow:=WordLEtoN(AStream.ReadWord);
fc:=WordLEtoN(AStream.ReadWord);
Pending:=RecordSize-sizeof(fc)-Sizeof(ARow);
while Pending > (sizeof(XF)+sizeof(RK)) do begin
XF:=AStream.ReadWord; //XF record (not used)
RK:=DWordLEtoN(AStream.ReadDWord);
Number:=DecodeRKValue(RK);
FWorksheet.WriteNumber(ARow,fc,Number);
inc(fc);
dec(Pending,(sizeof(XF)+sizeof(RK)));
end;
if Pending=2 then begin
//Just for completeness
lc:=WordLEtoN(AStream.ReadWord);
if lc+1<>fc then begin
//Stream error... bypass by now
end;
end;
end;
procedure TsSpreadBIFF5Reader.ReadFormulaExcel(AStream: TStream); procedure TsSpreadBIFF5Reader.ReadFormulaExcel(AStream: TStream);
var var
ARow, ACol: Cardinal; ARow, ACol: Cardinal;
@@ -1454,35 +1402,6 @@ begin
ApplyCellFormatting(ARow, ACol, XF); ApplyCellFormatting(ARow, ACol, XF);
end; end;
function TsSpreadBIFF5Reader.DecodeRKValue(const ARK: DWORD): Double;
var
Number: Double;
Tmp: LongInt;
begin
if ARK and 2 = 2 then begin
// Signed integer value
if LongInt(ARK)<0 then begin
//Simulates a sar
Tmp:=LongInt(ARK)*-1;
Tmp:=Tmp shr 2;
Tmp:=Tmp*-1;
Number:=Tmp-1;
end else begin
Number:=ARK shr 2;
end;
end else begin
// Floating point value
// NOTE: This is endian dependent and IEEE dependent (Not checked, working win-i386)
PDWORD(@Number)^:= $00000000;
(PDWORD(@Number)+1)^:=ARK and $FFFFFFFC;
end;
if ARK and 1 = 1 then begin
// Encoded value is multiplied by 100
Number:=Number / 100;
end;
Result:=Number;
end;
procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook); procedure TsSpreadBIFF5Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
var var
MemStream: TMemoryStream; MemStream: TMemoryStream;
@@ -1503,7 +1422,7 @@ begin
MemStream.Position := 0; MemStream.Position := 0;
ReadFromStream(MemStream, AData); ReadFromStream(MemStream, AData);
// Uncomment to verify if the data was correctly optained from the OLE file // Uncomment to verify if the data was correctly obtained from the OLE file
// MemStream.SaveToFile(SysUtils.ChangeFileExt(AFileName, 'bin.xls')); // MemStream.SaveToFile(SysUtils.ChangeFileExt(AFileName, 'bin.xls'));
finally finally
MemStream.Free; MemStream.Free;

View File

@@ -72,14 +72,11 @@ type
FWorksheetNames: TStringList; FWorksheetNames: TStringList;
FCurrentWorksheet: Integer; FCurrentWorksheet: Integer;
FSharedStringTable: TStringList; FSharedStringTable: TStringList;
function DecodeRKValue(const ARK: DWORD): Double;
function ReadWideString(const AStream: TStream; const ALength: WORD): WideString; overload; function ReadWideString(const AStream: TStream; const ALength: WORD): WideString; overload;
function ReadWideString(const AStream: TStream; const AUse8BitLength: Boolean): WideString; overload; function ReadWideString(const AStream: TStream; const AUse8BitLength: Boolean): WideString; overload;
procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook); procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook);
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook); procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
procedure ReadBoundsheet(AStream: TStream); procedure ReadBoundsheet(AStream: TStream);
procedure ReadRKValue(const AStream: TStream);
procedure ReadMulRKValues(const AStream: TStream);
function ReadString(const AStream: TStream; const ALength: WORD): UTF8String; function ReadString(const AStream: TStream; const ALength: WORD): UTF8String;
procedure ReadSST(const AStream: TStream); procedure ReadSST(const AStream: TStream);
procedure ReadLabelSST(const AStream: TStream); procedure ReadLabelSST(const AStream: TStream);
@@ -1312,35 +1309,6 @@ begin
inherited; inherited;
end; end;
function TsSpreadBIFF8Reader.DecodeRKValue(const ARK: DWORD): Double;
var
Number: Double;
Tmp: LongInt;
begin
if ARK and 2 = 2 then begin
// Signed integer value
if LongInt(ARK)<0 then begin
//Simulates a sar
Tmp:=LongInt(ARK)*-1;
Tmp:=Tmp shr 2;
Tmp:=Tmp*-1;
Number:=Tmp-1;
end else begin
Number:=ARK shr 2;
end;
end else begin
// Floating point value
// NOTE: This is endian dependent and IEEE dependent (Not checked) (working win-i386)
(PDWORD(@Number))^:= $00000000;
(PDWORD(@Number)+1)^:=(ARK and $FFFFFFFC);
end;
if ARK and 1 = 1 then begin
// Encoded value is multiplied by 100
Number:=Number / 100;
end;
Result:=Number;
end;
function TsSpreadBIFF8Reader.ReadWideString(const AStream: TStream; function TsSpreadBIFF8Reader.ReadWideString(const AStream: TStream;
const ALength: WORD): WideString; const ALength: WORD): WideString;
var var
@@ -1568,77 +1536,10 @@ begin
FWorksheetNames.Add(UTF8Encode(WideName)); FWorksheetNames.Add(UTF8Encode(WideName));
end; end;
procedure TsSpreadBIFF8Reader.ReadRKValue(const AStream: TStream);
var
RK: DWORD;
ARow, ACol: Cardinal;
XF: WORD;
lDateTime: TDateTime;
Number: Double;
nf: TsNumberFormat; // Number format
nd: word; // decimals
nfs: String; // Number format string
begin
{Retrieve XF record, row and column}
ReadRowColXF(AStream, ARow, ACol, XF);
{Encoded RK value}
RK:=DWordLEtoN(AStream.ReadDWord);
{Check RK codes}
Number:=DecodeRKValue(RK);
{Find out what cell type, set contenttype and value}
ExtractNumberFormat(XF, nf, nd, nfs);
if IsDateTime(Number, nf, lDateTime) then
FWorksheet.WriteDateTime(ARow, ACol, lDateTime, nf, nfs)
else
FWorksheet.WriteNumber(ARow, ACol, Number, nf);
{Add attributes}
ApplyCellFormatting(ARow, ACol, XF);
end;
procedure TsSpreadBIFF8Reader.ReadMulRKValues(const AStream: TStream);
var
ARow, fc,lc,XF: Word;
lDateTime: TDateTime;
Pending: integer;
RK: DWORD;
Number: Double;
nf: TsNumberFormat;
nd: word;
nfs: String;
begin
ARow:=WordLEtoN(AStream.ReadWord);
fc:=WordLEtoN(AStream.ReadWord);
Pending:=RecordSize-sizeof(fc)-Sizeof(ARow);
while Pending > (sizeof(XF)+sizeof(RK)) do begin
XF:=AStream.ReadWord; //XF record (used for date checking)
RK:=DWordLEtoN(AStream.ReadDWord);
Number:=DecodeRKValue(RK);
{Find out what cell type, set contenttype and value}
ExtractNumberFormat(XF, nf, nd, nfs);
if IsDateTime(Number, nf, lDateTime) then
FWorksheet.WriteDateTime(ARow, fc, lDateTime, nf, nfs)
else
FWorksheet.WriteNumber(ARow, fc, Number, nf, nd);
inc(fc);
dec(Pending,(sizeof(XF)+sizeof(RK)));
end;
if Pending=2 then begin
//Just for completeness
lc:=WordLEtoN(AStream.ReadWord);
if lc+1<>fc then begin
//Stream error... bypass by now
end;
end;
end;
function TsSpreadBIFF8Reader.ReadString(const AStream: TStream; function TsSpreadBIFF8Reader.ReadString(const AStream: TStream;
const ALength: WORD): UTF8String; const ALength: WORD): UTF8String;
begin begin
Result:=UTF16ToUTF8(ReadWideString(AStream, ALength)); Result := UTF16ToUTF8(ReadWideString(AStream, ALength));
end; end;
procedure TsSpreadBIFF8Reader.ReadFromFile(AFileName: string; AData: TsWorkbook); procedure TsSpreadBIFF8Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);

View File

@@ -378,6 +378,8 @@ type
FXFList: TFPList; // of TXFListData FXFList: TFPList; // of TXFListData
FFormatList: TFPList; // of TFormatListData FFormatList: TFPList; // of TFormatListData
procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); virtual; procedure ApplyCellFormatting(ARow, ACol: Cardinal; XFIndex: Word); virtual;
// Extracts a number out of an RK value
function DecodeRKValue(const ARK: DWORD): Double;
// Returns the numberformat for a given XF record // Returns the numberformat for a given XF record
procedure ExtractNumberFormat(AXFIndex: WORD; procedure ExtractNumberFormat(AXFIndex: WORD;
out ANumberFormat: TsNumberFormat; out ADecimals: Word; out ANumberFormat: TsNumberFormat; out ADecimals: Word;
@@ -397,12 +399,16 @@ type
procedure ReadFormat(AStream: TStream); virtual; procedure ReadFormat(AStream: TStream); virtual;
// Read multiple blank cells // Read multiple blank cells
procedure ReadMulBlank(AStream: TStream); procedure ReadMulBlank(AStream: TStream);
// Read multiple RK cells
procedure ReadMulRKValues(const AStream: TStream);
// Read floating point number // Read floating point number
procedure ReadNumber(AStream: TStream); override; procedure ReadNumber(AStream: TStream); override;
// Read palette // Read palette
procedure ReadPalette(AStream: TStream); procedure ReadPalette(AStream: TStream);
// Read PANE record // Read PANE record
procedure ReadPane(AStream: TStream); procedure ReadPane(AStream: TStream);
// Read an RK value cell
procedure ReadRKValue(AStream: TStream);
// Read the row, column, and XF index at the current stream position // Read the row, column, and XF index at the current stream position
procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); virtual; procedure ReadRowColXF(AStream: TStream; out ARow, ACol: Cardinal; out AXF: Word); virtual;
// Read row info // Read row info
@@ -608,6 +614,38 @@ begin
end; end;
end; end;
{ Extracts a number out of an RK value.
Valid since BIFF3. }
function TsSpreadBIFFReader.DecodeRKValue(const ARK: DWORD): Double;
var
Number: Double;
Tmp: LongInt;
begin
if ARK and 2 = 2 then begin
// Signed integer value
if LongInt(ARK) < 0 then begin
//Simulates a sar
Tmp := LongInt(ARK) * (-1);
Tmp := Tmp shr 2;
Tmp := Tmp * (-1);
Number := Tmp - 1;
end else begin
Number := ARK shr 2;
end;
end else begin
// Floating point value
// NOTE: This is endian dependent and IEEE dependent (Not checked) (working win-i386)
(PDWORD(@Number))^ := $00000000;
(PDWORD(@Number)+1)^ := ARK and $FFFFFFFC;
end;
if ARK and 1 = 1 then begin
// Encoded value is multiplied by 100
Number := Number / 100;
end;
Result := Number;
end;
{ Extracts number format data from an XF record index by AXFIndex. { Extracts number format data from an XF record index by AXFIndex.
Valid for BIFF5-BIFF8. Needs to be overridden for BIFF2 } Valid for BIFF5-BIFF8. Needs to be overridden for BIFF2 }
procedure TsSpreadBIFFReader.ExtractNumberFormat(AXFIndex: WORD; procedure TsSpreadBIFFReader.ExtractNumberFormat(AXFIndex: WORD;
@@ -855,6 +893,7 @@ begin
end; end;
// Reads multiple blank cell records // Reads multiple blank cell records
// Valid for BIFF5 and BIFF8 (does not exist before)
procedure TsSpreadBIFFReader.ReadMulBlank(AStream: TStream); procedure TsSpreadBIFFReader.ReadMulBlank(AStream: TStream);
var var
ARow, fc, lc, XF: Word; ARow, fc, lc, XF: Word;
@@ -879,6 +918,44 @@ begin
end; end;
end; end;
{ Reads multiple RK records.
Valid for BIFF5 and BIFF8 (does not exist before) }
procedure TsSpreadBIFFReader.ReadMulRKValues(const AStream: TStream);
var
ARow, fc, lc, XF: Word;
lNumber: Double;
lDateTime: TDateTime;
pending: integer;
RK: DWORD;
nf: TsNumberFormat;
nd: word;
nfs: String;
begin
ARow := WordLEtoN(AStream.ReadWord);
fc := WordLEtoN(AStream.ReadWord);
pending := RecordSize - SizeOf(fc) - SizeOf(ARow);
while pending > SizeOf(XF) + SizeOf(RK) do begin
XF := AStream.ReadWord; //XF record (used for date checking)
RK := DWordLEtoN(AStream.ReadDWord);
lNumber := DecodeRKValue(RK);
{Find out what cell type, set contenttype and value}
ExtractNumberFormat(XF, nf, nd, nfs);
if IsDateTime(lNumber, nf, lDateTime) then
FWorksheet.WriteDateTime(ARow, fc, lDateTime, nf, nfs)
else
FWorksheet.WriteNumber(ARow, fc, lNumber, nf, nd);
inc(fc);
dec(pending, SizeOf(XF) + SizeOf(RK));
end;
if pending = 2 then begin
//Just for completeness
lc := WordLEtoN(AStream.ReadWord);
if lc + 1 <> fc then begin
//Stream error... bypass by now
end;
end;
end;
// Reads a floating point number and seeks the number format // Reads a floating point number and seeks the number format
// NOTE: This procedure is valid after BIFF 3. // NOTE: This procedure is valid after BIFF 3.
procedure TsSpreadBIFFReader.ReadNumber(AStream: TStream); procedure TsSpreadBIFFReader.ReadNumber(AStream: TStream);
@@ -958,6 +1035,39 @@ begin
AXF := WordLEtoN(AStream.ReadWord); AXF := WordLEtoN(AStream.ReadWord);
end; end;
{ Reads an RK value cell from the stream
Valid since BIFF3. }
procedure TsSpreadBIFFReader.ReadRKValue(AStream: TStream);
var
RK: DWord;
ARow, ACol: Cardinal;
XF: Word;
lDateTime: TDateTime;
Number: Double;
nf: TsNumberFormat; // Number format
nd: Word; // decimals
nfs: String; // Number format string
begin
{Retrieve XF record, row and column}
ReadRowColXF(AStream, ARow, ACol, XF);
{Encoded RK value}
RK := DWordLEtoN(AStream.ReadDWord);
{Check RK codes}
Number := DecodeRKValue(RK);
{Find out what cell type, set contenttype and value}
ExtractNumberFormat(XF, nf, nd, nfs);
if IsDateTime(Number, nf, lDateTime) then
FWorksheet.WriteDateTime(ARow, ACol, lDateTime, nf, nfs)
else
FWorksheet.WriteNumber(ARow, ACol, Number, nf);
{Add attributes}
ApplyCellFormatting(ARow, ACol, XF);
end;
// Read the part of the ROW record that is common to all BIFF versions // Read the part of the ROW record that is common to all BIFF versions
procedure TsSpreadBIFFReader.ReadRowInfo(AStream: TStream); procedure TsSpreadBIFFReader.ReadRowInfo(AStream: TStream);
type type