Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/basic/source/sbx/sbxbase.cxx
Line
Count
Source
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 <memory>
21
#include <tools/debug.hxx>
22
#include <tools/stream.hxx>
23
#include <vcl/svapp.hxx>
24
25
#include <basic/sbx.hxx>
26
#include <sbxfac.hxx>
27
#include <sbxform.hxx>
28
#include <basic/sbxmeth.hxx>
29
#include <sbxprop.hxx>
30
#include <sbxbase.hxx>
31
32
#include <rtl/ustring.hxx>
33
#include <sal/log.hxx>
34
#include <filefmt.hxx>
35
36
// AppData-Structure for SBX:
37
38
39
SbxAppData::SbxAppData()
40
21
    : eErrCode(ERRCODE_NONE)
41
21
    , aErrorMsg(OUString())
42
21
    , eBasicFormaterLangType(LANGUAGE_DONTKNOW)
43
21
{
44
21
}
45
46
SbxAppData::~SbxAppData()
47
0
{
48
0
    SolarMutexGuard g;
49
50
0
    pBasicFormater.reset();
51
    // basic manager repository must be destroyed before factories
52
0
    mrImplRepository.clear();
53
0
}
54
55
SbxBase::SbxBase()
56
4.95k
{
57
4.95k
    nFlags  = SbxFlagBits::ReadWrite;
58
4.95k
}
59
60
50.3k
SbxBase::SbxBase(const SbxBase& r) = default;
61
62
SbxBase::~SbxBase()
63
55.2k
{
64
55.2k
}
65
66
SbxBase& SbxBase::operator=( const SbxBase& r )
67
0
{
68
0
    nFlags = r.nFlags;
69
0
    return *this;
70
0
}
71
72
SbxDataType SbxBase::GetType() const
73
0
{
74
0
    return SbxEMPTY;
75
0
}
76
77
bool SbxBase::IsFixed() const
78
0
{
79
0
    return IsSet( SbxFlagBits::Fixed );
80
0
}
81
82
void SbxBase::SetModified( bool b )
83
71.9k
{
84
71.9k
    if( IsSet( SbxFlagBits::NoModify ) )
85
0
        return;
86
71.9k
    if( b )
87
71.9k
        SetFlag( SbxFlagBits::Modified );
88
0
    else
89
0
        ResetFlag( SbxFlagBits::Modified );
90
71.9k
}
91
92
ErrCode const & SbxBase::GetError()
93
81.3k
{
94
81.3k
    return GetSbxData_Impl().eErrCode;
95
81.3k
}
96
97
OUString const & SbxBase::GetErrorMsg()
98
0
{
99
0
    return GetSbxData_Impl().aErrorMsg;
100
0
}
101
102
void SbxBase::SetError(ErrCode e, const OUString& rMsg)
103
0
{
104
0
    SbxAppData& r = GetSbxData_Impl();
105
0
    if (e && r.eErrCode == ERRCODE_NONE)
106
0
    {
107
0
        r.eErrCode = e;
108
0
        r.aErrorMsg = rMsg;
109
0
    }
110
0
}
111
112
void SbxBase::SetError( ErrCode e )
113
0
{
114
0
    SbxAppData& r = GetSbxData_Impl();
115
0
    if( e && r.eErrCode == ERRCODE_NONE )
116
0
        r.eErrCode = e;
117
0
}
118
119
bool SbxBase::IsError()
120
81.8k
{
121
81.8k
    return GetSbxData_Impl().eErrCode != ERRCODE_NONE;
122
81.8k
}
123
124
void SbxBase::ResetError()
125
0
{
126
0
    GetSbxData_Impl().eErrCode = ERRCODE_NONE;
127
0
    GetSbxData_Impl().aErrorMsg = OUString();
128
0
}
129
130
void SbxBase::AddFactory( SbxFactory* pFac )
131
0
{
132
0
    GetSbxData_Impl().m_Factories.emplace_back(pFac);
133
0
}
134
135
void SbxBase::RemoveFactory( SbxFactory const * pFac )
136
0
{
137
0
    if (!IsSbxData_Impl())
138
0
        return;
139
0
    SbxAppData& r = GetSbxData_Impl();
140
0
    auto it = std::find(r.m_Factories.begin(), r.m_Factories.end(), pFac);
141
0
    if (it != r.m_Factories.end())
142
0
        r.m_Factories.erase( it );
143
0
}
144
145
146
SbxBaseRef SbxBase::Create( sal_uInt16 nSbxId, sal_uInt32 nCreator )
147
0
{
148
    // #91626: Hack to skip old Basic dialogs
149
    // Problem: There does not exist a factory any more,
150
    // so we have to create a dummy SbxVariable instead
151
0
    if( nSbxId == 0x65 )    // Dialog Id
152
0
        return new SbxVariable;
153
154
0
    if( nCreator == SBXCR_SBX )
155
0
      switch( nSbxId )
156
0
    {
157
0
        case SBXID_VALUE:       return new SbxValue;
158
0
        case SBXID_VARIABLE:    return new SbxVariable;
159
0
        case SBXID_ARRAY:       return new SbxArray;
160
0
        case SBXID_DIMARRAY:    return new SbxDimArray;
161
0
        case SBXID_OBJECT:      return new SbxObject( u""_ustr );
162
0
        case SBXID_COLLECTION:  return new SbxCollection;
163
0
        case SBXID_FIXCOLLECTION:
164
0
                                return new SbxStdCollection;
165
0
        case SBXID_METHOD:      return new SbxMethod( u""_ustr, SbxEMPTY );
166
0
        case SBXID_PROPERTY:    return new SbxProperty( u""_ustr, SbxEMPTY );
167
0
    }
168
    // Unknown type: go over the factories!
169
0
    SbxAppData& r = GetSbxData_Impl();
170
0
    SbxBaseRef pNew;
171
0
    for (auto const& rpFac : r.m_Factories)
172
0
    {
173
0
        pNew = rpFac->Create( nSbxId, nCreator );
174
0
        if( pNew )
175
0
            break;
176
0
    }
177
0
    SAL_WARN_IF(!pNew, "basic", "No factory for SBX ID " << nSbxId);
178
0
    return pNew;
179
0
}
180
181
SbxObjectRef SbxBase::CreateObject( const OUString& rClass )
182
0
{
183
0
    SbxAppData& r = GetSbxData_Impl();
184
0
    SbxObjectRef pNew;
185
0
    for (auto const& rpFac : r.m_Factories)
186
0
    {
187
0
        pNew = rpFac->CreateObject( rClass );
188
0
        if( pNew )
189
0
            break;
190
0
    }
191
0
    SAL_WARN_IF(!pNew, "basic", "No factory for object class " << rClass);
192
0
    return pNew;
193
0
}
194
195
namespace {
196
197
[[nodiscard]] SbxFlagBits CorrectFlags(SbxFlagBits nFlags)
198
0
{
199
    // Correcting a foolishness of mine:
200
0
    if (nFlags & SbxFlagBits::Reserved)
201
0
        nFlags |= SbxFlagBits::GlobalSearch;
202
0
    return nFlags & ~SbxFlagBits::Reserved;
203
0
}
204
205
}
206
207
SbxBaseRef SbxBase::Load( SvStream& rStrm )
208
0
{
209
0
    sal_uInt16 nSbxId(0), nFlagsTmp(0), nVer(0);
210
0
    sal_uInt32 nCreator(0), nSize(0);
211
0
    rStrm.ReadUInt32( nCreator ).ReadUInt16( nSbxId ).ReadUInt16( nFlagsTmp ).ReadUInt16( nVer );
212
0
    SbxFlagBits nFlags = CorrectFlags(static_cast<SbxFlagBits>(nFlagsTmp));
213
214
0
    sal_uInt64 nOldPos = rStrm.Tell();
215
0
    rStrm.ReadUInt32( nSize );
216
0
    SbxBaseRef p = Create( nSbxId, nCreator );
217
0
    if( p )
218
0
    {
219
0
        p->nFlags = nFlags;
220
0
        if( p->LoadData( rStrm, nVer ) )
221
0
        {
222
0
            sal_uInt64 const nNewPos = rStrm.Tell();
223
0
            nOldPos += nSize;
224
0
            DBG_ASSERT( nOldPos >= nNewPos, "SBX: Too much data loaded" );
225
0
            if( nOldPos != nNewPos )
226
0
                rStrm.Seek( nOldPos );
227
0
            if( !p->LoadCompleted() )
228
0
            {
229
                // Deleting of the object
230
0
                SbxBaseRef xDeleteRef( p );
231
0
                p = nullptr;
232
0
            }
233
0
        }
234
0
        else
235
0
        {
236
0
            rStrm.SetError( SVSTREAM_FILEFORMAT_ERROR );
237
            // Deleting of the object
238
0
            SbxBaseRef xDeleteRef( p );
239
0
            p = nullptr;
240
0
        }
241
0
    }
242
0
    else
243
0
        rStrm.SetError( SVSTREAM_FILEFORMAT_ERROR );
244
0
    return p;
245
0
}
246
247
std::pair<bool, sal_uInt32> SbxBase::Store( SvStream& rStrm )
248
0
{
249
0
    if( ( nFlags & SbxFlagBits::DontStore ) == SbxFlagBits::NONE )
250
0
    {
251
0
        rStrm.WriteUInt32( SBXCR_SBX )
252
0
             .WriteUInt16( GetSbxId() )
253
0
             .WriteUInt16( static_cast<sal_uInt16>(GetFlags()) )
254
0
             .WriteUInt16( GetVersion() );
255
0
        sal_uInt64 const nOldPos = rStrm.Tell();
256
0
        rStrm.WriteUInt32( 0 );
257
0
        auto [bRes, nVersion] = StoreData(rStrm);
258
0
        sal_uInt64 const nNewPos = rStrm.Tell();
259
0
        rStrm.Seek( nOldPos );
260
0
        rStrm.WriteUInt32( nNewPos - nOldPos );
261
0
        rStrm.Seek( nNewPos );
262
0
        if( rStrm.GetError() != ERRCODE_NONE )
263
0
            bRes = false;
264
0
        if( bRes )
265
0
            bRes = true;
266
0
        return { bRes, nVersion };
267
0
    }
268
0
    else
269
0
        return { true, B_IMG_VERSION_12 };
270
0
}
271
272
bool SbxBase::LoadCompleted()
273
0
{
274
0
    return true;
275
0
}
276
277
//////////////////////////////// SbxFactory
278
279
SbxFactory::~SbxFactory()
280
0
{
281
0
}
282
283
SbxBaseRef SbxFactory::Create( sal_uInt16, sal_uInt32 )
284
0
{
285
0
    return nullptr;
286
0
}
287
288
SbxObjectRef SbxFactory::CreateObject( const OUString& )
289
0
{
290
0
    return nullptr;
291
0
}
292
293
///////////////////////////////// SbxInfo
294
295
SbxInfo::~SbxInfo()
296
0
{}
297
298
void SbxInfo::AddParam(const OUString& rName, SbxDataType eType, SbxFlagBits nFlags)
299
0
{
300
0
    m_Params.push_back(std::make_unique<SbxParamInfo>(rName, eType, nFlags));
301
0
}
302
303
const SbxParamInfo* SbxInfo::GetParam( sal_uInt16 n ) const
304
0
{
305
0
    if (n < 1 || n > m_Params.size())
306
0
        return nullptr;
307
0
    else
308
0
        return m_Params[n - 1].get();
309
0
}
310
311
void SbxInfo::LoadData( SvStream& rStrm, sal_uInt16 nVer )
312
0
{
313
0
    m_Params.clear();
314
0
    sal_uInt16 nParam;
315
0
    aComment = read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm,
316
0
        RTL_TEXTENCODING_ASCII_US);
317
0
    aHelpFile = read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm,
318
0
        RTL_TEXTENCODING_ASCII_US);
319
0
    rStrm.ReadUInt32( nHelpId ).ReadUInt16( nParam );
320
0
    while( nParam-- )
321
0
    {
322
0
        sal_uInt16 nType(0), nFlagsTmp(0);
323
0
        sal_uInt32 nUserData = 0;
324
0
        OUString aName = read_uInt16_lenPrefixed_uInt8s_ToOUString(rStrm,
325
0
            RTL_TEXTENCODING_ASCII_US);
326
0
        rStrm.ReadUInt16( nType ).ReadUInt16( nFlagsTmp );
327
0
        SbxFlagBits nFlags = static_cast<SbxFlagBits>(nFlagsTmp);
328
0
        if( nVer > 1 )
329
0
            rStrm.ReadUInt32( nUserData );
330
0
        AddParam( aName, static_cast<SbxDataType>(nType), nFlags );
331
0
        SbxParamInfo& p(*m_Params.back());
332
0
        p.nUserData = nUserData;
333
0
    }
334
0
}
335
336
void SbxInfo::StoreData( SvStream& rStrm ) const
337
0
{
338
0
    write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm, aComment,
339
0
        RTL_TEXTENCODING_ASCII_US );
340
0
    write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm, aHelpFile,
341
0
        RTL_TEXTENCODING_ASCII_US);
342
0
    rStrm.WriteUInt32( nHelpId ).WriteUInt16( m_Params.size() );
343
0
    for (auto const& i : m_Params)
344
0
    {
345
0
        write_uInt16_lenPrefixed_uInt8s_FromOUString(rStrm, i->aName,
346
0
            RTL_TEXTENCODING_ASCII_US);
347
0
        rStrm.WriteUInt16( i->eType )
348
0
             .WriteUInt16( static_cast<sal_uInt16>(i->nFlags) )
349
0
             .WriteUInt32( i->nUserData );
350
0
    }
351
0
}
352
353
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */