All checks were successful
continuous-integration/drone/push Build is passing
See #478
86 lines
1.7 KiB
Go
86 lines
1.7 KiB
Go
// +build windows
|
|
|
|
package localereader
|
|
|
|
import (
|
|
"io"
|
|
"syscall"
|
|
"unicode/utf8"
|
|
"unsafe"
|
|
|
|
"golang.org/x/text/transform"
|
|
)
|
|
|
|
const (
|
|
CP_ACP = 0
|
|
MB_ERR_INVALID_CHARS = 8
|
|
)
|
|
|
|
var (
|
|
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar")
|
|
procIsDBCSLeadByte = modkernel32.NewProc("IsDBCSLeadByte")
|
|
)
|
|
|
|
type codepageDecoder struct {
|
|
transform.NopResetter
|
|
|
|
cp int
|
|
}
|
|
|
|
func (codepageDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
|
r, size := rune(0), 0
|
|
loop:
|
|
for ; nSrc < len(src); nSrc += size {
|
|
switch c0 := src[nSrc]; {
|
|
case c0 < utf8.RuneSelf:
|
|
r, size = rune(c0), 1
|
|
|
|
default:
|
|
br, _, _ := procIsDBCSLeadByte.Call(uintptr(src[nSrc]))
|
|
if br == 0 {
|
|
r = rune(src[nSrc])
|
|
size = 1
|
|
break
|
|
}
|
|
if nSrc >= len(src)-1 {
|
|
r = rune(src[nSrc])
|
|
size = 1
|
|
break
|
|
}
|
|
n, _, _ := procMultiByteToWideChar.Call(CP_ACP, 0, uintptr(unsafe.Pointer(&src[nSrc])), uintptr(2), uintptr(0), 0)
|
|
if n <= 0 {
|
|
err = syscall.GetLastError()
|
|
break
|
|
}
|
|
var us [1]uint16
|
|
rc, _, _ := procMultiByteToWideChar.Call(CP_ACP, 0, uintptr(unsafe.Pointer(&src[nSrc])), uintptr(2), uintptr(unsafe.Pointer(&us[0])), 1)
|
|
if rc == 0 {
|
|
size = 1
|
|
break
|
|
}
|
|
r = rune(us[0])
|
|
size = 2
|
|
}
|
|
if nDst+utf8.RuneLen(r) > len(dst) {
|
|
err = transform.ErrShortDst
|
|
break loop
|
|
}
|
|
nDst += utf8.EncodeRune(dst[nDst:], r)
|
|
}
|
|
return nDst, nSrc, err
|
|
|
|
}
|
|
|
|
func newReader(r io.Reader) io.Reader {
|
|
return transform.NewReader(r, NewAcpDecoder())
|
|
}
|
|
|
|
func NewCodePageDecoder(cp int) transform.Transformer {
|
|
return &codepageDecoder{cp: cp}
|
|
}
|
|
|
|
func NewAcpDecoder() transform.Transformer {
|
|
return &codepageDecoder{cp: CP_ACP}
|
|
}
|