diff --git a/trunk/Makefile b/trunk/Makefile index c939c73..f09f2e5 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -1,5 +1,5 @@ -LIBS = boost_program_options boost_filesystem boost_system -CFLAGS = -O2 -Wall -pedantic `Magick++-config --cppflags` +LIBS = boost_program_options boost_filesystem boost_system magic +CFLAGS = -O2 -Wall `Magick++-config --cppflags` LINKER_FLAGS = `Magick++-config --libs` PROJECT_NAME = pn SRC_DIR = src diff --git a/trunk/src/default_main.cpp b/trunk/src/default_main.cpp index d3d7ef5..248ca18 100644 --- a/trunk/src/default_main.cpp +++ b/trunk/src/default_main.cpp @@ -45,7 +45,7 @@ class accumulator: public arr, boost::shared_ptr > { void default_main(const program_options& po) { struct : end< boost::shared_ptr > { - void next(const boost::shared_ptr& t) { std::cout << t->path() << "\n"; } + void next(const boost::shared_ptr& t) { std::cout << t->path().string() << "\n"; } void stop() { std::cout << "\n"; } } output; diff --git a/trunk/src/file_types/base.cpp b/trunk/src/file_types/base.cpp index 8fd66bf..7f056ad 100644 --- a/trunk/src/file_types/base.cpp +++ b/trunk/src/file_types/base.cpp @@ -6,10 +6,14 @@ #include "base.h" #include "../kleisli.h" #include "../filesystem.h" +#include "../magic_file.h" namespace file_type { -base::base(const fs::path& p): _path(p), _size(fs::file_size(p)) { } +base::base(const fs::path& p): _path(p), _size(fs::file_size(p)) { + const char* s = magic::mime_type(p.c_str()); + _mime = s ? s : ""; +} boost::shared_ptr base::try_file(const fs::path& file) { return boost::make_shared(file); diff --git a/trunk/src/file_types/base.h b/trunk/src/file_types/base.h index 20bb31d..08d48c8 100644 --- a/trunk/src/file_types/base.h +++ b/trunk/src/file_types/base.h @@ -2,7 +2,9 @@ #define _FILE_TYPE_BASE_H_ #include +#include #include +#include #include "../filesystem.h" #include "../type_list.h" @@ -19,12 +21,26 @@ enum comparison_result class base { fs::path _path; unsigned int _size; + std::string _mime; public: base(const fs::path& p); const fs::path& path() const { return _path; } + const std::string& mime() const { return _mime; } static boost::shared_ptr try_file(const fs::path& file); virtual boost::shared_ptr compare(const boost::shared_ptr& a) const; virtual comparison_result precompare(const boost::shared_ptr& a) const; + + template + bool check_type(It1 mimes, It1 mimes_end, It2 exts, It2 exts_end) const { + bool res; + if (!_mime.empty()) { + res = std::find(mimes, mimes_end, _mime) != mimes_end; + } else { + std::string ext = boost::to_lower_copy(_path.extension().string()); + res = std::find(exts, exts_end, ext) != exts_end; + } + return res; + } }; } diff --git a/trunk/src/file_types/img.cpp b/trunk/src/file_types/img.cpp index 45b3407..073daa6 100644 --- a/trunk/src/file_types/img.cpp +++ b/trunk/src/file_types/img.cpp @@ -27,16 +27,17 @@ img::img(const fs::path& p, const Magick::Image& image): base(p), _image(image) } } for (unsigned int j = 0; j < BUCKET_COUNT; ++j) { - bucket[0][j] /= size; - bucket[1][j] /= size; - bucket[2][j] /= size; + for (unsigned int k = 0; k < HISTOGRAM_COUNT; ++k) { + bucket[k][j] /= size; + } } } boost::shared_ptr img::try_file(const boost::shared_ptr& file) { - static const fs::path exts[] = { ".JPG", ".png" }; - static const fs::path* exts_end = exts + sizeof(exts)/sizeof(fs::path); - if (find(exts, exts_end, file->path().extension()) != exts_end) { + static const std::string mimes[] = { "image/jpeg", "image/png" }; + static const std::string exts[] = { ".jpg", ".png" }; + if (file->check_type(mimes, mimes + sizeof(mimes)/sizeof(std::string), + exts, exts + sizeof(exts)/sizeof(std::string))) { try { Magick::Image image; image.read(file->path().string()); @@ -54,7 +55,9 @@ boost::shared_ptr img::compare(const boost::shared_ptr& _a) const { const img* a = static_cast(_a.get()); double res = 0; for (unsigned int i = 0; i < BUCKET_COUNT; ++i) { - res += abs(bucket[0][i] - a->bucket[0][i]) + abs(bucket[1][i] - a->bucket[1][i]) + abs(bucket[2][i] - a->bucket[2][i]); + for (unsigned int k = 0; k < HISTOGRAM_COUNT; ++k) { + res += abs(bucket[k][i] - a->bucket[k][i]); + } } return res > THRESHOLD ? boost::shared_ptr() : _a; } diff --git a/trunk/src/file_types/img.h b/trunk/src/file_types/img.h index c92e186..6eca2c1 100644 --- a/trunk/src/file_types/img.h +++ b/trunk/src/file_types/img.h @@ -16,7 +16,8 @@ struct img: base { comparison_result precompare(const boost::shared_ptr& a) const; private: static const unsigned int BUCKET_COUNT = 4; - double bucket[3][BUCKET_COUNT]; + static const unsigned int HISTOGRAM_COUNT = 3; + double bucket[HISTOGRAM_COUNT][BUCKET_COUNT]; Magick::Image _image; }; diff --git a/trunk/src/file_types/text.cpp b/trunk/src/file_types/text.cpp index c4d80cf..ff6ff0d 100644 --- a/trunk/src/file_types/text.cpp +++ b/trunk/src/file_types/text.cpp @@ -9,12 +9,11 @@ namespace file_type { boost::shared_ptr text::try_file(const boost::shared_ptr& file) { - static const fs::path exts[] = { ".txt" }; - static const fs::path* exts_end = exts + sizeof(exts)/sizeof(fs::path); - if (find(exts, exts_end, file->path().extension()) != exts_end) { - return boost::make_shared(file->path()); - } - return boost::shared_ptr(); + static const std::string mimes[] = { "text/plain" }; + static const std::string exts[] = { ".txt" }; + return file->check_type(mimes, mimes + sizeof(mimes)/sizeof(std::string), + exts, exts + sizeof(exts)/sizeof(std::string)) ? + boost::make_shared(file->path()) : boost::shared_ptr(); } static int clean_str(char* s, int size) { diff --git a/trunk/src/filesystem.cpp b/trunk/src/filesystem.cpp index a780b3f..b543fad 100644 --- a/trunk/src/filesystem.cpp +++ b/trunk/src/filesystem.cpp @@ -12,7 +12,7 @@ void recursive::next(const std::string& value) { void next(const fs::path& value) { if (is_regular_file(value)) pass(value); } } filter; boost::system::error_code e; - make_pair(recursive_directory_iterator(value, e), recursive_directory_iterator()) + std::make_pair(recursive_directory_iterator(value, e), recursive_directory_iterator()) >>= filter >>= continuation(); if (e) { logger::std_stream() << value << ": " << e.message() << "\n"; diff --git a/trunk/src/magic_file.cpp b/trunk/src/magic_file.cpp new file mode 100644 index 0000000..266212e --- /dev/null +++ b/trunk/src/magic_file.cpp @@ -0,0 +1,25 @@ +#include + +#include "magic_file.h" + +static magic_t magic_cookie = 0; + +namespace magic { + +void initialize() { + if ((magic_cookie = magic_open(MAGIC_MIME_TYPE))) { + magic_load(magic_cookie, 0); + } +} + +void destroy() { + if (magic_cookie) { + magic_close(magic_cookie); + } +} + +const char* mime_type(const char* s) { + return magic_cookie ? magic_file(magic_cookie, s) : 0; +} + +} diff --git a/trunk/src/magic_file.h b/trunk/src/magic_file.h new file mode 100644 index 0000000..fab3dac --- /dev/null +++ b/trunk/src/magic_file.h @@ -0,0 +1,10 @@ +#ifndef _MAGIC_FILE_H_ +#define _MAGIC_FILE_H_ + +namespace magic { + void initialize(); + void destroy(); + const char* mime_type(const char* s); +} + +#endif diff --git a/trunk/src/main.cpp b/trunk/src/main.cpp index c0be4df..afb5a6f 100644 --- a/trunk/src/main.cpp +++ b/trunk/src/main.cpp @@ -1,5 +1,6 @@ #include "logger.h" #include "program_options.h" +#include "magic_file.h" void default_main(const program_options& po); @@ -9,7 +10,11 @@ int main(int argc, char* argv[]) { program_options po(argc, argv); + magic::initialize(); + default_main(po); + magic::destroy(); + return 0; }