utils.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package winapi
  2. import (
  3. "errors"
  4. "reflect"
  5. "syscall"
  6. "unsafe"
  7. "golang.org/x/sys/windows"
  8. )
  9. // Uint16BufferToSlice wraps a uint16 pointer-and-length into a slice
  10. // for easier interop with Go APIs
  11. func Uint16BufferToSlice(buffer *uint16, bufferLength int) (result []uint16) {
  12. hdr := (*reflect.SliceHeader)(unsafe.Pointer(&result))
  13. hdr.Data = uintptr(unsafe.Pointer(buffer))
  14. hdr.Cap = bufferLength
  15. hdr.Len = bufferLength
  16. return
  17. }
  18. // UnicodeString corresponds to UNICODE_STRING win32 struct defined here
  19. // https://docs.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_unicode_string
  20. type UnicodeString struct {
  21. Length uint16
  22. MaximumLength uint16
  23. Buffer *uint16
  24. }
  25. // NTSTRSAFE_UNICODE_STRING_MAX_CCH is a constant defined in ntstrsafe.h. This value
  26. // denotes the maximum number of wide chars a path can have.
  27. const NTSTRSAFE_UNICODE_STRING_MAX_CCH = 32767
  28. //String converts a UnicodeString to a golang string
  29. func (uni UnicodeString) String() string {
  30. // UnicodeString is not guaranteed to be null terminated, therefore
  31. // use the UnicodeString's Length field
  32. return windows.UTF16ToString(Uint16BufferToSlice(uni.Buffer, int(uni.Length/2)))
  33. }
  34. // NewUnicodeString allocates a new UnicodeString and copies `s` into
  35. // the buffer of the new UnicodeString.
  36. func NewUnicodeString(s string) (*UnicodeString, error) {
  37. buf, err := windows.UTF16FromString(s)
  38. if err != nil {
  39. return nil, err
  40. }
  41. if len(buf) > NTSTRSAFE_UNICODE_STRING_MAX_CCH {
  42. return nil, syscall.ENAMETOOLONG
  43. }
  44. uni := &UnicodeString{
  45. // The length is in bytes and should not include the trailing null character.
  46. Length: uint16((len(buf) - 1) * 2),
  47. MaximumLength: uint16((len(buf) - 1) * 2),
  48. Buffer: &buf[0],
  49. }
  50. return uni, nil
  51. }
  52. // ConvertStringSetToSlice is a helper function used to convert the contents of
  53. // `buf` into a string slice. `buf` contains a set of null terminated strings
  54. // with an additional null at the end to indicate the end of the set.
  55. func ConvertStringSetToSlice(buf []byte) ([]string, error) {
  56. var results []string
  57. prev := 0
  58. for i := range buf {
  59. if buf[i] == 0 {
  60. if prev == i {
  61. // found two null characters in a row, return result
  62. return results, nil
  63. }
  64. results = append(results, string(buf[prev:i]))
  65. prev = i + 1
  66. }
  67. }
  68. return nil, errors.New("string set malformed: missing null terminator at end of buffer")
  69. }