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