@@ -429,6 +429,103 @@ size_t UTF8_WriteCodePoint (char *dst, size_t maxbytes, uint32_t codepoint)
429429 return 0 ;
430430}
431431
432+ // clang-format off
433+ static const uint32_t qchar_to_unicode [256 ] =
434+ {/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
435+ ----------------------------------------------------------------------------------------------------------------------------------
436+ 0 */ 0x00B7 , 0 , 0 , 0 , 0 , 0x00B7 , 0 , 0 , 0 , 0 , '\n' , 0x25A0 , ' ' , 0x25B6 , 0x00B7 , 0x00B7 , /*
437+ 1 */ 0x301A , 0x301B , '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 0x00B7 , '-' , '-' , '-' , /*
438+ 2 */ ' ' , '!' , '"' , '#' , '$' , '%' , '&' , '\'' , '(' , ')' , '*' , '+' , ',' , '-' , '.' , '/' , /*
439+ 3 */ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , ':' , ';' , '<' , '=' , '>' , '?' , /*
440+ 4 */ '@' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , /*
441+ 5 */ 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z' , '[' , '\\' , ']' , '^' , '_' , /*
442+ 6 */ '`' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , /*
443+ 7 */ 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' , '{' , '|' , '}' , '~' , 0x2190 , /*
444+
445+ 8 */ '-' , '-' , '-' , '-' , 0 , 0x2022 , 0 , 0 , 0 , 0 , '\n' , 0x25A0 , ' ' , 0x25B6 , 0x2022 , 0x2022 , /*
446+ 9 */ 0x301A , 0x301B , '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 0x2022 , '-' , '-' , '-' , /*
447+ 10 */ ' ' , '!' , '"' , '#' , '$' , '%' , '&' , '\'' , '(' , ')' , '*' , '+' , ',' , '-' , '.' , '/' , /*
448+ 11 */ '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , ':' , ';' , '<' , '=' , '>' , '?' , /*
449+ 12 */ '@' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' , /*
450+ 13 */ 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z' , '[' , '\\' , ']' , '^' , '_' , /*
451+ 14 */ '`' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , /*
452+ 15 */ 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' , '{' , '|' , '}' , '~' , 0x2190 , /*
453+ ----------------------------------------------------------------------------------------------------------------------------------
454+ */ };
455+ // clang-format on
456+
457+ /*
458+ ==================
459+ UTF8_CodePointLength
460+
461+ Returns the number of bytes needed to encode the codepoint
462+ using UTF-8 (max 4), or 0 for an invalid code point
463+ ==================
464+ */
465+ size_t UTF8_CodePointLength (uint32_t codepoint )
466+ {
467+ if (codepoint < 0x80 )
468+ return 1 ;
469+
470+ if (codepoint < 0x800 )
471+ return 2 ;
472+
473+ if (codepoint < 0x10000 )
474+ return 3 ;
475+
476+ if (codepoint < 0x110000 )
477+ return 4 ;
478+
479+ return 0 ;
480+ }
481+
482+ /*
483+ ==================
484+ UTF8_FromQuake
485+
486+ Converts a string from Quake encoding to UTF-8
487+
488+ Returns the number of written characters (including the NUL terminator)
489+ if a valid output buffer is provided (dst is non-NULL, maxbytes > 0),
490+ or the total amount of space necessary to encode the entire src string
491+ if dst is NULL and maxbytes is 0.
492+ ==================
493+ */
494+ size_t UTF8_FromQuake (char * dst , size_t maxbytes , const char * src )
495+ {
496+ size_t i , j , written ;
497+
498+ if (!maxbytes )
499+ {
500+ if (dst )
501+ return 0 ; // error
502+ for (i = 0 , j = 0 ; src [i ]; i ++ )
503+ {
504+ uint32_t codepoint = qchar_to_unicode [(unsigned char )src [i ]];
505+ if (codepoint )
506+ j += UTF8_CodePointLength (codepoint );
507+ }
508+ return j + 1 ; // include terminator
509+ }
510+
511+ -- maxbytes ;
512+
513+ for (i = 0 , j = 0 ; j < maxbytes && src [i ]; i ++ )
514+ {
515+ uint32_t codepoint = qchar_to_unicode [(unsigned char )src [i ]];
516+ if (!codepoint )
517+ continue ;
518+ written = UTF8_WriteCodePoint (dst + j , maxbytes - j , codepoint );
519+ if (!written )
520+ break ;
521+ j += written ;
522+ }
523+
524+ dst [j ++ ] = '\0' ;
525+
526+ return j ;
527+ }
528+
432529char * q_strtrim (char * str )
433530{
434531 // trim leading and ending whitespaces:
0 commit comments