How to Create a Simple Encoder and Decoder with C++ the Right Way

🚀 Improving the code shown in the short videos.


How to Create a Simple Encoder and Decoder with C++ the Right Way


A while ago I posted on Shorts, Reels and Tik Tok a code that created a simple and fast way to encode and decode strings that can be used for countless situations where people only expect encoders like: base64, for example.

Therefore, this method makes it a little more difficult to know which algorithm to use to decode. The C++ code was summarized as follows:

#include <iostream>

constexpr auto encode = [](auto S){
    while((*S++)++);
};

constexpr auto decode = [](auto S){
    while(--(*S++));
};

int main(int argc, char **argv){
    std::string str {};
    if(argc > 1){
        str = argv[1];
    }else{ return EXIT_FAILURE;}

    encode(str.data());
    std::cout << "Encode: " << str << '\n';

    decode(str.data());
    std::cout << "Decode: " << str << '\n';

    return EXIT_SUCCESS;
}

Although it works, this code has some problems:

  • The ideal is not to use constexpr, we are modifying the pointer of the string, making the function of type void is the most logical;
  • The encode function does not check for end of line and this results in a serious problem that causes memory corruption.

I realized this when I was implementing it in a solution I was creating, where I just copied the code generated by the encode function and used it in an application and when I tried to run it, the following error appeared:

*** stack smashing detected ***: terminated
Aborted (core image saved)

Therefore, the corrected code looks like this:

#include <iostream>

void encode(char * s) {
    while (*s != '\0') { // Check the end of the string
        ++(*s); // Increment the current character
        ++s; // Advance to the next character
    }
}

void decode(char * s) {
    while (*s != '\0') { // Check the end of the string
        --(*s); // Decrement the current character
        ++s; // Advance to the next character
    }
}

int main(int argc, char **argv) {
    if (argc > 1) {
        std::string str = argv[1];

        encode(str.data());
        std::cout << "Encode: " << str << '\n';

        decode(str.data());
        std::cout << "Decode: " << str << '\n';
    }

    return EXIT_SUCCESS;
}

Now if you copy the encoded result you can use it to decode in another implementation without having a stack smashing.

To confirm this, you can use flags that check if there was a memory violation, for example:

g++ -g -Wpedantic -Wall -Werror -fsanitize=address encode.cpp

After running, for example:

./a.out "Terminal Root"
Encode: Ufsnjobm!Sppu
Decode: Terminal Root

If you want to make it even more difficult, you can use loops to run the function as many times as you want and use the same number of times to decode, for example, what I’m talking about without loops:

That’s it, modifies the string 4 times and we use it 4 times again to return the string original:

encode(str.data());
encode(str.data());
encode(str.data());
encode(str.data());
std::cout << "Encode: " << str << '\n';

decode(str.data());
decode(str.data());
decode(str.data());
decode(str.data());
std::cout << "Decode: " << str << '\n';

Or using a loop for:

for(int i = {}; i < 4; ++i){
    encode(str.data());
}
std::cout << "Encode: " << str << '\n';

for(int i = {}; i < 4; ++i){
    decode(str.data());
}
std::cout << "Decode: " << str << '\n';

In both cases the output will be the same:

./a.out "Terminal Root"
Encode: Xivqmrep$Vssx
Decode: Terminal Root

How does it work?

  • Encode: Each character of the string is incremented by 1. For example:
  • ‘T’ -> ‘U’
  • ‘e’ -> ‘f’
  • ‘r’ -> ‘s’
  • etc.
  • Decode: Each character of the string is decremented by 1, reversing the encode operation. For example:
  • ‘U’ -> ‘T’
  • ‘f’ -> ‘e’
  • ’s’ -> ‘r’
  • etc.

For more information, I suggest the following links:


cpp cppdaily


Share


YouTube channel

Subscribe


Marcos Oliveira

Marcos Oliveira

Software developer
https://github.com/terroo

Related articles