1- // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
1+ // SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
22//
33// SPDX-License-Identifier: GPL-3.0-or-later
44
2323
2424namespace {
2525
26+ // DOCX conversion timeout constants (in milliseconds)
27+ static constexpr int UNZIP_BASE_TIMEOUT = 30000 ; // 30 seconds base timeout for unzip
28+ static constexpr int UNZIP_TIMEOUT_PER_MB = 2000 ; // 2 seconds per MB for unzip
29+ static constexpr int PANDOC_BASE_TIMEOUT = 60000 ; // 60 seconds base timeout for pandoc
30+ static constexpr int PANDOC_TIMEOUT_PER_MB = 5000 ; // 5 seconds per MB for pandoc
31+ static constexpr int HTMLTOPDF_BASE_TIMEOUT = 120000 ; // 120 seconds base timeout for html to pdf
32+ static constexpr int HTMLTOPDF_TIMEOUT_PER_MB = 10000 ; // 10 seconds per MB for html to pdf
33+ static constexpr int BYTES_PER_MB = 1024 * 1024 ; // Bytes in one megabyte
34+ static constexpr int MAX_TIMEOUT_MS = 600000 ; // Maximum timeout: 10 minutes
35+
2636QString getHtmlToPdfPath () {
2737
2838 QString path = QString (INSTALL_PREFIX) + " /lib/deepin-reader/htmltopdf" ;
@@ -102,6 +112,36 @@ deepin_reader::Document *deepin_reader::DocumentFactory::getDocument(const int &
102112 return nullptr ;
103113 }
104114
115+ // Calculate dynamic timeout based on file size
116+ qint64 fileSizeInMB = file.size () / BYTES_PER_MB;
117+
118+ auto calculateTimeout = [](qint64 sizeInMB, int baseTimeout, int perMbTimeout) -> int {
119+ // Ensure base timeout is returned for zero or negative size
120+ if (sizeInMB <= 0 ) {
121+ return baseTimeout;
122+ }
123+
124+ // Check for potential overflow before multiplication
125+ qint64 maxSafeSize = (MAX_TIMEOUT_MS - baseTimeout) / perMbTimeout;
126+ if (sizeInMB > maxSafeSize) {
127+ qCWarning (appLog) << " File size" << sizeInMB << " MB exceeds safe calculation limit, using max timeout" ;
128+ return MAX_TIMEOUT_MS;
129+ }
130+
131+ // Safe to calculate now
132+ qint64 calculated = sizeInMB * perMbTimeout + baseTimeout;
133+ int timeout = static_cast <int >(qMin (calculated, static_cast <qint64>(MAX_TIMEOUT_MS)));
134+
135+ return qMax (baseTimeout, timeout);
136+ };
137+
138+ int unzipTimeout = calculateTimeout (fileSizeInMB, UNZIP_BASE_TIMEOUT, UNZIP_TIMEOUT_PER_MB);
139+ int pandocTimeout = calculateTimeout (fileSizeInMB, PANDOC_BASE_TIMEOUT, PANDOC_TIMEOUT_PER_MB);
140+ int htmlToPdfTimeout = calculateTimeout (fileSizeInMB, HTMLTOPDF_BASE_TIMEOUT, HTMLTOPDF_TIMEOUT_PER_MB);
141+
142+ qCInfo (appLog) << " File size:" << fileSizeInMB << " MB, Timeouts - unzip:" << unzipTimeout/1000
143+ << " s, pandoc:" << pandocTimeout/1000 << " s, htmltopdf:" << htmlToPdfTimeout/1000 << " s" ;
144+
105145 // 解压的目的是为了让资源文件可以被转换的时候使用到,防止转换后丢失图片等媒体信息
106146 QProcess decompressor;
107147 *pprocess = &decompressor;
@@ -117,7 +157,7 @@ deepin_reader::Document *deepin_reader::DocumentFactory::getDocument(const int &
117157 *pprocess = nullptr ;
118158 return nullptr ;
119159 }
120- if (!decompressor.waitForFinished ()) {
160+ if (!decompressor.waitForFinished (unzipTimeout )) {
121161 qCritical () << " Unzip process failed for file:" << targetDoc;
122162 error = deepin_reader::Document::ConvertFailed;
123163 *pprocess = nullptr ;
@@ -158,7 +198,7 @@ deepin_reader::Document *deepin_reader::DocumentFactory::getDocument(const int &
158198 *pprocess = nullptr ;
159199 return nullptr ;
160200 }
161- if (!converter.waitForFinished ()) {
201+ if (!converter.waitForFinished (pandocTimeout )) {
162202 qCritical () << " Pandoc conversion process failed" ;
163203 error = deepin_reader::Document::ConvertFailed;
164204 *pprocess = nullptr ;
@@ -192,7 +232,7 @@ deepin_reader::Document *deepin_reader::DocumentFactory::getDocument(const int &
192232 *pprocess = nullptr ;
193233 return nullptr ;
194234 }
195- if (!converter2.waitForFinished ()) {
235+ if (!converter2.waitForFinished (htmlToPdfTimeout )) {
196236 qCritical () << " Htmltopdf conversion process failed" ;
197237 error = deepin_reader::Document::ConvertFailed;
198238 *pprocess = nullptr ;
0 commit comments