55# define NOMINMAX
66#endif
77#include < windows.h>
8+ #else
9+ #include < dirent.h>
10+ #include < sys/stat.h>
11+ #include < sys/types.h>
812#endif
913
1014#include " mtmd.h"
@@ -442,16 +446,16 @@ mtmd_bitmap * mtmd_helper_bitmap_init_from_buf(mtmd_context * ctx, const unsigne
442446 return result;
443447}
444448
445- mtmd_bitmap * mtmd_helper_bitmap_init_from_file (mtmd_context * ctx, const char * fname ) {
449+ mtmd_bitmap * mtmd_helper_bitmap_init_from_file (mtmd_context * ctx, const char * path ) {
446450 // although we could read the file into memory and call mtmd_helper_bitmap_init_from_buf,
447451 // but for video files, it's better to let ffmpeg read from file
448- if (mtmd_video::is_video_file (fname )){
449- return mtmd_video::init_video_bitmap (ctx, fname );
452+ if (mtmd_video::is_video_file (path) || mtmd_helper::is_dir (path )){
453+ return mtmd_video::init_video_bitmap (ctx, path );
450454 }
451455
452- FILE * f = fopen (fname , " rb" );
456+ FILE * f = fopen (path , " rb" );
453457 if (!f) {
454- LOG_ERR (" Unable to open file %s: %s\n " , fname , strerror (errno));
458+ LOG_ERR (" Unable to open path %s: %s\n " , path , strerror (errno));
455459 return nullptr ;
456460 }
457461
@@ -463,11 +467,76 @@ mtmd_bitmap * mtmd_helper_bitmap_init_from_file(mtmd_context * ctx, const char *
463467 size_t n_read = fread (buf, 1 , file_size, f);
464468 fclose (f);
465469 if (n_read != (size_t )file_size) {
466- LOG_ERR (" Failed to read entire file %s" , fname );
470+ LOG_ERR (" Failed to read entire path %s" , path );
467471 return nullptr ;
468472 }
469473
470474 auto * res = mtmd_helper_bitmap_init_from_buf (ctx, buf, file_size);
471475 delete [] buf;
472476 return res;
473477}
478+
479+ namespace mtmd_helper {
480+
481+ bool has_image_ext (const std::string & name) {
482+ auto lower = name;
483+ std::transform (lower.begin (), lower.end (), lower.begin (), [](unsigned char c){ return (char )std::tolower (c); });
484+ return lower.rfind (" .jpg" ) != std::string::npos ||
485+ lower.rfind (" .jpeg" ) != std::string::npos ||
486+ lower.rfind (" .png" ) != std::string::npos ||
487+ lower.rfind (" .bmp" ) != std::string::npos ||
488+ lower.rfind (" .gif" ) != std::string::npos ||
489+ lower.rfind (" .webp" ) != std::string::npos;
490+ }
491+
492+ bool is_dir (const std::string & path) {
493+ #if defined(_WIN32)
494+ DWORD attrs = GetFileAttributesA (path.c_str ());
495+ return (attrs != INVALID_FILE_ATTRIBUTES) && (attrs & FILE_ATTRIBUTE_DIRECTORY);
496+ #else
497+ struct stat st;
498+ if (stat (path.c_str (), &st) != 0 ) return false ;
499+ return S_ISDIR (st.st_mode );
500+ #endif
501+ }
502+
503+ void list_files (const std::string & dir, std::vector<std::string> & out, bool recursive) {
504+ #if defined(_WIN32)
505+ std::string pattern = dir;
506+ if (!pattern.empty () && pattern.back () != ' /' && pattern.back () != ' \\ ' ) pattern += " \\ " ;
507+ pattern += " *" ;
508+ WIN32_FIND_DATAA ffd;
509+ HANDLE hFind = FindFirstFileA (pattern.c_str (), &ffd);
510+ if (hFind == INVALID_HANDLE_VALUE) return ;
511+ do {
512+ std::string name = ffd.cFileName ;
513+ if (name == " ." || name == " .." ) continue ;
514+ std::string path = dir;
515+ if (!path.empty () && path.back () != ' /' && path.back () != ' \\ ' ) path += " \\ " ;
516+ path += name;
517+ if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
518+ if (recursive) list_files (path, out, recursive);
519+ } else {
520+ out.push_back (path);
521+ }
522+ } while (FindNextFileA (hFind, &ffd) != 0 );
523+ FindClose (hFind);
524+ #else
525+ DIR * dp = opendir (dir.c_str ());
526+ if (!dp) return ;
527+ struct dirent * de;
528+ while ((de = readdir (dp)) != nullptr ) {
529+ std::string name = de->d_name ;
530+ if (name == " ." || name == " .." ) continue ;
531+ std::string path = dir + " /" + name;
532+ if (is_dir (path)) {
533+ if (recursive) list_files (path, out, recursive);
534+ } else {
535+ out.push_back (path);
536+ }
537+ }
538+ closedir (dp);
539+ #endif
540+ }
541+
542+ }
0 commit comments