Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/bastyp/sfxhtml.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
21
#include <tools/urlobj.hxx>
22
#include <tools/debug.hxx>
23
24
#include <sfx2/docfile.hxx>
25
#include <sfx2/event.hxx>
26
#include <openflag.hxx>
27
28
#include <svl/numformat.hxx>
29
#include <svtools/htmlkywd.hxx>
30
#include <svtools/htmltokn.h>
31
#include <vcl/imap.hxx>
32
#include <vcl/imapcirc.hxx>
33
#include <vcl/imapobj.hxx>
34
#include <vcl/imappoly.hxx>
35
#include <vcl/imaprect.hxx>
36
#include <svl/zforlist.hxx>
37
38
#include <sfx2/sfxhtml.hxx>
39
40
#include <comphelper/string.hxx>
41
#include <o3tl/string_view.hxx>
42
43
#include <vector>
44
45
46
using namespace ::com::sun::star;
47
48
49
// <INPUT TYPE=xxx>
50
HTMLOptionEnum<IMapObjectType> const aAreaShapeOptEnums[] =
51
{
52
    { OOO_STRING_SVTOOLS_HTML_SH_rect,      IMapObjectType::Rectangle  },
53
    { OOO_STRING_SVTOOLS_HTML_SH_rectangle, IMapObjectType::Rectangle  },
54
    { OOO_STRING_SVTOOLS_HTML_SH_circ,      IMapObjectType::Circle     },
55
    { OOO_STRING_SVTOOLS_HTML_SH_circle,    IMapObjectType::Circle     },
56
    { OOO_STRING_SVTOOLS_HTML_SH_poly,      IMapObjectType::Polygon    },
57
    { OOO_STRING_SVTOOLS_HTML_SH_polygon,   IMapObjectType::Polygon    },
58
    { nullptr,                              IMapObjectType::Rectangle  }
59
};
60
61
SfxHTMLParser::SfxHTMLParser( SvStream& rStream, bool bIsNewDoc,
62
                              SfxMedium *pMed )
63
13.8k
    : HTMLParser(rStream, bIsNewDoc)
64
13.8k
    , pMedium(pMed)
65
13.8k
    , eScriptType(STARBASIC)
66
13.8k
{
67
13.8k
    DBG_ASSERT( RTL_TEXTENCODING_UTF8 == GetSrcEncoding( ),
68
13.8k
                "SfxHTMLParser::SfxHTMLParser: From where comes ZS?" );
69
70
13.8k
    DBG_ASSERT( !IsSwitchToUCS2(),
71
13.8k
                "SfxHTMLParser::SfxHTMLParser: Switch to UCS2?" );
72
73
    // If the file starts with a BOM, switch to UCS2.
74
13.8k
    SetSwitchToUCS2( true );
75
13.8k
}
76
77
SfxHTMLParser::~SfxHTMLParser()
78
13.8k
{
79
13.8k
    DBG_ASSERT( !pDLMedium, "Here is a File Download that has got stuck" );
80
13.8k
}
81
82
bool SfxHTMLParser::ParseMapOptions(
83
    ImageMap* pImageMap, const HTMLOptions& rOptions)
84
1.85k
{
85
1.85k
    DBG_ASSERT( pImageMap, "ParseMapOptions: No Image-Map" );
86
87
1.85k
    OUString aName;
88
89
3.77k
    for (size_t i = rOptions.size(); i; )
90
1.92k
    {
91
1.92k
        const HTMLOption& aOption = rOptions[--i];
92
1.92k
        if ( aOption.GetToken() == HtmlOptionId::NAME )
93
1.45k
            aName = aOption.GetString();
94
1.92k
    }
95
96
1.85k
    if( !aName.isEmpty() )
97
1.20k
        pImageMap->SetName( aName );
98
99
1.85k
    return !aName.isEmpty();
100
1.85k
}
101
102
bool SfxHTMLParser::ParseAreaOptions(ImageMap * pImageMap, std::u16string_view rBaseURL,
103
                                     const HTMLOptions& rOptions,
104
                                     SvMacroItemId nEventMouseOver,
105
                                     SvMacroItemId nEventMouseOut )
106
2.54k
{
107
2.54k
    DBG_ASSERT( pImageMap, "ParseAreaOptions: no Image-Map" );
108
109
2.54k
    IMapObjectType nShape = IMapObjectType::Rectangle;
110
2.54k
    std::vector<sal_uInt32> aCoords;
111
2.54k
    OUString aName, aHRef, aAlt, aTarget;
112
2.54k
    bool bNoHRef = false;
113
2.54k
    SvxMacroTableDtor aMacroTbl;
114
115
11.4k
    for (size_t i = rOptions.size(); i; )
116
8.92k
    {
117
8.92k
        SvMacroItemId nEvent = SvMacroItemId::NONE;
118
8.92k
        ScriptType eScrpType = STARBASIC;
119
8.92k
        const HTMLOption& rOption = rOptions[--i];
120
8.92k
        switch( rOption.GetToken() )
121
8.92k
        {
122
38
        case HtmlOptionId::NAME:
123
38
            aName = rOption.GetString();
124
38
            break;
125
1.93k
        case HtmlOptionId::SHAPE:
126
1.93k
            rOption.GetEnum( nShape, aAreaShapeOptEnums );
127
1.93k
            break;
128
2.14k
        case HtmlOptionId::COORDS:
129
2.14k
            rOption.GetNumbers( aCoords );
130
2.14k
            break;
131
942
        case HtmlOptionId::HREF:
132
942
            aHRef = INetURLObject::GetAbsURL( rBaseURL, rOption.GetString() );
133
942
            break;
134
2
        case HtmlOptionId::NOHREF:
135
2
            bNoHRef = true;
136
2
            break;
137
991
        case HtmlOptionId::ALT:
138
991
            aAlt = rOption.GetString();
139
991
            break;
140
78
        case HtmlOptionId::TARGET:
141
78
            aTarget = rOption.GetString();
142
78
            break;
143
144
18
        case HtmlOptionId::ONMOUSEOVER:
145
18
            eScrpType = JAVASCRIPT;
146
18
            [[fallthrough]];
147
18
        case HtmlOptionId::SDONMOUSEOVER:
148
18
            nEvent = nEventMouseOver;
149
18
            goto IMAPOBJ_SETEVENT;
150
151
44
        case HtmlOptionId::ONMOUSEOUT:
152
44
            eScrpType = JAVASCRIPT;
153
44
            [[fallthrough]];
154
44
        case HtmlOptionId::SDONMOUSEOUT:
155
44
            nEvent = nEventMouseOut;
156
44
            goto IMAPOBJ_SETEVENT;
157
62
IMAPOBJ_SETEVENT:
158
62
            if( nEvent != SvMacroItemId::NONE)
159
62
            {
160
62
                OUString sTmp( rOption.GetString() );
161
62
                if( !sTmp.isEmpty() )
162
62
                {
163
62
                    sTmp = convertLineEnd(sTmp, GetSystemLineEnd());
164
62
                    aMacroTbl.Insert( nEvent, SvxMacro( sTmp, u""_ustr, eScrpType ));
165
62
                }
166
62
            }
167
62
            break;
168
2.72k
        default: break;
169
8.92k
        }
170
8.92k
    }
171
172
2.54k
    if( bNoHRef )
173
2
        aHRef.clear();
174
175
2.54k
    bool bNewArea = true;
176
2.54k
    switch( nShape )
177
2.54k
    {
178
2.41k
    case IMapObjectType::Rectangle:
179
2.41k
        if( aCoords.size() >=4 )
180
1.63k
        {
181
1.63k
            tools::Rectangle aRect( aCoords[0], aCoords[1],
182
1.63k
                             aCoords[2], aCoords[3] );
183
1.63k
            std::unique_ptr<IMapRectangleObject> pMapRObj( new IMapRectangleObject(aRect, aHRef, aAlt, OUString(), aTarget, aName,
184
1.63k
                                          !bNoHRef ));
185
1.63k
            if( !aMacroTbl.empty() )
186
3
                pMapRObj->SetMacroTable( aMacroTbl );
187
1.63k
            pImageMap->InsertIMapObject( std::move(pMapRObj) );
188
1.63k
        }
189
2.41k
        break;
190
53
    case IMapObjectType::Circle:
191
53
        if( aCoords.size() >=3 )
192
52
        {
193
52
            Point aPoint( aCoords[0], aCoords[1] );
194
52
            std::unique_ptr<IMapCircleObject> pMapCObj(new IMapCircleObject(aPoint, aCoords[2],aHRef, aAlt, OUString(),
195
52
                                       aTarget, aName, !bNoHRef ));
196
52
            if( !aMacroTbl.empty() )
197
0
                pMapCObj->SetMacroTable( aMacroTbl );
198
52
            pImageMap->InsertIMapObject( std::move(pMapCObj) );
199
52
        }
200
53
        break;
201
79
    case IMapObjectType::Polygon:
202
79
        if( aCoords.size() >=6 )
203
66
        {
204
66
            sal_uInt16 nCount = aCoords.size() / 2;
205
66
            tools::Polygon aPoly( nCount );
206
393
            for( sal_uInt16 i=0; i<nCount; i++ )
207
327
                aPoly[i] = Point( aCoords[2*i], aCoords[2*i+1] );
208
66
            std::unique_ptr<IMapPolygonObject> pMapPObj(new IMapPolygonObject( aPoly, aHRef, aAlt, OUString(), aTarget, aName,
209
66
                                        !bNoHRef ));
210
66
            if( !aMacroTbl.empty() )
211
1
                pMapPObj->SetMacroTable( aMacroTbl );
212
66
            pImageMap->InsertIMapObject( std::move(pMapPObj) );
213
66
        }
214
79
        break;
215
0
    default:
216
0
        bNewArea = false;
217
2.54k
    }
218
219
2.54k
    return bNewArea;
220
2.54k
}
221
222
void SfxHTMLParser::StartFileDownload(const OUString& rURL)
223
0
{
224
0
    DBG_ASSERT( !pDLMedium, "StartFileDownload when active Download" );
225
0
    if( pDLMedium )
226
0
        return;
227
228
0
    pDLMedium.reset( new SfxMedium( rURL, SFX_STREAM_READONLY ) );
229
0
    pDLMedium->Download();
230
0
}
231
232
bool SfxHTMLParser::FinishFileDownload( OUString& rStr )
233
0
{
234
0
    bool bOK = pDLMedium && pDLMedium->GetErrorCode() == ERRCODE_NONE;
235
0
    if( bOK )
236
0
    {
237
0
        SvStream* pStream = pDLMedium->GetInStream();
238
0
        DBG_ASSERT( pStream, "No In-Stream received from Medium" );
239
240
0
        SvMemoryStream aStream;
241
0
        if( pStream )
242
0
            aStream.WriteStream( *pStream );
243
244
0
        sal_uInt64 const nLen = aStream.TellEnd();
245
0
        aStream.Seek( 0 );
246
0
        rStr = read_uInt8s_ToOUString(aStream, nLen, RTL_TEXTENCODING_UTF8);
247
0
    }
248
249
0
    pDLMedium.reset();
250
251
0
    return bOK;
252
0
}
253
254
void SfxHTMLParser::GetScriptType_Impl( SvKeyValueIterator *pHTTPHeader )
255
6.77k
{
256
6.77k
    aScriptType = SVX_MACRO_LANGUAGE_JAVASCRIPT;
257
6.77k
    eScriptType = JAVASCRIPT;
258
6.77k
    if( !pHTTPHeader )
259
0
        return;
260
261
6.77k
    SvKeyValue aKV;
262
8.68k
    for( bool bCont = pHTTPHeader->GetFirst( aKV ); bCont;
263
6.77k
         bCont = pHTTPHeader->GetNext( aKV ) )
264
1.90k
    {
265
1.90k
        if( aKV.GetKey().equalsIgnoreAsciiCase(
266
1.90k
                                OOO_STRING_SVTOOLS_HTML_META_content_script_type ) )
267
5
        {
268
5
            if( !aKV.GetValue().isEmpty() )
269
4
            {
270
4
                OUString aTmp( aKV.GetValue() );
271
4
                if( aTmp.startsWithIgnoreAsciiCase( "text/" ) )
272
3
                    aTmp = aTmp.copy( 5 );
273
1
                else if( aTmp.startsWithIgnoreAsciiCase( "application/" ) )
274
0
                    aTmp = aTmp.copy( 12 );
275
1
                else
276
1
                    break;
277
278
3
                if( aTmp.startsWithIgnoreAsciiCase( "x-" ) ) // MIME-experimental
279
0
                {
280
0
                    aTmp = aTmp.copy( 2 );
281
0
                }
282
283
3
                if( aTmp.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_LG_starbasic ) )
284
0
                {
285
0
                    eScriptType = STARBASIC;
286
0
                    aScriptType = SVX_MACRO_LANGUAGE_STARBASIC;
287
0
                }
288
3
                if( !aTmp.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_LG_javascript ) )
289
0
                {
290
0
                    eScriptType = EXTENDED_STYPE;
291
0
                    aScriptType = aTmp;
292
0
                }
293
3
            }
294
4
            break;
295
5
        }
296
1.90k
    }
297
6.77k
}
298
299
ScriptType SfxHTMLParser::GetScriptType( SvKeyValueIterator *pHTTPHeader ) const
300
91.5k
{
301
91.5k
    if( aScriptType.isEmpty() )
302
6.77k
        const_cast<SfxHTMLParser *>(this)->GetScriptType_Impl( pHTTPHeader );
303
304
91.5k
    return eScriptType;
305
91.5k
}
306
307
const OUString& SfxHTMLParser::GetScriptTypeString(
308
                                    SvKeyValueIterator *pHTTPHeader ) const
309
91.5k
{
310
91.5k
    if( aScriptType.isEmpty() )
311
0
        const_cast<SfxHTMLParser *>(this)->GetScriptType_Impl( pHTTPHeader );
312
313
91.5k
    return aScriptType;
314
91.5k
}
315
316
double SfxHTMLParser::GetTableDataOptionsValNum( sal_uInt32& nNumForm,
317
        LanguageType& eNumLang, const OUString& aValStr, std::u16string_view aNumStr,
318
        SvNumberFormatter& rFormatter )
319
148k
{
320
148k
    LanguageType eParseLang(o3tl::toInt32(aNumStr));
321
148k
    sal_uInt32 nParseForm = rFormatter.GetFormatForLanguageIfBuiltIn( 0, eParseLang );
322
148k
    double fVal;
323
148k
    (void)rFormatter.IsNumberFormat(aValStr, nParseForm, fVal);
324
148k
    if ( comphelper::string::getTokenCount(aNumStr, ';') > 2 )
325
131k
    {
326
131k
        sal_Int32 nIdx {0};
327
131k
        eNumLang = LanguageType(o3tl::toInt32(o3tl::getToken(aNumStr, 1, ';', nIdx )));
328
131k
        OUString aFormat( aNumStr.substr( nIdx ) );
329
131k
        sal_Int32 nCheckPos;
330
131k
        SvNumFormatType nType;
331
131k
        if ( eNumLang != LANGUAGE_SYSTEM )
332
64.2k
            rFormatter.PutEntry( aFormat, nCheckPos, nType, nNumForm, eNumLang );
333
66.8k
        else
334
66.8k
            rFormatter.PutandConvertEntry( aFormat, nCheckPos, nType, nNumForm,
335
66.8k
                                           eParseLang, eNumLang, true);
336
131k
    }
337
17.1k
    else
338
17.1k
    {
339
17.1k
        eNumLang = LANGUAGE_SYSTEM;
340
17.1k
        nNumForm = rFormatter.GetFormatForLanguageIfBuiltIn( 0, eNumLang );
341
17.1k
    }
342
148k
    return fVal;
343
148k
}
344
345
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */