CreateJavaOutputStreamAdaptor.cpp revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1#include "CreateJavaOutputStreamAdaptor.h" 2 3#define RETURN_NULL_IF_NULL(value) \ 4 do { if (!(value)) { SkASSERT(0); return NULL; } } while (false) 5 6static jclass gInputStream_Clazz; 7static jmethodID gInputStream_resetMethodID; 8static jmethodID gInputStream_availableMethodID; 9static jmethodID gInputStream_readMethodID; 10static jmethodID gInputStream_skipMethodID; 11 12class JavaInputStreamAdaptor : public SkStream { 13public: 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 printf("------- reset threw an exception\n"); 32 return false; 33 } 34 return true; 35 } 36 37 virtual size_t read(void* buffer, size_t size) { 38 JNIEnv* env = fEnv; 39 40 if (buffer == NULL && size == 0) { 41 jint avail = env->CallIntMethod(fJavaInputStream, 42 gInputStream_availableMethodID); 43 if (env->ExceptionCheck()) { 44 env->ExceptionDescribe(); 45 env->ExceptionClear(); 46 printf("------- available threw an exception\n"); 47 avail = 0; 48 } 49 return avail; 50 } 51 52 size_t bytesRead = 0; 53 54 if (buffer == NULL) { // skip 55 jlong skipped = env->CallLongMethod(fJavaInputStream, 56 gInputStream_skipMethodID, (jlong)size); 57 if (env->ExceptionCheck()) { 58 env->ExceptionDescribe(); 59 env->ExceptionClear(); 60 printf("------- available threw an exception\n"); 61 return 0; 62 } 63 if (skipped < 0) { 64 return 0; 65 } 66 return (size_t)skipped; 67 } 68 69 // read the bytes 70 do { 71 size_t requested = size; 72 if (requested > fCapacity) 73 requested = fCapacity; 74 75 jint n = env->CallIntMethod(fJavaInputStream, 76 gInputStream_readMethodID, fJavaByteArray, 0, requested); 77 if (env->ExceptionCheck()) { 78 env->ExceptionDescribe(); 79 env->ExceptionClear(); 80 printf("---- read threw an exception\n"); 81 return 0; 82 } 83 84 if (n <= 0) { 85 break; // eof 86 } 87 88 jbyte* array = env->GetByteArrayElements(fJavaByteArray, NULL); 89 memcpy(buffer, array, n); 90 env->ReleaseByteArrayElements(fJavaByteArray, array, 0); 91 92 buffer = (void*)((char*)buffer + n); 93 bytesRead += n; 94 size -= n; 95 fBytesRead += n; 96 } while (size != 0); 97 98 return bytesRead; 99 } 100 101private: 102 JNIEnv* fEnv; 103 jobject fJavaInputStream; // the caller owns this object 104 jbyteArray fJavaByteArray; // the caller owns this object 105 size_t fCapacity; 106 size_t fBytesRead; 107}; 108 109SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream, 110 jbyteArray storage) { 111 static bool gInited; 112 113 if (!gInited) { 114 gInputStream_Clazz = env->FindClass("java/io/InputStream"); 115 RETURN_NULL_IF_NULL(gInputStream_Clazz); 116 gInputStream_Clazz = (jclass)env->NewGlobalRef(gInputStream_Clazz); 117 118 gInputStream_resetMethodID = env->GetMethodID(gInputStream_Clazz, 119 "reset", "()V"); 120 gInputStream_availableMethodID = env->GetMethodID(gInputStream_Clazz, 121 "available", "()I"); 122 gInputStream_readMethodID = env->GetMethodID(gInputStream_Clazz, 123 "read", "([BII)I"); 124 gInputStream_skipMethodID = env->GetMethodID(gInputStream_Clazz, 125 "skip", "(J)J"); 126 127 RETURN_NULL_IF_NULL(gInputStream_resetMethodID); 128 RETURN_NULL_IF_NULL(gInputStream_availableMethodID); 129 RETURN_NULL_IF_NULL(gInputStream_availableMethodID); 130 RETURN_NULL_IF_NULL(gInputStream_skipMethodID); 131 132 gInited = true; 133 } 134 135 return new JavaInputStreamAdaptor(env, stream, storage); 136} 137 138/////////////////////////////////////////////////////////////////////////////// 139 140static jclass gOutputStream_Clazz; 141static jmethodID gOutputStream_writeMethodID; 142static jmethodID gOutputStream_flushMethodID; 143 144class SkJavaOutputStream : public SkWStream { 145public: 146 SkJavaOutputStream(JNIEnv* env, jobject stream, jbyteArray storage) 147 : fEnv(env), fJavaOutputStream(stream), fJavaByteArray(storage) { 148 fCapacity = env->GetArrayLength(storage); 149 } 150 151 virtual bool write(const void* buffer, size_t size) { 152 JNIEnv* env = fEnv; 153 jbyteArray storage = fJavaByteArray; 154 155 while (size > 0) { 156 size_t requested = size; 157 if (requested > fCapacity) { 158 requested = fCapacity; 159 } 160 161 jbyte* array = env->GetByteArrayElements(storage, NULL); 162 memcpy(array, buffer, requested); 163 env->ReleaseByteArrayElements(storage, array, 0); 164 165 fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_writeMethodID, 166 storage, 0, requested); 167 if (env->ExceptionCheck()) { 168 env->ExceptionDescribe(); 169 env->ExceptionClear(); 170 printf("------- write threw an exception\n"); 171 return false; 172 } 173 174 buffer = (void*)((char*)buffer + requested); 175 size -= requested; 176 } 177 return true; 178 } 179 180 virtual void flush() { 181 fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_flushMethodID); 182 } 183 184private: 185 JNIEnv* fEnv; 186 jobject fJavaOutputStream; // the caller owns this object 187 jbyteArray fJavaByteArray; // the caller owns this object 188 size_t fCapacity; 189}; 190 191SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream, 192 jbyteArray storage) { 193 static bool gInited; 194 195 if (!gInited) { 196 gOutputStream_Clazz = env->FindClass("java/io/OutputStream"); 197 RETURN_NULL_IF_NULL(gOutputStream_Clazz); 198 gOutputStream_Clazz = (jclass)env->NewGlobalRef(gOutputStream_Clazz); 199 200 gOutputStream_writeMethodID = env->GetMethodID(gOutputStream_Clazz, 201 "write", "([BII)V"); 202 RETURN_NULL_IF_NULL(gOutputStream_writeMethodID); 203 gOutputStream_flushMethodID = env->GetMethodID(gOutputStream_Clazz, 204 "flush", "()V"); 205 RETURN_NULL_IF_NULL(gOutputStream_flushMethodID); 206 207 gInited = true; 208 } 209 210 return new SkJavaOutputStream(env, stream, storage); 211} 212 213