library of assembled shared sources

http://lass.cocamware.com

binary_i_memory_map.cpp

Go to the documentation of this file.
00001 /**     @file
00002  *      @author Bram de Greve (bramz@users.sourceforge.net)
00003  *      @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *      *** BEGIN LICENSE INFORMATION ***
00006  *      
00007  *      The contents of this file are subject to the Common Public Attribution License 
00008  *      Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *      the License. You may obtain a copy of the License at 
00010  *      http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *      Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *      use of software over a computer network and provide for limited attribution for 
00013  *      the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *      with Exhibit B.
00015  *      
00016  *      Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *      WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *      language governing rights and limitations under the License.
00019  *      
00020  *      The Original Code is LASS - Library of Assembled Shared Sources.
00021  *      
00022  *      The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *      The Original Developer is the Initial Developer.
00024  *      
00025  *      All portions of the code written by the Initial Developer are:
00026  *      Copyright (C) 2004-2007 the Initial Developer.
00027  *      All Rights Reserved.
00028  *      
00029  *      Contributor(s):
00030  *
00031  *      Alternatively, the contents of this file may be used under the terms of the 
00032  *      GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *      provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *      of your version of this file only under the terms of the GPL and not to allow 
00035  *      others to use your version of this file under the CPAL, indicate your decision by 
00036  *      deleting the provisions above and replace them with the notice and other 
00037  *      provisions required by the GPL License. If you do not delete the provisions above,
00038  *      a recipient may use your version of this file under either the CPAL or the GPL.
00039  *      
00040  *      *** END LICENSE INFORMATION ***
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_); // down to nearest boundary
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 // --- public --------------------------------------------------------------------------------------
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 // --- private -------------------------------------------------------------------------------------
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 }

Generated on Mon Nov 10 14:20:00 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo