Home | History | Annotate | Download | only in graphics
      1 #include "CreateJavaOutputStreamAdaptor.h"
      2 
      3 #define RETURN_NULL_IF_NULL(value) \
      4     do { if (!(value)) { SkASSERT(0); return NULL; } } while (false)
      5 
      6 static jclass       gInputStream_Clazz;
      7 static jmethodID    gInputStream_resetMethodID;
      8 static jmethodID    gInputStream_availableMethodID;
      9 static jmethodID    gInputStream_readMethodID;
     10 static jmethodID    gInputStream_skipMethodID;
     11 
     12 class JavaInputStreamAdaptor : public SkStream {
     13 public:
     14     JavaInputStreamAdaptor(JNIEnv* env, jobject js, jbyteArray ar)
     15         : fEnv(env), fJavaInputStream(js), fJavaByteArray(ar) {
     16         SkASSERT(ar);
     17         fCapacity   = env->GetArrayLength(ar);
     18         SkASSERT(fCapacity > 0);
     19         fBytesRead  = 0;
     20     }
     21 
     22 	virtual bool rewind() {
     23         JNIEnv* env = fEnv;
     24 
     25         fBytesRead = 0;
     26 
     27         env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
     28         if (env->ExceptionCheck()) {
     29             env->ExceptionDescribe();
     30             env->ExceptionClear();
     31             SkDebugf("------- reset threw an exception\n");
     32             return false;
     33         }
     34         return true;
     35     }
     36 
     37     size_t doRead(void* buffer, size_t size) {
     38         JNIEnv* env = fEnv;
     39         size_t bytesRead = 0;
     40         // read the bytes
     41         do {
     42             size_t requested = size;
     43             if (requested > fCapacity)
     44                 requested = fCapacity;
     45 
     46             jint n = env->CallIntMethod(fJavaInputStream,
     47                                         gInputStream_readMethodID, fJavaByteArray, 0, requested);
     48             if (env->ExceptionCheck()) {
     49                 env->ExceptionDescribe();
     50                 env->ExceptionClear();
     51                 SkDebugf("---- read threw an exception\n");
     52                 return 0;
     53             }
     54 
     55             if (n <= 0) {
     56                 break;  // eof
     57             }
     58 
     59             env->GetByteArrayRegion(fJavaByteArray, 0, n,
     60                                     reinterpret_cast<jbyte*>(buffer));
     61             if (env->ExceptionCheck()) {
     62                 env->ExceptionDescribe();
     63                 env->ExceptionClear();
     64                 SkDebugf("---- read:GetByteArrayRegion threw an exception\n");
     65                 return 0;
     66             }
     67 
     68             buffer = (void*)((char*)buffer + n);
     69             bytesRead += n;
     70             size -= n;
     71             fBytesRead += n;
     72         } while (size != 0);
     73 
     74         return bytesRead;
     75     }
     76 
     77     size_t doSkip(size_t size) {
     78         JNIEnv* env = fEnv;
     79         jlong skipped = env->CallLongMethod(fJavaInputStream,
     80                                             gInputStream_skipMethodID, (jlong)size);
     81         if (env->ExceptionCheck()) {
     82             env->ExceptionDescribe();
     83             env->ExceptionClear();
     84             SkDebugf("------- available threw an exception\n");
     85             return 0;
     86         }
     87         if (skipped < 0) {
     88             skipped = 0;
     89         }
     90         return (size_t)skipped;
     91     }
     92 
     93     size_t doSize() {
     94         JNIEnv* env = fEnv;
     95         jint avail = env->CallIntMethod(fJavaInputStream,
     96                                         gInputStream_availableMethodID);
     97         if (env->ExceptionCheck()) {
     98             env->ExceptionDescribe();
     99             env->ExceptionClear();
    100             SkDebugf("------- available threw an exception\n");
    101             avail = 0;
    102         }
    103         return avail;
    104     }
    105 
    106 	virtual size_t read(void* buffer, size_t size) {
    107         JNIEnv* env = fEnv;
    108         if (NULL == buffer) {
    109             if (0 == size) {
    110                 return this->doSize();
    111             } else {
    112                 /*  InputStream.skip(n) can return <=0 but still not be at EOF
    113                     If we see that value, we need to call read(), which will
    114                     block if waiting for more data, or return -1 at EOF
    115                  */
    116                 size_t amountSkipped = 0;
    117                 do {
    118                     size_t amount = this->doSkip(size);
    119                     if (0 == amount) {
    120                         char tmp;
    121                         amount = this->doRead(&tmp, 1);
    122                         if (0 == amount) {
    123                             // if read returned 0, we're at EOF
    124                             break;
    125                         }
    126                     }
    127                     amountSkipped += amount;
    128                 } while (amountSkipped < size);
    129                 return amountSkipped;
    130             }
    131         }
    132         return this->doRead(buffer, size);
    133     }
    134 
    135 private:
    136     JNIEnv*     fEnv;
    137     jobject     fJavaInputStream;   // the caller owns this object
    138     jbyteArray  fJavaByteArray;     // the caller owns this object
    139     size_t      fCapacity;
    140     size_t      fBytesRead;
    141 };
    142 
    143 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
    144                                        jbyteArray storage) {
    145     static bool gInited;
    146 
    147     if (!gInited) {
    148         gInputStream_Clazz = env->FindClass("java/io/InputStream");
    149         RETURN_NULL_IF_NULL(gInputStream_Clazz);
    150         gInputStream_Clazz = (jclass)env->NewGlobalRef(gInputStream_Clazz);
    151 
    152         gInputStream_resetMethodID      = env->GetMethodID(gInputStream_Clazz,
    153                                                            "reset", "()V");
    154         gInputStream_availableMethodID  = env->GetMethodID(gInputStream_Clazz,
    155                                                            "available", "()I");
    156         gInputStream_readMethodID       = env->GetMethodID(gInputStream_Clazz,
    157                                                            "read", "([BII)I");
    158         gInputStream_skipMethodID       = env->GetMethodID(gInputStream_Clazz,
    159                                                            "skip", "(J)J");
    160 
    161         RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
    162         RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
    163         RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
    164         RETURN_NULL_IF_NULL(gInputStream_skipMethodID);
    165 
    166         gInited = true;
    167     }
    168 
    169     return new JavaInputStreamAdaptor(env, stream, storage);
    170 }
    171 
    172 ///////////////////////////////////////////////////////////////////////////////
    173 
    174 static jclass       gOutputStream_Clazz;
    175 static jmethodID    gOutputStream_writeMethodID;
    176 static jmethodID    gOutputStream_flushMethodID;
    177 
    178 class SkJavaOutputStream : public SkWStream {
    179 public:
    180     SkJavaOutputStream(JNIEnv* env, jobject stream, jbyteArray storage)
    181         : fEnv(env), fJavaOutputStream(stream), fJavaByteArray(storage) {
    182         fCapacity = env->GetArrayLength(storage);
    183     }
    184 
    185 	virtual bool write(const void* buffer, size_t size) {
    186         JNIEnv* env = fEnv;
    187         jbyteArray storage = fJavaByteArray;
    188 
    189         while (size > 0) {
    190             size_t requested = size;
    191             if (requested > fCapacity) {
    192                 requested = fCapacity;
    193             }
    194 
    195             env->SetByteArrayRegion(storage, 0, requested,
    196                                     reinterpret_cast<const jbyte*>(buffer));
    197             if (env->ExceptionCheck()) {
    198                 env->ExceptionDescribe();
    199                 env->ExceptionClear();
    200                 SkDebugf("--- write:SetByteArrayElements threw an exception\n");
    201                 return false;
    202             }
    203 
    204             fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_writeMethodID,
    205                                  storage, 0, requested);
    206             if (env->ExceptionCheck()) {
    207                 env->ExceptionDescribe();
    208                 env->ExceptionClear();
    209                 SkDebugf("------- write threw an exception\n");
    210                 return false;
    211             }
    212 
    213             buffer = (void*)((char*)buffer + requested);
    214             size -= requested;
    215         }
    216         return true;
    217     }
    218 
    219     virtual void flush() {
    220         fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_flushMethodID);
    221     }
    222 
    223 private:
    224     JNIEnv*     fEnv;
    225     jobject     fJavaOutputStream;  // the caller owns this object
    226     jbyteArray  fJavaByteArray;     // the caller owns this object
    227     size_t      fCapacity;
    228 };
    229 
    230 SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
    231                                          jbyteArray storage) {
    232     static bool gInited;
    233 
    234     if (!gInited) {
    235         gOutputStream_Clazz = env->FindClass("java/io/OutputStream");
    236         RETURN_NULL_IF_NULL(gOutputStream_Clazz);
    237         gOutputStream_Clazz = (jclass)env->NewGlobalRef(gOutputStream_Clazz);
    238 
    239         gOutputStream_writeMethodID = env->GetMethodID(gOutputStream_Clazz,
    240                                                        "write", "([BII)V");
    241         RETURN_NULL_IF_NULL(gOutputStream_writeMethodID);
    242         gOutputStream_flushMethodID = env->GetMethodID(gOutputStream_Clazz,
    243                                                        "flush", "()V");
    244         RETURN_NULL_IF_NULL(gOutputStream_flushMethodID);
    245 
    246         gInited = true;
    247     }
    248 
    249     return new SkJavaOutputStream(env, stream, storage);
    250 }
    251 
    252