neptools

Modding tools to Neptunia games
git clone https://git.neptards.moe/neptards/neptools.git
Log | Files | Refs | Submodules | README | LICENSE

sink.hpp (3774B)


      1 #ifndef UUID_8EC8FF70_7F93_4281_9370_FF756B846775
      2 #define UUID_8EC8FF70_7F93_4281_9370_FF756B846775
      3 #pragma once
      4 
      5 #include "utils.hpp"
      6 
      7 #include <libshit/check.hpp>
      8 #include <libshit/meta.hpp>
      9 #include <libshit/meta_utils.hpp>
     10 #include <libshit/nonowning_string.hpp>
     11 #include <libshit/shared_ptr.hpp>
     12 #include <libshit/lua/dynamic_object.hpp>
     13 
     14 #include <cstring>
     15 #include <boost/endian/arithmetic.hpp>
     16 #include <boost/filesystem/path.hpp>
     17 
     18 namespace Neptools
     19 {
     20 
     21   LIBSHIT_GEN_EXCEPTION_TYPE(SinkOverflow, std::logic_error);
     22 
     23   class Sink : public Libshit::RefCounted, public Libshit::Lua::DynamicObject
     24   {
     25     LIBSHIT_DYNAMIC_OBJECT;
     26   public:
     27     static Libshit::NotNull<Libshit::RefCountedPtr<Sink>> ToFile(
     28       boost::filesystem::path fname, FilePosition size, bool try_mmap = true);
     29     static Libshit::NotNull<Libshit::RefCountedPtr<Sink>> ToStdOut();
     30 
     31     FilePosition Tell() const noexcept { return offset + buf_put; }
     32 
     33     template <typename Checker = Libshit::Check::Assert, typename T>
     34     LIBSHIT_NOLUA void WriteGen(const T& x)
     35     { Write<Checker>({reinterpret_cast<const char*>(&x), Libshit::EmptySizeof<T>}); }
     36 
     37     template <typename Checker = Libshit::Check::Assert>
     38     void Write(Libshit::StringView data)
     39     {
     40       LIBSHIT_CHECK(SinkOverflow, offset+buf_put+data.length() <= size,
     41                     "Sink overflow during write");
     42       auto cp = std::min(data.length(), size_t(buf_size - buf_put));
     43       memcpy(buf+buf_put, data.data(), cp);
     44       data.remove_prefix(cp);
     45       buf_put += cp;
     46 
     47       if (!data.empty()) Write_(data);
     48     }
     49 
     50     template <typename Checker = Libshit::Check::Assert>
     51     void Pad(FileMemSize len)
     52     {
     53       LIBSHIT_CHECK(SinkOverflow, offset+buf_put+len <= size,
     54                     "Sink overflow during pad");
     55       auto cp = std::min(len, buf_size - buf_put);
     56       memset(buf+buf_put, 0, cp);
     57       buf_put += cp;
     58       len -= cp;
     59 
     60       if (len) Pad_(len);
     61     }
     62 
     63     virtual void Flush() {}
     64 
     65 #define NEPTOOLS_GEN(bits)                                               \
     66     template <typename Checker = Libshit::Check::Assert>                 \
     67     void WriteLittleUint##bits (boost::endian::little_uint##bits##_t  i) \
     68     { WriteGen<Checker>(i); }
     69     NEPTOOLS_GEN(8) NEPTOOLS_GEN(16) NEPTOOLS_GEN(32) NEPTOOLS_GEN(64)
     70 #undef NEPTOOLS_GEN
     71 
     72     template <typename Checker = Libshit::Check::Assert>
     73     void WriteCString(Libshit::NonowningString str)
     74     { Write<Checker>({str.c_str(), str.size()+1}); }
     75 
     76   protected:
     77     Sink(FilePosition size) : size{size} {}
     78 
     79     Byte* buf = nullptr;
     80     FilePosition offset = 0, size;
     81     FileMemSize buf_put = 0, buf_size;
     82 
     83   private:
     84     virtual void Write_(Libshit::StringView data) = 0;
     85     virtual void Pad_(FileMemSize len) = 0;
     86   } LIBSHIT_LUAGEN(post_register: %q(
     87     // hack to get close call __gc
     88     lua_getfield(bld, -2, "__gc");
     89     bld.SetField("close");
     90   ));
     91 
     92   class MemorySink final : public Sink
     93   {
     94     LIBSHIT_DYNAMIC_OBJECT;
     95   public:
     96 
     97     LIBSHIT_NOLUA
     98     MemorySink(Byte* buffer, FileMemSize size) : Sink{size}
     99     { this->buf = buffer; this->buf_size = size; }
    100 
    101     LIBSHIT_NOLUA
    102     MemorySink(std::unique_ptr<Byte[]> buffer, FileMemSize size)
    103       : Sink{size}, uniq_buf{std::move(buffer)}
    104     { this->buf = uniq_buf.get(); this->buf_size = size; }
    105 
    106     MemorySink(FileMemSize size) : Sink{size}, uniq_buf{new Byte[size]}
    107     { buf = uniq_buf.get(); buf_size = size; }
    108 
    109     LIBSHIT_LUAGEN(name: "to_string")
    110     Libshit::StringView GetStringView() const noexcept
    111     { return {buf, buf_size}; }
    112 
    113     LIBSHIT_NOLUA
    114     std::unique_ptr<Byte[]> Release() noexcept { return std::move(uniq_buf); }
    115 
    116   private:
    117     std::unique_ptr<Byte[]> uniq_buf;
    118 
    119     void Write_(Libshit::StringView) override;
    120     void Pad_(FileMemSize) override;
    121   };
    122 
    123 }
    124 #endif