OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / core / jni / android / graphics / CreateJavaOutputStreamAdaptor.cpp
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