File indexing completed on 2025-01-19 03:56:04
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2021-02-18 0007 * Description : Qt5 and Qt6 interface for exiftool - private container. 0008 * Based on ZExifTool Qt interface published at 18 Feb 2021 0009 * https://github.com/philvl/ZExifTool 0010 * 0011 * SPDX-FileCopyrightText: 2021-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0012 * SPDX-FileCopyrightText: 2021 by Philippe Vianney Liaud <philvl dot dev at gmail dot com> 0013 * 0014 * SPDX-License-Identifier: GPL-2.0-or-later 0015 * 0016 * ============================================================ */ 0017 0018 #include "exiftoolprocess_p.h" 0019 0020 namespace Digikam 0021 { 0022 0023 ExifToolProcess::Private::Private(ExifToolProcess* const q) 0024 : QObject (q), 0025 pp (q), 0026 cmdNumber (0), 0027 cmdAction (ExifToolProcess::NO_ACTION), 0028 writeChannelIsClosed(true), 0029 processError (QProcess::UnknownError), 0030 nextCmdId (CMD_ID_MIN) 0031 { 0032 outAwait[0] = false; 0033 outAwait[1] = false; 0034 outReady[0] = false; 0035 outReady[1] = false; 0036 } 0037 0038 void ExifToolProcess::Private::slotExecNextCmd() 0039 { 0040 if ((pp->state() != QProcess::Running) || 0041 writeChannelIsClosed) 0042 { 0043 qCWarning(DIGIKAM_METAENGINE_LOG) << "ExifToolProcess::execNextCmd(): ExifTool is not running"; 0044 return; 0045 } 0046 0047 QMutexLocker locker(&cmdMutex); 0048 0049 if (cmdNumber || cmdQueue.isEmpty()) 0050 { 0051 return; 0052 } 0053 0054 // Clear QProcess buffers 0055 0056 pp->readAllStandardOutput(); 0057 pp->readAllStandardError(); 0058 0059 // Clear internal buffers 0060 0061 outBuff[0] = QByteArray(); 0062 outBuff[1] = QByteArray(); 0063 outAwait[0] = false; 0064 outAwait[1] = false; 0065 outReady[0] = false; 0066 outReady[1] = false; 0067 0068 // Exec Command 0069 0070 execTimer.start(); 0071 0072 Command command = cmdQueue.takeFirst(); 0073 cmdNumber = command.id; 0074 cmdAction = command.ac; 0075 0076 pp->write(command.argsStr); 0077 } 0078 0079 void ExifToolProcess::Private::readOutput(const QProcess::ProcessChannel channel) 0080 { 0081 if (cmdNumber == 0) 0082 { 0083 return; 0084 } 0085 0086 pp->setReadChannel(channel); 0087 0088 while (pp->canReadLine() && !outReady[channel]) 0089 { 0090 QByteArray line = pp->readLine(); 0091 /* 0092 qCDebug(DIGIKAM_METAENGINE_LOG) << channel << line; 0093 */ 0094 if (!outAwait[channel]) 0095 { 0096 if (line.startsWith(QByteArray("{await"))) 0097 { 0098 if (line.endsWith(QByteArray("}\n"))) 0099 { 0100 outAwait[channel] = line.mid(6, line.size() - 8).toInt(); 0101 } 0102 else if (line.endsWith(QByteArray("}\r\n"))) 0103 { 0104 outAwait[channel] = line.mid(6, line.size() - 9).toInt(); 0105 } 0106 } 0107 0108 continue; 0109 } 0110 0111 outBuff[channel] += line; 0112 0113 if (line.endsWith(QByteArray("{ready}\n"))) 0114 { 0115 outBuff[channel].chop(8); 0116 outReady[channel] = true; 0117 0118 break; 0119 } 0120 else if (line.endsWith(QByteArray("{ready}\r\n"))) 0121 { 0122 outBuff[channel].chop(9); 0123 outReady[channel] = true; 0124 0125 break; 0126 } 0127 } 0128 0129 // Check if outputChannel and errorChannel are both ready 0130 0131 if (!(outReady[QProcess::StandardOutput] && 0132 outReady[QProcess::StandardError])) 0133 { 0134 /* 0135 qCWarning(DIGIKAM_METAENGINE_LOG) << "ExifToolProcess::readOutput(): ExifTool read channels are not ready"; 0136 */ 0137 return; 0138 } 0139 0140 if ( 0141 (cmdNumber != outAwait[QProcess::StandardOutput]) || 0142 (cmdNumber != outAwait[QProcess::StandardError]) 0143 ) 0144 { 0145 qCCritical(DIGIKAM_METAENGINE_LOG) << "ExifToolProcess::readOutput: Sync error between CmdID(" 0146 << cmdNumber 0147 << "), outChannel(" 0148 << outAwait[0] 0149 << ") and errChannel(" 0150 << outAwait[1] 0151 << ")"; 0152 0153 setProcessErrorAndEmit(QProcess::ReadError, i18n("Synchronization error between the channels")); 0154 } 0155 else 0156 { 0157 qCDebug(DIGIKAM_METAENGINE_LOG) << "ExifToolProcess::readOutput(): ExifTool command completed"; 0158 0159 setCommandResult(ExifToolProcess::COMMAND_RESULT); 0160 } 0161 0162 Q_EMIT pp->signalExecNextCmd(); // Exec next command 0163 } 0164 0165 void ExifToolProcess::Private::setProcessErrorAndEmit(QProcess::ProcessError error, const QString& description) 0166 { 0167 processError = error; 0168 errorString = description; 0169 0170 setCommandResult(ExifToolProcess::ERROR_RESULT); 0171 } 0172 0173 void ExifToolProcess::Private::setCommandResult(int cmdStatus) 0174 { 0175 QMutexLocker locker(&mutex); 0176 0177 ExifToolProcess::Result result; 0178 0179 result.waitError = false; 0180 result.cmdStatus = cmdStatus; 0181 result.cmdAction = cmdAction; 0182 result.cmdNumber = cmdNumber; 0183 result.elapsed = execTimer.elapsed(); 0184 result.output = outBuff[QProcess::StandardOutput]; 0185 0186 resultMap.insert(cmdNumber, result); 0187 0188 Q_EMIT pp->signalExifToolResult(cmdNumber); 0189 0190 cmdNumber = 0; 0191 cmdAction = ExifToolProcess::NO_ACTION; 0192 0193 condVar.wakeAll(); 0194 } 0195 0196 } // namespace Digikam 0197 0198 #include "moc_exiftoolprocess_p.cpp"