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