From f8bd6cbacb30c0c10dba47fa896e0f37e3d83272 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Fri, 5 Aug 2022 12:39:19 +0200 Subject: Java: Adopt to ByteInStream changes of commit c82d4c266a80a8b41a184cdadd8ecae37bd635fd --- java_jni/jni/jau/ByteInStream_Feed.cxx | 99 ++++++++++++++----- java_jni/jni/jau/ByteInStream_File.cxx | 153 ++++++++++++++++++++++------- java_jni/jni/jau/ByteInStream_URL.cxx | 98 +++++++++++++----- java_jni/org/jau/io/ByteInStream.java | 112 ++++++++++++++------- java_jni/org/jau/io/ByteInStreamUtil.java | 12 +-- java_jni/org/jau/io/ByteInStream_Feed.java | 43 ++++++-- java_jni/org/jau/io/ByteInStream_File.java | 65 +++++++++--- java_jni/org/jau/io/ByteInStream_URL.java | 43 ++++++-- java_jni/org/jau/io/IOState.java | 92 +++++++++++++++++ 9 files changed, 558 insertions(+), 159 deletions(-) create mode 100644 java_jni/org/jau/io/IOState.java diff --git a/java_jni/jni/jau/ByteInStream_Feed.cxx b/java_jni/jni/jau/ByteInStream_Feed.cxx index 0d69ca7..e7c7e77 100644 --- a/java_jni/jni/jau/ByteInStream_Feed.cxx +++ b/java_jni/jni/jau/ByteInStream_Feed.cxx @@ -66,10 +66,79 @@ void Java_org_jau_io_ByteInStream_1Feed_dtorImpl(JNIEnv *env, jclass clazz, jlon } } -jboolean Java_org_jau_io_ByteInStream_1Feed_check_1available(JNIEnv *env, jobject obj, jlong n) { + +void Java_org_jau_io_ByteInStream_1Feed_clearImpl(JNIEnv *env, jobject obj, jint mask) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + ref->clear( static_cast(mask) ); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } +} + +jint Java_org_jau_io_ByteInStream_1Feed_rdStateImpl(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return static_cast( ref->rdstate() ); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return static_cast(jau::io::iostate::failbit); +} + +void Java_org_jau_io_ByteInStream_1Feed_setStateImpl(JNIEnv *env, jobject obj, jint mask) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + ref->setstate( static_cast(mask) ); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } +} + +jboolean Java_org_jau_io_ByteInStream_1Feed_good(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->good() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_FALSE; +} + +jboolean Java_org_jau_io_ByteInStream_1Feed_eof(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->eof() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_TRUE; +} + +jboolean Java_org_jau_io_ByteInStream_1Feed_fail(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->fail() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_TRUE; +} + +jboolean Java_org_jau_io_ByteInStream_1Feed_bad(JNIEnv *env, jobject obj) { try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return ref->check_available((size_t)n) ? JNI_TRUE : JNI_FALSE; + return ref->bad() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_FALSE; +} + +jboolean Java_org_jau_io_ByteInStream_1Feed_available(JNIEnv *env, jobject obj, jlong n) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->available((size_t)n) ? JNI_TRUE : JNI_FALSE; } catch(...) { rethrow_and_raise_java_exception_jau(env); } @@ -142,26 +211,6 @@ jint Java_org_jau_io_ByteInStream_1Feed_peek(JNIEnv *env, jobject obj, jbyteArra return 0; } -jboolean Java_org_jau_io_ByteInStream_1Feed_end_1of_1data(JNIEnv *env, jobject obj) { - try { - jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return ref->end_of_data() ? JNI_TRUE : JNI_FALSE; - } catch(...) { - rethrow_and_raise_java_exception_jau(env); - } - return JNI_TRUE; -} - -jboolean Java_org_jau_io_ByteInStream_1Feed_error(JNIEnv *env, jobject obj) { - try { - jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return ref->error() ? JNI_TRUE : JNI_FALSE; - } catch(...) { - rethrow_and_raise_java_exception_jau(env); - } - return JNI_TRUE; -} - jstring Java_org_jau_io_ByteInStream_1Feed_id(JNIEnv *env, jobject obj) { try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done @@ -176,7 +225,7 @@ jlong Java_org_jau_io_ByteInStream_1Feed_discard_1next(JNIEnv *env, jobject obj, try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done - const size_t res = ref->discard_next(n); + const size_t res = ref->discard(n); return (jlong)res; } catch(...) { rethrow_and_raise_java_exception_jau(env); @@ -184,10 +233,10 @@ jlong Java_org_jau_io_ByteInStream_1Feed_discard_1next(JNIEnv *env, jobject obj, return 0; } -jlong Java_org_jau_io_ByteInStream_1Feed_get_1bytes_1read(JNIEnv *env, jobject obj) { +jlong Java_org_jau_io_ByteInStream_1Feed_tellg(JNIEnv *env, jobject obj) { try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return static_cast( ref->get_bytes_read() ); + return static_cast( ref->tellg() ); } catch(...) { rethrow_and_raise_java_exception_jau(env); } diff --git a/java_jni/jni/jau/ByteInStream_File.cxx b/java_jni/jni/jau/ByteInStream_File.cxx index 5b2002d..6e6fb4b 100644 --- a/java_jni/jni/jau/ByteInStream_File.cxx +++ b/java_jni/jni/jau/ByteInStream_File.cxx @@ -22,20 +22,45 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "org_jau_io_ByteInStream_File.h" +#include "jau/byte_stream.hpp" #include #include "jau/jni/helper_jni.hpp" -#include "jau/byte_stream.hpp" +// #include "org_jau_io_IOState.h" +#include "org_jau_io_ByteInStream_File.h" + + +extern "C" { + #include +} + +// +// IOState +// + +jstring Java_org_jau_io_IOState_to_1string(JNIEnv *env, jclass cls, jint mask) { + (void)cls; + try { + const std::string s = jau::io::to_string(static_cast(mask)); + return jau::jni::from_string_to_jstring(env, s); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return nullptr; +} -jlong Java_org_jau_io_ByteInStream_1File_ctorImpl1(JNIEnv *env, jobject obj, jstring jpath) { +// +// ByteInStream_File +// + +jlong Java_org_jau_io_ByteInStream_1File_ctorImpl1(JNIEnv *env, jclass cls, jstring jpath) { try { - (void)obj; + (void)cls; // new instance - const std::string path = jau::jni::from_jstring_to_string(env, jpath); - jau::jni::shared_ptr_ref ref( new jau::io::ByteInStream_File(path) ); + const std::string _path = jau::jni::from_jstring_to_string(env, jpath); + jau::jni::shared_ptr_ref ref( new jau::io::ByteInStream_File( _path ) ); return ref.release_to_jlong(); } catch(...) { rethrow_and_raise_java_exception_jau(env); @@ -43,9 +68,9 @@ jlong Java_org_jau_io_ByteInStream_1File_ctorImpl1(JNIEnv *env, jobject obj, jst return (jlong) (intptr_t)nullptr; } -jlong Java_org_jau_io_ByteInStream_1File_ctorImpl2(JNIEnv *env, jobject obj, jint dirfd, jstring jpath) { +jlong Java_org_jau_io_ByteInStream_1File_ctorImpl2(JNIEnv *env, jclass cls, jint dirfd, jstring jpath) { try { - (void)obj; + (void)cls; // new instance const std::string path = jau::jni::from_jstring_to_string(env, jpath); jau::jni::shared_ptr_ref ref( new jau::io::ByteInStream_File(dirfd, path) ); @@ -56,9 +81,9 @@ jlong Java_org_jau_io_ByteInStream_1File_ctorImpl2(JNIEnv *env, jobject obj, jin return (jlong) (intptr_t)nullptr; } -jlong Java_org_jau_io_ByteInStream_1File_ctorImpl3(JNIEnv *env, jobject obj, jint fd) { +jlong Java_org_jau_io_ByteInStream_1File_ctorImpl3(JNIEnv *env, jclass cls, jint fd) { try { - (void)obj; + (void)cls; // new instance jau::jni::shared_ptr_ref ref( new jau::io::ByteInStream_File(fd) ); return ref.release_to_jlong(); @@ -90,10 +115,88 @@ void Java_org_jau_io_ByteInStream_1File_dtorImpl(JNIEnv *env, jclass clazz, jlon } } -jboolean Java_org_jau_io_ByteInStream_1File_check_1available(JNIEnv *env, jobject obj, jlong n) { +void Java_org_jau_io_ByteInStream_1File_clearImpl(JNIEnv *env, jobject obj, jint mask) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + ref->clear( static_cast(mask) ); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } +} + +jint Java_org_jau_io_ByteInStream_1File_fd(JNIEnv *env, jobject obj) { try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return ref->check_available((size_t)n) ? JNI_TRUE : JNI_FALSE; + return ref->fd(); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return -1; +} + +jint Java_org_jau_io_ByteInStream_1File_rdStateImpl(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return static_cast( ref->rdstate() ); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return static_cast(jau::io::iostate::failbit); +} + +void Java_org_jau_io_ByteInStream_1File_setStateImpl(JNIEnv *env, jobject obj, jint mask) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + ref->setstate( static_cast(mask) ); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } +} + +jboolean Java_org_jau_io_ByteInStream_1File_good(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->good() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_FALSE; +} + +jboolean Java_org_jau_io_ByteInStream_1File_eof(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->eof() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_TRUE; +} + +jboolean Java_org_jau_io_ByteInStream_1File_fail(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->fail() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_TRUE; +} + +jboolean Java_org_jau_io_ByteInStream_1File_bad(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->bad() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_FALSE; +} + +jboolean Java_org_jau_io_ByteInStream_1File_available(JNIEnv *env, jobject obj, jlong n) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->available((size_t)n) ? JNI_TRUE : JNI_FALSE; } catch(...) { rethrow_and_raise_java_exception_jau(env); } @@ -166,26 +269,6 @@ jint Java_org_jau_io_ByteInStream_1File_peek(JNIEnv *env, jobject obj, jbyteArra return 0; } -jboolean Java_org_jau_io_ByteInStream_1File_end_1of_1data(JNIEnv *env, jobject obj) { - try { - jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return ref->end_of_data() ? JNI_TRUE : JNI_FALSE; - } catch(...) { - rethrow_and_raise_java_exception_jau(env); - } - return JNI_TRUE; -} - -jboolean Java_org_jau_io_ByteInStream_1File_error(JNIEnv *env, jobject obj) { - try { - jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return ref->error() ? JNI_TRUE : JNI_FALSE; - } catch(...) { - rethrow_and_raise_java_exception_jau(env); - } - return JNI_TRUE; -} - jstring Java_org_jau_io_ByteInStream_1File_id(JNIEnv *env, jobject obj) { try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done @@ -200,7 +283,7 @@ jlong Java_org_jau_io_ByteInStream_1File_discard_1next(JNIEnv *env, jobject obj, try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done - const size_t res = ref->discard_next(n); + const size_t res = ref->discard(n); return (jlong)res; } catch(...) { rethrow_and_raise_java_exception_jau(env); @@ -208,10 +291,10 @@ jlong Java_org_jau_io_ByteInStream_1File_discard_1next(JNIEnv *env, jobject obj, return 0; } -jlong Java_org_jau_io_ByteInStream_1File_get_1bytes_1read(JNIEnv *env, jobject obj) { +jlong Java_org_jau_io_ByteInStream_1File_tellg(JNIEnv *env, jobject obj) { try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return static_cast( ref->get_bytes_read() ); + return static_cast( ref->tellg() ); } catch(...) { rethrow_and_raise_java_exception_jau(env); } diff --git a/java_jni/jni/jau/ByteInStream_URL.cxx b/java_jni/jni/jau/ByteInStream_URL.cxx index b85c114..17892d5 100644 --- a/java_jni/jni/jau/ByteInStream_URL.cxx +++ b/java_jni/jni/jau/ByteInStream_URL.cxx @@ -66,10 +66,78 @@ void Java_org_jau_io_ByteInStream_1URL_dtorImpl(JNIEnv *env, jclass clazz, jlong } } -jboolean Java_org_jau_io_ByteInStream_1URL_check_1available(JNIEnv *env, jobject obj, jlong n) { +void Java_org_jau_io_ByteInStream_1URL_clearImpl(JNIEnv *env, jobject obj, jint mask) { try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return ref->check_available((size_t)n) ? JNI_TRUE : JNI_FALSE; + ref->clear( static_cast(mask) ); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } +} + +jint Java_org_jau_io_ByteInStream_1URL_rdStateImpl(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return static_cast( ref->rdstate() ); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return static_cast(jau::io::iostate::failbit); +} + +void Java_org_jau_io_ByteInStream_1URL_setStateImpl(JNIEnv *env, jobject obj, jint mask) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + ref->setstate( static_cast(mask) ); + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } +} + +jboolean Java_org_jau_io_ByteInStream_1URL_good(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->good() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_FALSE; +} + +jboolean Java_org_jau_io_ByteInStream_1URL_eof(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->eof() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_TRUE; +} + +jboolean Java_org_jau_io_ByteInStream_1URL_fail(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->fail() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_TRUE; +} + +jboolean Java_org_jau_io_ByteInStream_1URL_bad(JNIEnv *env, jobject obj) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->bad() ? JNI_TRUE : JNI_FALSE; + } catch(...) { + rethrow_and_raise_java_exception_jau(env); + } + return JNI_FALSE; +} + +jboolean Java_org_jau_io_ByteInStream_1URL_available(JNIEnv *env, jobject obj, jlong n) { + try { + jau::jni::shared_ptr_ref ref(env, obj); // hold until done + return ref->available((size_t)n) ? JNI_TRUE : JNI_FALSE; } catch(...) { rethrow_and_raise_java_exception_jau(env); } @@ -142,26 +210,6 @@ jint Java_org_jau_io_ByteInStream_1URL_peek(JNIEnv *env, jobject obj, jbyteArray return 0; } -jboolean Java_org_jau_io_ByteInStream_1URL_end_1of_1data(JNIEnv *env, jobject obj) { - try { - jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return ref->end_of_data() ? JNI_TRUE : JNI_FALSE; - } catch(...) { - rethrow_and_raise_java_exception_jau(env); - } - return JNI_TRUE; -} - -jboolean Java_org_jau_io_ByteInStream_1URL_error(JNIEnv *env, jobject obj) { - try { - jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return ref->error() ? JNI_TRUE : JNI_FALSE; - } catch(...) { - rethrow_and_raise_java_exception_jau(env); - } - return JNI_TRUE; -} - jstring Java_org_jau_io_ByteInStream_1URL_id(JNIEnv *env, jobject obj) { try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done @@ -176,7 +224,7 @@ jlong Java_org_jau_io_ByteInStream_1URL_discard_1next(JNIEnv *env, jobject obj, try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done - const size_t res = ref->discard_next(n); + const size_t res = ref->discard(n); return (jlong)res; } catch(...) { rethrow_and_raise_java_exception_jau(env); @@ -184,10 +232,10 @@ jlong Java_org_jau_io_ByteInStream_1URL_discard_1next(JNIEnv *env, jobject obj, return 0; } -jlong Java_org_jau_io_ByteInStream_1URL_get_1bytes_1read(JNIEnv *env, jobject obj) { +jlong Java_org_jau_io_ByteInStream_1URL_tellg(JNIEnv *env, jobject obj) { try { jau::jni::shared_ptr_ref ref(env, obj); // hold until done - return static_cast( ref->get_bytes_read() ); + return static_cast( ref->tellg() ); } catch(...) { rethrow_and_raise_java_exception_jau(env); } diff --git a/java_jni/org/jau/io/ByteInStream.java b/java_jni/org/jau/io/ByteInStream.java index 7737fca..407f08b 100644 --- a/java_jni/org/jau/io/ByteInStream.java +++ b/java_jni/org/jau/io/ByteInStream.java @@ -26,7 +26,7 @@ package org.jau.io; import java.nio.ByteBuffer; /** - * This class represents an abstract byte input stream object. + * Abstract byte input stream object. * * Its specializations utilize a native C++ implementation * derived from `jau::io::ByteInStream`. @@ -36,15 +36,17 @@ import java.nio.ByteBuffer; * The byte input stream can originate from a local source w/o delay, * remote URL like http connection or even from another thread feeding the input buffer.
* Both latter asynchronous resources may expose blocking properties - * in check_available(). + * in available(). * * Asynchronous resources benefit from knowing their content size, - * as their check_available() implementation may avoid + * as their available() implementation may avoid * blocking and waiting for requested bytes available * if the stream is already beyond its scope. * - * One may use error() to detect whether an error has occurred, - * while end_of_data() not only covered the EOS case but includes error(). + * All method implementations are of `noexcept`. + * + * One may use fail() to detect whether an error has occurred, + * while end_of_data() not only covers the end-of-stream (EOS) case but includes fail(). * * @see @ref byte_in_stream_properties "ByteInStream Properties" */ @@ -69,37 +71,87 @@ public interface ByteInStream extends AutoCloseable { @Override void close(); + /** Clears state flags by assignment to the given value. */ + void clear(final IOState state); + + /** + * Returns the current state flags. + * + * Method is marked `virtual` to allow implementations with asynchronous resources + * to determine or update the current iostate. + * + * Method is used throughout all query members and setstate(), + * hence they all will use the updated state from a potential override implementation. + */ + IOState rdState(); + + /** Sets state flags, by keeping its previous bits. */ + void setState(final IOState state); + + /** Checks if no error nor eof() has occurred i.e. I/O operations are available. */ + boolean good(); + + /** Checks if end-of-file has been reached. */ + boolean eof(); + + /** Checks if an error has occurred. */ + boolean fail(); + + /** Checks if a non-recoverable error has occurred. */ + boolean bad(); + + /** + * Test whether the source still has data that can be read, synonym for !good(). + * + * Hence this includes errors in the underlying implementation, see fail() + * + * @return true if there is no more data to read, false otherwise + * @see good() + * @see fail() + */ + boolean end_of_data(); + /** - * Check whether n bytes are available in the input stream. + * Return whether n bytes are available in the input stream, + * if has_content_size() or using an asynchronous source. * - * This method may be blocking when using an asynchronous source - * up until the requested bytes are actually available. + * If !has_content_size() and not being an asynchronous source, + * !end_of_data() is returned. + * + * Method may be blocking when using an asynchronous source + * up until the requested bytes are available. * * A subsequent call to read() shall return immediately with at least - * the requested numbers of bytes available. + * the requested numbers of bytes available, + * if has_content_size() or using an asynchronous source. + * + * See details of the implementing class. * * @param n byte count to wait for * @return true if n bytes are available, otherwise false * + * @see has_content_size() * @see read() * @see @ref byte_in_stream_properties "ByteInStream Properties" */ - boolean check_available(long n); + boolean available(long n); /** * Read from the source. Moves the internal offset so that every * call to read will return a new portion of the source. * - * Use check_available() to wait and ensure a certain amount of bytes are available. + * Use available() to try to wait for a certain amount of bytes available. * - * This method is not blocking. + * This method shall only block until `min(available, length)` bytes are transfered. + * + * See details of the implementing class. * * @param out the byte array to write the result to * @param offset offset to in byte array to read into - * @param length number of in bytes to read into starting at offset + * @param length the length of the byte array out * @return length in bytes that was actually read and put into out * - * @see check_available() + * @see available() * @see @ref byte_in_stream_properties "ByteInStream Properties" */ int read(byte out[], final int offset, final int length); @@ -108,20 +160,19 @@ public interface ByteInStream extends AutoCloseable { * Read from the source. Moves the internal offset so that every * call to read will return a new portion of the source. * - * Use check_available() to wait and ensure a certain amount of bytes are available. + * Use available() to try to wait for a certain amount of bytes available. * - * This method is not blocking. + * This method shall only block until `min(available, length)` bytes are transfered. + * + * See details of the implementing class. * * @param out the direct {@link ByteBuffer} to write the result starting at its {@link ByteBuffer#position() position} up to its {@link ByteBuffer#capacity() capacity}. * {@link ByteBuffer#limit() Limit} will be set to {@link ByteBuffer#position() position} + read-bytes. * @return length in bytes that was actually read and put into out, * equal to its {@link ByteBuffer#limit() limit} - {@link ByteBuffer#position() position}, i.e. {@link ByteBuffer#remaining() remaining}. * - * @see check_available() + * @see available() * @see @ref byte_in_stream_properties "ByteInStream Properties" - * - * @param out - * @return */ int read(ByteBuffer out); @@ -138,23 +189,6 @@ public interface ByteInStream extends AutoCloseable { */ int peek(byte out[], final int offset, final int length, final long peek_offset); - /** - * Test whether the source still has data that can be read. - * - * This may include a failure and/or error in the underlying implementation, see error() - * - * @return true if there is no more data to read, false otherwise - * @see error() - */ - boolean end_of_data(); - - /** - * Return whether an error has occurred, excluding end_of_data(). - * - * @return true if an error has occurred, false otherwise - */ - boolean error(); - /** * return the id of this data source * @return std::string representing the id of this data source @@ -169,9 +203,11 @@ public interface ByteInStream extends AutoCloseable { long discard_next(long N); /** + * Returns the input position indicator, similar to std::basic_istream. + * * @return number of bytes read so far. */ - long bytes_read(); + long tellg(); /** * Returns true if implementation is aware of content_size(), otherwise false. diff --git a/java_jni/org/jau/io/ByteInStreamUtil.java b/java_jni/org/jau/io/ByteInStreamUtil.java index a58c408..b38785b 100644 --- a/java_jni/org/jau/io/ByteInStreamUtil.java +++ b/java_jni/org/jau/io/ByteInStreamUtil.java @@ -77,7 +77,7 @@ public interface ByteInStreamUtil { long total = 0; boolean has_more = !in.end_of_data(); while( has_more ) { - if( in.check_available(1) ) { // at least one byte to stream .. + if( in.available(1) ) { // at least one byte to stream .. final int got = in.read(buffer, 0, buffer.length); total += got; @@ -128,7 +128,7 @@ public interface ByteInStreamUtil { long total = 0; boolean has_more = !in.end_of_data(); while( has_more ) { - if( in.check_available(1) ) { // at least one byte to stream .. + if( in.available(1) ) { // at least one byte to stream .. final int got = in.read(buffer); total += got; @@ -157,7 +157,7 @@ public interface ByteInStreamUtil { * If non of the above leads to a ByteInStream without {@link ByteInStreamUtil#error()}, null is returned. * * @param path_or_uri given path or uri for with a ByteInStream instance shall be established. - * @param timeoutMS a timeout in case ByteInStream_URL is being used as maximum duration in milliseconds to wait for next bytes at {@link ByteInStream_URL#check_available(long)}, defaults to 20_s + * @param timeoutMS a timeout in case ByteInStream_URL is being used as maximum duration in milliseconds to wait for next bytes at {@link ByteInStream_URL#available(long)}, defaults to 20_s * @return a working ByteInStream w/o {@link ByteInStreamUtil#error()} or nullptr */ public static ByteInStream to_ByteInStream(final String path_or_uri, final long timeoutMS) { @@ -165,12 +165,12 @@ public interface ByteInStreamUtil { org.jau.io.UriTk.protocol_supported(path_or_uri) ) { final ByteInStream res = new ByteInStream_URL(path_or_uri, timeoutMS); - if( null != res && !res.error() ) { + if( null != res && !res.fail() ) { return res; } } final ByteInStream res = new ByteInStream_File(path_or_uri); - if( null != res && !res.error() ) { + if( null != res && !res.fail() ) { return res; } return null; @@ -183,7 +183,7 @@ public interface ByteInStreamUtil { * * If non of the above leads to a ByteInStream without {@link ByteInStreamUtil#error()}, null is returned. * - * Method uses a timeout of 20_s for maximum duration to wait for next bytes at {@link ByteInStream_URL#check_available(long)} + * Method uses a timeout of 20_s for maximum duration to wait for next bytes at {@link ByteInStream_URL#available(long)} * * @param path_or_uri given path or uri for with a ByteInStream instance shall be established. * @return a working ByteInStream w/o {@link ByteInStreamUtil#error()} or nullptr diff --git a/java_jni/org/jau/io/ByteInStream_Feed.java b/java_jni/org/jau/io/ByteInStream_Feed.java index e9cb26e..96faa3f 100644 --- a/java_jni/org/jau/io/ByteInStream_Feed.java +++ b/java_jni/org/jau/io/ByteInStream_Feed.java @@ -71,7 +71,40 @@ public final class ByteInStream_Feed implements ByteInStream { } @Override - public native boolean check_available(final long n); + public void clear(final IOState state) { + clearImpl( state.mask ); + } + private native void clearImpl(int s); + + @Override + public IOState rdState() { + return new IOState( rdStateImpl() ); + } + private native int rdStateImpl(); + + @Override + public void setState(final IOState state) { + setStateImpl( state.mask ); + } + private native void setStateImpl(int s); + + @Override + public native boolean good(); + + @Override + public native boolean eof(); + + @Override + public native boolean fail(); + + @Override + public native boolean bad(); + + @Override + public boolean end_of_data() { return !good(); } + + @Override + public native boolean available(final long n); @Override public native int read(final byte[] out, final int offset, final int length); @@ -90,12 +123,6 @@ public final class ByteInStream_Feed implements ByteInStream { @Override public native int peek(byte[] out, final int offset, final int length, final long peek_offset); - @Override - public native boolean end_of_data(); - - @Override - public native boolean error(); - @Override public native String id(); @@ -103,7 +130,7 @@ public final class ByteInStream_Feed implements ByteInStream { public native long discard_next(long N); @Override - public native long bytes_read(); + public native long tellg(); @Override public native boolean has_content_size(); diff --git a/java_jni/org/jau/io/ByteInStream_File.java b/java_jni/org/jau/io/ByteInStream_File.java index 4b30431..ff2448f 100644 --- a/java_jni/org/jau/io/ByteInStream_File.java +++ b/java_jni/org/jau/io/ByteInStream_File.java @@ -26,10 +26,13 @@ package org.jau.io; import java.nio.ByteBuffer; /** - * This class represents a file based byte input stream, including named file descriptor. + * File based byte input stream, including named file descriptor. * - * If source path denotes a named file descriptor, i.e. {@link org.jau.fs.FileStats#has_fd()} returns true, - * has_content_size() returns false and check_available() returns true as long the stream is open and EOS hasn't occurred. + * Implementation mimics std::ifstream via OS level file descriptor (FD) operations, + * giving more flexibility, allowing reusing existing FD and enabling openat() operations. + * + * If source path denotes a named file descriptor, i.e. jau::fs::file_stats::is_fd() returns true, + * has_content_size() returns false and available() returns true as long the stream is open and EOS hasn't occurred. * * Instance uses the native C++ object `jau::io::ByteInStream_File`. */ @@ -53,7 +56,7 @@ public final class ByteInStream_File implements ByteInStream { throw t; } } - private native long ctorImpl1(final String path); + private static native long ctorImpl1(final String path); /** * Construct a stream based byte input stream from filesystem path and parent directory file descriptor @@ -72,7 +75,7 @@ public final class ByteInStream_File implements ByteInStream { throw t; } } - private native long ctorImpl2(final int dirfd, final String path); + private static native long ctorImpl2(final int dirfd, final String path); /** * Construct a stream based byte input stream by duplicating given file descriptor @@ -90,7 +93,7 @@ public final class ByteInStream_File implements ByteInStream { throw t; } } - private native long ctorImpl3(final int fd); + private static native long ctorImpl3(final int fd); @Override public native void closeStream(); @@ -114,7 +117,47 @@ public final class ByteInStream_File implements ByteInStream { } @Override - public native boolean check_available(final long n); + public void clear(final IOState state) { + clearImpl( state.mask ); + } + private native void clearImpl(int s); + + /** + * Returns the file descriptor if is_open(), otherwise -1 for no file descriptor. + * + * @see is_open() + */ + public native int fd(); + + @Override + public IOState rdState() { + return new IOState( rdStateImpl() ); + } + private native int rdStateImpl(); + + @Override + public void setState(final IOState state) { + setStateImpl( state.mask ); + } + private native void setStateImpl(int s); + + @Override + public native boolean good(); + + @Override + public native boolean eof(); + + @Override + public native boolean fail(); + + @Override + public native boolean bad(); + + @Override + public boolean end_of_data() { return !good(); } + + @Override + public native boolean available(final long n); @Override public native int read(final byte[] out, final int offset, final int length); @@ -133,12 +176,6 @@ public final class ByteInStream_File implements ByteInStream { @Override public native int peek(byte[] out, final int offset, final int length, final long peek_offset); - @Override - public native boolean end_of_data(); - - @Override - public native boolean error(); - @Override public native String id(); @@ -146,7 +183,7 @@ public final class ByteInStream_File implements ByteInStream { public native long discard_next(long N); @Override - public native long bytes_read(); + public native long tellg(); @Override public native boolean has_content_size(); diff --git a/java_jni/org/jau/io/ByteInStream_URL.java b/java_jni/org/jau/io/ByteInStream_URL.java index 99ac020..e4d0a68 100644 --- a/java_jni/org/jau/io/ByteInStream_URL.java +++ b/java_jni/org/jau/io/ByteInStream_URL.java @@ -75,7 +75,40 @@ public final class ByteInStream_URL implements ByteInStream { } @Override - public native boolean check_available(final long n); + public void clear(final IOState state) { + clearImpl( state.mask ); + } + private native void clearImpl(int s); + + @Override + public IOState rdState() { + return new IOState( rdStateImpl() ); + } + private native int rdStateImpl(); + + @Override + public void setState(final IOState state) { + setStateImpl( state.mask ); + } + private native void setStateImpl(int s); + + @Override + public native boolean good(); + + @Override + public native boolean eof(); + + @Override + public native boolean fail(); + + @Override + public native boolean bad(); + + @Override + public boolean end_of_data() { return !good(); } + + @Override + public native boolean available(final long n); @Override public native int read(final byte[] out, final int offset, final int length); @@ -94,12 +127,6 @@ public final class ByteInStream_URL implements ByteInStream { @Override public native int peek(byte[] out, final int offset, final int length, final long peek_offset); - @Override - public native boolean end_of_data(); - - @Override - public native boolean error(); - @Override public native String id(); @@ -107,7 +134,7 @@ public final class ByteInStream_URL implements ByteInStream { public native long discard_next(long N); @Override - public native long bytes_read(); + public native long tellg(); @Override public native boolean has_content_size(); diff --git a/java_jni/org/jau/io/IOState.java b/java_jni/org/jau/io/IOState.java new file mode 100644 index 0000000..b5e5eb3 --- /dev/null +++ b/java_jni/org/jau/io/IOState.java @@ -0,0 +1,92 @@ +/** + * Author: Sven Gothel + * Copyright (c) 2022 Gothel Software e.K. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package org.jau.io; + +/** + * Mimic std::ios_base::iostate for state functionality, see iostate_func. + * + * This `enum class` type fulfills `C++ named requirements: BitmaskType`. + * + * @see ByteInStream + */ +public class IOState { + public enum Bit { + /** No error occurred nor has EOS being reached. Value is no bit set! */ + none ( 0 ), + + /** No error occurred nor has EOS being reached. Value is no bit set! */ + goodbit ( 0 ), + + /** Irrecoverable stream error, including loss of integrity of the underlying stream or media. */ + badbit ( 1 << 0 ), + + /** An input operation reached the end of its stream. */ + eofbit ( 1 << 1 ), + + /** Input or output operation failed (formatting or extraction error). */ + failbit ( 1 << 2 ); + + Bit(final int v) { value = v; } + public final int value; + } + public int mask; + + public IOState(final int v) { + mask = v; + } + public IOState() { + mask = 0; + } + + public boolean isSet(final Bit bit) { return bit.value == ( mask & bit.value ); } + + /** + * Sets the given bit and returns this instance for chaining. + * @param bit the given Bit value to set + * @return this instance for chaining. + */ + public IOState set(final Bit bit) { mask = (short) ( mask | bit.value ); return this; } + + public IOState mask(final int bits) { + final int r = mask & bits; + if( r == mask ) { return this; } + else { return new IOState(r); } + } + + private static native String to_string(final int mask); + + @Override + public String toString() { + return to_string(mask); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } + return (other instanceof IOState) && + this.mask == ((IOState)other).mask; + } +} -- cgit v1.2.3