Skip to content

Commit fa633aa

Browse files
author
MarcoFalke
committed
streams: Teach AutoFile how to XOR
1 parent 000019e commit fa633aa

File tree

3 files changed

+82
-5
lines changed

3 files changed

+82
-5
lines changed

src/streams.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,20 @@
55
#include <span.h>
66
#include <streams.h>
77

8+
#include <array>
9+
810
std::size_t AutoFile::detail_fread(Span<std::byte> dst)
911
{
1012
if (!m_file) throw std::ios_base::failure("AutoFile::read: file handle is nullptr");
11-
return std::fread(dst.data(), 1, dst.size(), m_file);
13+
if (m_xor.empty()) {
14+
return std::fread(dst.data(), 1, dst.size(), m_file);
15+
} else {
16+
const auto init_pos{std::ftell(m_file)};
17+
if (init_pos < 0) throw std::ios_base::failure("AutoFile::read: ftell failed");
18+
std::size_t ret{std::fread(dst.data(), 1, dst.size(), m_file)};
19+
util::Xor(dst.subspan(0, ret), m_xor, init_pos);
20+
return ret;
21+
}
1222
}
1323

1424
void AutoFile::read(Span<std::byte> dst)
@@ -34,7 +44,23 @@ void AutoFile::ignore(size_t nSize)
3444
void AutoFile::write(Span<const std::byte> src)
3545
{
3646
if (!m_file) throw std::ios_base::failure("AutoFile::write: file handle is nullptr");
37-
if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) {
38-
throw std::ios_base::failure("AutoFile::write: write failed");
47+
if (m_xor.empty()) {
48+
if (std::fwrite(src.data(), 1, src.size(), m_file) != src.size()) {
49+
throw std::ios_base::failure("AutoFile::write: write failed");
50+
}
51+
} else {
52+
auto current_pos{std::ftell(m_file)};
53+
if (current_pos < 0) throw std::ios_base::failure("AutoFile::write: ftell failed");
54+
std::array<std::byte, 4096> buf;
55+
while (src.size() > 0) {
56+
auto buf_now{Span{buf}.first(std::min<size_t>(src.size(), buf.size()))};
57+
std::copy(src.begin(), src.begin() + buf_now.size(), buf_now.begin());
58+
util::Xor(buf_now, m_xor, current_pos);
59+
if (std::fwrite(buf_now.data(), 1, buf_now.size(), m_file) != buf_now.size()) {
60+
throw std::ios_base::failure{"XorFile::write: failed"};
61+
}
62+
src = src.subspan(buf_now.size());
63+
current_pos += buf_now.size();
64+
}
3965
}
4066
}

src/streams.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -482,9 +482,10 @@ class AutoFile
482482
{
483483
protected:
484484
std::FILE* m_file;
485+
const std::vector<std::byte> m_xor;
485486

486487
public:
487-
explicit AutoFile(std::FILE* file) : m_file{file} {}
488+
explicit AutoFile(std::FILE* file, std::vector<std::byte> data_xor={}) : m_file{file}, m_xor{std::move(data_xor)} {}
488489

489490
~AutoFile() { fclose(); }
490491

@@ -553,7 +554,7 @@ class CAutoFile : public AutoFile
553554
const int nVersion;
554555

555556
public:
556-
CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : AutoFile{filenew}, nType(nTypeIn), nVersion(nVersionIn) {}
557+
explicit CAutoFile(std::FILE* file, int type, int version, std::vector<std::byte> data_xor = {}) : AutoFile{file, std::move(data_xor)}, nType{type}, nVersion{version} {}
557558
int GetType() const { return nType; }
558559
int GetVersion() const { return nVersion; }
559560

src/test/streams_tests.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,63 @@
66
#include <test/util/random.h>
77
#include <test/util/setup_common.h>
88
#include <util/fs.h>
9+
#include <util/strencodings.h>
910

1011
#include <boost/test/unit_test.hpp>
1112

1213
using namespace std::string_literals;
1314

1415
BOOST_FIXTURE_TEST_SUITE(streams_tests, BasicTestingSetup)
1516

17+
BOOST_AUTO_TEST_CASE(xor_file)
18+
{
19+
fs::path xor_path{m_args.GetDataDirBase() / "test_xor.bin"};
20+
auto raw_file{[&](const auto& mode) { return fsbridge::fopen(xor_path, mode); }};
21+
const std::vector<uint8_t> test1{1, 2, 3};
22+
const std::vector<uint8_t> test2{4, 5};
23+
const std::vector<std::byte> xor_pat{std::byte{0xff}, std::byte{0x00}};
24+
{
25+
// Check errors for missing file
26+
AutoFile xor_file{raw_file("rb"), xor_pat};
27+
BOOST_CHECK_EXCEPTION(xor_file << std::byte{}, std::ios_base::failure, HasReason{"AutoFile::write: file handle is nullpt"});
28+
BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure, HasReason{"AutoFile::read: file handle is nullpt"});
29+
BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure, HasReason{"AutoFile::ignore: file handle is nullpt"});
30+
}
31+
{
32+
AutoFile xor_file{raw_file("wbx"), xor_pat};
33+
xor_file << test1 << test2;
34+
}
35+
{
36+
// Read raw from disk
37+
AutoFile non_xor_file{raw_file("rb")};
38+
std::vector<std::byte> raw(7);
39+
non_xor_file >> Span{raw};
40+
BOOST_CHECK_EQUAL(HexStr(raw), "fc01fd03fd04fa");
41+
// Check that no padding exists
42+
BOOST_CHECK_EXCEPTION(non_xor_file.ignore(1), std::ios_base::failure, HasReason{"AutoFile::ignore: end of file"});
43+
}
44+
{
45+
AutoFile xor_file{raw_file("rb"), xor_pat};
46+
std::vector<std::byte> read1, read2;
47+
xor_file >> read1 >> read2;
48+
BOOST_CHECK_EQUAL(HexStr(read1), HexStr(test1));
49+
BOOST_CHECK_EQUAL(HexStr(read2), HexStr(test2));
50+
// Check that eof was reached
51+
BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure, HasReason{"AutoFile::read: end of file"});
52+
}
53+
{
54+
AutoFile xor_file{raw_file("rb"), xor_pat};
55+
std::vector<std::byte> read2;
56+
// Check that ignore works
57+
xor_file.ignore(4);
58+
xor_file >> read2;
59+
BOOST_CHECK_EQUAL(HexStr(read2), HexStr(test2));
60+
// Check that ignore and read fail now
61+
BOOST_CHECK_EXCEPTION(xor_file.ignore(1), std::ios_base::failure, HasReason{"AutoFile::ignore: end of file"});
62+
BOOST_CHECK_EXCEPTION(xor_file >> std::byte{}, std::ios_base::failure, HasReason{"AutoFile::read: end of file"});
63+
}
64+
}
65+
1666
BOOST_AUTO_TEST_CASE(streams_vector_writer)
1767
{
1868
unsigned char a(1);

0 commit comments

Comments
 (0)