summaryrefslogtreecommitdiff
path: root/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_PropLib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/bindings/javahl/native/org_apache_subversion_javahl_util_PropLib.cpp')
-rw-r--r--subversion/bindings/javahl/native/org_apache_subversion_javahl_util_PropLib.cpp381
1 files changed, 381 insertions, 0 deletions
diff --git a/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_PropLib.cpp b/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_PropLib.cpp
new file mode 100644
index 0000000..3456dea
--- /dev/null
+++ b/subversion/bindings/javahl/native/org_apache_subversion_javahl_util_PropLib.cpp
@@ -0,0 +1,381 @@
+/**
+ * @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
+ *
+ * @file org_apache_subversion_javahl_util_PropLib.cpp
+ * @brief Implementation of the native methods in the Java class PropLib
+ */
+
+#include <iostream>
+#include <sstream>
+
+#include "../include/org_apache_subversion_javahl_util_PropLib.h"
+
+#include "jniwrapper/jni_stack.hpp"
+#include "jniwrapper/jni_array.hpp"
+#include "jniwrapper/jni_list.hpp"
+#include "jniwrapper/jni_string.hpp"
+#include "jniwrapper/jni_io_stream.hpp"
+#include "ExternalItem.hpp"
+#include "SubversionException.hpp"
+
+#include "EnumMapper.h"
+#include "Pool.h"
+
+#include "svn_props.h"
+#include "svn_time.h"
+#include "svn_wc.h"
+
+#include "private/svn_wc_private.h"
+#include "svn_private_config.h"
+
+
+namespace {
+class PropGetter
+{
+public:
+ PropGetter(const char* mime_type, svn_stream_t* contents)
+ : m_mime_type(mime_type),
+ m_contents(contents)
+ {}
+
+ static svn_error_t* callback(const svn_string_t** mime_type,
+ svn_stream_t* stream, void* baton,
+ apr_pool_t* pool)
+ {
+ PropGetter* self = static_cast<PropGetter*>(baton);
+ if (mime_type)
+ {
+ if (self->m_mime_type)
+ *mime_type = svn_string_create(self->m_mime_type, pool);
+ else
+ *mime_type = svn_string_create_empty(pool);
+ }
+
+ if (stream && self->m_contents)
+ {
+ SVN_ERR(svn_stream_copy3(self->m_contents,
+ svn_stream_disown(stream, pool),
+ NULL, NULL, pool));
+ }
+
+ return SVN_NO_ERROR;
+ }
+
+private:
+ const char* m_mime_type;
+ svn_stream_t* m_contents;
+};
+
+struct FormatRevision
+{
+ explicit FormatRevision(const svn_opt_revision_t* const& revarg,
+ const SVN::Pool& poolarg)
+ : rev(revarg), pool(poolarg)
+ {}
+
+ const svn_opt_revision_t* const& rev;
+ const SVN::Pool& pool;
+};
+
+std::ostream& operator<<(std::ostream& os, const FormatRevision& pr)
+{
+ switch (pr.rev->kind)
+ {
+ case svn_opt_revision_number:
+ os << pr.rev->value.number;
+ break;
+ case svn_opt_revision_date:
+ os << '{'
+ << svn_time_to_cstring(pr.rev->value.date, pr.pool.getPool())
+ << '}';
+ break;
+ default:
+ throw std::logic_error(
+ _("Invalid revision tag; must be a number or a date"));
+ }
+ return os;
+}
+
+bool operator==(const svn_opt_revision_t& a,
+ const svn_opt_revision_t& b)
+{
+ if (a.kind != b.kind)
+ return false;
+ if (a.kind == svn_opt_revision_number
+ && a.value.number != b.value.number)
+ return false;
+ if (a.kind == svn_opt_revision_date
+ && a.value.date != b.value.date)
+ return false;
+ return true;
+}
+
+inline bool operator!=(const svn_opt_revision_t& a,
+ const svn_opt_revision_t& b)
+{
+ return !(a == b);
+}
+
+class UnparseFunctor
+{
+public:
+ explicit UnparseFunctor(std::ostringstream& buffer, bool old_format,
+ SVN::Pool& iterpool)
+ : m_buffer(buffer),
+ m_old_format(old_format),
+ m_iterpool(iterpool)
+ {}
+
+ void operator()(const JavaHL::ExternalItem& item)
+ {
+ m_iterpool.clear();
+
+ const Java::Env env(item.get_env());
+ const Java::LocalFrame frame(env);
+
+ if (!m_old_format)
+ {
+ if (item.revision()->kind != svn_opt_revision_head
+ && *item.revision() != *item.peg_revision())
+ {
+ m_buffer << "-r"
+ << FormatRevision(item.revision(), m_iterpool)
+ << ' ';
+ }
+ if (item.peg_revision()->kind == svn_opt_revision_head)
+ m_buffer << item.url() << ' ';
+ else
+ {
+ m_buffer << item.url() << '@'
+ << FormatRevision(item.peg_revision(), m_iterpool)
+ << ' ';
+ }
+ m_buffer << item.target_dir() << '\n';
+ }
+ else
+ {
+ // Sanity check: old format does not support peg revisions
+ if (item.peg_revision()->kind != svn_opt_revision_head
+ && *item.revision() != *item.peg_revision())
+ {
+ JavaHL::SubversionException(env)
+ .raise(_("Clients older than Subversion 1.5"
+ " do not support peg revision syntax"
+ " in the svn:externals property"));
+ }
+
+ // Sanity check: old format does not support relative URLs
+ const std::string url = item.url();
+ if ( (url.size() >= 1 && (url[0] == '.' || url[0] == '/'))
+ || (url.size() >= 2 && (url[0] == '^' && url[1] == '/')))
+ {
+ JavaHL::SubversionException(env)
+ .raise(_("Clients older than Subversion 1.5"
+ " do not support relative URLs"
+ " in the svn:externals property"));
+ }
+
+ m_buffer << item.target_dir() << ' ';
+ if (item.revision()->kind != svn_opt_revision_head)
+ {
+ m_buffer << "-r"
+ << FormatRevision(item.revision(), m_iterpool)
+ << ' ';
+ }
+ m_buffer << url << '\n';
+ }
+ }
+
+private:
+ std::ostringstream& m_buffer;
+ const bool m_old_format;
+ SVN::Pool& m_iterpool;
+};
+} // anoymous namespace
+
+
+JNIEXPORT jbyteArray JNICALL
+Java_org_apache_subversion_javahl_util_PropLib_checkNodeProp(
+ JNIEnv* jenv, jobject jthis,
+ jstring jname, jbyteArray jvalue, jstring jpath, jobject jkind,
+ jstring jmime_type, jobject jfile_contents,
+ jboolean jskip_some_checks)
+{
+ SVN_JAVAHL_JNI_TRY(PropLib, checkLocalProp)
+ {
+ const Java::Env env(jenv);
+
+ const svn_node_kind_t kind = EnumMapper::toNodeKind(jkind);
+ SVN_JAVAHL_OLDSTYLE_EXCEPTION_CHECK(env);
+
+ const Java::String name_str(env, jname);
+ const Java::ByteArray value(env, jvalue);
+ const Java::String path_str(env, jpath);
+ const Java::String mime_type_str(env, jmime_type);
+ Java::InputStream file_contents(env, jfile_contents);
+
+ // 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::String::Contents name(name_str);
+ const Java::String::Contents path(path_str);
+ const Java::String::Contents mime_type(mime_type_str);
+ PropGetter getter(mime_type.c_str(), file_contents.get_stream(pool));
+
+ const svn_string_t* canonval;
+ SVN_JAVAHL_CHECK(env,
+ svn_wc_canonicalize_svn_prop(
+ &canonval, name.c_str(),
+ Java::ByteArray::Contents(value).get_string(pool),
+ path.c_str(), kind,
+ svn_boolean_t(jskip_some_checks),
+ PropGetter::callback, &getter,
+ pool.getPool()));
+ return Java::ByteArray(env, canonval->data, jint(canonval->len)).get();
+ }
+ SVN_JAVAHL_JNI_CATCH;
+ return NULL;
+}
+
+
+JNIEXPORT jobject JNICALL
+Java_org_apache_subversion_javahl_util_PropLib_parseExternals(
+ JNIEnv* jenv, jobject jthis,
+ jbyteArray jdescription, jstring jparent_dir, jboolean jcanonicalize_url)
+{
+ SVN_JAVAHL_JNI_TRY(PropLib, parseExternals)
+ {
+ const Java::Env env(jenv);
+
+ const Java::ByteArray description(env, jdescription);
+ const Java::String parent_dir(env, jparent_dir);
+
+ // Using a "global" request pool since we don't keep a context
+ // with its own pool around for these functions.
+ SVN::Pool pool;
+
+ apr_array_header_t* externals;
+ {
+ // There is no guarantee that the description contents are
+ // null-terminated. Copy them to an svn_string_t to make sure
+ // that they are.
+ svn_string_t* const description_contents =
+ Java::ByteArray::Contents(description).get_string(pool);
+
+ SVN_JAVAHL_CHECK(env,
+ svn_wc_parse_externals_description3(
+ &externals,
+ Java::String::Contents(parent_dir).c_str(),
+ description_contents->data,
+ svn_boolean_t(jcanonicalize_url),
+ pool.getPool()));
+ }
+
+ Java::List<JavaHL::ExternalItem> items(env, externals->nelts);
+ for (jint i = 0; i < externals->nelts; ++i)
+ {
+ // References to the newly created external items are stored
+ // in the list, so make sure the local reference in this
+ // frame get cleared on each iteration.
+ Java::LocalFrame frame;
+
+ const svn_wc_external_item2_t* const item =
+ APR_ARRAY_IDX(externals, i, svn_wc_external_item2_t*);
+ items.add(JavaHL::ExternalItem(env,
+ item->target_dir,
+ item->url,
+ &item->revision,
+ &item->peg_revision));
+ }
+ return items.get();
+ }
+ SVN_JAVAHL_JNI_CATCH;
+ return NULL;
+}
+
+
+JNIEXPORT jbyteArray JNICALL
+Java_org_apache_subversion_javahl_util_PropLib_unparseExternals(
+ JNIEnv* jenv, jobject jthis,
+ jobject jitems, jstring jparent_dir, jboolean jold_format)
+{
+ SVN_JAVAHL_JNI_TRY(PropLib, unparseExternals)
+ {
+ const Java::Env env(jenv);
+
+ const Java::ImmutableList<JavaHL::ExternalItem> items(env, jitems);
+ const Java::String parent_dir(env, jparent_dir);
+
+ // Using a "global" iteration pool since we don't keep a context
+ // with its own pool around for these functions.
+ SVN::Pool iterpool;
+
+ std::ostringstream buffer;
+ items.for_each(UnparseFunctor(buffer, jold_format, iterpool));
+ const std::string description(buffer.str());
+
+ // Validate the result. Even though we generated the string
+ // ourselves, we did not validate the input paths and URLs.
+ SVN_JAVAHL_CHECK(env,
+ svn_wc_parse_externals_description3(
+ NULL,
+ Java::String::Contents(parent_dir).c_str(),
+ description.c_str(),
+ false, iterpool.getPool()));
+ return Java::ByteArray(env, description).get();
+ }
+ SVN_JAVAHL_JNI_CATCH;
+ return NULL;
+}
+
+
+JNIEXPORT jstring JNICALL
+Java_org_apache_subversion_javahl_util_PropLib_resolveExternalsUrl(
+ JNIEnv* jenv, jobject jthis,
+ jobject jitem, jstring jrepos_root_url, jstring jparent_dir_url)
+{
+ SVN_JAVAHL_JNI_TRY(PropLib, unparseExternals)
+ {
+ const Java::Env env(jenv);
+
+ const Java::String repos_root_url(env, jrepos_root_url);
+ const Java::String parent_dir_url(env, jparent_dir_url);
+ const JavaHL::ExternalItem item(env, jitem);
+
+ // Using a "global" request pool since we don't keep a context
+ // with its own pool around for these functions.
+ SVN::Pool pool;
+
+ const char* resolved_url;
+ SVN_JAVAHL_CHECK(env,
+ svn_wc__resolve_relative_external_url(
+ &resolved_url,
+ item.get_external_item(pool),
+ Java::String::Contents(repos_root_url).c_str(),
+ Java::String::Contents(parent_dir_url).c_str(),
+ pool.getPool(), pool.getPool()));
+ return Java::String(env, resolved_url).get();
+ }
+ SVN_JAVAHL_JNI_CATCH;
+ return NULL;
+}