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 14 Writer::Writer() 15 : file_(NULL), fd_(-1), stream_(NULL), needs_fclose_(false) {} 16 17 Writer::Writer(std::FILE *file) 18 : file_(file), fd_(-1), stream_(NULL), needs_fclose_(false) {} 19 20 Writer::Writer(int fd) 21 : file_(NULL), fd_(fd), stream_(NULL), needs_fclose_(false) {} 22 23 Writer::Writer(std::ostream *stream) 24 : file_(NULL), fd_(-1), stream_(stream), needs_fclose_(false) {} 25 26 Writer::~Writer() { 27 if (needs_fclose_) { 28 ::fclose(file_); 29 } 30 } 31 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 64 void Writer::clear() { 65 Writer().swap(this); 66 } 67 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 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