blob: 6ce3f51925ac269b35b516068eb9c100104716f7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001#include "CreateJavaOutputStreamAdaptor.h"
2
3#define RETURN_NULL_IF_NULL(value) \
4 do { if (!(value)) { SkASSERT(0); return NULL; } } while (false)
5
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006static jmethodID gInputStream_resetMethodID;
Joseph Wenf1f48bc2010-07-19 16:59:51 +08007static jmethodID gInputStream_markMethodID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008static 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 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022 virtual bool rewind() {
23 JNIEnv* env = fEnv;
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025 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 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 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;
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046 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 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070054
Gilles Debunne8cd48572010-07-15 18:06:36 -070055 if (n < 0) { // n == 0 should not be possible, see InputStream read() specifications.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 break; // eof
57 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 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 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070067
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 buffer = (void*)((char*)buffer + n);
69 bytesRead += n;
70 size -= n;
71 fBytesRead += n;
72 } while (size != 0);
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 return bytesRead;
75 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 size_t doSkip(size_t size) {
78 JNIEnv* env = fEnv;
Gilles Debunne8cd48572010-07-15 18:06:36 -070079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 jlong skipped = env->CallLongMethod(fJavaInputStream,
81 gInputStream_skipMethodID, (jlong)size);
82 if (env->ExceptionCheck()) {
83 env->ExceptionDescribe();
84 env->ExceptionClear();
Gilles Debunne8cd48572010-07-15 18:06:36 -070085 SkDebugf("------- skip threw an exception\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 return 0;
87 }
88 if (skipped < 0) {
89 skipped = 0;
90 }
Gilles Debunne8cd48572010-07-15 18:06:36 -070091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 return (size_t)skipped;
93 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -070094
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 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 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 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 {
Gilles Debunne8cd48572010-07-15 18:06:36 -0700120 size_t amount = this->doSkip(size - amountSkipped);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 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 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137private:
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
145SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
Joseph Wenf1f48bc2010-07-19 16:59:51 +0800146 jbyteArray storage, int markSize) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 static bool gInited;
148
149 if (!gInited) {
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700150 jclass inputStream_Clazz = env->FindClass("java/io/InputStream");
151 RETURN_NULL_IF_NULL(inputStream_Clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700153 gInputStream_resetMethodID = env->GetMethodID(inputStream_Clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 "reset", "()V");
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700155 gInputStream_markMethodID = env->GetMethodID(inputStream_Clazz,
Joseph Wenf1f48bc2010-07-19 16:59:51 +0800156 "mark", "(I)V");
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700157 gInputStream_availableMethodID = env->GetMethodID(inputStream_Clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 "available", "()I");
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700159 gInputStream_readMethodID = env->GetMethodID(inputStream_Clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 "read", "([BII)I");
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700161 gInputStream_skipMethodID = env->GetMethodID(inputStream_Clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 "skip", "(J)J");
163
164 RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
Joseph Wenf1f48bc2010-07-19 16:59:51 +0800165 RETURN_NULL_IF_NULL(gInputStream_markMethodID);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
167 RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
168 RETURN_NULL_IF_NULL(gInputStream_skipMethodID);
169
170 gInited = true;
171 }
172
Joseph Wenf1f48bc2010-07-19 16:59:51 +0800173 if (markSize) {
174 env->CallVoidMethod(stream, gInputStream_markMethodID, markSize);
175 }
176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 return new JavaInputStreamAdaptor(env, stream, storage);
178}
179
180///////////////////////////////////////////////////////////////////////////////
181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182static jmethodID gOutputStream_writeMethodID;
183static jmethodID gOutputStream_flushMethodID;
184
185class SkJavaOutputStream : public SkWStream {
186public:
187 SkJavaOutputStream(JNIEnv* env, jobject stream, jbyteArray storage)
188 : fEnv(env), fJavaOutputStream(stream), fJavaByteArray(storage) {
189 fCapacity = env->GetArrayLength(storage);
190 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 virtual bool write(const void* buffer, size_t size) {
193 JNIEnv* env = fEnv;
194 jbyteArray storage = fJavaByteArray;
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 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 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 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 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 buffer = (void*)((char*)buffer + requested);
221 size -= requested;
222 }
223 return true;
224 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 virtual void flush() {
227 fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_flushMethodID);
228 }
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230private:
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
237SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
238 jbyteArray storage) {
239 static bool gInited;
240
241 if (!gInited) {
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700242 jclass outputStream_Clazz = env->FindClass("java/io/OutputStream");
243 RETURN_NULL_IF_NULL(outputStream_Clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700245 gOutputStream_writeMethodID = env->GetMethodID(outputStream_Clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 "write", "([BII)V");
247 RETURN_NULL_IF_NULL(gOutputStream_writeMethodID);
Elliott Hughesdd66bcb2011-04-12 11:28:59 -0700248 gOutputStream_flushMethodID = env->GetMethodID(outputStream_Clazz,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 "flush", "()V");
250 RETURN_NULL_IF_NULL(gOutputStream_flushMethodID);
251
252 gInited = true;
253 }
254
255 return new SkJavaOutputStream(env, stream, storage);
256}