Browse Source

The header is loaded.

pull/1/head
Daniel Scharrer 15 years ago
parent
commit
13925809e4
  1. 4
      CMakeLists.txt
  2. 240
      src/BitfieldConverter.hpp
  3. 69
      src/BlockReader.cpp
  4. 9
      src/BlockReader.hpp
  5. 4
      src/ChunkFilter.cpp
  6. 18
      src/ChunkFilter.hpp
  7. 63
      src/Enum.hpp
  8. 44
      src/ExeReader.cpp
  9. 171
      src/Flags.hpp
  10. 186
      src/InnoExtract.cpp
  11. 87
      src/LoadingUtils.cpp
  12. 119
      src/LoadingUtils.hpp
  13. 4
      src/LzmaFilter.cpp
  14. 8
      src/Output.cpp
  15. 66
      src/Output.hpp
  16. 586
      src/SetupHeader.cpp
  17. 307
      src/SetupHeader.hpp
  18. 804
      src/SetupHeaderFormat.hpp
  19. 38
      src/SetupLoader.cpp
  20. 18
      src/SetupLoader.hpp
  21. 22
      src/SetupLoaderFormat.hpp
  22. 2
      src/Types.h
  23. 10
      src/UnDeflate.cpp
  24. 72
      src/Utils.hpp
  25. 181
      src/Version.cpp
  26. 64
      src/Version.hpp

4
CMakeLists.txt

@ -31,9 +31,13 @@ set(INNOEXTRACT_SOURCES
src/ChunkFilter.cpp
src/ExeReader.cpp
src/InnoExtract.cpp
src/LoadingUtils.cpp
src/LzmaFilter.cpp
src/Output.cpp
src/SetupHeader.cpp
src/SetupLoader.cpp
src/Utils.cpp
src/Version.cpp
)
add_executable(innoextract ${INNOEXTRACT_SOURCES})

240
src/BitfieldConverter.hpp

@ -0,0 +1,240 @@
#include <boost/utility/enable_if.hpp>
#include <boost/integer.hpp>
#include <boost/integer/static_log2.hpp>
#include <boost/integer/static_min_max.hpp>
#include <boost/integer_traits.hpp>
namespace boost {
template <class T>
class integer_traits<const T> : public integer_traits<T> { };
}
template <size_t N, class Type = void, class Enable = void>
struct is_power_of_two {
static const bool value = false;
};
template <size_t N, class Type>
struct is_power_of_two<N, Type, typename boost::enable_if_c<(N & (N - 1)) == 0>::type> {
static const bool value = true;
typedef Type type;
};
template <size_t N, class Enable = void>
struct log_next_power_of_two {
static const size_t value = boost::static_log2<N>::value + 1;
};
template <size_t N>
struct log_next_power_of_two<N, typename boost::enable_if<is_power_of_two<N> >::type> {
static const size_t value = boost::static_log2<N>::value;
};
template <size_t N, class Enable = void>
struct next_power_of_two {
static const size_t value = size_t(1) << (boost::static_log2<N>::value + 1);
};
template <size_t N>
struct next_power_of_two<N, typename boost::enable_if<is_power_of_two<N> >::type> {
static const size_t value = N;
};
struct fast_integers {
private:
template <size_t Bits, class Dummy = void> struct _impl { };
template <class Dummy> struct _impl<8, Dummy> { typedef uint_fast8_t type; };
template <class Dummy> struct _impl<16, Dummy> { typedef uint_fast16_t type; };
template <class Dummy> struct _impl<32, Dummy> { typedef uint_fast32_t type; };
template <class Dummy> struct _impl<64, Dummy> { typedef uint_fast64_t type; };
template <class Dummy> struct _impl<128, Dummy> { typedef __uint128_t type; };
public:
template <size_t Bits>
struct bits : public _impl<boost::static_unsigned_max<8, next_power_of_two<Bits>::value>::value> { };
};
struct exact_integers {
private:
template <size_t Bits, class Dummy = void> struct _impl { };
template <class Dummy> struct _impl<8, Dummy> { typedef uint8_t type; };
template <class Dummy> struct _impl<16, Dummy> { typedef uint16_t type; };
template <class Dummy> struct _impl<32, Dummy> { typedef uint32_t type; };
template <class Dummy> struct _impl<64, Dummy> { typedef uint64_t type; };
template <class Dummy> struct _impl<128, Dummy> { typedef __uint128_t type; };
public:
template <size_t Bits>
struct bits : public _impl<boost::static_unsigned_max<8, next_power_of_two<Bits>::value>::value> { };
};
struct bitset_types {
template <size_t Bits>
struct bits {
typedef std::bitset<Bits> type;
};
};
/*!
* Converter that rearranges bits in an integer.
*
* Conversion is reduced to a minimal number of mask & shift operations at compile-time.
*
* Usage:
*
* bitset_converter&lt;&gt; is an empty converter list (cannot be used without adding at least one mappings).
* (list)::add::map&lt;from, to&gt maps the from'th input bit to the to'th output bit.
*
* Convenience function to add a continous region of mappings:
* bitset_converter&lt;&gt;::add::value&lt;to2&gt; is equivalent to bitset_converter&lt;&gt;::add::map&lt;0, to2&gt;
* (list)::add::map&lt;from, to&gt::add::value&lt;to2&gt; is equivalent to ::add::map&lt;from, to&gt::add::map&lt;from + 1, to2&gt;
*
* Inut bits without a corresponding "from" entry are ignored.
* Output bit without a corresponding "to" entry are always zero.
*
* The same input/output bit can appear in multiple mappings.
*
* Invoke the converter: (list)::convert(integer)
*
* Limitations:
*
* Input bits must fit in a native integer type provided by in_types::bits&lt;bits&gt;.
*
* Output bits must fit in an integer type selected by out_types::bits&lt;bits&gt;.
*
* Example:
*
* // Create a converter that swaps the first two bits, keeps the next one and ignores all others.
* typedef bitset_converter<>::add::map<0, 1>::add::map<1, 0>::add::value<2> Converter;
*
* // Convert something.
* Converter::convert(3);
*
*/
template <class out_types = fast_integers, class in_types = fast_integers>
struct bitset_converter {
private:
typedef ptrdiff_t shift_type;
typedef size_t index_type;
template <class Combiner, class Entry>
struct IterateEntries {
static const typename Combiner::type value = Combiner::template combine<Entry, (IterateEntries<Combiner, typename Entry::next>::value)>::value;
};
template <class Combiner> struct IterateEntries<Combiner, void> { static const typename Combiner::type value = Combiner::base; };
template <class Type, Type Base> struct Combiner { typedef Type type; static const Type base = Base; };
template<class Getter, class Type>
struct MaxCombiner : public Combiner<Type, boost::integer_traits<Type>::const_min> {
template <class Entry, Type accumulator>
struct combine { static const Type value = boost::static_signed_max<Getter::template get<Entry>::value, accumulator>::value; };
};
template<class Getter, class Type>
struct MinCombiner : public Combiner<Type, boost::integer_traits<Type>::const_max> {
template <class Entry, Type accumulator>
struct combine { static const Type value = boost::static_signed_min<Getter::template get<Entry>::value, accumulator>::value; };
};
struct ShiftGetter { template<class Entry> struct get { static const shift_type value = Entry::shift; }; };
struct FromGetter { template<class Entry> struct get { static const index_type value = Entry::from; }; };
struct ToGetter { template<class Entry> struct get { static const index_type value = Entry::to; }; };
template<shift_type Shift, class Type>
struct ShiftMaskCombiner : public Combiner<Type, Type(0)> {
template <class Entry, Type mask>
struct combine { static const Type value = mask | ( (Entry::shift == Shift) ? (Type(1) << Entry::from) : Type(0) ); };
};
template<class List>
struct Builder;
template<index_type From, index_type To, class Next = void>
struct Entry {
typedef Entry<From, To, Next> This;
static const index_type from = From;
static const index_type to = To;
typedef Next next;
static const shift_type shift = shift_type(from) - shift_type(to);
static const shift_type max_shift = IterateEntries<MaxCombiner<ShiftGetter, shift_type>, This>::value;
static const shift_type min_shift = IterateEntries<MinCombiner<ShiftGetter, shift_type>, This>::value;
static const index_type in_bits = IterateEntries<MaxCombiner<FromGetter, index_type>, This>::value + 1;
typedef typename in_types::template bits<in_bits>::type in_type;
static const index_type out_bits = IterateEntries<MaxCombiner<ToGetter, index_type>, This>::value + 1;
typedef typename out_types::template bits<out_bits>::type out_type;
template<shift_type Shift>
struct ShiftMask { static const in_type value = IterateEntries<ShiftMaskCombiner<Shift, in_type>, This>::value; };
template <shift_type Shift>
inline static typename boost::enable_if_c<(Shift >= shift_type(0)), out_type>::type evaluate(in_type value) {
return out_type((value & ShiftMask<Shift>::value) >> Shift);
}
template <shift_type Shift>
inline static typename boost::enable_if_c<(Shift < shift_type(0)), out_type>::type evaluate(in_type value) {
return out_type(value & ShiftMask<Shift>::value) << (-Shift);
}
template<shift_type Shift, class Enable = void>
struct NextShift { static const shift_type value = Shift + 1; };
template<shift_type Shift>
struct NextShift<Shift, typename boost::enable_if_c<Shift != max_shift && ShiftMask<Shift + 1>::value == in_type(0)>::type > {
static const shift_type value = NextShift<Shift + 1>::value;
};
template <shift_type Shift>
inline static typename boost::enable_if_c<(NextShift<Shift>::value != max_shift + 1), out_type>::type map(in_type value) {
return evaluate<Shift>(value) | (map<NextShift<Shift>::value>(value));
}
template <shift_type Shift>
inline static typename boost::enable_if_c<(NextShift<Shift>::value == max_shift + 1), out_type>::type map(in_type value) {
return evaluate<Shift>(value);
}
public:
typedef Builder<This> add;
static out_type convert(in_type value) {
return map<min_shift>(value);
}
};
template<class List>
struct Builder {
template<index_type From, index_type To>
struct map : public Entry<From, To, List> { };
template<index_type To, class Current = List>
struct value : public Entry<Current::from + 1, To, Current> { };
template<index_type To>
struct value<To, void> : public Entry<0, To> { };
};
public:
typedef Builder<void> add;
};

69
src/BlockReader.cpp

@ -5,52 +5,87 @@
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/restrict.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <lzma.h>
#include "Types.h"
#include "Utils.hpp"
#include "ChunkFilter.hpp"
#include "LzmaFilter.hpp"
#include "LoadingUtils.hpp"
#include "Enum.hpp"
using std::cout;
using std::endl;
namespace io = boost::iostreams;
#pragma pack(push,1)
struct BlockHeader {
u32 storedSize; //!< Total bytes written, including the CRCs.
u8 compressed; //!< True if data is compressed, false if not.
enum Compression {
Stored,
Zlib,
LZMA1,
};
#pragma pack(pop)
NAMED_ENUM(Compression)
ENUM_NAMES(Compression, "Compression", "stored", "zlib", "lzma1")
template <class T>
T loadNumberChecked(std::istream & is, u32 & crc) {
T value = load<T>(is);
crc = lzma_crc32(reinterpret_cast<const uint8_t *>(&value), sizeof(value), crc);
return fromLittleEndian(value);
};
std::istream * BlockReader::get(std::istream & base) {
std::istream * BlockReader::get(std::istream & base, const InnoVersion & version) {
u32 crc;
BlockHeader block;
if(read(read(base, crc), block).fail()) {
return NULL;
u32 expectedCrc = loadNumber<u32>(base);
u32 actualCrc = 0;
u64 storedSize;
Compression compression;
bool chunked;
if(version >= INNO_VERSION(4, 0, 9)) {
storedSize = loadNumberChecked<u32>(base, actualCrc);
u8 compressed = loadNumberChecked<u8>(base, actualCrc);
compression = compressed ? (version >= INNO_VERSION(4, 1, 6) ? LZMA1 : Zlib) : Stored;
chunked = true;
} else {
u32 compressedSize = loadNumberChecked<u32>(base, actualCrc);
u32 uncompressedSize = loadNumberChecked<u32>(base, actualCrc);
if(compressedSize == u32(-1)) {
storedSize = uncompressedSize, compression = Stored;
} else {
storedSize = compressedSize, compression = Zlib;
}
// Add the size of a CRC32 checksum for each 4KiB chunk.
storedSize += ceildiv(storedSize, 4096) * 4;
}
u32 actual = lzma_crc32(reinterpret_cast<const uint8_t *>(&block), sizeof(block), 0);
if(crc != actual) {
if(actualCrc != expectedCrc) {
error << "block CRC32 mismatch";
return NULL;
}
cout << "block size: " << block.storedSize << " compressed: " << int(block.compressed) << endl;
cout << "[block] size: " << storedSize << " compression: " << compression << endl;
io::filtering_istream * fis;
fis = new io::filtering_istream;
if(block.compressed) {
fis->push(inno_lzma_decompressor(), 8192);
switch(compression) {
case Stored: break;
case Zlib: fis->push(io::zlib_decompressor(), 8192); break;
case LZMA1: fis->push(inno_lzma_decompressor(), 8192); break;
}
fis->push(inno_chunk_filter(), 4096);
fis->push(io::restrict(base, 0, block.storedSize));
fis->push(io::restrict(base, 0, storedSize));
return fis;
}

9
src/BlockReader.hpp

@ -1,10 +1,17 @@
#ifndef INNOEXTRACT_BLOCKREADER_HPP
#define INNOEXTRACT_BLOCKREADER_HPP
#include <iostream>
#include "Version.hpp"
class BlockReader {
public:
static std::istream * get(std::istream & base);
static std::istream * get(std::istream & base, const InnoVersion & version);
};
#endif // INNOEXTRACT_BLOCKREADER_HPP

4
src/ChunkFilter.cpp

@ -3,12 +3,14 @@
#include <lzma.h>
#include <zlib.h>
void inno_chunk_filter::checkCrc(u32 expected) const {
u32 actual = lzma_crc32(reinterpret_cast<const uint8_t *>(buffer), length, 0);
if(actual != expected) {
std::cout << "[chunk] crc failed" << std::endl;
error << "[chunk] CRC32 mismatch";
throw std::string("chunk CRC32 mismatch");
}

18
src/ChunkFilter.hpp

@ -1,4 +1,7 @@
#ifndef INNOEXTRACT_CHUNKFILTER_HPP
#define INNOEXTRACT_CHUNKFILTER_HPP
#include <string>
#include <algorithm>
#include <iostream>
@ -7,6 +10,7 @@
#include <boost/iostreams/read.hpp>
#include "Types.h"
#include "Output.hpp"
class inno_chunk_filter : public boost::iostreams::multichar_input_filter {
@ -26,25 +30,23 @@ public:
template<typename Source>
bool readChunk(Source & src) {
std::cout << "[chunk] big read" << std::endl;
u32 chunkCrc32 = *reinterpret_cast<u32 *>(buffer);
std::streamsize nread = boost::iostreams::read(src, reinterpret_cast<char *>(&chunkCrc32), 4);
if(nread == -1) {
std::cout << "[chunk] end" << std::endl;
return false;
} else if(nread != 4) {
std::cout << "[chunk] unexpected block end" << std::endl;
error << "[chunk] unexpected block end";
throw std::string("unexpected block end");
}
length = boost::iostreams::read(src, buffer, sizeof(buffer));
if(length == (size_t)-1) {
std::cout << "[chunk] unexpected chunk end" << std::endl;
error << "[chunk] unexpected chunk end";
throw std::string("unexpected chunk end");
}
std::cout << "[chunk] -> length=" << length << std::endl;
std::cout << "[chunk] read chunk: " << length << " bytes" << std::endl;
checkCrc(chunkCrc32);
@ -56,8 +58,6 @@ public:
template<typename Source>
std::streamsize read(Source & src, char * dest, std::streamsize n) {
std::cout << "[chunk] small read " << n << std::endl;
size_t read = 0;
while(n) {
@ -72,8 +72,6 @@ public:
dest += size, n -= size;
read += size;
std::cout << "[chunk] +" << size << " remaining: " << (length - pos) << std::endl;
}
return read;
@ -86,3 +84,5 @@ private:
char buffer[4096];
};
#endif // INNOEXTRACT_CHUNKFILTER_HPP

63
src/Enum.hpp

@ -0,0 +1,63 @@
#ifndef INNOEXTRACT_ENUM_HPP
#define INNOEXTRACT_ENUM_HPP
#include <iostream>
#include <boost/static_assert.hpp>
#include "Utils.hpp"
#include "Flags.hpp"
#include "Output.hpp"
template <class Enum>
struct EnumNames {
const size_t count;
const char * name;
const char * names[0];
};
#define NAMED_ENUM(Enum) \
template <> struct EnumNames<Enum> { \
static const char * name; \
static const char * names[]; \
static const size_t count; \
}; \
std::ostream & operator<<(std::ostream & os, Enum value);
#define ENUM_NAMES(Enum, Name, ...) \
const char * EnumNames<Enum>::name = (Name); \
const char * EnumNames<Enum>::names[] = { __VA_ARGS__ }; \
const size_t EnumNames<Enum>::count = ARRAY_SIZE(EnumNames<Enum>::names); \
std::ostream & operator<<(std::ostream & os, Enum value) { \
if(value < EnumNames<Enum>::count) { \
return os << EnumNames<Enum>::names[value]; \
} else { \
return os << "(unknown:" << int(value) << ')'; \
} \
}
template <class Enum>
std::ostream & operator<<(std::ostream & os, Flags<Enum> flags) {
color::shell_command prev = color::current;
if(flags) {
bool first = true;
for(size_t i = 0; i < Flags<Enum>::bits; i++) {
if(flags & Enum(i)) {
if(first) {
first = false;
} else {
os << color::dim_white << ", " << prev;
}
os << Enum(i);
}
}
return os;
} else {
return os << color::dim_white << "(none)" << prev;
}
}
#endif // INNOEXTRACT_ENUM_HPP

44
src/ExeReader.cpp

@ -9,9 +9,9 @@
#include "Types.h"
#include "ExeFormat.hpp"
#include "Utils.hpp"
#include "Output.hpp"
using std::cout;
using std::cerr;
using std::string;
using std::endl;
using std::setw;
@ -23,7 +23,7 @@ size_t ExeReader::findResourceEntry(std::istream & ifs, int id) {
CoffResourceTable table;
if(read(ifs, table).fail()) {
cerr << "error reading resource table" << endl;
error << "error reading resource table";
return 0;
}
@ -37,7 +37,7 @@ size_t ExeReader::findResourceEntry(std::istream & ifs, int id) {
CoffResourceEntry entry;
if(read(ifs, entry).fail()) {
cerr << "error reading resource table entry" << endl;
error << "error reading resource table entry";
return 0;
}
@ -61,7 +61,7 @@ bool ExeReader::loadSectionTable(std::istream & ifs, size_t peOffset, const Coff
ifs.seekg(sectionTableOffset);
if(ifs.read(reinterpret_cast<char *>(table.data()), sizeof(CoffSection) * table.size()).fail()) {
cerr << "error coff loading section table";
error << "error coff loading section table";
return false;
}
@ -94,31 +94,31 @@ ExeReader::Resource ExeReader::findResource(std::istream & is, int name, int typ
u16 peOffset;
if(read(is.seekg(0x3c), peOffset).fail()) {
cerr << "error reading PE signature offset";
error << "error reading PE signature offset";
return result;
}
cout << "PE signature is @ " << hex << peOffset << dec << endl;
char magic[4];
if(is.seekg(peOffset).read(magic, 4).fail()) {
cerr << "error reading PE signature" << endl;
error << "error reading PE signature";
return result;
}
static const char expectedMagic[] = { 'P', 'E', 0, 0 };
if(std::memcmp(magic, expectedMagic, 4)) {
cerr << "wrong PE signature - not an exe file" << endl;
error << "wrong PE signature - not an exe file";
return result;
}
CoffFileHeader coff;
if(read(is, coff).fail()) {
cerr << "error reading COFF file header" << endl;
error << "error reading COFF file header";
return result;
}
u16 optionalHeaderMagic;
if(read(is, optionalHeaderMagic).fail()) {
cerr << "error reading the optional header magic number" << endl;
error << "error reading the optional header magic number";
return result;
}
@ -131,22 +131,22 @@ ExeReader::Resource ExeReader::findResource(std::istream & is, int name, int typ
u32 ndirectories;
if(read(is, ndirectories).fail()) {
cerr << "error reading number of data directories" << endl;
error << "error reading number of data directories";
return result;
}
cout << "number of directories is " << ndirectories << endl;
if(ndirectories < 3) {
cerr << "no resource directory found" << endl;
error << "no resource directory found";
return result;
}
CoffDataDirectory resources;
if(read(is.seekg(16, strm::cur), resources).fail()) {
cerr << "error reading resource directory offset";
error << "error reading resource directory offset";
return result;
}
if(!resources.address || !resources.size) {
cerr << "missing resource directory" << endl;
error << "missing resource directory";
return result;
}
@ -157,7 +157,7 @@ ExeReader::Resource ExeReader::findResource(std::istream & is, int name, int typ
size_t resourceOffset = memoryAddressToFileOffset(sections, resources.address);
if(!resourceOffset) {
cerr << "error mapping virtual resource address " << hex << resources.address << dec << " to file offset" << endl;
error << "error mapping virtual resource address " << hex << resources.address << dec << " to file offset";
return result;
}
cout << "resource table is @ RVA " << hex << resources.address << " -> @ " << resourceOffset << dec << endl;
@ -166,11 +166,11 @@ ExeReader::Resource ExeReader::findResource(std::istream & is, int name, int typ
u32 typeOffset = findResourceEntry(is, type);
if(!typeOffset) {
cerr << "missing data resource entry" << endl;
error << "missing data resource entry";
return result;
}
if(!(typeOffset & (1 << 31))) {
cerr << "unexpected resource leaf for data" << endl;
error << "unexpected resource leaf for data";
return result;
}
typeOffset &= ~(1 << 31), typeOffset += resourceOffset;
@ -181,11 +181,11 @@ ExeReader::Resource ExeReader::findResource(std::istream & is, int name, int typ
u32 nameOffset = findResourceEntry(is, name);
if(!nameOffset) {
cerr << "missing installer resource entry" << endl;
error << "missing installer resource entry";
return result;
}
if(!(nameOffset & (1 << 31))) {
cerr << "unexpected resource leaf for installer" << endl;
error << "unexpected resource leaf for installer";
return result;
}
nameOffset &= ~(1 << 31), nameOffset += resourceOffset;
@ -196,11 +196,11 @@ ExeReader::Resource ExeReader::findResource(std::istream & is, int name, int typ
u32 finalOffset = findResourceEntry(is, language);
if(!finalOffset) {
cerr << "missing final resource entry" << endl;
error << "missing final resource entry";
return result;
}
if(finalOffset & (1 << 31)) {
cerr << "unexpected table for final resource entry" << endl;
error << "unexpected table for final resource entry";
return result;
}
finalOffset += resourceOffset;
@ -209,7 +209,7 @@ ExeReader::Resource ExeReader::findResource(std::istream & is, int name, int typ
CoffResourceLeaf leaf;
if(read(is.seekg(finalOffset), leaf).fail()) {
cerr << "error loading final resource entry" << endl;
error << "error loading final resource entry";
return result;
}
@ -217,7 +217,7 @@ ExeReader::Resource ExeReader::findResource(std::istream & is, int name, int typ
size_t dataOffset = memoryAddressToFileOffset(sections, leaf.address);
if(!dataOffset) {
cerr << "error mapping final virtual resource address " << hex << leaf.address << dec << " to file offset" << endl;
error << "error mapping final virtual resource address " << hex << leaf.address << dec << " to file offset";
return result;
}

171
src/Flags.hpp

@ -0,0 +1,171 @@
#ifndef INNOEXTRACT_FLAGS_HPP
#define INNOEXTRACT_FLAGS_HPP
#include <bitset>
// loosely based on QFlags from Qt
template <typename Enum>
class EnumSize { static const size_t value = 32; };
/*!
* A typesafe way to define flags as a combination of enum values.
*
* This type should not be used directly, only through DECLARE_FLAGS.
*/
template <typename _Enum>
class Flags {
public:
typedef _Enum Enum;
static const size_t bits = EnumSize<Enum>::value;
typedef std::bitset<bits> Type;
private:
typedef void ** Zero;
typedef void(*TypesafeBoolean)();
Type flags;
inline Flags(Type flag) : flags(flag) { }
public:
inline Flags(Enum flag) : flags(Type().set(size_t(flag))) { }
inline Flags(Zero = 0) : flags() { }
inline Flags(const Flags & o) : flags(o.flags) { }
static inline Flags load(Type flags) {
return Flags(flags, true);
}
inline bool has(Enum flag) const {
return flags.test(size_t(flag));
}
inline bool hasAll(Flags o) const {
return (flags & o.flags) == o.flags;
}
inline operator TypesafeBoolean() const {
return reinterpret_cast<TypesafeBoolean>(flags.any());
}
inline Flags operator~() const {
return Flags(~flags);
}
inline bool operator!() const {
return flags.none();
}
inline Flags operator&(Flags o) const {
return Flags(flags & o.flags);
}
inline Flags operator|(Flags o) const {
return Flags(flags | o.flags);
}
inline Flags operator^(Flags o) const {
return Flags(flags ^ o.flags);
}
inline Flags & operator&=(const Flags & o) {
flags &= o.flags;
return *this;
}
inline Flags & operator|=(Flags o) {
flags |= o.flags;
return *this;
}
inline Flags & operator^=(Flags o) {
flags ^= o.flags;
return *this;
}
inline Flags operator&(Enum flag) const {
return operator&(Flags(flag));
}
inline Flags operator|(Enum flag) const {
return operator|(Flags(flag));
}
inline Flags operator^(Enum flag) const {
return operator^(Flags(flag));
}
inline Flags & operator&=(Enum flag) {
return operator&=(Flags(flag));
}
inline Flags & operator|=(Enum flag) {
return operator|=(Flags(flag));
}
inline Flags & operator^=(Enum flag) {
return operator^=(flag);
}
inline Flags & operator=(Flags o) {
flags = o.flags;
return *this;
}
static inline Flags all() {
return Flags(Type().flip());
}
};
/*!
* Declare a flag type using values from a given enum.
* This should always be used instead of using Flags&lt;Enum&gt; directly.
*
* @param Enum should be an enum with values that have exactly one bit set.
* @param Flagname is the name for the flag type to be defined.
*/
#define DECLARE_FLAGS_SIZE(Enum, Flagname, Size) \
template <> \
struct EnumSize<Enum> { \
static const size_t value = (Size); \
}; \
typedef Flags<Enum> Flagname;
#define FLAGS_ENUM_END_HELPER(Enum) Enum ## __End
#define FLAGS_ENUM_END(Enum) FLAGS_ENUM_END_HELPER(Enum)
#define DECLARE_FLAGS(Enum, Flagname) DECLARE_FLAGS_SIZE(Enum, Flagname, FLAGS_ENUM_END(Enum))
/*!
* Declare overloaded operators for a given flag type.
*/
#define DECLARE_FLAGS_OPERATORS(Flagname) \
inline Flagname operator|(Flagname::Enum a, Flagname::Enum b) { \
return Flagname(a) | b; \
} \
inline Flagname operator|(Flagname::Enum a, Flagname b) { \
return b | a; \
} \
inline Flagname operator~(Flagname::Enum a) { \
return ~Flagname(a); \
}
// TODO prevent combination with integers!
#define FLAGS_ENUM(Flagname) Flagname ## __Enum
#define FLAGS(Flagname, ...) \
enum FLAGS_ENUM(Flagname) { \
__VA_ARGS__ \
FLAGS_ENUM_END(Flagname) \
}; \
DECLARE_FLAGS_SIZE(FLAGS_ENUM(Flagname), Flagname, FLAGS_ENUM_END(Flagname)) \
DECLARE_FLAGS_OPERATORS(Flagname)
#endif // INNOEXTRACT_FLAGS_HPP

186
src/InnoExtract.cpp

@ -12,13 +12,13 @@
#include <lzma.h>
#include "Types.h"
#include "SetupHeader.hpp"
#include "SetupLoader.hpp"
#include "Utils.hpp"
#include "Output.hpp"
#include "BlockReader.hpp"
using std::cout;
using std::cerr;
using std::string;
using std::endl;
using std::setw;
@ -38,93 +38,185 @@ struct BlockHeader {
int main(int argc, char * argv[]) {
if(argc <= 1) {
cerr << "usage: innoextract <Inno Setup installer>" << endl;
std::cout << "usage: innoextract <Inno Setup installer>" << endl;
return 1;
}
std::ifstream ifs(argv[1], strm::in | strm::binary | strm::ate);
if(!ifs.is_open()) {
cerr << "error opening file" << endl;
error << "error opening file";
return 1;
}
u64 fileSize = ifs.tellg();
if(!fileSize) {
cerr << "cannot read file or empty file" << endl;
error << "cannot read file or empty file";
return 1;
}
SetupLoader::Offsets offsets;
if(!SetupLoader::getOffsets(ifs, offsets)) {
cerr << "failed to load setup loader offsets" << endl;
error << "failed to load setup loader offsets";
// TODO try offset0 = 0
return 1;
}
cout << color::white;
cout << "loaded offsets:" << endl;
cout << "- total size: " << offsets.totalSize << endl;
cout << "- exe: @ " << hex << offsets.exeOffset << dec << " compressed: " << offsets.exeCompressedSize << " uncompressed: " << offsets.exeUncompressedSize << endl;
cout << "- exe checksum: " << hex << setfill('0') << setw(8) << offsets.exeChecksum << dec << " (" << (offsets.exeChecksumMode == ChecksumAdler32 ? "Alder32" : "CRC32") << ')' << endl;
cout << "- messageOffset: " << hex << offsets.messageOffset << dec << endl;
cout << "- offset: 0: " << hex << offsets.offset0 << " 1: " << offsets.messageOffset << dec << endl;
cout << color::reset;
ifs.seekg(offsets.offset0);
char version[64];
if(read(ifs, version).fail()) {
cerr << "error reading version!" << endl;
InnoVersion version;
version.load(ifs);
if(ifs.fail()) {
error << "error reading setup data version!";
return 1;
}
cout << "version: \"" << safestring(version) << '"' << endl;
std::istream * _is = BlockReader::get(ifs);
cout << "version: " << color::white << version << color::reset << endl;
std::istream * _is = BlockReader::get(ifs, version);
if(!_is) {
cerr << "error reading block" << endl;
error << "error reading block";
return 1;
}
std::istream & is = *_is;
std::string strings[29];
for(size_t i = 0; i < sizeof(strings)/sizeof(*strings); i++) {
u32 size;
if(read(is, size).fail()) {
cerr << "error reading string size #" << i << endl;
return 1;
}
strings[i].resize(size);
if(is.read(&strings[i][0], size).fail()) {
cerr << "error reading string #" << i << endl;
return 1;
}
is.exceptions(strm::badbit | strm::failbit);
/*
std::ofstream ofs("dump.bin", strm::trunc | strm::out | strm::binary);
do {
char buf[4096];
size_t in = is.read(buf, ARRAY_SIZE(buf)).gcount();
cout << in << endl;
ofs.write(buf, in);
} while(!is.eof());
if(is.bad()) {
error << "read error";
} else if(!is.eof()) {
warning << "not eof";
}
return 0;*/
SetupHeader header;
header.load(is, version);
if(is.fail()) {
error << "error reading setup data header!";
return 1;
}
cout << IfNotEmpty("App name", header.appName);
cout << IfNotEmpty("App ver name", header.appVerName);
cout << IfNotEmpty("App id", header.appId);
cout << IfNotEmpty("Copyright", header.appCopyright);
cout << IfNotEmpty("Publisher", header.appPublisher);
cout << IfNotEmpty("Publisher URL", header.appPublisherURL);
cout << IfNotEmpty("Support phone", header.appSupportPhone);
cout << IfNotEmpty("Support URL", header.appSupportURL);
cout << IfNotEmpty("Updates URL", header.appUpdatesURL);
cout << IfNotEmpty("Version", header.appVersion);
cout << IfNotEmpty("Default dir name", header.defaultDirName);
cout << IfNotEmpty("Default group name", header.defaultGroupName);
cout << IfNotEmpty("Uninstall icon name", header.uninstallIconName);
cout << IfNotEmpty("Base filename", header.baseFilename);
cout << IfNotEmpty("Uninstall files dir", header.uninstallFilesDir);
cout << IfNotEmpty("Uninstall display name", header.uninstallDisplayName);
cout << IfNotEmpty("Uninstall display icon", header.uninstallDisplayIcon);
cout << IfNotEmpty("App mutex", header.appMutex);
cout << IfNotEmpty("Default user name", header.defaultUserInfoName);
cout << IfNotEmpty("Default user org", header.defaultUserInfoOrg);
cout << IfNotEmpty("Default user serial", header.defaultUserInfoSerial);
cout << IfNotEmpty("Readme", header.appReadmeFile);
cout << IfNotEmpty("Contact", header.appContact);
cout << IfNotEmpty("Comments", header.appComments);
cout << IfNotEmpty("Modify path", header.appModifyPath);
cout << IfNotEmpty("Uninstall reg key", header.createUninstallRegKey);
cout << IfNotEmpty("Uninstallable", header.uninstallable);
cout << IfNotEmpty("License", header.licenseText);
cout << IfNotEmpty("Info before text", header.infoBeforeText);
cout << IfNotEmpty("Info after text", header.infoAfterText);
cout << IfNotEmpty("Uninstaller signature", header.signedUninstallerSignature);
cout << IfNotEmpty("Compiled code", header.compiledCodeText);
cout << IfNotZero("Lead bytes", header.leadBytes);
cout << IfNotZero("Language entries", header.numLanguageEntries);
cout << IfNotZero("Custom message entries", header.numCustomMessageEntries);
cout << IfNotZero("Permission entries", header.numPermissionEntries);
cout << IfNotZero("Type entries", header.numTypeEntries);
cout << IfNotZero("Component entries", header.numComponentEntries);
cout << IfNotZero("Task entries", header.numTaskEntries);
cout << IfNotZero("Dir entries", header.numDirEntries);
cout << IfNotZero("File entries", header.numFileEntries);
cout << IfNotZero("File location entries", header.numFileLocationEntries);
cout << IfNotZero("Icon entries", header.numIconEntries);
cout << IfNotZero("Ini entries", header.numIniEntries);
cout << IfNotZero("Registry entries", header.numRegistryEntries);
cout << IfNotZero("Delete entries", header.numInstallDeleteEntries);
cout << IfNotZero("Uninstall delete entries", header.numUninstallDeleteEntries);
cout << IfNotZero("Run entries", header.numRunEntries);
cout << IfNotZero("Uninstall run entries", header.numUninstallRunEntries);
cout << IfNotZero("License size", header.licenseSize);
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;
}
const char * names[29] = {
"App Name", "App Ver Name", "App Id", "Copyright", "Publisher", "Publisher URL",
"SupportPhone", "Support URL", "Updates URL", "Version", "Default Dir Name",
"Default Group Name", "Base Filename", "License Text",
"Info Before Text", "Info After Text", "Uninstall Files Dir", "Uninstall Display Name",
"Uninstall Display Icon", "App Mutex", "Default User Info Name",
"Default User Info Org", "Default User Info Serial", "Compiled Code Text",
"Readme", "Contact", "Comments", "App Modify Path",
"Signed Uninstaller Signature"
};
for(size_t i = 0; i < sizeof(strings)/sizeof(*strings); i++) {
if(i != 23) {
cout << "- " << names[i] << ": \"" << strings[i] << '"' << endl;
} else {
cout << "- " << names[i] << ": " << strings[i].length() << " bytes" << endl;
}
cout << hex;
cout << IfNotZero("Back color", header.backColor);
cout << IfNotZero("Back color2", header.backColor2);
cout << IfNotZero("Wizard image back color", header.wizardImageBackColor);
cout << IfNotZero("Wizard small image back color", header.wizardSmallImageBackColor);
cout << dec;
if(header.options & (shPassword|shEncryptionUsed)) {
cout << "Password type: " << color::cyan << header.passwordType << color::reset << endl;
// TODO print password
// TODO print salt
}
cout << IfNotZero("Extra disk space required", header.extraDiskSpaceRequired);
cout << IfNotZero("Slices per disk", header.slicesPerDisk);
cout << IfNot("Install mode", header.installMode, SetupHeader::NormalInstallMode);
cout << "Uninstall log mode: " << color::cyan << header.uninstallLogMode << color::reset << endl;
cout << "Uninstall style: " << color::cyan << header.uninstallStyle << color::reset << endl;
cout << "Dir exists warning: " << color::cyan << header.dirExistsWarning << color::reset << endl;
cout << IfNot("Privileges required", header.privilegesRequired, SetupHeader::NoPrivileges);
cout << "Show language dialog: " << color::cyan << header.showLanguageDialog << color::reset << endl;
cout << IfNot("Danguage detection", header.languageDetectionMethod, SetupHeader::NoLanguageDetection);
cout << "Compression: " << color::cyan << header.compressMethod << color::reset << endl;
cout << "Architectures allowed: " << color::cyan << header.architecturesAllowed << color::reset << endl;
cout << "Architectures installed in 64-bit mode: " << color::cyan << header.architecturesInstallIn64BitMode << color::reset << endl;
if(header.options & shSignedUninstaller) {
cout << IfNotZero("Size before signing uninstaller", header.signedUninstallerOrigSize);
cout << IfNotZero("Uninstaller header checksum", header.signedUninstallerHdrChecksum);
}
cout << "Disable dir page: " << color::cyan << header.disableDirPage << color::reset << endl;
cout << "Disable program group page: " << color::cyan << header.disableProgramGroupPage << color::reset << endl;
cout << IfNotZero("Uninstall display size", header.uninstallDisplaySize);
delete _is;
cout << "Options: " << color::green << header.options << color::reset << endl;
cout << color::reset;
return 0;
}

87
src/LoadingUtils.cpp

@ -0,0 +1,87 @@
#include "LoadingUtils.hpp"
#include <iterator>
#include <iconv.h>
#include <errno.h>
#include "Output.hpp"
#include "Utils.hpp"
void BinaryString::loadInto(std::istream & is, std::string & target) {
size_t length = loadNumber<u32>(is);
if(is.fail()) {
return;
}
target.resize(length);
is.read(&target[0], length);
}
static void convert(iconv_t converter, const std::string & from, std::string & to) {
const char * inbuf = from.data();
size_t insize = from.size();
size_t outbase = 0;
if(!insize) {
to.clear();
return;
}
iconv(converter, NULL, NULL, NULL, NULL);
while(insize) {
to.resize(outbase + insize);
char * outbuf = &to[0] + outbase;
size_t outsize = to.size() - outbase;
size_t ret = iconv(converter, const_cast<char**>(&inbuf), &insize, &outbuf, &outsize);
if(ret == size_t(-1) && errno != E2BIG) {
error << "iconv error";
to.clear();
return;
}
outbase = to.size() - outsize;
}
}
void AnsiString::loadInto(std::istream & is, std::string & target) {
std::string temp;
BinaryString::loadInto(is, temp);
static iconv_t converter = NULL;
if(!converter) {
converter = iconv_open("UTF-8", "CP1252");
if(!converter) {
error << "missing CP1252 -> UTF-8 converter";
}
}
convert(converter, temp, target);
}
void WideString::loadInto(std::istream & is, std::string & target) {
std::string temp;
BinaryString::loadInto(is, temp);
static iconv_t converter = NULL;
if(!converter) {
converter = iconv_open("UTF-8", "UTF-16");
if(!converter) {
error << "missing UTF-16 -> UTF-8 converter";
}
}
convert(converter, temp, target);
}

119
src/LoadingUtils.hpp

@ -0,0 +1,119 @@
#ifndef INNOEXTRACT_LOADINGUTILS_HPP
#define INNOEXTRACT_LOADINGUTILS_HPP
#include <iostream>
#include <string>
#include <limits>
#include <boost/detail/endian.hpp>
#include "Types.h"
inline u8 fromLittleEndian(u8 value) { return value; }
inline s8 fromLittleEndian(s8 value) { return value; }
#ifdef BOOST_LITTLE_ENDIAN
inline u16 fromLittleEndian(u16 value) { return value; }
inline u32 fromLittleEndian(u32 value) { return value; }
inline u64 fromLittleEndian(u64 value) { return value; }
inline s16 fromLittleEndian(s16 value) { return value; }
inline s32 fromLittleEndian(s32 value) { return value; }
inline s64 fromLittleEndian(s64 value) { return value; }
#else
// TODO implement!
#error "Host endianness not supported!"
#endif
struct BinaryString {
std::string & data;
inline BinaryString(std::string & target) : data(target) { }
static void loadInto(std::istream & is, std::string & target);
};
inline std::istream & operator>>(std::istream & is, const BinaryString & str) {
BinaryString::loadInto(is, str.data);
return is;
}
struct AnsiString {
std::string & data;
inline AnsiString(std::string & target) : data(target) { }
static void loadInto(std::istream & is, std::string & target);
};
inline std::istream & operator>>(std::istream & is, const AnsiString & str) {
AnsiString::loadInto(is, str.data);
return is;
}
struct WideString {
std::string & data;
bool wide;
inline WideString(std::string & target, bool _wide /*= true*/) : data(target), wide(_wide) { }
static void loadInto(std::istream & is, std::string & target);
};
inline std::istream & operator>>(std::istream & is, const WideString & str) {
str.wide ? WideString::loadInto(is, str.data) : AnsiString::loadInto(is, str.data);
return is;
}
template <class T>
inline T load(std::istream & is) {
T value;
is.read(reinterpret_cast<char *>(&value), sizeof(value));
return value;
}
template <class T>
inline T loadNumber(std::istream & is) {
return fromLittleEndian(load<T>(is));
}
template <class Base, size_t Bits, bool Signed = std::numeric_limits<Base>::is_signed>
struct compatible_integer { typedef void type; };
template <class Base>
struct compatible_integer<Base, 8, false> { typedef u8 type; };
template <class Base>
struct compatible_integer<Base, 8, true> { typedef s8 type; };
template <class Base>
struct compatible_integer<Base, 16, false> { typedef u16 type; };
template <class Base>
struct compatible_integer<Base, 16, true> { typedef s16 type; };
template <class Base>
struct compatible_integer<Base, 32, false> { typedef u32 type; };
template <class Base>
struct compatible_integer<Base, 32, true> { typedef s32 type; };
template <class Base>
struct compatible_integer<Base, 64, false> { typedef u64 type; };
template <class Base>
struct compatible_integer<Base, 64, true> { typedef s64 type; };
template <class T>
T loadNumber(std::istream & is, size_t bits) {
if(bits == 8) {
return loadNumber<typename compatible_integer<T, 8>::type>(is);
} else if(bits == 16) {
return loadNumber<typename compatible_integer<T, 16>::type>(is);
} else if(bits == 32) {
return loadNumber<typename compatible_integer<T, 32>::type>(is);
} else {
return loadNumber<typename compatible_integer<T, 64>::type>(is);
}
}
#endif // INNOEXTRACT_LOADINGUTILS_HPP

4
src/LzmaFilter.cpp

@ -17,7 +17,7 @@ inno_lzma_decompressor_impl::~inno_lzma_decompressor_impl() { close(); }
bool inno_lzma_decompressor_impl::filter(const char * & begin_in, const char * end_in, char * & begin_out, char * end_out, bool flush) {
(void)flush;
cout << "[lzma] filter " << (end_in - begin_in) << " -> " << (end_out - begin_out) << endl;
size_t bufsize_in = (end_in - begin_in), bufsize_out = (end_out - begin_out);
// Read enough bytes to decode the header.
while(nread != 5) {
@ -81,7 +81,7 @@ bool inno_lzma_decompressor_impl::filter(const char * & begin_in, const char * e
lzma_ret ret = lzma_code(strm, LZMA_RUN);
cout << "[lzma] consumed " << (reinterpret_cast<const char *>(strm->next_in) - begin_in) << " -> " << (reinterpret_cast<char *>(strm->next_out) - begin_out) << " ret=" << ret << endl;
cout << "[lzma] decompressed " << (reinterpret_cast<const char *>(strm->next_in) - begin_in) << " / " << bufsize_in << " -> " << (reinterpret_cast<char *>(strm->next_out) - begin_out) << " / " << bufsize_out << " ret=" << ret << endl;
begin_in = reinterpret_cast<const char *>(strm->next_in);

8
src/Output.cpp

@ -0,0 +1,8 @@
#include "Output.hpp"
namespace color {
shell_command current = color::reset;
}

66
src/Output.hpp

@ -0,0 +1,66 @@
#ifndef INNOEXTRACT_COLOROUT_HPP
#define INNOEXTRACT_COLOROUT_HPP
#include <iostream>
#include <iomanip>
namespace color {
struct shell_command {
int c0;
int c1;
};
const shell_command reset = { 0, 0 };
const shell_command black = { 1, 30 };
const shell_command red = { 1, 31 };
const shell_command green = { 1, 32 };
const shell_command yellow = { 1, 33 };
const shell_command blue = { 1, 34 };
const shell_command magenta = { 1, 35 };
const shell_command cyan = { 1, 36 };
const shell_command white = { 1, 37 };
const shell_command dim_black = { 0, 30 };
const shell_command dim_red = { 0, 31 };
const shell_command dim_green = { 0, 32 };
const shell_command dim_yellow = { 0, 33 };
const shell_command dim_blue = { 0, 34 };
const shell_command dim_magenta = { 0, 35 };
const shell_command dim_cyan = { 0, 36 };
const shell_command dim_white = { 0, 37 };
extern shell_command current;
};
inline std::ostream & operator<<(std::ostream & os, const color::shell_command command) {
color::current = command;
std::ios_base::fmtflags old = os.flags();
os << "\x1B[" << std::dec << command.c0 << ';' << command.c1 << 'm';
os.setf(old, std::ios_base::basefield);
return os;
}
struct error_base {
color::shell_command previous;
inline error_base(color::shell_command type) : previous(color::current) {
std::cerr << type << "!! ";
}
inline ~error_base() {
std::cerr << previous << std::endl;
}
};
#define error (error_base(color::red), std::cerr)
#define warning (error_base(color::yellow), std::cerr)
#endif // INNOEXTRACT_COLOROUT_HPP

586
src/SetupHeader.cpp

@ -0,0 +1,586 @@
#include "SetupHeader.hpp"
#include <cstdio>
#include <cstring>
#include <boost/static_assert.hpp>
#include "LoadingUtils.hpp"
#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<u16>(is);
ntVersion = loadNumber<u16>(is);
ntServicePack = 0;
} else {
winVersion = loadNumber<u32>(is);
ntVersion = loadNumber<u32>(is);
ntServicePack = loadNumber<u16>(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;
if(version <= INNO_VERSION(1, 2, 16)) {
loadNumber<u32>(is); // uncompressed size of the setup header structure
}
is >> WideString(appName, version.unicode);
is >> WideString(appVerName, version.unicode);
if(version > INNO_VERSION(1, 2, 16)) { // not in 1.2.16, in 1.3.25
is >> WideString(appId, version.unicode);
}
is >> WideString(appCopyright, version.unicode);
if(version > INNO_VERSION(1, 2, 16)) { // not in 1.2.16, in 1.3.25
is >> WideString(appPublisher, version.unicode);
is >> WideString(appPublisherURL, version.unicode);
} else {
appPublisher.clear(), appPublisherURL.clear();
}
if(version >= INNO_VERSION(5, 1, 13)) {
is >> WideString(appSupportPhone, version.unicode);
} else {
appSupportPhone.clear();
}
if(version > INNO_VERSION(1, 2, 16)) { // not in 1.2.16, in 1.3.25
is >> WideString(appSupportURL, version.unicode);
is >> WideString(appUpdatesURL, version.unicode);
is >> WideString(appVersion, version.unicode);
} else {
appSupportURL.clear(), appUpdatesURL.clear(), appVersion.clear();
}
is >> WideString(defaultDirName, version.unicode);
is >> WideString(defaultGroupName, version.unicode);
if(version < INNO_VERSION(3, 0, 0)) {
is >> AnsiString(uninstallIconName);
} else {
uninstallIconName.clear();
}
is >> WideString(baseFilename, version.unicode);
if(version > INNO_VERSION(1, 2, 16)) { // not in 1.2.16, in 1.3.25
if(version < INNO_VERSION(5, 2, 5)) {
is >> AnsiString(licenseText);
is >> AnsiString(infoBeforeText);
is >> AnsiString(infoAfterText);
}
is >> WideString(uninstallFilesDir, version.unicode);
is >> WideString(uninstallDisplayName, version.unicode);
is >> WideString(uninstallDisplayIcon, version.unicode);
is >> WideString(appMutex, version.unicode);
} else {
licenseText.clear(), infoBeforeText.clear(), infoAfterText.clear();
uninstallFilesDir.clear(), uninstallDisplayName.clear();
uninstallDisplayIcon.clear(), appMutex.clear();
}
if(version >= INNO_VERSION(3, 0, 0)) {
is >> WideString(defaultUserInfoName, version.unicode);
is >> WideString(defaultUserInfoOrg, version.unicode);
} else {
defaultUserInfoName.clear(), defaultUserInfoOrg.clear();
}
if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) {
is >> WideString(defaultUserInfoSerial, version.unicode);
if(version < INNO_VERSION(5, 2, 5)) {
is >> BinaryString(compiledCodeText);
}
} else {
defaultUserInfoSerial.clear(), compiledCodeText.clear();
}
if(version >= INNO_VERSION(4, 2, 4)) {
is >> WideString(appReadmeFile, version.unicode);
is >> WideString(appContact, version.unicode);
is >> WideString(appComments, version.unicode);
is >> WideString(appModifyPath, version.unicode);
} else {
appReadmeFile.clear(), appContact.clear();
appComments.clear(), appModifyPath.clear();
}
if(version >= INNO_VERSION(5, 3, 8)) {
is >> WideString(createUninstallRegKey, version.unicode);
} else {
createUninstallRegKey.clear();
}
if(version >= INNO_VERSION(5, 3, 10)) {
is >> WideString(uninstallable, version.unicode);
} else {
uninstallable.clear();
}
if(version >= INNO_VERSION(5, 2, 5)) {
is >> AnsiString(licenseText);
is >> AnsiString(infoBeforeText);
is >> AnsiString(infoAfterText);
}
if(version >= INNO_VERSION(5, 2, 1) && version < INNO_VERSION(5, 3, 10)) {
is >> BinaryString(signedUninstallerSignature);
} else {
signedUninstallerSignature.clear();
}
if(version >= INNO_VERSION(5, 2, 5)) {
is >> BinaryString(compiledCodeText);
}
if(version > INNO_VERSION(1, 3, 26) && !version.unicode) {
leadBytes = CharSet(is).getBitSet();
} else {
leadBytes = 0;
}
if(version >= INNO_VERSION(4, 0, 0)) {
numLanguageEntries = loadNumber<u32>(is);
} else {
numLanguageEntries = 0;
}
if(version >= INNO_VERSION(4, 2, 1)) {
numCustomMessageEntries = loadNumber<u32>(is);
} else {
numCustomMessageEntries = 0;
}
if(version >= INNO_VERSION(4, 1, 0)) {
numPermissionEntries = loadNumber<u32>(is);
} else {
numPermissionEntries = 0;
}
if(version > INNO_VERSION(1, 3, 26)) { // not in 1.3.26, in 2.0.8
numTypeEntries = loadNumber<u32>(is);
numComponentEntries = loadNumber<u32>(is);
numTaskEntries = loadNumber<u32>(is);
} else {
numTypeEntries = 0, numComponentEntries = 0, numTaskEntries = 0;
}
numDirEntries = loadNumber<u32>(is, version.bits);
numFileEntries = loadNumber<u32>(is, version.bits);
numFileLocationEntries = loadNumber<u32>(is, version.bits);
numIconEntries = loadNumber<u32>(is, version.bits);
numIniEntries = loadNumber<u32>(is, version.bits);
numRegistryEntries = loadNumber<u32>(is, version.bits);
numInstallDeleteEntries = loadNumber<u32>(is, version.bits);
numUninstallDeleteEntries = loadNumber<u32>(is, version.bits);
numRunEntries = loadNumber<u32>(is, version.bits);
numUninstallRunEntries = loadNumber<u32>(is, version.bits);
if(version <= INNO_VERSION(1, 2, 16)) { // in 1.2.16, not in 1.3.25
licenseSize = loadNumber<u32>(is, version.bits);
infoBeforeSize = loadNumber<u32>(is, version.bits);
infoAfterSize = loadNumber<u32>(is, version.bits);
} else {
licenseSize = infoBeforeSize = infoAfterSize = 0;
}
minVersion.load(is, version);
onlyBelowVersion.load(is, version);
backColor = loadNumber<u32>(is);
if(version > INNO_VERSION(1, 2, 16)) { // not in 1.2.16, in 1.3.25
backColor2 = loadNumber<u32>(is);
} else {
backColor2 = 0;
}
wizardImageBackColor = loadNumber<u32>(is);
if(version > INNO_VERSION(1, 3, 26) && version < INNO_VERSION(5, 0, 4)) { // not in 1.3.26, in 2.0.8
wizardSmallImageBackColor = loadNumber<u32>(is);
} else {
wizardSmallImageBackColor = 0;
}
if(version < INNO_VERSION(4, 2, 0)) {
password = loadNumber<s32>(is), passwordType = PlainPassword;
} else if(version < INNO_VERSION(5, 3, 9)) {
is.read(passwordMd5, sizeof(passwordMd5)), passwordType = Md5Password;
} else {
is.read(passwordSha1, sizeof(passwordSha1)), passwordType = Sha1Password;
}
if(version >= INNO_VERSION(4, 2, 2)) {
is.read(passwordSalt, sizeof(passwordSalt));
} else {
memset(passwordSalt, 0, sizeof(passwordSalt));
}
if(version < INNO_VERSION(4, 0, 0)) {
extraDiskSpaceRequired = loadNumber<s32>(is);
slicesPerDisk = 0;
} else {
extraDiskSpaceRequired = loadNumber<s64>(is);
slicesPerDisk = loadNumber<s32>(is);
}
if(version > INNO_VERSION(1, 3, 26) && version < INNO_VERSION(5, 0, 0)) {
// removed in 5.0.0, not in 1.2.10, not in 1.3.25
installMode = StoredEnum<StoredInstallMode>(is).get();
} else {
installMode = NormalInstallMode;
}
if(version > INNO_VERSION(1, 2, 16)) { // not in 1.2.16, in 1.3.25
uninstallLogMode = StoredEnum<StoredUninstallLogMode>(is).get();
} else {
uninstallLogMode = AppendLog;
}
if(version > INNO_VERSION(1, 3, 26) && version < INNO_VERSION(5, 0, 0)) {
uninstallStyle = StoredEnum<StoredUninstallStyle>(is).get();
} else {
uninstallStyle = (version < INNO_VERSION(5, 0, 0)) ? ClassicStyle : ModernStyle;
}
if(version > INNO_VERSION(1, 2, 16)) { // not in 1.2.16, in 1.3.25
dirExistsWarning = StoredEnum<StoredDirExistsWarning>(is).get();
} else {
dirExistsWarning = Auto;
}
if(version >= INNO_VERSION(3, 0, 0) && version < INNO_VERSION(3, 0, 3)) { // only in [3.0.0, 3.0.3)?
AutoBoolean val = StoredEnum<StoredRestartComputer>(is).get();
switch(val) {
case Yes: options |= shAlwaysRestart; break;
case Auto: options |= shRestartIfNeededByRun; break;
case No: break;
}
}
if(version >= INNO_VERSION(5, 3, 7)) {
privilegesRequired = StoredEnum<StoredPrivileges1>(is).get();
} else if(version >= INNO_VERSION(3, 0, 4)) {
privilegesRequired = StoredEnum<StoredPrivileges0>(is).get();
}
if(version >= INNO_VERSION(4, 0, 10)) {
showLanguageDialog = StoredEnum<StoredShowLanguageDialog>(is).get();
languageDetectionMethod = StoredEnum<StoredLanguageDetectionMethod>(is).get();
}
if(version >= INNO_VERSION(5, 3, 9)) {
compressMethod = StoredEnum<StoredCompressionMethod3>(is).get();
} else if(version >= INNO_VERSION(4, 2, 6)) {
compressMethod = StoredEnum<StoredCompressionMethod2>(is).get();
} else if(version >= INNO_VERSION(4, 2, 5)) {
compressMethod = StoredEnum<StoredCompressionMethod1>(is).get();
} else if(version >= INNO_VERSION(4, 1, 5)) {
compressMethod = StoredEnum<StoredCompressionMethod0>(is).get();
}
if(version >= INNO_VERSION(5, 0, 2)) {
architecturesAllowed = StoredFlags<StoredArchitectures>(is).get();
architecturesInstallIn64BitMode = StoredFlags<StoredArchitectures>(is).get();
} else {
architecturesAllowed = Architectures::all();
architecturesInstallIn64BitMode = Architectures::all();
}
if(version >= INNO_VERSION(5, 2, 1) && version < INNO_VERSION(5, 3, 10)) {
signedUninstallerOrigSize = loadNumber<s32>(is);
signedUninstallerHdrChecksum = loadNumber<u32>(is);
} else {
signedUninstallerOrigSize = signedUninstallerHdrChecksum = 0;
}
if(version >= INNO_VERSION(5, 3, 3)) {
disableDirPage = StoredEnum<StoredDisablePage>(is).get();
disableProgramGroupPage = StoredEnum<StoredDisablePage>(is).get();
}
if(version >= INNO_VERSION(5, 3, 6)) {
uninstallDisplaySize = loadNumber<u32>(is);
} else {
uninstallDisplaySize = 0;
}
StoredFlagReader<SetupHeaderOptions> flags;
flags.add(shDisableStartupPrompt);
if(version < INNO_VERSION(5, 3, 10)) {
flags.add(shUninstallable);
}
flags.add(shCreateAppDir);
if(version < INNO_VERSION(5, 3, 3)) {
flags.add(shDisableDirPage);
}
if(version <= INNO_VERSION(1, 2, 16)) {
flags.add(shDisableDirExistsWarning); // only in 1.2.10, not in 1.3.25
}
if(version < INNO_VERSION(5, 3, 3)) {
flags.add(shDisableProgramGroupPage);
}
flags.add(shAllowNoIcons);
if(version < INNO_VERSION(3, 0, 0) || version >= INNO_VERSION(3, 0, 3)) {
flags.add(shAlwaysRestart);
}
if(version <= INNO_VERSION(1, 2, 16)) {
flags.add(shBackSolid); // only in 1.2.10, not in 1.3.25
}
flags.add(shAlwaysUsePersonalGroup);
flags.add(shWindowVisible);
flags.add(shWindowShowCaption);
flags.add(shWindowResizable);
flags.add(shWindowStartMaximized);
flags.add(shEnableDirDoesntExistWarning);
if(version < INNO_VERSION(4, 1, 2)) {
flags.add(shDisableAppendDir);
}
flags.add(shPassword);
flags.add(shAllowRootDirectory);
flags.add(shDisableFinishedPage);
if(version.bits != 16) {
if(version < INNO_VERSION(3, 0, 4)) {
flags.add(shAdminPrivilegesRequired);
}
if(version < INNO_VERSION(3, 0, 0)) {
flags.add(shAlwaysCreateUninstallIcon);
}
if(version <= INNO_VERSION(1, 2, 16)) {
flags.add(shOverwriteUninstRegEntries); // only in 1.2.10, win32-only); not in 1.3.25
}
flags.add(shChangesAssociations);
}
if(version > INNO_VERSION(1, 2, 16)) { // new after 1.2.16); in 1.3.25
if(version < INNO_VERSION(5, 3, 8)) {
flags.add(shCreateUninstallRegKey);
}
flags.add(shUsePreviousAppDir);
flags.add(shBackColorHorizontal);
flags.add(shUsePreviousGroup);
flags.add(shUpdateUninstallLogAppName);
}
if(version > INNO_VERSION(1, 3, 26)) { // new after 1.3.26
flags.add(shUsePreviousSetupType);
flags.add(shDisableReadyMemo);
flags.add(shAlwaysShowComponentsList);
flags.add(shFlatComponentsList);
flags.add(shShowComponentSizes);
flags.add(shUsePreviousTasks);
flags.add(shDisableReadyPage);
flags.add(shAlwaysShowDirOnReadyPage);
flags.add(shAlwaysShowGroupOnReadyPage);
}
if(version >= INNO_VERSION(2, 0, 17) && version < INNO_VERSION(4, 1, 5)) {
flags.add(shBzipUsed);
}
if(version >= INNO_VERSION(2, 0, 18)) {
flags.add(shAllowUNCPath);
}
if(version >= INNO_VERSION(3, 0, 0)) {
flags.add(shUserInfoPage);
flags.add(shUsePreviousUserInfo);
}
if(version >= INNO_VERSION(3, 0, 1)) {
flags.add(shUninstallRestartComputer);
}
if(version >= INNO_VERSION(3, 0, 3)) {
flags.add(shRestartIfNeededByRun);
}
if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) {
flags.add(shShowTasksTreeLines);
}
if(version >= INNO_VERSION(4, 0, 0) && version < INNO_VERSION(4, 0, 10)) {
flags.add(shShowLanguageDialog);
}
if(version >= INNO_VERSION(4, 0, 1) && version < INNO_VERSION(4, 0, 10)) {
flags.add(shDetectLanguageUsingLocale);
}
if(version >= INNO_VERSION(4, 0, 9)) {
flags.add(shAllowCancelDuringInstall);
}
if(version >= INNO_VERSION(4, 1, 3)) {
flags.add(shWizardImageStretch);
}
if(version >= INNO_VERSION(4, 1, 8)) {
flags.add(shAppendDefaultDirName);
flags.add(shAppendDefaultGroupName);
}
if(version >= INNO_VERSION(4, 2, 2)) {
flags.add(shEncryptionUsed);
}
if(version >= INNO_VERSION(5, 0, 4)) {
flags.add(shChangesEnvironment);
}
if(version >= INNO_VERSION(5, 1, 7) && !version.unicode) {
flags.add(shShowUndisplayableLanguages);
}
if(version >= INNO_VERSION(5, 1, 13)) {
flags.add(shSetupLogging);
}
if(version >= INNO_VERSION(5, 2, 1)) {
flags.add(shSignedUninstaller);
}
if(version >= INNO_VERSION(5, 3, 8)) {
flags.add(shUsePreviousLanguage);
}
if(version >= INNO_VERSION(5, 3, 9)) {
flags.add(shDisableWelcomePage);
}
options |= flags.get(is);
if(version < INNO_VERSION(3, 0, 4)) {
privilegesRequired = (options & shAdminPrivilegesRequired) ? AdminPriviliges : NoPrivileges;
}
if(version < INNO_VERSION(4, 0, 10)) {
showLanguageDialog = (options & shShowLanguageDialog) ? Yes : No;
languageDetectionMethod = (options & shDetectLanguageUsingLocale) ? LocaleLanguage : UILanguage;
}
if(version < INNO_VERSION(4, 1, 5)) {
compressMethod = (options & shBzipUsed) ? BZip2 : Zlib;
}
if(version < INNO_VERSION(5, 3, 3)) {
disableDirPage = (options & shDisableDirPage) ? Yes : No;
disableProgramGroupPage = (options & shDisableProgramGroupPage) ? Yes : No;
}
}
ENUM_NAMES(SetupHeaderOptions::Enum, "Setup Option",
"disable startup prompt",
"create app dir",
"allow no icons",
"always restart",
"always use personal group",
"window visible",
"window show caption",
"window resizable",
"window start maximized",
"enable dir doesn't exist warning",
"password",
"allow root directory",
"disable finished page",
"changes associations",
"use previous app dir",
"back color horizontal",
"use previous group",
"update uninstall log app name",
"use previous setup type",
"disable ready memo",
"always show components list",
"flat components list",
"show component sizes",
"use previous tasks",
"disable ready page",
"always show dir on ready page",
"always show group on ready page",
"allow unc path",
"user info page",
"use previous user info",
"uninstall restart computer",
"restart if needed by run",
"show tasks tree lines",
"allow cancel during install",
"wizard image stretch",
"append default dir name",
"append default group name",
"encrypted",
"changes environment",
"show undisplayable languages",
"setup logging",
"signed uninstaller",
"use previous language",
"disable welcome page",
"uninstallable",
"disable dir page",
"disable program group page",
"disable append dir",
"admin privilegesrequired",
"always create uninstall icon",
"create uninstall reg key",
"bzip used",
"show language dialog",
"detect language using locale",
"disable dir exists warning",
"back solid",
"overwrite uninst reg entries",
)
BOOST_STATIC_ASSERT(EnumSize<SetupHeaderOptions::Enum>::value == EnumNames<SetupHeaderOptions::Enum>::count);
ENUM_NAMES(Architectures::Enum, "Architecture",
"unknown",
"x86",
"amd64",
"IA64",
)
ENUM_NAMES(SetupHeader::PasswordType, "Password Type",
"plain",
"MD5",
"SHA1",
)
ENUM_NAMES(SetupHeader::InstallMode, "Install Mode",
"normal",
"silent",
"very silent",
)
ENUM_NAMES(SetupHeader::UninstallLogMode, "Uninstall Log Mode",
"append",
"new log",
"overwrite",
)
ENUM_NAMES(SetupHeader::UninstallStyle, "Uninstall Style",
"classic",
"modern",
)
ENUM_NAMES(SetupHeader::AutoBoolean, "Auto Boolean",
"auto",
"no",
"yes",
)
ENUM_NAMES(SetupHeader::Privileges, "Privileges",
"none",
"power user",
"admin",
"lowest",
)
ENUM_NAMES(SetupHeader::LanguageDetection, "Language Detection",
"ui language",
"locale",
"none",
)
ENUM_NAMES(SetupHeader::CompressionMethod, "Compression Method",
"stored",
"zlib",
"bzip2",
"lzma1",
"lzma2",
"unknown",
)

307
src/SetupHeader.hpp

@ -0,0 +1,307 @@
#ifndef INNOEXTRACT_SETUPHEADER_HPP
#define INNOEXTRACT_SETUPHEADER_HPP
#include <stddef.h>
#include <bitset>
#include <string>
#include <iostream>
#include "Types.h"
#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);
typedef char MD5Digest[16];
typedef char SHA1Digest[20];
typedef char SetupSalt[8];
FLAGS(SetupHeaderOptions,
shDisableStartupPrompt,
shCreateAppDir,
shAllowNoIcons,
shAlwaysRestart, // TODO missing in [3.0.0, 3.0.3)
shAlwaysUsePersonalGroup,
shWindowVisible,
shWindowShowCaption,
shWindowResizable,
shWindowStartMaximized,
shEnableDirDoesntExistWarning,
shPassword,
shAllowRootDirectory,
shDisableFinishedPage,
shChangesAssociations,
shUsePreviousAppDir,
shBackColorHorizontal,
shUsePreviousGroup,
shUpdateUninstallLogAppName,
shUsePreviousSetupType,
shDisableReadyMemo,
shAlwaysShowComponentsList,
shFlatComponentsList,
shShowComponentSizes,
shUsePreviousTasks,
shDisableReadyPage,
shAlwaysShowDirOnReadyPage,
shAlwaysShowGroupOnReadyPage,
// new in 2.0.18
shAllowUNCPath,
// new in 3.0.0
shUserInfoPage,
shUsePreviousUserInfo,
// new in 3.0.1
shUninstallRestartComputer,
// new in 3.0.3
shRestartIfNeededByRun,
// new in 3.0.8
shShowTasksTreeLines,
// new in 4.0.9
shAllowCancelDuringInstall,
// new in 4.1.3
shWizardImageStretch,
// new in 4.1.8
shAppendDefaultDirName,
shAppendDefaultGroupName,
// new in 4.2.2
shEncryptionUsed,
// new in 5.0.4
shChangesEnvironment,
// new in 5.1.7
shShowUndisplayableLanguages, // TODO 5.2.5+: only if not unicode
// new in 5.1.13
shSetupLogging,
// new in 5.2.1
shSignedUninstaller,
// new in 5.3.8
shUsePreviousLanguage,
// new in 5.3.9
shDisableWelcomePage,
// Obsolete flags
shUninstallable, // TODO removed in 5.3.10
shDisableDirPage, // TODO removed in 5.3.3
shDisableProgramGroupPage, // TODO removed in 5.3.3
shDisableAppendDir, // TODO removed in 4.1.2
shAdminPrivilegesRequired, // TODO removed in 3.0.4
shAlwaysCreateUninstallIcon, // TODO removed in 3.0.0
shCreateUninstallRegKey, // TODO removed in 5.3.8
shBzipUsed, // only in [2.0.17, 4.1.5)
shShowLanguageDialog, // only in [4.0.0, 4.0.10)
shDetectLanguageUsingLocale, // only in [4.0.1, 4.0.10)
// only in very old versions:
shDisableDirExistsWarning,
shBackSolid,
shOverwriteUninstRegEntries,
)
NAMED_ENUM(SetupHeaderOptions::Enum)
FLAGS(Architectures,
ArchitectureUnknown,
ArchitectureX86,
ArchitectureAmd64,
ArchitectureIA64,
)
NAMED_ENUM(Architectures::Enum)
struct SetupHeader {
// Setup data header.
std::string appName;
std::string appVerName;
std::string appId;
std::string appCopyright;
std::string appPublisher;
std::string appPublisherURL;
std::string appSupportPhone;
std::string appSupportURL;
std::string appUpdatesURL;
std::string appVersion;
std::string defaultDirName;
std::string defaultGroupName;
std::string uninstallIconName;
std::string baseFilename;
std::string uninstallFilesDir;
std::string uninstallDisplayName;
std::string uninstallDisplayIcon;
std::string appMutex;
std::string defaultUserInfoName;
std::string defaultUserInfoOrg;
std::string defaultUserInfoSerial;
std::string appReadmeFile;
std::string appContact;
std::string appComments;
std::string appModifyPath;
std::string createUninstallRegKey;
std::string uninstallable;
std::string licenseText;
std::string infoBeforeText;
std::string infoAfterText;
std::string signedUninstallerSignature;
std::string compiledCodeText;
std::bitset<256> leadBytes;
size_t numLanguageEntries;
size_t numCustomMessageEntries;
size_t numPermissionEntries;
size_t numTypeEntries;
size_t numComponentEntries;
size_t numTaskEntries;
size_t numDirEntries;
size_t numFileEntries;
size_t numFileLocationEntries;
size_t numIconEntries;
size_t numIniEntries;
size_t numRegistryEntries;
size_t numInstallDeleteEntries;
size_t numUninstallDeleteEntries;
size_t numRunEntries;
size_t numUninstallRunEntries;
size_t licenseSize;
size_t infoBeforeSize;
size_t infoAfterSize;
SetupVersionData minVersion;
SetupVersionData onlyBelowVersion;
Color backColor;
Color backColor2;
Color wizardImageBackColor;
Color wizardSmallImageBackColor;
enum PasswordType {
PlainPassword,
Md5Password,
Sha1Password
};
union {
s32 password; // probably CRC32
MD5Digest passwordMd5;
SHA1Digest passwordSha1;
};
PasswordType passwordType;
SetupSalt passwordSalt;
s64 extraDiskSpaceRequired;
size_t slicesPerDisk;
enum InstallMode {
NormalInstallMode,
SilentInstallMode,
VerySilentInstallMode,
};
InstallMode installMode;
enum UninstallLogMode {
AppendLog,
NewLog,
OverwriteLog
};
UninstallLogMode uninstallLogMode;
enum UninstallStyle {
ClassicStyle,
ModernStyle
};
UninstallStyle uninstallStyle;
enum AutoBoolean {
Auto,
No,
Yes
};
AutoBoolean dirExistsWarning;
enum Privileges {
NoPrivileges,
PowerUserPrivileges,
AdminPriviliges,
LowestPrivileges
};
Privileges privilegesRequired;
AutoBoolean showLanguageDialog;
enum LanguageDetection {
UILanguage,
LocaleLanguage,
NoLanguageDetection
};
LanguageDetection languageDetectionMethod;
enum CompressionMethod {
Stored,
Zlib,
BZip2,
LZMA1,
LZMA2,
Unknown
};
CompressionMethod compressMethod;
Architectures architecturesAllowed;
Architectures architecturesInstallIn64BitMode;
u64 signedUninstallerOrigSize;
u32 signedUninstallerHdrChecksum;
AutoBoolean disableDirPage;
AutoBoolean disableProgramGroupPage;
size_t uninstallDisplaySize;
SetupHeaderOptions options;
void load(std::istream & is, const InnoVersion & version);
};
NAMED_ENUM(SetupHeader::PasswordType)
NAMED_ENUM(SetupHeader::InstallMode)
NAMED_ENUM(SetupHeader::UninstallLogMode)
NAMED_ENUM(SetupHeader::UninstallStyle)
NAMED_ENUM(SetupHeader::AutoBoolean)
NAMED_ENUM(SetupHeader::Privileges)
NAMED_ENUM(SetupHeader::LanguageDetection)
NAMED_ENUM(SetupHeader::CompressionMethod)
#endif // INNOEXTRACT_SETUPHEADER_HPP

804
src/SetupHeaderFormat.hpp

@ -1,84 +1,245 @@
#include <vector>
#include <boost/utility/enable_if.hpp>
#include <boost/static_assert.hpp>
#include "Types.h"
#include "SetupHeader.hpp"
#include "LoadingUtils.hpp"
#include "Enum.hpp"
#include "Output.hpp"
#include <string>
#include <bitset>
#include <iostream>
template <class Enum>
struct EnumValueMap {
typedef Enum enum_type;
typedef Enum flag_type;
};
#include <boost/utility/enable_if.hpp>
#include <boost/integer.hpp>
#include <boost/integer/static_log2.hpp>
#include <boost/integer/static_min_max.hpp>
#include <boost/integer_traits.hpp>
#define STORED_ENUM_MAP(MapName, Default, ...) \
struct MapName : public EnumValueMap<typeof(Default)> { \
static const flag_type default_value; \
static const flag_type values[]; \
static const size_t count; \
}; \
const MapName::flag_type MapName::default_value = Default; \
const MapName::flag_type MapName::values[] = { __VA_ARGS__ }; \
const size_t MapName::count = ARRAY_SIZE(MapName::values)
#pragma pack(push,1)
#define STORED_FLAGS_MAP(MapName, Flag0, ...) STORED_ENUM_MAP(MapName, Flag0, Flag0, ## __VA_ARGS__)
/*
// 2.0.8, 2.0.11
enum SetupHeaderOption_20008 {
shDisableStartupPrompt,
shUninstallable,
shCreateAppDir,
shDisableDirPage,
shDisableProgramGroupPage,
shAllowNoIcons,
shAlwaysRestart,
shAlwaysUsePersonalGroup,
shWindowVisible,
shWindowShowCaption,
shWindowResizable,
shWindowStartMaximized,
shEnableDirDoesntExistWarning,
shDisableAppendDir,
shPassword,
shAllowRootDirectory,
shDisableFinishedPage,
shAdminPrivilegesRequired,
shAlwaysCreateUninstallIcon,
shChangesAssociations,
shCreateUninstallRegKey,
shUsePreviousAppDir,
shBackColorHorizontal,
shUsePreviousGroup,
shUpdateUninstallLogAppName,
shUsePreviousSetupType,
shDisableReadyMemo,
shAlwaysShowComponentsList,
shFlatComponentsList,
shShowComponentSizes,
shUsePreviousTasks,
shDisableReadyPage,
shAlwaysShowDirOnReadyPage,
shAlwaysShowGroupOnReadyPage,
template <class Mapping>
struct StoredEnum {
u32 value;
public:
typedef Mapping mapping_type;
typedef typename Mapping::enum_type enum_type;
static const size_t size = Mapping::count;
inline StoredEnum(std::istream & is) {
value = loadNumber<u8>(is); // TODO use larger types for larger enums
}
enum_type get() {
if(value < size) {
return Mapping::values[value];
}
warning << "warning: unexpected " << EnumNames<enum_type>::name << " value: " << value;
return Mapping::default_value;
}
};
// 5.2.3
enum SetupHeaderOption_50203 {
template <size_t Bits>
class StoredBitfield {
typedef u8 base_type;
static const size_t base_size = sizeof(base_type) * 8;
static const size_t count = (Bits + (base_size - 1)) / base_size; // ceildiv
base_type bits[count];
public:
static const size_t size = Bits;
inline StoredBitfield(std::istream & is) {
for(size_t i = 0; i < count; i++) {
bits[i] = loadNumber<base_type>(is);
}
}
inline u64 getLowerBits() const {
BOOST_STATIC_ASSERT(sizeof(u64) % sizeof(base_type) == 0);
u64 result = 0;
for(size_t i = 0; i < std::min(sizeof(u64) / sizeof(base_type), count); i++) {
result |= (u64(bits[i]) << (i * base_size));
}
return result;
}
inline std::bitset<size> getBitSet() const {
static const size_t ulong_size = sizeof(unsigned long) * 8;
BOOST_STATIC_ASSERT(base_size % ulong_size == 0 || base_size < ulong_size);
std::bitset<size> result(0);
for(size_t i = 0; i < count; i++) {
for(size_t j = 0; j < ceildiv(base_size, ulong_size); j++) {
result |= std::bitset<size>(static_cast<unsigned long>(bits[i] >> (j * ulong_size)))
<< ((i * base_size) + (j * ulong_size));
}
}
return result;
}
};
template <class Mapping>
class StoredFlags : private StoredBitfield<Mapping::count> {
public:
typedef Mapping mapping_type;
typedef typename Mapping::enum_type enum_type;
typedef Flags<enum_type> flag_type;
inline StoredFlags(std::istream & is) : StoredBitfield<Mapping::count>(is) { }
flag_type get() {
u64 bits = this->getLowerBits();
flag_type result = 0;
for(size_t i = 0; i < this->size; i++) {
if(bits & (u64(1) << i)) {
result |= Mapping::values[i];
bits &= ~(u64(1) << i);
}
}
if(bits) {
warning << "unexpected " << EnumNames<enum_type>::name << " flags: " << std::hex << bits << std::dec;
}
return result;
}
};
template <class Enum>
class StoredFlagReader {
public:
typedef Enum enum_type;
typedef Flags<enum_type> flag_type;
std::vector<enum_type> mappings;
void add(enum_type flag) {
mappings.push_back(flag);
}
flag_type get(std::istream & is) {
u64 bits = 0;
/*
if(mappings.size() <= 32) {
bits = loadNumber<u32>(is);
} else if(mappings.size() <= 256) {
bits = loadNumber<u64>(is);
for(size_t i = 1; i < 4; i++) {
u64 temp = loadNumber<u64>(is);
if(temp) {
warning << "unexpected " << EnumNames<enum_type>::name << " flags: " << std::hex << bits << std::dec << " @ " << i;
}
}
} else {
error << "error reading " << EnumNames<enum_type>::name << ": too many flags: " << mappings.size();
bits = 0;
}*/
typedef u8 stored_type;
static const size_t stored_bits = sizeof(stored_type) * 8;
for(size_t i = 0; i < ceildiv(mappings.size(), stored_bits); i++) {
bits |= u64(load<stored_type>(is)) << (i * stored_bits);
}
std::cout << "read " << mappings.size() << " flags: " << std::hex << bits << std::dec << std::endl;
flag_type result = 0;
for(size_t i = 0; i < mappings.size(); i++) {
if(bits & (u64(1) << i)) {
result |= mappings[i];
bits &= ~(u64(1) << i);
}
}
if(bits) {
warning << "unexpected " << EnumNames<enum_type>::name << " flags: " << std::hex << bits << std::dec;
}
return result;
}
};
template <class Enum>
class StoredFlagReader<Flags<Enum> > : public StoredFlagReader<Enum> { };
/*
enum _SetupHeaderOption {
shDisableStartupPrompt,
shUninstallable,
shUninstallable, // TODO removed in 5.3.10
shCreateAppDir,
shDisableDirPage,
shDisableProgramGroupPage,
shDisableDirPage, // TODO removed in 5.3.3
shDisableDirExistsWarning, // TODO only in 1.2.10, not in 1.3.25
shDisableProgramGroupPage, // TODO removed in 5.3.3
shAllowNoIcons,
shAlwaysRestart,
shAlwaysRestart, // TODO missing in [3.0.0, 3.0.3)
shBackSolid, // TODO only in 1.2.10, not in 1.3.25
shAlwaysUsePersonalGroup,
shWindowVisible,
shWindowShowCaption,
shWindowResizable,
shWindowStartMaximized,
shEnableDirDoesntExistWarning,
// -shDisableAppendDir
shDisableAppendDir, // TODO removed in 4.1.2
shPassword,
shAllowRootDirectory,
shDisableFinishedPage,
// -shAdminPrivilegesRequired
// -shAlwaysCreateUninstallIcon
shChangesAssociations,
shCreateUninstallRegKey,
shAdminPrivilegesRequired, // TODO removed in 3.0.4, 1.2.10: win32-only
shAlwaysCreateUninstallIcon, // TODO removed in 3.0.0, 1.2.10: win32-only
shOverwriteUninstRegEntries, // TODO only in 1.2.10, win32-only, not in 1.3.25
shChangesAssociations, // TODO 1.2.10: win32-only
// new after 1.2.16, in 1.3.25
shCreateUninstallRegKey, // TODO removed in 5.3.8
shUsePreviousAppDir,
shBackColorHorizontal,
shUsePreviousGroup,
shUpdateUninstallLogAppName,
// new after 1.3.26
shUsePreviousSetupType,
shDisableReadyMemo,
shAlwaysShowComponentsList,
@ -88,66 +249,276 @@ enum SetupHeaderOption_50203 {
shDisableReadyPage,
shAlwaysShowDirOnReadyPage,
shAlwaysShowGroupOnReadyPage,
// New:
// only in [2.0.17, 4.1.5)
shBzipUsed,
// new in 2.0.18
shAllowUNCPath,
// new in 3.0.0
shUserInfoPage,
shUsePreviousUserInfo,
// new in 3.0.1
shUninstallRestartComputer,
// new in 3.0.3
shRestartIfNeededByRun,
// new in 3.0.6.1
shShowTasksTreeLines,
// only in [4.0.0, 4.0.10)
shShowLanguageDialog,
// only in [4.0.1, 4.0.10)
shDetectLanguageUsingLocale,
// new in 4.0.9
shAllowCancelDuringInstall,
// new in 4.1.3
shWizardImageStretch,
// new in 4.1.8
shAppendDefaultDirName,
shAppendDefaultGroupName,
// new in 4.2.2
shEncryptionUsed,
// new in 5.0.4
shChangesEnvironment,
shShowUndisplayableLanguages,
// new in 5.1.7
shShowUndisplayableLanguages, // TODO 5.2.5+: only if not unicode
// new in 5.1.13
shSetupLogging,
// new in 5.2.1
shSignedUninstaller,
};
typedef u8 MD5Digest[16];
typedef u8 SetupSalt[8];
// new in 5.3.8
shUsePreviousLanguage,
// new in 5.3.9
shDisableWelcomePage,
};*/
// 2.0.8, 2.0.11
struct SetupVersionData {
s32 WinVersion, NTVersion; // Cardinal
s16 NTServicePack; // Word
};
typedef StoredBitfield<256> CharSet;
STORED_ENUM_MAP(StoredInstallMode, SetupHeader::NormalInstallMode,
SetupHeader::NormalInstallMode,
SetupHeader::SilentInstallMode,
SetupHeader::VerySilentInstallMode
);
STORED_ENUM_MAP(StoredUninstallLogMode, SetupHeader::AppendLog,
SetupHeader::AppendLog,
SetupHeader::NewLog,
SetupHeader::OverwriteLog
);
STORED_ENUM_MAP(StoredUninstallStyle, SetupHeader::ClassicStyle,
SetupHeader::ClassicStyle,
SetupHeader::ModernStyle
);
STORED_ENUM_MAP(StoredDirExistsWarning, SetupHeader::Auto,
SetupHeader::Auto,
SetupHeader::No,
SetupHeader::Yes
);
// pre- 5.3.7
STORED_ENUM_MAP(StoredPrivileges0, SetupHeader::NoPrivileges,
SetupHeader::NoPrivileges,
SetupHeader::PowerUserPrivileges,
SetupHeader::AdminPriviliges,
);
// post- 5.3.7
STORED_ENUM_MAP(StoredPrivileges1, SetupHeader::NoPrivileges,
SetupHeader::NoPrivileges,
SetupHeader::PowerUserPrivileges,
SetupHeader::AdminPriviliges,
SetupHeader::LowestPrivileges
);
STORED_ENUM_MAP(StoredShowLanguageDialog, SetupHeader::Yes,
SetupHeader::Yes,
SetupHeader::No,
SetupHeader::Auto
);
STORED_ENUM_MAP(StoredLanguageDetectionMethod, SetupHeader::UILanguage,
SetupHeader::UILanguage,
SetupHeader::LocaleLanguage,
SetupHeader::NoLanguageDetection
);
STORED_FLAGS_MAP(StoredArchitectures,
ArchitectureUnknown,
ArchitectureX86,
ArchitectureAmd64,
ArchitectureIA64
);
STORED_ENUM_MAP(StoredRestartComputer, SetupHeader::Auto,
SetupHeader::Auto,
SetupHeader::No,
SetupHeader::Yes
);
// pre-4.2.5
STORED_ENUM_MAP(StoredCompressionMethod0, SetupHeader::Unknown,
SetupHeader::Zlib,
SetupHeader::BZip2,
SetupHeader::LZMA1
);
// 4.2.5
STORED_ENUM_MAP(StoredCompressionMethod1, SetupHeader::Unknown,
SetupHeader::Stored,
SetupHeader::BZip2,
SetupHeader::LZMA1
);
// [4.2.6 5.3.9)
STORED_ENUM_MAP(StoredCompressionMethod2, SetupHeader::Unknown,
SetupHeader::Stored,
SetupHeader::Zlib,
SetupHeader::BZip2,
SetupHeader::LZMA1
);
// 5.3.9+
STORED_ENUM_MAP(StoredCompressionMethod3, SetupHeader::Unknown,
SetupHeader::Stored,
SetupHeader::Zlib,
SetupHeader::BZip2,
SetupHeader::LZMA1,
SetupHeader::LZMA2
);
STORED_ENUM_MAP(StoredDisablePage, SetupHeader::Auto,
SetupHeader::Auto,
SetupHeader::No,
SetupHeader::Yes
);
// 2.0.8, 2.0.11
struct SetupHeader_20008 {
/*
struct SetupHeader {
union {
struct {
std::string AppName, AppVerName, AppId, AppCopyright; // String TODO 1.2.10: PChar
std::string AppPublisher, AppPublisherURL; // String TODO not in 1.2.10
std::string AppSupportPhone; // String TODO new in 5.1.13
std::string AppSupportURL, AppUpdatesURL, AppVersion; // String TODO not in 1.2.10
std::string DefaultDirName, DefaultGroupName; // String
std::string UninstallIconName; // String TODO removed in 3.0.0
std::string BaseFilename; //String
std::string LicenseText, InfoBeforeText, InfoAfterText, UninstallFilesDir,
UninstallDisplayName, UninstallDisplayIcon, AppMutex; // String TODO not in 1.2.10
std::string DefaultUserInfoName, DefaultUserInfoOrg; // String TODO new in 3.0.0
std::string DefaultUserInfoSerial, CompiledCodeText; // String TODO new in 3.0.6.1
std::string AppReadmeFile, AppContact, AppComments, AppModifyPath; // String TODO new in 4.2.4
std::string SignedUninstallerSignature; // String TODO new in 5.2.1
};
struct { // TODO 5.2.5+
const size_t numstrings;
std::wstring AppName, AppVerName, AppId, AppCopyright, AppPublisher, AppPublisherURL,
AppSupportPhone, AppSupportURL, AppUpdatesURL, AppVersion, DefaultDirName,
DefaultGroupName, BaseFilename, UninstallFilesDir, UninstallDisplayName,
UninstallDisplayIcon, AppMutex, DefaultUserInfoName, DefaultUserInfoOrg,
DefaultUserInfoSerial, AppReadmeFile, AppContact, AppComments,
AppModifyPath; // String / WideString
std::string CreateUninstallRegKey; // String / WideString TODO new in 5.3.8
std::string Uninstallable; // String / WideString TODO new in 5.3.10
std::string LicenseText, InfoBeforeText, InfoAfterText; // AnsiString
std::string SignedUninstallerSignature; // AnsiString TODO removed in 5.3.10
std::string CompiledCodeText; // AnsiString
};
std::string AppName, AppVerName, AppId, AppCopyright, AppPublisher, AppPublisherURL,
AppSupportURL, AppUpdatesURL, AppVersion, DefaultDirName,
DefaultGroupName, UninstallIconName, BaseFilename, LicenseText,
InfoBeforeText, InfoAfterText, UninstallFilesDir, UninstallDisplayName,
UninstallDisplayIcon, AppMutex; // String
};
CharSet LeadBytes;
CharSet LeadBytes; // set of Char TODO 5.2.5+: set of AnsiChar, only exists if not unicode
s32 NumTypeEntries, NumComponentEntries, NumTaskEntries; // Integer
s32 NumLanguageEntries; // Integer TODO new in 4.0.0
s32 NumCustomMessageEntries; // Integer TODO new in 4.2.1
s32 NumPermissionEntries; // Integer TODO new in 4.1.0
s32 NumTypeEntries, NumComponentEntries, NumTaskEntries; // Integer TODO not in 1.2.10, not in 1.3.25
s32 NumDirEntries, NumFileEntries, NumFileLocationEntries, NumIconEntries,
NumIniEntries, NumRegistryEntries, NumInstallDeleteEntries,
NumUninstallDeleteEntries, NumRunEntries, NumUninstallRunEntries; // Integer
SetupVersionData MinVersion, OnlyBelowVersion;
s32 BackColor, BackColor2, WizardImageBackColor; // LongInt
s32 WizardSmallImageBackColor; // LongInt
s32 Password; // LongInt
s32 ExtraDiskSpaceRequired; // LongInt
u8 InstallMode; // (imNormal, imSilent, imVerySilent);
u8 UninstallLogMode; // (lmAppend, lmNew, lmOverwrite);
u8 UninstallStyle; // (usClassic, usModern);
u8 DirExistsWarning; // (ddAuto, ddNo, ddYes);
u64 Options; // set of SetupHeaderOption_20008
}; */
u32 LicenseSize, InfoBeforeSize, InfoAfterSize; // Cardinal TODO only in 1.2.10
union {
LegacySetupVersionData MinVersion, OnlyBelowVersion; // TODO only in 1.2.10
SetupVersionData MinVersion, OnlyBelowVersion;
};
s32 BackColor; // LongInt
s32 BackColor2; // LongInt TODO not in 1.2.10
s32 WizardImageBackColor; // LongInt
s32 WizardSmallImageBackColor; // LongInt TODO removed in 4.0.4, not in 1.2.10, not in 1.3.25
union {
s32 Password; // LongInt TODO removed in 4.2.0
MD5Digest PasswordHash; // TODO only in [4.2.0, 5.3.9)
SHA1Digest PasswordHash; // TODO new in 5.3.9
};
SetupSalt PasswordSalt; // TODO new in 4.2.2
s32 ExtraDiskSpaceRequired; // LongInt TODO from 4.0.0: Integer64
s32 SlicesPerDisk; // Integer TODO new in 4.0.0
StoredEnum<InstallMode> installMode; // (imNormal, imSilent, imVerySilent) TODO removed in 5.0.0, not in 1.2.10, not in 1.3.25
StoredEnum<UninstallLogMode> uninstallLogMode; // (lmAppend, lmNew, lmOverwrite) TODO not in 1.2.10
StoredEnum<UninstallStyle> uninstallStyle; // (usClassic, usModern) TODO removed in 5.0.0, not in 1.2.10, not in 1.3.25
StoredEnum<DirExistsWarning> dirExistsWarning; // (ddAuto, ddNo, ddYes) TODO not in 1.2.10
StoredEnum<RestartComputer> restartComputer; // (rcAuto, rcNo, rcYes) TODO only in [3.0.0, 3.0.3)?
StoredEnum<PrivilegesRequired> privilegesRequired; // (prNone, prPowerUser, prAdmin) TODO new in 3.0.4
StoredEnum<ShowLanguageDialog> showLanguageDialog; // (slYes, slNo, slAuto) TODO new in 4.0.10
StoredEnum<LanguageDetectionMethod> languageDetectionMethod; // (ldUILanguage, ldLocale, ldNone) TODO new in 4.0.10
StoredEnum<CompressMethod> compressMethod; // CompressionMethod TODO new in 4.1.5
StoredFlags<SetupProcessorArchitecture> architecturesAllowed, architecturesInstallIn64BitMode; // set of SetupProcessorArchitecture TODO new in 5.1.0
s32 signedUninstallerOrigSize; // LongWord TODO only in [5.2.1, 5.3.10)
u32 signedUninstallerHdrChecksum; // DWORD TODO only in [5.2.1, 5.3.10)
StoredEnum<SetupDisablePage> disableDirPage, disableProgramGroupPage; // new in 5.3.3
u32 UninstallDisplaySize; // Cardinal TODO new in 5.3.6
StoredFlags<SetupHeaderOption> options; // set of SetupHeaderOption
};
*/
/*
#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*(array)))
// ---------------------------------------------------------------------------------------
/* TODO remove:
* - TSetupHeader
* - TSetupVersionData
* - TSetupHeaderOption
* - TSetupProcessorArchitecture
* - SetupHeaderStrings
* - SetupID
* - TSetupID
*/
/*
template <class Enum>
struct enum_size { };
@ -223,218 +594,9 @@ static std::ostream & operator<<(std::ostream & os, EnumSet<Enum> rhs) {
return os << rhs.bitset();
}
template <class Enum>
struct EnumValueMap {
typedef Enum enum_type;
typedef Enum flag_type;
};
template <class Enum>
struct EnumValueMap<EnumSet<Enum> > {
typedef Enum enum_type;
typedef EnumSet<Enum> flag_type;
};*/
namespace boost {
template <class T>
class integer_traits<const T> : public integer_traits<T> { };
}
template <size_t N, class Type = void, class Enable = void>
struct is_power_of_two {
static const bool value = false;
};
template <size_t N, class Type>
struct is_power_of_two<N, Type, typename boost::enable_if_c<(N & (N - 1)) == 0>::type> {
static const bool value = true;
typedef Type type;
};
template <size_t N, class Enable = void>
struct log_next_power_of_two {
static const size_t value = boost::static_log2<N>::value + 1;
};
template <size_t N>
struct log_next_power_of_two<N, typename boost::enable_if<is_power_of_two<N> >::type> {
static const size_t value = boost::static_log2<N>::value;
};
template <size_t N, class Enable = void>
struct next_power_of_two {
static const size_t value = size_t(1) << (boost::static_log2<N>::value + 1);
};
template <size_t N>
struct next_power_of_two<N, typename boost::enable_if<is_power_of_two<N> >::type> {
static const size_t value = N;
};
template <size_t Bits> struct fast_type_impl { };
template <> struct fast_type_impl<8> { typedef uint_fast8_t type; };
template <> struct fast_type_impl<16> { typedef uint_fast16_t type; };
template <> struct fast_type_impl<32> { typedef uint_fast32_t type; };
template <> struct fast_type_impl<64> { typedef uint_fast64_t type; };
template <> struct fast_type_impl<128> { typedef __uint128_t type; };
template <size_t Bits>
struct fast_type : public fast_type_impl< boost::static_unsigned_max<8, next_power_of_two<Bits>::value>::value > { };
struct BitsetConverter {
private:
typedef ptrdiff_t shift_type;
typedef size_t index_type;
template <class Combiner, class Entry>
struct IterateEntries {
static const typename Combiner::type value = Combiner::template combine<Entry, (IterateEntries<Combiner, typename Entry::next>::value)>::value;
};
template <class Combiner> struct IterateEntries<Combiner, void> { static const typename Combiner::type value = Combiner::base; };
template <class Type, Type Base> struct Combiner { typedef Type type; static const Type base = Base; };
template<class Getter, class Type>
struct MaxCombiner : public Combiner<Type, boost::integer_traits<Type>::const_min> {
template <class Entry, Type accumulator>
struct combine { static const Type value = boost::static_signed_max<Getter::template get<Entry>::value, accumulator>::value; };
};
template<class Getter, class Type>
struct MinCombiner : public Combiner<Type, boost::integer_traits<Type>::const_max> {
template <class Entry, Type accumulator>
struct combine { static const Type value = boost::static_signed_min<Getter::template get<Entry>::value, accumulator>::value; };
};
struct ShiftGetter { template<class Entry> struct get { static const shift_type value = Entry::shift; }; };
struct FromGetter { template<class Entry> struct get { static const index_type value = Entry::from; }; };
struct ToGetter { template<class Entry> struct get { static const index_type value = Entry::to; }; };
template<shift_type Shift, class Type>
struct ShiftMaskCombiner : public Combiner<Type, Type(0)> {
template <class Entry, Type mask>
struct combine { static const Type value = mask | ( (Entry::shift == Shift) ? (Type(1) << Entry::from) : Type(0) ); };
};
template<class List>
struct Builder;
template<index_type From, index_type To, class Next = void>
struct Entry {
typedef Entry<From, To, Next> This;
static const index_type from = From;
static const index_type to = To;
typedef Next next;
static const shift_type shift = shift_type(from) - shift_type(to);
static const shift_type max_shift = IterateEntries<MaxCombiner<ShiftGetter, shift_type>, This>::value;
static const shift_type min_shift = IterateEntries<MinCombiner<ShiftGetter, shift_type>, This>::value;
static const index_type max_from = IterateEntries<MaxCombiner<FromGetter, index_type>, This>::value;
typedef typename fast_type<max_from + 1>::type in_type;
static const index_type max_to = IterateEntries<MaxCombiner<ToGetter, index_type>, This>::value;
typedef typename fast_type<max_to + 1>::type out_type;
template<shift_type Shift> struct ShiftMask { static const in_type value = IterateEntries<ShiftMaskCombiner<Shift, in_type>, This>::value; };
template <shift_type Shift> inline static typename boost::enable_if_c<(Shift >= shift_type(0)), out_type>::type evaluate(in_type value) {
return out_type((value & ShiftMask<Shift>::value) >> Shift);
}
template <shift_type Shift> inline static typename boost::enable_if_c<(Shift < shift_type(0)), out_type>::type evaluate(in_type value) {
return out_type(value & ShiftMask<Shift>::value) << (-Shift);
}
template<shift_type Shift, class Enable = void> struct NextShift { static const shift_type value = Shift + 1; };
template<shift_type Shift>
struct NextShift<Shift, typename boost::enable_if_c<Shift != max_shift && ShiftMask<Shift + 1>::value == in_type(0)>::type > {
static const shift_type value = NextShift<Shift + 1>::value;
};
template <shift_type Shift>
inline static typename boost::enable_if_c<(NextShift<Shift>::value != max_shift + 1), out_type>::type map(in_type value) {
return evaluate<Shift>(value) | (map<NextShift<Shift>::value>(value));
}
template <shift_type Shift>
inline static typename boost::enable_if_c<(NextShift<Shift>::value == max_shift + 1), out_type>::type map(in_type value) {
return evaluate<Shift>(value);
}
public:
typedef Builder<This> add;
static out_type convert(in_type value) {
return map<min_shift>(value);
}
};
template<class List>
struct Builder {
template<index_type From, index_type To>
struct map : public Entry<From, To, List> { };
template<index_type To, class Current = List>
struct value : public Entry<Current::from + 1, To, Current> { };
template<index_type To>
struct value<To, void> : public Entry<0, To> { };
};
public:
typedef Builder<void> add;
};
/*
#define STORED_ENUM_MAP(MapName, Default, ...) \
struct MapName : public EnumValueMap<typeof(Default)> { \
static const flag_type default_value; \
static const flag_type values[]; \
static const size_t count; \
}; \
const MapName::flag_type MapName::default_value = Default; \
const MapName::flag_type MapName::values[] = { __VA_ARGS__ }; \
const size_t MapName::count = ARRAY_SIZE(MapName::values)
template <class Enum>
struct EnumNames {
const size_t count;
const char * name;
const char * names[0];
};
#define ENUM_NAMES(Enum, Default, ...)
enum UninstallLogMode { lmAppend, lmNew, lmOverwrite, lmUnknown };
ENUM_NAMES(UninstallLogMode, "Append", "New", "Overwrite");
enum DirExistsWarning { ddAuto, ddNo, ddYes, ddUnknown };
ENUM_NAMES(DirExistsWarning, "Auto", "No", "Yes");
STORED_ENUM_MAP(UninstallLogModeMapper, lmUnknown, lmAppend, lmNew, lmOverwrite);
STORED_ENUM_MAP(DirExistsWarningMapper, ddUnknown, ddAuto, ddNo, ddYes);
@ -574,42 +736,4 @@ struct StoredFlags {
};*/
/*
// 5.2.3
struct SetupHeader_50203 {
std::string AppName, AppVerName, AppId, AppCopyright, AppPublisher, AppPublisherURL,
AppSupportPhone, AppSupportURL, AppUpdatesURL, AppVersion, DefaultDirName,
DefaultGroupName, BaseFilename, LicenseText,
InfoBeforeText, InfoAfterText, UninstallFilesDir, UninstallDisplayName,
UninstallDisplayIcon, AppMutex, DefaultUserInfoName,
DefaultUserInfoOrg, DefaultUserInfoSerial, CompiledCodeText,
AppReadmeFile, AppContact, AppComments, AppModifyPath,
SignedUninstallerSignature;
CharSet LeadBytes;
s32 NumLanguageEntries, NumCustomMessageEntries, NumPermissionEntries,
NumTypeEntries, NumComponentEntries, NumTaskEntries, NumDirEntries,
NumFileEntries, NumFileLocationEntries, NumIconEntries, NumIniEntries,
NumRegistryEntries, NumInstallDeleteEntries, NumUninstallDeleteEntries,
NumRunEntries, NumUninstallRunEntries; // Integer
SetupVersionData MinVersion, OnlyBelowVersion;
s32 BackColor, BackColor2, WizardImageBackColor; // LongInt
MD5Digest PasswordHash;
u64 PasswordSalt; // array[0..7] of Byte
s64 ExtraDiskSpaceRequired; // Integer64
s32 SlicesPerDisk; // Integer
StoredEnum<UninstallLogModeMapper> uninstallLogMode; // (lmAppend, lmNew, lmOverwrite)
u8 DirExistsWarning; // (ddAuto, ddNo, ddYes)
u8 PrivilegesRequired; // (prNone, prPowerUser, prAdmin)
u8 ShowLanguageDialog; // (slYes, slNo, slAuto)
LanguageDetectionMethod: (ldUILanguage, ldLocale, ldNone);
CompressMethod: TSetupCompressMethod;
ArchitecturesAllowed, ArchitecturesInstallIn64BitMode: TSetupProcessorArchitectures;
SignedUninstallerOrigSize: LongWord;
SignedUninstallerHdrChecksum: DWORD;
u64 Options; // set of SetupHeaderOption_50203;
}; */
#pragma pack(pop)
//#pragma pack(pop)

38
src/SetupLoader.cpp

@ -8,9 +8,9 @@
#include "ExeReader.hpp"
#include "SetupLoaderFormat.hpp"
#include "Utils.hpp"
#include "Output.hpp"
using std::cout;
using std::cerr;
using std::string;
using std::endl;
using std::setw;
@ -22,17 +22,17 @@ bool SetupLoader::getOldOffsets(std::istream & is, Offsets & offsets) {
SetupLoaderHeader locator;
if(read(is.seekg(0x30), locator).fail()) {
cerr << "error reading exe header" << endl;
error << "error reading exe header";
return false;
}
if(locator.id != SetupLoaderHeaderMagic) {
cerr << "invalid exe header id: " << hex << locator.id << dec << endl;
cout << "invalid exe header id: " << hex << locator.id << dec << endl;
return false;
}
if(locator.offsetTableOffset != ~locator.notOffsetTableOffset) {
cerr << "offset table offset mismatch" << endl;
cout << "offset table offset mismatch" << endl;
return false;
}
@ -56,23 +56,23 @@ bool SetupLoader::getNewOffsets(std::istream & is, Offsets & offsets) {
bool SetupLoader::getOffsetsAt(std::istream & is, Offsets & offsets, size_t pos) {
if(is.seekg(pos).fail()) {
cerr << "invalid offset table offset" << endl;
error << "invalid offset table offset";
return false;
}
u32 magic;
if(read(is, magic).fail()) {
cerr << "error reading setup loader offset magic" << endl;
error << "error reading setup loader offset magic";
return false;
}
if(magic != SetupLoaderOffsetTableMagic) {
cerr << "invalid setup loader offset id: " << hex << magic << dec << endl;
error << "invalid setup loader offset id: " << hex << magic << dec;
return false;
}
u64 bigversion;
if(read(is, bigversion).fail()) {
cerr << "error reading setup loader offset bigversion" << endl;
error << "error reading setup loader offset bigversion";
return false;
}
@ -82,11 +82,11 @@ bool SetupLoader::getOffsetsAt(std::istream & is, Offsets & offsets, size_t pos)
switch(bigversion) {
case SetupLoaderOffsetTableID_20: {
case SetupLoaderOffsetTableID_10: {
SetupLoaderOffsetTable20 offsets20;
SetupLoaderOffsetTable10 offsets20;
if(read(is, offsets20).fail()) {
cerr << "error reading setup loader offsets v20" << endl;
error << "error reading setup loader offsets v20";
return false;
}
@ -106,7 +106,7 @@ bool SetupLoader::getOffsetsAt(std::istream & is, Offsets & offsets, size_t pos)
SetupLoaderOffsetTable40 offsets40;
if(read(is, offsets40).fail()) {
cerr << "error reading setup loader offsets v40" << endl;
error << "error reading setup loader offsets v40";
return false;
}
@ -127,7 +127,7 @@ bool SetupLoader::getOffsetsAt(std::istream & is, Offsets & offsets, size_t pos)
SetupLoaderOffsetTable40b offsets40b;
if(read(is, offsets40b).fail()) {
cerr << "error reading setup loader offsets v40" << endl;
error << "error reading setup loader offsets v40";
return false;
}
@ -142,7 +142,7 @@ bool SetupLoader::getOffsetsAt(std::istream & is, Offsets & offsets, size_t pos)
if(bigversion == SetupLoaderOffsetTableID_40c) {
if(read(is, expected).fail()) {
cerr << "error reading crc checksum" << endl;
error << "error reading crc checksum";
return false;
}
actual = lzma_crc32(reinterpret_cast<const uint8_t *>(&offsets40b), sizeof(offsets40b), actual);
@ -156,7 +156,7 @@ bool SetupLoader::getOffsetsAt(std::istream & is, Offsets & offsets, size_t pos)
SetupLoaderOffsetTable41 offsets41;
if(read(is, offsets41).fail()) {
cerr << "error reading setup loader offsets v40" << endl;
error << "error reading setup loader offsets v40";
return false;
}
@ -178,12 +178,12 @@ bool SetupLoader::getOffsetsAt(std::istream & is, Offsets & offsets, size_t pos)
SetupLoaderOffsetTable51 offsets51;
if(read(is, offsets51).fail()) {
cerr << "error reading setup loader offsets v40" << endl;
error << "error reading setup loader offsets v40";
return false;
}
if(offsets51.version != 1) {
cerr << "warning: unexpected setup loader offset table version: " << offsets51.version << endl;
error << "warning: unexpected setup loader offset table version: " << offsets51.version;
}
offsets.totalSize = offsets51.totalSize;
@ -201,14 +201,14 @@ bool SetupLoader::getOffsetsAt(std::istream & is, Offsets & offsets, size_t pos)
}
default: {
cerr << "unsupported setup loader offset table version: " << hex << bigversion << dec << endl;
error << "unsupported setup loader offset table version: " << hex << bigversion << dec;
return false;
}
}
if(actual != expected) {
cerr << "CRC32 mismatch in setup loader offsets" << endl;
error << "CRC32 mismatch in setup loader offsets";
return false;
} else {
cout << "setup loader offset table CRC32 match" << endl;

18
src/SetupLoader.hpp

@ -15,18 +15,18 @@ public:
struct Offsets {
size_t totalSize;
size_t totalSize; //!< Minimum expected size of the setup file
size_t exeOffset;
size_t exeCompressedSize;
size_t exeUncompressedSize;
s32 exeChecksum;
ChecksumMode exeChecksumMode;
size_t exeOffset; //!< Offset of compressed setup.e32
size_t exeCompressedSize; //!< Size of setup.e32 after compression
size_t exeUncompressedSize; //!< Size of setup.e32 before compression
s32 exeChecksum; //!< Checksum of setup.e32 before compression
ChecksumMode exeChecksumMode; //! Type of the checksum in exeChecksum
size_t messageOffset;
size_t messageOffset; // TODO document
size_t offset0;
size_t offset1;
size_t offset0; //!< Offset of embedded setup-0.bin data
size_t offset1; //!< Offset of embedded setup-1.bin data, or 0 when DiskSpanning=yes
};

22
src/SetupLoaderFormat.hpp

@ -9,7 +9,7 @@ const u32 SetupLoaderOffsetTableMagic = 0x506c4472;
const u32 SetupLoaderHeaderMagic = 0x6f6e6e49;
enum SetupLoaderOffsetTableID {
SetupLoaderOffsetTableID_20 = 0x7856658732305374l,
SetupLoaderOffsetTableID_10 = 0x7856658732305374l,
SetupLoaderOffsetTableID_40 = 0x7856658734305374l,
SetupLoaderOffsetTableID_40b = 0x7856658735305374l,
SetupLoaderOffsetTableID_40c = 0x7856658736305374l,
@ -19,7 +19,7 @@ enum SetupLoaderOffsetTableID {
// 2.0.8, 2.0.11, 2.0.17, 2.0.18
// 3.0.0, 3.0.1, 3.0.2, 3.0.3, 3.0.4, 3.0.5, 3.0.6, 3.0.7, 3.0.8
struct SetupLoaderOffsetTable20 {
struct SetupLoaderOffsetTable10 {
s32 totalSize;
s32 exeOffset;
s32 exeCompressedSize;
@ -58,7 +58,7 @@ struct SetupLoaderOffsetTable40b {
// 4.1.0, 4.1.1, 4.1.2, 4.1.3, 4.1.4, 4.1.5
//! added tableCrc
struct SetupLoaderOffsetTable40c : public SetupLoaderOffsetTable40b {
s32 tableCrc;
s32 tableCrc; //!< CRC32 of all prior fields in this structure
};
// 4.1.6, 4.1.7, 4.1.8
@ -73,7 +73,7 @@ struct SetupLoaderOffsetTable41 {
s32 exeCrc;
s32 offset0;
s32 offset1;
s32 tableCrc;
s32 tableCrc; //!< CRC32 of all prior fields in this structure
};
// 5.1.5, 5.1.7, 5.1.10, 5.1.13
@ -82,13 +82,13 @@ struct SetupLoaderOffsetTable41 {
//! added version
struct SetupLoaderOffsetTable51 {
u32 version; //!< = 1
u32 totalSize; //!< Minimum expected size of setup.exe
u32 exeOffset; //!< Offset of compressed setup.e32
u32 exeUncompressedSize; //!< Size of setup.e32 before compression
s32 exeCrc; //!< CRC of setup.e32 before compression
u32 offset0; //!< Offset of embedded setup-0.bin data
u32 offset1; //!< Offset of embedded setup-1.bin data, or 0 when DiskSpanning=yes
s32 tableCrc; //!< CRC of all prior fields in this record
u32 totalSize;
u32 exeOffset;
u32 exeUncompressedSize;
s32 exeCrc;
u32 offset0;
u32 offset1;
s32 tableCrc; //!< CRC32 of all prior fields in this structure
};
// 2.0.8, 2.0.11, 2.0.17, 2.0.18

2
src/Types.h

@ -11,4 +11,6 @@ typedef uint32_t u32;
typedef int64_t s64;
typedef uint64_t u64;
typedef u32 Color;
typedef std::ios_base strm;

10
src/UnDeflate.cpp

@ -11,7 +11,7 @@
#include <sstream>
#include <algorithm>
#include "liblzmadec/lzmadec.h"
//#include "liblzmadec/lzmadec.h"
#include "Types.h"
@ -215,7 +215,7 @@ int main(int argc, const char * argv[]) {
} while(false);
// Try to interpret as LZMA1 datastream.
do {
/*do {
u8 properties = u8(data[offset]);
@ -279,7 +279,7 @@ int main(int argc, const char * argv[]) {
case LZMADEC_OK:
case LZMADEC_STREAM_END:
case LZMADEC_BUF_ERROR: { */
case LZMADEC_BUF_ERROR: {
size_t filesize = bufsize - stream.avail_out;
@ -302,7 +302,7 @@ int main(int argc, const char * argv[]) {
/* }
} */
}
} while(false);
} while((ret == LZMADEC_BUF_ERROR || ret == LZMADEC_OK) && stream.avail_in);
@ -313,7 +313,7 @@ int main(int argc, const char * argv[]) {
lzmadec_end(&stream);
} while(false);
} while(false);*/
// Try to interpret as XZ datastream.
do {

72
src/Utils.hpp

@ -1,7 +1,12 @@
#ifndef INNOEXTRACT_UTILS_HPP
#define INNOEXTRACT_UTILS_HPP
#include <iostream>
#include <string>
#include "Output.hpp"
template <class T>
inline std::istream & read(std::istream & ifs, T & data) {
return ifs.read(reinterpret_cast<char *>(&data), sizeof(T));
@ -16,3 +21,70 @@ std::string safestring(const char (&data)[N]) {
return safestring(data, N);
}
#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*(array)))
struct Quoted {
const std::string & str;
Quoted(const std::string & _str) : str(_str) { }
};
inline std::ostream & operator<<(std::ostream & os, const Quoted & q) {
color::shell_command prev = color::current;
return os << '"' << color::green << q.str << prev << '"';
}
struct IfNotEmpty {
const std::string & name;
const std::string & value;
IfNotEmpty(const std::string & _name, const std::string & _value) : name(_name), value(_value) { }
};
inline std::ostream & operator<<(std::ostream & os, const IfNotEmpty & s) {
if(s.value.length() > 100) {
color::shell_command prev = color::current;
return os << s.name << ": " << color::white << s.value.length() << prev << " bytes" << std::endl;
} else if(!s.value.empty()) {
return os << s.name << ": " << Quoted(s.value) << std::endl;
} else {
return os;
}
}
template <class T>
struct _IfNot {
const std::string & name;
const T value;
const T excluded;
_IfNot(const std::string & _name, T _value, T _excluded) : name(_name), value(_value), excluded(_excluded) { }
};
template <class T>
inline std::ostream & operator<<(std::ostream & os, const _IfNot<T> & s) {
if(s.value != s.excluded) {
color::shell_command prev = color::current;
return os << s.name << ": " << color::cyan << s.value << prev << std::endl;
} else {
return os;
}
}
template <class T>
_IfNot<T> IfNot(const std::string & name, T value, T excluded) {
return _IfNot<T>(name, value, excluded);
}
template <class T>
_IfNot<T> IfNotZero(const std::string & name, T value) {
return _IfNot<T>(name, value, T(0));
}
template <class A, class B>
inline A ceildiv(A num, B denom) {
return A((num + (denom - 1)) / denom);
}
#endif // INNOEXTRACT_UTILS_HPP

181
src/Version.cpp

@ -0,0 +1,181 @@
#include "Version.hpp"
#include <cstring>
#include <boost/static_assert.hpp>
#include "Utils.hpp"
typedef char StoredLegacySetupDataVersion[12];
struct KnownLegacySetupDataVersion {
char name[13]; // terminating 0 byte is ignored
InnoVersionConstant version;
unsigned char bits;
};
const KnownLegacySetupDataVersion knownLegacySetupDataVersions[] = {
{ "i1.2.10--16\x1a", INNO_VERSION(1, 2, 10), 16 },
{ "i1.2.10--32\x1a", INNO_VERSION(1, 2, 10), 32 },
};
typedef char StoredSetupDataVersion[64];
struct KnownSetupDataVersion {
StoredSetupDataVersion name;
InnoVersionConstant version;
bool unicode;
};
const KnownSetupDataVersion knownSetupDataVersions[] = {
{ "Inno Setup Setup Data (1.3.25)", INNO_VERSION_EXT(1, 3, 25, 0) },
{ "Inno Setup Setup Data (2.0.8)", INNO_VERSION_EXT(2, 0, 8, 0) },
{ "Inno Setup Setup Data (2.0.11)", INNO_VERSION_EXT(2, 0, 11, 0) },
{ "Inno Setup Setup Data (2.0.17)", INNO_VERSION_EXT(2, 0, 17, 0) },
{ "Inno Setup Setup Data (2.0.18)", INNO_VERSION_EXT(2, 0, 18, 0) },
{ "Inno Setup Setup Data (3.0.0a)", INNO_VERSION_EXT(3, 0, 0, 0) },
{ "Inno Setup Setup Data (3.0.1)", INNO_VERSION_EXT(3, 0, 1, 0) },
{ "Inno Setup Setup Data (3.0.3)", INNO_VERSION_EXT(3, 0, 3, 0) },
{ "Inno Setup Setup Data (3.0.5)", INNO_VERSION_EXT(3, 0, 5, 0) },
{ "My Inno Setup Extensions Setup Data (3.0.6.1)", INNO_VERSION_EXT(3, 0, 6, 1) },
{ "Inno Setup Setup Data (4.0.0a)", INNO_VERSION_EXT(4, 0, 0, 0) },
{ "Inno Setup Setup Data (4.0.1)", INNO_VERSION_EXT(4, 0, 1, 0) },
{ "Inno Setup Setup Data (4.0.3)", INNO_VERSION_EXT(4, 0, 3, 0) },
{ "Inno Setup Setup Data (4.0.5)", INNO_VERSION_EXT(4, 0, 5, 0) },
{ "Inno Setup Setup Data (4.0.9)", INNO_VERSION_EXT(4, 0, 9, 0) },
{ "Inno Setup Setup Data (4.0.10)", INNO_VERSION_EXT(4, 0, 10, 0) },
{ "Inno Setup Setup Data (4.0.11)", INNO_VERSION_EXT(4, 0, 11, 0) },
{ "Inno Setup Setup Data (4.1.0)", INNO_VERSION_EXT(4, 1, 0, 0) },
{ "Inno Setup Setup Data (4.1.2)", INNO_VERSION_EXT(4, 1, 2, 0) },
{ "Inno Setup Setup Data (4.1.3)", INNO_VERSION_EXT(4, 1, 3, 0) },
{ "Inno Setup Setup Data (4.1.4)", INNO_VERSION_EXT(4, 1, 4, 0) },
{ "Inno Setup Setup Data (4.1.5)", INNO_VERSION_EXT(4, 1, 5, 0) },
{ "Inno Setup Setup Data (4.1.6)", INNO_VERSION_EXT(4, 1, 6, 0) },
{ "Inno Setup Setup Data (4.1.8)", INNO_VERSION_EXT(4, 1, 8, 0) },
{ "Inno Setup Setup Data (4.2.0)", INNO_VERSION_EXT(4, 2, 0, 0) },
{ "Inno Setup Setup Data (4.2.1)", INNO_VERSION_EXT(4, 2, 1, 0) },
{ "Inno Setup Setup Data (4.2.2)", INNO_VERSION_EXT(4, 2, 2, 0) },
{ "Inno Setup Setup Data (4.2.3)", INNO_VERSION_EXT(4, 2, 3, 0) },
{ "Inno Setup Setup Data (4.2.5)", INNO_VERSION_EXT(4, 2, 5, 0) },
{ "Inno Setup Setup Data (4.2.6)", INNO_VERSION_EXT(4, 2, 6, 0) },
{ "Inno Setup Setup Data (5.0.0)", INNO_VERSION_EXT(5, 0, 0, 0) },
{ "Inno Setup Setup Data (5.0.1)", INNO_VERSION_EXT(5, 0, 1, 0) },
{ "Inno Setup Setup Data (5.0.3)", INNO_VERSION_EXT(5, 0, 3, 0) },
{ "Inno Setup Setup Data (5.0.4)", INNO_VERSION_EXT(5, 0, 4, 0) },
{ "Inno Setup Setup Data (5.1.0)", INNO_VERSION_EXT(5, 1, 0, 0) },
{ "Inno Setup Setup Data (5.1.2)", INNO_VERSION_EXT(5, 1, 2, 0) },
{ "Inno Setup Setup Data (5.1.7)", INNO_VERSION_EXT(5, 1, 7, 0) },
{ "Inno Setup Setup Data (5.1.10)", INNO_VERSION_EXT(5, 1, 10, 0) },
{ "Inno Setup Setup Data (5.1.13)", INNO_VERSION_EXT(5, 1, 13, 0) },
{ "Inno Setup Setup Data (5.2.0)", INNO_VERSION_EXT(5, 2, 0, 0) },
{ "Inno Setup Setup Data (5.2.1)", INNO_VERSION_EXT(5, 2, 1, 0) },
{ "Inno Setup Setup Data (5.2.3)", INNO_VERSION_EXT(5, 2, 3, 0) },
{ "Inno Setup Setup Data (5.2.5)", INNO_VERSION_EXT(5, 2, 5, 0) },
{ "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) },
{ "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) },
{ "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) },
{ "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) },
{ "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) },
{ "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) },
{ "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) },
{ "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) },
{ "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) },
{ "Inno Setup Setup Data (5.4.2) (u)", INNO_VERSION_EXT(5, 4, 2, 0), true },
};
using std::cout;
using std::string;
using std::endl;
std::ostream & operator<<(std::ostream & os, const InnoVersion & v) {
os << (v.version >> 24) << '.' << ((v.version >> 16) & 0xff) << '.' << ((v.version >> 8) & 0xff);
if(v.version & 0xff) {
os << '.' << (v.version & 0xff);
}
if(v.unicode) {
os << " (unicode)";
}
if(v.bits != 32) {
os << " (" << int(v.bits) << "-bit)";
}
if(!v.known) {
os << " [unsupported]";
}
return os;
}
void InnoVersion::load(std::istream & is) {
BOOST_STATIC_ASSERT(sizeof(StoredLegacySetupDataVersion) <= sizeof(StoredSetupDataVersion));
StoredLegacySetupDataVersion legacyVersion;
is.read(legacyVersion, sizeof(legacyVersion));
if(legacyVersion[0] == 'i' && legacyVersion[sizeof(legacyVersion) - 1] == '\x1a') {
cout << "found legacy version: \"" << safestring(legacyVersion, sizeof(legacyVersion) - 1) << '"' << endl;
for(size_t i = 0; i < ARRAY_SIZE(knownLegacySetupDataVersions); i++) {
if(!memcmp(legacyVersion, knownLegacySetupDataVersions[i].name, sizeof(legacyVersion))) {
version = knownLegacySetupDataVersions[i].version;
bits = knownLegacySetupDataVersions[i].bits;
unicode = false;
known = true;
cout << "-> version is known" << endl;
return;
}
}
// TODO autodetect version
known = false;
cout << "-> unknown version" << endl;
throw new string("bad version");
}
StoredSetupDataVersion storedVersion;
memcpy(storedVersion, legacyVersion, sizeof(legacyVersion));
is.read(storedVersion + sizeof(legacyVersion), sizeof(storedVersion) - sizeof(legacyVersion));
cout << "found version: \"" << safestring(storedVersion) << '"' << endl;
for(size_t i = 0; i < ARRAY_SIZE(knownSetupDataVersions); i++) {
if(!memcmp(storedVersion, knownSetupDataVersions[i].name, sizeof(storedVersion))) {
version = knownSetupDataVersions[i].version;
bits = 32;
unicode = knownSetupDataVersions[i].unicode;
known = true;
cout << "-> version is known" << endl;
return;
}
}
// TODO autodetect version
known = false;
cout << "-> unknown version" << endl;
throw new string("bad version");
}

64
src/Version.hpp

@ -0,0 +1,64 @@
#ifndef INNOEXTRACT_VERSION_HPP
#define INNOEXTRACT_VERSION_HPP
#include <iostream>
#include <utility>
#include "Types.h"
typedef u32 InnoVersionConstant;
#define INNO_VERSION_EXT(a, b, c, d) ((u32(a) << 24) | (u32(b) << 16) | (u32(c) << 8) | u32(d))
#define INNO_VERSION(a, b, c) INNO_VERSION_EXT(a, b, c, 0)
struct InnoVersion {
InnoVersionConstant version;
char bits; // 16 or 32
bool unicode;
bool known;
inline InnoVersion() : known(false) { };
inline InnoVersion(InnoVersionConstant _version, bool _unicode = false, bool _known = false, char _bits = 32) : version(_version), unicode(_unicode), known(_known), bits(_bits) { };
inline InnoVersion(char a, char b, char c, char d = 0, bool _unicode = false, bool _known = false, char _bits = 32) : version(INNO_VERSION_EXT(a, b, c, d)), unicode(_unicode), known(_known), bits(_bits) { };
inline int a() { return version >> 24; }
inline int b() { return (version >> 16) & 0xff; }
inline int c() { return (version >> 8) & 0xff; }
inline int d() { return version & 0xff; }
void load(std::istream & is);
};
inline bool operator==(const InnoVersion & a, const InnoVersion & b) { return a.version == b.version; }
inline bool operator!=(const InnoVersion & a, const InnoVersion & b) { return !operator==(a, b); }
inline bool operator< (const InnoVersion & a, const InnoVersion & b) { return a.version < b.version; }
inline bool operator> (const InnoVersion & a, const InnoVersion & b) { return operator< (b, a); }
inline bool operator<=(const InnoVersion & a, const InnoVersion & b) { return !operator> (a, b); }
inline bool operator>=(const InnoVersion & a, const InnoVersion & b) { return !operator< (a, b); }
inline bool operator==(const InnoVersion & a, InnoVersionConstant b) { return a.version == b; }
inline bool operator!=(const InnoVersion & a, InnoVersionConstant b) { return !operator==(a, b); }
inline bool operator< (const InnoVersion & a, InnoVersionConstant b) { return a.version < b; }
inline bool operator> (const InnoVersion & a, InnoVersionConstant b) { return operator< (b, a); }
inline bool operator<=(const InnoVersion & a, InnoVersionConstant b) { return !operator> (a, b); }
inline bool operator>=(const InnoVersion & a, InnoVersionConstant b) { return !operator< (a, b); }
inline bool operator==(InnoVersionConstant a, const InnoVersion & b) { return a == b.version; }
inline bool operator!=(InnoVersionConstant a, const InnoVersion & b) { return !operator==(a, b); }
inline bool operator< (InnoVersionConstant a, const InnoVersion & b) { return a < b.version; }
inline bool operator> (InnoVersionConstant a, const InnoVersion & b) { return operator< (b, a); }
inline bool operator<=(InnoVersionConstant a, const InnoVersion & b) { return !operator> (a, b); }
inline bool operator>=(InnoVersionConstant a, const InnoVersion & b) { return !operator< (a, b); }
std::ostream & operator<<(std::ostream & os, const InnoVersion & version);
#endif // INNOEXTRACT_VERSION_HPP
Loading…
Cancel
Save