github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/asset/asset_android.go (about)

     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  
     5  package asset
     6  
     7  /*
     8  #cgo LDFLAGS: -llog -landroid
     9  #include <android/log.h>
    10  #include <android/asset_manager.h>
    11  #include <android/asset_manager_jni.h>
    12  #include <jni.h>
    13  #include <stdlib.h>
    14  
    15  #define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "Go/asset", __VA_ARGS__)
    16  
    17  // asset_manager is the asset manager of the app.
    18  AAssetManager* asset_manager;
    19  
    20  void asset_manager_init(void* java_vm, void* ctx) {
    21  	JavaVM* vm = (JavaVM*)(java_vm);
    22  	JNIEnv* env;
    23  	int err;
    24  	int attached = 0;
    25  
    26  	err = (*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6);
    27  	if (err != JNI_OK) {
    28  		if (err == JNI_EDETACHED) {
    29  			if ((*vm)->AttachCurrentThread(vm, &env, 0) != 0) {
    30  				LOG_FATAL("cannot attach JVM");
    31  			}
    32  			attached = 1;
    33  		} else {
    34  			LOG_FATAL("GetEnv unexpected error: %d", err);
    35  		}
    36  	}
    37  
    38  	// Equivalent to:
    39  	//	assetManager = ctx.getResources().getAssets();
    40  	jclass ctx_clazz = (*env)->FindClass(env, "android/content/Context");
    41  	jmethodID getres_id = (*env)->GetMethodID(env, ctx_clazz, "getResources", "()Landroid/content/res/Resources;");
    42  	jobject res = (*env)->CallObjectMethod(env, ctx, getres_id);
    43  	jclass res_clazz = (*env)->FindClass(env, "android/content/res/Resources");
    44  	jmethodID getam_id = (*env)->GetMethodID(env, res_clazz, "getAssets", "()Landroid/content/res/AssetManager;");
    45  	jobject am = (*env)->CallObjectMethod(env, res, getam_id);
    46  
    47  	// Pin the AssetManager and load an AAssetManager from it.
    48  	am = (*env)->NewGlobalRef(env, am);
    49  	asset_manager = AAssetManager_fromJava(env, am);
    50  
    51  	if (attached) {
    52  		(*vm)->DetachCurrentThread(vm);
    53  	}
    54  }
    55  */
    56  import "C"
    57  import (
    58  	"fmt"
    59  	"io"
    60  	"os"
    61  	"sync"
    62  	"unsafe"
    63  
    64  	"github.com/c-darwin/mobile/internal/mobileinit"
    65  )
    66  
    67  var assetOnce sync.Once
    68  
    69  func assetInit() {
    70  	ctx := mobileinit.Context{}
    71  	C.asset_manager_init(ctx.JavaVM(), ctx.AndroidContext())
    72  }
    73  
    74  func openAsset(name string) (File, error) {
    75  	assetOnce.Do(assetInit)
    76  	cname := C.CString(name)
    77  	defer C.free(unsafe.Pointer(cname))
    78  	a := &asset{
    79  		ptr:  C.AAssetManager_open(C.asset_manager, cname, C.AASSET_MODE_UNKNOWN),
    80  		name: name,
    81  	}
    82  	if a.ptr == nil {
    83  		return nil, a.errorf("open", "bad asset")
    84  	}
    85  	return a, nil
    86  }
    87  
    88  type asset struct {
    89  	ptr  *C.AAsset
    90  	name string
    91  }
    92  
    93  func (a *asset) errorf(op string, format string, v ...interface{}) error {
    94  	return &os.PathError{
    95  		Op:   op,
    96  		Path: a.name,
    97  		Err:  fmt.Errorf(format, v...),
    98  	}
    99  }
   100  
   101  func (a *asset) Read(p []byte) (n int, err error) {
   102  	n = int(C.AAsset_read(a.ptr, unsafe.Pointer(&p[0]), C.size_t(len(p))))
   103  	if n == 0 && len(p) > 0 {
   104  		return 0, io.EOF
   105  	}
   106  	if n < 0 {
   107  		return 0, a.errorf("read", "negative bytes: %d", n)
   108  	}
   109  	return n, nil
   110  }
   111  
   112  func (a *asset) Seek(offset int64, whence int) (int64, error) {
   113  	// TODO(crawshaw): use AAsset_seek64 if it is available.
   114  	off := C.AAsset_seek(a.ptr, C.off_t(offset), C.int(whence))
   115  	if off == -1 {
   116  		return 0, a.errorf("seek", "bad result for offset=%d, whence=%d", offset, whence)
   117  	}
   118  	return int64(off), nil
   119  }
   120  
   121  func (a *asset) Close() error {
   122  	C.AAsset_close(a.ptr)
   123  	return nil
   124  }