asset_android.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // Copyright 2015 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package asset
  5. /*
  6. #cgo LDFLAGS: -landroid
  7. #include <android/asset_manager.h>
  8. #include <android/asset_manager_jni.h>
  9. #include <jni.h>
  10. #include <stdlib.h>
  11. static AAssetManager* asset_manager_init(uintptr_t java_vm, uintptr_t jni_env, jobject ctx) {
  12. JavaVM* vm = (JavaVM*)java_vm;
  13. JNIEnv* env = (JNIEnv*)jni_env;
  14. // Equivalent to:
  15. // assetManager = ctx.getResources().getAssets();
  16. jclass ctx_clazz = (*env)->FindClass(env, "android/content/Context");
  17. jmethodID getres_id = (*env)->GetMethodID(env, ctx_clazz, "getResources", "()Landroid/content/res/Resources;");
  18. jobject res = (*env)->CallObjectMethod(env, ctx, getres_id);
  19. jclass res_clazz = (*env)->FindClass(env, "android/content/res/Resources");
  20. jmethodID getam_id = (*env)->GetMethodID(env, res_clazz, "getAssets", "()Landroid/content/res/AssetManager;");
  21. jobject am = (*env)->CallObjectMethod(env, res, getam_id);
  22. // Pin the AssetManager and load an AAssetManager from it.
  23. am = (*env)->NewGlobalRef(env, am);
  24. return AAssetManager_fromJava(env, am);
  25. }
  26. */
  27. import "C"
  28. import (
  29. "fmt"
  30. "io"
  31. "log"
  32. "os"
  33. "sync"
  34. "unsafe"
  35. "golang.org/x/mobile/internal/mobileinit"
  36. )
  37. var assetOnce sync.Once
  38. // asset_manager is the asset manager of the app.
  39. var assetManager *C.AAssetManager
  40. func assetInit() {
  41. err := mobileinit.RunOnJVM(func(vm, env, ctx uintptr) error {
  42. assetManager = C.asset_manager_init(C.uintptr_t(vm), C.uintptr_t(env), C.jobject(ctx))
  43. return nil
  44. })
  45. if err != nil {
  46. log.Fatalf("asset: %v", err)
  47. }
  48. }
  49. func openAsset(name string) (File, error) {
  50. assetOnce.Do(assetInit)
  51. cname := C.CString(name)
  52. defer C.free(unsafe.Pointer(cname))
  53. a := &asset{
  54. ptr: C.AAssetManager_open(assetManager, cname, C.AASSET_MODE_UNKNOWN),
  55. name: name,
  56. }
  57. if a.ptr == nil {
  58. return nil, a.errorf("open", "bad asset")
  59. }
  60. return a, nil
  61. }
  62. type asset struct {
  63. ptr *C.AAsset
  64. name string
  65. }
  66. func (a *asset) errorf(op string, format string, v ...interface{}) error {
  67. return &os.PathError{
  68. Op: op,
  69. Path: a.name,
  70. Err: fmt.Errorf(format, v...),
  71. }
  72. }
  73. func (a *asset) Read(p []byte) (n int, err error) {
  74. n = int(C.AAsset_read(a.ptr, unsafe.Pointer(&p[0]), C.size_t(len(p))))
  75. if n == 0 && len(p) > 0 {
  76. return 0, io.EOF
  77. }
  78. if n < 0 {
  79. return 0, a.errorf("read", "negative bytes: %d", n)
  80. }
  81. return n, nil
  82. }
  83. func (a *asset) Seek(offset int64, whence int) (int64, error) {
  84. // TODO(crawshaw): use AAsset_seek64 if it is available.
  85. off := C.AAsset_seek(a.ptr, C.off_t(offset), C.int(whence))
  86. if off == -1 {
  87. return 0, a.errorf("seek", "bad result for offset=%d, whence=%d", offset, whence)
  88. }
  89. return int64(off), nil
  90. }
  91. func (a *asset) Close() error {
  92. C.AAsset_close(a.ptr)
  93. return nil
  94. }