1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <tokstack.hxx>
21 #include <scmatrix.hxx>
23 #include <svl/sharedstringpool.hxx>
24 #include <sal/log.hxx>
25 #include <osl/diagnose.h>
30 const sal_uInt16
TokenPool::nScTokenOff
= 8192;
32 TokenStack::TokenStack( )
33 : pStack( new TokenId
[ nSize
] )
38 TokenStack::~TokenStack()
42 // !ATTENTION!": to the outside the numbering starts with 1!
43 // !ATTENTION!": SC-Token are stored with an offset nScTokenOff
44 // -> to distinguish from other tokens
46 TokenPool::TokenPool( svl::SharedStringPool
& rSPool
) :
49 // pool for Id-sequences
51 pP_Id
.reset( new sal_uInt16
[ nP_Id
] );
55 pElement
.reset( new sal_uInt16
[ nElement
] );
56 pType
.reset( new E_TYPE
[ nElement
] );
57 pSize
.reset( new sal_uInt16
[ nElement
] );
61 ppP_Matrix
.reset( new ScMatrix
*[ nP_Matrix
] );
62 memset( ppP_Matrix
.get(), 0, sizeof( ScMatrix
* ) * nP_Matrix
);
67 TokenPool::~TokenPool()
72 /** Returns the new number of elements, or 0 if overflow. */
73 static sal_uInt16
lcl_canGrow( sal_uInt16 nOld
)
77 if (nOld
== SAL_MAX_UINT16
)
79 sal_uInt32 nNew
= ::std::max( static_cast<sal_uInt32
>(nOld
) * 2,
80 static_cast<sal_uInt32
>(nOld
) + 1);
81 if (nNew
> SAL_MAX_UINT16
)
82 nNew
= SAL_MAX_UINT16
;
85 return static_cast<sal_uInt16
>(nNew
);
88 bool TokenPool::GrowId()
90 sal_uInt16 nP_IdNew
= lcl_canGrow( nP_Id
);
94 sal_uInt16
* pP_IdNew
= new (::std::nothrow
) sal_uInt16
[ nP_IdNew
];
98 for( sal_uInt16 nL
= 0 ; nL
< nP_Id
; nL
++ )
99 pP_IdNew
[ nL
] = pP_Id
[ nL
];
103 pP_Id
.reset( pP_IdNew
);
107 bool TokenPool::CheckElementOrGrow()
109 // Last possible ID to be assigned somewhere is nElementCurrent+1
110 if (nElementCurrent
+ 1 == nScTokenOff
- 1)
112 SAL_WARN("sc.filter","TokenPool::CheckElementOrGrow - last possible ID " << nElementCurrent
+1);
116 if (nElementCurrent
>= nElement
)
117 return GrowElement();
122 bool TokenPool::GrowElement()
124 sal_uInt16 nElementNew
= lcl_canGrow( nElement
);
128 std::unique_ptr
<sal_uInt16
[]> pElementNew(new (::std::nothrow
) sal_uInt16
[ nElementNew
]);
129 std::unique_ptr
<E_TYPE
[]> pTypeNew(new (::std::nothrow
) E_TYPE
[ nElementNew
]);
130 std::unique_ptr
<sal_uInt16
[]> pSizeNew(new (::std::nothrow
) sal_uInt16
[ nElementNew
]);
131 if (!pElementNew
|| !pTypeNew
|| !pSizeNew
)
136 for( sal_uInt16 nL
= 0 ; nL
< nElement
; nL
++ )
138 pElementNew
[ nL
] = pElement
[ nL
];
139 pTypeNew
[ nL
] = pType
[ nL
];
140 pSizeNew
[ nL
] = pSize
[ nL
];
143 nElement
= nElementNew
;
145 pElement
= std::move( pElementNew
);
146 pType
= std::move( pTypeNew
);
147 pSize
= std::move( pSizeNew
);
151 bool TokenPool::GrowMatrix()
153 sal_uInt16 nNewSize
= lcl_canGrow( nP_Matrix
);
157 ScMatrix
** ppNew
= new (::std::nothrow
) ScMatrix
*[ nNewSize
];
161 memset( ppNew
, 0, sizeof( ScMatrix
* ) * nNewSize
);
162 for( sal_uInt16 nL
= 0 ; nL
< nP_Matrix
; nL
++ )
163 ppNew
[ nL
] = ppP_Matrix
[ nL
];
165 ppP_Matrix
.reset( ppNew
);
166 nP_Matrix
= nNewSize
;
170 bool TokenPool::GetElement( const sal_uInt16 nId
, ScTokenArray
* pScToken
)
172 if (nId
>= nElementCurrent
)
174 SAL_WARN("sc.filter","TokenPool::GetElement - Id too large, " << nId
<< " >= " << nElementCurrent
);
179 if( pType
[ nId
] == T_Id
)
180 bRet
= GetElementRek( nId
, pScToken
);
183 switch( pType
[ nId
] )
187 sal_uInt16 n
= pElement
[ nId
];
188 auto* p
= ppP_Str
.getIfInRange( n
);
190 pScToken
->AddString(mrStringPool
.intern(**p
));
197 sal_uInt16 n
= pElement
[ nId
];
198 if (n
< pP_Dbl
.m_writemark
)
199 pScToken
->AddDouble( pP_Dbl
[ n
] );
206 /* TODO: in case we had FormulaTokenArray::AddError() */
209 sal_uInt16 n
= pElement
[ nId
];
211 pScToken
->AddError( pP_Err
[ n
] );
218 sal_uInt16 n
= pElement
[ nId
];
219 auto p
= ppP_RefTr
.getIfInRange(n
);
221 pScToken
->AddSingleReference( **p
);
228 sal_uInt16 n
= pElement
[ nId
];
229 if (n
< ppP_RefTr
.m_writemark
&& ppP_RefTr
[ n
] && n
+1 < ppP_RefTr
.m_writemark
&& ppP_RefTr
[ n
+ 1 ])
231 ScComplexRefData aScComplexRefData
;
232 aScComplexRefData
.Ref1
= *ppP_RefTr
[ n
];
233 aScComplexRefData
.Ref2
= *ppP_RefTr
[ n
+ 1 ];
234 pScToken
->AddDoubleReference( aScComplexRefData
);
242 sal_uInt16 n
= pElement
[nId
];
243 if (n
< maRangeNames
.size())
245 const RangeName
& r
= maRangeNames
[n
];
246 pScToken
->AddRangeName(r
.mnIndex
, r
.mnSheet
);
252 sal_uInt16 n
= pElement
[ nId
];
253 auto p
= ppP_Ext
.getIfInRange(n
);
257 if( (*p
)->eId
== ocEuroConvert
)
258 pScToken
->AddOpCode( (*p
)->eId
);
260 pScToken
->AddExternal( (*p
)->aText
, (*p
)->eId
);
268 sal_uInt16 n
= pElement
[ nId
];
269 auto p
= ppP_Nlf
.getIfInRange(n
);
272 pScToken
->AddColRowName( **p
);
279 sal_uInt16 n
= pElement
[ nId
];
280 ScMatrix
* p
= ( n
< nP_Matrix
)? ppP_Matrix
[ n
] : nullptr;
283 pScToken
->AddMatrix( p
);
290 sal_uInt16 n
= pElement
[nId
];
291 if (n
< maExtNames
.size())
293 const ExtName
& r
= maExtNames
[n
];
294 pScToken
->AddExternalName(r
.mnFileId
, mrStringPool
.intern( r
.maName
));
302 sal_uInt16 n
= pElement
[nId
];
303 if (n
< maExtCellRefs
.size())
305 const ExtCellRef
& r
= maExtCellRefs
[n
];
306 pScToken
->AddExternalSingleReference(r
.mnFileId
, mrStringPool
.intern( r
.maTabName
), r
.maRef
);
314 sal_uInt16 n
= pElement
[nId
];
315 if (n
< maExtAreaRefs
.size())
317 const ExtAreaRef
& r
= maExtAreaRefs
[n
];
318 pScToken
->AddExternalDoubleReference(r
.mnFileId
, mrStringPool
.intern( r
.maTabName
), r
.maRef
);
325 OSL_FAIL("-TokenPool::GetElement(): undefined state!?");
332 bool TokenPool::GetElementRek( const sal_uInt16 nId
, ScTokenArray
* pScToken
)
336 OSL_ENSURE(m_nRek
<= nP_Id
, "*TokenPool::GetElement(): recursion loops!?");
339 OSL_ENSURE( nId
< nElementCurrent
, "*TokenPool::GetElementRek(): nId >= nElementCurrent" );
341 if (nId
>= nElementCurrent
)
343 SAL_WARN("sc.filter", "*TokenPool::GetElementRek(): nId >= nElementCurrent");
350 if (pType
[ nId
] != T_Id
)
352 SAL_WARN("sc.filter", "-TokenPool::GetElementRek(): pType[ nId ] != T_Id");
360 sal_uInt16 nCnt
= pSize
[ nId
];
361 sal_uInt16 nFirstId
= pElement
[ nId
];
362 if (nFirstId
>= nP_Id
)
364 SAL_WARN("sc.filter", "TokenPool::GetElementRek: nFirstId >= nP_Id");
368 sal_uInt16
* pCurrent
= nCnt
? &pP_Id
[ nFirstId
] : nullptr;
369 if (nCnt
> nP_Id
- nFirstId
)
371 SAL_WARN("sc.filter", "TokenPool::GetElementRek: nCnt > nP_Id - nFirstId");
372 nCnt
= nP_Id
- nFirstId
;
375 for( ; nCnt
> 0 ; nCnt
--, pCurrent
++ )
378 if( *pCurrent
< nScTokenOff
)
379 {// recursion or not?
380 if (*pCurrent
>= nElementCurrent
)
382 SAL_WARN("sc.filter", "TokenPool::GetElementRek: *pCurrent >= nElementCurrent");
387 if (pType
[ *pCurrent
] == T_Id
)
388 bRet
= GetElementRek( *pCurrent
, pScToken
);
390 bRet
= GetElement( *pCurrent
, pScToken
);
393 else // elementary SC_Token
394 pScToken
->AddOpCode( static_cast<DefTokenId
>( *pCurrent
- nScTokenOff
) );
403 void TokenPool::operator >>( TokenId
& rId
)
405 rId
= static_cast<TokenId
>( nElementCurrent
+ 1 );
407 if (!CheckElementOrGrow())
410 pElement
[ nElementCurrent
] = nP_IdLast
; // Start of Token-sequence
411 pType
[ nElementCurrent
] = T_Id
; // set Typeinfo
412 pSize
[ nElementCurrent
] = nP_IdCurrent
- nP_IdLast
;
413 // write from nP_IdLast to nP_IdCurrent-1 -> length of the sequence
415 nElementCurrent
++; // start value for next sequence
416 nP_IdLast
= nP_IdCurrent
;
419 TokenId
TokenPool::Store( const double& rDouble
)
421 if (!CheckElementOrGrow())
422 return static_cast<const TokenId
>(nElementCurrent
+1);
424 if( pP_Dbl
.m_writemark
>= pP_Dbl
.m_capacity
)
426 return static_cast<const TokenId
>(nElementCurrent
+1);
428 pElement
[ nElementCurrent
] = pP_Dbl
.m_writemark
; // Index in Double-Array
429 pType
[ nElementCurrent
] = T_D
; // set Typeinfo Double
431 pP_Dbl
[ pP_Dbl
.m_writemark
] = rDouble
;
433 pSize
[ nElementCurrent
] = 1; // does not matter
436 pP_Dbl
.m_writemark
++;
438 return static_cast<const TokenId
>(nElementCurrent
); // return old value + 1!
441 TokenId
TokenPool::Store( const sal_uInt16 nIndex
)
443 return StoreName(nIndex
, -1);
446 TokenId
TokenPool::Store( const OUString
& rString
)
448 // mostly copied to Store( const sal_Char* ), to avoid a temporary string
449 if (!CheckElementOrGrow())
450 return static_cast<const TokenId
>(nElementCurrent
+1);
452 if( ppP_Str
.m_writemark
>= ppP_Str
.m_capacity
)
454 return static_cast<const TokenId
>(nElementCurrent
+1);
456 pElement
[ nElementCurrent
] = ppP_Str
.m_writemark
; // Index in String-Array
457 pType
[ nElementCurrent
] = T_Str
; // set Typeinfo String
460 if( !ppP_Str
[ ppP_Str
.m_writemark
] )
461 //...but only, if it does not exist already
462 ppP_Str
[ ppP_Str
.m_writemark
].reset( new OUString( rString
) );
465 *ppP_Str
[ ppP_Str
.m_writemark
] = rString
;
467 /* attention truncate to 16 bits */
468 pSize
[ nElementCurrent
] = static_cast<sal_uInt16
>(ppP_Str
[ ppP_Str
.m_writemark
]->getLength());
471 ppP_Str
.m_writemark
++;
473 return static_cast<const TokenId
>(nElementCurrent
); // return old value + 1!
476 TokenId
TokenPool::Store( const ScSingleRefData
& rTr
)
478 if (!CheckElementOrGrow())
479 return static_cast<const TokenId
>(nElementCurrent
+1);
481 if( ppP_RefTr
.m_writemark
>= ppP_RefTr
.m_capacity
)
482 if (!ppP_RefTr
.Grow())
483 return static_cast<const TokenId
>(nElementCurrent
+1);
485 pElement
[ nElementCurrent
] = ppP_RefTr
.m_writemark
;
486 pType
[ nElementCurrent
] = T_RefC
; // set Typeinfo Cell-Ref
488 if( !ppP_RefTr
[ ppP_RefTr
.m_writemark
] )
489 ppP_RefTr
[ ppP_RefTr
.m_writemark
].reset( new ScSingleRefData( rTr
) );
491 *ppP_RefTr
[ ppP_RefTr
.m_writemark
] = rTr
;
494 ppP_RefTr
.m_writemark
++;
496 return static_cast<const TokenId
>(nElementCurrent
); // return old value + 1!
499 TokenId
TokenPool::Store( const ScComplexRefData
& rTr
)
501 if (!CheckElementOrGrow())
502 return static_cast<const TokenId
>(nElementCurrent
+1);
504 if( ppP_RefTr
.m_writemark
+ 1 >= ppP_RefTr
.m_capacity
)
505 if (!ppP_RefTr
.Grow(2))
506 return static_cast<const TokenId
>(nElementCurrent
+1);
508 pElement
[ nElementCurrent
] = ppP_RefTr
.m_writemark
;
509 pType
[ nElementCurrent
] = T_RefA
; // setTypeinfo Area-Ref
511 if( !ppP_RefTr
[ ppP_RefTr
.m_writemark
] )
512 ppP_RefTr
[ ppP_RefTr
.m_writemark
].reset( new ScSingleRefData( rTr
.Ref1
) );
514 *ppP_RefTr
[ ppP_RefTr
.m_writemark
] = rTr
.Ref1
;
515 ppP_RefTr
.m_writemark
++;
517 if( !ppP_RefTr
[ ppP_RefTr
.m_writemark
] )
518 ppP_RefTr
[ ppP_RefTr
.m_writemark
].reset( new ScSingleRefData( rTr
.Ref2
) );
520 *ppP_RefTr
[ ppP_RefTr
.m_writemark
] = rTr
.Ref2
;
521 ppP_RefTr
.m_writemark
++;
525 return static_cast<const TokenId
>(nElementCurrent
); // return old value + 1!
528 TokenId
TokenPool::Store( const DefTokenId e
, const OUString
& r
)
530 if (!CheckElementOrGrow())
531 return static_cast<const TokenId
>(nElementCurrent
+1);
533 if( ppP_Ext
.m_writemark
>= ppP_Ext
.m_capacity
)
535 return static_cast<const TokenId
>(nElementCurrent
+1);
537 pElement
[ nElementCurrent
] = ppP_Ext
.m_writemark
;
538 pType
[ nElementCurrent
] = T_Ext
; // set Typeinfo String
540 if( ppP_Ext
[ ppP_Ext
.m_writemark
] )
542 ppP_Ext
[ ppP_Ext
.m_writemark
]->eId
= e
;
543 ppP_Ext
[ ppP_Ext
.m_writemark
]->aText
= r
;
546 ppP_Ext
[ ppP_Ext
.m_writemark
].reset( new EXTCONT( e
, r
) );
549 ppP_Ext
.m_writemark
++;
551 return static_cast<const TokenId
>(nElementCurrent
); // return old value + 1!
554 TokenId
TokenPool::StoreNlf( const ScSingleRefData
& rTr
)
556 if (!CheckElementOrGrow())
557 return static_cast<const TokenId
>(nElementCurrent
+1);
559 if( ppP_Nlf
.m_writemark
>= ppP_Nlf
.m_capacity
)
561 return static_cast<const TokenId
>(nElementCurrent
+1);
563 pElement
[ nElementCurrent
] = ppP_Nlf
.m_writemark
;
564 pType
[ nElementCurrent
] = T_Nlf
;
566 if( ppP_Nlf
[ ppP_Nlf
.m_writemark
] )
568 *ppP_Nlf
[ ppP_Nlf
.m_writemark
] = rTr
;
571 ppP_Nlf
[ ppP_Nlf
.m_writemark
].reset( new ScSingleRefData( rTr
) );
574 ppP_Nlf
.m_writemark
++;
576 return static_cast<const TokenId
>(nElementCurrent
);
579 TokenId
TokenPool::StoreMatrix()
581 if (!CheckElementOrGrow())
582 return static_cast<const TokenId
>(nElementCurrent
+1);
584 if( nP_MatrixCurrent
>= nP_Matrix
)
586 return static_cast<const TokenId
>(nElementCurrent
+1);
588 pElement
[ nElementCurrent
] = nP_MatrixCurrent
;
589 pType
[ nElementCurrent
] = T_Matrix
;
591 ScMatrix
* pM
= new ScMatrix( 0, 0 );
593 ppP_Matrix
[ nP_MatrixCurrent
] = pM
;
598 return static_cast<const TokenId
>(nElementCurrent
);
601 TokenId
TokenPool::StoreName( sal_uInt16 nIndex
, sal_Int16 nSheet
)
603 if (!CheckElementOrGrow())
604 return static_cast<const TokenId
>(nElementCurrent
+1);
606 pElement
[nElementCurrent
] = static_cast<sal_uInt16
>(maRangeNames
.size());
607 pType
[nElementCurrent
] = T_RN
;
609 maRangeNames
.emplace_back();
610 RangeName
& r
= maRangeNames
.back();
616 return static_cast<const TokenId
>(nElementCurrent
);
619 TokenId
TokenPool::StoreExtName( sal_uInt16 nFileId
, const OUString
& rName
)
621 if (!CheckElementOrGrow())
622 return static_cast<const TokenId
>(nElementCurrent
+1);
624 pElement
[nElementCurrent
] = static_cast<sal_uInt16
>(maExtNames
.size());
625 pType
[nElementCurrent
] = T_ExtName
;
627 maExtNames
.emplace_back();
628 ExtName
& r
= maExtNames
.back();
629 r
.mnFileId
= nFileId
;
634 return static_cast<const TokenId
>(nElementCurrent
);
637 TokenId
TokenPool::StoreExtRef( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScSingleRefData
& rRef
)
639 if (!CheckElementOrGrow())
640 return static_cast<const TokenId
>(nElementCurrent
+1);
642 pElement
[nElementCurrent
] = static_cast<sal_uInt16
>(maExtCellRefs
.size());
643 pType
[nElementCurrent
] = T_ExtRefC
;
645 maExtCellRefs
.emplace_back();
646 ExtCellRef
& r
= maExtCellRefs
.back();
647 r
.mnFileId
= nFileId
;
648 r
.maTabName
= rTabName
;
653 return static_cast<const TokenId
>(nElementCurrent
);
656 TokenId
TokenPool::StoreExtRef( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScComplexRefData
& rRef
)
658 if (!CheckElementOrGrow())
659 return static_cast<const TokenId
>(nElementCurrent
+1);
661 pElement
[nElementCurrent
] = static_cast<sal_uInt16
>(maExtAreaRefs
.size());
662 pType
[nElementCurrent
] = T_ExtRefA
;
664 maExtAreaRefs
.emplace_back();
665 ExtAreaRef
& r
= maExtAreaRefs
.back();
666 r
.mnFileId
= nFileId
;
667 r
.maTabName
= rTabName
;
672 return static_cast<const TokenId
>(nElementCurrent
);
675 void TokenPool::Reset()
677 nP_IdCurrent
= nP_IdLast
= nElementCurrent
678 = ppP_Str
.m_writemark
= pP_Dbl
.m_writemark
= pP_Err
.m_writemark
679 = ppP_RefTr
.m_writemark
= ppP_Ext
.m_writemark
= ppP_Nlf
.m_writemark
= nP_MatrixCurrent
= 0;
680 maRangeNames
.clear();
682 maExtCellRefs
.clear();
683 maExtAreaRefs
.clear();
687 bool TokenPool::IsSingleOp( const TokenId
& rId
, const DefTokenId eId
) const
689 sal_uInt16 nId
= static_cast<sal_uInt16
>(rId
);
690 if( nId
&& nId
<= nElementCurrent
)
693 if( T_Id
== pType
[ nId
] )
695 if( pSize
[ nId
] == 1 )
697 sal_uInt16 nPid
= pElement
[ nId
];
700 sal_uInt16 nSecId
= pP_Id
[ nPid
];
701 if( nSecId
>= nScTokenOff
)
703 return static_cast<DefTokenId
>( nSecId
- nScTokenOff
) == eId
; // wanted?
713 const OUString
* TokenPool::GetExternal( const TokenId
& rId
) const
715 const OUString
* p
= nullptr;
716 sal_uInt16 n
= static_cast<sal_uInt16
>(rId
);
717 if( n
&& n
<= nElementCurrent
)
720 if( pType
[ n
] == T_Ext
)
722 sal_uInt16 nExt
= pElement
[ n
];
723 if ( nExt
< ppP_Ext
.m_writemark
&& ppP_Ext
[ nExt
] )
724 p
= &ppP_Ext
[ nExt
]->aText
;
731 ScMatrix
* TokenPool::GetMatrix( unsigned int n
) const
733 if( n
< nP_MatrixCurrent
)
734 return ppP_Matrix
[ n
];
736 SAL_WARN("sc.filter", "GetMatrix: " << n
<< " >= " << nP_MatrixCurrent
);
740 void TokenPool::ClearMatrix()
742 for(sal_uInt16 n
= 0 ; n
< nP_Matrix
; n
++ )
744 if( ppP_Matrix
[ n
] )
746 ppP_Matrix
[ n
]->DecRef( );
747 ppP_Matrix
[n
] = nullptr;
752 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */