Browse Source

Allow to only extract files for a specific language.

pull/1/head
Daniel Scharrer 14 years ago
parent
commit
4be0e5b159
  1. 1
      CMakeLists.txt
  2. 3
      doc/innoextract.1
  3. 59
      src/cli/main.cpp
  4. 158
      src/setup/expression.cpp
  5. 32
      src/setup/expression.hpp

1
CMakeLists.txt

@ -108,6 +108,7 @@ set(INNOEXTRACT_SOURCES
src/setup/data.cpp
src/setup/delete.cpp
src/setup/directory.cpp
src/setup/expression.cpp
src/setup/file.cpp
src/setup/filename.cpp
src/setup/header.cpp

3
doc/innoextract.1

@ -49,6 +49,9 @@ and
.B \-h --help
Show a list of the supported options.
.TP
.B \--language [lang]
Extract only language-independent files and files for the given language. By default all files are extracted.
.TP
.B \--license
Show license information.
.TP

59
src/cli/main.cpp

@ -44,6 +44,7 @@
#include "loader/offsets.hpp"
#include "setup/data.hpp"
#include "setup/expression.hpp"
#include "setup/file.hpp"
#include "setup/filename.hpp"
#include "setup/info.hpp"
@ -125,6 +126,8 @@ struct options {
bool list;
bool test;
std::string language;
setup::filename_map filenames;
};
@ -218,27 +221,19 @@ static void process_file(const fs::path & file, const options & o) {
BOOST_FOREACH(const Files::value_type & location, chunk.second) {
const stream::file & file = location.first;
// Seek to the correct position within the chunk
if(!o.list) {
if(file.offset < offset) {
log_error << "bad offset";
throw std::runtime_error("unexpected error");
}
if(file.offset > offset) {
log_warning << "discarding " << print_bytes(file.offset - offset);
discard(*chunk_source, file.offset - offset);
}
offset = file.offset + file.size;
}
// Convert output filenames
typedef std::pair<fs::path, size_t> file_t;
std::vector<file_t> output_names;
for(size_t i = 0; i < files_for_location[location.second].size(); i++) {
size_t file_i = files_for_location[location.second][i];
if(!o.language.empty() && !info.files[file_i].languages.empty()) {
if(!setup::expression_match(o.language, info.files[file_i].languages)) {
continue;
}
}
if(!info.files[file_i].destination.empty()) {
fs::path path;
if(o.dump) {
@ -256,6 +251,11 @@ static void process_file(const fs::path & file, const options & o) {
}
}
if(output_names.empty()) {
extract_progress.update(location.first.size);
continue;
}
// Print filename and size
if(!o.silent) {
@ -295,6 +295,17 @@ static void process_file(const fs::path & file, const options & o) {
continue;
}
// Seek to the correct position within the chunk
if(file.offset < offset) {
log_error << "bad offset";
throw std::runtime_error("unexpected error");
}
if(file.offset > offset) {
debug("discarding " << print_bytes(file.offset - offset));
discard(*chunk_source, file.offset - offset);
}
offset = file.offset + file.size;
crypto::checksum checksum;
// Open input file
@ -361,11 +372,16 @@ int main(int argc, char * argv[]) {
po::options_description action("Actions");
action.add_options()
("dump", "Dump contents without converting filenames.")
("test,t", "Only verify checksums, don't write anything.")
("extract,e", "Extract files (default action).")
("list,l", "Only list files, don't write anything.")
;
po::options_description filter("Filters");
filter.add_options()
("dump", "Dump contents without converting filenames.")
("lowercase,L", "Convert extracted filenames to lower-case.")
("language", po::value<std::string>(), "Extract files for the given language.")
;
po::options_description io("I/O options");
@ -385,10 +401,10 @@ int main(int argc, char * argv[]) {
/**/;
po::options_description options_desc;
options_desc.add(generic).add(action).add(io).add(hidden);
options_desc.add(generic).add(action).add(filter).add(io).add(hidden);
po::options_description visible;
visible.add(generic).add(action).add(io);
visible.add(generic).add(action).add(filter).add(io);
po::positional_options_description p;
p.add("setup-files", -1);
@ -469,6 +485,11 @@ int main(int argc, char * argv[]) {
}
}
po::variables_map::const_iterator i = options.find("language");
if(i != options.end()) {
o.language = i->second.as<std::string>();
}
if(!options.count("setup-files")) {
if(!o.silent) {
std::cout << "no input files specified\n";

158
src/setup/expression.cpp

@ -0,0 +1,158 @@
/*
* Copyright (C) 2012 Daniel Scharrer
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the author(s) be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#include "setup/expression.hpp"
#include <stddef.h>
#include <cstring>
#include <vector>
#include <stdexcept>
#include "util/log.hpp"
namespace setup {
static bool is_identifier_start(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
}
static bool is_identifier(char c) {
return is_identifier_start(c) || (c >= '0' && c <= '9') || c == '\\';
}
struct evaluator {
const std::string & test;
const char * expr;
enum token_type {
end,
op_or,
op_and,
op_not,
paren_left,
paren_right,
identifier
} token;
std::string token_str;
evaluator(const std::string & expr, const std::string & test)
: test(test), expr(expr.c_str()) { }
token_type next() {
// Ignore whitespace
while(*expr > 0 && *expr <= 32) {
expr++;
}
if(!*expr) {
return (token = end);
} else if(*expr == '(') {
return (expr++, token = paren_left);
} else if(*expr == ')') {
return (expr++, token = paren_right);
} else if(is_identifier_start(*expr)) {
const char * start = expr++;
while(is_identifier(*expr)) {
expr++;
}
if(expr - start == 3 && !memcmp(start, "not", 3)) {
return (token = op_not);
} else if(expr - start == 3 && !memcmp(start, "and", 3)) {
return (token = op_and);
} else if(expr - start == 2 && !memcmp(start, "or", 2)) {
return (token = op_or);
}
return (token_str.assign(start, expr), token = identifier);
} else {
throw std::runtime_error(std::string("unexpected symbol: ") + *expr);
}
}
bool eval_identifier(bool lazy) {
bool result = lazy || token_str == test;
next();
return result;
}
bool eval_factor(bool lazy) {
if(token == paren_left) {
next();
bool result = eval_expression(lazy);
if(token != paren_right) {
throw std::runtime_error("expected closing parenthesis");
}
next();
return result;
} else if(token == op_not) {
next();
return !eval_factor(lazy);
} else if(token == identifier) {
return eval_identifier(lazy);
} else {
throw std::runtime_error("unexpected token");
}
}
bool eval_term(bool lazy) {
bool result = eval_factor(lazy);
while(token == op_and) {
next();
result = result && eval_factor(lazy || !result);
}
return result;
}
bool eval_expression(bool lazy) {
bool result = eval_term(lazy);
while(token == op_or || token == identifier) {
if(token == op_or) {
next();
}
result = result || eval_term(lazy || result);
}
return result;
}
bool eval() {
next();
return eval_expression(false);
}
};
bool expression_match(const std::string & test, const std::string & expr) {
try {
return evaluator(expr, test).eval();
} catch(const std::runtime_error & error) {
log_warning << "error evaluating \"" << expr << "\": " << error.what();
return true;
}
}
} // namespace setup

32
src/setup/expression.hpp

@ -0,0 +1,32 @@
/*
* Copyright (C) 2012 Daniel Scharrer
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the author(s) be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef INNOEXTRACT_SETUP_EXPRESSION_HPP
#define INNOEXTRACT_SETUP_EXPRESSION_HPP
#include <string>
namespace setup {
bool expression_match(const std::string & test, const std::string & expression);
} // namespace setup
#endif // INNOEXTRACT_SETUP_EXPRESSION_HPP
Loading…
Cancel
Save