subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From br...@apache.org
Subject svn commit: r1543985 - in /subversion/trunk/subversion/bindings/javahl: native/ native/jniwrapper/ src/org/apache/subversion/javahl/types/ src/org/apache/subversion/javahl/util/ tests/org/apache/subversion/javahl/
Date Wed, 20 Nov 2013 23:43:32 GMT
Author: brane
Date: Wed Nov 20 23:43:31 2013
New Revision: 1543985

URL: http://svn.apache.org/r1543985
Log:
Implement streamed file contents translation utilities in JavaHL.

[in subversion/bindings/javahl]
* src/org/apache/subversion/javahl/types/NativeInputStream.java,
  src/org/apache/subversion/javahl/types/NativeOutputStream.java:
   New classes. Provide Java-to-native stream translation.

* src/org/apache/subversion/javahl/util/SubstLib.java
  (SubstLib.translateInputStream, SubstLib.translateInputStream):
   Re-declare methods as native.

* native/NativeStream.hpp, native/NativeStream.cpp: New files.
  (JavaHL::NativeInputStream, JavaHL::NativeOutputStream):
   Native bound implementations of the equivalent Java classes.
* native/jniwrapper/jni_io_stream.hpp,
  native/jniwrapper/jni_io_stream.cpp: New files.
  (Java::InputStream, Java::OutputStream): New classes.
   Provide native-to-Java stream translation.

* native/org_apache_subversion_javahl_util_SubstLib.cpp
  (build_keywords_common, translate_stream_common
   KeywordHashBuilder, make_keywords_hash): New helper functions.
  (Java_org_apache_subversion_javahl_util_SubstLib_buildKeywords):
   Reimplement, using build_keywords_common.
  (Java_org_apache_subversion_javahl_util_SubstLib_translateInputStream,
   Java_org_apache_subversion_javahl_util_SubstLib_translateOutputStream):
   SustLib native method implementations.

* tests/org/apache/subversion/javahl/UtilTests.java
  (UtilTests.testTranslateStream): New test case.
  (UtilTests.testBuildKeywords): Tweak test data to match.

Added:
    subversion/trunk/subversion/bindings/javahl/native/NativeStream.cpp   (with props)
    subversion/trunk/subversion/bindings/javahl/native/NativeStream.hpp   (with props)
    subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp   (with props)
    subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.hpp   (with props)
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeInputStream.java   (with props)
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeOutputStream.java   (with props)
Modified:
    subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp
    subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java
    subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java

Added: subversion/trunk/subversion/bindings/javahl/native/NativeStream.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/NativeStream.cpp?rev=1543985&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/NativeStream.cpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/NativeStream.cpp Wed Nov 20 23:43:31 2013
@@ -0,0 +1,320 @@
+/**
+ * @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 "NativeStream.hpp"
+
+#include "jniwrapper/jni_stack.hpp"
+#include "jniwrapper/jni_exception.hpp"
+
+#include "svn_private_config.h"
+
+namespace JavaHL {
+
+// Class JavaHL::NativeInputStream
+
+const char* const NativeInputStream::m_class_name =
+    JAVA_PACKAGE "/types/NativeInputStream";
+
+NativeInputStream::~NativeInputStream() {}
+
+NativeInputStream*
+NativeInputStream::get_self(::Java::Env env, jobject jthis)
+{
+  jfieldID fid_cppaddr = NULL;
+  const jlong cppaddr =
+    findCppAddrForJObject(jthis, &fid_cppaddr, m_class_name);
+  if (!cppaddr)
+    ::Java::NullPointerException(env).raise(_("this [C++]"));
+  return reinterpret_cast<NativeInputStream*>(cppaddr);
+}
+
+void NativeInputStream::close(::Java::Env env, jobject jthis)
+{
+  SVN_JAVAHL_CHECK(env, svn_stream_close(m_stream));
+  dispose(jthis);
+}
+
+bool NativeInputStream::mark_supported(::Java::Env env) const
+{
+  return svn_stream_supports_mark(m_stream);
+}
+
+void NativeInputStream::mark(::Java::Env env)
+{
+  if (!svn_stream_supports_mark(m_stream))
+    return;
+  SVN_JAVAHL_CHECK(env, svn_stream_mark(m_stream, &m_mark, pool.getPool()));
+}
+
+void NativeInputStream::reset(::Java::Env env)
+{
+  if (!svn_stream_supports_mark(m_stream))
+    return;
+  if (m_mark)
+    SVN_JAVAHL_CHECK(env, svn_stream_seek(m_stream, m_mark));
+  else
+    ::Java::IOException(env).raise(_("Invalid seek on native stream"));
+ }
+
+jint NativeInputStream::read(::Java::Env env)
+{
+  apr_size_t len = 1;
+  char byte;
+  SVN_JAVAHL_CHECK(env, svn_stream_read(m_stream, &byte, &len));
+  if (len == 0)
+    return -1;                  // EOF
+  if (len != 1)
+    return jint(byte & 0xff);
+  ::Java::IOException(env).raise(_("Read from native stream failed"));
+  return -1;
+}
+
+jint NativeInputStream::read(::Java::Env env,
+                             ::Java::ByteArray::MutableContents& dst,
+                             jint offset, jint length)
+{
+  if (offset < 0 || length < 0 || offset + length > dst.length())
+    ::Java::IndexOutOfBoundsException(env).raise();
+  if (!dst.data())
+    ::Java::NullPointerException(env).raise();
+
+  apr_size_t len = length;
+  SVN_JAVAHL_CHECK(env, svn_stream_read(m_stream, dst.data() + offset, &len));
+  if (len == 0)
+    return -1;                  // EOF
+  if (len <= length)
+    return jint(len);
+  ::Java::IOException(env).raise(_("Read from native stream failed"));
+  return -1;
+}
+
+jlong NativeInputStream::skip(::Java::Env env, jlong count)
+{
+  const apr_size_t len = count;
+  SVN_JAVAHL_CHECK(env, svn_stream_skip(m_stream, len));
+  return count;
+}
+
+void NativeInputStream::dispose(jobject jthis)
+{
+  jfieldID fid_cppaddr = NULL;
+  SVNBase::dispose(jthis, &fid_cppaddr, m_class_name);
+}
+
+
+// Class JavaHL::NativeOutputStream
+
+const char* const NativeOutputStream::m_class_name =
+  JAVA_PACKAGE "/types/NativeOutputStream";
+
+NativeOutputStream::~NativeOutputStream() {}
+
+NativeOutputStream*
+NativeOutputStream::get_self(::Java::Env env, jobject jthis)
+{
+  jfieldID fid_cppaddr = NULL;
+  const jlong cppaddr =
+    findCppAddrForJObject(jthis, &fid_cppaddr, m_class_name);
+  if (!cppaddr)
+    ::Java::NullPointerException(env).raise(_("this [C++]"));
+  return reinterpret_cast<NativeOutputStream*>(cppaddr);
+}
+
+void NativeOutputStream::close(::Java::Env env, jobject jthis)
+{
+  SVN_JAVAHL_CHECK(env, svn_stream_close(m_stream));
+  dispose(jthis);
+}
+
+void NativeOutputStream::write(::Java::Env env, jint byte)
+{
+  const char data = char(byte & 0xff);
+  apr_size_t len = 1;
+  SVN_JAVAHL_CHECK(env, svn_stream_write(m_stream, &data, &len));
+  if (len != 1)
+    ::Java::IOException(env).raise(_("Write to native stream failed"));
+}
+
+void NativeOutputStream::write(::Java::Env env,
+                               const ::Java::ByteArray::Contents& src,
+                               jint offset, jint length)
+{
+  if (offset < 0 || length < 0 || offset + length > src.length())
+    ::Java::IndexOutOfBoundsException(env).raise();
+  if (!src.data())
+    ::Java::NullPointerException(env).raise();
+
+  apr_size_t len = length;
+  SVN_JAVAHL_CHECK(env, svn_stream_write(m_stream, src.data() + offset, &len));
+  if (len != length)
+    ::Java::IOException(env).raise(_("Write to native stream failed"));
+}
+
+void NativeOutputStream::dispose(jobject jthis)
+{
+  jfieldID fid_cppaddr = NULL;
+  SVNBase::dispose(jthis, &fid_cppaddr, m_class_name);
+}
+
+} // namespace JavaHL
+
+
+// Class JavaHL::NativeInputStream native method implementation
+#include "../include/org_apache_subversion_javahl_types_NativeInputStream.h"
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_types_NativeInputStream_close(
+    JNIEnv* jenv, jobject jthis)
+{
+  SVN_JAVAHL_JNI_TRY(NativeInputStream, close)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeInputStream, self);
+      self->close(Java::Env(jenv), jthis);
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_org_apache_subversion_javahl_types_NativeInputStream_markSupported(
+    JNIEnv* jenv, jobject jthis)
+{
+  SVN_JAVAHL_JNI_TRY(NativeInputStream, markSupported)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeInputStream, self);
+      self->mark_supported(Java::Env(jenv));
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+  return false;
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_types_NativeInputStream_mark(
+    JNIEnv* jenv, jobject jthis, jint)
+{
+  SVN_JAVAHL_JNI_TRY(NativeInputStream, mark)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeInputStream, self);
+      self->mark(Java::Env(jenv));
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_types_NativeInputStream_reset(
+    JNIEnv* jenv, jobject jthis)
+{
+  SVN_JAVAHL_JNI_TRY(NativeInputStream, reset)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeInputStream, self);
+      self->reset(Java::Env(jenv));
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_apache_subversion_javahl_types_NativeInputStream_read__(
+    JNIEnv* jenv, jobject jthis)
+{
+  SVN_JAVAHL_JNI_TRY(NativeInputStream, read)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeInputStream, self);
+      return self->read(Java::Env(jenv));
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+  return 0;
+}
+
+JNIEXPORT jint JNICALL
+Java_org_apache_subversion_javahl_types_NativeInputStream_read___3BII(
+    JNIEnv* jenv, jobject jthis, jbyteArray jdst, jint joffset, jint jlength)
+{
+  SVN_JAVAHL_JNI_TRY(NativeInputStream, read)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeInputStream, self);
+
+      const Java::Env env(jenv);
+      Java::ByteArray dst(env, jdst);
+      Java::ByteArray::MutableContents dst_contents(dst);
+
+      return self->read(env, dst_contents, joffset, jlength);
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+  return 0;
+}
+
+JNIEXPORT jlong JNICALL
+Java_org_apache_subversion_javahl_types_NativeInputStream_skip(
+    JNIEnv* jenv, jobject jthis, jlong jcount)
+{
+  SVN_JAVAHL_JNI_TRY(NativeInputStream, skip)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeInputStream, self);
+      return self->skip(Java::Env(jenv), jcount);
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+  return 0;
+}
+
+
+// Class JavaHL::NativeOutputStream native method implementation
+#include "../include/org_apache_subversion_javahl_types_NativeOutputStream.h"
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_types_NativeOutputStream_close(
+    JNIEnv* jenv, jobject jthis)
+{
+  SVN_JAVAHL_JNI_TRY(NativeOutputStream, close)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeOutputStream, self);
+      self->close(Java::Env(jenv), jthis);
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_types_NativeOutputStream_write__I(
+    JNIEnv* jenv, jobject jthis, jint byte)
+{
+  SVN_JAVAHL_JNI_TRY(NativeOutputStream, write)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeOutputStream, self);
+      self->write(Java::Env(jenv), byte);
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+}
+
+JNIEXPORT void JNICALL
+Java_org_apache_subversion_javahl_types_NativeOutputStream_write___3BII(
+    JNIEnv* jenv, jobject jthis, jbyteArray jsrc, jint joffset, jint jlength)
+{
+  SVN_JAVAHL_JNI_TRY(NativeOutputStream, write)
+    {
+      SVN_JAVAHL_GET_BOUND_OBJECT(JavaHL::NativeOutputStream, self);
+
+      const Java::Env env(jenv);
+      const Java::ByteArray src(env, jsrc);
+
+      self->write(env, Java::ByteArray::Contents(src), joffset, jlength);
+    }
+  SVN_JAVAHL_JNI_CATCH_TO_EXCEPTION(Java::IOException);
+}

Propchange: subversion/trunk/subversion/bindings/javahl/native/NativeStream.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/trunk/subversion/bindings/javahl/native/NativeStream.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/NativeStream.hpp?rev=1543985&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/NativeStream.hpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/NativeStream.hpp Wed Nov 20 23:43:31 2013
@@ -0,0 +1,218 @@
+/**
+ * @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
+ */
+
+#ifndef SVN_JAVAHL_NATIVE_STREAM_HPP
+#define SVN_JAVAHL_NATIVE_STREAM_HPP
+
+#include <stdexcept>
+
+#include "jniwrapper/jni_array.hpp"
+
+#include "SVNBase.h"
+
+#include "svn_io.h"
+#include "svn_private_config.h"
+
+namespace JavaHL {
+
+/**
+ * Object wrapper for @c org.apache.subversion.javahl.types.NativeInputStream.
+ *
+ * @since New in 1.9.
+ */
+class NativeInputStream : public ::SVNBase
+{
+public:
+  /**
+   * Construcs the native instance that will be wrapped in a Java obejct.
+   * If @a stream is @c NULL, you must call #set_stream before creating
+   * the Java wrapper.
+   */
+  explicit NativeInputStream(svn_stream_t* stream = NULL)
+    : m_stream(stream),
+      m_mark(NULL)
+    {}
+
+  ~NativeInputStream();
+
+  /**
+   * Returns a reference to the pool owned by this wrapped object.
+   */
+  const SVN::Pool& get_pool() const
+    {
+      return pool;
+    }
+
+  /**
+   * Sets the @a stream that this object will own.
+   * Do not call this function if a stream was passed to the constructor.
+   */
+  void set_stream(svn_stream_t* stream)
+    {
+      if (m_stream)
+        throw std::logic_error(_("Native input stream is already bound"));
+      m_stream = stream;
+    }
+
+  /**
+   * Create the Java object that binds to this native object.
+   */
+  jobject create_java_wrapper()
+    {
+      return createCppBoundObject(m_class_name);
+    }
+
+  /**
+   * Retreive the address of the native object from the bound Java object.
+   */
+  static NativeInputStream* get_self(::Java::Env env, jobject jthis);
+
+public:
+  /**
+   * Implements @c InputStream.close().
+   * Also disposes the native object.
+   */
+  void close(::Java::Env env, jobject jthis);
+
+  /**
+   * Implements @c InputStream.markSupported().
+   */
+  bool mark_supported(::Java::Env env) const;
+
+  /**
+   * Implements @c InputStream.mark(int).
+   * The @c readlimit parameter of the Java method is ignored.
+   */
+  void mark(::Java::Env env);
+
+  /**
+   * Implements @c InputStream.reset().
+   */
+  void reset(::Java::Env env);
+
+  /**
+   * Implements @c InputStream.read().
+   */
+  jint read(::Java::Env env);
+
+  /**
+   * Implements @c InputStream.read(byte[],int,int).
+   */
+  jint read(::Java::Env env,
+            ::Java::ByteArray::MutableContents& dst,
+            jint offset, jint length);
+
+  /**
+   * Implements @c InputStream.skip(long).
+   */
+  jlong skip(::Java::Env env, jlong count);
+
+private:
+  virtual void dispose(jobject jthis);
+
+  static const char* const m_class_name;
+  svn_stream_t* m_stream;
+  svn_stream_mark_t* m_mark;
+};
+
+
+/**
+ * Object wrapper for @c org.apache.subversion.javahl.types.NativeOutputStream.
+ *
+ * @since New in 1.9.
+ */
+class NativeOutputStream : public ::SVNBase
+{
+public:
+  /**
+   * Construcs the native instance that will be wrapped in a Java obejct.
+   * If @a stream is @c NULL, you must call #set_stream before creating
+   * the Java wrapper.
+   */
+  explicit NativeOutputStream(svn_stream_t* stream = NULL)
+    : m_stream(stream)
+    {}
+
+  ~NativeOutputStream();
+
+  /**
+   * Returns a reference to the pool owned by this wrapped object.
+   */
+  const SVN::Pool& get_pool() const
+    {
+      return pool;
+    }
+
+  /**
+   * Sets the @a stream that this object will own.
+   * Do not call this function if a stream was passed to the constructor.
+   */
+  void set_stream(svn_stream_t* stream)
+    {
+      if (m_stream)
+        throw std::logic_error(_("Native output stream is already bound"));
+      m_stream = stream;
+    }
+
+  /**
+   * Create the Java object that binds to this native object.
+   */
+  jobject create_java_wrapper()
+    {
+      return createCppBoundObject(m_class_name);
+    }
+
+  /**
+   * Retreive the address of the native object from the bound Java object.
+   */
+  static NativeOutputStream* get_self(::Java::Env env, jobject jthis);
+
+public:
+  /**
+   * Implements @c OutputStream.close().
+   * Also disposes the native object.
+   */
+  void close(::Java::Env env, jobject jthis);
+
+  /**
+   * Implements @c OutputStream.write(int).
+   */
+  void write(::Java::Env env, jint byte);
+
+  /**
+   * Implements @c OutputStream.write(byte[],int,int).
+   */
+  void write(::Java::Env env,
+             const ::Java::ByteArray::Contents& src,
+             jint offset, jint length);
+
+private:
+  virtual void dispose(jobject jthis);
+
+  static const char* const m_class_name;
+  svn_stream_t* m_stream;
+};
+
+} // namespace JavaHL
+
+#endif // SVN_JAVAHL_NATIVE_STREAM_HPP

Propchange: subversion/trunk/subversion/bindings/javahl/native/NativeStream.hpp
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp?rev=1543985&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp Wed Nov 20 23:43:31 2013
@@ -0,0 +1,240 @@
+/**
+ * @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)
+{
+  InputStream* const self = static_cast<InputStream*>(baton);
+  SVN_JAVAHL_CATCH(self->get_env(), SVN_ERR_BASE,
+                   *len = self->read(buffer, jint(*len)));
+  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";
+
+svn_stream_t*
+InputStream::get_global_stream(Env env, jobject jstream,
+                               const SVN::Pool& pool)
+{
+  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_read(stream, global_stream_read);
+  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)
+{
+  const bool has_mark = mark_supported();
+
+  svn_stream_t* const stream = svn_stream_create(this, pool.getPool());
+  svn_stream_set_read(stream, stream_read);
+  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;
+}
+
+
+// Class Java::OutputStream
+
+const char* const OutputStream::m_class_name = "java/io/OutputStream";
+
+svn_stream_t*
+OutputStream::get_global_stream(Env env, jobject jstream,
+                               const SVN::Pool& pool)
+{
+  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)
+{
+  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

Propchange: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.hpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.hpp?rev=1543985&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.hpp (added)
+++ subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.hpp Wed Nov 20 23:43:31 2013
@@ -0,0 +1,260 @@
+/**
+ * @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
+ */
+
+#ifndef SVN_JAVAHL_JNIWRAPPER_IO_STREAM_HPP
+#define SVN_JAVAHL_JNIWRAPPER_IO_STREAM_HPP
+
+#include <cstring>
+#include <string>
+#include <memory>
+
+#include "jni_object.hpp"
+#include "jni_array.hpp"
+
+#include "../Pool.h"
+
+#include "svn_io.h"
+
+namespace Java {
+
+/**
+ * Object wrapper for @c java.io.InputStream.
+ *
+ * @since New in 1.9.
+ */
+class InputStream : public Object
+{
+public:
+  /**
+   * Constructs a wrapper around an existing @c InputStream @a jstream.
+   */
+  explicit InputStream(Env env, jobject jstream)
+    : Object(env, m_class_name, jstream)
+    {}
+
+  /**
+   * Creates a stand-alone @c svn_stream_t allocated from @a pool that
+   * contains a global reference to @a jstream. This stream can safely
+   * be used in long-lived bound objects.
+   */
+  static svn_stream_t*
+  get_global_stream(Env env, jobject jstream, const SVN::Pool& pool);
+
+  /**
+   * Creates an @c svn_stream_t allocated from @a pool.
+   * <b>Do not use the returned stream past the lifetime of the
+   * current JNI native frame.</b>
+   */
+  svn_stream_t* get_stream(const SVN::Pool& pool);
+
+public:
+  /**
+   * Implements @c InputStream.close()
+   */
+  void close()
+    {
+      if (!m_mid_close)
+        m_mid_close = m_env.GetMethodID(m_class, "close", "()V");
+      m_env.CallVoidMethod(m_jthis, m_mid_close);
+    }
+
+  /**
+   * Implements @c InputStream.markSupported()
+   */
+  bool mark_supported()
+    {
+      if (!m_mid_mark_supported)
+        m_mid_mark_supported = m_env.GetMethodID(m_class,
+                                                 "markSupported", "()Z");
+      return m_env.CallBooleanMethod(m_jthis, m_mid_mark_supported);
+    }
+
+  /**
+   * Implements @c InputStream.mark(int)
+   */
+  void mark(jint readlimit)
+    {
+      if (!m_mid_mark)
+        m_mid_mark = m_env.GetMethodID(m_class, "mark", "(I)V");
+      m_env.CallVoidMethod(m_jthis, m_mid_mark, readlimit);
+    }
+
+  /**
+   * Implements @c InputStream.reset()
+   */
+  void reset()
+    {
+      if (!m_mid_reset)
+        m_mid_reset = m_env.GetMethodID(m_class, "reset", "()V");
+      m_env.CallVoidMethod(m_jthis, m_mid_reset);
+    }
+
+  /**
+   * Implements @c InputStream.read()
+   */
+  jint read()
+    {
+      if (!m_mid_read_byte)
+        m_mid_read_byte = m_env.GetMethodID(m_class, "read", "()I");
+      return m_env.CallIntMethod(m_jthis, m_mid_read_byte);
+    }
+
+  /**
+   * Implements @c InputStream.read(byte[],int,int)
+   */
+  jint read(ByteArray& dst, jint length = -1, jint offset = 0)
+    {
+      if (!m_mid_read_bytearray)
+        m_mid_read_bytearray = m_env.GetMethodID(m_class, "read", "([BII)I");
+      return m_env.CallIntMethod(m_jthis, m_mid_read_bytearray,
+                                 dst.get(), offset,
+                                 (length >= 0 ? length
+                                  : dst.length() - offset));
+    }
+
+  /**
+   * Helper method to read data into a native buffer.
+   */
+  jint read(void* data, jint length, jint offset = 0)
+    {
+      ByteArray array(m_env, length);
+      const jint size = read(array);
+      ByteArray::Contents contents(array);
+      ::memcpy(static_cast<char*>(data) + offset, contents.data(), size);
+      return size;
+    }
+
+  /**
+   * Implements @c InputStream.skip(long)
+   */
+  jlong skip(jlong count);
+
+private:
+  static const char* const m_class_name;
+  MethodID m_mid_close;
+  MethodID m_mid_mark_supported;
+  MethodID m_mid_mark;
+  MethodID m_mid_reset;
+  MethodID m_mid_read_byte;
+  MethodID m_mid_read_bytearray;
+};
+
+
+/**
+ * Object wrapper for @c java.io.OutputStream.
+ *
+ * @since New in 1.9.
+ */
+class OutputStream : public Object
+{
+public:
+  /**
+   * Constructs a wrapper around an existing @c OutputStream @a jstream.
+   */
+  explicit OutputStream(Env env, jobject jstream)
+    : Object(env, m_class_name, jstream)
+    {}
+
+  /**
+   * Creates a stand-alone @c svn_stream_t allocated from @a pool that
+   * contains a global reference to @a jstream. This stream can safely
+   * be used in long-lived bound objects.
+   */
+  static svn_stream_t*
+  get_global_stream(Env env, jobject jstream, const SVN::Pool& pool);
+
+  /**
+   * Creates an @c svn_stream_t allocated from @a pool.
+   * <b>Do not use the returned stream past the lifetime of the
+   * current JNI native frame.</b>
+   */
+  svn_stream_t* get_stream(const SVN::Pool& pool);
+
+public:
+  /**
+   * Implements @c OuptutStream.close()
+   */
+  void close()
+    {
+      if (!m_mid_close)
+        m_mid_close = m_env.GetMethodID(m_class, "close", "()V");
+      m_env.CallVoidMethod(m_jthis, m_mid_close);
+    }
+
+  /**
+   * Implements @c OuptutStream.write(int)
+   */
+  void write(jint byte)
+    {
+      if (!m_mid_write_byte)
+        m_mid_write_byte = m_env.GetMethodID(m_class, "write", "(I)V");
+      m_env.CallVoidMethod(m_jthis, m_mid_write_byte, byte);
+    }
+
+  /**
+   * Implements @c OuptutStream.write(byte[],int,int)
+   */
+  void write(const ByteArray& src, jint length = -1, jint offset = 0)
+    {
+      if (!m_mid_write_bytearray)
+        m_mid_write_bytearray = m_env.GetMethodID(m_class, "write", "([BII)V");
+      m_env.CallVoidMethod(m_jthis, m_mid_write_bytearray,
+                           src.get(), offset,
+                           (length >= 0 ? length
+                            : src.length() - offset));
+    }
+
+  /**
+   * Helper method to write data from a native buffer.
+   */
+  void write(const void* data, jint length, jint offset = 0)
+    {
+      write(ByteArray(m_env, data, length));
+    }
+
+  /**
+   * Helper method to write a C string to the stream.
+   */
+  void write(const char* text)
+    {
+      write(ByteArray(m_env, text));
+    }
+
+  /**
+   * Helper method to write a C++ string to the stream.
+   */
+  void write(const std::string& text)
+    {
+      write(ByteArray(m_env, text));
+    }
+
+private:
+  static const char* const m_class_name;
+  MethodID m_mid_close;
+  MethodID m_mid_write_byte;
+  MethodID m_mid_write_bytearray;
+};
+
+} // namespace Java
+
+#endif // SVN_JAVAHL_JNIWRAPPER_IO_STREAM_HPP

Propchange: subversion/trunk/subversion/bindings/javahl/native/jniwrapper/jni_io_stream.hpp
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp?rev=1543985&r1=1543984&r2=1543985&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_SubstLib.cpp Wed Nov 20 23:43:31 2013
@@ -24,15 +24,18 @@
  * @brief Implementation of the native methods in the Java class SubstLib
  */
 
+#include <memory>
+
 #include "../include/org_apache_subversion_javahl_util_SubstLib.h"
 
 #include "jniwrapper/jni_stack.hpp"
 #include "jniwrapper/jni_array.hpp"
 #include "jniwrapper/jni_string.hpp"
 #include "jniwrapper/jni_string_map.hpp"
+#include "jniwrapper/jni_io_stream.hpp"
 
 #include "JNIUtil.h"
-#include "InputStream.h"
+#include "NativeStream.hpp"
 
 #include <apr_strings.h>
 #include <apr_hash.h>
@@ -43,6 +46,99 @@
 
 
 namespace {
+apr_hash_t*
+build_keywords_common(Java::Env env, const SVN::Pool& pool,
+                      jbyteArray jkeywords_value, jlong jrevision,
+                      jstring jurl, jstring jrepos_root_url,
+                      jobject jdate, jstring jauthor)
+{
+  const Java::ByteArray keywords_value(env, jkeywords_value);
+  const Java::String url(env, jurl);
+  const Java::String repos_root_url(env, jrepos_root_url);
+  const Java::String author(env, jauthor);
+
+  const Java::ByteArray::Contents keywords_contents(keywords_value);
+  svn_string_t* keywords_string = keywords_contents.get_string(pool);
+  const char* revision = (jrevision < 0 ? NULL
+                          : apr_psprintf(pool.getPool(),
+                                         "%"APR_UINT64_T_FMT,
+                                         apr_uint64_t(jrevision)));
+  const Java::String::Contents url_contents(url);
+  const Java::String::Contents root_url_contents(repos_root_url);
+  const Java::String::Contents author_contents(author);
+
+  apr_hash_t* kw = NULL;
+  SVN_JAVAHL_CHECK(env,
+                   svn_subst_build_keywords3(
+                       &kw,
+                       keywords_string->data,
+                       revision,
+                       url_contents.c_str(),
+                       root_url_contents.c_str(),
+                       (jdate ? JNIUtil::getDate(jdate) : 0),
+                       author_contents.c_str(),
+                       pool.getPool()));
+  return kw;
+}
+
+class KeywordHashBuilder
+{
+public:
+  explicit KeywordHashBuilder(const SVN::Pool& pool)
+    : m_pool(pool),
+      m_hash(apr_hash_make(pool.getPool()))
+    {}
+
+  void operator()(const std::string& key, const Java::ByteArray& value)
+    {
+      Java::ByteArray::Contents val(value);
+      apr_hash_set(m_hash, key.c_str(), key.size(), val.get_string(m_pool));
+    }
+
+  apr_hash_t* get() const
+    {
+      return m_hash;
+    }
+
+private:
+  const SVN::Pool& m_pool;
+  apr_hash_t* const m_hash;
+};
+
+inline apr_hash_t*
+make_keywords_hash(Java::Env env, const SVN::Pool& pool, jobject jkeywords)
+{
+  const Java::Map<Java::ByteArray, jbyteArray> keywords(env, jkeywords);
+  return keywords.for_each(KeywordHashBuilder(pool)).get();
+}
+
+svn_stream_t*
+translate_stream_common(Java::Env env, const SVN::Pool& pool,
+                        svn_stream_t* stream,
+                        jbyteArray jeol_marker, jboolean jrepair_eol,
+                        jobject jkeywords, jboolean juse_keywords,
+                        jboolean jexpand_keywords,
+                        jbyteArray jkeywords_value, jlong jrevision,
+                        jstring jurl, jstring jrepos_root_url,
+                        jobject jdate, jstring jauthor)
+{
+  apr_hash_t* const keywords =
+    (juse_keywords
+     ? make_keywords_hash(env, pool, jkeywords)
+     : build_keywords_common(
+         env, pool, jkeywords_value, jrevision,
+         jurl, jrepos_root_url, jdate, jauthor));
+
+  const Java::ByteArray eol_marker(env, jeol_marker);
+  svn_string_t* const eol_str =
+    Java::ByteArray::Contents(eol_marker).get_string(pool);
+  return svn_subst_stream_translated(stream,
+                                     eol_str->data,
+                                     svn_boolean_t(jrepair_eol),
+                                     keywords,
+                                     svn_boolean_t(jexpand_keywords),
+                                     pool.getPool());
+}
 } // anoymous namespace
 
 
@@ -57,36 +153,13 @@ Java_org_apache_subversion_javahl_util_S
     {
       const Java::Env env(jenv);
 
-      const Java::ByteArray keywords_value(env, jkeywords_value);
-      const Java::String url(env, jurl);
-      const Java::String repos_root_url(env, jrepos_root_url);
-      const Java::String author(env, jauthor);
-
       // Using a "global" request pool since we don't keep a context with
       // its own pool around for these functions.
       SVN::Pool pool;
 
-      const Java::ByteArray::Contents keywords_contents(keywords_value);
-      svn_string_t* keywords_string = keywords_contents.get_string(pool);
-      const char* revision = (jrevision < 0 ? NULL
-                              : apr_psprintf(pool.getPool(),
-                                             "%"APR_UINT64_T_FMT,
-                                             apr_uint64_t(jrevision)));
-      const Java::String::Contents url_contents(url);
-      const Java::String::Contents root_url_contents(repos_root_url);
-      const Java::String::Contents author_contents(author);
-
-      apr_hash_t* kw = NULL;
-      SVN_JAVAHL_CHECK(env,
-                       svn_subst_build_keywords3(
-                           &kw,
-                           keywords_string->data,
-                           revision,
-                           url_contents.c_str(),
-                           root_url_contents.c_str(),
-                           (jdate ? JNIUtil::getDate(jdate) : 0),
-                           author_contents.c_str(),
-                           pool.getPool()));
+      apr_hash_t* const kw = build_keywords_common(
+          env, pool, jkeywords_value, jrevision,
+          jurl, jrepos_root_url, jdate, jauthor);
 
       Java::MutableMap<Java::ByteArray, jbyteArray>
         keywords(env, jint(apr_hash_count(kw)));
@@ -106,3 +179,71 @@ Java_org_apache_subversion_javahl_util_S
   SVN_JAVAHL_JNI_CATCH;
   return NULL;
 }
+
+
+JNIEXPORT jobject JNICALL
+Java_org_apache_subversion_javahl_util_SubstLib_translateInputStream(
+    JNIEnv* jenv, jobject jthis,
+    jobject jsource, jbyteArray jeol_marker, jboolean jrepair_eol,
+    jobject jkeywords, jboolean juse_keywords, jboolean jexpand_keywords,
+    jbyteArray jkeywords_value, jlong jrevision,
+    jstring jurl, jstring jrepos_root_url,
+    jobject jdate, jstring jauthor)
+{
+  SVN_JAVAHL_JNI_TRY(SubstLib, translateInputStream)
+    {
+      const Java::Env env(jenv);
+
+      // We'll allocate the stream in the bound object's pool.
+      std::auto_ptr<JavaHL::NativeInputStream>
+        translated(new JavaHL::NativeInputStream());
+      svn_stream_t* source = Java::InputStream::get_global_stream(
+          env, jsource, translated->get_pool());
+
+      translated->set_stream(translate_stream_common(
+                                 env, translated->get_pool(), source,
+                                 jeol_marker, jrepair_eol,
+                                 jkeywords, juse_keywords, jexpand_keywords,
+                                 jkeywords_value, jrevision,
+                                 jurl, jrepos_root_url, jdate, jauthor));
+      const jobject jtranslated = translated->create_java_wrapper();
+      translated.release();
+      return jtranslated;
+    }
+  SVN_JAVAHL_JNI_CATCH;
+  return NULL;
+}
+
+
+JNIEXPORT jobject JNICALL
+Java_org_apache_subversion_javahl_util_SubstLib_translateOutputStream(
+    JNIEnv* jenv, jobject jthis,
+    jobject jdestination, jbyteArray jeol_marker, jboolean jrepair_eol,
+    jobject jkeywords, jboolean juse_keywords, jboolean jexpand_keywords,
+    jbyteArray jkeywords_value, jlong jrevision,
+    jstring jurl, jstring jrepos_root_url,
+    jobject jdate, jstring jauthor)
+{
+  SVN_JAVAHL_JNI_TRY(SubstLib, translateInputStream)
+    {
+      const Java::Env env(jenv);
+
+      // We'll allocate the stream in the bound object's pool.
+      std::auto_ptr<JavaHL::NativeOutputStream>
+        translated(new JavaHL::NativeOutputStream());
+      svn_stream_t* destination = Java::OutputStream::get_global_stream(
+          env, jdestination, translated->get_pool());
+
+      translated->set_stream(translate_stream_common(
+                                 env, translated->get_pool(), destination,
+                                 jeol_marker, jrepair_eol,
+                                 jkeywords, juse_keywords, jexpand_keywords,
+                                 jkeywords_value, jrevision,
+                                 jurl, jrepos_root_url, jdate, jauthor));
+      const jobject jtranslated = translated->create_java_wrapper();
+      translated.release();
+      return jtranslated;
+    }
+  SVN_JAVAHL_JNI_CATCH;
+  return NULL;
+}

Added: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeInputStream.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeInputStream.java?rev=1543985&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeInputStream.java (added)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeInputStream.java Wed Nov 20 23:43:31 2013
@@ -0,0 +1,108 @@
+/**
+ * @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
+ */
+
+package org.apache.subversion.javahl.types;
+
+import org.apache.subversion.javahl.NativeResources;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Implementation class for {@link InputStream} objects returned from
+ * JavaHL methods.
+ *
+ * @since 1.9
+ */
+public class NativeInputStream extends InputStream
+{
+    /**
+     * Load the required native library.
+     */
+    static
+    {
+        NativeResources.loadNativeLibrary();
+    }
+
+    /**
+     * Flushes buffers, closes the underlying native stream, and
+     * releases the native object.
+     * @see InputStream.close()
+     */
+    @Override
+    public native void close() throws IOException;
+
+    /**
+     * @see InputStream.markSupported()
+     */
+    @Override
+    public native boolean markSupported();
+
+    /**
+     * @see InputStream.mark(int)
+     */
+    @Override
+    public native void mark(int readlimit);
+
+    /**
+     * @see InputStream.reset()
+     */
+    @Override
+    public native void reset() throws IOException;
+
+    /**
+     * Reads a single byte from the underyling native stream.
+     * @see InputStream.read()
+     */
+    @Override
+    public native int read() throws IOException;
+
+    /**
+     * Reads <code>len</code> bytes to offset <code>off</code> in
+     * <code>b</code> from the underyling native stream.
+     * @see InputStream.read(byte[],int,int)
+     */
+    @Override
+    public native int read(byte[] b, int off, int len) throws IOException;
+
+    /**
+     * @see InputStream.skip(long)
+     */
+    @Override
+    public native long skip(long count) throws IOException;
+
+
+    private long cppAddr;
+
+    private NativeInputStream(long cppAddr)
+    {
+        this.cppAddr = cppAddr;
+    }
+
+    private long getCppAddr()
+    {
+        return cppAddr;
+    }
+
+    public native void finalize();
+}

Propchange: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeOutputStream.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeOutputStream.java?rev=1543985&view=auto
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeOutputStream.java (added)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeOutputStream.java Wed Nov 20 23:43:31 2013
@@ -0,0 +1,84 @@
+/**
+ * @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
+ */
+
+package org.apache.subversion.javahl.types;
+
+import org.apache.subversion.javahl.NativeResources;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Implementation class for {@link OutputStream} objects returned from
+ * JavaHL methods.
+ *
+ * @since 1.9
+ */
+public class NativeOutputStream extends OutputStream
+{
+    /**
+     * Load the required native library.
+     */
+    static
+    {
+        NativeResources.loadNativeLibrary();
+    }
+
+    /**
+     * Flushes buffers, closes the underlying native stream, and
+     * releases the native object.
+     * @see OutputStream.close()
+     */
+    @Override
+    public native void close() throws IOException;
+
+    /**
+     * Writes a single byte to the underyling native stream.
+     * @see OutputStream.write(int)
+     */
+    @Override
+    public native void write(int b) throws IOException;
+
+    /**
+     * Writes <code>len</code> bytes at offset <code>off</code> from
+     * <code>b</code> to the underyling native stream.
+     * @see OutputStream.write(byte[],int,int)
+     */
+    @Override
+    public native void write(byte[] b, int off, int len) throws IOException;
+
+
+    private long cppAddr;
+
+    private NativeOutputStream(long cppAddr)
+    {
+        this.cppAddr = cppAddr;
+    }
+
+    private long getCppAddr()
+    {
+        return cppAddr;
+    }
+
+    public native void finalize();
+}

Propchange: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/types/NativeOutputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java?rev=1543985&r1=1543984&r2=1543985&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java (original)
+++ subversion/trunk/subversion/bindings/javahl/src/org/apache/subversion/javahl/util/SubstLib.java Wed Nov 20 23:43:31 2013
@@ -78,42 +78,36 @@ public class SubstLib
     /**
      * @see SVNUtil.translateStream
      */
-    public /*native*/ InputStream translateInputStream(
-                                      InputStream source,
-                                      byte[] eolMarker,
-                                      boolean repairEol,
-                                      Map<String, byte[]> keywords,
-                                      boolean useKeywordsMap,
-                                      boolean expandKeywords,
-                                      byte[] keywordsValue,
-                                      long revision,
-                                      String url,
-                                      String reposRootUrl,
-                                      Date date,
-                                      String author)
-        throws SubversionException, ClientException//;
-    {
-        throw new RuntimeException("Not implemented: SubstLib.translateInputStream");
-    }
+    public native InputStream translateInputStream(
+                                  InputStream source,
+                                  byte[] eolMarker,
+                                  boolean repairEol,
+                                  Map<String, byte[]> keywords,
+                                  boolean useKeywordsMap,
+                                  boolean expandKeywords,
+                                  byte[] keywordsValue,
+                                  long revision,
+                                  String url,
+                                  String reposRootUrl,
+                                  Date date,
+                                  String author)
+        throws SubversionException, ClientException;
 
     /**
      * @see SVNUtil.translateStream
      */
-    public /*native*/ OutputStream translateOutputStream(
-                                      OutputStream destination,
-                                      byte[] eolMarker,
-                                      boolean repairEol,
-                                      Map<String, byte[]> keywords,
-                                      boolean useKeywordsMap,
-                                      boolean expandKeywords,
-                                      byte[] keywordsValue,
-                                      long revision,
-                                      String url,
-                                      String reposRootUrl,
-                                      Date date,
-                                      String author)
-        throws SubversionException, ClientException//;
-    {
-        throw new RuntimeException("Not implemented: SubstLib.translateOutputStream");
-    }
+    public native OutputStream translateOutputStream(
+                                   OutputStream destination,
+                                   byte[] eolMarker,
+                                   boolean repairEol,
+                                   Map<String, byte[]> keywords,
+                                   boolean useKeywordsMap,
+                                   boolean expandKeywords,
+                                   byte[] keywordsValue,
+                                   long revision,
+                                   String url,
+                                   String reposRootUrl,
+                                   Date date,
+                                   String author)
+        throws SubversionException, ClientException;
 }

Modified: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java?rev=1543985&r1=1543984&r2=1543985&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java (original)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/UtilTests.java Wed Nov 20 23:43:31 2013
@@ -30,7 +30,10 @@ import org.apache.subversion.javahl.type
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Date;
@@ -404,9 +407,170 @@ public class UtilTests extends SVNTests
                                        null, null, null, null);
         assertEquals("     ", new String(result.get("TEST")));
 
-        result = SVNUtil.buildKeywords(kwval, 48, "http://a/b/c",
+        result = SVNUtil.buildKeywords(kwval, 42, "http://a/b/c",
                                        "http://a", new Date(1), "X");
-        assertEquals("b/c 48 1970-01-01 00:00:00Z X c http://a/b/c",
+        assertEquals("b/c 42 1970-01-01 00:00:00Z X c http://a/b/c",
                      new String(result.get("TEST")));
     }
+
+    public void testTranslateStream() throws Throwable
+    {
+        final byte[] keywordsValue = "Id TEST=%H%_%b%_%u".getBytes();
+        final byte[] contentsContracted = "$Id$\n$TEST$\n".getBytes();
+        final byte[] contentsExpanded =
+            ("$Id: c 42 1970-01-01 00:00:00Z X $\r" +
+             "$TEST: b/c 42 1970-01-01 00:00:00Z X c http://a/b/c $\r"
+             ) .getBytes();
+        final Map<String, byte[]> keywords =
+            SVNUtil.buildKeywords(keywordsValue, 42, "http://a/b/c",
+                                  "http://a", new Date(1), "X");
+        byte[] buffer = new byte[1024];
+
+        // InputStream; expand
+        InputStream testin = null;
+        try {
+            testin = SVNUtil.translateStream(
+                         new ByteArrayInputStream(contentsContracted),
+                         SVNUtil.EOL_CR, true, keywords, true);
+            final int size = testin.read(buffer);
+            testin.close();
+            testin = null;
+
+            assertEquals(new String(contentsExpanded),
+                         new String(buffer, 0, size));
+        } finally {
+            if (testin != null) {
+                testin.close();
+                testin = null;
+            }
+        }
+
+        try {
+            testin = SVNUtil.translateStream(
+                         new ByteArrayInputStream(contentsContracted),
+                         SVNUtil.EOL_CR, true, true,
+                         keywordsValue, 42, "http://a/b/c",
+                         "http://a", new Date(1), "X");
+            final int size = testin.read(buffer);
+            testin.close();
+            testin = null;
+
+            assertEquals(new String(contentsExpanded),
+                         new String(buffer, 0, size));
+        } finally {
+            if (testin != null) {
+                testin.close();
+                testin = null;
+            }
+        }
+
+        // InputStream; contract
+        try {
+            testin = SVNUtil.translateStream(
+                         new ByteArrayInputStream(contentsExpanded),
+                         SVNUtil.EOL_LF, true, keywords, false);
+            final int size = testin.read(buffer);
+            testin.close();
+            testin = null;
+
+            assertEquals(new String(contentsContracted),
+                         new String(buffer, 0, size));
+        } finally {
+            if (testin != null) {
+                testin.close();
+                testin = null;
+            }
+        }
+
+        try {
+            testin = SVNUtil.translateStream(
+                         new ByteArrayInputStream(contentsExpanded),
+                         SVNUtil.EOL_LF, true, false,
+                         keywordsValue, 42, "http://a/b/c",
+                         "http://a", new Date(1), "X");
+            final int size = testin.read(buffer);
+            testin.close();
+            testin = null;
+
+            assertEquals(new String(contentsContracted),
+                         new String(buffer, 0, size));
+        } finally {
+            if (testin != null) {
+                testin.close();
+                testin = null;
+            }
+        }
+
+
+        // OutputStream; expand
+        OutputStream testout = null;
+        try {
+            ByteArrayOutputStream result = new ByteArrayOutputStream();
+            testout = SVNUtil.translateStream(
+                         result, SVNUtil.EOL_CR, true, keywords, true);
+            testout.write(contentsContracted);
+            testout.close();
+            testout = null;
+
+            assertEquals(new String(contentsExpanded), result.toString());
+        } finally {
+            if (testout != null) {
+                testout.close();
+                testout = null;
+            }
+        }
+
+        try {
+            ByteArrayOutputStream result = new ByteArrayOutputStream();
+            testout = SVNUtil.translateStream(
+                         result, SVNUtil.EOL_CR, true, true,
+                         keywordsValue, 42, "http://a/b/c",
+                         "http://a", new Date(1), "X");
+            testout.write(contentsContracted);
+            testout.close();
+            testout = null;
+
+            assertEquals(new String(contentsExpanded), result.toString());
+        } finally {
+            if (testout != null) {
+                testout.close();
+                testout = null;
+            }
+        }
+
+        // OutputStream; contract
+        try {
+            ByteArrayOutputStream result = new ByteArrayOutputStream();
+            testout = SVNUtil.translateStream(
+                         result, SVNUtil.EOL_LF, true, keywords, false);
+            testout.write(contentsExpanded);
+            testout.close();
+            testout = null;
+
+            assertEquals(new String(contentsContracted), result.toString());
+        } finally {
+            if (testout != null) {
+                testout.close();
+                testout = null;
+            }
+        }
+
+        try {
+            ByteArrayOutputStream result = new ByteArrayOutputStream();
+            testout = SVNUtil.translateStream(
+                         result, SVNUtil.EOL_LF, true, false,
+                         keywordsValue, 42, "http://a/b/c",
+                         "http://a", new Date(1), "X");
+            testout.write(contentsExpanded);
+            testout.close();
+            testout = null;
+
+            assertEquals(new String(contentsContracted), result.toString());
+        } finally {
+            if (testout != null) {
+                testout.close();
+                testout = null;
+            }
+        }
+    }
 }



Mime
View raw message