yapb-noob-edition/ext/crlib/cr-files.h
2021-01-01 00:00:33 +03:00

389 lines
7.8 KiB
C++

//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <stdio.h>
#include <crlib/cr-string.h>
#include <crlib/cr-lambda.h>
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 <char> data (255);
line.clear ();
while ((ch = get ()) != EOF && !eof ()) {
data.push (static_cast <char> (ch));
if (ch == '\n') {
break;
}
}
if (!data.empty ()) {
line.assign (data.data (), data.length ());
}
return !line.empty ();
}
template <typename ...Args> size_t puts (const char *fmt, Args &&...args) {
if (!*this) {
return 0;
}
return fputs (strings.format (fmt, cr::forward <Args> (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 <char *> (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 <MemFileStorage> {
private:
using LoadFunction = Lambda <uint8 * (const char *, int *)>;
using FreeFunction = Lambda <void (void *)>;
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 <int> (file.length ());
auto data = Memory::get <uint8> (*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 <char *> (buffer), result);
defaultUnload (buffer);
return data;
}
return "";
}
};
class MemFile final : public DenyCopying {
private:
enum : char {
Eof = static_cast <char> (-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 <int *> (&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 <char> (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 <char> 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