You've already forked lazarus-ccr
fpspreadsheet: Improved auto-format detection (check extension first, check file header when extension test fails). Fix ods reader crashing when extension has been renamed.
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6760 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
@ -2613,97 +2613,103 @@ begin
|
|||||||
XMLStream.Free;
|
XMLStream.Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ReadFontFaces(Doc.DocumentElement.FindNode('office:font-face-decls'));
|
if Assigned(Doc) then begin
|
||||||
|
ReadFontFaces(Doc.DocumentElement.FindNode('office:font-face-decls'));
|
||||||
|
|
||||||
StylesNode := Doc.DocumentElement.FindNode('office:styles');
|
StylesNode := Doc.DocumentElement.FindNode('office:styles');
|
||||||
ReadNumFormats(StylesNode);
|
ReadNumFormats(StylesNode);
|
||||||
ReadStyles(StylesNode);
|
ReadStyles(StylesNode);
|
||||||
ReadAutomaticStyles(Doc.DocumentElement.FindNode('office:automatic-styles'));
|
ReadAutomaticStyles(Doc.DocumentElement.FindNode('office:automatic-styles'));
|
||||||
ReadMasterStyles(Doc.DocumentElement.FindNode('office:master-styles'));
|
ReadMasterStyles(Doc.DocumentElement.FindNode('office:master-styles'));
|
||||||
FreeAndNil(Doc);
|
FreeAndNil(Doc);
|
||||||
|
end;
|
||||||
|
|
||||||
//process the content.xml file
|
//process the content.xml file
|
||||||
XMLStream := CreateXMLStream;
|
XMLStream := CreateXMLStream;
|
||||||
try
|
try
|
||||||
if UnzipToStream(AStream, 'content.xml', XMLStream) then
|
if UnzipToStream(AStream, 'content.xml', XMLStream) then
|
||||||
ReadXMLStream(Doc, XMLStream);
|
ReadXMLStream(Doc, XMLStream)
|
||||||
|
else
|
||||||
|
raise EFPSpreadsheetReader.CreateFmt(rsDefectiveInternalFileStructure, ['ods']);
|
||||||
finally
|
finally
|
||||||
XMLStream.Free;
|
XMLStream.Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
ReadFontFaces(Doc.DocumentElement.FindNode('office:font-face-decls'));
|
if Assigned(Doc) then begin
|
||||||
StylesNode := Doc.DocumentElement.FindNode('office:automatic-styles');
|
ReadFontFaces(Doc.DocumentElement.FindNode('office:font-face-decls'));
|
||||||
ReadNumFormats(StylesNode);
|
StylesNode := Doc.DocumentElement.FindNode('office:automatic-styles');
|
||||||
ReadStyles(StylesNode);
|
ReadNumFormats(StylesNode);
|
||||||
|
ReadStyles(StylesNode);
|
||||||
|
|
||||||
BodyNode := Doc.DocumentElement.FindNode('office:body');
|
BodyNode := Doc.DocumentElement.FindNode('office:body');
|
||||||
if not Assigned(BodyNode) then
|
if not Assigned(BodyNode) then
|
||||||
raise EFPSpreadsheet.Create('[TsSpreadOpenDocReader.ReadFromStream] Node "office:body" not found.');
|
raise EFPSpreadsheet.Create('[TsSpreadOpenDocReader.ReadFromStream] Node "office:body" not found.');
|
||||||
|
|
||||||
SpreadSheetNode := BodyNode.FindNode('office:spreadsheet');
|
SpreadSheetNode := BodyNode.FindNode('office:spreadsheet');
|
||||||
if not Assigned(SpreadSheetNode) then
|
if not Assigned(SpreadSheetNode) then
|
||||||
raise EFPSpreadsheet.Create('[TsSpreadOpenDocReader.ReadFromStream] Node "office:spreadsheet" not found.');
|
raise EFPSpreadsheet.Create('[TsSpreadOpenDocReader.ReadFromStream] Node "office:spreadsheet" not found.');
|
||||||
|
|
||||||
ReadSheets(SpreadsheetNode);
|
ReadSheets(SpreadsheetNode);
|
||||||
ReadDocumentProtection(SpreadsheetNode);
|
ReadDocumentProtection(SpreadsheetNode);
|
||||||
ReadDateMode(SpreadSheetNode);
|
ReadDateMode(SpreadSheetNode);
|
||||||
|
|
||||||
//process each table (sheet)
|
//process each table (sheet)
|
||||||
TableNode := SpreadSheetNode.FindNode('table:table');
|
TableNode := SpreadSheetNode.FindNode('table:table');
|
||||||
while Assigned(TableNode) do
|
while Assigned(TableNode) do
|
||||||
begin
|
|
||||||
nodename := TableNode.Nodename;
|
|
||||||
// These nodes occur due to leading spaces which are not skipped
|
|
||||||
// automatically any more due to PreserveWhiteSpace option applied
|
|
||||||
// to ReadXMLFile
|
|
||||||
if nodeName <> 'table:table' then
|
|
||||||
begin
|
begin
|
||||||
TableNode := TableNode.NextSibling;
|
nodename := TableNode.Nodename;
|
||||||
continue;
|
// These nodes occur due to leading spaces which are not skipped
|
||||||
end;
|
// automatically any more due to PreserveWhiteSpace option applied
|
||||||
|
// to ReadXMLFile
|
||||||
|
if nodeName <> 'table:table' then
|
||||||
|
begin
|
||||||
|
TableNode := TableNode.NextSibling;
|
||||||
|
continue;
|
||||||
|
end;
|
||||||
|
|
||||||
// Tables with external references contain a copy of the external table
|
// Tables with external references contain a copy of the external table
|
||||||
// having the filename as sheet name - which is not valid for fps.
|
// having the filename as sheet name - which is not valid for fps.
|
||||||
// Since external references are not supported ATM we skip this table.
|
// Since external references are not supported ATM we skip this table.
|
||||||
if TableNode.FindNode('table:table-source') <> nil then begin
|
if TableNode.FindNode('table:table-source') <> nil then begin
|
||||||
TableNode := TableNode.NextSibling;
|
TableNode := TableNode.NextSibling;
|
||||||
Continue;
|
Continue;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
sheetName := GetAttrValue(TableNode, 'table:name');
|
sheetName := GetAttrValue(TableNode, 'table:name');
|
||||||
FWorksheet := TsWorkbook(FWorkbook).GetWorksheetByName(sheetName);
|
FWorksheet := TsWorkbook(FWorkbook).GetWorksheetByName(sheetName);
|
||||||
// FWorkSheet := TsWorkbook(FWorkbook).AddWorksheet(sheetName, true);
|
// FWorkSheet := TsWorkbook(FWorkbook).AddWorksheet(sheetName, true);
|
||||||
tablestyleName := GetAttrValue(TableNode, 'table:style-name');
|
tablestyleName := GetAttrValue(TableNode, 'table:style-name');
|
||||||
// Read protection
|
// Read protection
|
||||||
ReadSheetProtection(TableNode, FWorksheet);
|
ReadSheetProtection(TableNode, FWorksheet);
|
||||||
// Collect embedded images
|
// Collect embedded images
|
||||||
ReadShapes(TableNode);
|
ReadShapes(TableNode);
|
||||||
// Collect column styles used
|
// Collect column styles used
|
||||||
ReadColumns(TableNode);
|
ReadColumns(TableNode);
|
||||||
// Process each row inside the sheet and process each cell of the row
|
// Process each row inside the sheet and process each cell of the row
|
||||||
ReadRowsAndCells(TableNode);
|
ReadRowsAndCells(TableNode);
|
||||||
// Read page layout
|
// Read page layout
|
||||||
ReadPageLayout(StylesNode, GetAttrValue(TableNode, 'table:style-name'),
|
ReadPageLayout(StylesNode, GetAttrValue(TableNode, 'table:style-name'),
|
||||||
(FWorksheet as TsWorksheet).PageLayout);
|
(FWorksheet as TsWorksheet).PageLayout);
|
||||||
// Repeated cols/rows already have been determined.
|
// Repeated cols/rows already have been determined.
|
||||||
(FWorksheet as TsWorksheet).PageLayout.SetRepeatedRows(
|
(FWorksheet as TsWorksheet).PageLayout.SetRepeatedRows(
|
||||||
FRepeatedRows.FirstIndex, FRepeatedRows.LastIndex);
|
FRepeatedRows.FirstIndex, FRepeatedRows.LastIndex);
|
||||||
(FWorksheet as TsWorksheet).PageLayout.SetRepeatedCols(
|
(FWorksheet as TsWorksheet).PageLayout.SetRepeatedCols(
|
||||||
FRepeatedCols.FirstIndex, FRepeatedCols.LastIndex);
|
FRepeatedCols.FirstIndex, FRepeatedCols.LastIndex);
|
||||||
// Read print ranges
|
// Read print ranges
|
||||||
ReadPrintRanges(TableNode, FWorksheet);
|
ReadPrintRanges(TableNode, FWorksheet);
|
||||||
// Apply table style
|
// Apply table style
|
||||||
ApplyTableStyle(FWorksheet, tablestylename);
|
ApplyTableStyle(FWorksheet, tablestylename);
|
||||||
// Handle columns
|
// Handle columns
|
||||||
ApplyColWidths;
|
ApplyColWidths;
|
||||||
// Page layout
|
// Page layout
|
||||||
FixCols(FWorksheet);
|
FixCols(FWorksheet);
|
||||||
FixRows(FWorksheet);
|
FixRows(FWorksheet);
|
||||||
// Continue with next table
|
// Continue with next table
|
||||||
TableNode := TableNode.NextSibling;
|
TableNode := TableNode.NextSibling;
|
||||||
end; //while Assigned(TableNode)
|
end; //while Assigned(TableNode)
|
||||||
|
|
||||||
FreeAndNil(Doc);
|
FreeAndNil(Doc);
|
||||||
|
end;
|
||||||
|
|
||||||
// process the settings.xml file (Note: it does not always exist!)
|
// process the settings.xml file (Note: it does not always exist!)
|
||||||
XMLStream := CreateXMLStream;
|
XMLStream := CreateXMLStream;
|
||||||
@ -2718,9 +2724,6 @@ begin
|
|||||||
XMLStream.Free;
|
XMLStream.Free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Convert formulas from OpenDocument to ExcelA1 dialect
|
|
||||||
// FixFormulas;
|
|
||||||
|
|
||||||
// Active sheet
|
// Active sheet
|
||||||
if FActiveSheet <> '' then
|
if FActiveSheet <> '' then
|
||||||
sheet := (FWorkbook as TsWorkbook).GetWorksheetByName(FActiveSheet) else
|
sheet := (FWorkbook as TsWorkbook).GetWorksheetByName(FActiveSheet) else
|
||||||
|
@ -8691,18 +8691,47 @@ procedure TsWorkbook.ReadFromFile(AFileName: string; APassword: String = '';
|
|||||||
AParams: TsStreamParams = []);
|
AParams: TsStreamParams = []);
|
||||||
var
|
var
|
||||||
success: Boolean;
|
success: Boolean;
|
||||||
|
fmtID: TsSpreadFormatID;
|
||||||
fileFormats: TsSpreadFormatIDArray;
|
fileFormats: TsSpreadFormatIDArray;
|
||||||
i: Integer;
|
i: Integer;
|
||||||
|
found: Boolean;
|
||||||
begin
|
begin
|
||||||
if not FileExists(AFileName) then
|
if not FileExists(AFileName) then
|
||||||
raise EFPSpreadsheetReader.CreateFmt(rsFileNotFound, [AFileName]);
|
raise EFPSpreadsheetReader.CreateFmt(rsFileNotFound, [AFileName]);
|
||||||
|
|
||||||
|
// First try to determine file format from the extension
|
||||||
|
if GetFormatFromFileName(AFilename, fmtID) then begin
|
||||||
|
try
|
||||||
|
ReadFromFile(AFileName, fmtID, APassword, AParams);
|
||||||
|
exit;
|
||||||
|
except
|
||||||
|
// format does not match. We must continue with rest of procedure
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
fmtID := MaxInt;
|
||||||
|
|
||||||
// Try to get file format from file header
|
// Try to get file format from file header
|
||||||
GetFormatFromFileHeader(AFileName, fileformats);
|
GetFormatFromFileHeader(AFileName, fileformats);
|
||||||
if Length(fileformats) = 0 then
|
if Length(fileformats) = 0 then
|
||||||
// If not successful use formats defined by extension
|
// If not successful use formats defined by extension
|
||||||
fileFormats := GetSpreadFormatsFromFileName(faRead, AFileName);
|
fileFormats := GetSpreadFormatsFromFileName(faRead, AFileName);
|
||||||
|
|
||||||
|
// Remove already tested format
|
||||||
|
found := false;
|
||||||
|
i := 0;
|
||||||
|
while (i <= High(fileFormats)) do begin
|
||||||
|
if fileFormats[i] = fmtID then begin
|
||||||
|
found := true;
|
||||||
|
inc(i);
|
||||||
|
while (i <= High(fileFormats)) do begin
|
||||||
|
fileFormats[i-1] := fileFormats[i];
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
inc(i);
|
||||||
|
end;
|
||||||
|
if found then SetLength(fileFormats, Length(fileFormats)-1);
|
||||||
|
|
||||||
// No file format found for this file --> error
|
// No file format found for this file --> error
|
||||||
if Length(fileformats) = 0 then
|
if Length(fileformats) = 0 then
|
||||||
raise EFPSpreadsheetReader.CreateFmt(rsReaderNotFound, [AFileName]);
|
raise EFPSpreadsheetReader.CreateFmt(rsReaderNotFound, [AFileName]);
|
||||||
|
@ -1370,7 +1370,7 @@ var
|
|||||||
fileformats: TsSpreadFormatIDArray;
|
fileformats: TsSpreadFormatIDArray;
|
||||||
begin
|
begin
|
||||||
fileFormats := GetSpreadFormatsFromFileName(faRead, AFileName, ord(sfExcel8));
|
fileFormats := GetSpreadFormatsFromFileName(faRead, AFileName, ord(sfExcel8));
|
||||||
Result := (Length(fileFormats) > 0) and (fileFormats[0] <= sfidUnknown);
|
Result := (Length(fileFormats) > 0); // and (fileFormats[0] <= sfidUnknown); // wp - removed for new format detection
|
||||||
if Result then AFormatID := fileFormats[0];
|
if Result then AFormatID := fileFormats[0];
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user