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