Library of Assembled Shared Sources
binary_i_memory_map.cpp
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2022 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#include "lass_common.h"
44#include "binary_i_memory_map.h"
46#include <string.h>
47
48#if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
49# define LASS_IO_MEMORY_MAP_WIN
50# include <windows.h>
51#else
52# if LASS_HAVE_SYS_MMAN_H && LASS_HAVE_SYS_STAT_H && LASS_HAVE_FCNTL_H && LASS_HAVE_UNISTD_H
53# define LASS_IO_MEMORY_MAP_MMAP
55# include <unistd.h>
56# include <fcntl.h>
57# include <sys/stat.h>
58# include <sys/mman.h>
59# endif
60#endif
61
62namespace lass
63{
64namespace io
65{
66
67namespace impl
68{
69
70#if defined(LASS_IO_MEMORY_MAP_WIN)
71
72class BinaryIMemoryMapImpl
73{
74public:
75 BinaryIMemoryMapImpl(const wchar_t* filename)
76 {
77 file_ = LASS_ENFORCE_WINAPI(::CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ,
78 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0));
79 LARGE_INTEGER size;
80 if (!GetFileSizeEx(file_, &size))
81 {
82 const unsigned lastError = util::impl::lass_GetLastError();
83 LASS_THROW("Failed to get file size: (" << lastError << ") "
84 << util::impl::lass_FormatMessage(lastError));
85 }
86#if LASS_ADDRESS_SIZE == 64
87 static_assert(sizeof(size.QuadPart) == sizeof(size_t), "LARGE_INTEGER::QuadPart must have same size as size_t");
88 fileSize_ = static_cast<size_t>(size.QuadPart);
89#else
90 if (size.HighPart != 0)
91 {
92 LASS_THROW("File too large");
93 }
94 fileSize_ = size.LowPart;
95#endif
96 map_ = LASS_ENFORCE_WINAPI(::CreateFileMapping(file_, 0, PAGE_READONLY, 0, 0, 0));
97 data_ = static_cast<char*>(LASS_ENFORCE_WINAPI(
98 ::MapViewOfFile(map_, FILE_MAP_READ, 0, 0, 0)));
99 }
100
101 BinaryIMemoryMapImpl(const char* filename) :
102 BinaryIMemoryMapImpl(util::utf8ToWchar(filename).c_str())
103 {
104 }
105
106 ~BinaryIMemoryMapImpl()
107 {
108 LASS_WARN_WINAPI(::UnmapViewOfFile(data_));
109 data_ = nullptr;
110 LASS_WARN_WINAPI(::CloseHandle(map_));
111 map_ = 0;
112 LASS_WARN_WINAPI(::CloseHandle(file_));
113 file_ = 0;
114 }
115
116 size_t fileSize() const noexcept
117 {
118 return fileSize_;
119 }
120
121 const char* data() const
122 {
123 return data_;
124 }
125
126private:
127 const char* data_;
128 HANDLE file_{ 0 };
129 HANDLE map_{ 0 };
130 size_t fileSize_;
131};
132
133#elif defined(LASS_IO_MEMORY_MAP_MMAP)
134
135class BinaryIMemoryMapImpl
136{
137public:
138 BinaryIMemoryMapImpl(const char* filename)
139 {
140 file_ = LASS_ENFORCE_CLIB(::open(filename, O_RDONLY));
141 struct stat buf;
142 LASS_ENFORCE_CLIB(::fstat(file_, &buf));
143 fileSize_ = static_cast<size_t>(buf.st_size);
144 view_ = static_cast<char*>(LASS_ENFORCE_CLIB_EX(
145 ::mmap(0, static_cast<size_t>(fileSize_), PROT_READ, MAP_SHARED, file_, 0),
146 (char*)MAP_FAILED));
147 }
148
149 BinaryIMemoryMapImpl(const wchar_t* filename) :
150 BinaryIMemoryMapImpl(util::wcharToUtf8(filename).c_str())
151 {
152 }
153
154 ~BinaryIMemoryMapImpl()
155 {
156 LASS_WARN_CLIB(::munmap(view_, static_cast<size_t>(fileSize_)));
157 view_ = nullptr;
158 LASS_WARN_CLIB(::close(file_));
159 file_ = 0;
160 }
161
162 const char* data() const
163 {
164 return view_;
165 }
166
167 size_t fileSize() const noexcept
168 {
169 return fileSize_;
170 }
171
172private:
173 char* view_;
174 size_t fileSize_;
175 int file_;
176};
177
178#else
179
180# error "[LASS BUILD MSG] no implementation for BinaryIMemoryMap"
181
182#endif
183
184}
185
186// --- public --------------------------------------------------------------------------------------
187
188BinaryIMemoryMap::BinaryIMemoryMap():
190{
191}
192
193BinaryIMemoryMap::BinaryIMemoryMap(const char* filename):
194 BinaryIStream()
195{
196 open(filename);
197}
198
199BinaryIMemoryMap::BinaryIMemoryMap(const std::string& filename):
200 BinaryIStream()
201{
202 open(filename);
203}
204
205#if LASS_HAVE_WCHAR_SUPPORT
206
207BinaryIMemoryMap::BinaryIMemoryMap(const wchar_t* filename):
208 BinaryIStream()
209{
210 open(filename);
211}
212
213BinaryIMemoryMap::BinaryIMemoryMap(const std::wstring& filename):
214 BinaryIStream()
215{
216 open(filename);
217}
218
219#endif
220
221#if LASS_HAVE_STD_FILESYSTEM
222
223BinaryIMemoryMap::BinaryIMemoryMap(const std::filesystem::path& filename):
224 BinaryIStream()
225{
226 open(filename);
227}
228
229#endif
230
231BinaryIMemoryMap::~BinaryIMemoryMap()
232{
233 close();
234}
235
236
237
238void BinaryIMemoryMap::open(const char* filename)
239{
240 close();
241 try
242 {
243 pimpl_.reset(new impl::BinaryIMemoryMapImpl(filename));
244 }
245 catch (const std::exception& error)
246 {
247 LASS_LOG("Error: " << error.what());
248 pimpl_.reset();
249 setstate(std::ios_base::badbit);
250 }
251}
252
253
254
255void BinaryIMemoryMap::open(const std::string& filename)
256{
257 open(filename.c_str());
258}
259
260#if LASS_HAVE_WCHAR_SUPPORT
261
262void BinaryIMemoryMap::open(const wchar_t* filename)
263{
264 close();
265 try
266 {
267 pimpl_.reset(new impl::BinaryIMemoryMapImpl(filename));
268 }
269 catch (const std::exception& error)
270 {
271 LASS_LOG("Error: " << error.what());
272 pimpl_.reset();
273 setstate(std::ios_base::badbit);
274 }
275}
276
277
278
279void BinaryIMemoryMap::open(const std::wstring& filename)
280{
281 open(filename.c_str());
282}
283
284
285#endif
286
287
288#if LASS_HAVE_STD_FILESYSTEM
289
290void BinaryIMemoryMap::open(const std::filesystem::path& filename)
291{
292 open(filename.native());
293}
294
295#endif
296
297
298void BinaryIMemoryMap::close()
299{
300 pimpl_.reset();
301}
302
303
304
305bool BinaryIMemoryMap::is_open() const
306{
307 return pimpl_.get() != nullptr;
308}
309
310
311
312// --- private -------------------------------------------------------------------------------------
313
314BinaryIMemoryMap::pos_type BinaryIMemoryMap::doTellg() const
315{
316 return position_;
317}
318
319
320
321void BinaryIMemoryMap::doSeekg(pos_type position)
322{
323 LASS_ASSERT(good());
324 if (!pimpl_)
325 {
326 setstate(std::ios_base::badbit);
327 return;
328 }
329 position_ = position;
330}
331
332
333
334void BinaryIMemoryMap::doSeekg(off_type offset, std::ios_base::seekdir direction)
335{
336 LASS_ASSERT(good());
337
338 if (!pimpl_)
339 {
340 setstate(std::ios_base::badbit);
341 return;
342 }
343
344 auto seek = [this](pos_type current, off_type offset)
345 {
346 if (offset < 0)
347 {
348 const pos_type negoffset = static_cast<pos_type>(-offset);
349 if (negoffset > current)
350 {
351 setstate(std::ios_base::failbit);
352 return;
353 }
354 this->position_ = current - negoffset;
355 }
356 else
357 {
358 const pos_type posoffset = static_cast<pos_type>(offset);
359 if (current > num::NumTraits<pos_type>::max - posoffset)
360 {
361 setstate(std::ios_base::failbit);
362 return;
363 }
364 this->position_ = current + posoffset;
365 }
366 };
367
368 switch (direction)
369 {
370 case std::ios_base::beg:
371 if (offset < 0)
372 {
373 setstate(std::ios_base::failbit);
374 return;
375 }
376 position_ = static_cast<pos_type>(offset);
377 break;
378 case std::ios_base::cur:
379 seek(position_, offset);
380 break;
381 case std::ios_base::end:
382 seek(pimpl_->fileSize(), offset);
383 break;
384 default:
385 LASS_ASSERT_UNREACHABLE;
386 setstate(std::ios_base::badbit);
387 return;
388 };
389}
390
391
392
393size_t BinaryIMemoryMap::doRead(void* output, size_t numberOfBytes)
394{
395 if (!good())
396 {
397 return 0;
398 }
399
400 if (!pimpl_ )
401 {
402 setstate(std::ios_base::badbit);
403 return 0;
404 }
405
406 const size_t size = pimpl_->fileSize();
407 const char* data = pimpl_->data();
408 if (position_ >= size)
409 {
410 setstate(std::ios_base::eofbit);
411 return 0;
412 }
413 pos_type next = position_ + numberOfBytes;
414 if (next > size || next < position_)
415 {
416 next = size;
417 numberOfBytes = size - position_;
418 }
419 memcpy(output, &data[position_], numberOfBytes);
420 position_ = next;
421 return numberOfBytes;
422}
423
424
425
426}
427
428}
base class of binary input streams.
const lass::python::impl::IterNextSlot next("__next__", Py_tp_iternext)
__next__ method (iterator next)
streams, binary streams, vrmlstreams, ...
Library for Assembled Shared Sources.
Definition config.h:53