// // YaPB - Counter-Strike Bot based on PODBot by Markus Klinge. // Copyright © 2004-2020 YaPB Project . // // SPDX-License-Identifier: MIT // #pragma once #include #include #include CR_NAMESPACE_BEGIN // simple stdio file wrapper class File final : private DenyCopying { private: FILE *handle_ = nullptr; size_t length_ {}; public: explicit File () = default; File (StringRef file, StringRef mode = "rt") { open (file, mode); } ~File () { close (); } public: bool open (StringRef file, StringRef mode) { if (!openFile (file, mode)) { return false; } fseek (handle_, 0L, SEEK_END); length_ = ftell (handle_); fseek (handle_, 0L, SEEK_SET); return true; } void close () { if (handle_ != nullptr) { fclose (handle_); handle_ = nullptr; } length_ = 0; } bool eof () const { return !!feof (handle_); } bool flush () const { return !!fflush (handle_); } int get () const { return fgetc (handle_); } char *getString (char *buffer, int count) const { return fgets (buffer, count, handle_); } bool getLine (String &line) { int ch = 0; SmallArray data (255); line.clear (); while ((ch = get ()) != EOF && !eof ()) { data.push (static_cast (ch)); if (ch == '\n') { break; } } if (!data.empty ()) { line.assign (data.data (), data.length ()); } return !line.empty (); } template size_t puts (const char *fmt, Args &&...args) { if (!*this) { return 0; } return fputs (strings.format (fmt, cr::forward (args)...), handle_); } bool puts (const char *buffer) { if (!*this) { return 0; } if (fputs (buffer, handle_) < 0) { return false; } return true; } int putChar (int ch) { return fputc (ch, handle_); } size_t read (void *buffer, size_t size, size_t count = 1) { return fread (buffer, size, count, handle_); } size_t write (void *buffer, size_t size, size_t count = 1) { return fwrite (buffer, size, count, handle_); } bool seek (long offset, int origin) { if (fseek (handle_, offset, origin) != 0) { return false; } return true; } void rewind () { ::rewind (handle_); } size_t length () const { return length_; } public: explicit operator bool () const { return handle_ != nullptr; } public: static inline bool exists (StringRef file) { File fp; if (fp.open (file, "rb")) { fp.close (); return true; } return false; } static inline void createPath (const char *path) { for (auto str = const_cast (path) + 1; *str; ++str) { if (*str == '/') { *str = 0; plat.createDirectory (path); *str = '/'; } } plat.createDirectory (path); } private: bool openFile (StringRef filename, StringRef mode) { if (*this) { close (); } #if defined (CR_WINDOWS) fopen_s (&handle_, filename.chars (), mode.chars ()); #else handle_ = fopen (filename.chars (), mode.chars ()); #endif return handle_ != nullptr; } }; // wrapper for memory file for loading data into the memory class MemFileStorage : public Singleton { private: using LoadFunction = Lambda ; using FreeFunction = Lambda ; private: LoadFunction loadFun_ = nullptr; FreeFunction freeFun_ = nullptr; public: explicit MemFileStorage () = default; ~MemFileStorage () = default; public: void initizalize (LoadFunction loader, FreeFunction unloader) { loadFun_ = cr::move (loader); freeFun_ = cr::move (unloader); } public: uint8 *load (StringRef file, int *size) { if (loadFun_) { return loadFun_ (file.chars (), size); } return nullptr; } void unload (void *buffer) { if (freeFun_) { freeFun_ (buffer); } } public: static uint8 *defaultLoad (const char *path, int *size) { File file (path, "rb"); if (!file) { *size = 0; return nullptr; } *size = static_cast (file.length ()); auto data = Memory::get (*size); file.read (data, *size); return data; } static void defaultUnload (void *buffer) { Memory::release (buffer); } static String loadToString (StringRef filename) { int32 result = 0; auto buffer = defaultLoad (filename.chars (), &result); if (result > 0 && buffer) { String data (reinterpret_cast (buffer), result); defaultUnload (buffer); return data; } return ""; } }; class MemFile final : public DenyCopying { private: enum : char { Eof = static_cast (-1) }; private: uint8 *contents_ = nullptr; size_t length_ {}; size_t seek_ {}; public: explicit MemFile () = default; MemFile (StringRef file) { open (file); } ~MemFile () { close (); } public: bool open (StringRef file) { length_ = 0; seek_ = 0; contents_ = MemFileStorage::instance ().load (file.chars (), reinterpret_cast (&length_)); if (!contents_) { return false; } return true; } void close () { MemFileStorage::instance ().unload (contents_); length_ = 0; seek_ = 0; contents_ = nullptr; } char get () { if (!contents_ || seek_ >= length_) { return Eof; } return static_cast (contents_[seek_++]); } char *getString (char *buffer, size_t count) { if (!contents_ || seek_ >= length_) { return nullptr; } size_t index = 0; buffer[0] = 0; for (; index < count - 1;) { if (seek_ < length_) { buffer[index] = contents_[seek_++]; if (buffer[index++] == '\n') { break; } } else { break; } } buffer[index] = 0; return index ? buffer : nullptr; } bool getLine (String &line) { char ch; SmallArray data (255); line.clear (); while ((ch = get ()) != Eof && !eof ()) { data.push (ch); if (ch == '\n') { break; } } if (!data.empty ()) { line.assign (data.data (), data.length ()); } return !line.empty (); } size_t read (void *buffer, size_t size, size_t count = 1) { if (!contents_ || length_ <= seek_ || !buffer || !size || !count) { return 0; } size_t blocksRead = size * count <= length_ - seek_ ? size * count : length_ - seek_; memcpy (buffer, &contents_[seek_], blocksRead); seek_ += blocksRead; return blocksRead / size; } bool seek (size_t offset, int origin) { if (!contents_ || seek_ >= length_) { return false; } if (origin == SEEK_SET) { if (offset >= length_) { return false; } seek_ = offset; } else if (origin == SEEK_END) { if (offset >= length_) { return false; } seek_ = length_ - offset; } else { if (seek_ + offset >= length_) { return false; } seek_ += offset; } return true; } size_t length () const { return length_; } bool eof () const { return seek_ >= length_; } void rewind () { seek_ = 0; } public: explicit operator bool () const { return !!contents_ && length_ > 0; } }; CR_NAMESPACE_END