34
34
#include " settings.h"
35
35
36
36
#if KFArchive_FOUND
37
+ #include < K7Zip>
37
38
#include < KCompressionDevice>
39
+ #include < KTar>
40
+ #include < KZip>
41
+
42
+ #include < QMimeDatabase>
38
43
#endif
39
44
40
45
Q_LOGGING_CATEGORY (LOG_PERFPARSER, " hotspot.perfparser" , QtWarningMsg)
@@ -2043,19 +2048,112 @@ void PerfParser::exportResults(const QUrl& url)
2043
2048
});
2044
2049
}
2045
2050
2051
+ // helper for extracting files from archives
2052
+ namespace {
2053
+ #if KFArchive_FOUND
2054
+ // create archive reader from mimetype
2055
+ auto getArchiveFromMime = [](const QString& filename, const QMimeType& mimeType) -> std::unique_ptr<KArchive> {
2056
+ if (mimeType.name () == QLatin1String (" application/x-tar" )) {
2057
+ return std::make_unique<KTar>(filename);
2058
+ } else if (mimeType.name () == QLatin1String (" application/zip" )) {
2059
+ return std::make_unique<KZip>(filename);
2060
+ } else if (mimeType.name () == QLatin1String (" application/x-7z-compressed" )) {
2061
+ return std::make_unique<K7Zip>(filename);
2062
+ }
2063
+ return {};
2064
+ };
2065
+
2066
+ auto extractFromArchive = [](const std::unique_ptr<KArchive>& archive) -> std::unique_ptr<QTemporaryFile> {
2067
+ auto extractFile = [](const KArchiveDirectory* directory,
2068
+ const QString& filename) -> std::unique_ptr<QTemporaryFile> {
2069
+ auto extracted = std::make_unique<QTemporaryFile>();
2070
+ extracted->open ();
2071
+
2072
+ auto fileToExtract = directory->file (filename);
2073
+ if (!fileToExtract) {
2074
+ return {};
2075
+ }
2076
+
2077
+ auto fileToExtractHandle = fileToExtract->createDevice ();
2078
+
2079
+ const int chunkSize = 1024 * 100 ;
2080
+
2081
+ QByteArray buffer;
2082
+ buffer.resize (chunkSize);
2083
+
2084
+ while (!fileToExtractHandle->atEnd ()) {
2085
+ const auto size = fileToExtractHandle->read (buffer.data (), buffer.size ());
2086
+ extracted->write (buffer.data (), size);
2087
+ }
2088
+ extracted->flush ();
2089
+
2090
+ return extracted;
2091
+ };
2092
+
2093
+ if (!archive->open (QIODevice::ReadOnly)) {
2094
+ qWarning () << " Failed to open archive:" << archive->errorString ();
2095
+ return {};
2096
+ }
2097
+
2098
+ auto dir = archive->directory ();
2099
+ auto entries = dir->entries ();
2100
+
2101
+ if (entries.size () == 1 ) {
2102
+ return extractFile (dir, entries[0 ]);
2103
+ }
2104
+
2105
+ for (const auto & file : {QStringLiteral (" perf.data" ), QStringLiteral (" perf.data.perfparser" )}) {
2106
+ if (entries.contains (file)) {
2107
+ return extractFile (dir, file);
2108
+ }
2109
+ }
2110
+
2111
+ return {};
2112
+ };
2113
+ #endif // KFArchive_FOUND
2114
+ }
2115
+
2046
2116
QString PerfParser::decompressIfNeeded (const QString& path)
2047
2117
{
2048
2118
#if KFArchive_FOUND
2049
- m_decompressed = std::make_unique<QTemporaryFile>(this );
2050
-
2051
2119
KCompressionDevice compressedFile (path);
2052
2120
2121
+ QMimeDatabase mimedb;
2122
+
2123
+ // extract perf.data file form archive, on success set m_decompressed to that file
2124
+ // otherwise return the archive path
2125
+ auto extractArchive = [this , &mimedb](const QString& path) {
2126
+ const auto mimetype = mimedb.mimeTypeForFile (path);
2127
+ auto archive = getArchiveFromMime (path, mimetype);
2128
+
2129
+ if (!archive) {
2130
+ // we don't have and archive -> return original file
2131
+ return path;
2132
+ }
2133
+
2134
+ auto extracted = extractFromArchive (archive);
2135
+ if (extracted) {
2136
+ m_decompressed = std::move (extracted);
2137
+ }
2138
+ return m_decompressed->fileName ();
2139
+ };
2140
+
2141
+ // uncompressed file -> check if it is an archive (tar for example)
2142
+ // extractArchive returns the original path if it couldn't open the archive
2053
2143
if (compressedFile.compressionType () == KCompressionDevice::None) {
2144
+ return extractArchive (path);
2145
+ }
2146
+
2147
+ if (!compressedFile.open (QIODevice::ReadOnly)) {
2148
+ // we failed to open the compressed file
2149
+ qWarning () << " Failed to open:" << path;
2054
2150
return path;
2055
2151
}
2056
2152
2057
- if (compressedFile.open (QIODevice::ReadOnly)) {
2058
- m_decompressed->open ();
2153
+ // we now have a compressed file that could be an archive -> decompress
2154
+ {
2155
+ auto decompressed = std::make_unique<QTemporaryFile>();
2156
+ decompressed->open ();
2059
2157
2060
2158
const int chunkSize = 1024 * 100 ;
2061
2159
@@ -2064,13 +2162,16 @@ QString PerfParser::decompressIfNeeded(const QString& path)
2064
2162
2065
2163
while (!compressedFile.atEnd ()) {
2066
2164
const auto size = compressedFile.read (buffer.data (), buffer.size ());
2067
- m_decompressed ->write (buffer.data (), size);
2165
+ decompressed ->write (buffer.data (), size);
2068
2166
}
2069
- m_decompressed ->flush ();
2167
+ decompressed ->flush ();
2070
2168
2071
2169
compressedFile.close ();
2072
- return m_decompressed-> fileName ( );
2170
+ m_decompressed = std::move (decompressed );
2073
2171
}
2172
+
2173
+ // if m_decompressed is not an archive, this will return m_decompressed
2174
+ return extractArchive (m_decompressed->fileName ());
2074
2175
#endif
2075
2176
// fallback
2076
2177
return path;
0 commit comments