1 #include <stdio.h>
2
3 #ifdef _WIN32
4 #include <io.h>
5 #else // _WIN32
6 #include <unistd.h>
7 #endif // _WIN32
8
9 #include <limits>
10
11 #include "marisa/grimoire/io/reader.h"
12
13 namespace marisa {
14 namespace grimoire {
15 namespace io {
16
Reader()17 Reader::Reader()
18 : file_(NULL), fd_(-1), stream_(NULL), needs_fclose_(false) {}
19
~Reader()20 Reader::~Reader() {
21 if (needs_fclose_) {
22 ::fclose(file_);
23 }
24 }
25
open(const char * filename)26 void Reader::open(const char *filename) {
27 MARISA_THROW_IF(filename == NULL, MARISA_NULL_ERROR);
28
29 Reader temp;
30 temp.open_(filename);
31 swap(temp);
32 }
33
open(std::FILE * file)34 void Reader::open(std::FILE *file) {
35 MARISA_THROW_IF(file == NULL, MARISA_NULL_ERROR);
36
37 Reader temp;
38 temp.open_(file);
39 swap(temp);
40 }
41
open(int fd)42 void Reader::open(int fd) {
43 MARISA_THROW_IF(fd == -1, MARISA_CODE_ERROR);
44
45 Reader temp;
46 temp.open_(fd);
47 swap(temp);
48 }
49
open(std::istream & stream)50 void Reader::open(std::istream &stream) {
51 Reader temp;
52 temp.open_(stream);
53 swap(temp);
54 }
55
clear()56 void Reader::clear() {
57 Reader().swap(*this);
58 }
59
swap(Reader & rhs)60 void Reader::swap(Reader &rhs) {
61 marisa::swap(file_, rhs.file_);
62 marisa::swap(fd_, rhs.fd_);
63 marisa::swap(stream_, rhs.stream_);
64 marisa::swap(needs_fclose_, rhs.needs_fclose_);
65 }
66
seek(std::size_t size)67 void Reader::seek(std::size_t size) {
68 MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR);
69 if (size == 0) {
70 return;
71 } else if (size <= 16) {
72 char buf[16];
73 read_data(buf, size);
74 } else {
75 char buf[1024];
76 while (size != 0) {
77 const std::size_t count = (size < sizeof(buf)) ? size : sizeof(buf);
78 read_data(buf, count);
79 size -= count;
80 }
81 }
82 }
83
is_open() const84 bool Reader::is_open() const {
85 return (file_ != NULL) || (fd_ != -1) || (stream_ != NULL);
86 }
87
open_(const char * filename)88 void Reader::open_(const char *filename) {
89 std::FILE *file = NULL;
90 #ifdef _MSC_VER
91 MARISA_THROW_IF(::fopen_s(&file, filename, "rb") != 0, MARISA_IO_ERROR);
92 #else // _MSC_VER
93 file = ::fopen(filename, "rb");
94 MARISA_THROW_IF(file == NULL, MARISA_IO_ERROR);
95 #endif // _MSC_VER
96 file_ = file;
97 needs_fclose_ = true;
98 }
99
open_(std::FILE * file)100 void Reader::open_(std::FILE *file) {
101 file_ = file;
102 }
103
open_(int fd)104 void Reader::open_(int fd) {
105 fd_ = fd;
106 }
107
open_(std::istream & stream)108 void Reader::open_(std::istream &stream) {
109 stream_ = &stream;
110 }
111
read_data(void * buf,std::size_t size)112 void Reader::read_data(void *buf, std::size_t size) {
113 MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR);
114 if (size == 0) {
115 return;
116 } else if (fd_ != -1) {
117 while (size != 0) {
118 #ifdef _WIN32
119 static const std::size_t CHUNK_SIZE =
120 std::numeric_limits<int>::max();
121 const unsigned int count = (size < CHUNK_SIZE) ? size : CHUNK_SIZE;
122 const int size_read = ::_read(fd_, buf, count);
123 #else // _WIN32
124 static const std::size_t CHUNK_SIZE =
125 std::numeric_limits< ::ssize_t>::max();
126 const ::size_t count = (size < CHUNK_SIZE) ? size : CHUNK_SIZE;
127 const ::ssize_t size_read = ::read(fd_, buf, count);
128 #endif // _WIN32
129 MARISA_THROW_IF(size_read <= 0, MARISA_IO_ERROR);
130 buf = static_cast<char *>(buf) + size_read;
131 size -= static_cast<std::size_t>(size_read);
132 }
133 } else if (file_ != NULL) {
134 MARISA_THROW_IF(::fread(buf, 1, size, file_) != size, MARISA_IO_ERROR);
135 } else if (stream_ != NULL) {
136 try {
137 MARISA_THROW_IF(!stream_->read(static_cast<char *>(buf),
138 static_cast<std::streamsize>(size)), MARISA_IO_ERROR);
139 } catch (const std::ios_base::failure &) {
140 MARISA_THROW(MARISA_IO_ERROR, "std::ios_base::failure");
141 }
142 }
143 }
144
145 } // namespace io
146 } // namespace grimoire
147 } // namespace marisa
148