file_ios.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. //go:build ios
  2. // +build ios
  3. package mobile
  4. /*
  5. #cgo CFLAGS: -x objective-c
  6. #cgo LDFLAGS: -framework Foundation
  7. #import <stdlib.h>
  8. #import <stdbool.h>
  9. bool iosExistsPath(const char* path);
  10. void* iosParseUrl(const char* url);
  11. const void* iosReadFromURL(void* url, int* len);
  12. const int iosWriteToURL(void* url, const void* bytes, int len);
  13. */
  14. import "C"
  15. import (
  16. "errors"
  17. "io"
  18. "unsafe"
  19. "fyne.io/fyne/v2"
  20. "fyne.io/fyne/v2/storage/repository"
  21. )
  22. type secureReadCloser struct {
  23. url unsafe.Pointer
  24. closer func()
  25. data []byte
  26. offset int
  27. }
  28. // Declare conformity to ReadCloser interface
  29. var _ io.ReadCloser = (*secureReadCloser)(nil)
  30. func (s *secureReadCloser) Read(p []byte) (int, error) {
  31. if s.data == nil {
  32. var length C.int
  33. s.data = C.GoBytes(C.iosReadFromURL(s.url, &length), length)
  34. }
  35. count := len(p)
  36. remain := len(s.data) - s.offset
  37. var err error
  38. if count >= remain {
  39. count = remain
  40. err = io.EOF
  41. }
  42. newOffset := s.offset + count
  43. o := 0
  44. for i := s.offset; i < newOffset; i++ {
  45. p[o] = s.data[i]
  46. o++
  47. }
  48. s.offset = newOffset
  49. return count, err
  50. }
  51. func (s *secureReadCloser) Close() error {
  52. if s.closer != nil {
  53. s.closer()
  54. }
  55. s.url = nil
  56. return nil
  57. }
  58. type secureWriteCloser struct {
  59. url unsafe.Pointer
  60. closer func()
  61. offset int
  62. }
  63. // Declare conformity to WriteCloser interface
  64. var _ io.WriteCloser = (*secureWriteCloser)(nil)
  65. func (s *secureWriteCloser) Write(p []byte) (int, error) {
  66. count := int(C.iosWriteToURL(s.url, C.CBytes(p), C.int(len(p))))
  67. s.offset += count
  68. return count, nil
  69. }
  70. func (s *secureWriteCloser) Close() error {
  71. if s.closer != nil {
  72. s.closer()
  73. }
  74. s.url = nil
  75. return nil
  76. }
  77. func existsURI(u fyne.URI) (bool, error) {
  78. if u.Scheme() != "file" {
  79. return true, errors.New("cannot check existence of " + u.Scheme() + " on iOS")
  80. }
  81. cStr := C.CString(u.Path())
  82. defer C.free(unsafe.Pointer(cStr))
  83. exists := C.iosExistsPath(cStr)
  84. return bool(exists), nil
  85. }
  86. func nativeFileOpen(f *fileOpen) (io.ReadCloser, error) {
  87. if f.uri == nil || f.uri.String() == "" {
  88. return nil, nil
  89. }
  90. cStr := C.CString(f.uri.String())
  91. defer C.free(unsafe.Pointer(cStr))
  92. url := C.iosParseUrl(cStr)
  93. fileStruct := &secureReadCloser{url: url, closer: f.done}
  94. return fileStruct, nil
  95. }
  96. func nativeFileSave(f *fileSave) (io.WriteCloser, error) {
  97. if f.uri == nil || f.uri.String() == "" {
  98. return nil, nil
  99. }
  100. cStr := C.CString(f.uri.String())
  101. defer C.free(unsafe.Pointer(cStr))
  102. url := C.iosParseUrl(cStr)
  103. fileStruct := &secureWriteCloser{url: url, closer: f.done}
  104. return fileStruct, nil
  105. }
  106. func registerRepository(d *mobileDriver) {
  107. repo := &mobileFileRepo{}
  108. repository.Register("file", repo)
  109. }