diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas index 77f4f12c0..4d6b11e88 100755 --- a/components/fpspreadsheet/xlsbiff5.pas +++ b/components/fpspreadsheet/xlsbiff5.pas @@ -109,8 +109,10 @@ type WorkBookEncoding: TsEncoding; protected { Record writing methods } + { procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); override; + } procedure WriteBOF(AStream: TStream; ADataType: Word); function WriteBoundsheet(AStream: TStream; ASheetName: string): Int64; procedure WriteDimensions(AStream: TStream; AWorksheet: TsWorksheet); @@ -120,8 +122,6 @@ type procedure WriteIndex(AStream: TStream); procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; const AValue: string; ACell: PCell); override; - procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; - const AValue: double; ACell: PCell); override; procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal; const AFormula: TsRPNFormula; ACell: PCell); override; procedure WriteStyle(AStream: TStream); @@ -133,7 +133,6 @@ type AWordWrap: Boolean = false; AddBackground: Boolean = false; ABackgroundColor: TsColor = scSilver); procedure WriteXFFieldsForFormattingStyles(AStream: TStream); - procedure WriteXFIndex(AStream: TStream; ACell: PCell); procedure WriteXFRecords(AStream: TStream); public { General writing methods } @@ -221,17 +220,13 @@ implementation const { Excel record IDs } - INT_EXCEL_ID_BLANK = $0201; INT_EXCEL_ID_BOF = $0809; INT_EXCEL_ID_BOUNDSHEET = $0085; // Renamed to SHEET in the latest OpenOffice docs INT_EXCEL_ID_EOF = $000A; INT_EXCEL_ID_DIMENSIONS = $0200; - INT_EXCEL_ID_FONT = $0031; INT_EXCEL_ID_FORMAT = $041E; INT_EXCEL_ID_FORMULA = $0006; INT_EXCEL_ID_INDEX = $020B; - INT_EXCEL_ID_LABEL = $0204; - INT_EXCEL_ID_NUMBER = $0203; INT_EXCEL_ID_ROWINFO = $0208; INT_EXCEL_ID_STYLE = $0293; INT_EXCEL_ID_WINDOW1 = $003D; @@ -434,7 +429,7 @@ begin SetLength(Boundsheets, 0); end; - + (* {******************************************************************* * TsSpreadBIFF5Writer.WriteBlank * @@ -455,7 +450,7 @@ begin { Index to XF record } WriteXFIndex(AStream, ACell); end; - + *) {******************************************************************* * TsSpreadBIFF5Writer.WriteBOF () * @@ -927,49 +922,6 @@ begin } end; -{******************************************************************* -* TsSpreadBIFF5Writer.WriteNumber () -* -* DESCRIPTION: Writes an Excel 5 NUMBER record -* -* Writes a number (64-bit floating point) to the sheet -* -*******************************************************************} -procedure TsSpreadBIFF5Writer.WriteNumber(AStream: TStream; const ARow, - ACol: Cardinal; const AValue: double; ACell: PCell); -begin - { BIFF Record header } - AStream.WriteWord(WordToLE(INT_EXCEL_ID_NUMBER)); - AStream.WriteWord(WordToLE(14)); - - { BIFF Record data } - AStream.WriteWord(WordToLE(ARow)); - AStream.WriteWord(WordToLE(ACol)); - - { Index to XF record } - WriteXFIndex(AStream, ACell); - - { IEE 754 floating-point value } - AStream.WriteBuffer(AValue, 8); -end; - (* -{******************************************************************* -* TsSpreadBIFF2Writer.WriteDateTime () -* -* DESCRIPTION: Writes a date/time value as a text -* ISO 8601 format is used to preserve interoperability -* between locales. -* -* Note: this should be replaced by writing actual date/time values -* -*******************************************************************} -procedure TsSpreadBIFF5Writer.WriteDateTime(AStream: TStream; - const ARow, ACol: Cardinal; const AValue: TDateTime; ACell: PCell); -begin - WriteLabel(AStream, ARow, ACol, FormatDateTime(ISO8601Format, AValue), ACell); -end; - *) - {******************************************************************* * TsSpreadBIFF5Writer.WriteStyle () * @@ -1285,56 +1237,6 @@ begin end; end; -{ Index to XF record, according to formatting } -procedure TsSpreadBIFF5Writer.WriteXFIndex(AStream: TStream; ACell: PCell); -var - lIndex: Integer; - lXFIndex: Word; -begin - // First try the fast methods for default formats - if ACell^.UsedFormattingFields = [] then - begin - AStream.WriteWord(WordToLE(15)); //XF15; see TsSpreadBIFF8Writer.AddDefaultFormats - Exit; - end; - (* - if ACell^.UsedFormattingFields = [uffTextRotation] then - begin - case ACell^.TextRotation of - rt90DegreeCounterClockwiseRotation: AStream.WriteWord(WordToLE(16)); //XF_16 - rt90DegreeClockwiseRotation: AStream.WriteWord(WordToLE(17)); //XF_17 - else - AStream.WriteWord(WordToLE(15)); //XF_15 - end; - Exit; - end; - *) - - { - uffNumberFormat does not seem to have default XF indexes, but perhaps look at XF_21 - if ACell^.UsedFormattingFields = [uffNumberFormat] then - begin - case ACell^.NumberFormat of - nfShortDate: AStream.WriteWord(WordToLE(???)); //what XF index? - nfShortDateTime: AStream.WriteWord(WordToLE(???)); //what XF index? - else - AStream.WriteWord(WordToLE(15)); //e.g. nfGeneral: XF_15 - end; - Exit; - end; - } - - // If not, then we need to search in the list of dynamic formats - lIndex := FindFormattingInList(ACell); - // Carefully check the index - if (lIndex < 0) or (lIndex > Length(FFormattingStyles)) then - raise Exception.Create('[TsSpreadBIFF5Writer.WriteXFIndex] Invalid Index, this should not happen!'); - - lXFIndex := FFormattingStyles[lIndex].Row; - - AStream.WriteWord(WordToLE(lXFIndex)); -end; - procedure TsSpreadBIFF5Writer.WriteXFRecords(AStream: TStream); begin // XF0 diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index babee06a0..8b5bb55ff 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -107,12 +107,10 @@ type TsSpreadBIFF8Writer = class(TsSpreadBIFFWriter) private // Writes index to XF record according to cell's formatting - procedure WriteXFIndex(AStream: TStream; ACell: PCell); + //procedure WriteXFIndex(AStream: TStream; ACell: PCell); procedure WriteXFFieldsForFormattingStyles(AStream: TStream); protected { Record writing methods } - procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; - ACell: PCell); override; procedure WriteBOF(AStream: TStream; ADataType: Word); function WriteBoundsheet(AStream: TStream; ASheetName: string): Int64; // procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal; @@ -126,8 +124,6 @@ type procedure WriteIndex(AStream: TStream); procedure WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; const AValue: string; ACell: PCell); override; - procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; - const AValue: double; ACell: PCell); override; procedure WriteRPNFormula(AStream: TStream; const ARow, ACol: Cardinal; const AFormula: TsRPNFormula; ACell: PCell); override; procedure WriteStyle(AStream: TStream); @@ -223,7 +219,6 @@ implementation const { Excel record IDs } - INT_EXCEL_ID_BLANK = $0201; INT_EXCEL_ID_BOF = $0809; INT_EXCEL_ID_BOUNDSHEET = $0085; // Renamed to SHEET in the latest OpenOffice docs INT_EXCEL_ID_COUNTRY = $008C; @@ -231,8 +226,6 @@ const INT_EXCEL_ID_DIMENSIONS = $0200; INT_EXCEL_ID_FORMULA = $0006; INT_EXCEL_ID_INDEX = $020B; - INT_EXCEL_ID_LABEL = $0204; - INT_EXCEL_ID_NUMBER = $0203; INT_EXCEL_ID_ROWINFO = $0208; INT_EXCEL_ID_STYLE = $0293; INT_EXCEL_ID_WINDOW1 = $003D; @@ -308,57 +301,6 @@ const { TsSpreadBIFF8Writer } -{ Index to XF record, according to formatting } -procedure TsSpreadBIFF8Writer.WriteXFIndex(AStream: TStream; ACell: PCell); -var - lIndex: Integer; - lXFIndex: Word; -begin - // First try the fast methods for default formats - if ACell^.UsedFormattingFields = [] then - begin - AStream.WriteWord(WordToLE(15)); //XF15; see TsSpreadBIFF8Writer.AddDefaultFormats - Exit; - end; - -{ - if ACell^.UsedFormattingFields = [uffTextRotation] then - begin - case ACell^.TextRotation of - rt90DegreeCounterClockwiseRotation: AStream.WriteWord(WordToLE(16)); //XF_16 - rt90DegreeClockwiseRotation: AStream.WriteWord(WordToLE(17)); //XF_17 - else - AStream.WriteWord(WordToLE(15)); //XF_15 - end; - Exit; - end; - } - - { - uffNumberFormat does not seem to have default XF indexes, but perhaps look at XF_21 - if ACell^.UsedFormattingFields = [uffNumberFormat] then - begin - case ACell^.NumberFormat of - nfShortDate: AStream.WriteWord(WordToLE(???)); //what XF index? - nfShortDateTime: AStream.WriteWord(WordToLE(???)); //what XF index? - else - AStream.WriteWord(WordToLE(15)); //e.g. nfGeneral: XF_15 - end; - Exit; - end; - } - - // If not, then we need to search in the list of dynamic formats - lIndex := FindFormattingInList(ACell); - // Carefully check the index - if (lIndex < 0) or (lIndex > Length(FFormattingStyles)) then - raise Exception.Create('[TsSpreadBIFF8Writer.WriteXFIndex] Invalid Index, this should not happen!'); - - lXFIndex := FFormattingStyles[lIndex].Row; - - AStream.WriteWord(WordToLE(lXFIndex)); -end; - procedure TsSpreadBIFF8Writer.WriteXFFieldsForFormattingStyles(AStream: TStream); var i: Integer; @@ -574,27 +516,6 @@ begin SetLength(Boundsheets, 0); end; -{******************************************************************* -* TsSpreadBIFF8Writer.WriteBlank -* -* DESCRIPTION: Writes the record for an empty cell -* -*******************************************************************} -procedure TsSpreadBIFF8Writer.WriteBlank(AStream: TStream; - const ARow, ACol: Cardinal; ACell: PCell); -begin - { BIFF Record header } - AStream.WriteWord(WordToLE(INT_EXCEL_ID_BLANK)); - AStream.WriteWord(WordToLE(6)); - - { BIFF Record data } - AStream.WriteWord(WordToLE(ARow)); - AStream.WriteWord(WordToLE(ACol)); - - { Index to XF record, according to formatting } - WriteXFIndex(AStream, ACell); -end; - {******************************************************************* * TsSpreadBIFF8Writer.WriteBOF () @@ -1167,32 +1088,6 @@ begin } end; -{******************************************************************* -* TsSpreadBIFF8Writer.WriteNumber () -* -* DESCRIPTION: Writes an Excel 8 NUMBER record -* -* Writes a number (64-bit floating point) to the sheet -* -*******************************************************************} -procedure TsSpreadBIFF8Writer.WriteNumber(AStream: TStream; const ARow, - ACol: Cardinal; const AValue: double; ACell: PCell); -begin - { BIFF Record header } - AStream.WriteWord(WordToLE(INT_EXCEL_ID_NUMBER)); - AStream.WriteWord(WordToLE(14)); //total record size - - { BIFF Record data } - AStream.WriteWord(WordToLE(ARow)); - AStream.WriteWord(WordToLE(ACol)); - - { Index to XF record, according to formatting } - WriteXFIndex(AStream, ACell); - - { IEE 754 floating-point value (is different in BIGENDIAN???) } - AStream.WriteBuffer(AValue, 8); -end; - {******************************************************************* * TsSpreadBIFF8Writer.WriteStyle () * diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index ad38463dd..3e99c7d3f 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -23,6 +23,11 @@ const INT_EXCEL_ID_PALETTE = $0092; INT_EXCEL_ID_XF = $00E0; + { RECORD IDs which did not change across versions 5-8 } + INT_EXCEL_ID_BLANK = $0201; + INT_EXCEL_ID_NUMBER = $0203; + INT_EXCEL_ID_LABEL = $0204; + { FONT record constants } INT_FONT_WEIGHT_NORMAL = $0190; INT_FONT_WEIGHT_BOLD = $02BC; @@ -371,6 +376,9 @@ type function GetLastColIndex(AWorksheet: TsWorksheet): Word; function FormulaElementKindToExcelTokenID(AElementKind: TFEKind; out ASecondaryID: Word): Word; + // Write out BLANK cell record + procedure WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; + ACell: PCell); override; // Write out used codepage for character encoding procedure WriteCodepage(AStream: TStream; AEncoding: TsEncoding); // Writes out column info(s) @@ -381,8 +389,13 @@ type // Writes out a TIME/DATE/TIMETIME procedure WriteDateTime(AStream: TStream; const ARow, ACol: Cardinal; const AValue: TDateTime; ACell: PCell); override; + // Writes out a floating point NUMBER record + procedure WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; + const AValue: Double; ACell: PCell); override; // Writes out a PALETTE record containing all colors defined in the workbook procedure WritePalette(AStream: TStream); + // Writes the index of the XF record used in the given cell + procedure WriteXFIndex(AStream: TStream; ACell: PCell); public constructor Create(AWorkbook: TsWorkbook); override; @@ -1083,6 +1096,24 @@ begin Result := FLastCol; end; +{ Writes an empty ("blank") cell. Needed for formatting empty cells. + Valid for BIFF5 and BIFF8. Needs to be overridden for BIFF2 which has a + different record structure. } +procedure TsSpreadBIFFWriter.WriteBlank(AStream: TStream; + const ARow, ACol: Cardinal; ACell: PCell); +begin + { BIFF Record header } + AStream.WriteWord(WordToLE(INT_EXCEL_ID_BLANK)); + AStream.WriteWord(WordToLE(6)); + + { Row and column index } + AStream.WriteWord(WordToLE(ARow)); + AStream.WriteWord(WordToLE(ACol)); + + { Index to XF record, according to formatting } + WriteXFIndex(AStream, ACell); +end; + procedure TsSpreadBIFFWriter.WriteCodepage(AStream: TStream; AEncoding: TsEncoding); var @@ -1107,6 +1138,8 @@ begin AStream.WriteWord(WordToLE(lCodepage)); end; +{ Writes column info for the given column. Currently only the colum width is used. + Valid for BIFF5 and BIFF8 (BIFF2 uses a different record. } procedure TsSpreadBIFFWriter.WriteColInfo(AStream: TStream; ACol: PCol); var w: Integer; @@ -1126,6 +1159,7 @@ begin end; end; +{ Writes the column info records for all used columns. } procedure TsSpreadBIFFWriter.WriteColInfos(AStream: TStream; ASheet: TsWorksheet); var @@ -1167,6 +1201,26 @@ begin WriteNumber(AStream, ARow, ACol, ExcelDateSerial, ACell); end; +{ Writes a 64-bit floating point NUMBER record. + Valid for BIFF5 and BIFF8 (BIFF2 has a different record structure.). } +procedure TsSpreadBIFFWriter.WriteNumber(AStream: TStream; + const ARow, ACol: Cardinal; const AValue: double; ACell: PCell); +begin + { BIFF Record header } + AStream.WriteWord(WordToLE(INT_EXCEL_ID_NUMBER)); + AStream.WriteWord(WordToLE(14)); + + { BIFF Record data } + AStream.WriteWord(WordToLE(ARow)); + AStream.WriteWord(WordToLE(ACol)); + + { Index to XF record } + WriteXFIndex(AStream, ACell); + + { IEE 754 floating-point value } + AStream.WriteBuffer(AValue, 8); +end; + procedure TsSpreadBIFFWriter.WritePalette(AStream: TStream); var i, n: Integer; @@ -1189,6 +1243,33 @@ begin end; +{ Write the index of the XF record, according to formatting of the given cell + Valid for BIFF5 and BIFF8. + BIFF2 is handled differently. } +procedure TsSpreadBIFFWriter.WriteXFIndex(AStream: TStream; ACell: PCell); +var + lIndex: Integer; + lXFIndex: Word; +begin + // First try the fast methods for default formats + if ACell^.UsedFormattingFields = [] then begin + AStream.WriteWord(WordToLE(15)); //XF15; see TsSpreadBIFF8Writer.AddDefaultFormats + Exit; + end; + + // If not, then we need to search in the list of dynamic formats + lIndex := FindFormattingInList(ACell); + + // Carefully check the index + if (lIndex < 0) or (lIndex > Length(FFormattingStyles)) then + raise Exception.Create('[TsSpreadBIFFWriter.WriteXFIndex] Invalid Index, this should not happen!'); + + lXFIndex := FFormattingStyles[lIndex].Row; + + AStream.WriteWord(WordToLE(lXFIndex)); +end; + + { Format checking procedures } { This simple parsing procedure of the Excel format string checks for a fixed