/* * This file is part of libgim. * * libgim is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * libgim is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with libgim. If not, see . * * Copyright 2010-2014 Danny Robson */ #include "io.hpp" #include "debug.hpp" #include "except.hpp" #include "platform.hpp" #include "types/casts.hpp" #include #include #include #include #include #include using namespace std; using namespace util; //---------------------------------------------------------------------------- std::unique_ptr util::slurp (const boost::filesystem::path& path) { fd_ref fd(path); // Calculate the total file size off_t size = lseek (fd, 0, SEEK_END); if (size == (off_t)-1) throw errno_error(); if (lseek (fd, 0, SEEK_SET) == (off_t)-1) throw errno_error (); // Allocate a buffer, and keep reading until it's full. We provide a null // padding at the tail as a 'just in case' measure for string manipulation. unique_ptr buffer (new char[size + 1]); buffer.get()[size] = '\0'; CHECK_HARD (size >= 0); size_t remaining = (size_t)size; char *cursor = buffer.get(); while (remaining) { ssize_t consumed = ::read (fd, cursor, remaining); if (consumed == -1) throw errno_error(); CHECK_HARD ( consumed > 0); CHECK_HARD ((size_t)consumed <= remaining); remaining -= (size_t)consumed; cursor += consumed; } return buffer; } //---------------------------------------------------------------------------- void util::write (const boost::filesystem::path &path, const char *data, size_t len) { CHECK_SOFT (len > 0); CHECK_HARD (data); fd_ref fd (path); const char *cursor = data; size_t remaining = len; while (remaining) { ssize_t consumed = ::write (fd, cursor, remaining); if (consumed < 0) errno_error::throw_code (); remaining -= sign_cast (consumed); cursor += sign_cast (consumed); } } //---------------------------------------------------------------------------- fd_ref::fd_ref (int _fd): fd (_fd) { if (fd < 0) throw invalid_argument ("invalid file descriptor"); } fd_ref::fd_ref (const boost::filesystem::path &path): #ifdef PLATFORM_WIN32 fd (open (path.string ().c_str (), O_RDONLY | O_BINARY)) #else fd (open (path.string ().c_str (), O_RDONLY)) #endif { if (fd < 0) throw path_error (path); } fd_ref::~fd_ref () { CHECK (fd >= 0); close (fd); } fd_ref::operator int (void) const { return fd; } //---------------------------------------------------------------------------- int indenter::overflow (int ch) { if (m_line_start && ch != '\n') m_dest->sputn (m_indent.data (), sign_cast (m_indent.size ())); m_line_start = ch == '\n'; return m_dest->sputc (ch); } indenter::indenter (std::streambuf* _dest, size_t _indent) : m_dest (_dest) , m_line_start (true) , m_indent (_indent, ' ') , m_owner (NULL) { ; } indenter::indenter (std::ostream& _dest, size_t _indent) : m_dest (_dest.rdbuf()) , m_line_start (true) , m_indent (_indent, ' ') , m_owner (&_dest) { m_owner->rdbuf (this); } indenter::~indenter () { if (m_owner != NULL) m_owner->rdbuf (m_dest); } //---------------------------------------------------------------------------- scoped_cwd::scoped_cwd (): m_original(boost::filesystem::canonical (getcwd (nullptr, 0))) { ; } scoped_cwd::~scoped_cwd () { set_cwd (m_original); } void util::set_cwd (const boost::filesystem::path &path) { CHECK (path.string ().size () > 0); if (chdir (path.string ().c_str ()) != 0) throw errno_error (); } //---------------------------------------------------------------------------- #if defined(HAVE_MMAP) #include mapped_file::mapped_file (const boost::filesystem::path &_path): m_fd (open (_path.native ().c_str (), O_RDWR)) { load_fd (); } mapped_file::~mapped_file () { CHECK (m_data != NULL); munmap (m_data, m_size); } void mapped_file::load_fd (void) { struct stat meta; if (fstat (m_fd, &meta) < 0) throw errno_error (); m_size = (size_t)meta.st_size; m_data = (uint8_t *)mmap (NULL, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0); if (m_data == MAP_FAILED) throw errno_error (); } size_t mapped_file::size (void) const { CHECK (m_size > 0); CHECK (m_data != NULL); return m_size; } uint8_t* mapped_file::data (void) { CHECK (m_size > 0); CHECK (m_data != NULL); return m_data; } const uint8_t* mapped_file::data (void) const { CHECK (m_size > 0); CHECK (m_data != NULL); return m_data; } #endif