Add IO support

This commit is contained in:
Michele Rodolfi 2020-12-12 01:44:49 +01:00
parent 3f22ff89e7
commit ff96e73fc7
8 changed files with 304 additions and 2 deletions

View File

@ -1,4 +1,4 @@
set(SOURCES main.cpp crypto.cpp utils.cpp)
set(SOURCES main.cpp crypto.cpp io.cpp utils.cpp)
add_executable(horcrux ${SOURCES})
add_library(${CMAKE_PROJECT_NAME}_lib STATIC ${SOURCES})

97
src/io.cpp Normal file
View File

@ -0,0 +1,97 @@
#include <iostream>
#include "io.h"
namespace horcrux {
namespace fs = std::filesystem;
FsPlainInput::FsPlainInput(const std::string& path) : file_path(path)
{
if (fs::status(path).type() != fs::file_type::regular){
throw std::invalid_argument("Input is not a regular file");
}
file_size = fs::file_size(file_path);
if (file_size == 0){
throw std::invalid_argument("Input is empty, nothing to encrypt");
}
file_stream = std::ifstream(file_path, std::ios::binary);
}
std::vector<unsigned char> FsPlainInput::read(){
std::vector<unsigned char> result(file_size);
file_stream.read(reinterpret_cast<char*>(result.data()), file_size);
return result;
}
FsCryptoInput::FsCryptoInput(const std::vector<std::string>& filenames)
{
if (filenames.empty()){
throw std::invalid_argument("No files to decrypt");
}
for (auto name : filenames){
auto path = fs::path{name};
if (fs::status(path).type() != fs::file_type::regular){
throw std::invalid_argument("Input is not a regular file");
}
file_paths.emplace_back(path, fs::file_size(path));
total_size += file_paths.back().second;
}
if (total_size == 0){
throw std::invalid_argument("No data to decrypt");
}
}
std::vector<unsigned char> FsCryptoInput::read(){
std::vector<unsigned char> result(total_size);
size_t data_read{0};
for (auto& f : file_paths){
std::ifstream ifstream(f.first);
ifstream.read(reinterpret_cast<char*>(result.data()) + data_read, f.second);
data_read += f.second;
}
return result;
}
FsPlainOutput::FsPlainOutput(const std::string& filename)
: file_path(filename)
{
if (fs::exists(file_path) && fs::status(file_path).type() != fs::file_type::regular){
throw std::invalid_argument("Output file is not a regular file");
}
}
size_t FsPlainOutput::write(const std::vector<unsigned char>& to_write){
std::ofstream out(file_path, std::ios::binary);
out.write(reinterpret_cast<const char*>(to_write.data()), to_write.size());
return to_write.size();
}
FsCryptoOutput::FsCryptoOutput(const std::string& folder, const int horcrux_num, const size_t horcrux_size = 0,
const std::string& filename = "horcrux")
: folder_path(folder), base_name(filename),
num(horcrux_num), size(horcrux_size)
{
if (fs::status(folder_path).type() != fs::file_type::directory){
throw std::invalid_argument("Output is not a directory");
}
if (horcrux_num <= 0){
throw std::invalid_argument("Invalid horcrux num");
}
}
size_t FsCryptoOutput::write(const std::vector<unsigned char>& to_write){
size = to_write.size() / num;
std::ofstream f;
created_files.clear();
size_t data_written{0};
for (int i = 0; i < num; ++i){
std::string name = base_name + '_' + std::to_string(i) + ".enc";
created_files.emplace_back(folder_path / name);
f = std::ofstream(created_files.back(),
std::ios::binary | std::ios::trunc);
auto chunk_size = i + 1 != num ? size : size + to_write.size() % size;
f.write(reinterpret_cast<const char*>(to_write.data()) + data_written, chunk_size);
data_written += chunk_size;
}
return data_written;
}
};

47
src/io.h Normal file
View File

@ -0,0 +1,47 @@
#include <string>
#include <filesystem>
#include <fstream>
#include <vector>
namespace horcrux {
class FsPlainInput {
std::filesystem::path file_path;
size_t file_size;
std::ifstream file_stream;
public:
FsPlainInput(const std::string& path);
std::vector<unsigned char> read();
};
class FsCryptoInput {
std::vector<std::pair<std::filesystem::path, size_t>> file_paths;
size_t total_size{0};
public:
FsCryptoInput(const std::vector<std::string>& filenames);
std::vector<unsigned char> read();
};
class FsPlainOutput {
std::filesystem::path file_path;
public:
FsPlainOutput(const std::string& filename);
size_t write(const std::vector<unsigned char>& to_write);
};
class FsCryptoOutput {
std::filesystem::path folder_path;
std::string base_name;
int num;
size_t size;
public:
std::vector<std::filesystem::path> created_files;
FsCryptoOutput(const std::string& folder, const int horcrux_num, const size_t horcrux_size, const std::string& filename);
size_t write(const std::vector<unsigned char>& to_write);
};
};

View File

@ -1,7 +1,11 @@
set(BINARY ${CMAKE_PROJECT_NAME}_test)
add_executable(${BINARY} main.cpp crypto-test.cpp utils-test.cpp)
add_executable(${BINARY} main.cpp crypto-test.cpp io-test.cpp utils-test.cpp)
add_test(NAME test COMMAND ${BINARY})
target_link_libraries(${BINARY} PUBLIC ${CMAKE_PROJECT_NAME}_lib gtest)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_work_dir
DESTINATION ${CMAKE_BINARY_DIR})
add_definitions(-DTEST_WORK_DIR="${CMAKE_BINARY_DIR}/test_work_dir")

126
test/io-test.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "gtest/gtest.h"
#include "io.cpp"
#ifndef TEST_WORK_DIR
#error Please define TEST_WORK_DIR
#endif
const std::string folder{TEST_WORK_DIR};
const std::string noexist{TEST_WORK_DIR "/nope"};
const std::string empty{TEST_WORK_DIR "/empty"};
const std::string text{TEST_WORK_DIR "/test.txt"};
const std::string image{TEST_WORK_DIR "/mangoni.jpg"};
static std::vector<unsigned char> generic_read_file(const std::string& filename){
auto ifstream = std::ifstream{filename, std::ios::binary};
auto path = std::filesystem::path{filename};
auto size = std::filesystem::file_size(path);
std::vector<unsigned char> buf(size);
ifstream.read(reinterpret_cast<char*>(buf.data()), size);
return buf;
}
TEST(IoTests, FsPlainInput) {
EXPECT_THROW(horcrux::FsPlainInput input{noexist}, std::invalid_argument);
EXPECT_THROW(horcrux::FsPlainInput input{folder}, std::invalid_argument);
EXPECT_THROW(horcrux::FsPlainInput input{empty}, std::invalid_argument);
EXPECT_NO_THROW(horcrux::FsPlainInput input{text});
EXPECT_NO_THROW(horcrux::FsPlainInput input{image});
}
TEST(IoTests, FsPlainInputReadText) {
auto input = horcrux::FsPlainInput{text};
auto buf = generic_read_file(text);
EXPECT_EQ(buf, input.read());
}
TEST(IoTests, FsPlainInputReadImg) {
auto input = horcrux::FsPlainInput{image};
auto buf = generic_read_file(image);
EXPECT_EQ(buf, input.read());
}
TEST(IoTests, FsCryptoOutput) {
EXPECT_THROW(horcrux::FsCryptoOutput output(noexist, 1), std::invalid_argument);
EXPECT_NO_THROW(horcrux::FsCryptoOutput output(folder, 1));
EXPECT_THROW(horcrux::FsCryptoOutput output(folder, 0), std::invalid_argument);
EXPECT_THROW(horcrux::FsCryptoOutput output(empty, 1), std::invalid_argument);
EXPECT_THROW(horcrux::FsCryptoOutput output(text, 1), std::invalid_argument);
EXPECT_THROW(horcrux::FsCryptoOutput output(image, 1), std::invalid_argument);
}
TEST(IoTests, FsCryptoOutputWriteImage){
auto ifstream = std::ifstream{image, std::ios::binary};
auto buf = generic_read_file(image);
horcrux::FsCryptoOutput out(folder, 10);
auto written = out.write(buf);
EXPECT_EQ(written, buf.size());
EXPECT_EQ(10, out.created_files.size());
for_each(out.created_files.begin(), out.created_files.end(),
[](auto f){std::filesystem::remove(f);});
}
TEST(IoTests, FsCryptoOutputWriteText){
auto buf = generic_read_file(text);
horcrux::FsCryptoOutput out(folder, 2);
auto written = out.write(buf);
EXPECT_EQ(written, buf.size());
EXPECT_EQ(2, out.created_files.size());
for_each(out.created_files.begin(), out.created_files.end(),
[](auto f){std::filesystem::remove(f);});
}
TEST(IoTest, FsCryptoInput){
EXPECT_THROW(horcrux::FsCryptoInput output({noexist, text, image}), std::invalid_argument);
EXPECT_THROW(horcrux::FsCryptoInput output({folder, text, image}), std::invalid_argument);
EXPECT_THROW(horcrux::FsCryptoInput output({}), std::invalid_argument);
EXPECT_THROW(horcrux::FsCryptoInput output({empty}), std::invalid_argument);
EXPECT_THROW(horcrux::FsCryptoInput output({empty, empty}), std::invalid_argument);
EXPECT_NO_THROW(horcrux::FsCryptoInput output({empty, empty, text}));
EXPECT_NO_THROW(horcrux::FsCryptoInput output({image, empty, text}));
}
TEST(IoTest, FsCryptoInputImage){
auto buf = generic_read_file(image);
//split image using FsCryptoOutput
auto out = horcrux::FsCryptoOutput(folder, 7);
auto written = out.write(buf);
EXPECT_EQ(written, buf.size());
std::vector<std::string> files;
transform(out.created_files.begin(), out.created_files.end(),std::back_inserter(files), [](auto p){return p.string();});
auto in = horcrux::FsCryptoInput(files);
auto read = in.read();
EXPECT_EQ(read, buf);
files.push_back(text);
in = horcrux::FsCryptoInput(files);
read = in.read();
EXPECT_NE(read, buf);
for_each(out.created_files.begin(), out.created_files.end(),
[](auto f){std::filesystem::remove(f);});
}
TEST(IoTest, FsPlainOuput){
EXPECT_NO_THROW(horcrux::FsPlainOutput output{noexist});
EXPECT_THROW(horcrux::FsPlainOutput output{folder}, std::invalid_argument);
EXPECT_NO_THROW(horcrux::FsPlainOutput output{empty});
EXPECT_NO_THROW(horcrux::FsPlainOutput output{text});
EXPECT_NO_THROW(horcrux::FsPlainOutput output{image});
}
TEST(IoTest, FsPlainOutputWrite){
auto buf = generic_read_file(image);
auto out = horcrux::FsPlainOutput(noexist);
auto written = out.write(buf);
EXPECT_EQ(written, buf.size());
auto buf2 = generic_read_file(noexist);
EXPECT_EQ(buf, buf2);
std::filesystem::remove(noexist);
}

0
test/test_work_dir/empty Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -0,0 +1,28 @@
What's your name Catalogna
What's your name Catalogna
What's your name Catalogna
What's your name Catalogna
Cara non so perché ma quando io ti vedo mi vien da vomitare
Forse sara' perché tu mangi troppa catalogna, catalogna
Catalogna catalogna cata cata cata cata catalogna
Catalogna catalogna e nessun altro tipo di verdura cotta.
Sono andato in un centro di allevamento di cinghiali in Lunigiana
E ti ho comprato un cinghialino, l'ho arrostito e l'ho riempito
Con un tacchino di terra cotta ripieno di un piccione vivo con il verme
In bocca, ho arrostito tutto insieme te l'ho portato, oh, non l'hai
Mangiato eri immersa in una vasca di catalogna. Non si fa cosi'!
Catalogna catalogna cata cata cata cata catalogna
Catalogna catalogna cata cata cata cata catalogna
Non puoi mangiare solo catalogna
E' una dieta costituita da un elemento solo
Non mi puoi far credere che questo sia sufficiente
Alla tua corretta crescita, perdi i capelli,
Non puoi vivere mangiando solo catalogna,
Non mi puoi convincere di questo fatto.
Ehi... ma... no... amore ma... solo ora invece capisco
Che la catalogna effettivamente ci permette di condurre
Una vita psichicamente corretta e anche sessualmente
Fantastica! Si', ho capito, infilami la catalogna nel culo,
Voglio fare all'amore con te, infilamela nei capezzoli,
Voglio godere tantissimo!...
Siamo cresciuti mangiando verdura voglio morire con te