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 
24 #include <rtl/strbuf.hxx>
25 #include <osl/diagnose.h>
26 #include <sal/log.hxx>
27 
28 #include <object.hxx>
29 #include <globals.hxx>
30 #include <database.hxx>
31 
32 
SvClassElement()33 SvClassElement::SvClassElement()
34 {
35 };
36 
SvMetaClass()37 SvMetaClass::SvMetaClass()
38 {
39 }
40 
ReadContextSvIdl(SvIdlDataBase & rBase,SvTokenStream & rInStm)41 void SvMetaClass::ReadContextSvIdl( SvIdlDataBase & rBase,
42                                     SvTokenStream & rInStm )
43 {
44     sal_uInt32  nTokPos = rInStm.Tell();
45     SvToken&    rTok = rInStm.GetToken_Next();
46 
47     if( rTok.Is( SvHash_import() ) )
48     {
49         SvMetaClass * pClass = rBase.ReadKnownClass( rInStm );
50         if( !pClass )
51             throw SvParseException( rInStm, "unknown imported interface" );
52         SvClassElement aEle;
53         aEle.SetClass( pClass );
54         aClassElementList.push_back( aEle );
55 
56         rTok = rInStm.GetToken();
57         if( rTok.IsString() )
58         {
59             aEle.SetPrefix( rTok.GetString() );
60             rInStm.GetToken_Next();
61         }
62         return;
63     }
64     else
65     {
66         rInStm.Seek( nTokPos );
67         SvMetaType * pType = rBase.ReadKnownType( rInStm );
68 
69         bool bOk = false;
70         tools::SvRef<SvMetaAttribute> xAttr;
71         if( !pType || pType->IsItem() )
72         {
73             xAttr = new SvMetaSlot( pType );
74             if( xAttr->ReadSvIdl( rBase, rInStm ) )
75                 bOk = xAttr->Test( rInStm );
76         }
77         else
78         {
79             xAttr = new SvMetaAttribute( pType );
80             if( xAttr->ReadSvIdl( rBase, rInStm ) )
81                 bOk = xAttr->Test( rInStm );
82         }
83 
84         if( bOk )
85             bOk = TestAttribute( rBase, rInStm, *xAttr );
86         if( bOk )
87         {
88             if( !xAttr->GetSlotId().IsSet() )
89             {
90                 SvIdentifier aI;
91                 aI.SetValue( rBase.GetUniqueId() );
92                 xAttr->SetSlotId( aI );
93             }
94             aAttrList.push_back( xAttr.get() );
95             return;
96         }
97     }
98     rInStm.Seek( nTokPos );
99 }
100 
TestAttribute(SvIdlDataBase & rBase,SvTokenStream & rInStm,SvMetaAttribute & rAttr) const101 bool SvMetaClass::TestAttribute( SvIdlDataBase & rBase, SvTokenStream & rInStm,
102                                  SvMetaAttribute & rAttr ) const
103 {
104     if ( !rAttr.GetRef() && dynamic_cast<const SvMetaSlot *>(&rAttr) )
105     {
106         SAL_WARN( "idl", "new slot : " << rAttr.GetSlotId().getString() );
107     }
108 
109     for( size_t n = 0; n < aAttrList.size(); n++ )
110     {
111         SvMetaAttribute * pS = aAttrList[n];
112         if( pS->GetName() == rAttr.GetName() )
113         {
114             // values have to match
115             if( pS->GetSlotId().GetValue() != rAttr.GetSlotId().GetValue() )
116             {
117                 throw SvParseException( rInStm, "Attribute's " + pS->GetName() + " with different id's");
118              }
119         }
120         else
121         {
122             sal_uInt32 nId1 = pS->GetSlotId().GetValue();
123             sal_uInt32 nId2 = rAttr.GetSlotId().GetValue();
124             if( nId1 == nId2 && nId1 != 0 )
125             {
126                 OString aStr = "Attribute " + pS->GetName() + " and Attribute " + rAttr.GetName() + " with equal id's";
127                 throw SvParseException(rInStm, aStr);
128              }
129         }
130     }
131     SvMetaClass * pSC = aSuperClass.get();
132     if( pSC )
133         return pSC->TestAttribute( rBase, rInStm, rAttr );
134     return true;
135 }
136 
WriteSlotParamArray(SvIdlDataBase & rBase,SvSlotElementList & rSlotList,SvStream & rOutStm)137 sal_uInt16 SvMetaClass::WriteSlotParamArray( SvIdlDataBase & rBase,
138                                         SvSlotElementList & rSlotList,
139                                         SvStream & rOutStm )
140 {
141     sal_uInt16 nCount = 0;
142     for ( size_t i = 0, n = rSlotList.size(); i < n; ++i )
143     {
144         SvMetaSlot *pAttr = rSlotList[ i ];
145         nCount = nCount + pAttr->WriteSlotParamArray( rBase, rOutStm );
146     }
147 
148     return nCount;
149 }
150 
WriteSlots(std::string_view rShellName,SvSlotElementList & rSlotList,SvIdlDataBase & rBase,SvStream & rOutStm)151 sal_uInt16 SvMetaClass::WriteSlots( std::string_view rShellName,
152                                 SvSlotElementList & rSlotList,
153                                 SvIdlDataBase & rBase,
154                                 SvStream & rOutStm )
155 {
156     sal_uInt16 nSCount = 0;
157     for ( size_t i = 0, n = rSlotList.size(); i < n; ++i )
158     {
159         SvMetaSlot * pAttr = rSlotList[ i ];
160         nSCount = nSCount + pAttr->WriteSlotMap( rShellName, nSCount,
161                                         rSlotList, i, rBase,
162                                         rOutStm );
163     }
164 
165     return nSCount;
166 }
167 
InsertSlots(SvSlotElementList & rList,std::vector<sal_uLong> & rSuperList,SvMetaClassList & rClassList,const OString & rPrefix,SvIdlDataBase & rBase)168 void SvMetaClass::InsertSlots( SvSlotElementList& rList, std::vector<sal_uLong>& rSuperList,
169                             SvMetaClassList &rClassList,
170                             const OString& rPrefix, SvIdlDataBase& rBase)
171 {
172     // was this class already written?
173     for ( size_t i = 0, n = rClassList.size(); i < n ; ++i )
174         if ( rClassList[ i ] == this )
175             return;
176 
177     rClassList.push_back( this );
178 
179     // write all direct attributes
180     sal_uLong n;
181     for( n = 0; n < aAttrList.size(); n++ )
182     {
183         SvMetaAttribute * pAttr = aAttrList[n];
184 
185         sal_uLong nId = pAttr->GetSlotId().GetValue();
186 
187         std::vector<sal_uLong>::iterator iter = std::find(rSuperList.begin(),
188                                                       rSuperList.end(),nId);
189 
190         if( iter == rSuperList.end() )
191         {
192             // Write only if not already written by subclass or
193             // imported interface.
194             rSuperList.push_back(nId);
195             pAttr->Insert(rList);
196         }
197     }
198 
199     // All Interfaces already imported by SuperShell should not be
200     // written any more.
201     // It is prohibited that Shell and SuperShell directly import the same
202     // class.
203     if( GetMetaTypeType() == MetaTypeType::Shell && aSuperClass.is() )
204         aSuperClass->FillClasses( rClassList );
205 
206     // Write all attributes of the imported classes, as long as they have
207     // not already been imported by the superclass.
208     for( n = 0; n < aClassElementList.size(); n++ )
209     {
210         SvClassElement& rElement = aClassElementList[n];
211         SvMetaClass * pCl = rElement.GetClass();
212         OStringBuffer rPre(rPrefix.getLength() + 1 + rElement.GetPrefix().getLength());
213         rPre.append(rPrefix);
214         if( !rPre.isEmpty() && !rElement.GetPrefix().isEmpty() )
215             rPre.append('.');
216         rPre.append(rElement.GetPrefix());
217 
218         // first of all write direct imported interfaces
219         pCl->InsertSlots( rList, rSuperList, rClassList,
220             rPre.makeStringAndClear(), rBase );
221     }
222 
223     // only write superclass if no shell and not in the list
224     if( GetMetaTypeType() != MetaTypeType::Shell && aSuperClass.is() )
225     {
226         aSuperClass->InsertSlots( rList, rSuperList, rClassList, rPrefix, rBase );
227     }
228 }
229 
FillClasses(SvMetaClassList & rList)230 void SvMetaClass::FillClasses( SvMetaClassList & rList )
231 {
232     // Am I not yet in?
233     for ( size_t i = 0, n = rList.size(); i < n; ++i )
234         if ( rList[ i ] == this )
235             return;
236 
237     rList.push_back( this );
238 
239     // my imports
240     for( size_t n = 0; n < aClassElementList.size(); n++ )
241     {
242         SvClassElement& rElement = aClassElementList[n];
243         SvMetaClass * pCl = rElement.GetClass();
244         pCl->FillClasses( rList );
245     }
246 
247     // my superclass
248     if( aSuperClass.is() )
249         aSuperClass->FillClasses( rList );
250 }
251 
252 
WriteSlotStubs(std::string_view rShellName,SvSlotElementList & rSlotList,std::vector<OString> & rList,SvStream & rOutStm)253 void SvMetaClass::WriteSlotStubs( std::string_view rShellName,
254                                 SvSlotElementList & rSlotList,
255                                 std::vector<OString> & rList,
256                                 SvStream & rOutStm )
257 {
258     // write all attributes
259     for ( size_t i = 0, n = rSlotList.size(); i < n; ++i )
260     {
261         SvMetaSlot *pAttr = rSlotList[ i ];
262         pAttr->WriteSlotStubs( rShellName, rList, rOutStm );
263     }
264 }
265 
WriteSfx(SvIdlDataBase & rBase,SvStream & rOutStm)266 void SvMetaClass::WriteSfx( SvIdlDataBase & rBase, SvStream & rOutStm )
267 {
268     WriteStars( rOutStm );
269     // define class
270     rOutStm.WriteCharPtr( "#ifdef ShellClass_" ).WriteOString( GetName() ) << endl;
271     rOutStm.WriteCharPtr( "#undef ShellClass" ) << endl;
272     rOutStm.WriteCharPtr( "#undef ShellClass_" ).WriteOString( GetName() ) << endl;
273     rOutStm.WriteCharPtr( "#define ShellClass " ).WriteOString( GetName() ) << endl;
274 
275     // no slotmaps get written for interfaces
276     if( GetMetaTypeType() != MetaTypeType::Shell )
277     {
278         rOutStm.WriteCharPtr( "#endif" ) << endl << endl;
279         return;
280     }
281     // write parameter array
282     rOutStm.WriteCharPtr("static SfxFormalArgument a").WriteOString(GetName()).WriteCharPtr("Args_Impl[] =") << endl;
283     rOutStm.WriteChar('{') << endl;
284 
285     std::vector<sal_uLong> aSuperList;
286     SvMetaClassList classList;
287     SvSlotElementList aSlotList;
288     InsertSlots(aSlotList, aSuperList, classList, OString(), rBase);
289     for ( size_t i = 0, n = aSlotList.size(); i < n; ++i )
290     {
291         SvMetaSlot *pSlot = aSlotList[ i ];
292         pSlot->SetListPos( i );
293     }
294 
295     size_t nSlotCount = aSlotList.size();
296 
297     // write all attributes
298     sal_uInt16 nArgCount = WriteSlotParamArray( rBase, aSlotList, rOutStm );
299     if( nArgCount )
300         Back2Delimiter( rOutStm );
301     else
302     {
303         // at least one dummy
304         WriteTab( rOutStm, 1 );
305         rOutStm.WriteCharPtr("{ (const SfxType*) &aSfxVoidItem_Impl, 0, 0 }" ) << endl;
306     }
307     rOutStm << endl;
308     rOutStm.WriteCharPtr( "};" ) << endl << endl;
309 
310     std::vector<OString> aStringList;
311     WriteSlotStubs( GetName(), aSlotList, aStringList, rOutStm );
312     aStringList.clear();
313 
314     rOutStm << endl;
315 
316     // write slotmap
317     rOutStm.WriteCharPtr("static SfxSlot a").WriteOString(GetName()).WriteCharPtr("Slots_Impl[] =") << endl;
318     rOutStm.WriteChar( '{' ) << endl;
319 
320     // write all attributes
321     WriteSlots( GetName(), aSlotList, rBase, rOutStm );
322     if( nSlotCount )
323         Back2Delimiter( rOutStm );
324     else
325     {
326         // at least one dummy
327         WriteTab( rOutStm, 1 );
328         rOutStm.WriteCharPtr( "SFX_SLOT_ARG(" ).WriteOString( GetName() )
329                .WriteCharPtr( ", 0, SfxGroupId::NONE, " )
330                .WriteCharPtr( "SFX_STUB_PTR_EXEC_NONE," )
331                .WriteCharPtr( "SFX_STUB_PTR_STATE_NONE," )
332                .WriteCharPtr( "SfxSlotMode::NONE, SfxVoidItem, 0, 0, \"\", SfxSlotMode::NONE )" ) << endl;
333     }
334     rOutStm << endl;
335     rOutStm.WriteCharPtr( "};" ) << endl;
336     rOutStm.WriteCharPtr( "#endif" ) << endl << endl;
337 
338     for( size_t i = 0, n = aSlotList.size(); i < n; ++i )
339     {
340         SvMetaSlot* pAttr = aSlotList[ i ];
341         pAttr->ResetSlotPointer();
342     }
343 
344     aSlotList.clear();
345 }
346 
347 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
348