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