Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 91 additions & 51 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.diff
*.cmd
build
10 changes: 8 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
4 changes: 2 additions & 2 deletions VERSION
Original file line number Diff line number Diff line change
@@ -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 changes: 4 additions & 0 deletions cmake/BuildType.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 2 additions & 0 deletions src/cli/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/cli/extract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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));
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/checksum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
80 changes: 53 additions & 27 deletions src/loader/offsets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions src/loader/offsets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
*
Expand Down
4 changes: 3 additions & 1 deletion src/setup/component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading