Browse Source

Merge e8960a05ee into 6e9e34ed08

pull/205/merge
Charles Pigott 2 months ago committed by GitHub
parent
commit
f196211aeb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 142
      .github/workflows/ci.yml
  2. 3
      .gitignore
  3. 10
      CMakeLists.txt
  4. 2
      README.md
  5. 4
      VERSION
  6. 4
      cmake/BuildType.cmake
  7. 2
      src/cli/debug.cpp
  8. 4
      src/cli/extract.cpp
  9. 4
      src/crypto/checksum.cpp
  10. 80
      src/loader/offsets.cpp
  11. 5
      src/loader/offsets.hpp
  12. 4
      src/setup/component.cpp
  13. 20
      src/setup/data.cpp
  14. 46
      src/setup/file.cpp
  15. 18
      src/setup/file.hpp
  16. 144
      src/setup/header.cpp
  17. 38
      src/setup/header.hpp
  18. 86
      src/setup/info.cpp
  19. 8
      src/setup/info.hpp
  20. 33
      src/setup/issigkey.cpp
  21. 41
      src/setup/issigkey.hpp
  22. 43
      src/setup/language.cpp
  23. 2
      src/setup/language.hpp
  24. 4
      src/setup/task.cpp
  25. 10
      src/setup/version.cpp
  26. 6
      src/setup/version.hpp
  27. 31
      src/stream/block.cpp
  28. 4
      src/stream/chunk.hpp
  29. 67
      src/stream/slice.cpp
  30. 2
      src/stream/slice.hpp
  31. 61
      src/util/output.hpp

142
.github/workflows/ci.yml

@ -1,57 +1,97 @@
name: CI
name: Release
on:
workflow_dispatch:
push:
branches: [ master ]
pull_request:
branches: [ master ]
schedule:
- cron: '21 11 * * 5'
tags:
- '*'
jobs:
linux:
name: Linux build
runs-on: ubuntu-latest
build:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- name: Update
run: sudo apt-get update
- name: Dependencies
run: sudo apt-get install build-essential cmake libboost-all-dev liblzma-dev
- name: Configure
run: cmake --version && cmake -B ${{github.workspace}}/build -Werror=dev -Werror=deprecated -DCONTINUOUS_INTEGRATION=1
- name: Build
run: cmake --build ${{github.workspace}}/build
- name: Check Style
run: cmake --build ${{github.workspace}}/build --target style
macos:
name: macOS build
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Update
run: brew update
- name: Workaround for Python install isssues - https://github.com/actions/runner-images/issues/8838
run: brew install python@3 || brew link --overwrite python@3
- name: Dependencies
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
run: brew install boost xz
- name: Configure
run: cmake --version && cmake -B ${{github.workspace}}/build -Werror=dev -Werror=deprecated -DCONTINUOUS_INTEGRATION=1
- name: Build
run: cmake --build ${{github.workspace}}/build
- name: Checkout code
uses: actions/checkout@v4
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: >-
mingw-w64-x86_64-gcc
mingw-w64-x86_64-toolchain
base-devel
mingw-w64-x86_64-make
mingw-w64-x86_64-cmake
mingw-w64-x86_64-boost
mingw-w64-x86_64-zlib
mingw-w64-x86_64-bzip2
mingw-w64-x86_64-xz
- name: Build
run: |
mkdir build
cd build
cmake -G"MSYS Makefiles" \
-DUSE_LTO=OFF \
-DCMAKE_EXE_LINKER_FLAGS="-static -static-libgcc -static-libstdc++" \
-DCMAKE_BUILD_TYPE=Release \
-DUSE_STATIC_LIBS=ON \
-DBUILD_SHARED_LIBS=OFF ..
mingw32-make -j8
strip innoextract.exe
- name: Find and Copy Required DLLs
run: |
mkdir release
cp build/innoextract.exe release/
echo "Checking for missing DLL dependencies..."
ldd release/innoextract.exe | grep "not found" || true
echo "Copying necessary DLLs..."
for dll in $(ldd release/innoextract.exe | grep mingw64 | awk '{print $3}'); do
cp -v "$dll" release/ || true
done
echo "Final dependency check..."
ldd release/innoextract.exe | grep "not found" || true
- name: Package Binaries
shell: pwsh
run: |
$VERSION = if ($env:GITHUB_REF -match '^refs/tags/(.+)') { $matches[1] } else { 'dev' }
$ZIP_NAME = "innoextract$VERSION.zip"
Set-Location release
7z a "..\$ZIP_NAME" *
echo "UPLOAD_FILE=$ZIP_NAME" >> $env:GITHUB_ENV
$TAG = $VERSION
if ($TAG.Length -ge 3) {
$X = $TAG[0]
$Y = $TAG[1]
$Z = $TAG[2]
$INNO_VERSION = "$X.$Y.$Z"
} else {
$INNO_VERSION = "dev"
}
echo "INNO_VERSION=$INNO_VERSION" >> $env:GITHUB_ENV
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v2
#if: startsWith(github.ref, 'refs/tags/')
with:
name: Windows version
body: Latest innoextract Windows x64 build with support of Inno Setup installers up to version ${{ env.INNO_VERSION }}
files: ${{ env.UPLOAD_FILE }}
draft: false
prerelease: false
generate_release_notes: false

3
.gitignore vendored

@ -0,0 +1,3 @@
*.diff
*.cmd
build

10
CMakeLists.txt

@ -173,13 +173,17 @@ else()
set(INNOEXTRACT_HAVE_LZMA 0)
endif()
find_package(Boost REQUIRED COMPONENTS
set(BOOST_REQUIRED_COMPONENTS
iostreams
filesystem
date_time
system
program_options
)
find_package(Boost REQUIRED COMPONENTS ${BOOST_REQUIRED_COMPONENTS})
if(Boost_MAJOR_VERSION EQUAL 1 AND Boost_MINOR_VERSION LESS 69)
list(APPEND BOOST_REQUIRED_COMPONENTS system)
find_package(Boost REQUIRED COMPONENTS ${BOOST_REQUIRED_COMPONENTS})
endif()
list(APPEND LIBRARIES ${Boost_LIBRARIES})
link_directories(${Boost_LIBRARY_DIRS})
include_directories(SYSTEM ${Boost_INCLUDE_DIR})
@ -416,6 +420,8 @@ set(INNOEXTRACT_SOURCES
src/setup/info.cpp
src/setup/ini.hpp
src/setup/ini.cpp
src/setup/issigkey.hpp
src/setup/issigkey.cpp
src/setup/item.hpp
src/setup/item.cpp
src/setup/language.hpp

2
README.md

@ -1,7 +1,7 @@
# innoextract - A tool to unpack installers created by Inno Setup
[Inno Setup](https://jrsoftware.org/isinfo.php) is a tool to create installers for Microsoft Windows applications. innoextract allows to extract such installers under non-Windows systems without running the actual installer using wine. innoextract currently supports installers created by Inno Setup 1.2.10 to 6.3.3.
[Inno Setup](https://jrsoftware.org/isinfo.php) is a tool to create installers for Microsoft Windows applications. innoextract allows to extract such installers under non-Windows systems without running the actual installer using wine. innoextract currently supports installers created by Inno Setup 1.2.10 to 6.5.4.
In addition to standard Inno Setup installers, innoextract also supports some modified Inno Setup variants including Martijn Laan's My Inno Setup Extensions 1.3.10 to 3.0.6.1 as well as GOG.com's Inno Setup-based game installers. innoextract is able to unpack Wadjet Eye Games installers (to play with AGS), Arx Fatalis patches (for use with Arx Libertatis) as well as various other Inno Setup executables.

4
VERSION

@ -1,7 +1,7 @@
innoextract 1.10-dev
innoextract 1.11-dev
Known working Inno Setup versions:
Inno Setup 1.2.10 to 6.3.3
Inno Setup 1.2.10 to 6.5.4
Bug tracker:
https://innoextract.constexpr.org/issues

4
cmake/BuildType.cmake

@ -25,6 +25,10 @@ option(SET_OPTIMIZATION_FLAGS "Adjust compiler optimization flags" ON)
if(MSVC)
if(DEBUG)
add_compile_options(/MP /MT $<$<CONFIG:Debug>:/MTd>)
endif()
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")

2
src/cli/debug.cpp

@ -124,6 +124,8 @@ static void print_entry(const setup::info & info, size_t i,
std::cout << if_not_zero(" Dialog font size", entry.dialog_font_size);
std::cout << if_not_zero(" Dialog font standard height",
entry.dialog_font_standard_height);
std::cout << if_not_zero(" Dialog font scale height", entry.dialog_font_scale_height);
std::cout << if_not_zero(" Dialog font scale width", entry.dialog_font_scale_width);
std::cout << if_not_zero(" Title font size", entry.title_font_size);
std::cout << if_not_zero(" Welcome font size", entry.welcome_font_size);
std::cout << if_not_zero(" Copyright font size", entry.copyright_font_size);

4
src/cli/extract.cpp

@ -988,7 +988,7 @@ void process_file(const fs::path & installer, const extract_options & o) {
ifs.seekg(offsets.header_offset);
setup::info info;
try {
info.load(ifs, entries, o.codepage);
info.load(ifs, entries, o.codepage, offsets.revision);
} catch(const setup::version_error &) {
fs::path headerfile = installer;
headerfile.replace_extension(".0");
@ -1100,7 +1100,7 @@ void process_file(const fs::path & installer, const extract_options & o) {
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::uint64_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));

4
src/crypto/checksum.cpp

@ -90,8 +90,8 @@ std::ostream & operator<<(std::ostream & os, const crypto::checksum & checksum)
break;
}
case crypto::SHA256: {
for(size_t i = 0; i < size_t(boost::size(checksum.sha1)); i++) {
os << std::setfill('0') << std::hex << std::setw(2) << int(boost::uint8_t(checksum.sha1[i]));
for(size_t i = 0; i < size_t(boost::size(checksum.sha256)); i++) {
os << std::setfill('0') << std::hex << std::setw(2) << int(boost::uint8_t(checksum.sha256[i]));
}
break;
}

80
src/loader/offsets.cpp

@ -142,45 +142,67 @@ bool offsets::load_offsets_at(std::istream & is, boost::uint32_t pos) {
checksum.init();
checksum.update(magic, sizeof(magic));
if(version >= INNO_VERSION(5, 1, 5)) {
boost::uint32_t revision = checksum.load<boost::uint32_t>(is);
revision = 1;
if(version >= INNO_VERSION(5, 1, 5)) {
revision = checksum.load<boost::uint32_t>(is);
if(is.fail()) {
is.clear();
debug("could not read loader header revision");
return false;
} else if(revision != 1) {
} else if(revision != 1 && revision != 2) {
log_warning << "Unexpected setup loader revision: " << revision;
}
}
(void)checksum.load<boost::uint32_t>(is);
exe_offset = checksum.load<boost::uint32_t>(is);
if(version >= INNO_VERSION(4, 1, 6)) {
exe_compressed_size = 0;
} else {
exe_compressed_size = checksum.load<boost::uint32_t>(is);
}
exe_uncompressed_size = checksum.load<boost::uint32_t>(is);
if(version >= INNO_VERSION(4, 0, 3)) {
if(revision == 2) {
exe_offset = static_cast<boost::uint32_t>(checksum.load<boost::uint64_t>(is));
exe_uncompressed_size = static_cast<boost::uint32_t>(checksum.load<boost::uint64_t>(is));
exe_checksum.type = crypto::CRC32;
exe_checksum.crc32 = checksum.load<boost::uint32_t>(is);
} else {
exe_checksum.type = crypto::Adler32;
exe_checksum.adler32 = checksum.load<boost::uint32_t>(is);
}
if(version >= INNO_VERSION(4, 0, 0)) {
(void)checksum.load<boost::uint32_t>(is);
header_offset = static_cast<boost::uint32_t>(checksum.load<boost::uint64_t>(is));
data_offset = static_cast<boost::uint32_t>(checksum.load<boost::uint64_t>(is));
(void)checksum.load<boost::uint32_t>(is);
exe_compressed_size = 0;
message_offset = 0;
} else {
message_offset = util::load<boost::uint32_t>(is);
(void)checksum.load<boost::uint32_t>(is);
exe_offset = checksum.load<boost::uint32_t>(is);
if(version >= INNO_VERSION(4, 1, 6)) {
exe_compressed_size = 0;
} else {
exe_compressed_size = checksum.load<boost::uint32_t>(is);
}
exe_uncompressed_size = checksum.load<boost::uint32_t>(is);
if(version >= INNO_VERSION(4, 0, 3)) {
exe_checksum.type = crypto::CRC32;
exe_checksum.crc32 = checksum.load<boost::uint32_t>(is);
} else {
exe_checksum.type = crypto::Adler32;
exe_checksum.adler32 = checksum.load<boost::uint32_t>(is);
}
if(version >= INNO_VERSION(4, 0, 0)) {
message_offset = 0;
} else {
message_offset = util::load<boost::uint32_t>(is);
}
header_offset = checksum.load<boost::uint32_t>(is);
data_offset = checksum.load<boost::uint32_t>(is);
}
header_offset = checksum.load<boost::uint32_t>(is);
data_offset = checksum.load<boost::uint32_t>(is);
if(is.fail()) {
is.clear();
debug("could not read loader header");
@ -194,14 +216,18 @@ bool offsets::load_offsets_at(std::istream & is, boost::uint32_t pos) {
debug("could not read loader header checksum");
return false;
}
if(checksum.finalize() != expected) {
log_warning << "Setup loader checksum mismatch!";
boost::uint32_t actual = checksum.finalize();
if(actual != expected) {
log_warning << "Setup loader checksum mismatch! Expected: "
<< print_hex(expected)
<< " Actual: " << print_hex(actual);
}
}
return true;
}
void offsets::load(std::istream & is) {
found_magic = false;

5
src/loader/offsets.hpp

@ -55,6 +55,11 @@ struct offsets {
*/
bool found_magic;
/*!
* Marks 64 bit offset usage if 2
*/
boost::uint32_t revision;
/*!
* Offset of compressed `setup.e32` (the actual installer code)
*

4
src/setup/component.cpp

@ -74,7 +74,9 @@ void component_entry::load(std::istream & is, const info & i) {
} else {
extra_disk_pace_required = util::load<boost::uint32_t>(is);
}
if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(3, 0, 3))) {
if(i.version >= INNO_VERSION(6, 7, 0)) {
level = util::load<boost::uint8_t>(is);
} else if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(3, 0, 3))) {
level = util::load<boost::int32_t>(is);
} else {
level = 0;

20
src/setup/data.cpp

@ -55,8 +55,12 @@ void data_entry::load(std::istream & is, const info & i) {
chunk.first_slice--, chunk.last_slice--;
}
}
chunk.sort_offset = chunk.offset = util::load<boost::uint32_t>(is);
if(i.version >= INNO_VERSION(6, 5, 2)) {
chunk.sort_offset = chunk.offset = util::load<boost::uint64_t>(is);
} else {
chunk.sort_offset = chunk.offset = util::load<boost::uint32_t>(is);
}
if(i.version >= INNO_VERSION(4, 0, 1)) {
file.offset = util::load<boost::uint64_t>(is);
@ -136,20 +140,22 @@ void data_entry::load(std::istream & is, const info & i) {
stored_flag_reader<flags> flagreader(is, i.version.bits());
flagreader.add(VersionInfoValid);
flagreader.add(VersionInfoNotValid);
if(i.version < INNO_VERSION(6, 4, 3)) {
flagreader.add(VersionInfoNotValid);
}
if(i.version >= INNO_VERSION(2, 0, 17) && i.version < INNO_VERSION(4, 0, 1)) {
flagreader.add(BZipped);
}
if(i.version >= INNO_VERSION(4, 0, 10)) {
flagreader.add(TimeStampInUTC);
}
if(i.version >= INNO_VERSION(4, 1, 0)) {
if(i.version >= INNO_VERSION(4, 1, 0) && i.version < INNO_VERSION(6, 4, 3)) {
flagreader.add(IsUninstallerExe);
}
if(i.version >= INNO_VERSION(4, 1, 8)) {
flagreader.add(CallInstructionOptimized);
}
if(i.version >= INNO_VERSION(4, 2, 0)) {
if(i.version >= INNO_VERSION(4, 2, 0) && i.version < INNO_VERSION(6, 4, 3)) {
flagreader.add(Touch);
}
if(i.version >= INNO_VERSION(4, 2, 2)) {
@ -160,7 +166,7 @@ void data_entry::load(std::istream & is, const info & i) {
} else {
options |= ChunkCompressed;
}
if(i.version >= INNO_VERSION(5, 1, 13)) {
if(i.version >= INNO_VERSION(5, 1, 13) && i.version < INNO_VERSION(6, 4, 3)) {
flagreader.add(SolidBreak);
}
if(i.version >= INNO_VERSION(5, 5, 7) && i.version < INNO_VERSION(6, 3, 0)) {
@ -171,7 +177,7 @@ void data_entry::load(std::istream & is, const info & i) {
options |= flagreader.finalize();
if(i.version >= INNO_VERSION(6, 3, 0)) {
if(i.version >= INNO_VERSION(6, 3, 0) && i.version < INNO_VERSION(6, 4, 3)) {
sign = stored_enum<stored_sign_mode>(is).get();
} else if(options & SignOnce) {
sign = Once;

46
src/setup/file.cpp

@ -29,6 +29,11 @@
namespace setup {
namespace {
STORED_ENUM_MAP(stored_file_verification_type, file_entry::fvNone,
file_entry::fvNone,
file_entry::fvHash,
file_entry::fvISSig,
);
enum file_copy_mode {
cmNormal,
@ -60,6 +65,14 @@ STORED_ENUM_MAP(stored_file_type_1, file_entry::UserFile,
} // namespace setup
NAMED_ENUM(setup::file_entry::file_verification_type)
NAMES(setup::file_entry::file_verification_type, "File Verification Type",
"none",
"hash",
"IS sig",
)
NAMED_ENUM(setup::file_copy_mode)
NAMES(setup::file_copy_mode, "File Copy Mode",
@ -92,6 +105,26 @@ void file_entry::load(std::istream & is, const info & i) {
load_condition_data(is, i);
if(i.version >= INNO_VERSION(6, 5, 0)) {
is >> util::encoded_string(excludes, i.codepage, i.header.lead_bytes);
is >> util::encoded_string(download_issig_source, i.codepage, i.header.lead_bytes);
is >> util::encoded_string(download_user_name, i.codepage, i.header.lead_bytes);
is >> util::encoded_string(download_password, i.codepage, i.header.lead_bytes);
is >> util::encoded_string(extract_archive_password, i.codepage, i.header.lead_bytes);
// Verification structure
is >> util::ansi_string(issig_allowed_keys);
is.read(checksum.sha256, std::streamsize(sizeof(checksum.sha256)));
checksum.type = crypto::SHA256;
verification = stored_enum<stored_file_verification_type>(is).get();
} else {
excludes.clear();
download_issig_source.clear();
download_user_name.clear();
download_password.clear();
extract_archive_password.clear();
}
load_version_data(is, i.version);
location = util::load<boost::uint32_t>(is, i.version.bits());
@ -189,8 +222,19 @@ void file_entry::load(std::istream & is, const info & i) {
if(i.version >= INNO_VERSION(5, 2, 5)) {
flagreader.add(GacInstall);
}
if(i.version >= INNO_VERSION(6, 5, 0)) {
flagreader.add(Download);
flagreader.add(ExtractArchive);
}
options |= flagreader.finalize();
if(i.version >= INNO_VERSION(6, 7, 0)) {
// Inno forces the TSetupFileEntryOption enum to be 8 bytes,
// but currently only contains 5 bytes of values
(void)util::load<boost::uint8_t>(is);
(void)util::load<boost::uint8_t>(is);
(void)util::load<boost::uint8_t>(is);
}
if(i.version.bits() == 16 || i.version >= INNO_VERSION(5, 0, 0)) {
type = stored_enum<stored_file_type_0>(is).get();
@ -239,6 +283,8 @@ NAMES(setup::file_entry::flags, "File Option",
"set ntfs compression",
"unset ntfs compression",
"gac install",
"download",
"extract archive",
"readme",
)

18
src/setup/file.hpp

@ -77,11 +77,19 @@ struct file_entry : public item {
SetNtfsCompression,
UnsetNtfsCompression,
GacInstall,
Download,
ExtractArchive,
// obsolete options:
IsReadmeFile
);
enum file_verification_type {
fvNone,
fvHash,
fvISSig,
};
enum file_type {
UserFile,
UninstExe,
@ -96,6 +104,14 @@ struct file_entry : public item {
std::string destination;
std::string install_font_name;
std::string strong_assembly_name;
std::string excludes;
std::string download_issig_source;
std::string download_user_name;
std::string download_password;
std::string extract_archive_password;
std::string issig_allowed_keys;
file_verification_type verification;
boost::uint32_t location; //!< index into the data entry list
boost::uint32_t attributes;

144
src/setup/header.cpp

@ -51,11 +51,23 @@ STORED_ENUM_MAP(stored_log_mode, header::AppendLog,
header::OverwriteLog
);
STORED_ENUM_MAP(stored_light_control_styling, header::All,
header::All,
header::AllButButtons,
header::OnlyRequired
);
STORED_ENUM_MAP(stored_setup_style, header::ClassicStyle,
header::ClassicStyle,
header::ModernStyle
);
STORED_ENUM_MAP(stored_setup_dark_style, header::LightStyle,
header::LightStyle,
header::DarkStyle,
header::DynamicStyle
);
STORED_ENUM_MAP(stored_bool_auto_no_yes, header::Auto,
header::Auto,
header::No,
@ -266,6 +278,30 @@ void header::load(std::istream & is, const version & version) {
is >> util::binary_string(architectures_allowed_expr);
is >> util::binary_string(architectures_installed_in_64bit_mode_expr);
}
if(version >= INNO_VERSION(6, 4, 2)) {
is >> util::binary_string(close_applications_filter_excludes);
} else {
close_applications_filter_excludes.clear();
}
if(version >= INNO_VERSION(6, 5, 0)) {
is >> util::binary_string(seven_zip_library_name);
} else {
seven_zip_library_name.clear();
}
if(version >= INNO_VERSION(6, 7, 0)) {
std::string tmp;
is >> util::binary_string(use_previous_app_dir);
is >> util::binary_string(use_previous_group);
is >> util::binary_string(use_previous_setup_type);
is >> util::binary_string(use_previous_tasks);
is >> util::binary_string(use_previous_user_info);
} else {
use_previous_app_dir.clear();
use_previous_group.clear();
use_previous_setup_type.clear();
use_previous_tasks.clear();
use_previous_user_info.clear();
}
if(version >= INNO_VERSION(5, 2, 5)) {
is >> util::ansi_string(license_text);
is >> util::ansi_string(info_before);
@ -319,6 +355,11 @@ void header::load(std::istream & is, const version & version) {
}
directory_count = util::load<boost::uint32_t>(is, version.bits());
if(version >= INNO_VERSION(6, 5, 0)) {
issig_key_count = util::load<boost::uint32_t>(is);
} else {
issig_key_count = 0;
}
file_count = util::load<boost::uint32_t>(is, version.bits());
data_entry_count = util::load<boost::uint32_t>(is, version.bits());
icon_count = util::load<boost::uint32_t>(is, version.bits());
@ -350,6 +391,7 @@ void header::load(std::istream & is, const version & version) {
} else {
back_color2 = 0;
}
// added again in 6.6, see below
if(version < INNO_VERSION(5, 5, 7)) {
image_back_color = util::load<boost::uint32_t>(is);
} else {
@ -361,10 +403,14 @@ void header::load(std::istream & is, const version & version) {
small_image_back_color = 0;
}
if(version >= INNO_VERSION(6, 0, 0)) {
if(version >= INNO_VERSION(6, 6, 0)) {
wizard_resize_percent_x = util::load<boost::uint32_t>(is, version.bits());
wizard_resize_percent_y = util::load<boost::uint32_t>(is, version.bits());
wizard_dark_style = stored_enum<stored_setup_dark_style>(is).get();
} else if(version >= INNO_VERSION(6, 0, 0)) {
wizard_style = stored_enum<stored_setup_style>(is).get();
wizard_resize_percent_x = util::load<boost::uint32_t>(is);
wizard_resize_percent_y = util::load<boost::uint32_t>(is);
wizard_resize_percent_x = util::load<boost::uint32_t>(is, version.bits());
wizard_resize_percent_y = util::load<boost::uint32_t>(is, version.bits());
} else {
wizard_style = ClassicStyle;
wizard_resize_percent_x = 0;
@ -376,8 +422,28 @@ void header::load(std::istream & is, const version & version) {
} else {
image_alpha_format = AlphaIgnored;
}
if(version >= INNO_VERSION(6, 4, 0)) {
if(version >= INNO_VERSION(6, 7, 0)) {
image_back_color = util::load<boost::uint32_t>(is, version.bits());
small_image_back_color = util::load<boost::uint32_t>(is, version.bits());
back_color = util::load<boost::uint32_t>(is, version.bits());
image_back_color2 = util::load<boost::uint32_t>(is, version.bits());
small_image_back_color2 = util::load<boost::uint32_t>(is, version.bits());
back_color2 = util::load<boost::uint32_t>(is, version.bits());
image_opacity = util::load<boost::uint8_t>(is, version.bits());
back_image_opacity = util::load<boost::uint8_t>(is, version.bits());
wizard_light_control_styling = stored_enum<stored_light_control_styling>(is).get();
} else if(version >= INNO_VERSION(6, 6, 0)) {
image_back_color = util::load<boost::uint32_t>(is, version.bits());
small_image_back_color = util::load<boost::uint32_t>(is, version.bits());
image_back_color2 = util::load<boost::uint32_t>(is, version.bits());
small_image_back_color2 = util::load<boost::uint32_t>(is, version.bits());
}
if(version >= INNO_VERSION(6, 5, 0)) {
// moved to encryption header (read in setup::info::load)
password.type = crypto::PBKDF2_SHA256_XChaCha20;
} else if(version >= INNO_VERSION(6, 4, 0)) {
is.read(password.sha256, 4);
password.type = crypto::PBKDF2_SHA256_XChaCha20;
} else if(version >= INNO_VERSION(5, 3, 9)) {
@ -390,7 +456,9 @@ void header::load(std::istream & is, const version & version) {
password.crc32 = util::load<boost::uint32_t>(is);
password.type = crypto::CRC32;
}
if(version >= INNO_VERSION(6, 4, 0)) {
if(version >= INNO_VERSION(6, 5, 0)) {
// moved to encryption header (read in setup::info::load)
} else if(version >= INNO_VERSION(6, 4, 0)) {
password_salt.resize(44); // PBKDF2 salt + iteration count + ChaCha2 base nonce
is.read(&password_salt[0], std::streamsize(password_salt.length()));
} else if(version >= INNO_VERSION(4, 2, 2)) {
@ -527,6 +595,12 @@ void header::load(std::istream & is, const version & version) {
}
options |= load_flags(is, version);
if(version >= INNO_VERSION(6, 7, 0)) {
// Inno forces the TSetupHeaderOption enum to be 8 bytes,
// but currently only contains 6 bytes of values
(void)util::load<boost::uint8_t>(is);
(void)util::load<boost::uint8_t>(is);
}
if(version < INNO_VERSION(3, 0, 4)) {
privileges_required = (options & AdminPrivilegesRequired) ? AdminPriviliges : NoPrivileges;
@ -626,19 +700,20 @@ header::flags header::load_flags(std::istream & is, const version & version) {
if(version >= INNO_VERSION(1, 3, 0) && version < INNO_VERSION(5, 3, 8)) {
flagreader.add(CreateUninstallRegKey);
}
if(version >= INNO_VERSION(1, 3, 1)) {
if(version >= INNO_VERSION(1, 3, 1) && version < INNO_VERSION(6, 7, 0)) {
flagreader.add(UsePreviousAppDir);
}
if(version >= INNO_VERSION(1, 3, 3) && version < INNO_VERSION_EXT(6, 4, 0, 1)) {
flagreader.add(BackColorHorizontal);
}
if(version >= INNO_VERSION(1, 3, 10)) {
if(version >= INNO_VERSION(1, 3, 10) && version < INNO_VERSION(6, 7, 0)) {
flagreader.add(UsePreviousGroup);
}
if(version >= INNO_VERSION(1, 3, 20)) {
flagreader.add(UpdateUninstallLogAppName);
}
if(version >= INNO_VERSION(2, 0, 0) || (version.is_isx() && version >= INNO_VERSION(1, 3, 10))) {
if((version >= INNO_VERSION(2, 0, 0) || (version.is_isx() && version >= INNO_VERSION(1, 3, 10)))
&& version < INNO_VERSION(6, 7, 0)) {
flagreader.add(UsePreviousSetupType);
}
if(version >= INNO_VERSION(2, 0, 0)) {
@ -646,7 +721,9 @@ header::flags header::load_flags(std::istream & is, const version & version) {
flagreader.add(AlwaysShowComponentsList);
flagreader.add(FlatComponentsList);
flagreader.add(ShowComponentSizes);
flagreader.add(UsePreviousTasks);
if(version < INNO_VERSION(6, 7, 0)) {
flagreader.add(UsePreviousTasks);
}
flagreader.add(DisableReadyPage);
}
if(version >= INNO_VERSION(2, 0, 7)) {
@ -661,7 +738,9 @@ header::flags header::load_flags(std::istream & is, const version & version) {
}
if(version >= INNO_VERSION(3, 0, 0)) {
flagreader.add(UserInfoPage);
flagreader.add(UsePreviousUserInfo);
if(version < INNO_VERSION(6, 7, 0)) {
flagreader.add(UsePreviousUserInfo);
}
}
if(version >= INNO_VERSION(3, 0, 1)) {
flagreader.add(UninstallRestartComputer);
@ -690,7 +769,7 @@ header::flags header::load_flags(std::istream & is, const version & version) {
flagreader.add(AppendDefaultDirName);
flagreader.add(AppendDefaultGroupName);
}
if(version >= INNO_VERSION(4, 2, 2)) {
if(version >= INNO_VERSION(4, 2, 2) && version < INNO_VERSION(6, 5, 0)) {
flagreader.add(EncryptionUsed);
}
if(version >= INNO_VERSION(5, 0, 4) && version < INNO_VERSION(5, 6, 1)) {
@ -724,11 +803,27 @@ header::flags header::load_flags(std::istream & is, const version & version) {
if(version >= INNO_VERSION(6, 0, 0)) {
flagreader.add(AppNameHasConsts);
flagreader.add(UsePreviousPrivileges);
}
if(version >= INNO_VERSION(6, 0, 0) && version < INNO_VERSION(6, 6, 0)) {
flagreader.add(WizardResizable);
}
if(version >= INNO_VERSION(6, 3, 0)) {
flagreader.add(UninstallLogging);
}
if(version >= INNO_VERSION(6, 6, 0)) {
flagreader.add(WizardModern);
flagreader.add(WizardBorderStyled);
flagreader.add(WizardKeepAspectRatio);
}
if(version >= INNO_VERSION(6, 6, 0) && version < INNO_VERSION(6, 7, 0)) {
flagreader.add(WizardLightButtonsUnstyled);
}
if(version >= INNO_VERSION(6, 7, 0)) {
flagreader.add(RedirectionGuard);
flagreader.add(WizardBevelsHidden);
}
return flagreader.finalize();
}
@ -762,6 +857,8 @@ void header::decode(util::codepage_id codepage) {
util::to_utf8(create_uninstall_registry_key, codepage, &lead_bytes);
util::to_utf8(uninstallable, codepage);
util::to_utf8(close_applications_filter, codepage);
util::to_utf8(close_applications_filter_excludes, codepage);
util::to_utf8(seven_zip_library_name, codepage);
util::to_utf8(setup_mutex, codepage, &lead_bytes);
util::to_utf8(changes_environment, codepage);
util::to_utf8(changes_associations, codepage);
@ -808,7 +905,6 @@ NAMES(setup::header::flags, "Setup Option",
"wizard image stretch",
"append default dir name",
"append default group name",
"encrypted",
"changes environment",
"show undisplayable languages",
"setup logging",
@ -821,8 +917,13 @@ NAMES(setup::header::flags, "Setup Option",
"force close applications",
"app name_has_consts",
"use_previous_privileges",
"wizard_resizable",
"uninstall_logging",
"wizard_modern",
"wizard_border_styled",
"wizard_keep_aspect_ratio",
"redirection_guard",
"wizard_bevels_hidden",
"uninstallable",
"disable dir page",
"disable program group page",
@ -836,6 +937,9 @@ NAMES(setup::header::flags, "Setup Option",
"disable dir exists warning",
"back solid",
"overwrite uninst reg entries",
"encrypted",
"wizard_light_buttons_unstyled",
"wizard_resizable",
)
NAMES(setup::header::architecture_types, "Architecture",
@ -870,11 +974,23 @@ NAMES(setup::header::log_mode, "Uninstall Log Mode",
"overwrite",
)
NAMES(setup::header::light_control_styling, "Light Control Styling",
"all",
"all but buttons",
"only required",
)
NAMES(setup::header::style, "Style",
"classic",
"modern",
)
NAMES(setup::header::dark_style, "DarkStyle",
"light",
"dark",
"dynamic",
)
NAMES(setup::header::auto_bool, "Auto Boolean",
"auto",
"no",

38
src/setup/header.hpp

@ -87,7 +87,6 @@ struct header {
WizardImageStretch,
AppendDefaultDirName,
AppendDefaultGroupName,
EncryptionUsed,
ChangesEnvironment,
ShowUndisplayableLanguages,
SetupLogging,
@ -100,8 +99,12 @@ struct header {
ForceCloseApplications,
AppNameHasConsts,
UsePreviousPrivileges,
WizardResizable,
UninstallLogging,
WizardModern,
WizardBorderStyled,
WizardKeepAspectRatio,
RedirectionGuard,
WizardBevelsHidden,
// Obsolete flags
Uninstallable,
@ -116,7 +119,10 @@ struct header {
DetectLanguageUsingLocale,
DisableDirExistsWarning,
BackSolid,
OverwriteUninstRegEntries
OverwriteUninstRegEntries,
EncryptionUsed,
WizardLightButtonsUnstyled,
WizardResizable
);
@ -167,6 +173,13 @@ struct header {
std::string changes_associations;
std::string architectures_allowed_expr;
std::string architectures_installed_in_64bit_mode_expr;
std::string close_applications_filter_excludes;
std::string seven_zip_library_name;
std::string use_previous_app_dir;
std::string use_previous_group;
std::string use_previous_setup_type;
std::string use_previous_tasks;
std::string use_previous_user_info;
std::string license_text;
std::string info_before;
std::string info_after;
@ -182,6 +195,7 @@ struct header {
size_t component_count;
size_t task_count;
size_t directory_count;
size_t issig_key_count;
size_t file_count;
size_t data_entry_count;
size_t icon_count;
@ -198,13 +212,29 @@ struct header {
Color back_color;
Color back_color2;
Color image_back_color;
Color image_back_color2;
Color small_image_back_color;
Color small_image_back_color2;
uint8_t image_opacity;
uint8_t back_image_opacity;
enum light_control_styling {
All,
AllButButtons,
OnlyRequired,
};
light_control_styling wizard_light_control_styling;
enum style {
ClassicStyle,
ModernStyle
};
style wizard_style;
enum dark_style {
LightStyle,
DarkStyle,
DynamicStyle
};
dark_style wizard_dark_style;
boost::uint32_t wizard_resize_percent_x;
boost::uint32_t wizard_resize_percent_y;
@ -297,7 +327,9 @@ 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)
NAMED_ENUM(setup::header::light_control_styling)
NAMED_ENUM(setup::header::style)
NAMED_ENUM(setup::header::dark_style)
NAMED_ENUM(setup::header::auto_bool)
NAMED_ENUM(setup::header::privilege_level)
NAMED_ENUM(setup::header::language_detection_method)

86
src/setup/info.cpp

@ -30,6 +30,7 @@
#include "crypto/pbkdf2.hpp"
#include "crypto/sha256.hpp"
#include "crypto/xchacha20.hpp"
#include "crypto/crc32.hpp"
#include "setup/component.hpp"
#include "setup/data.hpp"
#include "setup/delete.hpp"
@ -38,6 +39,7 @@
#include "setup/icon.hpp"
#include "setup/ini.hpp"
#include "setup/item.hpp"
#include "setup/issigkey.hpp"
#include "setup/language.hpp"
#include "setup/message.hpp"
#include "setup/permission.hpp"
@ -110,6 +112,23 @@ void load_wizard_and_decompressor(std::istream & is, const setup::version & vers
if(version >= INNO_VERSION(2, 0, 0) || version.is_isx()) {
load_wizard_images(is, version, info.wizard_images_small, entries);
}
if(version >= INNO_VERSION(6, 7, 0))
{
load_wizard_images(is, version, info.wizard_images_back, entries);
}
// Duplicated dark mode versions
// TODO: figure out some way of specifying this
if(version >= INNO_VERSION(6, 6, 0)) {
load_wizard_images(is, version, info.wizard_images, entries);
load_wizard_images(is, version, info.wizard_images_small, entries);
}
if(version >= INNO_VERSION(6, 7, 0))
{
load_wizard_images(is, version, info.wizard_images_back, entries);
}
info.decompressor_dll.clear();
if(header.compression == stream::BZip2
@ -158,7 +177,7 @@ void info::try_load(std::istream & is, entry_types entries, util::codepage_id fo
debug("loading main header");
header.load(*reader, version);
debug("loading languages");
debug("loading " << header.language_count << " languages");
load_entries(*reader, entries, header.language_count, languages, Languages);
debug("determining encoding");
@ -192,34 +211,36 @@ void info::try_load(std::istream & is, entry_types entries, util::codepage_id fo
load_wizard_and_decompressor(*reader, version, header, *this, entries);
}
debug("loading messages");
debug("loading " << header.message_count << " messages");
load_entries(*reader, entries, header.message_count, messages, Messages);
debug("loading permissions");
debug("loading " << header.permission_count << " permissions");
load_entries(*reader, entries, header.permission_count, permissions, Permissions);
debug("loading types");
debug("loading " << header.type_count << " types");
load_entries(*reader, entries, header.type_count, types, Types);
debug("loading components");
debug("loading " << header.component_count << " components");
load_entries(*reader, entries, header.component_count, components, Components);
debug("loading tasks");
debug("loading " << header.task_count << " tasks");
load_entries(*reader, entries, header.task_count, tasks, Tasks);
debug("loading directories");
debug("loading " << header.directory_count << " directories");
load_entries(*reader, entries, header.directory_count, directories, Directories);
debug("loading files");
debug("loading " << header.issig_key_count << " issigs");
load_entries(*reader, entries, header.issig_key_count, issig_keys, ISSigs);
debug("loading " << header.file_count << " files");
load_entries(*reader, entries, header.file_count, files, Files);
debug("loading icons");
debug("loading " << header.icon_count << " icons");
load_entries(*reader, entries, header.icon_count, icons, Icons);
debug("loading ini entries");
debug("loading " << header.ini_entry_count << " ini entries");
load_entries(*reader, entries, header.ini_entry_count, ini_entries, IniEntries);
debug("loading registry entries");
debug("loading " << header.registry_entry_count << " registry entries");
load_entries(*reader, entries, header.registry_entry_count, registry_entries, RegistryEntries);
debug("loading delete entries");
debug("loading " << header.delete_entry_count << " delete entries");
load_entries(*reader, entries, header.delete_entry_count, delete_entries, DeleteEntries);
debug("loading uninstall delete entries");
debug("loading " << header.uninstall_delete_entry_count << " uninstall delete entries");
load_entries(*reader, entries, header.uninstall_delete_entry_count, uninstall_delete_entries,
UninstallDeleteEntries);
debug("loading run entries");
debug("loading " << header.run_entry_count << " run entries");
load_entries(*reader, entries, header.run_entry_count, run_entries, RunEntries);
debug("loading uninstall run entries");
debug("loading " << header.uninstall_run_entry_count << " uninstall run entries");
load_entries(*reader, entries, header.uninstall_run_entry_count, uninstall_run_entries,
UninstallRunEntries);
@ -238,10 +259,14 @@ void info::try_load(std::istream & is, entry_types entries, util::codepage_id fo
check_is_end(reader, "unknown data at end of secondary header stream");
}
void info::load(std::istream & is, entry_types entries, util::codepage_id force_codepage) {
void info::load(std::istream & is, entry_types entries, util::codepage_id force_codepage,
boost::uint32_t loader_revision) {
version.load(is);
if(loader_revision == 2 && version >= INNO_VERSION(6, 5, 0)) {
version.set_64bit();
}
if(!version.known) {
if(entries & NoUnknownVersion) {
std::ostringstream oss;
@ -263,6 +288,31 @@ void info::load(std::istream & is, entry_types entries, util::codepage_id force_
entries |= NoSkip;
}
if(version >= INNO_VERSION(6, 5, 0)) {
boost::uint32_t expected_encryption_crc = util::load<boost::uint32_t>(is);
crypto::crc32 checksum;
checksum.init();
boost::uint8_t encryption_use = checksum.load<boost::uint8_t>(is);
if(encryption_use != 0) {
log_error << "Unsupported encrypted setup";
}
for(int i = 0; i < 16; i++) {
/* KDFSalt */(void)checksum.load<boost::uint8_t>(is);
}
/* KDFIterations */(void)checksum.load<boost::uint32_t>(is);
/* BaseNonce.RandomXorStartOffset */(void)checksum.load<boost::uint64_t>(is);
/* BaseNonce.RandomXorFirstSlice */(void)checksum.load<boost::uint32_t>(is);
for(int i = 0; i < 3; i++) {
/* BaseNonce.RemainingRandom */(void)checksum.load<boost::uint32_t>(is);
}
/* PasswordTest */(void)checksum.load<boost::uint32_t>(is);
if(checksum.finalize() != expected_encryption_crc) {
log_warning << "Encryption header checksum mismatch!";
}
}
bool parsed_without_errors = false;
std::streampos start = is.tellg();
for(;;) {

8
src/setup/info.hpp

@ -31,6 +31,7 @@
#include "setup/header.hpp"
#include "setup/version.hpp"
#include "setup/issigkey.hpp"
#include "util/encoding.hpp"
#include "util/flags.hpp"
@ -40,6 +41,7 @@ struct component_entry;
struct data_entry;
struct delete_entry;
struct directory_entry;
struct issig_key_entry;
struct file_entry;
struct icon_entry;
struct ini_entry;
@ -66,6 +68,7 @@ struct info {
DeleteEntries,
UninstallDeleteEntries,
Directories,
ISSigs,
Files,
Icons,
IniEntries,
@ -95,6 +98,7 @@ struct info {
std::vector<delete_entry> delete_entries; //! \c DeleteEntries
std::vector<delete_entry> uninstall_delete_entries; //! \c UninstallDeleteEntries
std::vector<directory_entry> directories; //! \c Directories
std::vector<issig_key_entry> issig_keys; //! \c ISSigKeys
std::vector<file_entry> files; //! \c Files
std::vector<icon_entry> icons; //! \c Icons
std::vector<ini_entry> ini_entries; //! \c IniEntries
@ -111,6 +115,7 @@ struct info {
//! Loading enabled by \c WizardImages
std::vector<std::string> wizard_images;
std::vector<std::string> wizard_images_small;
std::vector<std::string> wizard_images_back;
//! Contents of the helper DLL used to decompress setup data in some versions.
//! Loading enabled by \c DecompressorDll
@ -130,7 +135,8 @@ struct info {
* \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, util::codepage_id force_codepage = 0);
void load(std::istream & is, entry_types entries, util::codepage_id force_codepage = 0,
boost::uint32_t loader_revision = 1);
std::string get_key(const std::string & password);

33
src/setup/issigkey.cpp

@ -0,0 +1,33 @@
/*
* Copyright (C) 2011-2025 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
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "setup/issigkey.hpp"
#include "setup/info.hpp"
#include "util/load.hpp"
namespace setup {
void issig_key_entry::load(std::istream & is, const info & i) {
is >> util::encoded_string(public_x, i.codepage);
is >> util::encoded_string(public_y, i.codepage);
is >> util::encoded_string(runtime_id, i.codepage);
}
} // namespace setup

41
src/setup/issigkey.hpp

@ -0,0 +1,41 @@
/*
* Copyright (C) 2011-2025 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
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef INNOEXTRACT_SETUP_ISSIGKEY_HPP
#define INNOEXTRACT_SETUP_ISSIGKEY_HPP
#include <string>
#include <iosfwd>
namespace setup {
struct info;
struct issig_key_entry {
std::string public_x;
std::string public_y;
std::string runtime_id;
void load(std::istream & is, const info & i);
};
} // namespace setup
#endif // INNOEXTRACT_SETUP_ISSIGKEY_HPP

43
src/setup/language.cpp

@ -140,9 +140,17 @@ void language_entry::load(std::istream & is, const info & i) {
}
is >> util::binary_string(dialog_font);
is >> util::binary_string(title_font);
if(i.version < INNO_VERSION(6, 6, 0)) {
is >> util::binary_string(title_font);
} else {
title_font.clear();
}
is >> util::binary_string(welcome_font);
is >> util::binary_string(copyright_font);
if(i.version < INNO_VERSION(6, 6, 0)) {
is >> util::binary_string(copyright_font);
} else {
copyright_font.clear();
}
if(i.version >= INNO_VERSION(4, 0, 0)) {
is >> util::binary_string(data);
@ -156,7 +164,11 @@ void language_entry::load(std::istream & is, const info & i) {
license_text.clear(), info_before.clear(), info_after.clear();
}
language_id = util::load<boost::uint32_t>(is);
if(i.version < INNO_VERSION(6, 6, 0)) {
language_id = util::load<boost::uint32_t>(is);
} else {
language_id = util::load<boost::uint16_t>(is);
}
if(i.version < INNO_VERSION(4, 2, 2)) {
codepage = default_codepage_for_language(language_id);
@ -165,10 +177,10 @@ void language_entry::load(std::istream & is, const info & i) {
if(!codepage) {
codepage = util::cp_windows1252;
}
} else if(i.version < INNO_VERSION(5, 3, 0)) {
(void)util::load<boost::uint32_t>(is);
codepage = util::cp_utf16le;
} else {
if(i.version < INNO_VERSION(5, 3, 0)) {
(void)util::load<boost::uint32_t>(is);
}
codepage = util::cp_utf16le;
}
@ -185,10 +197,25 @@ void language_entry::load(std::istream & is, const info & i) {
} else {
dialog_font_standard_height = 0;
}
if(i.version >= INNO_VERSION(6, 6, 0)) {
dialog_font_scale_height = util::load<boost::uint32_t>(is);
dialog_font_scale_width = util::load<boost::uint32_t>(is);
} else {
dialog_font_scale_height = dialog_font_scale_width = 0;
}
title_font_size = util::load<boost::uint32_t>(is);
if(i.version < INNO_VERSION(6, 6, 0)) {
title_font_size = util::load<boost::uint32_t>(is);
} else {
title_font_size = 0;
}
welcome_font_size = util::load<boost::uint32_t>(is);
copyright_font_size = util::load<boost::uint32_t>(is);
if(i.version < INNO_VERSION(6, 6, 0)) {
copyright_font_size = util::load<boost::uint32_t>(is);
} else {
copyright_font_size = 0;
}
if(i.version == INNO_VERSION_EXT(5, 5, 7, 1)) {
util::load<boost::uint32_t>(is); // always 8 or 9?

2
src/setup/language.hpp

@ -56,6 +56,8 @@ struct language_entry {
boost::uint32_t codepage;
size_t dialog_font_size;
size_t dialog_font_standard_height;
size_t dialog_font_scale_height;
size_t dialog_font_scale_width;
size_t title_font_size;
size_t welcome_font_size;
size_t copyright_font_size;

4
src/setup/task.cpp

@ -45,7 +45,9 @@ void task_entry::load(std::istream & is, const info & i) {
} else {
check.clear();
}
if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(3, 0, 3))) {
if(i.version >= INNO_VERSION(6, 7, 0)) {
level = util::load<boost::uint8_t>(is);
} else if(i.version >= INNO_VERSION(4, 0, 0) || (i.version.is_isx() && i.version >= INNO_VERSION(3, 0, 3))) {
level = util::load<boost::int32_t>(is);
} else {
level = 0;

10
src/setup/version.cpp

@ -186,6 +186,16 @@ const known_version versions[] = {
{ "Inno Setup Setup Data (6.3.0)", INNO_VERSION_EXT(6, 3, 0, 0), version::Unicode },
{ "Inno Setup Setup Data (6.4.0)", /* prerelease */ INNO_VERSION_EXT(6, 4, 0, 0), version::Unicode },
{ "Inno Setup Setup Data (6.4.0.1)", /* 6.4.0 */ INNO_VERSION_EXT(6, 4, 0, 1), version::Unicode },
{ "Inno Setup Setup Data (6.4.2)", INNO_VERSION_EXT(6, 4, 2, 0), version::Unicode },
{ "Inno Setup Setup Data (6.4.3)", INNO_VERSION_EXT(6, 4, 3, 0), version::Unicode },
{ "Inno Setup Setup Data (6.5.0)", INNO_VERSION_EXT(6, 5, 0, 0), version::Unicode },
{ "Inno Setup Setup Data (6.5.1)", INNO_VERSION_EXT(6, 5, 1, 0), version::Unicode },
{ "Inno Setup Setup Data (6.5.2)", INNO_VERSION_EXT(6, 5, 2, 0), version::Unicode },
{ "Inno Setup Setup Data (6.5.3)", INNO_VERSION_EXT(6, 5, 3, 0), version::Unicode },
{ "Inno Setup Setup Data (6.5.4)", INNO_VERSION_EXT(6, 5, 4, 0), version::Unicode },
{ "Inno Setup Setup Data (6.6.0)", INNO_VERSION_EXT(6, 6, 0, 0), version::Unicode },
{ "Inno Setup Setup Data (6.6.1)", INNO_VERSION_EXT(6, 6, 1, 0), version::Unicode },
{ "Inno Setup Setup Data (6.7.0)", INNO_VERSION_EXT(6, 7, 0, 0), version::Unicode },
};
} // anonymous namespace

6
src/setup/version.hpp

@ -51,7 +51,8 @@ struct version {
FLAGS(flags,
Bits16,
Unicode,
ISX
ISX,
Bits64
);
version_constant value;
@ -78,8 +79,11 @@ struct version {
void load(std::istream & is);
boost::uint16_t bits() const { return (variant & Bits16) ? 16 : 32; }
void set_64bit() { variant |= Bits64; }
bool is_unicode() const { return (variant & Unicode) != 0; }
bool is_isx() const { return (variant & ISX) != 0; }
bool is_64bit() const { return (variant & Bits64) != 0; }
//! \return true if the version stored might not be correct
bool is_ambiguous() const;

31
src/stream/block.cpp

@ -39,6 +39,7 @@
#include "setup/version.hpp"
#include "stream/lzma.hpp"
#include "util/endian.hpp"
#include "util/output.hpp"
#include "util/enum.hpp"
#include "util/load.hpp"
#include "util/log.hpp"
@ -154,20 +155,40 @@ block_reader::pointer block_reader::get(std::istream & base, const setup::versio
USE_ENUM_NAMES(block_compression)
#ifdef DEBUG
std::streamoff current_pos = base.tellg();
char dump_buffer[128];
std::streamsize bytes_read = base.read(dump_buffer, sizeof(dump_buffer)).gcount();
base.clear();
debug("block header at offset " << print_hex(current_pos) << ":");
debug(print_hex_dump(dump_buffer, std::size_t(bytes_read), std::size_t(current_pos)));
base.seekg(current_pos);
#endif
boost::uint32_t expected_checksum = util::load<boost::uint32_t>(base);
crypto::crc32 actual_checksum;
actual_checksum.init();
boost::uint32_t stored_size;
boost::uint64_t stored_size;
block_compression compression;
if(version >= INNO_VERSION(4, 0, 9)) {
stored_size = actual_checksum.load<boost::uint32_t>(base);
if(version >= INNO_VERSION(6, 7, 0)) {
stored_size = actual_checksum.load<boost::uint64_t>(base);
} else {
stored_size = actual_checksum.load<boost::uint32_t>(base);
}
boost::uint8_t compressed = actual_checksum.load<boost::uint8_t>(base);
#ifdef DEBUG
debug("" << (version.is_64bit() ? "64 bit offsets" : "32 bit offsets"));
debug("read stored_size: " << print_hex(stored_size) << " (" << stored_size << " bytes)");
debug("compressed flag: " << print_hex(boost::uint32_t(compressed)));
#endif
compression = compressed ? (version >= INNO_VERSION(4, 1, 6) ? LZMA1 : Zlib) : Stored;
} else {
boost::uint32_t compressed_size = actual_checksum.load<boost::uint32_t>(base);
@ -180,7 +201,7 @@ block_reader::pointer block_reader::get(std::istream & base, const setup::versio
}
// Add the size of a CRC32 checksum for each 4KiB subblock.
stored_size += boost::uint32_t(util::ceildiv<boost::uint64_t>(stored_size, 4096) * 4);
stored_size += util::ceildiv<boost::uint64_t>(stored_size, 4096) * 4;
}
if(actual_checksum.finalize() != expected_checksum) {
@ -204,7 +225,7 @@ block_reader::pointer block_reader::get(std::istream & base, const setup::versio
fis->push(inno_block_filter(), 4096);
fis->push(io::restrict(base, 0, stored_size));
fis->push(io::restrict(base, 0, static_cast<boost::uint32_t>(stored_size)));
fis->exceptions(std::ios_base::badbit | std::ios_base::failbit);

4
src/stream/chunk.hpp

@ -81,9 +81,9 @@ struct chunk {
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::uint64_t sort_offset;
boost::uint32_t offset; //!< Offset of the compressed chunk in firstSlice.
boost::uint64_t offset; //!< Offset of the compressed chunk in firstSlice.
boost::uint64_t size; //! Total compressed size of the chunk.
compression_method compression; //!< Compression method used by the chunk.

67
src/stream/slice.cpp

@ -46,6 +46,7 @@ namespace {
const char slice_ids[][8] = {
{ 'i', 'd', 's', 'k', 'a', '1', '6', 0x1a },
{ 'i', 'd', 's', 'k', 'a', '3', '2', 0x1a },
{ 'i', 'd', 's', 'k', 'b', '3', '2', 0x1a },
};
} // anonymous namespace
@ -109,31 +110,69 @@ bool slice_reader::open_file(const path_type & file) {
ifs.close();
throw slice_error("could not read slice magic number in \"" + file.string() + "\"");
}
bool found = false;
for(size_t i = 0; boost::size(slice_ids); i++) {
bool is_64bit_size = false;
for(size_t i = 0; i < boost::size(slice_ids); i++) {
if(!std::memcmp(magic, slice_ids[i], 8)) {
found = true;
if(magic[4] == 'b') {
is_64bit_size = true;
}
break;
}
}
if(!found) {
ifs.close();
throw slice_error("bad slice magic number in \"" + file.string() + "\"");
}
slice_size = util::load<boost::uint32_t>(ifs);
if(ifs.fail()) {
ifs.close();
throw slice_error("could not read slice size in \"" + file.string() + "\"");
} else if(std::streampos(slice_size) > file_size) {
ifs.close();
std::ostringstream oss;
oss << "bad slice size in " << file << ": " << slice_size << " > " << file_size;
throw slice_error(oss.str());
} else if(std::streampos(slice_size) < ifs.tellg()) {
std::streampos header_end_pos;
if(is_64bit_size) {
boost::uint64_t slice_size_64 = util::load<boost::uint64_t>(ifs);
if(ifs.fail()) {
ifs.close();
throw slice_error("could not read slice size in \"" + file.string() + "\"");
}
header_end_pos = ifs.tellg();
if(slice_size_64 > std::numeric_limits<boost::uint32_t>::max()) {
ifs.close();
throw slice_error("slice size exceeds 32-bit limit in \"" + file.string() + "\"");
}
slice_size = boost::uint32_t(slice_size_64);
if(slice_size_64 > boost::uint64_t(file_size)) {
ifs.close();
std::ostringstream oss;
oss << "bad slice size in " << file << ": " << slice_size_64 << " > " << file_size;
throw slice_error(oss.str());
}
} else {
slice_size = util::load<boost::uint32_t>(ifs);
if(ifs.fail()) {
ifs.close();
throw slice_error("could not read slice size in \"" + file.string() + "\"");
}
header_end_pos = ifs.tellg();
if(std::streampos(slice_size) > file_size) {
ifs.close();
std::ostringstream oss;
oss << "bad slice size in " << file << ": " << slice_size << " > " << file_size;
throw slice_error(oss.str());
}
}
if(std::streampos(slice_size) < header_end_pos) {
ifs.close();
std::ostringstream oss;
oss << "bad slice size in " << file << ": " << slice_size << " < " << ifs.tellg();
oss << "bad slice size in " << file << ": " << slice_size << " < " << header_end_pos;
throw slice_error(oss.str());
}
@ -208,7 +247,7 @@ void slice_reader::open(size_t slice) {
throw slice_error(oss.str());
}
bool slice_reader::seek(size_t slice, boost::uint32_t offset) {
bool slice_reader::seek(size_t slice, boost::uint64_t offset) {
seek(slice);
@ -218,7 +257,7 @@ bool slice_reader::seek(size_t slice, boost::uint32_t offset) {
return false;
}
if(is->seekg(offset).fail()) {
if(is->seekg(std::streamoff(offset)).fail()) {
return false;
}

2
src/stream/slice.hpp

@ -126,7 +126,7 @@ public:
* \return \c false if the requested slice could not be opened, or if the requested
* offset is not a valid position in that slice - \c true otherwise.
*/
bool seek(size_t slice, boost::uint32_t offset);
bool seek(size_t slice, boost::uint64_t offset);
/*!
* Read a number of bytes starting at the current slice and offset within that slice.

61
src/util/output.hpp

@ -182,6 +182,67 @@ inline detail::print_hex_string print_hex(const std::string & data) {
return print_hex(data.c_str(), data.size());
}
namespace detail {
struct print_hex_dump {
const char * data;
size_t size;
size_t start_offset;
size_t bytes_per_line;
explicit print_hex_dump(const char * buffer, size_t length, size_t offset = 0, size_t width = 16)
: data(buffer), size(length), start_offset(offset), bytes_per_line(width) { }
};
inline std::ostream & operator<<(std::ostream & os, const print_hex_dump & s) {
std::ios_base::fmtflags old = os.flags();
char oldfill = os.fill('0');
for(size_t i = 0; i < s.size; i += s.bytes_per_line) {
os << std::hex << std::setw(8) << (s.start_offset + i) << ": ";
size_t line_bytes = std::min(s.bytes_per_line, s.size - i);
for(size_t j = 0; j < s.bytes_per_line; j++) {
if(j < line_bytes) {
os << std::hex << std::setw(2) << int(boost::uint8_t(s.data[i + j])) << " ";
} else {
os << " ";
}
if(j == 7) os << " ";
}
os << " |";
for(size_t j = 0; j < line_bytes; j++) {
char c = s.data[i + j];
if(c >= 0x20 && c < 0x7F) {
os << c;
} else {
os << '.';
}
}
for(size_t j = line_bytes; j < s.bytes_per_line; j++) {
os << ' ';
}
os << "|\n";
}
os.fill(oldfill);
os.setf(old, std::ios_base::basefield);
return os;
}
} // namespace detail
inline detail::print_hex_dump print_hex_dump(const char * data, size_t size, size_t offset = 0, size_t width = 16) {
return detail::print_hex_dump(data, size, offset, width);
}
inline detail::print_hex_dump print_hex_dump(const std::string & data, size_t offset = 0, size_t width = 16) {
return print_hex_dump(data.c_str(), data.size(), offset, width);
}
const char * const byte_size_units[] = {
"B",
"KiB",

Loading…
Cancel
Save