1// Copyright 2016 Keybase Inc. All rights reserved.
2// Use of this source code is governed by a BSD
3// license that can be found in the LICENSE file.
4
5// +build windows
6
7package libdokan
8
9import (
10	"reflect"
11	"strings"
12	"syscall"
13	"unicode/utf16"
14	"unicode/utf8"
15	"unsafe"
16
17	"golang.org/x/sys/windows"
18)
19
20func isNewFolderName(name string) bool {
21	return name == newFolderName || name == newFolderAltName
22}
23
24var newFolderName, newFolderNameErr = getNewFolderName()
25var newFolderAltName = altCase(newFolderName)
26
27func altCase(s string) string {
28	_, idx := utf8.DecodeRuneInString(s)
29	return s[:idx] + strings.ToLower(s[idx:])
30}
31
32// The resourse IDs are not considered stable by Microsoft.
33// Luckily for us this happens to be the same for our
34// targeted Windows versions where kbfsdokan works.
35// Tested for Windows 7, 8, 8.1 and 10.
36// TODO test this for new Windows versions!
37const newFolderWindws7to10ResourceID = 16888
38
39func getNewFolderName() (string, error) {
40	var u16ptr *uint16
41	// The following id is valid for at least Windows 7, 8.1 and 10.
42	res, _, err := syscall.Syscall6(procLoadStringW.Addr(), 4, shell32DLL.Handle(),
43		newFolderWindws7to10ResourceID, uintptr(unsafe.Pointer(&u16ptr)), 0, 0, 0)
44	if res == 0 {
45		return "New Folder", err
46	}
47	return lpcwstrToString(u16ptr), nil
48}
49
50var (
51	shell32DLL      = windows.NewLazySystemDLL("shell32.dll")
52	user32DLL       = windows.NewLazySystemDLL("user32.dll")
53	procLoadStringW = user32DLL.NewProc("LoadStringW")
54)
55
56// lpcwstrToString converts a nul-terminated Windows wide string to a Go string,
57func lpcwstrToString(ptr *uint16) string {
58	if ptr == nil {
59		return ""
60	}
61	var len = 0
62	for tmp := ptr; *tmp != 0; tmp = (*uint16)(unsafe.Pointer((uintptr(unsafe.Pointer(tmp)) + 2))) {
63		len++
64	}
65	raw := ptrUcs2Slice(ptr, len)
66	return string(utf16.Decode(raw))
67}
68
69// ptrUcs2Slice takes a C Windows wide string and length in UCS2
70// and returns it aliased as a uint16 slice.
71func ptrUcs2Slice(ptr *uint16, lenUcs2 int) []uint16 {
72	return *(*[]uint16)(unsafe.Pointer(&reflect.SliceHeader{
73		Data: uintptr(unsafe.Pointer(ptr)),
74		Len:  lenUcs2,
75		Cap:  lenUcs2}))
76}
77