Krita Source Code Documentation
Loading...
Searching...
No Matches
KisExiv2IODevice.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2022 Sharaf Zaman <shzam@sdf.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7#include "KisExiv2IODevice.h"
8
9#include <QDebug>
10#include <QFileInfo>
11
13 : m_file(path)
14 , m_mappedArea(nullptr)
15{
16}
17
22
24{
25 if (m_file.isOpen()) {
26 m_file.close();
27 }
28
29 // return zero if successful
30 return !m_file.open(QFile::ReadWrite);
31}
32
34{
35 if (munmap() != 0) {
36 return 1;
37 }
38 m_file.close();
39 return 0;
40}
41
42#if EXIV2_TEST_VERSION(0,28,0)
43size_t KisExiv2IODevice::write(const Exiv2::byte *data, size_t wcount)
44#else
45long KisExiv2IODevice::write(const Exiv2::byte *data, long wcount)
46#endif
47{
48 if (!m_file.isWritable()) {
49 qWarning() << "KisExiv2IODevice: File not open for writing.";
50 return 0;
51 }
52 const qint64 writeCount = m_file.write(reinterpret_cast<const char *>(data), wcount);
53 if (writeCount > 0) {
54 return writeCount;
55 }
56
57 return 0;
58}
59
60#if EXIV2_TEST_VERSION(0,28,0)
61size_t KisExiv2IODevice::write(Exiv2::BasicIo &src)
62#else
63long KisExiv2IODevice::write(Exiv2::BasicIo &src)
64#endif
65{
66 if (static_cast<BasicIo *>(this) == &src) {
67 return 0;
68 }
69 if (!src.isopen()) {
70 return 0;
71 }
72 if (!m_file.isWritable()) {
73 qWarning() << "KisExiv2IODevice: File not open for writing.";
74 return 0;
75 }
76 Exiv2::byte buffer[4096];
77 long readCount = 0;
78 long totalWriteCount = 0;
79 while ((readCount = src.read(buffer, sizeof(buffer))) != 0) {
80 totalWriteCount += write(buffer, readCount);
81 }
82
83 return totalWriteCount;
84}
85
86int KisExiv2IODevice::putb(Exiv2::byte data)
87{
88 if (!m_file.isWritable()) {
89 qWarning() << "KisExiv2IODevice: File not open for writing.";
90 return 0;
91 }
92 if (m_file.putChar(data)) {
93 return data;
94 } else {
95 return EOF;
96 }
97}
98
99#if EXIV2_TEST_VERSION(0,28,0)
100Exiv2::DataBuf KisExiv2IODevice::read(size_t rcount)
101#else
102Exiv2::DataBuf KisExiv2IODevice::read(long rcount)
103#endif
104{
105 Exiv2::DataBuf buf(rcount);
106#if EXIV2_TEST_VERSION(0,28,0)
107 const size_t readCount = read(buf.data(), buf.size());
108 buf.resize(readCount);
109#else
110 const long readCount = read(buf.pData_, buf.size_);
111 buf.size_ = readCount;
112#endif
113 return buf;
114}
115
116#if EXIV2_TEST_VERSION(0,28,0)
117size_t KisExiv2IODevice::read(Exiv2::byte *buf, size_t rcount)
118#else
119long KisExiv2IODevice::read(Exiv2::byte *buf, long rcount)
120#endif
121{
122 const qint64 bytesRead = m_file.read(reinterpret_cast<char *>(buf), rcount);
123 if (bytesRead > 0) {
124 return bytesRead;
125 } else {
126 qWarning() << "KisExiv2IODevice: Couldn't read file:" << m_file.errorString();
127 // some error or EOF
128 return 0;
129 }
130}
131
133{
134 char c;
135 if (m_file.getChar(&c)) {
136 return c;
137 } else {
138 return EOF;
139 }
140}
141
142void KisExiv2IODevice::transfer(Exiv2::BasicIo &src)
143{
144 bool isFileBased = (dynamic_cast<Exiv2::FileIo *>(&src) || dynamic_cast<KisExiv2IODevice *>(&src));
145 bool useFallback = false;
146
147 if (isFileBased) {
148 const QString srcPath = QString::fromStdString(src.path());
149 // use fallback if copying failed (e.g on Android :( )
150 useFallback = !renameToCurrent(srcPath);
151 }
152
153 if (!isFileBased || useFallback) {
154 const bool wasOpen = isopen();
155 const QIODevice::OpenMode oldMode = m_file.openMode();
156
157 // this sets file positioner to the beginning.
158 if (src.open() != 0) {
159 qWarning() << "KisExiv2IODevice::transfer: Couldn't open src file" << QString::fromStdString(src.path());
160 return;
161 }
162
163 if (!open(QIODevice::ReadWrite | QIODevice::Truncate)) {
164 qWarning() << "KisExiv2IODevice::transfer: Couldn't open dest file" << filePathQString();
165 return;
166 }
167 write(src);
168 src.close();
169
170 if (wasOpen) {
171 open(oldMode);
172 } else {
173 close();
174 }
175 }
176}
177
178#if defined(_MSC_VER) || EXIV2_TEST_VERSION(0,28,0)
179int KisExiv2IODevice::seek(int64_t offset, Exiv2::BasicIo::Position position)
180#else
181int KisExiv2IODevice::seek(long offset, Exiv2::BasicIo::Position position)
182#endif
183{
184 qint64 pos = 0;
185 switch (position) {
186 case Exiv2::BasicIo::beg:
187 pos = offset;
188 break;
189 case Exiv2::BasicIo::cur:
190 pos = tell() + offset;
191 break;
192 case Exiv2::BasicIo::end:
193 pos = size() + offset;
194 break;
195 }
196 return m_file.seek(pos);
197}
198
199Exiv2::byte *KisExiv2IODevice::mmap(bool isWriteable)
200{
201 Q_UNUSED(isWriteable);
202
203 if (munmap() != 0) {
204 qWarning() << "KisExiv2IODevice::mmap: Couldn't unmap the mapped file";
205 return nullptr;
206 }
207
208 m_mappedArea = m_file.map(0, size(), QFile::NoOptions);
209 if (!m_mappedArea) {
210 // We show a warning, but originally we should be throwing an exception.
211 qWarning() << "KisExiv2IODevice::mmap: Couldn't map the file" << m_file.fileName();
212 }
213 return m_mappedArea;
214}
215
217{
218 if (m_mappedArea) {
219 bool successful = m_file.unmap(m_mappedArea);
220 m_mappedArea = nullptr;
221 return !successful;
222 }
223 return 0;
224}
225
226#if EXIV2_TEST_VERSION(0,28,0)
227void KisExiv2IODevice::populateFakeData()
228{
229 return;
230}
231#endif
232
233#if EXIV2_TEST_VERSION(0,28,0)
234size_t KisExiv2IODevice::tell() const
235#else
237#endif
238{
239 return m_file.pos();
240}
241
243{
244 if (m_file.isWritable()) {
245 m_file.flush();
246 }
247 return m_file.size();
248}
249
251{
252 return m_file.isOpen();
253}
254
256{
257 // zero if no error
258 return m_file.error() != QFileDevice::NoError;
259}
260
262{
263 return m_file.atEnd();
264}
265
266#if EXIV2_TEST_VERSION(0,28,0)
267const std::string& KisExiv2IODevice::path() const noexcept
268#else
269std::string KisExiv2IODevice::path() const
270#endif
271{
272 return filePathQString().toStdString();
273}
274
275bool KisExiv2IODevice::open(QFile::OpenMode mode)
276{
277 if (m_file.isOpen()) {
278 m_file.close();
279 }
280 return m_file.open(mode);
281}
282
283bool KisExiv2IODevice::renameToCurrent(const QString srcPath)
284{
285 QFile::Permissions permissions = QFile::permissions(filePathQString());
286 if (QFile::exists(filePathQString())) {
287 QFile::remove(filePathQString());
288 }
289
290 if (!QFile(srcPath).rename(filePathQString())) {
291 qWarning() << "KisExiv2IODevice:renameToCurrent Couldn't copy file from" << srcPath << "to" << filePathQString();
292 return false;
293 }
294 return QFile(filePathQString()).setPermissions(permissions);
295}
296
298{
299 return QFileInfo(m_file).absoluteFilePath();
300}
long write(const Exiv2::byte *data, long wcount) override
int error() const override
Exiv2::DataBuf read(long rcount) override
size_t size() const override
QString filePathQString() const
int munmap() override
Exiv2::byte * m_mappedArea
~KisExiv2IODevice() override
int seek(long offset, Position pos) override
long tell() const override
int close() override
bool isopen() const override
bool renameToCurrent(const QString srcPath)
int putb(Exiv2::byte data) override
Exiv2::byte * mmap(bool isWriteable=false) override
int open() override
std::string path() const override
void transfer(BasicIo &src) override
bool eof() const override
KisExiv2IODevice(QString path)