From 4c723b9fc3249518c08ed204ff7dc5aedf98c316 Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Tue, 15 Jul 2014 21:00:49 +0000 Subject: [PATCH] fpspreadsheet: Convert some more biff methods such records are written in a single block (biff2: WriteLabel, WriteNumber, all: WriteFormat, WriteBlank, WriteColInfo). git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@3325 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../examples/excel2demo/excel2write.lpi | 5 + components/fpspreadsheet/fpsopendocument.pas | 17 +- components/fpspreadsheet/xlsbiff2.pas | 206 +++++++++++++++++- components/fpspreadsheet/xlsbiff5.pas | 96 ++++++-- components/fpspreadsheet/xlsbiff8.pas | 35 +++ components/fpspreadsheet/xlscommon.pas | 58 +++++ components/fpspreadsheet/xlsxooxml.pas | 15 +- 7 files changed, 395 insertions(+), 37 deletions(-) diff --git a/components/fpspreadsheet/examples/excel2demo/excel2write.lpi b/components/fpspreadsheet/examples/excel2demo/excel2write.lpi index b796af7d9..5d80f62c2 100644 --- a/components/fpspreadsheet/examples/excel2demo/excel2write.lpi +++ b/components/fpspreadsheet/examples/excel2demo/excel2write.lpi @@ -54,5 +54,10 @@ + + + + + diff --git a/components/fpspreadsheet/fpsopendocument.pas b/components/fpspreadsheet/fpsopendocument.pas index 0eb47c027..e3ac875f6 100755 --- a/components/fpspreadsheet/fpsopendocument.pas +++ b/components/fpspreadsheet/fpsopendocument.pas @@ -2995,11 +2995,10 @@ begin Format('table:number-columns-repeated="%d"', [colsRepeated])); AppendToStream(AStream, Format( - '', [styleName, rowsRepeatedStr])); - AppendToStream(AStream, Format( - '', [colsRepeatedStr])); - AppendToStream(AStream, - ''); + '' + + '' + + '', + [styleName, rowsRepeatedStr, colsRepeatedStr])); r := rr; continue; @@ -3476,8 +3475,8 @@ begin // The row should already be the correct one AppendToStream(AStream, - '', - '' + UTF8TextToXMLText(AValue) + '', + '' + + '' + UTF8TextToXMLText(AValue) + '' + ''); end; @@ -3514,8 +3513,8 @@ begin end; AppendToStream(AStream, - '', - '' + DisplayStr + '', + '' + + '' + DisplayStr + '' + ''); end; diff --git a/components/fpspreadsheet/xlsbiff2.pas b/components/fpspreadsheet/xlsbiff2.pas index a590191ef..c8788a8cd 100755 --- a/components/fpspreadsheet/xlsbiff2.pas +++ b/components/fpspreadsheet/xlsbiff2.pas @@ -87,6 +87,8 @@ type TsSpreadBIFF2Writer = class(TsSpreadBIFFWriter) private function FindXFIndex(ACell: PCell): Word; + procedure GetCellAttributes(ACell: PCell; XFIndex: Word; + out Attrib1, Attrib2, Attrib3: Byte); { Record writing methods } procedure WriteBOF(AStream: TStream); procedure WriteCellFormatting(AStream: TStream; ACell: PCell; XFIndex: Word); @@ -850,6 +852,50 @@ begin end; end; +{ Determines the cell attributes needed for writing a cell content record, such + as WriteLabel, WriteNumber, etc. + The cell attributes contain, in bit masks, xf record index, font index, borders, etc.} +procedure TsSpreadBIFF2Writer.GetCellAttributes(ACell: PCell; XFIndex: Word; + out Attrib1, Attrib2, Attrib3: Byte); +begin + if ACell^.UsedFormattingFields = [] then begin + Attrib1 := 15; + Attrib2 := 0; + Attrib3 := 0; + exit; + end; + + // 1st byte: + // Mask $3F: Index to XF record + // Mask $40: 1 = Cell is locked + // Mask $80: 1 = Formula is hidden + Attrib1 := Min(XFIndex, $3F) and $3F; + + // 2nd byte: + // Mask $3F: Index to FORMAT record + // Mask $C0: Index to FONT record + Attrib2 := ACell^.FontIndex shr 6; + + // 3rd byte + // Mask $07: horizontal alignment + // Mask $08: Cell has left border + // Mask $10: Cell has right border + // Mask $20: Cell has top border + // Mask $40: Cell has bottom border + // Mask $80: Cell has shaded background + Attrib3 := 0; + if uffHorAlign in ACell^.UsedFormattingFields then + Attrib3 := ord (ACell^.HorAlignment); + if uffBorder in ACell^.UsedFormattingFields then begin + if cbNorth in ACell^.Border then Attrib3 := Attrib3 or $20; + if cbWest in ACell^.Border then Attrib3 := Attrib3 or $08; + if cbEast in ACell^.Border then Attrib3 := Attrib3 or $10; + if cbSouth in ACell^.Border then Attrib3 := Attrib3 or $40; + end; + if uffBackgroundColor in ACell^.UsedFormattingFields then + Attrib3 := Attrib3 or $80; +end; + { Builds up the list of number formats to be written to the biff2 file. Unlike biff5+ no formats are added here because biff2 supports only 21 standard formats; these formats have been added by the NumFormatList's @@ -888,7 +934,7 @@ begin // 2nd byte: // Mask $3F: Index to FORMAT record // Mask $C0: Index to FONT record - w := ACell.FontIndex shl 6; + w := ACell.FontIndex shr 6; // was shl --> MUST BE shr! b := Lo(w); //b := ACell.FontIndex shl 6; AStream.WriteByte(b); @@ -918,10 +964,36 @@ end; Writes an Excel 2 COLWIDTH record } procedure TsSpreadBIFF2Writer.WriteColWidth(AStream: TStream; ACol: PCol); +type + TColRecord = packed record + RecordID: Word; + RecordSize: Word; + StartCol: Byte; + EndCol: Byte; + ColWidth: Word; + end; var + rec: TColRecord; w: Integer; begin if Assigned(ACol) then begin + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_COLWIDTH); + rec.RecordSize := WordToLE(4); + + { Start and end column } + rec.StartCol := ACol^.Col; + rec.EndCol := ACol^.Col; + + { Column width } + { calculate width to be in units of 1/256 of pixel width of character "0" } + w := round(ACol^.Width * 256); + rec.ColWidth := WordToLE(w); + + { Write out } + AStream.WriteBuffer(rec, SizeOf(rec)); + + (* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_COLWIDTH)); // BIFF record header AStream.WriteWord(WordToLE(4)); // Record size @@ -930,6 +1002,7 @@ begin { calculate width to be in units of 1/256 of pixel width of character "0" } w := round(ACol^.Width * 256); AStream.WriteWord(WordToLE(w)); // write width + *) end; end; @@ -1257,15 +1330,42 @@ end; procedure TsSpreadBiff2Writer.WriteFormat(AStream: TStream; AFormatData: TsNumFormatData; AListIndex: Integer); +type + TNumFormatRecord = packed record + RecordID: Word; + RecordSize: Word; + FormatLen: Byte; + end; var len: Integer; s: ansistring; + rec: TNumFormatRecord; + buf: array of byte; begin Unused(AFormatData); s := NumFormatList.FormatStringForWriting(AListIndex); len := Length(s); + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_FORMAT); + rec.RecordSize := WordToLE(1 + len); + + { Length byte of format string } + rec.FormatLen := len; + + { Copy the format string characters into a buffer immediately after rec } + SetLength(buf, SizeOf(rec) + SizeOf(ansiChar)*len); + Move(rec, buf[0], SizeOf(rec)); + Move(s[1], buf[SizeOf(rec)], len*SizeOf(ansiChar)); + + { Write out } + AStream.WriteBuffer(buf[0], SizeOf(Rec) + SizeOf(ansiChar)*len); + + { Clean up } + SetLength(buf, 0); + + (* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT)); AStream.WriteWord(WordToLE(1 + len)); @@ -1273,6 +1373,7 @@ begin { Format string } AStream.WriteByte(len); // AnsiString, char count in 1 byte AStream.WriteBuffer(s[1], len); // String data + *) end; procedure TsSpreadBIFF2Writer.WriteFormatCount(AStream: TStream); @@ -1401,13 +1502,38 @@ end; *******************************************************************} procedure TsSpreadBIFF2Writer.WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); +type + TBlankRecord = packed record + RecordID: Word; + RecordSize: Word; + Row: Word; + Col: Word; + Attrib1, Attrib2, Attrib3: Byte; + end; + var xf: Word; + rec: TBlankRecord; begin xf := FindXFIndex(ACell); if xf >= 63 then WriteIXFE(AStream, xf); + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_BLANK); + rec.RecordSize := WordToLE(7); + + { BIFF record data } + rec.Row := WordToLE(ARow); + rec.Col := WordToLE(ACol); + + { BIFF2 attributes } + GetCellAttributes(ACell, xf, rec.Attrib1, rec.Attrib2, rec.Attrib3); + + { Write out } + AStream.WriteBuffer(rec, Sizeof(rec)); + + (* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_BLANK)); AStream.WriteWord(WordToLE(7)); @@ -1418,6 +1544,7 @@ begin { BIFF2 Attributes } WriteCellFormatting(AStream, ACell, xf); + *) end; {******************************************************************* @@ -1433,12 +1560,25 @@ end; *******************************************************************} procedure TsSpreadBIFF2Writer.WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; const AValue: string; ACell: PCell); +type + TLabelRecord = packed record + RecordID: Word; + RecordSize: Word; + Row: Word; + Col: Word; + Attrib1: Byte; + Attrib2: Byte; + Attrib3: Byte; + TextLen: Byte; + end; const - MaxBytes=255; //limit for this format + MAXBYTES = 255; //limit for this format var L: Byte; AnsiText: ansistring; TextTooLong: boolean=false; + rec: TLabelRecord; + buf: array of byte; var xf: Word; begin @@ -1446,14 +1586,13 @@ begin AnsiText := UTF8ToISO_8859_1(AValue); - if Length(AnsiText)>MaxBytes then - begin + if Length(AnsiText) > MAXBYTES then begin // BIFF 5 does not support labels/text bigger than 255 chars, // so BIFF2 won't either // Rather than lose data when reading it, let the application programmer deal // with the problem or purposefully ignore it. TextTooLong:=true; - AnsiText := Copy(AnsiText,1,MaxBytes); + AnsiText := Copy(AnsiText, 1, MAXBYTES); end; L := Length(AnsiText); @@ -1461,6 +1600,30 @@ begin if xf >= 63 then WriteIXFE(AStream, xf); + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_LABEL); + rec.RecordSize := WordToLE(8 + L); + + { BIFF record data } + rec.Row := WordToLE(ARow); + rec.Col := WordToLE(ACol); + + { BIFF2 attributes } + GetCellAttributes(ACell, xf, rec.Attrib1, rec.Attrib2, rec.Attrib3); + + { Text length: 8 bit } + rec.TextLen := L; + + { Copy the text characters into a buffer immediately after rec } + SetLength(buf, SizeOf(rec) + SizeOf(ansiChar)*L); + Move(rec, buf[0], SizeOf(rec)); + Move(AnsiText[1], buf[SizeOf(rec)], L*SizeOf(ansiChar)); + + { Write out } + AStream.WriteBuffer(buf[0], SizeOf(Rec) + SizeOf(ansiChar)*L); + + + (* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_LABEL)); AStream.WriteWord(WordToLE(8 + L)); @@ -1475,6 +1638,7 @@ begin { String with 8-bit size } AStream.WriteByte(L); AStream.WriteBuffer(AnsiText[1], L); + *) { //todo: keep a log of errors and show with an exception after writing file or something. @@ -1495,13 +1659,25 @@ end; *******************************************************************} procedure TsSpreadBIFF2Writer.WriteNumber(AStream: TStream; const ARow, ACol: Cardinal; const AValue: double; ACell: PCell); +type + TNumberRecord = packed record + RecordID: Word; + RecordSize: Word; + Row: Word; + Col: Word; + Attrib1: Byte; + Attrib2: Byte; + Attrib3: Byte; + Value: Double; + end; var xf: Word; + rec: TNumberRecord; begin xf := FindXFIndex(ACell); if xf >= 63 then WriteIXFE(AStream, xf); - + (* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_NUMBER)); AStream.WriteWord(WordToLE(15)); @@ -1515,6 +1691,24 @@ begin { IEE 754 floating-point value } AStream.WriteBuffer(AValue, 8); + *) + + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_NUMBER); + rec.RecordSize := WordToLE(15); + + { BIFF record data } + rec.Row := WordToLE(ARow); + rec.Col := WordToLE(ACol); + + { BIFF2 attributes } + GetCellAttributes(ACell, xf, rec.Attrib1, rec.Attrib2, rec.Attrib3); + + { Number value } + rec.Value := AValue; + + { Write out } + AStream.WriteBuffer(rec, SizeOf(Rec)); end; procedure TsSpreadBIFF2Writer.WriteRow(AStream: TStream; ASheet: TsWorksheet; diff --git a/components/fpspreadsheet/xlsbiff5.pas b/components/fpspreadsheet/xlsbiff5.pas index 20f6450f0..14069d8d7 100755 --- a/components/fpspreadsheet/xlsbiff5.pas +++ b/components/fpspreadsheet/xlsbiff5.pas @@ -667,9 +667,18 @@ end; *******************************************************************} procedure TsSpreadBiff5Writer.WriteFormat(AStream: TStream; AFormatData: TsNumFormatData; AListIndex: Integer); +type + TNumFormatRecord = packed record + RecordID: Word; + RecordSize: Word; + FormatIndex: Word; + FormatStringLen: Byte; + end; var len: Integer; s: ansistring; + rec: TNumFormatRecord; + buf: array of byte; begin if (AFormatData = nil) or (AFormatData.FormatString = '') then exit; @@ -677,6 +686,28 @@ begin s := NumFormatList.FormatStringForWriting(AListIndex); len := Length(s); + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_FORMAT); + rec.RecordSize := WordToLE(2 + 1 + len * SizeOf(AnsiChar)); + + { Format index } + rec.FormatIndex := WordToLE(AFormatData.Index); + + { Format string } + { Length in 1 byte } + rec.FormatStringLen := len; + { Copy the format string characters into a buffer immediately after rec } + SetLength(buf, SizeOf(rec) + SizeOf(ansiChar)*len); + Move(rec, buf[0], SizeOf(rec)); + Move(s[1], buf[SizeOf(rec)], len*SizeOf(ansiChar)); + + { Write out } + AStream.WriteBuffer(buf[0], SizeOf(Rec) + SizeOf(ansiChar)*len); + + { Clean up } + SetLength(buf, 0); + +(* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT)); AStream.WriteWord(WordToLE(2 + 1 + len * SizeOf(AnsiChar))); @@ -687,7 +718,9 @@ begin { Format string } AStream.WriteByte(len); // AnsiString, char count in 1 byte AStream.WriteBuffer(s[1], len * SizeOf(AnsiChar)); // String data + *) end; + (* {******************************************************************* * TsSpreadBIFF5Writer.WriteRPNFormula () @@ -893,44 +926,79 @@ end; *******************************************************************} procedure TsSpreadBIFF5Writer.WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; const AValue: string; ACell: PCell); +type + TLabelRecord = packed record + RecordID: Word; + RecordSize: Word; + Row: Word; + Col: Word; + XFIndex: Word; + TextLen: Word; + end; const - MaxBytes=255; //limit for this format + MAXBYTES = 255; //limit for this format var L: Word; AnsiValue: ansistring; TextTooLong: boolean=false; + rec: TLabelRecord; + buf: array of byte; begin case WorkBookEncoding of - seLatin2: AnsiValue := UTF8ToCP1250(AValue); - seCyrillic: AnsiValue := UTF8ToCP1251(AValue); - seGreek: AnsiValue := UTF8ToCP1253(AValue); - seTurkish: AnsiValue := UTF8ToCP1254(AValue); - seHebrew: AnsiValue := UTF8ToCP1255(AValue); - seArabic: AnsiValue := UTF8ToCP1256(AValue); + seLatin2: AnsiValue := UTF8ToCP1250(AValue); + seCyrillic: AnsiValue := UTF8ToCP1251(AValue); + seGreek: AnsiValue := UTF8ToCP1253(AValue); + seTurkish: AnsiValue := UTF8ToCP1254(AValue); + seHebrew: AnsiValue := UTF8ToCP1255(AValue); + seArabic: AnsiValue := UTF8ToCP1256(AValue); else // Latin 1 is the default AnsiValue := UTF8ToCP1252(AValue); end; - if AnsiValue = '' then - begin + if AnsiValue = '' then begin // Bad formatted UTF8String (maybe ANSI?) - if Length(AValue)<>0 then begin + if Length(AValue) <> 0 then begin //It was an ANSI string written as UTF8 quite sure, so raise exception. Raise Exception.CreateFmt('Expected UTF8 text but probably ANSI text found in cell [%d,%d]',[ARow,ACol]); end; Exit; end; - if Length(AnsiValue)>MaxBytes then - begin + if Length(AnsiValue) > MAXBYTES then begin // Rather than lose data when reading it, let the application programmer deal // with the problem or purposefully ignore it. TextTooLong := true; - AnsiValue := Copy(AnsiValue,1,MaxBytes); + AnsiValue := Copy(AnsiValue, 1, MAXBYTES); end; L := Length(AnsiValue); + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_LABEL); + rec.RecordSize := WordToLE(8 + L); + + { BIFF record data } + rec.Row := WordToLE(ARow); + rec.Col := WordToLE(ACol); + + { Index to XF record } + rec.XFIndex := WordToLE(FindXFIndex(ACell)); + + { String length, 16 bit } + rec.TextLen := WordToLE(L); + + { Copy the text characters into a buffer immediately after rec } + SetLength(buf, SizeOf(rec) + SizeOf(ansiChar)*L); + Move(rec, buf[0], SizeOf(rec)); + Move(AnsiValue[1], buf[SizeOf(rec)], L*SizeOf(ansiChar)); + + { Write out } + AStream.WriteBuffer(buf[0], SizeOf(Rec) + SizeOf(ansiChar)*L); + + { Clean up } + SetLength(buf, 0); + + (* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_LABEL)); AStream.WriteWord(WordToLE(8 + L)); @@ -945,7 +1013,7 @@ begin { Byte String with 16-bit size } AStream.WriteWord(WordToLE(L)); AStream.WriteBuffer(AnsiValue[1], L); - + *) { //todo: keep a log of errors and show with an exception after writing file or something. We can't just do the following diff --git a/components/fpspreadsheet/xlsbiff8.pas b/components/fpspreadsheet/xlsbiff8.pas index 2540ca7a9..bbf02277f 100755 --- a/components/fpspreadsheet/xlsbiff8.pas +++ b/components/fpspreadsheet/xlsbiff8.pas @@ -687,9 +687,19 @@ end; procedure TsSpreadBiff8Writer.WriteFormat(AStream: TStream; AFormatData: TsNumFormatData; AListIndex: Integer); +type + TNumFormatRecord = packed record + RecordID: Word; + RecordSize: Word; + FormatIndex: Word; + FormatStringLen: Word; + FormatStringFlags: Byte; + end; var len: Integer; s: widestring; + rec: TNumFormatRecord; + buf: array of byte; begin if (AFormatData = nil) or (AFormatData.FormatString = '') then exit; @@ -697,6 +707,30 @@ begin s := NumFormatList.FormatStringForWriting(AListIndex); len := Length(s); + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_FORMAT); + rec.RecordSize := WordToLE(2 + 2 + 1 + len * SizeOf(WideChar)); + + { Format index } + rec.FormatIndex := WordToLE(AFormatData.Index); + + { Format string } + { - length of string = 16 bits } + rec.FormatStringLen := WordToLE(len); + { - Widestring flags, 1 = regular unicode LE string } + rec.FormatStringFlags := 1; + { - Copy the text characters into a buffer immediately after rec } + SetLength(buf, SizeOf(rec) + SizeOf(WideChar)*len); + Move(rec, buf[0], SizeOf(rec)); + Move(s[1], buf[SizeOf(rec)], len*SizeOf(WideChar)); + + { Write out } + AStream.WriteBuffer(buf[0], SizeOf(rec) + SizeOf(WideChar)*len); + + { Clean up } + SetLength(buf, 0); + +(* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_FORMAT)); AStream.WriteWord(WordToLE(2 + 2 + 1 + len * SizeOf(WideChar))); @@ -711,6 +745,7 @@ begin AStream.WriteByte(1); { - String data } AStream.WriteBuffer(WideStringToLE(s)[1], len * Sizeof(WideChar)); + *) end; {******************************************************************* diff --git a/components/fpspreadsheet/xlscommon.pas b/components/fpspreadsheet/xlscommon.pas index 181e8aefa..5c51ff4ae 100644 --- a/components/fpspreadsheet/xlscommon.pas +++ b/components/fpspreadsheet/xlscommon.pas @@ -1730,7 +1730,31 @@ end; different record structure. } procedure TsSpreadBIFFWriter.WriteBlank(AStream: TStream; const ARow, ACol: Cardinal; ACell: PCell); +type + TBlankRecord = packed record + RecordID: Word; + RecordSize: Word; + Row: Word; + Col: Word; + XFIndex: Word; + end; +var + rec: TBlankRecord; begin + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_BLANK); + rec.RecordSize := WordToLE(6); + + { Row and column index } + rec.Row := WordToLE(ARow); + rec.Col := WordToLE(ACol); + + { Index to XF record, according to formatting } + rec.XFIndex := WordToLE(FindXFIndex(ACell)); + + { Write out } + AStream.WriteBuffer(rec, SizeOf(rec)); + (* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_BLANK)); AStream.WriteWord(WordToLE(6)); @@ -1741,6 +1765,7 @@ begin { Index to XF record, according to formatting } WriteXFIndex(AStream, ACell); + *) end; procedure TsSpreadBIFFWriter.WriteCodepage(AStream: TStream; @@ -1770,10 +1795,42 @@ 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); +type + TColRecord = packed record + RecordID: Word; + RecordSize: Word; + StartCol: Word; + EndCol: Word; + ColWidth: Word; + XFIndex: Word; + OptionFlags: Word; + NotUsed: Word; + end; var + rec: TColRecord; w: Integer; begin if Assigned(ACol) then begin + { BIFF record header } + rec.RecordID := WordToLE(INT_EXCEL_ID_COLINFO); + rec.RecordSize := WordToLE(12); + + { Start and end column } + rec.StartCol := WordToLE(ACol^.Col); + rec.EndCol := WordToLE(ACol^.Col); + + { calculate width to be in units of 1/256 of pixel width of character "0" } + w := round(ACol^.Width * 256); + + rec.ColWidth := WordToLE(w); + rec.XFIndex := WordToLE(15); // Index of XF record, not used + rec.OptionFlags := 0; // not used + rec.NotUsed := 0; + + { Write out } + AStream.WriteBuffer(rec, SizeOf(rec)); + + (* { BIFF Record header } AStream.WriteWord(WordToLE(INT_EXCEL_ID_COLINFO)); // BIFF record header AStream.WriteWord(WordToLE(12)); // Record size @@ -1785,6 +1842,7 @@ begin AStream.WriteWord(15); // XF record, ignored AStream.WriteWord(0); // option flags, ignored AStream.WriteWord(0); // "not used" + *) end; end; diff --git a/components/fpspreadsheet/xlsxooxml.pas b/components/fpspreadsheet/xlsxooxml.pas index c6b63a934..a39fc91e6 100755 --- a/components/fpspreadsheet/xlsxooxml.pas +++ b/components/fpspreadsheet/xlsxooxml.pas @@ -1189,7 +1189,7 @@ end; procedure TsSpreadOOXMLWriter.WriteLabel(AStream: TStream; const ARow, ACol: Cardinal; const AValue: string; ACell: PCell); const - MaxBytes=32767; //limit for this format + MAXBYTES = 32767; //limit for this format var CellPosText: string; lStyleIndex: Cardinal; @@ -1201,18 +1201,17 @@ begin Unused(ARow, ACol, ACell); // Office 2007-2010 (at least) support no more characters in a cell; - if Length(AValue)>MaxBytes then - begin - TextTooLong:=true; - ResultingValue:=Copy(AValue,1,MaxBytes); //may chop off multicodepoint UTF8 characters but well... + if Length(AValue) > MAXBYTES then begin + TextTooLong := true; + ResultingValue := Copy(AValue, 1, MAXBYTES); //may chop off multicodepoint UTF8 characters but well... end else ResultingValue:=AValue; AppendToStream(FSSharedStrings, - '', Format( - '%s', [UTF8TextToXMLText(ResultingValue)]), - '' ); + '' + + '' + UTF8TextToXMLText(ResultingValue) + '' + + ''); CellPosText := TsWorksheet.CellPosToText(ARow, ACol); lStyleIndex := GetStyleIndex(ACell);