mirror of https://github.com/sz3/libcimbar
Switch fountain encoding to use 2-byte blocks, because...
...this is the current wirehair limitation anyway. Also added some test cases!
This commit is contained in:
parent
75e88a6d72
commit
e4b02d4a85
|
@ -10,7 +10,7 @@ template <unsigned _bufferSize> // 599
|
|||
class fountain_decoder_stream
|
||||
{
|
||||
public:
|
||||
static const unsigned _headerSize = 3;
|
||||
static const unsigned _headerSize = 2;
|
||||
|
||||
public:
|
||||
fountain_decoder_stream(unsigned dataSize)
|
||||
|
@ -42,7 +42,7 @@ public:
|
|||
{
|
||||
// if we're full
|
||||
_buffIndex = 0;
|
||||
unsigned blockId = ((unsigned)_buffer[0]) << 16 | (unsigned)(_buffer[1]) << 8 | _buffer[2];
|
||||
unsigned blockId = (unsigned)(_buffer[0]) << 8 | _buffer[1];
|
||||
return _decoder.decode(blockId, _buffer.data() + _headerSize, block_size());
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ template <unsigned _bufferSize> // 599
|
|||
class fountain_encoder_stream
|
||||
{
|
||||
public:
|
||||
static const unsigned _headerSize = 3;
|
||||
static const unsigned _headerSize = 2;
|
||||
|
||||
protected:
|
||||
fountain_encoder_stream(std::string&& data)
|
||||
|
@ -66,9 +66,8 @@ public:
|
|||
_encoder.encode(_block++, data, block_size()); // try twice -- the last initial block will be the wrong size
|
||||
|
||||
unsigned block = _block - 1;
|
||||
_buffer.data()[0] = (block >> 16) & 0xFF;
|
||||
_buffer.data()[1] = (block >> 8) & 0xFF;
|
||||
_buffer.data()[2] = block & 0xFF;
|
||||
_buffer.data()[0] = (block >> 8) & 0xFF;
|
||||
_buffer.data()[1] = block & 0xFF;
|
||||
_buffIndex = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "FountainDecoder.h"
|
||||
#include "FountainEncoder.h"
|
||||
#include "serialize/format.h"
|
||||
|
||||
#include "base91/base.hpp"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
@ -11,6 +13,18 @@
|
|||
using std::string;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
std::vector<std::string> blocks()
|
||||
{
|
||||
std::vector<std::string> precomp = {
|
||||
R"(gw_,$k_i$Js@hN7R;4!x;m?zs12+Xv$Sb%ob^heMAJ-:N[*T6texAkZdx2G?uCbRA2IbLmUuFKR*|jgSr!=EWo!G-1m/=*lT{+(abj5XgJ8=%N|QQztEml0o[2;(8YAS77Z.wnXB7IB.y6FTL)CF2i~RR2W-mCLUgw_,$k_i$Js@hN7R;4!x;m?zs12+Xv$Sb%ob^heMAJ-:N[*T6texAkZdx2G?uCbRA2IbLmUuFKR*|jgSr!=EWo!G-1m/=*lT{+(abj5XgJ8=%N|QQztEml0o[2;(8YAS77Z.wnXB7IB.y6FTL)CF2i~RR2W-mCLUgw_,$k_i$Js@hN7R;4!x;m?zs12+Xv$Sb%ob^heMAJ-:N[*T6texAkZdx2G?uCbRA2IbLmUuFKR*|jgSr!=EWo!G-1m/=*lT{+(abj5XgJ8=%N|QQztEml0o[2;(8YAS77Z.wnXB7IB.y6FTL)CF2i~RR2W-mCLUgw_,$k_i$Js@hN7R;4!x;m?zs12+Xv$Sb%ob^heMAJ-:N[*T6texAkZdx2G?uCbRA2IbLmUuFKR*|jgSr!=EWo!G-1m/=*lT{+(abj5XgJ8=%N|QQztEml0o[2;(8YAS77Z.wnXB7IB.y6FTL)CF2i~RR2W-mCLUgw_,$k_i$Js@hN7R;4!x;m?zs12+Xv$Sb%ob^heMAJ-:N[*T6texAkZdx2G?uCbRA2IbLmUuFKR*|jgSr!=EWo!G-1m/=*lT{+(abj5XgJ8=%N|QQztEml0o[2;(8YAS77B)",
|
||||
R"(b%ob^heMAJ-:N[*T6texAkZdx2G?uCbRA2IbLmUuFKR*|jgSr!=EWo!G-1m/=*lT{+(abj5XgJ8=%N|QQztEml0o[2;(8YAS77Z.wnXB7IB.y6FTL)CF2i~RR2W-mCLUgw_,$k_i$Js@hN7R;4!x;m?zs12+Xv$Sb%ob^heMAJ-:N[*T6texAkZdx2G?uCbRA2IbLmUuFKR*|jgSr!=EWo!G-1m/=*lT{+(abj5XgJ8=%N|QQztEml0o[2;(8YAS77Z.wnXB7IB.y6FTL)CF2i~RR2W-mCLUgw_,$k_i$Js@hN7R;4!x;m?zs12+Xv$Sb%ob^heMAJ-:N[*T6texAkZdx2G?uCbRA2IbLmUuFKR*|jgSr!=EWo!G-1m/=*lT{+(abj5XgJ8=%N|QQztEml0o[2;(8YAS77Z.wnXB7IB.y6FTL)CF2i~RR2W-mCLUgw_,$k_i$Js@A)",
|
||||
R"(c%Uhlr*CCfs)S[@q4^ELGi@D*2w[l$TsWuwP'mG44=-{`EM!`%Vsmoc=+Ts)%^_{8,QnK??D;$8=3Q%&juuPX?2op&:{vFE!{uj.+`T=JWM)*HtTE//mn}qCGf~=KWU%8^@JWi\pr}-@2$yn{um=-^c1h\S))H5nc%Uhlr*CCfs)S[@q4^ELGi@D*2w[l$TsWuwP'mG44=-{`EM!`%Vsmoc=+Ts)%^_{8,QnK??D;$8=3Q%&juuPX?2op&:{vFE!{uj.+`T=JWM)*HtTE//mn}qCGf~=KWU%8^@JWi\pr}-@2$yn{um=-^c1h\S))H5nc%Uhlr*CCfs)S[@q4^ELGi@D*2w[l$TsWuwP'mG44=-{`EM!`%Vsmoc=+Ts)%^_{8,QnK??D;$8=3Q%&juuPX?2op&:{vFE!{uj.+`T=JWM)*HtTE//mn}qCGf~=KWU%8^@JWi\pr}-@9j[%o[##DKr^90w^%3*:Oo;#9eG$=q'c5+Y;!gV-j[{ZpMCf(o?iu3.N:xGi`.qx'pR3TTYu!V-R|=%o\-BF){f,*p?.ilHU_-ePE=mVu7d@5lg9Km$`~5Vzv8i%o!*.]z]YE!r[(*'U2b3JN)=3^I'^gUnmuCir9j[%o[##DKr^90w^%3*:Oo;#9eG$=q'c5+Y;!gV-j[{ZpMCf(o?iu3.N:xGi`.qx'pR3TTYu!V-R|=%o\-BF){f,*p?.ilHU_-ePE=mVu7d@5lg9Km$`~5Vzv8i%o!*.]z]YE!r[(*'U2b3JN)=3^ID)"
|
||||
};
|
||||
return precomp;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "FountainEncodingTest/testEncoder", "[unit]" )
|
||||
{
|
||||
FountainEncoder::init();
|
||||
|
@ -83,3 +97,81 @@ TEST_CASE( "FountainEncodingTest/testEncodingAndDecoding", "[unit]" )
|
|||
assertEquals( 11, block_id );
|
||||
assertEquals( 8, decoded_blocks );
|
||||
}
|
||||
|
||||
TEST_CASE( "FountainEncodingTest/testConsistency", "[unit]" )
|
||||
{
|
||||
const std::vector<std::string> precomputed = blocks();
|
||||
static const unsigned packetSize = 626;
|
||||
FountainEncoder::init();
|
||||
|
||||
int messageSize = 1000;
|
||||
std::string message;
|
||||
while (message.size() < messageSize)
|
||||
message += "0123456789";
|
||||
message.resize(messageSize);
|
||||
|
||||
// make sure encoding is consistent
|
||||
FountainEncoder encoder((uint8_t*)message.data(), message.size(), packetSize);
|
||||
std::array<uint8_t,packetSize> block;
|
||||
|
||||
for (unsigned block_id = 0; block_id < 3; ++block_id)
|
||||
{
|
||||
unsigned bites = encoder.encode(block_id, block.data(), block.size());
|
||||
std::string actual = base91::encode(std::string((char*)block.data(), bites));
|
||||
//std::cout << block_id << " : " << actual << std::endl;
|
||||
assertEquals( precomputed[block_id], actual );
|
||||
}
|
||||
|
||||
// make sure decoding is consistent
|
||||
FountainDecoder decoder(messageSize, packetSize);
|
||||
for (unsigned block_id = 0; block_id < 3; ++block_id)
|
||||
{
|
||||
if (block_id == 1)
|
||||
continue;
|
||||
std::string block_data = base91::decode(precomputed[block_id]);
|
||||
std::optional<vector<uint8_t>> res = decoder.decode(block_id, (uint8_t*)block_data.data(), block_data.size());
|
||||
if (block_id == 2)
|
||||
{
|
||||
assertTrue( res );
|
||||
std::string actual = std::string((char*)res->data(), res->size());
|
||||
assertEquals( message, actual );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "FountainEncodingTest/testWhichN", "[unit]" )
|
||||
{
|
||||
const std::vector<std::string> precomputed = blocks();
|
||||
static const unsigned packetSize = 624;
|
||||
FountainEncoder::init();
|
||||
|
||||
int messageSize = 6000;
|
||||
std::string message;
|
||||
while (message.size() < messageSize)
|
||||
message += "0123456789";
|
||||
message.resize(messageSize);
|
||||
|
||||
// create encoder and decoder
|
||||
FountainEncoder encoder((uint8_t*)message.data(), message.size(), packetSize);
|
||||
FountainDecoder decoder(messageSize, packetSize);
|
||||
|
||||
std::array<uint8_t,packetSize> block;
|
||||
std::vector<uint8_t> final_result;
|
||||
|
||||
// decode backwards, never using the "real" data blocks
|
||||
int block_id = 105;
|
||||
for (; block_id >= 0; block_id -= 1)
|
||||
{
|
||||
unsigned bites = encoder.encode(block_id, block.data(), block.size());
|
||||
std::optional<vector<uint8_t>> res = decoder.decode(block_id, block.data(), bites);
|
||||
if (res)
|
||||
{
|
||||
final_result = *res;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals( 96, block_id );
|
||||
assertEquals( message, string((char*)final_result.data(), final_result.size()) );
|
||||
}
|
||||
|
||||
|
|
|
@ -115,9 +115,8 @@ TEST_CASE( "FountainSinkTest/testMultipart", "[unit]" )
|
|||
|
||||
TEST_CASE( "FountainSinkTest/testSameFrameManyTimes", "[unit]" )
|
||||
{
|
||||
// this is the current test case for what is either a wirehair bug or "undefined behavior"
|
||||
// tl;dr -- if you give it the same frame (under certain circumstances), you get a seg fault
|
||||
|
||||
// if you give wirehair the same frame (under certain circumstances), you get a seg fault
|
||||
// sometimes it's fine. The docs say "don't do it", so FountainDecoder acts as the bouncer.
|
||||
FountainInit::init();
|
||||
|
||||
fountain_decoder_sink<626> sink("/tmp");
|
||||
|
|
|
@ -59,12 +59,11 @@ TEST_CASE( "FountainStreamTest/testEncoder_BlockHeader", "[unit]" )
|
|||
assertEquals( res, buff.size() );
|
||||
|
||||
assertEquals( 0, buff[0] );
|
||||
assertEquals( 0, buff[1] );
|
||||
|
||||
if (i+1 >= fes.blocks_required())
|
||||
assertEquals( i+1, buff[2] );
|
||||
assertEquals( i+1, buff[1] );
|
||||
else
|
||||
assertEquals( i, buff[2] );
|
||||
assertEquals( i, buff[1] );
|
||||
}
|
||||
|
||||
assertEquals( 21, fes.block_count() );
|
||||
|
@ -143,7 +142,7 @@ TEST_CASE( "FountainStreamTest/testDecode", "[unit]" )
|
|||
assertMsg((bool)output, "couldn't decode :(");
|
||||
}
|
||||
|
||||
assertEquals( 827, fds.block_size() );
|
||||
assertEquals( 828, fds.block_size() );
|
||||
assertEquals( 10000, fds.data_size() );
|
||||
assertTrue( fds.good() );
|
||||
|
||||
|
@ -185,7 +184,7 @@ TEST_CASE( "FountainStreamTest/testDecode_BigPackets", "[unit]" )
|
|||
assertMsg((bool)output, "couldn't decode :(");
|
||||
}
|
||||
|
||||
assertEquals( 827, fds.block_size() );
|
||||
assertEquals( 828, fds.block_size() );
|
||||
assertEquals( 10000, fds.data_size() );
|
||||
assertTrue( fds.good() );
|
||||
|
||||
|
|
Loading…
Reference in New Issue