1#include <limits.h>
2#include <stdio.h>
3
4#ifdef _MSC_VER
5#include <io.h>
6#else  // _MSC_VER
7#include <unistd.h>
8#endif  // _MSC_VER
9
10#include "reader.h"
11
12namespace marisa_alpha {
13
14Reader::Reader()
15    : file_(NULL), fd_(-1), stream_(NULL), needs_fclose_(false) {}
16
17Reader::Reader(std::FILE *file)
18    : file_(file), fd_(-1), stream_(NULL), needs_fclose_(false) {}
19
20Reader::Reader(int fd)
21    : file_(NULL), fd_(fd), stream_(NULL), needs_fclose_(false) {}
22
23Reader::Reader(std::istream *stream)
24    : file_(NULL), fd_(-1), stream_(stream), needs_fclose_(false) {}
25
26Reader::~Reader() {
27  if (needs_fclose_) {
28    ::fclose(file_);
29  }
30}
31
32void Reader::open(const char *filename, long offset, int whence) {
33  MARISA_ALPHA_THROW_IF(is_open(), MARISA_ALPHA_STATE_ERROR);
34  MARISA_ALPHA_THROW_IF(filename == NULL, MARISA_ALPHA_PARAM_ERROR);
35#ifdef _MSC_VER
36  std::FILE *file = NULL;
37  if (::fopen_s(&file, filename, "rb") != 0) {
38    MARISA_ALPHA_THROW(MARISA_ALPHA_IO_ERROR);
39  }
40#else  // _MSC_VER
41  std::FILE * const file = ::fopen(filename, "rb");
42  MARISA_ALPHA_THROW_IF(file == NULL, MARISA_ALPHA_IO_ERROR);
43#endif  // _MSC_VER
44  if (::fseek(file, offset, whence) != 0) {
45    ::fclose(file);
46    MARISA_ALPHA_THROW(MARISA_ALPHA_IO_ERROR);
47  }
48  file_ = file;
49  needs_fclose_ = true;
50}
51
52void Reader::clear() {
53  Reader().swap(this);
54}
55
56void Reader::swap(Reader *rhs) {
57  MARISA_ALPHA_THROW_IF(rhs == NULL, MARISA_ALPHA_PARAM_ERROR);
58  Swap(&file_, &rhs->file_);
59  Swap(&fd_, &rhs->fd_);
60  Swap(&stream_, &rhs->stream_);
61  Swap(&needs_fclose_, &rhs->needs_fclose_);
62}
63
64void Reader::read_data(void *buf, std::size_t size) {
65  if (fd_ != -1) {
66    while (size != 0) {
67#ifdef _MSC_VER
68      const unsigned int count = (size < INT_MAX) ? size : INT_MAX;
69      const int size_read = _read(fd_, buf, count);
70#else  // _MSC_VER
71      const ::size_t count = (size < SSIZE_MAX) ? size : SSIZE_MAX;
72      const ::ssize_t size_read = ::read(fd_, buf, count);
73#endif  // _MSC_VER
74      MARISA_ALPHA_THROW_IF(size_read <= 0, MARISA_ALPHA_IO_ERROR);
75      buf = static_cast<char *>(buf) + size_read;
76      size -= size_read;
77    }
78  } else if (file_ != NULL) {
79    if (::fread(buf, 1, size, file_) != size) {
80      MARISA_ALPHA_THROW(MARISA_ALPHA_IO_ERROR);
81    }
82  } else if (stream_ != NULL) {
83    try {
84      if (!stream_->read(static_cast<char *>(buf), size)) {
85        MARISA_ALPHA_THROW(MARISA_ALPHA_IO_ERROR);
86      }
87    } catch (const std::ios_base::failure &) {
88      MARISA_ALPHA_THROW(MARISA_ALPHA_IO_ERROR);
89    }
90  } else {
91    MARISA_ALPHA_THROW(MARISA_ALPHA_STATE_ERROR);
92  }
93}
94
95}  // namespace marisa_alpha
96