diff --git a/Docs/src/compiler.but b/Docs/src/compiler.but index 4ca90b3d..0c75073f 100644 --- a/Docs/src/compiler.but +++ b/Docs/src/compiler.but @@ -213,6 +213,13 @@ NSIS version as a 32 bit number. \c !error "NSIS 2.47 or higher is required to build this installer!" \c !endif +\S1{preunicodecodepoint} $\{U+1\}...$\{U+FFFFFFFF\} + +A Unicode (UCS-4) character. + +\c !define U+ABC "SIS" # Define will override +\c DetailPrint "${U+2115}${U+ABC}" # DOUBLE-STRUCK CAPITAL N + "SIS" + \S1{scopepredefines} Scope Predefines Standard predefines that contain information of the current code scope. diff --git a/Docs/src/history.but b/Docs/src/history.but index bcb53c9d..cdfeef77 100644 --- a/Docs/src/history.but +++ b/Docs/src/history.but @@ -24,6 +24,8 @@ Released on ?, 2013 \b The index of the changed section is stored in $0 during .onSelChange callbacks (\W{http://sourceforge.net/support/tracker.php?aid=1634936}{RFE #1634936}) +\b $\{U+1\}...$\{U+FFFFFFFF\} are treated as a Unicode codepoint unless there is already a define with that name + \S2{} Minor Changes \b %temp%\\Low will be used if the installer cannot write to %temp% nor %windir%\\Temp (\W{http://sourceforge.net/support/tracker.php?aid=2909242}{bug #2909242}, \W{http://sourceforge.net/support/tracker.php?aid=2912824}{patch #2912824}) diff --git a/Source/script.cpp b/Source/script.cpp index 2b230e1d..8bc639ae 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -684,6 +684,23 @@ void CEXEBuild::ps_addtoline(const TCHAR *str, GrowBuf &linedata, StringList &hi ps_addtoline(s,defname,hist); defname.add(_T(""),sizeof(_T(""))); t=definedlist.find((TCHAR*)defname.get()); + TCHAR unichar[4+1]; + if (!t && _T('U')==s[0] && _T('+')==s[1]) + { + TCHAR *n=s+2; + unsigned long utf32=_tcstoul(n,&t,16); + // We only want to accept "${U+HEXDIGITS}" and not "${U+ -HEXDIGITS }" + if (*t || _T('-')==*n || _T('+')==*n) t=0; + if (_T(' ')==*n || _T('\t')==*n) t=0; // TODO: _istspace()? + if (!utf32) t=0; // Don't allow "${U+0}" + if (t) + { + UINT32 codpts[]={utf32,UNICODE_REPLACEMENT_CHARACTER,'?'}; + for(UINT i=0; i < COUNTOF(codpts); ++i) + if (WCFromCodePoint(unichar,COUNTOF(unichar),codpts[i])) break; + t=unichar; + } + } if (t && hist.find((TCHAR*)defname.get(),0)<0) { in+=_tcslen(s)+2; diff --git a/Source/utf.cpp b/Source/utf.cpp index c9bfb80a..bcf85278 100644 --- a/Source/utf.cpp +++ b/Source/utf.cpp @@ -56,6 +56,33 @@ inline UINT UTF8ToWC_Prepare(LPCSTR StrU8,UINT cbU8) return UTF8ToWC_Convert(StrU8,cbU8,0,0); } +UINT WCFromCodePoint(wchar_t*Dest,UINT cchDest,UINT32 CodPt) +{ + // Don't allow half surrogate pairs + if (CodPt >= 0xd800 && CodPt <= 0xdfff) CodPt = UNICODE_REPLACEMENT_CHARACTER; +#ifdef _WIN32 + if (CodPt <= 0xffff && cchDest) + { + *Dest = (wchar_t) CodPt; + return 1; + } + else if (cchDest >= 2) + { + const UINT32 lead_offset = 0xd800 - (0x10000 >> 10); + UINT16 lead = lead_offset + (CodPt >> 10), trail = 0xdc00 + (CodPt & 0x3ff); + Dest[0] = lead, Dest[1] = trail; + return 2; + } + return 0; +#else + iconvdescriptor iconvd; + if (!iconvd.Open("wchar_t",iconvd::GetHostEndianUCS4Code())) return 0; + size_t inleft = 4; + UINT cchW = iconvd.Convert(&codpt,&inleft,Dest,cchDest*sizeof(wchar_t)) / sizeof(wchar_t); + return !inleft ? cchW : 0; +#endif +} + wchar_t* DupWCFromBytes(void*Buffer,UINT cbBuffer,WORD SrcCP) { /*\ diff --git a/Source/utf.h b/Source/utf.h index 9d4c5e3f..3a54a10e 100644 --- a/Source/utf.h +++ b/Source/utf.h @@ -23,6 +23,8 @@ #include #include "util.h" // For my_fopen +const UINT16 UNICODE_REPLACEMENT_CHARACTER = 0xfffd; + #define TSTR_INPUTCHARSET _T("ACP|OEM|CP#|UTF8|UTF16LE") @@ -54,6 +56,7 @@ inline UINT32 CodePointFromUTF16SurrogatePair(unsigned short lea,unsigned short UINT StrLenUTF16LE(const void*str); bool StrSetUTF16LE(tstring&dest, const void*src); +UINT WCFromCodePoint(wchar_t*Dest,UINT cchDest,UINT32 CodPt); wchar_t* DupWCFromBytes(void*Buffer,UINT cbBuffer,WORD SrcCP); UINT DetectUTFBOM(FILE*strm); WORD GetEncodingFromString(const TCHAR*s);