summary refs log tree commit diff stats
path: root/tests/stdlib/twchartoutf8.nim
blob: a6602e3e39812f5f7ac80e66b1fd30f18da80250 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.high
discard """
  output: '''OK'''
"""

#assume WideCharToMultiByte always produce correct result
#windows only

when not defined(windows):
  echo "OK"
else:
  {.push gcsafe.}

  const CP_UTF8 = 65001'i32

  type
    LPBOOL = ptr int32
    LPWCSTR = ptr uint16

  proc WideCharToMultiByte*(CodePage: int32, dwFlags: int32,
                            lpWideCharStr: LPWCSTR, cchWideChar: int32,
                            lpMultiByteStr: cstring, cchMultiByte: int32,
                            lpDefaultChar: cstring, lpUsedDefaultChar: LPBOOL): int32{.
      stdcall, dynlib: "kernel32", importc: "WideCharToMultiByte".}

  {.pop.}

  proc convertToUTF8(wc: WideCString, wclen: int32): string =
    let size = WideCharToMultiByte(CP_UTF8, 0'i32, cast[LPWCSTR](addr(wc[0])), wclen,
      cstring(nil), 0'i32, cstring(nil), LPBOOL(nil))
    result = newString(size)
    let res = WideCharToMultiByte(CP_UTF8, 0'i32, cast[LPWCSTR](addr(wc[0])), wclen,
      cstring(result), size, cstring(nil), LPBOOL(nil))
    doAssert size == res

  proc testCP(wc: WideCString, lo, hi: int) =
    var x = 0
    let chunk = 1024
    for i in lo..hi:
      wc[x] = cast[Utf16Char](i)
      if (x >= chunk) or (i >= hi):
        wc[x] = Utf16Char(0)
        var a = convertToUTF8(wc, int32(x))
        var b = wc $ chunk
        doAssert a == b
        x = 0
      inc x

  proc testCP2(wc: WideCString, lo, hi: int) =
    doAssert((lo >= 0x10000) and (hi <= 0x10FFFF))
    var x = 0
    let chunk = 1024
    for i in lo..hi:
      let ch = i - 0x10000
      let W1 = 0xD800 or (ch shr 10)
      let W2 = 0xDC00 or (0x3FF and ch)
      wc[x] = cast[Utf16Char](W1)
      wc[x+1] = cast[Utf16Char](W2)
      inc(x, 2)

      if (x >= chunk) or (i >= hi):
        wc[x] = Utf16Char(0)
        var a = convertToUTF8(wc, int32(x))
        var b = wc $ chunk
        doAssert a == b
        x = 0

  #RFC-2781 "UTF-16, an encoding of ISO 10646"

  var wc: WideCString
  unsafeNew(wc, 1024 * 4 + 2)

  #U+0000 to U+D7FF
  #skip the U+0000
  wc.testCP(1, 0xD7FF)

  #U+E000 to U+FFFF
  wc.testCP(0xE000, 0xFFFF)

  #U+10000 to U+10FFFF
  wc.testCP2(0x10000, 0x10FFFF)

  #invalid UTF-16
  const
    b = "\xEF\xBF\xBD"
    c = "\xEF\xBF\xBF"

  wc[0] = cast[Utf16Char](0xDC00)
  wc[1] = Utf16Char(0)
  var a = $wc
  doAssert a == b

  wc[0] = cast[Utf16Char](0xFFFF)
  wc[1] = cast[Utf16Char](0xDC00)
  wc[2] = Utf16Char(0)
  a = $wc
  doAssert a == c & b

  wc[0] = cast[Utf16Char](0xD800)
  wc[1] = Utf16Char(0)
  a = $wc
  doAssert a == b

  wc[0] = cast[Utf16Char](0xD800)
  wc[1] = cast[Utf16Char](0xFFFF)
  wc[2] = Utf16Char(0)
  a = $wc
  doAssert a == b & c

  echo "OK"