#ifndef OSRM_STORAGE_IO_HPP_ #define OSRM_STORAGE_IO_HPP_ #include "util/exception.hpp" #include "util/exception_utils.hpp" #include "util/fingerprint.hpp" #include "util/log.hpp" #include "util/version.hpp" #include #include #include #include #include namespace osrm { namespace storage { namespace io { class FileReader { private: const boost::filesystem::path filepath; boost::filesystem::ifstream input_stream; public: class LineWrapper : public std::string { friend std::istream &operator>>(std::istream &is, LineWrapper &line) { return std::getline(is, line); } }; auto GetLineIteratorBegin() { return std::istream_iterator(input_stream); } auto GetLineIteratorEnd() { return std::istream_iterator(); } enum FingerprintFlag { VerifyFingerprint, HasNoFingerprint }; FileReader(const std::string &filename, const FingerprintFlag flag) : FileReader(boost::filesystem::path(filename), flag) { } FileReader(const boost::filesystem::path &filepath_, const FingerprintFlag flag) : filepath(filepath_) { input_stream.open(filepath, std::ios::binary); if (!input_stream) throw util::exception("Error opening " + filepath.string()); if (flag == VerifyFingerprint && !ReadAndCheckFingerprint()) { throw util::exception("Fingerprint mismatch in " + filepath_.string() + SOURCE_REF); } } /* Read count objects of type T into pointer dest */ template void ReadInto(T *dest, const std::size_t count) { #if not defined __GNUC__ or __GNUC__ > 4 static_assert(std::is_trivially_copyable::value, "bytewise reading requires trivially copyable type"); #endif if (count == 0) return; const auto &result = input_stream.read(reinterpret_cast(dest), count * sizeof(T)); const std::size_t bytes_read = input_stream.gcount(); if (bytes_read != count && !result) { if (result.eof()) { throw util::exception("Error reading from " + filepath.string() + ": Unexpected end of file " + SOURCE_REF); } throw util::exception("Error reading from " + filepath.string() + " " + SOURCE_REF); } } template void ReadInto(std::vector &target) { ReadInto(target.data(), target.size()); } template void ReadInto(T &target) { ReadInto(&target, 1); } template T ReadOne() { T tmp; ReadInto(tmp); return tmp; } template void Skip(const std::size_t element_count) { boost::iostreams::seek(input_stream, element_count * sizeof(T), BOOST_IOS::cur); } /*******************************************/ std::uint32_t ReadElementCount32() { return ReadOne(); } std::uint64_t ReadElementCount64() { return ReadOne(); } template void DeserializeVector(std::vector &data) { const auto count = ReadElementCount64(); data.resize(count); ReadInto(data.data(), count); } bool ReadAndCheckFingerprint() { auto loaded_fingerprint = ReadOne(); const auto expected_fingerprint = util::FingerPrint::GetValid(); if (!loaded_fingerprint.IsValid()) { util::Log(logERROR) << "Fingerprint magic number or checksum is invalid in " << filepath.string(); return false; } if (!expected_fingerprint.IsDataCompatible(loaded_fingerprint)) { util::Log(logERROR) << filepath.string() << " is not compatible with this version of OSRM"; util::Log(logERROR) << "It was prepared with OSRM " << loaded_fingerprint.GetMajorVersion() << "." << loaded_fingerprint.GetMinorVersion() << "." << loaded_fingerprint.GetPatchVersion() << " but you are running " << OSRM_VERSION; util::Log(logERROR) << "Data is only compatible between minor releases."; return false; } return true; } std::size_t Size() { auto current_pos = input_stream.tellg(); input_stream.seekg(0, input_stream.end); auto length = input_stream.tellg(); input_stream.seekg(current_pos, input_stream.beg); return length; } std::vector ReadLines() { std::vector result; std::string thisline; try { while (std::getline(input_stream, thisline)) { result.push_back(thisline); } } catch (const std::ios_base::failure &) { // EOF is OK here, everything else, re-throw if (!input_stream.eof()) throw; } return result; } std::string ReadLine() { std::string thisline; try { std::getline(input_stream, thisline); } catch (const std::ios_base::failure & /*e*/) { // EOF is OK here, everything else, re-throw if (!input_stream.eof()) throw; } return thisline; } }; class FileWriter { private: const boost::filesystem::path filepath; boost::filesystem::ofstream output_stream; public: enum FingerprintFlag { GenerateFingerprint, HasNoFingerprint }; FileWriter(const std::string &filename, const FingerprintFlag flag) : FileWriter(boost::filesystem::path(filename), flag) { } FileWriter(const boost::filesystem::path &filepath_, const FingerprintFlag flag) : filepath(filepath_) { output_stream.open(filepath, std::ios::binary); if (!output_stream) throw util::exception("Error opening " + filepath.string()); if (flag == GenerateFingerprint) { WriteFingerprint(); } } /* Write count objects of type T from pointer src to output stream */ template void WriteFrom(const T *src, const std::size_t count) { #if not defined __GNUC__ or __GNUC__ > 4 static_assert(std::is_trivially_copyable::value, "bytewise writing requires trivially copyable type"); #endif if (count == 0) return; const auto &result = output_stream.write(reinterpret_cast(src), count * sizeof(T)); if (!result) { throw util::exception("Error writing to " + filepath.string()); } } template void WriteFrom(const T &target) { WriteFrom(&target, 1); } template void WriteOne(const T tmp) { WriteFrom(tmp); } void WriteElementCount32(const std::uint32_t count) { WriteOne(count); } void WriteElementCount64(const std::uint64_t count) { WriteOne(count); } template void SerializeVector(const std::vector &data) { const auto count = data.size(); WriteElementCount64(count); return WriteFrom(data.data(), count); } void WriteFingerprint() { const auto fingerprint = util::FingerPrint::GetValid(); return WriteOne(fingerprint); } }; } } } #endif