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 
21 #include <basic/sberrors.hxx>
22 #include <basic/sbx.hxx>
23 #include <basic/sbmeth.hxx>
24 #include <basic/sbmod.hxx>
25 #include <image.hxx>
26 #include <codegen.hxx>
27 #include <parser.hxx>
28 #include <sbintern.hxx>
29 #include <cstddef>
30 #include <limits>
31 #include <algorithm>
32 #include <string_view>
33 #include <osl/diagnose.h>
34 #include <rtl/ustrbuf.hxx>
35 #include <com/sun/star/script/ModuleType.hpp>
36 
37 // nInc is the increment size of the buffers
38 
SbiCodeGen(SbModule & r,SbiParser * p,short nInc)39 SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
40          : rMod( r ), aCode( p, nInc )
41 {
42     pParser = p;
43     bStmnt = false;
44     nLine = 0;
45     nCol = 0;
46     nForLevel = 0;
47 }
48 
GetPC() const49 sal_uInt32 SbiCodeGen::GetPC() const
50 {
51     return aCode.GetSize();
52 }
53 
54 // memorize the statement
55 
Statement()56 void SbiCodeGen::Statement()
57 {
58     if( pParser->IsCodeCompleting() )
59         return;
60 
61     bStmnt = true;
62 
63     nLine = pParser->GetLine();
64     nCol  = pParser->GetCol1();
65 
66     // #29955 Store the information of the for-loop-layer
67     // in the upper Byte of the column
68     nCol = (nCol & 0xff) + 0x100 * nForLevel;
69 }
70 
71 // Mark the beginning of a statement
72 
GenStmnt()73 void SbiCodeGen::GenStmnt()
74 {
75     if( pParser->IsCodeCompleting() )
76         return;
77 
78     if( bStmnt )
79     {
80         bStmnt = false;
81         Gen( SbiOpcode::STMNT_, nLine, nCol );
82     }
83 }
84 
85 // The Gen-Routines return the offset of the 1. operand,
86 // so that jumps can sink their backchain there.
87 
Gen(SbiOpcode eOpcode)88 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode )
89 {
90     if( pParser->IsCodeCompleting() )
91         return 0;
92 
93 #ifdef DBG_UTIL
94     if( eOpcode < SbiOpcode::SbOP0_START || eOpcode > SbiOpcode::SbOP0_END )
95         pParser->Error( ERRCODE_BASIC_INTERNAL_ERROR, "OPCODE1" );
96 #endif
97     GenStmnt();
98     aCode += static_cast<sal_uInt8>(eOpcode);
99     return GetPC();
100 }
101 
Gen(SbiOpcode eOpcode,sal_uInt32 nOpnd)102 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd )
103 {
104     if( pParser->IsCodeCompleting() )
105         return 0;
106 
107 #ifdef DBG_UTIL
108     if( eOpcode < SbiOpcode::SbOP1_START || eOpcode > SbiOpcode::SbOP1_END )
109         pParser->Error( ERRCODE_BASIC_INTERNAL_ERROR, "OPCODE2" );
110 #endif
111     GenStmnt();
112     aCode += static_cast<sal_uInt8>(eOpcode);
113     sal_uInt32 n = GetPC();
114     aCode += nOpnd;
115     return n;
116 }
117 
Gen(SbiOpcode eOpcode,sal_uInt32 nOpnd1,sal_uInt32 nOpnd2)118 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd1, sal_uInt32 nOpnd2 )
119 {
120     if( pParser->IsCodeCompleting() )
121         return 0;
122 
123 #ifdef DBG_UTIL
124     if( eOpcode < SbiOpcode::SbOP2_START || eOpcode > SbiOpcode::SbOP2_END )
125         pParser->Error( ERRCODE_BASIC_INTERNAL_ERROR, "OPCODE3" );
126 #endif
127     GenStmnt();
128     aCode += static_cast<sal_uInt8>(eOpcode);
129     sal_uInt32 n = GetPC();
130     aCode += nOpnd1;
131     aCode += nOpnd2;
132     return n;
133 }
134 
135 // Storing of the created image in the module
136 
Save()137 void SbiCodeGen::Save()
138 {
139     if( pParser->IsCodeCompleting() )
140         return;
141 
142     SbiImage* p = new SbiImage;
143     rMod.StartDefinitions();
144     // OPTION BASE-Value:
145     p->nDimBase = pParser->nBase;
146     // OPTION take over the EXPLICIT-Flag
147     if( pParser->bExplicit )
148         p->SetFlag( SbiImageFlags::EXPLICIT );
149 
150     int nIfaceCount = 0;
151     if( rMod.mnType == css::script::ModuleType::CLASS )
152     {
153         rMod.bIsProxyModule = true;
154         p->SetFlag( SbiImageFlags::CLASSMODULE );
155         GetSbData()->pClassFac->AddClassModule( &rMod );
156 
157         nIfaceCount = pParser->aIfaceVector.size();
158         if( !rMod.pClassData )
159             rMod.pClassData.reset(new SbClassData);
160         if( nIfaceCount )
161         {
162             for( int i = 0 ; i < nIfaceCount ; i++ )
163             {
164                 const OUString& rIfaceName = pParser->aIfaceVector[i];
165                 SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT );
166                 pIfaceVar->SetName( rIfaceName );
167                 SbxArray* pIfaces = rMod.pClassData->mxIfaces.get();
168                 pIfaces->Insert( pIfaceVar, pIfaces->Count() );
169             }
170         }
171 
172         rMod.pClassData->maRequiredTypes = pParser->aRequiredTypes;
173     }
174     else
175     {
176         GetSbData()->pClassFac->RemoveClassModule( &rMod );
177         // Only a ClassModule can revert to Normal
178         if ( rMod.mnType == css::script::ModuleType::CLASS )
179         {
180             rMod.mnType = css::script::ModuleType::NORMAL;
181         }
182         rMod.bIsProxyModule = false;
183     }
184 
185     // GlobalCode-Flag
186     if( pParser->HasGlobalCode() )
187     {
188         p->SetFlag( SbiImageFlags::INITCODE );
189     }
190     // The entry points:
191     for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
192          pDef = pParser->aPublics.Next() )
193     {
194         SbiProcDef* pProc = pDef->GetProcDef();
195         if( pProc && pProc->IsDefined() )
196         {
197             OUString aProcName = pProc->GetName();
198             OUStringBuffer aIfaceProcName;
199             OUString aIfaceName;
200             sal_uInt16 nPassCount = 1;
201             if( nIfaceCount )
202             {
203                 int nPropPrefixFound = aProcName.indexOf("Property ");
204                 OUString aPureProcName = aProcName;
205                 OUString aPropPrefix;
206                 if( nPropPrefixFound == 0 )
207                 {
208                     aPropPrefix = aProcName.copy( 0, 13 );      // 13 == Len( "Property ?et " )
209                     aPureProcName = aProcName.copy( 13 );
210                 }
211                 for( int i = 0 ; i < nIfaceCount ; i++ )
212                 {
213                     const OUString& rIfaceName = pParser->aIfaceVector[i];
214                     int nFound = aPureProcName.indexOf( rIfaceName );
215                     if( nFound == 0 && aPureProcName[rIfaceName.getLength()] == '_' )
216                     {
217                         if( nPropPrefixFound == 0 )
218                         {
219                             aIfaceProcName.append(aPropPrefix);
220                         }
221                         aIfaceProcName.append(std::u16string_view(aPureProcName).substr(rIfaceName.getLength() + 1) );
222                         aIfaceName = rIfaceName;
223                         nPassCount = 2;
224                         break;
225                     }
226                 }
227             }
228             SbMethod* pMeth = nullptr;
229             for( sal_uInt16 nPass = 0 ; nPass < nPassCount ; nPass++ )
230             {
231                 if( nPass == 1 )
232                 {
233                     aProcName = aIfaceProcName.toString();
234                 }
235                 PropertyMode ePropMode = pProc->getPropertyMode();
236                 if( ePropMode != PropertyMode::NONE )
237                 {
238                     SbxDataType ePropType = SbxEMPTY;
239                     switch( ePropMode )
240                     {
241                     case PropertyMode::Get:
242                         ePropType = pProc->GetType();
243                         break;
244                     case PropertyMode::Let:
245                     {
246                         // type == type of first parameter
247                         ePropType = SbxVARIANT;     // Default
248                         SbiSymPool* pPool = &pProc->GetParams();
249                         if( pPool->GetSize() > 1 )
250                         {
251                             SbiSymDef* pPar = pPool->Get( 1 );
252                             if( pPar )
253                             {
254                                 ePropType = pPar->GetType();
255                             }
256                         }
257                         break;
258                     }
259                     case PropertyMode::Set:
260                         ePropType = SbxOBJECT;
261                         break;
262                     default:
263                         OSL_FAIL("Illegal PropertyMode");
264                         break;
265                     }
266                     OUString aPropName = pProc->GetPropName();
267                     if( nPass == 1 )
268                     {
269                         aPropName = aPropName.copy( aIfaceName.getLength() + 1 );
270                     }
271                     rMod.GetProcedureProperty( aPropName, ePropType );
272                 }
273                 if( nPass == 1 )
274                 {
275                     rMod.GetIfaceMapperMethod( aProcName, pMeth );
276                 }
277                 else
278                 {
279                     pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
280 
281                     if( !pProc->IsPublic() )
282                     {
283                         pMeth->SetFlag( SbxFlagBits::Private );
284                     }
285                     // Declare? -> Hidden
286                     if( !pProc->GetLib().isEmpty())
287                     {
288                         pMeth->SetFlag( SbxFlagBits::Hidden );
289                     }
290                     pMeth->nStart = pProc->GetAddr();
291                     pMeth->nLine1 = pProc->GetLine1();
292                     pMeth->nLine2 = pProc->GetLine2();
293                     // The parameter:
294                     SbxInfo* pInfo = pMeth->GetInfo();
295                     OUString aHelpFile, aComment;
296                     sal_uInt32 nHelpId = 0;
297                     if( pInfo )
298                     {
299                         // Rescue the additional data
300                         aHelpFile = pInfo->GetHelpFile();
301                         aComment  = pInfo->GetComment();
302                         nHelpId   = pInfo->GetHelpId();
303                     }
304                     // And reestablish the parameter list
305                     pInfo = new SbxInfo( aHelpFile, nHelpId );
306                     pInfo->SetComment( aComment );
307                     SbiSymPool* pPool = &pProc->GetParams();
308                     // The first element is always the value of the function!
309                     for( sal_uInt16 i = 1; i < pPool->GetSize(); i++ )
310                     {
311                         SbiSymDef* pPar = pPool->Get( i );
312                         SbxDataType t = pPar->GetType();
313                         if( !pPar->IsByVal() )
314                         {
315                             t = static_cast<SbxDataType>( t | SbxBYREF );
316                         }
317                         if( pPar->GetDims() )
318                         {
319                             t = static_cast<SbxDataType>( t | SbxARRAY );
320                         }
321                         // #33677 hand-over an Optional-Info
322                         SbxFlagBits nFlags = SbxFlagBits::Read;
323                         if( pPar->IsOptional() )
324                         {
325                             nFlags |= SbxFlagBits::Optional;
326                         }
327                         pInfo->AddParam( pPar->GetName(), t, nFlags );
328 
329                         sal_uInt32 nUserData = 0;
330                         sal_uInt16 nDefaultId = pPar->GetDefaultId();
331                         if( nDefaultId )
332                         {
333                             nUserData |= nDefaultId;
334                         }
335                         if( pPar->IsParamArray() )
336                         {
337                             nUserData |= PARAM_INFO_PARAMARRAY;
338                         }
339                         if( pPar->IsWithBrackets() )
340                         {
341                             nUserData |= PARAM_INFO_WITHBRACKETS;
342                         }
343                         SbxParamInfo* pParam = nullptr;
344                         if( nUserData )
345                         {
346                             pParam = const_cast<SbxParamInfo*>(pInfo->GetParam( i ));
347                         }
348                         if( pParam )
349                         {
350                             pParam->nUserData = nUserData;
351                         }
352                     }
353                     pMeth->SetInfo( pInfo );
354                 }
355             }   // for( iPass...
356         }
357     }
358     // The code
359     p->AddCode( std::unique_ptr<char[]>(aCode.GetBuffer()), aCode.GetSize() );
360 
361     // The global StringPool. 0 is not occupied.
362     SbiStringPool* pPool = &pParser->aGblStrings;
363     sal_uInt16 nSize = pPool->GetSize();
364     p->MakeStrings( nSize );
365     sal_uInt16 i;
366     for( i = 1; i <= nSize; i++ )
367     {
368         p->AddString( pPool->Find( i ) );
369     }
370     // Insert types
371     sal_uInt16 nCount = pParser->rTypeArray->Count();
372     for (i = 0; i < nCount; i++)
373     {
374          p->AddType(static_cast<SbxObject *>(pParser->rTypeArray->Get(i)));
375     }
376     // Insert enum objects
377     nCount = pParser->rEnumArray->Count();
378     for (i = 0; i < nCount; i++)
379     {
380          p->AddEnum(static_cast<SbxObject *>(pParser->rEnumArray->Get(i)));
381     }
382     if( !p->IsError() )
383     {
384         rMod.pImage = p;
385     }
386     else
387     {
388         delete p;
389     }
390     rMod.EndDefinitions();
391 }
392 
393 template < class T >
394 class PCodeVisitor
395 {
396 public:
397     virtual ~PCodeVisitor();
398 
399     virtual void start( const sal_uInt8* pStart ) = 0;
400     virtual void processOpCode0( SbiOpcode eOp ) = 0;
401     virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
402     virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
403     virtual bool processParams() = 0;
404 };
405 
~PCodeVisitor()406 template <class T> PCodeVisitor< T >::~PCodeVisitor()
407 {}
408 
409 template <class T>
410 class PCodeBufferWalker
411 {
412 private:
413     T  m_nBytes;
414     const sal_uInt8* m_pCode;
readParam(sal_uInt8 const * & pCode)415     static T readParam( sal_uInt8 const *& pCode )
416     {
417         T nOp1=0;
418         for ( std::size_t i=0; i<sizeof( T ); ++i )
419             nOp1 |= *pCode++ << ( i * 8);
420         return nOp1;
421     }
422 public:
PCodeBufferWalker(const sal_uInt8 * pCode,T nBytes)423     PCodeBufferWalker( const sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
424     {
425     }
visitBuffer(PCodeVisitor<T> & visitor)426     void visitBuffer( PCodeVisitor< T >& visitor )
427     {
428         const sal_uInt8* pCode = m_pCode;
429         if ( !pCode )
430             return;
431         const sal_uInt8* pEnd = pCode + m_nBytes;
432         visitor.start( m_pCode );
433         T nOp1 = 0, nOp2 = 0;
434         for( ; pCode < pEnd; )
435         {
436             SbiOpcode eOp = static_cast<SbiOpcode>(*pCode++);
437 
438             if ( eOp <= SbiOpcode::SbOP0_END )
439                 visitor.processOpCode0( eOp );
440             else if( eOp >= SbiOpcode::SbOP1_START && eOp <= SbiOpcode::SbOP1_END )
441             {
442                 if ( visitor.processParams() )
443                     nOp1 = readParam( pCode );
444                 else
445                     pCode += sizeof( T );
446                 visitor.processOpCode1( eOp, nOp1 );
447             }
448             else if( eOp >= SbiOpcode::SbOP2_START && eOp <= SbiOpcode::SbOP2_END )
449             {
450                 if ( visitor.processParams() )
451                 {
452                     nOp1 = readParam( pCode );
453                     nOp2 = readParam( pCode );
454                 }
455                 else
456                     pCode += ( sizeof( T ) * 2 );
457                 visitor.processOpCode2( eOp, nOp1, nOp2 );
458             }
459         }
460     }
461 };
462 
463 template < class T, class S >
464 class OffSetAccumulator : public PCodeVisitor< T >
465 {
466     T m_nNumOp0;
467     T m_nNumSingleParams;
468     T m_nNumDoubleParams;
469 public:
470 
OffSetAccumulator()471     OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
start(const sal_uInt8 *)472     virtual void start( const sal_uInt8* /*pStart*/ ) override {}
processOpCode0(SbiOpcode)473     virtual void processOpCode0( SbiOpcode /*eOp*/ ) override { ++m_nNumOp0; }
processOpCode1(SbiOpcode,T)474     virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ) override {  ++m_nNumSingleParams; }
processOpCode2(SbiOpcode,T,T)475     virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) override { ++m_nNumDoubleParams; }
offset()476     S offset()
477     {
478         typedef decltype(T(1) + S(1)) larger_t; // type capable to hold both value ranges of T and S
479         T result = 0 ;
480         static const S max = std::numeric_limits< S >::max();
481         result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 )  * m_nNumDoubleParams );
482         return std::min<larger_t>(max, result);
483     }
processParams()484     virtual bool processParams() override { return false; }
485 };
486 
487 
488 template < class T, class S >
489 class BufferTransformer : public PCodeVisitor< T >
490 {
491     const sal_uInt8* m_pStart;
492     SbiBuffer m_ConvertedBuf;
493 public:
BufferTransformer()494     BufferTransformer():m_pStart(nullptr), m_ConvertedBuf( nullptr, 1024 ) {}
start(const sal_uInt8 * pStart)495     virtual void start( const sal_uInt8* pStart ) override { m_pStart = pStart; }
processOpCode0(SbiOpcode eOp)496     virtual void processOpCode0( SbiOpcode eOp ) override
497     {
498         m_ConvertedBuf += static_cast<sal_uInt8>(eOp);
499     }
processOpCode1(SbiOpcode eOp,T nOp1)500     virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) override
501     {
502         m_ConvertedBuf += static_cast<sal_uInt8>(eOp);
503         switch( eOp )
504         {
505             case SbiOpcode::JUMP_:
506             case SbiOpcode::JUMPT_:
507             case SbiOpcode::JUMPF_:
508             case SbiOpcode::GOSUB_:
509             case SbiOpcode::CASEIS_:
510             case SbiOpcode::RETURN_:
511             case SbiOpcode::ERRHDL_:
512             case SbiOpcode::TESTFOR_:
513                 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
514                 break;
515             case SbiOpcode::RESUME_:
516                 if ( nOp1 > 1 )
517                     nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
518                 break;
519             default:
520                 break;
521 
522         }
523         m_ConvertedBuf += static_cast<S>(nOp1);
524     }
processOpCode2(SbiOpcode eOp,T nOp1,T nOp2)525     virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) override
526     {
527         m_ConvertedBuf += static_cast<sal_uInt8>(eOp);
528         if ( eOp == SbiOpcode::CASEIS_  && nOp1 )
529             nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
530         m_ConvertedBuf += static_cast<S>(nOp1);
531         m_ConvertedBuf += static_cast<S>(nOp2);
532 
533     }
processParams()534     virtual bool processParams() override { return true; }
535     // yeuch, careful here, you can only call
536     // GetBuffer on the returned SbiBuffer once, also
537     // you (as the caller) get to own the memory
buffer()538     SbiBuffer& buffer()
539     {
540         return m_ConvertedBuf;
541     }
convertBufferOffSet(const sal_uInt8 * pStart,T nOp1)542     static S convertBufferOffSet( const sal_uInt8* pStart, T nOp1 )
543     {
544         PCodeBufferWalker< T > aBuff( pStart, nOp1);
545         OffSetAccumulator< T, S > aVisitor;
546         aBuff.visitBuffer( aVisitor );
547         return aVisitor.offset();
548     }
549 };
550 
551 sal_uInt32
calcNewOffSet(sal_uInt8 const * pCode,sal_uInt16 nOffset)552 SbiCodeGen::calcNewOffSet( sal_uInt8 const * pCode, sal_uInt16 nOffset )
553 {
554     return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset );
555 }
556 
557 sal_uInt16
calcLegacyOffSet(sal_uInt8 const * pCode,sal_uInt32 nOffset)558 SbiCodeGen::calcLegacyOffSet( sal_uInt8 const * pCode, sal_uInt32 nOffset )
559 {
560     return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset );
561 }
562 
563 template <class T, class S>
564 void
convert()565 PCodeBuffConvertor<T,S>::convert()
566 {
567     PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
568     BufferTransformer< T, S > aTrnsfrmer;
569     aBuf.visitBuffer( aTrnsfrmer );
570     m_pCnvtdBuf = reinterpret_cast<sal_uInt8*>(aTrnsfrmer.buffer().GetBuffer());
571     m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
572 }
573 
574 template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >;
575 template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >;
576 
577 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
578