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 <sal/config.h>
25 #include <database.hxx>
26 #include <globals.hxx>
28 #include <osl/file.hxx>
30 void SvIdlParser::ReadSvIdl( const OUString
& rPath
)
32 rBase
.SetPath(rPath
); // only valid for this iteration
33 SvToken
& rTok
= rInStm
.GetToken();
37 rTok
= rInStm
.GetToken();
41 Read( SvHash_module() );
42 tools::SvRef
<SvMetaModule
> aModule
= new SvMetaModule
;
43 ReadModuleHeader(*aModule
);
44 rBase
.GetModuleList().push_back( aModule
.get() );
48 void SvIdlParser::ReadModuleHeader(SvMetaModule
& rModule
)
50 OString aName
= ReadIdentifier();
51 rModule
.SetName( aName
);
52 rBase
.Push( &rModule
); // onto the context stack
53 ReadModuleBody(rModule
);
54 rBase
.GetStack().pop_back(); // remove from stack
57 void SvIdlParser::ReadModuleBody(SvMetaModule
& rModule
)
64 if( !ReadStringSvIdl( SvHash_SlotIdFile(), rInStm
, aSlotIdFile
) )
66 if( !rBase
.ReadIdFile( aSlotIdFile
) )
68 throw SvParseException( rInStm
, "cannot read file: " + aSlotIdFile
);
78 sal_uInt32 nBeginPos
= 0;
79 while( nBeginPos
!= rInStm
.Tell() )
81 nBeginPos
= rInStm
.Tell();
82 ReadModuleElement( rModule
);
88 void SvIdlParser::ReadModuleElement( SvMetaModule
& rModule
)
90 if( ReadIf( SvHash_interface() ) )
92 ReadInterfaceOrShell(rModule
, MetaTypeType::Interface
);
94 else if( ReadIf( SvHash_shell() ) )
96 ReadInterfaceOrShell(rModule
, MetaTypeType::Shell
);
98 else if( ReadIf( SvHash_enum() ) )
102 else if( ReadIf( SvHash_item() ) )
106 else if( ReadIf( SvHash_struct() ) )
110 else if( ReadIf( SvHash_include() ) )
112 ReadInclude(rModule
);
116 tools::SvRef
<SvMetaSlot
> xSlot( new SvMetaSlot() );
118 if (ReadSlot(*xSlot
))
120 if( xSlot
->Test( rInStm
) )
123 rBase
.AppendSlot( xSlot
.get() );
129 void SvIdlParser::ReadInclude( SvMetaModule
& rModule
)
131 sal_uInt32 nTokPos
= rInStm
.Tell();
133 OUString
aFullName(OStringToOUString(ReadString(), RTL_TEXTENCODING_ASCII_US
));
134 rBase
.StartNewFile( aFullName
);
135 osl::FileBase::RC searchError
= osl::File::searchFileURL(aFullName
, rBase
.GetPath(), aFullName
);
136 if( osl::FileBase::E_None
!= searchError
)
138 OString aStr
= "cannot find file:" +
139 OUStringToOString(aFullName
, RTL_TEXTENCODING_UTF8
);
140 throw SvParseException(aStr
, rInStm
.GetToken());
142 osl::FileBase::getSystemPathFromFileURL( aFullName
, aFullName
);
143 rBase
.AddDepFile( aFullName
);
144 SvTokenStream
aTokStm( aFullName
);
145 if( ERRCODE_NONE
!= aTokStm
.GetStream().GetError() )
147 OString aStr
= "cannot open file: " +
148 OUStringToOString(aFullName
, RTL_TEXTENCODING_UTF8
);
149 throw SvParseException(aStr
, rInStm
.GetToken());
151 // rescue error from old file
152 SvIdlError aOldErr
= rBase
.GetError();
154 rBase
.SetError( SvIdlError() );
157 SvIdlParser
aIncludeParser( rBase
, aTokStm
);
158 sal_uInt32 nBeginPos
= 0xFFFFFFFF; // can not happen with Tell
159 while( nBeginPos
!= aTokStm
.Tell() )
161 nBeginPos
= aTokStm
.Tell();
162 aIncludeParser
.ReadModuleElement(rModule
);
163 aTokStm
.ReadIfDelimiter();
165 } catch (const SvParseException
& ex
) {
166 rBase
.SetError(ex
.aError
);
167 rBase
.WriteError(aTokStm
);
169 bOk
= aTokStm
.GetToken().IsEof();
172 rBase
.WriteError( aTokStm
);
174 // recover error from old file
175 rBase
.SetError( aOldErr
);
177 rInStm
.Seek( nTokPos
);
180 void SvIdlParser::ReadStruct()
182 tools::SvRef
<SvMetaType
> xStruct(new SvMetaType() );
183 xStruct
->SetType( MetaTypeType::Struct
);
184 xStruct
->SetName( ReadIdentifier() );
188 tools::SvRef
<SvMetaAttribute
> xAttr( new SvMetaAttribute() );
189 xAttr
->aType
= ReadKnownType();
190 xAttr
->SetName(ReadIdentifier());
191 xAttr
->aSlotId
.setString(ReadIdentifier());
193 if( !rBase
.FindId( xAttr
->aSlotId
.getString(), &n
) )
194 throw SvParseException( rInStm
, "no value for identifier <" + xAttr
->aSlotId
.getString() + "> " );
195 xAttr
->aSlotId
.SetValue(n
);
196 xStruct
->GetAttrList().push_back( xAttr
.get() );
197 if( !ReadIfDelimiter() )
199 if( rInStm
.GetToken().IsChar() && rInStm
.GetToken().GetChar() == '}')
205 rBase
.GetTypeList().push_back( xStruct
.get() );
208 void SvIdlParser::ReadItem()
210 tools::SvRef
<SvMetaType
> xItem(new SvMetaType() );
211 xItem
->SetItem(true);
212 xItem
->SetRef( ReadKnownType() );
213 xItem
->SetName( ReadIdentifier() );
215 rBase
.GetTypeList().push_back( xItem
.get() );
218 void SvIdlParser::ReadEnum()
220 tools::SvRef
<SvMetaTypeEnum
> xEnum( new SvMetaTypeEnum() );
221 xEnum
->SetType( MetaTypeType::Enum
);
222 xEnum
->SetName( ReadIdentifier() );
227 ReadEnumValue( *xEnum
);
228 if( !ReadIfDelimiter() )
233 rBase
.GetTypeList().push_back( xEnum
.get() );
236 static std::string_view
getCommonSubPrefix(std::string_view rA
, std::string_view rB
)
238 sal_Int32 nMax
= std::min(rA
.size(), rB
.size());
242 if (rA
[nI
] != rB
[nI
])
246 return rA
.substr(0, nI
);
249 void SvIdlParser::ReadEnumValue( SvMetaTypeEnum
& rEnum
)
251 tools::SvRef
<SvMetaEnumValue
> aEnumVal
= new SvMetaEnumValue();
252 aEnumVal
->SetName( ReadIdentifier() );
253 if( rEnum
.aEnumValueList
.empty() )
256 rEnum
.aPrefix
= aEnumVal
->GetName();
260 rEnum
.aPrefix
= OString(getCommonSubPrefix(rEnum
.aPrefix
, aEnumVal
->GetName()));
262 rEnum
.aEnumValueList
.push_back( aEnumVal
.get() );
265 void SvIdlParser::ReadInterfaceOrShell( SvMetaModule
& rModule
, MetaTypeType aMetaTypeType
)
267 tools::SvRef
<SvMetaClass
> aClass( new SvMetaClass() );
269 aClass
->SetType( aMetaTypeType
);
271 aClass
->SetName( ReadIdentifier() );
275 aClass
->aSuperClass
= ReadKnownClass();
279 sal_uInt32 nBeginPos
= 0; // can not happen with Tell
280 while( nBeginPos
!= rInStm
.Tell() )
282 nBeginPos
= rInStm
.Tell();
283 ReadInterfaceOrShellEntry(*aClass
);
288 rModule
.aClassList
.push_back( aClass
.get() );
290 rBase
.GetClassList().push_back( aClass
.get() );
293 void SvIdlParser::ReadInterfaceOrShellEntry(SvMetaClass
& rClass
)
295 if( ReadIf( SvHash_import() ) )
297 SvMetaClass
* pClass
= ReadKnownClass();
298 SvClassElement
aEle(pClass
);
299 SvToken
& rTok
= rInStm
.GetToken();
300 if( rTok
.IsString() )
302 aEle
.SetPrefix( rTok
.GetString() );
303 rInStm
.GetToken_Next();
305 rClass
.aClassElementList
.push_back( aEle
);
309 SvMetaType
* pType
= rBase
.ReadKnownType( rInStm
);
310 tools::SvRef
<SvMetaAttribute
> xAttr
;
312 if( !pType
|| pType
->IsItem() )
314 xAttr
= new SvMetaSlot( pType
);
315 bOk
= ReadSlot(static_cast<SvMetaSlot
&>(*xAttr
));
319 xAttr
= new SvMetaAttribute( pType
);
320 ReadInterfaceOrShellMethod(*xAttr
);
324 bOk
= xAttr
->Test( rInStm
);
326 bOk
= rClass
.TestAttribute( rBase
, rInStm
, *xAttr
);
329 if( !xAttr
->GetSlotId().IsSet() )
330 xAttr
->SetSlotId( SvIdentifier(rBase
.GetUniqueId()) );
331 rClass
.aAttrList
.push_back( xAttr
.get() );
336 bool SvIdlParser::ReadSlot(SvMetaSlot
& rSlot
)
338 sal_uInt32 nTokPos
= rInStm
.Tell();
341 SvMetaAttribute
* pAttr
= rBase
.ReadKnownAttr( rInStm
, rSlot
.GetType() );
344 SvMetaSlot
* pKnownSlot
= dynamic_cast<SvMetaSlot
*>( pAttr
);
346 throw SvParseException( rInStm
, "attribute " + pAttr
->GetName() + " is method or variable but not a slot" );
347 rSlot
.SetRef( pKnownSlot
);
348 rSlot
.SetName( pKnownSlot
->GetName() );
351 sal_uInt32 nBeginPos
= 0; // can not happen with Tell
352 while( nBeginPos
!= rInStm
.Tell() )
354 nBeginPos
= rInStm
.Tell();
355 ReadSlotAttribute(rSlot
);
363 bOk
= rSlot
.SvMetaAttribute::ReadSvIdl( rBase
, rInStm
);
364 SvMetaAttribute
*pAttr2
= rBase
.FindKnownAttr( rSlot
.GetSlotId() );
367 SvMetaSlot
* pKnownSlot
= dynamic_cast<SvMetaSlot
*>( pAttr2
);
369 throw SvParseException( rInStm
, "attribute " + pAttr2
->GetName() + " is method or variable but not a slot" );
370 rSlot
.SetRef( pKnownSlot
);
371 // names may differ, because explicitly given
372 if ( pKnownSlot
->GetName() != rSlot
.GetName() )
373 throw SvParseException( rInStm
, "Illegal definition!"_ostr
);
378 rInStm
.Seek( nTokPos
);
383 void SvIdlParser::ReadSlotAttribute( SvMetaSlot
& rSlot
)
385 ReadIfIdAttribute(rSlot
.aGroupId
, SvHash_GroupId() );
386 ReadIfIdAttribute(rSlot
.aExecMethod
, SvHash_ExecMethod() );
387 ReadIfIdAttribute(rSlot
.aStateMethod
, SvHash_StateMethod() );
388 ReadStringSvIdl( SvHash_DisableFlags(), rInStm
, rSlot
.aDisableFlags
);
389 ReadIfBoolAttribute(rSlot
.aReadOnlyDoc
, SvHash_ReadOnlyDoc() );
391 ReadIfBoolAttribute(rSlot
.aToggle
, SvHash_Toggle() );
392 ReadIfBoolAttribute(rSlot
.aAutoUpdate
, SvHash_AutoUpdate() );
393 ReadIfBoolAttribute(rSlot
.aAsynchron
, SvHash_Asynchron() );
394 ReadIfBoolAttribute(rSlot
.aRecordAbsolute
, SvHash_RecordAbsolute() );
396 if( ReadIfBoolAttribute(rSlot
.aRecordPerItem
, SvHash_RecordPerItem()) )
398 if (rSlot
.aRecordPerSet
.IsSet() || rSlot
.aNoRecord
.IsSet())
399 throw SvParseException(rInStm
, "conflicting attributes"_ostr
);
400 rSlot
.SetRecordPerItem( rSlot
.aRecordPerItem
);
402 if( ReadIfBoolAttribute(rSlot
.aRecordPerSet
, SvHash_RecordPerSet() ) )
404 if (rSlot
.aRecordPerItem
.IsSet() || rSlot
.aNoRecord
.IsSet())
405 throw SvParseException(rInStm
, "conflicting attributes"_ostr
);
406 rSlot
.SetRecordPerSet( rSlot
.aRecordPerSet
);
408 if( ReadIfBoolAttribute(rSlot
.aNoRecord
, SvHash_NoRecord() ) )
410 if (rSlot
.aRecordPerItem
.IsSet() || rSlot
.aRecordPerSet
.IsSet())
411 throw SvParseException(rInStm
, "conflicting attributes"_ostr
);
412 rSlot
.SetNoRecord( rSlot
.aNoRecord
);
415 ReadIfBoolAttribute(rSlot
.aMenuConfig
, SvHash_MenuConfig() );
416 ReadIfBoolAttribute(rSlot
.aToolBoxConfig
, SvHash_ToolBoxConfig() );
417 ReadIfBoolAttribute(rSlot
.aAccelConfig
, SvHash_AccelConfig() );
419 ReadIfBoolAttribute(rSlot
.aFastCall
, SvHash_FastCall() );
420 ReadIfBoolAttribute(rSlot
.aContainer
, SvHash_Container() );
423 void SvIdlParser::ReadInterfaceOrShellMethod( SvMetaAttribute
& rAttr
)
425 rAttr
.SetName( ReadIdentifier() );
426 ReadSlotId( rAttr
.aSlotId
);
428 // read method arguments
430 tools::SvRef
<SvMetaType
> xT(new SvMetaType() );
431 xT
->SetRef(rAttr
.GetType() );
432 rAttr
.aType
= std::move(xT
);
433 rAttr
.aType
->SetType( MetaTypeType::Method
);
439 tools::SvRef
<SvMetaAttribute
> xParamAttr( new SvMetaAttribute() );
440 xParamAttr
->aType
= ReadKnownType();
441 xParamAttr
->SetName( ReadIdentifier() );
442 ReadSlotId(xParamAttr
->aSlotId
);
443 rAttr
.aType
->GetAttrList().push_back( xParamAttr
.get() );
444 if (!ReadIfDelimiter())
450 void SvIdlParser::ReadSlotId(SvIdentifier
& rSlotId
)
452 rSlotId
.setString( ReadIdentifier() );
454 if( !rBase
.FindId( rSlotId
.getString(), &n
) )
455 throw SvParseException( rInStm
, "no value for identifier <" + rSlotId
.getString() + "> " );
459 SvMetaClass
* SvIdlParser::ReadKnownClass()
461 OString
aName(ReadIdentifier());
462 SvMetaClass
* pClass
= rBase
.FindKnownClass( aName
);
464 throw SvParseException( rInStm
, "unknown class"_ostr
);
468 SvMetaType
* SvIdlParser::ReadKnownType()
470 OString aName
= ReadIdentifier();
471 for( const auto& aType
: rBase
.GetTypeList() )
473 if( aType
->GetName() == aName
)
476 throw SvParseException( rInStm
, "wrong typedef: "_ostr
);
479 bool SvIdlParser::ReadIfBoolAttribute( SvBOOL
& rBool
, SvStringHashEntry
const * pName
)
481 sal_uInt32 nTokPos
= rInStm
.Tell();
482 SvToken
& rTok
= rInStm
.GetToken_Next();
484 if( rTok
.Is( pName
) )
486 if( rInStm
.ReadIf( '=' ) )
488 rTok
= rInStm
.GetToken();
490 throw SvParseException(rInStm
, "xxx"_ostr
);
491 rBool
= rTok
.GetBool();
492 rInStm
.GetToken_Next();
495 rBool
= true; //default action set to TRUE
498 rInStm
.Seek( nTokPos
);
502 void SvIdlParser::ReadIfIdAttribute( SvIdentifier
& rIdentifier
, SvStringHashEntry
const * pName
)
504 sal_uInt32 nTokPos
= rInStm
.Tell();
505 SvToken
& rTok
= rInStm
.GetToken_Next();
507 if( rTok
.Is( pName
) )
509 if( rInStm
.ReadIf( '=' ) )
511 rTok
= rInStm
.GetToken();
512 if( !rTok
.IsIdentifier() )
513 throw SvParseException(rInStm
, "expected identifier"_ostr
);
514 rIdentifier
.setString(rTok
.GetString());
515 rInStm
.GetToken_Next();
519 rInStm
.Seek( nTokPos
);
522 void SvIdlParser::ReadDelimiter()
524 if( !ReadIfDelimiter() )
525 throw SvParseException(rInStm
, "expected delimiter"_ostr
);
528 bool SvIdlParser::ReadIfDelimiter()
530 if( rInStm
.GetToken().IsChar()
531 && (';' == rInStm
.GetToken().GetChar()
532 || ',' == rInStm
.GetToken().GetChar()) )
534 rInStm
.GetToken_Next();
540 OString
SvIdlParser::ReadIdentifier()
542 SvToken
& rTok
= rInStm
.GetToken();
543 if( !rTok
.IsIdentifier() )
544 throw SvParseException("expected identifier"_ostr
, rTok
);
545 rInStm
.GetToken_Next();
546 return rTok
.GetString();
549 OString
SvIdlParser::ReadString()
551 SvToken
& rTok
= rInStm
.GetToken();
552 if( !rTok
.IsString() )
553 throw SvParseException("expected string"_ostr
, rTok
);
554 rInStm
.GetToken_Next();
555 return rTok
.GetString();
558 void SvIdlParser::Read(char cChar
)
561 throw SvParseException(rInStm
, "expected char '" + OStringChar(cChar
) + "'");
564 bool SvIdlParser::ReadIf(char cChar
)
566 if( rInStm
.GetToken().IsChar() && rInStm
.GetToken().GetChar() == cChar
)
568 rInStm
.GetToken_Next();
574 void SvIdlParser::Read(SvStringHashEntry
const * entry
)
576 if( !rInStm
.GetToken().Is(entry
) )
577 throw SvParseException("expected " + entry
->GetName(), rInStm
.GetToken());
578 rInStm
.GetToken_Next();
581 bool SvIdlParser::ReadIf(SvStringHashEntry
const * entry
)
583 if( rInStm
.GetToken().Is(entry
) )
585 rInStm
.GetToken_Next();
590 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */