libjxl

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

file_io.h (3942B)


      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 
      6 #ifndef TOOLS_FILE_IO_H_
      7 #define TOOLS_FILE_IO_H_
      8 
      9 #include <errno.h>
     10 #include <limits.h>
     11 #include <stdint.h>
     12 #include <stdio.h>
     13 #include <string.h>
     14 #include <sys/stat.h>
     15 
     16 #include <list>
     17 #include <string>
     18 #include <vector>
     19 
     20 #include "lib/jxl/base/compiler_specific.h"
     21 
     22 namespace jpegxl {
     23 namespace tools {
     24 
     25 // RAII, ensures files are closed even when returning early.
     26 class FileWrapper {
     27  public:
     28   FileWrapper(const FileWrapper& other) = delete;
     29   FileWrapper& operator=(const FileWrapper& other) = delete;
     30 
     31   explicit FileWrapper(const std::string& pathname, const char* mode)
     32       : file_(pathname == "-" ? (mode[0] == 'r' ? stdin : stdout)
     33                               : fopen(pathname.c_str(), mode)),
     34         close_on_delete_(pathname != "-") {
     35 #ifdef _WIN32
     36     struct __stat64 s = {};
     37     const int err = _stat64(pathname.c_str(), &s);
     38     const bool is_file = (s.st_mode & S_IFREG) != 0;
     39 #else
     40     struct stat s = {};
     41     const int err = stat(pathname.c_str(), &s);
     42     const bool is_file = S_ISREG(s.st_mode);
     43 #endif
     44     if (err == 0 && is_file) {
     45       size_ = s.st_size;
     46     }
     47   }
     48 
     49   ~FileWrapper() {
     50     if (file_ != nullptr && close_on_delete_) {
     51       const int err = fclose(file_);
     52       if (err) {
     53         fprintf(stderr,
     54                 "Could not close file\n"
     55                 "Error: %s",
     56                 strerror(errno));
     57       }
     58     }
     59   }
     60 
     61   // We intend to use FileWrapper as a replacement of FILE.
     62   // NOLINTNEXTLINE(google-explicit-constructor)
     63   operator FILE*() const { return file_; }
     64 
     65   int64_t size() const { return size_; }
     66 
     67  private:
     68   FILE* const file_;
     69   bool close_on_delete_ = true;
     70   int64_t size_ = -1;
     71 };
     72 
     73 template <typename ContainerType>
     74 static inline bool ReadFile(FileWrapper& f, ContainerType* JXL_RESTRICT bytes) {
     75   if (!f) return false;
     76 
     77   // Get size of file in bytes
     78   const int64_t size = f.size();
     79   if (size < 0) {
     80     // Size is unknown, loop reading chunks until EOF.
     81     bytes->clear();
     82     std::list<std::vector<uint8_t>> chunks;
     83 
     84     size_t total_size = 0;
     85     while (true) {
     86       std::vector<uint8_t> chunk(16 * 1024);
     87       const size_t bytes_read = fread(chunk.data(), 1, chunk.size(), f);
     88       if (ferror(f) || bytes_read > chunk.size()) {
     89         return false;
     90       }
     91 
     92       chunk.resize(bytes_read);
     93       total_size += bytes_read;
     94       if (bytes_read != 0) {
     95         chunks.emplace_back(std::move(chunk));
     96       }
     97       if (feof(f)) {
     98         break;
     99       }
    100     }
    101     bytes->resize(total_size);
    102     size_t pos = 0;
    103     for (const auto& chunk : chunks) {
    104       memcpy(bytes->data() + pos, chunk.data(), chunk.size());
    105       pos += chunk.size();
    106     }
    107   } else {
    108     // Size is known, read the file directly.
    109     bytes->resize(static_cast<size_t>(size));
    110 
    111     const size_t bytes_read = fread(bytes->data(), 1, bytes->size(), f);
    112     if (bytes_read != static_cast<size_t>(size)) return false;
    113   }
    114 
    115   return true;
    116 }
    117 
    118 template <typename ContainerType>
    119 static inline bool ReadFile(const std::string& filename,
    120                             ContainerType* JXL_RESTRICT bytes) {
    121   FileWrapper f(filename, "rb");
    122   return ReadFile(f, bytes);
    123 }
    124 
    125 template <typename ContainerType>
    126 static inline bool WriteFile(const std::string& filename,
    127                              const ContainerType& bytes) {
    128   FileWrapper file(filename, "wb");
    129   if (!file) {
    130     fprintf(stderr,
    131             "Could not open %s for writing\n"
    132             "Error: %s",
    133             filename.c_str(), strerror(errno));
    134     return false;
    135   }
    136   if (fwrite(bytes.data(), 1, bytes.size(), file) != bytes.size()) {
    137     fprintf(stderr,
    138             "Could not write to file\n"
    139             "Error: %s",
    140             strerror(errno));
    141     return false;
    142   }
    143   return true;
    144 }
    145 
    146 }  // namespace tools
    147 }  // namespace jpegxl
    148 
    149 #endif  // TOOLS_FILE_IO_H_