1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #pragma once
21 
22 #include "xltable.hxx"
23 
24 #include <vector>
25 #include "xladdress.hxx"
26 #include "xecontent.hxx"
27 #include "xerecord.hxx"
28 #include "xestyle.hxx"
29 #include "xlformula.hxx"
30 
31 #include <map>
32 #include <memory>
33 #include <unordered_map>
34 #include <o3tl/sorted_vector.hxx>
35 
36 class XclExtLst;
37 
38 /* ============================================================================
39 Export of cell tables including row and column description.
40 - Managing all used and formatted cells in a sheet.
41 - Row and column properties, i.e. width/height, visibility.
42 - Find default row formatting and default column formatting.
43 - Merged cell ranges.
44 ============================================================================ */
45 
46 // Helper records for cell records
47 
48 /** Represents a STRING record that contains the result of a string formula. */
49 class XclExpStringRec : public XclExpRecord
50 {
51 public:
52     explicit            XclExpStringRec( const XclExpRoot& rRoot, const OUString& rResult );
53 
54 private:
55     virtual void        WriteBody( XclExpStream& rStrm ) override;
56 
57 private:
58     XclExpStringRef     mxResult;
59 };
60 
61 // Additional records for special formula ranges
62 
63 /** Base record for additional range formula records (i.e. ARRAY, SHRFMLA). */
64 class XclExpRangeFmlaBase : public XclExpRecord
65 {
66 public:
67     /** Returns true, if the passed cell position is equal to own base position. */
68     bool                IsBasePos( sal_uInt16 nXclCol, sal_uInt32 nXclRow ) const;
69 
70     /** Derived classes create the token array for a corresponding FORMULA cell record. */
71     virtual XclTokenArrayRef CreateCellTokenArray( const XclExpRoot& rRoot ) const = 0;
72     /** Derived classes return true, if the own formula contains volatile functions. */
73     virtual bool        IsVolatile() const = 0;
74 
75 protected:
76     /** Constructs the record with a single cell. */
77     explicit            XclExpRangeFmlaBase(
78                             sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScAddress& rScPos );
79     /** Constructs the record with a cell range. */
80     explicit            XclExpRangeFmlaBase(
81                             sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScRange& rScRange );
82 
83     /** Extends the cell range to include the passed cell address. */
84     void                Extend( const ScAddress& rScPos );
85 
86     /** Writes the range address covered by this record. */
87     void                WriteRangeAddress( XclExpStream& rStrm ) const;
88 
89 protected:
90     XclRange            maXclRange;     /// Range described by this record.
91     XclAddress          maBaseXclPos;   /// Address of base cell (first FORMULA record).
92 };
93 
94 typedef rtl::Reference< XclExpRangeFmlaBase > XclExpRangeFmlaRef;
95 
96 // Array formulas =============================================================
97 
98 class ScTokenArray;
99 
100 /** Represents an ARRAY record that contains the token array of a matrix formula.
101 
102     An ARRAY record is stored following the first FORMULA record that is part
103     of a matrix formula. All FORMULA records of a matrix formula contain a
104     reference to the ARRAY record, while the ARRAY record contains the formula
105     token array used by all formulas.
106  */
107 class XclExpArray : public XclExpRangeFmlaBase
108 {
109 public:
110     explicit            XclExpArray( const XclTokenArrayRef& xTokArr, const ScRange& rScRange );
111 
112     /** Creates and returns the token array for a corresponding FORMULA cell record. */
113     virtual XclTokenArrayRef CreateCellTokenArray( const XclExpRoot& rRoot ) const override;
114     /** Returns true, if the array formula contains volatile functions. */
115     virtual bool        IsVolatile() const override;
116 
117 private:
118     virtual void        WriteBody( XclExpStream& rStrm ) override;
119 
120 private:
121     XclTokenArrayRef    mxTokArr;       /// The token array of a matrix formula.
122 };
123 
124 typedef rtl::Reference< XclExpArray > XclExpArrayRef;
125 
126 /** Caches all ARRAY records. */
127 class XclExpArrayBuffer : protected XclExpRoot
128 {
129 public:
130     explicit            XclExpArrayBuffer( const XclExpRoot& rRoot );
131 
132     /** Inserts a new ARRAY record into the buffer and returns it. */
133     XclExpArrayRef      CreateArray( const ScTokenArray& rScTokArr, const ScRange& rScRange );
134     /** Tries to find an ARRAY record that corresponds to an ocMatRef token. */
135     XclExpArrayRef FindArray( const ScTokenArray& rScTokArr, const ScAddress& rBasePos ) const;
136 
137 private:
138     typedef ::std::map< ScAddress, XclExpArrayRef > XclExpArrayMap;
139     XclExpArrayMap      maRecMap;       /// Map containing the ARRAY records.
140 };
141 
142 // Shared formulas ============================================================
143 
144 /** Represents a SHRFMLA record that contains the token array of a shared formula.
145 
146     A SHRFMLA record is stored following the first FORMULA record that is part
147     of a shared formula. All FORMULA records of a shared formula contain a
148     reference to the SHRFMLA record, while the SHRFMLA record contains the
149     formula token array used by all formulas.
150  */
151 class XclExpShrfmla : public XclExpRangeFmlaBase
152 {
153 public:
154     /** Creates a SHRFMLA record that consists of the passed cell address only. */
155     explicit            XclExpShrfmla( const XclTokenArrayRef& xTokArr, const ScAddress& rScPos );
156 
157     /** Extends the cell range to include the passed cell address. */
158     void                ExtendRange( const ScAddress& rScPos );
159 
160     /** Creates and returns the token array for a corresponding FORMULA cell record. */
161     virtual XclTokenArrayRef CreateCellTokenArray( const XclExpRoot& rRoot ) const override;
162     /** Returns true, if the shared formula contains volatile functions. */
163     virtual bool        IsVolatile() const override;
164 
165 private:
166     virtual void        WriteBody( XclExpStream& rStrm ) override;
167 
168 private:
169     XclTokenArrayRef    mxTokArr;       /// The token array of a shared formula.
170     sal_uInt8           mnUsedCount;    /// Number of FORMULA records referring to this record.
171 };
172 
173 typedef rtl::Reference< XclExpShrfmla > XclExpShrfmlaRef;
174 
175 /** Caches all SHRFMLA records and provides functions to update their ranges. */
176 class XclExpShrfmlaBuffer : protected XclExpRoot
177 {
178 public:
179     explicit            XclExpShrfmlaBuffer( const XclExpRoot& rRoot );
180 
181     /** Tries to create a new or to update an existing SHRFMLA record.
182         @return  An empty reference, if the passed token array does not contain
183             a shared formula. If the token array is a shared formula, this
184             function updates its cell range to include the passed cell position,
185             if there is a SHRFMLA record for the passed token array; otherwise
186             this function creates and returns a new SHRFMLA record. */
187     XclExpShrfmlaRef CreateOrExtendShrfmla( const ScFormulaCell& rScCell, const ScAddress& rScPos );
188 
189 private:
190     /**
191      * Check for presence of token that's not allowed in Excel's shared
192      * formula. Refer to the "SharedParsedFormula" section of [MS-XLS] spec
193      * for more info.
194      */
195     bool IsValidTokenArray( const ScTokenArray& rArray ) const;
196 
197     typedef std::unordered_map<const ScTokenArray*, XclExpShrfmlaRef> TokensType;
198     typedef o3tl::sorted_vector<const ScTokenArray*> BadTokenArraysType;
199 
200     TokensType         maRecMap;    /// Map containing the SHRFMLA records.
201     BadTokenArraysType maBadTokens; /// shared tokens we should *not* export as SHRFMLA
202 };
203 
204 // Multiple operations ========================================================
205 
206 /** Represents a TABLEOP record for a multiple operations range. */
207 class XclExpTableop : public XclExpRangeFmlaBase
208 {
209 public:
210     explicit            XclExpTableop( const ScAddress& rScPos,
211                             const XclMultipleOpRefs& rRefs, sal_uInt8 nScMode );
212 
213     /** Returns true, if the cell range has been extended to the passed position.
214         @descr  All references passed in rRefs must fit the ranges passed in the constructor. */
215     bool                TryExtend( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs );
216 
217     /** Finalizes the record. Tests on valid cell range and reference addresses. */
218     void                Finalize();
219 
220     /** Creates and returns the token array for a corresponding FORMULA cell record. */
221     virtual XclTokenArrayRef CreateCellTokenArray( const XclExpRoot& rRoot ) const override;
222     /** Returns true, if the multiple operations range is volatile. */
223     virtual bool        IsVolatile() const override;
224     /** Writes the record if it is valid. */
225     virtual void        Save( XclExpStream& rStrm ) override;
226 
227 private:
228     /** Returns true, if the passed cell position can be appended to this record. */
229     bool                IsAppendable( sal_uInt16 nXclCol, sal_uInt16 nXclRow ) const;
230 
231     /** Writes the contents of the TABLEOP record. */
232     virtual void        WriteBody( XclExpStream& rStrm ) override;
233 
234 private:
235     sal_uInt16          mnLastAppXclCol;/// Column index of last appended cell.
236     sal_uInt16          mnColInpXclCol; /// Column index of column input cell.
237     sal_uInt32          mnColInpXclRow; /// Row index of column input cell.
238     sal_uInt16          mnRowInpXclCol; /// Column index of row input cell.
239     sal_uInt32          mnRowInpXclRow; /// Row index of row input cell.
240     sal_uInt8           mnScMode;       /// Type of the multiple operation (Calc constant).
241     bool                mbValid;        /// true = Contains valid references.
242 };
243 
244 typedef rtl::Reference< XclExpTableop > XclExpTableopRef;
245 
246 /** Contains all created TABLEOP records and supports creating or updating them. */
247 class XclExpTableopBuffer : protected XclExpRoot
248 {
249 public:
250     explicit            XclExpTableopBuffer( const XclExpRoot& rRoot );
251 
252     /** Tries to update an existing or to create a new TABLEOP record.
253         @return  Reference to the TABLEOP record for this cell (existing or new),
254             or an empty reference, if rScTokArr does not contain a multiple
255             operations formula. */
256     XclExpTableopRef    CreateOrExtendTableop(
257                             const ScTokenArray& rScTokArr, const ScAddress& rScPos );
258 
259     /** Finalizes all contained TABLEOP records. */
260     void                Finalize();
261 
262 private:
263     /** Tries to create a new TABLEOP record, if rRefs contains valid references. */
264     XclExpTableopRef    TryCreate( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs );
265 
266 private:
267     XclExpRecordList< XclExpTableop > maTableopList;  /// List of all TABLEOP records.
268 };
269 
270 // Cell records
271 
272 /** The base class of all cell records. */
273 class XclExpCellBase : public XclExpRecord
274 {
275 public:
276     /** Returns the (first) address of the cell(s). */
GetXclPos() const277     const XclAddress& GetXclPos() const { return maXclPos; }
278     /** Returns the (first) Excel column index of the cell(s). */
GetXclCol() const279     sal_uInt16   GetXclCol() const { return maXclPos.mnCol; }
280     /** Returns the Excel row index of the cell. */
GetXclRow() const281     sal_uInt32   GetXclRow() const { return maXclPos.mnRow; }
282 
283     /** Derived classes return the column index of the last contained cell. */
284     virtual sal_uInt16  GetLastXclCol() const = 0;
285     /** Derived classes return the XF identifier of the first contained cell. */
286     virtual sal_uInt32  GetFirstXFId() const = 0;
287     /** Derived classes return true, if this record does not contain at least one valid cell. */
288     virtual bool        IsEmpty() const = 0;
289     /** Derived classes return whether the cell contains multi-line text. */
290     virtual bool        IsMultiLineText() const;
291 
292     /** Derived classes try to merge the contents of the passed cell to own data. */
293     virtual bool        TryMerge( const XclExpCellBase& rCell );
294     /** Derived classes convert the XF identifier(s) into the Excel XF index(es).
295         @param rXFIndexes  The converted XF index(es) are inserted here. */
296     virtual void        ConvertXFIndexes( const XclExpRoot& rRoot ) = 0;
297     /** Derived classes for blank cells insert the Excel XF index(es) into the passed vector. */
298     virtual void        GetBlankXFIndexes( ScfUInt16Vec& rXFIndexes ) const;
299     /** Derived classes for blank cells remove unused Excel XF index(es). */
300     virtual void        RemoveUnusedBlankCells( const ScfUInt16Vec& rXFIndexes );
301 
302 protected:
303     explicit            XclExpCellBase(
304                             sal_uInt16 nRecId, std::size_t nContSize, const XclAddress& rXclPos );
305 
306     /** Sets this record to a new column position. */
SetXclCol(sal_uInt16 nXclCol)307     void         SetXclCol( sal_uInt16 nXclCol ) { maXclPos.mnCol = nXclCol; }
308 
309 private:
310     XclAddress          maXclPos;       /// Address of the cell.
311 };
312 
313 typedef rtl::Reference< XclExpCellBase > XclExpCellRef;
314 
315 // Single cell records ========================================================
316 
317 /** Base class for all cell records not supporting multiple contents. */
318 class XclExpSingleCellBase : public XclExpCellBase
319 {
320 public:
321     /** Returns the last column, which is equal to the first column for single cells. */
322     virtual sal_uInt16  GetLastXclCol() const override;
323     /** Return the XF identifier of the cell. */
324     virtual sal_uInt32  GetFirstXFId() const override;
325     /** Returns true, if this record does not contain at least one valid cell. */
326     virtual bool        IsEmpty() const override;
327     /** Converts the XF identifier into the Excel XF index. */
328     virtual void        ConvertXFIndexes( const XclExpRoot& rRoot ) override;
329     /** Writes cell address, XF index, and calls WriteContents() for each cell. */
330     virtual void        Save( XclExpStream& rStrm ) override;
331 
332 protected:
333     explicit            XclExpSingleCellBase( sal_uInt16 nRecId, std::size_t nContSize,
334                             const XclAddress& rXclPos, sal_uInt32 nXFId );
335 
336     explicit            XclExpSingleCellBase( const XclExpRoot& rRoot,
337                             sal_uInt16 nRecId, std::size_t nContSize, const XclAddress& rXclPos,
338                             const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uInt32 nForcedXFId );
339 
SetContSize(std::size_t nContSize)340     void         SetContSize( std::size_t nContSize ) { mnContSize = nContSize; }
GetContSize() const341     std::size_t  GetContSize() const { return mnContSize; }
342 
SetXFId(sal_uInt32 nXFId)343     void         SetXFId( sal_uInt32 nXFId ) { maXFId.mnXFId = nXFId; }
GetXFId() const344     sal_uInt32   GetXFId() const { return maXFId.mnXFId; }
345 
346 private:
347     /** Writes cell address, XF index, and calls WriteContents() for each cell. */
348     virtual void        WriteBody( XclExpStream& rStrm ) override;
349     /** Derived classes write the contents of the specified cell (without XF index). */
350     virtual void        WriteContents( XclExpStream& rStrm ) = 0;
351 
352 private:
353     XclExpXFId          maXFId;         /// The XF identifier of the cell formatting.
354     std::size_t         mnContSize;     /// The size of the cell contents.
355 };
356 
357 /** Represents a NUMBER record that describes a cell with a double value. */
358 class XclExpNumberCell : public XclExpSingleCellBase
359 {
360 public:
361     explicit            XclExpNumberCell( const XclExpRoot& rRoot, const XclAddress& rXclPos,
362                             const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
363                             double fValue );
364 
365     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
366 private:
367     virtual void        WriteContents( XclExpStream& rStrm ) override;
368 
369 private:
370     double              mfValue;        /// The cell value.
371 };
372 
373 /** Represents a BOOLERR record that describes a cell with a Boolean value. */
374 class XclExpBooleanCell : public XclExpSingleCellBase
375 {
376 public:
377     explicit            XclExpBooleanCell( const XclExpRoot& rRoot, const XclAddress& rXclPos,
378                             const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
379                             bool bValue );
380 
381     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
382 private:
383     virtual void        WriteContents( XclExpStream& rStrm ) override;
384 
385 private:
386     bool                mbValue;        /// The cell value.
387 };
388 
389 class XclExpHyperlinkHelper;
390 class EditTextObject;
391 
392 /** Represents a text cell record.
393 
394     May contain a BIFF2-BIFF7 LABEL record for a simple string, or a BIFF2-BIFF7
395     RSTRING record for a formatted string, or a BIFF8 LABELSST string for any
396     string (simply stores a reference to the Shared String Table).
397  */
398 class XclExpLabelCell : public XclExpSingleCellBase
399 {
400 public:
401     /** Constructs the record from an unformatted Calc string cell. */
402     explicit            XclExpLabelCell( const XclExpRoot& rRoot, const XclAddress& rXclPos,
403                             const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
404                             const OUString& rStr );
405 
406     /** Constructs the record from a formatted Calc edit cell. */
407     explicit            XclExpLabelCell( const XclExpRoot& rRoot, const XclAddress& rXclPos,
408                             const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
409                             const EditTextObject* pEditText, XclExpHyperlinkHelper& rHlinkHelper );
410 
411     /** Returns true if the cell contains multi-line text. */
412     virtual bool        IsMultiLineText() const override;
413 
414     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
415 private:
416     /** Initializes the record contents. Called from constructors. */
417     void                Init( const XclExpRoot& rRoot,
418                             const ScPatternAttr* pPattern, XclExpStringRef const & xText );
419 
420     virtual void        WriteContents( XclExpStream& rStrm ) override;
421 
422 private:
423     XclExpStringRef     mxText;         /// The cell text.
424     sal_uInt32          mnSstIndex;     /// Index into Shared String Table (only used for BIFF8).
425     bool                mbLineBreak;    /// True = cell has automatic linebreaks enabled.
426 };
427 
428 class ScFormulaCell;
429 
430 /** Represents a FORMULA record that describes a cell with a formula. */
431 class XclExpFormulaCell : public XclExpSingleCellBase
432 {
433 public:
434     explicit            XclExpFormulaCell( const XclExpRoot& rRoot, const XclAddress& rXclPos,
435                             const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
436                             const ScFormulaCell& rScFmlaCell,
437                             XclExpArrayBuffer& rArrayBfr,
438                             XclExpShrfmlaBuffer& rShrfmlaBfr,
439                             XclExpTableopBuffer& rTableopBfr );
440 
441     /** Writes the FORMULA record and additional records related to the formula. */
442     virtual void        Save( XclExpStream& rStrm ) override;
443     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
444 
445 private:
446     virtual void        WriteContents( XclExpStream& rStrm ) override;
447 
448 private:
449     ScFormulaCell&      mrScFmlaCell;   /// The Calc formula cell.
450     XclTokenArrayRef    mxTokArr;       /// The token array of the formula.
451     XclExpRangeFmlaRef  mxAddRec;       /// Additional record for matrix/shared formulas.
452     XclExpRecordRef     mxStringRec;    /// STRING record for string result.
453 };
454 
455 // Multiple cell records ======================================================
456 
457 struct XclExpMultiXFId : public XclExpXFId
458 {
459     sal_uInt16          mnCount;        /// Number of XF identifiers.
460 
XclExpMultiXFIdXclExpMultiXFId461     explicit     XclExpMultiXFId( sal_uInt32 nXFId, sal_uInt16 nCount = 1 ) :
462                             XclExpXFId( nXFId ), mnCount( nCount ) {}
463 };
464 
465 /** Base class for all cell records supporting multiple contents. */
466 class XclExpMultiCellBase : public XclExpCellBase
467 {
468 public:
469     /** Returns the column index of the last cell this record describes. */
470     virtual sal_uInt16  GetLastXclCol() const override;
471     /** Return the XF identifier of the first contained cell. */
472     virtual sal_uInt32  GetFirstXFId() const override;
473     /** Returns true, if this record does not contain at least one valid cell. */
474     virtual bool        IsEmpty() const override;
475 
476     /** Convert all XF identifiers into the Excel XF indexes. */
477     virtual void        ConvertXFIndexes( const XclExpRoot& rRoot ) override;
478     /** Writes the record, calls WriteContents() for each contained cell.
479         @descr  May write several records, if unused XF indexes are contained. */
480     virtual void        Save( XclExpStream& rStrm ) override;
481     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
482 
483 protected:
484     explicit            XclExpMultiCellBase( sal_uInt16 nRecId, sal_uInt16 nMulRecId,
485                             std::size_t nContSize, const XclAddress& rXclPos );
486 
487     /** Returns the number of cells this record represents. */
488     sal_uInt16          GetCellCount() const;
489 
490     /** Appends the passed XF identifier nCount times to the list of XF identifiers. */
491     void                AppendXFId( const XclExpMultiXFId& rXFId );
492     /** Appends the passed cell format nCount times to the list of XF identifiers. */
493     void                AppendXFId( const XclExpRoot& rRoot,
494                             const ScPatternAttr* pPattern, sal_uInt16 nScript,
495                             sal_uInt32 nForcedXFId, sal_uInt16 nCount = 1 );
496 
497     /** Tries to merge the XF ID list of the passed cell with the own list. */
498     bool                TryMergeXFIds( const XclExpMultiCellBase& rCell );
499     /** Inserts the Excel XF index(es) into the passed vector. */
500     void                GetXFIndexes( ScfUInt16Vec& rXFIndexes ) const;
501 
502     /** Removes unused Excel XF index(es).
503         @param rXFIndexes  Specifies which XF indexes are used. */
504     void                RemoveUnusedXFIndexes( const ScfUInt16Vec& rXFIndexes );
505 
506 private:
507     /** Derived classes write the remaining contents of the specified cell (without XF index).
508         @param nRelCol  Relative column index (starts with 0 for first cell of this record). */
509     virtual void        WriteContents( XclExpStream& rStrm, sal_uInt16 nRelCol ) = 0;
510     virtual void        WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 nRelCol ) = 0;
511 
512 private:
513     typedef ::std::vector< XclExpMultiXFId > XclExpMultiXFIdDeq;
514 
515     sal_uInt16          mnMulRecId;     /// Record ID for multiple record variant.
516     std::size_t         mnContSize;     /// Data size of contents for one cell
517     XclExpMultiXFIdDeq  maXFIds;        /// The XF identifiers of the cell formatting.
518 };
519 
520 /** Represents a BLANK or MULBLANK record that describes empty but formatted cells. */
521 class XclExpBlankCell : public XclExpMultiCellBase
522 {
523 public:
524     explicit            XclExpBlankCell( const XclAddress& rXclPos, const XclExpMultiXFId& rXFId );
525 
526     explicit            XclExpBlankCell( const XclExpRoot& rRoot,
527                             const XclAddress& rXclPos, sal_uInt16 nLastXclCol,
528                             const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId );
529 
530     /** Tries to merge the contents of the passed cell to own data. */
531     virtual bool        TryMerge( const XclExpCellBase& rCell ) override;
532     /** Inserts the Excel XF index(es) into the passed vector. */
533     virtual void        GetBlankXFIndexes( ScfUInt16Vec& rXFIndexes ) const override;
534     /** Tries to remove unused Excel XF index(es). */
535     virtual void        RemoveUnusedBlankCells( const ScfUInt16Vec& rXFIndexes ) override;
536 
537 private:
538     /** Writes the remaining contents of the specified cell (without XF index). */
539     virtual void        WriteContents( XclExpStream& rStrm, sal_uInt16 nRelCol ) override;
540     virtual void        WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 nRelCol ) override;
541 };
542 
543 /** Represents an RK or MULRK record that describes cells with a compressed double values. */
544 class XclExpRkCell : public XclExpMultiCellBase
545 {
546 public:
547     explicit            XclExpRkCell( const XclExpRoot& rRoot, const XclAddress& rXclPos,
548                             const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
549                             sal_Int32 nRkValue );
550 
551     /** Tries to merge the contents of the passed cell to own data. */
552     virtual bool        TryMerge( const XclExpCellBase& rCell ) override;
553 
554 private:
555     /** Writes the remaining contents of the specified cell (without XF index). */
556     virtual void        WriteContents( XclExpStream& rStrm, sal_uInt16 nRelCol ) override;
557     virtual void        WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 nRelCol ) override;
558 
559 private:
560     ScfInt32Vec         maRkValues;     /// The cell values.
561 };
562 
563 // Rows and Columns
564 
565 class ScOutlineArray;
566 
567 /** Base class for buffers containing row or column outline data. */
568 class XclExpOutlineBuffer
569 {
570 public:
571     /** Returns true, if a collapsed group ends at the last processed position. */
IsCollapsed() const572     bool         IsCollapsed() const { return mbCurrCollapse; }
573     /** Returns the highest level of an open group at the last processed position. */
GetLevel() const574     sal_uInt8    GetLevel() const { return ::std::min( mnCurrLevel, EXC_OUTLINE_MAX ); }
575 
576 protected:
577     /** Constructs the outline buffer.
578         @param bRows  true = Process row outline array; false = Process column outline array. */
579     explicit            XclExpOutlineBuffer( const XclExpRoot& rRoot, bool bRows );
580 
581     /** Updates the current state by processing the settings at the passed Calc position. */
582     void                UpdateColRow( SCCOLROW nScPos );
583 
584 private:
585     /** Data about an outline level. */
586     struct XclExpLevelInfo
587     {
588         SCCOLROW            mnScEndPos;         /// The end position of a group in a level.
589         bool                mbHidden;           /// true = Group in this level is hidden.
XclExpLevelInfoXclExpOutlineBuffer::XclExpLevelInfo590         explicit     XclExpLevelInfo() : mnScEndPos( 0 ), mbHidden( false ) {}
591     };
592 
593     const ScOutlineArray* mpScOLArray;      /// Pointer to Calc outline array.
594     std::vector< XclExpLevelInfo >
595                         maLevelInfos;       /// Info for current row and all levels.
596     sal_uInt8           mnCurrLevel;        /// Highest level of an open group for current position.
597     bool                mbCurrCollapse;     /// true = Collapsed group ends at current position.
598 };
599 
600 /** The outline buffer for column outlines. */
601 class XclExpColOutlineBuffer : public XclExpOutlineBuffer
602 {
603 public:
XclExpColOutlineBuffer(const XclExpRoot & rRoot)604     explicit     XclExpColOutlineBuffer( const XclExpRoot& rRoot ) :
605                             XclExpOutlineBuffer( rRoot, false ) {}
606 
607     /** Updates the current state by processing the settings of the passed Calc column. */
Update(SCCOL nScCol)608     void         Update( SCCOL nScCol )
609                             { UpdateColRow( static_cast< SCCOLROW >( nScCol ) ); }
610 };
611 
612 /** The outline buffer for row outlines. */
613 class XclExpRowOutlineBuffer : public XclExpOutlineBuffer
614 {
615 public:
XclExpRowOutlineBuffer(const XclExpRoot & rRoot)616     explicit     XclExpRowOutlineBuffer( const XclExpRoot& rRoot ) :
617                             XclExpOutlineBuffer( rRoot, true ) {}
618 
619     /** Updates the current state by processing the settings of the passed Calc row. */
Update(SCROW nScRow)620     void         Update( SCROW nScRow )
621                             { UpdateColRow( static_cast< SCCOLROW >( nScRow ) ); }
622 };
623 
624 /** Represents a GUTS record containing the level count of row and column outlines. */
625 class XclExpGuts : public XclExpRecord
626 {
627 public:
628     explicit            XclExpGuts( const XclExpRoot& rRoot );
629 
630 private:
631     virtual void        WriteBody( XclExpStream& rStrm ) override;
632 
633 private:
634     sal_uInt16          mnColLevels;    /// Number of visible column outline levels.
635     sal_uInt16          mnColWidth;     /// Width of column outline area (pixels).
636     sal_uInt16          mnRowLevels;    /// Number of visible row outline levels.
637     sal_uInt16          mnRowWidth;     /// Width of row outline area (pixels).
638 };
639 
640 /** Represents a DIMENSIONS record containing the used area of a sheet. */
641 class XclExpDimensions : public XclExpRecord
642 {
643 public:
644     explicit            XclExpDimensions( const XclExpRoot& rRoot );
645 
646     /** Sets the used area to the record. */
647     void                SetDimensions(
648                             sal_uInt16 nFirstUsedXclCol, sal_uInt32 nFirstUsedXclRow,
649                             sal_uInt16 nFirstFreeXclCol, sal_uInt32 nFirstFreeXclRow );
650 
651     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
652 private:
653     /** Writes the contents of the DIMENSIONS record. */
654     virtual void        WriteBody( XclExpStream& rStrm ) override;
655 
656 private:
657     const XclExpRoot&   mrRoot;
658     sal_uInt32          mnFirstUsedXclRow;  /// First used row.
659     sal_uInt32          mnFirstFreeXclRow;  /// First unused row after used area.
660     sal_uInt16          mnFirstUsedXclCol;  /// First used column.
661     sal_uInt16          mnFirstFreeXclCol;  /// First free column after used area.
662 };
663 
664 /** Represents the DEFCOLWIDTH record containing the default column width of a sheet.
665 
666     Excel stores the default column width in entire character widths of the '0'
667     character using the application default font (i.e. the default width is 10,
668     if the '0' character fits 10 times into a cell in a column with default
669     width.
670 
671     Half of character width is reserved for non character display.
672     It is margin padding (two on each side) and padding for the gridlines.
673 
674     The IsDefWidth() function returns true, if the passed width (measured in
675     1/256 of the width of the '0' character) could be converted exactly to the
676     default width. If the passed width is rounded up or down to get the default
677     width, the function returns false.
678  */
679 class XclExpDefcolwidth : public XclExpDoubleRecord, protected XclExpRoot
680 {
681 public:
682     explicit            XclExpDefcolwidth( const XclExpRoot& rRoot );
683 
684     /** Returns true, if the own default width exactly matches the passed width. */
685     bool                IsDefWidth( sal_uInt16 nXclColWidth ) const;
686 
687     /** Sets the passed column width (in 1/256 character width) as default width. */
688     void                SetDefWidth( sal_uInt16 nXclColWidth, bool bXLS );
689 
690     virtual void        Save(XclExpStream& rStrm) override;
691 };
692 
693 /** Contains the column settings for a range of columns.
694 
695     After construction the record contains a temporary XF identifier returned
696     from the XF buffer. After creating the entire Excel document in memory, the
697     ConvertXFIndexes() function converts it into the real Excel XF index.
698  */
699 class XclExpColinfo : public XclExpRecord, protected XclExpRoot
700 {
701 public:
702     /** Constructs the record with the settings in the Calc document. */
703     explicit            XclExpColinfo( const XclExpRoot& rRoot,
704                             SCCOL nScCol, SCROW nLastScRow,
705                             XclExpColOutlineBuffer& rOutlineBfr );
706 
707     /** Converts the XF identifier into the Excel XF index. */
708     void                ConvertXFIndexes();
709 
710     /** Tries to merge this record with the passed record.
711         @descr  Possible, if passed record directly follows this record and has equal contents.
712         @return  true = This record is equal to passed record and has been updated. */
713     bool                TryMerge( const XclExpColinfo& rColInfo );
714 
715     /** Returns the Excel width of the column(s). */
GetColWidth() const716     sal_uInt16   GetColWidth() const { return mnWidth; }
717     /** Returns the final Excel XF index of the column(s). */
GetXFIndex() const718     sal_uInt16   GetXFIndex() const { return maXFId.mnXFIndex; }
719     /** Returns the number of columns represented by this record. */
GetColCount() const720     sal_uInt16   GetColCount() const { return mnLastXclCol - mnFirstXclCol + 1; }
721 
722     /** Returns true, if the column has default format and width. Also sets mbCustomWidth */
723     bool                IsDefault( const XclExpDefcolwidth& rDefColWidth );
724 
725     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
726 
727 private:
728     /** Writes the contents of this COLINFO record. */
729     virtual void        WriteBody( XclExpStream& rStrm ) override;
730 
731 private:
732     XclExpXFId          maXFId;             /// The XF identifier for column default format.
733     bool                mbCustomWidth;      /// True = Column width is different from default width
734     sal_uInt16          mnWidth;            /// Excel width of the column.
735     sal_uInt16          mnScWidth;          /// Calc width of the column.
736     sal_uInt16          mnFlags;            /// Additional column flags.
737     sal_uInt8           mnOutlineLevel;     /// Outline Level of column (for OOXML)
738     sal_uInt16          mnFirstXclCol;      /// Index to first column.
739     sal_uInt16          mnLastXclCol;       /// Index to last column.
740 };
741 
742 /** Contains COLINFO records for all columns of a Calc sheet.
743 
744     On construction one COLINFO record per column is created. After creating
745     the entire Excel document in memory, the ConvertXFIndexes() function converts
746     all temporary XF identifiers into real Excel XF indexes and merges all equal
747     COLINFO records together.
748  */
749 class XclExpColinfoBuffer : public XclExpRecordBase, protected XclExpRoot
750 {
751 public:
752     explicit            XclExpColinfoBuffer( const XclExpRoot& rRoot );
753 
754     /** Initializes the buffer: finds settings and formatting of all columns.
755         @param nLastScRow  Last row used to find default formatting. */
756     void                Initialize( SCROW nLastScRow );
757     /** Converts the XF identifiers into the Excel XF indexes and merges equal columns.
758         @param rXFIndexes  Returns the final XF indexes of all columns. */
759     void                Finalize( ScfUInt16Vec& rXFIndexes, bool bXLS );
760 
761     /** Writes all COLINFO records of this buffer. */
762     virtual void        Save( XclExpStream& rStrm ) override;
763     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
GetHighestOutlineLevel() const764     sal_uInt8           GetHighestOutlineLevel() const { return mnHighestOutlineLevel; }
GetDefColWidth() const765     double              GetDefColWidth() const { return maDefcolwidth.GetValue(); }
766 
767 private:
768     typedef XclExpRecordList< XclExpColinfo >   XclExpColinfoList;
769     typedef XclExpColinfoList::RecordRefType    XclExpColinfoRef;
770 
771     XclExpColinfoList   maColInfos;         /// List of COLINFO records.
772     XclExpDefcolwidth   maDefcolwidth;      /// The DEFCOLWIDTH record.
773     XclExpColOutlineBuffer maOutlineBfr;    /// Buffer for column outline groups.
774     sal_uInt8           mnHighestOutlineLevel; /// Highest number of outline levels for columns in sheet.
775 };
776 
777 class XclExpRow;
778 
779 /** Contains all possible default row settings. */
780 struct XclExpDefaultRowData
781 {
782     sal_uInt16          mnFlags;            /// Default flags for unspecified rows.
783     sal_uInt16          mnHeight;           /// Default height for unspecified rows.
784 
785     explicit            XclExpDefaultRowData();
786     explicit            XclExpDefaultRowData( const XclExpRow& rRow );
787 
788     /** Returns true, if rows are hidden by default. */
IsHiddenXclExpDefaultRowData789     bool         IsHidden() const { return ::get_flag( mnFlags, EXC_DEFROW_HIDDEN ); }
790     /** Returns true, if the rows have a manually set height by default. */
IsUnsyncedXclExpDefaultRowData791     bool         IsUnsynced() const { return ::get_flag( mnFlags, EXC_DEFROW_UNSYNCED ); }
792 };
793 
794 /** Represents a DEFROWHEIGHT record containing default format for unused rows. */
795 class XclExpDefrowheight : public XclExpRecord
796 {
797 public:
798     explicit            XclExpDefrowheight();
799 
800     /** Sets the passed default data as current record contents. */
801     void                SetDefaultData( const XclExpDefaultRowData& rDefData );
GetDefaultData()802     XclExpDefaultRowData& GetDefaultData() { return maDefData; }
803 private:
804     /** Writes the contents of the record. */
805     virtual void        WriteBody( XclExpStream& rStrm ) override;
806 
807 private:
808     XclExpDefaultRowData maDefData;         /// Record data.
809 };
810 
811 /** Represents a ROW record and additionally contains all cells records of a row.
812 
813     This class contains all cell records of a row in a spreadsheet. There are 2
814     cell records in Excel that support storing a range of cells in one record
815     (MULBLANK for multiple blank cells, and MULRK for multiple RK values). The
816     insertion functions try to merge a new inserted cell with existing
817     neighbors, if this is supported by the current type of cell record.
818 
819     The Finalize() function converts the XF identifiers of all cell records to
820     the final Excel XF indexes. Then a default
821  */
822 class XclExpRow : public XclExpRecord, protected XclExpRoot
823 {
824 public:
825     /** Constructs the ROW record and converts the Calc row settings.
826         @param bAlwaysEmpty  true = This row will not be filled with blank cells
827             in the Finalize() function. */
828     explicit            XclExpRow( const XclExpRoot& rRoot, sal_uInt32 nXclRow,
829                             XclExpRowOutlineBuffer& rOutlineBfr, bool bAlwaysEmpty, bool bHidden, sal_uInt16 nHeight );
830 
831     /** Returns the excel row index of this ROW record. */
GetXclRow() const832     sal_uInt32   GetXclRow() const { return mnXclRow; }
833     /** Returns the height of the row in twips. */
GetHeight() const834     sal_uInt16   GetHeight() const { return mnHeight; }
835     /** Returns true, if this row does not contain at least one valid cell. */
IsEmpty() const836     bool         IsEmpty() const { return maCellList.IsEmpty(); }
837     /** Returns true, if this row is hidden. */
IsHidden() const838     bool         IsHidden() const { return ::get_flag( mnFlags, EXC_ROW_HIDDEN ); }
839     /** Returns true, if this row contains a manually set height. */
IsUnsynced() const840     bool         IsUnsynced() const { return ::get_flag( mnFlags, EXC_ROW_UNSYNCED ); }
841     /** Returns true, if this row is enabled (will be exported). */
IsEnabled() const842     bool         IsEnabled() const { return mbEnabled; }
843 
844     /** Appends the passed cell object to this row. */
845     void                AppendCell( XclExpCellRef const & xCell, bool bIsMergedBase );
846 
847     /** Converts all XF identifiers into the Excel XF indexes. */
848     void                Finalize( const ScfUInt16Vec& rColXFIndexes,
849                                   bool bUpdateProgress );
850 
851     /** Returns the column index of the first used cell in this row.
852         @descr  This function can only be called after Finalize(). */
853     sal_uInt16          GetFirstUsedXclCol() const;
854     /** Returns the column index of the first unused cell following all used cells in this row.
855         @descr  This function can only be called after Finalize(). */
856     sal_uInt16          GetFirstFreeXclCol() const;
857 
858     /** Returns true, if this row may be omitted by using the DEFROWHEIGHT record.
859         @descr  A row may be omitted, if it does not contain any cell or
860         explicit default cell formatting, and is not part of an outline.
861         This function can only be called after Finalize(). */
862     bool                IsDefaultable() const;
863     /** Disables this row, if it is defaultable and has the passed default format.
864         @descr  Disabled rows will not be saved.
865             This function can only be called after Finalize(). */
866     void                DisableIfDefault( const XclExpDefaultRowData& rDefRowData );
867 
868     /** Writes all cell records of this row. */
869     void                WriteCellList( XclExpStream& rStrm );
870 
871     /** Writes the ROW record if the row is not disabled (see DisableIfDefault() function). */
872     virtual void        Save( XclExpStream& rStrm ) override;
873     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
874 
GetXclRowRpt() const875     sal_uInt32   GetXclRowRpt() const { return mnXclRowRpt; }
SetXclRowRpt(sal_uInt32 nRpt)876     void         SetXclRowRpt( sal_uInt32 nRpt ){ mnXclRowRpt = nRpt; }
877 private:
878     /** Inserts a cell at the specified list position, tries to merge with neighbors. */
879     void                InsertCell( XclExpCellRef xCell, size_t nPos, bool bIsMergedBase );
880 
881     /** Writes the contents of the ROW record. */
882     virtual void        WriteBody( XclExpStream& rStrm ) override;
883 
884 private:
885     XclExpRecordList< XclExpCellBase >
886                         maCellList;         /// List of cell records for this row.
887     sal_uInt32          mnXclRow;           /// Excel row index of this row.
888     sal_uInt16          mnHeight;           /// Row height in twips.
889     sal_uInt16          mnFlags;            /// Flags for the ROW record.
890     sal_uInt16          mnXFIndex;          /// Default row formatting.
891     sal_uInt8           mnOutlineLevel;     /// Outline Level of row (for OOXML)
892     sal_uInt32          mnXclRowRpt;
893     sal_uInt32          mnCurrentRow;
894     bool                mbAlwaysEmpty;      /// true = Do not add blank cells in Finalize().
895     bool                mbEnabled;          /// true = Write this ROW record.
896 };
897 
898 /** Collects all rows which contain all cells of a sheet.
899 
900     This row buffer automatically creates ROW records when cells are inserted
901     with the AppendCell() function. It is possible to force creation of more
902     ROW records with the CreateRows() function. In both cases, all preceding
903     missing ROW records are inserted too.
904  */
905 class XclExpRowBuffer : public XclExpRecordBase, protected XclExpRoot
906 {
907 public:
908     explicit            XclExpRowBuffer( const XclExpRoot& rRoot );
909 
910     /** Appends the passed cell object to the row that the cell specifies. */
911     void                AppendCell( XclExpCellRef const & xCell, bool bIsMergedBase );
912     /** Forces insertion of all ROW records before the passed row. */
913     void                CreateRows( SCROW nFirstFreeScRow );
914 
915     /** Converts all XF identifiers into the Excel XF indexes and calculates default formats.
916         @param rDefRowData  (out-param) The default row format is returned here.
917         @param rColXFIndexes  The column default XF indexes. */
918     void                Finalize( XclExpDefaultRowData& rDefRowData, const ScfUInt16Vec& rColXFIndexes );
919 
920     /** Writes the DIMENSIONS record, all ROW records and all cell records. */
921     virtual void        Save( XclExpStream& rStrm ) override;
922     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
923 
GetDimensions()924     XclExpDimensions&   GetDimensions() { return maDimensions; }
GetHighestOutlineLevel() const925     sal_uInt8           GetHighestOutlineLevel() const { return mnHighestOutlineLevel; }
926 
927 private:
928     /** Returns access to the specified ROW record. Inserts preceding missing ROW records.
929         @param bRowAlwaysEmpty  true = Created rows will not be filled with blank cells
930             in the XclExpRow::Finalize() function. */
931     XclExpRow&          GetOrCreateRow( sal_uInt32 nXclRow, bool bRowAlwaysEmpty );
932 
933 private:
934     typedef std::shared_ptr<XclExpRow>  RowRef;
935     typedef ::std::map<sal_uInt32, RowRef>  RowMap;
936 
937     RowMap              maRowMap;
938     XclExpRowOutlineBuffer maOutlineBfr;    /// Buffer for row outline groups.
939     XclExpDimensions    maDimensions;       /// DIMENSIONS record for used area.
940     sal_uInt8           mnHighestOutlineLevel; /// Highest number of outline levels for rows in sheet.
941 };
942 
943 // Cell Table
944 
945 class XclExpNote;
946 class XclExpMergedcells;
947 class XclExpHyperlink;
948 class XclExpDval;
949 
950 /** This class contains the cell contents and more of an entire sheet.
951 
952     The cell table includes the settings and default formatting of all columns,
953     the settings and default formatting of all used rows, and the contents of
954     all cells of one sheet in a spreadsheet document.
955 
956     The constructor does all the work creating the cell table. It reads the
957     Calc sheet and converts all columns, rows, and cells to Excel record data.
958     Additionally, hyperlink records, note records, additional records for
959     formula cells, data validation records, and outline records are created.
960 
961     The Finalize() function does even more work. It calculates default column
962     settings and removes column records that are equal to this default. The
963     same happens with rows: A default format is calculated for each row, and
964     all blank cells in this row that have the same format are removed. Then,
965     the most used row settings are calculated, and all empty rows that have the
966     same settings are removed too.
967 
968     Records that are not stored inside the cell table area in an Excel file
969     (i.e. DEFROWHEIGHT record, NOTE records, MERGEDCELLS record, HLINK records,
970     DVAL and DV records for data validation) can be accessed with the function
971     CreateRecord(). It returns the reference to the respective record (or
972     record list) which can be inserted into a record list.
973  */
974 class XclExpCellTable : public XclExpRecordBase, protected XclExpRoot
975 {
976 public:
977     explicit            XclExpCellTable( const XclExpRoot& rRoot );
978 
979     /** Converts all XF identifiers into the Excel XF indexes and calculates default formats. */
980     void                Finalize(bool bXLS);
981 
982     /** Returns the reference to an internal record specified by the passed record id.
983         @param nRecId  The record identifier that specifies which record is
984             returned. Possible values are: EXC_ID_DEFROWHEIGHT, EXC_ID_NOTE,
985             EXC_ID_MERGEDCELLS, EXC_ID_HLINK, EXC_ID_DVAL. */
986     XclExpRecordRef     CreateRecord( sal_uInt16 nRecId ) const;
987     /** Saves the entire cell table. */
988     virtual void        Save( XclExpStream& rStrm ) override;
989     virtual void        SaveXml( XclExpXmlStream& rStrm ) override;
990 
991 private:
992     typedef XclExpRecordList< XclExpNote >      XclExpNoteList;
993     typedef XclExpRecordList< XclExpHyperlink > XclExpHyperlinkList;
994 
995     typedef rtl::Reference< XclExpDefrowheight >       XclExpDefrowhRef;
996     typedef rtl::Reference< XclExpNoteList >           XclExpNoteListRef;
997     typedef rtl::Reference< XclExpMergedcells >        XclExpMergedcellsRef;
998     typedef rtl::Reference< XclExpHyperlinkList >      XclExpHyperlinkRef;
999     typedef rtl::Reference< XclExpDval >               XclExpDvalRef;
1000     typedef rtl::Reference< XclExtLst >                XclExtLstRef;
1001 
1002     XclExpColinfoBuffer maColInfoBfr;       /// Buffer for column formatting.
1003     XclExpRowBuffer     maRowBfr;           /// Rows and cell records.
1004     XclExpArrayBuffer   maArrayBfr;         /// Buffer for ARRAY records.
1005     XclExpShrfmlaBuffer maShrfmlaBfr;       /// Buffer for SHRFMLA records.
1006     XclExpTableopBuffer maTableopBfr;       /// Buffer for TABLEOP records.
1007     XclExpDefrowhRef    mxDefrowheight;     /// DEFROWHEIGHT record for default row format.
1008     XclExpRecordRef     mxGuts;             /// GUTS record for outline areas.
1009     XclExpNoteListRef   mxNoteList;         /// List of NOTE records.
1010     XclExpMergedcellsRef mxMergedcells;     /// MERGEDCELLS record for merged cell ranges.
1011     XclExpHyperlinkRef  mxHyperlinkList;    /// List of HLINK records.
1012     XclExpDvalRef       mxDval;             /// Data validation with DVAL and DV records.
1013     XclExtLstRef        mxExtLst;
1014 };
1015 
1016 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1017