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