241 lines
5.5 KiB
C++
241 lines
5.5 KiB
C++
|
#include "StarFile.hpp"
|
||
|
#include "StarFormat.hpp"
|
||
|
|
||
|
#include <fstream>
|
||
|
|
||
|
namespace Star {
|
||
|
|
||
|
void File::makeDirectoryRecursive(String const& fileName) {
|
||
|
auto parent = dirName(fileName);
|
||
|
if (!isDirectory(parent))
|
||
|
makeDirectoryRecursive(parent);
|
||
|
if (!isDirectory(fileName))
|
||
|
makeDirectory(fileName);
|
||
|
}
|
||
|
|
||
|
void File::removeDirectoryRecursive(String const& fileName) {
|
||
|
{
|
||
|
String fileInDir;
|
||
|
bool isDir;
|
||
|
|
||
|
for (auto const& p : dirList(fileName)) {
|
||
|
std::tie(fileInDir, isDir) = p;
|
||
|
|
||
|
fileInDir = relativeTo(fileName, fileInDir);
|
||
|
|
||
|
if (isDir)
|
||
|
removeDirectoryRecursive(fileInDir);
|
||
|
else
|
||
|
remove(fileInDir);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
remove(fileName);
|
||
|
}
|
||
|
|
||
|
void File::copy(String const& source, String const& target) {
|
||
|
auto sourceFile = File::open(source, IOMode::Read);
|
||
|
auto targetFile = File::open(target, IOMode::ReadWrite);
|
||
|
|
||
|
targetFile->resize(0);
|
||
|
|
||
|
char buf[1024];
|
||
|
while (!sourceFile->atEnd()) {
|
||
|
size_t r = sourceFile->read(buf, 1024);
|
||
|
targetFile->writeFull(buf, r);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FilePtr File::open(const String& filename, IOMode mode) {
|
||
|
auto file = make_shared<File>(filename);
|
||
|
file->open(mode);
|
||
|
return file;
|
||
|
}
|
||
|
|
||
|
ByteArray File::readFile(String const& filename) {
|
||
|
FilePtr file = File::open(filename, IOMode::Read);
|
||
|
ByteArray bytes;
|
||
|
while (!file->atEnd()) {
|
||
|
char buffer[1024];
|
||
|
size_t r = file->read(buffer, 1024);
|
||
|
bytes.append(buffer, r);
|
||
|
}
|
||
|
|
||
|
return bytes;
|
||
|
}
|
||
|
|
||
|
String File::readFileString(String const& filename) {
|
||
|
FilePtr file = File::open(filename, IOMode::Read);
|
||
|
std::string str;
|
||
|
while (!file->atEnd()) {
|
||
|
char buffer[1024];
|
||
|
size_t r = file->read(buffer, 1024);
|
||
|
for (size_t i = 0; i < r; ++i)
|
||
|
str.push_back(buffer[i]);
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
StreamOffset File::fileSize(String const& filename) {
|
||
|
return File::open(filename, IOMode::Read)->size();
|
||
|
}
|
||
|
|
||
|
void File::writeFile(char const* data, size_t len, String const& filename) {
|
||
|
FilePtr file = File::open(filename, IOMode::Write | IOMode::Truncate);
|
||
|
file->writeFull(data, len);
|
||
|
}
|
||
|
|
||
|
void File::writeFile(ByteArray const& data, String const& filename) {
|
||
|
writeFile(data.ptr(), data.size(), filename);
|
||
|
}
|
||
|
|
||
|
void File::writeFile(String const& data, String const& filename) {
|
||
|
writeFile(data.utf8Ptr(), data.utf8Size(), filename);
|
||
|
}
|
||
|
|
||
|
void File::overwriteFileWithRename(ByteArray const& data, String const& filename, String const& newSuffix) {
|
||
|
overwriteFileWithRename(data.ptr(), data.size(), filename, newSuffix);
|
||
|
}
|
||
|
|
||
|
void File::overwriteFileWithRename(String const& data, String const& filename, String const& newSuffix) {
|
||
|
overwriteFileWithRename(data.utf8Ptr(), data.utf8Size(), filename, newSuffix);
|
||
|
}
|
||
|
|
||
|
void File::backupFileInSequence(String const& targetFile, unsigned maximumBackups, String const& backupExtensionPrefix) {
|
||
|
for (unsigned i = maximumBackups; i > 0; --i) {
|
||
|
String curExtension = i == 1 ? "" : strf("%s%s", backupExtensionPrefix, i - 1);
|
||
|
String nextExtension = strf("%s%s", backupExtensionPrefix, i);
|
||
|
|
||
|
if (File::isFile(targetFile + curExtension))
|
||
|
File::copy(targetFile + curExtension, targetFile + nextExtension);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
File::File()
|
||
|
: IODevice(IOMode::Closed) {
|
||
|
m_file = 0;
|
||
|
}
|
||
|
|
||
|
File::File(String filename)
|
||
|
: IODevice(IOMode::Closed), m_filename(move(filename)), m_file(0) {}
|
||
|
|
||
|
File::~File() {
|
||
|
close();
|
||
|
}
|
||
|
|
||
|
StreamOffset File::pos() {
|
||
|
if (!m_file)
|
||
|
throw IOException("pos called on closed File");
|
||
|
|
||
|
return ftell(m_file);
|
||
|
}
|
||
|
|
||
|
void File::seek(StreamOffset offset, IOSeek seekMode) {
|
||
|
if (!m_file)
|
||
|
throw IOException("seek called on closed File");
|
||
|
|
||
|
fseek(m_file, offset, seekMode);
|
||
|
}
|
||
|
|
||
|
StreamOffset File::size() {
|
||
|
return fsize(m_file);
|
||
|
}
|
||
|
|
||
|
bool File::atEnd() {
|
||
|
if (!m_file)
|
||
|
throw IOException("eof called on closed File");
|
||
|
|
||
|
return ftell(m_file) >= fsize(m_file);
|
||
|
}
|
||
|
|
||
|
size_t File::read(char* data, size_t len) {
|
||
|
if (!m_file)
|
||
|
throw IOException("read called on closed File");
|
||
|
|
||
|
if (!isReadable())
|
||
|
throw IOException("read called on non-readable File");
|
||
|
|
||
|
return fread(m_file, data, len);
|
||
|
}
|
||
|
|
||
|
size_t File::write(const char* data, size_t len) {
|
||
|
if (!m_file)
|
||
|
throw IOException("write called on closed File");
|
||
|
|
||
|
if (!isWritable())
|
||
|
throw IOException("write called on non-writable File");
|
||
|
|
||
|
return fwrite(m_file, data, len);
|
||
|
}
|
||
|
|
||
|
size_t File::readAbsolute(StreamOffset readPosition, char* data, size_t len) {
|
||
|
return pread(m_file, data, len, readPosition);
|
||
|
}
|
||
|
|
||
|
size_t File::writeAbsolute(StreamOffset writePosition, char const* data, size_t len) {
|
||
|
return pwrite(m_file, data, len, writePosition);
|
||
|
}
|
||
|
|
||
|
String File::fileName() const {
|
||
|
return m_filename;
|
||
|
}
|
||
|
|
||
|
void File::setFilename(String filename) {
|
||
|
if (isOpen())
|
||
|
throw IOException("Cannot call setFilename while File is open");
|
||
|
m_filename = move(filename);
|
||
|
}
|
||
|
|
||
|
void File::remove() {
|
||
|
close();
|
||
|
if (m_filename.empty())
|
||
|
throw IOException("Cannot remove file, no filename set");
|
||
|
remove(m_filename);
|
||
|
}
|
||
|
|
||
|
void File::resize(StreamOffset s) {
|
||
|
bool tempOpen = false;
|
||
|
if (!isOpen()) {
|
||
|
tempOpen = true;
|
||
|
open(mode());
|
||
|
}
|
||
|
|
||
|
File::resize(m_file, s);
|
||
|
|
||
|
if (tempOpen)
|
||
|
close();
|
||
|
}
|
||
|
|
||
|
void File::sync() {
|
||
|
if (!m_file)
|
||
|
throw IOException("sync called on closed File");
|
||
|
|
||
|
fsync(m_file);
|
||
|
}
|
||
|
|
||
|
void File::open(IOMode m) {
|
||
|
close();
|
||
|
if (m_filename.empty())
|
||
|
throw IOException("Cannot open file, no filename set");
|
||
|
|
||
|
m_file = fopen(m_filename.utf8Ptr(), m);
|
||
|
setMode(m);
|
||
|
}
|
||
|
|
||
|
void File::close() {
|
||
|
if (m_file)
|
||
|
fclose(m_file);
|
||
|
m_file = 0;
|
||
|
setMode(IOMode::Closed);
|
||
|
}
|
||
|
|
||
|
String File::deviceName() const {
|
||
|
if (m_filename.empty())
|
||
|
return "<unnamed temp file>";
|
||
|
else
|
||
|
return m_filename;
|
||
|
}
|
||
|
|
||
|
}
|