block_reader::pointer block_reader::get(std::istream & base, const setup::version & version) { USE_ENUM_NAMES(block_compression) uint32_t expected_checksum = load_number<uint32_t>(base); crypto::crc32 actual_checksum; actual_checksum.init(); uint32_t stored_size; block_compression compression; if(version >= INNO_VERSION(4, 0, 9)) { stored_size = actual_checksum.load_number<uint32_t>(base); uint8_t compressed = actual_checksum.load_number<uint8_t>(base); compression = compressed ? (version >= INNO_VERSION(4, 1, 6) ? LZMA1 : Zlib) : Stored; } else { uint32_t compressed_size = actual_checksum.load_number<uint32_t>(base); uint32_t uncompressed_size = actual_checksum.load_number<uint32_t>(base); if(compressed_size == uint32_t(-1)) { stored_size = uncompressed_size, compression = Stored; } else { stored_size = compressed_size, compression = Zlib; } // Add the size of a CRC32 checksum for each 4KiB subblock. stored_size += uint32_t(ceildiv<uint64_t>(stored_size, 4096) * 4); } if(actual_checksum.finalize() != expected_checksum) { throw block_error("block CRC32 mismatch"); } debug("[block] size: " << stored_size << " compression: " << compression); boost::shared_ptr<io::filtering_istream> fis = boost::make_shared<io::filtering_istream>(); switch(compression) { case Stored: break; case Zlib: fis->push(io::zlib_decompressor(), 8192); break; #if INNOEXTRACT_HAVE_LZMA case LZMA1: fis->push(inno_lzma1_decompressor(), 8192); break; #else case LZMA1: throw block_error("LZMA decompression not supported by this " + std::string(innoextract_name) + " build"); #endif } fis->push(inno_block_filter(), 4096); fis->push(io::restrict(base, 0, stored_size)); return fis; }
void run_entry::load(std::istream & is, const version & version) { if(version < INNO_VERSION(1, 3, 21)) { ::load<uint32_t>(is); // uncompressed size of the directory entry structure } is >> encoded_string(name, version.codepage()); is >> encoded_string(parameters, version.codepage()); is >> encoded_string(working_dir, version.codepage()); if(version >= INNO_VERSION(1, 3, 21)) { is >> encoded_string(run_once_id, version.codepage()); } else {
void header::load(std::istream & is, const version & version) { options = 0; if(version < INNO_VERSION(1, 3, 21)) { (void)util::load<boost::uint32_t>(is); // uncompressed size of the setup header } is >> util::encoded_string(app_name, version.codepage()); is >> util::encoded_string(app_versioned_name, version.codepage()); if(version >= INNO_VERSION(1, 3, 21)) { is >> util::encoded_string(app_id, version.codepage()); }
void registry_entry::load(std::istream & is, const version & version) { if(version < INNO_VERSION(1, 3, 21)) { (void)util::load<boost::uint32_t>(is); // uncompressed size of the entry } is >> util::encoded_string(key, version.codepage()); if(version.bits != 16) { is >> util::encoded_string(name, version.codepage()); } else {
static void load_wizard_and_decompressor(std::istream & is, const setup::version & version, const setup::header & header, setup::info & info, info::entry_types entries) { (void)entries; info.wizard_image.clear(); info.wizard_image_small.clear(); if(entries & (info::WizardImages | info::NoSkip)) { is >> util::binary_string(info.wizard_image); if(version >= INNO_VERSION(2, 0, 0)) { is >> util::binary_string(info.wizard_image_small); }
bool version::is_ambiguous() const { if(value == INNO_VERSION(2, 0, 1)) { // might be either 2.0.1 or 2.0.2 return true; } if(value == INNO_VERSION(3, 0, 3)) { // might be either 3.0.3 or 3.0.4 return true; } if(value == INNO_VERSION(4, 2, 3)) { // might be either 4.2.3 or 4.2.4 return true; } if(value == INNO_VERSION(5, 5, 0)) { // might be either 5.5.0 or 5.5.0.1 return true; } return false; }
void ini_entry::load(std::istream & is, const version & version) { if(version < INNO_VERSION(1, 3, 21)) { ::load<uint32_t>(is); // uncompressed size of the ini entry structure } is >> encoded_string(inifile, version.codepage()); if(inifile.empty()) { inifile = "{windows}/WIN.INI"; } is >> encoded_string(section, version.codepage()); is >> encoded_string(key, version.codepage()); is >> encoded_string(value, version.codepage()); load_condition_data(is, version); load_version_data(is, version); if(version.bits != 16) { options = stored_flags<stored_ini_flags>(is).get(); } else { options = stored_flags<stored_ini_flags, 16>(is).get(); } }
void version::load(std::istream & is) { static const char digits[] = "0123456789"; BOOST_STATIC_ASSERT(sizeof(stored_legacy_version) <= sizeof(stored_version)); stored_legacy_version legacy_version; is.read(legacy_version, std::streamsize(sizeof(legacy_version))); if(legacy_version[0] == 'i' && legacy_version[sizeof(legacy_version) - 1] == '\x1a') { for(size_t i = 0; i < size_t(boost::size(legacy_versions)); i++) { if(!memcmp(legacy_version, legacy_versions[i].name, sizeof(legacy_version))) { value = legacy_versions[i].version; bits = legacy_versions[i].bits; unicode = false; known = true; debug("known legacy version: \"" << versions[i].name << '"'); return; } } debug("unknown legacy version: \"" << std::string(legacy_version, sizeof(legacy_version)) << '"'); if(legacy_version[0] != 'i' || legacy_version[2] != '.' || legacy_version[4] != '.' || legacy_version[7] != '-' || legacy_version[8] != '-') { throw version_error(); } if(legacy_version[9] == '1' && legacy_version[10] == '6') { bits = 16; } else if(legacy_version[9] == '3' && legacy_version[10] == '2') { bits = 32; } else { throw version_error(); } std::string version_str(legacy_version, sizeof(legacy_version)); try { unsigned a = util::to_unsigned(version_str.data() + 1, 1); unsigned b = util::to_unsigned(version_str.data() + 3, 1); unsigned c = util::to_unsigned(version_str.data() + 5, 2); value = INNO_VERSION(a, b, c); } catch(boost::bad_lexical_cast) { throw version_error(); } unicode = false; known = false; return; } stored_version version; BOOST_STATIC_ASSERT(sizeof(legacy_version) <= sizeof(version)); memcpy(version, legacy_version, sizeof(legacy_version)); is.read(version + sizeof(legacy_version), std::streamsize(sizeof(version) - sizeof(legacy_version))); for(size_t i = 0; i < size_t(boost::size(versions)); i++) { if(!memcmp(version, versions[i].name, sizeof(version))) { value = versions[i].version; bits = 32; unicode = versions[i].unicode; known = true; debug("known version: \"" << versions[i].name << '"'); return; } } char * end = std::find(version, version + boost::size(version), '\0'); std::string version_str(version, end); debug("unknown version: \"" << version_str << '"'); if(version_str.find("Inno Setup") == std::string::npos) { throw version_error(); } size_t bracket = version_str.find('('); for(; bracket != std::string::npos; bracket = version_str.find('(', bracket + 1)) { if(version_str.length() - bracket < 6) { continue; } try { size_t a_start = bracket + 1; size_t a_end = version_str.find_first_not_of(digits, a_start); if(a_end == std::string::npos || version_str[a_end] != '.') { continue; } unsigned a = util::to_unsigned(version_str.data() + a_start, a_end - a_start); size_t b_start = a_end + 1; size_t b_end = version_str.find_first_not_of(digits, b_start); if(b_end == std::string::npos || version_str[b_end] != '.') { continue; } unsigned b = util::to_unsigned(version_str.data() + b_start, b_end - b_start); size_t c_start = b_end + 1; size_t c_end = version_str.find_first_not_of(digits, c_start); if(c_end == std::string::npos) { continue; } unsigned c = util::to_unsigned(version_str.data() + c_start, c_end - c_start); size_t d_start = c_end; if(version_str[d_start] == 'a') { if(d_start + 1 >= version_str.length()) { continue; } d_start++; } unsigned d = 0; if(version_str[d_start] == '.') { d_start++; size_t d_end = version_str.find_first_not_of(digits, d_start); if(d_end != std::string::npos && d_end != d_start) { d = util::to_unsigned(version_str.data() + d_start, d_end - d_start); } } value = INNO_VERSION_EXT(a, b, c, d); break; } catch(boost::bad_lexical_cast) { continue; } } if(bracket == std::string::npos) { throw version_error(); } bits = 32; unicode = (version_str.find("(u)") != std::string::npos); known = false; }
void data_entry::load(std::istream & is, const version & version) { chunk.first_slice = util::load<boost::uint32_t>(is, version.bits); chunk.last_slice = util::load<boost::uint32_t>(is, version.bits); if(version < INNO_VERSION(4, 0, 0)) { if(chunk.first_slice < 1 || chunk.last_slice < 1) { log_warning << "[file location] unexpected disk number: " << chunk.first_slice << " / " << chunk.last_slice; } else { chunk.first_slice--, chunk.last_slice--; } } chunk.offset = util::load<boost::uint32_t>(is); if(version >= INNO_VERSION(4, 0, 1)) { file.offset = util::load<boost::uint64_t>(is); } else { file.offset = 0; } if(version >= INNO_VERSION(4, 0, 0)) { file.size = util::load<boost::uint64_t>(is); chunk.size = util::load<boost::uint64_t>(is); } else { file.size = util::load<boost::uint32_t>(is); chunk.size = util::load<boost::uint32_t>(is); } if(version >= INNO_VERSION(5, 3, 9)) { is.read(file.checksum.sha1, std::streamsize(sizeof(file.checksum.sha1))); file.checksum.type = crypto::SHA1; } else if(version >= INNO_VERSION(4, 2, 0)) { is.read(file.checksum.md5, std::streamsize(sizeof(file.checksum.md5))); file.checksum.type = crypto::MD5; } else if(version >= INNO_VERSION(4, 0, 1)) { file.checksum.crc32 = util::load<boost::uint32_t>(is); file.checksum.type = crypto::CRC32; } else { file.checksum.adler32 = util::load<boost::uint32_t>(is); file.checksum.type = crypto::Adler32; } if(version.bits == 16) { // 16-bit installers use the FAT filetime format boost::uint16_t time = util::load<boost::uint16_t>(is); boost::uint16_t date = util::load<boost::uint16_t>(is); struct tm t; t.tm_sec = util::get_bits(time, 0, 4) * 2; // [0, 58] t.tm_min = util::get_bits(time, 5, 10); // [0, 59] t.tm_hour = util::get_bits(time, 11, 15); // [0, 23] t.tm_mday = util::get_bits(date, 0, 4); // [1, 31] t.tm_mon = util::get_bits(date, 5, 8) - 1; // [0, 11] t.tm_year = util::get_bits(date, 9, 15) + 1980 - 1900; // [80, 199] timestamp = util::parse_time(t); timestamp_nsec = 0; } else { // 32-bit installers use the Win32 FILETIME format boost::int64_t filetime = util::load<boost::int64_t>(is); static const boost::int64_t FiletimeOffset = 0x19DB1DED53E8000ll; if(filetime < FiletimeOffset) { log_warning << "[file location] unexpected filetime: " << filetime; } filetime -= FiletimeOffset; timestamp = filetime / 10000000; timestamp_nsec = boost::uint32_t(filetime % 10000000) * 100; } file_version_ms = util::load<boost::uint32_t>(is); file_version_ls = util::load<boost::uint32_t>(is); options = 0; stored_flag_reader<flags> flagreader(is, version.bits); flagreader.add(VersionInfoValid); flagreader.add(VersionInfoNotValid); if(version >= INNO_VERSION(2, 0, 17) && version < INNO_VERSION(4, 0, 1)) { flagreader.add(BZipped); } if(version >= INNO_VERSION(4, 0, 10)) { flagreader.add(TimeStampInUTC); } if(version >= INNO_VERSION(4, 1, 0)) { flagreader.add(IsUninstallerExe); } if(version >= INNO_VERSION(4, 1, 8)) { flagreader.add(CallInstructionOptimized); } if(version >= INNO_VERSION(4, 2, 0)) { flagreader.add(Touch); } if(version >= INNO_VERSION(4, 2, 2)) { flagreader.add(ChunkEncrypted); } if(version >= INNO_VERSION(4, 2, 5)) { flagreader.add(ChunkCompressed); } else { options |= ChunkCompressed; } if(version >= INNO_VERSION(5, 1, 13)) { flagreader.add(SolidBreak); } options |= flagreader; if(options & ChunkCompressed) { chunk.compression = stream::UnknownCompression; } else { chunk.compression = stream::Stored; } if(options & BZipped) { options |= ChunkCompressed; chunk.compression = stream::BZip2; } chunk.encrypted = ((options & ChunkEncrypted) != 0); if(options & CallInstructionOptimized) { if(version < INNO_VERSION(5, 2, 0)) { file.filter = stream::InstructionFilter4108; } else if(version < INNO_VERSION(5, 3, 9)) { file.filter = stream::InstructionFilter5200; } else { file.filter = stream::InstructionFilter5309; } } else { file.filter = stream::NoFilter; } }