-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGifCreateJavaInputStreamAdaptor.cpp
executable file
·165 lines (137 loc) · 5.85 KB
/
GifCreateJavaInputStreamAdaptor.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "GifCreateJavaInputStreamAdaptor.h"
#define RETURN_NULL_IF_NULL(value) \
do { if (!(value)) { return NULL ; } } while (false)
static jmethodID gInputStream_resetMethodID;
static jmethodID gInputStream_markMethodID;
static jmethodID gInputStream_availableMethodID;
static jmethodID gInputStream_readMethodID;
static jmethodID gInputStream_skipMethodID;
GifJavaInputStreamAdaptor::GifJavaInputStreamAdaptor(JNIEnv* env, jobject js, jbyteArray ar)
: fEnv(env), fJavaInputStream(js), fJavaByteArray(ar) {
fCapacity = env->GetArrayLength(ar);
fBytesRead = 0;
}
bool GifJavaInputStreamAdaptor::rewind() {
JNIEnv* env = fEnv;
fBytesRead = 0;
env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return false;
}
return true;
}
size_t GifJavaInputStreamAdaptor::doRead(void* buffer, size_t size) {
JNIEnv* env = fEnv;
size_t bytesRead = 0;
// read the bytes
do {
size_t requested = size;
if (requested > fCapacity)
requested = fCapacity;
jint n = env->CallIntMethod(fJavaInputStream,
gInputStream_readMethodID, fJavaByteArray, 0, requested);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return 0;
}
if (n < 0) { // n == 0 should not be possible, see InputStream read() specifications.
break; // eof
}
env->GetByteArrayRegion(fJavaByteArray, 0, n,
reinterpret_cast<jbyte*>(buffer));
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return 0;
}
buffer = (void*)((char*)buffer + n);
bytesRead += n;
size -= n;
fBytesRead += n;
} while (size != 0);
return bytesRead;
}
size_t GifJavaInputStreamAdaptor::doSkip(size_t size) {
JNIEnv* env = fEnv;
jlong skipped = env->CallLongMethod(fJavaInputStream,
gInputStream_skipMethodID, (jlong)size);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
return 0;
}
if (skipped < 0) {
skipped = 0;
}
return (size_t)skipped;
}
size_t GifJavaInputStreamAdaptor::doSize() {
JNIEnv* env = fEnv;
jint avail = env->CallIntMethod(fJavaInputStream,
gInputStream_availableMethodID);
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
avail = 0;
}
return avail;
}
size_t GifJavaInputStreamAdaptor::read(void* buffer, size_t size) {
JNIEnv* env = fEnv;
if (0 == buffer) {
if (0 == size) {
return this->doSize();
} else {
/* InputStream.skip(n) can return <=0 but still not be at EOF
If we see that value, we need to call read(), which will
block if waiting for more data, or return -1 at EOF
*/
size_t amountSkipped = 0;
do {
size_t amount = this->doSkip(size - amountSkipped);
if (0 == amount) {
char tmp;
amount = this->doRead(&tmp, 1);
if (0 == amount) {
// if read returned 0, we're at EOF
break;
}
}
amountSkipped += amount;
} while (amountSkipped < size);
return amountSkipped;
}
}
return this->doRead(buffer, size);
}
GifJavaInputStreamAdaptor* GifJavaInputStreamAdaptor::CreateGifJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
jbyteArray storage, int markSize) {
static bool gInited;
if (!gInited) {
jclass inputStream_Clazz = env->FindClass("java/io/InputStream");
//RETURN_NULL_IF_NULL(inputStream_Clazz);
gInputStream_resetMethodID = env->GetMethodID(inputStream_Clazz,
"reset", "()V");
gInputStream_markMethodID = env->GetMethodID(inputStream_Clazz,
"mark", "(I)V");
gInputStream_availableMethodID = env->GetMethodID(inputStream_Clazz,
"available", "()I");
gInputStream_readMethodID = env->GetMethodID(inputStream_Clazz,
"read", "([BII)I");
gInputStream_skipMethodID = env->GetMethodID(inputStream_Clazz,
"skip", "(J)J");
// RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
// RETURN_NULL_IF_NULL(gInputStream_markMethodID);
// RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
// RETURN_NULL_IF_NULL(gInputStream_availableMethodID);
// RETURN_NULL_IF_NULL(gInputStream_skipMethodID);
gInited = true;
}
if (markSize) {
env->CallVoidMethod(stream, gInputStream_markMethodID, markSize);
}
return new GifJavaInputStreamAdaptor(env, stream, storage);
}