148 lines
3.3 KiB
C++
148 lines
3.3 KiB
C++
#include <stdio.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <io.h>
|
|
#else // _WIN32
|
|
#include <unistd.h>
|
|
#endif // _WIN32
|
|
|
|
#include <limits>
|
|
|
|
#include "marisa/grimoire/io/reader.h"
|
|
|
|
namespace marisa {
|
|
namespace grimoire {
|
|
namespace io {
|
|
|
|
Reader::Reader()
|
|
: file_(NULL), fd_(-1), stream_(NULL), needs_fclose_(false) {}
|
|
|
|
Reader::~Reader() {
|
|
if (needs_fclose_) {
|
|
::fclose(file_);
|
|
}
|
|
}
|
|
|
|
void Reader::open(const char *filename) {
|
|
MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR);
|
|
|
|
Reader temp;
|
|
temp.open_(filename);
|
|
swap(temp);
|
|
}
|
|
|
|
void Reader::open(std::FILE *file) {
|
|
MARISA_THROW_IF(file == NULL, MARISA_NULL_ERROR);
|
|
|
|
Reader temp;
|
|
temp.open_(file);
|
|
swap(temp);
|
|
}
|
|
|
|
void Reader::open(int fd) {
|
|
MARISA_THROW_IF(fd == -1, MARISA_CODE_ERROR);
|
|
|
|
Reader temp;
|
|
temp.open_(fd);
|
|
swap(temp);
|
|
}
|
|
|
|
void Reader::open(std::istream &stream) {
|
|
Reader temp;
|
|
temp.open_(stream);
|
|
swap(temp);
|
|
}
|
|
|
|
void Reader::clear() {
|
|
Reader().swap(*this);
|
|
}
|
|
|
|
void Reader::swap(Reader &rhs) {
|
|
marisa::swap(file_, rhs.file_);
|
|
marisa::swap(fd_, rhs.fd_);
|
|
marisa::swap(stream_, rhs.stream_);
|
|
marisa::swap(needs_fclose_, rhs.needs_fclose_);
|
|
}
|
|
|
|
void Reader::seek(std::size_t size) {
|
|
MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR);
|
|
if (size == 0) {
|
|
return;
|
|
} else if (size <= 16) {
|
|
char buf[16];
|
|
read_data(buf, size);
|
|
} else {
|
|
char buf[1024];
|
|
while (size != 0) {
|
|
const std::size_t count = (size < sizeof(buf)) ? size : sizeof(buf);
|
|
read_data(buf, count);
|
|
size -= count;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Reader::is_open() const {
|
|
return (file_ != NULL) || (fd_ != -1) || (stream_ != NULL);
|
|
}
|
|
|
|
void Reader::open_(const char *filename) {
|
|
std::FILE *file = NULL;
|
|
#ifdef _MSC_VER
|
|
MARISA_THROW_IF(::fopen_s(&file, filename, "rb") != 0, MARISA_IO_ERROR);
|
|
#else // _MSC_VER
|
|
file = ::fopen(filename, "rb");
|
|
MARISA_THROW_IF(file == NULL, MARISA_IO_ERROR);
|
|
#endif // _MSC_VER
|
|
file_ = file;
|
|
needs_fclose_ = true;
|
|
}
|
|
|
|
void Reader::open_(std::FILE *file) {
|
|
file_ = file;
|
|
}
|
|
|
|
void Reader::open_(int fd) {
|
|
fd_ = fd;
|
|
}
|
|
|
|
void Reader::open_(std::istream &stream) {
|
|
stream_ = &stream;
|
|
}
|
|
|
|
void Reader::read_data(void *buf, std::size_t size) {
|
|
MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR);
|
|
if (size == 0) {
|
|
return;
|
|
} else if (fd_ != -1) {
|
|
while (size != 0) {
|
|
#ifdef _WIN32
|
|
static const std::size_t CHUNK_SIZE =
|
|
std::numeric_limits<int>::max();
|
|
const unsigned int count = (size < CHUNK_SIZE) ? size : CHUNK_SIZE;
|
|
const int size_read = ::_read(fd_, buf, count);
|
|
#else // _WIN32
|
|
static const std::size_t CHUNK_SIZE =
|
|
std::numeric_limits< ::ssize_t>::max();
|
|
const ::size_t count = (size < CHUNK_SIZE) ? size : CHUNK_SIZE;
|
|
const ::ssize_t size_read = ::read(fd_, buf, count);
|
|
#endif // _WIN32
|
|
MARISA_THROW_IF(size_read <= 0, MARISA_IO_ERROR);
|
|
buf = static_cast<char *>(buf) + size_read;
|
|
size -= static_cast<std::size_t>(size_read);
|
|
}
|
|
} else if (file_ != NULL) {
|
|
MARISA_THROW_IF(::fread(buf, 1, size, file_) != size, MARISA_IO_ERROR);
|
|
} else if (stream_ != NULL) {
|
|
try {
|
|
MARISA_THROW_IF(!stream_->read(static_cast<char *>(buf),
|
|
static_cast<std::streamsize>(size)), MARISA_IO_ERROR);
|
|
} catch (const std::ios_base::failure &) {
|
|
MARISA_THROW(MARISA_IO_ERROR, "std::ios_base::failure");
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace io
|
|
} // namespace grimoire
|
|
} // namespace marisa
|