You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
227 lines
5.8 KiB
227 lines
5.8 KiB
|
15 years ago
|
|
||
|
|
#include <fstream>
|
||
|
|
#include <iostream>
|
||
|
|
#include <iomanip>
|
||
|
|
#include <string>
|
||
|
|
#include <algorithm>
|
||
|
|
#include <cstring>
|
||
|
|
#include <vector>
|
||
|
|
#include <bitset>
|
||
|
15 years ago
|
#include <ctime>
|
||
|
15 years ago
|
#include <map>
|
||
|
15 years ago
|
|
||
|
15 years ago
|
#include <boost/shared_ptr.hpp>
|
||
|
15 years ago
|
#include <boost/foreach.hpp>
|
||
|
|
#include <boost/ref.hpp>
|
||
|
15 years ago
|
#include <boost/make_shared.hpp>
|
||
|
15 years ago
|
#include <boost/filesystem/path.hpp>
|
||
|
15 years ago
|
#include <boost/iostreams/copy.hpp>
|
||
|
15 years ago
|
|
||
|
14 years ago
|
#include "version.hpp"
|
||
|
|
|
||
|
15 years ago
|
#include "cli/debug.hpp"
|
||
|
15 years ago
|
|
||
|
15 years ago
|
#include "loader/offsets.hpp"
|
||
|
15 years ago
|
|
||
|
15 years ago
|
#include "setup/data.hpp"
|
||
|
|
#include "setup/file.hpp"
|
||
|
15 years ago
|
#include "setup/info.hpp"
|
||
|
15 years ago
|
#include "setup/version.hpp"
|
||
|
15 years ago
|
|
||
|
15 years ago
|
#include "stream/chunk.hpp"
|
||
|
|
#include "stream/file.hpp"
|
||
|
|
#include "stream/slice.hpp"
|
||
|
15 years ago
|
|
||
|
15 years ago
|
#include "util/console.hpp"
|
||
|
15 years ago
|
#include "util/load.hpp"
|
||
|
15 years ago
|
#include "util/log.hpp"
|
||
|
15 years ago
|
#include "util/output.hpp"
|
||
|
15 years ago
|
|
||
|
|
using std::cout;
|
||
|
|
using std::string;
|
||
|
|
using std::endl;
|
||
|
|
using std::setw;
|
||
|
|
using std::setfill;
|
||
|
|
|
||
|
15 years ago
|
namespace io = boost::iostreams;
|
||
|
15 years ago
|
namespace fs = boost::filesystem;
|
||
|
15 years ago
|
|
||
|
15 years ago
|
int main(int argc, char * argv[]) {
|
||
|
|
|
||
|
15 years ago
|
color::init();
|
||
|
|
|
||
|
15 years ago
|
// logger::debug = true;
|
||
|
15 years ago
|
|
||
|
15 years ago
|
if(argc <= 1) {
|
||
|
14 years ago
|
cout << "usage: innoextract <Inno Setup installer>" << endl;
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version")) {
|
||
|
|
cout << innoextract_version << endl;
|
||
|
15 years ago
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
15 years ago
|
std::ifstream ifs(argv[1], std::ios_base::in | std::ios_base::binary | std::ios_base::ate);
|
||
|
15 years ago
|
if(!ifs.is_open()) {
|
||
|
15 years ago
|
log_error << "error opening file \"" << argv[1] << '"';
|
||
|
15 years ago
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
15 years ago
|
loader::offsets offsets;
|
||
|
15 years ago
|
offsets.load(ifs);
|
||
|
15 years ago
|
|
||
|
15 years ago
|
cout << std::boolalpha;
|
||
|
|
|
||
|
15 years ago
|
if(logger::debug) {
|
||
|
|
print_offsets(offsets);
|
||
|
|
cout << '\n';
|
||
|
|
}
|
||
|
15 years ago
|
|
||
|
15 years ago
|
ifs.seekg(offsets.header_offset);
|
||
|
15 years ago
|
setup::info info;
|
||
|
|
info.load(ifs);
|
||
|
15 years ago
|
|
||
|
15 years ago
|
const std::string & name = info.header.app_versioned_name.empty()
|
||
|
|
? info.header.app_name : info.header.app_versioned_name;
|
||
|
|
cout << "Extracting \"" << color::green << name << color::reset
|
||
|
|
<< "\" - setup data version " << color::white << info.version << color::reset << std::endl;
|
||
|
15 years ago
|
|
||
|
15 years ago
|
if(logger::debug) {
|
||
|
|
cout << '\n';
|
||
|
|
print_info(info);
|
||
|
|
}
|
||
|
15 years ago
|
|
||
|
15 years ago
|
cout << '\n';
|
||
|
15 years ago
|
|
||
|
|
std::vector<std::vector<size_t> > files_for_location;
|
||
|
15 years ago
|
files_for_location.resize(info.data_entries.size());
|
||
|
|
for(size_t i = 0; i < info.files.size(); i++) {
|
||
|
|
if(info.files[i].location < files_for_location.size()) {
|
||
|
|
files_for_location[info.files[i].location].push_back(i);
|
||
|
15 years ago
|
}
|
||
|
|
}
|
||
|
|
|
||
|
15 years ago
|
typedef std::map<stream::file, size_t> Files;
|
||
|
|
typedef std::map<stream::chunk, Files> Chunks;
|
||
|
15 years ago
|
Chunks chunks;
|
||
|
15 years ago
|
for(size_t i = 0; i < info.data_entries.size(); i++) {
|
||
|
|
setup::data_entry & location = info.data_entries[i];
|
||
|
15 years ago
|
if(location.chunk.compression == stream::UnknownCompression) {
|
||
|
15 years ago
|
location.chunk.compression = info.header.compression;
|
||
|
15 years ago
|
}
|
||
|
15 years ago
|
chunks[location.chunk][location.file] = i;
|
||
|
15 years ago
|
}
|
||
|
|
|
||
|
15 years ago
|
boost::shared_ptr<stream::slice_reader> slice_reader;
|
||
|
15 years ago
|
|
||
|
15 years ago
|
if(offsets.data_offset) {
|
||
|
|
slice_reader = boost::make_shared<stream::slice_reader>(argv[1], offsets.data_offset);
|
||
|
15 years ago
|
} else {
|
||
|
|
fs::path path(argv[1]);
|
||
|
15 years ago
|
slice_reader = boost::make_shared<stream::slice_reader>(path.parent_path().string() + '/',
|
||
|
|
path.stem().string(),
|
||
|
15 years ago
|
info.header.slices_per_disk);
|
||
|
15 years ago
|
}
|
||
|
15 years ago
|
|
||
|
|
try {
|
||
|
|
|
||
|
15 years ago
|
BOOST_FOREACH(const Chunks::value_type & chunk, chunks) {
|
||
|
15 years ago
|
|
||
|
15 years ago
|
cout << "[starting " << chunk.first.compression << " chunk @ " << chunk.first.first_slice
|
||
|
|
<< " + " << print_hex(offsets.data_offset) << " + " << print_hex(chunk.first.offset)
|
||
|
|
<< ']' << std::endl;
|
||
|
15 years ago
|
|
||
|
15 years ago
|
stream::chunk_reader::pointer chunk_source;
|
||
|
|
chunk_source = stream::chunk_reader::get(*slice_reader, chunk.first);
|
||
|
15 years ago
|
|
||
|
|
uint64_t offset = 0;
|
||
|
|
|
||
|
15 years ago
|
BOOST_FOREACH(const Files::value_type & location, chunk.second) {
|
||
|
|
const stream::file & file = location.first;
|
||
|
15 years ago
|
|
||
|
15 years ago
|
if(file.offset < offset) {
|
||
|
15 years ago
|
log_error << "bad offset";
|
||
|
15 years ago
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
15 years ago
|
if(file.offset > offset) {
|
||
|
|
std::cout << "discarding " << print_bytes(file.offset - offset) << std::endl;
|
||
|
|
discard(*chunk_source, file.offset - offset);
|
||
|
15 years ago
|
}
|
||
|
15 years ago
|
offset = file.offset + file.size;
|
||
|
15 years ago
|
|
||
|
|
std::cout << "-> reading ";
|
||
|
|
bool named = false;
|
||
|
15 years ago
|
BOOST_FOREACH(size_t file_i, files_for_location[location.second]) {
|
||
|
15 years ago
|
if(!info.files[file_i].destination.empty()) {
|
||
|
|
std::cout << '"' << info.files[file_i].destination << '"';
|
||
|
15 years ago
|
named = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if(!named) {
|
||
|
|
std::cout << "unnamed file";
|
||
|
|
}
|
||
|
15 years ago
|
std::cout << " @ " << print_hex(file.offset)
|
||
|
|
<< " (" << print_bytes(file.size) << ')' << std::endl;
|
||
|
15 years ago
|
|
||
|
15 years ago
|
crypto::checksum checksum;
|
||
|
15 years ago
|
|
||
|
15 years ago
|
stream::file_reader::pointer file_source;
|
||
|
15 years ago
|
file_source = stream::file_reader::get(*chunk_source, file, &checksum);
|
||
|
15 years ago
|
|
||
|
15 years ago
|
BOOST_FOREACH(size_t file_i, files_for_location[location.second]) {
|
||
|
15 years ago
|
if(!info.files[file_i].destination.empty()) {
|
||
|
|
std::ofstream ofs(info.files[file_i].destination.c_str());
|
||
|
15 years ago
|
|
||
|
14 years ago
|
progress extract_progress(file.size);
|
||
|
15 years ago
|
|
||
|
14 years ago
|
char buffer[8192 * 10];
|
||
|
15 years ago
|
|
||
|
15 years ago
|
while(!file_source->eof()) {
|
||
|
|
std::streamsize n = file_source->read(buffer, ARRAY_SIZE(buffer)).gcount();
|
||
|
15 years ago
|
if(n > 0) {
|
||
|
|
ofs.write(buffer, n);
|
||
|
14 years ago
|
extract_progress.update(uint64_t(n));
|
||
|
15 years ago
|
}
|
||
|
|
}
|
||
|
|
|
||
|
14 years ago
|
extract_progress.clear();
|
||
|
|
|
||
|
15 years ago
|
break; // TODO ...
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
15 years ago
|
if(checksum != file.checksum) {
|
||
|
15 years ago
|
log_warning << "checksum mismatch:";
|
||
|
15 years ago
|
log_warning << "actual: " << checksum;
|
||
|
15 years ago
|
log_warning << "expected: " << file.checksum;
|
||
|
15 years ago
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
15 years ago
|
} catch(std::ios_base::failure e) {
|
||
|
|
log_error << e.what();
|
||
|
15 years ago
|
}
|
||
|
|
|
||
|
15 years ago
|
std::cout << color::green << "Done" << color::reset << std::dec;
|
||
|
15 years ago
|
|
||
|
15 years ago
|
if(logger::total_errors || logger::total_warnings) {
|
||
|
15 years ago
|
std::cout << " with ";
|
||
|
15 years ago
|
if(logger::total_errors) {
|
||
|
|
std::cout << color::red << logger::total_errors << " errors" << color::reset;
|
||
|
15 years ago
|
}
|
||
|
15 years ago
|
if(logger::total_errors && logger::total_warnings) {
|
||
|
15 years ago
|
std::cout << " and ";
|
||
|
|
}
|
||
|
15 years ago
|
if(logger::total_warnings) {
|
||
|
|
std::cout << color::yellow << logger::total_warnings << " warnings" << color::reset;
|
||
|
15 years ago
|
}
|
||
|
|
}
|
||
|
15 years ago
|
|
||
|
15 years ago
|
std::cout << '.' << std::endl;
|
||
|
|
|
||
|
15 years ago
|
return 0;
|
||
|
|
}
|