00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include "io_common.h"
00044 #include "binary_i_memory_map.h"
00045 #include "../util/impl/lass_errno.h"
00046
00047 #if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
00048 # define LASS_IO_MEMORY_MAP_WIN
00049 # include <windows.h>
00050 #else
00051 # if LASS_HAVE_SYS_MMAN_H && LASS_HAVE_SYS_STAT_H && LASS_HAVE_FCNTL_H && LASS_HAVE_UNISTD_H
00052 # define LASS_IO_MEMORY_MAP_MMAP
00053 # include <unistd.h>
00054 # include <fcntl.h>
00055 # include <sys/stat.h>
00056 # include <sys/mman.h>
00057 # if !defined(_STAT_VER_KERNEL)
00058 # error "blah"
00059 # endif
00060 # endif
00061 #endif
00062
00063 namespace lass
00064 {
00065 namespace io
00066 {
00067
00068 namespace impl
00069 {
00070 class BinaryIMemoryMapImpl
00071 {
00072 public:
00073 BinaryIMemoryMapImpl(const char* filename):
00074 view_(0)
00075 {
00076 #if defined(LASS_IO_MEMORY_MAP_WIN)
00077 pageSize_ = 4096;
00078 map_ = 0;
00079 # ifdef UNICODE
00080 const int bufferLength = MultiByteToWideChar(CP_UTF8, 0, filename, -1, 0, 0);
00081 std::vector<WCHAR> buffer(bufferLength);
00082 MultiByteToWideChar(CP_UTF8, 0, filename, -1, &buffer[0], bufferLength);
00083 LPCWSTR szFile = &buffer[0];
00084 # else
00085 LPCSTR szFile = filename;
00086 # endif
00087 file_ = LASS_ENFORCE_WINAPI(::CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ,
00088 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0));
00089 const DWORD fsize = GetFileSize(file_, 0);
00090 if (fsize == INVALID_FILE_SIZE)
00091 {
00092 const unsigned lastError = util::impl::lass_GetLastError();
00093 LASS_THROW("Failed to get file size: (" << lastError << ") "
00094 << util::impl::lass_FormatMessage(lastError));
00095 }
00096 fileSize_ = static_cast<long>(fsize);
00097 if (fileSize_ < 0 || static_cast<DWORD>(fileSize_) != fsize)
00098 {
00099 LASS_THROW("Filesize overflow");
00100 }
00101 map_ = LASS_ENFORCE_WINAPI(::CreateFileMapping(file_, 0, PAGE_READONLY, 0, 0, 0));
00102 #elif defined(LASS_IO_MEMORY_MAP_MMAP)
00103 pageSize_ = LASS_ENFORCE_CLIB(::sysconf(_SC_PAGE_SIZE));
00104 file_ = LASS_ENFORCE_CLIB(::open(filename, O_RDONLY));
00105 struct stat buf;
00106 LASS_ENFORCE_CLIB(::fstat(file_, &buf));
00107 fileSize_ = static_cast<long>(buf.st_size);
00108 if (fileSize_ < 0 || static_cast<off_t>(fileSize_) != buf.st_size)
00109 {
00110 LASS_THROW("Filesize overflow");
00111 }
00112 #else
00113 # error "[LASS BUILD MSG] no implementation for BinaryIMemoryMap"
00114 #endif
00115 }
00116
00117
00118 ~BinaryIMemoryMapImpl()
00119 {
00120 unmap();
00121 #if defined(LASS_IO_MEMORY_MAP_WIN)
00122 LASS_WARN_WINAPI(::CloseHandle(map_));
00123 map_ = 0;
00124 LASS_WARN_WINAPI(::CloseHandle(file_));
00125 file_ = 0;
00126 #elif defined(LASS_IO_MEMORY_MAP_MMAP)
00127 LASS_WARN_CLIB(::close(file_));
00128 file_ = 0;
00129 #endif
00130 }
00131
00132
00133 const long fileSize() const
00134 {
00135 return fileSize_;
00136 }
00137
00138
00139 char* const remap(long newBegin, long& begin, long& end)
00140 {
00141 newBegin = pageSize_ * (newBegin / pageSize_);
00142 long newEnd = newBegin + pageSize_;
00143 if (newEnd > fileSize_ || newEnd < 0)
00144 {
00145 newEnd = fileSize_;
00146 }
00147 LASS_ASSERT(newEnd >= newBegin);
00148 const long mapSize = newEnd - newBegin;
00149 #if defined(LASS_IO_MEMORY_MAP_WIN)
00150 char* view = static_cast<char*>(LASS_ENFORCE_WINAPI(
00151 ::MapViewOfFile(map_, FILE_MAP_READ, 0, newBegin, mapSize)));
00152 #elif defined(LASS_IO_MEMORY_MAP_MMAP)
00153 char* view = static_cast<char*>(LASS_ENFORCE_CLIB_EX(
00154 ::mmap(0, mapSize, PROT_READ, MAP_SHARED, file_, newBegin),
00155 (char*)MAP_FAILED));
00156 #else
00157 char* view = 0;
00158 return 0;
00159 #endif
00160 unmap();
00161 mapSize_ = mapSize;
00162 view_ = view;
00163 begin = newBegin;
00164 end = newEnd;
00165 return view_;
00166 }
00167
00168 private:
00169
00170 void unmap()
00171 {
00172 if (!view_)
00173 {
00174 return;
00175 }
00176 #if defined(LASS_IO_MEMORY_MAP_WIN)
00177 LASS_WARN_WINAPI(::UnmapViewOfFile(view_));
00178 #elif defined(LASS_IO_MEMORY_MAP_MMAP)
00179 LASS_WARN_CLIB(::munmap(view_, mapSize_));
00180 #endif
00181 view_ = 0;
00182 }
00183
00184 long pageSize_;
00185 long fileSize_;
00186 long mapSize_;
00187 char* view_;
00188 #if defined(LASS_IO_MEMORY_MAP_WIN)
00189 HANDLE file_;
00190 HANDLE map_;
00191 #elif defined(LASS_IO_MEMORY_MAP_MMAP)
00192 int file_;
00193 #endif
00194 };
00195 }
00196
00197
00198
00199 BinaryIMemoryMap::BinaryIMemoryMap():
00200 BinaryIStream(),
00201 pimpl_(0)
00202 {
00203 }
00204
00205 BinaryIMemoryMap::BinaryIMemoryMap(const char* filename):
00206 BinaryIStream(),
00207 pimpl_(0)
00208 {
00209 open(filename);
00210 }
00211
00212 BinaryIMemoryMap::BinaryIMemoryMap(const std::string& filename):
00213 BinaryIStream(),
00214 pimpl_(0)
00215 {
00216 open(filename);
00217 }
00218
00219
00220
00221 BinaryIMemoryMap::~BinaryIMemoryMap()
00222 {
00223 close();
00224 }
00225
00226
00227
00228 void BinaryIMemoryMap::open(const char* filename)
00229 {
00230 std::auto_ptr<impl::BinaryIMemoryMapImpl> pimpl;
00231 long begin, end, size;
00232 char* data;
00233
00234 try
00235 {
00236 pimpl.reset(new impl::BinaryIMemoryMapImpl(filename));
00237 size = pimpl->fileSize();
00238 data = pimpl->remap(0, begin, end);
00239 }
00240 catch (std::exception& error)
00241 {
00242 LASS_LOG("Error: " << error.what());
00243 setstate(std::ios_base::failbit);
00244 return;
00245 }
00246
00247 close();
00248 pimpl_ = pimpl.release();
00249 data_ = data;
00250 size_ = size;
00251 begin_ = begin_;
00252 end_ = end_;
00253 position_ = 0;
00254 }
00255
00256
00257
00258 void BinaryIMemoryMap::open(const std::string& filename)
00259 {
00260 open(filename.c_str());
00261 }
00262
00263
00264
00265 void BinaryIMemoryMap::close()
00266 {
00267 delete pimpl_;
00268 pimpl_ = 0;
00269 }
00270
00271
00272
00273 bool BinaryIMemoryMap::is_open() const
00274 {
00275 return pimpl_ != 0;
00276 }
00277
00278
00279
00280
00281
00282 long BinaryIMemoryMap::doTellg() const
00283 {
00284 return position_;
00285 }
00286
00287
00288
00289 void BinaryIMemoryMap::doSeekg(long offset, std::ios_base::seekdir direction)
00290 {
00291 if (!good())
00292 {
00293 return;
00294 }
00295 if (!pimpl_)
00296 {
00297 setstate(std::ios_base::badbit);
00298 return;
00299 }
00300
00301 switch (direction)
00302 {
00303 case std::ios_base::beg:
00304 position_ = offset;
00305 break;
00306 case std::ios_base::cur:
00307 position_ += offset;
00308 break;
00309 case std::ios_base::end:
00310 position_ = size_ + offset;
00311 break;
00312 default:
00313 LASS_ASSERT_UNREACHABLE;
00314 setstate(std::ios_base::badbit);
00315 return;
00316 };
00317 if (position_ < begin_ || position_ >= end_)
00318 {
00319 try
00320 {
00321 data_ = pimpl_->remap(position_, begin_, end_);
00322 }
00323 catch (std::exception& error)
00324 {
00325 LASS_LOG("Error: " << error.what());
00326 setstate(std::ios_base::badbit);
00327 }
00328 }
00329 }
00330
00331
00332
00333 void BinaryIMemoryMap::doRead(void* output, size_t numberOfBytes)
00334 {
00335 if (!pimpl_ || !data_)
00336 {
00337 setstate(std::ios_base::failbit);
00338 return;
00339 }
00340 if (!good())
00341 {
00342 return;
00343 }
00344
00345 const long last = position_ + static_cast<long>(numberOfBytes);
00346 if (last > size_ || last < position_)
00347 {
00348 setstate(std::ios_base::eofbit | std::ios_base::failbit);
00349 }
00350
00351 char* dest = static_cast<char*>(output);
00352 while (last >= end_)
00353 {
00354 ::memcpy(dest, &data_[position_ - begin_], end_ - position_);
00355 dest += end_ - position_;
00356 try
00357 {
00358 data_ = pimpl_->remap(end_, begin_, end_);
00359 }
00360 catch (std::exception& error)
00361 {
00362 LASS_LOG("Error: " << error.what());
00363 setstate(std::ios_base::badbit);
00364 return;
00365 }
00366 position_ = begin_;
00367 }
00368 ::memcpy(dest, &data_[position_ - begin_], last - position_);
00369 position_ = last;
00370 }
00371
00372 }
00373
00374 }