Coverage Report

Created: 2026-07-10 11:04

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