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 jmethodID    gInputStream_resetMethodID;
      7 static jmethodID    gInputStream_markMethodID;
      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) { // n == 0 should not be possible, see InputStream read() specifications.
     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 
     80         jlong skipped = env->CallLongMethod(fJavaInputStream,
     81                                             gInputStream_skipMethodID, (jlong)size);
     82         if (env->ExceptionCheck()) {
     83             env->ExceptionDescribe();
     84             env->ExceptionClear();
     85             SkDebugf("------- skip threw an exception\n");
     86             return 0;
     87         }
     88         if (skipped < 0) {
     89             skipped = 0;
     90         }
     91 
     92         return (size_t)skipped;
     93     }
     94 
     95     size_t doSize() {
     96         JNIEnv* env = fEnv;
     97         jint avail = env->CallIntMethod(fJavaInputStream,
     98                                         gInputStream_availableMethodID);
     99         if (env->ExceptionCheck()) {
    100             env->ExceptionDescribe();
    101             env->ExceptionClear();
    102             SkDebugf("------- available threw an exception\n");
    103             avail = 0;
    104         }
    105         return avail;
    106     }
    107 
    108 	virtual size_t read(void* buffer, size_t size) {
    109         JNIEnv* env = fEnv;
    110         if (NULL == buffer) {
    111             if (0 == size) {
    112                 return this->doSize();
    113             } else {
    114                 /*  InputStream.skip(n) can return <=0 but still not be at EOF
    115                     If we see that value, we need to call read(), which will
    116                     block if waiting for more data, or return -1 at EOF
    117                  */
    118                 size_t amountSkipped = 0;
    119                 do {
    120                     size_t amount = this->doSkip(size - amountSkipped);
    121                     if (0 == amount) {
    122                         char tmp;
    123                         amount = this->doRead(&tmp, 1);
    124                         if (0 == amount) {
    125                             // if read returned 0, we're at EOF
    126                             break;
    127                         }
    128                     }
    129                     amountSkipped += amount;
    130                 } while (amountSkipped < size);
    131                 return amountSkipped;
    132             }
    133         }
    134         return this->doRead(buffer, size);
    135     }
    136 
    137 private:
    138     JNIEnv*     fEnv;
    139     jobject     fJavaInputStream;   // the caller owns this object
    140     jbyteArray  fJavaByteArray;     // the caller owns this object
    141     size_t      fCapacity;
    142     size_t      fBytesRead;
    143 };
    144 
    145 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
    146                                        jbyteArray storage, int markSize) {
    147     static bool gInited;
    148 
    149     if (!gInited) {
    150         jclass inputStream_Clazz = env->FindClass("java/io/InputStream");
    151         RETURN_NULL_IF_NULL(inputStream_Clazz);
    152 
    153         gInputStream_resetMethodID      = env->GetMethodID(inputStream_Clazz,
    154                                                            "reset", "()V");
    155         gInputStream_markMethodID       = env->GetMethodID(inputStream_Clazz,
    156                                                            "mark", "(I)V");
    157         gInputStream_availableMethodID  = env->GetMethodID(inputStream_Clazz,
    158                                                            "available", "()I");
    159         gInputStream_readMethodID       = env->GetMethodID(inputStream_Clazz,
    160                                                            "read", "([BII)I");
    161         gInputStream_skipMethodID       = env->GetMethodID(inputStream_Clazz,
    162                                                            "skip", "(J)J");
    163 
    164         RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
    165         RETURN_NULL_IF_NULL(gInputStream_markMethodID);
    166         RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
    167         RETURN_NULL_IF_NULL(gInputStream_readMethodID);
    168         RETURN_NULL_IF_NULL(gInputStream_skipMethodID);
    169 
    170         gInited = true;
    171     }
    172 
    173     if (markSize) {
    174         env->CallVoidMethod(stream, gInputStream_markMethodID, markSize);
    175     }
    176 
    177     return new JavaInputStreamAdaptor(env, stream, storage);
    178 }
    179 
    180 ///////////////////////////////////////////////////////////////////////////////
    181 
    182 static jmethodID    gOutputStream_writeMethodID;
    183 static jmethodID    gOutputStream_flushMethodID;
    184 
    185 class SkJavaOutputStream : public SkWStream {
    186 public:
    187     SkJavaOutputStream(JNIEnv* env, jobject stream, jbyteArray storage)
    188         : fEnv(env), fJavaOutputStream(stream), fJavaByteArray(storage) {
    189         fCapacity = env->GetArrayLength(storage);
    190     }
    191 
    192 	virtual bool write(const void* buffer, size_t size) {
    193         JNIEnv* env = fEnv;
    194         jbyteArray storage = fJavaByteArray;
    195 
    196         while (size > 0) {
    197             size_t requested = size;
    198             if (requested > fCapacity) {
    199                 requested = fCapacity;
    200             }
    201 
    202             env->SetByteArrayRegion(storage, 0, requested,
    203                                     reinterpret_cast<const jbyte*>(buffer));
    204             if (env->ExceptionCheck()) {
    205                 env->ExceptionDescribe();
    206                 env->ExceptionClear();
    207                 SkDebugf("--- write:SetByteArrayElements threw an exception\n");
    208                 return false;
    209             }
    210 
    211             fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_writeMethodID,
    212                                  storage, 0, requested);
    213             if (env->ExceptionCheck()) {
    214                 env->ExceptionDescribe();
    215                 env->ExceptionClear();
    216                 SkDebugf("------- write threw an exception\n");
    217                 return false;
    218             }
    219 
    220             buffer = (void*)((char*)buffer + requested);
    221             size -= requested;
    222         }
    223         return true;
    224     }
    225 
    226     virtual void flush() {
    227         fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_flushMethodID);
    228     }
    229 
    230 private:
    231     JNIEnv*     fEnv;
    232     jobject     fJavaOutputStream;  // the caller owns this object
    233     jbyteArray  fJavaByteArray;     // the caller owns this object
    234     size_t      fCapacity;
    235 };
    236 
    237 SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
    238                                          jbyteArray storage) {
    239     static bool gInited;
    240 
    241     if (!gInited) {
    242         jclass outputStream_Clazz = env->FindClass("java/io/OutputStream");
    243         RETURN_NULL_IF_NULL(outputStream_Clazz);
    244 
    245         gOutputStream_writeMethodID = env->GetMethodID(outputStream_Clazz,
    246                                                        "write", "([BII)V");
    247         RETURN_NULL_IF_NULL(gOutputStream_writeMethodID);
    248         gOutputStream_flushMethodID = env->GetMethodID(outputStream_Clazz,
    249                                                        "flush", "()V");
    250         RETURN_NULL_IF_NULL(gOutputStream_flushMethodID);
    251 
    252         gInited = true;
    253     }
    254 
    255     return new SkJavaOutputStream(env, stream, storage);
    256 }
    257