You've already forked lazarus-ccr
fpspreadsheet: Starts preparation to support reading dates from Excel 8, not yet functional
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@2262 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -85,7 +85,7 @@ type
|
||||
{@@ Describes the type of content of a cell on a TsWorksheet }
|
||||
|
||||
TCellContentType = (cctEmpty, cctFormula, cctRPNFormula, cctNumber,
|
||||
cctUTF8String);
|
||||
cctUTF8String, cctDateTime);
|
||||
|
||||
{@@ List of possible formatting fields }
|
||||
|
||||
@ -164,6 +164,7 @@ type
|
||||
RPNFormulaValue: TsRPNFormula;
|
||||
NumberValue: double;
|
||||
UTF8StringValue: ansistring;
|
||||
DateTimeValue: TDateTime;
|
||||
{ Formatting fields }
|
||||
UsedFormattingFields: TsUsedFormattingFields;
|
||||
TextRotation: TsTextRotation;
|
||||
@ -202,9 +203,11 @@ type
|
||||
function GetLastRowNumber: Cardinal;
|
||||
function ReadAsUTF8Text(ARow, ACol: Cardinal): ansistring;
|
||||
function ReadAsNumber(ARow, ACol: Cardinal): Double;
|
||||
function ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean;
|
||||
procedure RemoveAllCells;
|
||||
procedure WriteUTF8Text(ARow, ACol: Cardinal; AText: ansistring);
|
||||
procedure WriteNumber(ARow, ACol: Cardinal; ANumber: double);
|
||||
procedure WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime);
|
||||
procedure WriteFormula(ARow, ACol: Cardinal; AFormula: TsFormula);
|
||||
procedure WriteRPNFormula(ARow, ACol: Cardinal; AFormula: TsRPNFormula);
|
||||
procedure WriteTextRotation(ARow, ACol: Cardinal; ARotation: TsTextRotation);
|
||||
@ -259,6 +262,7 @@ type
|
||||
FWorkbook: TsWorkbook;
|
||||
FCurrentWorksheet: TsWorksheet;
|
||||
public
|
||||
constructor Create; virtual;
|
||||
{ General writing methods }
|
||||
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); virtual;
|
||||
procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); virtual;
|
||||
@ -638,6 +642,19 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Reads the contents of a cell and returns the date/time value of the cell.
|
||||
|
||||
@param ARow The row of the cell
|
||||
@param ACol The column of the cell
|
||||
|
||||
@return True if the cell is a datetime value, false otherwise
|
||||
}
|
||||
function TsWorksheet.ReadAsDateTime(ARow, ACol: Cardinal; out AResult: TDateTime): Boolean;
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
{@@
|
||||
Clears the list of Cells and releases their memory.
|
||||
}
|
||||
@ -691,6 +708,16 @@ begin
|
||||
ACell^.NumberValue := ANumber;
|
||||
end;
|
||||
|
||||
procedure TsWorksheet.WriteDateTime(ARow, ACol: Cardinal; AValue: TDateTime);
|
||||
var
|
||||
ACell: PCell;
|
||||
begin
|
||||
ACell := GetCell(ARow, ACol);
|
||||
|
||||
ACell^.ContentType := cctDateTime;
|
||||
ACell^.DateTimeValue := AValue;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Writes a formula to a determined cell
|
||||
|
||||
@ -1063,6 +1090,11 @@ end;
|
||||
|
||||
{ TsCustomSpreadReader }
|
||||
|
||||
constructor TsCustomSpreadReader.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
end;
|
||||
|
||||
{@@
|
||||
Default file reading method.
|
||||
|
||||
|
@ -62,6 +62,16 @@ uses
|
||||
fpsutils, lazutf8;
|
||||
|
||||
type
|
||||
TXFRecordData = class
|
||||
public
|
||||
FormatIndex: Integer;
|
||||
end;
|
||||
|
||||
TFormatRecordData = class
|
||||
public
|
||||
Index: Integer;
|
||||
FormatString: widestring;
|
||||
end;
|
||||
|
||||
{ TsSpreadBIFF8Reader }
|
||||
|
||||
@ -73,8 +83,11 @@ type
|
||||
FWorksheetNames: TStringList;
|
||||
FCurrentWorksheet: Integer;
|
||||
FSharedStringTable: TStringList;
|
||||
FXFList: TFPList; // of TXFRecordData
|
||||
FFormatList: TFPList; // of TFormatRecordData
|
||||
function DecodeRKValue(const ARK: DWORD): Double;
|
||||
function ReadWideString(const AStream: TStream;const ALength: WORD): WideString;
|
||||
function ReadWideString(const AStream: TStream;const ALength: WORD): WideString; overload;
|
||||
function ReadWideString(const AStream: TStream; const AUse8BitLength: Boolean): WideString; overload;
|
||||
procedure ReadWorkbookGlobals(AStream: TStream; AData: TsWorkbook);
|
||||
procedure ReadWorksheet(AStream: TStream; AData: TsWorkbook);
|
||||
procedure ReadBoundsheet(AStream: TStream);
|
||||
@ -87,11 +100,18 @@ type
|
||||
procedure ReadRichString(const AStream: TStream);
|
||||
procedure ReadSST(const AStream: TStream);
|
||||
procedure ReadLabelSST(const AStream: TStream);
|
||||
//
|
||||
procedure ReadXF(const AStream: TStream);
|
||||
procedure ReadFormat(const AStream: TStream);
|
||||
function FindFormatRecordForCell(const AFXIndex: Integer): TFormatRecordData;
|
||||
class function ConvertExcelDateToTDateTime(const AExcelDateNum: Integer): TDateTime;
|
||||
|
||||
// Workbook Globals records
|
||||
// procedure ReadCodepage in xlscommon
|
||||
procedure ReadFont(const AStream: TStream);
|
||||
public
|
||||
constructor Create; override;
|
||||
destructor Destroy; override;
|
||||
{ General reading methods }
|
||||
procedure ReadFromFile(AFileName: string; AData: TsWorkbook); override;
|
||||
procedure ReadFromStream(AStream: TStream; AData: TsWorkbook); override;
|
||||
@ -99,8 +119,6 @@ type
|
||||
procedure ReadFormula(AStream: TStream); override;
|
||||
procedure ReadLabel(AStream: TStream); override;
|
||||
procedure ReadNumber(AStream: TStream); override;
|
||||
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
{ TsSpreadBIFF8Writer }
|
||||
@ -164,6 +182,7 @@ const
|
||||
INT_EXCEL_ID_LABELSST = $00FD; //BIFF8 only
|
||||
INT_EXCEL_ID_PALETTE = $0092;
|
||||
INT_EXCEL_ID_CODEPAGE = $0042;
|
||||
INT_EXCEL_ID_FORMAT = $041E;
|
||||
|
||||
{ Cell Addresses constants }
|
||||
MASK_EXCEL_ROW = $3FFF;
|
||||
@ -1412,6 +1431,20 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TsSpreadBIFF8Reader.ReadWideString(const AStream: TStream;
|
||||
const AUse8BitLength: Boolean): WideString;
|
||||
var
|
||||
Len: Word;
|
||||
WideName: WideString;
|
||||
begin
|
||||
if AUse8BitLength then
|
||||
Len := AStream.ReadByte()
|
||||
else
|
||||
Len := WordLEtoN(AStream.ReadWord());
|
||||
|
||||
Result := ReadWideString(AStream, Len);
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF8Reader.ReadWorkbookGlobals(AStream: TStream;
|
||||
AData: TsWorkbook);
|
||||
var
|
||||
@ -1437,6 +1470,8 @@ begin
|
||||
INT_EXCEL_ID_SST: ReadSST(AStream);
|
||||
INT_EXCEL_ID_CODEPAGE: ReadCodepage(AStream);
|
||||
INT_EXCEL_ID_FONT: ReadFont(AStream);
|
||||
INT_EXCEL_ID_XF: ReadXF(AStream);
|
||||
INT_EXCEL_ID_FORMAT: ReadFormat(AStream);
|
||||
else
|
||||
// nothing
|
||||
end;
|
||||
@ -1521,6 +1556,7 @@ var
|
||||
RK: DWORD;
|
||||
ARow, ACol, XF: WORD;
|
||||
Number: Double;
|
||||
lFormatData: TFormatRecordData;
|
||||
begin
|
||||
ReadRowColXF(AStream,ARow,ACol,XF);
|
||||
|
||||
@ -1529,6 +1565,20 @@ begin
|
||||
|
||||
{Check RK codes}
|
||||
Number:=DecodeRKValue(RK);
|
||||
|
||||
// Now try to figure out if the number is really a number of a date or time value
|
||||
// See: http://www.gaia-gis.it/FreeXL/freexl-1.0.0a-doxy-doc/Format.html
|
||||
// Unfornately Excel doesnt give us a direct way to find this,
|
||||
// we need to guess by the FORMAT field
|
||||
{ lFormatData := FindFormatRecordForCell(XF);
|
||||
if lFormatData <> nil then
|
||||
begin
|
||||
// Dates have /
|
||||
if Pos('/', lFormatData.FormatString) > 0 then
|
||||
begin
|
||||
end;
|
||||
end;}
|
||||
|
||||
FWorksheet.WriteNumber(ARow,ACol,Number);
|
||||
end;
|
||||
|
||||
@ -1616,6 +1666,20 @@ begin
|
||||
Result:=UTF16ToUTF8(ReadWideString(AStream, ALength));
|
||||
end;
|
||||
|
||||
constructor TsSpreadBIFF8Reader.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
FXFList := TFPList.Create;
|
||||
FFormatList := TFPList.Create;
|
||||
end;
|
||||
|
||||
destructor TsSpreadBIFF8Reader.Destroy;
|
||||
begin
|
||||
FXFList.Free;
|
||||
FFormatList.Free;
|
||||
if Assigned(FSharedStringTable) then FSharedStringTable.Free;
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF8Reader.ReadFromFile(AFileName: string; AData: TsWorkbook);
|
||||
var
|
||||
MemStream: TMemoryStream;
|
||||
@ -1732,11 +1796,6 @@ begin
|
||||
FWorksheet.WriteNumber(ARow, ACol, AValue);
|
||||
end;
|
||||
|
||||
destructor TsSpreadBIFF8Reader.Destroy;
|
||||
begin
|
||||
if Assigned(FSharedStringTable) then FSharedStringTable.Free;
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF8Reader.ReadRichString(const AStream: TStream);
|
||||
var
|
||||
L: Word;
|
||||
@ -1829,6 +1888,86 @@ begin
|
||||
FWorksheet.WriteUTF8Text(ARow, ACol, FSharedStringTable[SSTIndex]);
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF8Reader.ReadXF(const AStream: TStream);
|
||||
var
|
||||
lData: TXFRecordData;
|
||||
begin
|
||||
lData := TXFRecordData.Create;
|
||||
|
||||
// Record XF, BIFF8:
|
||||
// Offset Size Contents
|
||||
// 0 2 Index to FONT record (➜5.45)
|
||||
WordLEtoN(AStream.ReadWord);
|
||||
|
||||
// 2 2 Index to FORMAT record (➜5.49)
|
||||
lData.FormatIndex := WordLEtoN(AStream.ReadWord);
|
||||
|
||||
{4 2 XF type, cell protection, and parent style XF:
|
||||
Bit Mask Contents
|
||||
2-0 0007H XF_TYPE_PROT – XF type, cell protection (see above)
|
||||
15-4 FFF0H Index to parent style XF (always FFFH in style XFs)
|
||||
6 1 Alignment and text break:
|
||||
Bit Mask Contents
|
||||
2-0 07H XF_HOR_ALIGN – Horizontal alignment (see above)
|
||||
3 08H 1 = Text is wrapped at right border
|
||||
6-4 70H XF_VERT_ALIGN – Vertical alignment (see above)
|
||||
7 80H 1 = Justify last line in justified or distibuted text
|
||||
7 1 XF_ROTATION: Text rotation angle (see above)
|
||||
8 1 Indentation, shrink to cell size, and text direction:
|
||||
Bit Mask Contents
|
||||
3-0 0FH Indent level
|
||||
4 10H 1 = Shrink content to fit into cell
|
||||
7-6 C0H Text direction:
|
||||
0 = According to context
|
||||
35
|
||||
; 1 = Left-to-right; 2 = Right-to-left
|
||||
9 1 Flags for used attribute groups:
|
||||
....}
|
||||
|
||||
// Add the XF to the list
|
||||
FXFList.Add(lData);
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF8Reader.ReadFormat(const AStream: TStream);
|
||||
var
|
||||
lData: TFormatRecordData;
|
||||
begin
|
||||
lData := TFormatRecordData.Create;
|
||||
|
||||
// Record FORMAT, BIFF8:
|
||||
// Offset Size Contents
|
||||
// 0 2 Format index used in other records
|
||||
lData.Index := WordLEtoN(AStream.ReadWord);
|
||||
|
||||
// 2 var. Number format string (Unicode string, 16-bit string length, ➜2.5.3)
|
||||
lData.FormatString := ReadWideString(AStream, False);
|
||||
|
||||
// Add to the list
|
||||
FFormatList.Add(lData);
|
||||
end;
|
||||
|
||||
function TsSpreadBIFF8Reader.FindFormatRecordForCell(const AFXIndex: Integer
|
||||
): TFormatRecordData;
|
||||
var
|
||||
lXFData: TXFRecordData;
|
||||
lFormatData: TFormatRecordData;
|
||||
i: Integer;
|
||||
begin
|
||||
Result := nil;
|
||||
lXFData := TXFRecordData(FXFList.Items[AFXIndex]);
|
||||
for i := 0 to FFormatList.Count-1 do
|
||||
begin
|
||||
lFormatData := TFormatRecordData(FFormatList.Items[i]);
|
||||
if lFormatData.Index = lXFData.FormatIndex then Exit(lFormatData);
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TsSpreadBIFF8Reader.ConvertExcelDateToTDateTime(
|
||||
const AExcelDateNum: Integer): TDateTime;
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
procedure TsSpreadBIFF8Reader.ReadFont(const AStream: TStream);
|
||||
var
|
||||
lCodePage: Word;
|
||||
|
Reference in New Issue
Block a user