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 #include <sal/config.h>
21 
22 #include <algorithm>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string_view>
26 
27 #include <database.hxx>
28 #include <globals.hxx>
29 #include <rtl/strbuf.hxx>
30 #include <osl/file.hxx>
31 
32 
SvParseException(SvTokenStream const & rInStm,const OString & rError)33 SvParseException::SvParseException( SvTokenStream const & rInStm, const OString& rError )
34 {
35     SvToken& rTok = rInStm.GetToken();
36     aError = SvIdlError( rTok.GetLine(), rTok.GetColumn() );
37     aError.SetText( rError );
38 };
39 
SvParseException(const OString & rError,SvToken const & rTok)40 SvParseException::SvParseException( const OString& rError, SvToken const & rTok )
41 {
42     aError = SvIdlError( rTok.GetLine(), rTok.GetColumn() );
43     aError.SetText( rError );
44 };
45 
46 
SvIdlDataBase(const SvCommand & rCmd)47 SvIdlDataBase::SvIdlDataBase( const SvCommand& rCmd )
48     : bExport( false )
49     , nUniqueId( 0 )
50     , nVerbosity( rCmd.nVerbosity )
51 {
52     sSlotMapFile = rCmd.aSlotMapFile;
53 }
54 
~SvIdlDataBase()55 SvIdlDataBase::~SvIdlDataBase()
56 {
57     aIdFileList.clear();
58 }
59 
60 #define ADD_TYPE( Name )            \
61     aTypeList.push_back( new SvMetaType( SvHash_##Name()->GetName() ) );
62 
GetTypeList()63 SvRefMemberList<SvMetaType *>& SvIdlDataBase::GetTypeList()
64 {
65     if( aTypeList.empty() )
66     { // fill initially
67         aTypeList.push_back( new SvMetaTypeString() );
68         aTypeList.push_back( new SvMetaTypevoid() );
69 
70         // MI: IDispatch::Invoke can not unsigned
71         ADD_TYPE( UINT16 );
72         ADD_TYPE( INT16 );
73         ADD_TYPE( UINT32 );
74         ADD_TYPE( INT32 );
75         ADD_TYPE( BOOL );
76         ADD_TYPE( BYTE );
77         ADD_TYPE( float );
78         ADD_TYPE( double );
79         ADD_TYPE( SbxObject );
80 
81         // Attention! When adding types all binary data bases get incompatible
82 
83     }
84     return aTypeList;
85 }
86 
SetError(const OString & rError,SvToken const & rTok)87 void SvIdlDataBase::SetError( const OString& rError, SvToken const & rTok )
88 {
89     if( rTok.GetLine() > 10000 )
90         aError.SetText( "line count overflow" );
91 
92     if( aError.nLine < rTok.GetLine()
93       || (aError.nLine == rTok.GetLine() && aError.nColumn < rTok.GetColumn()) )
94     {
95         aError = SvIdlError( rTok.GetLine(), rTok.GetColumn() );
96         aError.SetText( rError );
97     }
98 }
99 
SetAndWriteError(SvTokenStream & rInStm,const OString & rError)100 void SvIdlDataBase::SetAndWriteError( SvTokenStream & rInStm, const OString& rError )
101 {
102     SetError( rError, rInStm.GetToken() );
103     WriteError( rInStm );
104 }
105 
Push(SvMetaObject * pObj)106 void SvIdlDataBase::Push( SvMetaObject * pObj )
107 {
108     GetStack().push_back( pObj );
109 }
110 
FindId(const OString & rIdName,sal_uInt32 * pVal)111 bool SvIdlDataBase::FindId( const OString& rIdName, sal_uInt32 * pVal )
112 {
113     if( pIdTable )
114     {
115         sal_uInt32 nHash;
116         if( pIdTable->Test( rIdName, &nHash ) )
117         {
118             *pVal = pIdTable->Get( nHash )->GetValue();
119             return true;
120         }
121     }
122     return false;
123 }
124 
InsertId(const OString & rIdName,sal_uInt32 nVal)125 void SvIdlDataBase::InsertId( const OString& rIdName, sal_uInt32 nVal )
126 {
127     if( !pIdTable )
128         pIdTable.reset( new SvStringHashTable );
129 
130     sal_uInt32 nHash;
131     pIdTable->Insert( rIdName, &nHash )->SetValue( nVal );
132 }
133 
ReadIdFile(std::string_view rOFileName)134 bool SvIdlDataBase::ReadIdFile( std::string_view rOFileName )
135 {
136     OUString rFileName = OStringToOUString(rOFileName, RTL_TEXTENCODING_ASCII_US);
137     OUString aFullName;
138     osl::File::searchFileURL( rFileName, GetPath(), aFullName);
139     osl::FileBase::getSystemPathFromFileURL( aFullName, aFullName );
140 
141     for ( size_t i = 0, n = aIdFileList.size(); i < n; ++i )
142         if ( aIdFileList[ i ] == rFileName )
143             return true;
144 
145     aIdFileList.push_back( rFileName );
146     AddDepFile( aFullName );
147     SvTokenStream aTokStm( aFullName );
148     if( aTokStm.GetStream().GetError() != ERRCODE_NONE )
149         return false;
150 
151     SvToken& rTok = aTokStm.GetToken_Next();
152 
153     while( !rTok.IsEof() )
154     {
155         if( rTok.IsChar() && rTok.GetChar() == '#' )
156         {
157             rTok = aTokStm.GetToken_Next();
158             if( rTok.Is( SvHash_define() ) )
159             {
160                 rTok = aTokStm.GetToken_Next();
161                 OString aDefName;
162                 if( !rTok.IsIdentifier() )
163                     throw SvParseException( "unexpected token after define", rTok );
164                 aDefName = rTok.GetString();
165 
166                 sal_uInt32 nVal = 0;
167                 bool bOk = true;
168                 while( bOk )
169                 {
170                     rTok = aTokStm.GetToken_Next();
171                     if (rTok.GetTokenAsString().startsWith("TypedWhichId"))
172                     {
173                         rTok = aTokStm.GetToken_Next();
174                         if( !rTok.IsChar() || rTok.GetChar() != '<')
175                             throw SvParseException( "expected '<'", rTok );
176                         rTok = aTokStm.GetToken_Next();
177                         if( !rTok.IsIdentifier() )
178                             throw SvParseException( "expected identifier", rTok );
179                         rTok = aTokStm.GetToken_Next();
180                         if( !rTok.IsChar() || rTok.GetChar() != '>')
181                             throw SvParseException( "expected '<'", rTok );
182                         rTok = aTokStm.GetToken_Next();
183                     }
184                     else if( rTok.IsIdentifier() )
185                     {
186                         sal_uInt32 n;
187                         if( FindId( rTok.GetString(), &n ) )
188                             nVal += n;
189                         else
190                             bOk = false;
191                     }
192                     else if( rTok.IsChar() )
193                     {
194                         if( rTok.GetChar() == '-'
195                           || rTok.GetChar() == '/'
196                           || rTok.GetChar() == '*'
197                           || rTok.GetChar() == '&'
198                           || rTok.GetChar() == '|'
199                           || rTok.GetChar() == '^'
200                           || rTok.GetChar() == '~' )
201                         {
202                             throw SvParseException( "unknown operator '" + OStringChar(rTok.GetChar()) + "'in define", rTok );
203                         }
204                         if( rTok.GetChar() != '+'
205                           && rTok.GetChar() != '('
206                           && rTok.GetChar() != ')' )
207                             // only + is allowed, parentheses are immaterial
208                             // because + is commutative
209                             break;
210                     }
211                     else if( rTok.IsInteger() )
212                     {
213                         nVal += rTok.GetNumber();
214                     }
215                     else
216                         break;
217                 }
218                 if( bOk )
219                 {
220                     InsertId( aDefName, nVal );
221                 }
222             }
223             else if( rTok.Is( SvHash_include() ) )
224             {
225                 rTok = aTokStm.GetToken_Next();
226                 OStringBuffer aNameBuf(128);
227                 if( rTok.IsString() )
228                     aNameBuf.append(rTok.GetString());
229                 else if( rTok.IsChar() && rTok.GetChar() == '<' )
230                 {
231                     rTok = aTokStm.GetToken_Next();
232                     while( !rTok.IsEof()
233                       && !(rTok.IsChar() && rTok.GetChar() == '>') )
234                     {
235                         aNameBuf.append(rTok.GetTokenAsString());
236                         rTok = aTokStm.GetToken_Next();
237                     }
238                     if( rTok.IsEof() )
239                     {
240                         throw SvParseException("unexpected eof in #include", rTok);
241                     }
242                 }
243                 OString aName(aNameBuf.makeStringAndClear());
244                 if (aName == "sfx2/groupid.hxx")
245                 {
246                     // contains C++ code which we cannot parse
247                     // we special-case this by defining a macro internally in...
248                 }
249                 else if (aName == "svl/typedwhich.hxx")
250                 {
251                     // contains C++ code which we cannot parse
252                 }
253                 else if (!ReadIdFile(aName))
254                 {
255                     throw SvParseException("cannot read file: " + aName, rTok);
256                 }
257             }
258         }
259         else
260             rTok = aTokStm.GetToken_Next();
261     }
262     return true;
263 }
264 
FindType(const SvMetaType * pPType,SvRefMemberList<SvMetaType * > & rList)265 SvMetaType * SvIdlDataBase::FindType( const SvMetaType * pPType,
266                                     SvRefMemberList<SvMetaType *>& rList )
267 {
268     for (auto const& elem : rList)
269         if( elem == pPType )
270             return elem;
271     return nullptr;
272 }
273 
FindType(std::string_view rName)274 SvMetaType * SvIdlDataBase::FindType( std::string_view rName )
275 {
276     for (auto const& elem : aTypeList)
277         if( rName == elem->GetName() )
278             return elem;
279     return nullptr;
280 }
281 
ReadKnownType(SvTokenStream & rInStm)282 SvMetaType * SvIdlDataBase::ReadKnownType( SvTokenStream & rInStm )
283 {
284     sal_uInt32  nTokPos = rInStm.Tell();
285     SvToken& rTok = rInStm.GetToken_Next();
286 
287     if( rTok.IsIdentifier() )
288     {
289         const OString& aName = rTok.GetString();
290         for( const auto& aType : GetTypeList() )
291         {
292             if( aType->GetName() == aName )
293             {
294                 return aType;
295             }
296         }
297     }
298     rInStm.Seek( nTokPos );
299     return nullptr;
300 }
301 
ReadKnownAttr(SvTokenStream & rInStm,SvMetaType * pType)302 SvMetaAttribute * SvIdlDataBase::ReadKnownAttr
303 (
304     SvTokenStream & rInStm,
305     SvMetaType *    pType   /* If pType == NULL, then the type has
306                                still to be read. */
307 )
308 {
309     sal_uInt32  nTokPos = rInStm.Tell();
310 
311     if( !pType )
312         pType = ReadKnownType( rInStm );
313 
314     if( !pType )
315     {
316         // otherwise SlotId?
317         SvToken& rTok = rInStm.GetToken_Next();
318         if( rTok.IsIdentifier() )
319         {
320             sal_uInt32 n;
321             if( FindId( rTok.GetString(), &n ) )
322             {
323                 for( size_t i = 0; i < aSlotList.size(); i++ )
324                 {
325                     SvMetaSlot * pSlot = aSlotList[i];
326                     if( pSlot->GetSlotId().getString() == rTok.GetString() )
327                         return pSlot;
328                 }
329             }
330 
331             OSL_FAIL(OString("Not found : " + rTok.GetString()).getStr());
332         }
333     }
334 
335     rInStm.Seek( nTokPos );
336     return nullptr;
337 }
338 
FindKnownAttr(const SvIdentifier & rId)339 SvMetaAttribute* SvIdlDataBase::FindKnownAttr( const SvIdentifier& rId )
340 {
341     sal_uInt32 n;
342     if( FindId( rId.getString(), &n ) )
343     {
344         for( size_t i = 0; i < aSlotList.size(); i++ )
345         {
346             SvMetaSlot * pSlot = aSlotList[i];
347             if( pSlot->GetSlotId().getString() == rId.getString() )
348                 return pSlot;
349         }
350     }
351 
352     return nullptr;
353 }
354 
ReadKnownClass(SvTokenStream & rInStm)355 SvMetaClass * SvIdlDataBase::ReadKnownClass( SvTokenStream & rInStm )
356 {
357     sal_uInt32  nTokPos = rInStm.Tell();
358     SvToken& rTok = rInStm.GetToken_Next();
359 
360     if( rTok.IsIdentifier() )
361     {
362         SvMetaClass* p = FindKnownClass(rTok.GetString());
363         if (p)
364             return p;
365     }
366 
367     rInStm.Seek( nTokPos );
368     return nullptr;
369 }
370 
FindKnownClass(std::string_view aName)371 SvMetaClass * SvIdlDataBase::FindKnownClass( std::string_view aName )
372 {
373     for( size_t n = 0; n < aClassList.size(); n++ )
374     {
375         SvMetaClass * pClass = aClassList[n];
376         if( pClass->GetName() == aName )
377             return pClass;
378     }
379     return nullptr;
380 }
381 
Write(const OString & rText) const382 void SvIdlDataBase::Write(const OString& rText) const
383 {
384     if( nVerbosity != 0 )
385         fprintf( stdout, "%s", rText.getStr() );
386 }
387 
WriteError(SvTokenStream & rInStm)388 void SvIdlDataBase::WriteError( SvTokenStream & rInStm )
389 {
390     // error treatment
391     OUString aFileName( rInStm.GetFileName() );
392     OStringBuffer aErrorText;
393     sal_uInt64   nRow = 0, nColumn = 0;
394 
395     rInStm.SeekToMax();
396     SvToken& rTok = rInStm.GetToken();
397 
398     // error position
399     nRow    = rTok.GetLine();
400     nColumn = rTok.GetColumn();
401 
402     if( aError.IsError() )
403     { // error set
404         // search error token
405         // error text
406         if( !aError.GetText().isEmpty() )
407         {
408             aErrorText.append("may be <");
409             aErrorText.append(aError.GetText());
410         }
411         SvToken * pPrevTok = nullptr;
412         while( &rTok != pPrevTok )
413         {
414             pPrevTok = &rTok;
415             if( rTok.GetLine() == aError.nLine
416               && rTok.GetColumn() == aError.nColumn )
417                 break;
418             rTok = rInStm.GetToken_PrevAll();
419         }
420 
421         // error position
422         aErrorText.append("> at ( ");
423         aErrorText.append(static_cast<sal_Int64>(aError.nLine));
424         aErrorText.append(", ");
425         aErrorText.append(static_cast<sal_Int64>(aError.nColumn));
426         aErrorText.append(" )");
427 
428         // reset error
429         aError = SvIdlError();
430     }
431 
432     // error treatment
433     fprintf( stderr, "\n%s --- %s: ( %" SAL_PRIuUINT64 ", %" SAL_PRIuUINT64 " )\n",
434              OUStringToOString(aFileName, RTL_TEXTENCODING_UTF8).getStr(),
435              "error", nRow, nColumn );
436 
437     if( !aErrorText.isEmpty() )
438     { // error set
439         fprintf( stderr, "\t%s\n", aErrorText.getStr() );
440     }
441 
442     // look for identifier close by
443     if( !rTok.IsIdentifier() )
444     {
445         rInStm.GetToken_PrevAll();
446         rTok = rInStm.GetToken();
447     }
448     if( rTok.IsIdentifier() )
449     {
450         OString aN = GetIdlApp().pHashTable->GetNearString( rTok.GetString() );
451         if( !aN.isEmpty() )
452             fprintf( stderr, "%s versus %s\n", rTok.GetString().getStr(), aN.getStr() );
453     }
454 }
455 
SvIdlWorkingBase(const SvCommand & rCmd)456 SvIdlWorkingBase::SvIdlWorkingBase(const SvCommand& rCmd) : SvIdlDataBase(rCmd)
457 {
458 }
459 
460 
WriteSfx(SvStream & rOutStm)461 bool SvIdlWorkingBase::WriteSfx( SvStream & rOutStm )
462 {
463     if( rOutStm.GetError() != ERRCODE_NONE )
464         return false;
465 
466     // reset all tmp variables for writing
467     WriteReset();
468     SvMemoryStream aTmpStm( 256000, 256000 );
469     size_t n;
470     for( n = 0; n < GetModuleList().size(); n++ )
471     {
472         SvMetaModule * pModule = GetModuleList()[n];
473         pModule->WriteSfx( *this, aTmpStm );
474         aTmpStm.Seek( 0 );
475     }
476     for( n = 0; n < aUsedTypes.size(); n++ )
477     {
478         SvMetaType * pType = aUsedTypes[n];
479         pType->WriteSfx( *this, rOutStm );
480     }
481     aUsedTypes.clear();
482     rOutStm.WriteStream( aTmpStm );
483     return true;
484 }
485 
StartNewFile(std::u16string_view rName)486 void SvIdlDataBase::StartNewFile( std::u16string_view rName )
487 {
488     bExport = aExportFile.equalsIgnoreAsciiCase( rName );
489     assert ( !bExport );
490 }
491 
AppendSlot(SvMetaSlot * pSlot)492 void SvIdlDataBase::AppendSlot( SvMetaSlot *pSlot )
493 {
494     aSlotList.push_back( pSlot );
495     assert ( !bExport );
496 }
497 
AddDepFile(OUString const & rFileName)498 void SvIdlDataBase::AddDepFile(OUString const& rFileName)
499 {
500     m_DepFiles.insert(rFileName);
501 }
502 
503 namespace {
504 
505 struct WriteDep
506 {
507     SvFileStream & m_rStream;
WriteDep__anoncb1746a60111::WriteDep508     explicit WriteDep(SvFileStream & rStream) : m_rStream(rStream) { }
operator ()__anoncb1746a60111::WriteDep509     void operator() (std::u16string_view rItem)
510     {
511         m_rStream.WriteCharPtr( " \\\n " );
512         m_rStream.WriteOString( OUStringToOString(rItem, RTL_TEXTENCODING_UTF8) );
513     }
514 };
515 
516 // write a dummy target for one included file, so the incremental build does
517 // not break with "No rule to make target" if the included file is removed
518 struct WriteDummy
519 {
520     SvFileStream & m_rStream;
WriteDummy__anoncb1746a60111::WriteDummy521     explicit WriteDummy(SvFileStream & rStream) : m_rStream(rStream) { }
operator ()__anoncb1746a60111::WriteDummy522     void operator() (std::u16string_view rItem)
523     {
524         m_rStream.WriteOString( OUStringToOString(rItem, RTL_TEXTENCODING_UTF8) );
525         m_rStream.WriteCharPtr( " :\n\n" );
526     }
527 };
528 
529 }
530 
WriteDepFile(SvFileStream & rStream,std::u16string_view rTarget)531 void SvIdlDataBase::WriteDepFile(
532         SvFileStream & rStream, std::u16string_view rTarget)
533 {
534     rStream.WriteOString( OUStringToOString(rTarget, RTL_TEXTENCODING_UTF8) );
535     rStream.WriteCharPtr( " :" );
536     ::std::for_each(m_DepFiles.begin(), m_DepFiles.end(), WriteDep(rStream));
537     rStream.WriteCharPtr( "\n\n" );
538     ::std::for_each(m_DepFiles.begin(), m_DepFiles.end(), WriteDummy(rStream));
539 }
540 
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
542