diff -U 3 -b -B -d -r -- a/const.h b/const.h --- a/const.h 2013-10-02 00:38:05.000000000 +0200 +++ b/const.h 2014-02-23 17:30:27.297796331 +0100 @@ -24,9 +24,6 @@ #define HIDE 0 #define SHOW 1 -#define GET_NAME 0 -#define GET_PASSWD 1 - #define OK_EXIT 0 #define ERR_EXIT 1 diff -U 3 -b -B -d -r -- a/main.cpp b/main.cpp --- a/main.cpp 2013-10-02 00:38:05.000000000 +0200 +++ b/main.cpp 2014-02-23 17:33:57.891121965 +0100 @@ -16,6 +16,8 @@ int main(int argc, char** argv) { + // We need to set the locale to get the input encoded in UTF-8 + setlocale (LC_ALL, ""); LoginApp = new App(argc, argv); LoginApp->Run(); return 0; diff -U 3 -b -B -d -r -- a/panel.cpp b/panel.cpp --- a/panel.cpp 2013-10-02 00:38:05.000000000 +0200 +++ b/panel.cpp 2014-02-23 17:30:27.297796331 +0100 @@ -13,6 +13,7 @@ #include #include #include "panel.h" +#include "util.h" using namespace std; @@ -78,6 +79,15 @@ XftColorAllocName(Dpy, visual, colormap, cfg->getOption("session_shadow_color").c_str(), &sessionshadowcolor); + /* Build XIC and XIM to be able to get unicode string from keyboard events */ + char classname = 0; + displayIc = NULL; + displayIm = XOpenIM(Dpy, NULL, &classname, &classname); + if(displayIm) { + displayIc = XCreateIC(displayIm, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNResourceName, &classname, + XNResourceClass, &classname, NULL); + } /* Load properties from config / theme */ input_name_x = cfg->getIntOption("input_name_x"); input_name_y = cfg->getIntOption("input_name_y"); @@ -91,6 +101,8 @@ input_pass_y = input_name_y; } + Reset(); + /* Load panel and background image */ string panelpng = ""; panelpng = panelpng + themedir +"/panel.png"; @@ -210,6 +222,12 @@ Visual* visual = DefaultVisual(Dpy, Scr); Colormap colormap = DefaultColormap(Dpy, Scr); + if(displayIc) { + XDestroyIC(displayIc); + } + if(displayIm) { + XCloseIM(displayIm); + } XftColorFree(Dpy, visual, colormap, &inputcolor); XftColorFree(Dpy, visual, colormap, &inputshadowcolor); XftColorFree(Dpy, visual, colormap, &welcomecolor); @@ -289,7 +307,8 @@ XftDraw *draw = XftDrawCreate(Dpy, Win, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); - XftTextExtents8(Dpy, msgfont, reinterpret_cast(message.c_str()), + + XftTextExtentsUtf8(Dpy, msgfont, reinterpret_cast(message.c_str()), message.length(), &extents); string cfgX = cfg->getOption("passwd_feedback_x"); @@ -300,7 +319,7 @@ int msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height); OnExpose(); - SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message, + SlimDrawStringUtf8(draw, &msgcolor, msgfont, msg_x, msg_y, message, &msgshadowcolor, shadowXOffset, shadowYOffset); if (cfg->getOption("bell") == "1") @@ -312,7 +331,7 @@ OnExpose(); // The message should stay on the screen even after the password field is // cleared, methinks. I don't like this solution, but it works. - SlimDrawString8(draw, &msgcolor, msgfont, msg_x, msg_y, message, + SlimDrawStringUtf8(draw, &msgcolor, msgfont, msg_x, msg_y, message, &msgshadowcolor, shadowXOffset, shadowYOffset); XSync(Dpy, True); XftDrawDestroy(draw); @@ -330,9 +349,8 @@ draw = XftDrawCreate(Dpy, Root, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); - XftTextExtents8(Dpy, msgfont, - reinterpret_cast(text.c_str()), - text.length(), &extents); + XftTextExtentsUtf8(Dpy, msgfont, + reinterpret_cast(text.c_str()), text.length(), &extents); cfgX = cfg->getOption("msg_x"); cfgY = cfg->getOption("msg_y"); int shadowXOffset = cfg->getIntOption("msg_shadow_xoffset"); @@ -347,9 +365,8 @@ msg_y = Cfg::absolutepos(cfgY, XHeightOfScreen(ScreenOfDisplay(Dpy, Scr)), extents.height); } - SlimDrawString8 (draw, &msgcolor, msgfont, msg_x, msg_y, - text, - &msgshadowcolor, + SlimDrawStringUtf8(draw, &msgcolor, msgfont, msg_x, msg_y, + text, &msgshadowcolor, shadowXOffset, shadowYOffset); XFlush(Dpy); XftDrawDestroy(draw); @@ -383,24 +400,27 @@ } void Panel::Cursor(int visible) { - const char* text = NULL; - int xx = 0, yy = 0, y2 = 0, cheight = 0; + const uint16_t* text = NULL; + int xx = 0, yy = 0, y2 = 0, cheight = 0, textLen = 0; const char* txth = "Wj"; /* used to get cursor height */ if (mode == Mode_Lock) { - text = HiddenPasswdBuffer.c_str(); + text = hiddenPasswdBuffer; + textLen = passwdBufferLen; xx = input_pass_x; yy = input_pass_y; } else { switch(field) { case Get_Passwd: - text = HiddenPasswdBuffer.c_str(); + text = hiddenPasswdBuffer; + textLen = passwdBufferLen; xx = input_pass_x; yy = input_pass_y; break; case Get_Name: - text = NameBuffer.c_str(); + text = nameBuffer; + textLen = nameBufferLen; xx = input_name_x; yy = input_name_y; break; @@ -411,7 +431,7 @@ XftTextExtents8(Dpy, font, (XftChar8*)txth, strlen(txth), &extents); cheight = extents.height; y2 = yy - extents.y + extents.height; - XftTextExtents8(Dpy, font, (XftChar8*)text, strlen(text), &extents); + XftTextExtents16(Dpy, font, (XftChar16*)text, textLen, &extents); xx += extents.width; if(visible == SHOW) { @@ -478,27 +498,25 @@ XClearWindow(Dpy, Win); if (input_pass_x != input_name_x || input_pass_y != input_name_y){ - SlimDrawString8 (draw, &inputcolor, font, input_name_x, input_name_y, - NameBuffer, - &inputshadowcolor, + SlimDrawString16(draw, &inputcolor, font, input_name_x, input_name_y, + nameBuffer, nameBufferLen, &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); - SlimDrawString8 (draw, &inputcolor, font, input_pass_x, input_pass_y, - HiddenPasswdBuffer, - &inputshadowcolor, + SlimDrawString16(draw, &inputcolor, font, input_pass_x, input_pass_y, + hiddenPasswdBuffer, passwdBufferLen, &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); } else { /*single input mode */ switch(field) { case Get_Passwd: - SlimDrawString8 (draw, &inputcolor, font, + SlimDrawString16(draw, &inputcolor, font, input_pass_x, input_pass_y, - HiddenPasswdBuffer, + hiddenPasswdBuffer, passwdBufferLen, &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); break; case Get_Name: - SlimDrawString8 (draw, &inputcolor, font, + SlimDrawString16(draw, &inputcolor, font, input_name_x, input_name_y, - NameBuffer, + nameBuffer, nameBufferLen, &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); break; @@ -510,35 +528,105 @@ ShowText(); } -void Panel::EraseLastChar(string &formerString) { +int Panel::FieldEraseLastChar(const uint16_t **buf, int *len) { + + static const uint16_t emptyBuf = 0; + int formerTextBufferLen = 0; + switch(field) { - case GET_NAME: - if (! NameBuffer.empty()) { - formerString=NameBuffer; - NameBuffer.erase(--NameBuffer.end()); + case Get_Name: + formerTextBufferLen = nameBufferLen; + if (nameBufferLen > 0) { + nameBufferLen--; } + *buf = nameBuffer; + *len = nameBufferLen; break; - case GET_PASSWD: - if (!PasswdBuffer.empty()) { - formerString=HiddenPasswdBuffer; - PasswdBuffer.erase(--PasswdBuffer.end()); - HiddenPasswdBuffer.erase(--HiddenPasswdBuffer.end()); + case Get_Passwd: + formerTextBufferLen = passwdBufferLen; + if (passwdBufferLen > 0) { + passwdBufferLen--; + passwdBuffer[passwdBufferLen] = 0; } + *buf = hiddenPasswdBuffer; + *len = passwdBufferLen; + break; + + default: + *buf = &emptyBuf; + *len = 0; break; } + return formerTextBufferLen; } +int Panel::FieldClear(const uint16_t **buf, int *len) { + + static const uint16_t emptyBuf = 0; + int formerTextBufferLen = 0; + + switch(field) { + case Get_Name: + formerTextBufferLen = nameBufferLen; + nameBufferLen = 0; + *buf = nameBuffer; + *len = nameBufferLen; + break; + + case Get_Passwd: + formerTextBufferLen = passwdBufferLen; + memset(passwdBuffer, 0, sizeof(passwdBuffer)); + passwdBufferLen = 0; + *buf = hiddenPasswdBuffer; + *len = passwdBufferLen; + break; + + default: + *buf = &emptyBuf; + *len = 0; + break; + } + return formerTextBufferLen; +} + +/* Check if the input character is allowed */ +bool Panel::isUtf16CharAllowed(uint16_t c) { + return ((0x020 <= c && c <= 0x07E) || (0x0A0 <= c && c != 0x0AD)); +} + +#define SIZE_BUFFER_KEY_PRESS 64 + bool Panel::OnKeyPress(XEvent& event) { - char ascii; + int formerTextBufferLen = -1; + int textBufferLen = -1; + const uint16_t *textBuffer = NULL; KeySym keysym; + int nbReadBuf = -1; + uint16_t utf16buf[SIZE_BUFFER_KEY_PRESS]; + if(displayIc) + { + Status status; + char databuf[SIZE_BUFFER_KEY_PRESS]; + nbReadBuf = Xutf8LookupString(displayIc, &event.xkey, databuf, + SIZE_BUFFER_KEY_PRESS, &keysym, &status); + if(nbReadBuf > 0) { + nbReadBuf = Util::utf8ToUtf16(databuf, nbReadBuf, + utf16buf, SIZE_BUFFER_KEY_PRESS); + } + } + else + { XComposeStatus compstatus; - int xx = 0; - int yy = 0; - string text; - string formerString = ""; + char databuf[SIZE_BUFFER_KEY_PRESS]; + nbReadBuf = XLookupString(&event.xkey, databuf, + SIZE_BUFFER_KEY_PRESS, &keysym, &compstatus); + if(nbReadBuf > 0) { + nbReadBuf = Util::utf8ToUtf16(databuf, nbReadBuf, + utf16buf, SIZE_BUFFER_KEY_PRESS); + } + } - XLookupString(&event.xkey, &ascii, 1, &keysym, &compstatus); switch(keysym){ case XK_F1: SwitchSession(); @@ -553,17 +641,17 @@ case XK_KP_Enter: if (field==Get_Name){ /* Don't allow an empty username */ - if (NameBuffer.empty()) return true; + if (nameBufferLen <= 0) return true; - if (NameBuffer==CONSOLE_STR){ + if (Util::utf16EqualToAscii(CONSOLE_STR, nameBuffer, nameBufferLen)) { action = Console; - } else if (NameBuffer==HALT_STR){ + } else if (Util::utf16EqualToAscii(HALT_STR, nameBuffer, nameBufferLen)) { action = Halt; - } else if (NameBuffer==REBOOT_STR){ + } else if (Util::utf16EqualToAscii(REBOOT_STR, nameBuffer, nameBufferLen)) { action = Reboot; - } else if (NameBuffer==SUSPEND_STR){ + } else if (Util::utf16EqualToAscii(SUSPEND_STR, nameBuffer, nameBufferLen)) { action = Suspend; - } else if (NameBuffer==EXIT_STR){ + } else if (Util::utf16EqualToAscii(EXIT_STR, nameBuffer, nameBufferLen)) { action = Exit; } else{ if (mode == Mode_DM) @@ -581,80 +669,80 @@ switch(keysym){ case XK_Delete: case XK_BackSpace: - EraseLastChar(formerString); + formerTextBufferLen = FieldEraseLastChar(&textBuffer, &textBufferLen); break; case XK_w: case XK_u: if (reinterpret_cast(event).state & ControlMask) { - switch(field) { - case Get_Passwd: - formerString = HiddenPasswdBuffer; - HiddenPasswdBuffer.clear(); - PasswdBuffer.clear(); - break; - case Get_Name: - formerString = NameBuffer; - NameBuffer.clear(); - break; - } + formerTextBufferLen = FieldClear(&textBuffer, &textBufferLen); break; } case XK_h: if (reinterpret_cast(event).state & ControlMask) { - EraseLastChar(formerString); + formerTextBufferLen = FieldEraseLastChar(&textBuffer, &textBufferLen); break; } /* Deliberate fall-through */ default: - if (isprint(ascii) && (keysym < XK_Shift_L || keysym > XK_Hyper_R)){ + if(nbReadBuf > 0) { switch(field) { - case GET_NAME: - formerString=NameBuffer; - if (NameBuffer.length() < INPUT_MAXLENGTH_NAME-1){ - NameBuffer.append(&ascii,1); - }; + case Get_Name: + formerTextBufferLen = nameBufferLen; + for(int i = 0; i < nbReadBuf && + nameBufferLen < INPUT_MAXLENGTH_NAME; i++) { + + if(isUtf16CharAllowed(utf16buf[i])) { + nameBuffer[nameBufferLen++] = utf16buf[i]; + } + } + textBuffer = nameBuffer; + textBufferLen = nameBufferLen; break; - case GET_PASSWD: - formerString=HiddenPasswdBuffer; - if (PasswdBuffer.length() < INPUT_MAXLENGTH_PASSWD-1){ - PasswdBuffer.append(&ascii,1); - HiddenPasswdBuffer.append("*"); - }; + + case Get_Passwd: + formerTextBufferLen = passwdBufferLen; + for(int i = 0; i < nbReadBuf && + passwdBufferLen < INPUT_MAXLENGTH_PASSWD; i++) { + + if(isUtf16CharAllowed(utf16buf[i])) { + passwdBuffer[passwdBufferLen] = utf16buf[i]; + hiddenPasswdBuffer[passwdBufferLen++] = (uint16_t)'*'; + } + } + textBuffer = hiddenPasswdBuffer; + textBufferLen = passwdBufferLen; break; - }; - }; + } + } break; }; - XGlyphInfo extents; - XftDraw *draw = XftDrawCreate(Dpy, Win, - DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); + int xx = 0, yy = 0; + if (formerTextBufferLen > 0 || textBufferLen > 0) { switch(field) { case Get_Name: - text = NameBuffer; xx = input_name_x; yy = input_name_y; break; case Get_Passwd: - text = HiddenPasswdBuffer; xx = input_pass_x; yy = input_pass_y; break; } + } - if (!formerString.empty()){ + if (formerTextBufferLen > 0) { + XGlyphInfo extents; const char* txth = "Wj"; /* get proper maximum height ? */ XftTextExtents8(Dpy, font, reinterpret_cast(txth), strlen(txth), &extents); int maxHeight = extents.height; - XftTextExtents8(Dpy, font, - reinterpret_cast(formerString.c_str()), - formerString.length(), &extents); + XftTextExtents16(Dpy, font, (XftChar16*)textBuffer, formerTextBufferLen, &extents); int maxLength = extents.width; if (mode == Mode_Lock) @@ -666,14 +754,15 @@ maxLength + 6, maxHeight + 6, false); } - if (!text.empty()) { - SlimDrawString8 (draw, &inputcolor, font, xx, yy, - text, - &inputshadowcolor, - inputShadowXOffset, inputShadowYOffset); + if(textBufferLen > 0) { + XftDraw *draw = XftDrawCreate(Dpy, Win, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); + if(draw != NULL) { + SlimDrawString16(draw, &inputcolor, font, xx, yy, textBuffer, textBufferLen, + &inputshadowcolor, inputShadowXOffset, inputShadowYOffset); + XftDrawDestroy(draw); + } } - XftDrawDestroy (draw); Cursor(SHOW); return true; } @@ -690,7 +779,7 @@ XftDraw *draw = XftDrawCreate(Dpy, Win, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); /* welcome message */ - XftTextExtents8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(), + XftTextExtentsUtf8(Dpy, welcomefont, (XftChar8*)welcome_message.c_str(), strlen(welcome_message.c_str()), &extents); cfgX = cfg->getOption("welcome_x"); cfgY = cfg->getOption("welcome_y"); @@ -700,9 +789,8 @@ welcome_x = Cfg::absolutepos(cfgX, image->Width(), extents.width); welcome_y = Cfg::absolutepos(cfgY, image->Height(), extents.height); if (welcome_x >= 0 && welcome_y >= 0) { - SlimDrawString8 (draw, &welcomecolor, welcomefont, - welcome_x, welcome_y, - welcome_message, + SlimDrawStringUtf8(draw, &welcomecolor, welcomefont, + welcome_x, welcome_y, welcome_message, &welcomeshadowcolor, shadowXOffset, shadowYOffset); } @@ -710,7 +798,7 @@ string msg; if ((!singleInputMode|| field == Get_Passwd) && mode == Mode_DM) { msg = cfg->getOption("password_msg"); - XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(), + XftTextExtentsUtf8(Dpy, enterfont, (XftChar8*)msg.c_str(), strlen(msg.c_str()), &extents); cfgX = cfg->getOption("password_x"); cfgY = cfg->getOption("password_y"); @@ -719,14 +807,14 @@ password_x = Cfg::absolutepos(cfgX, image->Width(), extents.width); password_y = Cfg::absolutepos(cfgY, image->Height(), extents.height); if (password_x >= 0 && password_y >= 0){ - SlimDrawString8 (draw, &entercolor, enterfont, password_x, password_y, + SlimDrawStringUtf8(draw, &entercolor, enterfont, password_x, password_y, msg, &entershadowcolor, shadowXOffset, shadowYOffset); } } if (!singleInputMode|| field == Get_Name) { msg = cfg->getOption("username_msg"); - XftTextExtents8(Dpy, enterfont, (XftChar8*)msg.c_str(), + XftTextExtentsUtf8(Dpy, enterfont, (XftChar8*)msg.c_str(), strlen(msg.c_str()), &extents); cfgX = cfg->getOption("username_x"); cfgY = cfg->getOption("username_y"); @@ -735,7 +823,7 @@ username_x = Cfg::absolutepos(cfgX, image->Width(), extents.width); username_y = Cfg::absolutepos(cfgY, image->Height(), extents.height); if (username_x >= 0 && username_y >= 0){ - SlimDrawString8 (draw, &entercolor, enterfont, username_x, username_y, + SlimDrawStringUtf8(draw, &entercolor, enterfont, username_x, username_y, msg, &entershadowcolor, shadowXOffset, shadowYOffset); } } @@ -776,7 +864,7 @@ XftDraw *draw = XftDrawCreate(Dpy, Root, DefaultVisual(Dpy, Scr), DefaultColormap(Dpy, Scr)); - XftTextExtents8(Dpy, sessionfont, reinterpret_cast(currsession.c_str()), + XftTextExtentsUtf8(Dpy, sessionfont, reinterpret_cast(currsession.c_str()), currsession.length(), &extents); msg_x = cfg->getOption("session_x"); msg_y = cfg->getOption("session_y"); @@ -785,16 +873,37 @@ int shadowXOffset = cfg->getIntOption("session_shadow_xoffset"); int shadowYOffset = cfg->getIntOption("session_shadow_yoffset"); - SlimDrawString8(draw, &sessioncolor, sessionfont, x, y, - currsession, - &sessionshadowcolor, - shadowXOffset, shadowYOffset); + SlimDrawStringUtf8(draw, &sessioncolor, sessionfont, x, y, + currsession, &sessionshadowcolor, shadowXOffset, shadowYOffset); XFlush(Dpy); XftDrawDestroy(draw); } +void Panel::SlimDrawString16(XftDraw *d, XftColor *color, XftFont *font, + int x, int y, const uint16_t *str, int strLen, + XftColor* shadowColor, int xOffset, int yOffset) +{ + int calc_x = 0; + int calc_y = 0; + if (mode == Mode_Lock) { + calc_x = viewport.x; + calc_y = viewport.y; + } -void Panel::SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font, + if (xOffset && yOffset) { + XftDrawString16(d, shadowColor, font, + x + xOffset + calc_x, + y + yOffset + calc_y, + (XftChar16*)str, strLen); + } + + XftDrawString16(d, color, font, + x + calc_x, + y + calc_y, + (XftChar16*)str, strLen); +} + +void Panel::SlimDrawStringUtf8(XftDraw *d, XftColor *color, XftFont *font, int x, int y, const string& str, XftColor* shadowColor, int xOffset, int yOffset) @@ -831,28 +940,31 @@ } void Panel::ResetName(void){ - NameBuffer.clear(); + nameBufferLen = 0; + memset(nameBuffer, 0, sizeof(nameBuffer)); } void Panel::ResetPasswd(void){ - PasswdBuffer.clear(); - HiddenPasswdBuffer.clear(); + passwdBufferLen = 0; + memset(passwdBuffer, 0, sizeof(passwdBuffer)); + memset(hiddenPasswdBuffer, 0, sizeof(hiddenPasswdBuffer)); } void Panel::SetName(const string& name){ - NameBuffer=name; + nameBufferLen = Util::utf8ToUtf16(name.c_str(), name.length(), + nameBuffer, INPUT_MAXLENGTH_NAME); if (mode == Mode_DM) action = Login; else action = Lock; } -const string& Panel::GetName(void) const{ - return NameBuffer; +const string Panel::GetName(void) const{ + return Util::utf16BufToUtf8String(nameBuffer, nameBufferLen); } -const string& Panel::GetPasswd(void) const{ - return PasswdBuffer; +const string Panel::GetPasswd(void) const{ + return Util::utf16BufToUtf8String(passwdBuffer, passwdBufferLen); } Rectangle Panel::GetPrimaryViewport() { diff -U 3 -b -B -d -r -- a/panel.h b/panel.h --- a/panel.h 2013-10-02 00:38:05.000000000 +0200 +++ b/panel.h 2014-02-23 17:32:44.154457995 +0100 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -86,20 +87,26 @@ void ResetName(void); void ResetPasswd(void); void SetName(const std::string &name); - const std::string& GetName(void) const; - const std::string& GetPasswd(void) const; + const std::string GetName(void) const; + const std::string GetPasswd(void) const; void SwitchSession(); private: Panel(); void Cursor(int visible); unsigned long GetColor(const char *colorname); void OnExpose(void); - void EraseLastChar(string &formerString); + int FieldEraseLastChar(const uint16_t **buf, int *len); + int FieldClear(const uint16_t **buf, int *len); bool OnKeyPress(XEvent& event); void ShowText(); void ShowSession(); - void SlimDrawString8(XftDraw *d, XftColor *color, XftFont *font, + static bool isUtf16CharAllowed(uint16_t c); + void SlimDrawString16(XftDraw *d, XftColor *color, XftFont *font, + int x, int y, const uint16_t *str, int strLen, + XftColor* shadowColor, int xOffset, int yOffset); + + void SlimDrawStringUtf8(XftDraw *d, XftColor *color, XftFont *font, int x, int y, const std::string &str, XftColor *shadowColor, int xOffset, int yOffset); @@ -136,12 +143,16 @@ XftColor entershadowcolor; ActionType action; FieldType field; + XIM displayIm; + XIC displayIc; //Pixmap background; /* Username/Password */ - std::string NameBuffer; - std::string PasswdBuffer; - std::string HiddenPasswdBuffer; + uint16_t nameBuffer[INPUT_MAXLENGTH_NAME + 1]; + int nameBufferLen; + uint16_t passwdBuffer[INPUT_MAXLENGTH_PASSWD + 1]; + int passwdBufferLen; + uint16_t hiddenPasswdBuffer[INPUT_MAXLENGTH_PASSWD + 1]; /* screen stuff */ Rectangle viewport; diff -U 3 -b -B -d -r -- a/switchuser.h b/switchuser.h --- a/switchuser.h 2013-10-02 00:38:05.000000000 +0200 +++ b/switchuser.h 2014-02-23 17:30:27.301129665 +0100 @@ -32,8 +32,6 @@ void Login(const char* cmd, const char* mcookie); private: - SwitchUser(); - void SetEnvironment(); void SetUserId(); void Execute(const char* cmd); void SetClientAuth(const char* mcookie); diff -U 3 -b -B -d -r -- a/util.cpp b/util.cpp --- a/util.cpp 2013-10-02 00:38:05.000000000 +0200 +++ b/util.cpp 2014-02-23 17:30:27.301129665 +0100 @@ -67,3 +67,162 @@ return pid + tm + (ts.tv_sec ^ ts.tv_nsec); } + +/* Given a UTF-8 encoded string pointed to by utf8 of length length in +bytes, returns the corresponding UTF-16 encoded string in the +buffer pointed to by utf16. The maximum number of UTF-16 encoding +units (i.e., Unit16s) allowed in the buffer is specified in +utf16_max_length. The return value is the number of UTF-16 +encoding units placed in the output buffer pointed to by utf16. + +In case of an error, -1 is returned, leaving some unusable partial +results in the output buffer. + +The caller must estimate the size of utf16 buffer by itself before +calling this function. Insufficient output buffer is considered as +an error, and once an error occured, this function doesn't give any +clue how large the result will be. + +The error cases include following: + +- Invalid byte sequences were in the input UTF-8 bytes. The caller + has no way to know what point in the input buffer was the + errornous byte. + +- The input contained a character (a valid UTF-8 byte sequence) + whose scalar value exceeded the range that UTF-16 can represent + (i.e., characters whose Unicode scalar value above 0x110000). + +- The output buffer has no enough space to hold entire utf16 data. + +Please note: + +- '\0'-termination is not assumed both on the input UTF-8 string + and on the output UTF-16 string; any legal zero byte in the input + UTF-8 string will be converted to a 16-bit zero in output. As a + side effect, the last UTF-16 encoding unit stored in the output + buffer will have a non-zero value if the input UTF-8 was not + '\0'-terminated. + +- UTF-8 aliases are *not* considered as an error. They are + converted to UTF-16. For example, 0xC0 0xA0, 0xE0 0x80 0xA0, + and 0xF0 0x80 0x80 0xA0 are all mapped to a single UTF-16 + encoding unit 0x0020. + +- Three byte UTF-8 sequences whose value corresponds to a surrogate + code or other reserved scalar value are not considered as an + error either. They may cause an invalid UTF-16 data (e.g., those + containing unpaired surrogates). + +*/ +int Util::utf8ToUtf16(const char *buf, const int utf8_length, uint16_t *utf16, const int utf16_max_length) { + + /* p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. */ + uint16_t *p = utf16; + const uint16_t *max_ptr = utf16 + utf16_max_length; + const unsigned char *utf8 = (const unsigned char *)buf; + + /* end_of_input points to the last byte of input as opposed to the next to the last byte. */ + unsigned char const *const end_of_input = utf8 + utf8_length - 1; + + while (utf8 <= end_of_input) { + const unsigned char c = *utf8; + if (p >= max_ptr) { + /* No more output space. */ + return -1; + } + if (c < 0x80) { + /* One byte ASCII. */ + *p++ = c; + utf8 += 1; + } else if (c < 0xC0) { + /* Follower byte without preceeding leader bytes. */ + return -1; + } else if (c < 0xE0) { + /* Two byte sequence. We need one follower byte. */ + if (end_of_input - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) { + return -1; + } + *p++ = (uint16_t)(0xCF80 + (c << 6) + utf8[1]); + utf8 += 2; + } else if (c < 0xF0) { + /* Three byte sequence. We need two follower byte. */ + if (end_of_input - utf8 < 2 || (((utf8[1] ^ 0x80) | (utf8[2] ^ 0x80)) & 0xC0)) { + return -1; + } + *p++ = (uint16_t)(0xDF80 + (c << 12) + (utf8[1] << 6) + utf8[2]); + utf8 += 3; + } else if (c < 0xF8) { + int plane; + /* Four byte sequence. We need three follower bytes. */ + if (end_of_input - utf8 < 3 || (((utf8[1] ^ 0x80) | (utf8[2] ^0x80) | (utf8[3] ^ 0x80)) & 0xC0)) { + return -1; + } + plane = (-0xC8 + (c << 2) + (utf8[1] >> 4)); + if (plane == 0) { + /* This four byte sequence is an alias that + corresponds to a Unicode scalar value in BMP. + It fits in an UTF-16 encoding unit. */ + *p++ = (uint16_t)(0xDF80 + (utf8[1] << 12) + (utf8[2] << 6) + utf8[3]); + } else if (plane <= 16) { + /* This is a legal four byte sequence that corresponds to a surrogate pair. */ + if (p + 1 >= max_ptr) { + /* No enough space on the output buffer for the pair. */ + return -1; + } + *p++ = (uint16_t)(0xE5B8 + (c << 8) + (utf8[1] << 2) + (utf8[2] >> 4)); + *p++ = (uint16_t)(0xDB80 + ((utf8[2] & 0x0F) << 6) + utf8[3]); + } else { + /* This four byte sequence is out of UTF-16 code space. */ + return -1; + } + utf8 += 4; + } else { + /* Longer sequence or unused byte. */ + return -1; + } + } + return p - utf16; +} + +/* Compare an ASCII string with an UTF-16 string */ +bool Util::utf16EqualToAscii(const char *ascii, uint16_t *utf16, int utf16Len) { + + while(*ascii != 0 && utf16Len > 0) { + if(*utf16++ != (uint16_t)*ascii++) { + return false; + } + utf16Len--; + } + return *ascii == 0 && utf16Len == 0; +} + +std::string Util::utf16BufToUtf8String(const uint16_t *utf16Buf, int utf16Len) { + + std::string outStr; + outStr.reserve(utf16Len * 2); + + while(*utf16Buf != 0 && utf16Len > 0) { + + const uint16_t c16 = *utf16Buf++; + if (c16 <= 0x007F) { + outStr.push_back((char)c16); + } + else if (c16 <= 0x07FF) { + unsigned char c = 0xC0 | ((unsigned char)(c16 >> 6)); + outStr.push_back(c); + c = 0x80 | ((unsigned char)(c16 & 0x003F)); + outStr.push_back(c); + } + else { + unsigned char c = 0xE0 | ((unsigned char)(c16 >> 12)); + outStr.push_back(c); + c = 0x80 | ((unsigned char)((c16 >> 6) & 0x003F)); + outStr.push_back(c); + c = 0x80 | ((unsigned char)(c16 & 0x003F)); + outStr.push_back(c); + } + utf16Len--; + } + return outStr; +} diff -U 3 -b -B -d -r -- a/util.h b/util.h --- a/util.h 2013-10-02 00:38:05.000000000 +0200 +++ b/util.h 2014-02-23 17:32:32.471125088 +0100 @@ -10,6 +10,7 @@ #define _UTIL_H__ #include +#include namespace Util { bool add_mcookie(const std::string &mcookie, const char *display, @@ -19,6 +20,10 @@ long random(void); long makeseed(void); + int utf8ToUtf16(const char *utf8, const int utf8_length, + uint16_t *utf16, const int utf16_max_length); + bool utf16EqualToAscii(const char *ascii, uint16_t *utf16, int utf16Len); + std::string utf16BufToUtf8String(const uint16_t *utf16Buf, int utf16Len); } #endif /* _UTIL_H__ */