Browse Source

Improve output.

pull/1/head
Daniel Scharrer 15 years ago
parent
commit
8fcbdff79c
  1. 12
      CMakeLists.txt
  2. 149
      src/InnoExtract.cpp
  3. 8
      src/configure.hpp.in
  4. 4
      src/loader/SetupLoader.cpp
  5. 3
      src/setup/FileEntry.cpp
  6. 10
      src/setup/FileLocationEntry.cpp
  7. 21
      src/setup/SetupHeader.cpp
  8. 8
      src/stream/BlockReader.cpp
  9. 15
      src/stream/SliceReader.cpp
  10. 11
      src/util/color.cpp
  11. 69
      src/util/color.hpp
  12. 138
      src/util/console.cpp
  13. 53
      src/util/console.hpp
  14. 2
      src/util/enum.hpp
  15. 4
      src/util/load.cpp
  16. 17
      src/util/load.hpp
  17. 26
      src/util/log.cpp
  18. 71
      src/util/log.hpp
  19. 2
      src/util/output.hpp
  20. 213
      src/util/storedenum.hpp
  21. 6
      src/util/util.hpp

12
CMakeLists.txt

@ -5,6 +5,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
include(CompileCheck)
include(VersionString) # TODO use this
include(CheckSymbolExists)
# Force re-checking libraries if the compiler or compiler flags change.
if((NOT LAST_CMAKE_CXX_FLAGS STREQUAL CMAKE_CXX_FLAGS)
@ -34,6 +35,7 @@ include_directories(SYSTEM "${LZMA_INCLUDE_DIR}")
# TODO debugging-only
add_cxxflag("-ggdb")
add_cxxflag("-O3")
add_definitions(-D_DEBUG)
# TODO should probably be supplied by the user
add_cxxflag("-march=native")
@ -70,6 +72,9 @@ if(UNITY_BUILD)
add_cxxflag("-fwhole-program")
endif()
check_symbol_exists(isatty "unistd.h" HAVE_ISATTY)
check_symbol_exists(ioctl "sys/ioctl.h" HAVE_IOCTL)
set(INNOEXTRACT_SOURCES
src/crypto/Adler-32.cpp
@ -106,15 +111,18 @@ set(INNOEXTRACT_SOURCES
src/stream/LzmaFilter.cpp
src/stream/SliceReader.cpp
src/util/console.cpp
src/util/load.cpp
src/util/color.cpp
src/util/log.cpp
src/InnoExtract.cpp
)
file(GLOB_RECURSE ALL_INCLUDES "${CMAKE_SOURCE_DIR}/src/*.hpp")
include_directories(src)
include_directories(src ${CMAKE_CURRENT_BINARY_DIR})
configure_file("src/configure.hpp.in" "configure.hpp")
add_executable(innoextract ${INNOEXTRACT_SOURCES} ${ALL_INCLUDES})
target_link_libraries(innoextract ${LIBRARIES})

149
src/InnoExtract.cpp

@ -11,8 +11,6 @@
#include <ctime>
#include <map>
#include <sys/ioctl.h>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/ref.hpp>
@ -56,75 +54,17 @@
#include "stream/ChecksumFilter.hpp"
#include "stream/InstructionFilter.hpp"
#include "util/color.hpp"
#include "util/console.hpp"
#include "util/load.hpp"
#include "util/log.hpp"
#include "util/output.hpp"
class progress {
public:
static void show(float value, const std::string & label) {
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
clear();
std::ios_base::fmtflags flags = std::cout.flags();
size_t progress_length = w.ws_col - label.length() - 6 - 2 - 2 - 1;
if(progress_length > 10) {
size_t progress = size_t(ceil(float(progress_length) * value));
std::cout << '[';
for(size_t i = 0; i < progress; i++) {
std::cout << '=';
}
std::cout << '>';
for(size_t i = progress; i < progress_length; i++) {
std::cout << ' ';
}
std::cout << ']';
}
std::cout << std::right << std::fixed << std::setprecision(1) << std::setfill(' ')
<< std::setw(5) << (value * 100) << "% " << label;
std::cout.flush();
std::cout.flags(flags);
}
static void clear() {
std::cout << "\33[2K\r";
}
};
using std::cout;
using std::string;
using std::endl;
using std::setw;
using std::setfill;
template <class T>
void discard(T & is, uint64_t bytes) {
std::cout << "discarding " << print_bytes(bytes) << std::endl;
char buf[1024];
while(bytes) {
std::streamsize n = std::streamsize(std::min<uint64_t>(bytes, ARRAY_SIZE(buf)));
is.read(buf, n);
bytes -= uint64_t(n);
}
}
namespace io = boost::iostreams;
namespace fs = boost::filesystem;
@ -274,13 +214,17 @@ static void readWizardImageAndDecompressor(std::istream & is, const InnoVersion
}
if(is.fail()) {
LogError << "error reading misc setup data";
log_error << "error reading misc setup data";
}
}
int main(int argc, char * argv[]) {
color::init();
logger::debug = true;
if(argc <= 1) {
std::cout << "usage: innoextract <Inno Setup installer>" << endl;
return 1;
@ -289,7 +233,7 @@ int main(int argc, char * argv[]) {
std::ifstream ifs(argv[1], std::ios_base::in | std::ios_base::binary | std::ios_base::ate);
if(!ifs.is_open()) {
LogError << "error opening file";
log_error << "error opening file";
return 1;
}
@ -319,12 +263,12 @@ int main(int argc, char * argv[]) {
InnoVersion version;
version.load(ifs);
if(ifs.fail()) {
LogError << "error reading setup data version!";
log_error << "error reading setup data version!";
return 1;
}
if(!version.known) {
LogError << "unknown version!";
log_error << "unknown version!";
return 1; // TODO
}
@ -332,7 +276,7 @@ int main(int argc, char * argv[]) {
boost::shared_ptr<std::istream> is(BlockReader::get(ifs, version));
if(!is) {
LogError << "error reading block";
log_error << "error reading block";
return 1;
}
@ -341,7 +285,7 @@ int main(int argc, char * argv[]) {
SetupHeader header;
header.load(*is, version);
if(is->fail()) {
LogError << "error reading setup data header!";
log_error << "error reading setup data header!";
return 1;
}
@ -459,7 +403,7 @@ int main(int argc, char * argv[]) {
LanguageEntry & entry = languages[i];
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading language entry #" << i;
log_error << "error reading language entry #" << i;
}
cout << " - " << quoted(entry.name) << ':' << endl;
@ -498,11 +442,11 @@ int main(int argc, char * argv[]) {
MessageEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading custom message entry #" << i;
log_error << "error reading custom message entry #" << i;
}
if(entry.language >= 0 ? size_t(entry.language) >= languages.size() : entry.language != -1) {
LogWarning << "unexpected language index: " << entry.language;
log_warning << "unexpected language index: " << entry.language;
}
uint32_t codepage;
@ -534,7 +478,7 @@ int main(int argc, char * argv[]) {
PermissionEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading permission entry #" << i;
log_error << "error reading permission entry #" << i;
}
cout << " - " << entry.permissions.length() << " bytes";
@ -549,7 +493,7 @@ int main(int argc, char * argv[]) {
SetupTypeEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading type entry #" << i;
log_error << "error reading type entry #" << i;
}
cout << " - " << quoted(entry.name) << ':' << endl;
@ -574,7 +518,7 @@ int main(int argc, char * argv[]) {
SetupComponentEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading component entry #" << i;
log_error << "error reading component entry #" << i;
}
cout << " - " << quoted(entry.name) << ':' << endl;
@ -603,7 +547,7 @@ int main(int argc, char * argv[]) {
SetupTaskEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading task entry #" << i;
log_error << "error reading task entry #" << i;
}
cout << " - " << quoted(entry.name) << ':' << endl;
@ -633,7 +577,7 @@ int main(int argc, char * argv[]) {
DirectoryEntry & entry = directories[i];
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading directory entry #" << i;
log_error << "error reading directory entry #" << i;
}
cout << " - " << quoted(entry.name) << ':' << endl;
@ -663,7 +607,7 @@ int main(int argc, char * argv[]) {
FileEntry & entry = files[i];
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading file entry #" << i;
log_error << "error reading file entry #" << i;
}
if(entry.destination.empty()) {
@ -701,7 +645,7 @@ int main(int argc, char * argv[]) {
IconEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading icon entry #" << i;
log_error << "error reading icon entry #" << i;
}
cout << " - " << quoted(entry.name) << " -> " << quoted(entry.filename) << endl;
@ -731,7 +675,7 @@ int main(int argc, char * argv[]) {
IniEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading ini entry #" << i;
log_error << "error reading ini entry #" << i;
}
cout << " - in " << quoted(entry.inifile);
@ -752,7 +696,7 @@ int main(int argc, char * argv[]) {
RegistryEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading registry entry #" << i;
log_error << "error reading registry entry #" << i;
}
cout << " - ";
@ -793,7 +737,7 @@ int main(int argc, char * argv[]) {
DeleteEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading install delete entry #" << i;
log_error << "error reading install delete entry #" << i;
}
cout << " - " << quoted(entry.name)
@ -811,7 +755,7 @@ int main(int argc, char * argv[]) {
DeleteEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading uninstall delete entry #" << i;
log_error << "error reading uninstall delete entry #" << i;
}
cout << " - " << quoted(entry.name)
@ -829,7 +773,7 @@ int main(int argc, char * argv[]) {
RunEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading install run entry #" << i;
log_error << "error reading install run entry #" << i;
}
print(cout, entry, header);
@ -844,7 +788,7 @@ int main(int argc, char * argv[]) {
RunEntry entry;
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading uninstall run entry #" << i;
log_error << "error reading uninstall run entry #" << i;
}
print(cout, entry, header);
@ -859,7 +803,7 @@ int main(int argc, char * argv[]) {
is->exceptions(std::ios_base::goodbit);
char dummy;
if(!is->get(dummy).eof()) {
LogWarning << "expected end of stream";
log_warning << "expected end of stream";
}
}
@ -867,7 +811,7 @@ int main(int argc, char * argv[]) {
is.reset(BlockReader::get(ifs, version));
if(!is) {
LogError << "error reading block";
log_error << "error reading block";
return 1;
}
@ -883,7 +827,7 @@ int main(int argc, char * argv[]) {
FileLocationEntry & entry = locations[i];
entry.load(*is, version);
if(is->fail()) {
LogError << "error reading file location entry #" << i;
log_error << "error reading file location entry #" << i;
}
cout << " - " << "File location #" << i << ':' << endl;
@ -927,7 +871,7 @@ int main(int argc, char * argv[]) {
is->exceptions(std::ios_base::goodbit);
char dummy;
if(!is->get(dummy).eof()) {
LogWarning << "expected end of stream";
log_warning << "expected end of stream";
}
}
@ -975,7 +919,7 @@ int main(int argc, char * argv[]) {
std::sort(chunk.second.begin(), chunk.second.end(), FileLocationComparer(locations));
if(!slice_reader->seek(chunk.first.firstSlice, chunk.first.chunkOffset)) {
LogError << "error seeking" << std::endl;
log_error << "error seeking";
return 1;
}
@ -983,7 +927,7 @@ int main(int argc, char * argv[]) {
char magic[4];
if(slice_reader->read(magic, 4) != 4 || memcmp(magic, chunkId, 4)) {
LogError << "bad chunk id";
log_error << "bad chunk id";
return 1;
}
@ -997,7 +941,7 @@ int main(int argc, char * argv[]) {
case SetupHeader::BZip2: chunk_source.push(io::bzip2_decompressor(), 8192); break;
case SetupHeader::LZMA1: chunk_source.push(inno_lzma1_decompressor(), 8192); break;
case SetupHeader::LZMA2: chunk_source.push(inno_lzma2_decompressor(), 8192); break;
default: LogError << "unknown compression";
default: log_error << "unknown compression";
}
}
@ -1010,11 +954,12 @@ int main(int argc, char * argv[]) {
const FileLocationEntry & location = locations[location_i];
if(location.fileOffset < offset) {
LogError << "bad offset";
log_error << "bad offset";
return 1;
}
if(location.fileOffset > offset) {
std::cout << "discarding " << print_bytes(location.fileOffset - offset) << std::endl;
discard(chunk_source, location.fileOffset - offset);
}
offset = location.fileOffset + location.fileSize;
@ -1115,30 +1060,30 @@ int main(int argc, char * argv[]) {
Checksum actual;
hasher.finalize(actual);
if(actual != location.checksum) {
LogWarning << "checksum mismatch:";
LogWarning << "actual: " << actual;
LogWarning << "expected: " << location.checksum;
log_warning << "checksum mismatch:";
log_warning << "actual: " << actual;
log_warning << "expected: " << location.checksum;
}
}
}
} catch(io::bzip2_error e) {
LogError << e.what() << ": " <<
log_error << e.what() << ": " <<
e.error();
}
std::cout << color::green << "Done" << color::reset << std::dec;
if(total_errors || total_warnings) {
if(logger::total_errors || logger::total_warnings) {
std::cout << " with ";
if(total_errors) {
std::cout << color::red << total_errors << " errors" << color::reset;
if(logger::total_errors) {
std::cout << color::red << logger::total_errors << " errors" << color::reset;
}
if(total_errors && total_warnings) {
if(logger::total_errors && logger::total_warnings) {
std::cout << " and ";
}
if(total_warnings) {
std::cout << color::yellow << total_warnings << " warnings" << color::reset;
if(logger::total_warnings) {
std::cout << color::yellow << logger::total_warnings << " warnings" << color::reset;
}
}

8
src/configure.hpp.in

@ -0,0 +1,8 @@
#ifndef INNOEXTRACT_CONFIGURE_HPP
#define INNOEXTRACT_CONFIGURE_HPP
#cmakedefine HAVE_ISATTY
#cmakedefine HAVE_IOCTL
#endif // INNOEXTRACT_CONFIGURE_HPP

4
src/loader/SetupLoader.cpp

@ -9,8 +9,8 @@
#include "crypto/CRC32.hpp"
#include "loader/ExeReader.hpp"
#include "setup/Version.hpp"
#include "util/color.hpp"
#include "util/load.hpp"
#include "util/log.hpp"
namespace {
@ -147,7 +147,7 @@ bool SetupLoader::loadOffsetsAt(std::istream & is, uint32_t pos) {
return false;
}
if(checksum.finalize() != expected) {
LogError << "[loader] CRC32 mismatch";
log_error << "[loader] CRC32 mismatch";
return false;
}
}

3
src/setup/FileEntry.cpp

@ -2,6 +2,7 @@
#include "setup/FileEntry.hpp"
#include "util/load.hpp"
#include "util/log.hpp"
#include "util/storedenum.hpp"
namespace {
@ -161,7 +162,7 @@ void FileEntry::load(std::istream & is, const InnoVersion & version) {
// TODO find out where this byte comes from
int byte = is.get();
if(byte) {
LogWarning << "unknown byte: " << byte;
log_warning << "[file] unknown byte: " << byte;
}
}

10
src/setup/FileLocationEntry.cpp

@ -1,8 +1,8 @@
#include "setup/FileLocationEntry.hpp"
#include "util/color.hpp"
#include "util/load.hpp"
#include "util/log.hpp"
#include "util/storedenum.hpp"
void FileLocationEntry::load(std::istream & is, const InnoVersion & version) {
@ -11,9 +11,11 @@ void FileLocationEntry::load(std::istream & is, const InnoVersion & version) {
lastSlice = load_number<uint32_t>(is, version.bits);
if(version < INNO_VERSION(4, 0, 0)) {
if(firstSlice < 1 || lastSlice < 1) {
LogWarning << "unexpected disk number: " << firstSlice << " / " << lastSlice;
log_warning << "[file location] unexpected disk number: " << firstSlice << " / "
<< lastSlice;
} else {
firstSlice--, lastSlice--;
}
firstSlice--, lastSlice--;
}
chunkOffset = load_number<uint32_t>(is);
@ -58,7 +60,7 @@ void FileLocationEntry::load(std::istream & is, const InnoVersion & version) {
static const int64_t FILETIME_OFFSET = 0x19DB1DED53E8000l;
if(filetime < FILETIME_OFFSET) {
LogWarning << "unexpected filetime: " << filetime;
log_warning << "[file location] unexpected filetime: " << filetime;
}
filetime -= FILETIME_OFFSET;

21
src/setup/SetupHeader.cpp

@ -422,7 +422,6 @@ void SetupHeader::load(std::istream & is, const InnoVersion & version) {
flags.add(Password);
flags.add(AllowRootDirectory);
flags.add(DisableFinishedPage);
if(version.bits != 16) {
if(version < INNO_VERSION(3, 0, 4)) {
flags.add(AdminPrivilegesRequired);
@ -435,7 +434,6 @@ void SetupHeader::load(std::istream & is, const InnoVersion & version) {
}
flags.add(ChangesAssociations);
}
if(version >= INNO_VERSION(1, 3, 21)) {
if(version < INNO_VERSION(5, 3, 8)) {
flags.add(CreateUninstallRegKey);
@ -445,7 +443,6 @@ void SetupHeader::load(std::istream & is, const InnoVersion & version) {
flags.add(UsePreviousGroup);
flags.add(UpdateUninstallLogAppName);
}
if(version >= INNO_VERSION(2, 0, 0)) {
flags.add(UsePreviousSetupType);
flags.add(DisableReadyMemo);
@ -455,37 +452,29 @@ void SetupHeader::load(std::istream & is, const InnoVersion & version) {
flags.add(UsePreviousTasks);
flags.add(DisableReadyPage);
}
if(version >= INNO_VERSION(2, 0, 7)) {
flags.add(AlwaysShowDirOnReadyPage);
flags.add(AlwaysShowGroupOnReadyPage);
}
if(version >= INNO_VERSION(2, 0, 17) && version < INNO_VERSION(4, 1, 5)) {
flags.add(BzipUsed);
}
if(version >= INNO_VERSION(2, 0, 18)) {
flags.add(AllowUNCPath);
}
if(version >= INNO_VERSION(3, 0, 0)) {
flags.add(UserInfoPage);
flags.add(UsePreviousUserInfo);
}
if(version >= INNO_VERSION(3, 0, 1)) {
flags.add(UninstallRestartComputer);
}
if(version >= INNO_VERSION(3, 0, 3)) {
flags.add(RestartIfNeededByRun);
}
if(version >= INNO_VERSION_EXT(3, 0, 6, 1)) {
flags.add(ShowTasksTreeLines);
}
if(version >= INNO_VERSION(4, 0, 0) && version < INNO_VERSION(4, 0, 10)) {
flags.add(ShowLanguageDialog);
}
@ -493,46 +482,36 @@ void SetupHeader::load(std::istream & is, const InnoVersion & version) {
if(version >= INNO_VERSION(4, 0, 1) && version < INNO_VERSION(4, 0, 10)) {
flags.add(DetectLanguageUsingLocale);
}
if(version >= INNO_VERSION(4, 0, 9)) {
flags.add(AllowCancelDuringInstall);
} else {
options |= AllowCancelDuringInstall;
}
if(version >= INNO_VERSION(4, 1, 3)) {
flags.add(WizardImageStretch);
}
if(version >= INNO_VERSION(4, 1, 8)) {
flags.add(AppendDefaultDirName);
flags.add(AppendDefaultGroupName);
}
if(version >= INNO_VERSION(4, 2, 2)) {
flags.add(EncryptionUsed);
}
if(version >= INNO_VERSION(5, 0, 4)) {
flags.add(ChangesEnvironment);
}
if(version >= INNO_VERSION(5, 1, 7) && !version.unicode) {
flags.add(ShowUndisplayableLanguages);
}
if(version >= INNO_VERSION(5, 1, 13)) {
flags.add(SetupLogging);
}
if(version >= INNO_VERSION(5, 2, 1)) {
flags.add(SignedUninstaller);
}
if(version >= INNO_VERSION(5, 3, 8)) {
flags.add(UsePreviousLanguage);
}
if(version >= INNO_VERSION(5, 3, 9)) {
flags.add(DisableWelcomePage);
}

8
src/stream/BlockReader.cpp

@ -14,11 +14,9 @@
#include "stream/LzmaFilter.hpp"
#include "util/enum.hpp"
#include "util/load.hpp"
#include "util/log.hpp"
#include "util/util.hpp"
using std::cout;
using std::endl;
namespace io = boost::iostreams;
namespace {
@ -65,11 +63,11 @@ std::istream * BlockReader::get(std::istream & base, const InnoVersion & version
}
if(actualCrc.finalize() != expectedCrc) {
LogError << "block CRC32 mismatch";
log_error << "block CRC32 mismatch";
return NULL;
}
cout << "[block] size: " << storedSize << " compression: " << compression << endl;
debug("[block] size: " << storedSize << " compression: " << compression);
io::filtering_istream * fis;
fis = new io::filtering_istream;

15
src/stream/SliceReader.cpp

@ -6,8 +6,9 @@
#include <cstring>
#include <limits>
#include "util/color.hpp"
#include "util/console.hpp"
#include "util/load.hpp"
#include "util/log.hpp"
#include "util/util.hpp"
using std::string;
@ -45,7 +46,7 @@ bool SliceReader::seek(size_t slice) {
}
if(dataOffset != 0) {
LogError << "[slice] cannot change slices in single-file setup";
log_error << "[slice] cannot change slices in single-file setup";
return false;
}
@ -54,7 +55,7 @@ bool SliceReader::seek(size_t slice) {
bool SliceReader::openFile(const std::string & file) {
std::cout << color::cyan << "\33[2K\r[slice] opening " << file << color::reset << std::endl;
log_info << "[slice] opening " << file;
ifs.close();
@ -69,7 +70,7 @@ bool SliceReader::openFile(const std::string & file) {
char magic[8];
if(ifs.read(magic, 8).fail()) {
ifs.close();
LogError << "[slice] error reading magic number";
log_error << "[slice] error reading magic number";
return false;
}
bool found = false;
@ -80,14 +81,14 @@ bool SliceReader::openFile(const std::string & file) {
}
}
if(!found) {
LogError << "[slice] bad magic number";
log_error << "[slice] bad magic number";
ifs.close();
return false;
}
sliceSize = load_number<uint32_t>(ifs);
if(ifs.fail() || std::streampos(sliceSize) > fileSize) {
LogError << "[slice] bad slice size: " << sliceSize << " > " << fileSize;
log_error << "[slice] bad slice size: " << sliceSize << " > " << fileSize;
ifs.close();
return false;
}
@ -110,7 +111,7 @@ bool SliceReader::open(size_t slice, const std::string & file) {
ifs.close();
if(slicesPerDisk == 0) {
LogError << "[slice] slices per disk must not be zero";
log_error << "[slice] slices per disk must not be zero";
return false;
}

11
src/util/color.cpp

@ -1,11 +0,0 @@
#include "util/color.hpp"
namespace color {
shell_command current = color::reset;
}
size_t total_warnings = 0;
size_t total_errors = 0;

69
src/util/color.hpp

@ -1,69 +0,0 @@
#ifndef INNOEXTRACT_UTIL_COLOR_HPP
#define INNOEXTRACT_UTIL_COLOR_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;
} // namespace color
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;
}
};
extern size_t total_warnings;
extern size_t total_errors;
#define LogError (error_base(color::red), total_errors++, std::cerr)
#define LogWarning (error_base(color::yellow), total_warnings++, std::cerr)
#endif // INNOEXTRACT_UTIL_COLOR_HPP

138
src/util/console.cpp

@ -0,0 +1,138 @@
#include "util/console.hpp"
#include <iostream>
#include <cmath>
#include "configure.hpp"
#ifdef HAVE_ISATTY
#include <unistd.h>
#endif
#ifdef HAVE_IOCTL
#include <sys/ioctl.h>
#endif
static bool native_console = true;
namespace color {
shell_command reset = { "\x1b[0m" };
shell_command black = { "\x1b[1;30m" };
shell_command red = { "\x1b[1;31m" };
shell_command green = { "\x1b[1;32m" };
shell_command yellow = { "\x1b[1;33m" };
shell_command blue = { "\x1b[1;34m" };
shell_command magenta = { "\x1b[1;35m" };
shell_command cyan = { "\x1b[1;36m" };
shell_command white = { "\x1b[1;37m" };
shell_command dim_black = { "\x1b[0;30m" };
shell_command dim_red = { "\x1b[0;31m" };
shell_command dim_green = { "\x1b[0;32m" };
shell_command dim_yellow = { "\x1b[0;33m" };
shell_command dim_blue = { "\x1b[0;34m" };
shell_command dim_magenta = { "\x1b[0;35m" };
shell_command dim_cyan = { "\x1b[0;36m" };
shell_command dim_white = { "\x1b[0;37m" };
shell_command current = reset;
void init() {
#ifdef HAVE_ISATTY
if(isatty(1) && isatty(2)) {
return;
}
#endif
native_console = false;
reset.command = "";
black.command = "";
red.command = "";
green.command = "";
yellow.command = "";
blue.command = "";
magenta.command = "";
cyan.command = "";
white.command = "";
dim_black.command = "";
dim_red.command = "";
dim_green.command = "";
dim_yellow.command = "";
dim_blue.command = "";
dim_magenta.command = "";
dim_cyan.command = "";
dim_white.command = "";
current = reset;
}
}
namespace progress {
void show(float value, const std::string & label) {
if(!native_console) {
return;
}
#if defined(HAVE_IOCTL) && defined(TIOCGWINSZ)
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
clear();
std::ios_base::fmtflags flags = std::cout.flags();
size_t progress_length = w.ws_col - label.length() - 6 - 2 - 2 - 1;
if(progress_length > 10) {
size_t progress = size_t(std::ceil(float(progress_length) * value));
std::cout << '[';
for(size_t i = 0; i < progress; i++) {
std::cout << '=';
}
std::cout << '>';
for(size_t i = progress; i < progress_length; i++) {
std::cout << ' ';
}
std::cout << ']';
}
std::cout << std::right << std::fixed << std::setprecision(1) << std::setfill(' ')
<< std::setw(5) << (value * 100) << "% " << label;
std::cout.flush();
std::cout.flags(flags);
#endif
}
void clear() {
if(!native_console) {
return;
}
#ifdef HAVE_IOCTL
std::cout << "\33[2K\r";
#endif
}
} // namespace progress

53
src/util/console.hpp

@ -0,0 +1,53 @@
#ifndef INNOEXTRACT_UTIL_CONSOLE_HPP
#define INNOEXTRACT_UTIL_CONSOLE_HPP
#include <ostream>
#include <iomanip>
namespace color {
struct shell_command {
const char * command;
};
extern shell_command reset;
extern shell_command black;
extern shell_command red;
extern shell_command green;
extern shell_command yellow;
extern shell_command blue;
extern shell_command magenta;
extern shell_command cyan;
extern shell_command white;
extern shell_command dim_black;
extern shell_command dim_red;
extern shell_command dim_green;
extern shell_command dim_yellow;
extern shell_command dim_blue;
extern shell_command dim_magenta;
extern shell_command dim_cyan;
extern shell_command dim_white;
extern shell_command current;
void init();
} // namespace color
inline std::ostream & operator<<(std::ostream & os, const color::shell_command command) {
color::current = command;
return os << command.command;
}
namespace progress {
void show(float value, const std::string & label);
void clear();
} // namespace
#endif // INNOEXTRACT_UTIL_CONSOLE_HPP

2
src/util/enum.hpp

@ -5,7 +5,7 @@
#include <ostream>
#include <boost/utility/enable_if.hpp>
#include "util/color.hpp"
#include "util/console.hpp"
#include "util/flags.hpp"
#include "util/util.hpp"

4
src/util/load.cpp

@ -8,7 +8,7 @@
#include <iconv.h>
#include <errno.h>
#include "util/color.hpp"
#include "util/log.hpp"
namespace {
@ -79,7 +79,7 @@ void to_utf8(const std::string & from, std::string & to, uint32_t codepage) {
size_t ret = iconv(converter, const_cast<char**>(&inbuf), &insize, &outbuf, &outsize);
if(ret == size_t(-1) && errno != E2BIG) {
LogError << "iconv error while converting from CP" << codepage << ": " << errno;
log_error << "iconv error while converting from CP" << codepage << ": " << errno;
to.clear();
return;
}

17
src/util/load.hpp

@ -1,6 +1,6 @@
#ifndef INNOEXTRACT_UTIL_LOADINGUTILS_HPP
#define INNOEXTRACT_UTIL_LOADINGUTILS_HPP
#ifndef INNOEXTRACT_UTIL_LOAD_HPP
#define INNOEXTRACT_UTIL_LOAD_HPP
#include <stdint.h>
#include <cstring>
@ -9,6 +9,7 @@
#include "util/endian.hpp"
#include "util/types.hpp"
#include "util/util.hpp"
struct binary_string {
@ -77,4 +78,14 @@ T load_number(std::istream & is, size_t bits) {
}
}
#endif // INNOEXTRACT_UTIL_LOADINGUTILS_HPP
template <class T>
void discard(T & is, uint64_t bytes) {
char buf[1024];
while(bytes) {
std::streamsize n = std::streamsize(std::min<uint64_t>(bytes, ARRAY_SIZE(buf)));
is.read(buf, n);
bytes -= uint64_t(n);
}
}
#endif // INNOEXTRACT_UTIL_LOAD_HPP

26
src/util/log.cpp

@ -0,0 +1,26 @@
#include "util/log.hpp"
#include <iostream>
#include "util/console.hpp"
bool logger::debug = false;
size_t logger::total_errors = 0;
size_t logger::total_warnings = 0;
logger::~logger() {
color::shell_command previous = color::current;
progress::clear();
switch(level) {
case Debug: std::cout << color::cyan << buffer.str() << std::endl; break;
case Info: std::cout << color::white << buffer.str() << std::endl; break;
case Warning: std::cerr << color::yellow << buffer.str() << std::endl; break;
case Error: std::cerr << color::red << buffer.str() << std::endl; break;
}
std::cout << previous;
}

71
src/util/log.hpp

@ -0,0 +1,71 @@
#ifndef INNOEXTRACT_UTIL_LOG_HPP
#define INNOEXTRACT_UTIL_LOG_HPP
#include <sstream>
#include <string>
#ifdef _DEBUG
#define debug(...) \
if(::logger::debug) \
::logger(__FILE__, __LINE__, ::logger::Debug) << __VA_ARGS__
#define log_info ::logger(__FILE__, __LINE__, ::logger::Info)
#define log_warning ::logger(__FILE__, __LINE__, ::logger::Warning)
#define log_error ::logger(__FILE__, __LINE__, ::logger::Error)
#else
#define debug(...)
#define log_info ::logger(::logger::Info)
#define log_warning ::logger(::logger::Warning)
#define log_error ::logger(::logger::Error)
#endif
/*!
* logger class that allows longging via the stream operator.
*/
class logger {
public:
enum log_level {
Debug,
Info,
Warning,
Error
};
private:
#ifdef _DEBUG
const char * const file;
const int line;
#endif
const log_level level;
std::ostringstream buffer; //! Buffer for the log message excluding level, file and line.
public:
static size_t total_warnings;
static size_t total_errors;
static bool debug;
#ifdef _DEBUG
inline logger(const char * _file, int _line, log_level _level)
: file(_file), line(_line), level(_level) { }
#else
inline logger(log_level _level) : level(_level) { }
#endif
template<class T>
inline logger & operator<<(const T & i) {
buffer << i;
return *this;
}
~logger();
};
#endif // INNOEXTRACT_UTIL_LOG_HPP

2
src/util/output.hpp

@ -6,7 +6,7 @@
#include <iostream>
#include <string>
#include "util/color.hpp"
#include "util/console.hpp"
#include "util/util.hpp"
struct quoted {

213
src/util/storedenum.hpp

@ -0,0 +1,213 @@
#ifndef INNOEXTRACT_UTIL_STOREDENUM_HPP
#define INNOEXTRACT_UTIL_STOREDENUM_HPP
#include <stdint.h>
#include <stddef.h>
#include <vector>
#include <boost/utility/enable_if.hpp>
#include <boost/static_assert.hpp>
#include "util/load.hpp"
#include "util/enum.hpp"
#include "util/load.hpp"
#include "util/log.hpp"
#include "util/util.hpp"
template <class Enum>
struct enum_value_map {
typedef Enum enum_type;
typedef Enum flag_type;
};
#define STORED_ENUM_MAP(MapName, Default, ...) \
struct MapName : public enum_value_map<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)
#define STORED_FLAGS_MAP(MapName, Flag0, ...) \
STORED_ENUM_MAP(MapName, Flag0, Flag0, ## __VA_ARGS__)
template <class Mapping>
struct stored_enum {
size_t value;
public:
typedef Mapping mapping_type;
typedef typename Mapping::enum_type enum_type;
static const size_t size = Mapping::count;
inline stored_enum(std::istream & is) {
// TODO use larger types for larger enums
BOOST_STATIC_ASSERT(size <= (1 << 8));
value = load_number<uint8_t>(is);
}
enum_type get() {
if(value < size) {
return Mapping::values[value];
}
log_warning << "warning: unexpected " << enum_names<enum_type>::name << " value: " << value;
return Mapping::default_value;
}
};
template <size_t Bits>
class stored_bitfield {
typedef uint8_t 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 stored_bitfield(std::istream & is) {
for(size_t i = 0; i < count; i++) {
bits[i] = load_number<base_type>(is);
}
}
inline uint64_t lower_bits() const {
BOOST_STATIC_ASSERT(sizeof(uint64_t) % sizeof(base_type) == 0);
uint64_t result = 0;
for(size_t i = 0; i < std::min(sizeof(uint64_t) / sizeof(base_type), size_t(count)); i++) {
result |= (uint64_t(bits[i]) << (i * base_size));
}
return result;
}
inline operator std::bitset<size>() const {
// Make `make style` shut up since we really need unsigned long here.
#define stored_enum_concat_(a, b, c, d) a##b c##d
typedef stored_enum_concat_(unsi, gned, lo, ng) ulong_type;
#undef stored_enum_concat_
static const size_t ulong_size = sizeof(ulong_type) * 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<ulong_type>(bits[i] >> (j * ulong_size)))
<< ((i * base_size) + (j * ulong_size));
}
}
return result;
}
};
template <class Mapping>
class stored_flags : private stored_bitfield<Mapping::count> {
public:
typedef Mapping mapping_type;
typedef typename Mapping::enum_type enum_type;
typedef flags<enum_type> flag_type;
inline stored_flags(std::istream & is) : stored_bitfield<Mapping::count>(is) { }
flag_type get() {
uint64_t bits = this->lower_bits();
flag_type result = 0;
for(size_t i = 0; i < this->size; i++) {
if(bits & (uint64_t(1) << i)) {
result |= Mapping::values[i];
bits &= ~(uint64_t(1) << i);
}
}
if(bits) {
log_warning << "unexpected " << enum_names<enum_type>::name << " flags: "
<< std::hex << bits << std::dec;
}
return result;
}
};
template <class Enum>
class stored_flag_reader {
public:
typedef Enum enum_type;
typedef flags<enum_type> flag_type;
std::istream & is;
typedef uint8_t stored_type;
static const size_t stored_bits = sizeof(stored_type) * 8;
size_t pos;
stored_type buffer;
flag_type result;
size_t bits;
explicit stored_flag_reader(std::istream & _is) : is(_is), pos(0), result(0), bits(0) { }
void add(enum_type flag) {
if(pos == 0) {
buffer = load_number<stored_type>(is);
}
if(buffer & (stored_type(1) << pos)) {
result |= flag;
}
pos = (pos + 1) % stored_bits;
bits++;
}
operator flag_type() const {
return result;
}
};
template <class Enum>
class stored_flag_reader<flags<Enum> > : public stored_flag_reader<Enum> {
public:
explicit stored_flag_reader(std::istream & is) : stored_flag_reader<Enum>(is) { }
};
typedef stored_bitfield<256> stored_char_set;
#endif // INNOEXTRACT_UTIL_STOREDENUM_HPP

6
src/util/util.hpp

@ -1,6 +1,6 @@
#ifndef INNOEXTRACT_UTIL_ARRAY_HPP
#define INNOEXTRACT_UTIL_ARRAY_HPP
#ifndef INNOEXTRACT_UTIL_UTIL_HPP
#define INNOEXTRACT_UTIL_UTIL_HPP
#define ARRAY_SIZE(array) (sizeof(array)/sizeof(*(array)))
@ -63,4 +63,4 @@ inline T safe_left_shift(T value) {
return detail::safe_shifter<(bits >= (8 * sizeof(T)))>::left_shift(value, bits);
}
#endif // INNOEXTRACT_UTIL_ARRAY_HPP
#endif // INNOEXTRACT_UTIL_UTIL_HPP

Loading…
Cancel
Save