1 // =================================
 2 // Copyright (c) 2021 Seppo Laakko
 3 // Distributed under the MIT license
 4 // =================================
 5 
 6 #include <soulng/util/MappedInputFile.hpp>
 7 #include <soulng/util/FileLocking.hpp>
 8 #include <boost/filesystem.hpp>
 9 #include <boost/iostreams/device/mapped_file.hpp>
10 #include <stdexcept>
11 
12 namespace soulng { namespace util {
13 
14 class MappedInputFileImpl 
15 {
16 public:
17     MappedInputFileImpl(const std::string& fileName);
18     const char* Data() const { return mappedFile.const_data(); }
19     boost::iostreams::mapped_file_source::size_type Size() const { return mappedFile.size(); }
20 private:
21     boost::iostreams::mapped_file mappedFile;
22 };
23 
24 MappedInputFileImpl::MappedInputFileImpl(const std::string& fileName) : mappedFile()
25 {
26     try
27     {
28         LockFile(fileNameLockKind::read);
29         mappedFile.open(fileNameboost::iostreams::mapped_file::mapmode::readonly);
30     }
31     catch (std::exception& ex;)
32     {
33         throw std::runtime_error("error opening mapped file '" + fileName + "': " + ex.what());
34     }
35     catch (...)
36     {
37         throw std::runtime_error("error opening mapped file '" + fileName + "'");
38     }
39 }
40 
41 MappedInputFile::MappedInputFile(const std::string& fileName_) : fileName(fileName_)impl(new MappedInputFileImpl(fileName))
42 {
43 }
44 
45 MappedInputFile::~MappedInputFile()
46 {
47     delete impl;
48     UnlockFile(fileNameLockKind::read);
49 }
50 
51 const char* MappedInputFile::Begin() const
52 {
53     const char* start = impl->Data();
54     if (impl->Size() >= 3)
55     {
56         if ((unsigned char)start[0] == (unsigned char)0xEF && 
57             (unsigned char)start[1] == (unsigned char)0xBB && 
58             (unsigned char)start[2] == (unsigned char)0xBF)
59         {
60             start += 3;
61         }
62     }
63     return start;
64 }
65 
66 const char* MappedInputFile::End() const
67 {
68     return impl->Data() + impl->Size();
69 }
70 
71 std::string ReadFile(const std::string& fileName)
72 {
73     if (!boost::filesystem::exists(fileName))
74     {
75         throw std::runtime_error("file '" + fileName + "' does not exist");
76     }
77     if (boost::filesystem::file_size(fileName) == 0)
78     {
79         return std::string();
80     }
81     MappedInputFile mappedFile(fileName);
82     return std::string(mappedFile.Begin()mappedFile.End());
83 }
84 
85 } } // namespace soulng::util