diff options
Diffstat (limited to 'src/corelib/QtCompressMimeDatabase.cmake')
-rw-r--r-- | src/corelib/QtCompressMimeDatabase.cmake | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/src/corelib/QtCompressMimeDatabase.cmake b/src/corelib/QtCompressMimeDatabase.cmake new file mode 100644 index 0000000000..718d330f28 --- /dev/null +++ b/src/corelib/QtCompressMimeDatabase.cmake @@ -0,0 +1,156 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause +cmake_minimum_required(VERSION 3.16) + +get_filename_component(output_directory "${OUTPUT_FILE}" DIRECTORY) +file(MAKE_DIRECTORY "${output_directory}") + +find_program(xmlstarlet NAMES xmlstarlet xml) +if(xmlstarlet) + set(XML_STARLET_COMMAND COMMAND "${xmlstarlet}" sel -D -B -t -c / "${INPUT_FILE}") +else() + get_filename_component(mime_types_resource_filename "${INPUT_FILE}" NAME) + message(STATUS "xmlstarlet command was not found. ${mime_types_resource_filename}" + " will not be minified.") +endif() + +# The function tries to minify 'input_file' using the globally defined 'XML_STARLET_COMMAND'. +# Sets the full path of the output file to the 'out_var' argument. If 'XML_STARLET_COMMAND' fails +# to minify the 'input_file', 'out_var' is set to 'input_file'. +function(try_minify_xml out_var input_file output_directory) + get_filename_component(output_filename "${input_file}" NAME) + set(minified_output "${output_directory}/${output_filename}") + + # Assume XML_STARLET_COMMAND is globally defined. + if(XML_STARLET_COMMAND) + execute_process(${XML_STARLET_COMMAND} + OUTPUT_FILE "${minified_output}" + RESULT_VARIABLE failed_to_minify + ) + if(NOT failed_to_minify) + set(${out_var} "${minified_output}" PARENT_SCOPE) + return() + endif() + endif() + set(${out_var} "${input_file}" PARENT_SCOPE) +endfunction() + +unset(archive_command) + +if(COMPRESSION_TYPE STREQUAL "none") + try_minify_xml(qmimeprovider_db_data_file "${INPUT_FILE}" "${output_directory}") +else() + # CMake versions less than 3.26 don't support the value of the zstd compression level higher + # than 9. We want zstd to compress with level 19 if it's possible, so if zstd executable is + # found on a file system we prefer to use the 'External' archiving API instead of the CMake API. + # See for details: https://gitlab.kitware.com/cmake/cmake/-/issues/24160 + if(COMPRESSION_TYPE STREQUAL "zstd" AND CMAKE_VERSION VERSION_LESS 3.26) + find_program(archive_command NAMES zstd zstd.exe) + if(archive_command) + set(ARCHIVING_API "External") + endif() + endif() + + set(qmimeprovider_db_data_file "${OUTPUT_FILE}.archive") + if(ARCHIVING_API STREQUAL "External") + message(STATUS "Using external archive command to compress the mime type database") + if(COMPRESSION_TYPE STREQUAL "zstd") + find_program(archive_command NAMES zstd zstd.exe) + if(archive_command) + set(archive_command_args -cq19 -T1) + else() + message(WARNING + "Unable to use the preffered ${COMPRESSION_TYPE} compression for the mime type database." + " ${COMPRESSION_TYPE} binary is not found. Trying gzip.") + endif() + endif() + if(NOT archive_command) + # Trying to use gzip if zstd is binary is not found. + set(COMPRESSION_TYPE "gzip") + find_program(archive_command NAMES gzip gzip.exe) + set(archive_command_args -nc9) + endif() + if(archive_command) + if(NOT XML_STARLET_COMMAND) + set(intput_file_arg INPUT_FILE "${INPUT_FILE}") + endif() + execute_process(${XML_STARLET_COMMAND} + COMMAND ${archive_command} + ${archive_command_args} + ${intput_file_arg} + OUTPUT_FILE "${qmimeprovider_db_data_file}" + RESULTS_VARIABLE results + ERROR_VARIABLE error_string + ) + + foreach(result IN LISTS results) + if(NOT result EQUAL 0) + message(WARNING "Unable to compress mime type database: ${error_string}") + endif() + endforeach() + else() + message(WARNING "Unable to find ${COMPRESSION_TYPE} binary." + " Please make sure that the ${COMPRESSION_TYPE} binary is in PATH." + " Adding the uncompressed mime type database.") + set(COMPRESSION_TYPE "none") + set(qmimeprovider_db_data_file "${INPUT_FILE}") + endif() + else() + message(STATUS "Using CMake archive command to compress the mime type database") + + try_minify_xml(mimetypes_resource_file_minified "${INPUT_FILE}" "${output_directory}") + + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.26 AND COMPRESSION_TYPE STREQUAL "zstd") + set(additional_file_archive_create_parameters COMPRESSION_LEVEL 19) + elseif(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19) + set(additional_file_archive_create_parameters COMPRESSION_LEVEL 9) + endif() + + if(COMPRESSION_TYPE STREQUAL "gzip") + set(cmake_compression_type "GZip") + elseif(COMPRESSION_TYPE STREQUAL "zstd") + set(cmake_compression_type "Zstd") + endif() + + file(ARCHIVE_CREATE OUTPUT "${qmimeprovider_db_data_file}" + PATHS "${mimetypes_resource_file_minified}" + FORMAT raw + COMPRESSION ${cmake_compression_type} + ${additional_file_archive_create_parameters} + ) + if(NOT mimetypes_resource_file_minified STREQUAL INPUT_FILE) + file(REMOVE "${mimetypes_resource_file_minified}") + endif() + endif() +endif() +file(READ "${qmimeprovider_db_data_file}" qmime_db_data HEX) +file(SIZE "${qmimeprovider_db_data_file}" qmime_db_data_size) +if(NOT qmimeprovider_db_data_file STREQUAL INPUT_FILE) + file(SIZE "${INPUT_FILE}" qmime_db_resource_size) + file(REMOVE "${qmimeprovider_db_data_file}") +else() + set(qmime_db_resource_size ${qmime_db_data_size}) +endif() + +string(REGEX MATCHALL "([a-f0-9][a-f0-9])" qmime_db_hex "${qmime_db_data}") + +list(TRANSFORM qmime_db_hex PREPEND "0x") +math(EXPR qmime_db_data_size "${qmime_db_data_size} - 1") +foreach(index RANGE 0 ${qmime_db_data_size} 12) + list(APPEND index_list ${index}) +endforeach() +list(TRANSFORM qmime_db_hex PREPEND "\n " AT ${index_list}) +list(JOIN qmime_db_hex ", " qmime_db_hex_joined) + +if(NOT COMPRESSION_TYPE STREQUAL "none") + string(TOUPPER "${COMPRESSION_TYPE}" compression_type_upper) + set(qmime_db_content "#define MIME_DATABASE_IS_${compression_type_upper}\n") +endif() +string(APPEND qmime_db_content + "static const unsigned char mimetype_database[] = {" + "${qmime_db_hex_joined}" + "\n};\n" + "static constexpr size_t MimeTypeDatabaseOriginalSize = ${qmime_db_resource_size};\n" +) + +file(WRITE "${OUTPUT_FILE}" "${qmime_db_content}") |