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)39 SbiCodeGen::SbiCodeGen(SbModule& r, SbiParser* p)
40     : pParser(p)
41     , rMod(r)
42     , nLine(0)
43     , nCol(0)
44     , nForLevel(0)
45     , bStmnt(false)
46 {
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     std::unique_ptr<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(aPureProcName.subView(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     if (aCode.GetErrCode())
359     {
360         pParser->Error(aCode.GetErrCode(), aCode.GetErrMessage());
361     }
362     // The code
363     p->AddCode(aCode.GetBuffer());
364 
365     // The global StringPool. 0 is not occupied.
366     SbiStringPool* pPool = &pParser->aGblStrings;
367     sal_uInt16 nSize = pPool->GetSize();
368     p->MakeStrings( nSize );
369     sal_uInt32 i;
370     for( i = 1; i <= nSize; i++ )
371     {
372         p->AddString( pPool->Find( i ) );
373     }
374     // Insert types
375     sal_uInt32 nCount = pParser->rTypeArray->Count();
376     for (i = 0; i < nCount; i++)
377     {
378          p->AddType(static_cast<SbxObject *>(pParser->rTypeArray->Get(i)));
379     }
380     // Insert enum objects
381     nCount = pParser->rEnumArray->Count();
382     for (i = 0; i < nCount; i++)
383     {
384          p->AddEnum(static_cast<SbxObject *>(pParser->rEnumArray->Get(i)));
385     }
386     if( !p->IsError() )
387     {
388         rMod.pImage = std::move(p);
389     }
390     rMod.EndDefinitions();
391 }
392 
393 namespace {
394 
395 template < class T >
396 class PCodeVisitor
397 {
398 public:
399     virtual ~PCodeVisitor();
400 
401     virtual void start( const sal_uInt8* pStart ) = 0;
402     virtual void processOpCode0( SbiOpcode eOp ) = 0;
403     virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
404     virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
405     virtual bool processParams() = 0;
406 };
407 
408 }
409 
~PCodeVisitor()410 template <class T> PCodeVisitor< T >::~PCodeVisitor()
411 {}
412 
413 namespace {
414 
415 template <class T>
416 class PCodeBufferWalker
417 {
418 private:
419     T  m_nBytes;
420     const sal_uInt8* m_pCode;
readParam(sal_uInt8 const * & pCode)421     static T readParam( sal_uInt8 const *& pCode )
422     {
423         T nOp1=0;
424         for ( std::size_t i=0; i<sizeof( T ); ++i )
425             nOp1 |= *pCode++ << ( i * 8);
426         return nOp1;
427     }
428 public:
PCodeBufferWalker(const sal_uInt8 * pCode,T nBytes)429     PCodeBufferWalker( const sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
430     {
431     }
visitBuffer(PCodeVisitor<T> & visitor)432     void visitBuffer( PCodeVisitor< T >& visitor )
433     {
434         const sal_uInt8* pCode = m_pCode;
435         if ( !pCode )
436             return;
437         const sal_uInt8* pEnd = pCode + m_nBytes;
438         visitor.start( m_pCode );
439         T nOp1 = 0, nOp2 = 0;
440         for( ; pCode < pEnd; )
441         {
442             SbiOpcode eOp = static_cast<SbiOpcode>(*pCode++);
443 
444             if ( eOp <= SbiOpcode::SbOP0_END )
445                 visitor.processOpCode0( eOp );
446             else if( eOp >= SbiOpcode::SbOP1_START && eOp <= SbiOpcode::SbOP1_END )
447             {
448                 if ( visitor.processParams() )
449                     nOp1 = readParam( pCode );
450                 else
451                     pCode += sizeof( T );
452                 visitor.processOpCode1( eOp, nOp1 );
453             }
454             else if( eOp >= SbiOpcode::SbOP2_START && eOp <= SbiOpcode::SbOP2_END )
455             {
456                 if ( visitor.processParams() )
457                 {
458                     nOp1 = readParam( pCode );
459                     nOp2 = readParam( pCode );
460                 }
461                 else
462                     pCode += ( sizeof( T ) * 2 );
463                 visitor.processOpCode2( eOp, nOp1, nOp2 );
464             }
465         }
466     }
467 };
468 
469 template < class T, class S >
470 class OffSetAccumulator : public PCodeVisitor< T >
471 {
472     T m_nNumOp0;
473     T m_nNumSingleParams;
474     T m_nNumDoubleParams;
475 public:
476 
OffSetAccumulator()477     OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
start(const sal_uInt8 *)478     virtual void start( const sal_uInt8* /*pStart*/ ) override {}
processOpCode0(SbiOpcode)479     virtual void processOpCode0( SbiOpcode /*eOp*/ ) override { ++m_nNumOp0; }
processOpCode1(SbiOpcode,T)480     virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ) override {  ++m_nNumSingleParams; }
processOpCode2(SbiOpcode,T,T)481     virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) override { ++m_nNumDoubleParams; }
offset()482     S offset()
483     {
484         typedef decltype(T(1) + S(1)) larger_t; // type capable to hold both value ranges of T and S
485         T result = 0 ;
486         static const S max = std::numeric_limits< S >::max();
487         result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 )  * m_nNumDoubleParams );
488         return std::min<larger_t>(max, result);
489     }
processParams()490     virtual bool processParams() override { return false; }
491 };
492 
493 
494 template < class T, class S >
495 class BufferTransformer : public PCodeVisitor< T >
496 {
497     const sal_uInt8* m_pStart;
498     SbiBuffer m_ConvertedBuf;
499 public:
BufferTransformer()500     BufferTransformer():m_pStart(nullptr) {}
start(const sal_uInt8 * pStart)501     virtual void start( const sal_uInt8* pStart ) override { m_pStart = pStart; }
processOpCode0(SbiOpcode eOp)502     virtual void processOpCode0( SbiOpcode eOp ) override
503     {
504         m_ConvertedBuf += static_cast<sal_uInt8>(eOp);
505     }
processOpCode1(SbiOpcode eOp,T nOp1)506     virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) override
507     {
508         m_ConvertedBuf += static_cast<sal_uInt8>(eOp);
509         switch( eOp )
510         {
511             case SbiOpcode::JUMP_:
512             case SbiOpcode::JUMPT_:
513             case SbiOpcode::JUMPF_:
514             case SbiOpcode::GOSUB_:
515             case SbiOpcode::CASEIS_:
516             case SbiOpcode::RETURN_:
517             case SbiOpcode::ERRHDL_:
518             case SbiOpcode::TESTFOR_:
519                 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
520                 break;
521             case SbiOpcode::RESUME_:
522                 if ( nOp1 > 1 )
523                     nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
524                 break;
525             default:
526                 break;
527 
528         }
529         m_ConvertedBuf += static_cast<S>(nOp1);
530     }
processOpCode2(SbiOpcode eOp,T nOp1,T nOp2)531     virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) override
532     {
533         m_ConvertedBuf += static_cast<sal_uInt8>(eOp);
534         if ( eOp == SbiOpcode::CASEIS_  && nOp1 )
535             nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
536         m_ConvertedBuf += static_cast<S>(nOp1);
537         m_ConvertedBuf += static_cast<S>(nOp2);
538 
539     }
processParams()540     virtual bool processParams() override { return true; }
541     // yeuch, careful here, you can only call
542     // GetBuffer on the returned SbiBuffer once, also
543     // you (as the caller) get to own the memory
buffer()544     SbiBuffer& buffer()
545     {
546         return m_ConvertedBuf;
547     }
convertBufferOffSet(const sal_uInt8 * pStart,T nOp1)548     static S convertBufferOffSet( const sal_uInt8* pStart, T nOp1 )
549     {
550         PCodeBufferWalker< T > aBuff( pStart, nOp1);
551         OffSetAccumulator< T, S > aVisitor;
552         aBuff.visitBuffer( aVisitor );
553         return aVisitor.offset();
554     }
555 };
556 
557 }
558 
559 sal_uInt32
calcNewOffSet(sal_uInt8 const * pCode,sal_uInt16 nOffset)560 SbiCodeGen::calcNewOffSet( sal_uInt8 const * pCode, sal_uInt16 nOffset )
561 {
562     return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset );
563 }
564 
565 sal_uInt16
calcLegacyOffSet(sal_uInt8 const * pCode,sal_uInt32 nOffset)566 SbiCodeGen::calcLegacyOffSet( sal_uInt8 const * pCode, sal_uInt32 nOffset )
567 {
568     return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset );
569 }
570 
571 template <class T, class S>
572 void
convert()573 PCodeBuffConvertor<T,S>::convert()
574 {
575     PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
576     BufferTransformer< T, S > aTrnsfrmer;
577     aBuf.visitBuffer( aTrnsfrmer );
578     // TODO: handle buffer errors
579     m_aCnvtdBuf = aTrnsfrmer.buffer().GetBuffer();
580 }
581 
582 template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >;
583 template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >;
584 
585 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
586