diff -Nru innoextract-1.7/CHANGELOG innoextract-1.8/CHANGELOG --- innoextract-1.7/CHANGELOG 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/CHANGELOG 2019-09-15 07:52:37.000000000 +0000 @@ -1,4 +1,24 @@ +innoextract 1.8 (2019-09-15) + - Added support for Inno Setup 6.0.0 installers + - Added support for pre-release Inno Setup 5.6.2 installers used by GOG + - Added support for two modified Inno Setup 5.5.7 variants + - Added support for Inno Setup 1.3.0 to 1.3.23 + - Added support for My Inno Setup Extensions installers older than 3.0.6.1 + - Added support for modified Inno Setup variants using an alternative setup loader magic + - Added support for using boost_{zlib,bzip2} when statically linking Boost + - Added support for automatically reading external setup.0 files + - Encoding for non-Unicode installers is now determined from the languages supported by the installer, overridable using the --codepage option + - Implemented parsing of GOG Galaxy architecture constraints + - The architecture-specific suffixes @32bit and @64bit are now used to disambiguate colliding files + - Fixed extracting files from slices larger than 2 GiB with 32-bit builds + - Fixed output path for files with absolute paths (canonicalization now strips all unsafe characters) + - Fixed output directory being created even when not extracting files + - Fixed a hang when using the --language option + - Improved checksum verification for files reconstructed from GOG Galaxy file parts + - Changed header parsing to select the first version without warnings and failing that the first without errors + - Changed filesystem and output encoding to WTF-8 (extended UTF-8) to represent broken UTF-16 data + innoextract 1.7 (2018-06-12) - Added support for Inno Setup 5.6.0 installers - Added support for new GOG installers with GOG Galaxy file parts diff -Nru innoextract-1.7/cmake/BuildType.cmake innoextract-1.8/cmake/BuildType.cmake --- innoextract-1.7/cmake/BuildType.cmake 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/cmake/BuildType.cmake 2019-09-15 07:52:37.000000000 +0000 @@ -1,114 +1,339 @@ include(CompileCheck) +if(NOT CMAKE_VERSION VERSION_LESS 2.8.6) + include(CheckCXXSymbolExists) + check_cxx_symbol_exists(_LIBCPP_VERSION "cstddef" IS_LIBCXX) +else() + set(IS_LIBCXX OFF) +endif() + + option(DEBUG_EXTRA "Expensive debug options" OFF) option(SET_WARNING_FLAGS "Adjust compiler warning flags" ON) +option(SET_NOISY_WARNING_FLAGS "Enable noisy compiler warnings" OFF) option(SET_OPTIMIZATION_FLAGS "Adjust compiler optimization flags" ON) -if(CMAKE_BUILD_TYPE STREQUAL "") - set(CMAKE_BUILD_TYPE "Release") -endif() - if(MSVC) - if(SET_WARNING_FLAGS) - add_definitions(/wd4250) # harasses you when inheriting from std::basic_{i,o}stream + if(USE_LTO) + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") + endif() + + if(FASTLINK) + + # Optimize for link speed in developer builds + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /DEBUG:FASTLINK") + + elseif(SET_OPTIMIZATION_FLAGS) + + # Merge symbols and discard unused symbols + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF") + + endif() + + if(SET_WARNING_FLAGS AND NOT SET_NOISY_WARNING_FLAGS) + + # TODO TEMP - disable very noisy warning + # Conversion from 'A' to 'B', possible loss of data + add_definitions(/wd4244) + # warning C4245: 'return': conversion from 'A' to 'B', signed/unsigned mismatch + add_definitions(/wd4245) + # warning C4456: declaration of 'xxx' hides previous local declaration + add_definitions(/wd4456) # triggers on nested BOOST_FOREACH + # warning C4457: declaration of 'xxx' hides function parameter + add_definitions(/wd4457) + # warning C4458: declaration of 'xxx' hides class member + add_definitions(/wd4458) + # warning C4459: declaration of 'xxx' hides global declaration + add_definitions(/wd4459) + + # warning C4127: conditional expression is constant + add_definitions(/wd4127) + if(MSVC_VERSION LESS 1900) + # warning C4250: 'xxx': inherits 'std::basic_{i,o}stream::...' via dominance + add_definitions(/wd4250) # harasses you when inheriting from std::basic_{i,o}stream + # warning C4510: 'enum_names' : default constructor could not be generated + add_definitions(/wd4510) + # warning C4512: 'xxx' : assignment operator could not be generated + add_definitions(/wd4512) # not all classes need an assignment operator... + # warning C4610: struct 'xxx' can never be instantiated - user defined constructor required + add_definitions(/wd4610) + endif() + add_definitions(/wd4702) # warns in Boost + add_definitions(/wd4706) # warns in Boost add_definitions(/wd4996) # 'unsafe' stdlib functions used by Boost + + endif() + + if(WERROR) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") endif() if(SET_OPTIMIZATION_FLAGS) + + # Enable exceptions + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc") + # Enable linker optimization in release - # /OPT:REF Eliminate unreferenced code - # /OPT:ICF COMDAT folding (merge functions generating the same code) - # /GL + /LTCG - set(CMAKE_CXX_FLAGS_RELEASE - "${CMAKE_CXX_FLAGS_RELEASE} /Ox /Os /GL") - if(CMAKE_SIZEOF_VOID_P EQUAL 4) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /arch:SSE2") - endif() - set(CMAKE_EXE_LINKER_FLAGS_RELEASE - "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF /LTCG") - set(CMAKE_SHARED_LINKER_FLAGS_RELEASE - "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /OPT:REF /OPT:ICF /LTCG") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ox /Oi /Os") + + endif() + + foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE) + + # Disable Run time checks + if(NOT DEBUG_EXTRA) + string(REGEX REPLACE "(^| )/RTC1( |$)" "\\1" ${flag_var} "${${flag_var}}") + endif() + + # Remove definition of _DEBUG as it might conflict with libs we're linking with + string(REGEX REPLACE "(^| )/D_DEBUG( |$)" "\\1" ${flag_var} "${${flag_var}}") + set(${flag_var} "${${flag_var}} /DNDEBUG") + + # Force compiler warning level + if(SET_WARNING_FLAGS) + string(REGEX REPLACE "(^| )/W[0-4]( |$)" "\\1" ${flag_var} "${${flag_var}}") + set(${flag_var} "${${flag_var}} /W4") + endif() + + endforeach(flag_var) + + if(NOT MSVC_VERSION LESS 1900) + add_definitions(/utf-8) + endif() + + # Turn on standards compliant mode + # /Za is not compatible with /fp:fast, leave it off + if(NOT MSVC_VERSION LESS 1910) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /permissive-") + # /permissive- enables /Zc:twoPhase wich would be good if two phase lookup wasn't still broken in VS 2017 + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:twoPhase-") + endif() + if(NOT MSVC_VERSION LESS 1900) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:inline") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:throwingNew") + endif() + if(NOT MSVC_VERSION LESS 1914) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:__cplusplus") + endif() + + # Always build with debug information + if(NOT MSVC_VERSION LESS 1700) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG") endif() else(MSVC) + if(USE_LDGOLD) + add_ldflag("-fuse-ld=gold") + endif() + + if(USE_LTO) + add_cxxflag("-flto") + # TODO set CMAKE_INTERPROCEDURAL_OPTIMIZATION instead + add_ldflag("-fuse-linker-plugin") + endif() + + if(FASTLINK) + + # Optimize for link speed in developer builds + add_cxxflag("-gsplit-dwarf") + + elseif(SET_OPTIMIZATION_FLAGS) + + # Merge symbols and discard unused symbols + add_ldflag("-Wl,--gc-sections") + add_ldflag("-Wl,--icf=all") + add_cxxflag("-fmerge-all-constants") + + endif() + if(SET_WARNING_FLAGS) - # GCC (and compatible) + # GCC or Clang (and compatible) + add_cxxflag("-Wall") add_cxxflag("-Wextra") - add_cxxflag("-Wformat=2") - add_cxxflag("-Wundef") - add_cxxflag("-Wpointer-arith") + + add_cxxflag("-Warray-bounds=2") + add_cxxflag("-Wbool-conversions") add_cxxflag("-Wcast-qual") - add_cxxflag("-Woverloaded-virtual") - add_cxxflag("-Wlogical-op") - add_cxxflag("-Woverflow") + add_cxxflag("-Wcatch-value=3") add_cxxflag("-Wconversion") - add_cxxflag("-Wsign-conversion") + add_cxxflag("-Wdocumentation") + add_cxxflag("-Wdouble-promotion") + add_cxxflag("-Wduplicated-cond") + add_cxxflag("-Wextra-semi") + add_cxxflag("-Wformat=2") + add_cxxflag("-Wheader-guard") + add_cxxflag("-Winit-self") + add_cxxflag("-Wkeyword-macro") + add_cxxflag("-Wliteral-conversion") + add_cxxflag("-Wlogical-op") add_cxxflag("-Wmissing-declarations") + add_cxxflag("-Wnoexcept") + add_cxxflag("-Woverflow") + add_cxxflag("-Woverloaded-virtual") + add_cxxflag("-Wpessimizing-move") + add_cxxflag("-Wpointer-arith") add_cxxflag("-Wredundant-decls") - add_cxxflag("-Wdouble-promotion") - if(NOT DEBUG_EXTRA AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - # GCC is 'clever' and silently accepts -Wno-* - check for the non-negated variant - check_compiler_flag(FLAG_FOUND "-Wmaybe-uninitialized") - if(FLAG_FOUND) - add_cxxflag("-Wno-maybe-uninitialized") - endif() + add_cxxflag("-Wreserved-id-macro") + add_cxxflag("-Wshift-overflow") + add_cxxflag("-Wsign-conversion") + add_cxxflag("-Wstrict-null-sentinel") + add_cxxflag("-Wstringop-overflow=4") + add_cxxflag("-Wundef") + add_cxxflag("-Wunused-const-variable=1") + add_cxxflag("-Wunused-macros") + add_cxxflag("-Wvla") + + if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) + add_cxxflag("-Wold-style-cast") endif() - # clang - add_cxxflag("-Wliteral-conversion") - add_cxxflag("-Wshift-overflow") - add_cxxflag("-Wbool-conversions") - add_cxxflag("-Wheader-guard") - add_cxxflag("-Wpessimizing-move") + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5 + AND NOT SET_NOISY_WARNING_FLAGS) + # In older GCC versions this warning is too strict + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5 + AND NOT SET_NOISY_WARNING_FLAGS) + # In older Clang verstions this warns on BOOST_SCOPE_EXIT + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT SET_NOISY_WARNING_FLAGS) + # For icc this warning is too strict + else() + add_cxxflag("-Wshadow") + endif() - # icc - if(NOT DEBUG_EXTRA AND CMAKE_CXX_COMPILER_ID STREQUAL "Intel") - # '... was declared but never referenced' - # While normally a sensible warning, it also fires when a member isn't used for - # *all* instantiations of a template class, making the warning too annoying to - # be useful - add_cxxflag("-wd177") - # 'external function definition with no prior declaration' - # This gets annoying fast with small inline/template functions. - add_cxxflag("-wd1418") + add_ldflag("-Wl,--no-undefined") + + if(SET_NOISY_WARNING_FLAGS) + + # These are too noisy to enable right now but we still want to track new warnings. + # TODO enable by default as soon as most are silenced + add_cxxflag("-Wconditionally-supported") # warns on casting from pointer to function pointer + add_cxxflag("-Wduplicated-branches") + add_cxxflag("-Wstrict-aliasing=1") # has false positives + add_cxxflag("-Wuseless-cast") # has false positives + add_cxxflag("-Wsign-promo") + # add_cxxflag("-Wnull-dereference") not that useful without deduction path + + # Possible optimization opportunities + add_cxxflag("-Wdisabled-optimization") + add_cxxflag("-Wpadded") + add_cxxflag("-Wunsafe-loop-optimizations") + + if(NOT DEBUG_EXTRA OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_ldflag("-Wl,--detect-odr-violations") + endif() + + else() + + # icc + if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + # '... was declared but never referenced' + # While normally a sensible warning, it also fires when a member isn't used for + # *all* instantiations of a template class, making the warning too annoying to + # be useful + add_cxxflag("-wd177") + # 'external function definition with no prior declaration' + # This gets annoying fast with small inline/template functions. + add_cxxflag("-wd1418") + # 'non-pointer conversion from "int" to "…" may lose significant bits' + add_cxxflag("-wd2259") + endif() + + # -Wuninitialized causes too many false positives in older gcc versions + if(CMAKE_COMPILER_IS_GNUCXX) + # GCC is 'clever' and silently accepts -Wno-* - check for the non-negated variant + check_compiler_flag(FLAG_FOUND "-Wmaybe-uninitialized") + if(FLAG_FOUND) + add_cxxflag("-Wno-maybe-uninitialized") + else() + add_cxxflag("-Wno-uninitialized") + endif() + endif() + + # Xcode does not support -isystem yet + if(MACOS) + add_cxxflag("-Wno-undef") + endif() + + endif() + + if(IS_LIBCXX) + add_definitions(-D_LIBCPP_ENABLE_NODISCARD) endif() endif(SET_WARNING_FLAGS) + if(WERROR) + add_cxxflag("-Werror") + endif() + if(DEBUG_EXTRA) add_cxxflag("-ftrapv") # to add checks for (undefined) signed integer overflow add_cxxflag("-fbounds-checking") add_cxxflag("-fcatch-undefined-behavior") - add_cxxflag("-Wstrict-aliasing=1") + add_cxxflag("-fstack-protector-all") + add_cxxflag("-fsanitize=address") + add_cxxflag("-fsanitize=thread") + add_cxxflag("-fsanitize=leak") + if(IS_LIBCXX) + add_definitions(-D_LIBCPP_DEBUG=1) # libc++ + # libc++'s debug checks fail with -fsanitize=undefined + else() + add_definitions(-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC) # libstdc++ + add_cxxflag("-fsanitize=undefined") + endif() endif(DEBUG_EXTRA) + if(CMAKE_BUILD_TYPE STREQUAL "") + set(CMAKE_BUILD_TYPE "Release") + endif() + if(SET_OPTIMIZATION_FLAGS) - # Link as few libraries as possible - # This is much easier than trying to decide which libraries are needed for each system - # Specifically, the need for libboost_system depends on the Boost version - add_ldflag("-Wl,--as-needed") + if(MACOS) + # TODO For some reason this check succeeds on macOS, but then + # flag causes the actual build to fail :( + else() + # Link as few libraries as possible + # This is much easier than trying to decide which libraries are needed for each + # system + add_ldflag("-Wl,--as-needed") + endif() if(CMAKE_BUILD_TYPE STREQUAL "Debug") # set debug symbol level to -g3 check_compiler_flag(RESULT "-g3") if(NOT RESULT STREQUAL "") - string(REGEX REPLACE "-g(|[0-9]|gdb)" "" CMAKE_CXX_FLAGS_DEBUG - "${CMAKE_CXX_FLAGS_DEBUG}") + string(REGEX REPLACE "(^| )-g(|[0-9]|gdb)" "\\1" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${RESULT}") endif() # disable optimizations - check_compiler_flag(RESULT "-O0") + check_compiler_flag(RESULT "-Og") + if(NOT RESULT) + check_compiler_flag(RESULT "-O0") + endif() string(REGEX REPLACE "-O[0-9]" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${RESULT}") + elseif(CMAKE_BUILD_TYPE STREQUAL "Release") + + if((NOT CMAKE_CXX_FLAGS MATCHES "-g(|[0-9]|gdb)") + AND (NOT CMAKE_CXX_FLAGS_RELEASE MATCHES "-g(|[0-9]|gdb)")) + add_cxxflag("-g2") + endif() + + add_cxxflag("-ffast-math") + endif() endif(SET_OPTIMIZATION_FLAGS) diff -Nru innoextract-1.7/cmake/CompileCheck.cmake innoextract-1.8/cmake/CompileCheck.cmake --- innoextract-1.7/cmake/CompileCheck.cmake 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/cmake/CompileCheck.cmake 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ -# Copyright (C) 2011-2017 Daniel Scharrer +# Copyright (C) 2011-2019 Daniel Scharrer # # This software is provided 'as-is', without any express or implied # warranty. In no event will the author(s) be held liable for any damages @@ -35,6 +35,8 @@ return() endif() + string(REGEX REPLACE "[^a-zA-Z0-9]" "\\\\\\0" escaped_flag ${FLAG} ) + # CMake already has a check_cxx_compiler_flag macro in CheckCXXCompilerFlag, but # it prints the result variable in the output (which is ugly!) and also uses it # as a key to cache checks - so it would need to be unique for each flag. @@ -44,9 +46,11 @@ set(fail_regexps "warning:" # general "unrecognized .*option" # GNU + "${escaped_flag}.* not supported" # GNU "unknown .*option" # Clang "ignoring unknown option" # MSVC "warning D9002" # MSVC, any lang + "warning #[0-9]*:" # Intel "option.*not supported" # Intel "invalid argument .*option" # Intel "ignoring option .*argument required" # Intel @@ -75,10 +79,10 @@ # Check if we can compile and link a simple file with the new flags try_compile( check_compiler_flag ${PROJECT_BINARY_DIR} ${FILE} - CMAKE_FLAGS "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}" - "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}" - "-DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS}" - "-DCMAKE_MODULE_LINKER_FLAGS=${CMAKE_MODULE_LINKER_FLAGS}" + CMAKE_FLAGS "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}" + "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}" + "-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS}" + "-DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS}" OUTPUT_VARIABLE ERRORLOG ) diff -Nru innoextract-1.7/cmake/CXXVersionCheck.cmake innoextract-1.8/cmake/CXXVersionCheck.cmake --- innoextract-1.7/cmake/CXXVersionCheck.cmake 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/cmake/CXXVersionCheck.cmake 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ -# Copyright (C) 2013-2018 Daniel Scharrer +# Copyright (C) 2013-2019 Daniel Scharrer # # This software is provided 'as-is', without any express or implied # warranty. In no event will the author(s) be held liable for any damages @@ -20,68 +20,126 @@ include(CheckCXXSourceCompiles) include(CompileCheck) -set(_HAS_CXX11 0) -set(CXX11_CHECK_DIR "${CMAKE_CURRENT_LIST_DIR}/check") +set(CXX_VERSION 2003) +set(CXX_CHECK_DIR "${CMAKE_CURRENT_LIST_DIR}/check") function(enable_cxx_version version) + + set(versions 17 14 11) + if(MSVC) - if(NOT version LESS 2011 AND MSVC_VERSION LESS 1600) + if(NOT version LESS 2011 AND NOT MSVC_VERSION LESS 1600) + set(CXX_VERSION 2011) if(NOT version LESS 2017 AND NOT MSVC_VERSION LESS 1911) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17") + set(CXX_VERSION 2017) elseif(NOT version LESS 2014 AND NOT MSVC_VERSION LESS 1910) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++14") + set(CXX_VERSION 2014) elseif(NOT version LESS 2014 AND NOT MSVC_VERSION LESS 1900) # Only introduced with update 3 of MSVC 2015 add_cxxflag("/std:c++14") + if(FLAG_FOUND) + set(CXX_VERSION 2014) + endif() endif() - set(_HAS_CXX11 1 PARENT_SCOPE) endif() else() set(FLAG_FOUND 0) - if(NOT version LESS 2017) - add_cxxflag("-std=c++17") - endif() - if(NOT version LESS 2014 AND NOT FLAG_FOUND) - add_cxxflag("-std=c++14") + foreach(ver IN LISTS versions) + if(NOT version LESS 20${ver} AND NOT FLAG_FOUND) + add_cxxflag("-std=c++${ver}") + if(FLAG_FOUND) + set(CXX_VERSION 20${ver}) + break() + endif() + endif() + endforeach() + if(NOT FLAG_FOUND) + # Check if the compiler supports the -std flag at all + # Don't actually use the flag to allow for compiler extensions a la -sdt=gnu++03 + check_compiler_flag(FLAG_FOUND "-std=c++03") + if(NOT FLAG_FOUND) + check_compiler_flag(FLAG_FOUND "-std=c++98") + endif() endif() - if(NOT version LESS 2011 AND NOT FLAG_FOUND) - add_cxxflag("-std=c++11") + if(NOT FLAG_FOUND) + # Compiler does not support he -std flag, assume the highest supported C++ version is available + # by default or can be enabled by CMake and rely on tests for individual features. + foreach(ver IN LISTS versions) + if(NOT version LESS 20${ver}) + set(CXX_VERSION 20${ver}) + break() + endif() + endforeach() endif() - if(NOT version LESS 2011 AND FLAG_FOUND OR NOT CMAKE_COMPILER_IS_GNUCXX) - if(SET_WARNING_FLAGS) - add_cxxflag("-pedantic") - endif() - set(_HAS_CXX11 1 PARENT_SCOPE) + if(SET_WARNING_FLAGS AND NOT CXX_VERSION LESS 2011) + add_cxxflag("-pedantic") endif() endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE) + set(CXX_VERSION ${CXX_VERSION} PARENT_SCOPE) + + # Tell CMake about our desired C++ version so that it doesn't override our value with a lower version. + # We check -std ourselves first because + # - This feature is new in CMake 3.1 + # - Not all CMake versions know how to check for all C++ versions + # - CMake doesn't tell us what versions are available + if(NOT CMAKE_VERSION VERSION_LESS 3.12) + set(max_cxx_standard 20) + elseif(NOT CMAKE_VERSION VERSION_LESS 3.8) + set(max_cxx_standard 17) + else() + set(max_cxx_standard 14) + endif() + foreach(ver IN LISTS versions) + if(NOT CXX_VERSION LESS 20${ver} AND NOT max_cxx_standard LESS ver) + set(CMAKE_CXX_STANDARD ${ver} PARENT_SCOPE) + set(CMAKE_CXX_STANDARD_REQUIRED OFF PARENT_SCOPE) + set(CMAKE_CXX_EXTENSIONS OFF PARENT_SCOPE) + break() + endif() + endforeach() + endfunction(enable_cxx_version) -function(check_cxx11 CHECK RESULTVAR) - if(_HAS_CXX11) - if(MSVC AND ARGC GREATER 2) - if(MSVC_VERSION LESS ARGV2) - set(result) - else() +function(check_cxx version feature resultvar) + set(result) + if(NOT CXX_VERSION LESS 20${version} OR (ARGC GREATER 3 AND ARGV3 STREQUAL "ALWAYS")) + if(MSVC AND ARGC GREATER 3) + if(NOT MSVC_VERSION LESS ARGV3) set(result 1) endif() else() - string(REGEX REPLACE "[^a-zA-Z0-9_][^a-zA-Z0-9_]*" "-" check "${CHECK}") - set(file "${CXX11_CHECK_DIR}/cxx11-${check}.cpp") + string(REGEX REPLACE "[^a-zA-Z0-9_][^a-zA-Z0-9_]*" "-" check "${feature}") + string(REGEX REPLACE "^--*" "" check "${check}") + string(REGEX REPLACE "--*$" "" check "${check}") + set(file "${CXX_CHECK_DIR}/cxx${version}-${check}.cpp") set(old_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") set(old_CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") strip_warning_flags(CMAKE_CXX_FLAGS) strip_warning_flags(CMAKE_EXE_LINKER_FLAGS) - check_compile(result "${file}" "${CHECK}" "C++11 feature") + check_compile(result "${file}" "${feature}" "C++${version} feature") set(CMAKE_CXX_FLAGS "${old_CMAKE_CXX_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${old_CMAKE_EXE_LINKER_FLAGS}") endif() - if(NOT DEFINED result OR result STREQUAL "") - set(${RESULTVAR} OFF PARENT_SCOPE) - else() - set(${RESULTVAR} ON PARENT_SCOPE) - endif() + endif() + if(NOT DEFINED result OR result STREQUAL "") + set(${resultvar} OFF PARENT_SCOPE) else() - set(${RESULTVAR} OFF PARENT_SCOPE) + set(${resultvar} ON PARENT_SCOPE) endif() endfunction() + +macro(check_cxx11 feature resultvar) + check_cxx(11 ${ARGV}) +endmacro() + +macro(check_cxx14 feature resultvar) + check_cxx(14 ${ARGV}) +endmacro() + +macro(check_cxx17 feature resultvar) + check_cxx(17 ${ARGV}) +endmacro() diff -Nru innoextract-1.7/cmake/Findiconv.cmake innoextract-1.8/cmake/Findiconv.cmake --- innoextract-1.7/cmake/Findiconv.cmake 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/cmake/Findiconv.cmake 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ -# Copyright (C) 2012-2014 Daniel Scharrer +# Copyright (C) 2012-2019 Daniel Scharrer # # This software is provided 'as-is', without any express or implied # warranty. In no event will the author(s) be held liable for any damages @@ -38,37 +38,50 @@ # iconv_USE_STATIC_LIBS Statically link against libiconv (default: OFF) include(UseStaticLibs) -use_static_libs(iconv) -if(APPLE) - # Prefer local iconv.h location over the system iconv.h location as /opt/local/include - # may be added to the include path by other libraries, resulting in the #include - # statements finding the local copy while we will link agains the system lib. - # This way we always find both include file and library in /opt/local/ if there is one. +foreach(static IN ITEMS 1 0) + + if(static) + use_static_libs(iconv) + endif() + + if(APPLE) + # Prefer local iconv.h location over the system iconv.h location as /opt/local/include + # may be added to the include path by other libraries, resulting in the #include + # statements finding the local copy while we will link agains the system lib. + # This way we always find both include file and library in /opt/local/ if there is one. + find_path(iconv_INCLUDE_DIR iconv.h + PATHS /opt/local/include + DOC "The directory where iconv.h resides" + NO_CMAKE_SYSTEM_PATH + ) + endif(APPLE) + find_path(iconv_INCLUDE_DIR iconv.h PATHS /opt/local/include DOC "The directory where iconv.h resides" - NO_CMAKE_SYSTEM_PATH ) -endif(APPLE) - -find_path(iconv_INCLUDE_DIR iconv.h - PATHS /opt/local/include - DOC "The directory where iconv.h resides" -) -mark_as_advanced(iconv_INCLUDE_DIR) - -# Prefer libraries in the same prefix as the include files -string(REGEX REPLACE "(.*)/include/?" "\\1" iconv_BASE_DIR ${iconv_INCLUDE_DIR}) - -find_library(iconv_LIBRARY iconv libiconv - HINTS "${iconv_BASE_DIR}/lib" - PATHS /opt/local/lib - DOC "The iconv library" -) -mark_as_advanced(iconv_LIBRARY) - -use_static_libs_restore() + mark_as_advanced(iconv_INCLUDE_DIR) + + # Prefer libraries in the same prefix as the include files + string(REGEX REPLACE "(.*)/include/?" "\\1" iconv_BASE_DIR ${iconv_INCLUDE_DIR}) + + find_library(iconv_LIBRARY iconv libiconv + HINTS "${iconv_BASE_DIR}/lib" + PATHS /opt/local/lib + DOC "The iconv library" + ) + mark_as_advanced(iconv_LIBRARY) + + if(static) + use_static_libs_restore() + endif() + + if(iconv_LIBRARY OR STRICT_USE) + break() + endif() + +endforeach() set(iconv_DEFINITIONS) if(WIN32 AND iconv_USE_STATIC_LIBS) diff -Nru innoextract-1.7/cmake/FindLZMA.cmake innoextract-1.8/cmake/FindLZMA.cmake --- innoextract-1.7/cmake/FindLZMA.cmake 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/cmake/FindLZMA.cmake 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ -# Copyright (C) 2011-2013 Daniel Scharrer +# Copyright (C) 2011-2019 Daniel Scharrer # # This software is provided 'as-is', without any express or implied # warranty. In no event will the author(s) be held liable for any damages @@ -41,27 +41,40 @@ endif() include(UseStaticLibs) -use_static_libs(LZMA _PC_LZMA) -find_path(LZMA_INCLUDE_DIR lzma.h - HINTS - ${_PC_LZMA_INCLUDE_DIRS} - DOC "The directory where lzma.h resides" -) -mark_as_advanced(LZMA_INCLUDE_DIR) - -# Prefer libraries in the same prefix as the include files -string(REGEX REPLACE "(.*)/include/?" "\\1" LZMA_BASE_DIR ${LZMA_INCLUDE_DIR}) - -find_library(LZMA_LIBRARY lzma liblzma - HINTS - ${_PC_LZMA_LIBRARY_DIRS} - "${LZMA_BASE_DIR}/lib" - DOC "The LZMA library" -) -mark_as_advanced(LZMA_LIBRARY) - -use_static_libs_restore() +foreach(static IN ITEMS 1 0) + + if(static) + use_static_libs(LZMA _PC_LZMA) + endif() + + find_path(LZMA_INCLUDE_DIR lzma.h + HINTS + ${_PC_LZMA_INCLUDE_DIRS} + DOC "The directory where lzma.h resides" + ) + mark_as_advanced(LZMA_INCLUDE_DIR) + + # Prefer libraries in the same prefix as the include files + string(REGEX REPLACE "(.*)/include/?" "\\1" LZMA_BASE_DIR ${LZMA_INCLUDE_DIR}) + + find_library(LZMA_LIBRARY lzma liblzma + HINTS + ${_PC_LZMA_LIBRARY_DIRS} + "${LZMA_BASE_DIR}/lib" + DOC "The LZMA library" + ) + mark_as_advanced(LZMA_LIBRARY) + + if(static) + use_static_libs_restore() + endif() + + if(LZMA_LIBRARY OR STRICT_USE) + break() + endif() + +endforeach() set(LZMA_DEFINITIONS) if(WIN32 AND LZMA_USE_STATIC_LIBS) diff -Nru innoextract-1.7/cmake/UseStaticLibs.cmake innoextract-1.8/cmake/UseStaticLibs.cmake --- innoextract-1.7/cmake/UseStaticLibs.cmake 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/cmake/UseStaticLibs.cmake 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ -# Copyright (C) 2013-2016 Daniel Scharrer +# Copyright (C) 2013-2019 Daniel Scharrer # # This software is provided 'as-is', without any express or implied # warranty. In no event will the author(s) be held liable for any damages @@ -21,7 +21,7 @@ if(${ID}_USE_STATIC_LIBS) set(_UseStaticLibs_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if(WIN32) - set(CMAKE_FIND_LIBRARY_SUFFIXES _a.lib .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(CMAKE_FIND_LIBRARY_SUFFIXES _a.lib .lib .a) else() set(CMAKE_FIND_LIBRARY_SUFFIXES .a) endif() diff -Nru innoextract-1.7/CMakeLists.txt innoextract-1.8/CMakeLists.txt --- innoextract-1.7/CMakeLists.txt 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/CMakeLists.txt 2019-09-15 07:52:37.000000000 +0000 @@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 2.8) -if(CMAKE_VERSION VERSION_GREATER 3.4) - cmake_policy(VERSION 3.4) +if(CMAKE_VERSION VERSION_GREATER 3.15) + cmake_policy(VERSION 3.15) else() cmake_policy(VERSION ${CMAKE_VERSION}) endif() @@ -11,6 +11,12 @@ # Define configuration options +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + set(MACOS 1) +else() + set(MACOS 0) +endif() + macro(suboption _var _comment _type _default) if(NOT DEFINED ${_var}) set(${_var} "${_default}") @@ -19,22 +25,43 @@ endif() endmacro() -option(STRICT_USE "Abort if there are missing optional dependencies" OFF) +option(DEVELOPER "Use build settings suitable for developers" OFF) +option(CONTINUOUS_INTEGRATION "Use build settings suitable for CI" OFF) + +# Components option(USE_ARC4 "Build ARC4 decryption support" ON) + +# Optional dependencies option(USE_LZMA "Build LZMA decompression support" ON) +option(USE_DYNAMIC_UTIMENSAT "Dynamically load utimensat if not available at compile time" OFF) + +# Alternative dependencies set(WITH_CONV CACHE STRING "The library to use for charset conversions") + +# Build types option(DEBUG_EXTRA "Expensive debug options" OFF) option(SET_WARNING_FLAGS "Adjust compiler warning flags" ON) +option(SET_NOISY_WARNING_FLAGS "Enable noisy compiler warnings" OFF) option(SET_OPTIMIZATION_FLAGS "Adjust compiler optimization flags" ON) +suboption(USE_LDGOLD "Use the Gold linker" BOOL ${SET_OPTIMIZATION_FLAGS}) +set(default_FASTLINK OFF) +if(DEVELOPER OR CONTINUOUS_INTEGRATION) + set(default_FASTLINK ON) +endif() +suboption(FASTLINK "Optimize (incremental) linking speed" BOOL ${default_FASTLINK}) +set(default_USE_LTO OFF) +if(SET_OPTIMIZATION_FLAGS AND NOT FASTLINK) + set(default_USE_LTO ON) +endif() +suboption(USE_LTO "Use link-time code generation" BOOL ${default_USE_LTO}) +suboption(WERROR "Turn warnings into errors" BOOL ${CONTINUOUS_INTEGRATION}) suboption(CXX_STD_VERSION "Maximum C++ standard version to enable" STRING 2017) -option(USE_DYNAMIC_UTIMENSAT "Dynamically load utimensat if not available at compile time" OFF) - -set(default_DEBUG OFF) -if(CMAKE_BUILD_TYPE STREQUAL "Debug") +if(DEVELOPER OR CMAKE_BUILD_TYPE STREQUAL "Debug") set(default_DEBUG ON) +else() + set(default_DEBUG OFF) endif() suboption(DEBUG "Build with debug output" BOOL ${default_DEBUG}) - if(DEBUG) add_definitions(-DDEBUG=1) endif() @@ -50,15 +77,22 @@ option(Boost_USE_STATIC_LIBS "Statically link Boost" ${USE_STATIC_LIBS}) option(iconv_USE_STATIC_LIBS "Statically link libiconv" ${USE_STATIC_LIBS}) +# Make optional dependencies required +suboption(STRICT_USE "Abort if there are missing optional dependencies" BOOL ${CONTINUOUS_INTEGRATION}) +if(STRICT_USE) + set(OPTIONAL_DEPENDENCY REQUIRED) +else() + set(OPTIONAL_DEPENDENCY) +endif() # Install destinations if(CMAKE_VERSION VERSION_LESS 2.8.5) set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE - STRING "read-only architecture-independent data root (share) (relative to prefix).") + STRING "read-only architecture-independent data root (share) (relative to prefix).") set(CMAKE_INSTALL_BINDIR "bin" CACHE - STRING "user executables (bin) (relative to prefix).") + STRING "user executables (bin) (relative to prefix).") set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man" CACHE - STRING "man documentation (DATAROOTDIR/man) (relative to prefix).") + STRING "man documentation (DATAROOTDIR/man) (relative to prefix).") mark_as_advanced( CMAKE_INSTALL_DATAROOTDIR CMAKE_INSTALL_BINDIR @@ -146,22 +180,39 @@ list(APPEND LIBRARIES ${Boost_LIBRARIES}) link_directories(${Boost_LIBRARY_DIRS}) include_directories(SYSTEM ${Boost_INCLUDE_DIR}) +if(NOT Boost_VERSION_MACRO) + # CMP0093 changed Boost_VERSION to x.y.z format and provide the old format in Boost_VERSION_MACRO + set(Boost_VERSION_MACRO ${Boost_VERSION}) +endif() has_static_libs(Boost Boost_LIBRARIES) if(Boost_HAS_STATIC_LIBS) - - use_static_libs(ZLIB) - find_package(ZLIB REQUIRED) - use_static_libs_restore() - check_link_library(ZLIB ZLIB_LIBRARIES) - list(APPEND LIBRARIES ${ZLIB_LIBRARIES}) - - use_static_libs(BZip2) - find_package(BZip2 REQUIRED) - use_static_libs_restore() - check_link_library(BZip2 BZIP2_LIBRARIES) - list(APPEND LIBRARIES ${BZIP2_LIBRARIES}) - + foreach(Lib IN ITEMS ZLIB BZip2) + string(TOUPPER ${Lib} LIB) + string(TOLOWER ${Lib} lib) + foreach(static IN ITEMS 1 0) + if(static) + use_static_libs(${Lib}) + endif() + if(WIN32) + find_package(Boost COMPONENTS ${lib} QUIET) + endif() + if(Boost_${LIB}_FOUND) + message (STATUS "Found boost_${lib}") + set(${LIB}_LIBRARIES ${Boost_${LIB}_LIBRARY}) + else() + find_package(${Lib} REQUIRED) + endif() + if(static) + use_static_libs_restore() + endif() + if(${LIB}_LIBRARIES OR STRICT_USE) + break() + endif() + endforeach() + check_link_library(${Lib} ${LIB}_LIBRARIES) + list(APPEND LIBRARIES ${${LIB}_LIBRARIES}) + endforeach() endif() set(INNOEXTRACT_HAVE_ICONV 0) @@ -189,7 +240,7 @@ # Set compiler flags -if(Boost_VERSION LESS 104800) +if(Boost_VERSION_MACRO LESS 104800) # Older Boost versions don't work with C++11 elseif(NOT CXX_STD_VERSION LESS 2011) enable_cxx_version(${CXX_STD_VERSION}) @@ -208,9 +259,12 @@ # Older glibc versions won't provide some useful symbols by default - request them # This flag is currently also set by gcc when compiling C++, but not for plain C -if(CMAKE_SYSTEM_NAME MATCHES "Linux") - set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE=1") - add_definitions(-D_GNU_SOURCE=1) +if(NOT WIN32) + check_symbol_exists(__GLIBC__ "features.h" HAVE_GLIBC) + if(HAVE_GLIBC) + set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE=1") + add_definitions(-D_GNU_SOURCE=1) + endif() endif() if(WIN32) @@ -250,7 +304,9 @@ check_symbol_exists(utimes "sys/time.h" INNOEXTRACT_HAVE_UTIMES) endif() check_symbol_exists(posix_spawnp "spawn.h" INNOEXTRACT_HAVE_POSIX_SPAWNP) - if(NOT INNOEXTRACT_HAVE_POSIX_SPAWNP) + if(INNOEXTRACT_HAVE_POSIX_SPAWNP) + check_symbol_exists(environ "unistd.h" INNOEXTRACT_HAVE_UNISTD_ENVIRON) + else() check_symbol_exists(fork "unistd.h" INNOEXTRACT_HAVE_FORK) check_symbol_exists(execvp "unistd.h" INNOEXTRACT_HAVE_EXECVP) endif() diff -Nru innoextract-1.7/CONTRIBUTING.md innoextract-1.8/CONTRIBUTING.md --- innoextract-1.7/CONTRIBUTING.md 1970-01-01 00:00:00.000000000 +0000 +++ innoextract-1.8/CONTRIBUTING.md 2019-09-15 07:52:37.000000000 +0000 @@ -0,0 +1,8 @@ + +Contributions of all kinds are welcome as [GitHub pull requests](https://github.com/dscharrer/innoextract/pulls) or as patches mailed to daniel@constexpr.org. + +If you are planning to implement a larger feature and intend to get it merged, please contact me **first** at daniel@constexpr.org or on the [GitHub issue tracker](https://github.com/dscharrer/innoextract/issues) to discuss the planned changes in order to avoid duplicating work or having to re-do the changes in a way that fits with the project. + +There is no official code style guide, but please try to match the style of the existing code and git commit messages. + +All contributions must be licensed under the zlib license detailed in the LICENSE file. diff -Nru innoextract-1.7/debian/changelog innoextract-1.8/debian/changelog --- innoextract-1.7/debian/changelog 2018-06-12 18:50:32.000000000 +0000 +++ innoextract-1.8/debian/changelog 2019-09-15 07:52:36.000000000 +0000 @@ -1,3 +1,20 @@ +innoextract (1.8-0ppa1~trusty) trusty; urgency=low + + * Bump version to 1.8 (new upstream release): + * Added support for Inno Setup 5.6.2 to 6.0.2 installers + * Added support for modified Inno Setup variants + * Added support for older Inno Setup installers, including My Inno Setup + Extensions installers + * Encoding for non-Unicode installers is now determined from the languages + supported by the installer, overridable using the --codepage option + * Changed filesystem and output encoding to WTF-8 (extended UTF-8) to represent + broken UTF-16 data + * The architecture-specific suffixes @32bit and @64bit are now used to + disambiguate colliding files + * Fixed various bugs and improved robustness + + -- Daniel Scharrer Sun, 15 Sep 2019 09:52:36 +0200 + innoextract (1.7-0ppa1~trusty) trusty; urgency=low * Bump version to 1.7 (new upstream release): diff -Nru innoextract-1.7/debian/copyright innoextract-1.8/debian/copyright --- innoextract-1.7/debian/copyright 2018-06-12 13:49:18.000000000 +0000 +++ innoextract-1.8/debian/copyright 2019-09-15 07:52:36.000000000 +0000 @@ -3,7 +3,7 @@ Source: http://constexpr.org/innoextract/ Files: * -Copyright: 2011-2018 Daniel Scharrer +Copyright: 2011-2019 Daniel Scharrer License: Zlib This software is provided 'as-is', without any express or implied warranty. In no event will the author(s) be held liable for any damages diff -Nru innoextract-1.7/doc/innoextract.1.in innoextract-1.8/doc/innoextract.1.in --- innoextract-1.7/doc/innoextract.1.in 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/doc/innoextract.1.in 2019-09-15 07:52:37.000000000 +0000 @@ -46,6 +46,7 @@ .TP .B Modifiers: .nf + \-\-codepage \fICODEPAGE\fP Encoding for ANSI strings \-\-collisions \fIACTION\fP How to handle duplicate files \-\-default\-language Default language for renaming \-\-dump Dump contents without converting filenames @@ -85,6 +86,13 @@ The password checksum used for this check can be retrieved using the \fB\-\-show\-password\fP option. .TP +\fB\-\-codepage\fP \fICODEPAGE\fP +Non-Unicode versions of Inno Setup store strings in an unspecified encoding. By default, \fBinnoextract\fP will guess the encoding from the installer's language list, falling back to Windows-1252. This option can be used to override that guess by specifying a non-zero Windows codepage number to use. + +On non-Windows platforms, \fBinnoextract\fP will ignore the system locale and always use UTF-8 as the filesystem and standard output encoding - the \fB\-\-codepage\fP option only changes the input encoding. However, using codepage number "\fB65001\fP" instructs \fBinnoextract\fP to assume all strings are already encoded as UTF-8 and to output them without conversion. + +This option has no effect with Unicode-enabled installers, which always use UTF-16LE. Invalid UTF-16 data is represented using the WTF-8 encoding which is a straightforward extension of UTF-8 to represent unpaired UTF-16 surrogate code units. +.TP \fB\-\-collisions\fP \fIACTION\fP Inno Setup installers can contain duplicate files with the same name. This option tells innoextract what to do when such a collisions is encountered. Valid actions are: @@ -94,10 +102,10 @@ Extract only one of the colliding files. The choice is done similar to how Inno Setup overwrites files during installation. This is the default. .TP "\fBrename\fP" -Rename files that would be overwritten using the "\fBoverwrite\fP" action by appending a suffix comprised of the file's language, the component it belongs to and/or a number to make the filename unique. The language suffix (if applicable) is also appended to the \fIdefault\fP file that would have been extracted with the "\fBoverwrite\fP" action. +Rename files that would be overwritten using the "\fBoverwrite\fP" action by appending a suffix comprised of the file's language, its architecture, the component it belongs to and/or a number to make the filename unique. The language suffix (if applicable) is also appended to the \fIdefault\fP file that would have been extracted with the "\fBoverwrite\fP" action. .TP "\fBrename-all\fP" -Rename all colliding files by appending a suffix comprised of the file's language, the component it belongs to and/or a number to make the filename unique. The complete suffix is appended to both files that would have been overwritten using the "\fBoverwrite\fP" action and to those that would have overwritten other files. +Rename all colliding files by appending a suffix comprised of the file's language, its architecture, the component it belongs to and/or a number to make the filename unique. The complete suffix is appended to both files that would have been overwritten using the "\fBoverwrite\fP" action and to those that would have overwritten other files. .TP "\fBerror\fP" Exit when a collision is detected. @@ -107,16 +115,18 @@ 1. If the \fBcomponent\fP is not the same for all files in the collision set (all files with the same filename), "\fB#\fP" (without quotes) followed by the component id is appended to all files that are specific to a single component. -2. If the \fBlanguage\fP is not the same for all files in the collision set, "\fB@\fP" (without quotes) followed by the language id is appended to all files that are specific to a single component unless that language matches the default language specified by the \fB--default-language\fP. While the suffix is omitted for the default language, no numbered suffix is added in it's place unless needed to make the filename unique. +2. If the \fBlanguage\fP is not the same for all files in the collision set, "\fB@\fP" (without quotes) followed by the language id is appended to all files that are specific to a single language unless that language matches the default language specified by the \fB--default-language\fP. While the suffix is omitted for the default language, no numbered suffix is added in it's place unless needed to make the filename unique. -3. If no suffix was added by the previous steps, or if the filename is not yet unique, "\fB$\fP" (without quotes) followed by the lowest integer (starting at 0) to make the filename unique is appended. +3. If the \fBarchitecture\fP is not the same for all files in the collision set, "\fB@32bit\fP" or "\fB@64bit\fP" (without quotes) is appended to all files that are specific to a single architecture. + +4. If no suffix was added by the previous steps, or if the filename is not yet unique, "\fB$\fP" (without quotes) followed by the lowest integer (starting at 0) to make the filename unique is appended. With the "\fBrename\fP" action, steps 1 and 3 are only applied to files that would have been overwritten by the "\fBoverwrite\fP" action while "\fBrename-all\fP" applies them to all files in the collision set. .TP \fB\-c\fP, \fB\-\-color\fP[=\fIENABLE\fP] By default .B innoextract -will try to detect if the terminal supports shell escape codes and enable or disable color output accordingly. Specifically, colors will be enabled if both \fBstdout\fP and \fBstderr\fP point to a TTY and the \fBTERM\fP environment variable is not set to "\fBdumb\fP". Pass \fB1\fP or \fBtrue\fP to \fB\-\-color\fP to force color output. Pass \fB0\fP or \fBfalse\fP to never output color codes. +will try to detect if the terminal supports shell escape codes and enable or disable color output accordingly. Specifically, colors will be enabled if both \fBstdout\fP and \fBstderr\fP point to a TTY, the \fBTERM\fP environment variable is not set to "\fBdumb\fP" and the \fBNO_COLOR\fP environment variable is unset. Pass \fB1\fP or \fBtrue\fP to \fB\-\-color\fP to force color output. Pass \fB0\fP or \fBfalse\fP to never output color codes. .TP \fB\-V\FP, \fB\-\-data\-version\fP Print the Inno Setup data version of the installer and exit immediately. @@ -284,8 +294,6 @@ Checksum types can be \fBCRC32\fP, \fBMD5\fP or \fBSHA-1\fP although \fBCRC32\fP is not used in installers with encryption. -The password encoding is either \fBMS-ANSI\fP (Windows-1252) or \fBUTF16-LE\fP. - Use the \fB\-\-password\fP or \fB\-\-password\-file\fP option together with \fB\-\-check\-password\fP to check if a password matches this checksum. .TP \fB\-s\fP, \fB\-\-silent\fP @@ -310,7 +318,7 @@ .RS .HP "\fBnone\fP" -Don't preserve file times for extracted files, both for UTC and 'local' timestamps. The file times wil be left the way the OS set them when creating the output files. +Don't preserve file times for extracted files, both for UTC and 'local' timestamps. The file times will be left the way the OS set them when creating the output files. .HP "\fBlocal\fP" Use the system timezone for 'local' timestamps. This is the normal Inno Setup behavior, and can be used together with the \fBTZ\fP environment variable. diff -Nru innoextract-1.7/doc/update-copyright-years innoextract-1.8/doc/update-copyright-years --- innoextract-1.7/doc/update-copyright-years 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/doc/update-copyright-years 2019-09-15 07:52:37.000000000 +0000 @@ -34,7 +34,7 @@ continue ;; esac - c="$(grep -P "(^|[^a-zA-Z0-9_])Copyright( \\([cC]\\))? (\\d{4}\\-)?\\d{4} $copyright" "$file")" + c="$(grep -P "(^|[^a-zA-Z0-9_])Copyright( \\([cC]\\))? (\\d{4}\\-)?\\d{4} $copyright" "$path")" if [ -z "$c" ] ; then case "$file" in @@ -42,7 +42,7 @@ # These files don't have to contain copyright information ;; *.*|scripts/*) - c="$(grep -P "(^|[^a-zA-Z0-9_])Copyright( \([cC]\))?[ \:].*public domain" "$file")" + c="$(grep -P "(^|[^a-zA-Z0-9_])Copyright( \([cC]\))?[ \:].*public domain" "$path")" [ -z "$c" ] && printf 'No copyright info found in %s, skipping\n' "$file" ;; esac continue @@ -64,7 +64,7 @@ COPYING|LICENSE) new_year="$(git --git-dir="$repo/.git" log -1 --format=%cd --date=short)" ;; *) - new_year="$(git --git-dir="$repo/.git" log -1 --format=%cd --date=short -- "$path")" + new_year="$(git --git-dir="$repo/.git" log -1 --format=%cd --date=short -- "$file")" esac new_year="${new_year%%-*}" if [ -z "$new_year" ] || printf '%s\n' "$new_year" | grep -P '[^0-9]' > /dev/null ; then diff -Nru innoextract-1.7/LICENSE innoextract-1.8/LICENSE --- innoextract-1.7/LICENSE 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/LICENSE 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ -Copyright (C) 2011-2018 Daniel Scharrer +Copyright (C) 2011-2019 Daniel Scharrer This software is provided 'as-is', without any express or implied warranty. In no event will the author(s) be held liable for any damages diff -Nru innoextract-1.7/README.md innoextract-1.8/README.md --- innoextract-1.7/README.md 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/README.md 2019-09-15 07:52:37.000000000 +0000 @@ -41,31 +41,40 @@ # make install -Build options: +The default build settings are tuned for users - if you plan to make changes to Arx Libertatis you should append the `-DDEVELOPER=1` option to the `cmake` command to enable debug output and fast incremental builds. -| Option | Default | Description | -|:------------------------ |:---------:|:----------- | -| `USE_ARC4` | `ON` | Build ARC4 decryption support. -| `USE_LZMA` | `ON` | Use `liblzma`. -| `WITH_CONV` | *not set* | The charset conversion library to use. Valid values are `iconv`, `win32` and `builtin`^1. If not set, a library appropriate for the target platform will be chosen. -| `CMAKE_BUILD_TYPE` | `Release` | Set to `Debug` to enable debug output. -| `DEBUG` | `OFF`^2 | Enable debug output and runtime checks. -| `DEBUG_EXTRA` | `OFF` | Expensive debug options. -| `SET_WARNING_FLAGS` | `ON` | Adjust compiler warning flags. This should not affect the produced binaries but is useful to catch potential problems. -| `SET_OPTIMIZATION_FLAGS` | `ON` | Adjust compiler optimization flags. For non-debug builds the only thing this does is instruct the linker to only link against libraries that are actually needed. -| `CXX_STD_VERSION` | `2017` | Maximum C++ standard version to enable. -| `USE_DYNAMIC_UTIMENSAT` | `OFF` | Dynamically load utimensat(2) if not available at compile time -| `USE_STATIC_LIBS` | `OFF`^3 | Turns on static linking for all libraries, including `-static-libgcc` and `-static-libstdc++`. You can also use the individual options below: -| `LZMA_USE_STATIC_LIBS` | `OFF`^4 | Statically link `liblzma`. -| `Boost_USE_STATIC_LIBS` | `OFF`^4 | Statically link Boost. See also `FindBoost.cmake` -| `ZLIB_USE_STATIC_LIBS` | `OFF`^4 | Statically link `libz`. (used via Boost) -| `BZip2_USE_STATIC_LIBS` | `OFF`^4 | Statically link `libbz2`. (used via Boost) -| `iconv_USE_STATIC_LIBS` | `OFF`^4 | Statically link `libiconv`. -| `STRICT_USE` | `OFF` | Abort if there are missing optional dependencies +### Build options: + +| Option | Default | Description | +|:------------------------- |:---------:|:----------- | +| `USE_ARC4` | `ON` | Build ARC4 decryption support. +| `USE_LZMA` | `ON` | Use `liblzma`. +| `WITH_CONV` | *not set* | The charset conversion library to use. Valid values are `iconv`, `win32` and `builtin`¹. If not set, a library appropriate for the target platform will be chosen. +| `CMAKE_BUILD_TYPE` | `Release` | Set to `Debug` to enable debug output. +| `DEBUG` | `OFF`² | Enable debug output and runtime checks. +| `DEBUG_EXTRA` | `OFF` | Expensive debug options. +| `SET_WARNING_FLAGS` | `ON` | Adjust compiler warning flags. This should not affect the produced binaries but is useful to catch potential problems. +| `SET_NOISY_WARNING_FLAGS` | `OFF` | Enable warnings with false positives many cases that still need to be fixed. +| `SET_OPTIMIZATION_FLAGS` | `ON` | Adjust compiler optimization flags. +| `CXX_STD_VERSION` | `2017` | Maximum C++ standard version to enable. +| `USE_DYNAMIC_UTIMENSAT` | `OFF` | Dynamically load utimensat(2) if not available at compile time. +| `USE_STATIC_LIBS` | `OFF`³ | Turns on static linking for all libraries, including `-static-libgcc` and `-static-libstdc++`. You can also use the individual options below: +| `LZMA_USE_STATIC_LIBS` | `OFF`⁴ | Statically link `liblzma`. +| `Boost_USE_STATIC_LIBS` | `OFF`⁴ | Statically link Boost. See also `FindBoost.cmake`. +| `ZLIB_USE_STATIC_LIBS` | `OFF`⁴ | Statically link `libz`. (used via Boost) +| `BZip2_USE_STATIC_LIBS` | `OFF`⁴ | Statically link `libbz2`. (used via Boost) +| `iconv_USE_STATIC_LIBS` | `OFF`⁴ | Statically link `libiconv`. +| `STRICT_USE` | `OFF` | Abort if there are missing optional dependencies. +| `DEVELOPER` | `OFF` | Enable build options suitable for developers⁵. +| `FASTLINK` | `OFF`⁶ | Optimize for link speed. +| `USE_LTO` | `ON`² | Use link-time code generation. 1. The builtin charset conversion only supports Windows-1252 and UTF-16LE. This is normally enough for filenames, but custom message strings (which can be included in filenames) may use arbitrary encodings. 2. Enabled automatically if `CMAKE_BUILD_TYPE` is set to `Debug`. 3. Under Windows, the default is `ON`. 4. Default is `ON` if `USE_STATIC_LIBS` is enabled. +5. Currently this and enables `DEBUG` and `FASTLINK` for faster incremental builds and improved debug output, unless those options have been explicitly specified by the user. +6. Enabled automatically if `DEVELOPER` is enabled. +7. Disabled automatically if `SET_OPTIMIZATION_FLAGS` is disabled or `FASTLINK` is enabled. Install options: diff -Nru innoextract-1.7/src/cli/debug.cpp innoextract-1.8/src/cli/debug.cpp --- innoextract-1.7/src/cli/debug.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/cli/debug.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -492,7 +492,7 @@ setup::header::NoPrivileges); std::cout << "Show language dialog: " << color::cyan << header.show_language_dialog << color::reset << '\n'; - std::cout << if_not_equal("Danguage detection", header.language_detection, + std::cout << if_not_equal("Language detection", header.language_detection, setup::header::NoLanguageDetection); std::cout << "Compression: " << color::cyan << header.compression << color::reset << '\n'; diff -Nru innoextract-1.7/src/cli/extract.cpp innoextract-1.8/src/cli/extract.cpp --- innoextract-1.7/src/cli/extract.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/cli/extract.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -127,10 +127,10 @@ fs::path path_; const processed_file * file_; - util::ofstream stream_; + util::fstream stream_; crypto::hasher checksum_; - bool checksum_valid_; + boost::uint64_t checksum_position_; boost::uint64_t position_; boost::uint64_t total_written_; @@ -143,14 +143,18 @@ : path_(dir / f->path()) , file_(f) , checksum_(f->entry().checksum.type) - , checksum_valid_(f->entry().checksum.type != crypto::None) + , checksum_position_(f->entry().checksum.type == crypto::None ? boost::uint64_t(-1) : 0) , position_(0) , total_written_(0) , write_(write) { if(write_) { try { - stream_.open(path_, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); + std::ios_base::openmode flags = std::ios_base::out | std::ios_base::binary | std::ios_base::trunc; + if(file_->is_multipart()) { + flags |= std::ios_base::in; + } + stream_.open(path_, flags); if(!stream_.is_open()) { throw std::exception(); } @@ -166,8 +170,9 @@ stream_.write(data, std::streamsize(n)); } - if(checksum_valid_) { + if(checksum_position_ == position_) { checksum_.update(data, n); + checksum_position_ += n; } position_ += n; @@ -182,33 +187,23 @@ return; } - checksum_valid_ = false; - debug("seeking output from " << print_hex(position_) << " to " << print_hex(new_position)); if(!write_) { + position_ = new_position; return; } - const boost::uint64_t max = boost::uint64_t(std::numeric_limits::max() / 4); + const boost::uint64_t max = boost::uint64_t(std::numeric_limits::max() / 4); if(new_position <= max) { - stream_.seekp(util::ofstream::off_type(new_position), std::ios_base::beg); + stream_.seekp(util::fstream::off_type(new_position), std::ios_base::beg); } else { - if(new_position > position_) { - boost::uint64_t diff = new_position - position_; - while(diff > max) { - stream_.seekp(util::ofstream::off_type(max), std::ios_base::cur); - diff -= max; - } - stream_.seekp(util::ofstream::off_type(diff), std::ios_base::cur); - } else { - boost::uint64_t diff = position_ - new_position; - while(diff > max) { - stream_.seekp(-util::ofstream::off_type(max), std::ios_base::cur); - diff -= max; - } - stream_.seekp(-util::ofstream::off_type(diff), std::ios_base::cur); + util::fstream::off_type sign = (new_position > position_) ? 1 : -1; + boost::uint64_t diff = (new_position > position_) ? new_position - position_ : position_ - new_position; + while(diff > 0) { + stream_.seekp(sign * util::fstream::off_type(std::min(diff, max)), std::ios_base::cur); + diff -= std::min(diff, max); } } @@ -232,7 +227,44 @@ } bool has_checksum() const { - return checksum_valid_ && position_ == file_->entry().size; + return checksum_position_ == file_->entry().size; + } + + bool calculate_checksum() { + + if(has_checksum()) { + return true; + } + + if(!write_) { + return false; + } + + debug("calculating output checksum for " << path_); + + const boost::uint64_t max = boost::uint64_t(std::numeric_limits::max() / 4); + + boost::uint64_t diff = checksum_position_; + stream_.seekg(util::fstream::off_type(std::min(diff, max)), std::ios_base::beg); + diff -= std::min(diff, max); + while(diff > 0) { + stream_.seekg(util::fstream::off_type(std::min(diff, max)), std::ios_base::cur); + diff -= std::min(diff, max); + } + + while(!stream_.eof()) { + char buffer[8192]; + std::streamsize n = stream_.read(buffer, sizeof(buffer)).gcount(); + checksum_.update(buffer, size_t(n)); + checksum_position_ += boost::uint64_t(n); + } + + if(!has_checksum()) { + log_warning << "Could not read back " << path_ << " to calculate output checksum for multi-part file"; + return false; + } + + return true; } crypto::checksum checksum() { @@ -482,12 +514,14 @@ } bool rename_collision(const extract_options & o, FilesMap & processed_files, const std::string & path, - const processed_file & other, bool common_component, bool common_language, bool first) { + const processed_file & other, bool common_component, bool common_language, + bool common_arch, bool first) { const setup::file_entry & file = other.entry(); bool require_number_suffix = !first || (o.collisions == RenameAllCollisions); std::ostringstream oss; + const setup::file_entry::flags arch_flags = setup::file_entry::Bits32 | setup::file_entry::Bits64; if(!common_component && !file.components.empty()) { if(setup::is_simple_expression(file.components)) { @@ -503,6 +537,13 @@ } } } + if(!common_arch && (file.options & arch_flags) == setup::file_entry::Bits32) { + require_number_suffix = false; + oss << "@32bit"; + } else if(!common_arch && (file.options & arch_flags) == setup::file_entry::Bits64) { + require_number_suffix = false; + oss << "@64bit"; + } size_t i = 0; std::string suffix = oss.str(); @@ -536,23 +577,26 @@ const processed_file & base = processed_files.find(path)->second; const setup::file_entry & file = base.entry(); + const setup::file_entry::flags arch_flags = setup::file_entry::Bits32 | setup::file_entry::Bits64; bool common_component = true; bool common_language = true; + bool common_arch = true; BOOST_FOREACH(const processed_file & other, collision.second) { common_component = common_component && other.entry().components == file.components; common_language = common_language && other.entry().languages == file.languages; + common_arch = common_arch && (other.entry().options & arch_flags) == (file.options & arch_flags); } bool ignore_component = common_component || o.collisions != RenameAllCollisions; if(rename_collision(o, processed_files, path, base, - ignore_component, common_language, true)) { + ignore_component, common_language, common_arch, true)) { processed_files.erase(path); } BOOST_FOREACH(const processed_file & other, collision.second) { rename_collision(o, processed_files, path, other, - common_component, common_language, false); + common_component, common_language, common_arch, false); } } @@ -648,10 +692,10 @@ std::cout << '\n'; } if(o.silent) { - std::cout << util::encoding_name(info.version.codepage()) << '\n'; + std::cout << util::encoding_name(info.codepage) << '\n'; } else { std::cout << "Password encoding: " << color::yellow - << util::encoding_name(info.version.codepage()) << color::reset << '\n'; + << util::encoding_name(info.codepage) << color::reset << '\n'; } } else if(!o.quiet) { std::cout << "Setup is not passworded!\n"; @@ -834,27 +878,27 @@ } // anonymous namespace -void process_file(const fs::path & file, const extract_options & o) { +void process_file(const fs::path & installer, const extract_options & o) { bool is_directory; try { - is_directory = fs::is_directory(file); + is_directory = fs::is_directory(installer); } catch(...) { - throw std::runtime_error("Could not open file \"" + file.string() + throw std::runtime_error("Could not open file \"" + installer.string() + "\": access denied"); } if(is_directory) { - throw std::runtime_error("Input file \"" + file.string() + "\" is a directory!"); + throw std::runtime_error("Input file \"" + installer.string() + "\" is a directory!"); } util::ifstream ifs; try { - ifs.open(file, std::ios_base::in | std::ios_base::binary); + ifs.open(installer, std::ios_base::in | std::ios_base::binary); if(!ifs.is_open()) { throw std::exception(); } } catch(...) { - throw std::runtime_error("Could not open file \"" + file.string() + '"'); + throw std::runtime_error("Could not open file \"" + installer.string() + '"'); } loader::offsets offsets; @@ -903,8 +947,17 @@ ifs.seekg(offsets.header_offset); setup::info info; try { - info.load(ifs, entries); - } catch(const std::ios_base::failure & e) { + info.load(ifs, entries, o.codepage); + } catch(const setup::version_error &) { + fs::path headerfile = installer; + headerfile.replace_extension(".0"); + if(offsets.header_offset == 0 && headerfile != installer && fs::exists(headerfile)) { + log_info << "Opening \"" << color::cyan << headerfile.string() << color::reset << '"'; + process_file(headerfile, o); + return; + } + throw; + } catch(const std::exception & e) { std::ostringstream oss; oss << "Stream error while parsing setup headers!\n"; oss << " ├─ detected setup version: " << info.version << '\n'; @@ -924,7 +977,7 @@ log_warning << "Setup contains encrypted files, use the --password option to extract them"; } } else { - util::from_utf8(o.password, password, info.version.codepage()); + util::from_utf8(o.password, password, info.codepage); if(info.header.options & setup::header::Password) { crypto::hasher checksum(info.header.password.type); checksum.update(info.header.password_salt.c_str(), info.header.password_salt.length()); @@ -1003,9 +1056,22 @@ files_for_location[file.entry().location].push_back(output_location(&file, 0)); if(o.test || o.extract) { boost::uint64_t offset = info.data_entries[file.entry().location].uncompressed_size; + boost::uint32_t sort_slice = info.data_entries[file.entry().location].chunk.first_slice; + boost::uint32_t sort_offset = info.data_entries[file.entry().location].chunk.sort_offset; BOOST_FOREACH(boost::uint32_t location, file.entry().additional_locations) { + setup::data_entry & data = info.data_entries[location]; files_for_location[location].push_back(output_location(&file, offset)); - offset += info.data_entries[location].uncompressed_size; + offset += data.uncompressed_size; + if(data.chunk.first_slice > sort_slice || + (data.chunk.first_slice == sort_slice && data.chunk.sort_offset > sort_offset)) { + sort_slice = data.chunk.first_slice; + sort_offset = data.chunk.sort_offset; + } else if(data.chunk.first_slice == sort_slice && data.chunk.sort_offset == data.chunk.offset) { + data.chunk.sort_offset = ++sort_offset; + } else { + // Could not reorder chunk - no point in trying to reordder the remaining chunks + sort_slice = boost::uint32_t(-1); + } } } } @@ -1016,15 +1082,11 @@ typedef std::map Chunks; Chunks chunks; for(size_t i = 0; i < info.data_entries.size(); i++) { - if(files_for_location[i].empty()) { - continue; + if(!files_for_location[i].empty()) { + setup::data_entry & location = info.data_entries[i]; + chunks[location.chunk][location.file] = i; + total_size += location.uncompressed_size; } - setup::data_entry & location = info.data_entries[i]; - if(location.chunk.compression == stream::UnknownCompression) { - location.chunk.compression = info.header.compression; - } - chunks[location.chunk][location.file] = i; - total_size += location.uncompressed_size; } boost::scoped_ptr slice_reader; @@ -1032,8 +1094,8 @@ if(offsets.data_offset) { slice_reader.reset(new stream::slice_reader(&ifs, offsets.data_offset)); } else { - fs::path dir = file.parent_path(); - std::string basename = util::as_string(file.stem()); + fs::path dir = installer.parent_path(); + std::string basename = util::as_string(installer.stem()); std::string basename2 = info.header.base_filename; // Prevent access to unexpected files std::replace(basename2.begin(), basename2.end(), '/', '_'); @@ -1179,8 +1241,8 @@ // Open output files boost::ptr_vector single_outputs; std::vector outputs; - BOOST_FOREACH(const output_location & location, output_locations) { - const processed_file * fileinfo = location.first; + BOOST_FOREACH(const output_location & output_loc, output_locations) { + const processed_file * fileinfo = output_loc.first; try { if(!o.extract && fileinfo->entry().checksum.type == crypto::None) { @@ -1207,7 +1269,7 @@ outputs.push_back(output); - output->seek(location.second); + output->seek(output_loc.second); } catch(boost::bad_pointer &) { // should never happen @@ -1251,20 +1313,15 @@ } // Verify output checksum if available - if(output->file()->entry().checksum.type != crypto::None) { - if(output->has_checksum()) { - crypto::checksum checksum = output->checksum(); - if(checksum != output->file()->entry().checksum) { - log_warning << "Output checksum mismatch for " << output->file()->path() << ":\n" - << " ├─ actual: " << checksum << '\n' - << " └─ expected: " << output->file()->entry().checksum; - if(o.test) { - throw std::runtime_error("Integrity test failed!"); - } + if(output->file()->entry().checksum.type != crypto::None && output->calculate_checksum()) { + crypto::checksum output_checksum = output->checksum(); + if(output_checksum != output->file()->entry().checksum) { + log_warning << "Output checksum mismatch for " << output->file()->path() << ":\n" + << " ├─ actual: " << output_checksum << '\n' + << " └─ expected: " << output->file()->entry().checksum; + if(o.test) { + throw std::runtime_error("Integrity test failed!"); } - } else { - // This should not happen - log_warning << "Could not verify output checksum of file " << output->file()->path(); } } @@ -1310,7 +1367,7 @@ } if(o.warn_unused || o.gog) { - gog::probe_bin_files(o, info, file, offsets.data_offset == 0); + gog::probe_bin_files(o, info, installer, offsets.data_offset == 0); } } diff -Nru innoextract-1.7/src/cli/extract.hpp innoextract-1.8/src/cli/extract.hpp --- innoextract-1.7/src/cli/extract.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/cli/extract.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2018 Daniel Scharrer + * Copyright (C) 2014-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -30,6 +30,7 @@ #include #include +#include #include #include "setup/filename.hpp" @@ -77,6 +78,8 @@ std::string language; //!< Extract only files for this language std::vector include; //!< Extract only files matching these patterns + boost::uint32_t codepage; + setup::filename_map filenames; CollisionAction collisions; std::string default_language; @@ -111,6 +114,6 @@ }; -void process_file(const boost::filesystem::path & file, const extract_options & o); +void process_file(const boost::filesystem::path & installer, const extract_options & o); #endif // INNOEXTRACT_CLI_EXTRACT_HPP diff -Nru innoextract-1.7/src/cli/gog.cpp innoextract-1.8/src/cli/gog.cpp --- innoextract-1.7/src/cli/gog.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/cli/gog.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2018 Daniel Scharrer + * Copyright (C) 2014-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -45,8 +45,9 @@ #include "stream/slice.hpp" -#include "util/console.hpp" #include "util/boostfs_compat.hpp" +#include "util/console.hpp" +#include "util/encoding.hpp" #include "util/fstream.hpp" #include "util/log.hpp" #include "util/process.hpp" @@ -73,7 +74,9 @@ } if(boost::iequals(entry.name, "gameID")) { - return entry.value; + id = entry.value; + util::to_utf8(id, info.codepage); + break; } if(id.empty()) { @@ -495,7 +498,7 @@ bin_count += probe_bin_file_series(o, info, dir, basename + "-0" + ".bin"); - size_t max_slice = 0; + boost::uint32_t max_slice = 0; if(external) { BOOST_FOREACH(const setup::data_entry & location, info.data_entries) { max_slice = std::max(max_slice, location.chunk.first_slice); @@ -506,14 +509,14 @@ size_t slice = 0; size_t format = 1; if(external && info.header.slices_per_disk == 1) { - slice = max_slice + 1; + slice = size_t(max_slice) + 1; } bin_count += probe_bin_file_series(o, info, dir, basename, format, slice); slice = 0; format = 2; if(external && info.header.slices_per_disk != 1) { - slice = max_slice + 1; + slice = size_t(max_slice) + 1; format = info.header.slices_per_disk; } bin_count += probe_bin_file_series(o, info, dir, basename, format, slice); diff -Nru innoextract-1.7/src/cli/goggalaxy.cpp innoextract-1.8/src/cli/goggalaxy.cpp --- innoextract-1.7/src/cli/goggalaxy.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/cli/goggalaxy.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 Daniel Scharrer + * Copyright (C) 2018-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -180,7 +180,8 @@ std::string name; bool negated; - explicit constraint(const std::string & name, bool negated = false) : name(name), negated(negated) { } + explicit constraint(const std::string & constraint_name, bool is_negated = false) + : name(constraint_name), negated(is_negated) { } }; @@ -448,9 +449,35 @@ } - if(check.size() >= 2 && !check[1].empty() && check[1] != "32#64#") { - log_warning << "Ignoring architecture constraint for GOG Galaxy file " << file.destination - << ": " << check[1]; + if(check.size() >= 2 && !check[1].empty()) { + const setup::file_entry::flags all_arch = setup::file_entry::Bits32 | setup::file_entry::Bits64; + setup::file_entry::flags arch = 0; + if(check[1] != "32#64#") { + std::vector architectures = parse_constraints(check[1]); + BOOST_FOREACH(const constraint & architecture, architectures) { + if(architecture.negated && architectures.size() > 1) { + log_warning << "Ignoring architecture for GOG Galaxy file " << file.destination + << ": !" << architecture.name; + } else if(architecture.name == "32") { + arch |= setup::file_entry::Bits32; + } else if(architecture.name == "64") { + arch |= setup::file_entry::Bits64; + } else { + log_warning << "Unknown architecture for GOG Galaxy file " << file.destination + << ": " << architecture.name; + } + if(architecture.negated && architectures.size() <= 1) { + arch = all_arch & ~arch; + } + } + if(arch == all_arch) { + arch = 0; + } + } + if((file.options & all_arch) && (file.options & all_arch) != arch) { + log_warning << "Overwriting architecture constraints for GOG Galaxy file " << file.destination; + } + file.options = (file.options & ~all_arch) | arch; } if(check.size() >= 3 && !check[2].empty()) { diff -Nru innoextract-1.7/src/cli/main.cpp innoextract-1.8/src/cli/main.cpp --- innoextract-1.7/src/cli/main.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/cli/main.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -145,6 +145,7 @@ po::options_description modifiers("Modifiers"); modifiers.add_options() + ("codepage", po::value(), "Encoding for ANSI strings") ("collisions", po::value(), "How to handle duplicate files") ("default-language", po::value(), "Default language for renaming") ("dump", "Dump contents without converting filenames") @@ -289,13 +290,13 @@ o.preserve_file_times = true, o.local_timestamps = false; po::variables_map::const_iterator i = options.find("timestamps"); if(i != options.end()) { - std::string timezone = i->second.as(); - if(boost::iequals(timezone, "none")) { + std::string timezone_name = i->second.as(); + if(boost::iequals(timezone_name, "none")) { o.preserve_file_times = false; - } else if(!boost::iequals(timezone, "UTC")) { + } else if(!boost::iequals(timezone_name, "UTC")) { o.local_timestamps = true; - if(!boost::iequals(timezone, "local")) { - util::set_local_timezone(timezone); + if(!boost::iequals(timezone_name, "local")) { + util::set_local_timezone(timezone_name); } } } @@ -310,6 +311,10 @@ } { + po::variables_map::const_iterator i = options.find("codepage"); + o.codepage = (i != options.end()) ? i->second.as() : 0; + } + { o.collisions = OverwriteCollisions; po::variables_map::const_iterator i = options.find("collisions"); if(i != options.end()) { @@ -370,7 +375,7 @@ */ o.output_dir = i->second.as(); try { - if(!o.output_dir.empty() && !fs::exists(o.output_dir)) { + if(o.extract && !o.output_dir.empty() && !fs::exists(o.output_dir)) { fs::create_directory(o.output_dir); } } catch(...) { diff -Nru innoextract-1.7/src/configure.hpp.in innoextract-1.8/src/configure.hpp.in --- innoextract-1.7/src/configure.hpp.in 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/configure.hpp.in 2019-09-15 07:52:37.000000000 +0000 @@ -41,6 +41,7 @@ // Process functions #cmakedefine01 INNOEXTRACT_HAVE_POSIX_SPAWNP +#cmakedefine01 INNOEXTRACT_HAVE_UNISTD_ENVIRON #cmakedefine01 INNOEXTRACT_HAVE_FORK #cmakedefine01 INNOEXTRACT_HAVE_EXECVP #cmakedefine01 INNOEXTRACT_HAVE_WAITPID diff -Nru innoextract-1.7/src/crypto/adler32.cpp innoextract-1.8/src/crypto/adler32.cpp --- innoextract-1.7/src/crypto/adler32.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/crypto/adler32.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -29,8 +29,8 @@ const boost::uint_fast32_t base = 65521; - boost::uint_fast32_t s1 = this->s1; - boost::uint_fast32_t s2 = this->s2; + boost::uint_fast32_t s1 = boost::uint16_t(state); + boost::uint_fast32_t s2 = boost::uint16_t(state >> 16); if(length % 8 != 0) { @@ -70,8 +70,8 @@ } } - this->s1 = boost::uint16_t(s1); - this->s2 = boost::uint16_t(s2); + state = (boost::uint32_t(s2) << 16) | boost::uint16_t(s1); + } } // namespace crypto diff -Nru innoextract-1.7/src/crypto/adler32.hpp innoextract-1.8/src/crypto/adler32.hpp --- innoextract-1.7/src/crypto/adler32.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/crypto/adler32.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -37,15 +37,16 @@ //! Adler-32 checksum calculations struct adler32 : public checksum_base { - void init() { s1 = 1, s2 = 0; } + void init() { state = 1; } void update(const char * data, size_t length); - boost::uint32_t finalize() const { return (boost::uint32_t(s2) << 16) | s1; } + boost::uint32_t finalize() const { return state; } private: - boost::uint16_t s1, s2; + boost::uint32_t state; + }; } // namespace crypto diff -Nru innoextract-1.7/src/crypto/crc32.cpp innoextract-1.8/src/crypto/crc32.cpp --- innoextract-1.7/src/crypto/crc32.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/crypto/crc32.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -29,58 +29,58 @@ /* Table of CRC-32's of all single byte values (made by makecrc.c) */ static const boost::uint32_t crc32_table[] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL + 0x00000000l, 0x77073096l, 0xee0e612cl, 0x990951bal, 0x076dc419l, + 0x706af48fl, 0xe963a535l, 0x9e6495a3l, 0x0edb8832l, 0x79dcb8a4l, + 0xe0d5e91el, 0x97d2d988l, 0x09b64c2bl, 0x7eb17cbdl, 0xe7b82d07l, + 0x90bf1d91l, 0x1db71064l, 0x6ab020f2l, 0xf3b97148l, 0x84be41del, + 0x1adad47dl, 0x6ddde4ebl, 0xf4d4b551l, 0x83d385c7l, 0x136c9856l, + 0x646ba8c0l, 0xfd62f97al, 0x8a65c9ecl, 0x14015c4fl, 0x63066cd9l, + 0xfa0f3d63l, 0x8d080df5l, 0x3b6e20c8l, 0x4c69105el, 0xd56041e4l, + 0xa2677172l, 0x3c03e4d1l, 0x4b04d447l, 0xd20d85fdl, 0xa50ab56bl, + 0x35b5a8fal, 0x42b2986cl, 0xdbbbc9d6l, 0xacbcf940l, 0x32d86ce3l, + 0x45df5c75l, 0xdcd60dcfl, 0xabd13d59l, 0x26d930acl, 0x51de003al, + 0xc8d75180l, 0xbfd06116l, 0x21b4f4b5l, 0x56b3c423l, 0xcfba9599l, + 0xb8bda50fl, 0x2802b89el, 0x5f058808l, 0xc60cd9b2l, 0xb10be924l, + 0x2f6f7c87l, 0x58684c11l, 0xc1611dabl, 0xb6662d3dl, 0x76dc4190l, + 0x01db7106l, 0x98d220bcl, 0xefd5102al, 0x71b18589l, 0x06b6b51fl, + 0x9fbfe4a5l, 0xe8b8d433l, 0x7807c9a2l, 0x0f00f934l, 0x9609a88el, + 0xe10e9818l, 0x7f6a0dbbl, 0x086d3d2dl, 0x91646c97l, 0xe6635c01l, + 0x6b6b51f4l, 0x1c6c6162l, 0x856530d8l, 0xf262004el, 0x6c0695edl, + 0x1b01a57bl, 0x8208f4c1l, 0xf50fc457l, 0x65b0d9c6l, 0x12b7e950l, + 0x8bbeb8eal, 0xfcb9887cl, 0x62dd1ddfl, 0x15da2d49l, 0x8cd37cf3l, + 0xfbd44c65l, 0x4db26158l, 0x3ab551cel, 0xa3bc0074l, 0xd4bb30e2l, + 0x4adfa541l, 0x3dd895d7l, 0xa4d1c46dl, 0xd3d6f4fbl, 0x4369e96al, + 0x346ed9fcl, 0xad678846l, 0xda60b8d0l, 0x44042d73l, 0x33031de5l, + 0xaa0a4c5fl, 0xdd0d7cc9l, 0x5005713cl, 0x270241aal, 0xbe0b1010l, + 0xc90c2086l, 0x5768b525l, 0x206f85b3l, 0xb966d409l, 0xce61e49fl, + 0x5edef90el, 0x29d9c998l, 0xb0d09822l, 0xc7d7a8b4l, 0x59b33d17l, + 0x2eb40d81l, 0xb7bd5c3bl, 0xc0ba6cadl, 0xedb88320l, 0x9abfb3b6l, + 0x03b6e20cl, 0x74b1d29al, 0xead54739l, 0x9dd277afl, 0x04db2615l, + 0x73dc1683l, 0xe3630b12l, 0x94643b84l, 0x0d6d6a3el, 0x7a6a5aa8l, + 0xe40ecf0bl, 0x9309ff9dl, 0x0a00ae27l, 0x7d079eb1l, 0xf00f9344l, + 0x8708a3d2l, 0x1e01f268l, 0x6906c2fel, 0xf762575dl, 0x806567cbl, + 0x196c3671l, 0x6e6b06e7l, 0xfed41b76l, 0x89d32be0l, 0x10da7a5al, + 0x67dd4accl, 0xf9b9df6fl, 0x8ebeeff9l, 0x17b7be43l, 0x60b08ed5l, + 0xd6d6a3e8l, 0xa1d1937el, 0x38d8c2c4l, 0x4fdff252l, 0xd1bb67f1l, + 0xa6bc5767l, 0x3fb506ddl, 0x48b2364bl, 0xd80d2bdal, 0xaf0a1b4cl, + 0x36034af6l, 0x41047a60l, 0xdf60efc3l, 0xa867df55l, 0x316e8eefl, + 0x4669be79l, 0xcb61b38cl, 0xbc66831al, 0x256fd2a0l, 0x5268e236l, + 0xcc0c7795l, 0xbb0b4703l, 0x220216b9l, 0x5505262fl, 0xc5ba3bbel, + 0xb2bd0b28l, 0x2bb45a92l, 0x5cb36a04l, 0xc2d7ffa7l, 0xb5d0cf31l, + 0x2cd99e8bl, 0x5bdeae1dl, 0x9b64c2b0l, 0xec63f226l, 0x756aa39cl, + 0x026d930al, 0x9c0906a9l, 0xeb0e363fl, 0x72076785l, 0x05005713l, + 0x95bf4a82l, 0xe2b87a14l, 0x7bb12bael, 0x0cb61b38l, 0x92d28e9bl, + 0xe5d5be0dl, 0x7cdcefb7l, 0x0bdbdf21l, 0x86d3d2d4l, 0xf1d4e242l, + 0x68ddb3f8l, 0x1fda836el, 0x81be16cdl, 0xf6b9265bl, 0x6fb077e1l, + 0x18b74777l, 0x88085ae6l, 0xff0f6a70l, 0x66063bcal, 0x11010b5cl, + 0x8f659effl, 0xf862ae69l, 0x616bffd3l, 0x166ccf45l, 0xa00ae278l, + 0xd70dd2eel, 0x4e048354l, 0x3903b3c2l, 0xa7672661l, 0xd06016f7l, + 0x4969474dl, 0x3e6e77dbl, 0xaed16a4al, 0xd9d65adcl, 0x40df0b66l, + 0x37d83bf0l, 0xa9bcae53l, 0xdebb9ec5l, 0x47b2cf7fl, 0x30b5ffe9l, + 0xbdbdf21cl, 0xcabac28al, 0x53b39330l, 0x24b4a3a6l, 0xbad03605l, + 0xcdd70693l, 0x54de5729l, 0x23d967bfl, 0xb3667a2el, 0xc4614ab8l, + 0x5d681b02l, 0x2a6f2b94l, 0xb40bbe37l, 0xc30c8ea1l, 0x5a05df1bl, + 0x2d02ef8dl }; static boost::uint8_t crc32_index(boost::uint32_t crc) { diff -Nru innoextract-1.7/src/crypto/hasher.cpp innoextract-1.8/src/crypto/hasher.cpp --- innoextract-1.7/src/crypto/hasher.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/crypto/hasher.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -22,9 +22,9 @@ namespace crypto { -hasher::hasher(checksum_type type) : type(type) { +hasher::hasher(checksum_type type) : active_type(type) { - switch(type) { + switch(active_type) { case crypto::None: break; case crypto::Adler32: adler32.init(); break; case crypto::CRC32: crc32.init(); break; @@ -36,7 +36,7 @@ void hasher::update(const char * data, size_t size) { - switch(type) { + switch(active_type) { case crypto::None: break; case crypto::Adler32: adler32.update(data, size); break; case crypto::CRC32: crc32.update(data, size); break; @@ -50,9 +50,9 @@ checksum result; - result.type = type; + result.type = active_type; - switch(type) { + switch(active_type) { case crypto::None: break; case crypto::Adler32: result.adler32 = adler32.finalize(); break; case crypto::CRC32: result.crc32 = crc32.finalize(); break; diff -Nru innoextract-1.7/src/crypto/hasher.hpp innoextract-1.8/src/crypto/hasher.hpp --- innoextract-1.7/src/crypto/hasher.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/crypto/hasher.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -49,7 +49,7 @@ private: - checksum_type type; + checksum_type active_type; union { crypto::adler32 adler32; diff -Nru innoextract-1.7/src/crypto/iteratedhash.hpp innoextract-1.8/src/crypto/iteratedhash.hpp --- innoextract-1.7/src/crypto/iteratedhash.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/crypto/iteratedhash.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -90,7 +90,7 @@ if(num != 0) { // process left over data if(num + length >= block_size) { - std::memcpy(buffer + num, data, block_size-num); + std::memcpy(buffer + num, data, block_size - num); hash(buffer, block_size); data += (block_size - num); length -= (block_size - num); @@ -131,10 +131,10 @@ do { - hash_word buffer[block_size / sizeof(hash_word)]; - byte_order::load(input, buffer, size_t(boost::size(buffer))); + hash_word aligned_buffer[block_size / sizeof(hash_word)]; + byte_order::load(input, aligned_buffer, size_t(boost::size(aligned_buffer))); - transform::transform(state, buffer); + transform::transform(state, aligned_buffer); input += block_size; length -= block_size; diff -Nru innoextract-1.7/src/crypto/md5.cpp innoextract-1.8/src/crypto/md5.cpp --- innoextract-1.7/src/crypto/md5.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/crypto/md5.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -29,10 +29,10 @@ namespace crypto { void md5_transform::init(hash_word * state) { - state[0] = 0x67452301L; - state[1] = 0xefcdab89L; - state[2] = 0x98badcfeL; - state[3] = 0x10325476L; + state[0] = 0x67452301l; + state[1] = 0xefcdab89l; + state[2] = 0x98badcfel; + state[3] = 0x10325476l; } void md5_transform::transform(hash_word * state, const hash_word * data) { diff -Nru innoextract-1.7/src/crypto/sha1.cpp innoextract-1.8/src/crypto/sha1.cpp --- innoextract-1.7/src/crypto/sha1.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/crypto/sha1.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -28,11 +28,11 @@ namespace crypto { void sha1_transform::init(hash_word * state) { - state[0] = 0x67452301L; - state[1] = 0xEFCDAB89L; - state[2] = 0x98BADCFEL; - state[3] = 0x10325476L; - state[4] = 0xC3D2E1F0L; + state[0] = 0x67452301l; + state[1] = 0xefcdab89l; + state[2] = 0x98badcfel; + state[3] = 0x10325476l; + state[4] = 0xc3d2e1f0l; } void sha1_transform::transform(hash_word * state, const hash_word * data) { diff -Nru innoextract-1.7/src/loader/exereader.hpp innoextract-1.8/src/loader/exereader.hpp --- innoextract-1.7/src/loader/exereader.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/loader/exereader.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -81,7 +81,7 @@ /*! * \brief Find where a resource with a given ID is stored in a NE or PE binary. * - * Resources are addressed using a (\pname{name}, \pname{type}, \pname{language}) tuple. + * Resources are addressed using a (name, type, language) tuple. * * \param is a seekable stream of the binary containing the resource * \param name the user-defined name of the resource diff -Nru innoextract-1.7/src/loader/offsets.cpp innoextract-1.8/src/loader/offsets.cpp --- innoextract-1.7/src/loader/offsets.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/loader/offsets.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -21,6 +21,7 @@ #include "loader/offsets.hpp" #include +#include #include #include @@ -33,6 +34,7 @@ #include "setup/version.hpp" #include "util/load.hpp" #include "util/log.hpp" +#include "util/output.hpp" namespace loader { @@ -54,6 +56,7 @@ { { 'r', 'D', 'l', 'P', 't', 'S', '0', '6', 0x87, 'e', 'V', 'x' }, INNO_VERSION(4, 0, 10) }, { { 'r', 'D', 'l', 'P', 't', 'S', '0', '7', 0x87, 'e', 'V', 'x' }, INNO_VERSION(4, 1, 6) }, { { 'r', 'D', 'l', 'P', 't', 'S', 0xcd, 0xe6, 0xd7, '{', 0x0b, '*' }, INNO_VERSION(5, 1, 5) }, + { { 'n', 'S', '5', 'W', '7', 'd', 'T', 0x83, 0xaa, 0x1b, 0x0f, 'j' }, INNO_VERSION(5, 1, 5) }, }; const int ResourceNameInstaller = 11111; @@ -116,7 +119,8 @@ } } if(!version) { - return false; + log_warning << "Unexpected setup loader magic: " << print_hex(magic); + version = std::numeric_limits::max(); } crypto::crc32 checksum; @@ -125,9 +129,11 @@ if(version >= INNO_VERSION(5, 1, 5)) { boost::uint32_t revision = checksum.load(is); - if(is.fail() || revision != 1) { + if(is.fail()) { is.clear(); return false; + } else if(revision != 1) { + log_warning << "Unexpected setup loader revision: " << revision; } } @@ -171,8 +177,7 @@ return false; } if(checksum.finalize() != expected) { - log_error << "Loader checksum mismatch!"; - return false; + log_warning << "Setup loader checksum mismatch!"; } } diff -Nru innoextract-1.7/src/setup/component.cpp innoextract-1.8/src/setup/component.cpp --- innoextract-1.7/src/setup/component.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/component.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -20,6 +20,7 @@ #include "setup/component.hpp" +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" @@ -53,48 +54,52 @@ } // anonymous namespace -void component_entry::load(std::istream & is, const version & version) { +void component_entry::load(std::istream & is, const info & i) { - is >> util::encoded_string(name, version.codepage()); - is >> util::encoded_string(description, version.codepage()); - is >> util::encoded_string(types, version.codepage()); - if(version >= INNO_VERSION(4, 0, 1)) { - is >> util::encoded_string(languages, version.codepage()); + is >> util::encoded_string(name, i.codepage); + is >> util::encoded_string(description, i.codepage); + is >> util::encoded_string(types, i.codepage); + if(i.version >= INNO_VERSION(4, 0, 1)) { + is >> util::encoded_string(languages, i.codepage); } else { languages.clear(); } - if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) { - is >> util::encoded_string(check, version.codepage()); + if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(1, 3, 24))) { + is >> util::encoded_string(check, i.codepage); } else { check.clear(); } - - if(version >= INNO_VERSION(4, 0, 0)) { + if(i.version >= INNO_VERSION(4, 0, 0)) { extra_disk_pace_required = util::load(is); } else { extra_disk_pace_required = util::load(is); } - - if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) { + if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(3, 0, 3))) { level = util::load(is); + } else { + level = 0; + } + if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(3, 0, 4))) { used = util::load_bool(is); } else { - level = 0, used = true; + used = true; } - winver.load(is, version); + winver.load(is, i.version); - if(version >= INNO_VERSION(4, 2, 3)) { + if(i.version >= INNO_VERSION(4, 2, 3)) { options = stored_flags(is).get(); - } else if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) { + } else if(i.version >= INNO_VERSION(3, 0, 8) || + (i.version.is_isx() && i.version >= INNO_VERSION_EXT(3, 0, 6, 1))) { options = stored_flags(is).get(); } else { options = stored_flags(is).get(); } - if(version >= INNO_VERSION(4, 0, 0)) { + if(i.version >= INNO_VERSION(4, 0, 0)) { size = util::load(is); - } else { + } else if(i.version >= INNO_VERSION(2, 0, 0) || + (i.version.is_isx() && i.version >= INNO_VERSION(1, 3, 24))) { size = util::load(is); } } diff -Nru innoextract-1.7/src/setup/component.hpp innoextract-1.8/src/setup/component.hpp --- innoextract-1.7/src/setup/component.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/component.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -37,7 +37,7 @@ namespace setup { -struct version; +struct info; struct component_entry { @@ -68,7 +68,7 @@ boost::uint64_t size; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/data.cpp innoextract-1.8/src/setup/data.cpp --- innoextract-1.7/src/setup/data.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/data.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -22,6 +22,7 @@ #include +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/log.hpp" @@ -31,11 +32,11 @@ namespace setup { -void data_entry::load(std::istream & is, const version & version) { +void data_entry::load(std::istream & is, const info & i) { - chunk.first_slice = util::load(is, version.bits); - chunk.last_slice = util::load(is, version.bits); - if(version < INNO_VERSION(4, 0, 0)) { + chunk.first_slice = util::load(is, i.version.bits()); + chunk.last_slice = util::load(is, i.version.bits()); + if(i.version < INNO_VERSION(4, 0, 0)) { if(chunk.first_slice < 1 || chunk.last_slice < 1) { log_warning << "Unexpected slice number: " << chunk.first_slice << " to " << chunk.last_slice; @@ -44,15 +45,15 @@ } } - chunk.offset = util::load(is); + chunk.sort_offset = chunk.offset = util::load(is); - if(version >= INNO_VERSION(4, 0, 1)) { + if(i.version >= INNO_VERSION(4, 0, 1)) { file.offset = util::load(is); } else { file.offset = 0; } - if(version >= INNO_VERSION(4, 0, 0)) { + if(i.version >= INNO_VERSION(4, 0, 0)) { file.size = util::load(is); chunk.size = util::load(is); } else { @@ -61,13 +62,13 @@ } uncompressed_size = file.size; - if(version >= INNO_VERSION(5, 3, 9)) { + if(i.version >= INNO_VERSION(5, 3, 9)) { is.read(file.checksum.sha1, std::streamsize(sizeof(file.checksum.sha1))); file.checksum.type = crypto::SHA1; - } else if(version >= INNO_VERSION(4, 2, 0)) { + } else if(i.version >= INNO_VERSION(4, 2, 0)) { is.read(file.checksum.md5, std::streamsize(sizeof(file.checksum.md5))); file.checksum.type = crypto::MD5; - } else if(version >= INNO_VERSION(4, 0, 1)) { + } else if(i.version >= INNO_VERSION(4, 0, 1)) { file.checksum.crc32 = util::load(is); file.checksum.type = crypto::CRC32; } else { @@ -75,7 +76,7 @@ file.checksum.type = crypto::Adler32; } - if(version.bits == 16) { + if(i.version.bits() == 16) { // 16-bit installers use the FAT filetime format @@ -118,37 +119,37 @@ options = 0; - stored_flag_reader flagreader(is, version.bits); + stored_flag_reader flagreader(is, i.version.bits()); flagreader.add(VersionInfoValid); flagreader.add(VersionInfoNotValid); - if(version >= INNO_VERSION(2, 0, 17) && version < INNO_VERSION(4, 0, 1)) { + if(i.version >= INNO_VERSION(2, 0, 17) && i.version < INNO_VERSION(4, 0, 1)) { flagreader.add(BZipped); } - if(version >= INNO_VERSION(4, 0, 10)) { + if(i.version >= INNO_VERSION(4, 0, 10)) { flagreader.add(TimeStampInUTC); } - if(version >= INNO_VERSION(4, 1, 0)) { + if(i.version >= INNO_VERSION(4, 1, 0)) { flagreader.add(IsUninstallerExe); } - if(version >= INNO_VERSION(4, 1, 8)) { + if(i.version >= INNO_VERSION(4, 1, 8)) { flagreader.add(CallInstructionOptimized); } - if(version >= INNO_VERSION(4, 2, 0)) { + if(i.version >= INNO_VERSION(4, 2, 0)) { flagreader.add(Touch); } - if(version >= INNO_VERSION(4, 2, 2)) { + if(i.version >= INNO_VERSION(4, 2, 2)) { flagreader.add(ChunkEncrypted); } - if(version >= INNO_VERSION(4, 2, 5)) { + if(i.version >= INNO_VERSION(4, 2, 5)) { flagreader.add(ChunkCompressed); } else { options |= ChunkCompressed; } - if(version >= INNO_VERSION(5, 1, 13)) { + if(i.version >= INNO_VERSION(5, 1, 13)) { flagreader.add(SolidBreak); } - if(version >= INNO_VERSION(5, 5, 7)) { + if(i.version >= INNO_VERSION(5, 5, 7)) { // Actually added in Inno Setup 5.5.9 but the data version was not bumped flagreader.add(Sign); flagreader.add(SignOnce); @@ -157,7 +158,7 @@ options |= flagreader; if(options & ChunkCompressed) { - chunk.compression = stream::UnknownCompression; + chunk.compression = i.header.compression; } else { chunk.compression = stream::Stored; } @@ -167,7 +168,7 @@ } if(options & ChunkEncrypted) { - if(version >= INNO_VERSION(5, 3, 9)) { + if(i.version >= INNO_VERSION(5, 3, 9)) { chunk.encryption = stream::ARC4_SHA1; } else { chunk.encryption = stream::ARC4_MD5; @@ -177,9 +178,9 @@ } if(options & CallInstructionOptimized) { - if(version < INNO_VERSION(5, 2, 0)) { + if(i.version < INNO_VERSION(5, 2, 0)) { file.filter = stream::InstructionFilter4108; - } else if(version < INNO_VERSION(5, 3, 9)) { + } else if(i.version < INNO_VERSION(5, 3, 9)) { file.filter = stream::InstructionFilter5200; } else { file.filter = stream::InstructionFilter5309; diff -Nru innoextract-1.7/src/setup/data.hpp innoextract-1.8/src/setup/data.hpp --- innoextract-1.7/src/setup/data.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/data.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -39,7 +39,7 @@ namespace setup { -struct version; +struct info; struct data_entry { @@ -79,7 +79,7 @@ * * \note This function may not be thread-safe on all operating systems. */ - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/delete.cpp innoextract-1.8/src/setup/delete.cpp --- innoextract-1.7/src/setup/delete.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/delete.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -20,6 +20,7 @@ #include "setup/delete.hpp" +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" @@ -36,17 +37,17 @@ } // anonymous namespace -void delete_entry::load(std::istream & is, const version & version) { +void delete_entry::load(std::istream & is, const info & i) { - if(version < INNO_VERSION(1, 3, 21)) { + if(i.version < INNO_VERSION(1, 3, 0)) { (void)util::load(is); // uncompressed size of the entry } - is >> util::encoded_string(name, version.codepage()); + is >> util::encoded_string(name, i.codepage); - load_condition_data(is, version); + load_condition_data(is, i); - load_version_data(is, version); + load_version_data(is, i.version); type = stored_enum(is).get(); } diff -Nru innoextract-1.7/src/setup/delete.hpp innoextract-1.8/src/setup/delete.hpp --- innoextract-1.7/src/setup/delete.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/delete.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -34,7 +34,7 @@ namespace setup { -struct version; +struct info; struct delete_entry : public item { @@ -48,7 +48,7 @@ target_type type; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/directory.cpp innoextract-1.8/src/setup/directory.cpp --- innoextract-1.7/src/setup/directory.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/directory.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -20,6 +20,7 @@ #include "setup/directory.hpp" +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" @@ -45,39 +46,39 @@ } // anonymous namespace -void directory_entry::load(std::istream & is, const version & version) { +void directory_entry::load(std::istream & is, const info & i) { - if(version < INNO_VERSION(1, 3, 21)) { + if(i.version < INNO_VERSION(1, 3, 0)) { (void)util::load(is); // uncompressed size of the entry } - is >> util::encoded_string(name, version.codepage()); + is >> util::encoded_string(name, i.codepage); - load_condition_data(is, version); + load_condition_data(is, i); - if(version >= INNO_VERSION(4, 0, 11) && version < INNO_VERSION(4, 1, 0)) { - is >> util::encoded_string(permissions, version.codepage()); + if(i.version >= INNO_VERSION(4, 0, 11) && i.version < INNO_VERSION(4, 1, 0)) { + is >> util::binary_string(permissions); } else { permissions.clear(); } - if(version >= INNO_VERSION(2, 0, 11)) { + if(i.version >= INNO_VERSION(2, 0, 11)) { attributes = util::load(is); } else { attributes = 0; } - load_version_data(is, version); + load_version_data(is, i.version); - if(version >= INNO_VERSION(4, 1, 0)) { + if(i.version >= INNO_VERSION(4, 1, 0)) { permission = util::load(is); } else { permission = boost::int16_t(-1); } - if(version >= INNO_VERSION(5, 2, 0)) { + if(i.version >= INNO_VERSION(5, 2, 0)) { options = stored_flags(is).get(); - } else if(version.bits != 16) { + } else if(i.version.bits() != 16) { options = stored_flags(is).get(); } else { options = stored_flags(is).get(); diff -Nru innoextract-1.7/src/setup/directory.hpp innoextract-1.8/src/setup/directory.hpp --- innoextract-1.7/src/setup/directory.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/directory.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -37,7 +37,7 @@ namespace setup { -struct version; +struct info; struct directory_entry : public item { @@ -58,7 +58,7 @@ flags options; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/expression.cpp innoextract-1.8/src/setup/expression.cpp --- innoextract-1.7/src/setup/expression.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/expression.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2018 Daniel Scharrer + * Copyright (C) 2012-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -53,10 +53,11 @@ paren_right, identifier } token; - std::string token_str; + const char * token_start; + size_t token_length; - evaluator(const std::string & expr, const std::string & test) - : test(test), expr(expr.c_str()), token(end) { } + evaluator(const std::string & expression, const std::string & variable) + : test(variable), expr(expression.c_str()), token(end) { } token_type next() { @@ -89,7 +90,9 @@ return (token = op_or); } - return (token_str.assign(start, expr), token = identifier); + token_start = start; + token_length = size_t(expr - start); + return (token = identifier); } else { throw std::runtime_error(std::string("unexpected symbol: ") + *expr); @@ -97,7 +100,7 @@ } bool eval_identifier(bool lazy) { - bool result = lazy || token_str == test; + bool result = lazy || test.compare(0, std::string::npos, token_start, token_length) == 0; next(); return result; } @@ -125,25 +128,31 @@ bool result = eval_factor(lazy); while(token == op_and) { next(); - result = result && eval_factor(lazy || !result); + result = eval_factor(lazy || !result) && result; } return result; } - bool eval_expression(bool lazy) { + bool eval_expression(bool lazy, bool inner = true) { bool result = eval_term(lazy); + if(result && !inner) { + return result; + } while(token == op_or || token == identifier) { if(token == op_or) { next(); } - result = result || eval_term(lazy || result); + result = eval_term(lazy || result) || result; + if(result && !inner) { + return result; + } } return result; } bool eval() { next(); - return eval_expression(false); + return eval_expression(false, false); } }; diff -Nru innoextract-1.7/src/setup/expression.hpp innoextract-1.8/src/setup/expression.hpp --- innoextract-1.7/src/setup/expression.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/expression.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Daniel Scharrer + * Copyright (C) 2012-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -30,6 +30,9 @@ namespace setup { +/* + * Determine if the given expression is satisfied with (only) the given test variable set to true + */ bool expression_match(const std::string & test, const std::string & expression); bool is_simple_expression(const std::string & expression); diff -Nru innoextract-1.7/src/setup/file.cpp innoextract-1.8/src/setup/file.cpp --- innoextract-1.7/src/setup/file.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/file.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -20,6 +20,7 @@ #include "setup/file.hpp" +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/log.hpp" @@ -70,35 +71,35 @@ namespace setup { -void file_entry::load(std::istream & is, const version & version) { +void file_entry::load(std::istream & is, const info & i) { USE_ENUM_NAMES(file_copy_mode) options = 0; - if(version < INNO_VERSION(1, 3, 21)) { + if(i.version < INNO_VERSION(1, 3, 0)) { (void)util::load(is); // uncompressed size of the entry } - is >> util::encoded_string(source, version.codepage()); - is >> util::encoded_string(destination, version.codepage()); - is >> util::encoded_string(install_font_name, version.codepage()); - if(version >= INNO_VERSION(5, 2, 5)) { - is >> util::encoded_string(strong_assembly_name, version.codepage()); + is >> util::encoded_string(source, i.codepage); + is >> util::encoded_string(destination, i.codepage); + is >> util::encoded_string(install_font_name, i.codepage); + if(i.version >= INNO_VERSION(5, 2, 5)) { + is >> util::encoded_string(strong_assembly_name, i.codepage); } else { strong_assembly_name.clear(); } - load_condition_data(is, version); + load_condition_data(is, i); - load_version_data(is, version); + load_version_data(is, i.version); - location = util::load(is, version.bits); - attributes = util::load(is, version.bits); - external_size = (version >= INNO_VERSION(4, 0, 0)) ? util::load(is) - : util::load(is); + location = util::load(is, i.version.bits()); + attributes = util::load(is, i.version.bits()); + external_size = (i.version >= INNO_VERSION(4, 0, 0)) ? util::load(is) + : util::load(is); - if(version < INNO_VERSION(3, 0, 5)) { + if(i.version < INNO_VERSION(3, 0, 5)) { file_copy_mode copyMode = stored_enum(is).get(); switch(copyMode) { case cmNormal: options |= PromptIfOlder; break; @@ -108,85 +109,90 @@ } } - if(version >= INNO_VERSION(4, 1, 0)) { + if(i.version >= INNO_VERSION(4, 1, 0)) { permission = util::load(is); } else { permission = boost::int16_t(-1); } - stored_flag_reader flagreader(is, version.bits); + stored_flag_reader flagreader(is, i.version.bits()); flagreader.add(ConfirmOverwrite); flagreader.add(NeverUninstall); flagreader.add(RestartReplace); flagreader.add(DeleteAfterInstall); - if(version.bits != 16) { + if(i.version.bits() != 16) { flagreader.add(RegisterServer); flagreader.add(RegisterTypeLib); flagreader.add(SharedFile); } - if(version < INNO_VERSION(2, 0, 0)) { + if(i.version < INNO_VERSION(2, 0, 0) && !i.version.is_isx()) { flagreader.add(IsReadmeFile); } flagreader.add(CompareTimeStamp); flagreader.add(FontIsNotTrueType); - flagreader.add(SkipIfSourceDoesntExist); - flagreader.add(OverwriteReadOnly); - if(version >= INNO_VERSION(1, 3, 21)) { + if(i.version >= INNO_VERSION(1, 2, 5)) { + flagreader.add(SkipIfSourceDoesntExist); + } + if(i.version >= INNO_VERSION(1, 2, 6)) { + flagreader.add(OverwriteReadOnly); + } + if(i.version >= INNO_VERSION(1, 3, 21)) { flagreader.add(OverwriteSameVersion); flagreader.add(CustomDestName); } - if(version >= INNO_VERSION(1, 3, 25)) { + if(i.version >= INNO_VERSION(1, 3, 25)) { flagreader.add(OnlyIfDestFileExists); } - if(version >= INNO_VERSION(2, 0, 5)) { + if(i.version >= INNO_VERSION(2, 0, 5)) { flagreader.add(NoRegError); } - if(version >= INNO_VERSION(3, 0, 1)) { + if(i.version >= INNO_VERSION(3, 0, 1)) { flagreader.add(UninsRestartDelete); } - if(version >= INNO_VERSION(3, 0, 5)) { + if(i.version >= INNO_VERSION(3, 0, 5)) { flagreader.add(OnlyIfDoesntExist); flagreader.add(IgnoreVersion); flagreader.add(PromptIfOlder); } - if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) { + if(i.version >= INNO_VERSION(4, 0, 0) || + (i.version.is_isx() && i.version >= INNO_VERSION_EXT(3, 0, 6, 1))) { flagreader.add(DontCopy); } - if(version >= INNO_VERSION(4, 0, 5)) { + if(i.version >= INNO_VERSION(4, 0, 5)) { flagreader.add(UninsRemoveReadOnly); } - if(version >= INNO_VERSION(4, 1, 8)) { + if(i.version >= INNO_VERSION(4, 1, 8)) { flagreader.add(RecurseSubDirsExternal); } - if(version >= INNO_VERSION(4, 2, 1)) { + if(i.version >= INNO_VERSION(4, 2, 1)) { flagreader.add(ReplaceSameVersionIfContentsDiffer); } - if(version >= INNO_VERSION(4, 2, 5)) { + if(i.version >= INNO_VERSION(4, 2, 5)) { flagreader.add(DontVerifyChecksum); } - if(version >= INNO_VERSION(5, 0, 3)) { + if(i.version >= INNO_VERSION(5, 0, 3)) { flagreader.add(UninsNoSharedFilePrompt); } - if(version >= INNO_VERSION(5, 1, 0)) { + if(i.version >= INNO_VERSION(5, 1, 0)) { flagreader.add(CreateAllSubDirs); } - if(version >= INNO_VERSION(5, 1, 2)) { + if(i.version >= INNO_VERSION(5, 1, 2)) { flagreader.add(Bits32); flagreader.add(Bits64); } - if(version >= INNO_VERSION(5, 2, 0)) { + if(i.version >= INNO_VERSION(5, 2, 0)) { flagreader.add(ExternalSizePreset); flagreader.add(SetNtfsCompression); flagreader.add(UnsetNtfsCompression); } - if(version >= INNO_VERSION(5, 2, 5)) { + if(i.version >= INNO_VERSION(5, 2, 5)) { flagreader.add(GacInstall); } options |= flagreader; - if(version.bits == 16 || version >= INNO_VERSION(5, 0, 0)) { + if(i.version.bits() == 16 || i.version >= INNO_VERSION(5, 0, 0)) { type = stored_enum(is).get(); } else { type = stored_enum(is).get(); diff -Nru innoextract-1.7/src/setup/file.hpp innoextract-1.8/src/setup/file.hpp --- innoextract-1.7/src/setup/file.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/file.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -39,7 +39,7 @@ namespace setup { -struct version; +struct info; struct file_entry : public item { @@ -113,7 +113,7 @@ crypto::checksum checksum; boost::uint64_t size; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/filename.cpp innoextract-1.8/src/setup/filename.cpp --- innoextract-1.7/src/setup/filename.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/filename.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2018 Daniel Scharrer + * Copyright (C) 2012-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -79,7 +79,9 @@ while(pos != end && *pos != '{' && *pos != '}') { ++pos; } + ptrdiff_t obegin = ptrdiff_t(result.size()); result.append(begin, pos); + result.erase(std::remove_if(result.begin() + obegin, result.end(), is_unsafe_path_char()), result.end()); begin = pos; if(pos == end) { @@ -114,7 +116,7 @@ return result; } -std::string filename_map::shorten_path(const std::string & path) const { +std::string filename_map::shorten_path(const std::string & path) { std::string result; result.reserve(path.size()); diff -Nru innoextract-1.7/src/setup/filename.hpp innoextract-1.8/src/setup/filename.hpp --- innoextract-1.7/src/setup/filename.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/filename.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2016 Daniel Scharrer + * Copyright (C) 2012-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -52,7 +52,7 @@ typedef std::string::const_iterator it; std::string expand_variables(it & begin, it end, bool close = false) const; - std::string shorten_path(const std::string & path) const; + static std::string shorten_path(const std::string & path); public: diff -Nru innoextract-1.7/src/setup/header.cpp innoextract-1.8/src/setup/header.cpp --- innoextract-1.7/src/setup/header.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/header.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -26,7 +26,6 @@ #include #include "setup/version.hpp" -#include "util/encoding.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" @@ -136,106 +135,132 @@ stream::LZMA2 ); +// 6.0.0+ +STORED_FLAGS_MAP(stored_privileges_required_overrides, + header::Commandline, + header::Dialog +); + } // anonymous namespace void header::load(std::istream & is, const version & version) { options = 0; - if(version < INNO_VERSION(1, 3, 21)) { + if(version < INNO_VERSION(1, 3, 0)) { (void)util::load(is); // uncompressed size of the setup header } - is >> util::encoded_string(app_name, version.codepage()); - is >> util::encoded_string(app_versioned_name, version.codepage()); - if(version >= INNO_VERSION(1, 3, 21)) { - is >> util::encoded_string(app_id, version.codepage()); - } - is >> util::encoded_string(app_copyright, version.codepage()); - if(version >= INNO_VERSION(1, 3, 21)) { - is >> util::encoded_string(app_publisher, version.codepage()); - is >> util::encoded_string(app_publisher_url, version.codepage()); + is >> util::binary_string(app_name); + is >> util::binary_string(app_versioned_name); + if(version >= INNO_VERSION(1, 3, 0)) { + is >> util::binary_string(app_id); + } else { + app_id.clear(); + } + is >> util::binary_string(app_copyright); + if(version >= INNO_VERSION(1, 3, 0)) { + is >> util::binary_string(app_publisher); + is >> util::binary_string(app_publisher_url); } else { app_publisher.clear(), app_publisher_url.clear(); } if(version >= INNO_VERSION(5, 1, 13)) { - is >> util::encoded_string(app_support_phone, version.codepage()); + is >> util::binary_string(app_support_phone); } else { app_support_phone.clear(); } - if(version >= INNO_VERSION(1, 3, 21)) { - is >> util::encoded_string(app_support_url, version.codepage()); - is >> util::encoded_string(app_updates_url, version.codepage()); - is >> util::encoded_string(app_version, version.codepage()); + if(version >= INNO_VERSION(1, 3, 0)) { + is >> util::binary_string(app_support_url); + is >> util::binary_string(app_updates_url); + is >> util::binary_string(app_version); } else { app_support_url.clear(), app_updates_url.clear(), app_version.clear(); } - is >> util::encoded_string(default_dir_name, version.codepage()); - is >> util::encoded_string(default_group_name, version.codepage()); + is >> util::binary_string(default_dir_name); + is >> util::binary_string(default_group_name); if(version < INNO_VERSION(3, 0, 0)) { is >> util::ansi_string(uninstall_icon_name); } else { uninstall_icon_name.clear(); } - is >> util::encoded_string(base_filename, version.codepage()); - if(version >= INNO_VERSION(1, 3, 21)) { - if(version < INNO_VERSION(5, 2, 5)) { - is >> util::ansi_string(license_text); - is >> util::ansi_string(info_before); - is >> util::ansi_string(info_after); - } - is >> util::encoded_string(uninstall_files_dir, version.codepage()); - is >> util::encoded_string(uninstall_name, version.codepage()); - is >> util::encoded_string(uninstall_icon, version.codepage()); - is >> util::encoded_string(app_mutex, version.codepage()); + is >> util::binary_string(base_filename); + if(version >= INNO_VERSION(1, 3, 0) && version < INNO_VERSION(5, 2, 5)) { + is >> util::ansi_string(license_text); + is >> util::ansi_string(info_before); + is >> util::ansi_string(info_after); } else { license_text.clear(), info_before.clear(), info_after.clear(); - uninstall_files_dir.clear(), uninstall_name.clear(); - uninstall_icon.clear(), app_mutex.clear(); + } + if(version >= INNO_VERSION(1, 3, 3)) { + is >> util::binary_string(uninstall_files_dir); + } else { + uninstall_files_dir.clear(); + } + if(version >= INNO_VERSION(1, 3, 6)) { + is >> util::binary_string(uninstall_name); + is >> util::binary_string(uninstall_icon); + } else { + uninstall_name.clear(), uninstall_icon.clear(); + } + if(version >= INNO_VERSION(1, 3, 14)) { + is >> util::binary_string(app_mutex); + } else { + app_mutex.clear(); } if(version >= INNO_VERSION(3, 0, 0)) { - is >> util::encoded_string(default_user_name, version.codepage()); - is >> util::encoded_string(default_user_organisation, version.codepage()); + is >> util::binary_string(default_user_name); + is >> util::binary_string(default_user_organisation); } else { default_user_name.clear(), default_user_organisation.clear(); } - if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) { - is >> util::encoded_string(default_serial, version.codepage()); - if(version < INNO_VERSION(5, 2, 5)) { - is >> util::binary_string(compiled_code); - } + if(version >= INNO_VERSION(4, 0, 0) || (version.is_isx() && version >= INNO_VERSION_EXT(3, 0, 6, 1))) { + is >> util::binary_string(default_serial); + } else { + default_serial.clear(); + } + if((version >= INNO_VERSION(4, 0, 0) && version < INNO_VERSION(5, 2, 5)) || + (version.is_isx() && version >= INNO_VERSION(1, 3, 24))) { + is >> util::binary_string(compiled_code); } else { - default_serial.clear(), compiled_code.clear(); + compiled_code.clear(); } if(version >= INNO_VERSION(4, 2, 4)) { - is >> util::encoded_string(app_readme_file, version.codepage()); - is >> util::encoded_string(app_contact, version.codepage()); - is >> util::encoded_string(app_comments, version.codepage()); - is >> util::encoded_string(app_modify_path, version.codepage()); + is >> util::binary_string(app_readme_file); + is >> util::binary_string(app_contact); + is >> util::binary_string(app_comments); + is >> util::binary_string(app_modify_path); } else { app_readme_file.clear(), app_contact.clear(); app_comments.clear(), app_modify_path.clear(); } if(version >= INNO_VERSION(5, 3, 8)) { - is >> util::encoded_string(create_uninstall_registry_key, version.codepage()); + is >> util::binary_string(create_uninstall_registry_key); } else { create_uninstall_registry_key.clear(); } if(version >= INNO_VERSION(5, 3, 10)) { - is >> util::encoded_string(uninstallable, version.codepage()); + is >> util::binary_string(uninstallable); } else { uninstallable.clear(); } if(version >= INNO_VERSION(5, 5, 0)) { - is >> util::encoded_string(close_applications_filter, version.codepage()); + is >> util::binary_string(close_applications_filter); } else { close_applications_filter.clear(); } if(version >= INNO_VERSION(5, 5, 6)) { - is >> util::encoded_string(setup_mutex, version.codepage()); + is >> util::binary_string(setup_mutex); } else { setup_mutex.clear(); } + if(version >= INNO_VERSION(5, 6, 1)) { + is >> util::binary_string(changes_environment); + is >> util::binary_string(changes_associations); + } else { + changes_environment.clear(); + changes_associations.clear(); + } if(version >= INNO_VERSION(5, 2, 5)) { is >> util::ansi_string(license_text); is >> util::ansi_string(info_before); @@ -250,7 +275,7 @@ is >> util::binary_string(compiled_code); } - if(version >= INNO_VERSION(2, 0, 6) && !version.unicode) { + if(version >= INNO_VERSION(2, 0, 6) && !version.is_unicode()) { lead_bytes = stored_char_set(is); } else { lead_bytes = 0; @@ -276,38 +301,42 @@ permission_count = 0; } - if(version >= INNO_VERSION(2, 0, 0)) { + if(version >= INNO_VERSION(2, 0, 0) || version.is_isx()) { type_count = util::load(is); component_count = util::load(is); + } else { + type_count = 0, component_count = 0; + } + if(version >= INNO_VERSION(2, 0, 0) || (version.is_isx() && version >= INNO_VERSION(1, 3, 17))) { task_count = util::load(is); } else { - type_count = 0, component_count = 0, task_count = 0; + task_count = 0; } - directory_count = util::load(is, version.bits); - file_count = util::load(is, version.bits); - data_entry_count = util::load(is, version.bits); - icon_count = util::load(is, version.bits); - ini_entry_count = util::load(is, version.bits); - registry_entry_count = util::load(is, version.bits); - delete_entry_count = util::load(is, version.bits); - uninstall_delete_entry_count = util::load(is, version.bits); - run_entry_count = util::load(is, version.bits); - uninstall_run_entry_count = util::load(is, version.bits); + directory_count = util::load(is, version.bits()); + file_count = util::load(is, version.bits()); + data_entry_count = util::load(is, version.bits()); + icon_count = util::load(is, version.bits()); + ini_entry_count = util::load(is, version.bits()); + registry_entry_count = util::load(is, version.bits()); + delete_entry_count = util::load(is, version.bits()); + uninstall_delete_entry_count = util::load(is, version.bits()); + run_entry_count = util::load(is, version.bits()); + uninstall_run_entry_count = util::load(is, version.bits()); boost::int32_t license_size = 0; boost::int32_t info_before_size = 0; boost::int32_t info_after_size = 0; - if(version < INNO_VERSION(1, 3, 21)) { - license_size = util::load(is, version.bits); - info_before_size = util::load(is, version.bits); - info_after_size = util::load(is, version.bits); + if(version < INNO_VERSION(1, 3, 0)) { + license_size = util::load(is, version.bits()); + info_before_size = util::load(is, version.bits()); + info_after_size = util::load(is, version.bits()); } winver.load(is, version); back_color = util::load(is); - if(version >= INNO_VERSION(1, 3, 21)) { + if(version >= INNO_VERSION(1, 3, 3)) { back_color2 = util::load(is); } else { back_color2 = 0; @@ -317,12 +346,22 @@ } else { image_back_color = 0; } - if(version >= INNO_VERSION(2, 0, 0) && version < INNO_VERSION(5, 0, 4)) { + if((version >= INNO_VERSION(2, 0, 0) && version < INNO_VERSION(5, 0, 4)) || version.is_isx()) { small_image_back_color = util::load(is); } else { small_image_back_color = 0; } + if(version >= INNO_VERSION(6, 0, 0)) { + wizard_style = stored_enum(is).get(); + wizard_resize_percent_x = util::load(is); + wizard_resize_percent_y = util::load(is); + } else { + wizard_style = ClassicStyle; + wizard_resize_percent_x = 0; + wizard_resize_percent_y = 0; + } + if(version >= INNO_VERSION(5, 5, 7)) { image_alpha_format = stored_enum(is).get(); } else { @@ -355,30 +394,38 @@ slices_per_disk = 1; } - if(version >= INNO_VERSION(2, 0, 0) && version < INNO_VERSION(5, 0, 0)) { + if((version >= INNO_VERSION(2, 0, 0) && version < INNO_VERSION(5, 0, 0)) || + (version.is_isx() && version >= INNO_VERSION(1, 3, 4))) { install_mode = stored_enum(is).get(); } else { install_mode = NormalInstallMode; } - if(version >= INNO_VERSION(1, 3, 21)) { + if(version >= INNO_VERSION(1, 3, 0)) { uninstall_log_mode = stored_enum(is).get(); } else { - uninstall_log_mode = AppendLog; + uninstall_log_mode = NewLog; } - if(version >= INNO_VERSION(2, 0, 0) && version < INNO_VERSION(5, 0, 0)) { + if(version >= INNO_VERSION(5, 0, 0)) { + uninstall_style = ModernStyle; + } else if(version >= INNO_VERSION(2, 0, 0) || (version.is_isx() && version >= INNO_VERSION(1, 3, 13))) { uninstall_style = stored_enum(is).get(); } else { - uninstall_style = (version < INNO_VERSION(5, 0, 0)) ? ClassicStyle : ModernStyle; + uninstall_style = ClassicStyle; } - if(version >= INNO_VERSION(1, 3, 21)) { + if(version >= INNO_VERSION(1, 3, 6)) { dir_exists_warning = stored_enum(is).get(); } else { dir_exists_warning = Auto; } + if(version.is_isx() && version >= INNO_VERSION(2, 0, 10) && version < INNO_VERSION(3, 0, 0)) { + boost::int32_t code_line_offset = util::load(is); + (void)code_line_offset; + } + if(version >= INNO_VERSION(3, 0, 0) && version < INNO_VERSION(3, 0, 3)) { auto_bool val = stored_enum(is).get(); switch(val) { @@ -390,10 +437,16 @@ if(version >= INNO_VERSION(5, 3, 7)) { privileges_required = stored_enum(is).get(); - } else if(version >= INNO_VERSION(3, 0, 4)) { + } else if(version >= INNO_VERSION(3, 0, 4) || (version.is_isx() && version >= INNO_VERSION(3, 0, 3))) { privileges_required = stored_enum(is).get(); } + if(version >= INNO_VERSION(5, 7, 0)) { + privileges_required_override_allowed = stored_flags(is).get(); + } else { + privileges_required_override_allowed = 0; + } + if(version >= INNO_VERSION(4, 0, 10)) { show_language_dialog = stored_enum(is).get(); language_detection = stored_enum(is).get(); @@ -453,7 +506,7 @@ (void)util::load(is); } - stored_flag_reader flagreader(is, version.bits); + stored_flag_reader flagreader(is, version.bits()); flagreader.add(DisableStartupPrompt); if(version < INNO_VERSION(5, 3, 10)) { @@ -463,7 +516,7 @@ if(version < INNO_VERSION(5, 3, 3)) { flagreader.add(DisableDirPage); } - if(version < INNO_VERSION(1, 3, 21)) { + if(version < INNO_VERSION(1, 3, 6)) { flagreader.add(DisableDirExistsWarning); } if(version < INNO_VERSION(5, 3, 3)) { @@ -473,7 +526,7 @@ if(version < INNO_VERSION(3, 0, 0) || version >= INNO_VERSION(3, 0, 3)) { flagreader.add(AlwaysRestart); } - if(version < INNO_VERSION(1, 3, 21)) { + if(version < INNO_VERSION(1, 3, 3)) { flagreader.add(BackSolid); } flagreader.add(AlwaysUsePersonalGroup); @@ -486,31 +539,45 @@ flagreader.add(DisableAppendDir); } flagreader.add(Password); - flagreader.add(AllowRootDirectory); - flagreader.add(DisableFinishedPage); - if(version.bits != 16) { + if(version >= INNO_VERSION(1, 2, 6)) { + flagreader.add(AllowRootDirectory); + } + if(version >= INNO_VERSION(1, 2, 14)) { + flagreader.add(DisableFinishedPage); + } + if(version.bits() != 16) { if(version < INNO_VERSION(3, 0, 4)) { flagreader.add(AdminPrivilegesRequired); } if(version < INNO_VERSION(3, 0, 0)) { flagreader.add(AlwaysCreateUninstallIcon); } - if(version < INNO_VERSION(1, 3, 21)) { + if(version < INNO_VERSION(1, 3, 6)) { flagreader.add(OverwriteUninstRegEntries); } - flagreader.add(ChangesAssociations); - } - if(version >= INNO_VERSION(1, 3, 21)) { - if(version < INNO_VERSION(5, 3, 8)) { - flagreader.add(CreateUninstallRegKey); + if(version < INNO_VERSION(5, 6, 1)) { + flagreader.add(ChangesAssociations); } + } + if(version >= INNO_VERSION(1, 3, 0) && version < INNO_VERSION(5, 3, 8)) { + flagreader.add(CreateUninstallRegKey); + } + if(version >= INNO_VERSION(1, 3, 1)) { flagreader.add(UsePreviousAppDir); + } + if(version >= INNO_VERSION(1, 3, 3)) { flagreader.add(BackColorHorizontal); + } + if(version >= INNO_VERSION(1, 3, 10)) { flagreader.add(UsePreviousGroup); + } + if(version >= INNO_VERSION(1, 3, 20)) { flagreader.add(UpdateUninstallLogAppName); } - if(version >= INNO_VERSION(2, 0, 0)) { + if(version >= INNO_VERSION(2, 0, 0) || (version.is_isx() && version >= INNO_VERSION(1, 3, 10))) { flagreader.add(UsePreviousSetupType); + } + if(version >= INNO_VERSION(2, 0, 0)) { flagreader.add(DisableReadyMemo); flagreader.add(AlwaysShowComponentsList); flagreader.add(FlatComponentsList); @@ -538,7 +605,7 @@ if(version >= INNO_VERSION(3, 0, 3)) { flagreader.add(RestartIfNeededByRun); } - if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) { + if(version >= INNO_VERSION(4, 0, 0) || (version.is_isx() && version >= INNO_VERSION(3, 0, 3))) { flagreader.add(ShowTasksTreeLines); } if(version >= INNO_VERSION(4, 0, 0) && version < INNO_VERSION(4, 0, 10)) { @@ -562,10 +629,10 @@ if(version >= INNO_VERSION(4, 2, 2)) { flagreader.add(EncryptionUsed); } - if(version >= INNO_VERSION(5, 0, 4)) { + if(version >= INNO_VERSION(5, 0, 4) && version < INNO_VERSION(5, 6, 1)) { flagreader.add(ChangesEnvironment); } - if(version >= INNO_VERSION(5, 1, 7) && !version.unicode) { + if(version >= INNO_VERSION(5, 1, 7) && !version.is_unicode()) { flagreader.add(ShowUndisplayableLanguages); } if(version >= INNO_VERSION(5, 1, 13)) { @@ -590,6 +657,11 @@ if(version >= INNO_VERSION(5, 5, 7)) { flagreader.add(ForceCloseApplications); } + if(version >= INNO_VERSION(6, 0, 0)) { + flagreader.add(AppNameHasConsts); + flagreader.add(UsePreviousPrivileges); + flagreader.add(WizardResizable); + } options |= flagreader; @@ -611,29 +683,61 @@ disable_program_group_page = (options & DisableProgramGroupPage) ? Yes : No; } - if(version < INNO_VERSION(1, 3, 21)) { + if(version < INNO_VERSION(1, 3, 0)) { if(license_size > 0) { - std::string temp; - temp.resize(size_t(license_size)); - is.read(&temp[0], license_size); - util::to_utf8(temp, license_text); + license_text.resize(size_t(license_size)); + is.read(&license_text[0], license_size); + util::to_utf8(license_text); } if(info_before_size > 0) { - std::string temp; - temp.resize(size_t(info_before_size)); - is.read(&temp[0], info_before_size); - util::to_utf8(temp, info_before); + info_before.resize(size_t(info_before_size)); + is.read(&info_before[0], info_before_size); + util::to_utf8(info_before); } if(info_after_size > 0) { - std::string temp; - temp.resize(size_t(info_after_size)); - is.read(&temp[0], info_after_size); - util::to_utf8(temp, info_after); + info_after.resize(size_t(info_after_size)); + is.read(&info_after[0], info_after_size); + util::to_utf8(info_after); } } } +void header::decode(util::codepage_id codepage) { + + util::to_utf8(app_name, codepage); + util::to_utf8(app_versioned_name, codepage); + util::to_utf8(app_id, codepage); + util::to_utf8(app_copyright, codepage); + util::to_utf8(app_publisher, codepage); + util::to_utf8(app_publisher_url, codepage); + util::to_utf8(app_support_phone, codepage); + util::to_utf8(app_support_url, codepage); + util::to_utf8(app_updates_url, codepage); + util::to_utf8(app_version, codepage); + util::to_utf8(default_dir_name, codepage); + util::to_utf8(default_group_name, codepage); + util::to_utf8(base_filename, codepage); + util::to_utf8(uninstall_files_dir, codepage); + util::to_utf8(uninstall_name, codepage); + util::to_utf8(uninstall_icon, codepage); + util::to_utf8(app_mutex, codepage); + util::to_utf8(default_user_name, codepage); + util::to_utf8(default_user_organisation, codepage); + util::to_utf8(default_serial, codepage); + util::to_utf8(app_readme_file, codepage); + util::to_utf8(app_contact, codepage); + util::to_utf8(app_comments, codepage); + util::to_utf8(app_modify_path, codepage); + util::to_utf8(create_uninstall_registry_key, codepage); + util::to_utf8(uninstallable, codepage); + util::to_utf8(close_applications_filter, codepage); + util::to_utf8(setup_mutex, codepage); + util::to_utf8(changes_environment, codepage); + util::to_utf8(changes_associations, codepage); + +} + } // namespace setup NAMES(setup::header::flags, "Setup Option", @@ -708,6 +812,11 @@ "ARM64", ) +NAMES(setup::header::privileges_required_overrides, "Priviledge Override" + "commandline", + "dialog", +) + NAMES(setup::header::alpha_format, "Alpha Format", "ignored", "defined", @@ -726,7 +835,7 @@ "overwrite", ) -NAMES(setup::header::style, "Uninstall Style", +NAMES(setup::header::style, "Style", "classic", "modern", ) diff -Nru innoextract-1.7/src/setup/header.hpp innoextract-1.8/src/setup/header.hpp --- innoextract-1.7/src/setup/header.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/header.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -36,6 +36,7 @@ #include "crypto/checksum.hpp" #include "setup/windows.hpp" #include "stream/chunk.hpp" +#include "util/encoding.hpp" #include "util/enum.hpp" #include "util/flags.hpp" @@ -99,6 +100,9 @@ RestartApplications, AllowNetworkDrive, ForceCloseApplications, + AppNameHasConsts, + UsePreviousPrivileges, + WizardResizable, // Obsolete flags Uninstallable, @@ -125,6 +129,11 @@ ARM64 ); + FLAGS(privileges_required_overrides, + Commandline, + Dialog + ); + std::string app_name; std::string app_versioned_name; std::string app_id; @@ -154,6 +163,8 @@ std::string uninstallable; std::string close_applications_filter; std::string setup_mutex; + std::string changes_environment; + std::string changes_associations; std::string license_text; std::string info_before; std::string info_after; @@ -187,6 +198,14 @@ Color image_back_color; Color small_image_back_color; + enum style { + ClassicStyle, + ModernStyle + }; + style wizard_style; + boost::uint32_t wizard_resize_percent_x; + boost::uint32_t wizard_resize_percent_y; + enum alpha_format { AlphaIgnored, AlphaDefined, @@ -214,10 +233,6 @@ }; log_mode uninstall_log_mode; - enum style { - ClassicStyle, - ModernStyle - }; style uninstall_style; enum auto_bool { @@ -236,6 +251,8 @@ }; privilege_level privileges_required; + privileges_required_overrides privileges_required_override_allowed; + auto_bool show_language_dialog; enum language_detection_method { @@ -262,12 +279,15 @@ void load(std::istream & is, const version & version); + void decode(util::codepage_id codepage); + }; } // namespace setup NAMED_FLAGS(setup::header::flags) NAMED_FLAGS(setup::header::architecture_types) +NAMED_FLAGS(setup::header::privileges_required_overrides) NAMED_ENUM(setup::header::alpha_format) NAMED_ENUM(setup::header::install_verbosity) NAMED_ENUM(setup::header::log_mode) diff -Nru innoextract-1.7/src/setup/icon.cpp innoextract-1.8/src/setup/icon.cpp --- innoextract-1.7/src/setup/icon.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/icon.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -20,6 +20,7 @@ #include "setup/icon.hpp" +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" @@ -36,61 +37,65 @@ } // anonymous namespace -void icon_entry::load(std::istream & is, const version & version) { +void icon_entry::load(std::istream & is, const info & i) { - if(version < INNO_VERSION(1, 3, 21)) { + if(i.version < INNO_VERSION(1, 3, 0)) { (void)util::load(is); // uncompressed size of the entry } - is >> util::encoded_string(name, version.codepage()); - is >> util::encoded_string(filename, version.codepage()); - is >> util::encoded_string(parameters, version.codepage()); - is >> util::encoded_string(working_dir, version.codepage()); - is >> util::encoded_string(icon_file, version.codepage()); - is >> util::encoded_string(comment, version.codepage()); + is >> util::encoded_string(name, i.codepage); + is >> util::encoded_string(filename, i.codepage); + is >> util::encoded_string(parameters, i.codepage); + is >> util::encoded_string(working_dir, i.codepage); + is >> util::encoded_string(icon_file, i.codepage); + is >> util::encoded_string(comment, i.codepage); - load_condition_data(is, version); + load_condition_data(is, i); - if(version >= INNO_VERSION(5, 3, 5)) { - is >> util::encoded_string(app_user_model_id, version.codepage()); + if(i.version >= INNO_VERSION(5, 3, 5)) { + is >> util::encoded_string(app_user_model_id, i.codepage); } else { app_user_model_id.clear(); } - load_version_data(is, version); + load_version_data(is, i.version); - icon_index = util::load(is, version.bits); + icon_index = util::load(is, i.version.bits()); - if(version >= INNO_VERSION(1, 3, 21)) { + if(i.version >= INNO_VERSION(1, 3, 24)) { show_command = util::load(is); + } else { + show_command = 1; + } + if(i.version >= INNO_VERSION(1, 3, 15)) { close_on_exit = stored_enum(is).get(); } else { - show_command = 1, close_on_exit = NoSetting; + close_on_exit = NoSetting; } - if(version >= INNO_VERSION(2, 0, 7)) { + if(i.version >= INNO_VERSION(2, 0, 7)) { hotkey = util::load(is); } else { hotkey = 0; } - stored_flag_reader flagreader(is, version.bits); + stored_flag_reader flagreader(is, i.version.bits()); flagreader.add(NeverUninstall); - if(version >= INNO_VERSION(1, 3, 21)) { + if(i.version < INNO_VERSION(1, 3, 26)) { flagreader.add(RunMinimized); } flagreader.add(CreateOnlyIfFileExists); - if(version.bits != 16) { + if(i.version.bits() != 16) { flagreader.add(UseAppPaths); } - if(version >= INNO_VERSION(5, 0, 3)) { + if(i.version >= INNO_VERSION(5, 0, 3)) { flagreader.add(FolderShortcut); } - if(version >= INNO_VERSION(5, 4, 2)) { + if(i.version >= INNO_VERSION(5, 4, 2)) { flagreader.add(ExcludeFromShowInNewInstall); } - if(version >= INNO_VERSION(5, 5, 0)) { + if(i.version >= INNO_VERSION(5, 5, 0)) { flagreader.add(PreventPinning); } diff -Nru innoextract-1.7/src/setup/icon.hpp innoextract-1.8/src/setup/icon.hpp --- innoextract-1.7/src/setup/icon.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/icon.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -37,7 +37,7 @@ namespace setup { -struct version; +struct info; struct icon_entry : public item { @@ -76,7 +76,7 @@ flags options; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/info.cpp innoextract-1.8/src/setup/info.cpp --- innoextract-1.7/src/setup/info.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/info.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -42,54 +42,32 @@ #include "setup/task.hpp" #include "setup/type.hpp" #include "stream/block.hpp" +#include "util/fstream.hpp" #include "util/load.hpp" #include "util/log.hpp" +#include "util/output.hpp" namespace setup { -namespace { - -struct no_arg { }; - -template -void load_entry(std::istream & is, const setup::version & version, - Entry & entity, Arg arg) { - entity.load(is, version, arg); -} template -void load_entry(std::istream & is, const setup::version & version, - Entry & entity, no_arg arg) { - (void)arg; - entity.load(is, version); -} - -template -void load_entries(std::istream & is, const setup::version & version, - info::entry_types entry_types, size_t count, - std::vector & entries, info::entry_types::enum_type entry_type, - Arg arg = Arg()) { - - entries.clear(); - if(entry_types & entry_type) { - entries.resize(count); +void info::load_entries(std::istream & is, entry_types entries, size_t count, + std::vector & result, entry_types::enum_type entry_type) { + + result.clear(); + if(entries & entry_type) { + result.resize(count); for(size_t i = 0; i < count; i++) { - Entry & entry = entries[i]; - load_entry(is, version, entry, arg); + result[i].load(is, *this); } } else { for(size_t i = 0; i < count; i++) { Entry entry; - load_entry(is, version, entry, arg); + entry.load(is, *this); } } } -template -void load_entries(std::istream & is, const setup::version & version, - info::entry_types entry_types, size_t count, - std::vector & entries, info::entry_types::enum_type entry_type) { - load_entries(is, version, entry_types, count, entries, entry_type); -} +namespace { void load_wizard_images(std::istream & is, const setup::version & version, std::vector & images, info::entry_types entries) { @@ -124,7 +102,7 @@ load_wizard_images(is, version, info.wizard_images, entries); - if(version >= INNO_VERSION(2, 0, 0)) { + if(version >= INNO_VERSION(2, 0, 0) || version.is_isx()) { load_wizard_images(is, version, info.wizard_images_small, entries); } @@ -162,9 +140,11 @@ } // anonymous namespace -void info::load(std::istream & is, entry_types entries, const setup::version & version) { +void info::try_load(std::istream & is, entry_types entries, util::codepage_id force_codepage) { + + debug("trying to load setup headers for version " << version); - if(entries & (Messages | NoSkip)) { + if((entries & (Messages | NoSkip)) || (!version.is_unicode() && !force_codepage)) { entries |= Languages; } @@ -172,27 +152,52 @@ header.load(*reader, version); - load_entries(*reader, version, entries, header.language_count, languages, Languages); + load_entries(*reader, entries, header.language_count, languages, Languages); + + if(version.is_unicode()) { + // Unicode installers are always UTF16-LE, do not allow users to override that. + codepage = util::cp_utf16le; + } else if(force_codepage) { + codepage = force_codepage; + } else if(languages.empty()) { + codepage = util::cp_windows1252; + } else { + // Non-Unicode installers do not have a defined codepage but instead just assume the + // codepage of the system the installer is run on. + // Look at the list of available languages to guess a suitable codepage. + codepage = languages[0].codepage; + BOOST_FOREACH(const language_entry & language, languages) { + if(language.codepage == util::cp_windows1252) { + codepage = util::cp_windows1252; + break; + } + } + } + + header.decode(codepage); + BOOST_FOREACH(language_entry & language, languages) { + language.decode(codepage); + } if(version < INNO_VERSION(4, 0, 0)) { load_wizard_and_decompressor(*reader, version, header, *this, entries); } - load_entries(*reader, version, entries, header.message_count, messages, Messages, languages); - load_entries(*reader, version, entries, header.permission_count, permissions, Permissions); - load_entries(*reader, version, entries, header.type_count, types, Types); - load_entries(*reader, version, entries, header.component_count, components, Components); - load_entries(*reader, version, entries, header.task_count, tasks, Tasks); - load_entries(*reader, version, entries, header.directory_count, directories, Directories); - load_entries(*reader, version, entries, header.file_count, files, Files); - load_entries(*reader, version, entries, header.icon_count, icons, Icons); - load_entries(*reader, version, entries, header.ini_entry_count, ini_entries, IniEntries); - load_entries(*reader, version, entries, header.registry_entry_count, registry_entries, RegistryEntries); - load_entries(*reader, version, entries, header.delete_entry_count, delete_entries, DeleteEntries); - load_entries(*reader, version, entries, header.uninstall_delete_entry_count, uninstall_delete_entries, + load_entries(*reader, entries, header.message_count, messages, Messages); + load_entries(*reader, entries, header.permission_count, permissions, Permissions); + load_entries(*reader, entries, header.type_count, types, Types); + load_entries(*reader, entries, header.component_count, components, Components); + load_entries(*reader, entries, header.task_count, tasks, Tasks); + load_entries(*reader, entries, header.directory_count, directories, Directories); + load_entries(*reader, entries, header.file_count, files, Files); + load_entries(*reader, entries, header.icon_count, icons, Icons); + load_entries(*reader, entries, header.ini_entry_count, ini_entries, IniEntries); + load_entries(*reader, entries, header.registry_entry_count, registry_entries, RegistryEntries); + load_entries(*reader, entries, header.delete_entry_count, delete_entries, DeleteEntries); + load_entries(*reader, entries, header.uninstall_delete_entry_count, uninstall_delete_entries, UninstallDeleteEntries); - load_entries(*reader, version, entries, header.run_entry_count, run_entries, RunEntries); - load_entries(*reader, version, entries, header.uninstall_run_entry_count, uninstall_run_entries, + load_entries(*reader, entries, header.run_entry_count, run_entries, RunEntries); + load_entries(*reader, entries, header.uninstall_run_entry_count, uninstall_run_entries, UninstallRunEntries); if(version >= INNO_VERSION(4, 0, 0)) { @@ -203,12 +208,12 @@ check_is_end(reader, "unknown data at end of primary header stream"); reader = stream::block_reader::get(is, version); - load_entries(*reader, version, entries, header.data_entry_count, data_entries, DataEntries); + load_entries(*reader, entries, header.data_entry_count, data_entries, DataEntries); check_is_end(reader, "unknown data at end of secondary header stream"); } -void info::load(std::istream & is, entry_types entries) { +void info::load(std::istream & is, entry_types entries, util::codepage_id force_codepage) { version.load(is); @@ -225,37 +230,71 @@ version_constant listed_version = version.value; // Some setup versions didn't increment the data version number when they should have. - // To work around this, we try to parse the headers for both data versions. - bool ambiguous = version.is_ambiguous(); - if(ambiguous) { + // To work around this, we try to parse the headers for all data versions and use the first + // version that parses without warnings or errors. + bool ambiguous = !version.known || version.is_ambiguous(); + if(version.is_ambiguous()) { // Force parsing all headers so that we don't miss any errors. entries |= NoSkip; } - if(!version.known || ambiguous) { - std::streampos start = is.tellg(); + + bool parsed_without_errors = false; + std::streampos start = is.tellg(); + for(;;) { + + warning_suppressor warnings; + try { - load(is, entries, version); + + // Try to parse headers for this version + try_load(is, entries, force_codepage); + + if(warnings) { + // Parsed without errors but with warnings - try other versions first + if(!parsed_without_errors) { + listed_version = version.value; + parsed_without_errors = true; + } + throw std::exception(); + } + + warnings.flush(); return; + } catch(...) { - version.value = version.next(); - if(!version) { - version.value = listed_version; - throw; - } + is.clear(); is.seekg(start); + + version_constant next_version = version.next(); + + if(!ambiguous || !next_version) { + if(version.value != listed_version) { + // Rewind to a previous version that had better results and report those + version.value = listed_version; + warnings.restore(); + try_load(is, entries, force_codepage); + } else { + // Otherwise. report results for the current version + warnings.flush(); + if(!parsed_without_errors) { + throw; + } + } + return; + } + + // Retry with the next version + version.value = next_version; + ambiguous = version.is_ambiguous(); + } + } - try { - load(is, entries, version); - } catch(...) { - version.value = listed_version; - throw; - } } -info::info() { } +info::info() : codepage(0) { } info::~info() { } } // namespace setup diff -Nru innoextract-1.7/src/setup/info.hpp innoextract-1.8/src/setup/info.hpp --- innoextract-1.7/src/setup/info.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/info.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -31,6 +31,7 @@ #include "setup/header.hpp" #include "setup/version.hpp" +#include "util/encoding.hpp" #include "util/flags.hpp" namespace setup { @@ -85,6 +86,8 @@ setup::version version; + util::codepage_id codepage; + setup::header header; std::vector components; //! \c Components @@ -125,8 +128,11 @@ * identifier whose position is given by * \ref loader::offsets::header_offset. * \param entries What kinds of entries to load. + * \param force_codepage Windows codepage to use for strings in ANSI installers. */ - void load(std::istream & is, entry_types entries); + void load(std::istream & is, entry_types entries, util::codepage_id force_codepage = 0); + +private: /*! * Load setup headers for a specific version. @@ -137,11 +143,15 @@ * identifier whose position is given by * \ref loader::offsets::header_offset. * \param entries What kinds of entries to load. - * \param version The setup data version of the headers. + * \param force_codepage Windows codepage to use for strings in ANSI installers. * * This function does not set the \ref version member. */ - void load(std::istream & is, entry_types entries, const setup::version & version); + void try_load(std::istream & is, entry_types entries, util::codepage_id force_codepage); + + template + void load_entries(std::istream & is, entry_types entries, size_t count, + std::vector & result, entry_types::enum_type entry_type); }; diff -Nru innoextract-1.7/src/setup/ini.cpp innoextract-1.8/src/setup/ini.cpp --- innoextract-1.7/src/setup/ini.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/ini.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -22,6 +22,7 @@ #include +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" @@ -40,25 +41,25 @@ } // anonymous namespace -void ini_entry::load(std::istream & is, const version & version) { +void ini_entry::load(std::istream & is, const info & i) { - if(version < INNO_VERSION(1, 3, 21)) { + if(i.version < INNO_VERSION(1, 3, 0)) { (void)util::load(is); // uncompressed size of the entry } - is >> util::encoded_string(inifile, version.codepage()); + is >> util::encoded_string(inifile, i.codepage); if(inifile.empty()) { inifile = "{windows}/WIN.INI"; } - is >> util::encoded_string(section, version.codepage()); - is >> util::encoded_string(key, version.codepage()); - is >> util::encoded_string(value, version.codepage()); + is >> util::encoded_string(section, i.codepage); + is >> util::encoded_string(key, i.codepage); + is >> util::encoded_string(value, i.codepage); - load_condition_data(is, version); + load_condition_data(is, i); - load_version_data(is, version); + load_version_data(is, i.version); - if(version.bits != 16) { + if(i.version.bits() != 16) { options = stored_flags(is).get(); } else { options = stored_flags(is).get(); diff -Nru innoextract-1.7/src/setup/ini.hpp innoextract-1.8/src/setup/ini.hpp --- innoextract-1.7/src/setup/ini.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/ini.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -35,7 +35,7 @@ namespace setup { -struct version; +struct info; struct ini_entry : public item { @@ -54,7 +54,7 @@ flags options; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/item.cpp innoextract-1.8/src/setup/item.cpp --- innoextract-1.7/src/setup/item.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/item.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -20,33 +20,38 @@ #include "setup/item.hpp" +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" namespace setup { -void item::load_condition_data(std::istream & is, const version & version) { +void item::load_condition_data(std::istream & is, const info & i) { - if(version >= INNO_VERSION(2, 0, 0)) { - is >> util::encoded_string(components, version.codepage()); - is >> util::encoded_string(tasks, version.codepage()); + if(i.version >= INNO_VERSION(2, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(1, 3, 8))) { + is >> util::encoded_string(components, i.codepage); } else { - components.clear(), tasks.clear(); + components.clear(); } - if(version >= INNO_VERSION(4, 0, 1)) { - is >> util::encoded_string(languages, version.codepage()); + if(i.version >= INNO_VERSION(2, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(1, 3, 17))) { + is >> util::encoded_string(tasks, i.codepage); + } else { + tasks.clear(); + } + if(i.version >= INNO_VERSION(4, 0, 1)) { + is >> util::encoded_string(languages, i.codepage); } else { languages.clear(); } - if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) { - is >> util::encoded_string(check, version.codepage()); + if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(1, 3, 24))) { + is >> util::encoded_string(check, i.codepage); } else { check.clear(); } - if(version >= INNO_VERSION(4, 1, 0)) { - is >> util::encoded_string(after_install, version.codepage()); - is >> util::encoded_string(before_install, version.codepage()); + if(i.version >= INNO_VERSION(4, 1, 0)) { + is >> util::encoded_string(after_install, i.codepage); + is >> util::encoded_string(before_install, i.codepage); } else { after_install.clear(), before_install.clear(); } diff -Nru innoextract-1.7/src/setup/item.hpp innoextract-1.8/src/setup/item.hpp --- innoextract-1.7/src/setup/item.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/item.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -33,6 +33,7 @@ namespace setup { +struct info; struct version; struct item { @@ -49,7 +50,7 @@ protected: - void load_condition_data(std::istream & is, const version & version); + void load_condition_data(std::istream & is, const info & i); void load_version_data(std::istream & is, const version & version) { winver.load(is, version); diff -Nru innoextract-1.7/src/setup/language.cpp innoextract-1.8/src/setup/language.cpp --- innoextract-1.7/src/setup/language.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/language.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -20,52 +20,160 @@ #include "setup/language.hpp" +#include + +#include "boost/range/begin.hpp" +#include "boost/range/end.hpp" + +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" namespace setup { -void language_entry::load(std::istream & is, const version & version) { +namespace { + +struct windows_language { - if(version >= INNO_VERSION(4, 0, 0)) { - is >> util::encoded_string(name, version.codepage()); - } else { - name = "default"; + boost::uint16_t language_id; + boost::uint16_t codepage; + + bool operator<(boost::uint32_t language) const { + return language_id < language; } - is >> util::encoded_string(language_name, (version >= INNO_VERSION(4, 2, 2)) ? 1200u : 1252u); +}; + +/* + * Sorted list of Windows language IDs with their default ANSI codepages. + * This list omits Unicode-only languages and languages using the default Windows-1252 codepage. + */ +const windows_language languages[] = { + { 0x0401, util::cp_windows1256 }, + { 0x0402, util::cp_windows1251 }, + { 0x0404, util::cp_big5 }, + { 0x0405, util::cp_windows1250 }, + { 0x0408, util::cp_windows1253 }, + { 0x040d, util::cp_windows1255 }, + { 0x040e, util::cp_windows1250 }, + { 0x0411, util::cp_shift_jis }, + { 0x0412, util::cp_uhc }, + { 0x0415, util::cp_windows1250 }, + { 0x0418, util::cp_windows1250 }, + { 0x0419, util::cp_windows1251 }, + { 0x041a, util::cp_windows1250 }, + { 0x041b, util::cp_windows1250 }, + { 0x041c, util::cp_windows1250 }, + { 0x041e, util::cp_windows874 }, + { 0x041f, util::cp_windows1254 }, + { 0x0420, util::cp_windows1256 }, + { 0x0422, util::cp_windows1251 }, + { 0x0423, util::cp_windows1251 }, + { 0x0424, util::cp_windows1250 }, + { 0x0425, util::cp_windows1257 }, + { 0x0426, util::cp_windows1257 }, + { 0x0427, util::cp_windows1257 }, + { 0x0429, util::cp_windows1256 }, + { 0x042a, util::cp_windows1258 }, + { 0x042c, util::cp_windows1254 }, + { 0x042f, util::cp_windows1251 }, + { 0x043f, util::cp_windows1251 }, + { 0x0440, util::cp_windows1251 }, + { 0x0443, util::cp_windows1254 }, + { 0x0444, util::cp_windows1251 }, + { 0x0450, util::cp_windows1251 }, + { 0x0492, util::cp_iso_8859_14 }, + { 0x0801, util::cp_windows1256 }, + { 0x0804, util::cp_gbk }, + { 0x081a, util::cp_windows1250 }, + { 0x082c, util::cp_windows1251 }, + { 0x0843, util::cp_windows1251 }, + { 0x0c01, util::cp_windows1256 }, + { 0x0c04, util::cp_big5 }, + { 0x0c1a, util::cp_windows1251 }, + { 0x1001, util::cp_windows1256 }, + { 0x1004, util::cp_gbk }, + { 0x1401, util::cp_windows1256 }, + { 0x1404, util::cp_big5 }, + { 0x1801, util::cp_windows1256 }, + { 0x1c01, util::cp_windows1256 }, + { 0x2001, util::cp_windows1256 }, + { 0x2401, util::cp_windows1256 }, + { 0x2801, util::cp_windows1256 }, + { 0x2c01, util::cp_windows1256 }, + { 0x3001, util::cp_windows1256 }, + { 0x3401, util::cp_windows1256 }, + { 0x3801, util::cp_windows1256 }, + { 0x3c01, util::cp_windows1256 }, + { 0x4001, util::cp_windows1256 }, +}; + +util::codepage_id default_codepage_for_language(boost::uint32_t language) { + + const windows_language * entry = std::lower_bound(boost::begin(languages), boost::end(languages), language); + if(entry != boost::end(languages) && entry->language_id == language) { + return entry->codepage; + } - is >> util::encoded_string(dialog_font, version.codepage()); - is >> util::encoded_string(title_font, version.codepage()); - is >> util::encoded_string(welcome_font, version.codepage()); - is >> util::encoded_string(copyright_font, version.codepage()); + return util::cp_windows1252; +} + +} // anonymous namespace + +void language_entry::load(std::istream & is, const info & i) { - if(version >= INNO_VERSION(4, 0, 0)) { + if(i.version >= INNO_VERSION(4, 0, 0)) { + is >> util::binary_string(name); + } + + is >> util::binary_string(language_name); + + if(i.version == INNO_VERSION_EXT(5, 5, 7, 1)) { + util::binary_string::skip(is); + } + + is >> util::binary_string(dialog_font); + is >> util::binary_string(title_font); + is >> util::binary_string(welcome_font); + is >> util::binary_string(copyright_font); + + if(i.version >= INNO_VERSION(4, 0, 0)) { is >> util::binary_string(data); } - if(version >= INNO_VERSION(4, 0, 1)) { - is >> util::ansi_string(license_text); - is >> util::ansi_string(info_before); - is >> util::ansi_string(info_after); + if(i.version >= INNO_VERSION(4, 0, 1)) { + is >> util::binary_string(license_text); + is >> util::binary_string(info_before); + is >> util::binary_string(info_after); } else { license_text.clear(), info_before.clear(), info_after.clear(); } language_id = util::load(is); - if(version >= INNO_VERSION(4, 2, 2) && (version < INNO_VERSION(5, 3, 0) || !version.unicode)) { + if(i.version < INNO_VERSION(4, 2, 2)) { + codepage = default_codepage_for_language(language_id); + } else if(!i.version.is_unicode()) { codepage = util::load(is); + if(!codepage) { + codepage = util::cp_windows1252; + } } else { - codepage = 0; + if(i.version < INNO_VERSION(5, 3, 0)) { + (void)util::load(is); + } + codepage = util::cp_utf16le; } - if(!codepage) { - codepage = version.codepage(); + + if(i.version >= INNO_VERSION(4, 2, 2)) { + util::to_utf8(language_name, util::cp_utf16le); + } else { + util::to_utf8(language_name, codepage); } dialog_font_size = util::load(is); - if(version < INNO_VERSION(4, 1, 0)) { + if(i.version < INNO_VERSION(4, 1, 0)) { dialog_font_standard_height = util::load(is); } else { dialog_font_standard_height = 0; @@ -75,12 +183,25 @@ welcome_font_size = util::load(is); copyright_font_size = util::load(is); - if(version >= INNO_VERSION(5, 2, 3)) { + if(i.version == INNO_VERSION_EXT(5, 5, 7, 1)) { + util::load(is); // always 8 or 9? + } + + if(i.version >= INNO_VERSION(5, 2, 3)) { right_to_left = util::load_bool(is); } else { right_to_left = false; } } + +void language_entry::decode(util::codepage_id cp) { + + util::to_utf8(name, cp); + if(name.empty()) { + name = "default"; + } + +} } // namespace setup diff -Nru innoextract-1.7/src/setup/language.hpp innoextract-1.8/src/setup/language.hpp --- innoextract-1.7/src/setup/language.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/language.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -31,9 +31,11 @@ #include +#include "util/encoding.hpp" + namespace setup { -struct version; +struct info; struct language_entry { @@ -60,7 +62,9 @@ bool right_to_left; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); + + void decode(util::codepage_id cp); }; diff -Nru innoextract-1.7/src/setup/message.cpp innoextract-1.8/src/setup/message.cpp --- innoextract-1.7/src/setup/message.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/message.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -22,32 +22,36 @@ #include +#include "setup/info.hpp" #include "setup/language.hpp" #include "setup/version.hpp" #include "util/encoding.hpp" #include "util/load.hpp" +#include "util/log.hpp" namespace setup { -void message_entry::load(std::istream & is, const version & version, - const std::vector & languages) { +void message_entry::load(std::istream & is, const info & i) { - is >> util::encoded_string(name, version.codepage()); - std::string raw_value = util::binary_string::load(is); + is >> util::encoded_string(name, i.codepage); + is >> util::binary_string(value); language = util::load(is); boost::uint32_t codepage; if(language < 0) { - codepage = version.codepage(); - } else if(size_t(language) >= languages.size()) { + codepage = i.codepage; + } else if(size_t(language) >= i.languages.size()) { + if(!i.languages.empty()) { + log_warning << "Language index out of bounds: " << language; + } value.clear(); return; } else { - codepage = languages[size_t(language)].codepage; + codepage = i.languages[size_t(language)].codepage; } - util::to_utf8(raw_value, value, codepage); + util::to_utf8(value, codepage); } } // namespace setup diff -Nru innoextract-1.7/src/setup/message.hpp innoextract-1.8/src/setup/message.hpp --- innoextract-1.7/src/setup/message.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/message.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -28,12 +28,10 @@ #include #include -#include namespace setup { -struct version; -struct language_entry; +struct info; struct message_entry { @@ -48,8 +46,7 @@ // Index into the default language entry list or -1. int language; - void load(std::istream & is, const version & version, - const std::vector & languages); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/permission.cpp innoextract-1.8/src/setup/permission.cpp --- innoextract-1.7/src/setup/permission.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/permission.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -20,14 +20,11 @@ #include "setup/permission.hpp" -#include "setup/version.hpp" #include "util/load.hpp" namespace setup { -void permission_entry::load(std::istream & is, const version & version) { - - (void)version; +void permission_entry::load(std::istream & is, const info & /* i */) { is >> util::binary_string(permissions); // an array of TGrantPermissionEntry's diff -Nru innoextract-1.7/src/setup/permission.hpp innoextract-1.8/src/setup/permission.hpp --- innoextract-1.7/src/setup/permission.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/permission.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -31,7 +31,7 @@ namespace setup { -struct version; +struct info; struct permission_entry { @@ -39,7 +39,7 @@ std::string permissions; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/registry.cpp innoextract-1.8/src/setup/registry.cpp --- innoextract-1.7/src/setup/registry.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/registry.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -22,6 +22,7 @@ #include +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" @@ -58,67 +59,73 @@ } // anonymous namespace -void registry_entry::load(std::istream & is, const version & version) { +void registry_entry::load(std::istream & is, const info & i) { - if(version < INNO_VERSION(1, 3, 21)) { + if(i.version < INNO_VERSION(1, 3, 0)) { (void)util::load(is); // uncompressed size of the entry } - is >> util::encoded_string(key, version.codepage()); - if(version.bits != 16) { - is >> util::encoded_string(name, version.codepage()); + is >> util::encoded_string(key, i.codepage); + if(i.version.bits() != 16) { + is >> util::encoded_string(name, i.codepage); } else { name.clear(); } - is >> util::encoded_string(value, version.codepage()); + is >> util::binary_string(value); - load_condition_data(is, version); + load_condition_data(is, i); - if(version >= INNO_VERSION(4, 0, 11) && version < INNO_VERSION(4, 1, 0)) { - is >> util::encoded_string(permissions, version.codepage()); + if(i.version >= INNO_VERSION(4, 0, 11) && i.version < INNO_VERSION(4, 1, 0)) { + is >> util::binary_string(permissions); } else { permissions.clear(); } - load_version_data(is, version); + load_version_data(is, i.version); - if(version.bits != 16) { + if(i.version.bits() != 16) { hive = hive_name(util::load(is) & ~0x80000000); } else { hive = Unset; } - if(version >= INNO_VERSION(4, 1, 0)) { + if(i.version >= INNO_VERSION(4, 1, 0)) { permission = util::load(is); } else { permission = -1; } - if(version >= INNO_VERSION(5, 2, 5)) { + if(i.version >= INNO_VERSION(5, 2, 5)) { type = stored_enum(is).get(); - } else if(version.bits != 16) { + } else if(i.version.bits() != 16) { type = stored_enum(is).get(); } else { type = stored_enum(is).get(); } - stored_flag_reader flagreader(is, version.bits); + stored_flag_reader flagreader(is, i.version.bits()); - if(version.bits != 16) { + if(i.version.bits() != 16) { flagreader.add(CreateValueIfDoesntExist); flagreader.add(UninsDeleteValue); } flagreader.add(UninsClearValue); flagreader.add(UninsDeleteEntireKey); flagreader.add(UninsDeleteEntireKeyIfEmpty); - flagreader.add(PreserveStringType); - if(version >= INNO_VERSION(1, 3, 21)) { + if(i.version >= INNO_VERSION(1, 2, 6)) { + flagreader.add(PreserveStringType); + } + if(i.version >= INNO_VERSION(1, 3, 9)) { flagreader.add(DeleteKey); flagreader.add(DeleteValue); + } + if(i.version >= INNO_VERSION(1, 3, 12)) { flagreader.add(NoError); + } + if(i.version >= INNO_VERSION(1, 3, 16)) { flagreader.add(DontCreateKey); } - if(version >= INNO_VERSION(5, 1, 0)) { + if(i.version >= INNO_VERSION(5, 1, 0)) { flagreader.add(Bits32); flagreader.add(Bits64); } diff -Nru innoextract-1.7/src/setup/registry.hpp innoextract-1.8/src/setup/registry.hpp --- innoextract-1.7/src/setup/registry.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/registry.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -36,7 +36,7 @@ namespace setup { -struct version; +struct info; struct registry_entry : public item { @@ -90,7 +90,7 @@ flags options; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/run.cpp innoextract-1.8/src/setup/run.cpp --- innoextract-1.7/src/setup/run.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/run.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -22,6 +22,7 @@ #include +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" @@ -38,39 +39,39 @@ } // anonymous namespace -void run_entry::load(std::istream & is, const version & version) { +void run_entry::load(std::istream & is, const info & i) { - if(version < INNO_VERSION(1, 3, 21)) { + if(i.version < INNO_VERSION(1, 3, 0)) { (void)util::load(is); // uncompressed size of the entry } - is >> util::encoded_string(name, version.codepage()); - is >> util::encoded_string(parameters, version.codepage()); - is >> util::encoded_string(working_dir, version.codepage()); - if(version >= INNO_VERSION(1, 3, 21)) { - is >> util::encoded_string(run_once_id, version.codepage()); + is >> util::encoded_string(name, i.codepage); + is >> util::encoded_string(parameters, i.codepage); + is >> util::encoded_string(working_dir, i.codepage); + if(i.version >= INNO_VERSION(1, 3, 9)) { + is >> util::encoded_string(run_once_id, i.codepage); } else { run_once_id.clear(); } - if(version >= INNO_VERSION(2, 0, 2)) { - is >> util::encoded_string(status_message, version.codepage()); + if(i.version >= INNO_VERSION(2, 0, 2)) { + is >> util::encoded_string(status_message, i.codepage); } else { status_message.clear(); } - if(version >= INNO_VERSION(5, 1, 13)) { - is >> util::encoded_string(verb, version.codepage()); + if(i.version >= INNO_VERSION(5, 1, 13)) { + is >> util::encoded_string(verb, i.codepage); } else { verb.clear(); } - if(version >= INNO_VERSION(2, 0, 0)) { - is >> util::encoded_string(description, version.codepage()); + if(i.version >= INNO_VERSION(2, 0, 0) || i.version.is_isx()) { + is >> util::encoded_string(description, i.codepage); } - load_condition_data(is, version); + load_condition_data(is, i); - load_version_data(is, version); + load_version_data(is, i.version); - if(version >= INNO_VERSION(1, 3, 21)) { + if(i.version >= INNO_VERSION(1, 3, 24)) { show_command = util::load(is); } else { show_command = 0; @@ -78,26 +79,28 @@ wait = stored_enum(is).get(); - stored_flag_reader flagreader(is, version.bits); + stored_flag_reader flagreader(is, i.version.bits()); - flagreader.add(ShellExec); - if(version >= INNO_VERSION(1, 3, 21)) { + if(i.version >= INNO_VERSION(1, 2, 3)) { + flagreader.add(ShellExec); + } + if(i.version >= INNO_VERSION(1, 3, 9) || (i.version.is_isx() && i.version >= INNO_VERSION(1, 3, 8))) { flagreader.add(SkipIfDoesntExist); } - if(version >= INNO_VERSION(2, 0, 0)) { + if(i.version >= INNO_VERSION(2, 0, 0)) { flagreader.add(PostInstall); flagreader.add(Unchecked); flagreader.add(SkipIfSilent); - flagreader.add(Skipif_not_equalSilent); + flagreader.add(SkipIfNotSilent); } - if(version >= INNO_VERSION(2, 0, 8)) { + if(i.version >= INNO_VERSION(2, 0, 8)) { flagreader.add(HideWizard); } - if(version >= INNO_VERSION(5, 1, 10)) { + if(i.version >= INNO_VERSION(5, 1, 10)) { flagreader.add(Bits32); flagreader.add(Bits64); } - if(version >= INNO_VERSION(5, 2, 0)) { + if(i.version >= INNO_VERSION(5, 2, 0)) { flagreader.add(RunAsOriginalUser); } diff -Nru innoextract-1.7/src/setup/run.hpp innoextract-1.8/src/setup/run.hpp --- innoextract-1.7/src/setup/run.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/run.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -35,7 +35,7 @@ namespace setup { -struct version; +struct info; struct run_entry : public item { @@ -45,7 +45,7 @@ PostInstall, Unchecked, SkipIfSilent, - Skipif_not_equalSilent, + SkipIfNotSilent, HideWizard, Bits32, Bits64, @@ -72,7 +72,7 @@ flags options; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/task.cpp innoextract-1.8/src/setup/task.cpp --- innoextract-1.7/src/setup/task.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/task.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -22,44 +22,53 @@ #include +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" namespace setup { -void task_entry::load(std::istream & is, const version & version) { +void task_entry::load(std::istream & is, const info & i) { - is >> util::encoded_string(name, version.codepage()); - is >> util::encoded_string(description, version.codepage()); - is >> util::encoded_string(group_description, version.codepage()); - is >> util::encoded_string(components, version.codepage()); - if(version >= INNO_VERSION(4, 0, 1)) { - is >> util::encoded_string(languages, version.codepage()); + is >> util::encoded_string(name, i.codepage); + is >> util::encoded_string(description, i.codepage); + is >> util::encoded_string(group_description, i.codepage); + is >> util::encoded_string(components, i.codepage); + if(i.version >= INNO_VERSION(4, 0, 1)) { + is >> util::encoded_string(languages, i.codepage); } else { languages.clear(); } - if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) { - is >> util::encoded_string(check, version.codepage()); + if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(1, 3, 24))) { + is >> util::encoded_string(check, i.codepage); + } else { + check.clear(); + } + if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(3, 0, 3))) { level = util::load(is); + } else { + level = 0; + } + if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(3, 0, 4))) { used = util::load_bool(is); } else { - check.clear(), level = 0, used = true; + used = true; } - winver.load(is, version); + winver.load(is, i.version); stored_flag_reader flagreader(is); flagreader.add(Exclusive); flagreader.add(Unchecked); - if(version >= INNO_VERSION(2, 0, 5)) { + if(i.version >= INNO_VERSION(2, 0, 5)) { flagreader.add(Restart); } - if(version >= INNO_VERSION(2, 0, 6)) { + if(i.version >= INNO_VERSION(2, 0, 6)) { flagreader.add(CheckedOnce); } - if(version >= INNO_VERSION(4, 2, 3)) { + if(i.version >= INNO_VERSION(4, 2, 3)) { flagreader.add(DontInheritCheck); } diff -Nru innoextract-1.7/src/setup/task.hpp innoextract-1.8/src/setup/task.hpp --- innoextract-1.7/src/setup/task.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/task.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -35,7 +35,7 @@ namespace setup { -struct version; +struct info; struct task_entry { @@ -63,7 +63,7 @@ flags options; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/type.cpp innoextract-1.8/src/setup/type.cpp --- innoextract-1.7/src/setup/type.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/type.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2013 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -20,6 +20,7 @@ #include "setup/type.hpp" +#include "setup/info.hpp" #include "setup/version.hpp" #include "util/load.hpp" #include "util/storedenum.hpp" @@ -51,35 +52,35 @@ namespace setup { -void type_entry::load(std::istream & is, const version & version) { +void type_entry::load(std::istream & is, const info & i) { USE_FLAG_NAMES(setup::type_flags) - is >> util::encoded_string(name, version.codepage()); - is >> util::encoded_string(description, version.codepage()); - if(version >= INNO_VERSION(4, 0, 1)) { - is >> util::encoded_string(languages, version.codepage()); + is >> util::encoded_string(name, i.codepage); + is >> util::encoded_string(description, i.codepage); + if(i.version >= INNO_VERSION(4, 0, 1)) { + is >> util::encoded_string(languages, i.codepage); } else { languages.clear(); } - if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) { - is >> util::encoded_string(check, version.codepage()); + if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(1, 3, 24))) { + is >> util::encoded_string(check, i.codepage); } else { check.clear(); } - winver.load(is, version); + winver.load(is, i.version); type_flags options = stored_flags(is).get(); custom_type = ((options & CustomSetupType) != 0); - if(version >= INNO_VERSION(4, 0, 3)) { + if(i.version >= INNO_VERSION(4, 0, 3)) { type = stored_enum(is).get(); } else { type = User; } - if(version >= INNO_VERSION(4, 0, 0)) { + if(i.version >= INNO_VERSION(4, 0, 0)) { size = util::load(is); } else { size = util::load(is); diff -Nru innoextract-1.7/src/setup/type.hpp innoextract-1.8/src/setup/type.hpp --- innoextract-1.7/src/setup/type.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/type.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -37,7 +37,7 @@ namespace setup { -struct version; +struct info; struct type_entry { @@ -63,7 +63,7 @@ boost::uint64_t size; - void load(std::istream & is, const version & version); + void load(std::istream & is, const info & i); }; diff -Nru innoextract-1.7/src/setup/version.cpp innoextract-1.8/src/setup/version.cpp --- innoextract-1.7/src/setup/version.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/version.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -28,6 +28,7 @@ #include #include #include +#include "boost/algorithm/string.hpp" #include #include #include @@ -46,16 +47,15 @@ char name[13]; // terminating 0 byte is ignored version_constant version; - - unsigned char bits; + version::flags variant; operator version_constant() const { return version; } }; const known_legacy_version legacy_versions[] = { - { "i1.2.10--16\x1a", INNO_VERSION(1, 2, 10), 16 }, - { "i1.2.10--32\x1a", INNO_VERSION(1, 2, 10), 32 }, + { "i1.2.10--16\x1a", INNO_VERSION(1, 2, 10), version::Bits16 }, + { "i1.2.10--32\x1a", INNO_VERSION(1, 2, 10), 0 }, }; typedef char stored_version[64]; @@ -65,94 +65,119 @@ stored_version name; version_constant version; - bool unicode; + version::flags variant; operator version_constant() const { return version; } }; const known_version versions[] = { - { "Inno Setup Setup Data (1.3.21)", INNO_VERSION_EXT(1, 3, 21, 0), false }, - { "Inno Setup Setup Data (1.3.25)", INNO_VERSION_EXT(1, 3, 25, 0), false }, - { "Inno Setup Setup Data (2.0.0)", INNO_VERSION_EXT(2, 0, 0, 0), false }, - { "Inno Setup Setup Data (2.0.1)", INNO_VERSION_EXT(2, 0, 1, 0), false }, - { "Inno Setup Setup Data (2.0.2)", INNO_VERSION_EXT(2, 0, 2, 0), false }, // ! - { "Inno Setup Setup Data (2.0.5)", INNO_VERSION_EXT(2, 0, 5, 0), false }, - { "Inno Setup Setup Data (2.0.6a)", INNO_VERSION_EXT(2, 0, 6, 0), false }, - { "Inno Setup Setup Data (2.0.7)", INNO_VERSION_EXT(2, 0, 7, 0), false }, - { "Inno Setup Setup Data (2.0.8)", INNO_VERSION_EXT(2, 0, 8, 0), false }, - { "Inno Setup Setup Data (2.0.11)", INNO_VERSION_EXT(2, 0, 11, 0), false }, - { "Inno Setup Setup Data (2.0.17)", INNO_VERSION_EXT(2, 0, 17, 0), false }, - { "Inno Setup Setup Data (2.0.18)", INNO_VERSION_EXT(2, 0, 18, 0), false }, - { "Inno Setup Setup Data (3.0.0a)", INNO_VERSION_EXT(3, 0, 0, 0), false }, - { "Inno Setup Setup Data (3.0.1)", INNO_VERSION_EXT(3, 0, 1, 0), false }, - { "Inno Setup Setup Data (3.0.3)", INNO_VERSION_EXT(3, 0, 3, 0), false }, - { "Inno Setup Setup Data (3.0.4)", INNO_VERSION_EXT(3, 0, 4, 0), false }, // ! - { "Inno Setup Setup Data (3.0.5)", INNO_VERSION_EXT(3, 0, 5, 0), false }, - { "My Inno Setup Extensions Setup Data (3.0.6.1)", - INNO_VERSION_EXT(3, 0, 6, 1), false }, - { "Inno Setup Setup Data (4.0.0a)", INNO_VERSION_EXT(4, 0, 0, 0), false }, - { "Inno Setup Setup Data (4.0.1)", INNO_VERSION_EXT(4, 0, 1, 0), false }, - { "Inno Setup Setup Data (4.0.3)", INNO_VERSION_EXT(4, 0, 3, 0), false }, - { "Inno Setup Setup Data (4.0.5)", INNO_VERSION_EXT(4, 0, 5, 0), false }, - { "Inno Setup Setup Data (4.0.9)", INNO_VERSION_EXT(4, 0, 9, 0), false }, - { "Inno Setup Setup Data (4.0.10)", INNO_VERSION_EXT(4, 0, 10, 0), false }, - { "Inno Setup Setup Data (4.0.11)", INNO_VERSION_EXT(4, 0, 11, 0), false }, - { "Inno Setup Setup Data (4.1.0)", INNO_VERSION_EXT(4, 1, 0, 0), false }, - { "Inno Setup Setup Data (4.1.2)", INNO_VERSION_EXT(4, 1, 2, 0), false }, - { "Inno Setup Setup Data (4.1.3)", INNO_VERSION_EXT(4, 1, 3, 0), false }, - { "Inno Setup Setup Data (4.1.4)", INNO_VERSION_EXT(4, 1, 4, 0), false }, - { "Inno Setup Setup Data (4.1.5)", INNO_VERSION_EXT(4, 1, 5, 0), false }, - { "Inno Setup Setup Data (4.1.6)", INNO_VERSION_EXT(4, 1, 6, 0), false }, - { "Inno Setup Setup Data (4.1.8)", INNO_VERSION_EXT(4, 1, 8, 0), false }, - { "Inno Setup Setup Data (4.2.0)", INNO_VERSION_EXT(4, 2, 0, 0), false }, - { "Inno Setup Setup Data (4.2.1)", INNO_VERSION_EXT(4, 2, 1, 0), false }, - { "Inno Setup Setup Data (4.2.2)", INNO_VERSION_EXT(4, 2, 2, 0), false }, - { "Inno Setup Setup Data (4.2.3)", INNO_VERSION_EXT(4, 2, 3, 0), false }, - { "Inno Setup Setup Data (4.2.4)", INNO_VERSION_EXT(4, 2, 4, 0), false }, // ! - { "Inno Setup Setup Data (4.2.5)", INNO_VERSION_EXT(4, 2, 5, 0), false }, - { "Inno Setup Setup Data (4.2.6)", INNO_VERSION_EXT(4, 2, 6, 0), false }, - { "Inno Setup Setup Data (5.0.0)", INNO_VERSION_EXT(5, 0, 0, 0), false }, - { "Inno Setup Setup Data (5.0.1)", INNO_VERSION_EXT(5, 0, 1, 0), false }, - { "Inno Setup Setup Data (5.0.3)", INNO_VERSION_EXT(5, 0, 3, 0), false }, - { "Inno Setup Setup Data (5.0.4)", INNO_VERSION_EXT(5, 0, 4, 0), false }, - { "Inno Setup Setup Data (5.1.0)", INNO_VERSION_EXT(5, 1, 0, 0), false }, - { "Inno Setup Setup Data (5.1.2)", INNO_VERSION_EXT(5, 1, 2, 0), false }, - { "Inno Setup Setup Data (5.1.7)", INNO_VERSION_EXT(5, 1, 7, 0), false }, - { "Inno Setup Setup Data (5.1.10)", INNO_VERSION_EXT(5, 1, 10, 0), false }, - { "Inno Setup Setup Data (5.1.13)", INNO_VERSION_EXT(5, 1, 13, 0), false }, - { "Inno Setup Setup Data (5.2.0)", INNO_VERSION_EXT(5, 2, 0, 0), false }, - { "Inno Setup Setup Data (5.2.1)", INNO_VERSION_EXT(5, 2, 1, 0), false }, - { "Inno Setup Setup Data (5.2.3)", INNO_VERSION_EXT(5, 2, 3, 0), false }, - { "Inno Setup Setup Data (5.2.5)", INNO_VERSION_EXT(5, 2, 5, 0), false }, - { "Inno Setup Setup Data (5.2.5) (u)", INNO_VERSION_EXT(5, 2, 5, 0), true }, - { "Inno Setup Setup Data (5.3.0)", INNO_VERSION_EXT(5, 3, 0, 0), false }, - { "Inno Setup Setup Data (5.3.0) (u)", INNO_VERSION_EXT(5, 3, 0, 0), true }, - { "Inno Setup Setup Data (5.3.3)", INNO_VERSION_EXT(5, 3, 3, 0), false }, - { "Inno Setup Setup Data (5.3.3) (u)", INNO_VERSION_EXT(5, 3, 3, 0), true }, - { "Inno Setup Setup Data (5.3.5)", INNO_VERSION_EXT(5, 3, 5, 0), false }, - { "Inno Setup Setup Data (5.3.5) (u)", INNO_VERSION_EXT(5, 3, 5, 0), true }, - { "Inno Setup Setup Data (5.3.6)", INNO_VERSION_EXT(5, 3, 6, 0), false }, - { "Inno Setup Setup Data (5.3.6) (u)", INNO_VERSION_EXT(5, 3, 6, 0), true }, - { "Inno Setup Setup Data (5.3.7)", INNO_VERSION_EXT(5, 3, 7, 0), false }, - { "Inno Setup Setup Data (5.3.7) (u)", INNO_VERSION_EXT(5, 3, 7, 0), true }, - { "Inno Setup Setup Data (5.3.8)", INNO_VERSION_EXT(5, 3, 8, 0), false }, - { "Inno Setup Setup Data (5.3.8) (u)", INNO_VERSION_EXT(5, 3, 8, 0), true }, - { "Inno Setup Setup Data (5.3.9)", INNO_VERSION_EXT(5, 3, 9, 0), false }, - { "Inno Setup Setup Data (5.3.9) (u)", INNO_VERSION_EXT(5, 3, 9, 0), true }, - { "Inno Setup Setup Data (5.3.10)", INNO_VERSION_EXT(5, 3, 10, 0), false }, - { "Inno Setup Setup Data (5.3.10) (u)", INNO_VERSION_EXT(5, 3, 10, 0), true }, - { "Inno Setup Setup Data (5.4.2)", INNO_VERSION_EXT(5, 4, 2, 0), false }, - { "Inno Setup Setup Data (5.4.2) (u)", INNO_VERSION_EXT(5, 4, 2, 0), true }, - { "Inno Setup Setup Data (5.5.0)", INNO_VERSION_EXT(5, 5, 0, 0), false }, - { "Inno Setup Setup Data (5.5.0) (u)", INNO_VERSION_EXT(5, 5, 0, 0), true }, - { "!!! BlackBox v2?, marked as 5.5.0", INNO_VERSION_EXT(5, 5, 0, 1), true }, - { "Inno Setup Setup Data (5.5.6)", INNO_VERSION_EXT(5, 5, 6, 0), false }, - { "Inno Setup Setup Data (5.5.6) (u)", INNO_VERSION_EXT(5, 5, 6, 0), true }, - { "Inno Setup Setup Data (5.5.7)", INNO_VERSION_EXT(5, 5, 7, 0), false }, - { "Inno Setup Setup Data (5.5.7) (u)", INNO_VERSION_EXT(5, 5, 7, 0), true }, - { "Inno Setup Setup Data (5.6.0)", INNO_VERSION_EXT(5, 6, 0, 0), false }, - { "Inno Setup Setup Data (5.6.0) (u)", INNO_VERSION_EXT(5, 6, 0, 0), true }, + { "Inno Setup Setup Data (1.3.3)", INNO_VERSION_EXT(1, 3, 3, 0), 0 }, + { "Inno Setup Setup Data (1.3.9)", INNO_VERSION_EXT(1, 3, 9, 0), 0 }, + { "Inno Setup Setup Data (1.3.10)", INNO_VERSION_EXT(1, 3, 10, 0), 0 }, + { "Inno Setup Setup Data (1.3.10) with ISX (1.3.10)", INNO_VERSION_EXT(1, 3, 10, 0), version::ISX }, + { "Inno Setup Setup Data (1.3.12) with ISX (1.3.12.1)", INNO_VERSION_EXT(1, 3, 12, 1), version::ISX }, + { "Inno Setup Setup Data (1.3.21)", /* ambiguous */ INNO_VERSION_EXT(1, 3, 21, 0), 0 }, + { "Inno Setup Setup Data (1.3.21) with ISX (1.3.17)", INNO_VERSION_EXT(1, 3, 21, 0), version::ISX }, + { "Inno Setup Setup Data (1.3.24)", INNO_VERSION_EXT(1, 3, 24, 0), 0 }, + { "Inno Setup Setup Data (1.3.21) with ISX (1.3.24)", INNO_VERSION_EXT(1, 3, 24, 0), version::ISX }, + { "Inno Setup Setup Data (1.3.25)", INNO_VERSION_EXT(1, 3, 25, 0), 0 }, + { "Inno Setup Setup Data (1.3.25) with ISX (1.3.25)", INNO_VERSION_EXT(1, 3, 25, 0), version::ISX }, + { "Inno Setup Setup Data (2.0.0)", INNO_VERSION_EXT(2, 0, 0, 0), 0 }, + { "Inno Setup Setup Data (2.0.1)", /* ambiguous */ INNO_VERSION_EXT(2, 0, 1, 0), 0 }, + { "Inno Setup Setup Data (2.0.2)", INNO_VERSION_EXT(2, 0, 2, 0), 0 }, + { "Inno Setup Setup Data (2.0.5)", INNO_VERSION_EXT(2, 0, 5, 0), 0 }, + { "Inno Setup Setup Data (2.0.6a)", INNO_VERSION_EXT(2, 0, 6, 0), 0 }, + { "Inno Setup Setup Data (2.0.6a) with ISX (2.0.3)", INNO_VERSION_EXT(2, 0, 6, 0), version::ISX }, + { "Inno Setup Setup Data (2.0.7)", INNO_VERSION_EXT(2, 0, 7, 0), 0 }, + { "Inno Setup Setup Data (2.0.8)", INNO_VERSION_EXT(2, 0, 8, 0), 0 }, + { "Inno Setup Setup Data (2.0.8) with ISX (2.0.3)", INNO_VERSION_EXT(2, 0, 8, 0), version::ISX }, + { "Inno Setup Setup Data (2.0.8) with ISX (2.0.10)", INNO_VERSION_EXT(2, 0, 10, 0), version::ISX }, + { "Inno Setup Setup Data (2.0.11)", INNO_VERSION_EXT(2, 0, 11, 0), 0 }, + { "Inno Setup Setup Data (2.0.11) with ISX (2.0.11)", INNO_VERSION_EXT(2, 0, 11, 0), version::ISX }, + { "Inno Setup Setup Data (2.0.17)", INNO_VERSION_EXT(2, 0, 17, 0), 0 }, + { "Inno Setup Setup Data (2.0.17) with ISX (2.0.11)", INNO_VERSION_EXT(2, 0, 17, 0), version::ISX }, + { "Inno Setup Setup Data (2.0.18)", INNO_VERSION_EXT(2, 0, 18, 0), 0 }, + { "Inno Setup Setup Data (2.0.18) with ISX (2.0.11)", INNO_VERSION_EXT(2, 0, 18, 0), version::ISX }, + { "Inno Setup Setup Data (3.0.0a)", INNO_VERSION_EXT(3, 0, 0, 0), 0 }, + { "Inno Setup Setup Data (3.0.1)", INNO_VERSION_EXT(3, 0, 1, 0), 0 }, + { "Inno Setup Setup Data (3.0.1) with ISX (3.0.0)", INNO_VERSION_EXT(3, 0, 1, 0), version::ISX }, + { "Inno Setup Setup Data (3.0.3)", /* ambiguous */ INNO_VERSION_EXT(3, 0, 3, 0), 0 }, + { "Inno Setup Setup Data (3.0.3) with ISX (3.0.3)", INNO_VERSION_EXT(3, 0, 3, 0), version::ISX }, + { "Inno Setup Setup Data (3.0.4)", INNO_VERSION_EXT(3, 0, 4, 0), 0 }, + { "My Inno Setup Extensions Setup Data (3.0.4)", INNO_VERSION_EXT(3, 0, 4, 0), version::ISX }, + { "Inno Setup Setup Data (3.0.5)", INNO_VERSION_EXT(3, 0, 5, 0), 0 }, + { "My Inno Setup Extensions Setup Data (3.0.6.1)", INNO_VERSION_EXT(3, 0, 6, 1), version::ISX }, + { "Inno Setup Setup Data (4.0.0a)", INNO_VERSION_EXT(4, 0, 0, 0), 0 }, + { "Inno Setup Setup Data (4.0.1)", INNO_VERSION_EXT(4, 0, 1, 0), 0 }, + { "Inno Setup Setup Data (4.0.3)", INNO_VERSION_EXT(4, 0, 3, 0), 0 }, + { "Inno Setup Setup Data (4.0.5)", INNO_VERSION_EXT(4, 0, 5, 0), 0 }, + { "Inno Setup Setup Data (4.0.9)", INNO_VERSION_EXT(4, 0, 9, 0), 0 }, + { "Inno Setup Setup Data (4.0.10)", INNO_VERSION_EXT(4, 0, 10, 0), 0 }, + { "Inno Setup Setup Data (4.0.11)", INNO_VERSION_EXT(4, 0, 11, 0), 0 }, + { "Inno Setup Setup Data (4.1.0)", INNO_VERSION_EXT(4, 1, 0, 0), 0 }, + { "Inno Setup Setup Data (4.1.2)", INNO_VERSION_EXT(4, 1, 2, 0), 0 }, + { "Inno Setup Setup Data (4.1.3)", INNO_VERSION_EXT(4, 1, 3, 0), 0 }, + { "Inno Setup Setup Data (4.1.4)", INNO_VERSION_EXT(4, 1, 4, 0), 0 }, + { "Inno Setup Setup Data (4.1.5)", INNO_VERSION_EXT(4, 1, 5, 0), 0 }, + { "Inno Setup Setup Data (4.1.6)", INNO_VERSION_EXT(4, 1, 6, 0), 0 }, + { "Inno Setup Setup Data (4.1.8)", INNO_VERSION_EXT(4, 1, 8, 0), 0 }, + { "Inno Setup Setup Data (4.2.0)", INNO_VERSION_EXT(4, 2, 0, 0), 0 }, + { "Inno Setup Setup Data (4.2.1)", INNO_VERSION_EXT(4, 2, 1, 0), 0 }, + { "Inno Setup Setup Data (4.2.2)", INNO_VERSION_EXT(4, 2, 2, 0), 0 }, + { "Inno Setup Setup Data (4.2.3)", /* ambiguous */ INNO_VERSION_EXT(4, 2, 3, 0), 0 }, + { "Inno Setup Setup Data (4.2.4)", INNO_VERSION_EXT(4, 2, 4, 0), 0 }, + { "Inno Setup Setup Data (4.2.5)", INNO_VERSION_EXT(4, 2, 5, 0), 0 }, + { "Inno Setup Setup Data (4.2.6)", INNO_VERSION_EXT(4, 2, 6, 0), 0 }, + { "Inno Setup Setup Data (5.0.0)", INNO_VERSION_EXT(5, 0, 0, 0), 0 }, + { "Inno Setup Setup Data (5.0.1)", INNO_VERSION_EXT(5, 0, 1, 0), 0 }, + { "Inno Setup Setup Data (5.0.3)", INNO_VERSION_EXT(5, 0, 3, 0), 0 }, + { "Inno Setup Setup Data (5.0.4)", INNO_VERSION_EXT(5, 0, 4, 0), 0 }, + { "Inno Setup Setup Data (5.1.0)", INNO_VERSION_EXT(5, 1, 0, 0), 0 }, + { "Inno Setup Setup Data (5.1.2)", INNO_VERSION_EXT(5, 1, 2, 0), 0 }, + { "Inno Setup Setup Data (5.1.7)", INNO_VERSION_EXT(5, 1, 7, 0), 0 }, + { "Inno Setup Setup Data (5.1.10)", INNO_VERSION_EXT(5, 1, 10, 0), 0 }, + { "Inno Setup Setup Data (5.1.13)", INNO_VERSION_EXT(5, 1, 13, 0), 0 }, + { "Inno Setup Setup Data (5.2.0)", INNO_VERSION_EXT(5, 2, 0, 0), 0 }, + { "Inno Setup Setup Data (5.2.1)", INNO_VERSION_EXT(5, 2, 1, 0), 0 }, + { "Inno Setup Setup Data (5.2.3)", INNO_VERSION_EXT(5, 2, 3, 0), 0 }, + { "Inno Setup Setup Data (5.2.5)", INNO_VERSION_EXT(5, 2, 5, 0), 0 }, + { "Inno Setup Setup Data (5.2.5) (u)", INNO_VERSION_EXT(5, 2, 5, 0), version::Unicode }, + { "Inno Setup Setup Data (5.3.0)", INNO_VERSION_EXT(5, 3, 0, 0), 0 }, + { "Inno Setup Setup Data (5.3.0) (u)", INNO_VERSION_EXT(5, 3, 0, 0), version::Unicode }, + { "Inno Setup Setup Data (5.3.3)", INNO_VERSION_EXT(5, 3, 3, 0), 0 }, + { "Inno Setup Setup Data (5.3.3) (u)", INNO_VERSION_EXT(5, 3, 3, 0), version::Unicode }, + { "Inno Setup Setup Data (5.3.5)", INNO_VERSION_EXT(5, 3, 5, 0), 0 }, + { "Inno Setup Setup Data (5.3.5) (u)", INNO_VERSION_EXT(5, 3, 5, 0), version::Unicode }, + { "Inno Setup Setup Data (5.3.6)", INNO_VERSION_EXT(5, 3, 6, 0), 0 }, + { "Inno Setup Setup Data (5.3.6) (u)", INNO_VERSION_EXT(5, 3, 6, 0), version::Unicode }, + { "Inno Setup Setup Data (5.3.7)", INNO_VERSION_EXT(5, 3, 7, 0), 0 }, + { "Inno Setup Setup Data (5.3.7) (u)", INNO_VERSION_EXT(5, 3, 7, 0), version::Unicode }, + { "Inno Setup Setup Data (5.3.8)", INNO_VERSION_EXT(5, 3, 8, 0), 0 }, + { "Inno Setup Setup Data (5.3.8) (u)", INNO_VERSION_EXT(5, 3, 8, 0), version::Unicode }, + { "Inno Setup Setup Data (5.3.9)", INNO_VERSION_EXT(5, 3, 9, 0), 0 }, + { "Inno Setup Setup Data (5.3.9) (u)", INNO_VERSION_EXT(5, 3, 9, 0), version::Unicode }, + { "Inno Setup Setup Data (5.3.10)", INNO_VERSION_EXT(5, 3, 10, 0), 0 }, + { "Inno Setup Setup Data (5.3.10) (u)", INNO_VERSION_EXT(5, 3, 10, 0), version::Unicode }, + { "Inno Setup Setup Data (5.4.2)", INNO_VERSION_EXT(5, 4, 2, 0), 0 }, + { "Inno Setup Setup Data (5.4.2) (u)", INNO_VERSION_EXT(5, 4, 2, 0), version::Unicode }, + { "Inno Setup Setup Data (5.5.0)", INNO_VERSION_EXT(5, 5, 0, 0), 0 }, + { "Inno Setup Setup Data (5.5.0) (u)", /* ambiguous */ INNO_VERSION_EXT(5, 5, 0, 0), version::Unicode }, + { "" /* BlackBox v2? */, INNO_VERSION_EXT(5, 5, 0, 1), 0 }, + { "" /* BlackBox v2? */, INNO_VERSION_EXT(5, 5, 0, 1), version::Unicode }, + { "Inno Setup Setup Data (5.5.6)", INNO_VERSION_EXT(5, 5, 6, 0), 0 }, + { "Inno Setup Setup Data (5.5.6) (u)", INNO_VERSION_EXT(5, 5, 6, 0), version::Unicode }, + { "Inno Setup Setup Data (5.5.7)", /* ambiguous */ INNO_VERSION_EXT(5, 5, 7, 0), 0 }, + { "Inno Setup Setup Data (5.5.7) (u)", /* ambiguous */ INNO_VERSION_EXT(5, 5, 7, 0), version::Unicode }, + { "Inno Setup Setup Data (5.5.7) (U)", /* ambiguous */ INNO_VERSION_EXT(5, 5, 7, 0), version::Unicode }, + { "Inno Setup Setup Data (5.5.8) (u)", /* unofficial */ INNO_VERSION_EXT(5, 5, 7, 0), version::Unicode }, + { "" /* unknown 5.5.7 (u) variant */, /* ambiguous */ INNO_VERSION_EXT(5, 5, 7, 1), 0 }, + { "" /* unknown 5.5.7 (u) variant */, /* ambiguous */ INNO_VERSION_EXT(5, 5, 7, 1), version::Unicode }, + { "Inno Setup Setup Data (5.6.0)", INNO_VERSION_EXT(5, 6, 0, 0), 0 }, + { "Inno Setup Setup Data (5.6.0) (u)", INNO_VERSION_EXT(5, 6, 0, 0), version::Unicode }, + { "Inno Setup Setup Data (5.6.2)", /* prerelease */ INNO_VERSION_EXT(5, 6, 2, 0), 0 }, + { "Inno Setup Setup Data (5.6.2) (u)", /* prerelease */ INNO_VERSION_EXT(5, 6, 2, 0), version::Unicode }, + { "Inno Setup Setup Data (6.0.0) (u)", INNO_VERSION_EXT(6, 0, 0, 0), version::Unicode }, }; } // anonymous namespace @@ -164,12 +189,16 @@ os << '.' << version.d(); } - if(version.unicode) { + if(version.is_unicode()) { os << " (unicode)"; } - if(version.bits != 32) { - os << " (" << int(version.bits) << "-bit)"; + if(version.bits() != 32) { + os << " (" << int(version.bits()) << "-bit)"; + } + + if(version.is_isx()) { + os << " (isx)"; } return os; @@ -189,8 +218,7 @@ for(size_t i = 0; i < size_t(boost::size(legacy_versions)); i++) { if(!memcmp(legacy_version, legacy_versions[i].name, sizeof(legacy_version))) { value = legacy_versions[i].version; - bits = legacy_versions[i].bits; - unicode = false; + variant = legacy_versions[i].variant; known = true; debug("known legacy version: \"" << versions[i].name << '"'); return; @@ -206,9 +234,9 @@ } if(legacy_version[9] == '1' && legacy_version[10] == '6') { - bits = 16; + variant = Bits16; } else if(legacy_version[9] == '3' && legacy_version[10] == '2') { - bits = 32; + variant = 0; } else { throw version_error(); } @@ -224,37 +252,36 @@ throw version_error(); } - unicode = false; known = false; return; } - stored_version version; - BOOST_STATIC_ASSERT(sizeof(legacy_version) <= sizeof(version)); - memcpy(version, legacy_version, sizeof(legacy_version)); - is.read(version + sizeof(legacy_version), - std::streamsize(sizeof(version) - sizeof(legacy_version))); + stored_version version_string; + BOOST_STATIC_ASSERT(sizeof(legacy_version) <= sizeof(version_string)); + memcpy(version_string, legacy_version, sizeof(legacy_version)); + is.read(version_string + sizeof(legacy_version), + std::streamsize(sizeof(version_string) - sizeof(legacy_version))); for(size_t i = 0; i < size_t(boost::size(versions)); i++) { - if(!memcmp(version, versions[i].name, sizeof(version))) { + if(versions[i].name[0] != '\0' && !memcmp(version_string, versions[i].name, sizeof(version_string))) { value = versions[i].version; - bits = 32; - unicode = versions[i].unicode; + variant = versions[i].variant; known = true; debug("known version: \"" << versions[i].name << '"'); return; } } - char * end = std::find(version, version + boost::size(version), '\0'); - std::string version_str(version, end); + char * end = std::find(version_string, version_string + boost::size(version_string), '\0'); + std::string version_str(version_string, end); debug("unknown version: \"" << version_str << '"'); if(version_str.find("Inno Setup") == std::string::npos) { throw version_error(); } + value = 0; size_t bracket = version_str.find('('); for(; bracket != std::string::npos; bracket = version_str.find('(', bracket + 1)) { @@ -302,24 +329,34 @@ } } - value = INNO_VERSION_EXT(a, b, c, d); - break; + value = std::max(value, INNO_VERSION_EXT(a, b, c, d)); } catch(const boost::bad_lexical_cast &) { continue; } } - if(bracket == std::string::npos) { + if(!value) { throw version_error(); } - bits = 32; - unicode = (version_str.find("(u)") != std::string::npos); + variant = 0; + if(boost::contains(version_str, "(u)") || boost::contains(version_str, "(U)")) { + variant |= Unicode; + } + if(boost::contains(version_str, "My Inno Setup Extensions") || boost::contains(version_str, "with ISX")) { + variant |= ISX; + } + known = false; } bool version::is_ambiguous() const { + if(value == INNO_VERSION(1, 3, 21)) { + // might be either 1.3.21 or 1.3.24 + return true; + } + if(value == INNO_VERSION(2, 0, 1)) { // might be either 2.0.1 or 2.0.2 return true; @@ -340,8 +377,8 @@ return true; } - if(value == INNO_VERSION(5, 5, 7)) { - // might be either 5.5.7 or 5.6.0 + if(value == INNO_VERSION(5, 5, 7) || value == INNO_VERSION_EXT(5, 5, 7, 1)) { + // might be either 5.5.7, an unknown modification of 5.5.7, or 5.6.0 return true; } @@ -351,16 +388,22 @@ version_constant version::next() { const known_legacy_version * legacy_end = boost::end(legacy_versions); - const known_legacy_version * legacy_version; - legacy_version = std::upper_bound(boost::begin(legacy_versions), legacy_end, value); - if(legacy_version != legacy_end) { - return legacy_version->version; + const known_legacy_version * legacy_result; + legacy_result = std::upper_bound(boost::begin(legacy_versions), legacy_end, value); + while(legacy_result != legacy_end && legacy_result->variant != variant) { + legacy_result++; } - + if(legacy_result != legacy_end) { + return legacy_result->version; + } + const known_version * end = boost::end(versions); - const known_version * version = std::upper_bound(boost::begin(versions), end, value); - if(version != end) { - return version->version; + const known_version * result = std::upper_bound(boost::begin(versions), end, value); + while(result != end && result->variant != variant) { + result++; + } + if(result != end) { + return result->version; } return 0; diff -Nru innoextract-1.7/src/setup/version.hpp innoextract-1.8/src/setup/version.hpp --- innoextract-1.7/src/setup/version.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/version.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -31,6 +31,8 @@ #include +#include "util/flags.hpp" + namespace setup { struct version_error : public std::exception { }; @@ -46,24 +48,27 @@ struct version { - version_constant value; + FLAGS(flags, + Bits16, + Unicode, + ISX + ); - boost::uint8_t bits; // 16 or 32 + version_constant value; - bool unicode; + flags variant; bool known; - version() : value(0), bits(0), unicode(false), known(false) { } + version() : value(0), variant(0), known(false) { } - version(version_constant value, bool unicode = false, - bool known = false, boost::uint8_t bits = 32) - : value(value), bits(bits), unicode(unicode), known(known) { } + version(version_constant v, flags type = 0, bool is_known = false) + : value(v), variant(type), known(is_known) { } version(boost::uint8_t a, boost::uint8_t b, boost::uint8_t c, boost::uint8_t d = 0, - bool unicode = false, bool known = false, boost::uint8_t bits = 32) - : value(INNO_VERSION_EXT(a, b, c, d)), bits(bits), unicode(unicode), known(known) { } + flags type = 0, bool is_known = false) + : value(INNO_VERSION_EXT(a, b, c, d)), variant(type), known(is_known) { } unsigned int a() const { return value >> 24; } unsigned int b() const { return (value >> 16) & 0xff; } @@ -72,8 +77,9 @@ void load(std::istream & is); - //! \return the Windows codepage used to encode strings - boost::uint32_t codepage() const { return boost::uint32_t(unicode ? 1200 : 1252); } + boost::uint16_t bits() const { return (variant & Bits16) ? 16 : 32; } + bool is_unicode() const { return (variant & Unicode) != 0; } + bool is_isx() const { return (variant & ISX) != 0; } //! \return true if the version stored might not be correct bool is_ambiguous() const; diff -Nru innoextract-1.7/src/setup/windows.cpp innoextract-1.8/src/setup/windows.cpp --- innoextract-1.7/src/setup/windows.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/setup/windows.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -34,7 +34,7 @@ void windows_version::data::load(std::istream & is, const version & version) { - if(version >= INNO_VERSION(1, 3, 21)) { + if(version >= INNO_VERSION(1, 3, 19)) { build = util::load(is); } else { build = 0; @@ -50,7 +50,7 @@ win_version.load(is, version); nt_version.load(is, version); - if(version >= INNO_VERSION(1, 3, 21)) { + if(version >= INNO_VERSION(1, 3, 19)) { nt_service_pack.minor = util::load(is); nt_service_pack.major = util::load(is); } else { diff -Nru innoextract-1.7/src/stream/block.cpp innoextract-1.8/src/stream/block.cpp --- innoextract-1.7/src/stream/block.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/stream/block.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2016 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -111,21 +111,21 @@ template std::streamsize read(Source & src, char * dest, std::streamsize n) { - std::streamsize read = 0; + std::streamsize nread = 0; while(n) { if(pos == length && !read_chunk(src)) { - return read ? read : EOF; + return nread ? nread : EOF; } std::streamsize size = std::min(n, std::streamsize(length - pos)); - std::copy(buffer + pos, buffer + pos + size, dest + read); + std::copy(buffer + pos, buffer + pos + size, dest + nread); - pos += size_t(size), n -= size, read += size; + pos += size_t(size), n -= size, nread += size; } - return read; + return nread; } private: diff -Nru innoextract-1.7/src/stream/checksum.hpp innoextract-1.8/src/stream/checksum.hpp --- innoextract-1.7/src/stream/checksum.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/stream/checksum.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -52,12 +52,12 @@ typedef base_type::category category; /*! - * \param output Location to store the final checksum at. - * \param type The type of checksum to calculate. + * \param dest Location to store the final checksum at. + * \param type The type of checksum to calculate. */ - checksum_filter(crypto::checksum * output, crypto::checksum_type type) + checksum_filter(crypto::checksum * dest, crypto::checksum_type type) : hasher(type) - , output(output) + , output(dest) { } template diff -Nru innoextract-1.7/src/stream/chunk.cpp innoextract-1.8/src/stream/chunk.cpp --- innoextract-1.7/src/stream/chunk.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/stream/chunk.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -96,8 +96,8 @@ if(first_slice != o.first_slice) { return (first_slice < o.first_slice); - } else if(offset != o.offset) { - return (offset < o.offset); + } else if(sort_offset != o.sort_offset) { + return (sort_offset < o.sort_offset); } else if(size != o.size) { return (size < o.size); } else if(compression != o.compression) { @@ -111,7 +111,7 @@ bool chunk::operator==(const chunk & o) const { return (first_slice == o.first_slice - && offset == o.offset + && sort_offset == o.sort_offset && size == o.size && compression == o.compression && encryption == o.encryption); diff -Nru innoextract-1.7/src/stream/chunk.hpp innoextract-1.8/src/stream/chunk.hpp --- innoextract-1.7/src/stream/chunk.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/stream/chunk.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -77,8 +77,10 @@ */ struct chunk { - size_t first_slice; //!< Slice where the chunk starts. - size_t last_slice; //!< Slice where the chunk ends. + boost::uint32_t first_slice; //!< Slice where the chunk starts. + boost::uint32_t last_slice; //!< Slice where the chunk ends. + + boost::uint32_t sort_offset; boost::uint32_t offset; //!< Offset of the compressed chunk in firstSlice. boost::uint64_t size; //! Total compressed size of the chunk. diff -Nru innoextract-1.7/src/stream/exefilter.hpp innoextract-1.8/src/stream/exefilter.hpp --- innoextract-1.7/src/stream/exefilter.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/stream/exefilter.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -93,11 +93,11 @@ typedef base_type::category category; /*! - * \param flip_high_byte true if the high byte of addresses is flipped if bit 23 is set. - * This optimization is used in Inno Setup 5.3.9 and later. + * \param flip_high_bytes true if the high byte of addresses is flipped if bit 23 is set. + * This optimization is used in Inno Setup 5.3.9 and later. */ - explicit inno_exe_decoder_5200(bool flip_high_byte) - : flip_high_byte(flip_high_byte) { close(0); } + explicit inno_exe_decoder_5200(bool flip_high_bytes) + : flip_high_byte(flip_high_bytes) { close(0); } template std::streamsize read(Source & src, char * dest, std::streamsize n); diff -Nru innoextract-1.7/src/stream/lzma.cpp innoextract-1.8/src/stream/lzma.cpp --- innoextract-1.7/src/stream/lzma.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/stream/lzma.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -18,8 +18,6 @@ * 3. This notice may not be removed or altered from any source distribution. */ -#define INNOEXTRACT_HAVE_LZMA 1 - #include "stream/lzma.hpp" #include @@ -108,7 +106,7 @@ } options.pb = boost::uint32_t(properties / (9 * 5)); options.lp = boost::uint32_t((properties % (9 * 5)) / 9); - options.lc = properties % 9; + options.lc = boost::uint32_t(properties % 9); options.dict_size = util::little_endian::load(header + 1); diff -Nru innoextract-1.7/src/stream/restrict.hpp innoextract-1.8/src/stream/restrict.hpp --- innoextract-1.7/src/stream/restrict.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/stream/restrict.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Daniel Scharrer + * Copyright (C) 2013-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -45,8 +45,8 @@ restricted_source(const restricted_source & o) : base(o.base), remaining(o.remaining) { } - restricted_source(BaseSource & base, boost::uint64_t size) - : base(base), remaining(size) { } + restricted_source(BaseSource & source, boost::uint64_t size) + : base(source), remaining(size) { } std::streamsize read(char * buffer, std::streamsize bytes) { diff -Nru innoextract-1.7/src/stream/slice.cpp innoextract-1.8/src/stream/slice.cpp --- innoextract-1.7/src/stream/slice.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/stream/slice.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -44,8 +44,8 @@ } // anonymous namespace -slice_reader::slice_reader(std::istream * istream, boost::uint32_t data_offset) - : data_offset(data_offset), +slice_reader::slice_reader(std::istream * istream, boost::uint32_t offset) + : data_offset(offset), slices_per_disk(1), current_slice(0), slice_size(0), is(istream) { @@ -59,11 +59,11 @@ } } -slice_reader::slice_reader(const path_type & dir, const std::string & basename, - const std::string & basename2, size_t slices_per_disk) +slice_reader::slice_reader(const path_type & dirname, const std::string & basename, + const std::string & basename2, size_t disk_slice_count) : data_offset(0), - dir(dir), base_file(basename), base_file2(basename2), - slices_per_disk(slices_per_disk), current_slice(0), slice_size(0), + dir(dirname), base_file(basename), base_file2(basename2), + slices_per_disk(disk_slice_count), current_slice(0), slice_size(0), is(&ifs) { } void slice_reader::seek(size_t slice) { @@ -157,12 +157,12 @@ return oss.str(); } -bool slice_reader::open_file_case_insensitive(const path_type & dir, const path_type & filename) { +bool slice_reader::open_file_case_insensitive(const path_type & dirname, const path_type & filename) { boost::filesystem::directory_iterator end; - for(boost::filesystem::directory_iterator i(dir); i != end; ++i) { + for(boost::filesystem::directory_iterator i(dirname); i != end; ++i) { path_type actual_filename = i->path().filename(); - if(boost::iequals(actual_filename.string(), filename.string()) && open_file(dir / actual_filename)) { + if(boost::iequals(actual_filename.string(), filename.string()) && open_file(dirname / actual_filename)) { return true; } } @@ -231,17 +231,19 @@ if(read_pos > slice_size) { break; } - std::streamsize remaining = std::streamsize(slice_size - read_pos); + boost::uint32_t remaining = slice_size - read_pos; if(!remaining) { seek(current_slice + 1); read_pos = boost::uint32_t(is->tellg()); if(read_pos > slice_size) { break; } - remaining = std::streamsize(slice_size - read_pos); + remaining = slice_size - read_pos; } - if(is->read(buffer, std::min(remaining, bytes)).fail()) { + boost::uint64_t toread = std::min(boost::uint64_t(remaining), boost::uint64_t(bytes)); + toread = std::min(toread, boost::uint64_t(std::numeric_limits::max())); + if(is->read(buffer, std::streamsize(toread)).fail()) { break; } diff -Nru innoextract-1.7/src/stream/slice.hpp innoextract-1.8/src/stream/slice.hpp --- innoextract-1.7/src/stream/slice.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/stream/slice.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -77,7 +77,7 @@ void seek(size_t slice); bool open_file(const path_type & file); - bool open_file_case_insensitive(const path_type & dir, const path_type & filename); + bool open_file_case_insensitive(const path_type & dirname, const path_type & filename); void open(size_t slice); public: @@ -89,15 +89,15 @@ * Construct a \ref slice_reader to read from data inside the setup file. * Seeking to anything except the zeroeth slice is not allowed. * - * \param istream A seekable input stream for the setup executable. - * The initial read position of the stream is ignored. - * \param data_offset The offset within the given stream where the setup data starts. - * This offset is given by \ref loader::offsets::data_offset. + * \param istream A seekable input stream for the setup executable. + * The initial read position of the stream is ignored. + * \param offset The offset within the given stream where the setup data starts. + * This offset is given by \ref loader::offsets::data_offset. * * The constructed reader will allow reading the byte range [data_offset, file end) * from the setup executable and provide this as the range [0, file end - data_offset). */ - slice_reader(std::istream * istream, boost::uint32_t data_offset); + slice_reader(std::istream * istream, boost::uint32_t offset); /*! * Construct a \ref slice_reader to read from external data slices (aka disks). @@ -109,13 +109,13 @@ * The disk number is given by \code slice / slices_per_disk + 1 \endcode while * the sliceletter is the ASCII char \code 'a' + (slice % slices_per_disk) \endcode. * - * \param dir The directory containing the slice files. - * \param basename The base name for slice files. - * \param basename2 Alternative base name for slice files. - * \param slices_per_disk How many slices are grouped into one disk. Must not be \c 0. + * \param dirname The directory containing the slice files. + * \param basename The base name for slice files. + * \param basename2 Alternative base name for slice files. + * \param disk_slice_count How many slices are grouped into one disk. Must not be \c 0. */ - slice_reader(const path_type & dir, const std::string & basename, const std::string & basename2, - size_t slices_per_disk); + slice_reader(const path_type & dirname, const std::string & basename, const std::string & basename2, + size_t disk_slice_count); /*! * Attempt to seek to an offset within a slice. diff -Nru innoextract-1.7/src/util/console.cpp innoextract-1.8/src/util/console.cpp --- innoextract-1.7/src/util/console.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/console.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2016 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -123,18 +123,26 @@ // Initialize color output - shell_command * const all_colors[] = { - &reset, ¤t, - &black, &red, &green, &yellow, &blue, &magenta, &cyan, &white, - &dim_black, &dim_red, &dim_green, &dim_yellow, - &dim_blue, &dim_magenta, &dim_cyan, &dim_white, - }; - - if(color == disable || (color == automatic && !is_tty)) { + if(color == disable || (color == automatic && (!is_tty || std::getenv("NO_COLOR") != NULL))) { - BOOST_FOREACH(shell_command * color, all_colors) { - color->command = ""; - } + reset.command = ""; + current.command = ""; + black.command = ""; + red.command = ""; + green.command = ""; + yellow.command = ""; + blue.command = ""; + magenta.command = ""; + cyan.command = ""; + white.command = ""; + dim_black.command = ""; + dim_red.command = ""; + dim_green.command = ""; + dim_yellow.command = ""; + dim_blue.command = ""; + dim_magenta.command = ""; + dim_cyan.command = ""; + dim_white.command = ""; } else { @@ -333,8 +341,8 @@ progress_cleared = false; } -progress::progress(boost::uint64_t max, bool show_rate) - : max(max), value(0), show_rate(show_rate), +progress::progress(boost::uint64_t max_value, bool show_value_rate) + : max(max_value), value(0), show_rate(show_value_rate), start_time(boost::posix_time::microsec_clock::universal_time()), last_status(-1.f), last_time(0), last_rate(0.f) { } diff -Nru innoextract-1.7/src/util/console.hpp innoextract-1.8/src/util/console.hpp --- innoextract-1.7/src/util/console.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/console.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -113,11 +113,11 @@ public: /*! - * \param max Maximumum progress values. - * If this value is \c 0, the progress bar will be unbounded. - * \param show_rate Display the rate at which the progress changes. + * \param max_value Maximumum progress values. + * If this value is \c 0, the progress bar will be unbounded. + * \param show_value_rate Display the rate at which the progress changes. */ - progress(boost::uint64_t max = 0, bool show_rate = true); + progress(boost::uint64_t max_value = 0, bool show_value_rate = true); /*! * Update the progress bar. diff -Nru innoextract-1.7/src/util/encoding.cpp innoextract-1.8/src/util/encoding.cpp --- innoextract-1.7/src/util/encoding.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/encoding.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -78,99 +78,197 @@ namespace util { -enum known_codepages { - cp_utf16le = 1200, - cp_windows1252 = 1252, - cp_ascii = 20127, - cp_iso_8859_1 = 28591, - cp_utf8 = 65001, -}; - namespace { //! Get names for encodings where iconv doesn't have the codepage alias const char * get_encoding_name(codepage_id codepage) { switch(codepage) { - case 708: return "ISO-8859-6"; - case 936: return "GBK"; - case 949: return "UHC"; - case 950: return "BIG5"; - // iconv's behavior for "UTF-16" is platform-dependent if there is no BOM. - // There never is any BOM in Inno Setup files and it's always little-endian, - // so we specify the exact encoding. - case 1200: return "UTF-16LE"; - case 1201: return "UTF-16BE"; - case 1252: return "MS-ANSI"; - case 1361: return "JOHAB"; - case 10000: return "MACINTOSH"; - case 10002: return "BIG5"; - case 10008: return "GB2312"; - case 12000: return "UTF-32LE"; - case 12001: return "UTF-32BE"; - case 20003: return "IBM5550"; - case 20127: return "US-ASCII"; - case 20261: return "T.61"; - case 20269: return "ISO_6937"; - case 20273: return "IBM273"; - case 20277: return "IBM277"; - case 20278: return "IBM278"; - case 20280: return "IBM280"; - case 20284: return "IBM284"; - case 20285: return "IBM285"; - case 20290: return "IBM290"; - case 20297: return "IBM297"; - case 20420: return "IBM420"; - case 20423: return "IBM423"; - case 20424: return "IBM424"; - case 20866: return "KOI8-R"; - case 20871: return "IBM871"; - case 20880: return "IBM880"; - case 20905: return "IBM905"; - case 20924: return "IBM1047"; - case 20932: return "EUC-JP-MS"; - case 20936: return "EUC-CN"; - case 21025: return "IBM1025"; - case 21866: return "KOI8-U"; - case 28591: return "ISO-8859-1"; - case 28592: return "ISO-8859-2"; - case 28593: return "ISO-8859-3"; - case 28594: return "ISO-8859-4"; - case 28595: return "ISO-8859-5"; - case 28596: return "ISO-8859-6"; - case 28597: return "ISO-8859-7"; - case 28598: return "ISO-8859-8"; - case 28599: return "ISO-8859-9"; - case 28603: return "ISO-8859-13"; - case 28605: return "ISO-8859-15"; - case 38598: return "ISO-8859-8"; - case 50220: return "ISO-2022-JP"; - case 50221: return "ISO-2022-JP-2"; - case 50222: return "ISO-2022-JP-3"; - case 50225: return "ISO-2022-KR"; - case 50227: return "ISO-2022-CN"; - case 50229: return "ISO-2022-CN-EXT"; - case 50930: return "EBCDIC-JP-E"; - case 51932: return "EUC-JP"; - case 51936: return "EUC-CN"; - case 51949: return "EUC-KR"; - case 51950: return "EUC-CN"; - case 54936: return "GB18030"; - case 65000: return "UTF-7"; - case 65001: return "UTF-8"; + case cp_ascii: return "US-ASCII"; + case cp_big5: return "BIG5"; + case cp_big5_eten: return "BIG5"; + case cp_big5_hkscs: return "BIG5-HKSCS"; + case cp_cns: return "EUC-TW"; + case cp_dos708: return "ISO-8859-6"; + case cp_euc_cn: return "EUC-CN"; + case cp_euc_jp: return "EUC-JP"; + case cp_euc_jp_ms: return "EUC-JP-MS"; + case cp_euc_kr: return "EUC-KR"; + case cp_euc_tw: return "EUC-TW"; + case cp_gb2312_80: return "GB2312"; + case cp_gb2312_hz: return "GB2312"; + case cp_gb18030: return "GB18030"; + case cp_gbk: return "GBK"; + case cp_ia5: return "ISO_646.IRV:1991"; + case cp_ia5_de: return "ISO646-DE"; + case cp_ia5_no2: return "ISO646-NO2"; + case cp_ia5_se2: return "ISO646-SE2"; + case cp_ibm273: return "IBM273"; + case cp_ibm277: return "IBM277"; + case cp_ibm278: return "IBM278"; + case cp_ibm280: return "IBM280"; + case cp_ibm284: return "IBM284"; + case cp_ibm285: return "IBM285"; + case cp_ibm290: return "IBM290"; + case cp_ibm297: return "IBM297"; + case cp_ibm420: return "IBM420"; + case cp_ibm423: return "IBM423"; + case cp_ibm424: return "IBM424"; + case cp_ibm833: return "IBM833"; + case cp_ibm838: return "IBM1160"; + case cp_ibm871: return "IBM871"; + case cp_ibm880: return "IBM880"; + case cp_ibm905: return "IBM905"; + case cp_ibm924: return "IBM1047"; + case cp_ibm930: return "IBM930"; + case cp_ibm931: return "IBM931"; + case cp_ibm933: return "IBM933"; + case cp_ibm935: return "IBM935"; + case cp_ibm936: return "IBM936"; + case cp_ibm937: return "IBM937"; + case cp_ibm939: return "IBM939"; + case cp_ibm1025: return "IBM1025"; + case cp_iso_2022_cn: return "ISO-2022-CN"; + case cp_iso_2022_cn2: return "ISO-2022-CN-EXT"; + case cp_iso_2022_jp: return "ISO-2022-JP"; + case cp_iso_2022_jp2: return "ISO-2022-JP-2"; + case cp_iso_2022_jp3: return "ISO-2022-JP-3"; + case cp_iso_2022_kr: return "ISO-2022-KR"; + case cp_iso_6937: return "ISO_6937"; + case cp_iso_8859_10: return "ISO-8859-10"; + case cp_iso_8859_11: return "ISO-8859-11"; + case cp_iso_8859_13: return "ISO-8859-13"; + case cp_iso_8859_14: return "ISO-8859-14"; + case cp_iso_8859_15: return "ISO-8859-15"; + case cp_iso_8859_1: return "ISO-8859-1"; + case cp_iso_8859_2: return "ISO-8859-2"; + case cp_iso_8859_3: return "ISO-8859-3"; + case cp_iso_8859_4: return "ISO-8859-4"; + case cp_iso_8859_5: return "ISO-8859-5"; + case cp_iso_8859_6: return "ISO-8859-6"; + case cp_iso_8859_6i: return "ISO-8859-6"; + case cp_iso_8859_7: return "ISO-8859-7"; + case cp_iso_8859_8: return "ISO-8859-8"; + case cp_iso_8859_8i: return "ISO-8859-8"; + case cp_iso_8859_9: return "ISO-8859-9"; + case cp_johab: return "JOHAB"; + case cp_koi8_r: return "KOI8-R"; + case cp_koi8_u: return "KOI8-U"; + case cp_macarabic: return "MACARABIC"; + case cp_macchinese1: return "BIG5"; + case cp_macchinese2: return "EUC-CN"; + case cp_maccroatian: return "MACCROATIAN"; + case cp_maccyrillic: return "MACCYRILLIC"; + case cp_macgreek: return "MACGREEK"; + case cp_machebrew: return "MACHEBREW"; + case cp_maciceland: return "MACICELAND"; + case cp_macjapanese: return "SHIFT-JIS"; + case cp_mackorean: return "EUC-KR"; + case cp_macroman2: return "MACCENTRALEUROPE"; + case cp_macroman: return "MACINTOSH"; + case cp_macromania: return "MACROMANIA"; + case cp_macthai: return "MACTHAI"; + case cp_macturkish: return "MACTURKISH"; + case cp_macukraine: return "MACUKRAINE"; + case cp_shift_jis: return "SHIFT-JIS"; + case cp_t61: return "T.61"; + case cp_uhc: return "UHC"; + case cp_utf7: return "UTF-7"; + case cp_utf8: return "UTF-8"; + case cp_utf16be: return "UTF-16BE"; + case cp_utf16le: return "UTF-16LE"; // "UTF-16" is platform-dependent without a BOM + case cp_utf32be: return "UTF-32BE"; + case cp_utf32le: return "UTF-32LE"; + case cp_wansung: return "EUC-KR"; + case cp_windows1250: return "MS-EE"; + case cp_windows1251: return "MS-CYRL"; + case cp_windows1252: return "MS-ANSI"; + case cp_windows1253: return "MS-GREEK"; + case cp_windows1254: return "MS-TURK"; + case cp_windows1255: return "MS-HEBR"; + case cp_windows1256: return "MS-ARAB"; default: return NULL; } } +//! Check if a codepage is known to be a superset of ASCII - used for optimization only +bool is_extended_ascii(codepage_id codepage) { + + // cp_utf8 is handled separately + + if(codepage >= cp_windows1250 && codepage <= cp_windows1270) { + return true; + } + + if(codepage >= cp_iso_8859_1 && codepage <= cp_iso_8859_15) { + return true; + } + + switch(codepage) { + case cp_ascii: + case cp_big5: + case cp_big5_eten: + case cp_big5_hkscs: + case cp_cns: + case cp_dos708: + case cp_euc_cn: + case cp_euc_tw: + case cp_gb18030: + case cp_gbk: + case cp_iso_6937: + case cp_iso_8859_6i: + case cp_iso_8859_8i: + case cp_koi8_r: + case cp_koi8_u: + case cp_macarabic: + case cp_macchinese1: + case cp_macchinese2: + case cp_maccyrillic: + case cp_macgreek: + case cp_maciceland: + case cp_macroman: + case cp_uhc: + case cp_windows874: + return true; + default: + return false; + } + +} + +bool is_ascii(const std::string & data) { + // String in an extended ASCII encoding contains only ASCII characters + BOOST_FOREACH(char c, data) { + if(boost::uint8_t(c) >= 128) { + return false; + } + } + return true; +} + +//! Check if a string is compatible with UTF-8 +bool is_utf8(const std::string & data, codepage_id codepage) { + + if(codepage == cp_utf8 || codepage == cp_ascii) { + return true; + } + + if(is_extended_ascii(codepage) && is_ascii(data)) { + return true; + } + + return false; +} + typedef boost::uint32_t unicode_char; const unicode_char replacement_char = '_'; -size_t get_encoding_size(codepage_id codepage) { +size_t get_code_unit_size(codepage_id codepage) { switch(codepage) { - case 1200: return 2u; // UTF-16LE - case 1201: return 2u; // UTF-16BE - case 12000: return 4u; // UTF-32LE - case 12001: return 4u; // UTF-32BE + case cp_utf16le: return 2u; + case cp_utf16be: return 2u; + case cp_utf32le: return 4u; + case cp_utf32be: return 4u; default: return 1u; } } @@ -178,12 +276,12 @@ //! Fallback conversion that will at least work for ASCII characters void to_utf8_fallback(const std::string & from, std::string & to, codepage_id codepage) { - size_t skip = get_encoding_size(codepage); + size_t skip = get_code_unit_size(codepage); size_t shift = 0; switch(codepage) { - case 1201: shift = 1u * 8u; break; // UTF-16BE - case 12001: shift = 3u * 8u; break; // UTF-32BE + case cp_utf16be: shift = 1u * 8u; break; + case cp_utf32be: shift = 3u * 8u; break; default: break; } @@ -324,7 +422,9 @@ return chr >= 0xdc00 && chr <= 0xdfff; } -void utf16le_to_utf8(const std::string & from, std::string & to) { +} // anonymous namespace + +void utf16le_to_wtf8(const std::string & from, std::string & to) { if(from.size() % 2 != 0) { log_warning << "Unexpected trailing byte in UTF-16 string."; @@ -337,49 +437,30 @@ std::string::const_iterator it = from.begin(); std::string::const_iterator end = from.end(); + if(from.size() % 2 != 0) { + --end; + } while(it != end) { unicode_char chr = boost::uint8_t(*it++); - if(it == end) { - warn = true; - utf8_write(to, replacement_char); - break; - } chr |= unicode_char(boost::uint8_t(*it++)) << 8; // If it's a surrogate pair, convert to a single UTF-32 character - if(is_utf16_high_surrogate(chr)) { - if(it == end) { - warn = true; - utf8_write(to, replacement_char); - break; - } - unicode_char d = boost::uint8_t(*it++); - if(it == end) { - warn = true; - utf8_write(to, replacement_char); - break; - } - d |= unicode_char(boost::uint8_t(*it++)) << 8; + if(is_utf16_high_surrogate(chr) && it != end) { + unicode_char d = boost::uint8_t(*it); + d |= unicode_char(boost::uint8_t(*(it + 1))) << 8; if(is_utf16_low_surrogate(d)) { chr = ((chr - 0xd800) << 10) + (d - 0xdc00) + 0x0010000; - } else { - warn = true; - utf8_write(to, replacement_char); - continue; + it += 2; } } - // Replace invalid characters - if(chr > 0x0010FFFF) { - warn = true; - // Invalid character (greater than the maximum unicode value) - utf8_write(to, replacement_char); - continue; - } - utf8_write(to, chr); } + if(end != from.end()) { + warn = true; + utf8_write(to, replacement_char); + } if(warn) { log_warning << "Unexpected data while converting from UTF-16LE to UTF-8."; @@ -387,21 +468,16 @@ } -void utf8_to_utf16le(const std::string & from, std::string & to) { +void wtf8_to_utf16le(const std::string & from, std::string & to) { to.clear(); to.reserve(from.size() * 2); // optimistically, most strings only have ASCII characters - bool warn = false; - for(std::string::const_iterator i = from.begin(); i != from.end(); ) { unicode_char chr = utf8_read(i, from.end()); - if((chr >= 0xd800 && chr <= 0xdfff) || chr > 0x10ffff) { - chr = replacement_char; - warn = true; - } else if(chr >= 0x10000) { + if(chr >= 0x10000) { chr -= 0x10000; unicode_char high_surrogate = 0xd800 + (chr >> 10); to.push_back(char(boost::uint8_t(high_surrogate))); @@ -413,12 +489,10 @@ to.push_back(char(boost::uint8_t(chr >> 8))); } - if(warn) { - log_warning << "Unexpected data while converting from UTF-8 to UTF-16LE."; - } - } +namespace { + unicode_char windows1252_replacements[] = { 0x20ac, replacement_char, 0x201a, 0x192, 0x201e, 0x2026, 0x2020, 0x2021, 0x2c6, 0x2030, 0x160, 0x2039, 0x152, replacement_char, 0x17d, replacement_char, @@ -466,14 +540,14 @@ // Windows-1252 maps almost directly to Unicode - yay! if(chr >= 256 || (chr >= 128 && chr < 160)) { - size_t i = 0; - for(; i < size_t(boost::size(windows1252_replacements)); i++) { - if(chr == windows1252_replacements[i] && windows1252_replacements[i] != replacement_char) { + size_t j = 0; + for(; j < size_t(boost::size(windows1252_replacements)); j++) { + if(chr == windows1252_replacements[j] && windows1252_replacements[j] != replacement_char) { break; } } - if(i < size_t(boost::size(windows1252_replacements))) { - chr = unicode_char(128 + i); + if(j < size_t(boost::size(windows1252_replacements))) { + chr = unicode_char(128 + j); } else { chr = replacement_char; warn = true; @@ -494,10 +568,12 @@ typedef boost::unordered_map converter_map; converter_map converters; -iconv_t get_converter(codepage_id codepage) { +iconv_t get_converter(codepage_id codepage, bool reverse) { + + boost::uint32_t key = codepage | (reverse ? 0x80000000 : 0); // Try to reuse an existing converter if possible - converter_map::const_iterator i = converters.find(codepage); + converter_map::const_iterator i = converters.find(key); if(i != converters.end()) { return i->second; } @@ -506,7 +582,7 @@ const char * encoding = get_encoding_name(codepage); if(encoding) { - handle = iconv_open("UTF-8", encoding); + handle = reverse ? iconv_open(encoding, "UTF-8") : iconv_open("UTF-8", encoding); } // Otherwise, try a few different codepage name prefixes @@ -515,7 +591,7 @@ BOOST_FOREACH(const char * prefix, prefixes) { std::ostringstream oss; oss << prefix << std::setfill('0') << std::setw(3) << codepage; - handle = iconv_open("UTF-8", oss.str().c_str()); + handle = reverse ? iconv_open(oss.str().c_str(), "UTF-8") : iconv_open("UTF-8", oss.str().c_str()); if(handle != iconv_t(-1)) { break; } @@ -526,12 +602,12 @@ log_warning << "Could not get codepage " << codepage << " -> UTF-8 converter."; } - return converters[codepage] = handle; + return converters[key] = handle; } -bool to_utf8_iconv(const std::string & from, std::string & to, codepage_id codepage) { +bool utf8_iconv(const std::string & from, std::string & to, codepage_id codepage, bool reverse) { - iconv_t converter = get_converter(codepage); + iconv_t converter = get_converter(codepage, reverse); if(converter == iconv_t(-1)) { return false; } @@ -554,7 +630,7 @@ iconv(converter, NULL, NULL, NULL, NULL); - size_t skip = get_encoding_size(codepage); + size_t skip = get_code_unit_size(codepage); bool warn = false; @@ -591,7 +667,11 @@ } if(warn) { - log_warning << "Unexpected data while converting from CP" << codepage << " to UTF-8."; + if(reverse) { + log_warning << "Unexpected data while converting from UTF-8 to CP" << codepage << "."; + } else { + log_warning << "Unexpected data while converting from CP" << codepage << " to UTF-8."; + } } to.resize(outbase); @@ -599,6 +679,14 @@ return true; } +bool to_utf8_iconv(const std::string & from, std::string & to, codepage_id codepage) { + return utf8_iconv(from, to, codepage, false); +} + +bool from_utf8_iconv(const std::string & from, std::string & to, codepage_id codepage) { + return utf8_iconv(from, to, codepage, true); +} + #endif // INNOEXTRACT_HAVE_ICONV #if INNOEXTRACT_HAVE_WIN32_CONV @@ -606,8 +694,7 @@ std::string windows_error_string(DWORD code) { char * error; DWORD n = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, - NULL, code, 0, reinterpret_cast(&error), 0, - NULL); + NULL, code, 0, reinterpret_cast(&error), 0, NULL); if(n == 0) { return "unknown"; } else { @@ -621,40 +708,41 @@ } bool to_utf8_win32(const std::string & from, std::string & to, codepage_id codepage) { - - int ret = 0; - + // Convert from the source codepage to UTF-16LE - const WCHAR * utf16; - int utf16_size; - std::vector buffer; - if(codepage == cp_utf16le) { - utf16 = reinterpret_cast(from.data()); - utf16_size = int(from.size()) / 2; - } else { - utf16_size = MultiByteToWideChar(codepage, 0, from.data(), int(from.length()), NULL, 0); - if(utf16_size > 0) { - buffer.resize(size_t(utf16_size)); - ret = MultiByteToWideChar(codepage, 0, from.data(), int(from.length()), - &buffer.front(), utf16_size); - } - if(utf16_size <= 0 || ret <= 0) { - log_warning << "Error while converting from CP" << codepage << " to UTF-16: " - << windows_error_string(GetLastError()); - return false; - } - utf16 = &buffer.front(); + std::string buffer; + int ret = MultiByteToWideChar(codepage, 0, from.data(), int(from.length()), NULL, 0); + if(ret > 0) { + buffer.resize(size_t(ret) * 2); + ret = MultiByteToWideChar(codepage, 0, from.data(), int(from.length()), + reinterpret_cast(&buffer[0]), ret); } + if(ret <= 0) { + log_warning << "Error while converting from CP" << codepage << " to UTF-16: " + << windows_error_string(GetLastError()); + return false; + } + + utf16le_to_wtf8(buffer, to); + + return true; +} + +bool from_utf8_win32(const std::string & from, std::string & to, codepage_id codepage) { + + std::string buffer; + wtf8_to_utf16le(from, buffer); - // Convert from UTF-16LE to UTF-8 - int utf8_size = WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_size, NULL, 0, NULL, NULL); - if(utf8_size > 0) { - to.resize(size_t(utf8_size)); - ret = WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_size, - &to[0], utf8_size, NULL, NULL); + // Convert from UTF-16LE to the target codepage + LPCWSTR data = reinterpret_cast(buffer.c_str()); + int size = int(buffer.size() / 2); + int ret = WideCharToMultiByte(codepage, 0, data, size, NULL, 0, NULL, NULL); + if(ret > 0) { + to.resize(size_t(ret)); + ret = WideCharToMultiByte(codepage, 0, data, size, &to[0], ret, NULL, NULL); } - if(utf8_size <= 0 || ret <= 0) { - log_warning << "Error while converting from UTF-16 to UTF-8: " + if(ret <= 0) { + log_warning << "Error while converting from UTF-16 to CP" << codepage << ": " << windows_error_string(GetLastError()); return false; } @@ -664,22 +752,10 @@ #endif // INNOEXTRACT_HAVE_WIN32_CONV -} // anonymous namespace - void to_utf8(const std::string & from, std::string & to, codepage_id codepage) { - if(from.empty()) { - to.clear(); - return; - } - - if(codepage == cp_utf8 || codepage == cp_ascii) { - to = from; - return; - } - switch(codepage) { - case cp_utf16le: utf16le_to_utf8(from, to); return; + case cp_utf16le: utf16le_to_wtf8(from, to); return; case cp_windows1252: windows1252_to_utf8(from, to); return; case cp_iso_8859_1: windows1252_to_utf8(from, to); return; default: break; @@ -701,6 +777,20 @@ } +} // anonymous namespace + +void to_utf8(std::string & data, codepage_id codepage) { + + if(data.empty() || is_utf8(data, codepage)) { + // Already UTF-8 + return; + } + + std::string buffer; + to_utf8(data, buffer, codepage); + std::swap(data, buffer); +} + void from_utf8(const std::string & from, std::string & to, codepage_id codepage) { if(from.empty()) { @@ -708,21 +798,32 @@ return; } - if(codepage == cp_utf8) { + if(codepage == cp_utf8 || (is_extended_ascii(codepage) && is_ascii(from))) { to = from; return; } switch(codepage) { - case cp_utf16le: utf8_to_utf16le(from, to); return; + case cp_utf16le: wtf8_to_utf16le(from, to); return; case cp_windows1252: utf8_to_windows1252(from, to); return; - case cp_iso_8859_1: utf8_to_windows1252(from, to); return; - default: { - log_warning << "Unsupported output codepage: " << codepage; - to = from; - } + default: break; } + #if INNOEXTRACT_HAVE_ICONV + if(from_utf8_iconv(from, to, codepage)) { + return; + } + #endif + + #if INNOEXTRACT_HAVE_WIN32_CONV + if(from_utf8_win32(from, to, codepage)) { + return; + } + #endif + + log_warning << "Unsupported output codepage: " << codepage; + to = from; + } std::string encoding_name(codepage_id codepage) { diff -Nru innoextract-1.7/src/util/encoding.hpp innoextract-1.8/src/util/encoding.hpp --- innoextract-1.7/src/util/encoding.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/encoding.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -32,17 +32,137 @@ namespace util { +enum known_codepages { + cp_dos708 = 708, // arabic + cp_windows874 = 874, // thai + cp_shift_jis = 932, // japanese + cp_gbk = 936, // chinese + cp_uhc = 949, // korean + cp_big5 = 950, // chinese + cp_big5_hkscs = 951, // chinese + cp_utf16le = 1200, + cp_utf16be = 1201, + cp_windows1250 = 1250, // latin + cp_windows1251 = 1251, // cyrillic + cp_windows1252 = 1252, // latin + cp_windows1253 = 1253, // greek + cp_windows1254 = 1254, // turkish + cp_windows1255 = 1255, // hebrew + cp_windows1256 = 1256, // arabic + cp_windows1257 = 1257, // baltic + cp_windows1258 = 1258, // vietnamese + cp_windows1270 = 1270, // sami + cp_johab = 1361, // korean + cp_macroman = 10000, // latin + cp_macjapanese = 10001, // japanese + cp_macchinese1 = 10002, // chinese + cp_mackorean = 10003, // korean + cp_macarabic = 10004, // arabic + cp_machebrew = 10005, // hebrew + cp_macgreek = 10006, // greek + cp_maccyrillic = 10007, // cyrillic + cp_macchinese2 = 10008, // chinese + cp_macromania = 10010, // latin + cp_macukraine = 10017, // cyrillic + cp_macthai = 10021, // thai + cp_macroman2 = 10029, // latin + cp_maciceland = 10079, // latin + cp_macturkish = 10081, // turkish + cp_maccroatian = 10082, // latin + cp_utf32le = 12000, + cp_utf32be = 12001, + cp_cns = 20000, // chinese + cp_big5_eten = 20002, // chinese + cp_ia5 = 20105, // latin + cp_ia5_de = 20106, // latin + cp_ia5_se2 = 20107, // latin + cp_ia5_no2 = 20108, // latin + cp_ascii = 20127, // latin + cp_t61 = 20261, // latin + cp_iso_6937 = 20269, // latin + cp_ibm273 = 20273, // latin + cp_ibm277 = 20277, // latin + cp_ibm278 = 20278, // latin + cp_ibm280 = 20280, // latin + cp_ibm284 = 20284, // latin + cp_ibm285 = 20285, // latin + cp_ibm290 = 20290, // japanese + cp_ibm297 = 20297, // latin + cp_ibm420 = 20420, // arabic + cp_ibm423 = 20423, // greek + cp_ibm424 = 20424, // hebrew + cp_ibm833 = 20833, // korean + cp_ibm838 = 20838, // thai + cp_koi8_r = 20866, // cyrillic + cp_ibm871 = 20871, // latin + cp_ibm880 = 20880, // cyrillic + cp_ibm905 = 20905, // turkish + cp_ibm924 = 20924, // latin + cp_euc_jp_ms = 20932, // japanese + cp_gb2312_80 = 20936, // chinese + cp_wansung = 20949, // korean + cp_ibm1025 = 21025, // cyrillic + cp_koi8_u = 21866, // cyrillic + cp_iso_8859_1 = 28591, // latin + cp_iso_8859_2 = 28592, // latin + cp_iso_8859_3 = 28593, // latin + cp_iso_8859_4 = 28594, // latin + cp_iso_8859_5 = 28595, // cyrillic + cp_iso_8859_6 = 28596, // arabic + cp_iso_8859_7 = 28597, // greek + cp_iso_8859_8 = 28598, // hebrew + cp_iso_8859_9 = 28599, // turkish + cp_iso_8859_10 = 28600, // latin + cp_iso_8859_11 = 28601, // thai + cp_iso_8859_13 = 28603, // baltic + cp_iso_8859_14 = 28604, // celtic + cp_iso_8859_15 = 28605, // latin + cp_europa3 = 29001, // latin + cp_iso_8859_6i = 38596, // hebrew + cp_iso_8859_8i = 38598, // hebrew + cp_iso_2022_jp = 50220, // japanese + cp_iso_2022_jp2 = 50221, // japanese + cp_iso_2022_jp3 = 50222, // japanese + cp_iso_2022_kr = 50225, // korean + cp_iso_2022_cn = 50227, // chinese + cp_iso_2022_cn2 = 50229, // chinese + cp_ibm930 = 50930, // japanese + cp_ibm931 = 50931, // japanese + cp_ibm933 = 50933, // korean + cp_ibm935 = 50935, // chinese + cp_ibm936 = 50936, // chinese + cp_ibm937 = 50937, // chinese + cp_ibm939 = 50939, // japanese + cp_euc_jp = 51932, // japanese + cp_euc_cn = 51936, // chinese + cp_euc_kr = 51949, // korean + cp_euc_tw = 51950, // chinese + cp_gb2312_hz = 52936, // chinese + cp_gb18030 = 54936, // chinese + cp_utf7 = 65000, + cp_utf8 = 65001, +}; + typedef boost::uint32_t codepage_id; /*! - * Convert a string to UTF-8 from a specified encoding. - * \param from The input string to convert. - * \param to The output for the converted string. + * Convert a possibly broken UTF-16 string to WTF-8, an extension of UTF-8. + */ +void utf16le_to_wtf8(const std::string & from, std::string & to); + +/*! + * Convert WTF-8 to UTF-16 while preserving unpaired surrogates. + */ +void wtf8_to_utf16le(const std::string & from, std::string & to); + +/*! + * Convert a string in place to UTF-8 from a specified encoding. + * \param data The input string to convert. * \param codepage The Windows codepage number for the input string encoding. * * \note This function is not thread-safe. */ -void to_utf8(const std::string & from, std::string & to, codepage_id codepage = 1252); +void to_utf8(std::string & data, codepage_id codepage = cp_windows1252); /*! * Convert a string from UTF-8 to a specified encoding. @@ -52,7 +172,7 @@ * * \note This function is not thread-safe. */ -void from_utf8(const std::string & from, std::string & to, codepage_id codepage = 1252); +void from_utf8(const std::string & from, std::string & to, codepage_id codepage = cp_windows1252); std::string encoding_name(codepage_id codepage); diff -Nru innoextract-1.7/src/util/flags.hpp innoextract-1.8/src/util/flags.hpp --- innoextract-1.7/src/util/flags.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/flags.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -83,6 +83,22 @@ return reinterpret_cast(_flags.any()); } + bool operator==(flags o) const { + return _flags == o._flags; + } + + bool operator!=(flags o) const { + return _flags != o._flags; + } + + bool operator==(Zero /* zero */) const { + return _flags == 0; + } + + bool operator!=(Zero /* zero */) const { + return _flags != 0; + } + flags operator~() const { return flags(~_flags); } diff -Nru innoextract-1.7/src/util/load.cpp innoextract-1.8/src/util/load.cpp --- innoextract-1.7/src/util/load.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/load.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -55,7 +55,8 @@ } void encoded_string::load(std::istream & is, std::string & target, codepage_id codepage) { - to_utf8(binary_string::load(is), target, codepage); + binary_string::load(is, target); + to_utf8(target, codepage); } unsigned to_unsigned(const char * chars, size_t count) { diff -Nru innoextract-1.7/src/util/load.hpp innoextract-1.8/src/util/load.hpp --- innoextract-1.7/src/util/load.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/load.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2016 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -91,11 +91,10 @@ codepage_id codepage; /*! - * \param target The std::string object to receive the loaded UTF-8 string. - * \param codepage The Windows codepage for the encoding of the stored string. + * \param target The std::string object to receive the loaded UTF-8 string. + * \param cp The Windows codepage for the encoding of the stored string. */ - encoded_string(std::string & target, codepage_id codepage) - : data(target), codepage(codepage) { } + encoded_string(std::string & target, codepage_id cp) : data(target), codepage(cp) { } /*! * Load and convert a length-prefixed string diff -Nru innoextract-1.7/src/util/log.cpp innoextract-1.8/src/util/log.cpp --- innoextract-1.7/src/util/log.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/log.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2015 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -51,3 +51,14 @@ } } + +std::streambuf * warning_suppressor::set_streambuf(std::streambuf * streambuf) { + return std::cerr.rdbuf(streambuf); +} + +void warning_suppressor::flush() { + restore(); + std::cerr << buffer.str(); + logger::total_warnings += warnings; + logger::total_errors += errors; +} diff -Nru innoextract-1.7/src/util/log.hpp innoextract-1.8/src/util/log.hpp --- innoextract-1.7/src/util/log.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/log.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2014 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -91,4 +91,60 @@ }; +class warning_storage { + +protected: + + +public: + +}; + +class warning_suppressor : public warning_storage { + + std::ostringstream buffer; + std::streambuf * streambuf; + size_t warnings; + size_t errors; + + static std::streambuf * set_streambuf(std::streambuf * streambuf); + +public: + + warning_suppressor() + : streambuf(set_streambuf(buffer.rdbuf())) + , warnings(logger::total_warnings) + , errors(logger::total_errors) + { } + + ~warning_suppressor() { + restore(); + } + + void restore() { + + if(!streambuf) { + return; + } + + set_streambuf(streambuf); + streambuf = NULL; + + size_t new_warnings = logger::total_warnings - warnings; + size_t new_errors = logger::total_errors - errors; + logger::total_warnings = warnings; + logger::total_errors = errors; + warnings = new_warnings; + errors = new_errors; + + } + + void flush(); + + operator bool() { + return buffer.tellp() != std::ostringstream::pos_type(0); + } + +}; + #endif // INNOEXTRACT_UTIL_LOG_HPP diff -Nru innoextract-1.7/src/util/output.hpp innoextract-1.8/src/util/output.hpp --- innoextract-1.7/src/util/output.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/output.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2018 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -148,7 +148,7 @@ const char * data; size_t size; - explicit print_hex_string(const char * data, size_t size) : data(data), size(size) { } + explicit print_hex_string(const char * string, size_t length) : data(string), size(length) { } }; @@ -202,7 +202,7 @@ T value; int precision; - explicit print_bytes(T data, int precision = 3) : value(data), precision(precision) { } + explicit print_bytes(T data, int min_digits = 3) : value(data), precision(min_digits) { } bool operator==(const print_bytes & o) const { return value == o.value; } bool operator!=(const print_bytes & o) const { return value != o.value; } @@ -222,8 +222,7 @@ i++; } - if((whole >= 100 && s.precision <= 3) || (whole >= 10 && s.precision <= 2) - || s.precision <= 1) { + if((whole >= 100 && s.precision <= 3) || (whole >= 10 && s.precision <= 2) || s.precision <= 1) { os << whole; } else { float num = float(whole) + (float(frac) / 1024.f); diff -Nru innoextract-1.7/src/util/process.cpp innoextract-1.8/src/util/process.cpp --- innoextract-1.7/src/util/process.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/process.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Daniel Scharrer + * Copyright (C) 2013-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -37,6 +37,8 @@ #if INNOEXTRACT_HAVE_POSIX_SPAWNP #include +#if !INNOEXTRACT_HAVE_UNISTD_ENVIRON +extern "C" { #if defined(__FreeBSD__) && defined(__GNUC__) && __GNUC__ >= 4 /* * When combining -flto and -fvisibility=hidden we and up with a hidden @@ -46,7 +48,11 @@ #else extern char ** environ; #endif -#else +} +#endif +#endif + +#if INNOEXTRACT_HAVE_UNISTD_ENVIRON || (INNOEXTRACT_HAVE_FORK && INNOEXTRACT_HAVE_EXECVP) #include #endif @@ -60,6 +66,8 @@ #endif +#include "util/encoding.hpp" + namespace util { #if defined(_WIN32) || !(INNOEXTRACT_HAVE_POSIX_SPAWNP \ @@ -87,15 +95,6 @@ } #endif -#if defined(_WIN32) -static WCHAR * utf8_to_wchar(const char * string) { - int n = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0); - WCHAR * wstr = new WCHAR[n]; - MultiByteToWideChar(CP_UTF8, 0, string, -1, wstr, n); - return wstr; -} -#endif - int run(const char * const args[]) { std::cout.flush(); @@ -104,8 +103,12 @@ #if defined(_WIN32) // Format the command line arguments - WCHAR * exe = utf8_to_wchar(args[0]); - WCHAR * cmdline = utf8_to_wchar(format_command_line(args + 1).c_str()); + std::string exe; + wtf8_to_utf16le(args[0], exe); + exe.push_back('\0'); + std::string cmdline; + wtf8_to_utf16le(format_command_line(args + 1), exe); + cmdline.push_back('\0'); STARTUPINFO si; memset(&si, 0, sizeof(STARTUPINFO)); @@ -114,10 +117,8 @@ PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(PROCESS_INFORMATION)); - bool success = (CreateProcessW(exe, cmdline, 0, 0, 0, 0, 0, 0, &si, &pi) != 0); - - delete[] cmdline; - delete[] exe; + bool success = (CreateProcessW(reinterpret_cast(exe.c_str()), + reinterpret_cast(&cmdline[0]), 0, 0, 0, 0, 0, 0, &si, &pi) != 0); if(!success) { return -1; // Could not start process diff -Nru innoextract-1.7/src/util/storedenum.hpp innoextract-1.8/src/util/storedenum.hpp --- innoextract-1.7/src/util/storedenum.hpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/storedenum.hpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011-2017 Daniel Scharrer + * Copyright (C) 2011-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -167,19 +167,19 @@ flag_type get() { - boost::uint64_t bits = this->lower_bits(); + boost::uint64_t set_bits = this->lower_bits(); flag_type result = 0; for(size_t i = 0; i < this->size; i++) { - if(bits & (boost::uint64_t(1) << i)) { + if(set_bits & (boost::uint64_t(1) << i)) { result |= Mapping::values[i]; - bits &= ~(boost::uint64_t(1) << i); + set_bits &= ~(boost::uint64_t(1) << i); } } - if(bits) { + if(set_bits) { log_warning << "Unexpected " << enum_names::name << " flags: " - << std::hex << bits << std::dec; + << std::hex << set_bits << std::dec; } return result; @@ -204,7 +204,7 @@ const size_t pad_bits; - std::istream & is; + std::istream & stream; typedef boost::uint8_t stored_type; static const size_t stored_bits = sizeof(stored_type) * 8; @@ -218,15 +218,15 @@ public: - explicit stored_flag_reader(std::istream & _is, size_t pad_bits = 32) - : pad_bits(pad_bits), is(_is), pos(0), buffer(0), result(0), bytes(0) { } + explicit stored_flag_reader(std::istream & is, size_t padding_bits = 32) + : pad_bits(padding_bits), stream(is), pos(0), buffer(0), result(0), bytes(0) { } //! Declare the next possible flag. void add(enum_type flag) { if(pos == 0) { bytes++; - buffer = util::load(is); + buffer = util::load(stream); } if(buffer & (stored_type(1) << pos)) { @@ -239,7 +239,7 @@ operator flag_type() const { if(bytes == 3 && pad_bits == 32) { // 3-byte sets are padded to 4 bytes - (void)util::load(is); + (void)util::load(stream); } return result; } @@ -251,8 +251,8 @@ public: - explicit stored_flag_reader(std::istream & is, size_t pad_bits = 32) - : stored_flag_reader(is, pad_bits) { } + explicit stored_flag_reader(std::istream & is, size_t padding_bits = 32) + : stored_flag_reader(is, padding_bits) { } }; diff -Nru innoextract-1.7/src/util/time.cpp innoextract-1.8/src/util/time.cpp --- innoextract-1.7/src/util/time.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/time.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Daniel Scharrer + * Copyright (C) 2013-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -22,7 +22,7 @@ #include "configure.hpp" -#if INNOEXTRACT_HAVE_TIMEGM || INNOEXTRACT_HAVE_GMTIME_R +#if INNOEXTRACT_HAVE_TIMEGM || INNOEXTRACT_HAVE_GMTIME_R || defined(_WIN32) #include #endif @@ -68,14 +68,11 @@ static FILETIME to_filetime(time t, boost::uint32_t nsec = 0) { - static const boost::int64_t FiletimeOffset = 0x19DB1DED53E8000ll; - boost::int64_t time = boost::int64_t(t) * 10000000 + boost::int64_t(nsec) / 100; - - time += FiletimeOffset; + boost::int64_t filetime64 = boost::int64_t(t) * 10000000 + boost::int64_t(nsec) / 100 + FiletimeOffset; FILETIME filetime; - filetime.dwLowDateTime = DWORD(time); - filetime.dwHighDateTime = DWORD(time >> 32); + filetime.dwLowDateTime = DWORD(filetime64); + filetime.dwHighDateTime = DWORD(filetime64 >> 32); return filetime; } @@ -85,12 +82,12 @@ const char * variable = "TZ"; -#if defined(_WIN32) + #if defined(_WIN32) SetEnvironmentVariableA(variable, value); _tzset(); -#else + #else if(value) { setenv(variable, value, 1); @@ -99,7 +96,7 @@ } tzset(); -#endif + #endif } @@ -107,7 +104,7 @@ tm.tm_isdst = 0; -#if defined(_WIN32) + #if defined(_WIN32) // Windows @@ -126,13 +123,13 @@ } return from_filetime(ft); -#elif INNOEXTRACT_HAVE_TIMEGM + #elif INNOEXTRACT_HAVE_TIMEGM // GNU / BSD extension return timegm(&tm); -#else + #else // Standard, but not thread-safe - should be OK for our use though @@ -146,7 +143,7 @@ return ret; -#endif + #endif } @@ -166,7 +163,7 @@ std::tm ret; -#if defined(_WIN32) + #if defined(_WIN32) // Windows @@ -187,14 +184,14 @@ } ret.tm_isdst = -1; -#elif INNOEXTRACT_HAVE_GMTIME_R + #elif INNOEXTRACT_HAVE_GMTIME_R // POSIX.1 time_t tt = to_time_t(t); gmtime_r(&tt, &ret); -#else + #else // Standard C++ @@ -208,7 +205,7 @@ ret.tm_isdst = -1; } -#endif + #endif return ret; } @@ -216,11 +213,15 @@ time to_local_time(time t) { // Format time as UTC ... - std::tm time = format_time(t); + std::tm datetime = format_time(t); // ... and interpret it as local time - time.tm_isdst = 0; - return std::mktime(&time); + datetime.tm_isdst = 0; + #if defined(_WIN32) + return _mktime64(&datetime); + #else + return std::mktime(&datetime); + #endif } void set_local_timezone(std::string timezone) { @@ -260,8 +261,8 @@ bool set_file_time(const boost::filesystem::path & path, time sec, boost::uint32_t nsec) { -#if (INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT || INNOEXTRACT_HAVE_UTIMENSAT) \ - && INNOEXTRACT_HAVE_AT_FDCWD + #if (INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT || INNOEXTRACT_HAVE_UTIMENSAT) \ + && INNOEXTRACT_HAVE_AT_FDCWD // nanosecond precision, for Linux and POSIX.1-2008+ systems @@ -270,28 +271,28 @@ timens[0].tv_nsec = boost::int32_t(nsec); timens[1] = timens[0]; -#endif + #endif -#if INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD + #if INNOEXTRACT_HAVE_DYNAMIC_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD - static utimensat_proc utimensat_func = (utimensat_proc)dlsym(RTLD_DEFAULT, "utimensat"); + static utimensat_proc utimensat_func = reinterpret_cast(dlsym(RTLD_DEFAULT, "utimensat")); if(utimensat_func) { return (utimensat_func(AT_FDCWD, path.string().c_str(), timens, 0) == 0); } -#endif + #endif -#if INNOEXTRACT_HAVE_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD + #if INNOEXTRACT_HAVE_UTIMENSAT && INNOEXTRACT_HAVE_AT_FDCWD return (utimensat(AT_FDCWD, path.string().c_str(), timens, 0) == 0); -#elif defined(_WIN32) + #elif defined(_WIN32) // 100-nanosecond precision, for Windows // Prevent unused function warnings - (void)(HANDLE(*)(LPCSTR))open_file; - (void)(HANDLE(*)(LPCWSTR))open_file; + (void)static_cast(open_file); + (void)static_cast(open_file); HANDLE handle = open_file(path.c_str()); if(handle == INVALID_HANDLE_VALUE) { @@ -305,7 +306,7 @@ return ret; -#elif INNOEXTRACT_HAVE_UTIMES + #elif INNOEXTRACT_HAVE_UTIMES // microsecond precision, for older POSIX systems (4.3BSD, POSIX.1-2001) @@ -316,7 +317,7 @@ return (utimes(path.string().c_str(), times) == 0); -#else + #else // fallback with second precision or worse @@ -329,7 +330,7 @@ return false; } -#endif + #endif } diff -Nru innoextract-1.7/src/util/windows.cpp innoextract-1.8/src/util/windows.cpp --- innoextract-1.7/src/util/windows.cpp 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/src/util/windows.cpp 2019-09-15 07:52:37.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2016 Daniel Scharrer + * Copyright (C) 2013-2019 Daniel Scharrer * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -53,6 +54,7 @@ #endif #include "util/ansi.hpp" +#include "util/encoding.hpp" // Disable telemetry added in Visual Studio 2015 #if defined(_MSC_VER) && _MSC_VER >= 1900 @@ -374,10 +376,10 @@ public: - windows_console_sink(HANDLE handle, const utf8_codecvt * codecvt) - : handle(handle) + windows_console_sink(HANDLE console_handle, const utf8_codecvt * converter) + : handle(console_handle) , buffer(256) - , codecvt(codecvt) + , codecvt(converter) , initial_attributes(get_attributes()) , default_attributes(get_default_attributes()) , attributes(initial_attributes) @@ -505,17 +507,16 @@ // Convert the UTF-16 command-line parameters to UTF-8 int argc = 0; char ** argv = NULL; + std::vector args; { wchar_t ** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); - + args.resize(size_t(argc)); argv = new char *[argc + 1]; argv[argc] = NULL; - for(int i = 0; i < argc; i++) { - int n = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, NULL); - argv[i] = new char[n]; - WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], n, NULL, NULL); + for(size_t i = 0; i < args.size(); i++) { + util::utf16le_to_wtf8(std::string(reinterpret_cast(wargv[i]), wcslen(wargv[i]) * 2), args[i]); + argv[i] = &args[i][0]; } - LocalFree(wargv); } diff -Nru innoextract-1.7/VERSION innoextract-1.8/VERSION --- innoextract-1.7/VERSION 2018-06-12 18:50:34.000000000 +0000 +++ innoextract-1.8/VERSION 2019-09-15 07:52:37.000000000 +0000 @@ -1,7 +1,7 @@ -innoextract 1.7 +innoextract 1.8 Known working Inno Setup versions: -Inno Setup 1.2.10 to 5.6.0 +Inno Setup 1.2.10 to 6.0.2 Bug tracker: http://innoextract.constexpr.org/issues