diff options
Diffstat (limited to 'subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp')
-rw-r--r-- | subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp b/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp new file mode 100644 index 0000000..3c055ca --- /dev/null +++ b/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp @@ -0,0 +1,294 @@ +/** + * @copyright + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * @endcopyright + */ + +#include "jni_globalref.hpp" +#include "jni_io_stream.hpp" +#include "jni_stack.hpp" + +#include "svn_private_config.h" + +// Stream-wrapper-specific mark object type +struct svn_stream_mark_t +{ + void* m_baton; +}; + +namespace Java { + +namespace { +svn_error_t* stream_close_input(void* baton) +{ + InputStream* const self = static_cast<InputStream*>(baton); + SVN_JAVAHL_CATCH(self->get_env(), SVN_ERR_BASE, self->close()); + return SVN_NO_ERROR; +} + +svn_error_t* stream_mark(void* baton, svn_stream_mark_t** mark, + apr_pool_t* result_pool) +{ + InputStream* const self = static_cast<InputStream*>(baton); + SVN_JAVAHL_CATCH(self->get_env(), SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, + self->mark(16384)); // FIXME: invent better readlimit + + *mark = static_cast<svn_stream_mark_t*>( + apr_palloc(result_pool, sizeof(**mark))); + (*mark)->m_baton = baton; + return SVN_NO_ERROR; +} + +svn_error_t* stream_seek(void* baton, const svn_stream_mark_t* mark) +{ + if (mark->m_baton != baton) + return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, + NULL, _("Invalid mark")); + + InputStream* const self = static_cast<InputStream*>(baton); + SVN_JAVAHL_CATCH(self->get_env(), SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, + self->reset()); + return SVN_NO_ERROR; +} + +svn_error_t* stream_read(void* baton, char* buffer, apr_size_t* len) +{ + if (0 == *len) + return SVN_NO_ERROR; + + jint length = jint(*len); + InputStream* const self = static_cast<InputStream*>(baton); + SVN_JAVAHL_CATCH(self->get_env(), SVN_ERR_BASE, + length = self->read(buffer, length)); + if (length < 0) + *len = 0; + else + *len = length; + return SVN_NO_ERROR; +} + +svn_error_t* stream_skip(void* baton, apr_size_t len) +{ + InputStream* const self = static_cast<InputStream*>(baton); + SVN_JAVAHL_CATCH(self->get_env(), SVN_ERR_BASE, self->skip(jlong(len))); + return SVN_NO_ERROR; +} + +svn_error_t* stream_close_output(void* baton) +{ + OutputStream* const self = static_cast<OutputStream*>(baton); + SVN_JAVAHL_CATCH(self->get_env(), SVN_ERR_BASE, self->close()); + return SVN_NO_ERROR; +} + +svn_error_t* stream_write(void* baton, const char* data, apr_size_t* len) +{ + OutputStream* const self = static_cast<OutputStream*>(baton); + SVN_JAVAHL_CATCH(self->get_env(), SVN_ERR_BASE, + self->write(data, jint(*len))); + return SVN_NO_ERROR; +} + + +svn_error_t* +global_stream_close_input(void* baton) +{ + GlobalObject* ref = static_cast<GlobalObject*>(baton); + InputStream stream(Env(), ref->get()); + return stream_close_input(&stream); +} + +svn_error_t* +global_stream_mark(void* baton, svn_stream_mark_t** mark, + apr_pool_t* result_pool) +{ + GlobalObject* ref = static_cast<GlobalObject*>(baton); + InputStream stream(Env(), ref->get()); + return stream_mark(&stream, mark, result_pool); +} + +svn_error_t* +global_stream_seek(void* baton, const svn_stream_mark_t* mark) +{ + GlobalObject* ref = static_cast<GlobalObject*>(baton); + InputStream stream(Env(), ref->get()); + return stream_seek(&stream, mark); +} + +svn_error_t* +global_stream_read(void* baton, char* buffer, apr_size_t* len) +{ + GlobalObject* ref = static_cast<GlobalObject*>(baton); + InputStream stream(Env(), ref->get()); + return stream_read(&stream, buffer, len); +} + +svn_error_t* +global_stream_skip(void* baton, apr_size_t len) +{ + GlobalObject* ref = static_cast<GlobalObject*>(baton); + InputStream stream(Env(), ref->get()); + return stream_skip(&stream, len); +} + +svn_error_t* +global_stream_close_output(void* baton) +{ + GlobalObject* ref = static_cast<GlobalObject*>(baton); + OutputStream stream(Env(), ref->get()); + return stream_close_output(&stream); +} + +svn_error_t* +global_stream_write(void* baton, const char* data, apr_size_t* len) +{ + GlobalObject* ref = static_cast<GlobalObject*>(baton); + OutputStream stream(Env(), ref->get()); + return stream_write(&stream, data, len); +} + +apr_status_t cleanup_global_object(void* baton) +{ + delete static_cast<GlobalObject*>(baton); + return APR_SUCCESS; +} +} // anonymous namespace + + +// Class Java::InputStream + +const char* const InputStream::m_class_name = "java/io/InputStream"; +InputStream::ClassImpl::ClassImpl(Env env, jclass cls) + : Object::ClassImpl(env, cls), + m_mid_close(env.GetMethodID(cls, "close", "()V")), + m_mid_mark_supported(env.GetMethodID(cls, "markSupported", "()Z")), + m_mid_mark(env.GetMethodID(cls, "mark", "(I)V")), + m_mid_reset(env.GetMethodID(cls, "reset", "()V")), + m_mid_read_byte(env.GetMethodID(cls, "read", "()I")), + m_mid_read_bytearray(env.GetMethodID(cls, "read", "([BII)I")), + m_mid_skip(env.GetMethodID(cls, "skip", "(J)J")) +{} + +InputStream::ClassImpl::~ClassImpl() {} + +svn_stream_t* +InputStream::get_global_stream(Env env, jobject jstream, + const SVN::Pool& pool) +{ + if (!jstream) + return NULL; + + const bool has_mark = InputStream(env, jstream).mark_supported(); + + std::auto_ptr<GlobalObject> baton(new GlobalObject(env, jstream)); + + svn_stream_t* const stream = svn_stream_create(baton.get(), pool.getPool()); + svn_stream_set_read2(stream, global_stream_read, + NULL /* only partial read support */); + svn_stream_set_skip(stream, global_stream_skip); + svn_stream_set_close(stream, global_stream_close_input); + if (has_mark) + { + svn_stream_set_mark(stream, global_stream_mark); + svn_stream_set_seek(stream, global_stream_seek); + } + + apr_pool_cleanup_register(pool.getPool(), baton.release(), + cleanup_global_object, + apr_pool_cleanup_null); + return stream; +} + +svn_stream_t* InputStream::get_stream(const SVN::Pool& pool) +{ + if (!m_jthis) + return NULL; + + const bool has_mark = mark_supported(); + + svn_stream_t* const stream = svn_stream_create(this, pool.getPool()); + svn_stream_set_read2(stream, stream_read, + NULL /* only partial read support */); + svn_stream_set_skip(stream, stream_skip); + svn_stream_set_close(stream, stream_close_input); + if (has_mark) + { + svn_stream_set_mark(stream, stream_mark); + svn_stream_set_seek(stream, stream_seek); + } + return stream; +} + +jint InputStream::read(void* data, jint length) +{ + ByteArray array(m_env, length); + const jint size = read(array); + if (size > 0) + { + ByteArray::Contents contents(array); + ::memcpy(static_cast<char*>(data), contents.data(), size); + } + return size; +} + +// Class Java::OutputStream + +const char* const OutputStream::m_class_name = "java/io/OutputStream"; + +OutputStream::ClassImpl::ClassImpl(Env env, jclass cls) + : Object::ClassImpl(env, cls), + m_mid_close(env.GetMethodID(cls, "close", "()V")), + m_mid_write_byte(env.GetMethodID(cls, "write", "(I)V")), + m_mid_write_bytearray(env.GetMethodID(cls, "write", "([BII)V")) +{} + +OutputStream::ClassImpl::~ClassImpl() {} + +svn_stream_t* +OutputStream::get_global_stream(Env env, jobject jstream, + const SVN::Pool& pool) +{ + if (!jstream) + return NULL; + + std::auto_ptr<GlobalObject> baton(new GlobalObject(env, jstream)); + + svn_stream_t* const stream = svn_stream_create(baton.get(), pool.getPool()); + svn_stream_set_write(stream, global_stream_write); + svn_stream_set_close(stream, global_stream_close_output); + + apr_pool_cleanup_register(pool.getPool(), baton.release(), + cleanup_global_object, + apr_pool_cleanup_null); + return stream; +} + +svn_stream_t* OutputStream::get_stream(const SVN::Pool& pool) +{ + if (!m_jthis) + return NULL; + + svn_stream_t* const stream = svn_stream_create(this, pool.getPool()); + svn_stream_set_write(stream, stream_write); + svn_stream_set_close(stream, stream_close_output); + return stream; +} + +} // namespace Java |