19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "CreateJavaOutputStreamAdaptor.h"
2ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III#include "SkData.h"
3ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III#include "SkRefCnt.h"
4ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III#include "SkStream.h"
5ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III#include "SkTypes.h"
6ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III#include "Utils.h"
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
860126efd7d905ca24822765c6dafac17fef278abBen Wagner#include <JNIHelp.h>
960126efd7d905ca24822765c6dafac17fef278abBen Wagner#include <memory>
1060126efd7d905ca24822765c6dafac17fef278abBen Wagner
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jmethodID    gInputStream_readMethodID;
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jmethodID    gInputStream_skipMethodID;
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III/**
157315f1baee19476363235127bc1438e2a291fa15Leon Scroggins III *  Wrapper for a Java InputStream.
16ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III */
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass JavaInputStreamAdaptor : public SkStream {
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic:
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    JavaInputStreamAdaptor(JNIEnv* env, jobject js, jbyteArray ar)
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        : fEnv(env), fJavaInputStream(js), fJavaByteArray(ar) {
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SkASSERT(ar);
22ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III        fCapacity = env->GetArrayLength(ar);
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SkASSERT(fCapacity > 0);
24ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III        fBytesRead = 0;
25ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III        fIsAtEnd = false;
26ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III    }
27ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III
28ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III    virtual size_t read(void* buffer, size_t size) {
29ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III        if (NULL == buffer) {
30ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III            if (0 == size) {
31ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                return 0;
32ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III            } else {
33ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                /*  InputStream.skip(n) can return <=0 but still not be at EOF
34ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                    If we see that value, we need to call read(), which will
35ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                    block if waiting for more data, or return -1 at EOF
36ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                 */
37ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                size_t amountSkipped = 0;
38ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                do {
39ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                    size_t amount = this->doSkip(size - amountSkipped);
40ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                    if (0 == amount) {
41ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                        char tmp;
42ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                        amount = this->doRead(&tmp, 1);
43ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                        if (0 == amount) {
44ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                            // if read returned 0, we're at EOF
45ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                            fIsAtEnd = true;
46ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                            break;
47ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                        }
48ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                    }
49ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                    amountSkipped += amount;
50ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                } while (amountSkipped < size);
51ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                return amountSkipped;
52ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III            }
53ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III        }
54ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III        return this->doRead(buffer, size);
55ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III    }
56ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III
57ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III    virtual bool isAtEnd() const {
58ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III        return fIsAtEnd;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
60dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
61ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins IIIprivate:
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t doRead(void* buffer, size_t size) {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        JNIEnv* env = fEnv;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        size_t bytesRead = 0;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // read the bytes
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        do {
672bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat            jint requested = 0;
682bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat            if (size > static_cast<size_t>(fCapacity)) {
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                requested = fCapacity;
702bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat            } else {
712bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat                // This is safe because requested is clamped to (jint)
722bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat                // fCapacity.
732bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat                requested = static_cast<jint>(size);
742bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat            }
75dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            jint n = env->CallIntMethod(fJavaInputStream,
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        gInputStream_readMethodID, fJavaByteArray, 0, requested);
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (env->ExceptionCheck()) {
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionDescribe();
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionClear();
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                SkDebugf("---- read threw an exception\n");
8291332e7ecac06ef4cd3320095689e6af21e13dc6Leon Scroggins III                // Consider the stream to be at the end, since there was an error.
8391332e7ecac06ef4cd3320095689e6af21e13dc6Leon Scroggins III                fIsAtEnd = true;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
86dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
878cd48574a755bea86243e9f9eabaee341ecf9c60Gilles Debunne            if (n < 0) { // n == 0 should not be possible, see InputStream read() specifications.
88ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III                fIsAtEnd = true;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;  // eof
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
91dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->GetByteArrayRegion(fJavaByteArray, 0, n,
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    reinterpret_cast<jbyte*>(buffer));
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (env->ExceptionCheck()) {
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionDescribe();
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionClear();
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                SkDebugf("---- read:GetByteArrayRegion threw an exception\n");
9891332e7ecac06ef4cd3320095689e6af21e13dc6Leon Scroggins III                // The error was not with the stream itself, but consider it to be at the
9991332e7ecac06ef4cd3320095689e6af21e13dc6Leon Scroggins III                // end, since we do not have a way to recover.
10091332e7ecac06ef4cd3320095689e6af21e13dc6Leon Scroggins III                fIsAtEnd = true;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
103dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            buffer = (void*)((char*)buffer + n);
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            bytesRead += n;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            size -= n;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fBytesRead += n;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } while (size != 0);
109dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return bytesRead;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
112dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t doSkip(size_t size) {
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        JNIEnv* env = fEnv;
1158cd48574a755bea86243e9f9eabaee341ecf9c60Gilles Debunne
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jlong skipped = env->CallLongMethod(fJavaInputStream,
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                            gInputStream_skipMethodID, (jlong)size);
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (env->ExceptionCheck()) {
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->ExceptionDescribe();
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->ExceptionClear();
1218cd48574a755bea86243e9f9eabaee341ecf9c60Gilles Debunne            SkDebugf("------- skip threw an exception\n");
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (skipped < 0) {
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            skipped = 0;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1278cd48574a755bea86243e9f9eabaee341ecf9c60Gilles Debunne
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (size_t)skipped;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
130dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    JNIEnv*     fEnv;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jobject     fJavaInputStream;   // the caller owns this object
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jbyteArray  fJavaByteArray;     // the caller owns this object
1342bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat    jint        fCapacity;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    size_t      fBytesRead;
136ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III    bool        fIsAtEnd;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
139c7797525084ba0ea441e394aa0a2ba35d6ff3320Leon Scroggins IIISkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
140c7797525084ba0ea441e394aa0a2ba35d6ff3320Leon Scroggins III                                       jbyteArray storage) {
141ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III    return new JavaInputStreamAdaptor(env, stream, storage);
142ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III}
143ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III
144c7797525084ba0ea441e394aa0a2ba35d6ff3320Leon Scroggins III
14537b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins IIIstatic SkMemoryStream* adaptor_to_mem_stream(SkStream* stream) {
14637b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    SkASSERT(stream != NULL);
14737b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    size_t bufferSize = 4096;
14837b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    size_t streamLen = 0;
14937b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    size_t len;
15037b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    char* data = (char*)sk_malloc_throw(bufferSize);
15137b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III
15237b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    while ((len = stream->read(data + streamLen,
15337b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III                               bufferSize - streamLen)) != 0) {
15437b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III        streamLen += len;
15537b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III        if (streamLen == bufferSize) {
15637b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III            bufferSize *= 2;
15737b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III            data = (char*)sk_realloc_throw(data, bufferSize);
15837b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III        }
15937b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    }
16037b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    data = (char*)sk_realloc_throw(data, streamLen);
16137b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III
16237b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    SkMemoryStream* streamMem = new SkMemoryStream();
16337b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    streamMem->setMemoryOwned(data, streamLen);
16437b82e32324d0911aba897880c28b2fdedc3ec9aLeon Scroggins III    return streamMem;
165ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III}
166ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III
167c7797525084ba0ea441e394aa0a2ba35d6ff3320Leon Scroggins IIISkStreamRewindable* CopyJavaInputStream(JNIEnv* env, jobject stream,
168c7797525084ba0ea441e394aa0a2ba35d6ff3320Leon Scroggins III                                        jbyteArray storage) {
16960126efd7d905ca24822765c6dafac17fef278abBen Wagner    std::unique_ptr<SkStream> adaptor(CreateJavaInputStreamAdaptor(env, stream, storage));
170ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III    if (NULL == adaptor.get()) {
171ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III        return NULL;
172ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III    }
173ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III    return adaptor_to_mem_stream(adaptor.get());
174ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III}
175ca32021b43f326af7d3f4ae041f8db297f98a518Leon Scroggins III
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jmethodID    gOutputStream_writeMethodID;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectstatic jmethodID    gOutputStream_flushMethodID;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass SkJavaOutputStream : public SkWStream {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic:
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SkJavaOutputStream(JNIEnv* env, jobject stream, jbyteArray storage)
184cc11f15f76a62ded3e403cb2bc818c6aa5bf261cLeon Scroggins        : fEnv(env), fJavaOutputStream(stream), fJavaByteArray(storage), fBytesWritten(0) {
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fCapacity = env->GetArrayLength(storage);
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
187dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
188cc11f15f76a62ded3e403cb2bc818c6aa5bf261cLeon Scroggins    virtual size_t bytesWritten() const {
189cc11f15f76a62ded3e403cb2bc818c6aa5bf261cLeon Scroggins        return fBytesWritten;
190cc11f15f76a62ded3e403cb2bc818c6aa5bf261cLeon Scroggins    }
191cc11f15f76a62ded3e403cb2bc818c6aa5bf261cLeon Scroggins
1922bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat    virtual bool write(const void* buffer, size_t size) {
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        JNIEnv* env = fEnv;
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        jbyteArray storage = fJavaByteArray;
195dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (size > 0) {
1972bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat            jint requested = 0;
1982bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat            if (size > static_cast<size_t>(fCapacity)) {
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                requested = fCapacity;
2002bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat            } else {
2012bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat                // This is safe because requested is clamped to (jint)
2022bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat                // fCapacity.
2032bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat                requested = static_cast<jint>(size);
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            env->SetByteArrayRegion(storage, 0, requested,
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    reinterpret_cast<const jbyte*>(buffer));
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (env->ExceptionCheck()) {
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionDescribe();
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionClear();
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                SkDebugf("--- write:SetByteArrayElements threw an exception\n");
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
214dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_writeMethodID,
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                 storage, 0, requested);
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (env->ExceptionCheck()) {
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionDescribe();
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                env->ExceptionClear();
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                SkDebugf("------- write threw an exception\n");
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
223dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            buffer = (void*)((char*)buffer + requested);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            size -= requested;
226cc11f15f76a62ded3e403cb2bc818c6aa5bf261cLeon Scroggins            fBytesWritten += requested;
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
230dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    virtual void flush() {
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_flushMethodID);
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
234dd66bcbf9d6ef0c50a18d9c4b1b39ce7ef7afcc4Elliott Hughes
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectprivate:
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    JNIEnv*     fEnv;
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jobject     fJavaOutputStream;  // the caller owns this object
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    jbyteArray  fJavaByteArray;     // the caller owns this object
2392bb39d7a43fdb28ecdafd65ea4b89dc05c1ad7beAshok Bhat    jint        fCapacity;
240cc11f15f76a62ded3e403cb2bc818c6aa5bf261cLeon Scroggins    size_t      fBytesWritten;
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project};
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source ProjectSkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                         jbyteArray storage) {
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static bool gInited;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (!gInited) {
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        gInited = true;
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return new SkJavaOutputStream(env, stream, storage);
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
254d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III
255d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins IIIstatic jclass findClassCheck(JNIEnv* env, const char classname[]) {
256d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    jclass clazz = env->FindClass(classname);
257d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    SkASSERT(!env->ExceptionCheck());
258d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    return clazz;
259d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III}
260d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III
261d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins IIIstatic jmethodID getMethodIDCheck(JNIEnv* env, jclass clazz,
262d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III                                  const char methodname[], const char type[]) {
263d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    jmethodID id = env->GetMethodID(clazz, methodname, type);
264d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    SkASSERT(!env->ExceptionCheck());
265d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    return id;
266d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III}
267d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III
268d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins IIIint register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env) {
269d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    jclass inputStream_Clazz = findClassCheck(env, "java/io/InputStream");
270d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    gInputStream_readMethodID = getMethodIDCheck(env, inputStream_Clazz, "read", "([BII)I");
271d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    gInputStream_skipMethodID = getMethodIDCheck(env, inputStream_Clazz, "skip", "(J)J");
272d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III
273d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    jclass outputStream_Clazz = findClassCheck(env, "java/io/OutputStream");
274d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    gOutputStream_writeMethodID = getMethodIDCheck(env, outputStream_Clazz, "write", "([BII)V");
275d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    gOutputStream_flushMethodID = getMethodIDCheck(env, outputStream_Clazz, "flush", "()V");
276d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III
277d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III    return 0;
278d0d7eaf129b48ea04c06902a11c2a4f74056d76cLeon Scroggins III}
279