Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/graphic/BinaryDataContainer.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
 */
10
11
#include <vcl/BinaryDataContainer.hxx>
12
#include <o3tl/hash_combine.hxx>
13
#include <unotools/tempfile.hxx>
14
#include <comphelper/lok.hxx>
15
#include <comphelper/seqstream.hxx>
16
#include <comphelper/hash.hxx>
17
#include <sal/log.hxx>
18
19
#include <vector>
20
21
struct BinaryDataContainer::Impl
22
{
23
    // temp file to store the data out of RAM if necessary
24
    std::unique_ptr<utl::TempFileFast> mpFile;
25
    // the binary data
26
    std::shared_ptr<std::vector<sal_uInt8>> mpData;
27
28
103k
    Impl(SvStream& stream, size_t size) { readData(stream, size); }
29
30
    /// Populate mpData from the stream
31
    void readData(SvStream& stream, size_t size)
32
103k
    {
33
103k
        auto pData = std::make_shared<std::vector<sal_uInt8>>(size);
34
103k
        if (stream.ReadBytes(pData->data(), pData->size()) == size)
35
102k
            mpData = std::move(pData);
36
103k
    }
37
38
    /// ensure the data is in-RAM
39
    void ensureSwappedIn()
40
310k
    {
41
310k
        if (mpData || !mpFile)
42
310k
            return;
43
44
0
        auto pStream = mpFile->GetStream(StreamMode::READ);
45
0
        pStream->Seek(0);
46
0
        readData(*pStream, pStream->remainingSize());
47
48
        // Horrifying data loss ...
49
0
        SAL_WARN_IF(pStream->GetError(), "vcl",
50
0
                    "Inconsistent system - failed to swap image back in");
51
0
    }
52
53
    void swapOut()
54
0
    {
55
0
        if (mpFile)
56
0
        {
57
            // we already have it swapped out.
58
0
            mpData.reset();
59
0
            return;
60
0
        }
61
62
0
        if (!mpData || mpData->empty())
63
0
            return;
64
65
0
        mpFile.reset(new utl::TempFileFast());
66
0
        auto pStream = mpFile->GetStream(StreamMode::READWRITE);
67
68
0
        pStream->WriteBytes(mpData->data(), mpData->size());
69
70
0
        mpData.reset();
71
0
    }
72
};
73
74
BinaryDataContainer::BinaryDataContainer(SvStream& stream, size_t size)
75
103k
    : mpImpl(new Impl(stream, size))
76
103k
{
77
103k
}
78
79
size_t BinaryDataContainer::calculateHash() const
80
26
{
81
26
    size_t nSeed = 0;
82
26
    if (mpImpl && mpImpl->mpData && !mpImpl->mpData->empty())
83
18
    {
84
18
        o3tl::hash_combine(nSeed, getSize());
85
18
        for (sal_uInt8 const& rByte : *mpImpl->mpData)
86
108k
            o3tl::hash_combine(nSeed, rByte);
87
18
    }
88
26
    return nSeed;
89
26
}
90
91
std::vector<unsigned char> BinaryDataContainer::calculateSHA1() const
92
0
{
93
0
    comphelper::Hash aHashEngine(comphelper::HashType::SHA1);
94
0
    aHashEngine.update(getData(), getSize());
95
0
    return aHashEngine.finalize();
96
0
}
97
98
css::uno::Sequence<sal_Int8> BinaryDataContainer::getCopyAsByteSequence() const
99
0
{
100
0
    if (isEmpty())
101
0
        return css::uno::Sequence<sal_Int8>();
102
0
    assert(mpImpl);
103
104
0
    css::uno::Sequence<sal_Int8> aData(getSize());
105
106
0
    std::copy(mpImpl->mpData->cbegin(), mpImpl->mpData->cend(), aData.getArray());
107
108
0
    return aData;
109
0
}
110
111
namespace
112
{
113
/*
114
 * Hold a reference on the internal state in case we swap out
115
 * and free the vector while someone holds an SvStream pointer.
116
 */
117
class ReferencedMemoryStream : public SvMemoryStream
118
{
119
    std::shared_ptr<std::vector<sal_uInt8>> mpData;
120
121
public:
122
    ReferencedMemoryStream(const std::shared_ptr<std::vector<sal_uInt8>>& pData)
123
415
        : SvMemoryStream(pData->data(), pData->size(), StreamMode::READ)
124
415
        , mpData(pData)
125
415
    {
126
415
    }
127
};
128
129
class ReferencedXInputStream : public comphelper::MemoryInputStream
130
{
131
    std::shared_ptr<std::vector<sal_uInt8>> mpData;
132
133
public:
134
    ReferencedXInputStream(const std::shared_ptr<std::vector<sal_uInt8>>& pData)
135
42.8k
        : comphelper::MemoryInputStream(reinterpret_cast<const sal_Int8*>(pData->data()),
136
42.8k
                                        pData->size())
137
42.8k
        , mpData(pData)
138
42.8k
    {
139
42.8k
    }
140
};
141
}
142
143
std::unique_ptr<SvStream> BinaryDataContainer::getAsStream() const
144
415
{
145
415
    ensureSwappedIn(); // TODO: transfer in streamed chunks
146
415
    return std::make_unique<ReferencedMemoryStream>(mpImpl->mpData);
147
415
}
148
149
css::uno::Reference<css::io::XInputStream> BinaryDataContainer::getAsXInputStream() const
150
42.8k
{
151
42.8k
    ensureSwappedIn(); // TODO: transfer in streamed chunks
152
42.8k
    return new ReferencedXInputStream(mpImpl->mpData);
153
42.8k
}
154
155
std::size_t BinaryDataContainer::writeToStream(SvStream& rStream) const
156
0
{
157
0
    ensureSwappedIn(); // TODO: transfer in streamed chunks
158
0
    return rStream.WriteBytes(getData(), getSize());
159
0
}
160
161
size_t BinaryDataContainer::getSize() const
162
111k
{
163
111k
    ensureSwappedIn();
164
111k
    return mpImpl && mpImpl->mpData ? mpImpl->mpData->size() : 0;
165
111k
}
166
167
size_t BinaryDataContainer::getSizeBytes() const
168
0
{
169
0
    return mpImpl && mpImpl->mpData ? mpImpl->mpData->size() : 0;
170
0
}
171
172
bool BinaryDataContainer::isEmpty() const
173
126k
{
174
126k
    ensureSwappedIn();
175
126k
    return !mpImpl || !mpImpl->mpData || mpImpl->mpData->empty();
176
126k
}
177
178
const sal_uInt8* BinaryDataContainer::getData() const
179
53.4k
{
180
53.4k
    ensureSwappedIn();
181
53.4k
    return mpImpl && mpImpl->mpData ? mpImpl->mpData->data() : nullptr;
182
53.4k
}
183
184
void BinaryDataContainer::ensureSwappedIn() const
185
334k
{
186
334k
    if (mpImpl)
187
310k
        mpImpl->ensureSwappedIn();
188
334k
}
189
190
void BinaryDataContainer::swapOut() const
191
0
{
192
    // Only bother reducing memory footprint in kit mode - for mobile/online etc.
193
0
    if (!mpImpl || !comphelper::LibreOfficeKit::isActive())
194
0
        return;
195
196
0
    mpImpl->swapOut();
197
0
}
198
199
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */