github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libdokan/new_folder_name.go (about)

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