Created
October 30, 2015 22:07
-
-
Save agrippa1994/1aae3c1db3c6b418ef63 to your computer and use it in GitHub Desktop.
Byte Stuffing in C++11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <string> | |
template<typename T> | |
T stuff(const T& input, typename T::value_type flag, typename T::value_type escape) { | |
if (flag == escape) | |
throw std::exception("Flag and escape are the same"); | |
// Create header | |
T stuffed = { flag, flag }; | |
// Stuff data | |
for (auto it = input.begin(); it != input.end(); stuffed.push_back(*it++)) | |
if (*it == flag || *it == escape) | |
stuffed.push_back(escape); | |
// Create footer | |
for (int i = 0; i < 2; i++) | |
stuffed.push_back(flag); | |
return stuffed; | |
} | |
template<typename T> | |
T unstuff(T input, typename T::value_type flag, typename T::value_type escape) { | |
// Check if header and footer are valid | |
if (input.size() < 4 || flag == escape | |
|| *input.begin() != flag || *(input.begin() + 1) != flag | |
|| *(input.end() - 1) != flag || *(input.end() - 2) != flag | |
) throw std::exception("Invalid input"); | |
T unstuffed; | |
// Delete header and footer | |
input.erase(input.begin(), input.begin() + 2); | |
input.erase(input.end() - 2, input.end()); | |
// Unstuff data | |
for (auto it = input.begin(); it != input.end(); it++) { | |
if(*it == flag) { | |
if (it + 1 == input.end()) | |
return unstuffed; | |
throw std::exception("Invalid byte stuffing (flag found without escape)"); | |
} | |
else if (*it == escape) { | |
if (it + 1 == input.end()) | |
throw std::exception("Invalid byte stuffing (escape found at end)"); | |
unstuffed.push_back(*(it + 1)); | |
it++; | |
} | |
else { | |
unstuffed.push_back(*it); | |
} | |
} | |
return unstuffed; | |
} | |
// Output of a vector | |
template<typename T> | |
std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) { | |
for (auto i : vec) | |
os << std::hex << (int)i << ' '; | |
return os; | |
} | |
// Testing | |
void testStuffing() { } | |
template<typename T, typename ...A> | |
void testStuffing(T& what, typename T::value_type flag, typename T::value_type escape, A&&... args) { | |
std::cout << "Original: " << what << std::endl; | |
auto stuffedBytes = stuff(what, flag, escape); | |
std::cout << "Stuffed: " << stuffedBytes << std::endl; | |
std::cout << "Unstuffed: " << unstuff(stuffedBytes, flag, escape) << std::endl << std::endl; | |
testStuffing(args...); | |
} | |
template<typename ...A> | |
void testStuffings(A&&... args) { | |
try { | |
testStuffing(args...); | |
} | |
catch (const std::exception& e) { | |
std::cout << "Exception while testing: " << e.what() << std::endl; | |
} | |
} | |
int main() { | |
// Testing | |
testStuffings( | |
std::string("Hello, this text is going to be byte stuffed. 'f' is used as a flag and 'l' is used as an escape character"), 'f', 'l', | |
std::vector<uint8_t>({ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 }), 0x00, 0x01 | |
); | |
std::cin.get(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment