Skip to content

Instantly share code, notes, and snippets.

@agrippa1994
Created October 30, 2015 22:07
Show Gist options
  • Save agrippa1994/1aae3c1db3c6b418ef63 to your computer and use it in GitHub Desktop.
Save agrippa1994/1aae3c1db3c6b418ef63 to your computer and use it in GitHub Desktop.
Byte Stuffing in C++11
#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