Tuesday, March 7, 2023

Diary #5 C++ Hex Encoder/Decoder

As part of my Websocket Controller (over-network keyboard input forwarder), I wanted to send the clipboard from the client to the server. To do this with non-ASCII chars, I encoded them as hex. This is copy-pasted from the changes I made this morning, to enable the clipboard to send unicode long strings (wstring), as opposed to the previous single-byte std:::strings.

 (needs #include <string>)
const char *hexChars = "0123456789ABCDEF";
string encodeHex(std::wstring wstr){ // because we can only use std::string as an arg for websocketpp's send(). Encode wstring as hex.
    string o = "";
    cout << "wstring has length: " << wstr.length() << endl;
    for (int xint = 0, len = wstr.length(); xint < len; xint++){
        // high order byte of wchar_t
        unsigned char c1 = (wstr[xint] & 65280) >> 8;
        unsigned char c1_left = hexChars[c1 / 16];
        unsigned char c1_right = hexChars[c1 % 16];
        // low order byte of wchar_t
        unsigned char c2 = wstr[xint] & 255;
        unsigned char c2_left = hexChars[c2 / 16];
        unsigned char c2_right = hexChars[c2 % 16];
        o += c1_left;
        o += c1_right;
        o += c2_left;
        o += c2_right;
    }
    cout << "Finished encoded hex: " << o << endl;
    cout << "It has length: " << o.length() << endl;
    return o;
}

wstring decodeHex(std::string str){ // turn (uppercase) hex string back into wstring
    wstring o = L"";
    cout << "decoding from hex: " << str << endl;
    cout << "hex str len: " << str.length() << endl;
    int len = str.length();
    if ((len & 1) == 1) return L"[Odd num of chars, not hex]";
    if ((len % 4) != 0) return L"[Length wrong for wstring, can't de-hex]"; // need 4 hex letters per wchar_t
    for (int xint = 0; xint < len; xint++){
        unsigned char HI_left; // high order byte of wchar_t, left hex char
        unsigned char HI_right;
        unsigned char LO_left; // low order byte of wchar_t, left hex char
        unsigned char LO_right;

        // char 1, hex 1
        if (str[xint] >= 'A' && str[xint] <= 'F'){
            HI_left = 10 + (str[xint++] - 'A');
        }
        else if (str[xint] >= '0' && str[xint] <= '9'){
            HI_left = str[xint++] - '0';
        }
        else{
            return L"[Char invalid, not hex]"; // only accepting capital A-F & 0-9 as hex
        }

        // char 1, hex 2
        if (str[xint] >= 'A' && str[xint] <= 'F'){
            HI_right = 10 + (str[xint++] - 'A');
        }
        else if (str[xint] >= '0' && str[xint] <= '9'){
            HI_right = str[xint++] - '0';
        }
        else{
            return L"[Char invalid, not hex]";
        }

        // char 2, hex 1
        if (str[xint] >= 'A' && str[xint] <= 'F'){
            LO_left = 10 + (str[xint++] - 'A');
        }
        else if (str[xint] >= '0' && str[xint] <= '9'){
            LO_left = str[xint++] - '0';
        }
        else{
            return L"[Char invalid, not hex]";
        }

        // char 2, hex 2
        if (str[xint] >= 'A' && str[xint] <= 'F'){
            LO_right = 10 + (str[xint] - 'A');
        }
        else if (str[xint] >= '0' && str[xint] <= '9'){
            LO_right = str[xint] - '0';
        }
        else{
            return L"[Char invalid, not hex]";
        }


        wchar_t fin = ((HI_left * 16) + HI_right) << 8; // assemble high order byte
        fin += (LO_left * 16) + LO_right; // assemble low order byte
        wcout << L"___constructed char " << fin << endl;
        cout << "decode progress: " << xint << " / " << len << endl;
        o += fin; // add decoded wchar_t to wstring
    }
    wcout << L"finished wstring: " << o << endl;
    return o;
}

 

 

(needs #include <string> and #include <windows.h>)
/*
void toClipboard(string new_text){
    OpenClipboard(0);
    EmptyClipboard();
    HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, new_text.size() + 1);
    if (!hg){
        CloseClipboard();
        return;
    }
    memcpy(GlobalLock(hg), new_text.c_str(), new_text.size() + 1);
    GlobalUnlock(hg);
    SetClipboardData(CF_TEXT, hg);
    CloseClipboard();
    GlobalFree(hg);
}
legacy ASCII version
*/

void toClipboard(wstring new_text){
    OpenClipboard(0);
    EmptyClipboard();
    HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, (new_text.size() * 2) + 2); // 2 bytes per char, plus 2-byte null terminating char
    if (!hg){
        CloseClipboard();
        return;
    }
    memcpy(GlobalLock(hg), new_text.c_str(), (new_text.size() * 2) + 2);
    GlobalUnlock(hg);
    SetClipboardData(CF_UNICODETEXT, hg);
    CloseClipboard();
    GlobalFree(hg);
}

/*string fromClipboard(){
    string out = "";
    if (OpenClipboard(nullptr)){
        HANDLE hData = GetClipboardData(CF_TEXT); // CF_UNICODETEXT will only put 1 char into the char *pszText, CF_TEXT will work normally
        if (hData != nullptr){
            char *pszText = static_cast<char*>(GlobalLock(hData));
            cout << "pszText = " << pszText << endl;
            if (pszText != nullptr){
                out = pszText;
            }
            else{
                out = "pszText = nullptr";
            }
            GlobalUnlock(hData);
        }
        else{
            out = "hData = nullptr";
        }
        CloseClipboard();
    }
    else{
        out = "failed to open clipboard";
    }
    return out;
}
// legacy ASCII version
*/

No comments:

Post a Comment

Coding Challenge #54 C++ int to std::string (no stringstream or to_string())

Gets a string from an integer (ejemplo gratis: 123 -> "123") Wanted to come up with my own function for this like 10 years ago ...