diff --git a/CMakeLists.txt b/CMakeLists.txt index 56427a4..fc47965 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,9 +40,11 @@ set(INNOEXTRACT_SOURCES src/SetupComponentEntry.cpp src/SetupHeader.cpp src/SetupLoader.cpp + src/SetupTaskEntry.cpp src/SetupTypeEntry.cpp src/Utils.cpp src/Version.cpp + src/WindowsVersion.cpp ) add_executable(innoextract ${INNOEXTRACT_SOURCES}) diff --git a/src/InnoExtract.cpp b/src/InnoExtract.cpp index cfc1024..b59c091 100644 --- a/src/InnoExtract.cpp +++ b/src/InnoExtract.cpp @@ -22,6 +22,7 @@ #include "PermissionEntry.hpp" #include "SetupTypeEntry.hpp" #include "SetupComponentEntry.hpp" +#include "SetupTaskEntry.hpp" using std::cout; using std::string; @@ -67,6 +68,8 @@ int main(int argc, char * argv[]) { return 1; } + cout << std::boolalpha; + cout << color::white; cout << "loaded offsets:" << endl; cout << "- total size: " << offsets.totalSize << endl; @@ -179,10 +182,8 @@ int main(int argc, char * argv[]) { cout << IfNotZero("Info before size", header.infoBeforeSize); cout << IfNotZero("Info after size", header.infoAfterSize); - cout << "Min version: " << header.minVersion << endl; - if(header.onlyBelowVersion.winVersion || header.onlyBelowVersion.ntVersion || header.onlyBelowVersion.ntServicePack) { - cout << "Only below version: " << header.onlyBelowVersion << endl; - } + cout << IfNot("Min version", header.minVersion, WindowsVersion::none); + cout << IfNot("Only below version", header.onlyBelowVersion, WindowsVersion::none); cout << hex; cout << IfNotZero("Back color", header.backColor); @@ -357,10 +358,8 @@ int main(int argc, char * argv[]) { cout << IfNotEmpty(" Languages", entry.languages); cout << IfNotEmpty(" Check", entry.check); - cout << " Min version: " << entry.minVersion << endl; - if(entry.onlyBelowVersion.winVersion || entry.onlyBelowVersion.ntVersion || entry.onlyBelowVersion.ntServicePack) { - cout << " Only below version: " << entry.onlyBelowVersion << endl; - } + cout << IfNot(" Min version", entry.minVersion, header.minVersion); + cout << IfNot(" Only below version", entry.onlyBelowVersion, header.onlyBelowVersion); cout << IfNotZero(" Options", entry.options); cout << IfNot(" Type", entry.type, SetupTypeEntry::User); @@ -376,7 +375,7 @@ int main(int argc, char * argv[]) { SetupComponentEntry entry; entry.load(is, version); if(is.fail()) { - error << "error reading type entry #" << i; + error << "error reading component entry #" << i; } cout << " - " << Quoted(entry.name) << ':' << endl; @@ -389,15 +388,41 @@ int main(int argc, char * argv[]) { cout << IfNotZero(" Level", entry.level); cout << IfNot(" Used", entry.used, true); - cout << " Min version: " << entry.minVersion << endl; - if(entry.onlyBelowVersion.winVersion || entry.onlyBelowVersion.ntVersion || entry.onlyBelowVersion.ntServicePack) { - cout << " Only below version: " << entry.onlyBelowVersion << endl; - } + cout << IfNot(" Min version", entry.minVersion, header.minVersion); + cout << IfNot(" Only below version", entry.onlyBelowVersion, header.onlyBelowVersion); cout << IfNotZero(" Options", entry.options); cout << IfNotZero(" Size", entry.size); }; + if(header.numTaskEntries) { + cout << endl << "Task entries:" << endl; + } + for(size_t i = 0; i < header.numTaskEntries; i++) { + + SetupTaskEntry entry; + entry.load(is, version); + if(is.fail()) { + error << "error reading task entry #" << i; + } + + cout << " - " << Quoted(entry.name) << ':' << endl; + cout << IfNotEmpty(" Description", entry.description); + cout << IfNotEmpty(" Group description", entry.groupDescription); + cout << IfNotEmpty(" Components", entry.components); + cout << IfNotEmpty(" Languages", entry.languages); + cout << IfNotEmpty(" Check", entry.check); + + cout << IfNotZero(" Level", entry.level); + cout << IfNot(" Used", entry.used, true); + + cout << IfNot(" Min version", entry.minVersion, header.minVersion); + cout << IfNot(" Only below version", entry.onlyBelowVersion, header.onlyBelowVersion); + + cout << IfNotZero(" Options", entry.options); + + }; + return 0; } diff --git a/src/SetupComponentEntry.cpp b/src/SetupComponentEntry.cpp index dd54cad..7582198 100644 --- a/src/SetupComponentEntry.cpp +++ b/src/SetupComponentEntry.cpp @@ -49,8 +49,12 @@ void SetupComponentEntry::load(std::istream & is, const InnoVersion & version) { extraDiskSpaceRequired = loadNumber(is); } - level = loadNumber(is); - used = loadNumber(is); + if(version >= INNO_VERSION(3, 0, 8)) { + level = loadNumber(is); + used = loadNumber(is); + } else { + level = 0, used = true; + } minVersion.load(is, version); onlyBelowVersion.load(is, version); diff --git a/src/SetupComponentEntry.hpp b/src/SetupComponentEntry.hpp index 5d87d3e..4ac1e0e 100644 --- a/src/SetupComponentEntry.hpp +++ b/src/SetupComponentEntry.hpp @@ -4,8 +4,9 @@ #include #include "Version.hpp" -#include "SetupHeader.hpp" +#include "WindowsVersion.hpp" #include "Flags.hpp" +#include "Enum.hpp" FLAGS(SetupComponentOptions, coFixed, @@ -30,10 +31,10 @@ struct SetupComponentEntry { u64 extraDiskSpaceRequired; int level; - bool used; - SetupVersionData minVersion, onlyBelowVersion; + WindowsVersion minVersion; + WindowsVersion onlyBelowVersion; SetupComponentOptions options; diff --git a/src/SetupHeader.cpp b/src/SetupHeader.cpp index 6617a61..38b4158 100644 --- a/src/SetupHeader.cpp +++ b/src/SetupHeader.cpp @@ -9,24 +9,6 @@ #include "SetupHeaderFormat.hpp" #include "Utils.hpp" -void SetupVersionData::load(std::istream & is, const InnoVersion & version) { - - if(version <= INNO_VERSION(1, 2, 16)) { // in 1.2.16, not in 1.3.25 - winVersion = loadNumber(is); - ntVersion = loadNumber(is); - ntServicePack = 0; - } else { - winVersion = loadNumber(is); - ntVersion = loadNumber(is); - ntServicePack = loadNumber(is); - } - -} - -std::ostream & operator<<(std::ostream & os, const SetupVersionData & svd) { - return os << " win " << svd.winVersion << " nt " << svd.ntVersion << " service pack " << svd.ntServicePack; -} - void SetupHeader::load(std::istream & is, const InnoVersion & version) { options = 0; diff --git a/src/SetupHeader.hpp b/src/SetupHeader.hpp index 304155c..666bb9f 100644 --- a/src/SetupHeader.hpp +++ b/src/SetupHeader.hpp @@ -10,17 +10,7 @@ #include "Flags.hpp" #include "Enum.hpp" #include "Version.hpp" - -struct SetupVersionData { - - s32 winVersion, ntVersion; // Cardinal - s16 ntServicePack; // Word - - void load(std::istream & is, const InnoVersion & version); - -}; - -std::ostream & operator<<(std::ostream & os, const SetupVersionData & svd); +#include "WindowsVersion.hpp" typedef char MD5Digest[16]; typedef char SHA1Digest[20]; @@ -192,8 +182,8 @@ struct SetupHeader { size_t infoBeforeSize; size_t infoAfterSize; - SetupVersionData minVersion; - SetupVersionData onlyBelowVersion; + WindowsVersion minVersion; + WindowsVersion onlyBelowVersion; Color backColor; Color backColor2; diff --git a/src/SetupTaskEntry.cpp b/src/SetupTaskEntry.cpp new file mode 100644 index 0000000..4ea726f --- /dev/null +++ b/src/SetupTaskEntry.cpp @@ -0,0 +1,58 @@ + +#include "SetupTaskEntry.hpp" + +#include "LoadingUtils.hpp" +#include "StoredEnum.hpp" + +STORED_FLAGS_MAP(StoredSetupTaskOptions0, + toExclusive, + toUnchecked, + toRestart, + toCheckedOnce, +); + +// starting with version 4.2.3 +STORED_FLAGS_MAP(StoredSetupTaskOptions1, + toExclusive, + toUnchecked, + toRestart, + toCheckedOnce, + toDontInheritCheck, +); + +void SetupTaskEntry::load(std::istream & is, const InnoVersion & version) { + + is >> EncodedString(name, version.codepage()); + is >> EncodedString(description, version.codepage()); + is >> EncodedString(groupDescription, version.codepage()); + is >> EncodedString(components, version.codepage()); + if(version >= INNO_VERSION(4, 0, 1)) { + is >> EncodedString(languages, version.codepage()); + } else { + languages.clear(); + } + if(version >= INNO_VERSION(3, 0, 8)) { + is >> EncodedString(check, version.codepage()); + level = loadNumber(is); + used = loadNumber(is); + } else { + check.clear(), level = 0, used = true; + } + + minVersion.load(is, version); + onlyBelowVersion.load(is, version); + + if(version >= INNO_VERSION(4, 2, 3)) { + options = StoredFlags(is).get(); + } else { + options = StoredFlags(is).get(); + } +} + +ENUM_NAMES(SetupTaskOptions::Enum, "Setup Task Option", + "exclusive", + "unchecked", + "restart", + "checked once", + "don't inherit check", +) diff --git a/src/SetupTaskEntry.hpp b/src/SetupTaskEntry.hpp new file mode 100644 index 0000000..b00fbe4 --- /dev/null +++ b/src/SetupTaskEntry.hpp @@ -0,0 +1,44 @@ + +#ifndef INNOEXTRACT_SETUPTASKENTRY_HPP +#define INNOEXTRACT_SETUPTASKENTRY_HPP + +#include +#include "Version.hpp" +#include "WindowsVersion.hpp" +#include "Flags.hpp" +#include "Enum.hpp" + +FLAGS(SetupTaskOptions, + toExclusive, + toUnchecked, + toRestart, + toCheckedOnce, + toDontInheritCheck, +) + +NAMED_ENUM(SetupTaskOptions::Enum) + +struct SetupTaskEntry { + + // introduced after 1.3.26 + + std::string name; + std::string description; + std::string groupDescription; + std::string components; + std::string languages; + std::string check; + + int level; + bool used; + + WindowsVersion minVersion; + WindowsVersion onlyBelowVersion; + + SetupTaskOptions options; + + void load(std::istream & is, const InnoVersion & version); + +}; + +#endif // INNOEXTRACT_SETUPTASKENTRY_HPP diff --git a/src/SetupTypeEntry.hpp b/src/SetupTypeEntry.hpp index 9cbaba0..703f926 100644 --- a/src/SetupTypeEntry.hpp +++ b/src/SetupTypeEntry.hpp @@ -4,8 +4,9 @@ #include #include "Version.hpp" -#include "SetupHeader.hpp" +#include "WindowsVersion.hpp" #include "Flags.hpp" +#include "Enum.hpp" FLAGS(SetupTypeOptions, CustomSetupType, @@ -29,8 +30,8 @@ struct SetupTypeEntry { std::string languages; std::string check; - SetupVersionData minVersion; - SetupVersionData onlyBelowVersion; + WindowsVersion minVersion; + WindowsVersion onlyBelowVersion; SetupTypeOptions options; diff --git a/src/WindowsVersion.cpp b/src/WindowsVersion.cpp new file mode 100644 index 0000000..6dff7cc --- /dev/null +++ b/src/WindowsVersion.cpp @@ -0,0 +1,118 @@ + +#include "WindowsVersion.hpp" + +#include "LoadingUtils.hpp" +#include "Utils.hpp" + +const WindowsVersion WindowsVersion::none = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0 } }; + +void WindowsVersion::Version::load(std::istream& is, const InnoVersion& version) { + + if(version > INNO_VERSION(1, 2, 16)) { + build = loadNumber(is); + } else { + build = 0; + } + + minor = loadNumber(is); + major = loadNumber(is); + +} + +void WindowsVersion::load(std::istream & is, const InnoVersion & version) { + + winVersion.load(is, version); + ntVersion.load(is, version); + + if(version > INNO_VERSION(1, 2, 16)) { + ntServicePack.minor = loadNumber(is); + ntServicePack.major = loadNumber(is); + } else { + ntServicePack.major = 0, ntServicePack.minor = 0; + } + +} + +namespace { + +struct WindowsVersionName { + + const char * name; + + WindowsVersion::Version version; + + bool nt; + +}; + +WindowsVersionName windowsVersionNames[] = { + { "Windows 1.0", { 1, 4, 0 } }, + { "Windows 2.0", { 2, 11, 0 } }, + { "Windows 3.0", { 3, 0, 0 } }, + { "Windows NT Workstation 3.5", { 3, 5, 807 }, true }, + { "Windows NT 3.1", { 3, 10, 528 }, true }, + { "Windows for Workgroups 3.11", { 3, 11, 0 } }, + { "Windows NT Workstation 3.51", { 3, 51, 1057 }, true }, + { "Windows 95", { 4, 0, 950 } }, + { "Windows NT Workstation 4.0", { 4, 0, 1381 }, true }, + { "Windows 98", { 4, 1, 1998 } }, + { "Windows 98 Second Edition", { 4, 1, 2222 } }, + { "Windows ME", { 4, 90, 3000 } }, + { "Windows 2000", { 5, 0, 2195 }, true }, + { "Windows XP", { 5, 1, 2600 }, true }, + { "Windows XP x64", { 5, 2, 3790 }, true }, + { "Windows Vista", { 6, 0, 6000 }, true }, + { "Windows 7", { 6, 1, 7600 }, true } +}; + +const char * getVersionName(const WindowsVersion::Version & version, bool nt = false) { + for(size_t i = 0; i < ARRAY_SIZE(windowsVersionNames); i++) { + const WindowsVersionName & v = windowsVersionNames[i]; + if(v.version.major != version.major || v.version.minor < version.minor) { + continue; + } + if(nt != v.nt) { + continue; + } + return v.name; + }; + return NULL; +} + +} + +std::ostream & operator<<(std::ostream & os, const WindowsVersion::Version & v) { + os << v.major << '.' << v.minor; + if(v.build) { + os << v.build; + } +} + +std::ostream & operator<<(std::ostream & os, const WindowsVersion & v) { + os << v.winVersion; + if(v.ntVersion != v.winVersion) { + os << " nt " << v.ntVersion; + } + const char * winName = getVersionName(v.winVersion); + const char * ntName = getVersionName(v.ntVersion, true); + if(winName || ntName) { + os << " ("; + if(winName) { + os << winName; + } + if(ntName && ntName != winName) { + if(winName) { + os << " / "; + } + os << ntName; + } + os << ')'; + } + if(v.ntServicePack.major || v.ntServicePack.minor) { + os << " service pack " << v.ntServicePack.major; + if(v.ntServicePack.minor) { + os << '.' << v.ntServicePack.minor; + } + } + return os; +} diff --git a/src/WindowsVersion.hpp b/src/WindowsVersion.hpp new file mode 100644 index 0000000..b26169d --- /dev/null +++ b/src/WindowsVersion.hpp @@ -0,0 +1,68 @@ + +#ifndef INNOEXTRACT_SETUPVERSIONDATA_HPP +#define INNOEXTRACT_SETUPVERSIONDATA_HPP + +#include +#include "Types.hpp" +#include "Version.hpp" + +struct WindowsVersion { + + struct Version { + + unsigned major; + unsigned minor; + unsigned build; + + inline bool operator==(const Version & o) const { + return (build == o.build && major == o.major && minor == o.minor); + } + + inline bool operator!=(const Version & o) const { + return !(*this == o); + } + + void load(std::istream & is, const InnoVersion & version); + + }; + + Version winVersion; + Version ntVersion; + + struct ServicePack { + + unsigned major; + unsigned minor; + + inline bool operator==(const ServicePack & o) const { + return (major == o.major && minor == o.minor); + } + + inline bool operator!=(const ServicePack & o) const { + return !(*this == o); + } + + }; + + ServicePack ntServicePack; + + void load(std::istream & is, const InnoVersion & version); + + inline bool operator==(const WindowsVersion & o) const { + return (winVersion == o.winVersion + && ntServicePack == o.ntServicePack + && ntServicePack == o.ntServicePack); + } + + inline bool operator!=(const WindowsVersion & o) const { + return !(*this == o); + } + + const static WindowsVersion none; + +}; + +std::ostream & operator<<(std::ostream & os, const WindowsVersion::Version & svd); +std::ostream & operator<<(std::ostream & os, const WindowsVersion & svd); + +#endif // INNOEXTRACT_SETUPVERSIONDATA_HPP