From d8ff48676911b7f646c3e7af1c21aebc1ed56c55 Mon Sep 17 00:00:00 2001 From: sekelsenmat Date: Thu, 11 Aug 2011 14:30:25 +0000 Subject: [PATCH] fpspreadsheet: Patch from bug 19884, improves the format detection of the reader and adds a writer format auto-detector git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1797 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- components/fpspreadsheet/fpspreadsheet.pas | 77 +++++++++++++++++++--- 1 file changed, 68 insertions(+), 9 deletions(-) diff --git a/components/fpspreadsheet/fpspreadsheet.pas b/components/fpspreadsheet/fpspreadsheet.pas index 54b868c56..f01e73e4b 100755 --- a/components/fpspreadsheet/fpspreadsheet.pas +++ b/components/fpspreadsheet/fpspreadsheet.pas @@ -25,6 +25,7 @@ const STR_EXCEL_EXTENSION = '.xls'; STR_OOXML_EXCEL_EXTENSION = '.xlsx'; STR_OPENDOCUMENT_CALC_EXTENSION = '.ods'; + STR_COMMA_SEPARATED_EXTENSION = '.csv'; type @@ -222,6 +223,7 @@ type { Base methods } constructor Create; destructor Destroy; override; + class function GetFormatFromFileName(const AFileName: TFileName; var SheetType: TsSpreadsheetFormat): Boolean; function CreateSpreadReader(AFormat: TsSpreadsheetFormat): TsCustomSpreadReader; function CreateSpreadWriter(AFormat: TsSpreadsheetFormat): TsCustomSpreadWriter; procedure ReadFromFile(AFileName: string; AFormat: TsSpreadsheetFormat); overload; @@ -229,7 +231,8 @@ type procedure ReadFromStream(AStream: TStream; AFormat: TsSpreadsheetFormat); procedure WriteToFile(const AFileName: string; const AFormat: TsSpreadsheetFormat; - const AOverwriteExisting: Boolean = False); + const AOverwriteExisting: Boolean = False); overload; + procedure WriteToFile(const AFileName: String; const AOverwriteExisting: Boolean = False); overload; procedure WriteToStream(AStream: TStream; AFormat: TsSpreadsheetFormat); { Worksheet list handling methods } function AddWorksheet(AName: string): TsWorksheet; @@ -315,8 +318,6 @@ procedure RegisterSpreadFormat( AWriterClass: TsSpreadWriterClass; AFormat: TsSpreadsheetFormat); - - implementation uses @@ -364,6 +365,7 @@ begin Result := PCell(Item1).Col - PCell(Item2).Col; end; + {@@ Constructor. } @@ -767,6 +769,24 @@ begin inherited Destroy; end; +{@@ + Helper method for determining the spreadsheet type from the file type extension + + Returns: True if the file matches any of the known formats, false otherwise +} +class function TsWorkbook.GetFormatFromFileName(const AFileName: TFileName; var SheetType: TsSpreadsheetFormat): Boolean; +var + suffix: String; +begin + Result := True; + suffix := ExtractFileExt(AFileName); + if suffix = STR_EXCEL_EXTENSION then SheetType := sfExcel8 + else if suffix = STR_OOXML_EXCEL_EXTENSION then SheetType := sfOOXML + else if suffix = STR_OPENDOCUMENT_CALC_EXTENSION then SheetType := sfOpenDocument + else if suffix = STR_COMMA_SEPARATED_EXTENSION then SheetType := sfCSV + else Result := False; +end; + {@@ Convenience method which creates the correct reader object for a given spreadsheet format. @@ -831,14 +851,39 @@ end; the extension. In the case of the ambiguous xls extension, it will simply assume that it is BIFF8. Note that it could be BIFF2, 3, 4 or 5 too. } -procedure TsWorkbook.ReadFromFile(AFileName: string); +procedure TsWorkbook.ReadFromFile(AFileName: string); overload; var - Str: String; + SheetType: TsSpreadsheetFormat; + valid: Boolean; + lException: Exception = nil; begin - Str := ExtractFileExt(AFileName); - if Str = STR_EXCEL_EXTENSION then ReadFromFile(AFileName, sfExcel8) - else if Str = STR_OOXML_EXCEL_EXTENSION then ReadFromFile(AFileName, sfOOXML) - else if Str = STR_OPENDOCUMENT_CALC_EXTENSION then ReadFromFile(AFileName, sfOpenDocument); + valid := GetFormatFromFileName(AFileName, SheetType); + if valid then + begin + if SheetType = sfExcel8 then + begin + repeat + try + SheetType := Pred(SheetType); + ReadFromFile(AFileName, SheetType); + valid := True; + except + on E: Exception do + begin + if SheetType = sfExcel8 then lException := E; + valid := False + end; + end; + until valid or (SheetType = sfExcel2); + + // A failed attempt to read a file should bring an exception, so re-raise + // the exception if necessary. We re-raise the exception brought by Excel 8, + // since this is the most common format + if (not valid) and (lException <> nil) then raise lException; + end + else + ReadFromFile(AFileName, SheetType); + end; end; {@@ @@ -877,6 +922,20 @@ begin end; end; +{@@ + Writes the document to file based on the extension. If this was an earlier sfExcel type file, it will be upgraded to sfExcel8, +} +procedure TsWorkbook.WriteToFile(const AFileName: string; const AOverwriteExisting: Boolean = False); overload; +var + SheetType: TsSpreadsheetFormat; + valid: Boolean; +begin + valid := GetFormatFromFileName(AFileName, SheetType); + if valid then WriteToFile(AFileName, SheetType, AOverwriteExisting) + else raise Exception.Create(Format( + '[TsWorkbook.WriteToFile] Attempted to save a spreadsheet by extension, but the extension %s is invalid.', [ExtractFileExt(AFileName)])); +end; + {@@ Writes the document to a stream }