diff --git a/sc2/src/msvc++/UrQuanMasters.dsp b/sc2/src/msvc++/UrQuanMasters.dsp index 23ff633c7..b337080a4 100644 --- a/sc2/src/msvc++/UrQuanMasters.dsp +++ b/sc2/src/msvc++/UrQuanMasters.dsp @@ -743,6 +743,10 @@ SOURCE=..\sc2code\libs\strings\strings.c SOURCE=..\sc2code\libs\strings\strintrn.h # End Source File +# Begin Source File + +SOURCE=..\sc2code\libs\strings\unicode.c +# End Source File # End Group # Begin Group "video" diff --git a/sc2/src/sc2code/comm.c b/sc2/src/sc2code/comm.c index 3277ad039..bba8ace80 100644 --- a/sc2/src/sc2code/comm.c +++ b/sc2/src/sc2code/comm.c @@ -188,8 +188,8 @@ add_text (int status, PTEXT pTextIn) TEXT locText; PTEXT pText; SIZE leading; - UNICODE ch; - const UNICODE *pStr; + wchar_t ch; + const unsigned char *pStr; SIZE text_width; int num_lines = 0; static COORD last_baseline; @@ -238,13 +238,16 @@ add_text (int status, PTEXT pTextIn) switch (status) { case -3: - SetContextForeGroundColor (BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x14), 0x01)); + SetContextForeGroundColor ( + BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x14), 0x01)); break; case -2: - SetContextForeGroundColor (BUILD_COLOR (MAKE_RGB15 (0x00, 0x14, 0x14), 0x03)); + SetContextForeGroundColor ( + BUILD_COLOR (MAKE_RGB15 (0x00, 0x14, 0x14), 0x03)); break; case -1: - SetContextForeGroundColor (BUILD_COLOR (MAKE_RGB15 (0x1A, 0x1A, 0x1A), 0x12)); + SetContextForeGroundColor ( + BUILD_COLOR (MAKE_RGB15 (0x1A, 0x1A, 0x1A), 0x12)); break; } @@ -252,8 +255,7 @@ add_text (int status, PTEXT pTextIn) locText = *pTextIn; locText.baseline.x -= 8; locText.CharCount = 1; - ch = '*'; - locText.pStr = &ch; + locText.pStr = "*"; font_DrawText (&locText); locText = *pTextIn; @@ -264,7 +266,8 @@ add_text (int status, PTEXT pTextIn) numchars = 0; pStr = pText->pStr; - if (status > 0 && (CommData.AlienTextTemplate.valign & (VALIGN_MIDDLE|VALIGN_BOTTOM))) { + if (status > 0 && (CommData.AlienTextTemplate.valign & ( + VALIGN_MIDDLE|VALIGN_BOTTOM))) { num_lines = _count_lines(pText); if (CommData.AlienTextTemplate.valign == VALIGN_BOTTOM) pText->baseline.y -= (leading * num_lines); @@ -276,38 +279,55 @@ add_text (int status, PTEXT pTextIn) do { pText->pStr = pStr; - pText->CharCount = 1; pText->baseline.y += leading; { BOOLEAN eot; RECT r, old_r; - COUNT OldCount; + COUNT oldCount; + const unsigned char *oldPStr; + wchar_t oldCh; + COUNT charCount; GetContextClipRect (&r); - eot = FALSE; - do + oldCount = 1; + charCount = 0; + ch = '\0'; + for (;;) { old_r = r; - OldCount = pText->CharCount; - while (!(eot = (BOOLEAN)( - (ch = *++pStr) == '\0' - || ch == '\n' - || ch == '\r' - || (COUNT)(pStr - pText->pStr) >= maxchars - )) && ch != ' ') - ; - pText->CharCount = pStr - pText->pStr; + oldPStr = pStr; + oldCh = ch; + + for (;;) + { + ch = getCharFromString (&pStr); + eot = ch == '\0' || ch == '\n' || ch == '\r' + || charCount >= maxchars; + if (eot || ch == ' ') + break; + charCount++; + } + + oldCount = pText->CharCount; + pText->CharCount = charCount; TextRect (pText, &r, NULL_PTR); - } while (!eot && r.extent.width < text_width); + if (eot || r.extent.width >= text_width) + break; + charCount++; + // For the space in between words. + } if (r.extent.width >= text_width) { - pText->CharCount = OldCount; + pText->CharCount = oldCount; + pStr = oldPStr; r = old_r; + ch = oldCh; } - if (maxchars -= pText->CharCount) + maxchars -= pText->CharCount; + if (maxchars != 0) --maxchars; numchars += pText->CharCount; @@ -316,8 +336,7 @@ add_text (int status, PTEXT pTextIn) if (pText->baseline.y < SIS_SCREEN_HEIGHT) font_DrawText (pText); - pStr = pText->pStr + pText->CharCount; - if(status < -4 && pText->baseline.y >= -status - 10) + if (status < -4 && pText->baseline.y >= -status - 10) { ++pStr; break; @@ -346,11 +365,9 @@ add_text (int status, PTEXT pTextIn) --pText->baseline.y; font_DrawText (pText); - - pStr = pText->pStr + pText->CharCount; } } - } while ((ch = *pStr++) != '\0' && ch != '\n' && ch != '\r' && maxchars); + } while (ch != '\0' && ch != '\n' && ch != '\r' && maxchars); pText->pStr = pStr; if (status == 1) @@ -363,7 +380,8 @@ add_text (int status, PTEXT pTextIn) // restores background TFB_DrawScreen_Copy (&r, TFB_SCREEN_EXTRA, TFB_SCREEN_MAIN); // draws cached subtitle - TFB_DrawScreen_Image (subtitle_cache, r.corner.x, r.corner.y, 0, 0, TFB_SCREEN_MAIN); + TFB_DrawScreen_Image (subtitle_cache, r.corner.x, r.corner.y, 0, 0, + TFB_SCREEN_MAIN); last_baseline = pText->baseline.y; } diff --git a/sc2/src/sc2code/libs/graphics/font.c b/sc2/src/sc2code/libs/graphics/font.c index 9defcad18..c0187a7f5 100644 --- a/sc2/src/sc2code/libs/graphics/font.c +++ b/sc2/src/sc2code/libs/graphics/font.c @@ -22,7 +22,6 @@ extern FRAME Build_Font_Effect (FRAME FramePtr, DWORD from, DWORD to, BYTE type); -static wchar_t getNextChar(const unsigned char **ptr); static inline FRAME_DESC *getCharFrame (FONT_DESC *fontPtr, wchar_t ch); static BYTE char_delta_array[MAX_DELTAS]; @@ -134,28 +133,37 @@ GetContextFontLeading (PSIZE pheight) BOOLEAN TextRect (PTEXT lpText, PRECT pRect, PBYTE pdelta) { - COUNT num_chars; FONTPTR FontPtr; - if ((FontPtr = _CurFontPtr) != 0 && (num_chars = lpText->CharCount)) + FontPtr = _CurFontPtr; + if (FontPtr != 0 && lpText->CharCount != 0) { COORD top_y, bot_y; SIZE width; wchar_t next_ch; const unsigned char *pStr; - + COUNT num_chars; + + num_chars = lpText->CharCount; + /* At this point lpText->CharCount contains the *maximum* number of + * characters that lpText->pStr may contain. + * After the while loop below, it will contain the actual number. + */ if (pdelta == 0) { pdelta = char_delta_array; if (num_chars > MAX_DELTAS) + { num_chars = MAX_DELTAS; + lpText->CharCount = MAX_DELTAS; + } } top_y = 0; bot_y = 0; width = 0; pStr = lpText->pStr; - next_ch = getNextChar (&pStr); + next_ch = getCharFromString (&pStr); if (next_ch == '\0') num_chars = 0; while (num_chars--) @@ -167,9 +175,12 @@ TextRect (PTEXT lpText, PRECT pRect, PBYTE pdelta) last_width = width; ch = next_ch; - next_ch = getNextChar (&pStr); + next_ch = getCharFromString (&pStr); if (next_ch == '\0') + { + lpText->CharCount -= num_chars; num_chars = 0; + } charFrame = getCharFrame (FontPtr, ch); if (charFrame != NULL && GetFrameWidth (charFrame)) @@ -195,8 +206,6 @@ TextRect (PTEXT lpText, PRECT pRect, PBYTE pdelta) *pdelta++ = (BYTE)(width - last_width); } - lpText->CharCount = pStr - lpText->pStr - 1; - if (width > 0 && (bot_y -= top_y) > 0) { /* subtract off default character spacing */ @@ -258,7 +267,7 @@ _text_blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr) num_chars = TextPtr->CharCount; pStr = TextPtr->pStr; - next_ch = getNextChar (&pStr); + next_ch = getCharFromString (&pStr); if (next_ch == '\0') num_chars = 0; while (num_chars--) @@ -266,7 +275,7 @@ _text_blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr) wchar_t ch; ch = next_ch; - next_ch = getNextChar (&pStr); + next_ch = getCharFromString (&pStr); if (next_ch == '\0') num_chars = 0; @@ -320,99 +329,3 @@ getCharFrame (FONT_DESC *fontPtr, wchar_t ch) { return &fontPtr->CharDesc[ch - FIRST_CHAR]; } -// Get one character from a UTF-8 encoded string. -// *ptr will point to the start of the next character. -// Returns 0 if the encoding is bad. This can be distinguished from the -// '\0' character by checking whether **ptr == '\0'. -static wchar_t -getNextChar(const unsigned char **ptr) { - wchar_t result; - - if (**ptr < 0x80) { - // 0xxxxxxx, regular ASCII - result = **ptr; - (*ptr)++; - - return result; - } - - if ((**ptr & 0xe0) == 0xc0) { - // 110xxxxx; 10xxxxxx must follow - // Value between 0x00000080 and 0x0000007f (inclusive) - result = **ptr & 0x1f; - (*ptr)++; - - if ((**ptr & 0xc0) != 0x80) - goto err; - result = (result << 6) | ((**ptr) & 0x3f); - (*ptr)++; - - if (result < 0x00000080) { - // invalid encoding - must reject - goto err; - } - return result; - } - - if ((**ptr & 0xf0) == 0xe0) { - // 1110xxxx; 10xxxxxx 10xxxxxx must follow - // Value between 0x00000800 and 0x000007ff (inclusive) - result = **ptr & 0x0f; - (*ptr)++; - - if ((**ptr & 0xc0) != 0x80) - goto err; - result = (result << 6) | ((**ptr) & 0x3f); - (*ptr)++; - - if ((**ptr & 0xc0) != 0x80) - goto err; - result = (result << 6) | ((**ptr) & 0x3f); - (*ptr)++; - - if (result < 0x00000800) { - // invalid encoding - must reject - goto err; - } - return result; - } - - if ((**ptr & 0xf8) == 0xf0) { - // 11110xxx; 10xxxxxx 10xxxxxx 10xxxxxx must follow - // Value between 0x00010000 and 0x0010ffff (inclusive) - result = **ptr & 0x07; - (*ptr)++; - - if ((**ptr & 0xc0) != 0x80) - goto err; - result = (result << 6) | ((**ptr) & 0x3f); - (*ptr)++; - - if ((**ptr & 0xc0) != 0x80) - goto err; - result = (result << 6) | ((**ptr) & 0x3f); - (*ptr)++; - - if ((**ptr & 0xc0) != 0x80) - goto err; - result = (result << 6) | ((**ptr) & 0x3f); - (*ptr)++; - - if (result < 0x00010000) { - // invalid encoding - must reject - goto err; - } - return result; - } - -err: - fprintf(stderr, "Warning: Invalid UTF8 sequence.\n"); - - // Resynchronise (skip everything starting with 0x10xxxxxx): - while ((**ptr & 0xc0) == 0x80) - *ptr++; - - return 0; -} - - diff --git a/sc2/src/sc2code/libs/strings/Makeinfo b/sc2/src/sc2code/libs/strings/Makeinfo index 72ed7fca8..4daaa3ed6 100644 --- a/sc2/src/sc2code/libs/strings/Makeinfo +++ b/sc2/src/sc2code/libs/strings/Makeinfo @@ -1 +1 @@ -uqm_CFILES="getstr.c sfileins.c sresins.c strings.c" +uqm_CFILES="getstr.c sfileins.c sresins.c strings.c unicode.c" diff --git a/sc2/src/sc2code/libs/strings/unicode.c b/sc2/src/sc2code/libs/strings/unicode.c new file mode 100644 index 000000000..0cb3bfa67 --- /dev/null +++ b/sc2/src/sc2code/libs/strings/unicode.c @@ -0,0 +1,116 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +// Get one character from a UTF-8 encoded string. +// *ptr will point to the start of the next character. +// Returns 0 if the encoding is bad. This can be distinguished from the +// '\0' character by checking whether **ptr == '\0'. +wchar_t +getCharFromString(const unsigned char **ptr) { + wchar_t result; + + if (**ptr < 0x80) { + // 0xxxxxxx, regular ASCII + result = **ptr; + (*ptr)++; + + return result; + } + + if ((**ptr & 0xe0) == 0xc0) { + // 110xxxxx; 10xxxxxx must follow + // Value between 0x00000080 and 0x0000007f (inclusive) + result = **ptr & 0x1f; + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if (result < 0x00000080) { + // invalid encoding - must reject + goto err; + } + return result; + } + + if ((**ptr & 0xf0) == 0xe0) { + // 1110xxxx; 10xxxxxx 10xxxxxx must follow + // Value between 0x00000800 and 0x000007ff (inclusive) + result = **ptr & 0x0f; + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if (result < 0x00000800) { + // invalid encoding - must reject + goto err; + } + return result; + } + + if ((**ptr & 0xf8) == 0xf0) { + // 11110xxx; 10xxxxxx 10xxxxxx 10xxxxxx must follow + // Value between 0x00010000 and 0x0010ffff (inclusive) + result = **ptr & 0x07; + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if ((**ptr & 0xc0) != 0x80) + goto err; + result = (result << 6) | ((**ptr) & 0x3f); + (*ptr)++; + + if (result < 0x00010000) { + // invalid encoding - must reject + goto err; + } + return result; + } + +err: + fprintf(stderr, "Warning: Invalid UTF8 sequence.\n"); + + // Resynchronise (skip everything starting with 0x10xxxxxx): + while ((**ptr & 0xc0) == 0x80) + *ptr++; + + return 0; +} + + + diff --git a/sc2/src/sc2code/libs/strlib.h b/sc2/src/sc2code/libs/strlib.h index 8a297df05..1086d02e6 100644 --- a/sc2/src/sc2code/libs/strlib.h +++ b/sc2/src/sc2code/libs/strlib.h @@ -48,5 +48,8 @@ extern STRINGPTR GetStringTimeStamp (STRING String); extern BOOLEAN GetStringContents (STRING String, STRINGPTR StringBuf, BOOLEAN AppendSpace); +wchar_t getCharFromString(const unsigned char **ptr); + #endif /* _STRLIB_H */ +