3
* ====================================================================
4
* Licensed to the Apache Software Foundation (ASF) under one
5
* or more contributor license agreements. See the NOTICE file
6
* distributed with this work for additional information
7
* regarding copyright ownership. The ASF licenses this file
8
* to you under the Apache License, Version 2.0 (the
9
* "License"); you may not use this file except in compliance
10
* with the License. You may obtain a copy of the License at
12
* http://www.apache.org/licenses/LICENSE-2.0
14
* Unless required by applicable law or agreed to in writing,
15
* software distributed under the License is distributed on an
16
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17
* KIND, either express or implied. See the License for the
18
* specific language governing permissions and limitations
20
* ====================================================================
26
#include "jni_object.hpp"
27
#include "jni_array.hpp"
28
#include "jni_channel.hpp"
30
#include "svn_private_config.h"
35
// Get the ByteBuffer's internal array.
36
jbyteArray get_array(Env env, jobject buffer,
37
const MethodID& mid_has_array,
38
const MethodID& mid_get_array)
40
if (!env.CallBooleanMethod(buffer, mid_has_array))
42
return jbyteArray(env.CallObjectMethod(buffer, mid_get_array));
45
// Get the offset in the ByteBuffer's array. NEVER call this function
46
// unless the buffer actually has an accessible array.
47
jint get_array_offset(Env env, jobject buffer,
48
const MethodID& mid_get_array_offset)
50
return env.CallIntMethod(buffer, mid_get_array_offset);
53
// Get the remaining space in a ByteBuffer.
54
jint get_remaining(Env env, jobject buffer,
55
const MethodID& mid_get_remaining)
57
return env.CallIntMethod(buffer, mid_get_remaining);
60
// Get the current position of a ByteBuffer.
61
jint get_position(Env env, jobject buffer,
62
const MethodID& mid_get_position)
64
return env.CallIntMethod(buffer, mid_get_position);
67
// Set the new position of a ByteBuffer.
68
void set_position(Env env, jobject buffer,
69
const MethodID& mid_set_position,
72
env.CallObjectMethod(buffer, mid_set_position, new_position);
75
// Get byte array contents from a ByteBuffer.
76
void get_bytearray(Env env, jobject buffer,
77
const MethodID& mid_get_bytearray,
78
ByteArray& array, jint length = -1, jint offset = 0)
81
buffer, mid_get_bytearray, array.get(), offset,
82
(length >= 0 ? length : (array.length() - offset)));
85
// Put byte array contents into a ByteBuffer.
86
void put_bytearray(Env env, jobject buffer,
87
const MethodID& mid_put_bytearray,
88
ByteArray& array, jint length = -1, jint offset = 0)
90
env.CallObjectMethod(buffer, mid_put_bytearray,
92
(length >= 0 ? length : (array.length() - offset)));
95
struct BadReaderWriter : public ChannelReader, ChannelWriter
99
virtual jint operator()(Env, void*, jint)
101
throw std::logic_error(_("Reading from write-only channel"));
104
virtual jint operator()(Env, const void*, jint)
106
throw std::logic_error(_("Writing to read-only channel"));
110
} // anonymous namespace
113
ChannelReader& ByteChannel::m_null_reader = bad_reader_writer;
114
ChannelWriter& ByteChannel::m_null_writer = bad_reader_writer;
116
const char* const ByteChannel::ByteBuffer::m_class_name =
117
"java/nio/ByteBuffer";
119
ByteChannel::ByteBuffer::ClassImpl::ClassImpl(Env env, jclass cls)
120
: Object::ClassImpl(env, cls),
121
m_mid_has_array(env.GetMethodID(cls, "hasArray", "()Z")),
122
m_mid_get_array(env.GetMethodID(cls, "array", "()[B")),
123
m_mid_get_array_offset(env.GetMethodID(cls, "arrayOffset", "()I")),
124
m_mid_get_remaining(env.GetMethodID(cls, "remaining", "()I")),
125
m_mid_get_position(env.GetMethodID(cls, "position", "()I")),
126
m_mid_set_position(env.GetMethodID(cls, "position",
127
"(I)Ljava/nio/Buffer;")),
128
m_mid_get_bytearray(env.GetMethodID(cls, "get",
129
"([BII)Ljava/nio/ByteBuffer;")),
130
m_mid_put_bytearray(env.GetMethodID(cls, "put",
131
"([BII)Ljava/nio/ByteBuffer;"))
134
ByteChannel::ByteBuffer::ClassImpl::~ClassImpl() {}
136
jint ByteChannel::read(jobject destination)
138
const ByteBuffer::ClassImpl& bufimpl = ByteBuffer::impl(m_env);
140
const jint remaining = get_remaining(m_env, destination,
141
bufimpl.m_mid_get_remaining);
144
// No space in the buffer; don't try to read anything.
148
const jint position = get_position(m_env, destination,
149
bufimpl.m_mid_get_position);
152
void* data = m_env.GetDirectBufferAddress(destination);
155
data = static_cast<char*>(data) + position;
156
bytes_read = m_reader(m_env, data, remaining);
160
// It was not a direct buffer ... see if it has an array.
161
jbyteArray raw_array = get_array(m_env, destination,
162
bufimpl.m_mid_has_array,
163
bufimpl.m_mid_get_array);
166
const jint array_offset = get_array_offset(
168
bufimpl.m_mid_get_array_offset);
169
ByteArray array(m_env, raw_array);
170
ByteArray::MutableContents contents(array);
171
data = contents.data();
172
data = static_cast<char*>(data) + position + array_offset;
173
bytes_read = m_reader(m_env, data, remaining);
179
set_position(m_env, destination,
180
bufimpl.m_mid_set_position,
181
position + bytes_read);
185
// No accessible array, either. Oh well. Create a byte array and
186
// push it into the buffer.
187
ByteArray array(m_env, remaining);
188
ByteArray::MutableContents contents(array);
189
bytes_read = m_reader(m_env, contents.data(), contents.length());
191
put_bytearray(m_env, destination,
192
bufimpl.m_mid_put_bytearray,
197
jint ByteChannel::write(jobject source)
199
const ByteBuffer::ClassImpl& bufimpl = ByteBuffer::impl(m_env);
201
const jint remaining = get_remaining(m_env, source,
202
bufimpl.m_mid_get_remaining);
205
// No data in the buffer; don't try to write anything.
209
const jint position = get_position(m_env, source,
210
bufimpl.m_mid_get_position);
212
jint bytes_written = 0;
213
const void* data = m_env.GetDirectBufferAddress(source);
216
data = static_cast<const char*>(data) + position;
217
bytes_written = m_writer(m_env, data, remaining);
221
// It was not a direct buffer ... see if it has an array.
222
jbyteArray raw_array = get_array(m_env, source,
223
bufimpl.m_mid_has_array,
224
bufimpl.m_mid_get_array);
227
const jint array_offset = get_array_offset(
229
bufimpl.m_mid_get_array_offset);
230
const ByteArray array(m_env, raw_array);
231
ByteArray::Contents contents(array);
232
data = contents.data();
233
data = static_cast<const char*>(data) + position + array_offset;
234
bytes_written = m_writer(m_env, data, remaining);
239
if (bytes_written > 0)
240
set_position(m_env, source,
241
bufimpl.m_mid_set_position,
242
position + bytes_written);
243
return bytes_written;
246
// No accessible array, either. Oh well. Get an array from the
247
// buffer and read data from that.
248
ByteArray array(m_env, remaining);
249
get_bytearray(m_env, source,
250
bufimpl.m_mid_get_bytearray,
252
ByteArray::Contents contents(array);
253
bytes_written = m_writer(m_env, contents.data(), contents.length());
254
return bytes_written;