1f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#if defined _WIN32 || defined _WIN64
2f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#include <sys/types.h>
3f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#include <sys/stat.h>
4f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#include <Windows.h>
5f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#else  // defined _WIN32 || defined _WIN64
6f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#include <sys/mman.h>
7f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#include <sys/stat.h>
8f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#include <sys/types.h>
9f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#include <fcntl.h>
10f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#include <unistd.h>
11f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#endif  // defined _WIN32 || defined _WIN64
12f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
13f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#include "mapper.h"
14f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
15f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamathnamespace marisa {
16f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
17f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#if defined _WIN32 || defined _WIN64
18f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan KamathMapper::Mapper()
19f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    : ptr_(NULL), origin_(NULL), avail_(0), size_(0),
20f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      file_(NULL), map_(NULL) {}
21f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
22f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan KamathMapper::Mapper(const void *ptr, std::size_t size)
23f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    : ptr_(ptr), origin_(NULL), avail_(size), size_(0),
24f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      file_(NULL), map_(NULL) {
250172f3c6f03973e56208e013178ec68365255c60Narayan Kamath  MARISA_THROW_IF((ptr == NULL) || (size == 0), MARISA_PARAM_ERROR);
26f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
27f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#else  // defined _WIN32 || defined _WIN64
28f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan KamathMapper::Mapper()
29f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    : ptr_(NULL), origin_(MAP_FAILED), avail_(0), size_(0), fd_(-1) {}
30f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
31f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan KamathMapper::Mapper(const void *ptr, std::size_t size)
32f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    : ptr_(ptr), origin_(MAP_FAILED), avail_(size), size_(0), fd_(-1) {
330172f3c6f03973e56208e013178ec68365255c60Narayan Kamath  MARISA_THROW_IF((ptr == NULL) || (size == 0), MARISA_PARAM_ERROR);
34f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
35f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#endif  // defined _WIN32 || defined _WIN64
36f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
37f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#if defined _WIN32 || defined _WIN64
38f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan KamathMapper::~Mapper() {
39f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  if (origin_ != NULL) {
40f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    ::UnmapViewOfFile(origin_);
41f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  }
42f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
43f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  if (map_ != NULL) {
44f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    ::CloseHandle(map_);
45f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  }
46f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
47f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  if (file_ != NULL) {
48f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    ::CloseHandle(file_);
49f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  }
50f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
51f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#else  // defined _WIN32 || defined _WIN64
52f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan KamathMapper::~Mapper() {
53f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  if (origin_ != MAP_FAILED) {
54f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    ::munmap(origin_, size_);
55f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  }
56f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
57f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  if (fd_ != -1) {
58f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    ::close(fd_);
59f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  }
60f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
61f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#endif  // defined _WIN32 || defined _WIN64
62f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
63f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#if defined _WIN32 || defined _WIN64
64f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamathvoid Mapper::open(const char *filename, long offset, int whence) {
65f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(is_open(), MARISA_STATE_ERROR);
66f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(filename == NULL, MARISA_PARAM_ERROR);
67f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
68f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  struct __stat64 st;
69f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  if (::_stat64(filename, &st) != 0) {
70f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    MARISA_THROW(MARISA_IO_ERROR);
71f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  }
72f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  const UInt64 file_size = st.st_size;
73f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(file_size > MARISA_UINT32_MAX, MARISA_SIZE_ERROR);
74f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
75f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Mapper temp;
76f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.size_ = (std::size_t)file_size;
77f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
78f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.file_ = ::CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ,
79f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
80f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(temp.file_ == NULL, MARISA_IO_ERROR);
81f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
82f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.map_ = ::CreateFileMapping(temp.file_, NULL, PAGE_READONLY, 0, 0, NULL);
83f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(temp.map_ == NULL, MARISA_IO_ERROR);
84f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
85f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.origin_ = ::MapViewOfFile(temp.map_, FILE_MAP_READ, 0, 0, 0);
86f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(temp.origin_ == NULL, MARISA_IO_ERROR);
87f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
88f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.seek(offset, whence);
89f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.swap(this);
90f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
91f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#else  // defined _WIN32 || defined _WIN64
92f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamathvoid Mapper::open(const char *filename, long offset, int whence) {
93f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(is_open(), MARISA_STATE_ERROR);
94f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(filename == NULL, MARISA_PARAM_ERROR);
95f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
96f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  struct stat st;
97f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  if (::stat(filename, &st) != 0) {
98f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    MARISA_THROW(MARISA_IO_ERROR);
99f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  }
100f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  UInt64 file_size = st.st_size;
101f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(file_size > MARISA_UINT32_MAX, MARISA_SIZE_ERROR);
102f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
103f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Mapper temp;
104f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.size_ = (std::size_t)file_size;
105f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
106f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.fd_ = ::open(filename, O_RDONLY);
107f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(temp.fd_ == -1, MARISA_IO_ERROR);
108f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
109f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.origin_ = ::mmap(NULL, temp.size_, PROT_READ, MAP_SHARED, temp.fd_, 0);
110f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(temp.origin_ == MAP_FAILED, MARISA_IO_ERROR);
111f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
112f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.seek(offset, whence);
113f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  temp.swap(this);
114f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
115f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#endif  // defined _WIN32 || defined _WIN64
116f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
117f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamathvoid Mapper::clear() {
118f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Mapper().swap(this);
119f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
120f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
121f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamathvoid Mapper::swap(Mapper *rhs) {
122f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(rhs == NULL, MARISA_PARAM_ERROR);
123f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Swap(&ptr_, &rhs->ptr_);
124f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Swap(&avail_, &rhs->avail_);
125f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Swap(&origin_, &rhs->origin_);
126f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Swap(&size_, &rhs->size_);
127f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#if defined _WIN32 || defined _WIN64
128f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Swap(&file_, &rhs->file_);
129f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Swap(&map_, &rhs->map_);
130f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#else  // defined _WIN32 || defined _WIN64
131f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  Swap(&fd_, &rhs->fd_);
132f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath#endif  // defined _WIN32 || defined _WIN64
133f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
134f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
135f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamathvoid Mapper::seek(long offset, int whence) {
136f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  switch (whence) {
137f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    case SEEK_SET:
138f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    case SEEK_CUR: {
139f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      MARISA_THROW_IF((offset < 0) || ((unsigned long)offset > size_),
140f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath          MARISA_IO_ERROR);
141f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      ptr_ = static_cast<const UInt8 *>(origin_) + offset;
142f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      avail_ = (std::size_t)(size_ - offset);
143f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      return;
144f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    }
145f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    case SEEK_END: {
146f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      MARISA_THROW_IF((offset > 0) || ((unsigned long)-offset > size_),
147f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath          MARISA_IO_ERROR);
148f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      ptr_ = static_cast<const UInt8 *>(origin_) + size_ + offset;
149f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      avail_ = (std::size_t)-offset;
150f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      return;
151f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    }
152f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    default: {
153f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath      MARISA_THROW(MARISA_PARAM_ERROR);
154f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath    }
155f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  }
156f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
157f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
158f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamathconst void *Mapper::map_data(std::size_t size) {
159f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(!is_open(), MARISA_STATE_ERROR);
160f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  MARISA_THROW_IF(size > avail_, MARISA_IO_ERROR);
161f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  ptr_ = static_cast<const UInt8 *>(ptr_) + size;
162f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  avail_ -= size;
163f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath  return static_cast<const UInt8 *>(ptr_) - size;
164f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}
165f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath
166f163f6985a63328d07e3de249ad3daf4a0c67d8aNarayan Kamath}  // namespace marisa
167