libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

benchmark_file_io.cc (6875B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 #include "tools/benchmark/benchmark_file_io.h"
      6 
      7 #include <errno.h>
      8 #include <sys/stat.h>
      9 
     10 #include <cstdio>
     11 
     12 #if defined(_WIN32) || defined(_WIN64)
     13 #include "third_party/dirent.h"
     14 #else
     15 #include <dirent.h>
     16 #include <unistd.h>
     17 #endif
     18 
     19 #ifndef HAS_GLOB
     20 #define HAS_GLOB 0
     21 #if defined __has_include
     22 // <glob.h> is included in previous APIs but glob() function is not defined
     23 // until API 28.
     24 #if __has_include(<glob.h>) && \
     25     (!defined(__ANDROID_API__) || __ANDROID_API__ >= 28)
     26 #undef HAS_GLOB
     27 #define HAS_GLOB 1
     28 #endif  // __has_include(<glob.h>)
     29 #endif  // __has_include
     30 #endif  // HAS_GLOB
     31 
     32 #if HAS_GLOB
     33 #include <glob.h>
     34 #endif  // HAS_GLOB
     35 
     36 // There is no "user" in embedded filesystems.
     37 #ifndef GLOB_TILDE
     38 #define GLOB_TILDE 0
     39 #endif
     40 
     41 namespace jpegxl {
     42 namespace tools {
     43 
     44 const char kPathSeparator = '/';
     45 
     46 // RAII, ensures dir is closed even when returning early.
     47 class DirWrapper {
     48  public:
     49   DirWrapper(const DirWrapper& other) = delete;
     50   DirWrapper& operator=(const DirWrapper& other) = delete;
     51 
     52   explicit DirWrapper(const std::string& pathname)
     53       : dir_(opendir(pathname.c_str())) {}
     54 
     55   ~DirWrapper() {
     56     if (dir_ != nullptr) {
     57       const int err = closedir(dir_);
     58       JXL_CHECK(err == 0);
     59     }
     60   }
     61 
     62   // NOLINTNEXTLINE(google-explicit-constructor)
     63   operator DIR*() const { return dir_; }
     64 
     65  private:
     66   DIR* const dir_;
     67 };
     68 
     69 // Checks if the file exists, either as file or as directory
     70 bool PathExists(const std::string& fname) {
     71   struct stat s;
     72   if (stat(fname.c_str(), &s) != 0) return false;
     73   return true;
     74 }
     75 
     76 // Checks if the file exists and is a regular file.
     77 bool IsRegularFile(const std::string& fname) {
     78   struct stat s;
     79   if (stat(fname.c_str(), &s) != 0) return false;
     80   return S_ISREG(s.st_mode);
     81 }
     82 
     83 // Checks if the file exists and is a directory.
     84 bool IsDirectory(const std::string& fname) {
     85   struct stat s;
     86   if (stat(fname.c_str(), &s) != 0) return false;
     87   return S_ISDIR(s.st_mode);
     88 }
     89 
     90 // Recursively makes dir, or successfully does nothing if it already exists.
     91 Status MakeDir(const std::string& dirname) {
     92   size_t pos = 0;
     93   for (pos = dirname.size(); pos > 0; pos--) {
     94     if (pos == dirname.size() || dirname[pos] == kPathSeparator) {
     95       // Found existing dir or regular file, break and then start creating
     96       // from here (in the latter case we'll get error below).
     97       if (PathExists(dirname.substr(0, pos + 1))) {
     98         pos += 1;  // Skip past this existing path
     99         break;
    100       }
    101     }
    102   }
    103   for (; pos <= dirname.size(); pos++) {
    104     if (pos == dirname.size() || dirname[pos] == kPathSeparator) {
    105       std::string subdir = dirname.substr(0, pos + 1);
    106       if (mkdir(subdir.c_str(), 0777) && errno != EEXIST) {
    107         return JXL_FAILURE("Failed to create directory");
    108       }
    109     }
    110   }
    111   if (!IsDirectory(dirname)) return JXL_FAILURE("Failed to create directory");
    112   return true;  // success
    113 }
    114 
    115 Status DeleteFile(const std::string& fname) {
    116   if (!IsRegularFile(fname)) {
    117     return JXL_FAILURE("Trying to delete non-regular file");
    118   }
    119   if (std::remove(fname.c_str())) return JXL_FAILURE("Failed to delete file");
    120   return true;
    121 }
    122 
    123 std::string FileBaseName(const std::string& fname) {
    124   size_t pos = fname.rfind('/');
    125   if (pos == std::string::npos) return fname;
    126   return fname.substr(pos + 1);
    127 }
    128 
    129 std::string FileDirName(const std::string& fname) {
    130   size_t pos = fname.rfind('/');
    131   if (pos == std::string::npos) return "";
    132   return fname.substr(0, pos);
    133 }
    134 
    135 std::string FileExtension(const std::string& fname) {
    136   size_t pos = fname.rfind('.');
    137   if (pos == std::string::npos) return "";
    138   return fname.substr(pos);
    139 }
    140 
    141 std::string JoinPath(const std::string& first, const std::string& second) {
    142   JXL_CHECK(second.empty() || second[0] != kPathSeparator);
    143   return (!first.empty() && first.back() == kPathSeparator)
    144              ? (first + second)
    145              : (first + kPathSeparator + second);
    146 }
    147 
    148 // Can match a single file, or multiple files in a directory (non-recursive).
    149 // With POSIX, supports glob(), otherwise supports a subset.
    150 Status MatchFiles(const std::string& pattern, std::vector<std::string>* list) {
    151 #if HAS_GLOB
    152   glob_t g;
    153   memset(&g, 0, sizeof(g));
    154   int error = glob(pattern.c_str(), GLOB_TILDE, nullptr, &g);
    155   if (!error) {
    156     for (size_t i = 0; i < g.gl_pathc; ++i) {
    157       list->emplace_back(g.gl_pathv[i]);
    158     }
    159   }
    160   globfree(&g);
    161   if (error) return JXL_FAILURE("glob failed for %s", pattern.c_str());
    162   return true;
    163 #else
    164   std::string dirname = FileDirName(pattern);
    165   std::string basename = FileBaseName(pattern);
    166   size_t pos0 = basename.find('*');
    167   size_t pos1 = pos0 == std::string::npos ? pos0 : basename.find('*', pos0 + 1);
    168   std::string prefix, middle, suffix;
    169   if (pos0 != std::string::npos) {
    170     prefix = basename.substr(0, pos0);
    171     if (pos1 != std::string::npos) {
    172       middle = basename.substr(pos0 + 1, pos1 - pos0 - 1);
    173       suffix = basename.substr(pos1 + 1);
    174     } else {
    175       suffix = basename.substr(pos0 + 1);
    176     }
    177   }
    178 
    179   if (prefix.find_first_of("*?[") != std::string::npos ||
    180       middle.find_first_of("*?[") != std::string::npos ||
    181       suffix.find_first_of("*?[") != std::string::npos ||
    182       dirname.find_first_of("*?[") != std::string::npos) {
    183     return JXL_FAILURE(
    184         "Only glob patterns with max two '*' in the basename"
    185         " are supported, e.g. directory/path/*.png or"
    186         " /directory/path/*heatmap*");
    187   }
    188 
    189   if (pos0 != std::string::npos) {
    190     DirWrapper dir(dirname);
    191     if (!dir) return JXL_FAILURE("directory %s doesn't exist", dirname.c_str());
    192     for (;;) {
    193       dirent* ent = readdir(dir);
    194       if (!ent) break;
    195       std::string name = ent->d_name;
    196       // If there was a suffix, only add if it matches (e.g. ".png")
    197       bool matches =
    198           name.size() >= (prefix.size() + middle.size() + suffix.size());
    199       if (matches) {
    200         if (!prefix.empty() && name.substr(0, prefix.size()) != prefix) {
    201           matches = false;
    202         }
    203         if (!middle.empty()) {
    204           size_t pos = name.find(middle, prefix.size());
    205           if (pos == std::string::npos ||
    206               pos + middle.size() > name.size() - suffix.size()) {
    207             matches = false;
    208           }
    209         }
    210         if (!suffix.empty() &&
    211             name.substr(name.size() - suffix.size()) != suffix) {
    212           matches = false;
    213         }
    214       }
    215       if (matches) {
    216         std::string path = JoinPath(dirname, name);
    217 
    218         if (IsRegularFile(path)) {
    219           list->push_back(path);
    220         }
    221       }
    222     }
    223     return true;
    224   }
    225   // No *, so a single regular file is intended
    226   if (IsRegularFile(pattern)) {
    227     list->push_back(pattern);
    228   }
    229   return true;
    230 #endif  // HAS_GLOB
    231 }
    232 
    233 }  // namespace tools
    234 }  // namespace jpegxl