zeus/zeus/zeus-File.impl.cpp

243 lines
8.7 KiB
C++

/** @file
* @author Edouard DUPIN
* @copyright 2014, Edouard DUPIN, all right reserved
* @license MPL v2.0 (see license file)
*/
#include <zeus/zeus-File.impl.hpp>
#include <zeus/ProxyFile.hpp>
#include <zeus/mineType.hpp>
#include <algue/sha512.hpp>
#include <etk/path/fileSystem.hpp>
#include <etk/Exception.hpp>
#include "debug.hpp"
#include <etk/typeInfo.hpp>
ETK_DECLARE_TYPE(zeus::FileImpl);
ememory::SharedPtr<zeus::File> zeus::File::create(etk::Uri _fileNameReal) {
return ememory::makeShared<zeus::FileImpl>(_fileNameReal);
}
ememory::SharedPtr<zeus::File> zeus::File::create(etk::Uri _fileNameReal, etk::String _sha512) {
return ememory::makeShared<zeus::FileImpl>(_fileNameReal, _sha512);
}
ememory::SharedPtr<zeus::File> zeus::File::create(etk::Uri _fileNameReal, etk::String _fileNameShow, etk::String _mineType) {
return ememory::makeShared<zeus::FileImpl>(_fileNameReal, _fileNameShow, _mineType);
}
ememory::SharedPtr<zeus::File> zeus::File::create(etk::Uri _fileNameReal, etk::String _fileNameShow, etk::String _mineType, etk::String _sha512) {
return ememory::makeShared<zeus::FileImpl>(_fileNameReal, _fileNameShow, _mineType, _sha512);
}
ememory::SharedPtr<zeus::File> zeus::File::create(etk::Vector<uint8_t> _fileData, etk::String _virtualName, etk::String _mineType) {
return ememory::makeShared<zeus::FileImpl>(etk::move(_fileData), _virtualName, _mineType);
}
zeus::FileImpl::FileImpl(etk::Vector<uint8_t> _value, etk::String _virtualName, etk::String _mineType) :
m_filename(_virtualName),
m_gettedData(0),
m_mineType(_mineType),
m_sha512("") {
ZEUS_ERROR(" ==============>>>>>>>>>>>>>> CREATE FILE 1 " << _virtualName);
m_dataRaw = true;
m_data = _value;
m_size = m_data.size();
}
zeus::FileImpl::FileImpl(etk::Uri _fileNameReal, etk::String _sha512) :
m_filename(_fileNameReal.getPath().getFileName()),
m_file(etk::uri::get(_fileNameReal)),
m_gettedData(0),
m_sha512(_sha512) {
ZEUS_ERROR(" ==============>>>>>>>>>>>>>> CREATE FILE 3 " << _fileNameReal << " '" << _sha512 << "' size=" << m_file->size());
m_size = m_file->size();
etk::String extention = _fileNameReal.getPath().getExtention();
m_mineType = zeus::getMineType(extention);
if ( _sha512.size() > 0
&& _sha512.size() != 128) {
ZEUS_ERROR("Set a wrong sha512 file type");
_sha512.clear();
}
}
// sha 512 example: 6134b4a4b5b116cf1b1b757c5aa48bd8b3482b86c6d3fee389a0a3232f74e7331e5f8af6ad516d2ca92eda0a475f44e1291618562ce6f9e54634ba052650dcd7
// 000000000100000000020000000003000000000400000000050000000006000000000700000000080000000009000000000A000000000B000000000C00000000
zeus::FileImpl::FileImpl(etk::Uri _fileNameReal, etk::String _fileNameShow, etk::String _mineType, etk::String _sha512) :
m_filename(_fileNameShow),
m_file(etk::uri::get(_fileNameReal)),
m_gettedData(0),
m_mineType(_mineType),
m_sha512(_sha512) {
ZEUS_ERROR(" ==============>>>>>>>>>>>>>> CREATE FILE 2 " << _fileNameReal);
m_size = m_file->size();
if ( _sha512.size() > 0
&& _sha512.size() != 128) {
ZEUS_ERROR("Set a wrong sha512 file type");
_sha512.clear();
}
}
zeus::FileImpl::~FileImpl() {
ZEUS_ERROR(" <<<<<<<<<<<<<<============== DESTROY FILE");
if (m_file->isOpen() == true) {
m_file->close();
}
}
uint64_t zeus::FileImpl::getSize() {
return m_size;
}
etk::String zeus::FileImpl::getName() {
return m_filename;
}
etk::String zeus::FileImpl::getSha512() {
ZEUS_VERBOSE("Get SHA 512 ... " << m_sha512.size() << " '" << m_sha512 << "'");
if (m_sha512 == "") {
ZEUS_INFO("calculation of sha 512 (start)");
if (m_dataRaw == false) {
m_sha512 = algue::stringConvert(algue::sha512::encodeFromFile(m_file));
} else {
m_sha512 = algue::stringConvert(algue::sha512::encode(m_data));
}
ZEUS_INFO("calculation of sha 512 (stop)");
}
ZEUS_VERBOSE("return sha512 : '" << m_sha512 << "'");
return m_sha512;
}
etk::String zeus::FileImpl::getMineType() {
return m_mineType;
}
zeus::Raw zeus::FileImpl::getPart(uint64_t _start, uint64_t _stop) {
ZEUS_VERBOSE("REQUEST Get part ... " << _start << " " << _stop);
if ((_stop - _start) > 25*1024*1024) {
ZEUS_ERROR("REQUEST more that 25 Mo in a part file ...");
throw etk::exception::InvalidArgument("REQUEST more that 25 Mo in a part file ..." + etk::toString(_stop - _start) + " Bytes");
return zeus::Raw();
}
if (_start >= m_size) {
throw etk::exception::InvalidArgument("REQUEST start position out of file size" + etk::toString(_start) + " > " + etk::toString(m_size));
}
if (m_dataRaw == false) {
if (m_file->isOpen() == false) {
m_file->open(etk::io::OpenMode::Read);
}
m_gettedData += (_stop - _start);
//ZEUS_PRINT("Reading file : " << m_gettedData << "/" << m_size << " ==> " << float(m_gettedData)/float(m_size)*100.0f << "%");
printf("Reading file : %d/%d ==> %f \r", int(m_gettedData), int(m_size), float(m_gettedData)/float(m_size)*100.0f);
zeus::Raw tmp(_stop - _start);
if (m_file->seek(_start, etk::io::SeekMode::Start) == false) {
ZEUS_ERROR("REQUEST seek error ...");
throw etk::exception::RuntimeError("Seek in the file error");
return zeus::Raw();
}
int64_t sizeCopy = m_file->read(tmp.writeData(), 1, _stop-_start);
if (m_size <= _stop) {
m_file->close();
}
// TODO : Check if copy is correct ...
return etk::move(tmp);
} else {
m_gettedData += (_stop - _start);
//ZEUS_PRINT("Reading file : " << m_gettedData << "/" << m_size << " ==> " << float(m_gettedData)/float(m_size)*100.0f << "%");
printf("Reading file : %d/%d ==> %f \r", int(m_gettedData), int(m_size), float(m_gettedData)/float(m_size)*100.0f);
zeus::Raw tmp(_stop - _start);
memcpy(tmp.writeData(), &m_data[_start], _stop-_start);
return etk::move(tmp);
}
}
etk::String zeus::storeInFile(zeus::ProxyFile _file, etk::Uri _uri) {
zeus::ActionNotification<etk::String> tmp;
return zeus::storeInFileNotify(_file, _uri, tmp);
}
etk::String zeus::storeInFileNotify(zeus::ProxyFile _file, etk::Uri _uri, zeus::ActionNotification<etk::String> _notification) {
auto futSize = _file.getSize();
auto futSha = _file.getSha512();
futSize.wait();
int64_t retSize = futSize.get();
int64_t offset = 0;
algue::Sha512 shaCtx;
ememory::SharedPtr<etk::io::Interface> file = etk::uri::get(_uri);
file->open(etk::io::OpenMode::Write);
while (retSize > 0) {
// get by batch of 1 MB
int32_t nbElement = 1*1024*1024;
if (retSize<nbElement) {
nbElement = retSize;
}
auto futData = _file.getPart(offset, offset + nbElement);
// TODO: set a timeout
futData.wait();
if (futData.hasError() == true) {
ZEUS_DEBUG("read: ==> exception when read data ...");
throw etk::exception::RuntimeError("Error when loading data");
}
zeus::Raw buffer = futData.get();
shaCtx.update(buffer.data(), buffer.size());
file->write(buffer.data(), 1, buffer.size());
offset += nbElement;
retSize -= nbElement;
ZEUS_VERBOSE("read: " << offset << "/" << futSize.get() << " " << buffer.size());
_notification.notify("{\"pourcent\":" + etk::toString(float(offset)/float(buffer.size())) + ", \"comment\":\"download\"");
}
file->close();
// get the final sha512 of the file:
etk::String sha512String = algue::stringConvert(shaCtx.finalize());
futSha.wait();
if (sha512String != futSha.get()) {
ZEUS_ERROR("get wrong Sha512 local : '" << sha512String << "'");
ZEUS_ERROR("get wrong Sha512 remote: '" << futSha.get() << "'");
throw etk::exception::RuntimeError("SHA-512 error check");
}
return sha512String;
}
etk::Vector<uint8_t> zeus::storeInMemory(zeus::ProxyFile _file) {
etk::Vector<uint8_t> out;
auto futSize = _file.getSize();
auto futSha = _file.getSha512();
futSize.wait();
int64_t retSize = futSize.get();
int64_t offset = 0;
algue::Sha512 shaCtx;
out.resize(retSize);
int64_t currentOffset = 0;
while (retSize > 0) {
// get by batch of 1 MB
int32_t nbElement = 1*1024*1024;
if (retSize<nbElement) {
nbElement = retSize;
}
auto futData = _file.getPart(offset, offset + nbElement);
futData.wait();
if (futData.hasError() == true) {
throw etk::exception::RuntimeError("Error when loading data");
}
zeus::Raw buffer = futData.get();
shaCtx.update(buffer.data(), buffer.size());
memcpy(&out[currentOffset], buffer.data(), buffer.size());
currentOffset += buffer.size();
offset += nbElement;
retSize -= nbElement;
ZEUS_VERBOSE("read: " << offset << "/" << futSize.get() << " " << buffer.size());
}
// get the final sha512 of the file:
etk::String sha512String = algue::stringConvert(shaCtx.finalize());
futSha.wait();
if (sha512String != futSha.get()) {
ZEUS_ERROR("get wrong Sha512 local : '" << sha512String << "'");
ZEUS_ERROR("get wrong Sha512 remote: '" << futSha.get() << "'");
}
return out;
}