diff --git a/KodoTest/KodoTest.sdf b/KodoTest/KodoTest.sdf index 9fee1c334278a3efe28b597ede7b5894717c6ef2..2ae811d6a39c71f6dd334b62816184f936519195 100644 Binary files a/KodoTest/KodoTest.sdf and b/KodoTest/KodoTest.sdf differ diff --git a/KodoTest/KodoTest.v12.suo b/KodoTest/KodoTest.v12.suo index bee61c52ca0269dab36f165da5944a12f462b08f..4f4fe616e9de58f1ae4850ae54e570068ef6b44b 100644 Binary files a/KodoTest/KodoTest.v12.suo and b/KodoTest/KodoTest.v12.suo differ diff --git a/KodoTest/KodoTest/Source.cpp b/KodoTest/KodoTest/Source.cpp index 3e16e6e2dde37f2d99f3ac2d9da6f803f1dec582..d9269310f3b1c0b05c5aa8aa68beb1479f63e9da 100644 --- a/KodoTest/KodoTest/Source.cpp +++ b/KodoTest/KodoTest/Source.cpp @@ -1,72 +1,143 @@ -// Copyright Steinwurf ApS 2011-2012. +// Copyright Steinwurf ApS 2011. // Distributed under the "STEINWURF RESEARCH LICENSE 1.0". // See accompanying file LICENSE.rst or // http://www.steinwurf.com/licensing + +//! [0] +#include <kodo/object/file_encoder.hpp> +#include <kodo/object/file_decoder.hpp> + #include <kodo/rlnc/full_rlnc_codes.hpp> +//! [1] -/// @example encode_decode_simple.cpp +#include <cassert> +#include <cstdint> +#include <fstream> +#include <iostream> +#include <vector> + +/// @example encode_decode_file.cpp /// -/// Simple example showing how to encode and decode a block -/// of memory. +/// Often we want to encode / decode data that exceed a single +/// encoding/decoding block. In this case we need to "chop" up +/// the data into manageable chunks and then encode and decode +/// each chuck separately. This example shows how to use the +/// file encoder in Kodo. The file encoder operates directly on +/// a file in the file-system. For decoding we use an object decoder +/// which decodes data to memory, but which is compatible with +/// file encoder. + +#define BUFFER_SIZE 1000 + +bool isFilesEqual(const std::string& lFilePath, const std::string& rFilePath) +{ + std::ifstream lFile(lFilePath.c_str(), std::ifstream::in | std::ifstream::binary); + std::ifstream rFile(rFilePath.c_str(), std::ifstream::in | std::ifstream::binary); + + if (!lFile.is_open() || !rFile.is_open()) + { + return false; + } + + char *lBuffer = new char[BUFFER_SIZE](); + char *rBuffer = new char[BUFFER_SIZE](); + + do { + lFile.read(lBuffer, BUFFER_SIZE); + rFile.read(rBuffer, BUFFER_SIZE); + + if (std::memcmp(lBuffer, rBuffer, BUFFER_SIZE) != 0) + { + delete[] lBuffer; + delete[] rBuffer; + return false; + } + } while (lFile.good() || rFile.good()); + + delete[] lBuffer; + delete[] rBuffer; + return true; +} int main() { + //! [2] // Set the number of symbols (i.e. the generation size in RLNC // terminology) and the size of a symbol in bytes - uint32_t symbols = 42; - uint32_t symbol_size = 160; + uint32_t max_symbols = 42; + uint32_t max_symbol_size = 64; - // Typdefs for the encoder/decoder type we wish to use - typedef kodo::full_rlnc_encoder<fifi::binary8> rlnc_encoder; - typedef kodo::full_rlnc_decoder<fifi::binary8> rlnc_decoder; + uint32_t file_size = 23456; - // In the following we will make an encoder/decoder factory. - // The factories are used to build actual encoders/decoders - rlnc_encoder::factory encoder_factory(symbols, symbol_size); - auto encoder = encoder_factory.build(); + std::string encode_filename = "encode-file.bin"; + std::string decode_filename = "decode-file.bin"; - rlnc_decoder::factory decoder_factory(symbols, symbol_size); - auto decoder = decoder_factory.build(); + using file_encoder = kodo::object::file_encoder< + kodo::shallow_full_rlnc_encoder<fifi::binary >> ; - // Allocate some storage for a "payload" the payload is what we would - // eventually send over a network - std::vector<uint8_t> payload(encoder->payload_size()); + using file_decoder = kodo::object::file_decoder< + kodo::shallow_full_rlnc_decoder<fifi::binary >> ; + //! [3] - // Allocate some data to encode. In this case we make a buffer - // with the same size as the encoder's block size (the max. - // amount a single encoder can encode) - std::vector<uint8_t> data_in(encoder->block_size()); + //! [4] + // Create a test file for encoding. + std::ofstream encode_file; - // Just for fun - fill the data with random data - for (auto &e : data_in) - e = rand() % 256; + encode_file.open(encode_filename, std::ios::binary); + std::vector<char> data_in(file_size, 'x'); - // Assign the data buffer to the encoder so that we may start - // to produce encoded symbols from it - encoder->set_symbols(sak::storage(data_in)); + encode_file.write(data_in.data(), data_in.size()); + encode_file.close(); + //! [5] - while (!decoder->is_complete()) - { - // Encode a packet into the payload buffer - encoder->encode(&payload[0]); + //! [6] + // Actual encoding/decoding of the file + file_encoder::factory encoder_factory(max_symbols, max_symbol_size); + file_decoder::factory decoder_factory(max_symbols, max_symbol_size); - // Pass that packet to the decoder - decoder->decode(&payload[0]); - } + encoder_factory.set_filename(encode_filename); - // The decoder is complete, now copy the symbols from the decoder - std::vector<uint8_t> data_out(decoder->block_size()); - decoder->copy_symbols(sak::storage(data_out)); + decoder_factory.set_filename(decode_filename); + decoder_factory.set_file_size(file_size); - // Check we properly decoded the data - if (std::equal(data_out.begin(), data_out.end(), data_in.begin())) - { - std::cout << "Data decoded correctly" << std::endl; - } - else + auto encoder = encoder_factory.build(); + auto decoder = decoder_factory.build(); + + std::cout << "encoder blocks = " << encoder->blocks() << std::endl; + std::cout << "decoder blocks = " << decoder->blocks() << std::endl; + //! [7] + + //! [8] + for (uint32_t i = 0; i < encoder->blocks(); ++i) { - std::cout << "Unexpected failure to decode " - << "please file a bug report :)" << std::endl; + // If you want to store the encoder/decoder built. You should use + // the type available as `stack_pointer` in the + // file_encoder/file_decoder types. + // + // file_encoder::stack_pointer e = encoder->build(i); + // file_decoder::stack_pointer d = decoder->build(i); + + auto e = encoder->build(i); + auto d = decoder->build(i); + + std::vector<uint8_t> payload(e->payload_size()); + + while (!d->is_complete()) + { + e->encode(payload.data()); + + // Here we would send and receive the payload over a + // network. Lets throw away some packet to simulate. + if (rand() % 2) + { + continue; + } + + d->decode(payload.data()); + } } -} + //! [9] + + std::cout << isFilesEqual(encode_filename, decode_filename); +} \ No newline at end of file