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 "writer.h"
11 
12 namespace marisa {
13 
Writer()14 Writer::Writer()
15     : file_(NULL), fd_(-1), stream_(NULL), needs_fclose_(false) {}
16 
Writer(std::FILE * file)17 Writer::Writer(std::FILE *file)
18     : file_(file), fd_(-1), stream_(NULL), needs_fclose_(false) {}
19 
Writer(int fd)20 Writer::Writer(int fd)
21     : file_(NULL), fd_(fd), stream_(NULL), needs_fclose_(false) {}
22 
Writer(std::ostream * stream)23 Writer::Writer(std::ostream *stream)
24     : file_(NULL), fd_(-1), stream_(stream), needs_fclose_(false) {}
25 
~Writer()26 Writer::~Writer() {
27   if (needs_fclose_) {
28     ::fclose(file_);
29   }
30 }
31 
open(const char * filename,bool trunc_flag,long offset,int whence)32 void Writer::open(const char *filename, bool trunc_flag,
33     long offset, int whence) {
34   MARISA_THROW_IF(is_open(), MARISA_STATE_ERROR);
35   MARISA_THROW_IF(filename == NULL, MARISA_PARAM_ERROR);
36 #ifdef _MSC_VER
37   std::FILE *file = NULL;
38   if (!trunc_flag) {
39     ::fopen_s(&file, filename, "rb+");
40   }
41   if (file == NULL) {
42     if (::fopen_s(&file, filename, "wb") != 0) {
43       MARISA_THROW(MARISA_IO_ERROR);
44     }
45   }
46 #else  // _MSC_VER
47   std::FILE *file = NULL;
48   if (!trunc_flag) {
49     file = ::fopen(filename, "rb+");
50   }
51   if (file == NULL) {
52     file = ::fopen(filename, "wb");
53     MARISA_THROW_IF(file == NULL, MARISA_IO_ERROR);
54   }
55 #endif  // _MSC_VER
56   if (::fseek(file, offset, whence) != 0) {
57     ::fclose(file);
58     MARISA_THROW(MARISA_IO_ERROR);
59   }
60   file_ = file;
61   needs_fclose_ = true;
62 }
63 
clear()64 void Writer::clear() {
65   Writer().swap(this);
66 }
67 
swap(Writer * rhs)68 void Writer::swap(Writer *rhs) {
69   MARISA_THROW_IF(rhs == NULL, MARISA_PARAM_ERROR);
70   Swap(&file_, &rhs->file_);
71   Swap(&fd_, &rhs->fd_);
72   Swap(&stream_, &rhs->stream_);
73   Swap(&needs_fclose_, &rhs->needs_fclose_);
74 }
75 
write_data(const void * data,std::size_t size)76 void Writer::write_data(const void *data, std::size_t size) {
77   if (fd_ != -1) {
78     while (size != 0) {
79 #ifdef _MSC_VER
80       const unsigned int count = (size < INT_MAX) ? size : INT_MAX;
81       const int size_written = _write(fd_, data, count);
82 #else  // _MSC_VER
83       const ::size_t count = (size < SSIZE_MAX) ? size : SSIZE_MAX;
84       const ::ssize_t size_written = ::write(fd_, data, count);
85 #endif  // _MSC_VER
86       MARISA_THROW_IF(size_written <= 0, MARISA_IO_ERROR);
87       data = static_cast<const char *>(data) + size_written;
88       size -= size_written;
89     }
90   } else if (file_ != NULL) {
91     if ((::fwrite(data, 1, size, file_) != size) || (::fflush(file_) != 0)) {
92       MARISA_THROW(MARISA_IO_ERROR);
93     }
94   } else if (stream_ != NULL) {
95     if (!stream_->write(static_cast<const char *>(data), size)) {
96       MARISA_THROW(MARISA_IO_ERROR);
97     }
98   } else {
99     MARISA_THROW(MARISA_STATE_ERROR);
100   }
101 }
102 
103 }  // namespace marisa
104