#include #include #include #include namespace sp { File::File() : m_handle (NULL) { } File::File(const std::string& filename, Access access, unsigned int mode) : m_handle (NULL) { open(filename, access, mode); } File::~File() { close(); } bool File::open(const std::string& filename, Access access, unsigned int mode) { std::string m; close(); if (access == Access::READ) { m = "rb"; } else if (access == Access::WRITE) { if (mode & TRUNCATE) { m = "wb"; } else { // NOTE: this is append mode. but stdio does only // have "a" and "w". and "w" will truncate. // So we need to handle append with fseek() later. m = "ab"; } } // Read + Write else if (mode & TRUNCATE) { m = "wb+"; } else if (mode & APPEND) { m = "ab+"; } else { m = "rb+"; } // HACK. stdio does not have a mode for strictly create new files // independant of access (read/write). So we will fake it by open the // file in append mode and close it. creating the file if did not exist. if (mode & CREATE && (access == Access::WRITE || access == Access::READ_WRITE)) { m_handle = fopen(filename.c_str(), "a"); if (!m_handle) { m_error.assign(errno, std::generic_category()); return false; } fclose(m_handle); } m_handle = fopen(filename.c_str(), m.c_str()); if (m_handle) { // Hack, if we opened the file in "a" mode, but did not // have the append flag. seek to the beginning. if (m == "ab" && mode & ~APPEND) { fseek(m_handle, 0, SEEK_SET); } return true; } m_error.assign(errno, std::generic_category()); return false; } bool File::isOpen() const { if (m_handle == NULL) { m_error = std::errc::bad_file_descriptor; return false; } return true; } void File::close() { if (m_handle) { fclose(m_handle); m_handle = NULL; } m_error.clear(); } std::string File::getErrorMessage() const { return m_error.message(); } size_t File::pos() { if (isOpen()) { return ftell(m_handle); } return -1; } bool File::set(long int offset, bool from_end) { if (isOpen()) { return fseek(m_handle, offset, from_end ? SEEK_END : SEEK_SET) == 0; } return false; } bool File::seek(long int offset) { if (isOpen()) { return fseek(m_handle, offset, SEEK_CUR) == 0; } return false; } size_t File::size() const { size_t s = 0; while(::getc(m_handle) != EOF) s++; ::rewind(m_handle); return s; } size_t File::read(void *ptr, size_t size) { if (isOpen()) { return fread(ptr, 1, size, m_handle); } return -1; } size_t File::write(const void *ptr, size_t size) { if (isOpen()) { return fwrite(ptr, 1, size, m_handle); } return -1; } bool File::flush() { if (isOpen()) { return fflush(m_handle) == 0; } return false; } } // namespace sp