Cleanup utf8 decoding/encoding

This commit is contained in:
UnknownShadow200 2018-10-26 22:51:26 +11:00
parent 45b4af80af
commit 375f1a70b1
11 changed files with 137 additions and 121 deletions

View File

@ -198,7 +198,7 @@ static void Window_UpdateWindowState(void) {
break;
}
Event_RaiseVoid(&WindowEvents_WindowStateChanged);
Event_RaiseVoid(&WindowEvents_StateChanged);
Window_UpdateSize();
Event_RaiseVoid(&WindowEvents_Resized);
}

View File

@ -120,7 +120,7 @@ struct Event_Void WindowEvents_Closing; /* Window is about to close *
struct Event_Void WindowEvents_Closed; /* Window has closed */
struct Event_Void WindowEvents_VisibilityChanged; /* Visibility of the window changed */
struct Event_Void WindowEvents_FocusChanged; /* Focus of the window changed */
struct Event_Void WindowEvents_WindowStateChanged; /* WindowState of the window changed */
struct Event_Void WindowEvents_StateChanged; /* WindowState of the window changed */
struct Event_Int KeyEvents_Press; /* Raised when a character is typed. Arg is a character */
struct Event_Int KeyEvents_Down; /* Raised when a key is pressed. Arg is a member of Key enumeration */

View File

@ -822,12 +822,12 @@ ReturnCode Dat_Load(struct Stream* stream) {
static int Cw_WriteEndString(uint8_t* data, const String* text) {
Codepoint cp;
uint8_t* cur = data + 2;
int i, bytes, len = 0;
int i, wrote, len = 0;
for (i = 0; i < text->length; i++) {
cp = Convert_CP437ToUnicode(text->buffer[i]);
bytes = Stream_WriteUtf8(cur, cp);
len += bytes; cur += bytes;
wrote = Convert_UnicodeToUtf8(cp, cur);
len += wrote; cur += wrote;
}
Stream_SetU16_BE(data, len);

View File

@ -561,7 +561,7 @@ void Window_ProcessEvents(void) {
case PropertyNotify:
if (e.xproperty.atom == net_wm_state) {
Event_RaiseVoid(&WindowEvents_WindowStateChanged);
Event_RaiseVoid(&WindowEvents_StateChanged);
}
/*if (e.xproperty.atom == net_frame_extents) {
@ -608,9 +608,9 @@ void Window_ProcessEvents(void) {
int i, len = 0;
for (i = 0; i < clipboard_copy_text.length; i++) {
Codepoint cp = Convert_CP437ToUnicode(clipboard_copy_text.buffer[i]);
uint8_t* cur = data + len;
len += Stream_WriteUtf8(cur, cp);
uint8_t* cur = data + len;
Codepoint cp = Convert_CP437ToUnicode(clipboard_copy_text.buffer[i]);
len += Convert_UnicodeToUtf8(cp, cur);
}
XChangeProperty(win_display, reply.xselection.requestor, reply.xselection.property, xa_utf8_string, 8,

View File

@ -1804,15 +1804,18 @@ int Platform_GetCommandLineArgs(int argc, STRING_REF const char** argv, String*
#ifdef CC_BUILD_POSIX
int Platform_ConvertString(void* data, const String* src) {
uint8_t* dst = data;
uint8_t* cur;
Codepoint cp;
int i, len;
int i, len = 0;
if (src->length > FILENAME_SIZE) ErrorHandler_Fail("String too long to expand");
for (i = 0; i < src->length; i++) {
cp = Convert_CP437ToUnicode(src->buffer[i]);
len = Stream_WriteUtf8(dst, cp); dst += len;
cur = data + len;
cp = Convert_CP437ToUnicode(src->buffer[i]);
len += Convert_UnicodeToUtf8(cp, cur);
}
*dst = '\0';
dst[len] = '\0';
return len;
}

View File

@ -50,13 +50,13 @@ void GraphicsMode_MakeDefault(struct GraphicsMode* m);
/* NOTE: Only useful for platform specific function calls - do NOT try to interpret the data.
Returns the number of bytes written, excluding trailing NULL terminator. */
NOINLINE_ int Platform_ConvertString(void* data, const String* src);
/* Initalises the platform specific state */
/* Initalises the platform specific state. */
void Platform_Init(void);
/* Frees the platform specific state */
/* Frees the platform specific state. */
void Platform_Free(void);
/* Sets current directory to directory executable is in */
/* Sets current directory to the directory the executable is in. */
void Platform_SetWorkingDir(void);
/* Exits the process with the given return code */
/* Exits the process with the given return code .*/
void Platform_Exit(ReturnCode code);
/* Gets the command line arguments passed to the program. */
int Platform_GetCommandLineArgs(int argc, STRING_REF const char** argv, String* args);

View File

@ -380,45 +380,25 @@ ReturnCode Stream_ReadU32_BE(struct Stream* s, uint32_t* value) {
/*########################################################################################################################*
*--------------------------------------------------Read/Write strings-----------------------------------------------------*
*#########################################################################################################################*/
ReturnCode Stream_ReadUtf8(struct Stream* s, Codepoint* cp) {
uint8_t data;
ReturnCode res = s->ReadU8(s, &data);
if (res) return res;
/* Header byte is just the raw codepoint (common case) */
if (data <= 0x7F) { *cp = data; return 0; }
/* Header byte encodes variable number of following bytes */
/* The remaining bits of the header form first part of the character */
int byteCount = 0, i;
for (i = 7; i >= 0; i--) {
if (data & (1 << i)) {
byteCount++;
data &= (uint8_t)~(1 << i);
} else {
break;
}
}
*cp = data;
for (i = 0; i < byteCount - 1; i++) {
if ((res = s->ReadU8(s, &data))) return res;
*cp <<= 6;
/* Top two bits of each are always 10 */
*cp |= (Codepoint)(data & 0x3F);
}
return 0;
}
ReturnCode Stream_ReadLine(struct Stream* s, String* text) {
bool readAny = false;
Codepoint cp;
ReturnCode res;
text->length = 0;
for (;;) {
res = Stream_ReadUtf8(s, &cp);
uint8_t tmp[8];
uint32_t len;
text->length = 0;
for (;;) {
len = 0;
/* Read a UTF8 character from the stream */
/* (in most cases it's just one byte) */
do {
if ((res = s->ReadU8(s, &tmp[len]))) break;
len++;
} while (!Convert_Utf8ToUnicode(&cp, tmp, len));
if (res == ERR_END_OF_STREAM) break;
if (res) return res;
@ -431,22 +411,6 @@ ReturnCode Stream_ReadLine(struct Stream* s, String* text) {
return readAny ? 0 : ERR_END_OF_STREAM;
}
int Stream_WriteUtf8(uint8_t* buffer, Codepoint cp) {
if (cp <= 0x7F) {
buffer[0] = (uint8_t)cp;
return 1;
} else if (cp <= 0x7FF) {
buffer[0] = 0xC0 | ((cp >> 6) & 0x1F);
buffer[1] = 0x80 | ((cp) & 0x3F);
return 2;
} else {
buffer[0] = 0xE0 | ((cp >> 12) & 0x0F);
buffer[1] = 0x80 | ((cp >> 6) & 0x3F);
buffer[2] = 0x80 | ((cp) & 0x3F);
return 3;
}
}
ReturnCode Stream_WriteLine(struct Stream* s, String* text) {
uint8_t buffer[2048 + 10]; /* some space for newline */
uint8_t* cur;
@ -463,7 +427,7 @@ ReturnCode Stream_WriteLine(struct Stream* s, String* text) {
cur = buffer + len;
cp = Convert_CP437ToUnicode(text->buffer[i]);
len += Stream_WriteUtf8(cur, cp);
len += Convert_UnicodeToUtf8(cp, cur);
}
cur = Platform_NewLine;

View File

@ -85,13 +85,9 @@ ReturnCode Stream_ReadU32_LE(struct Stream* s, uint32_t* value);
/* Reads a big-endian 32 bit unsigned integer from the stream. */
ReturnCode Stream_ReadU32_BE(struct Stream* s, uint32_t* value);
/* Reads a UTF8 encoded character from the stream. */
ReturnCode Stream_ReadUtf8(struct Stream* s, Codepoint* cp);
/* Reads a line of UTF8 encoded character from the stream. */
/* NOTE: Reads one byte at a time. May want to use Stream_ReadonlyBuffered. */
ReturnCode Stream_ReadLine(struct Stream* s, String* text);
/* Writes a UTF8 encoded character to the stream. */
int Stream_WriteUtf8(uint8_t* buffer, Codepoint cp);
/* Writes a line of UTF8 encoded text to the stream. */
ReturnCode Stream_WriteLine(struct Stream* s, String* text);
#endif

View File

@ -481,7 +481,7 @@ void String_Format4(String* str, const char* format, const void* a1, const void*
/*########################################################################################################################*
*-------------------------------------------------------Conversions-------------------------------------------------------*
*------------------------------------------------Character set conversions------------------------------------------------*
*#########################################################################################################################*/
Codepoint Convert_ControlChars[32] = {
0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
@ -536,16 +536,64 @@ bool Convert_TryUnicodeToCP437(Codepoint cp, char* c) {
void String_DecodeUtf8(String* str, uint8_t* data, uint32_t len) {
Codepoint cp;
struct Stream mem;
Stream_ReadonlyMemory(&mem, data, len);
int read;
while (len) {
read = Convert_Utf8ToUnicode(&cp, data, len);
if (!read) break;
while (mem.Meta.Mem.Left) {
ReturnCode res = Stream_ReadUtf8(&mem, &cp);
if (res) break; /* Memory read only returns ERR_END_OF_STREAM */
String_Append(str, Convert_UnicodeToCP437(cp));
data += read; len -= read;
}
}
int Convert_Utf8ToUnicode(Codepoint* cp, const uint8_t* data, uint32_t len) {
*cp = '\0';
if (!len) return 0;
if (data[0] <= 0x7F) {
*cp = data[0];
return 1;
} else if ((data[0] & 0xE0) == 0xC0) {
if (len < 2) return 0;
*cp = ((data[0] & 0x1F) << 6) | ((data[1] & 0x3F));
return 2;
} else if ((data[0] & 0xF0) == 0xE0) {
if (len < 3) return 0;
*cp = ((data[0] & 0x0F) << 12) | ((data[1] & 0x3F) << 6)
| ((data[2] & 0x3F));
return 3;
} else {
if (len < 4) return 0;
*cp = ((data[0] & 0x07) << 18) | ((data[1] & 0x3F) << 12)
| ((data[2] & 0x3F) << 6) | (data[3] & 0x3F);
return 4;
}
}
int Convert_UnicodeToUtf8(Codepoint cp, uint8_t* data) {
if (cp <= 0x7F) {
data[0] = (uint8_t)cp;
return 1;
} else if (cp <= 0x7FF) {
data[0] = 0xC0 | ((cp >> 6) & 0x1F);
data[1] = 0x80 | ((cp) & 0x3F);
return 2;
} else {
data[0] = 0xE0 | ((cp >> 12) & 0x0F);
data[1] = 0x80 | ((cp >> 6) & 0x3F);
data[2] = 0x80 | ((cp) & 0x3F);
return 3;
}
}
/*########################################################################################################################*
*--------------------------------------------------Numerical conversions--------------------------------------------------*
*#########################################################################################################################*/
bool Convert_TryParseUInt8(const String* str, uint8_t* value) {
int tmp;
*value = 0;

View File

@ -153,6 +153,11 @@ char Convert_UnicodeToCP437(Codepoint cp);
bool Convert_TryUnicodeToCP437(Codepoint cp, char* c);
/* Appends all characters from UTF8 encoded data to the given string. */
void String_DecodeUtf8(String* str, uint8_t* data, uint32_t len);
/* Decodes a unicode character from UTF8, returning number of bytes read. */
/* Returns 0 if not enough input data to read the character. */
int Convert_Utf8ToUnicode(Codepoint* cp, const uint8_t* data, uint32_t len);
/* Encodes a unicode character in UTF8, returning number of bytes written. */
int Convert_UnicodeToUtf8(Codepoint cp, uint8_t* data);
/* Attempts to convert the given string into an unsigned 8 bit integer. */
NOINLINE_ bool Convert_TryParseUInt8(const String* str, uint8_t* value);

View File

@ -19,10 +19,10 @@
#define Rect_Width(rect) (rect.right - rect.left)
#define Rect_Height(rect) (rect.bottom - rect.top)
HINSTANCE win_Instance;
HWND win_Handle;
HINSTANCE win_instance;
HWND win_handle;
HDC win_DC;
int win_State = WINDOW_STATE_NORMAL;
int win_state;
bool invisible_since_creation; /* Set by WindowsMessage.CREATE and consumed by Visible = true (calls BringWindowToFront) */
int suppress_resize; /* Used in WindowBorder and WindowState in order to avoid rapid, consecutive resize events */
Rect2D prev_bounds; /* Used to restore previous size when leaving fullscreen mode */
@ -98,7 +98,7 @@ static Key Window_MapKey(WPARAM key) {
static void Window_Destroy(void) {
if (!Window_Exists) return;
DestroyWindow(win_Handle);
DestroyWindow(win_handle);
Window_Exists = false;
}
@ -120,7 +120,7 @@ static void Window_DoSetHiddenBorder(bool value) {
/* To ensure maximized/minimized windows work correctly, reset state to normal,
change the border, then go back to maximized/minimized. */
int state = win_State;
int state = win_state;
Window_ResetWindowState();
DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
style |= (value ? WS_POPUP : WS_OVERLAPPEDWINDOW);
@ -135,8 +135,8 @@ static void Window_DoSetHiddenBorder(bool value) {
/* This avoids leaving garbage on the background window. */
if (was_visible) Window_SetVisible(false);
SetWindowLongW(win_Handle, GWL_STYLE, style);
SetWindowPos(win_Handle, NULL, 0, 0, Rect_Width(rect), Rect_Height(rect),
SetWindowLongW(win_handle, GWL_STYLE, style);
SetWindowPos(win_handle, NULL, 0, 0, Rect_Width(rect), Rect_Height(rect),
SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
/* Force window to redraw update its borders, but only if it's
@ -185,7 +185,7 @@ static LRESULT CALLBACK Window_Procedure(HWND handle, UINT message, WPARAM wPara
case WM_WINDOWPOSCHANGED:
{
WINDOWPOS* pos = (WINDOWPOS*)lParam;
if (pos->hwnd != win_Handle) break;
if (pos->hwnd != win_handle) break;
if (pos->x != Window_Bounds.X || pos->y != Window_Bounds.Y) {
Window_Bounds.X = pos->x; Window_Bounds.Y = pos->y;
@ -196,7 +196,7 @@ static LRESULT CALLBACK Window_Procedure(HWND handle, UINT message, WPARAM wPara
Window_Bounds.Width = pos->cx; Window_Bounds.Height = pos->cy;
Window_UpdateClientSize(handle);
SetWindowPos(win_Handle, NULL,
SetWindowPos(win_handle, NULL,
Window_Bounds.X, Window_Bounds.Y, Window_Bounds.Width, Window_Bounds.Height,
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
@ -219,16 +219,16 @@ static LRESULT CALLBACK Window_Procedure(HWND handle, UINT message, WPARAM wPara
case WM_SIZE:
{
int new_state = win_State;
int new_state = win_state;
switch (wParam) {
case SIZE_RESTORED: new_state = WINDOW_STATE_NORMAL; break;
case SIZE_MINIMIZED: new_state = WINDOW_STATE_MINIMISED; break;
case SIZE_MAXIMIZED: new_state = win_hiddenBorder ? WINDOW_STATE_FULLSCREEN : WINDOW_STATE_MAXIMISED; break;
}
if (new_state != win_State) {
win_State = new_state;
Event_RaiseVoid(&WindowEvents_WindowStateChanged);
if (new_state != win_state) {
win_state = new_state;
Event_RaiseVoid(&WindowEvents_StateChanged);
}
} break;
@ -375,8 +375,8 @@ static LRESULT CALLBACK Window_Procedure(HWND handle, UINT message, WPARAM wPara
case WM_DESTROY:
Window_Exists = false;
UnregisterClassW(win_ClassName, win_Instance);
if (win_DC) ReleaseDC(win_Handle, win_DC);
UnregisterClassW(win_ClassName, win_instance);
if (win_DC) ReleaseDC(win_handle, win_DC);
Event_RaiseVoid(&WindowEvents_Closed);
break;
}
@ -388,7 +388,7 @@ static LRESULT CALLBACK Window_Procedure(HWND handle, UINT message, WPARAM wPara
*--------------------------------------------------Public implementation--------------------------------------------------*
*#########################################################################################################################*/
void Window_Create(int x, int y, int width, int height, struct GraphicsMode* mode) {
win_Instance = GetModuleHandleW(NULL);
win_instance = GetModuleHandleW(NULL);
/* TODO: UngroupFromTaskbar(); */
/* Find out the final window rectangle, after the WM has added its chrome (titlebar, sidebars etc). */
@ -398,7 +398,7 @@ void Window_Create(int x, int y, int width, int height, struct GraphicsMode* mod
WNDCLASSEXW wc = { 0 };
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = CS_OWNDC;
wc.hInstance = win_Instance;
wc.hInstance = win_instance;
wc.lpfnWndProc = Window_Procedure;
wc.lpszClassName = win_ClassName;
/* TODO: Set window icons here */
@ -407,12 +407,12 @@ void Window_Create(int x, int y, int width, int height, struct GraphicsMode* mod
ATOM atom = RegisterClassExW(&wc);
if (!atom) ErrorHandler_Fail2(GetLastError(), "Failed to register window class");
win_Handle = CreateWindowExW(0, atom, NULL, win_Style,
win_handle = CreateWindowExW(0, atom, NULL, win_Style,
rect.left, rect.top, Rect_Width(rect), Rect_Height(rect),
NULL, NULL, win_Instance, NULL);
if (!win_Handle) ErrorHandler_Fail2(GetLastError(), "Failed to create window");
NULL, NULL, win_instance, NULL);
if (!win_handle) ErrorHandler_Fail2(GetLastError(), "Failed to create window");
win_DC = GetDC(win_Handle);
win_DC = GetDC(win_handle);
if (!win_DC) ErrorHandler_Fail2(GetLastError(), "Failed to get device context");
Window_Exists = true;
}
@ -420,7 +420,7 @@ void Window_Create(int x, int y, int width, int height, struct GraphicsMode* mod
void Window_SetTitle(const String* title) {
WCHAR str[300];
Platform_ConvertString(str, title);
SetWindowTextW(win_Handle, str);
SetWindowTextW(win_handle, str);
}
void Window_GetClipboardText(String* value) {
@ -429,7 +429,7 @@ void Window_GetClipboardText(String* value) {
value->length = 0;
for (i = 0; i < 10; i++) {
if (!OpenClipboard(win_Handle)) {
if (!OpenClipboard(win_handle)) {
Thread_Sleep(100);
continue;
}
@ -466,7 +466,7 @@ void Window_SetClipboardText(const String* value) {
/* retry up to 10 times */
int i;
for (i = 0; i < 10; i++) {
if (!OpenClipboard(win_Handle)) {
if (!OpenClipboard(win_handle)) {
Thread_Sleep(100);
continue;
}
@ -491,48 +491,48 @@ void Window_SetClipboardText(const String* value) {
void Window_SetBounds(Rect2D rect) {
/* Note: the bounds variable is updated when the resize/move message arrives.*/
SetWindowPos(win_Handle, NULL, rect.X, rect.Y, rect.Width, rect.Height, 0);
SetWindowPos(win_handle, NULL, rect.X, rect.Y, rect.Width, rect.Height, 0);
}
void Window_SetLocation(int x, int y) {
SetWindowPos(win_Handle, NULL, x, y, 0, 0, SWP_NOSIZE);
SetWindowPos(win_handle, NULL, x, y, 0, 0, SWP_NOSIZE);
}
void Window_SetSize(int width, int height) {
SetWindowPos(win_Handle, NULL, 0, 0, width, height, SWP_NOMOVE);
SetWindowPos(win_handle, NULL, 0, 0, width, height, SWP_NOMOVE);
}
void Window_SetClientSize(int width, int height) {
DWORD style = GetWindowLongW(win_Handle, GWL_STYLE);
DWORD style = GetWindowLongW(win_handle, GWL_STYLE);
RECT rect = { 0, 0, width, height };
AdjustWindowRect(&rect, style, false);
Window_SetSize(Rect_Width(rect), Rect_Height(rect));
}
void* Window_GetWindowHandle(void) { return win_Handle; }
void* Window_GetWindowHandle(void) { return win_handle; }
bool Window_GetVisible(void) { return IsWindowVisible(win_Handle); }
bool Window_GetVisible(void) { return IsWindowVisible(win_handle); }
void Window_SetVisible(bool visible) {
if (visible) {
ShowWindow(win_Handle, SW_SHOW);
ShowWindow(win_handle, SW_SHOW);
if (invisible_since_creation) {
BringWindowToTop(win_Handle);
SetForegroundWindow(win_Handle);
BringWindowToTop(win_handle);
SetForegroundWindow(win_handle);
}
} else {
ShowWindow(win_Handle, SW_HIDE);
ShowWindow(win_handle, SW_HIDE);
}
}
void Window_Close(void) {
PostMessageW(win_Handle, WM_CLOSE, 0, 0);
PostMessageW(win_handle, WM_CLOSE, 0, 0);
}
int Window_GetWindowState(void) { return win_State; }
int Window_GetWindowState(void) { return win_state; }
void Window_SetWindowState(int state) {
if (win_State == state) return;
if (win_state == state) return;
DWORD command = 0;
bool exiting_fullscreen = false;
@ -542,7 +542,7 @@ void Window_SetWindowState(int state) {
command = SW_RESTORE;
/* If we are leaving fullscreen mode we need to restore the border. */
if (win_State == WINDOW_STATE_FULLSCREEN)
if (win_state == WINDOW_STATE_FULLSCREEN)
exiting_fullscreen = true;
break;
@ -567,11 +567,11 @@ void Window_SetWindowState(int state) {
Window_SetHiddenBorder(true);
command = SW_MAXIMIZE;
SetForegroundWindow(win_Handle);
SetForegroundWindow(win_handle);
break;
}
if (command != 0) ShowWindow(win_Handle, command);
if (command != 0) ShowWindow(win_handle, command);
/* Restore previous window border or apply pending border change when leaving fullscreen mode. */
if (exiting_fullscreen) Window_SetHiddenBorder(false);
@ -585,7 +585,7 @@ void Window_SetWindowState(int state) {
Point2D Window_PointToClient(int x, int y) {
Point2D point = { x, y };
if (!ScreenToClient(win_Handle, &point)) {
if (!ScreenToClient(win_handle, &point)) {
ErrorHandler_Fail2(GetLastError(), "Converting point from client to screen coordinates");
}
return point;
@ -593,7 +593,7 @@ Point2D Window_PointToClient(int x, int y) {
Point2D Window_PointToScreen(int x, int y) {
Point2D point = { x, y };
if (!ClientToScreen(win_Handle, &point)) {
if (!ClientToScreen(win_handle, &point)) {
ErrorHandler_Fail2(GetLastError(), "Converting point from screen to client coordinates");
}
return point;
@ -608,7 +608,7 @@ void Window_ProcessEvents(void) {
HWND foreground = GetForegroundWindow();
if (foreground) {
Window_Focused = foreground == win_Handle;
Window_Focused = foreground == win_handle;
}
}