1 #include "CreateJavaOutputStreamAdaptor.h"
3 #define RETURN_NULL_IF_NULL(value) \
4 do { if (!(value)) { SkASSERT(0); return NULL; } } while (false)
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;
13 class JavaInputStreamAdaptor : public SkStream {
15 JavaInputStreamAdaptor(JNIEnv* env, jobject js, jbyteArray ar)
16 : fEnv(env), fJavaInputStream(js), fJavaByteArray(ar) {
18 fCapacity = env->GetArrayLength(ar);
19 SkASSERT(fCapacity > 0);
23 virtual bool rewind() {
28 env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
29 if (env->ExceptionCheck()) {
30 env->ExceptionDescribe();
31 env->ExceptionClear();
32 SkDebugf("------- reset threw an exception\n");
38 size_t doRead(void* buffer, size_t size) {
43 size_t requested = size;
44 if (requested > fCapacity)
45 requested = fCapacity;
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");
56 if (n < 0) { // n == 0 should not be possible, see InputStream read() specifications.
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");
69 buffer = (void*)((char*)buffer + n);
78 size_t doSkip(size_t size) {
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");
93 return (size_t)skipped;
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");
109 virtual size_t read(void* buffer, size_t size) {
111 if (NULL == buffer) {
113 return this->doSize();
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
119 size_t amountSkipped = 0;
121 size_t amount = this->doSkip(size - amountSkipped);
124 amount = this->doRead(&tmp, 1);
126 // if read returned 0, we're at EOF
130 amountSkipped += amount;
131 } while (amountSkipped < size);
132 return amountSkipped;
135 return this->doRead(buffer, size);
140 jobject fJavaInputStream; // the caller owns this object
141 jbyteArray fJavaByteArray; // the caller owns this object
146 SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
147 jbyteArray storage, int markSize) {
151 gInputStream_Clazz = env->FindClass("java/io/InputStream");
152 RETURN_NULL_IF_NULL(gInputStream_Clazz);
153 gInputStream_Clazz = (jclass)env->NewGlobalRef(gInputStream_Clazz);
155 gInputStream_resetMethodID = env->GetMethodID(gInputStream_Clazz,
157 gInputStream_markMethodID = env->GetMethodID(gInputStream_Clazz,
159 gInputStream_availableMethodID = env->GetMethodID(gInputStream_Clazz,
161 gInputStream_readMethodID = env->GetMethodID(gInputStream_Clazz,
163 gInputStream_skipMethodID = env->GetMethodID(gInputStream_Clazz,
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);
176 env->CallVoidMethod(stream, gInputStream_markMethodID, markSize);
179 return new JavaInputStreamAdaptor(env, stream, storage);
182 ///////////////////////////////////////////////////////////////////////////////
184 static jclass gOutputStream_Clazz;
185 static jmethodID gOutputStream_writeMethodID;
186 static jmethodID gOutputStream_flushMethodID;
188 class SkJavaOutputStream : public SkWStream {
190 SkJavaOutputStream(JNIEnv* env, jobject stream, jbyteArray storage)
191 : fEnv(env), fJavaOutputStream(stream), fJavaByteArray(storage) {
192 fCapacity = env->GetArrayLength(storage);
195 virtual bool write(const void* buffer, size_t size) {
197 jbyteArray storage = fJavaByteArray;
200 size_t requested = size;
201 if (requested > fCapacity) {
202 requested = fCapacity;
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");
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");
223 buffer = (void*)((char*)buffer + requested);
229 virtual void flush() {
230 fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_flushMethodID);
235 jobject fJavaOutputStream; // the caller owns this object
236 jbyteArray fJavaByteArray; // the caller owns this object
240 SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
241 jbyteArray storage) {
245 gOutputStream_Clazz = env->FindClass("java/io/OutputStream");
246 RETURN_NULL_IF_NULL(gOutputStream_Clazz);
247 gOutputStream_Clazz = (jclass)env->NewGlobalRef(gOutputStream_Clazz);
249 gOutputStream_writeMethodID = env->GetMethodID(gOutputStream_Clazz,
251 RETURN_NULL_IF_NULL(gOutputStream_writeMethodID);
252 gOutputStream_flushMethodID = env->GetMethodID(gOutputStream_Clazz,
254 RETURN_NULL_IF_NULL(gOutputStream_flushMethodID);
259 return new SkJavaOutputStream(env, stream, storage);