Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/writerperfect/source/common/DocumentHandler.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
 *
7
 * For further information visit http://libwpd.sourceforge.net
8
 */
9
10
#include <DocumentHandler.hxx>
11
12
#include <string.h>
13
14
#include <com/sun/star/uno/Reference.hxx>
15
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
16
#include <com/sun/star/xml/sax/XAttributeList.hpp>
17
#include <comphelper/attributelist.hxx>
18
#include <xmloff/xmlimp.hxx>
19
20
namespace writerperfect
21
{
22
const unsigned char librvng_utf8_skip_data[256]
23
    = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
24
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
25
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
26
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
27
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
28
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
29
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
30
        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
31
        3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 };
32
33
static const char* librvng_utf8_next_char(const char* p)
34
0
{
35
0
    return p + librvng_utf8_skip_data[*reinterpret_cast<unsigned char const*>(p)];
36
0
}
37
38
static void unescapeXML(const char* s, const unsigned long sz, librevenge::RVNGString& res)
39
0
{
40
0
    const char* p = s;
41
0
    const char* const end = p + sz;
42
0
    while (p != end)
43
0
    {
44
0
        const char* const next = librvng_utf8_next_char(p);
45
0
        if (next > end)
46
0
        {
47
            // oops, the string is invalid
48
0
            break;
49
0
        }
50
0
        if (p + 4 <= end && p + 1 == next && *p == '&')
51
0
        {
52
            // look for &amp; , &lt; , &gt; , &apos; , &quot;
53
0
            bool escapedChar = false;
54
0
            switch (*(p + 1))
55
0
            {
56
0
                case 'a':
57
0
                    if (p + 5 <= end && strncmp(p, "&amp;", 5) == 0)
58
0
                    {
59
0
                        res.append('&');
60
0
                        p += 5;
61
0
                        escapedChar = true;
62
0
                    }
63
0
                    else if (p + 6 <= end && strncmp(p, "&apos;", 6) == 0)
64
0
                    {
65
0
                        res.append('\'');
66
0
                        p += 6;
67
0
                        escapedChar = true;
68
0
                    }
69
0
                    break;
70
0
                case 'g':
71
0
                    if (strncmp(p, "&gt;", 4) == 0)
72
0
                    {
73
0
                        res.append('>');
74
0
                        p += 4;
75
0
                        escapedChar = true;
76
0
                    }
77
0
                    break;
78
0
                case 'l':
79
0
                    if (strncmp(p, "&lt;", 4) == 0)
80
0
                    {
81
0
                        res.append('<');
82
0
                        p += 4;
83
0
                        escapedChar = true;
84
0
                    }
85
0
                    break;
86
0
                case 'q':
87
0
                    if (p + 6 <= end && strncmp(p, "&quot;", 6) == 0)
88
0
                    {
89
0
                        res.append('"');
90
0
                        p += 6;
91
0
                        escapedChar = true;
92
0
                    }
93
0
                    break;
94
0
                default:
95
0
                    break;
96
0
            }
97
0
            if (escapedChar)
98
0
                continue;
99
0
        }
100
101
0
        while (p != next)
102
0
        {
103
0
            res.append(*p);
104
0
            ++p;
105
0
        }
106
0
        p = next;
107
0
    }
108
0
}
109
110
using com::sun::star::uno::Reference;
111
using com::sun::star::xml::sax::XDocumentHandler;
112
113
DocumentHandler::DocumentHandler(Reference<XDocumentHandler> const& xHandler)
114
0
    : mxHandler(xHandler)
115
0
{
116
0
    if (SvXMLImport* pFastHandler = dynamic_cast<SvXMLImport*>(mxHandler.get()))
117
0
        mxHandler.set(new SvXMLLegacyToFastDocHandler(pFastHandler));
118
0
}
119
120
0
void DocumentHandler::startDocument() { mxHandler->startDocument(); }
121
122
0
void DocumentHandler::endDocument() { mxHandler->endDocument(); }
123
124
void DocumentHandler::startElement(const char* psName,
125
                                   const librevenge::RVNGPropertyList& xPropList)
126
0
{
127
0
    rtl::Reference<comphelper::AttributeList> pAttrList = new comphelper::AttributeList();
128
0
    librevenge::RVNGPropertyList::Iter i(xPropList);
129
0
    for (i.rewind(); i.next();)
130
0
    {
131
        // filter out librevenge elements
132
0
        if (strncmp(i.key(), "librevenge", 10) != 0)
133
0
        {
134
0
            size_t keyLength = strlen(i.key());
135
0
            OUString sName(i.key(), keyLength, RTL_TEXTENCODING_UTF8);
136
0
            OUString sValue(i()->getStr().cstr(), i()->getStr().len(), RTL_TEXTENCODING_UTF8);
137
138
            // libodfgen xml-encodes some attribute's value, so check if the value is encoded or not
139
0
            for (int j = 0; j < 9; ++j)
140
0
            {
141
                // list of the encoded attributes followed by their lengths
142
0
                static char const* const listEncoded[9]
143
0
                    = { "draw:name",        "svg:font-family",  "style:condition",
144
0
                        "style:num-prefix", "style:num-suffix", "table:formula",
145
0
                        "text:bullet-char", "text:label",       "xlink:href" };
146
0
                static size_t const listEncodedLength[9] = { 9, 15, 15, 16, 16, 13, 16, 10, 10 };
147
0
                if (keyLength == listEncodedLength[j]
148
0
                    && strncmp(i.key(), listEncoded[j], keyLength) == 0)
149
0
                {
150
0
                    librevenge::RVNGString decodedValue("");
151
0
                    unescapeXML(i()->getStr().cstr(),
152
0
                                static_cast<unsigned long>(i()->getStr().len()), decodedValue);
153
0
                    sValue
154
0
                        = OUString(decodedValue.cstr(), decodedValue.len(), RTL_TEXTENCODING_UTF8);
155
0
                    break;
156
0
                }
157
0
            }
158
0
            pAttrList->AddAttribute(sName, sValue);
159
0
        }
160
0
    }
161
162
0
    OUString sElementName(psName, strlen(psName), RTL_TEXTENCODING_UTF8);
163
0
    mxHandler->startElement(sElementName, pAttrList);
164
0
}
165
166
void DocumentHandler::endElement(const char* psName)
167
0
{
168
0
    OUString sElementName(psName, strlen(psName), RTL_TEXTENCODING_UTF8);
169
0
    mxHandler->endElement(sElementName);
170
0
}
171
172
void DocumentHandler::characters(const librevenge::RVNGString& sCharacters)
173
0
{
174
0
    OUString sCharU16(sCharacters.cstr(), strlen(sCharacters.cstr()), RTL_TEXTENCODING_UTF8);
175
0
    mxHandler->characters(sCharU16);
176
0
}
177
}
178
179
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */